T800 / Backflip Retargeting
Moving G1 backflips from an open motion dataset onto the T800 humanoid: 1.227× leg-length retargeting, per-frame IK correction, and MuJoCo kinematic replay rendered at 50 fps. The RL branch failed to produce a policy.
Ran the whole retargeting pipeline: read the reference motion data, mapped it onto the T800 by leg-length ratio, corrected joint angles with per-frame IK, and rendered the clips in MuJoCo. Separately ran an mjlab RL training line that did not succeed.
Portrait phone footage from 2026-10-31, 22 seconds at original speed. A crew line at the head was cut; nothing is sped up.
Two 640×480 simulation clips joined: the front view standing up from lying down, then the back view. No audio.
T800 walking on the left, the reference skeleton in blue on the right, cut side by side. 8 seconds, no audio.
The client's T800 humanoid needed a backflip it could show publicly. The motion came from open data: Unitree G1 backflips from the UniLab dataset, retargeted onto the T800 and rendered to video. The deliverables are six 50 fps clips and two retargeted joint trajectories. The reinforcement learning branch — teaching the T800 to do it on its own — did not work, and is written up separately below.
Three steps: match the scale, solve IK, replay frame by frame
- 01
Retarget by leg-length ratio
First measure the size difference. T800 leg length (pelvis to ankle pitch joint) is 0.923 m; the G1 is 0.752 m — a ratio of 1.227. Each reference frame carries fps, joint_pos (29 joint angles), body_pos_w (31 body positions), body_quat_w (wxyz quaternions) and velocity fields. The pelvis trajectory is scaled by 1.227, orientation is kept, and joint angles are mapped onto the T800's 25 hinges along the matching chains. The T800 has 26 degrees of freedom: 1 floating base plus 25 hinges.
scale 1.227 · 50 fps source · retargeting = mapping a motion from one robot's joint structure onto another
- 02
Correct joint angles with per-frame IK
Mapping joint by joint leaves feet floating and clipping wherever leg length and knee or ankle structure differ. Each frame runs an inverse kinematics solve (IK: given a target end-effector pose, solve for joint angles) with scipy.optimize.least_squares, capped at 200 function evaluations per frame, diff_step 1e-4.
Joint limits come from the T800 model as hard constraints: 0.02 rad margin, ankle pitch ±0.68 rad, knee −0.26…2.35 rad. The output is a qpos(N,32) frame-by-frame trajectory — 225 frames and 198 frames for the two motions, saved with fps, joint_names and scale.
least_squares · max_nfev 200 · diff_step 1e-4 · margin 0.02 rad · ankle ±0.68 rad · knee −0.26…2.35 rad
- 03
Replay and render in MuJoCo
Rendering uses MuJoCo offscreen rendering with no physics stepping: each frame writes qpos straight into the model state, renders one image, and the frames are assembled at 50 fps. So the footage has no contact forces and no balance control; the feet do not slide because the joint angles are locked to the trajectory, not because a solver found friction. Output is 1080p landscape plus 1080×1920 portrait, all on a single RTX 5060 Ti 16GB.
MuJoCo offscreen · 50 fps · 1920×1080 / 1080×1920 · kinematic replay = no physics, pose straight from the trajectory
What shipped
The motion itself works: both reference motions transferred completely, no joint limits were exceeded, nothing clipped, and both aspect ratios are publishable as-is. Two 10-second walking clips (T800 and G1) are included as visual reference.
The boundary matters too: these clips show that the T800 can take this shape, not that it does it by itself. Every joint angle comes from the reference trajectory plus IK correction; no step is produced by a policy network. Foot slip and landing impact were not quantified — in kinematic replay those quantities do not exist, so there was nothing to measure.
The RL branch produced no usable policy
Goal: not replay, but letting the T800 learn in simulation to run up, push off the wall and land — task ZQ-T800-12DOF-Vault, 12-DOF configuration, 2048 parallel environments, about 0.73 s per iteration. Curriculum raised wall height from 0.15 m to 0.55 m, wall thickness 0.18 m, placed 1.6 m ahead of the spawn point.
- The first run crashed at iteration 2488. NaN; NanGuard caught it at step 95022, environment 1189. At the time it looked like a one-off seed or precision problem.
- On restart it turned out not to be one-off but a scene bug. Spawn orientation was randomised over the full −3.14…3.14 rad circle, so half the time the wall sat behind the robot. "Walk to the wall" was never a solvable task. The fix: spawn orientation fixed at 0 rad (facing +x, the wall), random pushes relaxed from every 5 s to every 25–35 s.
- Retrained to iteration 2600, the policy still failed. It walked in a straight line at 0.4 m/s, fell at the wall, terminated every episode at step 200–300, and reward stayed flat at 37–40 with no upward trend. Curriculum wall height never left the lowest band, stuck at 0.16–0.25 m.
- Retrained again to iteration 2284, the second crash. NaN in the critic observations, this time not caught by NanGuard — the run was only discovered to be broken afterwards.
Conclusion: "the T800 learning to vault on its own" was not completed, and not partially completed. Every motion in the videos comes from a reference trajectory; no step is policy output. What this branch leaves behind are two reproducible failure points — a scene configuration error first, insufficient numerical guardrails second.
Technical details / data, parameters, configuration open
Reference motion data
| File | Frames / duration | Source task |
|---|---|---|
| flip_360_001__A304.npz | 225 frames · 4.50 s @ 50 fps | UniLab G1FlipTracking |
| flip_from_wall_104__A304.npz | 198 frames · 3.96 s @ 50 fps | UniLab G1WallFlipTracking |
Fields: fps, joint_pos(N,29), joint_vel, body_pos_w(N,31,3), body_quat_w(N,31,4) (wxyz), body_lin_vel_w, body_ang_vel_w. Data from the public UniLab / Motphys motion set (HuggingFace unilabsim/unilab-motions).
Retargeting output
| File | Content | Metadata |
|---|---|---|
| t800_flip360.npz | qpos(225,32) | fps · joint_names · scale 1.227 |
| t800_wallflip.npz | qpos(198,32) | fps · joint_names · scale 1.227 |
Robot and IK
| Leg length (pelvis → ankle pitch) | T800 0.923 m / G1 0.752 m |
| T800 DOF | 26 = 1 floating base + 25 hinges |
| Solver | scipy.optimize.least_squares, max_nfev 200, diff_step 1e-4 |
| Limits | 0.02 rad margin; ankle pitch ±0.68 rad; knee −0.26…2.35 rad |
| Render | MuJoCo offscreen, 50 fps, 1920×1080 and 1080×1920 |
| Hardware | single RTX 5060 Ti 16GB |
RL training configuration (failed run)
| Stack | mjlab 1.2.0 + rsl_rl 5.0.1 + warp 1.13.0 |
| Task / configuration | ZQ-T800-12DOF-Vault, 12 DOF |
| Parallel environments | 2048, about 0.73 s per iteration |
| Curriculum | wall 0.15 → 0.55 m, 0.18 m thick, 1.6 m along +x from spawn |
| Crash 1 | iteration 2488, NaN, NanGuard at step 95022 / env 1189 |
| Fix | spawn orientation ±3.14 rad random → fixed 0 rad; push interval 5 s → 25–35 s |
| Retrain result | to iteration 2600: straight walk at 0.4 m/s then fall, episodes end at step 200–300, reward 37–40, curriculum stuck at 0.16–0.25 m |
| Crash 2 | iteration 2284, NaN in critic observations, not caught by NanGuard |
What actually works here is the engineering chain: read public motion data, retarget by scale, run per-frame IK to hold limits and ground contact, render two aspect ratios — all on one consumer GPU, with publishable output. The chain's value is that it is reusable: swap the motion or the robot and the code structure holds.
But it demonstrates a pipeline, not motion intelligence. Retargeting plus kinematic replay is standard work in this field; the genuinely hard parts — contact forces, balance, landing impact, foot slip — are bypassed entirely by IK and replay. The footage looks good because the reference motion looks good. The RL branch exposes something more basic: the scene was wrong for 2488 iterations before anyone noticed, and numerical blow-ups happened twice without being caught, which means monitoring and unit checks were never in place. As portfolio material it is honest, reproducible and clearly bounded, which is worth more than claiming "it learned to backflip"; but on technical depth it currently sits at "can deliver a form demo", and is still one training curve away from research — one where the policy climbs the 0.55 m wall by itself.


