zcalibrate: rewrite the functions that get the location to probe due to reported issues
thanks Aubey
This commit is contained in:
parent
01193c203c
commit
f58cdcb31a
@ -8,22 +8,37 @@ It's strongly suggested to read Klipper documentation about [Bed level](https://
|
||||
## Buttons
|
||||
* "Start" will initiate the only method available, or ask the user if multiple methods are available.
|
||||
!!! note
|
||||
KlipperScreen will home if needed and move to the middle of the bed,
|
||||
but the location can be configured in [KlipperScreen.conf](https://klipperscreen.readthedocs.io/en/latest/Configuration/#printer-options)
|
||||
KlipperScreen will automatically Home(`G28`) if needed
|
||||
* The raise(+) and lower(-) buttons send `TESTZ Z=distance` where distance is selected in the bottom row.
|
||||
* Accept will send `ACCEPT`
|
||||
* Abort will send `ABORT`
|
||||
|
||||
## Calibration methods
|
||||
### Endstop (`Z_ENDSTOP_CALIBRATE`)
|
||||
Available when a physical endstop is defined for `[stepper_z]`
|
||||
|
||||
See Klipper documentation: [Calibrating a Z endstop](https://www.klipper3d.org/Manual_Level.html#calibrating-a-z-endstop)
|
||||
## Calibration methods
|
||||
|
||||
### Probe (`PROBE_CALIBRATE`)
|
||||
Available when a probe is defined. (BL-Touch is a probe)
|
||||
|
||||
See Klipper documentation: [Calibrating probe Z offset](https://www.klipper3d.org/Probe_Calibrate.html#calibrating-probe-z-offset)
|
||||
KlipperScreen will try to position the probe in the correct place before sendind a `PROBE_CALIBRATE`
|
||||
|
||||
??? info "Search order to select location"
|
||||
|
||||
1. `calibrate_x_position` and `calibrate_y_position` in [KlipperScreen.conf](https://klipperscreen.readthedocs.io/en/latest/Configuration/#printer-options)
|
||||
Both need to be configured, probe offsets are not applied. This is considered an override
|
||||
2. Probe at the [zero reference position of the mesh](https://www.klipper3d.org/Bed_Mesh.html#configuring-the-zero-reference-position)
|
||||
3. If `[safe_z_home]` is defined, those values are used. Unless `Z_ENDSTOP_CALIBRATE` is available.
|
||||
In other words, only use `[safe_z_home]` if `z_virtual_endstop` is used
|
||||
4. If the kinematics are `delta` probe is placed at 0, 0
|
||||
5. Probe at the center of the `bed_mesh`
|
||||
6. Probe at the center of the axes (`position_max` / 2)
|
||||
|
||||
|
||||
Klipper documentation: [Calibrating probe Z offset](https://www.klipper3d.org/Probe_Calibrate.html#calibrating-probe-z-offset)
|
||||
|
||||
### Endstop (`Z_ENDSTOP_CALIBRATE`)
|
||||
Available when a physical endstop is defined for `[stepper_z]`
|
||||
|
||||
Klipper documentation: [Calibrating a Z endstop](https://www.klipper3d.org/Manual_Level.html#calibrating-a-z-endstop)
|
||||
|
||||
### Bed mesh (`BED_MESH_CALIBRATE`)
|
||||
Available when a probe is not defined and `[bed_mesh]` is defined
|
||||
@ -38,7 +53,4 @@ this mode lets you create a mesh leveling bed using the paper test in various po
|
||||
### Delta Automatic/Manual (`DELTA_CALIBRATE`)
|
||||
Available when the kinematics are defined as delta.
|
||||
|
||||
See Klipper documentation: [Delta calibration](https://www.klipper3d.org/Delta_Calibrate.html)
|
||||
|
||||
!!! note
|
||||
KlipperScreen will automatically Home(`G28`) if needed
|
||||
Klipper documentation: [Delta calibration](https://www.klipper3d.org/Delta_Calibrate.html)
|
||||
|
@ -13,21 +13,35 @@ class Panel(ScreenPanel):
|
||||
|
||||
def __init__(self, screen, title):
|
||||
super().__init__(screen, title)
|
||||
self.z_offset = None
|
||||
self.mesh_min = []
|
||||
self.mesh_max = []
|
||||
self.zero_ref = []
|
||||
self.z_hop_speed = 15.0
|
||||
self.z_hop = 5.0
|
||||
self.probe = self._printer.get_probe()
|
||||
if self.probe:
|
||||
self.x_offset = float(self.probe['x_offset']) if "x_offset" in self.probe else 0.0
|
||||
self.y_offset = float(self.probe['y_offset']) if "y_offset" in self.probe else 0.0
|
||||
self.z_offset = float(self.probe['z_offset'])
|
||||
logging.info(f"Z offset: {self.z_offset}")
|
||||
if "sample_retract_dist" in self.probe:
|
||||
self.z_hop = float(self.probe['sample_retract_dist'])
|
||||
if "speed" in self.probe:
|
||||
self.z_hop_speed = float(self.probe['speed'])
|
||||
else:
|
||||
self.x_offset = 0.0
|
||||
self.y_offset = 0.0
|
||||
self.z_offset = 0.0
|
||||
logging.info(f"Offset X:{self.x_offset} Y:{self.y_offset} Z:{self.z_offset}")
|
||||
self.widgets['zposition'] = Gtk.Label(label="Z: ?")
|
||||
|
||||
self.widgets['zoffset'] = Gtk.Label(label="?")
|
||||
pos = Gtk.Grid(row_homogeneous=True, column_homogeneous=True)
|
||||
pos.attach(self.widgets['zposition'], 0, 1, 2, 1)
|
||||
if self.z_offset is not None:
|
||||
self.widgets['zoffset'] = Gtk.Label(label="?")
|
||||
pos.attach(Gtk.Label(_("Probe Offset") + ": "), 0, 2, 2, 1)
|
||||
pos.attach(Gtk.Label(_("Saved")), 0, 3, 1, 1)
|
||||
pos.attach(Gtk.Label(_("New")), 1, 3, 1, 1)
|
||||
pos.attach(Gtk.Label(f"{self.z_offset:.3f}"), 0, 4, 1, 1)
|
||||
if self.probe:
|
||||
pos.attach(Gtk.Label(label=_("Probe Offset") + ": "), 0, 2, 2, 1)
|
||||
pos.attach(Gtk.Label(label=_("Saved")), 0, 3, 1, 1)
|
||||
pos.attach(Gtk.Label(label=_("New")), 1, 3, 1, 1)
|
||||
pos.attach(Gtk.Label(label=f"{self.z_offset:.3f}"), 0, 4, 1, 1)
|
||||
pos.attach(self.widgets['zoffset'], 1, 4, 1, 1)
|
||||
self.buttons = {
|
||||
'zpos': self._gtk.Button('z-farther', _("Raise Nozzle"), 'color4'),
|
||||
@ -41,36 +55,9 @@ class Panel(ScreenPanel):
|
||||
self.buttons['complete'].connect("clicked", self.accept)
|
||||
self.buttons['cancel'].connect("clicked", self.abort)
|
||||
|
||||
functions = []
|
||||
pobox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||
|
||||
if "Z_ENDSTOP_CALIBRATE" in self._printer.available_commands:
|
||||
self._add_button("Endstop", "endstop", pobox)
|
||||
functions.append("endstop")
|
||||
if "PROBE_CALIBRATE" in self._printer.available_commands:
|
||||
self._add_button("Probe", "probe", pobox)
|
||||
functions.append("probe")
|
||||
if "BED_MESH_CALIBRATE" in self._printer.available_commands and "probe" not in functions:
|
||||
# This is used to do a manual bed mesh if there is no probe
|
||||
self._add_button("Bed mesh", "mesh", pobox)
|
||||
functions.append("mesh")
|
||||
if "DELTA_CALIBRATE" in self._printer.available_commands:
|
||||
if "probe" in functions:
|
||||
self._add_button("Delta Automatic", "delta", pobox)
|
||||
functions.append("delta")
|
||||
# Since probes may not be accturate enough for deltas, always show the manual method
|
||||
self._add_button("Delta Manual", "delta_manual", pobox)
|
||||
functions.append("delta_manual")
|
||||
|
||||
logging.info(f"Available functions for calibration: {functions}")
|
||||
|
||||
self.labels['popover'] = Gtk.Popover(position=Gtk.PositionType.BOTTOM)
|
||||
self.labels['popover'].add(pobox)
|
||||
|
||||
if len(functions) > 1:
|
||||
self.buttons['start'].connect("clicked", self.on_popover_clicked)
|
||||
else:
|
||||
self.buttons['start'].connect("clicked", self.start_calibration, functions[0])
|
||||
self.set_functions()
|
||||
|
||||
distgrid = Gtk.Grid()
|
||||
for j, i in enumerate(self.distances):
|
||||
@ -107,6 +94,45 @@ class Panel(ScreenPanel):
|
||||
grid.attach(distances, 0, 2, 3, 1)
|
||||
self.content.add(grid)
|
||||
|
||||
def set_functions(self):
|
||||
functions = []
|
||||
pobox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||
|
||||
if "Z_ENDSTOP_CALIBRATE" in self._printer.available_commands:
|
||||
self._add_button("Endstop", "endstop", pobox)
|
||||
functions.append("endstop")
|
||||
if "PROBE_CALIBRATE" in self._printer.available_commands:
|
||||
self._add_button("Probe", "probe", pobox)
|
||||
functions.append("probe")
|
||||
if "BED_MESH_CALIBRATE" in self._printer.available_commands:
|
||||
self.mesh_min = self._csv_to_array(self._printer.get_config_section("bed_mesh")['mesh_min'])
|
||||
self.mesh_max = self._csv_to_array(self._printer.get_config_section("bed_mesh")['mesh_max'])
|
||||
if 'zero_reference_position' in self._printer.get_config_section("bed_mesh"):
|
||||
self.zero_ref = self._csv_to_array(
|
||||
self._printer.get_config_section("bed_mesh")['zero_reference_position'])
|
||||
if "probe" not in functions:
|
||||
# This is used to do a manual bed mesh if there is no probe
|
||||
self._add_button("Bed mesh", "mesh", pobox)
|
||||
functions.append("mesh")
|
||||
if "DELTA_CALIBRATE" in self._printer.available_commands:
|
||||
if "probe" in functions:
|
||||
self._add_button("Delta Automatic", "delta", pobox)
|
||||
functions.append("delta")
|
||||
# Since probes may not be accturate enough for deltas, always show the manual method
|
||||
self._add_button("Delta Manual", "delta_manual", pobox)
|
||||
functions.append("delta_manual")
|
||||
|
||||
self.labels['popover'].add(pobox)
|
||||
if len(functions) > 1:
|
||||
self.buttons['start'].connect("clicked", self.on_popover_clicked)
|
||||
else:
|
||||
self.buttons['start'].connect("clicked", self.start_calibration, functions[0])
|
||||
logging.info(f"Available functions for calibration: {functions}")
|
||||
|
||||
@staticmethod
|
||||
def _csv_to_array(string):
|
||||
return [float(i.strip()) for i in string.split(',')]
|
||||
|
||||
def _add_button(self, label, method, pobox):
|
||||
popover_button = self._gtk.Button(label=label)
|
||||
popover_button.connect("clicked", self.start_calibration, method)
|
||||
@ -127,7 +153,7 @@ class Panel(ScreenPanel):
|
||||
else:
|
||||
self._screen._ws.klippy.gcode_script("BED_MESH_CLEAR")
|
||||
if method == "probe":
|
||||
self._move_to_position()
|
||||
self._move_to_position(*self._get_probe_location())
|
||||
self._screen._ws.klippy.gcode_script("PROBE_CALIBRATE")
|
||||
elif method == "delta":
|
||||
self._screen._ws.klippy.gcode_script("DELTA_CALIBRATE")
|
||||
@ -136,79 +162,61 @@ class Panel(ScreenPanel):
|
||||
elif method == "endstop":
|
||||
self._screen._ws.klippy.gcode_script("Z_ENDSTOP_CALIBRATE")
|
||||
|
||||
def _move_to_position(self):
|
||||
x_position = y_position = None
|
||||
z_hop = speed = None
|
||||
# Get position from config
|
||||
def _move_to_position(self, x, y):
|
||||
if not x or not y:
|
||||
self._screen.show_popup_message(_("Error: Couldn't get a position to probe"))
|
||||
return
|
||||
logging.info(f"Lifting Z: {self.z_hop}mm {self.z_hop_speed}mm/s")
|
||||
self._screen._ws.klippy.gcode_script(f"G91\nG0 Z{self.z_hop} F{self.z_hop_speed * 60}")
|
||||
logging.info(f"Moving to X:{x} Y:{y}")
|
||||
self._screen._ws.klippy.gcode_script(f'G90\nG0 X{x} Y{y} F3000')
|
||||
|
||||
def _get_probe_location(self):
|
||||
if self.ks_printer_cfg is not None:
|
||||
x_position = self.ks_printer_cfg.getfloat("calibrate_x_position", None)
|
||||
y_position = self.ks_printer_cfg.getfloat("calibrate_y_position", None)
|
||||
x = self.ks_printer_cfg.getfloat("calibrate_x_position", None)
|
||||
y = self.ks_printer_cfg.getfloat("calibrate_y_position", None)
|
||||
if x and y:
|
||||
logging.debug(f"Using KS configured position: {x}, {y}")
|
||||
return x, y
|
||||
|
||||
if self.probe:
|
||||
if "sample_retract_dist" in self.probe:
|
||||
z_hop = self.probe['sample_retract_dist']
|
||||
if "speed" in self.probe:
|
||||
speed = self.probe['speed']
|
||||
if self.zero_ref:
|
||||
logging.debug(f"Using zero reference position: {self.zero_ref}")
|
||||
return self.zero_ref[0] - self.x_offset, self.zero_ref[1] - self.y_offset
|
||||
|
||||
# Use safe_z_home position
|
||||
if ("safe_z_home" in self._printer.get_config_section_list() and
|
||||
"Z_ENDSTOP_CALIBRATE" not in self._printer.available_commands):
|
||||
safe_z = self._printer.get_config_section("safe_z_home")
|
||||
safe_z_xy = safe_z['home_xy_position']
|
||||
safe_z_xy = [str(i.strip()) for i in safe_z_xy.split(',')]
|
||||
if x_position is None:
|
||||
x_position = float(safe_z_xy[0])
|
||||
logging.debug(f"Using safe_z x:{x_position}")
|
||||
if y_position is None:
|
||||
y_position = float(safe_z_xy[1])
|
||||
logging.debug(f"Using safe_z y:{y_position}")
|
||||
if 'z_hop' in safe_z:
|
||||
z_hop = safe_z['z_hop']
|
||||
if 'z_hop_speed' in safe_z:
|
||||
speed = safe_z['z_hop_speed']
|
||||
|
||||
speed = 15 if speed is None else speed
|
||||
z_hop = 5 if z_hop is None else z_hop
|
||||
self._screen._ws.klippy.gcode_script(f"G91\nG0 Z{z_hop} F{float(speed) * 60}")
|
||||
if self._printer.get_stat("gcode_move", "absolute_coordinates"):
|
||||
self._screen._ws.klippy.gcode_script("G90")
|
||||
|
||||
if x_position is not None and y_position is not None:
|
||||
logging.debug(f"Configured probing position X: {x_position} Y: {y_position}")
|
||||
self._screen._ws.klippy.gcode_script(f'G0 X{x_position} Y{y_position} F3000')
|
||||
elif "delta" in self._printer.get_config_section("printer")['kinematics']:
|
||||
return self._get_safe_z()
|
||||
if "delta" in self._printer.get_config_section("printer")['kinematics']:
|
||||
logging.info("Detected delta kinematics calibrating at 0,0")
|
||||
self._screen._ws.klippy.gcode_script('G0 X0 Y0 F3000')
|
||||
else:
|
||||
self._calculate_position()
|
||||
return 0 - self.x_offset, 0 - self.y_offset
|
||||
|
||||
x, y = self._calculate_position()
|
||||
return x, y
|
||||
|
||||
def _get_safe_z(self):
|
||||
safe_z = self._printer.get_config_section("safe_z_home")
|
||||
safe_z_xy = self._csv_to_array(safe_z['home_xy_position'])
|
||||
logging.debug(f"Using safe_z {safe_z_xy[0]}, {safe_z_xy[1]}")
|
||||
if 'z_hop' in safe_z:
|
||||
self.z_hop = float(safe_z['z_hop'])
|
||||
if 'z_hop_speed' in safe_z:
|
||||
self.z_hop_speed = float(safe_z['z_hop_speed'])
|
||||
return safe_z_xy[0], safe_z_xy[1]
|
||||
|
||||
def _calculate_position(self):
|
||||
logging.debug("Position not configured, probing the middle of the bed")
|
||||
if self.mesh_max and self.mesh_min:
|
||||
mesh_mid_x = (self.mesh_min[0] + self.mesh_max[0]) / 2
|
||||
mesh_mid_y = (self.mesh_min[1] + self.mesh_max[1]) / 2
|
||||
logging.debug(f"Probe in the mesh center X:{mesh_mid_x} Y:{mesh_mid_y}")
|
||||
return mesh_mid_x - self.x_offset, mesh_mid_y - self.y_offset
|
||||
try:
|
||||
xmax = float(self._printer.get_config_section("stepper_x")['position_max'])
|
||||
ymax = float(self._printer.get_config_section("stepper_y")['position_max'])
|
||||
mid_x = float(self._printer.get_config_section("stepper_x")['position_max']) / 2
|
||||
mid_y = float(self._printer.get_config_section("stepper_y")['position_max']) / 2
|
||||
except KeyError:
|
||||
logging.error("Couldn't get max position from stepper_x and stepper_y")
|
||||
return
|
||||
x_position = xmax / 2
|
||||
y_position = ymax / 2
|
||||
logging.info(f"Center position X:{x_position} Y:{y_position}")
|
||||
|
||||
# Find probe offset
|
||||
x_offset = y_offset = None
|
||||
if self.probe:
|
||||
if "x_offset" in self.probe:
|
||||
x_offset = float(self.probe['x_offset'])
|
||||
if "y_offset" in self.probe:
|
||||
y_offset = float(self.probe['y_offset'])
|
||||
logging.info(f"Offset X:{x_offset} Y:{y_offset}")
|
||||
if x_offset is not None:
|
||||
x_position = x_position - x_offset
|
||||
if y_offset is not None:
|
||||
y_position = y_position - y_offset
|
||||
|
||||
logging.info(f"Moving to X:{x_position} Y:{y_position}")
|
||||
self._screen._ws.klippy.gcode_script(f'G0 X{x_position} Y{y_position} F3000')
|
||||
return None, None
|
||||
logging.debug(f"Probe in the center X:{mid_x} Y:{mid_y}")
|
||||
return mid_x - self.x_offset, mid_y - self.y_offset
|
||||
|
||||
def activate(self):
|
||||
if self._printer.get_stat("manual_probe", "is_active"):
|
||||
@ -238,8 +246,7 @@ class Panel(ScreenPanel):
|
||||
|
||||
def update_position(self, position):
|
||||
self.widgets['zposition'].set_text(f"Z: {position[2]:.3f}")
|
||||
if self.z_offset is not None:
|
||||
self.widgets['zoffset'].set_text(f"{abs(position[2] - self.z_offset):.3f}")
|
||||
self.widgets['zoffset'].set_text(f"{abs(position[2] - self.z_offset):.3f}")
|
||||
|
||||
def change_distance(self, widget, distance):
|
||||
logging.info(f"### Distance {distance}")
|
||||
|
Loading…
x
Reference in New Issue
Block a user