probe: Convert ProbePointsHelper to use ProbeResult

Change the ProbePointsHelper class to return ProbeResult tuples.
Callers of this class are also updated so that they use the tuple's
bed_xyz parameters instead of manually calculating these values from
the probe xyz offsets.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2025-12-21 12:28:36 -05:00
parent 9ccb4d96e9
commit 2e0c2262e7
8 changed files with 58 additions and 50 deletions

View file

@ -8,9 +8,17 @@ All dates in this document are approximate.
## Changes
20251122: An option `axis` has been added to `[carriage <name>]` sections
for `generic_cartesian` kinematics, allowing arbitrary names for primary
carriages. Users are encouraged to explicitly specify `axis` option now.
20260109: The `[screws_tilt_adjust]` module now reports the status
variable `{printer.screws_tilt_adjust.result.screw1.z}` with the
probe's `z_offset` applied. That is, one would previously need to
subtract the probe's configured `z_offset` to find the absolute Z
deviation at the given screw location and now one must not apply the
`z_offset`.
20251122: An option `axis` has been added to `[carriage <name>]`
sections for `generic_cartesian` kinematics, allowing arbitrary names
for primary carriages. Users are encouraged to explicitly specify
`axis` option now.
20251106: The status fields `{printer.toolhead.position}`,
`{printer.gcode_move.position}`,

View file

@ -651,9 +651,9 @@ class BedMeshCalibrate:
except BedMeshError as e:
raise gcmd.error(str(e))
self.probe_mgr.start_probe(gcmd)
def probe_finalize(self, offsets, positions):
z_offset = offsets[2]
positions = [[round(p[0], 2), round(p[1], 2), p[2]]
def probe_finalize(self, positions):
z_offset = 0.
positions = [[round(p.bed_x, 2), round(p.bed_y, 2), p.bed_z]
for p in positions]
if self.probe_mgr.get_zero_ref_mode() == ZrefMode.PROBE:
ref_pos = positions.pop()
@ -682,7 +682,7 @@ class BedMeshCalibrate:
idx_offset = 0
start_idx = 0
for i, pts in substitutes.items():
fpt = [p - o for p, o in zip(base_points[i], offsets[:2])]
fpt = base_points[i][:2]
# offset the index to account for additional samples
idx = i + idx_offset
# Add "normal" points
@ -702,7 +702,7 @@ class BedMeshCalibrate:
# validate length of result
if len(base_points) != len(positions):
self._dump_points(probed_pts, positions, offsets)
self._dump_points(probed_pts, positions)
raise self.gcode.error(
"bed_mesh: invalid position list size, "
"generated count: %d, probed count: %d"
@ -713,7 +713,7 @@ class BedMeshCalibrate:
row = []
prev_pos = base_points[0]
for pos, result in zip(base_points, positions):
offset_pos = [p - o for p, o in zip(pos, offsets[:2])]
offset_pos = pos[:2]
if (
not isclose(offset_pos[0], result[0], abs_tol=.5) or
not isclose(offset_pos[1], result[1], abs_tol=.5)
@ -786,7 +786,7 @@ class BedMeshCalibrate:
self.gcode.respond_info("Mesh Bed Leveling Complete")
if self._profile_name is not None:
self.bedmesh.save_profile(self._profile_name)
def _dump_points(self, probed_pts, corrected_pts, offsets):
def _dump_points(self, probed_pts, corrected_pts):
# logs generated points with offset applied, points received
# from the finalize callback, and the list of corrected points
points = self.probe_mgr.get_base_points()
@ -797,7 +797,7 @@ class BedMeshCalibrate:
for i in list(range(max_len)):
gen_pt = probed_pt = corr_pt = ""
if i < len(points):
off_pt = [p - o for p, o in zip(points[i], offsets[:2])]
off_pt = points[i][:2]
gen_pt = "(%.2f, %.2f)" % tuple(off_pt)
if i < len(probed_pts):
probed_pt = "(%.2f, %.2f, %.4f)" % tuple(probed_pts[i])
@ -1220,8 +1220,12 @@ class RapidScanHelper:
if is_probe_pt:
probe_session.run_probe(gcmd)
results = probe_session.pull_probed_results()
import manual_probe # XXX
results = [manual_probe.ProbeResult(
r[0]+offsets[0], r[1]+offsets[1], r[2]-offsets[2], r[0], r[1], r[2])
for r in results]
toolhead.get_last_move_time()
self.finalize_callback(offsets, results)
self.finalize_callback(results)
probe_session.end_probe_session()
def _raise_tool(self, gcmd, scan_height):

View file

@ -58,19 +58,17 @@ class BedTiltCalibrate:
cmd_BED_TILT_CALIBRATE_help = "Bed tilt calibration script"
def cmd_BED_TILT_CALIBRATE(self, gcmd):
self.probe_helper.start_probe(gcmd)
def probe_finalize(self, offsets, positions):
def probe_finalize(self, positions):
# Setup for coordinate descent analysis
z_offset = offsets[2]
logging.info("Calculating bed_tilt with: %s", positions)
params = { 'x_adjust': self.bedtilt.x_adjust,
'y_adjust': self.bedtilt.y_adjust,
'z_adjust': z_offset }
'z_adjust': 0. }
logging.info("Initial bed_tilt parameters: %s", params)
# Perform coordinate descent
def adjusted_height(pos, params):
x, y, z = pos
return (z - x*params['x_adjust'] - y*params['y_adjust']
- params['z_adjust'])
return (pos.bed_z - pos.bed_x*params['x_adjust']
- pos.bed_y*params['y_adjust'] - params['z_adjust'])
def errorfunc(params):
total_error = 0.
for pos in positions:
@ -81,8 +79,7 @@ class BedTiltCalibrate:
# Update current bed_tilt calculations
x_adjust = new_params['x_adjust']
y_adjust = new_params['y_adjust']
z_adjust = (new_params['z_adjust'] - z_offset
- x_adjust * offsets[0] - y_adjust * offsets[1])
z_adjust = new_params['z_adjust']
self.bedtilt.update_adjust(x_adjust, y_adjust, z_adjust)
# Log and report results
logging.info("Calculated bed_tilt parameters: %s", new_params)

View file

@ -152,12 +152,12 @@ class DeltaCalibrate:
"%.3f,%.3f,%.3f" % tuple(spos1))
configfile.set(section, "distance%d_pos2" % (i,),
"%.3f,%.3f,%.3f" % tuple(spos2))
def probe_finalize(self, offsets, positions):
def probe_finalize(self, positions):
# Convert positions into (z_offset, stable_position) pairs
z_offset = offsets[2]
kin = self.printer.lookup_object('toolhead').get_kinematics()
delta_params = kin.get_calibration()
probe_positions = [(z_offset, delta_params.calc_stable_position(p))
csp = kin.get_calibration().calc_stable_position
probe_positions = [(p.test_z - p.bed_z,
csp([p.test_x, p.test_y, p.test_z]))
for p in positions]
# Perform analysis
self.calculate_params(probe_positions, self.last_distances)

View file

@ -466,7 +466,7 @@ class ProbePointsHelper:
toolhead = self.printer.lookup_object('toolhead')
toolhead.get_last_move_time()
# Invoke callback
res = self.finalize_callback(self.probe_offsets, results)
res = self.finalize_callback(results)
return res != "retry"
def _move_next(self, probe_num):
# Move to next XY probe point
@ -502,6 +502,10 @@ class ProbePointsHelper:
self._raise_tool(not probe_num)
if probe_num >= len(self.probe_points):
results = probe_session.pull_probed_results()
results = [manual_probe.ProbeResult(
r[0] + self.probe_offsets[0], r[1] + self.probe_offsets[1],
r[2] - self.probe_offsets[2], r[0], r[1], r[2])
for r in results]
done = self._invoke_callback(results)
if done:
break
@ -514,9 +518,7 @@ class ProbePointsHelper:
def _manual_probe_start(self):
self._raise_tool(not self.manual_results)
if len(self.manual_results) >= len(self.probe_points):
results = [[mpr.bed_x, mpr.bed_y, mpr.bed_z]
for mpr in self.manual_results]
done = self._invoke_callback(results)
done = self._invoke_callback(self.manual_results)
if done:
return
# Caller wants a "retry" - clear results and restart probing

View file

@ -51,34 +51,34 @@ class QuadGantryLevel:
self.z_status.reset()
self.retry_helper.start(gcmd)
self.probe_helper.start_probe(gcmd)
def probe_finalize(self, offsets, positions):
def probe_finalize(self, positions):
# Mirror our perspective so the adjustments make sense
# from the perspective of the gantry
z_positions = [self.horizontal_move_z - p[2] for p in positions]
z_positions = [self.horizontal_move_z - p.bed_z for p in positions]
points_message = "Gantry-relative probe points:\n%s\n" % (
" ".join(["%s: %.6f" % (z_id, z_positions[z_id])
for z_id in range(len(z_positions))]))
self.gcode.respond_info(points_message)
# Calculate slope along X axis between probe point 0 and 3
ppx0 = [positions[0][0] + offsets[0], z_positions[0]]
ppx3 = [positions[3][0] + offsets[0], z_positions[3]]
ppx0 = [positions[0].bed_x, z_positions[0]]
ppx3 = [positions[3].bed_x, z_positions[3]]
slope_x_pp03 = self.linefit(ppx0, ppx3)
# Calculate slope along X axis between probe point 1 and 2
ppx1 = [positions[1][0] + offsets[0], z_positions[1]]
ppx2 = [positions[2][0] + offsets[0], z_positions[2]]
ppx1 = [positions[1].bed_x, z_positions[1]]
ppx2 = [positions[2].bed_x, z_positions[2]]
slope_x_pp12 = self.linefit(ppx1, ppx2)
logging.info("quad_gantry_level f1: %s, f2: %s"
% (slope_x_pp03, slope_x_pp12))
# Calculate gantry slope along Y axis between stepper 0 and 1
a1 = [positions[0][1] + offsets[1],
a1 = [positions[0].bed_y,
self.plot(slope_x_pp03, self.gantry_corners[0][0])]
a2 = [positions[1][1] + offsets[1],
a2 = [positions[1].bed_y,
self.plot(slope_x_pp12, self.gantry_corners[0][0])]
slope_y_s01 = self.linefit(a1, a2)
# Calculate gantry slope along Y axis between stepper 2 and 3
b1 = [positions[0][1] + offsets[1],
b1 = [positions[0].bed_y,
self.plot(slope_x_pp03, self.gantry_corners[1][0])]
b2 = [positions[1][1] + offsets[1],
b2 = [positions[1].bed_y,
self.plot(slope_x_pp12, self.gantry_corners[1][0])]
slope_y_s23 = self.linefit(b1, b2)
logging.info("quad_gantry_level af: %s, bf: %s"

View file

@ -63,7 +63,7 @@ class ScrewsTiltAdjust:
'max_deviation': self.max_diff,
'results': self.results}
def probe_finalize(self, offsets, positions):
def probe_finalize(self, positions):
self.results = {}
self.max_diff_error = False
# Factors used for CW-M3, CCW-M3, CW-M4, CCW-M4, CW-M5, CCW-M5, CW-M6
@ -79,15 +79,15 @@ class ScrewsTiltAdjust:
or (not is_clockwise_thread and self.direction == 'CCW'))
min_or_max = max if use_max else min
i_base, z_base = min_or_max(
enumerate([pos[2] for pos in positions]), key=lambda v: v[1])
enumerate([pos.bed_z for pos in positions]), key=lambda v: v[1])
else:
# First screw is the base position used for comparison
i_base, z_base = 0, positions[0][2]
i_base, z_base = 0, positions[0].bed_z
# Provide the user some information on how to read the results
self.gcode.respond_info("01:20 means 1 full turn and 20 minutes, "
"CW=clockwise, CCW=counter-clockwise")
for i, screw in enumerate(self.screws):
z = positions[i][2]
z = positions[i].bed_z
coord, name = screw
if i == i_base:
# Show the results

View file

@ -143,16 +143,14 @@ class ZTilt:
self.z_status.reset()
self.retry_helper.start(gcmd)
self.probe_helper.start_probe(gcmd)
def probe_finalize(self, offsets, positions):
def probe_finalize(self, positions):
# Setup for coordinate descent analysis
z_offset = offsets[2]
logging.info("Calculating bed tilt with: %s", positions)
params = { 'x_adjust': 0., 'y_adjust': 0., 'z_adjust': z_offset }
params = { 'x_adjust': 0., 'y_adjust': 0., 'z_adjust': 0. }
# Perform coordinate descent
def adjusted_height(pos, params):
x, y, z = pos
return (z - x*params['x_adjust'] - y*params['y_adjust']
- params['z_adjust'])
return (pos.bed_z - pos.bed_x*params['x_adjust']
- pos.bed_y*params['y_adjust'] - params['z_adjust'])
def errorfunc(params):
total_error = 0.
for pos in positions:
@ -165,8 +163,7 @@ class ZTilt:
logging.info("Calculated bed tilt parameters: %s", new_params)
x_adjust = new_params['x_adjust']
y_adjust = new_params['y_adjust']
z_adjust = (new_params['z_adjust'] - z_offset
- x_adjust * offsets[0] - y_adjust * offsets[1])
z_adjust = new_params['z_adjust']
adjustments = [x*x_adjust + y*y_adjust + z_adjust
for x, y in self.z_positions]
self.z_helper.adjust_steppers(adjustments, speed)