endstop_phase: Add support for reporting phase information via get_status()

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2021-04-28 20:49:37 -04:00
parent 703418de01
commit 93b9a85d19
2 changed files with 46 additions and 14 deletions

View File

@ -36,6 +36,20 @@ The following information is available in the `display_status` object
`virtual_sdcard.progress` if no recent `M73` received). `virtual_sdcard.progress` if no recent `M73` received).
- `message`: The message contained in the last `M117` G-Code command. - `message`: The message contained in the last `M117` G-Code command.
# endstop_phase
The following information is available in the
[endstop_phase](Config_Reference.md#endstop_phase) object:
- `last_home.<stepper name>.phase`: The phase of the stepper motor at
the end of the last home attempt.
- `last_home.<stepper name>.phases`: The total number of phases
available on the stepper motor.
- `last_home.<stepper name>.mcu_position`: The position (as tracked by
the micro-controller) of the stepper motor at the end of the last
home attempt. The position is the total number of steps taken in a
forward direction minus the total number of steps taken in the
reverse direction since the micro-controller was last restarted.
# fan # fan
The following information is available in The following information is available in

View File

@ -117,6 +117,7 @@ class EndstopPhases:
def __init__(self, config): def __init__(self, config):
self.printer = config.get_printer() self.printer = config.get_printer()
self.tracking = {} self.tracking = {}
self.last_home_info = {}
# Register handlers # Register handlers
self.printer.register_event_handler("homing:home_rails_end", self.printer.register_event_handler("homing:home_rails_end",
self.handle_home_rails_end) self.handle_home_rails_end)
@ -124,21 +125,30 @@ class EndstopPhases:
self.gcode.register_command("ENDSTOP_PHASE_CALIBRATE", self.gcode.register_command("ENDSTOP_PHASE_CALIBRATE",
self.cmd_ENDSTOP_PHASE_CALIBRATE, self.cmd_ENDSTOP_PHASE_CALIBRATE,
desc=self.cmd_ENDSTOP_PHASE_CALIBRATE_help) desc=self.cmd_ENDSTOP_PHASE_CALIBRATE_help)
def lookup_rail(self, stepper, stepper_name): def lookup_stepper(self, stepper, stepper_name):
mod_name = "endstop_phase %s" % (stepper_name,) mod_name = "endstop_phase %s" % (stepper_name,)
m = self.printer.lookup_object(mod_name, None) m = self.printer.lookup_object(mod_name, None)
if m is not None: if m is not None:
return (None, m.phase_history) return {"get_phase": None, "is_rail": False,
"phase_history": m.phase_history}
for driver in TRINAMIC_DRIVERS: for driver in TRINAMIC_DRIVERS:
mod_name = "%s %s" % (driver, stepper_name) mod_name = "%s %s" % (driver, stepper_name)
m = self.printer.lookup_object(mod_name, None) m = self.printer.lookup_object(mod_name, None)
if m is not None: if m is not None:
return (m.get_phase, [0] * (m.get_microsteps() * 4)) return {"get_phase": m.get_phase, "is_rail": False,
"phase_history": [0] * (m.get_microsteps() * 4)}
return None return None
def update_rail(self, info, stepper): def update_stepper(self, stepper, is_rail):
stepper_name = stepper.get_name()
if stepper_name not in self.tracking:
info = self.lookup_stepper(stepper, stepper_name)
self.tracking[stepper_name] = info
info = self.tracking[stepper_name]
if info is None: if info is None:
return return
get_phase, phase_history = info if is_rail:
info["is_rail"] = True
get_phase = info["get_phase"]
if get_phase is None: if get_phase is None:
return return
try: try:
@ -146,16 +156,19 @@ class EndstopPhases:
except: except:
logging.exception("Error in EndstopPhases get_phase") logging.exception("Error in EndstopPhases get_phase")
return return
phase_history = info["phase_history"]
phase = convert_phase(driver_phase, driver_phases, len(phase_history)) phase = convert_phase(driver_phase, driver_phases, len(phase_history))
phase_history[phase] += 1 phase_history[phase] += 1
self.last_home_info[stepper.get_name()] = {
'phase': phase, 'phases': len(phase_history),
'mcu_position': stepper.get_mcu_position()
}
def handle_home_rails_end(self, homing_state, rails): def handle_home_rails_end(self, homing_state, rails):
for rail in rails: for rail in rails:
stepper = rail.get_steppers()[0] is_rail = True
stepper_name = stepper.get_name() for stepper in rail.get_steppers():
if stepper_name not in self.tracking: self.update_stepper(stepper, is_rail)
info = self.lookup_rail(stepper, stepper_name) is_rail = False
self.tracking[stepper_name] = info
self.update_rail(self.tracking[stepper_name], stepper)
cmd_ENDSTOP_PHASE_CALIBRATE_help = "Calibrate stepper phase" cmd_ENDSTOP_PHASE_CALIBRATE_help = "Calibrate stepper phase"
def cmd_ENDSTOP_PHASE_CALIBRATE(self, gcmd): def cmd_ENDSTOP_PHASE_CALIBRATE(self, gcmd):
stepper_name = gcmd.get('STEPPER', None) stepper_name = gcmd.get('STEPPER', None)
@ -167,6 +180,8 @@ class EndstopPhases:
raise gcmd.error("Stats not available for stepper %s" raise gcmd.error("Stats not available for stepper %s"
% (stepper_name,)) % (stepper_name,))
endstop_phase, phases = self.generate_stats(stepper_name, info) endstop_phase, phases = self.generate_stats(stepper_name, info)
if not info["is_rail"]:
return
configfile = self.printer.lookup_object('configfile') configfile = self.printer.lookup_object('configfile')
section = 'endstop_phase %s' % (stepper_name,) section = 'endstop_phase %s' % (stepper_name,)
configfile.remove_section(section) configfile.remove_section(section)
@ -176,7 +191,7 @@ class EndstopPhases:
"The SAVE_CONFIG command will update the printer config\n" "The SAVE_CONFIG command will update the printer config\n"
"file with these parameters and restart the printer.") "file with these parameters and restart the printer.")
def generate_stats(self, stepper_name, info): def generate_stats(self, stepper_name, info):
get_phase, phase_history = info phase_history = info["phase_history"]
wph = phase_history + phase_history wph = phase_history + phase_history
count = sum(phase_history) count = sum(phase_history)
phases = len(phase_history) phases = len(phase_history)
@ -200,10 +215,13 @@ class EndstopPhases:
self.gcode.respond_info( self.gcode.respond_info(
"No steppers found. (Be sure to home at least once.)") "No steppers found. (Be sure to home at least once.)")
return return
for stepper_name, info in sorted(self.tracking.items()): for stepper_name in sorted(self.tracking.keys()):
if info is None: info = self.tracking[stepper_name]
if info is None or not info["is_rail"]:
continue continue
self.generate_stats(stepper_name, info) self.generate_stats(stepper_name, info)
def get_status(self, eventtime):
return { 'last_home': dict(self.last_home_info) }
def load_config_prefix(config): def load_config_prefix(config):
return EndstopPhase(config) return EndstopPhase(config)