explainer
PID control: build a command from error and measured motion
Build a PID controller from proportional, integral, and derivative terms. Compare tracking and load rejection, calculate each command contribution, and check the stability limit of integral gain.
What you will learn
- Calculate the proportional, integral, and derivative contributions to a command.
- Keep controller signs and gain units consistent with the plant.
- Explain how integral action can supply a holding command at zero error.
- Compare P, PI, PD, and PID using the same plant and disturbance.
- Check the analytic stability condition before interpreting a finite response plot.
Before you start
A controller needs a nonzero command to hold this plant at its target. Proportional control supplies that command through a remaining error. Integral action can supply it even after the error reaches zero, provided the loop stays stable.
You will build PID control one term at a time, compare four controller types, and inspect the command behind each response.
Define the plant for PID control
Use a normalized second-order plant with output y, command u, and opposing load d. Let T = 1 s set its time scale:
T²ÿ + Tẏ + y = u − d, with T = 1 s
ÿ + ẏ + y = u − d, using numerical time in seconds
Output, command, reference, and load are dimensionless normalized signals. The restoring term y means that holding a positive output requires a positive command, even with d = 0. This is a teaching model with fixed coefficients, not a fitted robot joint.
The reference r steps from zero to one at t = 0 and stays there. The load starts at zero, then changes to the selected nonnegative value at t = 4 s. Positive d opposes positive output acceleration because it enters as −d.
Every run starts with y = 0, ẏ = 0, and zero accumulated controller contribution. Measurement is exact, and the actuator applies the command immediately without saturation. The feedback-control lesson explains how the measurement path closes a loop; Modern Robotics' torque-input overview introduces PID terms for a physical joint model.
Turn current error into a proportional command
Define tracking error as e = r − y. Positive error means the output is below its target. A nonnegative proportional gain Kp creates:
P = Kp e = Kp(r − y)
With r = 1, y = 0.8, and Kp = 2, the proportional contribution is 0.4. If y rises above one, the error becomes negative and P requests motion back toward the target. Kp is dimensionless because input and output share normalized units.
P responds to the present error. It has no memory of how long that error has persisted. In this plant, zero error would make a P-only command zero, leaving no command to balance the restoring term or an opposing load.
Accumulate error in an integral state
Store the integral contribution directly in a controller state I:
İ = Ki e
I(t) = Ki ∫₀ᵗ e(τ) dτ, with I(0) = 0
Ki has units of 1/s. Integrating a dimensionless error over time and multiplying by Ki gives a dimensionless command contribution. With Ki = 1/s and a constant error of 0.2 over half a second, I increases by 0.1.
When the error reaches zero, I stops changing and keeps its stored value. That memory can supply the command required to hold the output against a constant load. A negative error decreases I; it does not instantly erase the accumulated contribution.
The experiment disables integral action when Ki = 0 and fixes I at zero. Each gain change restarts the calculation from the initial state. It does not retune a running controller while retaining an old integral value.
React to measured motion with derivative action
Use the measured output rate for the derivative contribution:
D = −Kd ẏ
Kd has units of seconds, so Kd times a rate in 1/s gives a dimensionless command. With Kd = 1 s and ẏ = 0.1/s, D = −0.1. Motion in the negative direction makes D positive.
For a constant reference, ė = −ẏ, so this matches derivative action on error. At a reference step, derivative on measurement avoids differentiating that jump. Our initial rate is zero, so D(0+) = 0, while the proportional contribution jumps to Kp.
MathWorks' PID controller forms call the full arrangement with P and I on error and D on measurement PI-D. It belongs to the PID family and gives the derivative term zero reference weight. An ideal derivative of error would produce a different reference response at a step.
The lab assumes exact measured rate. Real differentiation can amplify high-frequency sensor noise, and practical derivative filters add dynamics. Here D acts like extra damping in the plant equation; it does not predict an unknown future motion.
Derivative kick and filtering compares a reference step with a noisy measurement. Calculate the filtered command and see how the filter changes its amplitude and phase.
Add the three command contributions
The actuator receives their sum:
u = P + I + D
u = Kp(r − y) + I − Kd ẏ
For a checkable snapshot, choose Kp = 2, Ki = 1/s, Kd = 1 s, y = 0.8, ẏ = 0.1/s, and I = 0.7. These are supplied state values, not a claim about the default trajectory at a particular time.
| Contribution | Calculation | Value |
|---|---|---|
| P | 2 × (1 − 0.8) | 0.4 |
| I | Stored contribution | 0.7 |
| D | −1 × 0.1 | −0.1 |
| Total u | 0.4 + 0.7 − 0.1 | 1.0 |
If d = 0.5, the plant acceleration is 1.0 − 0.5 − 0.1 − 0.8 = −0.4/s². The output still moves upward at this instant, but its rate decreases. Meanwhile İ = 1 × 0.2 = 0.2/s, so the integral contribution continues to increase.
Compare P, PI, PD, and PID
Set selected gains to zero to remove their terms. The four main presets keep Kp = 2 and use the same opposing load of 0.5 beginning at four seconds.
| Type | Ki (1/s) | Kd (s) | Output at 6 s | Error at 6 s |
|---|---|---|---|---|
| P | 0 | 0 | 0.470141 | 0.529859 |
| PI | 1 | 0 | 0.886547 | 0.113453 |
| PD | 0 | 1 | 0.483487 | 0.516513 |
| PID | 1 | 1 | 0.824977 | 0.175023 |
These are numerical results for this plant and these gains. PI has less error than PID at this particular instant. Adding another term does not guarantee a better score on every response measure.
D changes damping, so compare the complete transient as well as one reading. I changes the eventual holding behavior and adds a dynamic state. The PID tuning lesson turns those effects into choices against stated goals.
Find what holds the output at its target
After the load becomes constant, an equilibrium has ẏ = ÿ = 0. The plant then requires u = y + d.
With P or PD and I disabled, D is zero at equilibrium. Solving Kp(1 − y) = y + d gives:
y∞ = (Kp − d)/(1 + Kp)
e∞ = (1 + d)/(1 + Kp)
For Kp = 2 and d = 0.5, the output approaches 0.5, the error approaches 0.5, and u approaches 1.0. The derivative gain changes the transient but vanishes from this equilibrium calculation. Even at zero load, this finite-gain P controller needs some error to balance the restoring term.
With Ki positive, a stable equilibrium also requires İ = Ki e = 0. Thus e = 0, y = 1, P = D = 0, and I = u = 1 + d = 1.5. Lynch and Park's PID treatment shows how a stored integral contribution supports a constant load at zero error.
This conclusion needs a stable loop and enough actuator authority. The integral-windup lesson adds actuator limits, which can prevent the command from producing the motion that the integrator expects.
Check how integral gain changes stability
Substitute the controller into the plant, then analyze its homogeneous state dynamics. When Ki = 0, the active model has two states and characteristic polynomial:
T²s² + (T + Kd)s + (1 + Kp), with T = 1 s
All its coefficients are positive for the lab's nonnegative gains. Both active modes decay. An unused, frozen integral variable is not an additional active pole at zero in this reduced experiment.
For Ki positive, I adds a third state. The characteristic polynomial and strict stability condition become:
p(s) = T²s³ + (T + Kd)s² + (1 + Kp)s + Ki
(T + Kd)(1 + Kp) > T²Ki
The cubic Routh criterion gives this inequality. With numerical time in seconds and T = 1, the lab reports the Routh gap as (1 + Kd)(1 + Kp) − Ki. Positive means asymptotic stability; zero marks the marginal boundary; negative gives two right-half-plane modes.
If a nonzero computed gap is too small to determine its sign reliably, the helper labels it near the boundary and withholds a stable-limit prediction. That numerical uncertainty does not establish an exactly marginal model.
For Kp = 2 and Kd = 0, the boundary is Ki = 3/s. Its numerical polynomial factors as (s + 1)(s² + 3). A decaying mode accompanies two undamped oscillatory modes; the loop is not BIBO stable because a bounded resonant input can produce unbounded output.
Ki = 4/s crosses that boundary and creates growing oscillations. This instability occurs even with an unlimited actuator. The default PID gains give a positive gap of (1 + 1)(1 + 2) − 1 = 5.
Because D uses measurement only, the zero-state reference transfer for Ki positive is Y(s)/R(s) = (Kp s + Ki)/p(s). The opposing-load transfer is Y(s)/D(s) = −s/p(s). Derivative feedback changes their denominator while leaving the derivative of the reference out of the numerator.
Inspect the command and response together
Compare P, PI, PD, and PID while keeping the load unchanged. The output chart retains a P-only comparison with the same Kp. Inspect I after the load begins and watch D change sign as the output changes direction.
Move the cursor to zero: the initial command comes entirely from P. At four seconds, the load changes acceleration immediately while output, rate, and controller states remain continuous. Select the boundary and excessive-integral-gain presets to compare the plot with the analytic stability label.
The chart covers twelve seconds. It uses fourth-order Runge–Kutta integration with steps at most 0.001 s and splits the calculation exactly at the load change. Independent state-transition calculations and step refinement check its numerical accuracy; a finite simulation cannot establish stability or an infinite-time settling claim.
The gain sliders recalculate a complete experiment from rest. This is a comparison tool for continuous-time models. It omits sensor noise, derivative filtering, sample-and-hold control, delays, and saturation, each of which can change practical behavior.
Reproduce the controller comparison in Python
This standard-library example integrates the three states and prints the four preset responses. Each RK4 interval uses one fixed load value, including its final stage, so the step at four seconds never leaks into earlier motion.
from math import ceil
def response(kp, ki, kd, load=0.5, t=6.0):
x = (0.0, 0.0, 0.0) # output, rate, integral contribution
for duration, d in ((min(t, 4.0), 0.0), (max(t-4.0, 0.0), load)):
n = ceil(duration / 0.001)
if not n:
continue
h = duration / n
def f(state):
y, v, integral = state
return (v, kp*(1-y)+integral-(1+kd)*v-y-d, ki*(1-y))
def add(state, slope, factor):
return tuple(a+factor*b for a, b in zip(state, slope))
for _ in range(n):
a = f(x)
b = f(add(x, a, h/2))
c = f(add(x, b, h/2))
e = f(add(x, c, h))
x = tuple(xi+h*(ai+2*bi+2*ci+ei)/6
for xi, ai, bi, ci, ei in zip(x, a, b, c, e))
y, v, integral = x
p, derivative = kp*(1-y), -kd*v
return y, 1-y, p+integral+derivative, p, integral, derivative
for name, gains in (("P", (2, 0, 0)), ("PI", (2, 1, 0)),
("PD", (2, 0, 1)), ("PID", (2, 1, 1))):
y, error, u, *_ = response(*gains)
print(f"{name}: y={y:.6f}, error={error:.6f}, u={u:.6f}")
_, _, _, p, integral, derivative = response(2, 1, 1)
print(f"PID terms: P={p:.6f}, I={integral:.6f}, D={derivative:.6f}")
print(f"PID initial command: {response(2, 1, 1, t=0)[2]:.6f}")
print(f"PI boundary gap: {(1+0)*(1+2)-3:.6f}")
Expected output:
P: y=0.470141, error=0.529859, u=1.059718
PI: y=0.886547, error=0.113453, u=1.387259
PD: y=0.483487, error=0.516513, u=1.044937
PID: y=0.824977, error=0.175023, u=1.469178
PID terms: P=0.350045, I=1.165782, D=-0.046649
PID initial command: 2.000000
PI boundary gap: 0.000000
Try it yourself
Exercise 1. Take r = 1, y = 0.75, ẏ = −0.2/s, and stored I = 0.6. Use Kp = 2, Ki = 1/s, Kd = 1 s, and load d = 0.5. Find P, I, D, total command, acceleration, and the rate of change of I.
Check the signed command budget
Error is 0.25, so P = 0.5 and İ = 0.25/s. The measured rate is negative, making D = +0.2. Together with I = 0.6, the command is 1.3.
Acceleration is 1.3 − 0.5 − (−0.2) − 0.75 = 0.25/s². The output currently moves downward, but the positive acceleration reduces that downward rate.
Exercise 2. Use Kp = 1, Kd = 1 s, and Ki = 4/s. Classify the active dynamics. Then disable integral action and find the new dynamic order and the steady error under load d = 0.5.
Check the boundary and reduced model
The numerical Routh gap is (1 + 1)(1 + 1) − 4 = 0. The cubic factors as (s + 2)(s² + 2), so the modes are −2/s and ±j√2/s. The loop is marginal and not BIBO stable.
With Ki = 0 and I disabled, the active second-order polynomial is s² + 2s + 2. Its roots −1 ± j per second decay. Steady error is (1 + 0.5)/(1 + 1) = 0.75, output is 0.25, and command is 0.75.
Sources and further study
- Lynch and Park, Modern Robotics 11.4, part 1: PID terms, PD joint control, and derivative action as added damping.
- Lynch and Park, Modern Robotics 11.4, part 2: integral action under a constant disturbance, the added state, and the risk of excessive integral gain.
- MathWorks, PID controller types: parallel forms, derivative filters, and PI-D with derivative action on measurement.
Continue with PID tuning to choose gains against response and command requirements, then use integral windup to account for a command that the actuator cannot deliver.