diff --git a/README.md b/README.md index 8f4775a363..1a9c118236 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,8 @@ See the [Kalico Additions document](https://docs.kalico.gg/Kalico_Additions.html - [probe: z_calibration](https://github.com/KalicoCrew/kalico/pull/31) ([klipper#4614](https://github.com/Klipper3d/klipper/pull/4614) / [protoloft/z_calibration](https://github.com/protoloft/klipper_z_calibration)) +- [probe: multiple probes](https://github.com/KalicoCrew/kalico/pull/972) + - [z_tilt: z-tilt calibration](https://github.com/KalicoCrew/kalico/pull/105) ([klipper3d#4083](https://github.com/Klipper3d/klipper/pull/4083) / [dk/ztilt_calibration](https://github.com/KalicoCrew/kalico/pull/54)) - [stepper: home_current](https://github.com/KalicoCrew/kalico/pull/65) diff --git a/docs/Config_Reference.md b/docs/Config_Reference.md index f5a1dc1f2f..0571ba9f01 100644 --- a/docs/Config_Reference.md +++ b/docs/Config_Reference.md @@ -2484,12 +2484,13 @@ pins: Z height probe. One may define this section to enable Z height probing hardware. When this section is enabled, PROBE and QUERY_PROBE extended [g-code commands](G-Codes.md#probe) become available. Also, see the -[probe calibrate guide](Probe_Calibrate.md). The probe section also -creates a virtual "probe:z_virtual_endstop" pin. One may set the -stepper_z endstop_pin to this virtual pin on cartesian style printers -that use the probe in place of a z endstop. If using -"probe:z_virtual_endstop" then do not define a position_endstop in the -stepper_z config section. +[probe calibrate guide](Probe_Calibrate.md). The probe section, and all +other probe types, also create virtual endstops by the name of +`:z_virtual_endstop`. The default probe additionally registers +itself as `probe:z_virtual_endstop`. One may set the stepper_z endstop_pin +to such a virtual pin on cartesian style printers that use the probe in +place of a z endstop. If using "probe:z_virtual_endstop" then do not define +a position_endstop in the stepper_z config section. ``` [probe] @@ -2537,6 +2538,11 @@ z_offset: # not obtained in the given number of retries then an error is # reported. The default is zero which causes an error to be reported # on the first sample that exceeds samples_tolerance. +#register_as_probe: True +# If this probe should be automatically registered as the default one. +# Defaults to true. When using multiple probes, only a single probe is +# allowed to register as the default, and all other probe configuration +# blocks must set this to false. #activate_gcode: # A list of G-Code commands to execute prior to each probe attempt. # See docs/Command_Templates.md for G-Code format. This may be @@ -2584,6 +2590,14 @@ z_offset: # 0 will disable scrubbing. The default is 0. ``` +It is also possible to create named probes. +``` +[probe named_probe] +# All options from [probe] are accepted. +``` +At most one probe may set `register_as_probe: True`. If an unnamed `[probe]` +is present, no other probe may set `register_as_probe: True`. + ### [nozzle_cleanup] Enables the [NOZZLE_CLEANUP](G-Codes.md#nozzle_cleanup) gcode command. This @@ -2600,7 +2614,8 @@ quality detection, such as the [load_cell_probe](#load_cell_probe). # Number of probe locations along the X axis. Can be negative. Default is 10. #pattern_y: 4 # Number of probe locations along the Y axis. Can be negative. Default is 4. -# +#probe: +# Probe to use, if not the default probe. #These config values are inherited from [probe] if not specified: #speed: #lift_speed: @@ -2666,6 +2681,7 @@ control_pin: #samples_result: #samples_tolerance: #samples_tolerance_retries: +#register_as_probe: # See the "probe" section for information on these parameters. ``` @@ -2776,6 +2792,7 @@ detach_position: 0,0,0 #samples_result: #samples_tolerance: #samples_tolerance_retries: +#register_as_probe: #activate_gcode: #deactivate_gcode: # See the "probe" section for information on these parameters. @@ -2829,6 +2846,7 @@ z_offset: #samples_result: #samples_tolerance: #samples_tolerance_retries: +#register_as_probe: #activate_gcode: #deactivate_gcode: #deactivate_on_each_sample: @@ -2872,6 +2890,7 @@ sensor_type: ldc1612 #samples_result: #samples_tolerance: #samples_tolerance_retries: +#register_as_probe: # See the "probe" section for information on these parameters. ``` @@ -6229,6 +6248,7 @@ sensor_type: #samples_result: #samples_tolerance: #samples_tolerance_retries: +#register_as_probe: #activate_gcode: #deactivate_gcode: # See the "[probe]" section for a description of the above parameters. diff --git a/docs/G-Codes.md b/docs/G-Codes.md index 69231b5a50..fcf055ed1c 100644 --- a/docs/G-Codes.md +++ b/docs/G-Codes.md @@ -164,7 +164,7 @@ The following commands are available when the section](Config_Reference.md#axis_twist_compensation) is enabled. #### AXIS_TWIST_COMPENSATION_CALIBRATE -`AXIS_TWIST_COMPENSATION_CALIBRATE [AXIS=] +`AXIS_TWIST_COMPENSATION_CALIBRATE [PROBE=] [AXIS=] [SAMPLE_COUNT=] [=]`: Calibrates axis twist compensation by specifying the target axis or @@ -1561,7 +1561,7 @@ The following commands are available when a see the [probe calibrate guide](Probe_Calibrate.md)). #### PROBE -`PROBE [PROBE_SPEED=] [LIFT_SPEED=] [SAMPLES=] +`PROBE [PROBE=] [PROBE_SPEED=] [LIFT_SPEED=] [SAMPLES=] [SAMPLE_RETRACT_DIST=] [SAMPLES_TOLERANCE=] [SAMPLES_TOLERANCE_RETRIES=] [SAMPLES_RESULT=median|average] [BAD_PROBE_STRATEGY=] [BAD_PROBE_RETRIES=] @@ -1570,6 +1570,8 @@ Move the nozzle downwards until the probe triggers. If any of the optional parameters are provided they override their equivalent setting in the [probe config section](Config_Reference.md#probe). - `HOME`: Set the value `z` to home the z axis from the probe result +- `PROBE`: Name of probe to use for this operation. Leave out to use the + default probe. The following optional parameters control probe quality handling (for probes that support quality detection): ⚠️ - `BAD_PROBE_STRATEGY`: Strategy to use when a bad probe is detected. @@ -1580,19 +1582,22 @@ that support quality detection): ⚠️ - `PATTERN_SPACING`: Spacing (in mm) for the circular retry pattern when using CIRCLE strategy. +#### LIST_PROBES +`LIST_PROBES`: List the registered probes. + #### QUERY_PROBE -`QUERY_PROBE`: Report the current status of the probe ("triggered" or +`QUERY_PROBE [PROBE=]`: Report the current status of the probe ("triggered" or "open"). #### PROBE_ACCURACY -`PROBE_ACCURACY [PROBE_SPEED=] [SAMPLES=] +`PROBE_ACCURACY [PROBE=] [PROBE_SPEED=] [SAMPLES=] [SAMPLE_RETRACT_DIST=]`: Calculate the maximum, minimum, average, median, and standard deviation of multiple probe samples. By default, 10 SAMPLES are taken. Otherwise the optional parameters default to their equivalent setting in the probe config section. #### PROBE_CALIBRATE -`PROBE_CALIBRATE [SPEED=] [=]`: Run a +`PROBE_CALIBRATE [PROBE=] [SPEED=] [=]`: Run a helper script useful for calibrating the probe's z_offset. See the PROBE command for details on the optional probe parameters. See the MANUAL_PROBE command for details on the SPEED parameter and the @@ -1601,7 +1606,7 @@ the PROBE_CALIBRATE command uses the speed variable to move in XY direction as well as Z. #### Z_OFFSET_APPLY_PROBE -`Z_OFFSET_APPLY_PROBE`: Take the current Z Gcode offset (aka, +`Z_OFFSET_APPLY_PROBE [PROBE=]`: Take the current Z Gcode offset (aka, babystepping), and subtract if from the probe's z_offset. This acts to take a frequently used babystepping value, and "make it permanent". Requires a `SAVE_CONFIG` to take effect. @@ -2319,9 +2324,9 @@ automatically upon homing. The following commands are available when a [z_calibration config section](Config_Reference.md#z_calibration) is enabled (also see the [Z-Calibration guide](Z_Calibration.md)): -- `CALIBRATE_Z`: This calibrates the current offset between the nozzle and +- `CALIBRATE_Z [PROBE=]`: This calibrates the current offset between the nozzle and the print surface. -- `PROBE_Z_ACCURACY [PROBE_SPEED=] [LIFT_SPEED=] [SAMPLES=] +- `PROBE_Z_ACCURACY [PROBE=] [PROBE_SPEED=] [LIFT_SPEED=] [SAMPLES=] [SAMPLE_RETRACT_DIST=]`: Calculate the maximum, minimum, average, median, and standard deviation of multiple probe samples. By default, 10 SAMPLES are taken. Otherwise the optional diff --git a/docs/Kalico_Additions.md b/docs/Kalico_Additions.md index 7967dcae7f..770bb48abd 100644 --- a/docs/Kalico_Additions.md +++ b/docs/Kalico_Additions.md @@ -38,6 +38,7 @@ ## Probes and Probing - [`[probe] drop_first_result: True`](./Config_Reference.md#probe) will drop the first result when probing. This can improve probe accuracy for printers that have an outlier for the first sample. +- [`[probe ]`](./Config_Reference.md#probe) adds named probes, so a printer can have more than one. Pick one with `PROBE=` on probing commands and list them with [`LIST_PROBES`](./G-Codes.md#list_probes). - [`[dockable_probe]`](./Config_Reference.md#dockable_probe) brings helpful native support for docked probes, such as the Annex Quickdraw, Klicky/Unklicky, and countless others. - [`[z_calibration]`](./Config_Reference.md#z_calibration) enables automatic probe Z offset calibration using a reference endstop like the Voron 2.4 nozzle endstop. - [`[z_tilt_ng]`](./Config_Reference.md#z_tilt_ng) adds enforced 3-point z tilt calibration diff --git a/klippy/extras/axis_twist_compensation.py b/klippy/extras/axis_twist_compensation.py index 54139cf93e..0f76ce2d2a 100644 --- a/klippy/extras/axis_twist_compensation.py +++ b/klippy/extras/axis_twist_compensation.py @@ -6,6 +6,8 @@ import math +from klippy.extras.probe import ProbeList + from . import bed_mesh, manual_probe DEFAULT_SAMPLE_COUNT = 3 @@ -140,9 +142,6 @@ def __init__(self, compensation, config): None, None, ) - self.printer.register_event_handler( - "klippy:connect", self._handle_connect - ) self.speed = compensation.speed self.horizontal_move_z = compensation.horizontal_move_z self.x_start_point = ( @@ -169,15 +168,6 @@ def __init__(self, compensation, config): # register gcode handlers self._register_gcode_handlers() - def _handle_connect(self): - self.probe = self.printer.lookup_object("probe", None) - if self.probe is None: - raise self.printer.config_error( - "AXIS_TWIST_COMPENSATION requires [probe] to be defined" - ) - self.lift_speed = self.probe.get_lift_speed() - self.probe_x_offset, self.probe_y_offset, _ = self.probe.get_offsets() - def _register_gcode_handlers(self): # register gcode handlers self.gcode = self.printer.lookup_object("gcode") @@ -194,6 +184,10 @@ def _register_gcode_handlers(self): """ def cmd_AXIS_TWIST_COMPENSATION_CALIBRATE(self, gcmd): + self.probe = ProbeList.get_list(self.printer).get_command_probe(gcmd) + self.lift_speed = self.probe.get_lift_speed() + self.probe_x_offset, self.probe_y_offset, _ = self.probe.get_offsets() + self.gcmd = gcmd sample_count = gcmd.get_int("SAMPLE_COUNT", DEFAULT_SAMPLE_COUNT) axis = gcmd.get("AXIS", "X") diff --git a/klippy/extras/bed_mesh.py b/klippy/extras/bed_mesh.py index 585b970371..93e24e859a 100644 --- a/klippy/extras/bed_mesh.py +++ b/klippy/extras/bed_mesh.py @@ -622,9 +622,9 @@ def _generate_points(self, error, probe_method="automatic"): def print_generated_points(self, print_func, truncate=False): x_offset = y_offset = 0.0 - probe = self.printer.lookup_object("probe", None) - if probe is not None: - x_offset, y_offset = probe.get_offsets()[:2] + pprobe = probe.ProbeList.get_list(self.printer).get_default_probe() + if pprobe is not None: + x_offset, y_offset = pprobe.get_offsets()[:2] print_func( "bed_mesh: generated points\nIndex | Tool Adjusted | Probe" ) diff --git a/klippy/extras/bltouch.py b/klippy/extras/bltouch.py index 295058df5b..609049f6d0 100644 --- a/klippy/extras/bltouch.py +++ b/klippy/extras/bltouch.py @@ -342,5 +342,5 @@ def load_config(config): global ENDSTOP_SAMPLE_COUNT ENDSTOP_SAMPLE_COUNT = get_danger_options().endstop_sample_count blt = BLTouchEndstopWrapper(config) - config.get_printer().add_object("probe", probe.PrinterProbe(config, blt)) + probe.PrinterProbe(config, blt) return blt diff --git a/klippy/extras/dockable_probe.py b/klippy/extras/dockable_probe.py index 2121e537d0..2b903862b9 100644 --- a/klippy/extras/dockable_probe.py +++ b/klippy/extras/dockable_probe.py @@ -945,5 +945,5 @@ def probing_move(self, pos, speed, gcmd): def load_config(config): msp = DockableProbe(config) - config.get_printer().add_object("probe", probe.PrinterProbe(config, msp)) + probe.PrinterProbe(config, msp) return msp diff --git a/klippy/extras/load_cell/load_cell_probe.py b/klippy/extras/load_cell/load_cell_probe.py index 001636c178..bbbb543537 100644 --- a/klippy/extras/load_cell/load_cell_probe.py +++ b/klippy/extras/load_cell/load_cell_probe.py @@ -1008,8 +1008,7 @@ def __init__( wrapper = LoadCellEndstopWrapper( config, homing_move, self._tapping_move ) - printer_probe = PrinterProbe(config, wrapper) - self._printer.add_object("probe", printer_probe) + PrinterProbe(config, wrapper) def get_status(self, eventtime): return self._tapping_move.get_status(eventtime) diff --git a/klippy/extras/nozzle_cleanup.py b/klippy/extras/nozzle_cleanup.py index 3fb4bba385..a693b2f3bd 100644 --- a/klippy/extras/nozzle_cleanup.py +++ b/klippy/extras/nozzle_cleanup.py @@ -6,7 +6,12 @@ from klippy import Printer from klippy.configfile import ConfigWrapper -from klippy.extras.probe import GcodeNozzleScrubber, PrinterProbe, RetryPolicy +from klippy.extras.probe import ( + GcodeNozzleScrubber, + PrinterProbe, + ProbeList, + RetryPolicy, +) from klippy.gcode import GCodeCommand, GCodeDispatch from klippy.toolhead import ToolHead @@ -21,9 +26,7 @@ class NozzleCleanupOptions: pattern_x: int pattern_y: int - def __init__(self, config: ConfigWrapper): - printer: Printer = config.get_printer() - probe: PrinterProbe = printer.lookup_object("probe") + def __init__(self, probe: PrinterProbe, config: ConfigWrapper): self._cfg_probe_speed = config.getfloat("speed", probe.speed, above=0.0) self._cfg_lift_speed = config.getfloat( "lift_speed", probe.lift_speed, above=0.0 @@ -105,7 +108,10 @@ def __init__(self, config: ConfigWrapper): self.cmd_NOZZLE_CLEANUP, desc=self.cmd_NOZZLE_CLEANUP_help, ) - self.options = NozzleCleanupOptions(config) + self.probe: PrinterProbe = ProbeList.get_list( + self.printer + ).get_config_probe(config) + self.options = NozzleCleanupOptions(self.probe, config) self.retry_policy: RetryPolicy = RetryPolicy(config) self.nozzle_scrubber: GcodeNozzleScrubber = GcodeNozzleScrubber(config) @@ -113,7 +119,7 @@ def _get_toolhead(self) -> ToolHead: return self.printer.lookup_object("toolhead") def _get_probe(self) -> PrinterProbe: - return self.printer.lookup_object("probe") + return self.probe def horizontal_move(self, pos: tuple[float, float]): self._get_toolhead().manual_move( diff --git a/klippy/extras/probe.py b/klippy/extras/probe.py index 69708c39a5..31c4ba1c53 100644 --- a/klippy/extras/probe.py +++ b/klippy/extras/probe.py @@ -10,7 +10,7 @@ from enum import IntEnum from typing import Optional, Union -from klippy import Printer, pins +from klippy import Printer, configfile, pins from klippy.configfile import ConfigWrapper from klippy.extras.gcode_macro import Template from klippy.gcode import GCodeCommand @@ -292,10 +292,106 @@ def set_retry_strategy(self, retry_strategy: RetryStrategy) -> None: self.retry_policy.bad_probe_strategy = retry_strategy +class sentinel: + pass + + +class ProbeList: + @staticmethod + def get_list(printer: Printer) -> ProbeList: + probes = printer.lookup_object("probe_list", None) + if probes is None: + probes = ProbeList(printer) + printer.add_object("probe_list", probes) + return probes + + def __init__(self, printer): + self.probes: dict[str, PrinterProbe] = {} + self.default_probe = None + gcode = printer.lookup_object("gcode") + gcode.register_command( + "LIST_PROBES", self.cmd_LIST_PROBES, desc=self.cmd_LIST_PROBES_help + ) + + def get_status(self, eventtime): + return { + "probes": list(self.probes.keys()), + "default_probe": self.default_probe and self.default_probe[0], + } + + def get_all(self): + return self.probes + + def get_probe(self, name) -> PrinterProbe | None: + return self.probes.get(name, None) + + def get_default_probe(self) -> PrinterProbe | None: + return self.default_probe and self.default_probe[1] + + def get_command_probe( + self, + gcmd, + default=sentinel, + no_default_error="No default probe registered, explicitly select probe by passing `PROBE=`", + ) -> PrinterProbe: + requested_probe = gcmd.get("PROBE", None) + if requested_probe is not None: + if requested_probe in self.probes: + return self.probes[requested_probe] + else: + raise gcmd.error(f"Unknown requested probe {requested_probe}") + else: + if self.default_probe is None and default is sentinel: + raise gcmd.error(no_default_error) + return (self.default_probe and self.default_probe[1]) or default + + def get_config_probe(self, config, default=sentinel) -> PrinterProbe: + probe_name = config.get("probe", None) + probe = None + if probe_name is None: + probe = self.get_default_probe() + else: + probe = self.get_probe(probe_name) + if probe is None and default is sentinel: + if probe_name is None: + raise configfile.error("No default probe available") + else: + raise configfile.error( + f"Requested probe {probe_name} couldn't be found" + ) + return probe or default + + def add_probe_object(self, obj, config): + if obj.probe_name in self.probes: + raise config.error(f"Duplicate probe name {obj.probe_name}") + if obj.is_default_probe: + # If we allow a [probe] config section together with a different default probe, the + # loader might ignore the true [probe] section entirely. + if config.get_name() != "probe" and config.has_section("probe"): + raise config.error( + "Having a [probe] section together with another probe marked `register_as_probe: True` is not supported" + ) + # The default probe gets registered as "probe" for compatibility with external plugins. + obj.printer.add_object("probe", obj) + self.default_probe = (obj.probe_name, obj) + self.probes[obj.probe_name] = obj + return obj + + cmd_LIST_PROBES_help = "List all registered probes" + + def cmd_LIST_PROBES(self, gcmd: GCodeCommand): + gcmd.respond_info("Registered probes:") + for key, probe in self.probes.items(): + gcmd.respond_info( + f"- {key}{' [default]' if probe.is_default_probe else ''}" + ) + + class PrinterProbe: def __init__(self, config, mcu_probe): self.printer = config.get_printer() self.name = config.get_name() + self.probe_name = self.name.split(" ")[-1] self.mcu_probe = mcu_probe self.speed = config.getfloat("speed", 5.0, above=0.0) self.retry_speed: float = config.getfloat( @@ -340,7 +436,12 @@ def __init__(self, config, mcu_probe): "samples_tolerance_retries", 0, minval=0 ) # Register z_virtual_endstop pin - self.printer.lookup_object("pins").register_chip("probe", self) + self.is_default_probe = config.getboolean("register_as_probe", True) + ppins = self.printer.lookup_object("pins") + ppins.register_chip(self.probe_name, self) + if self.is_default_probe and self.probe_name != "probe": + ppins.register_chip("probe", self) + ProbeList.get_list(self.printer).add_probe_object(self, config) # Register homing event handlers self.printer.register_event_handler( "homing:homing_move_begin", self._handle_homing_move_begin @@ -359,24 +460,39 @@ def __init__(self, config, mcu_probe): ) # Register PROBE/QUERY_PROBE commands self.gcode = self.printer.lookup_object("gcode") - self.gcode.register_command( - "PROBE", self.cmd_PROBE, desc=self.cmd_PROBE_help + self.register_commands(self.probe_name) + if self.is_default_probe: + self.register_commands(None) + + def register_commands(self, key): + self.gcode.register_mux_command( + "PROBE", "PROBE", key, self.cmd_PROBE, desc=self.cmd_PROBE_help ) - self.gcode.register_command( - "QUERY_PROBE", self.cmd_QUERY_PROBE, desc=self.cmd_QUERY_PROBE_help + self.gcode.register_mux_command( + "QUERY_PROBE", + "PROBE", + key, + self.cmd_QUERY_PROBE, + desc=self.cmd_QUERY_PROBE_help, ) - self.gcode.register_command( + self.gcode.register_mux_command( "PROBE_CALIBRATE", + "PROBE", + key, self.cmd_PROBE_CALIBRATE, desc=self.cmd_PROBE_CALIBRATE_help, ) - self.gcode.register_command( + self.gcode.register_mux_command( "PROBE_ACCURACY", + "PROBE", + key, self.cmd_PROBE_ACCURACY, desc=self.cmd_PROBE_ACCURACY_help, ) - self.gcode.register_command( + self.gcode.register_mux_command( "Z_OFFSET_APPLY_PROBE", + "PROBE", + key, self.cmd_Z_OFFSET_APPLY_PROBE, desc=self.cmd_Z_OFFSET_APPLY_PROBE_help, ) @@ -974,13 +1090,20 @@ def _move_next(self): toolhead.manual_move(self._next_pos(), self.speed) return False - def start_probe(self, gcmd): + def start_probe(self, gcmd: GCodeCommand): self.retry_session.start(gcmd) self.retry_session.reset_all() manual_probe.verify_no_manual_probe(self.printer) # Lookup objects - probe = self.printer.lookup_object("probe", None) + plist = ProbeList.get_list(self.printer) + probe = plist.get_command_probe(gcmd, None) method = gcmd.get("METHOD", "automatic").lower() + if method != "manual" and (probe is None and plist.get_all()): + raise gcmd.error( + "No default probe, but named probes are available. " + "Either select a probe with PROBE= or use METHOD=manual " + "to enter manual probing mode." + ) if method == "rapid_scan": gcmd.respond_info( "METHOD=rapid_scan not supported, using automatic" @@ -1044,3 +1167,7 @@ def _manual_probe_finalize(self, kin_pos): def load_config(config): return PrinterProbe(config, ProbeEndstopWrapper(config)) + + +def load_config_prefix(config): + return load_config(config) diff --git a/klippy/extras/probe_eddy_current.py b/klippy/extras/probe_eddy_current.py index 5abeb88cc2..11f26da832 100644 --- a/klippy/extras/probe_eddy_current.py +++ b/klippy/extras/probe_eddy_current.py @@ -16,6 +16,7 @@ class EddyCalibration: def __init__(self, config): self.printer = config.get_printer() self.name = config.get_name() + self.pprobe: probe.PrinterProbe | None = None # Current calibration data self.cal_freqs = [] self.cal_zpos = [] @@ -166,8 +167,7 @@ def post_manual_probe(self, kin_pos): curpos[2] += 5.0 move(curpos, self.probe_speed) # Move sensor over nozzle position - pprobe = self.printer.lookup_object("probe") - x_offset, y_offset, z_offset = pprobe.get_offsets() + x_offset, y_offset, z_offset = self.pprobe.get_offsets() curpos[0] -= x_offset curpos[1] -= y_offset move(curpos, self.probe_speed) @@ -383,7 +383,7 @@ def __init__(self, config): self.probe = EddyEndstopWrapper( config, self.sensor_helper, self.calibration ) - self.printer.add_object("probe", probe.PrinterProbe(config, self.probe)) + self.calibration.pprobe = probe.PrinterProbe(config, self.probe) def add_client(self, cb): self.sensor_helper.add_client(cb) diff --git a/klippy/extras/smart_effector.py b/klippy/extras/smart_effector.py index 08df7b6bd7..e08b46fd28 100644 --- a/klippy/extras/smart_effector.py +++ b/klippy/extras/smart_effector.py @@ -177,7 +177,5 @@ def cmd_RESET_SMART_EFFECTOR(self, gcmd): def load_config(config): smart_effector = SmartEffectorEndstopWrapper(config) - config.get_printer().add_object( - "probe", probe.PrinterProbe(config, smart_effector) - ) + probe.PrinterProbe(config, smart_effector) return smart_effector diff --git a/klippy/extras/z_calibration.py b/klippy/extras/z_calibration.py index 62b51bb877..65af406764 100644 --- a/klippy/extras/z_calibration.py +++ b/klippy/extras/z_calibration.py @@ -5,6 +5,7 @@ # This file may be distributed under the terms of the GNU GPLv3 license. import logging +from klippy.extras.probe import ProbeList from klippy.mcu import MCU_endstop @@ -124,12 +125,8 @@ def handle_connect(self): self.nozzle_site[1] + self.switch_xy_offsets[1], None, ] - # get probing settings - probe = self.printer.lookup_object("probe", default=None) - if probe is None: - raise self.printer.config_error( - "A probe is needed for %s" % (self.config.get_name()) - ) + + def load_probe(self, probe): if self.samples is None: self.samples = probe.sample_count if self.tolerance is None: @@ -172,6 +169,8 @@ def _build_config(self): ) def cmd_CALIBRATE_Z(self, gcmd): + probe = ProbeList.get_list(self.printer).get_command_probe(gcmd) + self.load_probe(probe) if self.z_homing is None: raise gcmd.error("Must home axes first") site_attr = gcmd.get("BED_POSITION", None) @@ -206,7 +205,7 @@ def cmd_CALIBRATE_Z(self, gcmd): " for %s" % (self.config.get_name()) ) self._log_config() - state = CalibrationState(self, gcmd) + state = CalibrationState(probe, self, gcmd) state.calibrate_z() cmd_PROBE_Z_ACCURACY_help = ( @@ -214,6 +213,8 @@ def cmd_CALIBRATE_Z(self, gcmd): ) def cmd_PROBE_Z_ACCURACY(self, gcmd): + probe = ProbeList.get_list(self.printer).get_command_probe(gcmd) + self.load_probe(probe) if self.z_homing is None: raise gcmd.error("Must home axes first") speed = gcmd.get_float("PROBE_SPEED", self.second_speed, above=0.0) @@ -428,12 +429,12 @@ def __init__(self, config, endstop): class CalibrationState: - def __init__(self, helper, gcmd): + def __init__(self, probe, helper, gcmd): self.helper = helper self.gcmd = gcmd self.gcode = helper.gcode self.z_endstop = helper.z_endstop - self.probe = helper.printer.lookup_object("probe") + self.probe = probe self.toolhead = helper.printer.lookup_object("toolhead") self.gcode_move = helper.printer.lookup_object("gcode_move") self.max_deviation = helper.max_deviation