Writing a G-code Interpreter
I’m currently working on a control system for a laser galvanometer (galvo) that I want to use in a stereolithography (SLA) resin printer. I don’t want to write a custom slicer, as I feel like model slicing can be incredibly complicated and existing free software (Cura, Slic3r, etc.) has many advanced features I don’t want to reimplement. However, this means my control system needs to understand G-code, the language that these slicers output.
As stated on the reprap wiki, “G-code is a list of fields that are separated by white spaces or line breaks. A field can be interpreted as a command, parameter, or for any other special purpose.” For now, we’ll ignore any special purposes. Here is an example of G-code that describes a movement of the tool/hotend/laser to a specific location:
G1 X10.4 Y7.4 Z8.3
I was able to parse commands with parameters using a two-stage procedure:
1. Retrieve the next white-space delimited token.
2. Accumulate tokens until two separate command tokens are found.
This second step is important because we can’t begin executing a command until we’ve found all of its parameters and we don’t know if we’ve found all of its parameters until we find the next command.
Once a command and all of its parameters have been parsed, it is passed to the controller which updates the state of the machine. For each command that the controller receives, it has to update its internal state, and in the case of physical movement commands, send the proper signal to the laser galvo. Most physical movement commands utilize interpolation so a timed control loop is utilized to ensure the laser follows as close to the intended path as possible.
System Diagram
Source Code
The source code for the G-code interpreter can be found here. You may have issues accessing the link if your ISP doesn’t support IPv6 yet.
Also, the names in the code are different than what’s shown in the diagram, so here’s the mapping to help out with understanding the code:
Diagram | Source File |
---|---|
tokenizer | token.c |
accumulator | command.c |
controller | machine.c |
I’ll try to keep this updated if the mapping changes as I continue to work on this project.