En los sistemas de control, un controlador corrige la salida de un sistema particular a una entrada
deseada en presencia de errores y perturbaciones. El tipo más popular de controlador es PID, que
es un acrónimo de Proportional, Integral and Derivative (Proporcional, Integral y Derivado). En
este tutorial de control PID de Arduino, te mostraremos cómo puedes emplear este tipo de
controlador en tu proyecto.
¿Qué es el PID?
Como se mencionó anteriormente, PID es la abreviatura en inglés de proporcional, integral y
derivada. El nombre proviene de los métodos de cómo este controlador trata las perturbaciones
en el sistema. Sin embargo, este tipo de controlador sólo se encuentra en los sistemas de
retroalimentación. Sugerimos leer un material escrito específicamente para este tema, pero
haremos todo lo posible para explicarlo aquí tan simple como se pueda.
Un sistema de retroalimentación es un sistema en el que parte de la salida se «retroalimenta» a la
entrada. Por ejemplo, puedes tener un proyecto que controle el fuego en el horno. Abajo tenemos
una ilustración simple:
Control de temperatura con PID
Deseas mantener la temperatura en el horno hasta un determinado punto de llegada. Un sensor
instalado en el horno determina la temperatura en cualquier momento. Este sensor, en este caso,
proporciona la retroalimentación como referencia sobre el aumento o disminución de la
temperatura requerida. La diferencia entre el valor del sensor de realimentación y un punto de
ajuste de temperatura es el error.
Control proporcional
El control proporcional se refiere a una revisión que es proporcional a la magnitud del error.
Digamos que el controlador en nuestro ejemplo es una válvula electrónica para controlar el
combustible al horno. Si el error es pequeño, la válvula liberará una pequeña cantidad de
combustible para que el punto de ajuste y la retroalimentación coincidan. Si el error es grande, la
válvula debe liberar más combustible.
Control integral
El control proporcional produce un desplazamiento en su corrección debido a las perturbaciones.
El controlador Integral tiene la capacidad de eliminar este desplazamiento y volver a poner el error
a cero. Dicho controlador produce un ajuste que se basa en el error acumulado a lo largo del
tiempo. Sin un control integral, el sistema no puede hacer frente a las tendencias de los errores.
Usando nuestro ejemplo anterior, un desplazamiento puede estar presente cuando la válvula de
combustible no volvió a su posición original cuando se incrementó y luego disminuyó su salida de
combustible. El controlador integral detectará esto y girará la válvula de combustible a su posición
original.
Control de Derivados
Finalmente, el control de Derivados se ocupa de la tasa de cambio del error. Si el control integral
examina el historial del error, el control derivado predice el error. Básicamente, la cantidad de
corrección se basará en la rapidez con la que cambia el error. Este tipo de controlador funciona
mejor con errores dinámicos en los que los controladores proporcionales e integrales no pueden
lidiar.
Digamos que la temperatura en el horno va de 130 °C a 140 °C contra un punto de ajuste de 120 °C
en 2 segundos. Los controladores proporcionales e integrales responderán a la magnitud del error,
pero le será difícil ponerse al día sobre la rapidez con la que ocurrió el error… El controlador de
derivados puede tratar con esto porque ha estado observando la tasa de cambio del error desde el
principio.
Un sistema de retroalimentación con un controlador PID:
sistema de retroalimentación con un controlador PID
Aquí la variable de entrada o punto de ajuste es r(t), la variable de salida es y(t), la variable
controlada es u(t) y el error es e(t). Continuando con nuestro ejemplo de horno, r(t) sería la
temperatura deseada e y(t) es la temperatura real; e(t) es la diferencia entre la temperatura
deseada y la temperatura real; u(t) es la suma de las correcciones de los controladores P, I y D que
se alimenta a la planta que es la válvula de combustible.
Ten en cuenta que un controlador PID no se puede utilizar fuera de la caja. La afinación debe
hacerse para asegurar que se logre el rendimiento deseado. Esto se hace cambiando
cuidadosamente las constantes K como se muestra en el diagrama de arriba. Estas constantes
deben determinarse de antemano y modificarse en función de la respuesta real del sistema hasta
que se alcancen los valores óptimos.
Implementación de PID en código
Para implementar un controlador PID en un código o un programa de Arduino, se deben conocer
cinco parámetros: constantes proporcionales, integrales y derivadas, valor de entrada y valor de
llegada.
El cálculo del PID debe estar dentro de una función de bucle. La primera parte de la función
debería ser determinar el tiempo transcurrido. En Arduino, el tiempo actual puede ser
determinado por milis() y el tiempo transcurrido es justo:
currentTime = millis();
elapsedTime = currentTime - previousTime;
A continuación, se debe determinar el error:
error = setPoint - input;
Recuerda que la integral del error es el error acumulativo en el tiempo:
cumError += error * elapsedTime;
La derivada del error es la tasa de cambio del error:
rateError = (error - lastError)/elapsedTime;
Por último, la salida calculada es:
output = Kp * error + Ki * cumError + Kd * rateError;
Aquí, el Kp, Ki y Kd son las constantes predeterminadas.
Finalmente, las variables deben ser anotadas para la siguiente iteración:
lastError = error;
previousTime = currentTime;
Intentemos un ejemplo más concreto. Imagínate una rueda unida a un motor. Queremos que la
rueda permanezca en la posición indicada:
ejemplo PID rueda
Un codificador rotativo en la rueda da el ángulo en grados de la posición actual de la rueda. En la
posición deseada de la rueda, el ángulo es cero.
Lo que queremos es que el motor gire cuando la rueda está fuera de posición. Además, el motor
se controla a través de la modulación de ancho de pulso. Cuanto más amplio es el pulso, más lejos
gira el motor.
A continuación, implementemos este sencillo sistema de control usando un Arduino. Aquí está el
código:
//PID constants
double kp = 2
double ki = 5
double kd = 1
unsigned long currentTime, previousTime;
double elapsedTime;
double error;
double lastError;
double input, output, setPoint;
double cumError, rateError;
void setup(){}
void loop(){
input = analogRead(A0); //read from rotary encoder connected to A0
output = computePID(input);
delay(100);
analogWrite(3, output); //control the motor based on PID value
double computePID(double inp){
currentTime = millis(); //get current time
elapsedTime = (double)(currentTime - previousTime); //compute time elapsed from previous
computation
error = Setpoint - inp; // determine error
cumError += error * elapsedTime; // compute integral
rateError = (error - lastError)/elapsedTime; // compute derivative
double out = kp*error + ki*cumError + kd*rateError; //PID output
lastError = error; //remember current error
previousTime = currentTime; //remember current time
return out; //have function return the PID output
}
En la función de bucle o loop, el codificador rotativo determina la posición actual de la rueda y su
valor de salida se convierte en un parámetro para la función computePID(). Esta función devuelve
un valor para controlar el motor utilizando PWM.
Librería PID de Arduino
Podemos simplificar aún más el uso de PID en proyectos de Arduino con la ayuda de la librería PID
de Brett Beauregard. La librería sólo requiere que especifiques los valores de kd, ki, kp y setpoint y
ya está listo.
Aquí está el código PID_Basic.ino que viene con la librería. Este código básicamente proporciona la
misma salida que el código que proporcionamos arriba, pero mejor:
#include <PID_v1.h>
#define PIN_INPUT 0
#define PIN_OUTPUT 3
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
//Specify the links and initial tuning parameters
double Kp=2, Ki=5, Kd=1;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
void setup()
//initialize the variables we're linked to
Input = analogRead(PIN_INPUT);
Setpoint = 100;
//turn the PID on
[Link](AUTOMATIC);
void loop()
Input = analogRead(PIN_INPUT);
[Link]();
analogWrite(PIN_OUTPUT, Output);
Aquí se puede crear una clase PID y tener como parámetros las constantes de entrada, salida,
consigna y k. Para calcular el PID, simplemente llame a la función Compute(). También contiene
una función SetMode() que activa (AUTOMATIC) o desactiva (MANUAL) el PID. La lista completa de
las funciones utilizadas por la biblioteca se encuentra aquí.
Hemos dicho que el código anterior es mejor que el que proporcioné porque trata de las
limitaciones del PID que está más allá del alcance de este artículo.