H2 Whole-Body Motion Tracking Policy

A whole-body control policy for the Unitree H2 (31 DoF, 32 bodies), trained with NVIDIA SONIC / GR00T-WholeBodyControl on the Bones-SEED motion corpus retargeted to H2.

SONIC's released config targets the Unitree G1. This is a port to H2, which required correcting several G1-specific assumptions that resolve on H2 with different meaning (body naming, a reversed ankle chain, wrist DoF indices, actuator limits). Trained from scratch β€” the released G1 checkpoint cannot warm-start a different embodiment.

Simulation only. Never validated on hardware or in a second simulator.

Which file do I want?

Goal File
VR teleoperation (headset + 2 controllers) onnx/model_step_100000_teleop.onnx
Replay motion clips / retargeted data onnx/model_step_100000_g1.onnx
Drive from SMPL human poses onnx/model_step_100000_smpl.onnx
Continue training, or evaluate in Isaac Lab model_step_100000.pt
Split inference (encode off-robot, decode on-robot) onnx/*_encoder.onnx + onnx/*_decoder.onnx

On the g1 in the filename: g1 is the name of the encoder, not the robot. SONIC names its three encoders g1 / teleop / smpl, where g1 means "robot-native full-body motion tracking" β€” so called because the framework was built around the Unitree G1 first. model_step_100000_g1.onnx is an H2 policy: 31 outputs, H2 body names, H2 actuator config. The decoder is likewise named g1_dyn for the same historical reason. Nothing in these files targets a G1.

Always ship onnx/model_config.yaml alongside any ONNX file. It carries the observation layout; the model is not usable without it.

The action contract β€” read before deploying

The network outputs 31 dimensionless numbers, not joint angles. Converting them to something the robot can execute is your side of the contract:

target_angle[j] = default_angle[j] + action[j] * action_scale[j]
torque[j]       = stiffness[j] * (target_angle[j] - actual_angle[j])
                  - damping[j] * actual_velocity[j]
  • policy runs at 50 Hz, PD control at 200 Hz
  • action_scale[j] = 0.25 * effort_limit[j] / stiffness[j]
  • gains derive from rotor inertia: stiffness = armature * w^2, damping = 2 * zeta * armature * w, with w = 2*pi*10 Hz, zeta = 2.0

These constants live in gear_sonic/envs/manager_env/robots/h2.py, not in the ONNX graph. Using the wrong action scale will produce behaviour unrelated to the reported numbers.

H2's rotor inertia is not published anywhere we could find, so the armature values are inherited from G1. We measured the sensitivity: perturbing simulated inertia by 0.5x / 2x / 3x while holding the trained gains fixed changed success rate by under 2 points (paired test over 500 motions, p = 0.16). It is not a significant source of error at that scale, but it is a known unknown.

Three input modes, one policy

One network with three encoders feeding a shared token, so the same weights serve dense and sparse inputs:

  • g1 (full body) β€” all 14 tracked body positions plus future frames (encoder name is historical; this is the H2 full-body path)
  • teleop β€” 3 points only (2 wrists + head) plus lower-body joint angles
  • smpl β€” SMPL human skeleton joints

Evaluation

500 held-out motions, Isaac Lab, encoder mode pinned per run. Termination at 0.25 m root or end-effector error.

mode success mpjpe_l mpjpe_g accel
full body 93.8% 33.3 mm 246.0 mm 1.84
teleop 92.0% 36.2 mm 241.5 mm 2.09
smpl 91.8% 34.3 mm 305.9 mm 2.06

mpjpe_l is root-relative per-joint error, mpjpe_g global.

Teleop landing within 1.8 points of full body β€” given only three points plus leg angles β€” is the result we find most interesting here.

Against NVIDIA's published targets

SONIC's own docs give G1 convergence targets "after 100K iterations", the same unit as this checkpoint:

success mpjpe_l mpjpe_g
NVIDIA target (G1) > 97% < 30 mm < 200 mm
this policy (H2, full body) 93.8% 33.3 mm 246.0 mm

Under target on all three. H2 is a heavier, higher-DoF robot and the corpus differs, so some gap is expected β€” but the figure above is pinned full-body, the most favourable reading, and it is still short. Reported rather than omitted because a user deciding whether to build on this should know.

Known failure concentration, measured over the 500-motion set:

  • reference root below 0.9 m (crouching): ~21% termination vs 6.6% upright
  • peak root speed 1.0–1.5 m/s: 21.7% termination, the worst band
  • reference travel distance does not predict failure

Training

iterations 100,000
envs 4096
wall time 160 h on 8 GPUs
episodes / timesteps 3.28e9 / 7.86e10
corpus Bones-SEED, 142,220 motions retargeted to H2
algorithm ppo_im_phc

Limitations

  • Simulation only. Isaac Sim / Isaac Lab. No MuJoCo cross-check, no hardware.
  • Under NVIDIA's reference bar on every eval metric.
  • ~6% of motions fail, concentrated in crouching and mid-speed locomotion.
  • Global placement lags pose accuracy β€” mpjpe_g is ~7x mpjpe_l. The robot performs the right motion more reliably than it arrives at the right place.
  • Armature inherited from G1 (see the note above).

Attribution

Produced at the USC PSI Lab.

Downloads last month

-

Downloads are not tracked for this model. How to track
Video Preview
loading