Skip to main content

Overview

The PID Controller module provides precise process control for temperature, position, speed, and other continuous variables. It includes auto-tuning algorithms and advanced features for production systems.

Basic PID Control

This example demonstrates a simple temperature control system using PID.
1

Enable the module

Add the module definition before including Kinematrix:
#define ENABLE_MODULE_PID_CONTROLLER
#include "Kinematrix.h"
2

Configure control parameters

Define your PID gains and control loop settings:
const float SETPOINT = 60.0;       // Target temperature in Celsius
const float KP = 2.0;              // Proportional gain
const float KI = 0.1;              // Integral gain
const float KD = 0.5;              // Derivative gain
const float TIME_STEP = 0.1;       // Control loop time step in seconds
const float MIN_OUTPUT = 0.0;      // Minimum output value
const float MAX_OUTPUT = 255.0;    // Maximum output value (PWM)
3

Create PID instance

Initialize the controller with your parameters:
PIDController pid(KP, KI, KD, TIME_STEP, MIN_OUTPUT, MAX_OUTPUT);
4

Set up in setup()

Configure the setpoint and pins:
void setup() {
    Serial.begin(115200);
    pinMode(HEATER_PIN, OUTPUT);
    
    // Set the target setpoint
    pid.setSetPoint(SETPOINT);
    
    // Calculate optimal integral limit
    pid.calculateOptimalIntegralLimit();
}
5

Run control loop

Compute and apply control output:
void loop() {
    // Read the temperature sensor
    currentTemperature = readTemperature();
    
    // Compute new control output
    controlOutput = pid.compute(currentTemperature);
    
    // Apply the control output to the heater
    analogWrite(HEATER_PIN, (int) controlOutput);
}

Complete Example

#define ENABLE_MODULE_PID_CONTROLLER
#include "Kinematrix.h"

// Pin definitions
const int TEMP_SENSOR_PIN = 33;
const int HEATER_PIN = 9;

// Control parameters
const float SETPOINT = 60.0;
const float KP = 2.0;
const float KI = 0.1;
const float KD = 0.5;
const float TIME_STEP = 0.1;
const float MIN_OUTPUT = 0.0;
const float MAX_OUTPUT = 255.0;

// Create the PID controller instance
PIDController pid(KP, KI, KD, TIME_STEP, MIN_OUTPUT, MAX_OUTPUT);

float currentTemperature = 0.0;
float controlOutput = 0.0;

float readTemperature() {
    int rawValue = analogRead(TEMP_SENSOR_PIN);
    // Convert to temperature (example for LM35)
    float temperature = (rawValue * 0.0048828125 * 100.0);
    return temperature;
}

void setup() {
    Serial.begin(115200);
    pinMode(HEATER_PIN, OUTPUT);
    
    pid.setSetPoint(SETPOINT);
    pid.calculateOptimalIntegralLimit();
}

void loop() {
    currentTemperature = readTemperature();
    controlOutput = pid.compute(currentTemperature);
    analogWrite(HEATER_PIN, (int) controlOutput);
    
    // Monitor PID components
    Serial.print("Temp: ");
    Serial.print(currentTemperature);
    Serial.print(", Output: ");
    Serial.print(controlOutput);
    Serial.print(", P: ");
    Serial.print(pid.getProportionalComponent());
    Serial.print(", I: ");
    Serial.print(pid.getIntegralComponent());
    Serial.print(", D: ");
    Serial.println(pid.getDerivativeComponent());
}

Advanced Features

The PID controller supports several advanced features for production systems.

Derivative Filter

Reduces noise sensitivity in the derivative term:
pid.enableDerivativeFilter(0.2);  // Alpha = 0.2 (lower = more filtering)

Deadband

Prevents control action for small errors near the setpoint:
pid.setDeadband(5.0);  // Errors less than 5 units are ignored

Setpoint Ramping

Creates gradual transitions to new setpoints:
pid.enableSetpointRamping(100.0);  // 100 units per second
pid.setSetPoint(800.0);  // Will ramp gradually to this value

// Get current ramped setpoint
float currentTarget = pid.getCurrentRampedSetpoint();

Output Rate Limiting

Prevents abrupt changes in control output:
pid.setOutputRateLimit(50.0);  // 50 units per second max change

Performance Monitoring

Track system performance metrics:
// Enable performance monitoring
pid.setSettlingThreshold(0.02);  // 2% threshold

// In loop, check if settled
if (pid.isSystemSettled()) {
    Serial.print("Settling time: ");
    Serial.print(pid.getSettlingTime());
    Serial.print(" seconds, Overshoot: ");
    Serial.print(pid.getOvershoot());
    Serial.println("%");
}

Motor Control Example

Bi-directional motor control with position feedback:
void applyMotorControl(float output) {
    if (output > 0) {
        digitalWrite(MOTOR_DIR_PIN, HIGH);
        analogWrite(MOTOR_PWM_PIN, (int) output);
    } else {
        digitalWrite(MOTOR_DIR_PIN, LOW);
        analogWrite(MOTOR_PWM_PIN, (int) abs(output));
    }
}

Auto-Tuning

The module includes auto-tuning algorithms to determine optimal PID gains.

Available Methods

  • Ziegler-Nichols Method 1: Classic oscillation method
  • Ziegler-Nichols Method 2: Step response method
  • Cohen-Coon: For processes with delay

Usage

Refer to the auto-tuning examples:
  • pid_controller_zn1-tuning-example.ino
  • pid_controller_zn2-tuning-example.ino
  • pid_controller_cohen-coon-example.ino

Parameter Persistence

Save and load PID parameters to/from EEPROM:
// Save current parameters
pid.saveToEEPROM(0);  // Address 0

// Load parameters
pid.loadFromEEPROM(0);
See pid_controller_esp32-eeprom-example.ino for complete implementation.

Key Methods

MethodDescription
setSetPoint(float)Set target value
compute(float)Calculate control output
reset()Reset controller state
getKp(), getKi(), getKd()Get current gains
setKp(), setKi(), setKd()Update gains
getProportionalComponent()Get P term
getIntegralComponent()Get I term
getDerivativeComponent()Get D term

Hardware Requirements

  • Temperature/position sensor with analog output
  • PWM-capable output pin
  • Actuator (heater, motor, etc.)

Source Files

Example files located at:
  • Basic: example/modules/control/EXAMPLE-PIDController/pid_controller_basic-pid-example/
  • Advanced: example/modules/control/EXAMPLE-PIDController/pid_controller_advanced-features-example/

Build docs developers (and LLMs) love