From 37211309130d7cdc251e698362d3b189224d351b Mon Sep 17 00:00:00 2001 From: Nick Weedon Date: Tue, 31 Dec 2024 23:50:25 -0500 Subject: [PATCH 1/2] probe_as_z_home: Initial implementation and documentation * Added tool 'probe_as_z_home' that allows probing to be used for Z homing when a empty [probe_as_z_home] section is added to the configuration. * Added relevant documentation to 'Config_Reference.md'. Signed-off-by: Nick Weedon --- docs/Config_Reference.md | 20 +++++++ klippy/extras/probe_as_z_home.py | 89 ++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 klippy/extras/probe_as_z_home.py diff --git a/docs/Config_Reference.md b/docs/Config_Reference.md index f797d2b06..53d3409f7 100644 --- a/docs/Config_Reference.md +++ b/docs/Config_Reference.md @@ -2091,6 +2091,26 @@ sensor_type: ldc1612 # See the "probe" section for information on these parameters. ``` +### [probe_as_z_home] + +This tool allows the homing procedure (```G28```) to use probing (i.e. the same as the ```PROBE``` command) so that in some cases the Z axis can be more accurately probed. + +You should only use this option if you are occasionally experiencing innacurate homing. + +Configuring this tool will also cause the ```G28``` G-Code to emit a console message stating the correction that was performed. You can use this to measure the level of benefit that the tool is providing. + +To enable this tool, add the following configuration section anywhere before either ```[safe_z_homing]``` section or the ```[homing_override]``` section. + +There is no specific G-Code for this command since it simply alters the behavior of the +existing standard 'G28' G-Code command. +See [command reference](G-Codes.md#G-Code_commands) for further information. + +``` +[probe_as_z_home] +``` + +_Note: The standing homing procedure is still perofrmed before probing since this is required to ensure safety and compatibility with the probing method since probing requires homing to first be performed_ + ### [axis_twist_compensation] A tool to compensate for inaccurate probe readings due to twist in X or Y diff --git a/klippy/extras/probe_as_z_home.py b/klippy/extras/probe_as_z_home.py new file mode 100644 index 000000000..eb0a84649 --- /dev/null +++ b/klippy/extras/probe_as_z_home.py @@ -0,0 +1,89 @@ +# Change Z Homing behavior to use probing instead of the typical G28 homing. +# +# Copyright (C) 2025 Nick Weedon +# +# This file may be distributed under the terms of the GNU GPLv3 license. +import logging +import copy + +class ProbeAsZHome: + def __init__(self, config): + logging.debug("Probe As Home: Initializing") + self.printer = config.get_printer() + self.gcode = self.printer.lookup_object('gcode') + if self.gcode.register_command("G28", None) is not None: + raise config.error("probe_as_z_home must be defined before \ + homing_override or safe_z_homing") + self.printer.load_object(config, 'homing') + self.prev_G28 = self.gcode.register_command("G28", None) + self.gcode.register_command("G28", self.cmd_G28) + + def cmd_G28(self, gcmd): + logging.debug("Probe As Home: Performing G28") + + # We need to pass on the parameters to the original G28 command + # we are 'decorating' but omit the Z axis as this tool will handle it + new_params = copy.deepcopy(gcmd.get_command_parameters()) + # If neither X,Y or Z are specified, then this implies + # that all axes need to be homed. + if all(new_params.get(axis, None) is None for axis in "XYZ"): + new_params['X'] = '0' + new_params['Y'] = '0' + + original_z_param = new_params.pop('Z', None) + + # Perform XY homing if necessary using the original G28 command + if any(new_params.get(axis, None) is not None for axis in "XY"): + g28_gcmd = self.gcode.create_gcode_command("G28", "G28", new_params) + self.prev_G28(g28_gcmd) + + # Perform Z homing using the probe + if original_z_param is not None: + logging.debug("Beggining probe based Z homing") + new_params['Z'] = original_z_param + new_params.pop('X', None) + new_params.pop('Y', None) + g28_gcmd = self.gcode.create_gcode_command("G28", "G28", new_params) + self.prev_G28(g28_gcmd) + + # Probe Z + probe = self.printer.lookup_object('probe', None) + + # Retract before probing since the homing procedure can position + # the toolhead too close to the bed such that BL-Touch based + # probes cannot deploy. + self.toolhead = self.printer.lookup_object('toolhead') + current_pos = self.toolhead.get_position() + + lift_speed = probe.get_probe_params()['lift_speed'] + retract_dist = probe.get_probe_params()['sample_retract_dist'] + + current_pos[2] += retract_dist + self.toolhead.move(current_pos, lift_speed) + + # Use the probe options from the configuration here + g28_gcmd = self.gcode.create_gcode_command("PROBE", "PROBE", {}) + probe_session = probe.start_probe_session(gcmd) + probe_session.run_probe(gcmd) + probed_pos = probe_session.pull_probed_results()[0] + current_pos = self.toolhead.get_position() + z_error_delta = probed_pos[2] - current_pos[2] + logging.debug("Result of probe: " + repr(probed_pos)) + logging.debug("Toolhead position: " + repr(current_pos)) + gcmd.respond_info("Correcting homed Z by: " + str(z_error_delta)) + + # Set the new position based on the probe result + new_position = current_pos.copy() + new_position[2] = probed_pos[2] + self.toolhead.set_position(new_position) + + # End the probe session only after setting the new position + # in case 'end_probe_session()' moves the toolhead. + probe_session.end_probe_session() + + def get_status(self, eventtime): + return {'probe_as_home': True} + + +def load_config(config): + return ProbeAsZHome(config) From 9dde27aef3a78af0b9db35a014b44a0dfaa4eb6b Mon Sep 17 00:00:00 2001 From: Nick Weedon Date: Wed, 29 Jan 2025 10:44:52 -0500 Subject: [PATCH 2/2] probe_as_z_home: Added g28_probe_cmd_args configuration option * Added the optional g28_probe_cmd_args configuration option to [probe_as_z_home] to allow gcode command arguments to be passed to the PROBE command during homing. * Updated documentation to 'Config_Reference.md'. Signed-off-by: Nick Weedon --- docs/Config_Reference.md | 7 ++++++- klippy/extras/probe_as_z_home.py | 20 ++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/docs/Config_Reference.md b/docs/Config_Reference.md index 53d3409f7..1af68b54e 100644 --- a/docs/Config_Reference.md +++ b/docs/Config_Reference.md @@ -2095,7 +2095,7 @@ sensor_type: ldc1612 This tool allows the homing procedure (```G28```) to use probing (i.e. the same as the ```PROBE``` command) so that in some cases the Z axis can be more accurately probed. -You should only use this option if you are occasionally experiencing innacurate homing. +You should use this option if you are occasionally experiencing innacurate homing. Configuring this tool will also cause the ```G28``` G-Code to emit a console message stating the correction that was performed. You can use this to measure the level of benefit that the tool is providing. @@ -2107,6 +2107,11 @@ See [command reference](G-Codes.md#G-Code_commands) for further information. ``` [probe_as_z_home] +#g28_probe_cmd_args: +# Optional command arguments passed to the PROBE command while homing. +# See [g-code PROBE command](G-Codes.md#probe). +# Example: +# g28_probe_cmd_args: SAMPLES=3 SAMPLES_TOLERANCE_RETRIES=5 ``` _Note: The standing homing procedure is still perofrmed before probing since this is required to ensure safety and compatibility with the probing method since probing requires homing to first be performed_ diff --git a/klippy/extras/probe_as_z_home.py b/klippy/extras/probe_as_z_home.py index eb0a84649..73eafc5e6 100644 --- a/klippy/extras/probe_as_z_home.py +++ b/klippy/extras/probe_as_z_home.py @@ -17,6 +17,7 @@ class ProbeAsZHome: self.printer.load_object(config, 'homing') self.prev_G28 = self.gcode.register_command("G28", None) self.gcode.register_command("G28", self.cmd_G28) + self.g28_probe_cmd_args = config.get("g28_probe_cmd_args", None) def cmd_G28(self, gcmd): logging.debug("Probe As Home: Performing G28") @@ -61,10 +62,21 @@ class ProbeAsZHome: current_pos[2] += retract_dist self.toolhead.move(current_pos, lift_speed) - # Use the probe options from the configuration here - g28_gcmd = self.gcode.create_gcode_command("PROBE", "PROBE", {}) - probe_session = probe.start_probe_session(gcmd) - probe_session.run_probe(gcmd) + # Parse and pass any arguments defined in the g28_probe_cmd_args + # configuration to the PROBE command. + probe_args_dict = {} + + if self.g28_probe_cmd_args is not None: + probe_arg_tokens = self.g28_probe_cmd_args.split(" ") + probe_arg_tokens = filter(lambda token: token.strip() != "", + probe_arg_tokens) + probe_args_dict = { operand[0]: operand[1] for operand in \ + [arg.split("=") for arg in probe_arg_tokens]} + + probe_gcmd = self.gcode.create_gcode_command( + "PROBE", "PROBE", probe_args_dict) + probe_session = probe.start_probe_session(probe_gcmd) + probe_session.run_probe(probe_gcmd) probed_pos = probe_session.pull_probed_results()[0] current_pos = self.toolhead.get_position() z_error_delta = probed_pos[2] - current_pos[2]