Original Work Credit:
This repository is based on lerobot-mujoco-tutorial by Jeongeun Park. This fork focuses on the ACT (Action-Chunking Transformer) pipeline for the EE5108 mini-project.
Collect demonstration data in MuJoCo, train an ACT policy, and deploy it in simulation. Single-task pick-and-place (SO-101 arm, blue block → bin).
LeRobot SO-101 arm simulation in Mujoco
- Installation
- EE5108 Mini-Project Workflow
- Project Structure
- Collect Data
- Playback Data
- Train ACT
- Deploy ACT
- Arm Profiles & Config
- Upload to Hugging Face
- Acknowledgements
- License
Python 3.12 recommended. Docker is the simplest option.
Two images:
- Runtime (
Dockerfile.runtime): data collection + policy deployment (smaller, no Jupyter). - Train/dev (
Dockerfile): same as runtime + Jupyter for local training.
Build from lerobot_mujoco_sim/:
docker build -t lerobot_mujoco_sim:runtime -f Dockerfile.runtime .
docker build -t lerobot_mujoco_sim:train -f Dockerfile .Run (GPU):
docker run --rm -it --gpus all -v "$PWD:/workspace" lerobot_mujoco_sim:runtimeInside the container: cd /workspace/lerobot_mujoco_sim (or /workspace if you mounted the repo root).
With docker-compose:
docker compose up -d lerobot-runtime
docker compose exec lerobot-runtime bash
cd /workspace/lerobot_mujoco_sim- Vendored:
third_party/SO-ARM100 - MuJoCo assets:
asset/so_arm100/SO101/,asset/so_arm100/SO100/ - Scene used for ACT:
asset/scene_so101_y.xml(SO-101, blue block → bin)
End-to-end flow: capture data → upload → train ACT (e.g. Colab) → deploy in MuJoCo.
From repo root on host:
docker build -t lerobot_mujoco_sim:runtime -f Dockerfile.runtime .
docker run --rm -it --gpus all -v "$PWD:/workspace" lerobot_mujoco_sim:runtimeThen inside container: cd /workspace/lerobot_mujoco_sim.
Manual teleop (recommended first time):
python scripts/collect/manual_collect_data.py \
--env-robot-profile so101 \
--num-demo 20 \
--repo-name <your-dataset-repo> \
--root data/demo_data_so101 \
--offline-local-onlyScripted batch (Mink FSM, no teleop):
python scripts/collect/batch_collect_data.py \
--env-robot-profile so101 \
--num-demo 200 \
--repo-name <your-dataset-repo> \
--root data/demo_data_so101 \
--offline-local-onlyBoth write a LeRobot-style dataset under data/demo_data_so101 (or a _fresh_* variant if the directory already exists and --offline-local-only is set).
You'll need a Huggingface account and an access token to create a dataset. Login (one of):
python -c "from huggingface_hub import login; login(token='hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')"Upload:
python scripts/hf/upload_hf.py \
--folder data/demo_data_so101 \
--repo-id <your-hf-username>/<your-dataset-repo> \
--repo-type dataset \
--create-if-missing \
--message "Upload SO101 dataset from demo_data_so101"Use --private for a private repo.
- Use Google Colab (recommended) and run the notebook
notebooks/EE5108_training_act.ipynb. - In the notebook, set
dataset.repo_idto<your-hf-username>/<your-dataset-repo>(the dataset you uploaded in step 3). - The notebook trains an ACT checkpoint and writes
deploy_metadata.jsoninto the checkpoint directory for easy deployment.
Copy the trained checkpoint (e.g. into checkpoints/act_y/), then:
python scripts/deploy/deploy_act.py --checkpoint checkpoints/act_yConfig-file driven deploy (recommended):
python scripts/deploy/deploy_act.py --config configs/deploy_act.yamlCPU-only:
python scripts/deploy/deploy_act.py --checkpoint checkpoints/act_y --device cpulerobot_mujoco_sim/
├── README.md
├── Dockerfile # Train/dev image (Jupyter + deps)
├── Dockerfile.runtime # Runtime image (collect + deploy)
├── docker-compose.yml
├── asset/
│ ├── scene_so101_y.xml # SO-101 pick-and-place scene
│ ├── so_arm100/ # SO-101/SO-100 MuJoCo assets
│ └── tabletop/
├── configs/
│ ├── collect_batch.yaml
│ ├── collect_manual.yaml
│ └── collect_data.yaml
├── scripts/
│ ├── collect/ # manual_collect_data.py, batch_collect_data.py
│ ├── deploy/ # deploy_act.py
│ ├── train/ # train_act.py
│ ├── visualize/ # visualize_data.py
│ └── hf/ # upload_hf.py
├── mujoco_env/ # MuJoCo environment
├── controllers/ # Mink FSM for batch collection
├── so101/ # SO-101 kinematics
└── third_party/SO-ARM100/
Data and checkpoints are local (e.g. data/, checkpoints/) and typically not committed.
Default task: pick blue block, place in bin. Scene: asset/scene_so101_y.xml.
- WASD + R/F + arrows: joint control (see Keyboard controls).
- SPACE: toggle gripper. Z: reset and discard current episode.
- Recording starts on first movement; finish a successful pick-and-place to save the episode.
Config and YAML:
python scripts/collect/manual_collect_data.py --config configs/collect_manual.yaml
python scripts/collect/batch_collect_data.py --config configs/collect_batch.yaml --num-demo 100| Key | Action |
|---|---|
| A / D | Shoulder pan |
| W / S | Shoulder lift |
| R / F | Elbow flex |
| ↑ / ↓ | Wrist flex |
| ← / → | Wrist roll |
| SPACE | Toggle gripper |
| Z | Reset & discard episode |
batch_collect_data.py uses a Mink-based FSM to generate demonstrations without teleop. Same dataset format as manual collection.
Replay saved episodes in MuJoCo:
python scripts/visualize/visualize_data.pyOr use the notebook notebooks/2.visualize_data.ipynb.
Recommended (students): run the Colab notebook notebooks/EE5108_training_act.ipynb.
Minimal local training example (if you already have the environment set up):
python scripts/train/train_act.pyCheckpoint is written to checkpoints/act_y/ (including deploy_metadata.json for deployment). For full training (e.g. Colab), use the LeRobot pipeline with your Hugging Face dataset.
Run the policy in the same SO-101 MuJoCo scene using a trained ACT checkpoint.
python scripts/deploy/deploy_act.py --checkpoint checkpoints/act_yscripts/deploy/deploy_act.py builds the ACT policy from your checkpoint’s config.json, then loads dataset normalization stats (needed to denormalize the action outputs correctly).
The dataset stats come from one of these places:
- If
checkpoints/<your-checkpoint>/deploy_metadata.jsonexists,deploy_act.pyuses that directly. - Otherwise, it looks for local dataset metadata under
--dataset-root. - It expects
meta/info.json(includesfeatures). - It expects
meta/stats.json(normalization statistics). - If those local files are missing, it downloads only
meta/info.jsonandmeta/stats.jsonfrom the Hugging Face dataset repo given by--dataset-repo-id.
Notes / gotchas:
- This repo’s deployment script is MuJoCo sim-only. Do not use
lerobot-recordfor this workflow (it targets the physical robot and requires a hardware--robot.port). - Make sure
--dataset-repo-idpoints to a Hugging Face dataset repo (uploaded with--repo-type dataset), not a model/policy repo.
Common command (local dataset stats):
python scripts/deploy/deploy_act.py \
--checkpoint checkpoints/act_y \
--dataset-root data/demo_data_so101Spawn bounds and runtime defaults for deploy live in configs/deploy_act.yaml.
python scripts/deploy/deploy_act.py --config configs/deploy_act.yamlCLI flags still override YAML values. Options include: --xml-path, --device cpu, --seed, --spawn-x-min, etc. See --help.
Run python scripts/deploy/deploy_act.py --help for the full list, but these are the key ones:
--checkpoint: checkpoint folder containing at leastconfig.json(and optionallydeploy_metadata.json)--dataset-root: local dataset folder (default is set in the YAML). Expected to containmeta/info.jsonandmeta/stats.json.--dataset-repo-id: Hugging Face dataset repo id used only if localmeta/files aren’t present--xml-path: MuJoCo scene XML
Set HF_TOKEN in the environment, or (when using the provided docker-compose runtime) place a token in token.txt at the repo root so the container can export it.
Profiles: so101 (default), so100, omy. Defaults come from configs/collect_data.yaml (e.g. env_robot_profile: so101, xml_path: ./asset/scene_so101_y.xml). Override at runtime:
python scripts/collect/manual_collect_data.py --env-robot-profile so100Spawn bounds and scene settings are in the same config.
After collecting data:
huggingface-cli login # or set HF_TOKEN
python scripts/hf/upload_hf.py \
--folder data/demo_data_so101 \
--repo-id <your-hf-username>/<your-dataset-repo> \
--repo-type dataset \
--create-if-missingIf using docker-compose with HF_HUB_OFFLINE=1, unset it for uploads.
- Original tutorial: lerobot-mujoco-tutorial by Jeongeun Park.
- SO-ARM assets: TheRobotStudio/SO-ARM100.
- LeRobot: huggingface/lerobot.
- MuJoCo parser inspiration: yet-another-mujoco-tutorial.
See LICENSE. Third-party components (e.g. SO-ARM100, LeRobot) have their own licenses.