Your policy scores much better when I give it all 29 joints - I think it wants to control its arms

#1
by rhoyn - opened

Hi, thanks for releasing this checkpoint.

I benchmarked 29 open-source Unitree G1 walking policies behind a single C++ interface. The task: a 60 s tour of 12 waypoints, 50 Hz control over a 2 ms step, a crane that holds a shared stance 3 s and releases, then a punch on every segment (random joint, random direction, 0.08 s, up to 600 N). By benchmark rule, a policy owns the 15 leg and waist joints and the 14 arm joints random-walk under the harness β€” no policy is allowed to use its arms for balance.

I ran yours twice, and the difference is the reason I am writing:

configuration completed (mujoco/physx) pos / yaw error
clobot β€” 15 joints, benchmark rule 0 / 0 % 131 cm / 75Β°
clobot_with_arms β€” all 29 joints 9 / 5 % 50 cm / 20Β°

Given the full 29 joints your policy goes from never finishing to finishing some runs, and its position error drops by 60 % while yaw error drops from 75Β° to 20Β°. That is a big enough gap that I do not think the 0 % is a fair characterisation. My reading is that this checkpoint outputs 29 actions and genuinely expects to drive the arms, so amputating them is not a neutral restriction for it the way it is for a legs-only policy.

I report clobot_with_arms in my table as unranked, with a footnote saying it is the same policy given all 29 joints instead of 15, precisely so this is visible rather than hidden.

My adapter: 29 actions, 5 frames of history over a 3+3+3+29+29+29+4 frame (a 4-dim gait block), ang-vel scale 0.2, dof-vel scale 0.05, action clip 5.0, control dt 0.02, gait period 1.0 s.

Questions:

  1. Is this policy intended to control all 29 joints, including arms, during locomotion?
  2. What are the 4 gait dimensions? I synthesise them at a fixed 1.0 s period and that is a guess.
  3. Is an action clip of 5.0 right?

If arms are intended, I would like to say so explicitly in my notes rather than leave a 0 % row that reads as a quality judgement.

https://github.com/rhoyn/teleop-walking-benchmark
https://rhoyn.com/stable-walk

CLOBOT-SKKU-CMU org

Hi, @rhoyn thanks for the careful write-up and for flagging this instead of just publishing the 0% row.

  1. Does the policy control all 29 joints?
    Yes, but with a caveat. The policy outputs all 29 joints, but during training the arm and waist joints were heavily penalized for deviating from the default pose β€” so it learned to hold them still, not to swing them for balance. It doesn't use its arms for balance in the sense your rule excludes. But it does expect to own them: it's never seen its arms driven externally, so when your harness random-walks them, that's an out-of-distribution disturbance, not a fair test of leg quality. I'd suggest framing the 15-joint row as "not trained for externally driven arms" rather than a quality judgement β€” your footnote instinct was right.

  2. The 4 gait dimensions
    It's a sin/cos pair for each leg's phase, driven by a free-running clock that starts at 0 and never resets β€” your 1.0 s period guess is correct. One thing to double check: the ordering is both sines first, then both cosines, not interleaved.

  3. Action clip 5.0
    Correct β€” it's applied to the raw network output before per-joint scaling, not after. Make sure last_action logs that clipped raw value, not the final joint target.

Two more things worth checking in your adapter, since either would hurt both rows:

Observation history is stacked term-by-term, not frame-by-frame: [ang_vel Γ—5 (15) | gravity Γ—5 (15) | cmd Γ—5 (15) | joint_pos_rel Γ—5 (145) | joint_vel_rel Γ—5 (145) | last_action Γ—5 (145) | gait Γ—5 (20)]. It is not five stacked 100-dim frames.
Joint ordering follows Isaac Lab's convention, which interleaves arms with legs β€” it's not "first 15 = legs." Use the joint_ids_map in deploy/deploy.yaml rather than assuming a fixed order.

A few other contract details are documented in deploy/deploy.yaml β€” per-joint PD gains, the reference pose, and the training command ranges β€” worth checking your adapter against those too.

Thank youπŸ‘

Thanks - exactly the detail I needed. Adjusted and re-run, eight rounds of 1024 run ids per engine.

Fixed: lin_vel_y was 0.17 with nothing behind it, deploy.yaml gives 0.5; last_action now logs the clipped raw value.

Already right, so unchanged: joint_ids_map, the term-by-term stacking (500), and both sines then both cosines.

clobot 0/0 %, 125 cm / 77Β°. clobot_with_arms 9/5 %, 39 cm / 21Β°.

Please verify my work - policies/clobot/policy.cpp is the whole adapter - and send PRs if you find something :) Thanks!

Sign up or log in to comment