Skip to main content

GCODE Parser for Python

Currently in development, pygcode is a low-level GCode interpreter for python.

Installation

Using PyPi:

pip install pygcode

Usage

Just brainstorming here…

Writing GCode

Writing gcode from python object instances to text

>>> from pygcode import *
>>> gcodes = [
...     GCodeRapidMove(Z=5),
...     GCodeStartSpindleCW(),
...     GCodeRapidMove(X=10, Y=20),
...     GCodeFeedRate(200),
...     GCodeLinearMove(Z=-1.5),
...     GCodeRapidMove(Z=5),
...     GCodeStopSpindle(),
... ]
>>> print('\n'.join(str(g) for g in gcodes))

G00 Z5
M03
G00 X10 Y20
F200
G01 Z-1.5
G00 Z5
M05

To plot along a lines of vectors, you could write…

>>> from pygcode import *
>>> from euclid import Vector3

>>> vectors = [
...     Vector3(0, 0, 0),
...     Vector3(10, 0, 0),
...     Vector3(10, 20, 0),
...     Vector3(10, 20, 3),
...     Vector3(0, 20, 3),
...     Vector3(0, 0, 3),
...     Vector3(0, 0, 0)
... ]

>>> to_coords = lambda v: {'X': v.x, 'Y': v.y, 'Z': v.z}
>>> for v in vectors:
...     print("%s" % GCodeLinearMove(**to_coords(v)))

G01 X0 Y0 Z0
G01 X10 Y0 Z0
G01 X10 Y20 Z0
G01 X10 Y20 Z3
G01 X0 Y20 Z3
G01 X0 Y0 Z3
G01 X0 Y0 Z0

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
>>> print(line.comment)
; blah

>>> line = Line('G0 x1 y2 (foo) f100 (bar) s1000')
>>> print(line)
G00 X1 Y2 F100 S1000 (foo. bar)
>>> print(line.comment)
(foo. bar)

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)

Development

This library came from my own needs to interpret and convert erroneous arcs to linear segments, and to expand canned drilling cycles, but also as a means to learn GCode.

As such there is no direct plan for further development, however I’m interested in what you’d like to use it for, and cater for that.

Generally, in terms of what to support, I’m following the lead of:

More support will come with increased interest. So that is… if you don’t like what it does, or how it’s documented, make some noise in the issue section. if you get in early, you may get some free labour out of me ;)

Supported G-Codes

All GCodes supported by LinuxCNC can be written, and parsed by pygcode.

Few GCodes are accurately interpreted by a virtual CNC Machine instance. Supported movements are currently;

  • linear movements

  • arc movements

  • canned drilling cycles

Metadata

Release files for pygcode 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pygcode 0.1.0
File Size Uploaded
pygcode-0.1.0.tar.gz 36.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pygcode 0.1.0
File Interpreter ABI Platform
pygcode-0.1.0-py2.py3-none-any.whl Python 3, Python 2 none any Details

Total release size: 90.2 kB

Release files / pygcode-0.1.0.tar.gz

Download URL pygcode-0.1.0.tar.gz
Size 36.1 kB
Tags Source
SHA-256 checksum
How to use checksums
0099a4fac8ee0816a235294db816e3623e601d95d75aa47ec9e137b4fbfa4f78
BLAKE2b-256 checksum
How to use checksums
966818effd8e44e05239e778bac9eef358884a1ddb2c9670a956c44a7f02da10
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Release files / pygcode-0.1.0-py2.py3-none-any.whl

Download URL pygcode-0.1.0-py2.py3-none-any.whl
Size 54.1 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
b8677cdd4537e55eed1f09df6fea1cc4559d2d68df19ae380eb0773ea9d5b907
BLAKE2b-256 checksum
How to use checksums
b070c74891e335e35a1a69a96751e422dd3de7e64ae053d460dcb2a3176ef429
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Release history Release notifications | RSS feed

0.2.1

2 release files

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page