Interpreting gcode - fragmuffin/pygcode GitHub Wiki

Interpreting GCode

Interpreting what a line of gcode does depends on the machine it's running on, and also that machine's state (or 'mode')

The simple line of a rapid move to x=10, y=10 may be G00 X10 Y10. However, if the machine in question is in "Incremental Motion" mode G91 then the machine will only end up at x=10, y=10 if it started at x=0, y=0

So, GCode interpretation is done via a virtual machine:

>>> from pygcode import Machine, GCodeRapidMove

>>> m = Machine()
>>> m.pos
<Position: X0 Y0 Z0>
>>> g = GCodeRapidMove(X=10, Y=20)
>>> m.process_gcodes(g)
>>> m.pos
<Position: X10 Y20 Z0>
>>> m.process_gcodes(g)
>>> m.pos
<Position: X10 Y20 Z0>   # same position; machine in absolute mode
>>> m.mode.distance
<GCodeAbsoluteDistanceMode: G90>  # see

>>> m.process_gcodes(GCodeIncrementalDistanceMode())
>>> m.process_gcodes(g)  # same gcode as above
>>> m.pos
<Position: X20 Y40 Z0>

all valid m.mode attributes can be found with from pygcode.gcodes import MODAL_GROUP_MAP; MODAL_GROUP_MAP.keys()

Also note that the order codes are interpreted is important. For example, the following code is WRONG

from pygcode import Machine, Line
m = Machine()
line = Line('G0 x10 y10 G91')
m.process_gcodes(*line.block.gcodes)  # WRONG!

This will process the movement to x=10, y=10, and then it will change the distance mode to Incremental... there are 2 ways to do this correctly.

  • m.process_gcodes(*sorted(line.block.gcodes)), or simply
  • m.process_block(line.block)

sorting a list of gcodes will sort them in execution order (as specified by LinuxCNC's order of execution). process_block does this automatically.

If you need to process & change one type of gcode (usually a movement), you must split a list of gcodes into those executed before, and after the one in question.

from pygcode import GCodeRapidMove, GCodeLinearMove
from pygcode import Machine, Line, split_gcodes
m = Machine()
line = Line('M0 G0 x10 y10 G91')
(befores, (g,), afters) = split_gcodes(line.block.gcodes, (GCodeRapidMove, GCodeLinearMove))
m.process_gcodes(*sorted(befores))
if g.X is not None:
    g.X += 100  # shift linear movements (rapid or otherwise)
m.process_gcodes(g)
m.process_gcodes(*sorted(afters))

For a more practical use of machines & interpreting gcode, have a look at the pygcode-norm script

At the time of writing this, that script converts arcs to linear codes, and expands drilling cycles to basic movements (so my GRBL machine can understand them)