PID Controller

The PIDController class is used to create a Proportional-Integral-Derivative controller:

\[u(t) = k_p e(t) + k_i \int\limits_0^t e(t) dt + k_d \frac{d}{dt} e(t)\]

This class handles all of the feedback loop calculation.

Creating a PID Controller

The constructor for PIDController requires the three controller gains: kp, ki, and kd.

//Create a new PID Controller with gains kp = 1.0, ki = 0.05, and kd = 0.1
LouLib::Controllers::PIDController controller(1.0, 0.05, 0.1);

The above code will create a working PID controller, but the PIDController class also contains multiple methods to configure the controller to provide more functionality.

Set Delta Time

The setDeltaTime method takes a LouLib::Units::Time that represents how much time is between each controller loop. If this value is not set, this value defaults to 10 milliseconds.

Set Setpoint

The setSetpoint method is used to set the setpoint, or target value, for the controller. If this value is not set, the value defaults to zero.

Set Tolerance

The setTolerance method takes two parameters: errorTolerance and derivativeTolerance.

errorTolerance is the maximum error the system can have while being considered at the setpoint. If setTolerance is not called, this value defaults to zero, meaning the system will never be considered to be at the setpoint.

derivativeTolerance is the maximum derivative of the error the system can have while being considered at the setpoint. This parameter is optional when calling the setTolerance method. If this value is not set, this value will default to infinity, meaning the derivative will not be taken into account when deciding whether or not the system is at the setpoint.

Set Integrator Range

One issue with some PID controllers is integral windup, where a large initial error causes the integral value to be unusably high. To fix this, PIDController contains the setIntegratorRange which allows the user to set the range that the integral can accumulate in. If the integrator range is not set, it will default to negative infinity to infinity, meaning the integral will accumulate at all times.

Set Output Range

The setOutputRange method is used to set the minimum and maximum controller outputs. If the output range is not set, it will default to negative infinity to infinity, meaning the controller can output any value.

Below is an example of creating a PID controller using the configuration methods:

//Create a new PID Controller with gains kp = 1.0, ki = 0.05, and kd = 0.1
LouLib::Controllers::PIDController controller(1.0, 0.05, 0.1);

//Set Delta Time to 20 milliseconds
controller.setDeltaTime(20_ms);

//Set the controller setpoint
controller.setSetpoint(100);

//Set error tolerance, with default derivative tolerance
controller.setTolerance(0.5);

//Set integrator range
controller.setIntegratorRange(-5, 5);

//Set output range to VEX motor voltage range in milliVolts
controller.setOutputRange(-12000, 12000);

Using the PID Controller

The PID Controller can be used by calling the update and getOutput methods. The atSetpoint method can also be used to check if the system has reached the setpoint.

Warning

The PIDController assumes the update method is being called at an interval consistent with the configured period. Failure to do this will result in unintended behavior.

//create a new PID controller
LouLib::Controllers::PIDController controller(1.0, 0.05, 0.1);

//set error tolerance
controller.setTolerance(0.5);

//set delta time
double deltaTimeMilliseconds = 10;
controller.setDeltaTime(deltaTimeMilliseconds * LouLib::Units::MILLISECOND);

//create PID loop
while(!controller.atSetpoint){

        //get sensor value
        double sensorData = sensor.getReading();

        //Update PID Controller
        controller.update(sensorData);

        //Get controller output
        motor.moveVelocity(controller.getOutput());

        //delay
        pros::delay(deltaTimeMilliseconds);

}

Tuning the PID Controller

In order to get a well-performing PID controller, the three controller gains need to be tuned. The easiest way to do this is manual tuning, which is done by trying different gains until the controller performance is satisfactory:

  1. Set kp, ki, and kd to zero.

  2. Increase kp until the system starts to oscillate.

  3. Increase kd until the system stops oscillating.

  4. Increase ki to eliminate any steady state error.

You may have to go through this process multiple times before the controller is properly tuned.