MuJoCo is the most widely used physics engine in robotics research — behind DeepMind's bipedal walking, OpenAI's Dactyl hand, and hundreds of robotics papers. Now free and open-source. This guide goes from pip install to training your first locomotion policy.
# MuJoCo 3.x is free, open-source, and pip-installable
pip install mujoco
# Verify installation
python -c "import mujoco; print(mujoco.__version__)"
# Expected: 3.x.x
# Install optional viewer (standalone window)
pip install mujoco[viewer]
# Also install dm_control for gym-style environments
pip install dm-control<!-- simple_arm.xml — a 2-DOF arm -->
<mujoco>
<worldbody>
<light diffuse=".5 .5 .5" pos="0 0 3" dir="0 0 -1"/>
<geom type="plane" size="1 1 0.1" rgba=".9 0 0 1"/>
<body name="upper_arm" pos="0 0 0.5">
<joint name="shoulder" type="hinge" axis="0 1 0"/>
<geom type="capsule" size="0.04" fromto="0 0 0 0 0 0.3" rgba="0 .9 0 1"/>
<body name="lower_arm" pos="0 0 0.3">
<joint name="elbow" type="hinge" axis="0 1 0"/>
<geom type="capsule" size="0.04" fromto="0 0 0 0 0 0.25" rgba="0 0 .9 1"/>
</body>
</body>
</worldbody>
<actuator>
<motor name="shoulder_motor" joint="shoulder" gear="100"/>
<motor name="elbow_motor" joint="elbow" gear="50"/>
</actuator>
</mujoco>import mujoco
import mujoco.viewer
import numpy as np
# Load model from XML file
model = mujoco.MjModel.from_xml_path("simple_arm.xml")
data = mujoco.MjData(model)
# Single step
mujoco.mj_step(model, data)
# Access state
print("Time:", data.time)
print("Joint positions:", data.qpos)
print("Joint velocities:", data.qvel)
print("Actuator forces:", data.ctrl)
# Set control and simulate
data.ctrl[0] = 0.5 # shoulder motor
data.ctrl[1] = -0.3 # elbow motor
for _ in range(1000):
mujoco.mj_step(model, data)
print(f"t={data.time:.3f} qpos={data.qpos}")
# Launch interactive viewer
with mujoco.viewer.launch_passive(model, data) as viewer:
while viewer.is_running():
mujoco.mj_step(model, data)
viewer.sync()# Clone the Menagerie (20+ robots in MJCF format)
git clone https://github.com/google-deepmind/mujoco_menagerie.git
# Load Franka Panda
import mujoco
model = mujoco.MjModel.from_xml_path(
"mujoco_menagerie/franka_emika_panda/panda_nohand.xml"
)
data = mujoco.MjData(model)
print("Model name:", model.body(0).name)
print("Number of joints:", model.njnt)
print("Number of actuators:", model.nu)
print("DOF:", model.nv)
# Other robots available:
# - unitree_a1 (quadruped)
# - unitree_go1 (quadruped)
# - anybotics_anymal_c (quadruped)
# - shadow_hand
# - robotis_op3 (humanoid)
# - boston_dynamics_spot (quadruped)import gymnasium as gym
import numpy as np
from stable_baselines3 import PPO
from stable_baselines3.common.env_util import make_vec_env
# MuJoCo environments via Gymnasium
# pip install gymnasium[mujoco]
# Classic benchmarks
env_id = "Ant-v4" # 4-legged locomotion
# env_id = "HalfCheetah-v4" # 2D running
# env_id = "Humanoid-v4" # Full humanoid walking
# Vectorize for parallel training
vec_env = make_vec_env(env_id, n_envs=4)
# Train with PPO
model = PPO(
"MlpPolicy",
vec_env,
verbose=1,
n_steps=2048,
batch_size=64,
n_epochs=10,
learning_rate=3e-4,
clip_range=0.2,
ent_coef=0.0,
vf_coef=0.5,
)
model.learn(total_timesteps=1_000_000)
model.save("ppo_ant")
# Evaluate
obs, _ = vec_env.reset()
for _ in range(1000):
action, _ = model.predict(obs, deterministic=True)
obs, reward, done, truncated, info = vec_env.step(action)<body name="link1" pos="0 0 0.2">
<joint name="j1" type="hinge" axis="0 1 0" range="-1.57 1.57"/>
<geom type="capsule" size="0.05" fromto="0 0 0 0 0 0.2"/>
</body><!-- Visual and collision geom -->
<geom type="sphere" size="0.05" rgba="0.8 0.2 0.2 1"/>
<geom type="mesh" mesh="my_mesh" rgba="0.3 0.3 0.3 1"/>
<!-- In <asset> section -->
<asset>
<mesh name="my_mesh" file="mesh.obj"/>
</asset><actuator>
<!-- Motor actuator (direct torque) -->
<motor name="hip" joint="hip_joint" gear="50" ctrlrange="-2 2"/>
<!-- Position actuator (PD control) -->
<position name="knee_pos" joint="knee" kp="100" ctrlrange="-1.57 1.57"/>
<!-- Velocity actuator -->
<velocity name="wheel" joint="wheel_joint" kv="10"/>
</actuator><sensor>
<jointpos name="hip_pos" joint="hip_joint"/>
<jointvel name="hip_vel" joint="hip_joint"/>
<force name="foot_force" site="foot_site"/>
<gyro name="imu_gyro" site="body_imu"/>
<accelerometer name="imu_acc" site="body_imu"/>
</sensor>
<!-- Read in Python -->
# data.sensor("hip_pos").data[0] # joint position value<default>
<geom condim="4" friction="1 0.005 0.0001" solref="0.01 1" solimp="0.9 0.95 0.001"/>
</default>
<!-- Per-geom override -->
<geom type="box" size="0.1 0.1 0.01"
friction="0.5 0.01 0.0001" <!-- tangential torsional rolling -->
solimp="0.95 0.99 0.001"/>| Feature | MuJoCo | NVIDIA Isaac Lab |
|---|---|---|
| Platform | All (Linux, macOS, Windows, Apple Silicon) | Linux + NVIDIA GPU only |
| GPU Parallelism | Limited (~500 envs) | 10,000+ envs on A100 |
| Install Complexity | pip install mujoco (seconds) | Requires Isaac Sim (~30 min) |
| Cost | Free (Apache 2.0) | Free (Isaac Sim free license) |
| Physics Accuracy | Industry standard — MJC physics | PhysX 5 — similar accuracy |
| Robot Library | MuJoCo Menagerie — 20+ robots | Official assets — 15+ robots |
| RL Ecosystem | Gymnasium — every RL framework supports it | RSL-RL, skrl, RL-Games, SB3 |
| Research Papers | DeepMind, OpenAI, MIT, CMU | ETH, ANYbotics, legged labs |
| Best For | Research, diversity, Apple Silicon devs | Locomotion training at scale, enterprise |
Rule of thumb: use MuJoCo if you're on macOS, need fast setup, or want ecosystem breadth. Use Isaac Lab if you have an NVIDIA GPU and need 10,000+ parallel environments for locomotion.