FTH 0 · The humanoid's body|INEMA.CLUB-PRO

Lesson 2 · 15 min

Open a humanoid in the simulator

A humanoid's spec sheet tells you what the maker wants to show; the simulation file tells you what the body is. In this lesson you install MuJoCo, download only the humanoids from MuJoCo Menagerie, and open the Unitree G1, reading from the file itself how many coordinates, velocities, and motors it has.

Start the lesson
Monitor on a dark workbench showing a humanoid robot in a 3D simulation on a checkered floor.

In this lesson you will

  1. 1What's in an MJCF: bodies, joints, actuators, sensors, and saved poses
  2. 2The workbench in ~/fth: venv, MuJoCo 3.16.0, and Menagerie pinned to a commit
  3. 3MjModel (the body) and MjData (the state)
  4. 4Why the G1 has nq=36, nv=35, and nu=29

Goal: install MuJoCo 3.16 and Menagerie and open the Unitree G1, reading nq, nv, and nu from the MJCF file itself.

01From file to simulation step

Click each block.

Click each block in the diagram to see what it does.

The maker's spec sheet and the file can differ: lesson 8 teaches you to note the difference.

02The three numbers you'll read on every humanoid

Click each one.

1. nq = 36

The humanoid's base is not fixed to the ground: it is a free joint with 7 numbers (x, y, z and a 4-number quaternion for orientation).

Adding the 29 articulated joints gives 36. That is the size of qpos.

03Set up the workbench (once)

Its own venv, MuJoCo pinned to 3.16.0 and the Menagerie pinned to the tested commit. The sparse-checkout downloads only 4 humanoids (about 150 MB) instead of the whole repository.

Terminal · set up ~/fth
F=${FTH:-$HOME/fth}; mkdir -p $F && cd $F
python3.12 -m venv .venv && . .venv/bin/activate
pip install -q mujoco==3.16.0 numpy
[ -d anatomia ] || git clone -q --depth 1 https://github.com/inematds/formacao-fth-anatomia-v72 anatomia
[ -d mujoco_menagerie ] || git clone -q --filter=blob:none --sparse https://github.com/google-deepmind/mujoco_menagerie
cd mujoco_menagerie && git sparse-checkout set unitree_g1 unitree_h1 robotis_op3 booster_t1
git checkout -q 62ab00f && git log -1 --format='menagerie %h (%ad)' --date=short
python3 -c "import mujoco, numpy; print('mujoco', mujoco.__version__, '· numpy', numpy.__version__)"
Example from the repository
menagerie 62ab00f (2026-10-15)
mujoco 3.16.0 · numpy 2.5.4

Two lines and no errors. If your MuJoCo version is different, the numbers in the next lessons may change in the last digit: pin the version.

04Open the G1 and the other humanoids

abrir.py only reads the model and prints its size. The excerpt from g1.xml shows where the numbers come from.

Terminal · open the G1
F=${FTH:-$HOME/fth}; cd $F/anatomia && . $F/.venv/bin/activate
python3 kit/abrir.py unitree_g1/scene.xml; echo "saída: $?"
Terminal · H1, OP3 and Booster T1
F=${FTH:-$HOME/fth}; cd $F/anatomia && . $F/.venv/bin/activate
for r in unitree_h1 robotis_op3 booster_t1; do
  echo "$r: $(python3 kit/abrir.py $r/scene.xml | sed -n 2p)"
done
Excerpt from mujoco_menagerie/unitree_g1/g1.xml (commit 62ab00f)
<option integrator="implicitfast"/>
<default class="g1">
  <joint armature="0.01" frictionloss="0.3"/>
  <position kp="500" dampratio="1" inheritrange="1"/>
</default>
<!-- ... -->
<joint name="left_knee_joint" axis="0 1 0" range="-0.087267 2.8798" actuatorfrcrange="-139 139"/>
<!-- ... -->
<position class="g1" name="left_knee_joint" joint="left_knee_joint"/>
Optional · with a screen: see the robot
F=${FTH:-$HOME/fth}; $F/.venv/bin/python -m mujoco.viewer --mjcf=$F/mujoco_menagerie/unitree_g1/scene.xml
Example from the repository
modelo: g1_29dof_rev_1_0 scene · arquivo unitree_g1/scene.xml
nq=36 nv=35 nu=29
juntas: 30 (1 base flutuante + 29 articuladas) · corpos: 30 · sensores: 4
massa total do modelo: 33.3 kg · passo de simulação: 2 ms
poses salvas (keyframes): stand
altura da base na pose inicial: 0.79 m
saída: 0

33.3 kg in the model against about 35 kg on the Unitree spec sheet: the simulation file is an approximation of the real robot.

05What is used at scale (shown)

To train policies with thousands of robots in parallel, the same models run on NVIDIA GPUs. It is not a prerequisite for this course: course 1 of the program uses it.

Shown · mjlab, NVIDIA GPU (not run here)
# github.com/mujocolab/mjlab — Isaac Lab API on top of MuJoCo Warp
uv run train Mjlab-Velocity-Flat-Unitree-G1 --env.scene.num-envs 4096

06Practice

Workbench ready and first model open.

E1 · Set up the workbench

10 min

Run the "set up ~/fth" block. If python3.12 is missing, install it with your system's package manager (the course was tested with Python 3.12.3).

Done when: the output shows menagerie 62ab00f (2026-10-15) and mujoco 3.16.0.

E2 · Open the G1

3 min

Run the "open the G1" block and explain, in your own words, where each number on the second line comes from.

Done when: python3 kit/abrir.py unitree_g1/scene.xml → nq=36 nv=35 nu=29 and saída: 0.

E3 · The G1 with hands

5 min

Open unitree_g1/scene_with_hands.xml with the same script and check the rule nq = nu + 7.

Done when: python3 kit/abrir.py unitree_g1/scene_with_hands.xml | sed -n 2p → nq=50 nv=49 nu=43.

07Lesson quiz

The explanation appears after you answer.

Question 1 of 4

Why does the G1 have nq=36 and not 29?skill

08In three sentences

FileThe MJCF describes the body, joints, actuators, sensors, and poses.
NumbersFree base: nq = nu + 7 and nv = nu + 6.
Workbench~/fth with MuJoCo 3.16.0 and Menagerie 62ab00f, pinned.

To go further

Previous lessonNext lesson