Asimov 1 β get up off the floor, then hand over
A get-up policy for Menlo Research's Asimov 1, trained from scratch, inside the robot's published speed-torque envelope, that hands control to Menlo's own walk policy the moment it is standing.
From face down: 24/24 rises, 24/24 still standing at the buzzer.
Face down at t=0 (trunk 0.09 m, 96Β° from vertical). The get-up policy rises; Menlo's walk policy takes over at 1.58 s and holds the stand to the buzzer.
Simulation only. This has never run on a robot.
Results
24 episodes per row, seeds 0β23, MuJoCo, under the dc speed-torque
envelope, with Menlo's shipped walk policy taking over once up.
| start | rises | still standing at 8 s |
|---|---|---|
| prone (face down) | 24/24 | 24/24 |
| supine (on its back) | 15/24 | 15/24 |
Those use a privileged handoff test (trunk height + MuJoCo's contact list). With the deployable switch below β observation only, nothing the robot cannot sense β prone still-standing is 23/24; rises and supine are unchanged. An independent re-scoring that reads the raw physics instead of this repo's own predicate puts it at 22/24, so read the honest figure as 22β24 of 24.
Other measurements, prone:
| measurement | value |
|---|---|
| joint error vs default pose, once settled | 1.30Β° mean, 4.18Β° worst |
| worst joint velocity while standing | 2.3 Β°/s (252 Β°/s without the handoff) |
| shoves survived | 24/24 (applied only once standing) |
| median radians outside a joint limit | 0.009 |
| median peak foot span | 0.888 m β see Limitations |
The handoff is the second half of the deliverable
The rise arrives with momentum a passive stance cannot absorb. Left in control, the get-up policy keeps acting and the worst joint runs 252 Β°/s while nominally standing. Handing to the walk policy drops that to 2.3 Β°/s with no loss of rises. Nine reward terms aimed at the same problem were all nulls; the architecture fixed it in an afternoon.
The switch runs on what the robot can sense. The obvious predicate (trunk height, contact list) uses quantities no Asimov has. This one reads only projected gravity plus two encoder channels β the elbow and ankle states that fool an IMU, since a robot propped on its forearms reads upright.
It costs one episode in 24, not nothing: rises are 24/24 either way, and
still-standing is 24/24 under the privileged test against 23/24 with the
switch. An earlier version of this card said "costs nothing" β that came from
a scorer which indexed the slot-ordered observation block with the
action-order joint list, so its "elbow" clause read a wrist and its "ankle"
clause read a knee. It never looked at an ankle, fired anyway, and scored
24/24. policies/run_getup_mujoco.py uses the correct indices and always
has.
Limitations β read these
It reads 390 floats, not 78. Five stacked frames of Menlo's published
layout, newest last. It will not hot-swap onto the robot and will not
load in Menlo's viewer, both of which expect 78. On device it needs a ring
buffer of the last five observations β Ring in the bundled runner, 12 lines.
The history is load-bearing, not a convenience: frozen to one repeated frame, these same weights rise 0/48 instead of 48/48. Their 78-float vector carries no base linear velocity and no contact state, which is survivable for walking and not for a get-up, where the whole problem is momentum and which limb is bearing load. That is a fact about the contract, not about this policy, and it is the most useful thing here.
It requires the speed-torque envelope it trained in. Under a flat
per-group torque clamp the same weights fall to 14/24 rises, 6/24 stays.
A flat limit is a robot that is weak standing still and unlimited once
moving, so the cheapest route through any reward is to fling everything.
policies/run_getup_mujoco.py implements the envelope; it is ~10 lines,
because a MuJoCo position servo already computes kp*(ctrl β q) β kd*qd and
clamps it to actuator_forcerange, so rewriting that range from the live
qvel is the whole model.
The stance is wide. Median peak foot span 0.888 m against a natural stance of 0.215 m. It gets up by spreading, and a narrow get-up is a different problem that is not solved here.
Supine is much weaker than prone β 15/24, and it was trained on prone.
Two joint orders. Actions, last_action, default_pose and the MJCF
actuators use one permutation; joint_pos_rel and joint_vel inside each
frame use another. Both are in getup_policy_spec.json. Mixing them still
produces actions and still moves the robot; it just falls over.
Files
| path | what |
|---|---|
policies/getup.onnx |
the policy, obs[1,390] β actions[1,23], 50 Hz |
policies/getup_policy_spec.json |
observation layout, both joint orders, action scaling, the speed-torque envelope, a settled prone pose |
policies/run_getup_mujoco.py |
self-contained runner: ring buffer, envelope, observation-only switch, walker handoff |
replay.mp4 |
a rendered episode from face down |
python policies/run_getup_mujoco.py \
--mjcf <Menlo scene with actuators>.xml \
--walk <Menlo's walk policy>.onnx
The runner reproduces the training observation to 6e-08 (float32 precision), so it is the reference rather than an illustration.
Provenance
Trained from random initialisation. No distillation, no imitation loss, no
weights from any other get-up: a 38-deep warm-start chain whose root records
init_from: None. The only external input is Menlo's own published
observation layout and MJCF, plus the peak_torque table from
openhorizon-labs/asimov1-getup-safefall
(Apache-2.0), which is attributed in the spec.
Trained on CPU MuJoCo with Stable Baselines 3 PPO β no GPU β in jonathanhawkins/microduck-lab (Apache-2.0), which carries the env, the reward economy, the acceptance script that produced every number above, and the write-up of what went wrong getting here.
Reproduce the scores:
uv run python scripts/getup_acceptance.py <run> --episodes=24 --pose=prone --handoff
Licence and attribution
Apache-2.0 for the policy weights, the spec and the runner.
Not redistributed here: Menlo Research's Asimov 1 model (GPL-2.0 /
CERN-OHL-S-2.0) and their shipped walk policy. Fetch those from
menloresearch/asimov-1. The
peak_torque values in the spec are openhorizon-labs', Apache-2.0, recorded
as theirs.
Evaluation results
- rises, 24/24 on Asimov 1 get-up from prone (MuJoCo, dc envelope)self-reported100.000
- still standing at 8 s, 24/24 on Asimov 1 get-up from prone (MuJoCo, dc envelope)self-reported100.000
- rises, 15/24 on Asimov 1 get-up from supine (MuJoCo, dc envelope)self-reported62.500
- still standing at 8 s, 15/24 on Asimov 1 get-up from supine (MuJoCo, dc envelope)self-reported62.500