[axis_twist_compensation] produces zero visible effect on bed mesh output regardless of the configured z_compensations values.
Observed behaviour is that even with extreme z_compensation values of 1,0,-1 and -1,0,1 the bed mesh results are near identical:
#*# [bed_mesh twist_a]
#*# version = 1
#*# points =
#*# 0.260111, 0.200111, 0.150111, 0.140111, 0.130111, 0.120111, 0.090111, 0.100111, 0.140111, 0.200111, 0.250111
#*# 0.250111, 0.160111, 0.140111, 0.120111, 0.100111, 0.080111, 0.080111, 0.090111, 0.100111, 0.150111, 0.190111
#*# 0.260111, 0.170111, 0.130111, 0.100111, 0.090111, 0.090111, 0.040111, 0.060111, 0.060111, 0.090111, 0.160111
#*# 0.230111, 0.160111, 0.100111, 0.070111, 0.060111, 0.040111, 0.040111, 0.030111, 0.050111, 0.090111, 0.150111
#*# 0.230111, 0.140111, 0.090111, 0.060111, 0.040111, 0.000111, -0.019889, 0.020111, 0.040111, 0.060111, 0.120111
#*# 0.220111, 0.120111, 0.090111, 0.050111, 0.000111, 0.000111, -0.009889, 0.040111, 0.050111, 0.070111, 0.130111
#*# 0.200111, 0.150111, 0.130111, 0.050111, 0.020111, -0.009889, -0.029889, -0.009889, 0.050111, 0.060111, 0.130111
#*# 0.240111, 0.130111, 0.070111, 0.040111, 0.040111, 0.020111, 0.030111, 0.040111, 0.070111, 0.090111, 0.140111
#*# 0.250111, 0.160111, 0.100111, 0.060111, 0.050111, 0.040111, 0.030111, 0.050111, 0.070111, 0.100111, 0.170111
#*# 0.260111, 0.150111, 0.080111, 0.080111, 0.060111, 0.060111, 0.060111, 0.090111, 0.090111, 0.130111, 0.200111
#*# 0.330111, 0.240111, 0.140111, 0.130111, 0.120111, 0.100111, 0.080111, 0.140111, 0.160111, 0.190111, 0.260111
#*# x_count = 11
#*# y_count = 11
#*# mesh_x_pps = 2
#*# mesh_y_pps = 2
#*# algo = bicubic
#*# tension = 0.2
#*# min_x = 5.0
#*# max_x = 218.0
#*# min_y = 10.0
#*# max_y = 210.0
#*#
#*# [bed_mesh twist_b]
#*# version = 1
#*# points =
#*# 0.279639, 0.209639, 0.169639, 0.149639, 0.149639, 0.139639, 0.099639, 0.119639, 0.159639, 0.209639, 0.269639
#*# 0.269639, 0.179639, 0.149639, 0.129639, 0.119639, 0.089639, 0.089639, 0.099639, 0.109639, 0.159639, 0.209639
#*# 0.259639, 0.179639, 0.139639, 0.099639, 0.099639, 0.069639, 0.059639, 0.069639, 0.069639, 0.089639, 0.179639
#*# 0.239639, 0.149639, 0.099639, 0.079639, 0.049639, 0.049639, 0.039639, 0.049639, 0.059639, 0.099639, 0.149639
#*# 0.229639, 0.149639, 0.089639, 0.069639, 0.049639, 0.009639, -0.010361, 0.009639, 0.039639, 0.069639, 0.129639
#*# 0.209639, 0.149639, 0.099639, 0.059639, 0.029639, -0.000361, -0.000361, 0.039639, 0.059639, 0.079639, 0.129639
#*# 0.209639, 0.179639, 0.129639, 0.069639, 0.039639, 0.039639, -0.020361, 0.009639, 0.059639, 0.069639, 0.149639
#*# 0.239639, 0.149639, 0.079639, 0.049639, 0.039639, 0.029639, 0.049639, 0.049639, 0.079639, 0.099639, 0.149639
#*# 0.259639, 0.169639, 0.089639, 0.069639, 0.069639, 0.049639, 0.039639, 0.059639, 0.079639, 0.099639, 0.179639
#*# 0.269639, 0.149639, 0.099639, 0.079639, 0.069639, 0.069639, 0.069639, 0.109639, 0.099639, 0.139639, 0.199639
#*# 0.339639, 0.229639, 0.149639, 0.139639, 0.119639, 0.099639, 0.089639, 0.139639, 0.169639, 0.189639, 0.269639
#*# x_count = 11
#*# y_count = 11
#*# mesh_x_pps = 2
#*# mesh_y_pps = 2
#*# algo = bicubic
#*# tension = 0.2
#*# min_x = 5.0
#*# max_x = 218.0
#*# min_y = 10.0
#*# max_y = 210.0
axis_twist_compensation's event handler applies the correction by replacing the list element, not by mutating the tuple in place (since it can't):
This only works if the caller re-reads the corrected value back out of that same list. However, every probing function in BDsensor.py builds a throwaway list, passes it to the event, and then keeps using the original (pre-event) local variable:
epos never gets reassigned from the list that was passed to send_event, so the compensation computed by axis_twist_compensation is silently thrown away every time. This pattern appears in at least:
Additionally, scan_sample_event (used when no_stop_probe is set) never calls the event at all — it's commented out:
Configure [axis_twist_compensation] with a clearly nonzero z_compensations (e.g. 1, 0, -1) spanning the bed's X range.
Run BED_MESH_CALIBRATE twice — once with those values, once with the sign flipped (e.g. -1, 0, 1) — with a full FIRMWARE_RESTART and SAVE_CONFIG between runs.
Compare the two [bed_mesh] outputs.
The two meshes should differ by roughly the shape of the compensation ramp — up to several mm at the X extremes for a 1mm-magnitude z_compensations array, tapering to ~0 near the center of the calibrated range.
The two meshes are nearly identical (sub-0.02mm differences, consistent with ordinary probe repeatability noise), with no correlation to X position, in both the no_stop_probe (rapid scan) and normal stop-and-probe modes.
Re-read the corrected value from the list passed to send_event in each affected function, e.g.:
And uncomment the equivalent call in scan_sample_event, applying the same fix there.
[axis_twist_compensation] produces zero visible effect on bed mesh output regardless of the configured z_compensations values.
Observed behaviour is that even with extreme z_compensation values of 1,0,-1 and -1,0,1 the bed mesh results are near identical:
LLM generated diagnosis below which may or may not be accurate:
Root cause: manual_probe.ProbeResult is an immutable namedtuple:
axis_twist_compensation's event handler applies the correction by replacing the list element, not by mutating the tuple in place (since it can't):
This only works if the caller re-reads the corrected value back out of that same list. However, every probing function in BDsensor.py builds a throwaway list, passes it to the event, and then keeps using the original (pre-event) local variable:
epos never gets reassigned from the list that was passed to send_event, so the compensation computed by axis_twist_compensation is silently thrown away every time. This pattern appears in at least:
BDPrinterProbe._probe
BDPrinterProbe._probe_external_endstop
The BED_MESH_CALIBRATE / QUAD_GANTRY_LEVEL / Z_TILT_ADJUST inline branch in run_probe
Additionally, scan_sample_event (used when no_stop_probe is set) never calls the event at all — it's commented out:
To Reproduce
Configure [axis_twist_compensation] with a clearly nonzero z_compensations (e.g. 1, 0, -1) spanning the bed's X range.
Run BED_MESH_CALIBRATE twice — once with those values, once with the sign flipped (e.g. -1, 0, 1) — with a full FIRMWARE_RESTART and SAVE_CONFIG between runs.
Compare the two [bed_mesh] outputs.
Expected behavior
The two meshes should differ by roughly the shape of the compensation ramp — up to several mm at the X extremes for a 1mm-magnitude z_compensations array, tapering to ~0 near the center of the calibrated range.
Actual behavior
The two meshes are nearly identical (sub-0.02mm differences, consistent with ordinary probe repeatability noise), with no correlation to X position, in both the no_stop_probe (rapid scan) and normal stop-and-probe modes.
Suggested fix
Re-read the corrected value from the list passed to send_event in each affected function, e.g.:
And uncomment the equivalent call in scan_sample_event, applying the same fix there.
Environment
Klipper version: v0.13.0-743-gac2a7f8b
BDsensor.py commit: v0.0.0-556-g087257f0-inferred
Config: [BDsensor] x_offset: 0, y_offset: 10