@@ -91,12 +91,19 @@ def _callback_motor_status(self, data):
9191 nSteppers = len (data ["steppers" ])
9292 stepSizes = np .array ((self .stepSizeA , self .stepSizeX , self .stepSizeY , self .stepSizeZ ))
9393 for iMotor in range (nSteppers ):
94- stepperID = data ["steppers" ][iMotor ]["stepperid" ]
94+ stepper = data ["steppers" ][iMotor ]
95+ # Intermediate status frames during a move carry only
96+ # {stepperid, isDone} with no "position" key — skip them instead
97+ # of raising KeyError 'position' (which previously aborted the
98+ # whole callback and left currentPosition stale).
99+ if "position" not in stepper :
100+ continue
101+ stepperID = stepper ["stepperid" ]
95102 # Hardware returns raw steps in firmware frame; convert to physical units
96103 # in user frame: phys = hw_steps * stepSize * direction. The direction sign
97104 # hides any wiring polarity flip from the caller.
98105 self .currentPosition [stepperID ] = (
99- data [ "steppers" ][ iMotor ] ["position" ]
106+ stepper ["position" ]
100107 * stepSizes [stepperID ]
101108 * self .direction [stepperID ]
102109 )
@@ -333,6 +340,26 @@ def setup_motor(self, axis, minPos, maxPos, stepSize, backlash, direction=None):
333340 self .stepSizeA = stepSize
334341 self .backlash [axisIdx ] = backlash
335342
343+ def set_backlash (self , axis , backlash ):
344+ """Set the per-axis backlash (in hardware steps) used as a reversal overshoot.
345+
346+ ``axis`` may be a name (\" X\" /\" Y\" /\" Z\" /\" A\" ) or a hardware index (0-3).
347+ The value is stored in :attr:`backlash` and consumed by
348+ :meth:`move_stepper`, which adds ``direction * backlash`` extra steps
349+ whenever the axis changes direction, taking up the mechanical slack so the
350+ stage still reaches the commanded target. Pass ``0`` to disable
351+ compensation for that axis. Typically fed from a camera-based backlash
352+ measurement (microns) after converting to steps with the axis step size.
353+ """
354+ idx = self .xyztTo1230 (axis ) if isinstance (axis , str ) else int (axis )
355+ self .backlash [idx ] = backlash
356+ return float (self .backlash [idx ])
357+
358+ def get_backlash (self , axis ):
359+ """Return the per-axis backlash (in hardware steps)."""
360+ idx = self .xyztTo1230 (axis ) if isinstance (axis , str ) else int (axis )
361+ return float (self .backlash [idx ])
362+
336363 def xyztTo1230 (self , axis ):
337364 axis = axis .upper ()
338365 if axis == "X" :
@@ -705,7 +732,7 @@ def move_stepper(self, steps=(0,0,0,0), speed=(1000,1000,1000,1000), is_absolute
705732 motorProp ["acceleration" ] = int (acceleration [iMotor ])
706733 else :
707734 motorProp ["accel" ] = self .DEFAULT_ACCELERATION
708- motorProp ["acceleleration " ] = self .DEFAULT_ACCELERATION
735+ motorProp ["acceleration " ] = self .DEFAULT_ACCELERATION
709736 motorPropList .append (motorProp )
710737 if len (motorPropList )== 0 :
711738 return "{'return':-1}"
0 commit comments