Skip to content

Software

GMR (General Motion Retargeting)

From github.com/YanjieZe/GMR (opens in a new tab)

  • Humanoids and robot learning
  • Tool
  • MIT

GMR is an open-source Python library that retargets human motion data onto many humanoid robots in real time, for whole-body teleoperation and training motion-tracking policies.

Facts

GitHub stars
2,818read on 6 Nov 2026
Last update
22 Oct 2026Newest commit on master
Maintenance
Activea commit in the last 90 days
Difficulty
Advanced
Hardware it needs, as the project states it
Tested on Ubuntu 22.04/20.04 with Python 3.10 in a conda environment. Speed benchmark: an AMD Ryzen Threadripper 7960X reaches 60~70 FPS and a 13th Gen Intel Core i9-13900K reaches 35~45 FPS. SMPL-X body model files are required for SMPL-X data.

Checked on GitHub on 6 Nov 2026.

Licenses

Code
MIT (opens in a new tab)

Read by Robotheca from LICENSE (opens in a new tab) (MIT) at commit 25f56db (opens in a new tab), on 23 Oct 2026.

Commercial use
Yes

Overview

What it does: Robotheca's summary

  • Retargets human motion to humanoid robot joint positions in real time, suited to whole-body teleoperation.
  • Tuned to give good performance for reinforcement-learning motion tracking policies.
  • Supports numerous humanoid robots, switchable by changing one argument.
  • Accepts several human motion formats: SMPL-X (AMASS, OMOMO), BVH (LAFAN1, Nokov, Xsens), FBX from OptiTrack, PICO streaming, and GVHMR video pose extraction.
  • Provides scripts for single-motion and batch retargeting, live streaming, and visualizing saved robot motion in MuJoCo.
  • Can convert retargeted pickle files to CSV for BeyondMimic.

Written by Robotheca from the project's README (opens in a new tab) at commit bb1bbe4, not by its creator.

The README

The creator's own README, copied as written: README.md by @YanjieZe, at commit 25f56db, under MIT (opens in a new tab). The original on GitHub (opens in a new tab).

Read the README here

GMR: General Motion Retargeting

(opens in a new tab) (opens in a new tab) (opens in a new tab) (opens in a new tab) (opens in a new tab) (opens in a new tab) (opens in a new tab)

Banner for GMR

GMR

Key features of GMR:
  • Real-time high-quality retargeting, unlock the potential of real-time whole-body teleoperation, i.e., TWIST (opens in a new tab).
  • Carefully tuned for good performance of RL tracking policies.
  • Support multiple humanoid robots and multiple human motion data formats (See our table below).

[!NOTE] If you want this repo to support a new robot or a new human motion data format, send the robot files (.xml, .urdf, and meshes) / human motion data to Yanjie Ze (opens in a new tab) or create an issue, we will support it as soon as possible. And please make sure the robot files you sent can be open-sourced in this repo.

This repo is licensed under the MIT License (opens in a new tab).

News & Updates

Demos
  Retargeting LAFAN1 dancing motion to 5 robots.

  

Watch this video on GitHub (opens in a new tab)

</td>
<td align="center" width="20%">
  <b>Demo 2</b>

  Galexea R1 Pro robot (view 1).

  

Watch this video on GitHub (opens in a new tab)

</td>
<td align="center" width="20%">
  <b>Demo 3</b>

  Galexea R1 Pro robot (view 2).

  

Watch this video on GitHub (opens in a new tab)

</td>
<td align="center" width="20%">
  <b>Demo 4</b>

  Switching robots by changing one argument.

  

Watch this video on GitHub (opens in a new tab)

</td>
<td align="center" width="20%">
  <b>Demo 5</b>

  HighTorque robot doing a twist dance.

  

Watch this video on GitHub (opens in a new tab)

</td>
  Kuavo robot picking up a box.

  

Watch this video on GitHub (opens in a new tab)

</td>
<td align="center">
  <b>Demo 7</b>

  Unitree H1 robot doing a ChaCha dance.

  

Watch this video on GitHub (opens in a new tab)

</td>
<td align="center">
  <b>Demo 8</b>

  Booster T1 robot jumping (view 1).

  

Watch this video on GitHub (opens in a new tab)

</td>
<td align="center">
  <b>Demo 9</b>

  Booster T1 robot jumping (view 2).

  

Watch this video on GitHub (opens in a new tab)

</td>
<td align="center">
  <b>Demo 10</b>

  Unitree H1-2 robot jumping.

  

Watch this video on GitHub (opens in a new tab)

</td>
  PND Adam Lite robot.

  

Watch this video on GitHub (opens in a new tab)

</td>
<td align="center">
  <b>Demo 12</b>

  Tienkung robot walking.

  

Watch this video on GitHub (opens in a new tab)

</td>
<td align="center">
  <b>Demo 13</b>

  Extracting human pose (GVHMR + GMR).

▶ Watch on Bilibili (opens in a new tab) Demo 14

  PAL Robotics’ Talos robot fighting.

  

Watch this video on GitHub (opens in a new tab)

</td>
<td align="center">
  <b>Demo 15</b>

  (Optional placeholder if you add a new one later!)

  <i>Coming soon...</i>
</td>
Supported Robots and Data Formats
Assigned IDRobot/Data FormatRobot DoFSMPLX (AMASS (opens in a new tab), OMOMO (opens in a new tab))BVH LAFAN1 (opens in a new tab)FBX (OptiTrack (opens in a new tab))BVH Nokov (opens in a new tab)PICO (XRoboToolkit (opens in a new tab))More formats coming soon
0Unitree G1 unitree_g1Leg (2*6) + Waist (3) + Arm (2*7) = 29✅✅✅✅✅
1Unitree G1 with Hands unitree_g1_with_handsLeg (2*6) + Waist (3) + Arm (2*7) + Hand (2*7) = 43✅✅✅TBDTBD
2Unitree H1 unitree_h1Leg (2*5) + Waist (1) + Arm (2*4) = 19✅TBDTBDTBDTBD
3Unitree H1 2 unitree_h1_2Leg (2*6) + Waist (1) + Arm (2*7) = 27✅TBDTBDTBDTBD
4Booster T1 booster_t1TBD✅TBDTBDTBD
5Booster T1 29dof booster_t1_29dofTBD✅✅TBDTBD
6Booster K1 booster_k1Neck (2) + Arm (2*4) + Leg (2*6) = 22✅TBDTBDTBD
7Stanford ToddlerBot stanford_toddyTBD✅✅TBDTBD
8Fourier N1 fourier_n1TBD✅✅TBDTBD
9ENGINEAI PM01 engineai_pm01TBD✅✅TBDTBD
10HighTorque Hi hightorque_hiHead (2) + Arm (2*5) + Waist (1) + Leg (2*6) = 25✅TBDTBDTBD
11Galaxea R1 Pro galaxea_r1pro (this is a wheeled robot!)Base (6) + Torso (4) + Arm (2*7) = 24✅TBDTBDTBD
12Kuavo kuavo_s45Head (2) + Arm (2*7) + Leg (2*6) = 28✅TBDTBDTBD
13Berkeley Humanoid Lite berkeley_humanoid_lite (need further tuning)Leg (2*6) + Arm (2*5) = 22✅TBDTBDTBD
14PND Adam Lite pnd_adam_liteLeg (2*6) + Waist (3) + Arm (2*5) = 25✅TBDTBDTBD
15Tienkung tienkungLeg (2*6) + Arm (2*4) = 20✅TBDTBDTBD
16PAL Robotics' Talos pal_talosHead (2) + Arm (2*7) + Waist (2) + Leg (2*6) = 30✅TBDTBDTBD
17Fourier GR3 fourier_gr3Head (2) + Arm (2*7) + Waist (3) + Leg (2*6) = 31✅TBDTBDTBD
18Unitree H2 unitree_h2Leg (2*6) + Waist (3) + Arm (2*7) = 29 (head fixed in the MJCF)TBD✅TBDTBDTBD
More robots coming soon !
19AgiBot A2 agibot_a2TBDTBDTBDTBDTBD
20OpenLoong openloongTBDTBDTBDTBDTBD
Installation

[!NOTE] The code is tested on Ubuntu 22.04/20.04.

If you do not have uv (opens in a new tab) installed, run:

curl -LsSf https://astral.sh/uv/install.sh | sh

Then, from the repo root:

uv sync

That's it. You can now run every command in this README directly through uv run, no environment activation needed.

First create your conda environment:

conda create -n gmr python=3.10 -y
conda activate gmr

Then, install GMR:

pip install -e .

With this setup, run the uv run <script> commands in this README as python <script> inside the activated environment.

And to resolve some possible rendering issues:

conda install -c conda-forge libstdcxx-ng -y
Data Preparation

[SMPLX (opens in a new tab) body model] download SMPL-X body models to assets/body_models from SMPL-X (opens in a new tab) and then structure as follows:

- assets/body_models/smplx/
-- SMPLX_NEUTRAL.pkl
-- SMPLX_FEMALE.pkl
-- SMPLX_MALE.pkl

[AMASS (opens in a new tab) motion data] download raw SMPL-X data to any folder you want from AMASS (opens in a new tab). NOTE: Do not download SMPL+H data.

[OMOMO (opens in a new tab) motion data] download raw OMOMO data to any folder you want from this google drive file (opens in a new tab). And process the data into the SMPL-X format using scripts/convert_omomo_to_smplx.py.

[LAFAN1 (opens in a new tab) motion data] download raw LAFAN1 bvh files from the official repo (opens in a new tab), i.e., lafan1.zip (opens in a new tab).

Human/Robot Motion Data Formulation

To better use this library, you can first have an understanding of the human motion data we use and the robot motion data we obtain.

Each frame of human motion data is formulated as a dict of (human_body_name, 3d global translation + global rotation). The rotation is usually represented as quaternion (with wxyz order by default, to align with mujoco).

Each frame of robot motion data can be understood as a tuple of (robot_base_translation, robot_base_rotation, robot_joint_positions).

Usage
[NEW] PICO Streaming to Robot (TWIST2)

Install PICO SDK:

  1. On your PICO, install PICO SDK: see here (opens in a new tab).
  2. On your own PC,
    • Download deb package for ubuntu 22.04 (opens in a new tab), or build from the repo source (opens in a new tab).
    • To install, use command
      sudo dpkg -i XRoboToolkit_PC_Service_1.0.0_ubuntu_22.04_amd64.deb
      
      then you should see xrobotoolkit-pc-service in your APPs. remember to start this app before you do teleopperation.
    • Build PICO PC Service SDK and Python SDK for PICO streaming:
      git clone https://github.com/YanjieZe/XRoboToolkit-PC-Service-Pybind.git
      cd XRoboToolkit-PC-Service-Pybind
      
      mkdir -p tmp
      cd tmp
      git clone https://github.com/XR-Robotics/XRoboToolkit-PC-Service.git
      cd XRoboToolkit-PC-Service/RoboticsService/PXREARobotSDK 
      bash build.sh
      cd ../../../..
      
      
      mkdir -p lib
      mkdir -p include
      cp tmp/XRoboToolkit-PC-Service/RoboticsService/PXREARobotSDK/PXREARobotSDK.h include/
      cp -r tmp/XRoboToolkit-PC-Service/RoboticsService/PXREARobotSDK/nlohmann include/nlohmann/
      cp tmp/XRoboToolkit-PC-Service/RoboticsService/PXREARobotSDK/build/libPXREARobotSDK.so lib/
      # rm -rf tmp
      
      # Install into GMR's environment from the GMR repo root.
      cd PATH/TO/GMR
      uv pip install pybind11 cmake
      uv pip install --no-build-isolation PATH/TO/XRoboToolkit-PC-Service-Pybind
      

You should be all set!

To try it, check this script from TWIST2 (opens in a new tab):

bash teleop.sh

You should be able to see the retargeted robot motion in a mujoco window.

Retargeting from SMPL-X (AMASS, OMOMO) to Robot

[!NOTE] NOTE: after install SMPL-X, change ext in smplx/body_models.py from npz to pkl if you are using SMPL-X pkl files.

Retarget a single motion:

uv run scripts/smplx_to_robot.py --smplx_file <path_to_smplx_data> --robot <path_to_robot_data> --save_path <path_to_save_robot_data.pkl> --rate_limit

By default you should see the visualization of the retargeted robot motion in a mujoco window. If you want to record video, add --record_video and --video_path <your_video_path,mp4>.

  • --rate_limit is used to limit the rate of the retargeted robot motion to keep the same as the human motion. If you want it as fast as possible, remove --rate_limit.

Retarget a folder of motions:

uv run scripts/smplx_to_robot_dataset.py --src_folder <path_to_dir_of_smplx_data> --tgt_folder <path_to_dir_to_save_robot_data> --robot <robot_name>

By default there is no visualization for batch retargeting.

Retargeting from GVHMR to Robot

First, install GVHMR by following their official instructions (opens in a new tab).

And run their demo that can extract human pose from monocular video:

cd PATH/TO/GVHMR
python tools/demo/demo.py --video=docs/example_video/tennis.mp4 -s

Then you should obtain the saved human pose data in GVHMR/outputs/demo/tennis/hmr4d_results.pt.

Then, run the command below to retarget the extracted human pose data to your robot:

uv run scripts/gvhmr_to_robot.py --gvhmr_pred_file <path_to_hmr4d_results.pt> --robot unitree_g1 --record_video
Retargeting from BVH (LAFAN1, Nokov) to Robot

Retarget a single motion:

# single motion
uv run scripts/bvh_to_robot.py --bvh_file <path_to_bvh_data> --robot <path_to_robot_data> --save_path <path_to_save_robot_data.pkl> --rate_limit --format <format>

By default you should see the visualization of the retargeted robot motion in a mujoco window.

  • --rate_limit is used to limit the rate of the retargeted robot motion to keep the same as the human motion. If you want it as fast as possible, remove --rate_limit.
  • --format is used to specify the format of the BVH data. Supported formats are lafan1 and nokov.

Retarget a folder of motions:

uv run scripts/bvh_to_robot_dataset.py --src_folder <path_to_dir_of_bvh_data> --tgt_folder <path_to_dir_to_save_robot_data> --robot <robot_name>

By default there is no visualization for batch retargeting.

Retargeting from Xsens to Robot
Offline: Xsens BVH to Robot
Visualize Xsens BVH Data using MuJoCo

Install PyQt6:

pip install PyQt6 PyQt6-Qt6 PyQt6-sip
uv run general_motion_retargeting/utils/xsens_vendor/mujoco_xsens_bvh_view.py \
  --bvh_file <path_to_dir_of_bvh_data> \
  --scale <displacement scaling size> \
  --reset_to_zero

like

uv run general_motion_retargeting/utils/xsens_vendor/mujoco_xsens_bvh_view.py \
  --scale 0.01 \
  --bvh_file assets/xsens_bvh_test/251021_04_boxing_120Hz_cm_3DsMax.bvh \
  --reset_to_zero
  • --start is used to specify the initial processing frame. If no input is given, processing will start from the first frame by default.

  • --end is used to specify the final processing frame. If not input, it will be processed by default to the last frame.

  • --reset_to_zero is used to reset the displacement and Z-axis rotation to zero.This function, when used in combination with --start, will set the data to the initial zero position very well.Because sometimes the first one or two frames of some datasets differ too much from the subsequent data, these data need to be discarded.

  • --scale is used to set the scaling value of the displacement, which depends on the relationship between the unit used for the displacement in the dataset and the meter.

  • Before using it, you must install PyQt6. pip install PyQt6
  • Upon executing this command, a UI interface will be launched, enabling you to adjust the angle values for each channel in the x, y, and z directions of every joint. After completing the adjustments, click the "Apply and Preview" button, which will generate an offset.json file locally and perform a MuJoCo visualization playback of the BVH file. When running xsens_bvh_to_robot.py, it will read the data from this JSON file. Therefore, you need to execute mujoco_xsens_bvh_view.py prior to using xsens_bvh_to_robot.py for motion retargeting, to ensure that the offset.json file exists locally.
Retarget a single motion:
# single motion
uv run scripts/xsens_bvh_to_robot.py \
  --bvh_file <path_to_bvh_data> \
  --robot <path_to_robot_data> \
  --save_path <path_to_save_robot_data.pkl> \
  --rate_limit \
  --start <number of the first frame> \
  --scale <displacement scaling size> \
  --reset_to_zero \
  --bvh_format <exported bvh format>

like

uv run scripts/xsens_bvh_to_robot.py  \
  --robot unitree_h1_2 \
  --scale 0.01 \
  --reset_to_zero \
  --bvh_format 3DSM \
  --bvh_file assets/xsens_bvh_test/251021_04_boxing_120Hz_cm_3DsMax.bvh \
  --save_path retargeting_data/h1/251021_04_boxing_120Hz_cm_3DsMax.pkl
By default you should see the visualization of the retargeted robot motion in a mujoco window.
  • --rate_limit is used to limit the rate of the retargeted robot motion to keep the same as the human motion. If you want it as fast as possible, remove --rate_limit.

  • --start is used to specify the initial processing frame. If no input is given, processing will start from the first frame by default.

  • --end is used to specify the final processing frame. If not input, it will be processed by default to the last frame.

  • --reset_to_zero is used to reset the displacement and Z-axis rotation to zero.This function, when used in combination with --start, will set the data to the initial zero position very well.Because sometimes the first one or two frames of some datasets differ too much from the subsequent data, these data need to be discarded.

  • --scale is used to set the scaling value of the displacement, which depends on the relationship between the unit used for the displacement in the dataset and the meter.

!!!!!!!!!!!!!!!!!! ATTENTION !!!!!!!!!!!!!!!!!!!!
  • --bvh_format is used to set the format of the bvh being parsed. In the Xsens MVN software, BVH files in three formats can be exported. There will be some differences among BVH files in different formats. Here I recommend using the 3D Studio Max format.(In fact, I have not yet completed the parsing of data in other formats.)

  • The exported pkl file will represent quaternions in the wxyz format. ^ _ ^


Online Streaming (Xsens MVN)

Stream live motion data from Xsens MVN Software directly into GMR for real-time robot retargeting.

1. Install the Xsens MVN UDP Data Parser

The xsens_mvn_robot_python library parses the Xsens MVN network datagram (Position + Orientation in quaternion format) into Python-accessible data structures. Install the correct .whl file for your Python version.

# Clone the parser repository
git clone https://github.com/jiminghe/xsens_mvn_robot_python.git
cd xsens_mvn_robot_python

# Install the matching wheel for your Python version
# Example for Python 3.10:
pip install xsens_mvn_robot_python-*-cp310-*.whl

Select the .whl file whose filename contains your Python version tag (e.g. cp310 for Python 3.10, cp38 for Python 3.8). This library handles UDP socket binding and datagram unpacking automatically.

2. Configure the Xsens MVN Network Streamer

Launch Xsens MVN Software on either Windows or Linux. You can stream from a live recording session while wearing the Xsens Link / Awinda suit, or replay a previously recorded .mvn file.

StepAction
1Click Options → Network Streamer
2In the pop-up window, click Add to create a new stream destination
3Set the Host Address (see table below)
4Under Network Streamer Options, tick Position + Orientation (Quaternion) only
5No other data sources are needed for GMR retargeting
6Click OK — confirm green status on the streamer

Host Address Reference:

ScenarioHost Address Setting
MVN on the same Linux machine (MVN Linux)127.0.0.1 (localhost)
MVN on Windows → streaming to Ubuntu (same LAN)Ubuntu IP address, e.g. 192.168.1.10

Important: When streaming from a Windows PC to an Ubuntu computer, ensure both machines are on the same LAN. Disable Windows Firewall for the MVN application or create an inbound UDP rule on the MVN default port (9763).

3. Run the GMR Live Streaming Script

With the Xsens MVN Network Streamer active, run the live-streaming retargeting script. A MuJoCo window will open showing the retargeted Unitree G1 robot mirroring your movements in real time.

uv run scripts/xsens_live_streaming.py
Retargeting from FBX (OptiTrack) to Robot
Offline FBX Files

Retarget a single motion:

  1. Install fbx_sdk by following these instructions (opens in a new tab) and these instructions (opens in a new tab). You will probably need a new conda environment for this.

  2. Activate the conda environment where you installed fbx_sdk. Use the following command to extract motion data from your .fbx file:

cd third_party
python poselib/fbx_importer.py --input <path_to_fbx_file.fbx> --output <path_to_save_motion_data.pkl> --root-joint <root_joint_name> --fps <fps>
  1. Then, run the command below to retarget the extracted motion data to your robot:
# single motion
uv run scripts/fbx_offline_to_robot.py --motion_file <path_to_saved_motion_data.pkl> --robot <path_to_robot_data> --save_path <path_to_save_robot_data.pkl> --rate_limit

By default you should see the visualization of the retargeted robot motion in a mujoco window.

  • --rate_limit is used to limit the rate of the retargeted robot motion to keep the same as the human motion. If you want it as fast as possible, remove --rate_limit.
Online Streaming

We provide the script to use OptiTrack MoCap data for real-time streaming and retargeting.

Usually you will have two computers, one is the server that installed with Motive (Desktop APP for OptiTrack) and the other is the client that installed with GMR.

Find the server ip (the computer that installed with Motive) and client ip (your computer). Set the streaming as follows:

OptiTrack Streaming

And then run:

uv run scripts/optitrack_to_robot.py --server_ip <server_ip> --client_ip <client_ip> --use_multicast False --robot unitree_g1

You should see the visualization of the retargeted robot motion in a mujoco window.

Visualize saved robot motion

Visualize a single motions:

uv run scripts/vis_robot_motion.py --robot <robot_name> --robot_motion_path <path_to_save_robot_data.pkl>

If you want to record video, add --record_video and --video_path <your_video_path,mp4>.

Visualize a folder of motions:

uv run scripts/vis_robot_motion_dataset.py --robot <robot_name> --robot_motion_folder <path_to_save_robot_data_folder>

After launching the MuJoCo visualization window and clicking on it, you can use the following keyboard controls::

  • [: play the previous motion
  • ]: play the next motion
  • space: toggle play/pause
Speed Benchmark
CPURetargeting Speed
AMD Ryzen Threadripper 7960X 24-Cores60~70 FPS
13th Gen Intel Core i9-13900K 24-Cores35~45 FPS
TBDTBD
Citation

If you find our code useful, please consider citing our related papers:

@article{joao2025gmr,
  title={Retargeting Matters: General Motion Retargeting for Humanoid Motion Tracking},
  author= {Joao Pedro Araujo and Yanjie Ze and Pei Xu and Jiajun Wu and C. Karen Liu},
  year= {2025},
  journal= {arXiv preprint arXiv:2510.02252}
}
@article{ze2025twist,
  title={TWIST: Teleoperated Whole-Body Imitation System},
  author= {Yanjie Ze and Zixuan Chen and João Pedro Araújo and Zi-ang Cao and Xue Bin Peng and Jiajun Wu and C. Karen Liu},
  year= {2025},
  journal= {arXiv preprint arXiv:2505.02833}
}

and this github repo:

@software{ze2025gmr,
  title={GMR: General Motion Retargeting},
  author= {Yanjie Ze and João Pedro Araújo and Jiajun Wu and C. Karen Liu},
  year= {2025},
  url= {https://github.com/YanjieZe/GMR},
  note= {GitHub repository}
}
Known Issues

Designing a single config for all different humans is not trivial. We observe some motions might have bad retargeting results. If you observe some bad results, please let us know! We now have a collection of such motions in TEST_MOTIONS.md (opens in a new tab).

Acknowledgement

Our IK solver is built upon mink (opens in a new tab) and mujoco (opens in a new tab). Our visualization is built upon mujoco (opens in a new tab). The human motion data we try includes AMASS (opens in a new tab), OMOMO (opens in a new tab), and LAFAN1 (opens in a new tab).

The original robot models can be found at the following locations:

Files and versions

Facts read at commit 25f56db

Robotheca read the repository at two versions: the summary at bb1bbe4 and the facts and the README at 25f56db (read on 6 Nov 2026).

Robotheca never hosts the code: each link goes to the creator's own page.

Use it

How to install it, in the creator's words: The project's README (opens in a new tab)

Robotheca doesn't review code. Read it before running it.

Robotheca lists software as a reference: nothing is hosted or run here, and every fact links to where it was read.