Skip to content

Commit 15bbd3b

Browse files
committed
Modernize MuJoCo Tutorial for v3.x
- Complete rewrite using modern mujoco Python API (no mujoco-py, no GLFW boilerplate) - 18 standalone examples covering basics to advanced control (LQR, impedance, operational space) - 13 tutorial notebooks (00-10 + quickstart + interactive) with Colab badges - Beginner-friendly Tutorial 00 (conceptual intro) and Tutorial 10 (troubleshooting) - Interactive PD tuning notebook with ipywidgets sliders - Expanded Tutorial 04 (all actuator types: motor/position/velocity/general/muscle) - Expanded Tutorial 06 (tendons, equality constraints) - CI workflow testing all examples headlessly on Python 3.10-3.12 - GIF previews in README - MIT License, CONTRIBUTING.md, examples/README.md with difficulty ratings - requirements.txt pinned to mujoco>=3.2 for MjSpec API support
0 parents  commit 15bbd3b

46 files changed

Lines changed: 6259 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: CI — Test Examples
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
python-version: ["3.10", "3.11", "3.12"]
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Set up Python ${{ matrix.python-version }}
20+
uses: actions/setup-python@v5
21+
with:
22+
python-version: ${{ matrix.python-version }}
23+
24+
- name: Install dependencies
25+
run: |
26+
pip install --upgrade pip
27+
pip install mujoco numpy scipy matplotlib mediapy gymnasium[mujoco]
28+
29+
- name: Test examples (headless)
30+
env:
31+
MUJOCO_GL: egl
32+
run: python scripts/test_examples.py

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__pycache__/

CONTRIBUTING.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Contributing to MuJoCo Tutorial 🤝
2+
3+
Thanks for your interest in contributing! This repo aims to be the best starting point for learning MuJoCo.
4+
5+
## Ways to Contribute
6+
7+
1. **Add a new example** — standalone scripts in `examples/`
8+
2. **Improve tutorials** — fix errors, add explanations, update for new MuJoCo versions
9+
3. **Fix bugs** — if an example doesn't work, open an issue or PR
10+
4. **Add translations** — README in other languages
11+
12+
## Adding a New Example
13+
14+
1. Fork and clone the repo
15+
2. Create `examples/your_example.py`
16+
3. Follow the existing style:
17+
- Docstring at the top explaining what the example demonstrates
18+
- Inline MJCF XML (no external files needed)
19+
- Use `mujoco.viewer.launch_passive()` for interactive viewing
20+
- Keep it under 150 lines
21+
4. Add a row to the examples table in `README.md`
22+
5. Submit a PR
23+
24+
### Example Template
25+
26+
```python
27+
"""Short description — what control/physics concept this demonstrates."""
28+
29+
import numpy as np
30+
import mujoco
31+
import mujoco.viewer
32+
33+
XML = """
34+
<mujoco>
35+
<!-- Your model here -->
36+
</mujoco>
37+
"""
38+
39+
40+
def main():
41+
model = mujoco.MjModel.from_xml_string(XML)
42+
data = mujoco.MjData(model)
43+
44+
with mujoco.viewer.launch_passive(model, data) as viewer:
45+
while viewer.is_running() and data.time < 10.0:
46+
# Your controller here
47+
mujoco.mj_step(model, data)
48+
viewer.sync()
49+
50+
51+
if __name__ == "__main__":
52+
main()
53+
```
54+
55+
## Adding/Editing Tutorials
56+
57+
- Notebooks are in `tutorial/` and numbered sequentially
58+
- Each notebook should have:
59+
- A Colab badge at the top
60+
- A `!pip install -q mujoco mediapy` cell
61+
- No embedded outputs (keeps files small)
62+
- Clear markdown explanations between code cells
63+
64+
## Code Style
65+
66+
- Python 3.10+
67+
- No type annotations required (keep examples simple)
68+
- Use `numpy` style (no one-letter variables except standard math: `x`, `q`, `F`)
69+
- Prefer inline MJCF over external XML files
70+
71+
## Running Tests
72+
73+
```bash
74+
python scripts/test_examples.py
75+
```
76+
77+
This runs each example headlessly for a few steps to verify it doesn't crash.
78+
79+
## Questions?
80+
81+
Open an issue or start a discussion. We're happy to help!

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022-2026 Manan Tayal
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
<p align="center">
2+
<img src="./img/Logo.svg" alt="MuJoCo Tutorial Logo" width="125"/>
3+
</p>
4+
5+
<h1 align="center">MuJoCo Tutorial 🤖</h1>
6+
7+
<p align="center">
8+
A modern tutorial for getting started with <a href="https://mujoco.org/">MuJoCo</a> — a fast, accurate physics engine for robotics, biomechanics, and reinforcement learning.
9+
</p>
10+
11+
> MuJoCo is open-source (Apache 2.0) and maintained by Google DeepMind. Since v3.0, it includes GPU-accelerated simulation via MJX.
12+
13+
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tayalmanan28/MuJoCo-Tutorial/blob/main/tutorial/quickstart.ipynb)
14+
15+
---
16+
17+
## Installation 🚀
18+
19+
MuJoCo is a pure Python package — no license keys, no system dependencies:
20+
21+
```bash
22+
pip install mujoco gymnasium[mujoco] mediapy
23+
```
24+
25+
That's it. For interactive visualization you also need a display (or use offscreen rendering in notebooks).
26+
27+
### Optional: Conda environment
28+
29+
```bash
30+
conda create -n mujoco-tut python=3.11
31+
conda activate mujoco-tut
32+
pip install -r requirements.txt
33+
```
34+
35+
---
36+
37+
## Quickstart
38+
39+
```python
40+
import mujoco
41+
import mujoco.viewer
42+
43+
model = mujoco.MjModel.from_xml_string("""
44+
<mujoco>
45+
<worldbody>
46+
<light pos="0 0 3" dir="0 0 -1"/>
47+
<geom type="plane" size="5 5 0.1"/>
48+
<body pos="0 0 2">
49+
<joint type="free"/>
50+
<geom type="sphere" size="0.2" rgba="1 0 0 1"/>
51+
</body>
52+
</worldbody>
53+
</mujoco>
54+
""")
55+
data = mujoco.MjData(model)
56+
57+
# Launch interactive viewer
58+
mujoco.viewer.launch(model, data)
59+
```
60+
61+
For headless/notebook rendering, see [`examples/offscreen_rendering.py`](examples/offscreen_rendering.py).
62+
63+
---
64+
65+
## Preview
66+
67+
<p align="center">
68+
<img src="img/previews/trajectory_tracking.gif" width="45%" alt="Trajectory Tracking"/>
69+
<img src="img/previews/lqr_control.gif" width="45%" alt="LQR Cart-Pole"/>
70+
</p>
71+
<p align="center">
72+
<img src="img/previews/impedance_control.gif" width="45%" alt="Impedance Control"/>
73+
<img src="img/previews/pick_and_place.gif" width="45%" alt="Pick and Place"/>
74+
</p>
75+
76+
<p align="center"><em>Left to right: trajectory tracking, LQR balancing, impedance control, pick-and-place</em></p>
77+
78+
---
79+
80+
## Contents
81+
82+
| Example | Description |
83+
|---------|-------------|
84+
| [`examples/projectile.py`](examples/projectile.py) | Projectile with drag force |
85+
| [`examples/pendulum_control.py`](examples/pendulum_control.py) | PD control of a pendulum |
86+
| [`examples/double_pendulum.py`](examples/double_pendulum.py) | Double pendulum swing-up control |
87+
| [`examples/hopper.py`](examples/hopper.py) | 2D hopper with open-loop jumping |
88+
| [`examples/inverse_kinematics.py`](examples/inverse_kinematics.py) | Damped least-squares IK with Jacobians |
89+
| [`examples/contact_forces.py`](examples/contact_forces.py) | Reading contact info & forces |
90+
| [`examples/domain_randomization.py`](examples/domain_randomization.py) | Varying physics params across episodes |
91+
| [`examples/menagerie_robot.py`](examples/menagerie_robot.py) | Loading robots from MuJoCo Menagerie |
92+
| [`examples/mjx_parallel.py`](examples/mjx_parallel.py) | GPU-parallel sim with MJX (JAX) |
93+
| [`examples/gymnasium_env.py`](examples/gymnasium_env.py) | Using Gymnasium's MuJoCo envs |
94+
| [`examples/offscreen_rendering.py`](examples/offscreen_rendering.py) | Headless rendering & video export |
95+
| [`examples/trajectory_tracking.py`](examples/trajectory_tracking.py) | Arm follows circular path (task-space PD) |
96+
| [`examples/operational_space_control.py`](examples/operational_space_control.py) | Full dynamics compensation in task space |
97+
| [`examples/lqr_control.py`](examples/lqr_control.py) | LQR cart-pole balancing (linearization + Riccati) |
98+
| [`examples/impedance_control.py`](examples/impedance_control.py) | Compliant end-effector (spring-damper behavior) |
99+
| [`examples/locomotion_controller.py`](examples/locomotion_controller.py) | Hopper FSM locomotion (finite state machine) |
100+
| [`examples/pick_and_place.py`](examples/pick_and_place.py) | Gripper pick-and-place with waypoint sequencing |
101+
| [`examples/record_playback.py`](examples/record_playback.py) | Save/load trajectories (record & replay) |
102+
103+
### Base class
104+
105+
[`mujoco_base.py`](mujoco_base.py) provides a minimal base class for building custom simulations:
106+
107+
```python
108+
from mujoco_base import MuJoCoBase
109+
110+
class MySim(MuJoCoBase):
111+
def reset(self):
112+
pass # set initial conditions
113+
114+
def controller(self, model, data):
115+
data.ctrl[0] = ... # your control logic
116+
117+
sim = MySim("my_model.xml")
118+
sim.run() # interactive viewer
119+
# or
120+
frames = sim.run_headless(duration=5.0) # offscreen
121+
```
122+
123+
---
124+
125+
## Tutorial Notebooks
126+
127+
Step-by-step Jupyter notebooks (run in Colab or locally):
128+
129+
| Notebook | Topic |
130+
|----------|-------|
131+
| [`tutorial/00_what_is_mujoco.ipynb`](tutorial/00_what_is_mujoco.ipynb) | **Start here!** What MuJoCo is, mental model, first simulation |
132+
| [`tutorial/quickstart.ipynb`](tutorial/quickstart.ipynb) | Zero-install quickstart (Colab-ready) |
133+
| [`tutorial/01_basics.ipynb`](tutorial/01_basics.ipynb) | MjModel, MjData, named access |
134+
| [`tutorial/02_rendering.ipynb`](tutorial/02_rendering.ipynb) | Rendering, cameras, scenes |
135+
| [`tutorial/03_simulation.ipynb`](tutorial/03_simulation.ipynb) | Time stepping, mj_step, mj_forward |
136+
| [`tutorial/04_control.ipynb`](tutorial/04_control.ipynb) | Actuators, PD control, callbacks |
137+
| [`tutorial/05_contact.ipynb`](tutorial/05_contact.ipynb) | Collision, contacts, force sensing |
138+
| [`tutorial/06_xml_modeling.ipynb`](tutorial/06_xml_modeling.ipynb) | MJCF modeling guide |
139+
| [`tutorial/07_mjx.ipynb`](tutorial/07_mjx.ipynb) | MJX: GPU-parallel simulation with JAX |
140+
| [`tutorial/08_gymnasium.ipynb`](tutorial/08_gymnasium.ipynb) | MuJoCo + Gymnasium for RL |
141+
| [`tutorial/09_sensors_and_estimation.ipynb`](tutorial/09_sensors_and_estimation.ipynb) | Sensors, IMU, noise, state estimation |
142+
| [`tutorial/10_troubleshooting.ipynb`](tutorial/10_troubleshooting.ipynb) | Common errors & how to fix them |
143+
| [`tutorial/interactive_control.ipynb`](tutorial/interactive_control.ipynb) | 🎮 Interactive PD tuning with sliders |
144+
145+
---
146+
147+
## Key Concepts
148+
149+
| Concept | Description |
150+
|---------|-------------|
151+
| **MJCF** | MuJoCo's XML format for defining models ([docs](https://mujoco.readthedocs.io/en/stable/XMLreference.html)) |
152+
| **`MjModel`** | Compiled model (static) — physics parameters, geometry |
153+
| **`MjData`** | Simulation state (dynamic) — positions, velocities, forces |
154+
| **`mujoco.viewer`** | Built-in interactive 3D viewer |
155+
| **`mujoco.Renderer`** | Offscreen rendering for headless environments |
156+
| **MJX** | JAX backend for GPU-parallel simulation ([docs](https://mujoco.readthedocs.io/en/stable/mjx.html)) |
157+
158+
---
159+
160+
## Resources
161+
162+
- [Official MuJoCo Documentation](https://mujoco.readthedocs.io/)
163+
- [MuJoCo GitHub](https://github.com/google-deepmind/mujoco)
164+
- [Gymnasium MuJoCo Environments](https://gymnasium.farama.org/environments/mujoco/)
165+
- [MuJoCo Menagerie](https://github.com/google-deepmind/mujoco_menagerie) — collection of robot models
166+
- [MJX Tutorial](https://mujoco.readthedocs.io/en/stable/mjx.html) — GPU-accelerated simulation
167+
168+
---
169+
170+
## What's Next? 🚀
171+
172+
Once you've completed these tutorials, explore:
173+
174+
| Resource | What you'll learn |
175+
|----------|-------------------|
176+
| [MuJoCo Menagerie](https://github.com/google-deepmind/mujoco_menagerie) | Production-quality robot models (Franka, UR5e, Unitree, etc.) |
177+
| [dm_control](https://github.com/google-deepmind/dm_control) | DeepMind's control suite — benchmarks for continuous control |
178+
| [Gymnasium Leaderboard](https://gymnasium.farama.org/environments/mujoco/) | Standard RL benchmarks (HalfCheetah, Humanoid, Ant) |
179+
| [Brax](https://github.com/google/brax) | Differentiable physics in JAX (alternative to MJX) |
180+
| [MuJoCo XLA (MJX) Paper](https://arxiv.org/abs/2307.00282) | Technical details of GPU-parallel MuJoCo |
181+
| [Robosuite](https://robosuite.ai/) | Manipulation benchmarks built on MuJoCo |
182+
| [IsaacLab](https://github.com/isaac-sim/IsaacLab) | NVIDIA's sim framework (comparison point) |
183+
184+
---
185+
186+
## Contributing 🤝
187+
188+
1. Fork this repository
189+
2. Create a new example in `examples/` with inline MJCF or an XML in `xml/`
190+
3. Submit a pull request
191+
192+
See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
193+
194+
---
195+
196+
## License 📃
197+
198+
MIT — free to use without restrictions.

examples/README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Examples
2+
3+
Standalone scripts demonstrating MuJoCo concepts. Each is self-contained with inline MJCF.
4+
5+
Run any example: `python examples/<name>.py`
6+
7+
## Basics
8+
9+
| Example | Concept | Difficulty |
10+
|---------|---------|:----------:|
11+
| `projectile.py` | External forces (drag), `xfrc_applied` ||
12+
| `pendulum_control.py` | PD control, `data.ctrl` ||
13+
| `double_pendulum.py` | Multi-joint control, energy shaping | ⭐⭐ |
14+
| `offscreen_rendering.py` | `mujoco.Renderer`, video export ||
15+
| `record_playback.py` | Save/load trajectories with NumPy ||
16+
17+
## Control Theory
18+
19+
| Example | Concept | Difficulty |
20+
|---------|---------|:----------:|
21+
| `trajectory_tracking.py` | Task-space PD, Jacobian transpose | ⭐⭐ |
22+
| `operational_space_control.py` | Dynamics compensation, Λ matrix | ⭐⭐⭐ |
23+
| `lqr_control.py` | Linearization, Riccati equation, LQR | ⭐⭐⭐ |
24+
| `impedance_control.py` | Compliance, spring-damper in task space | ⭐⭐ |
25+
| `inverse_kinematics.py` | Damped least-squares IK | ⭐⭐ |
26+
27+
## Robotics
28+
29+
| Example | Concept | Difficulty |
30+
|---------|---------|:----------:|
31+
| `locomotion_controller.py` | Finite state machine, hopper gait | ⭐⭐ |
32+
| `pick_and_place.py` | Gripper, waypoint sequencing | ⭐⭐ |
33+
| `hopper.py` | Open-loop jumping | ⭐⭐ |
34+
| `menagerie_robot.py` | Loading Menagerie models ||
35+
36+
## Advanced
37+
38+
| Example | Concept | Difficulty |
39+
|---------|---------|:----------:|
40+
| `contact_forces.py` | Contact detection, force reading | ⭐⭐ |
41+
| `domain_randomization.py` | Parameter variation, sim-to-real | ⭐⭐ |
42+
| `mjx_parallel.py` | GPU-parallel simulation (JAX) | ⭐⭐⭐ |
43+
| `gymnasium_env.py` | RL environments | ⭐⭐ |

0 commit comments

Comments
 (0)