This repository is the official implementation of OpenTrack, an open-source humanoid motion tracking codebase that uses MuJoCo JAX for simulation and supports multi-GPU parallel training.
[May 18, 2026] LAFAN1 generalist v2 released. A single policy can accurately track all 40/40 motions in LaFAN1, including highly challenging ones.
[April 24, 2026] DAgger training code released. Now you can distill your teacher trackers into a generalist student tracker.
[November 30, 2025] LAFAN1 generalist v1 released. Now you can track cartwheel, kungfu, fall and getup, and many other motions within a single policy.
[September 19, 2025] Simple Domain Randomization released.
[September 19, 2025] Tracking codebase released.
- Release motion tracking codebase
- Release domain randomization
- Release pretrained LAFAN1 generalist checkpoints
- Release DAgger code
- Release AnyAdapter
- Release real-world deployment code
-
Clone the repository:
git clone git@github.com:GalaxyGeneralRobotics/OpenTrack.git
-
Create a virtual environment and install dependencies:
uv sync -i https://pypi.org/simple
-
Create a
.envfile in the project directory with the following content:export GLI_PATH=<your_project_path> export WANDB_PROJECT=<your_project_name> export WANDB_ENTITY=<your_wandb_entity> export WANDB_API_KEY=<your_wandb_api_key>
-
Download the mocap data and put them under
storage/data/mocap/. Thanks for the retargeting motions of LAFAN1 dataset from LocoMuJoCo!The file structure should be like:
storage βββ assets β βββ mujoco_menagerie β βββ unitree_g1 βββ data β βββ hfield β β βββ terrain.npz β βββ mocap β βββ lafan1 β βββ UnitreeG1 βββ logs β βββ dagger # dagger student checkpoints β βββ track # tracking checkpoints βββ training_configs β βββ dagger β βββ demo.json βββ ... -
Initialize assets
# First, initialize the environment source .venv/bin/activate; source .env; # Then, initialize the assets python track_mj/app/mj_playground_init.py
- Initialize the MuJoCo environment:
source .venv/bin/activate; source .env;-
Download pretrained checkpoints and configs from checkpoints and configs, and put them under
storage/logs/dagger/. Visualization results of LAFAN1 generalist v2: videos. -
Run the evaluation script:
python -m track_mj.eval.dagger.mj_onnx_video --task G1TrackingGeneral --exp_name <your_exp_name> [--use_viewer] [--use_renderer] [--play_ref_motion]
As of May 18, 2026, we have open-sourced LAFAN1 generalist v1 and v2. Generalist v1 is daggered from four teachers and can track most motions. However, it fails on some extremely challenging motions (mainly because some teachers fail to track these motions). Generalist v2 is daggered from eight more carefully designed teachers. Each teacher policy successfully tracks all motions in its motion cluster. The student policy perfectly inherits the capabilities of different teachers and successfully tracked all 40/40 motions.
The checkpoints are trained with simple domain randomization (DR). You may try deploying it on a Unitree G1 robot using your own deployment code, since we have not yet open-sourced our real-robot deployment pipeline.
If you want to train on your own motion data, you should first put the .npz files under storage/data/mocap/<your_dataset_name>/UnitreeG1. Then, you should run the following preprocess script to:
- Align the frequency or the original motion data to the desired control frequency (50Hz by default).
- Recalculate velocities (angular, linear, joint) and other state features based on the aligned frequency.
Note: The preprocess script will overwrite the original motion files.
# Use `num_batches` to split data into multiple batches for parallel processing on multiple GPUs. You should manually launch multiple processes on different GPUs for parallel processing.
python scripts/process_motion/preprocess_motion.py --task G1TrackingGeneral --num_batches XXX --smooth_start_end False
# Or run on a single GPU without parallelism
python scripts/process_motion/preprocess_motion.py --task G1TrackingGeneral --num_batches 1 --smooth_start_end FalseArgument --smooth_start_end True can generate a natural transition motion from the default pose before the original motion.
An inverse-kinematics solver generates a smooth stepping motion from the default pose to the first motion frame. The solver uses QP optimization (OSQP) with foot position/orientation constraints and CoM balance constraints. One or two foot steps are automatically chosen based on the foot-placement gap between default pose and the pose of the first frame.
Here is a comparison of the original motion and the smoothed motion:
| Original Motion | Smoothed Motion |
|---|---|
![]() |
![]() |
python -m track_mj.learning.train.train_ppo_track --task G1TrackingGeneralDR --exp_name <your_exp_name>If you want to modify the training configuration, you should edit the config file associated with the corresponding environment. For example, for the command above, you should modify the g1_tracking_general_dr_task_config in the OpenTrack/track_mj/envs/g1_tracking/train/g1_env_tracking_general_dr.py.
For training on one GPU:
python -m track_mj.learning.train.train_dagger --task G1TrackingGeneralDR --exp_name <your_exp_name> --dagger-config-path <your_config_path>For training on multiple GPUs (8 for example):
torchrun --nproc_per_node=8 -m track_mj.learning.train.train_dagger \
--task G1TrackingGeneralDR \
--exp-name <your_exp_name> \
--dagger-config-path <your_config_path> \
--use_ddpFor an example DAgger config, please refer to storage/training_configs/dagger/demo.json.
In our experiments, we found that our specialist-to-generalist training framework is a flexible, controllable, and scalable approach for building a general tracker. Different teachers can be flexibly assigned to different categories of motions to maximize tracking quality. The capabilities of different teachers can be perfectly inherited by the student. Moreover, the studentβs performance improves significantly with more motion data, more teachers, longer training time, and larger model capacity.
# First, convert the Brax model checkpoint to ONNX
python -m track_mj.app.brax2onnx_tracking --task G1TrackingGeneral --exp_name <your_exp_name>
# Next, run the evaluation script
python -m track_mj.eval.tracking.mj_onnx_video --task G1TrackingGeneral --exp_name <your_exp_name> [--use_viewer] [--use_renderer] [--play_ref_motion] # First, convert the Torch model checkpoint to the ONNX format
python -m track_mj.eval.dagger.torch2onnx --ckpt_dir "storage/logs/dagger/<your_exp_name>"
# This writes ONNX to storage/logs/dagger/<your_exp_name>/checkpoints/model.onnx
# Next, run the evaluation script
python -m track_mj.eval.dagger.mj_onnx_video --task G1TrackingGeneral --exp_name <your_exp_name> [--use_viewer] [--use_renderer] [--play_ref_motion]This repository is build upon jax, brax, loco-mujoco, and mujoco_playground.
If you find this repository helpful, please cite our work:
@misc{zhang2025trackmotionsdisturbances,
title={Track Any Motions under Any Disturbances},
author={Zhikai Zhang and Jun Guo and Chao Chen and Jilong Wang and Chenghuai Lin and Yunrui Lian and Han Xue and Zhenrong Wang and Maoqi Liu and Jiangran Lyu and Huaping Liu and He Wang and Li Yi},
year={2025},
eprint={2509.13833},
archivePrefix={arXiv},
primaryClass={cs.RO},
url={https://arxiv.org/abs/2509.13833},
}
