Control
Control theory is about making a system do what you command, despite loads, noise and modelling errors, by measuring what it actually does and correcting for the difference. This page covers open and closed loop, PID and PD control, transfer functions and step responses, sampling rates, the hobby servo's internal loop, and compliance, using the Strido servos and its MuJoCo model as examples.
In Strido
- Rates: the firmware runs a
control and IMU loop ( kControlPeriodUs = 5000) and refreshes the servos at( kServoFrequencyHz; the SPT5435LV accepts up to). It streams state to the host at (all in firmware/strido_esp32s3/src/board_config.h). The joint command stream is( strido_sim/walk.py) and the learned policy runs at( strido/policy.py). - Servo model in simulation: MuJoCo position actuators with
kp="25" kv="0.4" forcerange="-3.432 3.432", plus jointdamping="0.25" armature="0.012" frictionloss="0.05"(models/mujoco/strido.xml). - Hardware: 12 SPT5435LV-180W position servos driven by a PCA9685 PWM board (servos, firmware).
Open loop and closed loop
Open loop applies a precomputed input and never checks the result. A trot gait that replays foot trajectories through inverse kinematics is open loop with respect to the body: if the robot slips, the gait does not notice.
Closed loop (feedback) measures the output
Strido stacks several loops, each faster than the one above it:
The servos give no position feedback to the host (strido_sim/rl/env.py). So the only joint-level loop closes inside each servo. The policy closes the body-level loop through the IMU.
PID control
The classic controller combines three terms:
- P pushes in proportion to the error, like a spring.
- I accumulates past error and removes steady-state offsets, at the cost of overshoot and wind-up.
- D opposes the rate of change, like a damper. In practice it acts on
instead of , which avoids a kick when the reference jumps.
For joints, the usual choice is PD with the target velocity set to zero:
This is exactly MuJoCo's <position kp kv> actuator. It is then clipped to the force range,
Transfer functions and the step response
Model one joint as an inertia
This standard second-order system explains most of what you see in a step response:
sets the speed. Rise time , and bandwidth for near . sets the shape. Below 1 the response overshoots and rings. The overshoot is . Above 1 it is sluggish but monotone. - Raising
speeds the response up but lowers , so you raise with it. - The static stiffness is
: a constant load leaves an error of . Only an integral term removes it.
Worked example: the MuJoCo knee
From models/mujoco/strido.xml: mass_report.yaml), so
That predicts a rise time of about
In the stand the knee carries
The policy can learn to command slightly past the target to cancel this. Because the RL environment randomises the servo stiffness each episode (env.py), the policy cannot rely on one exact value.
Sampling, delay and bandwidth
Digital controllers sample. The Nyquist limit says you need more than two samples per period of the fastest signal you care about. For good control, the rule of thumb is a loop 10–20 times faster than the closed-loop bandwidth. Delay matters just as much: a pure delay
For Strido:
| Loop | Rate | Period / worst-case added delay |
|---|---|---|
| Policy | ||
| Joint command stream | ||
| ESP32 control + IMU | ||
| Servo PWM frame | ||
| MuJoCo physics |
A classic analogue servo takes a new pulse only every GAIT_PERIOD_S in strido/policy.py). That gives 20 policy steps per cycle, while the fast loops below it do the stiff work.
The hobby servo's internal loop
A hobby servo is a small closed-loop system in a box: a DC motor, a gearbox, a potentiometer on the output and a controller chip. The pulse width encodes the target angle. The chip compares it with the pot reading and drives the motor with roughly proportional (often PD-like) control, saturating at the stall torque. You can neither read its position nor tune its gains. Externally it behaves like a stiff PD joint with a torque limit, a speed limit (no-load MAX_JOINT_SPEED_RAD_S), so that sudden steps do not pull near-stall current.
Impedance and compliance
A position controller with gains
Mapped to the foot through
Impedance control chooses this stiffness on purpose. A legged robot wants its feet compliant when they touch down, so impacts are absorbed and small terrain errors do not jolt the body, and stiff during stance. Robots with torque-controlled motors (the MIT Cheetah, for example) set
Check yourself
- Why does a PD-controlled joint carrying a constant load not reach its target exactly?
- If you double
and keep , what happens to and ? - Why would a
servo frame hurt more than a policy? - Where is the only joint-position feedback loop on the real robot?
Answers
- At steady state the P term must supply the load torque, so
. Only an integral term removes it. grows by . shrinks by , so there is more overshoot. - The frame delay sits inside the fast, stiff joint loop, whose bandwidth is several hertz. The policy shapes slower body motion (the
gait cycle) and relies on the joint loops beneath it. - Inside each servo, between its potentiometer and its controller chip. The host and the ESP32 never see the joint angle.
Further reading
- K. J. Åström and R. M. Murray, Feedback Systems: An Introduction for Scientists and Engineers, 2nd ed., Princeton University Press, 2021. Free online
- K. M. Lynch and F. C. Park, Modern Robotics, Cambridge University Press, 2017, ch. 11 (robot control, including impedance control).
- N. Hogan, "Impedance Control: An Approach to Manipulation", ASME J. Dynamic Systems, Measurement, and Control, 107(1), 1985.
- MuJoCo documentation: actuators.
- Servos and firmware in this wiki.