Skip to content

robotd: never start the homing ramp for a mode switch while limp - #237

Open
hadelan wants to merge 2 commits into
pollen-robotics:mainfrom
hadelan:fix/limp-mode-switch-homing-ramp
Open

robotd: never start the homing ramp for a mode switch while limp#237
hadelan wants to merge 2 commits into
pollen-robotics:mainfrom
hadelan:fix/limp-mode-switch-homing-ramp

Conversation

@hadelan

@hadelan hadelan commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

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.

@pierre-rouanet pierre-rouanet left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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::Ready
  • robot.init, main.rs:1906: the same branch, the same direct Bringup::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.
@hadelan
hadelan force-pushed the fix/limp-mode-switch-homing-ramp branch from e3ac408 to a53f8c3 Compare September 10, 2026 01:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants