mirror of
https://git.mirrors.martin98.com/https://github.com/petaflot/pygcode
synced 2025-06-04 11:25:20 +08:00
added pygcode-norm cleaning and finalizing
This commit is contained in:
parent
bb0ab66cc9
commit
5b3c070e8c
@ -18,12 +18,14 @@ for pygcode_lib_type in ('installed_lib', 'relative_lib'):
|
|||||||
from pygcode import Machine, Mode, Line
|
from pygcode import Machine, Mode, Line
|
||||||
from pygcode import GCodeArcMove, GCodeArcMoveCW, GCodeArcMoveCCW
|
from pygcode import GCodeArcMove, GCodeArcMoveCW, GCodeArcMoveCCW
|
||||||
from pygcode import GCodeCannedCycle
|
from pygcode import GCodeCannedCycle
|
||||||
|
from pygcode import GCodeRapidMove, GCodeStopSpindle, GCodeAbsoluteDistanceMode
|
||||||
from pygcode import split_gcodes
|
from pygcode import split_gcodes
|
||||||
from pygcode import Comment
|
from pygcode import Comment
|
||||||
from pygcode.transform import linearize_arc, simplify_canned_cycle
|
from pygcode.transform import linearize_arc, simplify_canned_cycle
|
||||||
from pygcode.transform import ArcLinearizeInside, ArcLinearizeOutside, ArcLinearizeMid
|
from pygcode.transform import ArcLinearizeInside, ArcLinearizeOutside, ArcLinearizeMid
|
||||||
from pygcode.gcodes import _subclasses
|
from pygcode.gcodes import _subclasses
|
||||||
from pygcode import utils
|
from pygcode import utils
|
||||||
|
from pygcode.exceptions import MachineInvalidState
|
||||||
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import sys, os, inspect
|
import sys, os, inspect
|
||||||
@ -65,7 +67,9 @@ def arc_lin_method_type(value):
|
|||||||
|
|
||||||
def word_list_type(value):
|
def word_list_type(value):
|
||||||
"""
|
"""
|
||||||
:return: [Word('G73'), Word('G89'), ... ]
|
Convert csv string list into Word instances.
|
||||||
|
>>> word_list_type("G73,G89") == set([Word('G73'), Word('G89')])
|
||||||
|
:return: set of Word instances
|
||||||
"""
|
"""
|
||||||
canned_code_words = set()
|
canned_code_words = set()
|
||||||
for word_str in re.split(r'\s*,\s*', value):
|
for word_str in re.split(r'\s*,\s*', value):
|
||||||
@ -157,6 +161,34 @@ group.add_argument(
|
|||||||
help="List of canned gcodes to expand, (default is '%s')" % DEFAULT_CANNED_CODES,
|
help="List of canned gcodes to expand, (default is '%s')" % DEFAULT_CANNED_CODES,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Finalize Code
|
||||||
|
group = parser.add_argument_group(
|
||||||
|
"Finalise File",
|
||||||
|
"standardize what's done at the end of a gcode program."
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
'--zero_xy', '-zxy', dest="zero_xy",
|
||||||
|
action='store_const', const=True, default=False,
|
||||||
|
help="On completion, move straight up to rapid_safety_height, "
|
||||||
|
"then across to X0 Y0.",
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
'--zero_z', '-zz', dest="zero_z",
|
||||||
|
action='store_const', const=True, default=False,
|
||||||
|
help="On completion, move down to Z0 (done after zero_xy, if set)",
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
'--rapid_safety_height', '-rsh', dest="rapid_safety_height",
|
||||||
|
type=float, default=None,
|
||||||
|
help="Z value to move to before traversing workpeice (if not set, max "
|
||||||
|
"value will be attempted)",
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
'--spindle_off', '-so', dest="spindle_off",
|
||||||
|
action='store_const', const=True, default=False,
|
||||||
|
help="On completion, turn spindle off",
|
||||||
|
)
|
||||||
|
|
||||||
# Removing non-functional content
|
# Removing non-functional content
|
||||||
group = parser.add_argument_group(
|
group = parser.add_argument_group(
|
||||||
"Removing Content",
|
"Removing Content",
|
||||||
@ -183,7 +215,11 @@ group.add_argument(
|
|||||||
help="remove gcode (and it's parameters) with words in the given list "
|
help="remove gcode (and it's parameters) with words in the given list "
|
||||||
"(eg: M6,G43) (note: only works for modal params with --full)",
|
"(eg: M6,G43) (note: only works for modal params with --full)",
|
||||||
)
|
)
|
||||||
|
group.add_argument(
|
||||||
|
'--rm_invalid_modal', '-rmim', dest='rm_invalid_modal',
|
||||||
|
action='store_const', const=True, default=False,
|
||||||
|
help="simply remove everything that isn't understood... not the safest strategy",
|
||||||
|
)
|
||||||
|
|
||||||
# --- Parse Arguments
|
# --- Parse Arguments
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
@ -195,6 +231,7 @@ class MyMode(Mode):
|
|||||||
|
|
||||||
class MyMachine(Machine):
|
class MyMachine(Machine):
|
||||||
MODE_CLASS = MyMode
|
MODE_CLASS = MyMode
|
||||||
|
ignore_invalid_modal = args.rm_invalid_modal
|
||||||
|
|
||||||
machine = MyMachine()
|
machine = MyMachine()
|
||||||
|
|
||||||
@ -276,6 +313,9 @@ def split_and_process(gcode_list, gcode_class, comment):
|
|||||||
for line_str in args.infile.readlines():
|
for line_str in args.infile.readlines():
|
||||||
line = Line(line_str)
|
line = Line(line_str)
|
||||||
|
|
||||||
|
if args.rm_invalid_modal:
|
||||||
|
machine.clean_block(line.block)
|
||||||
|
|
||||||
# Effective G-Codes:
|
# Effective G-Codes:
|
||||||
# fills in missing motion modal gcodes (using machine's current motion mode).
|
# fills in missing motion modal gcodes (using machine's current motion mode).
|
||||||
effective_gcodes = machine.block_modal_gcodes(line.block)
|
effective_gcodes = machine.block_modal_gcodes(line.block)
|
||||||
@ -315,3 +355,23 @@ for line_str in args.infile.readlines():
|
|||||||
else:
|
else:
|
||||||
write(line.block.gcodes, modal_params=line.block.modal_params, comment=line.comment, macro=line.macro)
|
write(line.block.gcodes, modal_params=line.block.modal_params, comment=line.comment, macro=line.macro)
|
||||||
machine.process_block(line.block)
|
machine.process_block(line.block)
|
||||||
|
|
||||||
|
# Finalizing Motion & Spindle
|
||||||
|
if any([args.spindle_off, args.zero_xy, args.zero_z]):
|
||||||
|
write([], comment=Comment("pygcode-norm: finalizing"))
|
||||||
|
if any([args.zero_xy, args.zero_z]) and not(isinstance(machine.mode.distance, GCodeAbsoluteDistanceMode)):
|
||||||
|
write([GCodeAbsoluteDistanceMode()])
|
||||||
|
if args.spindle_off:
|
||||||
|
write([GCodeStopSpindle()], comment=Comment("spindle off"))
|
||||||
|
|
||||||
|
if args.zero_xy:
|
||||||
|
rapid_safety_height = args.rapid_safety_height
|
||||||
|
if rapid_safety_height is None:
|
||||||
|
rapid_safety_height = machine.abs2work(machine.abs_range_max).Z
|
||||||
|
|
||||||
|
if args.zero_xy:
|
||||||
|
write([GCodeRapidMove(Z=rapid_safety_height)], comment=Comment("move to safe height"))
|
||||||
|
write([GCodeRapidMove(X=0, Y=0)], comment=Comment("move to planar origin"))
|
||||||
|
|
||||||
|
if args.zero_z:
|
||||||
|
write([GCodeRapidMove(Z=0)], comment=Comment("move to zero height"))
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# 1.x - Development Status :: 5 - Production/Stable
|
# 1.x - Development Status :: 5 - Production/Stable
|
||||||
# <any above>.y - developments on that version (pre-release)
|
# <any above>.y - developments on that version (pre-release)
|
||||||
# <any above>*.dev* - development release (intended purely to test deployment)
|
# <any above>*.dev* - development release (intended purely to test deployment)
|
||||||
__version__ = "0.2.0"
|
__version__ = "0.2.1"
|
||||||
|
|
||||||
__title__ = "pygcode"
|
__title__ = "pygcode"
|
||||||
__description__ = "Basic g-code parser, interpreter, and encoder library."
|
__description__ = "Basic g-code parser, interpreter, and encoder library."
|
||||||
@ -69,6 +69,7 @@ __all__ = [
|
|||||||
'GCodeCutterCompRight',
|
'GCodeCutterCompRight',
|
||||||
'GCodeCutterRadiusComp',
|
'GCodeCutterRadiusComp',
|
||||||
'GCodeCutterRadiusCompOff',
|
'GCodeCutterRadiusCompOff',
|
||||||
|
'GCodeDefinition',
|
||||||
'GCodeDigitalOutput',
|
'GCodeDigitalOutput',
|
||||||
'GCodeDigitalOutputOff',
|
'GCodeDigitalOutputOff',
|
||||||
'GCodeDigitalOutputOffSyncd',
|
'GCodeDigitalOutputOffSyncd',
|
||||||
@ -98,6 +99,7 @@ __all__ = [
|
|||||||
'GCodeInverseTimeMode',
|
'GCodeInverseTimeMode',
|
||||||
'GCodeLatheDiameterMode',
|
'GCodeLatheDiameterMode',
|
||||||
'GCodeLatheRadiusMode',
|
'GCodeLatheRadiusMode',
|
||||||
|
'GCodeLineNumber',
|
||||||
'GCodeLinearMove',
|
'GCodeLinearMove',
|
||||||
'GCodeMotion',
|
'GCodeMotion',
|
||||||
'GCodeMoveInMachineCoords',
|
'GCodeMoveInMachineCoords',
|
||||||
@ -113,6 +115,7 @@ __all__ = [
|
|||||||
'GCodePauseProgramOptional',
|
'GCodePauseProgramOptional',
|
||||||
'GCodePlaneSelect',
|
'GCodePlaneSelect',
|
||||||
'GCodeProgramControl',
|
'GCodeProgramControl',
|
||||||
|
'GCodeProgramName',
|
||||||
'GCodeQuadraticSpline',
|
'GCodeQuadraticSpline',
|
||||||
'GCodeRapidMove',
|
'GCodeRapidMove',
|
||||||
'GCodeResetCoordSystemOffset',
|
'GCodeResetCoordSystemOffset',
|
||||||
@ -190,7 +193,6 @@ from .words import (
|
|||||||
# GCode
|
# GCode
|
||||||
from .gcodes import (
|
from .gcodes import (
|
||||||
words2gcodes, text2gcodes, split_gcodes,
|
words2gcodes, text2gcodes, split_gcodes,
|
||||||
|
|
||||||
# $ python -c "from pygcode.gcodes import _gcode_class_infostr as x; print(x(prefix=' # '))"
|
# $ python -c "from pygcode.gcodes import _gcode_class_infostr as x; print(x(prefix=' # '))"
|
||||||
# - GCode:
|
# - GCode:
|
||||||
# - GCodeCannedCycle:
|
# - GCodeCannedCycle:
|
||||||
@ -214,6 +216,9 @@ from .gcodes import (
|
|||||||
# G40 - GCodeCutterRadiusCompOff: G40: Cutter Radius Compensation Off
|
# G40 - GCodeCutterRadiusCompOff: G40: Cutter Radius Compensation Off
|
||||||
# G41.1 - GCodeDynamicCutterCompLeft: G41.1: Dynamic Cutter Radius Compensation (left)
|
# G41.1 - GCodeDynamicCutterCompLeft: G41.1: Dynamic Cutter Radius Compensation (left)
|
||||||
# G42.1 - GCodeDynamicCutterCompRight: G42.1: Dynamic Cutter Radius Compensation (right)
|
# G42.1 - GCodeDynamicCutterCompRight: G42.1: Dynamic Cutter Radius Compensation (right)
|
||||||
|
# - GCodeDefinition:
|
||||||
|
# - GCodeLineNumber: N: Line Number
|
||||||
|
# - GCodeProgramName: O: Program Name
|
||||||
# - GCodeDistanceMode:
|
# - GCodeDistanceMode:
|
||||||
# G90.1 - GCodeAbsoluteArcDistanceMode: G90.1: Absolute Distance Mode for Arc IJK Parameters
|
# G90.1 - GCodeAbsoluteArcDistanceMode: G90.1: Absolute Distance Mode for Arc IJK Parameters
|
||||||
# G90 - GCodeAbsoluteDistanceMode: G90: Absolute Distance Mode
|
# G90 - GCodeAbsoluteDistanceMode: G90: Absolute Distance Mode
|
||||||
@ -346,6 +351,7 @@ from .gcodes import (
|
|||||||
GCodeCutterCompRight,
|
GCodeCutterCompRight,
|
||||||
GCodeCutterRadiusComp,
|
GCodeCutterRadiusComp,
|
||||||
GCodeCutterRadiusCompOff,
|
GCodeCutterRadiusCompOff,
|
||||||
|
GCodeDefinition,
|
||||||
GCodeDigitalOutput,
|
GCodeDigitalOutput,
|
||||||
GCodeDigitalOutputOff,
|
GCodeDigitalOutputOff,
|
||||||
GCodeDigitalOutputOffSyncd,
|
GCodeDigitalOutputOffSyncd,
|
||||||
@ -375,6 +381,7 @@ from .gcodes import (
|
|||||||
GCodeInverseTimeMode,
|
GCodeInverseTimeMode,
|
||||||
GCodeLatheDiameterMode,
|
GCodeLatheDiameterMode,
|
||||||
GCodeLatheRadiusMode,
|
GCodeLatheRadiusMode,
|
||||||
|
GCodeLineNumber,
|
||||||
GCodeLinearMove,
|
GCodeLinearMove,
|
||||||
GCodeMotion,
|
GCodeMotion,
|
||||||
GCodeMoveInMachineCoords,
|
GCodeMoveInMachineCoords,
|
||||||
@ -390,6 +397,7 @@ from .gcodes import (
|
|||||||
GCodePauseProgramOptional,
|
GCodePauseProgramOptional,
|
||||||
GCodePlaneSelect,
|
GCodePlaneSelect,
|
||||||
GCodeProgramControl,
|
GCodeProgramControl,
|
||||||
|
GCodeProgramName,
|
||||||
GCodeQuadraticSpline,
|
GCodeQuadraticSpline,
|
||||||
GCodeRapidMove,
|
GCodeRapidMove,
|
||||||
GCodeResetCoordSystemOffset,
|
GCodeResetCoordSystemOffset,
|
||||||
|
@ -5,6 +5,7 @@ from collections import defaultdict
|
|||||||
from .gcodes import (
|
from .gcodes import (
|
||||||
MODAL_GROUP_MAP, GCode,
|
MODAL_GROUP_MAP, GCode,
|
||||||
# Modal GCodes
|
# Modal GCodes
|
||||||
|
GCodeMotion,
|
||||||
GCodeIncrementalDistanceMode,
|
GCodeIncrementalDistanceMode,
|
||||||
GCodeUseInches, GCodeUseMillimeters,
|
GCodeUseInches, GCodeUseMillimeters,
|
||||||
# Utilities
|
# Utilities
|
||||||
@ -369,6 +370,7 @@ class Machine(object):
|
|||||||
STATE_CLASS = State
|
STATE_CLASS = State
|
||||||
|
|
||||||
axes = set('XYZ')
|
axes = set('XYZ')
|
||||||
|
ignore_invalid_modal = False
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.mode = self.MODE_CLASS()
|
self.mode = self.MODE_CLASS()
|
||||||
@ -407,12 +409,15 @@ class Machine(object):
|
|||||||
# TODO: convert coord systems between inches/mm, G20/G21 respectively
|
# TODO: convert coord systems between inches/mm, G20/G21 respectively
|
||||||
|
|
||||||
def modal_gcode(self, modal_params):
|
def modal_gcode(self, modal_params):
|
||||||
|
"""
|
||||||
|
:param ignore_unassigned: if truthy, unassigned parameters will be ignored
|
||||||
|
"""
|
||||||
|
|
||||||
if not modal_params:
|
if not modal_params:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if self.mode.motion is None:
|
if self.mode.motion is None:
|
||||||
unasigned_words = modal_params
|
(modal_gcodes, unasigned_words) = ([], modal_params)
|
||||||
# forces exception to be raised in next step
|
# forces exception to be raised in next step
|
||||||
else:
|
else:
|
||||||
params = copy(self.mode.motion.params) # dict
|
params = copy(self.mode.motion.params) # dict
|
||||||
@ -421,9 +426,11 @@ class Machine(object):
|
|||||||
[self.mode.motion.word] + list(params.values())
|
[self.mode.motion.word] + list(params.values())
|
||||||
)
|
)
|
||||||
|
|
||||||
if unasigned_words:
|
if unasigned_words and (not self.ignore_invalid_modal):
|
||||||
# Can't process with unknown words on the same line...
|
# Can't process with unknown words on the same line...
|
||||||
# raising: MachineInvalidState
|
# 2 choices:
|
||||||
|
# - raise MachineInvalidState
|
||||||
|
# - or remove unassigned parameters from line
|
||||||
plausable_codes = [w for w in unasigned_words if w.letter in set('GM')]
|
plausable_codes = [w for w in unasigned_words if w.letter in set('GM')]
|
||||||
if plausable_codes:
|
if plausable_codes:
|
||||||
# words in list are probably valid, but unsupported, G-Codes
|
# words in list are probably valid, but unsupported, G-Codes
|
||||||
@ -456,6 +463,25 @@ class Machine(object):
|
|||||||
gcodes.append(modal_gcode)
|
gcodes.append(modal_gcode)
|
||||||
return sorted(gcodes)
|
return sorted(gcodes)
|
||||||
|
|
||||||
|
def clean_block(self, block):
|
||||||
|
"""
|
||||||
|
Remove invalid modal parameters from given block
|
||||||
|
:param block: Block instance to clean
|
||||||
|
"""
|
||||||
|
assert isinstance(block, Block), "invalid parameter"
|
||||||
|
if self.mode.motion is None:
|
||||||
|
# no modal motion, modal parameters are all invalid
|
||||||
|
block.modal_params = []
|
||||||
|
elif any(True for g in block.gcodes if g.modal_group == GCodeMotion.modal_group):
|
||||||
|
# block defines new motion, modal motion is irrelevant
|
||||||
|
block.modal_params = []
|
||||||
|
else:
|
||||||
|
(modal_gcodes, unasigned_words) = words2gcodes(
|
||||||
|
[self.mode.motion.word] + list(block.modal_params)
|
||||||
|
)
|
||||||
|
for w in unasigned_words:
|
||||||
|
block.modal_params.remove(w)
|
||||||
|
|
||||||
def process_gcodes(self, *gcode_list, **kwargs):
|
def process_gcodes(self, *gcode_list, **kwargs):
|
||||||
"""
|
"""
|
||||||
Process gcodes
|
Process gcodes
|
||||||
@ -491,19 +517,28 @@ class Machine(object):
|
|||||||
line = Line(block_str)
|
line = Line(block_str)
|
||||||
self.process_block(line.block)
|
self.process_block(line.block)
|
||||||
|
|
||||||
|
# Position conversions (considering offsets)
|
||||||
|
def abs2work(self, abs_pos):
|
||||||
|
assert isinstance(abs_pos, Position), "bad abs_pos type"
|
||||||
|
coord_sys_offset = getattr(self.state.coord_sys, 'offset', Position(axes=self.axes))
|
||||||
|
temp_offset = self.state.offset
|
||||||
|
return (abs_pos - coord_sys_offset) - temp_offset
|
||||||
|
|
||||||
|
def work2abs(self, work_pos):
|
||||||
|
assert isinstance(work_pos, Position), "bad work_pos type"
|
||||||
|
coord_sys_offset = getattr(self.state.coord_sys, 'offset', Position(axes=self.axes))
|
||||||
|
temp_offset = self.state.offset
|
||||||
|
return (work_pos + temp_offset + coord_sys_offset)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pos(self):
|
def pos(self):
|
||||||
"""Return current position in current coordinate system"""
|
"""Return current position in current coordinate system"""
|
||||||
coord_sys_offset = getattr(self.state.coord_sys, 'offset', Position(axes=self.axes))
|
return self.abs2work(self.abs_pos)
|
||||||
temp_offset = self.state.offset
|
|
||||||
return (self.abs_pos - coord_sys_offset) - temp_offset
|
|
||||||
|
|
||||||
@pos.setter
|
@pos.setter
|
||||||
def pos(self, value):
|
def pos(self, value):
|
||||||
"""Set absolute position given current position and coordinate system"""
|
"""Set absolute position given current position and coordinate system"""
|
||||||
coord_sys_offset = getattr(self.state.coord_sys, 'offset', Position(axes=self.axes))
|
self.abs_pos = self.work2abs(value)
|
||||||
temp_offset = self.state.offset
|
|
||||||
self.abs_pos = (value + temp_offset) + coord_sys_offset
|
|
||||||
self._update_abs_range(self.abs_pos)
|
self._update_abs_range(self.abs_pos)
|
||||||
|
|
||||||
def _update_abs_range(self, pos):
|
def _update_abs_range(self, pos):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user