FTH 2 · From simulator to ground|INEMA.CLUB-PRO

Lesson 3 · 17 min

System identification: measure to model

Randomizing covers what you don't know; identifying shrinks what you don't know. In this lesson you hang the "simulated real" robot on the gantry, make the leg swing in a frequency sweep, record the encoders, and use MuJoCo's own system identification toolbox to find the kp and kd the motor really delivers.

Start the lesson
Humanoid robot suspended by straps on a steel gantry, feet off the ground, with cables connecting the leg to measurement equipment.

In this lesson you will

  1. 1The bench test: robot hanging, leg in a sweep from 0.5 to 3 Hz
  2. 2The mujoco.sysid toolbox (MuJoCo 3.5+): Parameter, ModelSequences, optimize
  3. 3Model error dropping from 8.16° to under 4° in the positions
  4. 4Why identifying only kp goes wrong when something is missing from the model

Goal: identify the actuator's kp and kd in a bench test with the mujoco.sysid toolbox and check them against the hidden value.

01From the test to the parameter

Click each block.

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

Each test identifies what it excites. A leg in the air says nothing about foot friction.

02What the toolbox does for you

mujoco.sysid arrived in MuJoCo 3.5.0 (02/12/2026); here, 3.16.0 with the [sysid] extra. Tap each step.

1. Parameter

Each parameter has a nominal value, a range, and a function that writes the value into the MjSpec (the editable model). In the kit: kp and kd scale the gains from deploy.yaml on the four tested joints.

03Install the toolbox and collect the test

The [sysid] extra brings scipy, matplotlib, and plotly. coletar.py records the test of the hanging "real robot".

Terminal · mujoco[sysid]
F=${FTH:-$HOME/fth}; cd $F && . .venv/bin/activate
pip install -q "mujoco[sysid]==3.16.0"
python3 -c "from mujoco import sysid; print('mujoco.sysid ok:', sysid.optimize.__name__, sysid.Parameter.__name__)"
Terminal · bench test
F=${FTH:-$HOME/fth}; cd $F/sim2real && . $F/.venv/bin/activate
python3 kit/coletar.py --saida $F/log.npz
Example from the repository
ensaio de bancada no mundo 'real': 1999 amostras em 4.0 s · 4 encoders + velocidades
  enc_left_hip_pitch     amplitude medida  18.6°
  enc_left_hip_roll      amplitude medida  29.6°
  enc_left_knee          amplitude medida  50.0°
  enc_left_ankle_pitch   amplitude medida  19.3°
gravado: ~/fth/log.npz

Four joints, 4 s, 1,999 samples. The knee swings 50° from end to end.

04Identify kp and kd

Starts from the nominal model (kp = kd = 1.0 × the one in deploy.yaml) and adjusts both.

Terminal · sysid
F=${FTH:-$HOME/fth}; cd $F/sim2real && . $F/.venv/bin/activate
python3 kit/sysid.py $F/log.npz --revelar; echo "saída: $?"
Terminal · kp only (the common mistake)
F=${FTH:-$HOME/fth}; cd $F/sim2real && . $F/.venv/bin/activate
python3 kit/sysid.py $F/log.npz --parametros kp --revelar | tail -4; echo "saída: ${PIPESTATUS[0]}"
Terminal · the same test in the "sim" world (E3)
F=${FTH:-$HOME/fth}; cd $F/sim2real && . $F/.venv/bin/activate
python3 kit/coletar.py --mundo sim --saida $F/log-sim.npz | tail -1
python3 kit/sysid.py $F/log-sim.npz | tail -4
Example from the repository
log: ~/fth/log.npz · 1999 amostras · sinais: 8 (posição e velocidade de 4 juntas)
resíduo, modelo nominal:       0.034
resíduo, modelo identificado:  0.014
erro das posições na bancada, modelo nominal:       8.16° (RMS)
erro das posições na bancada, modelo identificado:  3.14° (RMS)
kp         nominal   1.00 → identificado   0.57
kd         nominal   1.00 → identificado   1.08
kp         escondido   0.60 · dentro de ±10 %: sim
kd         escondido   1.00 · dentro de ±10 %: sim
saída: 0

kp comes back near 0.6 (the motor delivers 60% of the commanded gain) and kd stays near 1.0, because the "real" robot did not touch kd. The position error drops to less than half.

05Practice

Measure the actuator of the "simulated real" robot.

E1 · Recorded test

5 min

Install the toolbox and run the bench test.

Done when: python3 kit/coletar.py --saida ~/fth/log.npz ends with gravado: ~/fth/log.npz, showing enc_left_knee … 50.0°.

E2 · Identified kp and kd

5 min

Run the system identification and check it against the hidden value.

Done when: python3 kit/sysid.py ~/fth/log.npz --revelar; echo "saída: $?" → the kp line ends with dentro de ±10 %: sim (hidden 0.60) and saída: 0.

E3 · The test that lies

10 min

Run the same test in the "sim" world and identify (last block). Then explain in two lines why only kp, in the "real" log, falls outside ±10 %.

Done when: in the sim block, the kp line ends with identificado 1.00; you wrote that the latency (delay) missing from the model ended up in kp.

06Lesson quiz

The explanation appears after your answer.

Question 1 of 3

Why is the test done with the robot hanging from the gantry?skill

07In three sentences

TestRobot hanging, sweep from 0.5 to 3 Hz, noisy encoders: 1,999 samples in 4 s.
Toolboxmujoco.sysid fits kp and kd and brings kp back to within ±10 % of the hidden value.
CarefulWhat is missing from the model leaks into the parameters you left free.

Going further

Previous lessonNext lesson