E1 · Three brakes
5 minRun the knee step with kd 0, 2 and 10 and write down the overshoot of each.
Done when: the output shows sobressinal: 49 % (kd 0) and sobressinal: 1 % (kd 2).
Lesson 2 · 16 min
Between the policy and the motor sits a PD controller on each joint, with kp and kd chosen during training. In this lesson you measure a knee's response to a step with three kd values, hold the G1 upright with PD alone, and find out why the policy's gains can't keep the robot standing on their own.
Start the lesson
Goal: measure the effect of kp and kd on a joint and hold the G1 upright with PD alone, understanding why the policy's gains aren't enough without the policy.
Click each block. This is the loop that runs inside each of the 29 joints.
There's no I term: the full PID with integral and classic tuning is a topic for the robot course. In RL robots, the policy corrects the error that's left over.
degrau_junta.py frees the joint from the pelvis (the G1 hangs in the air) and sends the left knee from 0.3 to 0.8 rad with kp 100 and kd 0, 2, and 10.
F=${FTH:-$HOME/fth}; cd $F/locomocao && . $F/.venv/bin/activate
for kd in 0 2 10; do python3 kit/degrau_junta.py --kp 100 --kd $kd | tail -2; donesobressinal: 49 % · posição após 1 s: 0.78 rad (erro 0.02 rad) assentou (erro < 0.02 rad): em 992 ms sobressinal: 1 % · posição após 1 s: 0.77 rad (erro 0.03 rad) assentou (erro < 0.02 rad): não, em 1 s sobressinal: 0 % · posição após 1 s: 0.77 rad (erro 0.03 rad) assentou (erro < 0.02 rad): não, em 1 s
Two lines per kd (0, 2, and 10). With no kd, the knee overshoots the step by 49% and takes almost 1 s to settle. With kd 2, it overshoots only 1%. With kd 2 or 10, the joint stops 0.03 rad short of the target: with no integral term, the PD needs an error to produce the torque that holds up the leg's weight.
ficar_em_pe.py puts the robot on the ground in the default pose and holds each joint for 5 s, with no policy. Standing = pelvis between 0.70 and 0.85 m and tilt below 20°.
F=${FTH:-$HOME/fth}; cd $F/locomocao && . $F/.venv/bin/activate
python3 kit/ficar_em_pe.py --kp 300 --kd 5; echo "saída: $?"F=${FTH:-$HOME/fth}; cd $F/locomocao && . $F/.venv/bin/activate
python3 kit/ficar_em_pe.py --ganhos rl_lab; echo "saída: $?"ganhos: kp = 300 · kd = 5 em todas as juntas altura da pelve: 0.79 m no início → 0.78 m após 5 s · inclinação: 1° maior torque pedido: 12 N·m · juntas que bateram no limite de torque: 0 de pé (pelve entre 0.70 e 0.85 m, inclinação < 20°): sim saída: 0
With kp 300 on every joint, the G1 turns into a statue: it stands up, tilted 1°, asking for at most 12 N·m.
ganhos: kp/kd por junta do unitree_rl_lab altura da pelve: 0.79 m no início → 0.09 m após 5 s · inclinação: 95° maior torque pedido: 41 N·m · juntas que bateram no limite de torque: 2 de pé (pelve entre 0.70 e 0.85 m, inclinação < 20°): não saída: 1
With the per-joint gains from deploy.yaml (hip 100/2, knee 150/4, ankle 40/2, waist 200/5, arms 40/10), the robot collapses and two joints hit the torque limit. Measured here with the same kp on every joint, the standing G1 only stays up with kp from about 200.
This is not a bug: the policy was trained with these gains, and it is the policy that closes the balance loop. Changing the gains invalidates the policy.
ERRO: passe --kp e --kd (ex.: --kp 100 --kd 2) ou --ganhos rl_lab. saída: 1
The script requires both gains or the ready-made set. PD is a pair: kp without kd is a spring with no brake.
What changes when you read a real deploy.yaml.
In the unitree_rl_lab deploy.yaml, stiffness (kp) and damping (kd) come as a list with one value per joint, in the Unitree SDK order.
On the robot, the deploy sends q, dq, kp, kd and tau for each motor every cycle; the driver runs the PD.
The default pose and the actions come in Isaac Lab order, and joint_ids_map converts between them. Mixing the orders brings the robot down in 1 s: course 2, lesson 6, shows the mistake.
The gains go into training: the policy learns to walk with that PD. On the robot, using other kp/kd means running a different policy from the one you trained.
Feel the PD before putting a network on top of it.
Run the knee step with kd 0, 2 and 10 and write down the overshoot of each.
Done when: the output shows sobressinal: 49 % (kd 0) and sobressinal: 1 % (kd 2).
Keep the G1 standing for 5 s with only the stiff PD.
Done when: python3 kit/ficar_em_pe.py --kp 300 --kd 5; echo "saída: $?" → de pé (pelve entre 0.70 e 0.85 m, inclinação < 20°): sim and saída: 0.
Lower kp (keeping kd 5) until the robot falls. Write down the smallest kp that still holds and compare it with the policy's ankle value of 40.
Done when: you have a kp with de pé (…): sim and a lower one with de pé (…): não and saída: 1 (on 10/19/2026: 200 holds, 175 falls).
The explanation appears after your answer.
Question 1 of 3
With kd 2, the knee stops 0.03 rad from the target and never gets there. Why?skill
Question 2 of 3
With the deploy.yaml gains and no policy, the G1 falls. What does that tell you?
Question 3 of 3
Where do the kit and the robot run the PD?
Choose an option. The explanation appears after you try.