Skip to content
Automatic Controls 1

The PID controller: tuning and implementation

Proportional, integral and derivative actions, comparison of responses, Ziegler-Nichols tuning with an example, derivative filter, anti-windup and microcontroller code.

The PID controller (proportional, integral, derivative) is by far the most used in industry: it regulates temperatures, pressures, flows, motor speeds, robot arm positions, drone altitude. It has only three parameters, can be tuned even without an accurate plant model and works well in most cases. In this lesson we see what the three actions mean, tuning methods and the practical details that make a real PID work.

The three actions

    \[ u(t) = K_p\,e(t) + K_i\int_0^t e(\tau)\,d\tau + K_d\,\frac{de}{dt},\qquad C(s) = K_p + \frac{K_i}{s} + K_d s \]

It is often written with time constants, C(s) = K_p\left(1 + \frac{1}{T_i s} + T_d s\right).

  • Proportional: reacts to the current error. The larger K_p, the quicker the response and the smaller the steady-state error, but the less damped the loop. On its own it leaves a steady-state error on type 0 plants.
  • Integral: reacts to the error accumulated in the past. It removes the steady-state error for constant references and disturbances (lesson on errors), but adds phase lag and tends to cause oscillation.
  • Derivative: reacts to how fast the error is changing, that is it “anticipates” where it is going. It adds phase lead and damping, but amplifies high-frequency noise.
Closed-loop step responses with P, PI and PID controllers on a third-order plant
With proportional action alone the output settles far from the desired value, with a steady-state error. With PI the steady-state error disappears but the response is slower and more oscillatory. With PID the response is quicker, reaches the final value and the oscillation is damped.

The figure shows typical behaviour on a plant G(s) = 1/(s + 1)^3. With P alone (K_p = 2) the output stops at 2/3: the steady-state error is 1/(1 + 2). With PI it reaches 1 but more slowly. With PID it reaches 1, faster and with limited oscillation.

Ziegler-Nichols tuning

The classic method, from 1942, is applied directly to the plant:

  1. remove integral and derivative action and increase K_p until the loop oscillates steadily;
  2. note the ultimate gain K_u and the period of the oscillation T_u;
  3. choose the parameters from the table.
ControllerK_pT_iT_d
P0.5\,K_u
PI0.45\,K_uT_u/1.2
PID0.6\,K_uT_u/2T_u/8

Example. For G(s) = 1/(s + 1)^3 the ultimate gain is found with Routh: the characteristic equation is s^3 + 3s^2 + 3s + 1 + K = 0, stable for 3\cdot 3 \gt 1 + K, that is K \lt 8. At the limit the auxiliary equation 3s^2 + 9 = 0 gives \omega_u = \sqrt3, so T_u = 2\pi/\sqrt3 \approx 3.63 s. The Ziegler-Nichols PID is K_p = 4.8, T_i \approx 1.81 s, T_d \approx 0.45 s.

The Ziegler-Nichols rules give a quick but rather oscillatory response (overshoot often 30 to 50%): they are a good starting point to refine. Bringing a real plant to the edge of stability can be dangerous; there are variants using the open-loop step response, and modern industrial controllers have an autotuning function that runs a controlled test and computes the parameters by itself.

The details that matter

A PID written as in the formula works poorly in reality. The standard fixes are:

  • Derivative filter. A pure derivative amplifies sensor noise. One uses \frac{K_d s}{1 + T_f s}, with T_f about a tenth of T_d, which limits the gain at high frequencies.
  • Derivative on measurement. When the reference changes as a step, the derivative of the error is an impulse that gives the actuator a violent kick (the “derivative kick”). So only the measured output is differentiated, -K_d\,dy/dt: for disturbances the effect is the same.
  • Anti-windup. Every actuator has limits: a valve does not open beyond 100%, a motor has a maximum voltage. If the actuator is saturated the error does not shrink, but the integral keeps growing (windup); when the error finally changes sign, the huge integral takes a long time to unwind and the output overshoots the reference by a lot. The solution is to stop integrating while the command is saturated.

The PID in a microcontroller

In practice the PID is a program run at regular intervals T_s, much shorter than the plant time constants. The integral becomes a sum and the derivative a difference:

/* discrete-time PID with filtered derivative on measurement and anti-windup */
float kp = 4.8f, ki = 4.8f / 1.81f, kd = 4.8f * 0.45f;
float Ts = 0.01f, a = 0.1f;        /* sampling step and filter */
float integ = 0, d = 0, y_prev = 0;

float pid(float r, float y) {
    float e = r - y;
    d = (1 - a) * d - a * kd * (y - y_prev) / Ts;
    y_prev = y;
    float u = kp * e + integ + d;
    if (u > 10.0f) u = 10.0f;            /* actuator saturation */
    else if (u < -10.0f) u = -10.0f;
    else integ += ki * e * Ts;           /* integrate only when not saturated */
    return u;
}

That is all: a few multiplications per cycle. This is why a PID runs on any microcontroller, even the smallest, and is found inside household appliances, drones, 3D printers and digital power supplies.

Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
0
Would love your thoughts, please comment.x
()
x