gcode: Support parsing of "extended" gcode commands

Support human readable commands (eg, "help").  Add a "help" command to
list these extended commands.

Also, add support for declaring command aliases, command help, and
command availability next to the handlers themselves.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2016-11-30 22:34:38 -05:00
parent 35719e665c
commit a6055ce069
3 changed files with 39 additions and 30 deletions

View File

@ -28,11 +28,6 @@ Host user interaction
* Improve gcode interface:
* Support ASCII based commands in addition to common gcode
commands. It would be useful to support high-level commands such as
"query_endstops", "pid_autotune", and "help" instead of having to
invent cryptic gcode commands (eg, "M119" and "M303").
* Provide a better way to handle print nozzle z offsets. The M206
command is cryptic to use and it is too easy to set the value
incorrectly or to forget to set it.

View File

@ -45,20 +45,23 @@ class GCodeParser:
self.heater_bed = self.printer.objects.get('heater_bed')
self.fan = self.printer.objects.get('fan')
def build_handlers(self):
shutdown_handlers = ['M105', 'M110', 'M114']
handlers = ['G0', 'G1', 'G4', 'G20', 'G21', 'G28', 'G90', 'G91', 'G92',
'M18', 'M82', 'M83', 'M84',
'M105', 'M110', 'M114', 'M119', 'M206']
handlers = ['G1', 'G4', 'G20', 'G21', 'G28', 'G90', 'G91', 'G92',
'M18', 'M82', 'M83', 'M105', 'M110', 'M114', 'M206',
'HELP', 'QUERY_ENDSTOPS']
if self.heater_nozzle is not None:
handlers.extend(['M104', 'M109', 'M303'])
handlers.extend(['M104', 'M109', 'PID_TUNE'])
if self.heater_bed is not None:
handlers.extend(['M140', 'M190'])
if self.fan is not None:
handlers.extend(['M106', 'M107'])
if not self.is_printer_ready:
handlers = [h for h in handlers if h in shutdown_handlers]
handlers = [h for h in handlers
if getattr(self, 'cmd_'+h+'_when_not_ready', False)]
self.gcode_handlers = dict((h, getattr(self, 'cmd_'+h))
for h in handlers)
for h, f in self.gcode_handlers.items():
aliases = getattr(self, 'cmd_'+h+'_aliases', [])
self.gcode_handlers.update(dict([(a, f) for a in aliases]))
def finish(self):
self.reactor.end()
self.toolhead.motor_off()
@ -85,7 +88,7 @@ class GCodeParser:
for eventtime, data in self.input_log:
logging.info("Read %f: %s" % (eventtime, repr(data)))
# Parse input into commands
args_r = re.compile('([a-zA-Z*])')
args_r = re.compile('([a-zA-Z_]+|[a-zA-Z*])')
def process_commands(self, eventtime):
i = -1
for i in range(len(self.input_commands)-1):
@ -106,7 +109,7 @@ class GCodeParser:
if not parts:
self.cmd_default(params)
continue
params['#command'] = cmd = parts[0] + parts[1].strip()
params['#command'] = cmd = parts[0].upper() + parts[1].strip()
# Invoke handler for command
self.need_ack = True
handler = self.gcode_handlers.get(cmd, self.cmd_default)
@ -226,9 +229,8 @@ class GCodeParser:
logging.debug(params['#original'])
return
self.respond('echo:Unknown command:"%s"' % (cmd,))
def cmd_G0(self, params):
self.cmd_G1(params, sloppy=True)
def cmd_G1(self, params, sloppy=False):
cmd_G1_aliases = ['G0']
def cmd_G1(self, params):
# Move
for a, p in self.axis2pos.items():
if a in params:
@ -242,7 +244,7 @@ class GCodeParser:
if 'F' in params:
self.speed = float(params['F']) / 60.
try:
self.toolhead.move(self.last_position, self.speed, sloppy)
self.toolhead.move(self.last_position, self.speed)
except homing.EndstopError, e:
self.respond_error(str(e))
self.last_position = self.toolhead.get_position()
@ -299,12 +301,11 @@ class GCodeParser:
def cmd_M83(self, params):
# Use relative distances for extrusion
self.absoluteextrude = False
cmd_M18_aliases = ["M84"]
def cmd_M18(self, params):
# Turn off motors
self.toolhead.motor_off()
def cmd_M84(self, params):
# Stop idle hold
self.toolhead.motor_off()
cmd_M105_when_not_ready = True
def cmd_M105(self, params):
# Get Extruder Temperature
self.ack(self.get_temp())
@ -314,9 +315,11 @@ class GCodeParser:
def cmd_M109(self, params):
# Set Extruder Temperature and Wait
self.set_temp(self.heater_nozzle, params, wait=True)
cmd_M110_when_not_ready = True
def cmd_M110(self, params):
# Set Current Line Number
pass
cmd_M114_when_not_ready = True
def cmd_M114(self, params):
# Get Current Position
if self.toolhead is None:
@ -327,14 +330,6 @@ class GCodeParser:
self.last_position[0], self.last_position[1],
self.last_position[2], self.last_position[3],
kinpos[0], kinpos[1], kinpos[2]))
def cmd_M119(self, params):
# Get Endstop Status
if self.is_fileinput:
return
print_time = self.toolhead.get_last_move_time()
query_state = homing.QueryEndstops(print_time, self.respond)
self.toolhead.query_endstops(query_state)
self.set_busy(query_state)
def cmd_M140(self, params):
# Set Bed Temperature
self.set_temp(self.heater_bed, params)
@ -356,10 +351,29 @@ class GCodeParser:
v = float(params[a])
self.base_position[p] += self.homing_add[p] - v
self.homing_add[p] = v
def cmd_M303(self, params):
cmd_QUERY_ENDSTOPS_help = "Report on the status of each endstop"
cmd_QUERY_ENDSTOPS_aliases = ["M119"]
def cmd_QUERY_ENDSTOPS(self, params):
# Get Endstop Status
if self.is_fileinput:
return
print_time = self.toolhead.get_last_move_time()
query_state = homing.QueryEndstops(print_time, self.respond)
self.toolhead.query_endstops(query_state)
self.set_busy(query_state)
cmd_PID_TUNE_help = "Run PID Tuning"
cmd_PID_TUNE_aliases = ["M303"]
def cmd_PID_TUNE(self, params):
# Run PID tuning
heater = int(params.get('E', '0'))
heater = {0: self.heater_nozzle, -1: self.heater_bed}[heater]
temp = float(params.get('S', '60'))
heater.start_auto_tune(temp)
self.bg_temp(heater)
def cmd_HELP(self, params):
cmdhelp = ["// Available extended commands:"]
for cmd in self.gcode_handlers:
desc = getattr(self, 'cmd_'+cmd+'_help', None)
if desc is not None:
cmdhelp.append("%-10s: %s" % (cmd, desc))
self.respond("\n// ".join(cmdhelp))

View File

@ -248,7 +248,7 @@ class ToolHead:
self.move_queue.flush()
self.commanded_pos[:] = newpos
self.kin.set_position(newpos)
def move(self, newpos, speed, sloppy=False):
def move(self, newpos, speed):
speed = min(speed, self.max_speed)
move = Move(self, self.commanded_pos, newpos, speed, self.max_accel)
if not move.move_d: