moved machinestate contents back to machine.py

This commit is contained in:
Peter Boin 2017-07-07 14:38:08 +10:00
parent c62ee74b78
commit 3674f9d6aa
3 changed files with 109 additions and 108 deletions

View File

@ -1,4 +1,5 @@
from collections import defaultdict
from copy import copy
from .words import Word
@ -140,8 +141,9 @@ class GCode(object):
# Parameters associated to this gcode
param_letters = set()
# Modal Group
# Modal stuff
modal_group = None
modal_param_letters = set() # by default: no parameters are retained in modal state
# Execution Order
exec_order = 999 # if not otherwise specified, run last
@ -208,15 +210,12 @@ class GCode(object):
def description(self):
return self.__doc__
@property
def mode(self):
"""
Mode word for modal GCodes
:return: Word to save machine's state, or None if GCode is not modal
"""
if self.modal_group is None:
return None
return self.word
def modal_copy(self):
"""Copy of GCode instance containing only parameters listed in modal_param_letters"""
return self.__class__(self.word, *[
w for (l, w) in self.params.items()
if l in self.modal_param_letters
])
# ======================= Motion =======================

View File

@ -4,7 +4,98 @@ from collections import defaultdict
from .gcodes import MODAL_GROUP_MAP, GCode
from .line import Line
from .machinestate import MachineState
class State(object):
"""State of a Machine"""
# State is very forgiving:
# Anything possible in a machine's state may be changed & fetched.
# For example: x, y, z, a, b, c may all be set & requested.
# However, the machine for which this state is stored probably doesn't
# have all possible 6 axes.
# It is also possible to set an axis to an impossibly large distance.
# It is the responsibility of the Machine using this class to be
# discerning in these respects.
def __init__(self):
self.axes = defaultdict(lambda: 0.0) # aka: "machine coordinates"
self.work_offset = defaultdict(lambda: 0.0)
# TODO: how to manage work offsets? (probs not like the above)
# read up on:
# - G92: coordinate system offset
# - G54-G59: select coordinate system (offsets from machine coordinates set by G10 L2)
# TODO: Move this class into MachineState
class MachineState(object):
"""Machine's state, and mode"""
# Default Mode
default_mode = '''
G17 (plane_selection: X/Y plane)
G90 (distance: absolute position. ie: not "turtle" mode)
G91.1 (arc_ijk_distance: IJK sets arc center vertex relative to current position)
G94 (feed_rate_mode: feed-rate defined in units/min)
G21 (units: mm)
G40 (cutter_diameter_comp: no compensation)
G49 (tool_length_offset: no offset)
G61 (control_mode: exact path mode)
G97 (spindle_speed_mode: RPM Mode)
M0 (stopping: program paused)
M5 (spindle: off)
M9 (coolant: off)
F100 (feed_rate: 100 mm/min)
S1000 (tool: 1000 rpm, when it's switched on)
'''
# Mode is defined by gcodes set by processed blocks:
# see modal_group in gcode.py module for details
def __init__(self):
self.modal_groups = defaultdict(lambda: None)
# Initialize
self.set_mode(*Line(self.default_mode).block.gcodes)
def set_mode(self, *gcode_list):
for g in sorted(gcode_list): # sorted by execution order
if g.modal_group is not None:
self.modal_groups[g.modal_group] = g.modal_copy()
def __getattr__(self, key):
if key in MODAL_GROUP_MAP:
return self.modal_groups[MODAL_GROUP_MAP[key]]
raise AttributeError("'{cls}' object has no attribute '{key}'".format(
cls=self.__class__.__name__,
key=key
))
def __setattr__(self, key, value):
if key in MODAL_GROUP_MAP:
# Set/Clear modal group gcode
if value is None:
# clear mode group
self.modal_groups[MODAL_GROUP_MAP[key]] = None
else:
# set mode group explicitly
# (recommended to use self.set_mode(value) instead)
assert isinstance(value, GCode), "invalid value type: %r" % value
assert value.modal_group == MODAL_GROUP_MAP[key], \
"cannot set '%s' mode as %r, wrong group" % (key, value)
self.modal_groups[MODAL_GROUP_MAP[key]] = value.modal_copy()
else:
self.__dict__[key] = value
def __str__(self):
gcode_list = []
for modal_group in sorted(MODAL_GROUP_MAP.values()):
if self.modal_groups[modal_group]:
gcode_list.append(self.modal_groups[modal_group])
return ' '.join(str(g) for g in gcode_list)
def __repr__(self):
return "<{class_name}: {gcodes}>".format(
class_name=self.__class__.__name__, gcodes=str(self)
)
class Machine(object):
@ -18,7 +109,15 @@ class Machine(object):
:param modal_params: list of Word instances to be applied to current movement mode
"""
modal_params = kwargs.get('modal_params', [])
#process_gcodes =
for gcode in sorted(gcode_list):
self.state.set_mode(gcode) # if gcode is not modal, it's ignored
gcode.process(self.state)
# TODO: gcode instance to change machine's state
# Questions to drive design:
# - how much time did the command take?
# - what was the tool's distance / displacement
# - did the tool travel outside machine boundaries?

View File

@ -1,97 +0,0 @@
from .gcodes import GCode
from .line import Line
class State(object):
"""State of a Machine"""
# State is very forgiving:
# Anything possible in a machine's state may be changed & fetched.
# For example: x, y, z, a, b, c may all be set & requested.
# However, the machine for which this state is stored probably doesn't
# have all possible 6 axes.
# It is also possible to set an axis to an impossibly large distance.
# It is the responsibility of the Machine using this class to be
# discerning in these respects.
def __init__(self):
self.axes = defaultdict(lambda: 0.0) # aka: "machine coordinates"
self.work_offset = defaultdict(lambda: 0.0)
# TODO: how to manage work offsets? (probs not like the above)
# read up on:
# - G92: coordinate system offset
# - G54-G59: select coordinate system (offsets from machine coordinates set by G10 L2)
# TODO: Move this class into MachineState
class MachineState(object):
"""Machine's state, and mode"""
# Mode is defined by gcodes set by processed blocks:
# see modal_group in gcode.py module for details
def __init__(self):
self.modal_groups = defaultdict(lambda: None)
# populate with all groups
for modal_group in MODAL_GROUP_MAP.values():
self.modal_groups[modal_group] = None
# Default mode:
self.set_mode(*Line('''
G17 (plane_selection: X/Y plane)
G90 (distance: absolute position. ie: not "turtle" mode)
G91.1 (arc_ijk_distance: IJK sets arc center vertex relative to current position)
G94 (feed_rate_mode: feed-rate defined in units/min)
G21 (units: mm)
G40 (cutter_diameter_comp: no compensation)
G49 (tool_length_offset: no offset)
G61 (control_mode: exact path mode)
G97 (spindle_speed_mode: RPM Mode)
M0 (stopping: program paused)
M5 (spindle: off)
M9 (coolant: off)
F100 (feed_rate: 100 mm/min)
S1000 (tool: 1000 rpm, when it's switched on)
''').block.gcodes) # note: although this is not a single line
# '\n' is just treated like any other whitespace,
# so it behaves like a single line.
def set_mode(self, *gcode_list):
for g in sorted(gcode_list): # sorted by execution order
if g.modal_group is not None:
self.modal_groups[g.modal_group] = g
def __getattr__(self, key):
if key in MODAL_GROUP_MAP:
return self.modal_groups[MODAL_GROUP_MAP[key]]
raise AttributeError("'{cls}' object has no attribute '{key}'".format(
cls=self.__class__.__name__,
key=key
))
def __setattr__(self, key, value):
if key in MODAL_GROUP_MAP:
# Set/Clear modal group gcode
if value is None:
# clear mode group
self.modal_groups[MODAL_GROUP_MAP[key]] = None
else:
# set mode group explicitly
# (recommended to use self.set_mode(value) instead)
assert isinstance(value, GCode), "invalid value type: %r" % value
assert value.modal_group == MODAL_GROUP_MAP[key], \
"cannot set '%s' mode as %r, wrong group" % (key, value)
self.modal_groups[MODAL_GROUP_MAP[key]] = value
else:
self.__dict__[key] = value
def __str__(self):
gcode_list = []
for modal_group in sorted(MODAL_GROUP_MAP.values()):
if self.modal_groups[modal_group]:
gcode_list.append(self.modal_groups[modal_group])
return ' '.join(str(g) for g in gcode_list)
def __repr__(self):
return "<{class_name}: {gcodes}>".format(
class_name=self.__class__.__name__, gcodes=str(self)
)