como-implementar-un-controlador-pid-en-arduino

How to implement a PID controller on Arduino

  • 4 min

We continue with the series of posts dedicated to control theory by seeing how to implement a PID control in a microprocessor like Arduino.

In previous posts, we have seen an introduction to control theory, presented the on/off controller with hysteresis, the powerful PID controller, and seen how to adjust the parameters of a PID controller.

Now it’s time to leave theory behind, dust off the keyboard, and see how a PID controller is implemented in a microprocessor like Arduino. Fortunately, it’s quite simple to make a basic PID and, as we will see in the second part, we have a very complete library available to make it even easier.

A PID is an essential element when tackling a large number of interesting projects, such as automatically regulating light levels, maintaining temperature, making a motor spin at constant speed, stabilizing platforms, making a robot move straight, or even robots that balance on two wheels.

Manual PID Controller

First, let’s see how to implement a simple controller ourselves. Actually, the code is not overly complex. Let’s assume our controller takes the input of the controlled variable from A0, and outputs a PWM signal on pin 3.

The code for a basic PID could be as follows:

// Pin assignments
const int PIN_INPUT = A0;
const int PIN_OUTPUT = 3;

// Controller constants
double Kp=2, Ki=5, Kd=1;

// External controller variables
double Input, Output, Setpoint;
 
// Internal controller variables
unsigned long currentTime, previousTime;
double elapsedTime;
double error, lastError, cumError, rateError;
 
void setup()
{
  Input = analogRead(PIN_INPUT);
  Setpoint = 100;
}    
 
void loop(){
  
  pidController.Compute();
  
  Input = analogRead(PIN_INPUT);      // read a controller input
  Output = computePID(Input);    // calculate the controller
  delay(100);
  analogWrite(PIN_OUTPUT, Output);      // write the controller output
}
 
double computePID(double inp){     
        currentTime = millis();                          // get current time
        elapsedTime = (double)(currentTime - previousTime);     // calculate elapsed time
        
        error = Setpoint - Input;                               // determine the error between setpoint and measurement
        cumError += error * elapsedTime;                    // calculate the integral of the error
        rateError = (error - lastError) / elapsedTime;       // calculate the derivative of the error
 
        double output = kp*error + ki*cumError + kd*rateError;     // calculate the PID output
 
        lastError = error;                                    // store previous error
        previousTime = currentTime;                           // store previous time
 
        return output;
}
Copied!

As we can see, it’s not too difficult. We have a ‘computePID()’ function that does all the work. In this function, we calculate the elapsed time between calls, which we need to calculate both the derivative and the integral of the error.

Next, we compare the controller input with the setpoint to determine the error and perform the ‘pseudo’ integrals and derivatives (their discrete equivalent). Finally, we calculate the system response using the PID formula, and save the values for the next cycle.

That wasn’t so hard, was it? However, although it is completely functional, our PID controller is quite simple. Therefore, it has certain shortcomings when faced with situations that frequently occur in reality.

We could improve our code, but it would no longer be so simple or quick to do. And the best part is, we don’t need to! To our delight, someone has done all the work for us, as we will see in the next section.

PID Controller with Library

Fortunately, we have the PIDController library available, based on the ArduinoPID library developed by Brett Beauregard.

With this, creating a PID controller in Arduino is as simple as the following code.

#include <PIDController.hpp>

const int PIN_INPUT = 0;
const int PIN_OUTPUT = 3;

PID::PIDParameters<double> parameters(4.0, 0.2, 1);
PID::PIDController<double> pidController(parameters);

void setup()
{
  pidController.Input = analogRead(PIN_INPUT);
  pidController.Setpoint = 100;

  pidController.TurnOn();
}

void loop()
{
  pidController.Input = analogRead(PIN_INPUT);
  pidController.Update();

  analogWrite(PIN_OUTPUT, pidController.Output);
}
Copied!

We have seen that it is quite simple to implement a PID controller in a microprocessor like Arduino. And it’s even simpler with the little gem that is the Arduino PID library. So there are no excuses or fears when it comes to implementing a PID controller in our projects.

In the next posts of the series, we will start to see practical examples of projects where we can implement PID control in Arduino. See you soon!