Control PID para el horno eléctrico de casa
El horno eléctrico que uso a diario en casa, con el termostato bimetálico sustituido por un ESP8266 que regula la temperatura con un PID, enciende las resistencias por triac y sirve su propia página web desde el punto de acceso de la placa. Lleva cocinando desde 2020.


Un horno doméstico no controla la temperatura: la deja oscilar. El termostato bimetálico enciende las resistencias a tope, espera a pasarse, las apaga y espera a quedarse corto. Lo que el dial marca es el centro de un vaivén, no la temperatura de dentro, y en una masa que depende de los primeros minutos eso se nota. La pregunta del proyecto era si un microcontrolador de tres dólares podía hacerlo mejor que el bimetálico, y la respuesta hay que medirla, no suponerla.
El hardware es una NodeMCU v3 con ESP8266 sobre una placa hecha a la medida para este horno. La temperatura la lee un termopar tipo K con un MAX6675 por SPI. Las dos resistencias — la inferior de 1000 W y la superior de 1300 W — se mandan con triacs disparados por optoacopladores MOC3031 de cruce por cero, y las salidas digitales salen de un registro de desplazamiento 74HC595: el ESP8266 tiene pocos pines y ya se los llevan el SPI del termopar, el I²C del OLED y el zumbador. Una pantalla OLED de 128×32 en el frente dibuja la temperatura, el temporizador y qué resistencia está encendida.




El mando no es encendido y apagado sino PWM lento: cada segmento dura 100 ms y el periodo son 100 segmentos, o sea diez segundos, el mismo periodo de muestreo del PID. A una resistencia de horno diez segundos le dan igual — su constante térmica son minutos — y el cruce por cero evita trocear el ciclo de la red. La lectura del termopar va filtrada por una media móvil de diez muestras, una por segundo.
Para ajustar el PID hacía falta un modelo, y el modelo salió del horno mismo: se le dieron escalones de potencia, se registró la temperatura y con eso se identificó un ARX en Python — la librería SIPPY sobre python-control — con diez segundos de muestreo. Salió una función de transferencia discreta de quinto orden que sigue la curva medida de cerca, subida y enfriamiento incluidos. Eso es lo que enseña la primera gráfica: medido contra identificado, sobre la misma hoja.

Con el modelo en la mano, Ziegler-Nichols: un proporcional puro llevado hasta la oscilación sostenida da Kcr = 14,28 y Tcr = 340 s, y de ahí salen Kp = 6,93, Ki = 0,42, Kd = 30,34. En simulación se ve bien. En el horno de verdad, no: esas ganancias reaccionan demasiado rápido para un proceso cuya inercia térmica el modelo captura solo a medias, y lo que sobrepasa aquí es una resistencia al rojo. Las ganancias que quedaron en el firmware son Kp = 2,5, Ki = 0,005, Kd = 0, encontradas probando en el horno y registrando cada corrida, no leyendo la tabla.



Lo que de verdad resuelve el arranque no es el PID sino lo que va antes. Mientras falten más de 30 °C para la consigna, las dos resistencias van al 100 % y el término integral se mantiene en cero: integrar un error enorme durante quince minutos solo sirve para llegar arriba con el mando saturado y pasarse. Al entrar en esa banda el control se queda un minuto apagado — el calor que ya está en las paredes sigue subiendo la temperatura por su cuenta — y recién entonces arranca el PID. Ese minuto de espera es lo que quita el sobrepico, y no está en ninguna fórmula de sintonía.
El firmware es MicroPython, y ahí apareció el problema que no era de control: el servidor web no cabía. Un ESP8266 deja alrededor de 30 KB de montículo, y picoweb más el controlador más el PID más los drivers no entran si se cargan como ficheros .py normales. La solución fue recompilar el firmware con los módulos congelados en la imagen, que así se ejecutan desde flash en lugar de copiarse a RAM. El servidor corre sobre uasyncio con tres tareas: el controlador cada 100 ms, la pantalla y el temporizador cada segundo, y las peticiones HTTP cuando llegan.
La placa levanta su propio punto de acceso — SSID «Horno», sin contraseña — y sirve la página en 192.168.4.1. No hay nube, ni cuenta, ni aplicación que instalar: el teléfono se conecta a la red del horno y abre una dirección. La página enseña la temperatura en un indicador de aguja, la potencia que está entregando cada resistencia en vatios, el temporizador y el estado — «Calentando», «Listo», «Apagado» — y permite fijar la consigna en automático o mandar cada resistencia a mano. Cuando alcanza la temperatura suena el zumbador dos veces; cuando se acaba el temporizador suena tres y el horno se apaga solo.

La misma ruta que alimenta la página, /get_values, es la que convirtió el horno en un banco de pruebas: un script en la computadora la consulta cada diez segundos y escribe un CSV con temperatura, mando, error y potencia de cada resistencia. Todas las gráficas de este caso salen de esos ficheros. La instrumentación no se añadió para medir: ya estaba ahí porque la interfaz la necesitaba.
El resultado, medido en corridas reales de cocina y no en el banco: unas pizzas a 150 °C se mantienen dentro de unos pocos grados de la consigna durante los veinte minutos de horneado, con un sobrepico de unos 4 °C en la entrada; un pescado a 180 °C aguanta una hora de meseta, con las dos bajadas que se ven en la gráfica, que son la puerta abriéndose. Eso es lo que no hacía el bimetálico, y es la razón por la que el horno sigue así desde 2020.


Lo que no hace
- No tiene seguridad de red: el punto de acceso es abierto y la página no pide contraseña. Quien esté al alcance del WiFi puede encender el horno.
- No hay protección independiente contra sobretemperatura: si el firmware se cuelga con los triacs conducidos, nada lo corta por hardware.
- No se conecta al WiFi de la casa ni sale a Internet: se controla desde la red que levanta la propia placa.
- Las ganancias del PID están sintonizadas para este horno. En otro hay que repetir la identificación.
Es una instalación de casa y se comporta como tal: manipula 120 V directamente sobre resistencias de 2300 W en total y no tiene corte térmico redundante, así que no es un diseño para copiar tal cual. Las cifras de energía que aparecen en los registros son estimadas multiplicando el porcentaje de mando por la potencia nominal de cada resistencia, no medidas con un vatímetro.
- ESP8266 · NodeMCU v3
- MicroPython con módulos congelados
- picoweb · uasyncio
- MAX6675 · termopar tipo K
- Triac + MOC3031
- 74HC595
- OLED SSD1306 128×32 · I²C
- PID discreto
- SIPPY · python-control
- Fritzing