Sintonizar PID con Arduino – Control de temperatura
Introducción
Existen un montón de artículos sobre la implementación de controladores PID con Arduino, pero en la mayoría de ellos me encuentro que la sintonización se hace con el método de prueba y error. En este aspecto el algoritmo PID ha demostrado ser muy robusto, lo suficiente como para salir airoso incluso ante una «mala» sintonización. Esto no quiere decir que el método de prueba y error no sea válido, de hecho, cuando montamos algo serio por primera vez y no tenemos referencias de funcionamiento es normal recurrir a métodos pragmáticos, pero mi intención es que tengáis una alternativa de sintonización analítica.
No voy a aburriros con conceptos matemáticos ni espero perderme en la selva con las explicaciones, la intención de este artículo es que con un breve análisis y con unas sencillas herramientas desarrolladas para la ocasión seamos capaces de evitar el uso del famoso método de «prueba y error» y aplicarlo a la mayoría de nuestras implementaciones.
Sistema empleado
El sistema empleado es muy sencillo, en esencia consta de de una fuente de calor, un sensor de temperatura y un ventilador.
La fuente de calor es una resistencia de 12V como las que podemos encontrar para calentar el filamento de las impresoras 3D. Ojo porque a 12V se calienta hasta 350ºC por lo que para nuestro sistema la alimentaremos a 4,5V obteniendo unos 120ºC. En el interior y pegando a la fuente de calor he situado un sensor de temperatura DS18B20 y en la parte superior hay un ventilador de 12V capaz de girar a 7500 rpms para bajar la temperatura del sistema. El objetivo es mediante un controlador PID mantener estable la temperatura del interior aprovechando una salida PWM de Arduino.
Tanto el calentador como el ventilador son dos bestias pardas y necesitan de fuentes de alimentación externas. Como hemos comentado la resistencia la alimentaremos a 4,5V obteniendo 120ºC. El ventilador de 12V es de 4 pines por lo que aprovecharemos uno de sus pines para controlar mediante una salida PWM de Arduino la velocidad de giro. Una característica común en este tipo de ventiladores es que cuando la señal PWM que reciben es 0, estos giran a unas revoluciones mínimas, es decir, nunca paran. En nuestro caso con PWM 0 el ventilador gira a 1200 rpms enfriando nuestro sistema de 120ºC a 80ºC.
Componentes
- Arduino UNO
- Sensor DS18B20
- Ventilador de 12V y 7500 rpms (4 pines)
- Resistencia/Calentador 12V 50W
- Un potenciómetro
- Un interruptor
- Una resistencia de 220 ohm
- Una fuente externa de 12V
- Una fuente externa regulable de 4,5V
- Cables dupont para el conexionado
- Una protoboard
El coste aproximado si tienes que comprar todos los componentes es de entre 40-50€ sin contar con las fuentes externas.
Esquema de conexiones
Para el montaje la única consideración es que cuando trabajamos con varios voltajes las masas deben ir unidas.
Código de Arduino
//*************************************************************** // Desarrollado por Garikoitz Martínez [garikoitz.info] [05/2020] // https://garikoitz.info/blog/?p=638 // https://garikoitz.info/blog/?p=674 //*************************************************************** //=============================================================== // Librerías //=============================================================== #include <Arduino.h> #include <OneWire.h> #include <DallasTemperature.h> #include <Wire.h> #include <LCD.h> #include <LiquidCrystal_I2C.h> #include <math.h> #include <PID_v1.h> //=============================================================== // Variables globales & Constantes //=============================================================== OneWire onewire(8); DallasTemperature sensors(&onewire); double Setpoint, Input, Output; double Kp=55, Ki=29, Kd=0; PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, REVERSE); boolean modo = false; //false=auto true=manual String modos = ""; float OP; const int pot =0; // Potenciómetro conectado al pin A0 const int vent =5; // ventilador conectado al pin 5 int velocidad; LiquidCrystal_I2C lcd(0x3F,2, 1, 0, 4, 5, 6, 7); //=============================================================== // SETUP //=============================================================== void setup(void) { Serial.begin(9600); pinMode(vent, OUTPUT); sensors.begin(); sensors.setResolution(0, 11); lcd.begin(20,4); lcd.setBacklightPin(3,POSITIVE); lcd.home(); } //=============================================================== // BUCLE PRINCIPAL //=============================================================== void loop() { // Interruptor Auto/Manual if (digitalRead(12) == HIGH){ modo=true; modos="MANUAL"; myPID.SetMode(MANUAL); }else{ modo=false; modos="AUTOMATICO"; myPID.SetMode(AUTOMATIC); } sensors.requestTemperatures(); Input = sensors.getTempCByIndex(0); // MODO MANUAL Potenciómetro ---> PWM Ventilador if (modo==true){ velocidad = analogRead (pot); OP = map(velocidad, 0, 1023, 0, 255); analogWrite(vent, OP); myPID.SetMode(MANUAL); //LCD en MANUAL lcd.clear(); lcd.setCursor(0,0); lcd.print("====== "); lcd.print(modos); lcd.print(" ======"); lcd.setCursor(0,1); lcd.print(" T: "); lcd.print(Input,2); lcd.print("\337C "); lcd.setCursor(0,2); lcd.print(" OP: "); lcd.print(OP*0.3921); lcd.print(" % "); lcd.setCursor(0,3); lcd.print("PWM: "); lcd.print(OP,0); // DEBUG PUERTO SERIE (Para Arduino COM Plotter) Serial.print("#"); //Char inicio Serial.print(0); //Dejo vacío para ACP Serial.write(" "); //Char separador Serial.print(Input,2); //PV Serial.write(" "); //Char separador Serial.print(OP*0.3921,0); //OP Serial.println(); } // MODO AUTOMÁTICO--------------------------------------------- if (modo==false){ float set=analogRead(pot); Setpoint=map(set,0,1023,60.0,40.0); Input = sensors.getTempCByIndex(0); myPID.SetMode(AUTOMATIC); //----------------------------- //LCD en AUTO lcd.clear(); lcd.setCursor(0,0); lcd.print("==== "); lcd.print(modos); lcd.print(" ===="); // lcd.setCursor(0,1); lcd.print("PV: "); lcd.print(Input,2); lcd.print(" \337C "); lcd.setCursor(0,2); lcd.print("SP: "); lcd.print(Setpoint,2); lcd.print(" \337C "); lcd.setCursor(0,3); lcd.print("OP: "); lcd.print(Output*0.3921,2); lcd.print(" %"); // myPID.Compute(); analogWrite(vent, Output); //=============================================================== // DEBUG PUERTO SERIE (Para Arduino COM Plotter) //=============================================================== Serial.print("#"); //Char inicio Serial.print(Setpoint,0); //SP Serial.write(" "); //Char separador Serial.print(Input,2); //PV Serial.write(" "); //Char separador Serial.print(Output*0.3921,0); //OP Serial.println(); } delay(1000); }//Fin void loop
Identificación del sistema
Recopilación de datos en lazo abierto
Con el controlador de temperatura en manual hacemos una serie de movimientos en la salida PWM del ventilador para ver como reacciona la temperatura.
Se observa que la zona donde mejor trabaja el ventilador es en los tres primeros escalones, es decir, entre 55 y 45ºC. Por debajo de 45ºC y a medida que nos acercamos al límite inferior el tiempo de establecimiento es cada vez más corto y las constantes del sistema que hemos obtenido ya no son totalmente representativas y por lo tanto nuestro control se degradará.
Con la ayuda de ACP obtenemos las siguientes constantes del sistema.
K | 0,120 | %/% |
To | 8,5 | segundos |
Tp | 103,5 | segundos |
Facilidad de control
El cociente entre To y Tp nos sugiere la facilidad de control de un sistema. En este caso estamos en la zona de muy fácil ya que 8,5/103,5=0,08.
Ajuste y simulación en lazo cerrado
A continuación un resumen de las posibles sintonías ofrecidas por ACP para nuestro sistema.
Se aprecia que los métodos clásicos como el de Cohen Coon o Ziegler Nichols proponen sintonías más agresivas (>Kc y <Ti) y más centradas en la ganancia proporcional que los métodos más modernos como el Improved SIM C de Skogestad.
Algunos métodos tienen condiciones de aplicación normalmente relacionados con To y Tp. Si se da alguna condición, ACP nos avisará con una ventana emergente. Esto no significa que no lo podamos usar, sencillamente que el método tiene restricciones de aplicación.
Resultados
A continuación compararemos la respuesta real del sistema con la simulación en lazo cerrado de un par de sintonías clásicas como son Cohen Coon y Ziegler Nichols, en concreto un cambio de punto de consigna. Como se puede apreciar la simulación es fiel a la respuesta real del sistema lo que indica que la identificación mediante saltos escalón ha sido aceptable. Siento no tener más gráficas y más ejemplos pero he perdido los datos de esta maqueta.
CC-10 (PI)
ZN-LA-10 (PI)
Conclusiones
Desde el punto de vista de control se puede decir que todos los métodos probados han tenido una respuesta aceptable y por lo tanto con una dedicación mínima podemos realizar una sintonía robusta de nuestros sistemas para evitar el prueba y error.
Puede que le llame la atención al lector el «poco caso» que se le ha dado al termino derivativo, y es que en el 90% de los casos con un controlador PI es más que suficiente y por lo tanto os recomiendo que antes de usar un PID os hagáis la siguiente pregunta, ¿me aporta alguna mejora incluir el termino derivativo?. En nuestro caso, al incluir el término derivativo la única diferencia ha sido que la salida se ha vuelto más oscilante sin una mejora notable en la respuesta de control. Como norma general no se recomienda el uso del termino derivativo si T0 es pequeño en comparación con Tp (como es nuestro caso) y suele ser útil si T0 está en torno a Tp/2 y siempre y cuando la PV no tenga ruido.
Ha quedado patente que es factible caracterizar la dinámica de un sistema relativamente sencillo por pocos datos que tengamos. Aún así, lo más importante que me gustaría remarcar es la importancia que tiene conocer bien el sistema que queremos controlar.
Finalmente espero haber arrojado algo de luz sobre la sintonía PID y que os animéis a utilizar ACP para evitar el método prueba y error siempre que sea posible.
Referencias
Enlaces
- Arduino IDE
- PIDLab (Cálculo de sintonías y Simulador online)
- Manual de Arduino COM Plotter
- Métodos de sintonización en lazo abierto
- Cálculo manual de T1(28,3%) y T2(63,2%)
- Tuning PID control loops for fast response
- Comunicación de Arduino con puerto serie
- Arduino PID library by Brett Beauregard [01] [02]
- Introducción al algoritmo PID y su implementación en Arduino
Libros y Publicaciones
[1] Aidan O’Dwyer. Handbook of PI and PID controller tuning rules, 3rd edition, Imperial College Press. ISBN: 978-1-84816-242-6
[2] Karl J. Astrom, Tore Hagglund. Control PID avanzado, Pearson, ISBN: 978-84-8322-511-0
[3] Daniel Chuck. Los sistemas de primer orden y los controladores PID, edición 2012. [Link] [Link2]
[4] J.G. Ziegler, N.B. Nichols. Optimum Settings For Automatic Controllers, 1942 edition, American Society of Mechanical Engineers. [Link]
[5] G.H. Cohen, G.A. Coon. Theoretical Consideration of Retarded Control, 1953 edition, American Society of Mechanical Engineers. [Link] [Link2]
[6] Daniel E. Rivera. Internal Model Control: A Comprehensive View, 1999 edition, College of Engineering and Applied Sciences. [Link]
[7] R. Vilanova, A. Visioli. PID Control in the Third Millennium. Chapter 5, The SIMC Method for smooth PID Controller Tuning, Springer. ISBN: 978-1-4471-2424-5.
[8] Chriss Grimholt, Sigurd Skogestad. The improved SIMC method for PI controller tuning, IFAC-conference PID’12, Brescia, Italy, March 2012. [Link]
[9] Guillermo J. Silva, Aniruddha Datta, S.P. Bhattacharyya. PID Controllers for Time-Delay Systems. Chapter 10, Analysis of Some PID Tunning Techniques. Birkhäuser. ISBN: 0-8176-4266-8
8 comentarios en «Sintonizar PID con Arduino – Control de temperatura»
Cuáles son todos los componentes utilizados en la práctica?
Esta sería la lista completa:
Arduino UNO R3 + cable USB
Sensor de temperatura DS18B20
Ventilador de 12V y 7500 rpms (4 pines)
Controlador de Motor L298N
Resistencia/Calentador 12V 50W
Un potenciómetro de 10K
Un micro interruptor
Una resistencia de 220 ohm
Una fuente externa de 12V
Una fuente externa regulable (para alimentar el cartucho calefactor a 4,5V)
Cables dupont para el conexionado
Una protoboard
Display LCD 20×4
Adaptador I2C para Display LCD
*Para replicar la práctica no hace falta que uses exactamente los mismos componentes. Si dispones de otro ventilador, cartucho calefactor, sensor de temperatura, etc. Incorpóralos a tu proyecto y adecua el código. Si tienes cualquier duda no dudes en consultar.
Buenos dias, la programacion en arduino no me funciona, podria explicarme por que el error?
LiquidCrystal_I2C lcd(0x3F,2, 1, 0, 4, 5, 6, 7);
en esta parte no me funciona
Pueden fallar varias cosas. Lo primero es comprobar que el display lo tienes conectado con el módulo I2C y no de forma independiente a Arduino. Sigue este tutorial para despejar las dudas -> http://kio4.com/arduino/31pantallaLCD.htm
Al seguir el tutorial te recomiendo que hagas las pruebas de conexión primero sólo con Arduino y el display, y cuando te funcione lo traslades a mi código
Consulta, tendras el diagrama de bloque de este proyecto? la verdas muy interesante y explicado facilmente
Buenas Juan,
¿A que diagrama de bloques te refieres, del código, de control?
Si tendrias ambos mejor
He rebuscado y no tengo nada de esta entrada en concreto pero te dejo unas entradas donde tienes varios diagramas de bloques de control y diagramas de flujo de código.
Estrategias de control con Arduino: https://garikoitz.info/blog/2017/12/estrategias-de-control-con-arduino/
Introducción al algoritmo PID y su implementación en Arduino: https://garikoitz.info/blog/2022/05/introduccion-al-algoritmo-pid-y-su-implementacion-en-arduino/
PIC16F84 – Control PID: https://garikoitz.info/blog/2018/01/pic16f84-control-pid/