G1 motion tracking policies
Whole-body control policies that make a Unitree G1 humanoid follow human motion capture clips in simulation. One policy per motion.
The pipeline behind them: human mocap โ retargeting to the G1 โ reference motion โ policy training. Stages 1 to 3 have no physics; physics enters at stage 4, where the robot has to hold itself up.
What is here
policies/<sequence>/ holds one trained policy each.
model_29999.ptโ RSL-RL checkpoint at (30,000) iterationspolicy.onnxโ the actor network exported for inference, 160 in and 29 outrun_name.txtโ the training run folder the checkpoint came from
eval/<sequence>.json holds the measured numbers for that policy.
How to run a policy
policy.onnx is the actor network on its own. It takes one observation vector
and returns one action. It holds no reference motion, so the caller supplies the
reference terms.
The observation is 160 values concatenated in this order.
| index | term | dim |
|---|---|---|
| 0:29 | reference joint position at the current motion frame | 29 |
| 29:58 | reference joint velocity at the current motion frame | 29 |
| 58:61 | motion anchor position in the robot anchor frame | 3 |
| 61:67 | motion anchor orientation, first two columns of the rotation matrix | 6 |
| 67:70 | base linear velocity in the base frame | 3 |
| 70:73 | base angular velocity in the base frame | 3 |
| 73:102 | joint position relative to the default pose | 29 |
| 102:131 | joint velocity relative to the default pose | 29 |
| 131:160 | previous action | 29 |
The action is an offset on the joint position target: target = default joint position + action, for all (29) joints. Control runs at (50) Hz (sim step (0.005) s, decimation (4)), the same rate as the reference motion.
import numpy as np, onnxruntime as ort
sess = ort.InferenceSession("policies/walk1_subject1/policy.onnx")
obs = np.zeros((1, 160), dtype=np.float32) # fill as in the table above
action = sess.run(["actions"], {"obs": obs})[0] # (1, 29)
Joint order is the articulation order of the G1 asset used by BeyondMimic. Read it from the environment rather than assuming one.
How they were trained
BeyondMimic on Isaac Sim (5.1) and Isaac Lab (2.3.2), PPO, (4,096) environments, (30,000) iterations, one policy per motion. The reference motions come from LAFAN1 retargeted to the G1 with GMR.
Reward is tracking accuracy against the reference, not gait plausibility.
Results
Measured over (100) rollouts with domain randomization off. Completion rate is the share of rollouts that reach the end of the clip without the anchor body crossing a height or orientation threshold. The error column is the mean global body position error over all rollouts.
| sequence | completion | mean alive | E_g-mpbpe (mm) |
|---|---|---|---|
| aiming1_subject1 | 100% | 100% | 89 |
| dance2_subject3 | 100% | 100% | 103 |
| obstacles2_subject1 | 0% | 18% | 368 |
| walk1_subject1 | 99% | 99% | 83 |
| walk2_subject1 | 100% | 100% | 114 |
| walk2_subject4 | 99% | 100% | 90 |
| walk3_subject2 | 100% | 100% | 79 |
| walk3_subject4 | 0% | 88% | 116 |
| walk4_subject1 | - | - | - |
obstacles2_subject1 fails on purpose to be informative: that clip has the actor
climbing stairs, with the pelvis above (1.05 m) for (48.7) seconds. The training
ground is flat, so the reference is not reachable and the error never drops. It
is kept here as a record of what the selection criterion missed, since the
criterion only looked at retargeting foot error and never asked whether the
target was physically possible on flat ground.
Source data and license
The reference motions derive from LAFAN1 by Ubisoft, released under CC BY-NC-ND 4.0. That license does not permit sharing adapted material, so the retargeted motion data is not included here โ only the trained weights and the measured numbers. The onnx export carries the actor network alone and no reference motion.
Use is non-commercial. Credit Ubisoft for LAFAN1.