What MuJoCo computes
MuJoCo advances a mechanical model through time. Joint positions and velocities describe its state; motor forces, gravity and contacts change that state. A control program supplies inputs before each step. Loading a humanoid mesh alone supplies neither a walking controller nor a calibrated robot. [1]
The native engine is a C/C++ library with Python bindings. This tutorial uses its CPU path. OpenGL viewing, MJX and MuJoCo Warp are separate choices. A GPU training example therefore has different requirements from the short headless experiment below. [1]
Rigid links have mass and rotational inertia. Joints constrain their relative motion. Contact geometry determines where bodies can touch, while contact and friction parameters affect the resulting forces. The solver handles those constraints numerically; its tolerances and iteration budget can affect the result. Gravity is a model option, not a force inferred from the appearance of the scene. [2]
Six pieces of a robot model
| Piece | What it specifies | What it does not establish |
|---|---|---|
| MJCF | MuJoCo scene, bodies, joints, contacts, actuators and sensors in XML | That the parameters match a particular physical unit |
| URDF | A robot link and joint description that MuJoCo can import | A complete replacement for every MJCF simulation option |
| Visual mesh | The visible shape and material | Accurate inertia or a suitable contact surface |
| Physical model | Mass, inertia, joint limits and collision geometry | Motor response under temperature or battery changes |
| Actuator model | How a control input produces joint effort | That every ctrl value is a torque command |
| Sensor definition | Which simulated measurements enter sensordata | A physical sensor’s calibration, dropouts or communications delay |
The integrator advances time after forces have been computed. A smaller timestep can help resolve fast motion but also costs more steps. Contact settings and joint gains must be considered together. Reproducing a result requires retaining these settings alongside the controller, rather than saving only a final pose. [3]
The G1 used here
The inspected Menagerie directory contains scene.xml, g1.xml and assets/. The scene includes the robot and a ground plane. Separate files provide a model with hands and an MJX-oriented model. This exercise uses scene.xml and its unmodified g1.xml. The directory README describes a simplified model and warns that the added position actuators need tuning. [5]
The compiled model has 29 actuators and one free base. Its 30 joints comprise 29 hinges plus that free joint. There are 36 position coordinates and 35 velocity coordinates because base orientation uses a four-component quaternion while angular velocity has three components. These are model counts, not a revised product specification for the base G1 sold by Unitree. [6]
For the commercial configuration, Read the base G1 hardware profile. The simulator model and the purchased variant must be matched before any transfer work.
Four configured sensors provide torso and pelvis angular velocity and acceleration, producing 12 scalar sensor values. The stand keyframe initializes the floating base, joints and control targets. The default position actuator gain is 500 with damping-ratio configuration; joint force limits are separate. These settings describe this XML revision, not recommended physical motor gains. [6]
Install and fetch the pinned files
The execution used Python 3.12.14, MuJoCo 3.15.0 and NumPy 2.5.3 on Linux. Pinning these package versions and the model commit makes later differences inspectable. The small example needs no camera renderer, CUDA or policy checkpoint. The interactive viewer has its own graphics requirements. [7] [8]
python -m venv robot-labrobot-lab/bin/python -m pip install mujoco==3.15.0 numpy==2.5.3robot-lab\Scripts\python.exe -m pip install mujoco==3.15.0 numpy==2.5.3Save the next three linked files together. The fetch helper reads its JSON manifest, downloads 39 required model and licence files from the pinned commit, and checks each SHA-256 digest. It retains the model’s BSD-3-Clause licence. The meshes are downloaded from their source rather than silently substituted.
Download the model fetch helper
Download the required file manifest
Download the complete G1 experiment
robot-lab/bin/python get_g1_model.py
robot-lab/bin/python mujoco_g1.py menagerie/unitree_g1/scene.xml --output g1-resultsOn Windows, replace robot-lab/bin/python in those two commands with robot-lab\Scripts\python.exe. Run from the folder containing the downloaded files. The fetch needs internet access; the experiment then uses local files.
Command one joint and read the state
The complete downloadable program records every step to CSV and writes a JSON execution report. This smaller excerpt shows the same control operation. It asks the left elbow position actuator for a target 0.1 rad above the stand pose and takes 250 steps. No hardware connection is present.
from pathlib import Path
import mujoco
scene = Path("menagerie/unitree_g1/scene.xml")
model = mujoco.MjModel.from_xml_path(str(scene.resolve()))
state = mujoco.MjData(model)
mujoco.mj_resetDataKeyframe(model, state, model.key("stand").id)
actuator = model.actuator("left_elbow_joint").id
state.ctrl[actuator] += 0.1
for step in range(250):
mujoco.mj_step(model, state)
mujoco.mj_forward(model, state)
print(float(state.time))
print(state.joint("left_elbow_joint").qpos.copy())
print(state.sensor("imu-torso-angular-velocity").data.copy())Use names to find the actuator and sensor rather than assuming their array order. Copy a NumPy view when retaining a sample, since stepping updates the underlying state. The full program calls mj_forward after a step so derived readings correspond to the newly integrated state. Its contact count is the simulator’s active contact record, not a physical foot-switch measurement. [7]
| Recorded item | Actual execution |
|---|---|
| Timestep and duration | 0.002 s per step; 250 steps; 0.5 s simulated time |
| Elbow angle before the command | 1.280000 rad |
| Elbow target | 1.380000 rad |
| Final elbow angle | 1.379729 rad |
| Final floating-base height | 0.791613 m |
| MuJoCo warning counters | All seven counters were zero in this run |
Read the actual execution report
Download all 250 recorded samples
Plot time_s against elbow_angle_rad and elbow_target_rad to inspect the response. base_z_m and the gyro columns show that moving a joint occurs within a floating-body simulation. A native viewer can provide a separate visual inspection; no viewer or screenshot was used for this execution.
Targets, effort and feedback
A position actuator interprets its input as a target position and supplies a feedback force. A velocity actuator targets a speed. A motor actuator produces effort according to its transmission and gain settings. Never substitute a torque value into a position target slot merely because both are floating-point arrays. [2] [4]
In a joint-space PD controller, torque can be written as kp × (target angle − measured angle) + kd × (target velocity − measured velocity). Model-based control can add predicted gravity or dynamics terms. A learned policy may instead output offsets that a PD controller follows. The command interface must be explicit in every case. [2]
To isolate this feedback mechanism, Start with the single-joint exercise. The humanoid example adds coupled motion and ground contact.
A walking policy needs observations, rewards, resets and evaluation beyond this command test. Continue to the walking training pipeline
What the model leaves unresolved
The G1 mesh does not identify gearbox backlash, structural flex, thermal derating or communication delays. Its collision approximations may be sufficient for one locomotion experiment and unsuitable for another contact task. Holding a joint target for 0.5 s cannot settle those questions. Compare recorded physical response with the simulation before describing a calibrated model. [5]
Read how physical logs refine a model
For USD scenes and rendered sensor pipelines, Compare the Isaac Sim workflow
Sources and verification
- MuJoCo overview and runtime model ↗Google DeepMind · Read 8 October 2026
- MuJoCo dynamics, actuation and contact ↗Google DeepMind · Read 8 October 2026
- MuJoCo model construction and solver settings ↗Google DeepMind · Read 8 October 2026
- MJCF reference for joints, actuators and sensors ↗Google DeepMind · Read 8 October 2026
- Menagerie G1 model and licence at the tested commit ↗Google DeepMind / Unitree · Read 8 October 2026
The model folder is BSD-3-Clause. This is the 29-actuator model, not the base commercial G1 specification.
- G1 actuator, sensor and stand-keyframe definitions ↗Google DeepMind / Unitree · Read 8 October 2026
Source XML and its mesh dependencies were fetched and hash-checked before execution.
- MuJoCo Python bindings ↗Google DeepMind · Read 8 October 2026
- MuJoCo 3.15.0 release ↗Google DeepMind · Read 8 October 2026
Version used in the executed CPU example.
Article history
Added a sourced engineering guide with version-specific references, practical resources and explicit evidence limits.
Report a correction