INDX support was added in #904. This concerns IndxDockMeasurement.measure()
in klippy/extras/indx/toolboard.py.
Environment
- Kalico v2026.08.00-1-gae261624f
- BTT Octopus Pro v1.1 (STM32H723), Voron Trident 350, CoreXY
- X: physical endstop. Y: sensorless (TMC2240, StallGuard2 via
driver_SGT)
- 6-tool INDX, docks mounted at the front of the machine
Problem
Repeating CALIBRATE_DOCK_X / INDX_DOCK_MEASURE on the same dock, without
moving anything, returned X values scattered over 0.4–1.0 mm:
344.994 345.000 345.195 345.366 345.412 345.591
345.768 345.780 345.865 345.975 345.981 345.999
The INDX docks need roughly 0.2 mm, so this is not usable.
Cause
measure() homes every requested axis first and computes the start position
once, at the end, from the final kinematic state:
kin.home(homing_state) # all requested axes
final_position = toolhead.get_position()
kinematic_position_after = self._get_kinematic_position(kin)
start_position = [final + before - after for ...]
_get_kinematic_position() is derived from stepper.get_mcu_position(), i.e.
commanded steps. Sensorless homing ends by driving the gantry into a hard
stop, so some steps are physically lost. On CoreXY a loss on one motor shifts
X, because X = (a + b) / 2. The Y homing therefore corrupts the measured X.
X_FIRST=1 does not help. It only reorders the homing moves; the single
calculation still happens after every axis has homed.
Suggested fix
Home one axis at a time and settle that axis's start position immediately,
before the next axis moves:
start_position = [0.0, 0.0]
for axis in axes:
homing_state = Homing(self.printer)
homing_state.set_axes([axis])
kin.home(homing_state)
final_position = toolhead.get_position()
kinematic_position_after = self._get_kinematic_position(kin)
start_position[axis] = (
final_position[axis]
+ kinematic_position_before[axis]
- kinematic_position_after[axis]
)
With this change plus X_FIRST=1, the X result is settled while the machine
has only ever homed X against its physical switch.
Result
Same dock, same procedure, after the change:
345.195 345.195 345.195 345.195 (identical to 3 decimals)
Measuring the five other docks gave spreads of 0.02–0.23 mm.
Sanity check: deliberately parking 20–30 mm away from the dock returns
306.963, so the command is reading the real position and not a cached one.
Related, lower priority
On a machine where the toolhead is hand-placed into the dock, the dock-holding
axis cannot be homed first without dragging the tool sideways out of the dock.
A parameter to retreat along +Y under motor control before homing would make
X_FIRST=1 usable on such setups — moving the gantry by hand instead does not
work, because it disturbs X. I added a local RETREAT=<mm> for this, but I
suspect you would want to implement it differently: passing
homing_axes=(0, 1) to toolhead.set_position() failed here with
"Must home axis first", so I ended up calling Klipper's own
SET_KINEMATIC_POSITION via run_script_from_command().
INDX support was added in #904. This concerns
IndxDockMeasurement.measure()in
klippy/extras/indx/toolboard.py.Environment
driver_SGT)Problem
Repeating
CALIBRATE_DOCK_X/INDX_DOCK_MEASUREon the same dock, withoutmoving anything, returned X values scattered over 0.4–1.0 mm:
The INDX docks need roughly 0.2 mm, so this is not usable.
Cause
measure()homes every requested axis first and computes the start positiononce, at the end, from the final kinematic state:
_get_kinematic_position()is derived fromstepper.get_mcu_position(), i.e.commanded steps. Sensorless homing ends by driving the gantry into a hard
stop, so some steps are physically lost. On CoreXY a loss on one motor shifts
X, because X = (a + b) / 2. The Y homing therefore corrupts the measured X.
X_FIRST=1does not help. It only reorders the homing moves; the singlecalculation still happens after every axis has homed.
Suggested fix
Home one axis at a time and settle that axis's start position immediately,
before the next axis moves:
With this change plus
X_FIRST=1, the X result is settled while the machinehas only ever homed X against its physical switch.
Result
Same dock, same procedure, after the change:
Measuring the five other docks gave spreads of 0.02–0.23 mm.
Sanity check: deliberately parking 20–30 mm away from the dock returns
306.963, so the command is reading the real position and not a cached one.Related, lower priority
On a machine where the toolhead is hand-placed into the dock, the dock-holding
axis cannot be homed first without dragging the tool sideways out of the dock.
A parameter to retreat along +Y under motor control before homing would make
X_FIRST=1usable on such setups — moving the gantry by hand instead does notwork, because it disturbs X. I added a local
RETREAT=<mm>for this, but Isuspect you would want to implement it differently: passing
homing_axes=(0, 1)totoolhead.set_position()failed here with"Must home axis first", so I ended up calling Klipper's own
SET_KINEMATIC_POSITIONviarun_script_from_command().