PLC PID Control Loop Tuning: Implementation & Examples in Structured Text

Implement and tune PID controllers in Structured Text — from basic proportional control to full PID with anti-windup, used in temperature, pressure, and flow regulation.

What Is PID Control?

PID (Proportional-Integral-Derivative) control is the most widely used feedback control algorithm in industrial automation. It continuously calculates an error between a desired setpoint and a measured process variable, then applies a correction based on three terms:

TermSymbolActionCorrects
ProportionalKpReacts to current errorPresent error
IntegralKiAccumulates past errorSteady-state offset
DerivativeKdPredicts future errorOvershoot/oscillation

The PID Formula

Output = Kp × Error + Ki × ∫Error dt + Kd × dError/dt

In discrete PLC form (sampled every cycle):

Output = Kp × Error + Ki × ErrorSum × dt + Kd × (Error - PrevError) / dt

Basic PID in Structured Text

PROGRAM BasicPID
VAR
    // Process
    Setpoint : REAL := 75.0;      // Desired temperature °C
    ProcessValue : REAL := 20.0;  // Measured temperature °C
    Output : REAL := 0.0;         // Control output 0-100%
    
    // Tuning parameters
    Kp : REAL := 2.0;
    Ki : REAL := 0.5;
    Kd : REAL := 0.1;
    
    // Internal
    Error : REAL := 0.0;
    PrevError : REAL := 0.0;
    ErrorSum : REAL := 0.0;
    ErrorDiff : REAL := 0.0;
    dt : REAL := 0.1;            // Sample time in seconds
    
    // Output limits
    OutMin : REAL := 0.0;
    OutMax : REAL := 100.0;
END_VAR

// Calculate error Error := Setpoint - ProcessValue;

// Proportional term // Integral term (accumulated error) ErrorSum := ErrorSum + (Error * dt);

// Derivative term (rate of change). // dt is the sample period in seconds. It MUST be > 0 — set it to your // actual cyclic task period (e.g. 0.1 for a 100 ms task) and never expose // it as a tunable that can land on zero. Real PLCs fault on dt = 0. ErrorDiff := (Error - PrevError) / dt;

// PID output Output := (Kp Error) + (Ki ErrorSum) + (Kd * ErrorDiff);

// Clamp output IF Output > OutMax THEN Output := OutMax; ELSIF Output < OutMin THEN Output := OutMin; END_IF;

// Store previous error PrevError := Error;

Reusable PID Function Block

Professional PLC programs use a reusable function block:

FUNCTION_BLOCK FB_PID
VAR_INPUT
    Enable : BOOL := FALSE;
    Setpoint : REAL := 0.0;
    ProcessValue : REAL := 0.0;
    Kp : REAL := 1.0;
    Ki : REAL := 0.0;
    Kd : REAL := 0.0;
    dt : REAL := 0.1;
    OutMin : REAL := 0.0;
    OutMax : REAL := 100.0;
    ManualMode : BOOL := FALSE;
    ManualOutput : REAL := 0.0;
    Reset : BOOL := FALSE;
END_VAR
VAR_OUTPUT
    Output : REAL := 0.0;
    Error : REAL := 0.0;
    IsActive : BOOL := FALSE;
END_VAR
VAR
    PrevError : REAL := 0.0;
    Integral : REAL := 0.0;
    Derivative : REAL := 0.0;
    RawOutput : REAL := 0.0;
END_VAR

IF Reset THEN Integral := 0.0; PrevError := 0.0; Output := 0.0; RETURN; END_IF;

IF ManualMode THEN Output := ManualOutput; // Bumpless transfer: pre-seed Integral so the first Auto-mode output // equals ManualOutput. Rearranging Output = Kp·Error + Ki·Integral // gives Integral = (ManualOutput - Kp·Error) / Ki. The divisor is Ki, // so guard Ki — not Kp. A P-only controller (Ki = 0) has no integral // term to track, so leave Integral cleared on every Manual scan. IF Ki <> 0.0 THEN Integral := (ManualOutput - Kp * (Setpoint - ProcessValue)) / Ki; ELSE Integral := 0.0; END_IF; RETURN; END_IF;

IF NOT Enable THEN Output := 0.0; IsActive := FALSE; RETURN; END_IF;

IsActive := TRUE;

// Error Error := Setpoint - ProcessValue;

// Integral with anti-windup Integral := Integral + (Error * dt);

// Derivative — dt is a VAR_INPUT with default 0.1, but the caller can // override it. Bind dt to the actual task period; if the FB is wired // up with dt = 0 it will fault here on every scan. Derivative := (Error - PrevError) / dt;

// Raw PID output RawOutput := (Kp Error) + (Ki Integral) + (Kd * Derivative);

// Clamp and anti-windup IF RawOutput > OutMax THEN Output := OutMax; // Anti-windup: stop integrating when saturated Integral := Integral - (Error * dt); ELSIF RawOutput < OutMin THEN Output := OutMin; Integral := Integral - (Error * dt); ELSE Output := RawOutput; END_IF;

PrevError := Error;

Anti-Windup Explained

Integral windup occurs when the output is saturated (at min/max) but the integral term keeps accumulating. When the error finally reverses, the accumulated integral causes massive overshoot.

The anti-windup technique above stops accumulating the integral when the output is clamped. This is called conditional integration or clamping anti-windup.

Real-World Example: Temperature Control

PROGRAM OvenControl
VAR
    // Inputs
    TempSensor : REAL := 25.0;     // °C from thermocouple
    TempSetpoint : REAL := 180.0;  // Target °C
    Enable : BOOL := TRUE;
    
    // PID controller
    TempPID : FB_PID;
    HeaterOutput : REAL := 0.0;
    
    // Safety
    OverTempAlarm : BOOL := FALSE;
    MaxTemp : REAL := 220.0;
END_VAR

// Safety check first OverTempAlarm := TempSensor > MaxTemp;

// Run PID TempPID( Enable := Enable AND NOT OverTempAlarm, Setpoint := TempSetpoint, ProcessValue := TempSensor, Kp := 3.0, Ki := 0.2, Kd := 0.5, dt := 0.1, OutMin := 0.0, OutMax := 100.0 );

HeaterOutput := TempPID.Output;

// Override on alarm IF OverTempAlarm THEN HeaterOutput := 0.0; END_IF;

Manual Tuning Method (Ziegler-Nichols)

The Ziegler-Nichols method is the most common manual tuning approach:

  • Set Ki = 0 and Kd = 0
  • Increase Kp until the system oscillates with constant amplitude
  • Record this Ku (ultimate gain) and Tu (oscillation period)
  • Calculate tuning parameters:
  • ControllerKpKiKd
    P only0.5 × Ku
    PI0.45 × Ku1.2 × Kp / Tu
    PID0.6 × Ku2 × Kp / TuKp × Tu / 8

    Example Calculation

    If Ku = 4.0 and Tu = 2.0 seconds:

  • Kp = 0.6 × 4.0 = 2.4
  • Ki = 2 × 2.4 / 2.0 = 2.4
  • Kd = 2.4 × 2.0 / 8 = 0.6
  • Practical Tuning Tips

  • Start with P only — Get the right ballpark response before adding I and D
  • Add I slowly — Too much integral causes oscillation; start at 1/10th of calculated value
  • D is optional — Many industrial loops work fine with PI only. Add D only for fast processes
  • Watch the output — If it's banging between 0% and 100%, reduce Kp
  • Sample time matters — dt must match your PLC task cycle time exactly
  • Filter the PV — Noisy sensors cause derivative kick; use a low-pass filter on ProcessValue
  • Bumpless transfer — When switching Auto↔Manual, track the integral to prevent output jumps
  • Common PID Pitfalls

  • Wrong dt value — Must match actual scan time, not an approximation
  • No anti-windup — Causes massive overshoot after large setpoint changes
  • Derivative of setpoint — Use derivative of PV, not error, to avoid "derivative kick" on SP changes
  • Tuning at wrong operating point — A system tuned at 50°C may oscillate at 200°C
  • Ignoring actuator limits — A valve can only open 0-100%; don't expect more from the PID
  • Cascaded PID Loops

    Advanced processes use an inner/outer loop cascade:

    PROGRAM CascadeControl
    VAR
        // Outer loop: Temperature (slow)
        OuterPID : FB_PID;
        TempSetpoint : REAL := 180.0;
        Temperature : REAL := 25.0;
        
        // Inner loop: Flow (fast)
        InnerPID : FB_PID;
        FlowSetpoint : REAL := 0.0;
        FlowRate : REAL := 0.0;
        ValveOutput : REAL := 0.0;
    END_VAR

    // Outer loop sets flow setpoint OuterPID( Enable := TRUE, Setpoint := TempSetpoint, ProcessValue := Temperature, Kp := 2.0, Ki := 0.1, Kd := 0.3, dt := 1.0, // Slow loop: 1 second OutMin := 0.0, OutMax := 100.0 ); FlowSetpoint := OuterPID.Output;

    // Inner loop controls valve InnerPID( Enable := TRUE, Setpoint := FlowSetpoint, ProcessValue := FlowRate, Kp := 1.5, Ki := 0.8, Kd := 0.0, dt := 0.1, // Fast loop: 100ms OutMin := 0.0, OutMax := 100.0 ); ValveOutput := InnerPID.Output;

    Try PID Control in Our Simulator

    Experiment with PID tuning in our online ST editor. Adjust Kp, Ki, and Kd in real-time and watch how the process responds. Check our motion control lessons for guided PID exercises.