/*
Ejemplo básico de un calentador simulado con control PID.
Se lee una entrada analógica (potenciómetro) para controlar
una salida PWM (control del calentador).
*/
// Se incluye la biblioteca para implementar el control PID.
#include "PID_v1.h" // https://github.com/br3ttb/Arduino-PID-Library
// Variables para la temperatura objetivo (Setpoint),
// la temperatura medida (Input)
// y la señal de control generada por el PID (Output).
double Setpoint, Input, Output;
// Kp, Ki, Kd: Parámetros del control PID para proporcional,
// integral, y derivativo respectivamente.
// myPID: Objeto del controlador PID que conecta las variables
// definidas con los parámetros configurados.
double Kp = 17, Ki = 0.3, Kd = 2;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, P_ON_E, DIRECT);
// Pin de salida PWM para controlar el calentador.
const int PWM_PIN = 3;
// Entrada analógica que simula la medición de temperatura.
const int INPUT_PIN = -1;
// Entrada analógica para leer el valor del potenciómetro (Setpoint).
const int SETPOINT_PIN = A1;
// Pines PWM para mostrar los valores de temperatura objetivo y medida mediante LEDs.
const int SETPOINT_INDICATOR = 6;
const int INPUT_INDICATOR = 5;
void setup()
{
Serial.begin(115200);
// Define los límites de la salida PID para evitar valores extremos.
myPID.SetOutputLimits(-4, 255);
// Configura los pines de los indicadores como salidas.
if (SETPOINT_INDICATOR >= 0) pinMode(SETPOINT_INDICATOR, OUTPUT);
if (INPUT_INDICATOR >= 0) pinMode(INPUT_INDICATOR, OUTPUT);
// Inicializa el Setpoint en 0 y activa el modo automático del PID.
Setpoint = 0;
myPID.SetMode(AUTOMATIC);
// Si hay un sensor físico conectado, lee el valor desde el pin.
// Si no, utiliza la simulación.
if(INPUT_PIN > 0){
Input = analogRead(INPUT_PIN);
}
else {
Input = simPlant(0.0,1.0);
}
// Imprime los encabezados para la salida serial.
Serial.println("Setpoint Input Output Watts");
}
void loop()
{
// Convierte la salida PWM en potencia
// de calentamiento (simula un calentador de 20W).
float heaterWatts = (int)Output * 20.0 / 255;
// Si hay sensor, lee la temperatura real. Si no,
// calcula la temperatura simulada del bloque.
if (INPUT_PIN > 0) {
Input = analogRead(INPUT_PIN);
}
else {
float blockTemp = simPlant(heaterWatts, Output > 0 ? 1.0 : 1 - Output);
Input = blockTemp;
}
if (myPID.Compute()) {
// Calcula la nueva salida del PID y actualiza
// la señal PWM del calentador.
analogWrite(PWM_PIN, (int)Output);
// Lee el Setpoint del potenciómetro, ajusta los indicadores de
// temperatura y genera un reporte.
Setpoint = analogRead(SETPOINT_PIN) / 4;
if (INPUT_INDICATOR >= 0) analogWrite(INPUT_INDICATOR, Input);
if (SETPOINT_INDICATOR >= 0) analogWrite(SETPOINT_INDICATOR, Setpoint);
}
report();
}
void report(void)
{
static uint32_t last = 0;
const int interval = 1000;
if (millis() - last > interval) {
last += interval;
// Serial.print(millis()/1000.0);
Serial.print("SP:");
Serial.print(Setpoint);
Serial.print(" PV:");
Serial.print(Input);
Serial.print(" CV:");
Serial.print(Output);
Serial.print(" Int:");
//Serial.print(myPID.GetIntegral());
Serial.print(' ');
Serial.println();
}
}
//Define parámetros físicos: transferencia térmica (h),
// capacidad calorífica (Cps), área de convección,
// masa del bloque, y temperatura ambiente (Tamb).
float simPlant(float Q, float hfactor) {
float h = 5 * hfactor;
float Cps = 0.89;
float area = 1e-4;
float mass = 10;
float Tamb = 25;
static float T = Tamb;
static uint32_t last = 0;
uint32_t interval = 10;
// Simula el aumento de temperatura en un intervalo de tiempo,
// considerando la transferencia térmica.
if (millis() - last >= interval) {
last += interval;
T = T + Q * interval / 10 / mass / Cps - (T - Tamb) * area * h;
}
return T;
}255°
Setpoint
0°
PID_v1 with Heater Simulation
SP___PV___CV
°C___°C___Watt