Skip to content

Commit 5577d65

Browse files
committed
linuxcnc word map
1 parent 71d3e02 commit 5577d65

File tree

11 files changed

+323
-247
lines changed

11 files changed

+323
-247
lines changed

src/pygcode/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
'Block',
3535
# Comment
3636
'Comment', 'split_line',
37+
3738
# Word
3839
'Word', 'text2words', 'str2word', 'words2dict',
3940

src/pygcode/block.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import re
2-
from .words import text2words, WORD_MAP
2+
from .words import text2words
33
from .gcodes import words2gcodes
4+
from . import dialects
5+
46

57
class Block(object):
68
"""GCode block (effectively any gcode file line that defines any <word><value>)"""
79

8-
def __init__(self, text=None, verify=True):
10+
def __init__(self, text=None, dialect=None, verify=True):
911
"""
1012
Block Constructor
1113
:param text: gcode line content (including comments) as string
@@ -26,6 +28,12 @@ def __init__(self, text=None, verify=True):
2628
self.gcodes = []
2729
self.modal_params = []
2830

31+
if dialect is None:
32+
dialect = dialects.get_default()
33+
self.dialect = dialect
34+
35+
self._word_map = getattr(getattr(dialects, dialect), 'WORD_MAP')
36+
2937
# clean up block string
3038
if text:
3139
self._raw_text = text # unaltered block content (before alteration)
@@ -71,7 +79,7 @@ def _assert_gcodes(self):
7179
modal_groups.add(gc.modal_group)
7280

7381
def __getattr__(self, k):
74-
if k in WORD_MAP:
82+
if k in self._word_map:
7583
for w in self.words:
7684
if w.letter == k:
7785
return w

src/pygcode/dialect/__init__.py

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/pygcode/dialect/linuxcnc.py

Lines changed: 0 additions & 18 deletions
This file was deleted.

src/pygcode/dialects/__init__.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
__all__ = [
2+
'DEFAULT',
3+
4+
# registration decorators
5+
'gcode_dialect',
6+
'word_dialect',
7+
8+
# dialects
9+
'linuxcnc',
10+
'reprap',
11+
]
12+
13+
14+
# Registration decorators
15+
from .mapping import gcode_dialect
16+
from .mapping import word_dialect
17+
18+
# Dialects
19+
from . import linuxcnc
20+
from . import reprap
21+
22+
23+
_DEFAULT = 'linuxcnc'
24+
25+
26+
def get_default():
27+
"""
28+
Get the default gcode interpreter dialect.
29+
(see :meth:`set_default` for details)
30+
"""
31+
return _DEFAULT
32+
33+
34+
def set_default(name):
35+
"""
36+
Set the default gcode interpreter dialect.
37+
This dialect will be used if no other is specified for particular function
38+
calls.
39+
40+
:param name: name of dialect
41+
:type name: :class:`str`
42+
43+
.. doctest::
44+
45+
>>> from pygcode import dialect
46+
>>> dialect.get_default()
47+
'linuxcnc'
48+
>>> dialect.set_default('reprap')
49+
>>> dialect.get_default()
50+
'reprap'
51+
52+
"""
53+
54+
# TODO: verify valid name
55+
_DEFAULT = name

src/pygcode/dialects/linuxcnc.py

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
"""
2+
LinuxCNC
3+
4+
The linuxcnc gcode dialect is typically used for subtractive fabrication, such
5+
as milling.
6+
7+
This dialect is the basis for all other dialects; GCodes and Words in other
8+
dialects either inherit, or directly reference these classes.
9+
10+
**Specification:** http://www.linuxcnc.org
11+
12+
TODO: verify above info before publishing
13+
"""
14+
15+
import re
16+
17+
from .utils import WordType
18+
19+
# ======================== WORDS ========================
20+
21+
REGEX_FLOAT = re.compile(r'^\s*-?(\d+\.?\d*|\.\d+)') # testcase: ..tests.test_words.WordValueMatchTests.test_float
22+
REGEX_INT = re.compile(r'^\s*-?\d+')
23+
REGEX_POSITIVEINT = re.compile(r'^\s*\d+')
24+
REGEX_CODE = re.compile(r'^\s*\d+(\.\d)?') # float, but can't be negative
25+
26+
# Value cleaning functions
27+
def _clean_codestr(value):
28+
if value < 10:
29+
return "0%g" % value
30+
return "%g" % value
31+
32+
CLEAN_NONE = lambda v: v
33+
CLEAN_FLOAT = lambda v: "{0:g}".format(round(v, 3))
34+
CLEAN_CODE = _clean_codestr
35+
CLEAN_INT = lambda v: "%g" % v
36+
37+
WORD_MAP = {
38+
# Descriptions copied from wikipedia:
39+
# https://en.wikipedia.org/wiki/G-code#Letter_addresses
40+
41+
# Rotational Axes
42+
'A': WordType(
43+
cls=float,
44+
value_regex=REGEX_FLOAT,
45+
description="Absolute or incremental position of A axis (rotational axis around X axis)",
46+
clean_value=CLEAN_FLOAT,
47+
),
48+
'B': WordType(
49+
cls=float,
50+
value_regex=REGEX_FLOAT,
51+
description="Absolute or incremental position of B axis (rotational axis around Y axis)",
52+
clean_value=CLEAN_FLOAT,
53+
),
54+
'C': WordType(
55+
cls=float,
56+
value_regex=REGEX_FLOAT,
57+
description="Absolute or incremental position of C axis (rotational axis around Z axis)",
58+
clean_value=CLEAN_FLOAT,
59+
),
60+
'D': WordType(
61+
cls=float,
62+
value_regex=REGEX_FLOAT,
63+
description="Defines diameter or radial offset used for cutter compensation. D is used for depth of cut on lathes. It is used for aperture selection and commands on photoplotters.",
64+
clean_value=CLEAN_FLOAT,
65+
),
66+
# Feed Rates
67+
'E': WordType(
68+
cls=float,
69+
value_regex=REGEX_FLOAT,
70+
description="Precision feedrate for threading on lathes",
71+
clean_value=CLEAN_FLOAT,
72+
),
73+
'F': WordType(
74+
cls=float,
75+
value_regex=REGEX_FLOAT,
76+
description="Feedrate",
77+
clean_value=CLEAN_FLOAT,
78+
),
79+
# G-Codes
80+
'G': WordType(
81+
cls=float,
82+
value_regex=REGEX_CODE,
83+
description="Address for preparatory commands",
84+
clean_value=CLEAN_CODE,
85+
),
86+
# Tool Offsets
87+
'H': WordType(
88+
cls=float,
89+
value_regex=REGEX_FLOAT,
90+
description="Defines tool length offset; Incremental axis corresponding to C axis (e.g., on a turn-mill)",
91+
clean_value=CLEAN_FLOAT,
92+
),
93+
# Arc radius center coords
94+
'I': WordType(
95+
cls=float,
96+
value_regex=REGEX_FLOAT,
97+
description="Defines arc center in X axis for G02 or G03 arc commands. Also used as a parameter within some fixed cycles.",
98+
clean_value=CLEAN_FLOAT,
99+
),
100+
'J': WordType(
101+
cls=float,
102+
value_regex=REGEX_FLOAT,
103+
description="Defines arc center in Y axis for G02 or G03 arc commands. Also used as a parameter within some fixed cycles.",
104+
clean_value=CLEAN_FLOAT,
105+
),
106+
'K': WordType(
107+
cls=float,
108+
value_regex=REGEX_FLOAT,
109+
description="Defines arc center in Z axis for G02 or G03 arc commands. Also used as a parameter within some fixed cycles, equal to L address.",
110+
clean_value=CLEAN_FLOAT,
111+
),
112+
# Loop Count
113+
'L': WordType(
114+
cls=int,
115+
value_regex=REGEX_POSITIVEINT,
116+
description="Fixed cycle loop count; Specification of what register to edit using G10",
117+
clean_value=CLEAN_INT,
118+
),
119+
# Miscellaneous Function
120+
'M': WordType(
121+
cls=float,
122+
value_regex=REGEX_CODE,
123+
description="Miscellaneous function",
124+
clean_value=CLEAN_CODE,
125+
),
126+
# Line Number
127+
'N': WordType(
128+
cls=int,
129+
value_regex=REGEX_POSITIVEINT,
130+
description="Line (block) number in program; System parameter number to change using G10",
131+
clean_value=CLEAN_INT,
132+
),
133+
# Program Name
134+
'O': WordType(
135+
cls=str,
136+
value_regex=re.compile(r'^.+$'), # all the way to the end
137+
description="Program name",
138+
clean_value=CLEAN_NONE,
139+
),
140+
# Parameter (arbitrary parameter)
141+
'P': WordType(
142+
cls=float, # parameter is often an integer, but can be a float
143+
value_regex=REGEX_FLOAT,
144+
description="Serves as parameter address for various G and M codes",
145+
clean_value=CLEAN_FLOAT,
146+
),
147+
# Peck increment
148+
'Q': WordType(
149+
cls=float,
150+
value_regex=REGEX_FLOAT,
151+
description="Depth to increase on each peck; Peck increment in canned cycles",
152+
clean_value=CLEAN_FLOAT,
153+
),
154+
# Arc Radius
155+
'R': WordType(
156+
cls=float,
157+
value_regex=REGEX_FLOAT,
158+
description="Defines size of arc radius, or defines retract height in milling canned cycles",
159+
clean_value=CLEAN_FLOAT,
160+
),
161+
# Spindle speed
162+
'S': WordType(
163+
cls=float,
164+
value_regex=REGEX_FLOAT,
165+
description="Defines speed, either spindle speed or surface speed depending on mode",
166+
clean_value=CLEAN_FLOAT,
167+
),
168+
# Tool Selecton
169+
'T': WordType(
170+
cls=str,
171+
value_regex=REGEX_POSITIVEINT, # tool string may have leading '0's, but is effectively an index (integer)
172+
description="Tool selection",
173+
clean_value=CLEAN_NONE,
174+
),
175+
# Incremental axes
176+
'U': WordType(
177+
cls=float,
178+
value_regex=REGEX_FLOAT,
179+
description="Incremental axis corresponding to X axis (typically only lathe group A controls) Also defines dwell time on some machines (instead of 'P' or 'X').",
180+
clean_value=CLEAN_FLOAT,
181+
),
182+
'V': WordType(
183+
cls=float,
184+
value_regex=REGEX_FLOAT,
185+
description="Incremental axis corresponding to Y axis",
186+
clean_value=CLEAN_FLOAT,
187+
),
188+
'W': WordType(
189+
cls=float,
190+
value_regex=REGEX_FLOAT,
191+
description="Incremental axis corresponding to Z axis (typically only lathe group A controls)",
192+
clean_value=CLEAN_FLOAT,
193+
),
194+
# Linear Axes
195+
'X': WordType(
196+
cls=float,
197+
value_regex=REGEX_FLOAT,
198+
description="Absolute or incremental position of X axis.",
199+
clean_value=CLEAN_FLOAT,
200+
),
201+
'Y': WordType(
202+
cls=float,
203+
value_regex=REGEX_FLOAT,
204+
description="Absolute or incremental position of Y axis.",
205+
clean_value=CLEAN_FLOAT,
206+
),
207+
'Z': WordType(
208+
cls=float,
209+
value_regex=REGEX_FLOAT,
210+
description="Absolute or incremental position of Z axis.",
211+
clean_value=CLEAN_FLOAT,
212+
),
213+
}
214+
215+
216+
# ======================== G-CODES ========================

src/pygcode/dialects/utils.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
# Data Classes
3+
4+
class WordType(object):
5+
def __init__(self, cls, value_regex, description, clean_value):
6+
self.cls = cls
7+
self.value_regex = value_regex
8+
self.description = description
9+
self.clean_value = clean_value

0 commit comments

Comments
 (0)