feat(controls): adaptive PID balance controller with gain scheduling (Issue #136) #149
Loading…
x
Reference in New Issue
Block a user
No description provided.
Delete Branch "sl-controls/issue-136-adaptive-pid"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
GainSet(clamped kp/ki/kd),PIDController(anti-windup, D-on-error, output clamp),GainScheduler(empty/light/heavy weight table, exponential blending atgain_blend_alphaper tick, safety bounds, manual override, instant revert-to-defaults),InstabilityDetector(dual criteria: tilt threshold + oscillation sign-reversal count)WeightEstimator(rolling-window current→weight, steady-state gated by |tilt|, change detection),CalibrationRoutine(IDLE→ROCKING→SETTLING→DONE/FAILED; sinusoidal rocking output, settling current sampling, weight from avg current)/saltybot/imu+/saltybot/motor_current→/saltybot/balance_effort+/saltybot/weight_estimate+/saltybot/pid_state(JSON);/saltybot/calibrate_balanceTrigger service; IMU watchdog;override_enableddynamic reconfigure; instability → revert + PID reset + WARN logHow to use
Test plan
Closes #136
🤖 Generated with Claude Code
Pure modules (no ROS2 dep, fully unit-tested): - pid_controller.py: GainSet — (kp,ki,kd) with safety clamp helper PIDController — anti-windup integral, D-on-error, output clamping GainScheduler — 3-class weight table (empty/light/heavy), exponential gain blending (alpha per tick), safety bounds clamping, manual override, immediate revert-to-defaults on instability InstabilityDetector — dual criteria: tilt threshold (>50% of window) + sign-reversal count (oscillation) - weight_estimator.py: WeightEstimator — rolling-window current→weight, steady-state gating (|tilt|≤threshold), change detection (threshold_kg) CalibrationRoutine — IDLE→ROCKING→SETTLING→DONE/FAILED state machine; sinusoidal rocking output, settling current sampling, weight estimate from avg current; abort() / restart supported - adaptive_pid_node.py: 100 Hz ROS2 node Sub: /saltybot/imu (Imu, pitch from quaternion), /saltybot/motor_current Pub: /saltybot/balance_effort (Float32), /saltybot/weight_estimate, /saltybot/pid_state (JSON: gains, class, weight_kg, flags) Srv: /saltybot/calibrate_balance (std_srvs/Trigger) IMU watchdog (0.5 s), dynamic reconfigure via override_enabled param, instability → revert + PID reset, structured INFO/WARN logging - config/adaptive_pid_params.yaml, launch/adaptive_pid.launch.py, package.xml, setup.py, setup.cfg - test/test_adaptive_pid.py: 68/68 unit tests passing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>