FTH 1 · Teaching it to walk|INEMA.CLUB-PRO

Lesson 2 · 16 min

The bottom layer: PD control at the joints

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
A mechanical knee from a humanoid robot clamped to an aluminum bracket on a workbench, with a blurred oscilloscope in the background showing a damped curve.

In this lesson you will

  1. 1Torque = kp × (target − position) − kd × velocity, limited by the motor
  2. 249% overshoot with no kd; 1% with kd 2
  3. 3The per-joint gains in deploy.yaml (knee 150/4, ankle 40/2)
  4. 4Stiff PD holds the G1 up; the policy's gains alone don't

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.

01From target to torque

Click each block. This is the loop that runs inside each of the 29 joints.

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

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.

02One knee, three brakes

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.

Terminal · step on the knee
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; done
Example from the repository
sobressinal: 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.

03The G1 standing with PD alone

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

Terminal · kp 300, kd 5 on all of them
F=${FTH:-$HOME/fth}; cd $F/locomocao && . $F/.venv/bin/activate
python3 kit/ficar_em_pe.py --kp 300 --kd 5; echo "saída: $?"
Terminal · the policy's gains
F=${FTH:-$HOME/fth}; cd $F/locomocao && . $F/.venv/bin/activate
python3 kit/ficar_em_pe.py --ganhos rl_lab; echo "saída: $?"
Example from the repository
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.

04How RL repos store the PD

What changes when you read a real deploy.yaml.

1. Per joint

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.

05Practice

Feel the PD before putting a network on top of it.

E1 · Three brakes

5 min

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

E2 · Standing with PD

3 min

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.

E3 · Find the limit

10 min

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

06Lesson quiz

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

07In three sentences

PDTorque = kp × error − kd × velocity, clipped at the motor limit.
MeasureWithout kd, 49% overshoot; with kd 2, 1%, and a 0.03 rad error that only the policy corrects.
RuleThe gains are part of the policy: change the gains and you change the policy.

Going further

Previous lessonNext lesson