# unitree_lerobot: training and testing LeRobot policies on G1 dexterous hand data

> A modification of the LeRobot training framework that adds Unitree data conversion, a dataset editor and real machine inference for the G1 humanoid with dexterous hands. The useful part is the Unitree-specific glue, and the cost is a vendored copy of LeRobot pinned to one commit.

**unitreerobotics/unitree_lerobot** — The unitree_il_lerobot open-source project is a modification of the LeRobot open-source training framework, enabling the training and testing of data collected using the dual-arm dexterous hands of Unitree's G1 robot. 

- Repository: https://github.com/unitreerobotics/unitree_lerobot
- Stars: 781 · Forks: 138
- Language: Python
- License: NOASSERTION
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/unitreerobotics-unitree-lerobot

## What sits on top of LeRobot, and what does not

unitree_lerobot is not a new training framework. It is a modification of the LeRobot framework aimed at one concrete job: training and testing on data collected with the dual-arm dexterous hands of the Unitree G1 robot. The repository description says exactly that, and the scope in practice matches the description.

The top-level layout shows what the project adds on top of the upstream code. A directory named lerobot holds the LeRobot training code, with its corresponding commit version number given as 0878c68. A directory named utils holds the Unitree data processing tooling. A directory named eval_robot holds real machine inference verification of the model. On disk you also find data_editor for cleaning episodes, a docs directory, a test directory, a pyproject.toml, a pre-commit config and a .gitmodules file.

That split is the mental model worth keeping. Anything that is policy training, dataset format or evaluation harness logic lives in the vendored lerobot copy, and it will move only when a maintainer updates the pinned commit. Anything Unitree specific lives in utils, eval_robot and data_editor, and it changes on the project's own schedule. The description also mentions training and testing of data collected using the dual-arm dexterous hands, and the release notes show that support widened over time to other hands, including brainco and inspire1, and to the G1 with Dex1 and Dex3 hardware combinations.

Intended users are robotics engineers who have already committed to LeRobot as their training stack and who need their Unitree-recorded episodes in a format that LeRobot can read.

## A vendored LeRobot snapshot pinned to one commit

The largest structural decision in this repository is that it ships LeRobot as a git submodule rather than depending on the upstream package from PyPI. The clone command uses the --recurse-submodules flag, and a separate git submodule update --init --recursive call exists for checkouts that already downloaded the code.

The benefit is reproducibility. The training code is frozen at a known state, the 0878c68 commit recorded in the directory table, so a training run months from now uses the same policy implementations that produced the shipped results. The cost is upgrade work. Pulling in upstream LeRobot changes means resolving the diff between your pinned commit and current upstream by hand, and the project ships no automated merge tooling for that.

The release history shows what those merges involve. The v2.0 release added support for LeRobot v2.0 data conversion and for training and deployment with act, diffusion and pi0 policies. The v3.0 release updated the dataset format to v3.0 and added support for the pi0.5 and groot policies, whose source it points to in the upstream LeRobot tree. Each of those is a merge across the pinned commit, and each one produced a new tag. The README documents those releases under version headings v0.1, v0.2 and v0.3, where v0.1 covers data conversion, model deployment and real-world testing for the G1 with Dex1 and Dex3.

So expect a version of the framework that is one or more releases behind upstream, and expect the gap to widen as upstream moves.

## Setting up the conda environment and both packages

The setup has three layers: a conda environment with specific packages, an editable install of the vendored LeRobot, and an editable install of unitree_lerobot itself. The README gives the first two layers as a single sequence.

```bash
# Clone the source code
git clone --recurse-submodules https://github.com/unitreerobotics/unitree_lerobot.git

# If already downloaded:
git submodule update --init --recursive

# Create a conda environment
conda create -y -n unitree_lerobot python=3.10
conda activate unitree_lerobot
conda install pinocchio -c conda-forge
```

The environment name is unitree_lerobot, and the interpreter is pinned to Python 3.10, which matches the requires-python constraint of >=3.10,<3.11 in pyproject.toml. That narrow range is a real constraint: a system with Python 3.11 installed will not satisfy the package metadata, so the conda environment is not a convenience but the supported path.

```bash
conda install ffmpeg=7.1.1 -c conda-forge

# Install LeRobot
cd unitree_lerobot/lerobot && pip install -e .

# Install unitree_lerobot
cd ../../ && pip install -e .
```

Both installs are editable, so edits to the source take effect without reinstalling. ffmpeg is pinned to 7.1.1, which matters for video decoding of camera streams in the dataset.

Robot communication needs a separate SDK. For DDS communication on Unitree robots, the README asks you to install unitree_sdk2_python.

```bash
git clone https://github.com/unitreerobotics/unitree_sdk2_python.git
cd unitree_sdk2_python  && pip install -e .
```

Notice that the unitree_sdk2py dependency line in pyproject.toml is commented out, so a plain pip install of the project does not pull the SDK for you. On a machine without the SDK, the evaluation path fails at import time rather than at install time.

## Loading the recorded G1 dataset and visualizing an episode

You can skip recording and start from a dataset the project already published. The example in the README loads unitreerobotics/G1_Dex3_ToastedBread_Dataset from Hugging Face through the standard LeRobotDataset class. The default download location is ~/.cache/huggingface/lerobot/unitreerobotics, and the root parameter is what you change to point at a local copy instead.

```python
from lerobot.datasets.lerobot_dataset import LeRobotDataset
import tqdm

episode_index = 1
dataset = LeRobotDataset(repo_id="unitreerobotics/G1_Dex3_ToastedBread_Dataset")

from_idx = dataset.meta.episodes["dataset_from_index"][episode_index]
to_idx = dataset.meta.episodes["dataset_to_index"][episode_index]

for step_idx in tqdm.tqdm(range(from_idx, to_idx)):
    step = dataset[step_idx]
```

The indexing scheme is worth understanding rather than copying. The metadata table holds a dataset_from_index and a dataset_to_index per episode, and the loop walks the flattened step range between them. This is the v2.0 and above episode layout that the repository says it supports, and it is why the project needs recent LeRobot dataset conventions rather than only the original one.

For a visual check, the upstream visualization script is included in the vendored copy.

```bash
cd unitree_lerobot/lerobot

python src/lerobot/scripts/lerobot_dataset_viz.py \
    --repo-id unitreerobotics/G1_Dex3_ToastedBread_Dataset \
    --episode-index 0
```

If the window opens and you see the recorded camera views and joint values for episode 0, the dataset is readable and the environment is wired correctly.

## The data editor is a PyQt5 desktop app, not a pipeline step

Recorded episodes often contain failures, and the project treats cleaning as a first-class step. The stated reason is quality: if an episode failed to complete the task, you need to delete it, and excess segments should be cut out. The data editor handles both, through a graphical interface rather than a command line.

PyQt5 is required and is not in the dependency list, so it has to be installed by hand.

```bash
conda activate unitree_lerobot
pip install PyQt5
```

The editor then runs from the data_editor directory.

```bash
cd data_editor
python data_editor_EN.py
```

The interaction is mouse driven. You pick the dataset root with the Select Dataset Path button, for example a tree of episode_0001, episode_0003 and episode_0004 directories. You drag the red line to seek playback, hold Shift while dragging to select a range, and press Trim Selected Range to cut the selected part. Delete Current Episode removes the episode you are on.

This design is the main ergonomic limit of the project. A headless training server, a CI pipeline or a cluster cannot run the editor, and every manual trim is a decision a person makes by eye. Automating dataset cleaning means writing your own code against the LeRobot dataset structures, not calling something in utils. The pyproject.toml does declare tyro for command line argument parsing, so the CLI dependency exists, but the trimming flow documented in the README is the GUI.

## Where the packaging details hint at unfinished edges

The pyproject.toml is short, and a few lines in it are more telling than the release notes. The dependency list contains tyro, matplotlib, a pinned meshcat at 0.3.2 and logging_mp at 0.2.1, and nothing else of substance. The unitree_sdk2py entry is commented out, as noted above. The version is 0.3.0, and the project description in the metadata calls it unitree data conversion and real machine inference verification, which is a narrower description than the repository description at the top of the README, which frames the project around training and testing.

The tooling configuration is also partly inert. The ruff lint rule selection and ignore list are commented out, so only the default rule set runs, and the bandit configuration skips several checks by name. A pre-commit config exists, so formatting is enforced at commit time even though lint selection is not.

None of this is a blocker, and it does not affect the training path. It does mean the repository is a 0.3.x project whose packaging is still being shaped, and that the version numbering has a rough edge: the git tags are v0.1, v0.2 and v0.3 in the README while the GitHub releases list v2.0 and v3.0 for the dataset format support, and the package version is 0.3.0. If you pin dependencies in your own environment, pin on the commit hash rather than trying to map these numbers to each other.

The licence needs a note of its own. The repository carries a LICENSE file that GitHub cannot classify, while the pyproject.toml declares the licence text as Apache-2.0. Read the LICENSE file directly for the terms that actually apply; this is a description of the files, not advice on how to use them.

## Surrounding projects you will end up using anyway

The README points at a set of sibling repositories, and knowing what each one does keeps you from building the wrong thing in the wrong place. For data collection, the open-source teleoperation project avp_teleoperate collects data on the Unitree G1 humanoid, and the data conversion section names the same project. For simulation, unitree_sim_isaaclab is listed as a simulation environment verification step added in the v0.2 release, which is how you test a policy before touching hardware.

For version conversion, the table links to any4lerobot under its ds_version_convert path, described as conversion of various versions of lerobot datasets. That is the tool for the problem you hit when your recorded episodes are in a LeRobot dataset version that does not match the one your training code expects.

The upstream comparison is straightforward and important. Plain LeRobot from Hugging Face trains policies on LeRobot datasets and nothing else. unitree_lerobot is the same training framework plus the Unitree-specific data conversion, the episode editor and the real machine inference path. If your data is not from a Unitree robot, or if you do not need the G1 evaluation harness, the upstream project gives you the same training code with none of the maintenance surface of a vendored fork, and the extra dependency on a pinned LeRobot commit disappears.

The datasets themselves live on Hugging Face under the unitreerobotics organisation, which is also where the example dataset used in the loading tutorial comes from.

## Conclusion

Adopt it if you already work with LeRobot datasets and own a Unitree G1 setup, since the conversion tooling, episode editor and eval_robot path save real work. Do not adopt it if you want a current upstream LeRobot, a pure software stack, or a command line only workflow, because the dataset editor is a desktop PyQt5 application and the bundled LeRobot copy stays at commit 0878c68. Before committing, check that commit against your own LeRobot checkout, confirm the licence in the LICENSE file, and verify that the SDK2 DDS dependency installs on your machine.

## FAQ

### What is unitree_lerobot and who is it for?

It is a modification of the LeRobot training framework for data collected on Unitree robots with dexterous hands, covering data conversion, model deployment and real machine inference. It is aimed at engineers who already use LeRobot datasets version 2.0 or above and work with Unitree hardware such as the G1.

### How do I install unitree_lerobot?

Clone the repository with git clone --recurse-submodules, create a conda environment with Python 3.10, install pinocchio and ffmpeg 7.1.1 from conda-forge, then run pip install -e . inside both the lerobot subdirectory and the project root. The unitree_sdk2_python package is installed separately for DDS communication with the robots.

### How do I clean up a failed episode in the dataset?

Use the data editor, which needs PyQt5 installed, and launch it with python data_editor_EN.py from the data_editor directory. It can cut excess segments from an episode and delete bad episodes through a graphical interface.

### Which LeRobot dataset versions does unitree_lerobot support?

The README states that the project is used for LeRobot training validation and supports LeRobot datasets version 2.0 and above. The v3.0 release updated the dataset to the v3.0 format and added support for the pi0.5 and groot policies.

### How often is unitree_lerobot updated?

The last push was on 2026-05-25, and the repository is not archived. Tagged releases include v2.0 on 2025-11-12 and v3.0 on 2025-11-19, and the bundled LeRobot copy is pinned to commit 0878c68, so upstream changes arrive through deliberate merges rather than automatically.

## Sources

- [Issues](https://github.com/unitreerobotics/unitree_lerobot/issues)
- [README](https://github.com/unitreerobotics/unitree_lerobot/blob/main/README.md)
- [Releases](https://github.com/unitreerobotics/unitree_lerobot/releases)
- [unitreerobotics/unitree_lerobot on GitHub](https://github.com/unitreerobotics/unitree_lerobot)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/unitreerobotics-unitree-lerobot
