Skip to content

robotd, kinematics, robotd-params: four hardening fixes for the drive loop and startup - #199

Open
hadelan wants to merge 5 commits into
pollen-robotics:mainfrom
hadelan:drive-and-startup-hardening
Open

robotd, kinematics, robotd-params: four hardening fixes for the drive loop and startup#199
hadelan wants to merge 5 commits into
pollen-robotics:mainfrom
hadelan:drive-and-startup-hardening

Conversation

@hadelan

@hadelan hadelan commented Sep 2, 2026

Copy link
Copy Markdown

Four independent fixes, one commit each, every one with a regression test.

  • Never start the homing ramp for a mode switch while limp. A mode switch queued with torque off jumped straight to Homing, skipping the set_torque the enable path owns — the ramp "finished" over dead motors, the other mode's policies loaded, and the state reported Ready/homed for a robot lying on the floor. The same request on a tick with no position sample wedged mode_change forever, refusing every later switch as already in flight. Limp now stays Limp (the enable path turns the motors on and ramps; the queued switch completes when that ramp does), and a sample-less tick refuses the switch outright.
  • Drop non-finite command targets instead of poisoning the command filters. JSON parses 1e400 as infinity, so a client can put one on the wire. Folded into the twist/head/body EMAs it is permanent (ema += α·(inf − ema) is inf on every later tick), and since the safety layer refuses non-finite joint targets rather than clamping them, a single bad robot.move froze the robot on its hold pose until reboot. The filters now drop non-finite targets.
  • An empty band is no hand even when min_zones is 0. min_zones = 0 is a legal config value, and it made the length check pass on an empty band — straight into the low-percentile index, which panics on an empty Vec. The check is now floored at one zone.
  • Refuse policy.walk = "none" at load instead of panicking. The "none" sentinel legitimately disables the optional policy slots, but walk is the one slot resolved() cannot leave empty, so the config got past load and panicked at startup. validate() refuses it now, as a config error with the path attached.

cargo test --workspace (1035 passed, 0 failed), clippy -D warnings and fmt --check are all green.

hadelan and others added 5 commits September 2, 2026 14:43
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.

Assisted-by: Kimi:kimi-code
…and filters

JSON parses 1e400 as infinity, so a client can put one on the wire. Folded
into the twist/head/body EMAs it is permanent — ema += α·(inf − ema) is
inf on that tick and every tick after — and the safety layer refuses
non-finite joint targets rather than clamping them, so a single bad
robot.move froze the robot on its hold pose until reboot.

Assisted-by: Kimi:kimi-code
min_zones = 0 is a legal config value, and it makes the length check pass
on an empty band — straight into the low-percentile index below, which
panics on an empty Vec. Floor the check at one zone: no zones is no hand,
whatever the configured floor is.

Assisted-by: Kimi:kimi-code
The "none" sentinel disables the optional policy slots, but walk is the
one slot resolved() cannot leave empty — every mode has a default for it,
and the controller has nothing to load without it. A config that said
walk = "none" got past load and panicked in resolved() at startup.
Validate refuses it now, as a config error with the path attached.

Assisted-by: Kimi:kimi-code
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.

1 participant