El PID puro asume que el universo es perfecto y lineal: Si pides 0% de PWM, hay 0 litros. Si pides 50%, hay la mitad del flujo máximo. En la realidad, las electroválvulas proporcionales tienen una curva de respuesta sigmoidal (forma de 'S'):
Para no confundir al algoritmo PID, dejamos que calcule su salida del `0.0%` al `100.0%` como si viviera en un mundo ideal. Justo antes de enviar esa salida al hardware (Timer PWM), pasamos el número por una **Función de Mapeo**. Si el PID pide un modesto `1.0%` de apertura, el mapeo lo transforma en un `30.5%` de PWM físico, dándole el empujón exacto para vencer el resorte sin abrir de golpe la válvula.
Ejercicio 1: Tomaremos el algoritmo PID continuo del Día 151 y crearemos el envoltorio físico mapear_actuador_pwm(). Incorporaremos una constante de cierre de emergencia: Si el PID arroja 0.0 exacto o la venta terminó, ignoramos la zona muerta y apagamos el PWM al 0.0% absoluto para bloquear el paso de gas por completo.
/**
* @file control_valvula_pid.c
* @brief Implementación Física del PID con Compensación de Zona Muerta (Deadband)
*/
#include "stm32f401xe.h"
#include <stdbool.h>
// =========================================================================
// PARÁMETROS FÍSICOS DE LA VÁLVULA (Calibración Mecánica)
// =========================================================================
#define VALVE_DEADBAND_MIN 30.0f // % de PWM necesario para vencer el resorte
#define VALVE_SATURATION 85.0f // % de PWM donde el flujo ya es máximo físico
// Dependencias de nuestro sistema (Día 151)
extern float PID_Update(float setpoint, float medicion, float dt); // Función PID abstracta
extern void set_apertura_pwm_hardware(float porcentaje); // Control del Timer (Día 150/152)
extern float leer_sensor_litros(void);
/**
* @brief Mapea la salida abstracta del PID (0-100%) al rango efectivo de la válvula (30-85%)
* Implementa la función lineal matemática clásica de interpolación.
*
* @param pid_out Salida ideal del PID
* @return float Porcentaje de PWM compensado para inyectar al hardware
*/
float compensar_zona_muerta_valvula(float pid_out) {
// 1. CIERRE SEGURO (Shut-off)
// Si la matemática pide cerrar, cerramos por completo (0V absoluto)
if (pid_out <= 0.01f) {
return 0.0f;
}
// 2. SATURACIÓN MATEMÁTICA
// Si el PID pide más del 100%, limitarlo
if (pid_out > 100.0f) pid_out = 100.0f;
// 3. MAPEO LINEAL (Y = mX + b)
// Rango Entrada: 0.0 a 100.0
// Rango Salida : 30.0 a 85.0
float rango_entrada = 100.0f - 0.0f;
float rango_salida = VALVE_SATURATION - VALVE_DEADBAND_MIN;
// Y = ( (X - X_min) * (Y_max - Y_min) / (X_max - X_min) ) + Y_min
float pwm_compensado = ((pid_out / rango_entrada) * rango_salida) + VALVE_DEADBAND_MIN;
return pwm_compensado;
}
/**
* @brief Ejecutor principal del Bucle de Control.
* Aísla la lógica de negocio de la física de la planta.
*/
void despachar_gas_controlado(float meta_litros) {
float litros_actuales = leer_sensor_litros();
// Calcular el PID Ideal (Matemática pura 0-100)
// Nota: El 'dt' (delta time) asume 0.01 segundos si esto se llama cada 10ms
float pid_ideal = PID_Update(meta_litros, litros_actuales, 0.01f);
// Transformar a Física Real (Compensar el resorte electromecánico)
float pwm_real = compensar_zona_muerta_valvula(pid_ideal);
// Inyectar al Timer Hardware
set_apertura_pwm_hardware(pwm_real);
}
int main(void) {
// inicializar_sistema();
float venta_objetivo = 20.0f; // Litros
bool venta_activa = true;
while(1) {
// El marcapasos de nuestro PID (Sincronizado por SysTick)
if (bandera_timer_10ms && venta_activa) {
despachar_gas_controlado(venta_objetivo);
// Condición de paro estricto (Metrología completada)
float litros = leer_sensor_litros();
if (litros >= venta_objetivo) {
venta_activa = false;
// Forzar cierre eléctrico cortando el hardware directamente
set_apertura_pwm_hardware(0.0f);
// guardar_venta_en_eeprom();
}
bandera_timer_10ms = false;
}
}
return 0;
}
Objetivo del día: Control Fino y Cierre de Válvula Exacto (Smart Valve).
Si conectaras la ecuación PID pura directamente al Timer del PWM, ocurriría un desastre mecánico en los litros finales de la venta. El PID intentaría suavizar la entrega reduciendo su salida al `10%` o `5%`. Pero como tu válvula de gas requiere al menos un `30%` de fuerza PWM solo para vencer el resorte (Deadband), la válvula se cerraría físicamente por completo *antes* de tiempo. El gas dejaría de fluir cuando el marcador llevara 19.80 Litros.
El término Integral (I) del PID notaría que el flujo se detuvo, y empezaría a acumular error desesperadamente. Segundos después, la integral obligaría a la salida a saltar de golpe al `35%`, la válvula se abriría violentamente, y te pasarías a 20.15 Litros. Con este **Mapeo Lineal de Software**, tu algoritmo se vuelve consciente de la inercia del hierro y los resortes de la válvula. Cuando el PID pide un "susurro" de `1%` de gas, el STM32 inyecta inteligentemente un `30.5%` de PWM. La válvula se sostiene microscópicamente abierta, entregando el gas gota a gota, garantizando que el ticket de venta cierre en 20.00 Litros perfectos.
0.0-100.0) exclusivamente hacia el rango lineal de operación de la válvula (Ej. 30.0-85.0), pero manteniendo un Bypass de Seguridad (Shut-off) que force el 0.0% absoluto cuando se requiera sellar la máquina.