Skip to content

PD control, gains and armature

Stage 4 · Model and simulation · ~30 min · Before this: 04 Actuators, 13 The robot description, 14 Simulation · numbers from the repository as of 2026-11-02

A walking policy (the trained neural-network controller of page 16) does not command torques. Fifty times a second it sends each joint a target angle, and a much faster proportional-derivative (PD) loop turns the gap between target and actual angle into torque. How stiff and how damped that loop is, and how much hidden motor inertia sits behind it, decides whether a policy trained in simulation moves the same way on the robot.

Why a humanoid needs this: the “brain” (the policy) is too slow and too coarse to drive each motor’s current directly, the same way you decide “put my foot there” without thinking about each muscle fibre. A small, fast reflex in every joint does the last step. This page is about tuning that reflex, and about one hidden number (the motor’s spinning inertia) that simulators get wrong if nobody writes it down.

Picture the knee as a heavy door on a hinge, with a spring that pulls it towards a chosen angle and a shock absorber that resists speed. The spring’s stiffness is the proportional gain kp, the shock absorber is the derivative gain kd. Move the chosen angle and the door swings towards it. Too little spring and gravity wins; too much spring and too little damping and it overshoots and rings; damping matched to stiffness and inertia and it glides in. The “door’s” inertia is not only the leg: the motor’s rotor, spinning nine times faster than the joint through the gearbox, adds an inertia that the joint feels as if it were 81 times larger. That hidden inertia is called armature. (The 81 is the gear ratio squared, 9 × 9; the maths is below.)

One joint, one link, gravity, a motor with a torque limit and a torque-speed line, and a PD loop that runs at a chosen rate, possibly with a delay. At t = 0.05 s the target jumps. The simulation integrates the joint with 4th-order Runge-Kutta at 0.1 ms steps and holds the torque constant between controller updates, as a digital motor driver does.

Start here: press Marvin Bot knee, then Too stiff and Too soft, and compare the curves. How to read the plot: the blue line is where the joint actually is, the orange line is where it was told to go; the closer and quicker blue settles on orange without swinging past it, the better. The green line (lower plot) is the motor torque, which must stay inside the red limit. Good readouts: overshoot under about 20%, settling time a few tenths of a second, small steady-state error. Several sliders are on a log scale so they can span tiny wrists and heavy knees.

Presets

Link and gravity

Knee: shin, ankle and foot, 3.42 kg, 0.184 kg·m² (from the URDF).
Torque gravity puts on the joint with the link horizontal. Knee with the foot off the ground: 3.42 × 9.81 × 0.205 m = 6.9 N·m.

Motor

How hard the motor's own spinning rotor is to speed up, measured at the motor shaft, before the gearbox.
Motor turns per joint turn. RobStride RS04: 9. The armature grows with its square.
Most torque the motor can give, briefly (RS04: 120 N·m).
Top joint speed; the faster the joint turns, the less torque is left (RS04: 20.9 rad/s = 200 rpm).
Dry friction torque in the gearbox that always resists motion.

Gains

The spring: torque per radian of error. Higher = snappier, less sag (log scale).
The shock absorber: torque per rad/s of speed. Higher = less swinging past the target (log scale).

Controller timing

How late information arrives, e.g. over the CAN cable (page 10).

Step

Armature IrN²
–
Natural frequency
–
Damping ratio ζ
–
Overshoot
–
Settling time (2%)
–
Steady-state error
–
Peak torque
–
Verdict
–
joint angletarget (as the motor sees it)same gains, no armaturetorquetorque limit

Notation: q is the joint angle; a dot on top means “rate of change”, so q̇ (“q-dot”) is the joint’s speed and q̈ (“q-double-dot”) its acceleration. An equation that links a quantity to its own rates of change, like the one below, is called a differential equation; the simulator solves it by taking small time steps (page 14).

Newton’s second law for rotation says J q̈ = τtotal: the angular acceleration q̈ (rad/s²) equals the net torque (N·m) divided by the inertia J (kg·m²). For one joint carrying one link,

J q̈ = τmotor − m g r sin q − τfriction

where m g r is the gravity moment (mass × 9.81 m/s² × distance from the joint to the link’s centre of mass) and q is measured from hanging straight down. This page holds every other joint still; in a real robot the inertia each joint feels changes with the pose of all the others.[1]

A PD controller sets the motor torque from the position error and the velocity:

τ = kp (q* − q) − kd q̇

q* is the target angle, kp (N·m/rad) the stiffness, kd (N·m·s/rad) the damping. RobStride’s MIT-style operation mode computes exactly this inside the motor driver, with an extra feed-forward torque term, from a target, a target velocity, kp and kd sent over CAN (robot/drivers/robstride.py; for the RS04 kp may be 0-5000 and kd 0-100).[4]

Without gravity and friction, substituting gives J q̈ + kd q̇ + kp q = kp q*, a mass-spring-damper. Its behaviour is set by two numbers:[2]

ωn = √(kp / J) ζ = kd / (2 √(kp J))

The natural frequency ωn (rad/s; divide by 2π for Hz) says how fast the joint responds; the damping ratio ζ says how it settles. Below ζ = 1 a step overshoots by e−πζ/√(1−ζ²) of the step size (ζ = 0.5: 16%; ζ = 0.7: 4.6%); at ζ = 1 it arrives as fast as possible without overshoot; above 1 it creeps in. With gravity the joint stops short of the target by the steady-state error m g r sin q / kp: a spring only pushes back when stretched. (A policy compensates by asking for a slightly higher target; an integral term would remove it but is rarely used under a learned policy.)

The motor’s rotor turns N times for each turn of the joint (N = 9 for the RS04). Its kinetic energy is ½ Irotor (N q̇)² = ½ (Irotor N²) q̇², so seen from the joint the rotor behaves like an extra inertia

Iarmature = Irotor × N²

that adds to the link’s: J = Ilink + Iarmature. It does not depend on the pose and it is not part of any link’s mass, so a URDF cannot hold it; MuJoCo and Isaac Lab add it to the joint directly (armature).[3][6] BeyondMimic reports that setting armature to zero in simulation gives excessive joint accelerations, overswinging and self-collisions.[5] It also matters numerically: a light link on a stiff PD loop has a very high ωn, which the simulator’s timestep may not resolve; armature lowers ωn and keeps the joint stable.

A real motor cannot deliver any torque at any speed. Isaac Lab’s DC motor model (DCMotor) clips the PD torque to a line that falls from the peak torque at standstill to zero at the no-load speed: τmax(q̇) = τpeak (1 − q̇/ω0), and the mirror image for braking.[6] When the PD torque is clipped the joint stops behaving like a linear spring-damper: steps take longer and overshoot changes, which is why a large stiff step looks different from a small one.

The policy is a neural network that sees the whole robot; running it costs milliseconds, and the walking dynamics it controls (steps, sway) happen at a few hertz, so 50 Hz is plenty. The joint’s own spring-mass dynamics are faster (the knee here: about 4 Hz with today’s gains, the wrist 8 Hz, and much faster for a stiffer loop), and a digital controller that updates its torque every T seconds adds a lag of about T/2. As ωnT approaches 1 the loop loses damping and at around 2 it goes unstable. So the policy outputs targets at 50 Hz, and the PD loop runs at the simulator’s physics step (5 ms in Isaac Lab, 2 ms in MuJoCo) or, on the robot, inside each motor driver, fed new targets at 500 Hz on the legs and 250 Hz on the arms.[7]

A delay of τd seconds shifts the phase of a signal at frequency ω by ω τd radians. Where the delay sits matters. A delay on the target (the policy’s command arriving late over CAN) leaves the PD loop untouched and simply makes every response late: harmless for the joint, but it matters for the policy’s balance loop, which is why training randomises it. A delay inside the loop (the torque computed from an old measurement, as if the PD ran on the main computer over CAN) eats phase margin (the loop’s safety buffer against the correction arriving so late that it pushes the wrong way): for the knee at today’s gains the loop crosses over near 30 rad/s, so 10 ms costs about 17° of a roughly 45° margin, and 25 ms nearly all of it.

Choice For Against
Stiff gains (high kp) Tracks targets closely, small gravity sag; a policy’s actions map almost directly to angles Amplifies sensor noise, hits torque limits, needs a fast loop, little passive compliance on impact; sim-to-real gaps in inertia show up as ringing
Soft gains Compliant on contact, robust to model error, gentle on gears Large tracking error that the policy must learn to compensate; the action scale has to grow
BeyondMimic rule: kp = Iarmω², kd = 2Iarmζω, ω = 10 Hz, ζ = 2[5] One principled rule for every joint, tied to the motor; ζ = 2 because armature alone underestimates the inertia Needs real rotor inertias (Marvin Bot’s are placeholders); light joints get very soft
Torque control (policy outputs torque) No hidden PD dynamics The policy must run fast and stabilise every joint itself; much harder to train and transfer
Learned actuator network[8] Captures the real motor’s dynamics, delay and friction from bench data Needs a bench and data per motor type; a black box

The BeyondMimic rule applied to the knee: Iarm = 0.03 kg·m², ω = 2π × 10 = 62.8 rad/s gives kp = 118 N·m/rad and kd = 7.5 N·m·s/rad, close to today’s 150 / 5. Including the shin, the knee’s true ζ is then 2 × √(0.03/0.214) = 0.75 and its true ωn 3.7 Hz, which is why the rule picks ζ = 2 rather than 1. Try the BeyondMimic rule preset.

  • Gain policy: keep the placeholder table, or adopt one rule (BeyondMimic’s) for all joints once rotor inertias are measured. The trade: the table works today and matches other open humanoids; the rule is consistent and explainable, but is only as good as the rotor inertias you feed it, and it makes light joints such as the wrists very soft.
  • How much delay to randomise in training (today 0-10 ms on commands, 0-20 ms on observations), based on the bench’s measured CAN round trip. More randomised delay makes the policy robust to a slow bus, but it learns to move more cautiously; too little and a real delay may surprise it.
  • What the bench must measure: rotor inertia (armature), friction, and the torque-speed curve at 48 V, per motor model. Each measurement costs bench time in phase 2 but replaces a placeholder that every trained policy currently depends on.
Your decision note

Built from your settings above. Paste it into an issue, a design discussion or an AI assistant session.

  1. K. M. Lynch and F. C. Park, Modern Robotics, Cambridge University Press 2017 — used for: joint dynamics, configuration-dependent inertia, reflected rotor inertia through a gearbox.
  2. MIT OpenCourseWare 2.004 Dynamics and Control II — used for: second-order system, natural frequency, damping ratio, overshoot formula.
  3. MuJoCo documentation, XML Reference (joint armature) — used for: armature as rotor inertia added to a joint.
  4. RobStride, Product_Information (manuals) — used for: operation-control (MIT) mode, peak torque, no-load speed, gear ratio.
  5. Q. Liao, T. E. Truong, X. Huang, Y. Gao, G. Tevet, K. Sreenath, C. K. Liu, BeyondMimic: From Motion Tracking to Versatile Humanoid Control via Guided Diffusion, arXiv 2508.08241, 2025 — used for: armature = rotor inertia × gear ratio², gain rule kp = Iω², kd = 2Iζω with ω = 10 Hz, ζ = 2, action scale 0.25 τmax/kp, effects of zero armature.
  6. Isaac Lab documentation, Actuators — used for: DC motor model with torque-speed clipping, delayed actuators, armature.
  7. N. Rudin, D. Hoeller, P. Reist, M. Hutter, Learning to Walk in Minutes Using Massively Parallel Deep Reinforcement Learning, CoRL 2021 — used for: policies outputting joint position targets to PD controllers at a lower rate than the physics.
  8. J. Hwangbo et al., Learning agile and dynamic motor skills for legged robots, Science Robotics 2019 — used for: learned actuator networks as an alternative to analytic motor models.