libstp.step.calibration.calibrate_distance ========================================== .. py:module:: libstp.step.calibration.calibrate_distance .. autoapi-nested-parse:: Distance calibration step using the new UI library. Supports two calibration modes: - Runtime calibration: Apply measured ticks_to_rad for this run (best accuracy now) - Persistent learning: Update YAML baseline using EMA (converges over multiple runs) Attributes ---------- .. autoapisummary:: libstp.step.calibration.calibrate_distance.DEFAULT_EMA_ALPHA Exceptions ---------- .. autoapisummary:: libstp.step.calibration.calibrate_distance.CalibrationRequiredError Classes ------- .. autoapisummary:: libstp.step.calibration.calibrate_distance.DistanceCalibrationResult libstp.step.calibration.calibrate_distance.PerWheelCalibration libstp.step.calibration.calibrate_distance.CalibrateDistance Functions --------- .. autoapisummary:: libstp.step.calibration.calibrate_distance.is_distance_calibrated libstp.step.calibration.calibrate_distance.check_distance_calibration libstp.step.calibration.calibrate_distance.reset_distance_calibration libstp.step.calibration.calibrate_distance.calibrate_distance Module Contents --------------- .. py:data:: DEFAULT_EMA_ALPHA :value: 0.7 .. py:exception:: CalibrationRequiredError Bases: :py:obj:`Exception` Raised when an operation requires calibration but none has been performed. .. py:function:: is_distance_calibrated() -> bool Check if distance calibration has been performed. .. py:function:: check_distance_calibration() -> None Log a warning when distance calibration has not been performed yet. .. py:function:: reset_distance_calibration() -> None Reset the calibration flag (for testing). .. py:class:: DistanceCalibrationResult Result of distance calibration. .. py:attribute:: requested_distance_cm :type: float .. py:attribute:: measured_distance_cm :type: float .. py:attribute:: scale_factor :type: float .. py:class:: PerWheelCalibration Result of per-wheel distance calibration. .. py:attribute:: motor_port :type: int .. py:attribute:: old_ticks_to_rad :type: float .. py:attribute:: new_ticks_to_rad :type: float .. py:attribute:: delta_ticks :type: int .. py:attribute:: ema_baseline :type: float :value: 0.0 .. py:attribute:: motor_name :type: Optional[str] :value: None .. py:class:: CalibrateDistance(calibration_distance_cm: float = 30.0, calibrate_light_sensors: bool = False, persist_to_yaml: bool = True, ema_alpha: float = DEFAULT_EMA_ALPHA, calibration_sets: Optional[List[str]] = None, exclude_ir_sensors: Optional[List[libstp.sensor_ir.IRSensor]] = None) Bases: :py:obj:`libstp.ui.step.UIStep` Step for calibrating robot distance estimation via per-wheel ticks_to_rad adjustment. Two calibration mechanisms: 1. Runtime: Apply the measured ticks_to_rad directly for best accuracy this run 2. Persistent: Update YAML baseline using EMA so it converges over multiple runs The EMA formula: new_baseline = old_baseline × α + measured × (1 - α) With α=0.7, after ~5 calibrations the baseline absorbs ~83% of any systematic error. .. py:attribute:: calibration_distance_cm :value: 30.0 .. py:attribute:: calibrate_light_sensors :value: False .. py:attribute:: persist_to_yaml :value: True .. py:attribute:: ema_alpha :value: 0.7 .. py:attribute:: calibration_sets :value: ['default'] .. py:attribute:: exclude_ir_sensors :type: List[libstp.sensor_ir.IRSensor] :value: [] .. py:attribute:: result :type: Optional[DistanceCalibrationResult] :value: None .. py:attribute:: per_wheel_results :type: List[PerWheelCalibration] :value: [] .. py:function:: calibrate_distance(distance_cm: float = 30.0, calibrate_light_sensors: bool = False, persist_to_yaml: bool = True, ema_alpha: float = DEFAULT_EMA_ALPHA, calibration_sets: Optional[List[str]] = None, exclude_ir_sensors: Optional[List[libstp.sensor_ir.IRSensor]] = None) -> CalibrateDistance Calibrate per-wheel distance estimation via encoder measurement. Drives the robot a known distance, then prompts the user to enter the actual measured distance. The step computes a corrected ``ticks_to_rad`` value for each drive motor so that odometry matches real-world distances. The calibration operates in two modes simultaneously: - **Runtime**: Applies the measured ``ticks_to_rad`` directly for best accuracy during this run. - **Persistent**: Updates the YAML baseline using an exponential moving average (EMA) so the stored value converges toward the true value over multiple calibration runs. The EMA formula is: ``new_baseline = old * alpha + measured * (1 - alpha)``. Convergence rates for different alpha values: - ``alpha=0.5``: ~97% of error absorbed after 5 calibrations (responsive) - ``alpha=0.7`` (default): ~83% after 5 calibrations (balanced) - ``alpha=0.9``: ~41% after 5 calibrations (very stable) Prerequisites: The robot must have drive motors with encoder feedback and a configured kinematics model providing wheel radius. :param distance_cm: Distance (in cm) the robot drives during calibration. Default is 30 cm. Longer distances yield better accuracy. :param calibrate_light_sensors: If ``True``, run IR sensor calibration after the distance calibration is confirmed. Sensors are sampled during an additional drive over calibration surfaces. :param persist_to_yaml: If ``True``, write the EMA-filtered baseline to ``raccoon.project.yml`` so it persists across program runs. :param ema_alpha: EMA smoothing coefficient between 0.0 and 1.0. Higher values produce slower convergence but a more stable baseline. :param calibration_sets: List of named IR calibration surface sets (e.g. ``["default", "transparent"]``). Only used when ``calibrate_light_sensors`` is ``True``. :param exclude_ir_sensors: List of ``IRSensor`` instances to skip during IR calibration. :returns: A step that performs the interactive distance calibration flow. :rtype: CalibrateDistance Example:: from libstp.step.calibration import calibrate_distance # Distance-only calibration with defaults seq([ calibrate_distance(), drive_forward(100), ]) # Distance + IR sensor calibration, slower EMA convergence calibrate_distance( distance_cm=50.0, calibrate_light_sensors=True, ema_alpha=0.9, calibration_sets=["default", "transparent"], )