step.motion.auto_tune¶
Auto-tune PID controllers via system identification and iterative optimization.
The full pipeline lives in C++ (raccoon.autotune.AutoTuner) so phase-to-phase
state coherence is guaranteed: every phase reads its inputs from the live
IMotor / Drive / UnifiedMotionPidConfig objects and writes its
results back to those same objects before returning. The Python layer below
is a thin orchestrator that adds UI confirmations and YAML persistence.
Phases run in this dependency order:
- Phase 1 - Velocity LPF alpha (per-motor IIR filter)
Tunes the filter that downstream velocity feedback depends on, so every subsequent phase sees clean velocity estimates.
- Phase 2 - Static friction (kS, PWM percent)
Sweep per motor to find the duty cycle that overcomes static friction.
- Phase 3 - Firmware velocity PID (STM32 MAV-mode inner loop)
BEMF step-response identification per motor, CHR gains pushed to the STM32.
- Phase 4 - Encoder calibration (ticks_to_rad)
IMU-vs-odometry sweep scales each motor’s ticks_to_rad and re-publishes the kinematics config to the STM32.
- Phase 5 - Drive characterization (max velocity, accel, decel)
Raw-PWM trials measure the physical limits of every axis.
- Phase 6 - Velocity controller tuning (outer chassis loop)
Step-response identification + CHR gains, ISE-validated accept/revert.
- Phase 7 - Motion controller tuning (distance / heading PID)
Hooke-Jeeves coordinate descent on real LinearMotion / TurnMotion trials.
- Phase 8 - Tolerance derivation (pure math)
Reads back motion-trial residuals and updates distance/angle tolerances.
- Step classes:
AutoTune - full pipeline (all phases) AutoTuneVelLpf - Phase 1 only AutoTuneStaticFriction - Phase 2 only AutoTuneFirmwarePid - Phase 3 only AutoTuneVelocity - Phase 6 only AutoTuneMotion - Phase 7 only
Classes¶
Live checklist of the auto-tune pipeline. |
|
Tune the IIR velocity-filter alpha per motor (Phase 1). |
|
Measure per-motor static-friction threshold kS in PWM percent (Phase 2). |
|
Calibrate per-motor |
|
Tune per-motor STM32 MAV-mode velocity PID via BEMF step response (Phase 3). |
|
Calibrate the MCU chassis velocity-command gain per axis (Phase 6). |
|
Tune motion PID controllers via iterative real-world optimization (Phase 7). |
|
Run the full auto-tune pipeline. |
Module Contents¶
- class step.motion.auto_tune.AutoTuneProgressScreen(phases: list[tuple[str, str]])¶
Bases:
raccoon.ui.UIScreen[None]Live checklist of the auto-tune pipeline.
Shows every active phase with a status glyph so the operator can follow the pipeline’s progress on the robot screen. Reused across all phases of a single
AutoTunerun — the orchestrator mutates this object viamark()and re-displays it for each phase, so the checklist persists.- title = 'Auto-Tune'¶
- motion_toggle_callback = None¶
- mark(key: str, status: str, detail: str = '') None¶
Update a phase’s status (
pending/running/done/failed/skipped).
- set_motion_control_state(state: str, *, axis: str = '', detail: str | None = None, callback=None) None¶
- build() raccoon.ui.Widget¶
Build the screen layout.
Called on every render. Return a Widget tree describing what to display.
- class step.motion.auto_tune.AutoTuneVelLpf(persist: bool = True)¶
Bases:
step.StepTune the IIR velocity-filter alpha per motor (Phase 1).
Collects raw BEMF samples at a steady velocity, replays them through IIR low-pass filters with varying alpha, and applies the alpha that minimises a weighted noise+lag score. Runs first in the full pipeline because every downstream phase relies on the same velocity-feedback filter.
- Parameters:
persist – Write tuned
vel_lpf_alphavalues toraccoon.project.yml. DefaultTrue.
Example:
from raccoon.step.motion import auto_tune_vel_lpf auto_tune_vel_lpf()
- persist = True¶
- class step.motion.auto_tune.AutoTuneStaticFriction(persist: bool = True)¶
Bases:
step.StepMeasure per-motor static-friction threshold kS in PWM percent (Phase 2).
For each drive motor the PWM is swept from a low starting percentage upward in both directions. The first PWM level where the median BEMF exceeds a motion threshold is recorded as kS.
- Parameters:
persist – Reserved for future YAML persistence. Currently logs only.
Example:
from raccoon.step.motion import auto_tune_static_friction auto_tune_static_friction()
- persist = True¶
- class step.motion.auto_tune.AutoTuneBemfVelocity(persist: bool = True, pwm_min_percent: int = 30, pwm_max_percent: int = 90, pwm_steps: int = 6, sweeps: int = 3)¶
Bases:
step.StepCalibrate per-motor
ticks_to_rad(BEMF→rad) against the calibration board.Fully automatic. Drives the chassis straight forward at a sweep of open-loop PWM levels (back-and-forth, staying near the start) and, for each level, compares the ground-truth distance travelled — read from the external calibration board’s optical-flow + IMU odometry — against the accumulated BEMF ticks per motor. From that it derives, per motor,
ticks_to_rad = (distance / wheel_radius) / Δticks.Crucially it does not assume the ADC-BEMF↔velocity relationship is linear: it computes the per-motor coefficient of variation of
ticks_to_radacross the speed range plus an ω-vs-BEMF linear fit (slope/intercept/R²) and reports whether a single scale actually holds. If the relationship is clearly curved or offset, that is logged as a warning rather than silently persisting a misleading single value.- Prerequisites:
The calibration board must be connected. This step temporarily requests calibration-board odometry for the tune and restores the previous preference afterward; the tuner aborts if the board still is not the active source.
Roughly 1 m of clear runway forward/back.
- Parameters:
persist – Write tuned
ticks_to_radper motor toraccoon.project.yml. DefaultTrue.pwm_min_percent – Lowest PWM level in the sweep (percent). Default
30.pwm_max_percent – Highest PWM level in the sweep (percent). Default
90.pwm_steps – Number of evenly spaced PWM levels. Default
6.sweeps – Number of full sweeps to run; points from all sweeps are pooled into one per-motor fit. More sweeps stabilise the extrapolated
bemf_offset(the ω=0 intercept is noise-sensitive). Default3.
- Returns:
AutoTuneBemfVelocitystep.
Example:
from raccoon.step.motion import auto_tune_bemf_velocity auto_tune_bemf_velocity()
- persist = True¶
- pwm_min_percent = 30¶
- pwm_max_percent = 90¶
- pwm_steps = 6¶
- sweeps = 3¶
- class step.motion.auto_tune.AutoTuneFirmwarePid(persist: bool = True, max_bemf_speeds: dict[int, int] | None = None, csv_dir: str | None = '/tmp/auto_tune')¶
Bases:
step.StepTune per-motor STM32 MAV-mode velocity PID via BEMF step response (Phase 3).
For each drive motor: record a BEMF step response, fit a FOPDT plant, derive CHR PID gains, push them to the firmware. Gains are accepted only when the tuned ISE is strictly smaller than the baseline ISE.
- Parameters:
persist – Unused — gains are applied directly to firmware state.
max_bemf_speeds – Optional
{port: max_bemf_speed}map. If unset, the C++ side runs a brief power sweep to estimate it.csv_dir – When set, every step-response sample is dumped to a CSV under this directory (one per motor + phase) plus a summary CSV with the plant fit and gains. Default
"/tmp/auto_tune".
Example:
from raccoon.step.motion import auto_tune_firmware_pid auto_tune_firmware_pid()
- persist = True¶
- max_bemf_speeds = None¶
- csv_dir = '/tmp/auto_tune'¶
- class step.motion.auto_tune.AutoTuneVelocity(axes: list[str] | None = None, persist: bool = True)¶
Bases:
step.StepCalibrate the MCU chassis velocity-command gain per axis (Phase 6).
With the chassis velocity loop running on the coprocessor (forward kinematics + per-wheel MAV PID), there is no host velocity PID left to tune. What this phase tunes instead is the chassis-level command ACCURACY: it commands a mid-range body velocity, measures the achieved velocity against external ground truth (the calib board), and folds a per-axis correction gain into the STM32 forward-kinematics matrix so commanded == achieved. This compensates drivetrain efficiency the ideal geometry ignores (most notably mecanum roller slip, where wheels track their BEMF setpoint correctly yet the chassis travels less than predicted). The candidate gain is validated by re-measuring and accepted only if the effective gain moved closer to 1.0.
Prerequisites: Phase 5 (drive characterization) should have run first so a max-velocity-per-axis is known. Phases 1–4 (LPF, static friction, firmware MAV PID, ticks_to_rad) should also have run so the inner loop is stable. A calib board must be connected for the external measurement.
- Parameters:
axes – Velocity axes to tune (
"vx","vy","wz"). Default auto-detects from kinematics.persist – Write accepted gains to
raccoon.project.yml(robot.drive.kinematics.velocity_command_gain). DefaultTrue.
Example:
from raccoon.step.motion import auto_tune_velocity auto_tune_velocity() auto_tune_velocity(axes=["vx"])
- axes = None¶
- persist = True¶
- class step.motion.auto_tune.AutoTuneMotion(axes: list[str] | None = None, persist: bool = True)¶
Bases:
step.StepTune motion PID controllers via iterative real-world optimization (Phase 7).
Uses Hooke-Jeeves coordinate descent on the distance/heading PID kp & kd via real LinearMotion and TurnMotion trials with constraint-aware scoring.
Prerequisites: velocity controllers tuned (Phase 6) and drive limits characterized (Phase 5).
- Parameters:
axes – Motion parameters to tune (
"distance","lateral","heading"). Default auto-detects from kinematics.persist – Write final gains to
raccoon.project.yml. DefaultTrue.
Example:
from raccoon.step.motion import auto_tune_motion auto_tune_motion() auto_tune_motion(axes=["heading"])
- axes = None¶
- persist = True¶
- class step.motion.auto_tune.AutoTune(vel_axes: list[str] | None = None, characterize_axes: list[str] | None = None, motion_axes: list[str] | None = None, tune_bemf_velocity: bool = True, tune_vel_lpf: bool = True, tune_static_friction: bool = True, tune_firmware_pid: bool = True, tune_encoder_cal: bool = False, tune_characterize: bool = True, tune_velocity: bool = True, tune_motion: bool = True, tune_tolerances: bool = True, pwm_min_percent: int = 30, pwm_max_percent: int = 90, pwm_steps: int = 6, sweeps: int = 2, characterize_trials: int = 3, characterize_power_percent: int = 100, persist: bool = True, step_confirm: bool = True)¶
Bases:
raccoon.ui.UIStepRun the full auto-tune pipeline.
Drives the C++
AutoTunerone phase at a time so UI confirmations can pause between phases. Each phase reads its inputs from the live drive / motors / motion-config objects and writes back to those same objects, so state stays coherent without Python having to shuttle calibration values.Only the phases that are currently validated run by default. The remaining phases are kept but disabled — pass the matching
tune_*=Trueto re-enable.Default-enabled phases:
bemf_velocity— per-motorticks_to_radagainst the calibration board (the big validated win; supersedes the IMUencoder_cal).vel_lpf— per-motor IIR alpha for velocity feedback.static_friction— kS per motor (PWM percent).firmware_pid— STM32 MAV-mode inner velocity loop.characterize— max velocity / accel / decel per axis at 100% PWM, measured against calib-board ground truth (frame-independent straight-line distance).velocity— MCU chassis velocity-command gain per axis: makes commanded body velocity match the calib-board-measured achieved velocity.motion— distance / heading PID via real LinearMotion/TurnMotion trials (Hooke-Jeeves); linear trials return to start between runs.tolerances— distance/angle tolerances derived from motion residuals.
Default-disabled phases (re-enable explicitly):
encoder_cal— IMU ticks_to_rad; superseded bybemf_velocity.
- Parameters:
vel_axes – Override the auto-detected velocity axis list.
characterize_axes – Override the auto-detected characterize axis list.
motion_axes – Override the auto-detected motion-parameter list.
tune_bemf_velocity – Enable BEMF→velocity
ticks_to_radcalibration against the calibration board. DefaultTrue.tune_vel_lpf – Enable vel LPF alpha tuning. Default
True.tune_static_friction – Enable static friction measurement. Default
True.tune_firmware_pid – Enable firmware velocity PID tuning. Default
True.tune_encoder_cal – Enable IMU encoder calibration. Default
False.tune_characterize – Enable drive characterization (max vel/accel/decel per axis vs calib board). Default
True.tune_velocity – Enable MCU chassis velocity-command-gain calibration (commanded == achieved body velocity). Default
True.tune_motion – Enable motion PID tuning (distance / heading) via real LinearMotion/TurnMotion trials; linear trials return to start after each so the robot stays in place. Default
True.tune_tolerances – Enable tolerance derivation from motion residuals. Default
True.pwm_min_percent – Lowest PWM level for the bemf_velocity sweep. Default
30.pwm_max_percent – Highest PWM level for the bemf_velocity sweep. Default
90.pwm_steps – Number of bemf_velocity sweep PWM levels. Default
6.sweeps – Number of bemf_velocity sweeps to pool. Default
2.characterize_trials – Number of characterize trials per axis. Default
3.characterize_power_percent – Raw PWM for characterize trials (1–100). Default
100.persist – Write phase results to
raccoon.project.yml. DefaultTrue.step_confirm – Pause for a button press before every phase. Default
True.
- characterize_axes = None¶
- vel_axes = None¶
- motion_axes = None¶
- tune_bemf_velocity = True¶
- tune_vel_lpf = True¶
- tune_static_friction = True¶
- tune_firmware_pid = True¶
- tune_encoder_cal = False¶
- tune_characterize = True¶
- tune_velocity = True¶
- tune_motion = True¶
- tune_tolerances = True¶
- pwm_min_percent = 30¶
- pwm_max_percent = 90¶
- pwm_steps = 6¶
- sweeps = 2¶
- characterize_trials = 3¶
- characterize_power_percent = 100¶
- persist = True¶
- step_confirm = True¶