robotd: never start the homing ramp for a mode switch while limp - #237
robotd: never start the homing ramp for a mode switch while limp#237hadelan wants to merge 2 commits into
Conversation
pierre-rouanet
left a comment
There was a problem hiding this comment.
Both diagnoses hold up against the code. The enable path at main.rs:2426 is the only set_torque(true) on that route, so a Homing queued from Limp really did ramp over dead motors and publish Ready; and mode_change's only consumer is the Homing-finished branch at main.rs:2477, so the sample-less case really did wedge every later switch. Refusing before the chirp is the right order too — no voice cue on a switch that did not happen.
One hole left, though, and it is the same wedge on a different route.
mode_change is drained only by a Homing ramp finishing, but both bring-up paths can go Limp -> Ready without ever passing through Homing:
robot.enable,main.rs:2435:if seated_boot && controller.has_sitstand()->begin_boot_rise();bringup = Bringup::Readyrobot.init,main.rs:1906: the same branch, the same directBringup::Ready
So: robot boots seated (leg_deviation > SEATED_BOOT_RAD) with a sitstand policy loaded, held D-pad up arrives while limp. The switch is queued and bringup stays Limp — as intended. Then Start: the boot rise goes straight to Ready, no ramp, nothing takes mode_change. It stays Some(target) for the rest of the process: the mode never switches, every later switch is refused as already in flight, and robot.loadPolicy is refused too, because main.rs:2121 gates on mode_change.is_some().
Two ways out. The narrow one is to thread seated_boot && controller.has_sitstand() into mode_switch_bringup and refuse there, so it is a logged refusal like the sample-less case rather than a silent queue. The one I would rather have is draining mode_change wherever bringup becomes Ready, not only off the ramp — that makes the invariant "a queued switch is consumed by any arrival at Ready" instead of resting on which branch happened to run. It also means the next bring-up route added does not have to remember this.
Two smaller things.
The warn! still reads "mode switch: going home before loading the other policies" on the Limp path, where nothing moves and nothing loads until somebody presses Start. The comment explains the no-op; the line a human reads off the robot does not. Worth its own message for that case.
And a switch queued from Limp blocks robot.loadPolicy for as long as the robot stays limp. Not wrong given the model, but it is a new indefinite refusal window: relax after a queued switch now blocks policy loads until the next ramp completes, which it did not before.
The three tests are well chosen, and Bringup being Copy + PartialEq makes them read cleanly. CI is green on e3ac408 (board, check, coverage).
A mode switch queued with torque off jumped straight to Homing, skipping the set_torque the enable path owns. The ramp then "finished" over dead motors: the other mode's policies loaded, the state reported Ready and homed, and the robot lay on the floor. The same request on a tick with no position sample wedged mode_change forever — its only consumer is the ramp finishing — refusing every later switch as already in flight. Keep Limp (the enable path turns the motors on and ramps; the queued switch completes when that ramp does), and refuse the switch outright on a sample-less tick.
e3ac408 to
a53f8c3
Compare
Split out from #199.
A mode switch queued with torque off jumped straight to Homing, skipping the set_torque the enable path owns. The ramp then "finished" over dead motors: the other mode's policies loaded, the state reported Ready and homed, and the robot lay on the floor. The same request on a tick with no position sample wedged mode_change forever — its only consumer is the ramp finishing — refusing every later switch as already in flight. Keep Limp (the enable path turns the motors on and ramps; the queued switch completes when that ramp does), and refuse the switch outright on a sample-less tick.