Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
pythonic-gcode-machine
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Fabrice Salvaire
pythonic-gcode-machine
Commits
f2bafa75
Commit
f2bafa75
authored
Dec 24, 2018
by
Fabrice Salvaire
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
improved G-code API
parent
6898bc98
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
312 additions
and
15 deletions
+312
-15
Ast.py
PythonicGcodeMachine/Gcode/Rs274/Ast.py
+159
-12
annotate-gcode.py
examples/gcode/annotate-gcode.py
+7
-3
generate-gcode.py
examples/gcode/generate-gcode.py
+146
-0
No files found.
PythonicGcodeMachine/Gcode/Rs274/Ast.py
View file @
f2bafa75
...
...
@@ -19,6 +19,8 @@
####################################################################################################
"""Module to implement an AST for RS-274 G-code.
All classes are clonable.
"""
####################################################################################################
...
...
@@ -64,6 +66,7 @@ __all__ = [
####################################################################################################
import
math
import
re
import
colors
...
...
@@ -84,6 +87,8 @@ class Program:
str(program)
program2 = program.clone()
"""
##############################################
...
...
@@ -93,6 +98,16 @@ class Program:
##############################################
def
clone
(
self
):
program
=
self
.
__class__
()
for
line
in
self
:
program
+=
line
.
clone
()
return
program
##############################################
def
push
(
self
,
line
):
self
.
_lines
.
append
(
line
)
...
...
@@ -134,7 +149,42 @@ class Program:
####################################################################################################
class
LineItem
:
class
CloneMixin
:
@
staticmethod
def
_clone_value
(
value
):
if
hasattr
(
value
,
'clone'
):
return
value
.
clone
()
else
:
return
value
####################################################################################################
class
LineItem
(
CloneMixin
):
##############################################
def
_check_value
(
self
,
value
):
if
(
isinstance
(
value
,
(
int
,
float
))
or
isinstance
(
value
,
RealValue
)):
return
value
else
:
try
:
str_value
=
str
(
value
)
except
:
raise
ValueError
(
"Invalid value {}"
.
format
(
value
))
# Fixme:
from
.Parser
import
GcodeParser
,
GcodeParserError
parser
=
GcodeParser
()
try
:
# Fixme: parser hack
ast
=
parser
.
parse
(
'X'
+
value
)
return
ast
[
0
]
.
value
except
GcodeParserError
:
raise
ValueError
(
"Invalid G-code value {}"
.
format
(
value
))
##############################################
def
ansi_str
(
self
):
return
str
(
self
)
...
...
@@ -162,11 +212,13 @@ class Line:
line += Comment('move')
line += Word('X', 10)
line += Comment('Y value')
line += Word('Y', 20)
line += Word('Y', 20
.
)
line += ParameterSetting('1', 1.2)
# using expression
# using expression
, AST way
line += Word('Z', Addition(30, Multiply(Parameter(100), Cosine(30))))
# string way
line += Word('Z', '[30 + [#100 * cos[30]]]')
# Array interface
for item in line:
...
...
@@ -175,6 +227,18 @@ class Line:
str(line)
print(line.ansi_str()) # use ANSI colors, see Line.ANSI_... attributes
a_line = line.clone()
Values can be passed as:
* int or float,
* AST for expression,
* any object that "str" evaluate to a valid G-code expression.
As a shortcut, a G/M-code operation can be passed as string::
line += 'G0'
Expression can be evaluated using :code:`float(obj.value)`, excepted when we must access a parameter
value.
...
...
@@ -200,6 +264,16 @@ class Line:
##############################################
def
clone
(
self
):
line
=
self
.
__class__
(
self
.
_deleted
,
self
.
_line_number
,
self
.
_comment
)
for
item
in
self
:
line
+=
item
.
clone
()
return
line
##############################################
@
property
def
deleted
(
self
):
return
self
.
_deleted
...
...
@@ -233,13 +307,26 @@ class Line:
##############################################
def
_push_item
(
self
,
item
):
if
not
isinstance
(
item
,
LineItem
):
item
=
Word
.
from_str
(
item
)
# Fixme: try to parse ???
self
.
_items
.
append
(
item
)
def
push_items
(
self
,
iterable
):
"""Method to push an iterable"""
for
item
in
iterable
:
self
.
push
(
item
)
def
push
(
self
,
item
):
if
isinstance
(
item
,
LineItem
):
self
.
_items
.
append
(
item
)
"""Method to push a valid item, a 'G/Mxxx' shortcut string, a list or tuple"""
if
isinstance
(
item
,
(
list
,
tuple
,
Line
)):
self
.
push_items
(
item
)
else
:
raise
ValueError
self
.
_push_item
(
item
)
def
__iadd__
(
self
,
item
):
"""push shortcut"""
self
.
push
(
item
)
return
self
...
...
@@ -273,6 +360,24 @@ class Line:
##############################################
def
toggle
(
self
):
"""Toggle deleted flag"""
self
.
_deleted
=
not
self
.
_deleted
def
remove_line_number
(
self
):
self
.
_line_number
=
None
##############################################
def
remove_comment
(
self
):
self
.
_comment
=
None
for
i
,
item
in
enumerate
(
self
):
if
isinstance
(
item
,
Comment
):
# self._items.pop(i)
del
self
.
_items
[
i
]
##############################################
def
__repr__
(
self
):
items
=
[]
...
...
@@ -328,6 +433,11 @@ class Comment(LineItem):
##############################################
def
clone
(
self
):
return
self
.
__class__
(
self
.
_text
)
##############################################
def
set
(
self
,
text
):
if
'('
in
text
:
raise
ValueError
(
'Comment cannot contains a "("'
)
...
...
@@ -367,6 +477,20 @@ class Word(LineItem):
'X'
,
'Y'
,
'Z'
,
)
WORD_RE
=
re
.
compile
(
'(G|M)(
\
d+)'
)
##############################################
@
classmethod
def
from_str
(
cls
,
obj
):
str_obj
=
str
(
obj
)
match
=
cls
.
WORD_RE
.
match
(
str_obj
)
if
match
is
not
None
:
return
cls
(
*
match
.
groups
())
else
:
raise
ValueError
(
obj
)
##############################################
def
__init__
(
self
,
letter
,
value
):
...
...
@@ -375,6 +499,11 @@ class Word(LineItem):
##############################################
def
clone
(
self
):
return
self
.
__class__
(
self
.
_letter
,
self
.
_clone_value
(
self
.
_value
))
##############################################
@
property
def
letter
(
self
):
return
self
.
_letter
...
...
@@ -392,13 +521,12 @@ class Word(LineItem):
@
value
.
setter
def
value
(
self
,
value
):
# float expression ...
self
.
_value
=
value
self
.
_value
=
self
.
_check_value
(
value
)
##############################################
def
__repr__
(
self
):
return
'Word({0._letter} {0._value})'
.
format
(
self
)
return
'Word({0._letter}
,
{0._value})'
.
format
(
self
)
def
__str__
(
self
):
return
'{0._letter}{0._value}'
.
format
(
self
)
...
...
@@ -412,7 +540,7 @@ class Word(LineItem):
####################################################################################################
class
RealValue
:
class
RealValue
(
CloneMixin
)
:
pass
####################################################################################################
...
...
@@ -426,6 +554,11 @@ class ParameterMixin:
##############################################
def
clone
(
self
):
return
self
.
__class__
(
self
.
_parameter
)
##############################################
@
property
def
parameter
(
self
):
return
self
.
_parameter
...
...
@@ -450,6 +583,11 @@ class ParameterSetting(LineItem, ParameterMixin):
ParameterMixin
.
__init__
(
self
,
parameter
)
self
.
value
=
value
##############################################
def
clone
(
self
):
return
self
.
__class__
(
self
.
_parameter
,
self
.
_clone_value
(
self
.
_value
))
##############################################
@
property
def
value
(
self
):
...
...
@@ -457,8 +595,7 @@ class ParameterSetting(LineItem, ParameterMixin):
@
value
.
setter
def
value
(
self
,
value
):
# float expression ...
self
.
_value
=
value
self
.
_value
=
self
.
_check_value
(
value
)
##############################################
...
...
@@ -509,6 +646,11 @@ class UnaryOperation(RealValue):
##############################################
def
clone
(
self
):
return
self
.
__class__
(
self
.
_clone_value
(
self
.
_arg
))
##############################################
@
property
def
arg
(
self
):
return
self
.
_arg
...
...
@@ -601,6 +743,11 @@ class BinaryOperation(RealValue):
##############################################
def
clone
(
self
):
return
self
.
__class__
(
self
.
_clone_value
(
self
.
_arg1
),
self
.
_clone_value
(
self
.
arg2
))
##############################################
@
property
def
arg1
(
self
):
return
self
.
_arg1
...
...
examples/gcode/annotate-gcode.py
View file @
f2bafa75
...
...
@@ -20,11 +20,15 @@
####################################################################################################
#r# ===========================
#r# Annotate a G-code program
#r# ===========================
#r#
#r# ==================================================
#r# Example to show how to annotate a G-code program
#r# ==================================================
#r# For API see
#r#
#r# * :mod:`PythonicGcodeMachine.Gcode.Rs274`
#r# * :mod:`PythonicGcodeMachine.Gcode.Rs274.Ast`
#r# * :mod:`PythonicGcodeMachine.Gcode.Rs274.Parser`
####################################################################################################
...
...
examples/gcode/generate-gcode.py
0 → 100644
View file @
f2bafa75
#?##################################################################################################
#?#
#?# PythonicGcodeMachine - @licence_header_description@
#?# Copyright (C) 2018 Fabrice Salvaire
#?#
#?# This program is free software: you can redistribute it and/or modify
#?# it under the terms of the GNU General Public License as published by
#?# the Free Software Foundation, either version 3 of the License, or
#?# (at your option) any later version.
#?#
#?# This program is distributed in the hope that it will be useful,
#?# but WITHOUT ANY WARRANTY; without even the implied warranty of
#?# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#?# GNU General Public License for more details.
#?#
#?# You should have received a copy of the GNU General Public License
#?# along with this program. If not, see <http://www.gnu.org/licenses/>.
#?#
#?##################################################################################################
####################################################################################################
#r# ===========================
#r# Generate a G-code program
#r# ===========================
#r#
#r# For API see
#r#
#r# * :mod:`PythonicGcodeMachine.Gcode.Rs274`
#r# * :mod:`PythonicGcodeMachine.Gcode.Rs274.Ast`
#r# * :mod:`PythonicGcodeMachine.Gcode.Rs274.Parser`
####################################################################################################
from
PythonicGcodeMachine.Gcode.Rs274
import
*
from
PythonicGcodeMachine.Gcode.Rs274.Ast
import
*
####################################################################################################
#r# Create a G-code line (block) using AST API
line
=
Line
(
deleted
=
False
,
line_number
=
1
,
comment
=
'a G-code block'
)
# Push some items
# Note: order doesn't matter, see RS-274 for details
line
+=
Word
(
'G'
,
0
)
line
+=
Comment
(
'fast move'
)
line
+=
Word
(
'X'
,
10
)
line
+=
Word
(
'Y'
,
20
)
print
(
line
)
#o#
#r# More simpler way to pass G/M-code
a_line
=
Line
()
a_line
+=
'G0'
a_line
+=
Word
(
'X'
,
10
)
print
(
a_line
)
#o#
#r# Using the G-code parser
parser
=
GcodeParser
()
a_line
=
parser
.
parse
(
'G0 X0 Y0'
)
a_line
+=
Word
(
'Z'
,
0
)
print
(
a_line
)
#o#
a_line
=
Line
()
a_line
+=
'G0'
parsed_line
=
parser
.
parse
(
'X1 Y2'
)
print
(
list
(
parsed_line
))
first_item
=
parsed_line
[
0
]
print
(
first_item
)
a_line
+=
parsed_line
print
(
a_line
)
#o#
#r# Expression : the AST way
line2
=
line
.
clone
()
line2
+=
Word
(
'Z'
,
Addition
(
30
,
Multiply
(
Parameter
(
100
),
Cosine
(
30
))))
print
(
line2
)
#o#
#r# Expression : the literal way
line3
=
line
.
clone
()
line3
+=
Word
(
'Z'
,
'[30 + [#100 * cos[30]]]'
)
print
(
line3
)
#o#
#r# Invalid expression
try
:
line4
=
line
.
clone
()
line4
+=
Word
(
'Z'
,
'1 + 2]'
)
print
(
line4
)
except
ValueError
:
pass
#r# Create a G-code program
program
=
Program
()
program
+=
line
line2
.
line_number
=
2
line2
.
comment
=
'using expression'
program
+=
line2
line3
.
deleted
=
True
line3
.
line_number
=
3
line3
.
comment
=
None
program
+=
line3
print
(
program
)
#o#
#r# Line cleanup tools
line
=
Line
(
deleted
=
False
,
line_number
=
1
,
comment
=
'a G-code block'
)
line
+=
'G0'
line
+=
Comment
(
'fast move'
)
line
+=
Word
(
'X'
,
10
)
line
+=
Word
(
'Y'
,
20
)
print
(
line
)
#o#
line
.
toggle
()
print
(
line
)
#o#
line
.
toggle
()
line
.
remove_line_number
()
print
(
line
)
#o#
line
.
remove_comment
()
print
(
line
)
#o#
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment