aboutsummaryrefslogtreecommitdiffstats
path: root/klippy/extras/manual_probe.py
diff options
context:
space:
mode:
Diffstat (limited to 'klippy/extras/manual_probe.py')
-rw-r--r--klippy/extras/manual_probe.py228
1 files changed, 135 insertions, 93 deletions
diff --git a/klippy/extras/manual_probe.py b/klippy/extras/manual_probe.py
index 92f2d0f6..176a97e5 100644
--- a/klippy/extras/manual_probe.py
+++ b/klippy/extras/manual_probe.py
@@ -5,75 +5,89 @@
# This file may be distributed under the terms of the GNU GPLv3 license.
import logging, bisect
+
# Helper to lookup the Z stepper config section
def lookup_z_endstop_config(config):
- if config.has_section('stepper_z'):
- return config.getsection('stepper_z')
- elif config.has_section('carriage z'):
- return config.getsection('carriage z')
+ if config.has_section("stepper_z"):
+ return config.getsection("stepper_z")
+ elif config.has_section("carriage z"):
+ return config.getsection("carriage z")
return None
+
class ManualProbe:
def __init__(self, config):
self.printer = config.get_printer()
# Register commands
- self.gcode = self.printer.lookup_object('gcode')
+ self.gcode = self.printer.lookup_object("gcode")
self.gcode_move = self.printer.load_object(config, "gcode_move")
- self.gcode.register_command('MANUAL_PROBE', self.cmd_MANUAL_PROBE,
- desc=self.cmd_MANUAL_PROBE_help)
+ self.gcode.register_command(
+ "MANUAL_PROBE", self.cmd_MANUAL_PROBE, desc=self.cmd_MANUAL_PROBE_help
+ )
# Endstop value for cartesian printers with separate Z axis
zconfig = lookup_z_endstop_config(config)
if zconfig is not None:
- self.z_position_endstop = zconfig.getfloat('position_endstop', None,
- note_valid=False)
+ self.z_position_endstop = zconfig.getfloat(
+ "position_endstop", None, note_valid=False
+ )
self.z_endstop_config_name = zconfig.get_name()
else:
self.z_position_endstop = self.z_endstop_config_name = None
# Endstop values for linear delta printers with vertical A,B,C towers
- a_tower_config = config.getsection('stepper_a')
- self.a_position_endstop = a_tower_config.getfloat('position_endstop',
- None,
- note_valid=False)
- b_tower_config = config.getsection('stepper_b')
- self.b_position_endstop = b_tower_config.getfloat('position_endstop',
- None,
- note_valid=False)
- c_tower_config = config.getsection('stepper_c')
- self.c_position_endstop = c_tower_config.getfloat('position_endstop',
- None,
- note_valid=False)
+ a_tower_config = config.getsection("stepper_a")
+ self.a_position_endstop = a_tower_config.getfloat(
+ "position_endstop", None, note_valid=False
+ )
+ b_tower_config = config.getsection("stepper_b")
+ self.b_position_endstop = b_tower_config.getfloat(
+ "position_endstop", None, note_valid=False
+ )
+ c_tower_config = config.getsection("stepper_c")
+ self.c_position_endstop = c_tower_config.getfloat(
+ "position_endstop", None, note_valid=False
+ )
# Conditionally register appropriate commands depending on printer
# Cartestian printers with separate Z Axis
if self.z_position_endstop is not None:
self.gcode.register_command(
- 'Z_ENDSTOP_CALIBRATE', self.cmd_Z_ENDSTOP_CALIBRATE,
- desc=self.cmd_Z_ENDSTOP_CALIBRATE_help)
+ "Z_ENDSTOP_CALIBRATE",
+ self.cmd_Z_ENDSTOP_CALIBRATE,
+ desc=self.cmd_Z_ENDSTOP_CALIBRATE_help,
+ )
self.gcode.register_command(
- 'Z_OFFSET_APPLY_ENDSTOP',
+ "Z_OFFSET_APPLY_ENDSTOP",
self.cmd_Z_OFFSET_APPLY_ENDSTOP,
- desc=self.cmd_Z_OFFSET_APPLY_ENDSTOP_help)
+ desc=self.cmd_Z_OFFSET_APPLY_ENDSTOP_help,
+ )
# Linear delta printers with A,B,C towers
- if 'delta' == config.getsection('printer').get('kinematics'):
+ if "delta" == config.getsection("printer").get("kinematics"):
self.gcode.register_command(
- 'Z_OFFSET_APPLY_ENDSTOP',
+ "Z_OFFSET_APPLY_ENDSTOP",
self.cmd_Z_OFFSET_APPLY_DELTA_ENDSTOPS,
- desc=self.cmd_Z_OFFSET_APPLY_ENDSTOP_help)
+ desc=self.cmd_Z_OFFSET_APPLY_ENDSTOP_help,
+ )
self.reset_status()
+
def manual_probe_finalize(self, kin_pos):
if kin_pos is not None:
self.gcode.respond_info("Z position is %.3f" % (kin_pos[2],))
+
def reset_status(self):
self.status = {
- 'is_active': False,
- 'z_position': None,
- 'z_position_lower': None,
- 'z_position_upper': None
+ "is_active": False,
+ "z_position": None,
+ "z_position_lower": None,
+ "z_position_upper": None,
}
+
def get_status(self, eventtime):
return self.status
+
cmd_MANUAL_PROBE_help = "Start manual probe helper script"
+
def cmd_MANUAL_PROBE(self, gcmd):
ManualProbeHelper(self.printer, gcmd, self.manual_probe_finalize)
+
def z_endstop_finalize(self, kin_pos):
if kin_pos is None:
return
@@ -81,17 +95,25 @@ class ManualProbe:
self.gcode.respond_info(
"%s: position_endstop: %.3f\n"
"The SAVE_CONFIG command will update the printer config file\n"
- "with the above and restart the printer." % (
- self.z_endstop_config_name, z_pos,))
- configfile = self.printer.lookup_object('configfile')
- configfile.set(self.z_endstop_config_name, 'position_endstop',
- "%.3f" % (z_pos,))
+ "with the above and restart the printer."
+ % (
+ self.z_endstop_config_name,
+ z_pos,
+ )
+ )
+ configfile = self.printer.lookup_object("configfile")
+ configfile.set(
+ self.z_endstop_config_name, "position_endstop", "%.3f" % (z_pos,)
+ )
+
cmd_Z_ENDSTOP_CALIBRATE_help = "Calibrate a Z endstop"
+
def cmd_Z_ENDSTOP_CALIBRATE(self, gcmd):
ManualProbeHelper(self.printer, gcmd, self.z_endstop_finalize)
- def cmd_Z_OFFSET_APPLY_ENDSTOP(self,gcmd):
- offset = self.gcode_move.get_status()['homing_origin'].z
- configfile = self.printer.lookup_object('configfile')
+
+ def cmd_Z_OFFSET_APPLY_ENDSTOP(self, gcmd):
+ offset = self.gcode_move.get_status()["homing_origin"].z
+ configfile = self.printer.lookup_object("configfile")
if offset == 0:
self.gcode.respond_info("Nothing to do: Z Offset is 0")
else:
@@ -99,13 +121,18 @@ class ManualProbe:
self.gcode.respond_info(
"%s: position_endstop: %.3f\n"
"The SAVE_CONFIG command will update the printer config file\n"
- "with the above and restart the printer." % (
- self.z_endstop_config_name, new_calibrate))
- configfile.set(self.z_endstop_config_name, 'position_endstop',
- "%.3f" % (new_calibrate,))
- def cmd_Z_OFFSET_APPLY_DELTA_ENDSTOPS(self,gcmd):
- offset = self.gcode_move.get_status()['homing_origin'].z
- configfile = self.printer.lookup_object('configfile')
+ "with the above and restart the printer."
+ % (self.z_endstop_config_name, new_calibrate)
+ )
+ configfile.set(
+ self.z_endstop_config_name,
+ "position_endstop",
+ "%.3f" % (new_calibrate,),
+ )
+
+ def cmd_Z_OFFSET_APPLY_DELTA_ENDSTOPS(self, gcmd):
+ offset = self.gcode_move.get_status()["homing_origin"].z
+ configfile = self.printer.lookup_object("configfile")
if offset == 0:
self.gcode.respond_info("Nothing to do: Z Offset is 0")
else:
@@ -117,67 +144,70 @@ class ManualProbe:
"stepper_b: position_endstop: %.3f\n"
"stepper_c: position_endstop: %.3f\n"
"The SAVE_CONFIG command will update the printer config file\n"
- "with the above and restart the printer." % (new_a_calibrate,
- new_b_calibrate,
- new_c_calibrate))
- configfile.set('stepper_a', 'position_endstop',
- "%.3f" % (new_a_calibrate,))
- configfile.set('stepper_b', 'position_endstop',
- "%.3f" % (new_b_calibrate,))
- configfile.set('stepper_c', 'position_endstop',
- "%.3f" % (new_c_calibrate,))
+ "with the above and restart the printer."
+ % (new_a_calibrate, new_b_calibrate, new_c_calibrate)
+ )
+ configfile.set("stepper_a", "position_endstop", "%.3f" % (new_a_calibrate,))
+ configfile.set("stepper_b", "position_endstop", "%.3f" % (new_b_calibrate,))
+ configfile.set("stepper_c", "position_endstop", "%.3f" % (new_c_calibrate,))
+
cmd_Z_OFFSET_APPLY_ENDSTOP_help = "Adjust the z endstop_position"
+
# Verify that a manual probe isn't already in progress
def verify_no_manual_probe(printer):
- gcode = printer.lookup_object('gcode')
+ gcode = printer.lookup_object("gcode")
try:
- gcode.register_command('ACCEPT', 'dummy')
+ gcode.register_command("ACCEPT", "dummy")
except printer.config_error as e:
- raise gcode.error(
- "Already in a manual Z probe. Use ABORT to abort it.")
- gcode.register_command('ACCEPT', None)
+ raise gcode.error("Already in a manual Z probe. Use ABORT to abort it.")
+ gcode.register_command("ACCEPT", None)
+
Z_BOB_MINIMUM = 0.500
BISECT_MAX = 0.200
+
# Helper script to determine a Z height
class ManualProbeHelper:
def __init__(self, printer, gcmd, finalize_callback):
self.printer = printer
self.finalize_callback = finalize_callback
- self.gcode = self.printer.lookup_object('gcode')
- self.toolhead = self.printer.lookup_object('toolhead')
- self.manual_probe = self.printer.lookup_object('manual_probe')
- self.speed = gcmd.get_float("SPEED", 5.)
+ self.gcode = self.printer.lookup_object("gcode")
+ self.toolhead = self.printer.lookup_object("toolhead")
+ self.manual_probe = self.printer.lookup_object("manual_probe")
+ self.speed = gcmd.get_float("SPEED", 5.0)
self.past_positions = []
self.last_toolhead_pos = self.last_kinematics_pos = None
# Register commands
verify_no_manual_probe(printer)
- self.gcode.register_command('ACCEPT', self.cmd_ACCEPT,
- desc=self.cmd_ACCEPT_help)
- self.gcode.register_command('NEXT', self.cmd_ACCEPT)
- self.gcode.register_command('ABORT', self.cmd_ABORT,
- desc=self.cmd_ABORT_help)
- self.gcode.register_command('TESTZ', self.cmd_TESTZ,
- desc=self.cmd_TESTZ_help)
+ self.gcode.register_command(
+ "ACCEPT", self.cmd_ACCEPT, desc=self.cmd_ACCEPT_help
+ )
+ self.gcode.register_command("NEXT", self.cmd_ACCEPT)
+ self.gcode.register_command("ABORT", self.cmd_ABORT, desc=self.cmd_ABORT_help)
+ self.gcode.register_command("TESTZ", self.cmd_TESTZ, desc=self.cmd_TESTZ_help)
self.gcode.respond_info(
"Starting manual Z probe. Use TESTZ to adjust position.\n"
- "Finish with ACCEPT or ABORT command.")
+ "Finish with ACCEPT or ABORT command."
+ )
self.start_position = self.toolhead.get_position()
self.report_z_status()
+
def get_kinematics_pos(self):
toolhead_pos = self.toolhead.get_position()
if toolhead_pos == self.last_toolhead_pos:
return self.last_kinematics_pos
self.toolhead.flush_step_generation()
kin = self.toolhead.get_kinematics()
- kin_spos = {s.get_name(): s.get_commanded_position()
- for s in kin.get_steppers()}
+ kin_spos = {
+ s.get_name(): s.get_commanded_position() for s in kin.get_steppers()
+ }
kin_pos = kin.calc_position(kin_spos)
self.last_toolhead_pos = toolhead_pos
self.last_kinematics_pos = kin_pos
return kin_pos
+
def move_z(self, z_pos):
curpos = self.toolhead.get_position()
try:
@@ -188,13 +218,15 @@ class ManualProbeHelper:
except self.printer.command_error as e:
self.finalize(False)
raise
+
def report_z_status(self, warn_no_change=False, prev_pos=None):
# Get position
kin_pos = self.get_kinematics_pos()
z_pos = kin_pos[2]
if warn_no_change and z_pos == prev_pos:
self.gcode.respond_info(
- "WARNING: No change in position (reached stepper resolution)")
+ "WARNING: No change in position (reached stepper resolution)"
+ )
# Find recent positions that were tested
pp = self.past_positions
next_pos = bisect.bisect_left(pp, z_pos)
@@ -210,29 +242,37 @@ class ManualProbeHelper:
next_pos_val = pp[next_pos]
next_str = "%.3f" % (next_pos_val,)
self.manual_probe.status = {
- 'is_active': True,
- 'z_position': z_pos,
- 'z_position_lower': prev_pos_val,
- 'z_position_upper': next_pos_val,
+ "is_active": True,
+ "z_position": z_pos,
+ "z_position_lower": prev_pos_val,
+ "z_position_upper": next_pos_val,
}
# Find recent positions
- self.gcode.respond_info("Z position: %s --> %.3f <-- %s"
- % (prev_str, z_pos, next_str))
+ self.gcode.respond_info(
+ "Z position: %s --> %.3f <-- %s" % (prev_str, z_pos, next_str)
+ )
+
cmd_ACCEPT_help = "Accept the current Z position"
+
def cmd_ACCEPT(self, gcmd):
pos = self.toolhead.get_position()
start_pos = self.start_position
if pos[:2] != start_pos[:2] or pos[2] >= start_pos[2]:
gcmd.respond_info(
"Manual probe failed! Use TESTZ commands to position the\n"
- "nozzle prior to running ACCEPT.")
+ "nozzle prior to running ACCEPT."
+ )
self.finalize(False)
return
self.finalize(True)
+
cmd_ABORT_help = "Abort manual Z probing tool"
+
def cmd_ABORT(self, gcmd):
self.finalize(False)
+
cmd_TESTZ_help = "Move to new Z height"
+
def cmd_TESTZ(self, gcmd):
# Store current position for later reference
kin_pos = self.get_kinematics_pos()
@@ -243,35 +283,37 @@ class ManualProbeHelper:
pp.insert(insert_pos, z_pos)
# Determine next position to move to
req = gcmd.get("Z")
- if req in ('+', '++'):
+ if req in ("+", "++"):
check_z = 9999999999999.9
if insert_pos < len(self.past_positions) - 1:
check_z = self.past_positions[insert_pos + 1]
- if req == '+':
- check_z = (check_z + z_pos) / 2.
+ if req == "+":
+ check_z = (check_z + z_pos) / 2.0
next_z_pos = min(check_z, z_pos + BISECT_MAX)
- elif req in ('-', '--'):
+ elif req in ("-", "--"):
check_z = -9999999999999.9
if insert_pos > 0:
check_z = self.past_positions[insert_pos - 1]
- if req == '-':
- check_z = (check_z + z_pos) / 2.
+ if req == "-":
+ check_z = (check_z + z_pos) / 2.0
next_z_pos = max(check_z, z_pos - BISECT_MAX)
else:
next_z_pos = z_pos + gcmd.get_float("Z")
# Move to given position and report it
self.move_z(next_z_pos)
self.report_z_status(next_z_pos != z_pos, z_pos)
+
def finalize(self, success):
self.manual_probe.reset_status()
- self.gcode.register_command('ACCEPT', None)
- self.gcode.register_command('NEXT', None)
- self.gcode.register_command('ABORT', None)
- self.gcode.register_command('TESTZ', None)
+ self.gcode.register_command("ACCEPT", None)
+ self.gcode.register_command("NEXT", None)
+ self.gcode.register_command("ABORT", None)
+ self.gcode.register_command("TESTZ", None)
kin_pos = None
if success:
kin_pos = self.get_kinematics_pos()
self.finalize_callback(kin_pos)
+
def load_config(config):
return ManualProbe(config)