Pierre Rouanet 966d229965 docs: the image's username, not one operator's
Every provisioning example said `pierre@`, which is one person's account on one
board. A teammate pasting those either edits each command or gets "Permission
denied" from a username that was never theirs — the same class of friction as the
missing token header, in the same commands.

`radxa@` throughout, which is what the image creates. Also caught two
`/home/pierre/` paths in the policy examples, where a hardcoded home directory is
the same problem one level down.

Assisted-by: Claude:claude-opus-5
2026-08-05 17:01:11 +02:00
..

Policies

The ONNX gait policies robotd runs. Both are obs[1,61] -> actions[1,14]; robotd checks that at load rather than discovering it mid-stride.

This is a temporary home

These belong on the Hugging Face Hub, delivered as a model updater component that versions independently of the daemon — a gait retrain should not need a daemon release, and a daemon fix should not re-download 1.5 MB of unchanged weights. deploy/updater.toml already describes that component and deliberately leaves it unconfigured until the repos exist.

They are vendored here because they were not on the Hub yet and slice 2 cannot walk without them. Committing them makes a release self-contained, which is the property that makes the update path testable end to end: one robotctl update apply turns a standing robot into a walking one.

Removing this directory later is the whole migration: point [policy] walk/stand in deploy/robotd.toml at wherever the model component installs, and drop the two --include lines from .github/workflows/{release,dev}.yml.

Provenance

Copied from apirrone/microduck_runtime at commit 567fdcd, dereferencing the symlinks that repository uses to give stable names to specific training runs:

here there size
alpha_walking.onnx policies/BEST_alpha_walking_flat.onnx 793705
alpha_stand.onnx policies/BEST_alpha_stand.onnx 793695

Why not the ones microduck_runtime loads by default

Its src/main.rs defaults to policies/walking.onnx and policies/standing.onnx, which resolve into new_policies/. Those were vendored here briefly on the strength of being the proven pair, and the robot rejected them:

policy unavailable: .../walking.onnx: observation width is 51, expected 61

They are not an older generation — they are a different observation format. 51 is 3 gyro + 3 gravity + 42 joints + 3 command, the legacy [vx, vy, vtheta] command. 61 is the same sensors with the unified 13-value command ([vel(3), head(4), body(6)]) this daemon builds. The prototype runs the legacy path by default and reaches the 61-D policies only under --new-cmd-obs, so "what the working runtime loads by default" is the wrong question to ask of it. The right one is which policies match the observation we build, and that is the BEST_alpha_* family.

Worth noting the shape check earned its place here: it turned a wrong-policy mistake into one precise line naming both widths, instead of a robot moving in ways nobody could explain.

The names here are the roles — what deploy/robotd.toml asks for — not the training runs. That indirection is deliberate and worth keeping: swapping which run is "the walking policy" should not mean editing config on every robot.

The prototype carries 22 MB of policies across several revisions and skills. Only these two are copied: the rest belong to skills this daemon does not implement yet, and vendoring them would put weight in every robot's update for capabilities it cannot use.

Trying your own

No release needed — deploy/robotd.toml takes absolute paths:

[policy]
walk  = "/home/radxa/my_walk.onnx"
stand = "/home/radxa/my_stand.onnx"

Then sudo systemctl restart robotd. A policy that fails to load is reported through robot.health as policy unavailable: <reason> while the loop keeps ticking and holding its pose, so a bad file is visible without putting the robot on the floor.