Skip to content

Interpreting gcode

Peter Boin edited this page Jul 28, 2017 · 4 revisions

Reading / Interpreting GCode

To read gcode from a file, utilise the Line class. Each Line instance contains a Block and an optional Comment. The Block contains a list of gcodes you're after.

from pygcode import Line

with open('part.gcode', 'r') as fh:
    for line_text in fh.readlines():
        line = Line(line_text)

        print(line)  # will print the line (with cosmetic changes)
        line.block.gcodes  # is your list of gcodes
        line.block.modal_params  # are all parameters not assigned to a gcode, assumed to be motion modal parameters
        if line.comment:
            line.comment.text  # your comment text

To elaborate, here are some line examples

>>> from pygcode import Line

>>> line = Line('G01 x1 y2  f100 s1000 ; blah')
>>> print(line)
G01 X1 Y2 F100 S1000 ; blah
>>> print(line.block)
G01 X1 Y2 F100 S1000
>>> sorted(line.block.gcodes)
[<GCodeFeedRate: F100>,
 <GCodeSpindleSpeed: S1000>,
 <GCodeLinearMove: G01{X1, Y2}>]
>>> print(line.comment)
; blah

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 pygcode-normalize.py

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)

Clone this wiki locally