the mode switch block in control_loop (robotd/src/main.rs, where take_mode_switch is handled) acts on the request in the same tick it arrives, from whatever state the robot happens to be in. three of those states go wrong.
on a tick with no sample, the request is lost for good. the block arms mode_change and then only sets Bringup::Homing if there is a sample to ramp from. nothing looks at mode_change again until the robot next homes for some other reason, and every later robot.setMode is refused as "a mode switch is already in flight". so one bus dropout past the coast, during a held d-pad, and the mode cannot be changed again without robot.init or a restart.
on a limp robot, it goes Homing and then Ready with no torque write. Ready is the state that means torque on and at home, and it is what the enable driven bring-up checks for, since that only runs from Limp. so switch mode first and press start second, which is the natural order for someone who has just put the wheels on, and the policy drives a robot whose servos were never powered. pressing start again finds Ready and does nothing. robot.init from Ready re-homes without touching torque either. the only way out is robot.relax first, and nothing says so.
during a shutdown sit it is not refused, so it sets Homing and the robot ramps back to the standing pose at gain, torque on, until the sit timer cuts the torque out from under it. that is #159 by a third door. #170 gates robot.init and the enable driven bring-up for exactly this, and this path has the same hole.
all three reproduce in the loop's own test harness with FakeIo and no policy, except that the sit half of the third one needs the sitstand network, so its test drives the sibling path where robot.shutdown powers off at once. the tests are on the branch i am opening against this.
on main at 9f7eaad.
the mode switch block in
control_loop(robotd/src/main.rs, wheretake_mode_switchis handled) acts on the request in the same tick it arrives, from whatever state the robot happens to be in. three of those states go wrong.on a tick with no sample, the request is lost for good. the block arms
mode_changeand then only setsBringup::Homingif there is a sample to ramp from. nothing looks atmode_changeagain until the robot next homes for some other reason, and every laterrobot.setModeis refused as "a mode switch is already in flight". so one bus dropout past the coast, during a held d-pad, and the mode cannot be changed again withoutrobot.initor a restart.on a limp robot, it goes
Homingand thenReadywith no torque write.Readyis the state that means torque on and at home, and it is what the enable driven bring-up checks for, since that only runs fromLimp. so switch mode first and press start second, which is the natural order for someone who has just put the wheels on, and the policy drives a robot whose servos were never powered. pressing start again findsReadyand does nothing.robot.initfromReadyre-homes without touching torque either. the only way out isrobot.relaxfirst, and nothing says so.during a shutdown sit it is not refused, so it sets
Homingand the robot ramps back to the standing pose at gain, torque on, until the sit timer cuts the torque out from under it. that is #159 by a third door. #170 gatesrobot.initand the enable driven bring-up for exactly this, and this path has the same hole.all three reproduce in the loop's own test harness with
FakeIoand no policy, except that the sit half of the third one needs the sitstand network, so its test drives the sibling path whererobot.shutdownpowers off at once. the tests are on the branch i am opening against this.on main at 9f7eaad.