ROBOTICS FIELD NOTESENGLISH EDITION / 8 October 2026
Articles

MuJoCo for Humanoid Robotics

Load a pinned Unitree G1 model, inspect 29 actuators and record a joint response with a Python example executed in MuJoCo 3.15.0.

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

PieceWhat it specifiesWhat it does not establish
MJCFMuJoCo scene, bodies, joints, contacts, actuators and sensors in XMLThat the parameters match a particular physical unit
URDFA robot link and joint description that MuJoCo can importA complete replacement for every MJCF simulation option
Visual meshThe visible shape and materialAccurate inertia or a suitable contact surface
Physical modelMass, inertia, joint limits and collision geometryMotor response under temperature or battery changes
Actuator modelHow a control input produces joint effortThat every ctrl value is a torque command
Sensor definitionWhich simulated measurements enter sensordataA physical sensor’s calibration, dropouts or communications delay

[3] [4]

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]

Shell · create an isolated environment
python -m venv robot-lab
Linux or macOS · install the tested package versions
robot-lab/bin/python -m pip install mujoco==3.15.0 numpy==2.5.3
Windows PowerShell · install the same versions
robot-lab\Scripts\python.exe -m pip install mujoco==3.15.0 numpy==2.5.3

Save 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

Linux or macOS · fetch, validate and run
robot-lab/bin/python get_g1_model.py
robot-lab/bin/python mujoco_g1.py menagerie/unitree_g1/scene.xml --output g1-results

On 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.

Python 3.12 · the joint command used in the executed program
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]

CPU simulation executed on 8 October 2026
Recorded itemActual execution
Timestep and duration0.002 s per step; 250 steps; 0.5 s simulated time
Elbow angle before the command1.280000 rad
Elbow target1.380000 rad
Final elbow angle1.379729 rad
Final floating-base height0.791613 m
MuJoCo warning countersAll 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

  1. MuJoCo overview and runtime model ↗Google DeepMind · Read 8 October 2026
  2. MuJoCo dynamics, actuation and contact ↗Google DeepMind · Read 8 October 2026
  3. MuJoCo model construction and solver settings ↗Google DeepMind · Read 8 October 2026
  4. MJCF reference for joints, actuators and sensors ↗Google DeepMind · Read 8 October 2026
  5. 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.

  6. 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.

  7. MuJoCo Python bindings ↗Google DeepMind · Read 8 October 2026
  8. 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