diff options
Diffstat (limited to 'klippy/extras/axis_twist_compensation.py')
-rw-r--r-- | klippy/extras/axis_twist_compensation.py | 256 |
1 files changed, 131 insertions, 125 deletions
diff --git a/klippy/extras/axis_twist_compensation.py b/klippy/extras/axis_twist_compensation.py index 908ac4da..224f0a6c 100644 --- a/klippy/extras/axis_twist_compensation.py +++ b/klippy/extras/axis_twist_compensation.py @@ -9,112 +9,115 @@ from . import manual_probe, bed_mesh, probe DEFAULT_SAMPLE_COUNT = 3 -DEFAULT_SPEED = 50. -DEFAULT_HORIZONTAL_MOVE_Z = 5. +DEFAULT_SPEED = 50.0 +DEFAULT_HORIZONTAL_MOVE_Z = 5.0 class AxisTwistCompensation: def __init__(self, config): # get printer self.printer = config.get_printer() - self.gcode = self.printer.lookup_object('gcode') + self.gcode = self.printer.lookup_object("gcode") # get values from [axis_twist_compensation] section in printer .cfg - self.horizontal_move_z = config.getfloat('horizontal_move_z', - DEFAULT_HORIZONTAL_MOVE_Z) - self.speed = config.getfloat('speed', DEFAULT_SPEED) - self.calibrate_start_x = config.getfloat('calibrate_start_x', - default=None) - self.calibrate_end_x = config.getfloat('calibrate_end_x', default=None) - self.calibrate_y = config.getfloat('calibrate_y', default=None) - self.z_compensations = config.getlists('z_compensations', - default=[], parser=float) - self.compensation_start_x = config.getfloat('compensation_start_x', - default=None) - self.compensation_end_x = config.getfloat('compensation_end_x', - default=None) + self.horizontal_move_z = config.getfloat( + "horizontal_move_z", DEFAULT_HORIZONTAL_MOVE_Z + ) + self.speed = config.getfloat("speed", DEFAULT_SPEED) + self.calibrate_start_x = config.getfloat("calibrate_start_x", default=None) + self.calibrate_end_x = config.getfloat("calibrate_end_x", default=None) + self.calibrate_y = config.getfloat("calibrate_y", default=None) + self.z_compensations = config.getlists( + "z_compensations", default=[], parser=float + ) + self.compensation_start_x = config.getfloat( + "compensation_start_x", default=None + ) + self.compensation_end_x = config.getfloat("compensation_end_x", default=None) - self.calibrate_start_y = config.getfloat('calibrate_start_y', - default=None) - self.calibrate_end_y = config.getfloat('calibrate_end_y', default=None) - self.calibrate_x = config.getfloat('calibrate_x', default=None) - self.compensation_start_y = config.getfloat('compensation_start_y', - default=None) - self.compensation_end_y = config.getfloat('compensation_end_y', - default=None) - self.zy_compensations = config.getlists('zy_compensations', - default=[], parser=float) + self.calibrate_start_y = config.getfloat("calibrate_start_y", default=None) + self.calibrate_end_y = config.getfloat("calibrate_end_y", default=None) + self.calibrate_x = config.getfloat("calibrate_x", default=None) + self.compensation_start_y = config.getfloat( + "compensation_start_y", default=None + ) + self.compensation_end_y = config.getfloat("compensation_end_y", default=None) + self.zy_compensations = config.getlists( + "zy_compensations", default=[], parser=float + ) # setup calibrater self.calibrater = Calibrater(self, config) # register events - self.printer.register_event_handler("probe:update_results", - self._update_z_compensation_value) + self.printer.register_event_handler( + "probe:update_results", self._update_z_compensation_value + ) def _update_z_compensation_value(self, pos): if self.z_compensations: pos[2] += self._get_interpolated_z_compensation( - pos[0], self.z_compensations, + pos[0], + self.z_compensations, self.compensation_start_x, - self.compensation_end_x - ) + self.compensation_end_x, + ) if self.zy_compensations: pos[2] += self._get_interpolated_z_compensation( - pos[1], self.zy_compensations, + pos[1], + self.zy_compensations, self.compensation_start_y, - self.compensation_end_y - ) + self.compensation_end_y, + ) def _get_interpolated_z_compensation( - self, coord, z_compensations, - comp_start, - comp_end - ): + self, coord, z_compensations, comp_start, comp_end + ): sample_count = len(z_compensations) - spacing = ((comp_end - comp_start) - / (sample_count - 1)) + spacing = (comp_end - comp_start) / (sample_count - 1) interpolate_t = (coord - comp_start) / spacing interpolate_i = int(math.floor(interpolate_t)) interpolate_i = bed_mesh.constrain(interpolate_i, 0, sample_count - 2) interpolate_t -= interpolate_i interpolated_z_compensation = bed_mesh.lerp( - interpolate_t, z_compensations[interpolate_i], - z_compensations[interpolate_i + 1]) + interpolate_t, + z_compensations[interpolate_i], + z_compensations[interpolate_i + 1], + ) return interpolated_z_compensation def clear_compensations(self, axis=None): if axis is None: self.z_compensations = [] self.zy_compensations = [] - elif axis == 'X': + elif axis == "X": self.z_compensations = [] - elif axis == 'Y': + elif axis == "Y": self.zy_compensations = [] + class Calibrater: def __init__(self, compensation, config): # setup self attributes self.compensation = compensation self.printer = compensation.printer - self.gcode = self.printer.lookup_object('gcode') + self.gcode = self.printer.lookup_object("gcode") self.probe = None # probe settings are set to none, until they are available - self.lift_speed, self.probe_x_offset, self.probe_y_offset, _ = \ - None, None, None, None - self.printer.register_event_handler("klippy:connect", - self._handle_connect) + self.lift_speed, self.probe_x_offset, self.probe_y_offset, _ = ( + None, + None, + 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 = (compensation.calibrate_start_x, - compensation.calibrate_y) - self.x_end_point = (compensation.calibrate_end_x, - compensation.calibrate_y) - self.y_start_point = (compensation.calibrate_x, - compensation.calibrate_start_y) - self.y_end_point = (compensation.calibrate_x, - compensation.calibrate_end_y) + self.x_start_point = (compensation.calibrate_start_x, compensation.calibrate_y) + self.x_end_point = (compensation.calibrate_end_x, compensation.calibrate_y) + self.y_start_point = (compensation.calibrate_x, compensation.calibrate_start_y) + self.y_end_point = (compensation.calibrate_x, compensation.calibrate_end_y) self.results = None self.current_point_index = None self.gcmd = None @@ -124,21 +127,22 @@ class Calibrater: self._register_gcode_handlers() def _handle_connect(self): - self.probe = self.printer.lookup_object('probe', None) + 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_probe_params()['lift_speed'] - self.probe_x_offset, self.probe_y_offset, _ = \ - self.probe.get_offsets() + "AXIS_TWIST_COMPENSATION requires [probe] to be defined" + ) + self.lift_speed = self.probe.get_probe_params()["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') + self.gcode = self.printer.lookup_object("gcode") self.gcode.register_command( - 'AXIS_TWIST_COMPENSATION_CALIBRATE', + "AXIS_TWIST_COMPENSATION_CALIBRATE", self.cmd_AXIS_TWIST_COMPENSATION_CALIBRATE, - desc=self.cmd_AXIS_TWIST_COMPENSATION_CALIBRATE_help) + desc=self.cmd_AXIS_TWIST_COMPENSATION_CALIBRATE_help, + ) cmd_AXIS_TWIST_COMPENSATION_CALIBRATE_help = """ Performs the x twist calibration wizard @@ -148,32 +152,29 @@ class Calibrater: def cmd_AXIS_TWIST_COMPENSATION_CALIBRATE(self, gcmd): self.gcmd = gcmd - sample_count = gcmd.get_int('SAMPLE_COUNT', DEFAULT_SAMPLE_COUNT) - axis = gcmd.get('AXIS', 'X') + sample_count = gcmd.get_int("SAMPLE_COUNT", DEFAULT_SAMPLE_COUNT) + axis = gcmd.get("AXIS", "X") # check for valid sample_count if sample_count < 2: - raise self.gcmd.error( - "SAMPLE_COUNT to probe must be at least 2") + raise self.gcmd.error("SAMPLE_COUNT to probe must be at least 2") # calculate the points to put the probe at, returned as a list of tuples nozzle_points = [] - if axis == 'X': + if axis == "X": - self.compensation.clear_compensations('X') + self.compensation.clear_compensations("X") - if not all([ - self.x_start_point[0], - self.x_end_point[0], - self.x_start_point[1] - ]): + if not all( + [self.x_start_point[0], self.x_end_point[0], self.x_start_point[1]] + ): raise self.gcmd.error( """AXIS_TWIST_COMPENSATION for X axis requires calibrate_start_x, calibrate_end_x and calibrate_y to be defined """ - ) + ) start_point = self.x_start_point end_point = self.x_end_point @@ -186,21 +187,19 @@ class Calibrater: y = start_point[1] nozzle_points.append((x, y)) - elif axis == 'Y': + elif axis == "Y": - self.compensation.clear_compensations('Y') + self.compensation.clear_compensations("Y") - if not all([ - self.y_start_point[0], - self.y_end_point[0], - self.y_start_point[1] - ]): + if not all( + [self.y_start_point[0], self.y_end_point[0], self.y_start_point[1]] + ): raise self.gcmd.error( """AXIS_TWIST_COMPENSATION for Y axis requires calibrate_start_y, calibrate_end_y and calibrate_x to be defined """ - ) + ) start_point = self.y_start_point end_point = self.y_end_point @@ -214,12 +213,11 @@ class Calibrater: nozzle_points.append((x, y)) else: - raise self.gcmd.error( - "AXIS_TWIST_COMPENSATION_CALIBRATE: " - "Invalid axis.") + raise self.gcmd.error("AXIS_TWIST_COMPENSATION_CALIBRATE: " "Invalid axis.") probe_points = self._calculate_probe_points( - nozzle_points, self.probe_x_offset, self.probe_y_offset) + nozzle_points, self.probe_x_offset, self.probe_y_offset + ) # verify no other manual probe is in progress manual_probe.verify_no_manual_probe(self.printer) @@ -230,8 +228,7 @@ class Calibrater: self.current_axis = axis self._calibration(probe_points, nozzle_points, interval_dist) - def _calculate_probe_points(self, nozzle_points, - probe_x_offset, probe_y_offset): + def _calculate_probe_points(self, nozzle_points, probe_x_offset, probe_y_offset): # calculate the points to put the nozzle at # returned as a list of tuples probe_points = [] @@ -243,27 +240,34 @@ class Calibrater: def _move_helper(self, target_coordinates, override_speed=None): # pad target coordinates - target_coordinates = \ - (target_coordinates[0], target_coordinates[1], None) \ - if len(target_coordinates) == 2 else target_coordinates - toolhead = self.printer.lookup_object('toolhead') + target_coordinates = ( + (target_coordinates[0], target_coordinates[1], None) + if len(target_coordinates) == 2 + else target_coordinates + ) + toolhead = self.printer.lookup_object("toolhead") speed = self.speed if target_coordinates[2] == None else self.lift_speed speed = override_speed if override_speed is not None else speed toolhead.manual_move(target_coordinates, speed) def _calibration(self, probe_points, nozzle_points, interval): # begin the calibration process - self.gcmd.respond_info("AXIS_TWIST_COMPENSATION_CALIBRATE: " - "Probing point %d of %d" % ( - self.current_point_index + 1, - len(probe_points))) + self.gcmd.respond_info( + "AXIS_TWIST_COMPENSATION_CALIBRATE: " + "Probing point %d of %d" % (self.current_point_index + 1, len(probe_points)) + ) # horizontal_move_z (to prevent probe trigger or hitting bed) self._move_helper((None, None, self.horizontal_move_z)) # move to point to probe - self._move_helper((probe_points[self.current_point_index][0], - probe_points[self.current_point_index][1], None)) + self._move_helper( + ( + probe_points[self.current_point_index][0], + probe_points[self.current_point_index][1], + None, + ) + ) # probe the point pos = probe.run_single_probe(self.probe, self.gcmd) @@ -277,12 +281,12 @@ class Calibrater: # start the manual (nozzle) probe manual_probe.ManualProbeHelper( - self.printer, self.gcmd, - self._manual_probe_callback_factory( - probe_points, nozzle_points, interval)) + self.printer, + self.gcmd, + self._manual_probe_callback_factory(probe_points, nozzle_points, interval), + ) - def _manual_probe_callback_factory(self, probe_points, - nozzle_points, interval): + def _manual_probe_callback_factory(self, probe_points, nozzle_points, interval): # returns a callback function for the manual probe is_end = self.current_point_index == len(probe_points) - 1 @@ -291,7 +295,8 @@ class Calibrater: # probe was cancelled self.gcmd.respond_info( "AXIS_TWIST_COMPENSATION_CALIBRATE: Probe cancelled, " - "calibration aborted") + "calibration aborted" + ) return z_offset = self.current_measured_z - kin_pos[2] self.results.append(z_offset) @@ -302,6 +307,7 @@ class Calibrater: # move to next point self.current_point_index += 1 self._calibration(probe_points, nozzle_points, interval) + return callback def _finalize_calibration(self): @@ -312,29 +318,28 @@ class Calibrater: # so that they are independent of z_offset self.results = [avg - x for x in self.results] # save the config - configfile = self.printer.lookup_object('configfile') - values_as_str = ', '.join(["{:.6f}".format(x) - for x in self.results]) + configfile = self.printer.lookup_object("configfile") + values_as_str = ", ".join(["{:.6f}".format(x) for x in self.results]) - if(self.current_axis == 'X'): + if self.current_axis == "X": - configfile.set(self.configname, 'z_compensations', values_as_str) - configfile.set(self.configname, 'compensation_start_x', - self.x_start_point[0]) - configfile.set(self.configname, 'compensation_end_x', - self.x_end_point[0]) + configfile.set(self.configname, "z_compensations", values_as_str) + configfile.set( + self.configname, "compensation_start_x", self.x_start_point[0] + ) + configfile.set(self.configname, "compensation_end_x", self.x_end_point[0]) self.compensation.z_compensations = self.results self.compensation.compensation_start_x = self.x_start_point[0] self.compensation.compensation_end_x = self.x_end_point[0] - elif(self.current_axis == 'Y'): + elif self.current_axis == "Y": - configfile.set(self.configname, 'zy_compensations', values_as_str) - configfile.set(self.configname, 'compensation_start_y', - self.y_start_point[1]) - configfile.set(self.configname, 'compensation_end_y', - self.y_end_point[1]) + configfile.set(self.configname, "zy_compensations", values_as_str) + configfile.set( + self.configname, "compensation_start_y", self.y_start_point[1] + ) + configfile.set(self.configname, "compensation_end_y", self.y_end_point[1]) self.compensation.zy_compensations = self.results self.compensation.compensation_start_y = self.y_start_point[1] @@ -343,12 +348,13 @@ class Calibrater: self.gcode.respond_info( "AXIS_TWIST_COMPENSATION state has been saved " "for the current session. The SAVE_CONFIG command will " - "update the printer config file and restart the printer.") + "update the printer config file and restart the printer." + ) # output result self.gcmd.respond_info( "AXIS_TWIST_COMPENSATION_CALIBRATE: Calibration complete, " - "offsets: %s, mean z_offset: %f" - % (self.results, avg)) + "offsets: %s, mean z_offset: %f" % (self.results, avg) + ) # klipper's entry point using [axis_twist_compensation] section in printer.cfg |