← Índice del curso

Sensores y Actuadores · Tema 44

Seguridad, fallos y robustez

Un sistema que funciona cuando todo anda bien es un prototipo; uno que sigue siendo seguro cuando algo falla es un producto. Los sensores se desconectan, los relés se sueldan, el programa se cuelga, la tensión se cae. La pregunta de diseño no es si algo va a fallar, sino qué pasa entonces. Este tema reúne las técnicas para detectar las fallas, limitar sus consecuencias y llevar el sistema a un estado seguro: validación de sensores, redundancia, límites independientes, perro guardián, arranque seguro y modos de funcionamiento.

01 · Punto de partida

Diseñar desde la falla

Cada tema anterior asumió componentes que funcionan. Pero un sensor en un ambiente húmedo, un relé que conmuta decenas de veces por hora o un cable que se mueve cada vez que alguien pasa tienen una probabilidad real de fallar. El método de la ingeniería de seguridad es invertir la pregunta: en vez de «¿qué hace mi programa?», «¿qué es lo peor que puede pasar y cómo lo evito?».

Para el horno de los temas anteriores, lo peor es un sobrecalentamiento (que daña, quema o provoca un incendio) y lo que lo causa es casi cualquier falla que deje la resistencia encendida. Un análisis mínimo de modos de falla (una tabla estilo FMEA) para ese horno es:

Análisis mínimo de fallas del horno controlado por un microcontrolador.
FallaEfectoCómo se detectaRespuesta
Sensor desconectado (−127 °C, 1023 cuentas)El controlador ve frío y enciende a plenoRango físicoEstado seguro, calefactor apagado
Sensor que lee «frío» (congelado, deriva)Ídem: la temperatura real sube sin controlDiscrepancia, congelamiento, respuesta esperadaEstado seguro
Sensor que lee «caliente»El horno no calienta: falla segura (pero para el proceso)Rango, discrepanciaAlarma, parada
Calefactor o relé pegado en «encendido»Calienta sin parar, sin que el programa pueda impedirloTemperatura que sube con la salida apagadaProtección independiente que corta la alimentación
Relé abierto o resistencia cortadaNo calienta (segura)La temperatura no responde a la salidaAlarma de fallo del actuador
Programa colgado con la salida encendidaSe queda calentandoPerro guardiánReinicio con las salidas apagadas
Caída de tensión (brownout)Comportamiento impredecible, memoria corruptaDetector de baja tensiónReinicio limpio y arranque seguro

Dos ideas organizan el tema. La primera: el estado seguro, aquel en el que un sistema no puede hacer daño (calefactor apagado, válvula cerrada, motor frenado), y la regla de diseñar para que cualquier falla detectada lleve a él. La segunda: ninguna protección debe depender de lo que protege: un límite de temperatura que usa el mismo sensor, el mismo microcontrolador y el mismo relé que el control no protege de la falla de ninguno de los tres.

02 · Entradas dudosas

Sensores defectuosos

Un sensor falla de pocas maneras características. Reconocerlas dice qué hay que mirar:

Modos de falla de un sensor y el detector que los atrapa.
FallaCómo se veDetector
Circuito abierto o en cortoValores extremos: 0 o 1023 cuentas, −127 °C, 85 °C de arranque, NaNRango físico (mín. y máx. plausibles)
Pico (EMI, contacto intermitente)Salto imposible de una muestra a la siguienteTasa de cambio máxima
Congelado (stuck-at)El valor no cambia más, ni siquiera el último bit de ruidoCongelamiento: valor idéntico durante una ventana larga
Deriva (envejecimiento, contaminación)Se aparta lentamente de la realidad, sin saltosDiscrepancia con un segundo sensor o con un modelo
Ruido excesivoLa varianza crece de golpeTasa o desviación típica sobre una ventana corta
Dato viejoLa comunicación se cortó pero la variable conserva el último valorEdad de la lectura (marca de tiempo)

El último es el más traicionero: un programa que lee un sensor I2C o un DHT con una función que, al fallar, no escribe la variable deja el último valor bueno como si fuera actual. La defensa es la Lectura del tema 40, con valor, estado y marca de tiempo, y rechazar todo dato cuya edad supere un límite.

Una señal simulada de 40 ± 0,5 °C con un sensor de 12 bits (resolución de 0,0625 °C) y fallas inyectadas a los 300 s da estos tiempos de detección con un límite de tasa de 0,5 K por muestra, una ventana de congelamiento de 30 muestras y un segundo sensor que discrepa a partir de 0,5 K:

Segundos hasta detectar cada falla (– = ese detector no la ve).
FallaRangoTasaCongeladoDiscrepancia
Sensor congelado––28176
Pico de +15 °C durante 3 s–0–0
Deriva de 0,02 K/s–––25
Desconectado (−127)00290
Ráfaga de ruido–1–1

Ningún detector los atrapa a todos: la deriva solo la ve la discrepancia con un segundo sensor, y el sensor congelado, el detector de congelamiento (28 s) mucho antes que la discrepancia (176 s, cuando la temperatura real se aleja 0,5 K del valor retenido). Y cada detector tiene su costo de falsos positivos: con un límite de tasa de 0,05 K por muestra (menor que el ruido y la cuantización), el detector se dispara 391 veces en 600 s sin ninguna falla; con 0,5 K, ninguna. Los umbrales se eligen entre la variación normal más grande y la falla más chica que importa.

La política de reacción importa tanto como la detección. Una sola muestra mala (un pico) no debería parar un horno; se descarta y se conserva el último valor bueno. Una falla que persiste más de un tiempo corto (unos segundos a unos minutos, según la inercia del proceso) lleva al estado seguro. Y una falla detectada no se «cura» sola: se vuelve a la operación normal solo tras un período de lecturas buenas o un reconocimiento manual.

03 · Más de uno

Redundancia y votación

La discrepancia con un segundo sensor es el detector más potente, y de ahí la redundancia. Hay tres esquemas básicos:

  • Dos sensores comparados: si coinciden (dentro de una tolerancia), se promedian; si discrepan, se detecta la falla pero no se sabe cuál miente, y se pasa al estado seguro. Es lo mínimo para detectar una deriva.
  • Tres sensores con votación 2 de 3 (2oo3): se toma la mediana; la falla de uno se detecta, se identifica y el sistema sigue funcionando. Mantiene el servicio y la seguridad.
  • Redundancia disímil: dos sensores de tecnologías distintas (un NTC y un DS18B20) fallan por causas distintas.

El enemigo de la redundancia es la falla de causa común: lo que puede dañar a todos a la vez, como la misma fuente de alimentación, el mismo cable, un rayo, el mismo error de software o la misma contaminación. Con un modelo simple e ilustrativo (probabilidad anual de falla de un sensor p = 5 %, cobertura diagnóstica del 60 % para las verificaciones de la sección anterior y un 10 % de causa común), el resultado por año es:

Probabilidad anual de dato incorrecto sin detectar y de pérdida de servicio (modelo ilustrativo).
ConfiguraciónDato malo sin detectarPérdida de servicio (parada)
1 sensor2,00 %3,00 %
2 sensores, comparar0,28 %9,00 %
3 sensores, votar 2 de 30,44 %0,36 %

Los números enseñan un compromiso. Duplicar y comparar reduce siete veces el riesgo de un dato malo, pero triplica las paradas, porque cualquiera de los dos sensores que falle detiene el sistema. La votación 2 de 3 consigue casi la misma seguridad con muchas menos paradas. Y la causa común fija un piso: con ella en 10 %, los 0,28 % y 0,44 % están dominados por ese término, y agregar un cuarto sensor idéntico no los baja. Por eso conviene variar la tecnología, la alimentación y el cableado entre los sensores.

Lo que cuesta: más sensores, más cables y más código; solo se justifica donde la falla es grave. Y una verificación que no se sustituye con redundancia: cada sensor sigue necesitando sus propios detectores (la redundancia detecta la discrepancia, pero no distingue cuál de dos sensores miente).

04 · Capas

Límites y capas de protección

Ningún mecanismo es infalible; por eso la seguridad se arma en capas independientes, de modo que la falla de una no deje al sistema sin protección:

  1. Control normal: el PID mantiene 40 °C.
  2. Límites y alarmas por software: si la temperatura medida supera 55 °C, se apaga el calefactor y se enclava el modo seguro.
  3. Protección independiente (hardware): un termostato bimetálico de seguridad en serie con la alimentación de la resistencia, que abre a 55 o 60 °C sin ningún software; un fusible térmico de un solo uso por encima.
  4. Contención física: aislamiento, materiales que no arden, una carcasa que contenga el incendio.

Con el horno de los temas 42 y 43 (100 W a pleno, 65 °C de temperatura final), la simulación de tres fallas con distintas combinaciones de capas da:

Temperatura máxima del horno tras la falla, según las protecciones (daño a partir de unos 60 °C).
FallaProteccionesT máximaPrimera protección
Calefactor pegadoNinguna65,0 °C—
Calefactor pegadoSoftware y chequeos65,0 °CLímite por software a los 932 s: no puede abrir un relé pegado
Calefactor pegadoSoftware, chequeos y termostato de 55 °C55,0 °CEl termostato independiente corta la alimentación
Sensor que lee fríoSolo límite por software65,0 °CNinguna: el límite usa el mismo sensor que miente
Sensor que lee fríoSoftware y chequeos46,1 °CChequeo de respuesta a los 295 s
Sensor desconectadoNinguna65,0 °C—
Sensor desconectadoChequeo de rango40,5 °CDe inmediato (0 s)

Cada fila confirma una regla. Un límite por software con el mismo sensor no ve la falla de ese sensor (el sensor que lee frío mantiene el horno calentando hasta 65 °C). Un límite por software que actúa por el mismo relé no puede abrir un relé pegado (el calefactor sigue a 65 °C); solo la protección independiente en serie corta. Y cada capa se elige para atrapar lo que las otras no ven: el rango atrapa la desconexión al instante, la verificación de respuesta atrapa al sensor mentiroso en 295 s, el termostato atrapa al actuador pegado.

Reglas para los límites:

  • Escalonados: operación normal < alarma < disparo por software < protección independiente < daño. En el horno, 40 °C < 50 °C < 55 °C < 60 °C.
  • Con tiempo para reaccionar: con la salida a pleno, el horno llega de 40 a 55 °C en 916 s y a 60 °C en 1609 s; en un proceso rápido (un motor, un láser) las protecciones deben ser rápidas, y por eso de hardware.
  • Enclavados: un disparo de seguridad se mantiene hasta que una persona lo reconoce; una protección que se reinicia sola cuando baja la temperatura hace oscilar un calefactor defectuoso.
  • Probados periódicamente: una protección que nunca se prueba puede estar rota sin que nadie lo sepa.

05 · Salidas

Actuadores y estado seguro

Los actuadores también fallan, y de dos maneras distintas: fallan abiertos (no actúan; normalmente seguro) o fallan cerrados (actúan sin parar; normalmente peligroso). El diseño busca que la falla caiga del lado seguro:

Estado seguro típico de distintos actuadores.
ActuadorEstado seguroCómo se logra
CalefactorApagadoRelé normalmente abierto: sin corriente de bobina, abre
Válvula de gas o de aguaCerradaElectroválvula normalmente cerrada (tema 29): el resorte la cierra
Motor con carga que caeFrenadoFreno electromagnético que se aplica sin corriente
Ventilador de refrigeraciónEncendidoEl estado seguro depende de la función: aquí, lo seguro es enfriar
Bomba de riegoApagada, con tiempo máximoTemporizador de máxima duración de marcha
  • Tiempo máximo de marcha: un actuador que puede causar daño por permanecer activo (una bomba que inunda, un calefactor) tiene un límite de tiempo continuo en el driver (tema 40) y un tiempo de enfriamiento obligatorio.
  • Verificación de respuesta: si se manda calentar y la temperatura no sube, algo falla (actuador, sensor o fuente). Con el horno a pleno se esperan 1,5 K en 60 s; si tras 300 s encendido no subió al menos 0,5 K, se declara la falla. Es la misma comprobación que atrapó al sensor mentiroso en la tabla anterior.
  • El relé de estado sólido (SSR) falla en cortocircuito con frecuencia (el triac queda conduciendo): no se debe confiar solo en él para cortar; se coloca en serie un contactor electromecánico o un termostato de seguridad.
  • Contactos duplicados: dos relés en serie, cada uno comandado por una vía distinta, para que un relé pegado no deje la carga encendida.
  • Enclavamientos: el calefactor no se enciende si el ventilador no gira; la bomba no arranca sin agua; el motor no invierte sentido sin parar.

06 · El programa también falla

El perro guardián

Un programa se puede colgar por un error, una interferencia, una pila de llamadas corrupta o un dispositivo que no responde. El perro guardián (watchdog) es un temporizador de hardware que reinicia el microcontrolador si el programa no lo «alimenta» a tiempo. Lo normal es que el lazo principal lo reinicie en cada vuelta; si el lazo se detiene, el temporizador vence y fuerza un reinicio.

En un ATmega328P (Arduino Uno) los tiempos disponibles son 15, 30, 60, 120, 250, 500 ms y 1, 2, 4 y 8 s (valores nominales, con un oscilador interno poco preciso). Se activa con wdt_enable(WDTO_250MS) y se alimenta con wdt_reset(). El ESP32 tiene un perro guardián de tareas (por defecto unos 5 s) y el RP2040 uno configurable con watchdog_enable(). También existen circuitos externos (supervisores como el TPL5010 o el MAX6369) que no dependen del oscilador del microcontrolador.

La elección del tiempo tiene dos cotas:

  • Mínimo: mayor que el lazo más lento con margen, o habrá reinicios falsos. Una regla es 4 veces el tiempo máximo del lazo (se mide, tema 41): un lazo de 28 ms pide al menos 112 ms, y se elige 120 ms; uno de 150 ms, 600 ms (se elige 1 s).
  • Máximo: menor que el tiempo en que el sistema puede hacer daño sin control, incluido el tiempo de arranque. Con 250 ms de timeout y 600 ms de arranque, el sistema estará sin control 850 ms: de sobra para un horno (600 s) o una válvula (5 s), pero no alcanza para un motor con carga que debe frenar en 100 ms: ahí la protección debe ser de hardware (un límite de corriente del driver, un freno).

Cómo se usa bien, y los errores más comunes:

  • Un solo punto de alimentación, condicionado a que todo esté bien. Cada tarea marca una bandera al completarse y el lazo principal alimenta al perro solo si todas las banderas están levantadas, y luego las baja. Así un fallo de cualquier tarea provoca el reinicio.
  • No alimentarlo desde una interrupción ni desde un temporizador: la interrupción sigue funcionando aunque el lazo principal esté colgado, y el perro nunca vence.
  • No alimentarlo al principio del lazo «por si acaso» ni dentro de esperas largas: oculta el bloqueo que debería detectar.
  • Reaccionar al reinicio: leer la causa (en un AVR, el registro MCUSR: WDRF es el perro guardián, BORF la baja tensión), registrarla y contar los reinicios seguidos. Con tres seguidos, no seguir intentando: pasar al modo falla con las salidas apagadas, para no oscilar entre colgarse y reiniciar.
  • Perro guardián con ventana: algunos obligan a alimentarlo ni demasiado pronto ni demasiado tarde, y detectan un lazo que corre demasiado rápido.
  • Compatibilidad con el cargador de arranque: algunas placas con un cargador antiguo quedan atrapadas en bucles de reinicio si el perro guardián se activa sin desactivarse al arrancar; conviene probar con la placa concreta.

07 · Encender y reiniciar

Energía, reinicios y arranque seguro

Un reinicio es el momento más peligroso: los pines de un microcontrolador pasan a alta impedancia (flotantes) hasta que el programa los configura, y lo que está conectado a ellos recibe niveles indefinidos. La defensa es de hardware y de software:

  • Resistencias de reposo: un pull-down (10 kΩ a masa) en cada salida de activación alta (o un pull-up si el módulo es de activación baja) hace que durante el reinicio el actuador esté apagado. Los módulos de relé de activación baja suelen traer su propia resistencia de pull-up, pero hay que comprobarlo.
  • Reposo antes que salida: digitalWrite(pin, apagado); pinMode(pin, OUTPUT); (tema 40), nunca al revés.
  • Autoprueba al arrancar (POST): comprobar que los sensores responden y están dentro de rango, que la configuración guardada es válida (CRC) y que las salidas están apagadas, antes de habilitar nada. Si falla, no arrancar: ir al modo falla.
  • Detección de baja tensión (brown-out): con la tensión por debajo de lo que el microcontrolador necesita (a 16 MHz, cerca de 4,5 V), el procesador ejecuta mal y una escritura en la EEPROM puede corromper datos. El ATmega328P trae un detector programable (por ejemplo, 4,3 V) que mantiene el reinicio hasta que la tensión sube; con una batería o una fuente débil, un supervisor externo (MAX809 y similares) lo mejora.
  • Interferencia: los relés, motores y solenoides inyectan picos que reinician o perturban al microcontrolador: diodos de rebote (tema 27), redes RC en contactos de relé, capacitores de desacople, cableado de potencia separado del de señal y, si hace falta, alimentaciones separadas.

La causa del reinicio se lee al arrancar: encendido (PORF), pin de reset (EXTRF), baja tensión (BORF) o perro guardián (WDRF). Un equipo que se reinicia muchas veces por baja tensión tiene un problema de alimentación que el software no puede resolver.

08 · Máquina de modos

Modos de funcionamiento

Con las piezas anteriores, el programa se organiza en una máquina de modos (tema 41) con comportamiento definido en cada uno y reglas explícitas de transición:

Modos de un controlador con tolerancia a fallas.
ModoQué haceSalidasCómo se sale
INICIOAutoprueba: sensores, configuración, salidasApagadasPasa a NORMAL si todo está bien; a FALLA si no en unos 10 s
NORMALControl con datos válidosControladasUn dato malo → DEGRADADO
DEGRADADOSigue con el último valor bueno o con el sensor de respaldo, con alarmaControladas con límites más estrictosDato bueno → NORMAL; tiempo agotado (p. ej. 60 s) → SEGURO
SEGUROEstado seguro enclavado, con aviso (LED y zumbador)ApagadasSolo un reconocimiento manual, tras revisar la causa
FALLAFalla grave (autoprueba, reinicios repetidos): no intenta operarApagadasReinicio manual de la alimentación

Dos decisiones de diseño. El tiempo en DEGRADADO debe ser mucho menor que la inercia del proceso (60 s frente a los 1000 s del horno): el último valor bueno sigue siendo una buena estimación; con un proceso rápido, el modo degradado casi no existe. Y los modos SEGURO y FALLA están enclavados: no vuelven a NORMAL solos, para que una falla intermitente no deje al equipo conmutando entre ambos. Se informa siempre al usuario (un LED que parpadea con un patrón, tema 35; un zumbador, tema 39) y se registra la causa.

09 · Programación

Código defensivo

Programar a la defensiva es asumir que las entradas son dudosas, los tiempos de espera son finitos y la memoria puede estar corrupta. Reglas prácticas:

  • Validar toda entrada (rango, tasa, edad) antes de usarla, y tratar cualquier estado distinto de OK como falla.
  • Ninguna espera sin tiempo límite (tema 41): lecturas, comunicaciones, bucles while. Un while (!listo) sin límite es un cuelgue esperando ocurrir.
  • Un default seguro en cada switch sobre un estado, que lleve al modo seguro: una variable corrupta no puede dejar al programa en un estado sin salida.
  • Sin memoria dinámica en un microcontrolador pequeño (fragmentación, falta de memoria impredecible): objetos estáticos.
  • Cuidado con los límites aritméticos: desbordes de contadores y de millis() (tema 41), divisiones por cero, comparaciones de decimales con ==.
  • Configuración con suma de verificación (CRC) y valores por defecto seguros: si el CRC no coincide, no se usa el dato.
  • Registro de fallas en la EEPROM, con cuidado por el desgaste: cada celda soporta unas 100 000 escrituras. Un registro por minuto en la misma celda la agota en 69 días; repartido de forma rotativa en 256 celdas, dura 48,7 años. Se escribe solo lo que cambia (EEPROM.update).
#include <avr/wdt.h>
#include <EEPROM.h>

// ---------- 1. Validación de la lectura: un decorador de SensorTemperatura (tema 40) ----------
class SensorValidado : public SensorTemperatura {
public:
    SensorValidado(SensorTemperatura &s, float minimo, float maximo, float saltoMax, uint16_t ventanaCongelado)
        : s_(s), min_(minimo), max_(maximo), saltoMax_(saltoMax), ventana_(ventanaCongelado) {}
    bool begin() override { return s_.begin(); }
    void iniciar() override { s_.iniciar(); }
    bool lista() override { return s_.lista(); }

    Lectura leer() override {
        Lectura l = s_.leer();
        if (l.estado != Estado::OK) return l;                                    // el driver ya la marcó
        if (isnan(l.valor) || l.valor < min_ || l.valor > max_) {                // rango físico: -127, 85 de arranque, 1023...
            l.estado = Estado::FUERA_DE_RANGO; return l;
        }
        if (hay_ && fabsf(l.valor - ultimo_) > saltoMax_ && rechazos_ < 5) {     // salto imposible para el proceso
            rechazos_++; l.estado = Estado::FUERA_DE_RANGO; return l;            // tras 5 seguidos se acepta: puede ser real
        }
        rechazos_ = 0;
        iguales_ = (hay_ && l.valor == ultimo_) ? iguales_ + 1 : 0;              // valor exactamente igual durante muchas muestras
        if (iguales_ >= ventana_) { l.estado = Estado::SIN_RESPUESTA; return l; }   // sensor congelado
        ultimo_ = l.valor; hay_ = true;
        return l;
    }

private:
    SensorTemperatura &s_;
    float min_, max_, saltoMax_, ultimo_ = 0;
    uint16_t ventana_, iguales_ = 0, rechazos_ = 0;
    bool hay_ = false;
};

inline bool fresca(const Lectura &l, uint32_t edadMaxMs) { return (uint32_t)(millis() - l.tMs) <= edadMaxMs; }

// ---------- 2. Dos sensores: se comparan y, si discrepan, no se confía en ninguno ----------
class SensorRedundante : public SensorTemperatura {
public:
    SensorRedundante(SensorTemperatura &a, SensorTemperatura &b, float difMax) : a_(a), b_(b), dif_(difMax) {}
    bool begin() override { return a_.begin() & b_.begin(); }
    void iniciar() override { a_.iniciar(); b_.iniciar(); }
    bool lista() override { return a_.lista() && b_.lista(); }
    Lectura leer() override {
        Lectura a = a_.leer(), b = b_.leer();
        bool okA = a.estado == Estado::OK, okB = b.estado == Estado::OK;
        degradado_ = okA != okB;
        if (okA && okB) {
            if (fabsf(a.valor - b.valor) > dif_) return { NAN, Estado::FUERA_DE_RANGO, millis() };   // discrepan: no se sabe cuál miente
            return { (a.valor + b.valor) / 2, Estado::OK, a.tMs };
        }
        if (okA || okB) return okA ? a : b;                                      // uno falló: se sigue con el otro, degradado
        return { NAN, Estado::SIN_RESPUESTA, millis() };
    }
    bool degradado() const { return degradado_; }
private:
    SensorTemperatura &a_, &b_; float dif_; bool degradado_ = false;
};

// ---------- 3. Modos de funcionamiento con tiempos y enclavamiento ----------
enum class Modo : uint8_t { INICIO, NORMAL, DEGRADADO, SEGURO, FALLA };
Modo modo = Modo::INICIO;
uint32_t desdeMs = 0;
float ultimoBueno = NAN;

void entrar(Modo nuevo) { modo = nuevo; desdeMs = millis(); if (nuevo >= Modo::SEGURO) calefactor.apagar(); }

float temperaturaParaControl(const Lectura &l) {                                 // qué dato ve el controlador en cada modo
    bool buena = l.estado == Estado::OK && fresca(l, 5000);
    switch (modo) {
        case Modo::INICIO:
            if (buena && !isnan(l.valor)) { ultimoBueno = l.valor; entrar(Modo::NORMAL); }
            else if ((uint32_t)(millis() - desdeMs) > 10000) entrar(Modo::FALLA);       // la autoprueba no pasó
            break;
        case Modo::NORMAL:
            if (buena) ultimoBueno = l.valor; else entrar(Modo::DEGRADADO);
            break;
        case Modo::DEGRADADO:                                                     // se mantiene el último valor bueno un rato breve
            if (buena) { ultimoBueno = l.valor; entrar(Modo::NORMAL); }
            else if ((uint32_t)(millis() - desdeMs) > 60000) entrar(Modo::SEGURO);    // 60 s << constante de tiempo del horno
            break;
        case Modo::SEGURO: case Modo::FALLA:
            break;                                                                // enclavados: solo un reinicio manual los saca
    }
    return (modo == Modo::NORMAL || modo == Modo::DEGRADADO) ? ultimoBueno : NAN;
}

// ---------- 4. Comprobación de respuesta: ¿el calefactor encendido calienta? ----------
bool respuestaPlausible(bool encendido, float medida) {
    static uint32_t inicio = 0; static float t0 = 0; static bool contando = false;
    if (!encendido) { contando = false; return true; }
    if (!contando) { contando = true; inicio = millis(); t0 = medida; return true; }
    if ((uint32_t)(millis() - inicio) < 300000UL) return true;                   // 5 minutos con la salida a pleno
    return (medida - t0) >= 0.5f;                                                // debió subir al menos 0,5 °C
}

// ---------- 5. Perro guardián: se reinicia solo si TODAS las tareas dan señales de vida ----------
const uint8_t T_SENSOR = 1, T_CONTROL = 2, T_PANTALLA = 4, TODAS = 7;
volatile uint8_t vivas = 0;

void setup() {
    uint8_t causa = MCUSR; MCUSR = 0; wdt_disable();                             // por qué se reinició (WDRF = perro guardián)
    digitalWrite(PIN_CALEFACTOR, LOW); pinMode(PIN_CALEFACTOR, OUTPUT);          // reposo ANTES de ser salida (y pull-down externo)
    if (causa & _BV(WDRF)) { /* contar reinicios seguidos en la EEPROM; con 3, entrar(Modo::FALLA) */ }
    wdt_enable(WDTO_250MS);                                                      // >= 4 x el lazo más lento (28 ms) y << tiempo de daño
}

void loop() {
    // ... cada tarea hace su trabajo y marca: vivas |= T_SENSOR; etc.
    if (vivas == TODAS) { wdt_reset(); vivas = 0; }                              // un solo punto donde se alimenta al perro
}

// ---------- 6. Registro de fallas en la EEPROM: rotativo y con suma de verificación ----------
struct Registro { uint32_t t; uint8_t causa; uint8_t modo; uint8_t crc; };
const int N_REGISTROS = 32;

uint8_t crc8(const uint8_t *d, uint8_t n) { uint8_t c = 0; while (n--) { c ^= *d++; for (uint8_t i = 0; i < 8; i++) c = (c & 0x80) ? (c << 1) ^ 0x07 : c << 1; } return c; }

void registrar(uint32_t indice, uint8_t causa) {                                // el índice crece siempre: las escrituras se reparten
    Registro r = { millis(), causa, (uint8_t)modo, 0 };
    r.crc = crc8((uint8_t *)&r, sizeof(r) - 1);
    EEPROM.put((indice % N_REGISTROS) * sizeof(Registro), r);                   // put() solo escribe los bytes que cambian
}

Los decoradores del tema 40 permiten apilar esta validación sobre cualquier sensor sin tocar la aplicación: SensorValidado envuelve al driver, SensorRedundante combina dos, y el controlador del tema 43 recibe una lectura con estado, nunca un número sin contexto.

10 · Verificación

Pruebas con fallas inyectadas

Una protección que nunca se vio actuar no está probada. La técnica es inyectar fallas a propósito, primero en simulación y después en el montaje real con precauciones:

Plan de pruebas de fallas para el horno.
Falla inyectadaCómoResultado esperado
Sensor desconectadoDesenchufar el sensor en marchaSalida apagada en segundos; modo SEGURO con aviso
Sensor congelado o mentirosoSustituirlo por una resistencia fija, o forzar la lectura en el programaChequeo de respuesta o de discrepancia; salida apagada
Pico en la señalGolpear o acercar un motor al cableSe descarta la muestra; no hay disparo si dura poco
Programa colgadoUn bucle infinito de prueba en el lazoReinicio por perro guardián en el tiempo configurado; salidas apagadas
Reinicios repetidosProvocar tres reinicios seguidosModo FALLA, salidas apagadas, sin intentar operar
Caída de tensiónBajar la alimentación con una fuente regulableReinicio limpio por baja tensión; ninguna salida errática
Actuador pegado (en una prueba segura)Con la carga a baja potencia o una resistencia de pruebaLa protección independiente corta; se registra
Datos de configuración corruptosAlterar un byte de la EEPROMEl CRC falla; se usan los valores por defecto seguros
  1. Escribí el análisis de fallas antes que el código y verificá que cada fila tenga un detector y una respuesta.
  2. Probá cada protección una por una, deshabilitando las demás, para ver qué atrapa cada una.
  3. Medí los tiempos de reacción (detección, reinicio, corte) y compará con el tiempo que el proceso tarda en dañarse.
  4. Hacé las pruebas peligrosas con carga reducida y con un extintor y un corte de emergencia a mano; nunca con tensión de red sin experiencia ni aislamiento.
  5. Repetí las pruebas tras cada cambio de programa o de montaje.

11 · Analogía con programación

Fallas inyectadas, protecciones y confiabilidad

Simulamos las fallas y las defensas del tema: los cuatro detectores sobre cinco fallas de sensor, el horno con tres fallas y distintas combinaciones de protecciones, la elección del tiempo del perro guardián, el modelo de redundancia y el desgaste de la EEPROM.

Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar.

import math

M32 = 2 ** 32


class Ruido:
    """Ruido de desviación típica 1, reproducible (suma de seis uniformes)."""

    def __init__(self, semilla):
        self.x = semilla

    def dato(self):
        s = 0.0
        for _ in range(6):
            self.x = (self.x * 1664525 + 1013904223) % M32
            s += self.x / M32
        return (s - 3) / 0.7071


# ---- 1. Detectores de sensor defectuoso sobre una temperatura de 40 ± 0,5 °C ----
LSB = 0.0625                                            # resolución de un DS18B20 de 12 bits
N, T_FALLA = 600, 300


def cuantizar(x):
    return round(x / LSB) * LSB


def señales(falla):
    ruido_a, ruido_b = Ruido(12345), Ruido(54321)
    a, b = [], []
    for t in range(N):
        real = 40 + 0.5 * math.sin(2 * math.pi * t / 600)
        sigma = 1.0 if (falla == "ruido" and t >= T_FALLA) else 0.05
        lectura = real + sigma * ruido_a.dato()
        if falla == "pegado" and t >= T_FALLA:
            lectura = a[T_FALLA - 1]
        elif falla == "pico" and T_FALLA <= t < T_FALLA + 3:
            lectura += 15
        elif falla == "deriva" and t >= T_FALLA:
            lectura += 0.02 * (t - T_FALLA)
        elif falla == "desconectado" and t >= T_FALLA:
            lectura = -127.0
        a.append(cuantizar(lectura) if lectura != -127.0 else lectura)
        b.append(cuantizar(real + 0.05 * ruido_b.dato()))
    return a, b


def detectar(a, b, limite_tasa=0.5, ventana=30, redundante=True):
    marcas = {"rango": [], "tasa": [], "congelado": [], "discrepancia": []}
    for t in range(N):
        if a[t] < -40 or a[t] > 125:
            marcas["rango"].append(t)
        if t > 0 and abs(a[t] - a[t - 1]) > limite_tasa:
            marcas["tasa"].append(t)
        if t >= ventana and max(a[t - ventana + 1:t + 1]) == min(a[t - ventana + 1:t + 1]):
            marcas["congelado"].append(t)
        if redundante and abs(a[t] - b[t]) > 0.5:
            marcas["discrepancia"].append(t)
    return marcas


print("falla          rango   tasa  congelado  discrepancia   (segundos hasta detectarla; – = no la detecta)")
for falla in ("ninguna", "pegado", "pico", "deriva", "desconectado", "ruido"):
    a, b = señales(falla)
    marcas = detectar(a, b)
    celdas = []
    for nombre in ("rango", "tasa", "congelado", "discrepancia"):
        despues = [t - T_FALLA for t in marcas[nombre] if t >= T_FALLA]
        antes = [t for t in marcas[nombre] if t < T_FALLA]
        texto = "–" if not despues else str(despues[0])
        if antes:
            texto += f" (+{len(antes)} falsos)"
        celdas.append(texto)
    print(f"{falla:13s}  " + "  ".join(f"{c:>9s}" for c in celdas))

print()
for limite in (0.05, 0.5):
    a, b = señales("ninguna")
    falsos = len(detectar(a, b, limite_tasa=limite)["tasa"])
    print(f"límite de tasa de {limite} K por muestra: {falsos} falsos positivos en {N} s sin falla")

# ---- 2. Capas de protección del horno ----
P_MAX, CAP, RES, T_AMB = 100.0, 2000.0, 0.5, 15.0


def horno(falla, sw=False, chequeo=False, termostato=None, segundos=7200, t_falla=600):
    temp, orden, medida_prev = 40.0, False, 40.0
    seguro_sw = seguro_chk = False
    hw_cerrado = True
    seguidos, medida_ini, t_max, primera = 0, 40.0, 40.0, None
    for t in range(segundos):
        if falla == "frio" and t >= t_falla:
            medida = 20.0
        elif falla == "desconectado" and t >= t_falla:
            medida = -127.0
        else:
            medida = temp
        if chequeo and not seguro_chk:
            if medida < -40 or medida > 125:
                seguro_chk, primera = True, primera if primera is not None else (t, "chequeo del sensor")
            if orden:
                if seguidos == 0:
                    medida_ini = medida
                seguidos += 1
                if seguidos >= 300 and medida - medida_ini < 0.5:
                    seguro_chk, primera = True, primera if primera is not None else (t, "chequeo de respuesta")
            else:
                seguidos = 0
        if sw and not seguro_sw and medida > 55:
            seguro_sw, primera = True, primera if primera is not None else (t, "límite por software")
        if medida < 39.5:
            orden = True
        elif medida > 40.5:
            orden = False
        if seguro_sw or seguro_chk:
            orden = False
        pegado = falla == "pegado" and t >= t_falla
        if termostato is not None:
            if hw_cerrado and temp >= termostato:
                hw_cerrado, primera = False, primera if primera is not None else (t, "termostato independiente")
            elif not hw_cerrado and temp < termostato - 10:
                hw_cerrado = True
        potencia = (1.0 if (orden or pegado) else 0.0) * (1.0 if hw_cerrado else 0.0)
        temp += (P_MAX * potencia - (temp - T_AMB) / RES) / CAP
        t_max = max(t_max, temp)
    return t_max, primera


print()
print("falla                          protecciones                                T máx    primera protección")
casos = (("calefactor pegado", "pegado", dict(), "ninguna"),
         ("calefactor pegado", "pegado", dict(sw=True, chequeo=True), "software y chequeos"),
         ("calefactor pegado", "pegado", dict(sw=True, chequeo=True, termostato=55), "software, chequeos y termostato de 55 °C"),
         ("sensor lee frío", "frio", dict(), "ninguna"),
         ("sensor lee frío", "frio", dict(sw=True), "solo límite por software"),
         ("sensor lee frío", "frio", dict(sw=True, chequeo=True), "software y chequeos"),
         ("sensor desconectado", "desconectado", dict(), "ninguna"),
         ("sensor desconectado", "desconectado", dict(chequeo=True), "chequeo de rango"))
for nombre, falla, opciones, proteccion in casos:
    t_max, primera = horno(falla, **opciones)
    cuando = f"a los {primera[0] - 600} s de la falla: {primera[1]}" if primera else "ninguna actuó"
    print(f"{nombre:19s}  {proteccion:40s}  {t_max:6.1f} °C   {cuando}")

tau, t_ss = RES * CAP, T_AMB + P_MAX * RES
print(f"con la salida a pleno el horno tiende a {t_ss:.0f} °C; desde 40 °C llega a 55 °C en {tau * math.log((t_ss - 40) / (t_ss - 55)):.0f} s y a 60 °C en {tau * math.log((t_ss - 40) / (t_ss - 60)):.0f} s")

# ---- 3. Perro guardián ----
print()
TIEMPOS = [15, 30, 60, 120, 250, 500, 1000, 2000, 4000, 8000]
for lazo in (5, 28, 150, 700):
    minimo = 4 * lazo
    elegido = next((t for t in TIEMPOS if t >= minimo), None)
    print(f"lazo más lento de {lazo:4d} ms -> timeout mínimo {minimo:5d} ms -> se elige {elegido} ms")
for proceso, seguro in (("motor con carga (100 ms)", 100), ("válvula (5 s)", 5000), ("horno (600 s)", 600_000)):
    sin_control = 250 + 600
    print(f"{proceso:26s}: sin control durante {sin_control} ms (timeout de 250 ms + 600 ms de arranque): {'alcanza' if sin_control < seguro else 'NO alcanza'}")

# ---- 4. Redundancia (modelo ilustrativo) ----
print()
print("configuración               dato malo sin detectar   pérdida de servicio    (p = 5 %/año, cobertura 60 %, causa común 10 %)")


def modelo(p, d, beta):
    indep = ((1 - beta) * p) ** 2
    return {
        "1 sensor": (p * (1 - d), p * d),
        "2 sensores, comparar": (beta * p * (1 - d) + indep * (1 - d), 2 * (1 - beta) * p),
        "3 sensores, votar 2 de 3": (beta * p * (1 - d) + 3 * indep * (1 - d), 3 * indep * d),
    }


for nombre, (malo, parada) in modelo(0.05, 0.60, 0.10).items():
    print(f"{nombre:26s}  {malo * 100:8.2f} %               {parada * 100:6.2f} %")

# ---- 5. Desgaste de la EEPROM ----
print()
for celdas in (1, 256):
    minutos = 100_000 * celdas
    print(f"un registro por minuto en {celdas:3d} celda(s): {minutos / 1440:9.0f} días ({minutos / 1440 / 365:5.1f} años) hasta 100 000 escrituras por celda")

Resultado: los detectores atrapan el sensor congelado en 28 s (congelamiento) o 176 s (discrepancia), el pico y el ruido en 0 a 1 s con la tasa, la desconexión en 0 s con el rango y la deriva solo con el segundo sensor, en 25 s; con un límite de tasa de 0,05 K por muestra hay 391 falsos positivos en 600 s, con 0,5 K ninguno. Con el calefactor pegado, el límite por software y los chequeos no impiden los 65,0 °C; el termostato independiente de 55 °C lo deja en 55,0 °C. Con el sensor que lee frío, el límite por software no ve nada (65,0 °C); el chequeo de respuesta lo corta a los 295 s con 46,1 °C. La desconexión se atrapa de inmediato (40,5 °C). A pleno, el horno llega a 55 °C en 916 s y a 60 °C en 1609 s. Un lazo de 28 ms pide un perro guardián de 120 ms, y 850 ms sin control no alcanzan para un motor de 100 ms. Con p = 5 %, cobertura del 60 % y causa común del 10 %, el dato malo sin detectar es de 2,00 % con un sensor, 0,28 % con dos comparados y 0,44 % con votación 2 de 3, con pérdidas de servicio de 3,00 %, 9,00 % y 0,36 %. Un registro por minuto agota una celda de la EEPROM en 69 días y repartido en 256 celdas, en 48,7 años.

12 · Exploración interactiva

Detectores, protecciones, perro guardián y redundancia

El primer instrumento aplica cuatro detectores a una señal con una falla inyectada. El segundo simula el horno con una falla y capas de protección que se activan una por una. El tercero ayuda a elegir el tiempo del perro guardián. El cuarto compara las configuraciones de sensores con el modelo ilustrativo de la sección 3. Los dos primeros usan el mismo modelo del programa de Python.

Instrumento 1: detectores de sensor defectuoso

Rango · tasa (s tras la falla)—
Congelado · discrepancia (s tras la falla)—
Falsos positivos antes de la falla—
Estado
—

Instrumento 2: capas de protección del horno

Temperatura máxima—
Primera protección que actuó—
Margen hasta el daño (60 °C)—
Estado
—

Instrumento 3: tiempo del perro guardián

Timeout mínimo (4 × lazo) · menor disponible—
Sin control tras un cuelgue—
Margen frente a falsos reinicios—
Estado
—

Instrumento 4: redundancia de sensores

1 sensor: dato malo · parada—
2 sensores comparados: dato malo · parada—
3 sensores, 2 de 3: dato malo · parada—
Estado
—

Recorrido guiado

  1. Con «sensor congelado» a los 300 s, límite de tasa de 0,5 y ventana de 30: el detector de congelamiento lo atrapa a los 28 s y la discrepancia a los 176 s. Con una ventana de 120 muestras, el congelamiento tarda 118 s: la ventana es una decisión.
  2. Elegí «deriva»: con el segundo sensor se detecta a los 25 s. Desmarcá la casilla: ningún detector la ve y el estado lo avisa. Es la falla que la redundancia o un modelo deben atrapar.
  3. Con «pico» o «ráfaga de ruido», la tasa los detecta de inmediato. Bajá el límite a 0,05: aparecen cientos de falsos positivos antes de la falla.
  4. En las protecciones, con el relé pegado, el límite por software y los chequeos y sin termostato: 65,0 °C, daño. El límite por software no puede abrir un relé pegado. Activá el termostato de 55 °C: queda en 55,0 °C.
  5. Elegí «el sensor lee siempre 20 °C» con solo el límite por software: 65,0 °C. Agregá los chequeos: se detecta a los 295 s, con 46,1 °C. Elegí «sensor desconectado» con los chequeos: 40,5 °C de inmediato.
  6. En el perro guardián, con el lazo de 28 ms, timeout de 250 ms y un horno: correcto. Cambiá el proceso a «motor con carga»: 850 ms sin control son más que los 100 ms: no protege a tiempo.
  7. Con un bloqueo ocasional de 300 ms y un timeout de 250 ms, el programa se reinicia sin tener ninguna falla real: un falso reinicio. Subí el timeout a 500 ms.
  8. En la redundancia, con 5 %, 60 % y 10 %: 2,00 % de datos malos con un sensor, 0,28 % con dos y 0,44 % con tres; paradas de 3,00 %, 9,00 % y 0,36 %. Subí la causa común al 30 %: la redundancia casi no mejora el dato malo.
Desafío: un riego automático que no inunde

Un sistema de riego (tema 45 lo retoma) abre una electroválvula cuando la humedad del suelo baja del umbral. ¿Qué fallas hay y cómo se las protege? Sensor de humedad desconectado o en corto: lee «seco» y la válvula quedaría abierta; se valida el rango y, ante un dato inválido, se cierra (válvula normalmente cerrada). Sensor que lee seco por deriva: la humedad real sube pero la lectura no responde: se verifica que, tras un riego, el sensor cambie (respuesta esperada); si no, falla. Válvula que se queda abierta: un tiempo máximo de marcha (por ejemplo, 10 minutos) y un tiempo de espera mínimo entre riegos; y un segundo sensor (un caudalímetro o un sensor de nivel en el recipiente) que mida lo regado. Programa colgado con la válvula abierta: perro guardián con la válvula normalmente cerrada, que cierra al perder la corriente. Corte de luz: la válvula cierra sola. Protección independiente: un temporizador mecánico o un sensor de nivel que corta el agua de forma independiente del microcontrolador, si lo regado puede dañar algo. Se prueban todas las fallas una por una, con agua en un recipiente.

13 · Método de trabajo

Cómo diseñar para la falla, para cualquier proyecto

  1. Definí qué es peligroso y cuál es el estado seguro de cada actuador; elegí componentes que fallen hacia él.
  2. Hacé la tabla de fallas: falla, efecto, detección, respuesta; empezá por las que dejan una salida activa.
  3. Validá cada sensor (rango, tasa, congelamiento, edad), con umbrales entre lo normal y lo peligroso, y duplicá donde la falla sea grave.
  4. Armá capas independientes: control, límite por software, protección de hardware en serie con la carga, contención física.
  5. Verificá la respuesta de los actuadores, con tiempos máximos de marcha y contactos que no dependan de un solo elemento.
  6. Usá un perro guardián con tiempo medido y alimentación condicionada a todas las tareas; sin reinicios en bucle.
  7. Hacé el arranque seguro: pull-down, reposo antes que salida, autoprueba, baja tensión, causa del reinicio registrada.
  8. Organizá los modos (inicio, normal, degradado, seguro, falla), probalos con fallas inyectadas y documentá el resultado.

Si una sola falla puede dejar una salida activa sin que nada la detenga, falta una capa; si una protección depende de lo que protege, no es independiente; si el sistema reinicia sin parar, falta el modo falla; si nunca viste actuar una protección, no la probaste.

14 · Comprensión

Confusiones frecuentes

«Con un límite de temperatura en el programa ya estoy protegido»

Ese límite usa el mismo sensor, el mismo microcontrolador y el mismo relé que el control: no ve un sensor que miente ni puede abrir un relé pegado. Hace falta una protección independiente en serie con la carga.

«El perro guardián soluciona los cuelgues»

Reinicia el programa, no lo repara: si la causa persiste, el equipo se reinicia en bucle. Hay que registrar la causa, contar los reinicios y pasar a un modo seguro tras unos pocos.

«Con dos sensores ya sé cuál es el bueno»

Con dos, una discrepancia se detecta pero no se atribuye. Para identificar el defectuoso y seguir funcionando hacen falta tres (votación 2 de 3) o un detector adicional.

«Un sensor que devuelve un valor constante está estable»

Un sensor real tiene ruido; si el valor es idéntico durante decenas de muestras, probablemente esté congelado, sobre todo si el proceso cambia.

«Un relé de estado sólido corta siempre»

Los SSR suelen fallar en cortocircuito, quedando encendidos. Para cortar con seguridad se agrega un contactor electromecánico o un termostato en serie.

«Si el programa funciona en las pruebas, es robusto»

Las pruebas sin fallas solo muestran el caso feliz. La robustez se verifica inyectando fallas: sensor desconectado, programa colgado, baja tensión, memoria corrupta.

15 · Práctica guiada

Predecí antes de comprobar

1. Detectores

Un sensor de temperatura de un horno puede dar entre −40 y 125 °C, el proceso cambia como máximo 0,1 K por segundo y se lee cada 1 s. ¿Qué rango y qué límite de tasa usás? ¿Qué lecturas descartarías: 130 °C, 40,3 °C seguido de 41,5 °C, −127 °C?

Ver solución

Rango de −40 a 125 °C y un límite de tasa algo mayor que 0,1 K/muestra con margen para el ruido (por ejemplo 0,5 K). Se descartan: 130 °C (fuera de rango), 41,5 °C tras 40,3 °C (salto de 1,2 K, mayor que 0,5) y −127 °C (fuera de rango).

2. Ventana de congelamiento

Un sensor de 12 bits (0,0625 °C) en un proceso que cambia 0,002 K/s ¿puede dar un valor idéntico durante 30 muestras sin estar averiado?

Ver solución

En 30 s el proceso cambia 0,06 K, casi un escalón de resolución, y con ruido lo normal es ver al menos un cambio; pero puede darse sin avería en procesos muy lentos y estables. La ventana debe ser mayor que el tiempo que tarda el proceso en cambiar varios escalones (aquí, 0,0625 / 0,002 ≈ 31 s por escalón: conviene una ventana de varios minutos).

3. Votación

Tres sensores dan 40,2; 40,4 y 52,0 °C. ¿Qué valor usa una votación 2 de 3 por mediana y cuál es el sensor defectuoso?

Ver solución

La mediana es 40,4 °C; el sensor de 52,0 °C discrepa más de la tolerancia y se marca como defectuoso, y el sistema sigue (modo degradado con aviso).

4. Perro guardián

El lazo más lento dura 60 ms y el arranque tras un reinicio, 400 ms. ¿Qué timeout de los disponibles (15, 30, 60, 120, 250, 500 ms…) elegís y cuánto tiempo queda el sistema sin control ante un cuelgue?

Ver solución

4 × 60 = 240 ms mínimos → 250 ms. Sin control: 250 + 400 = 650 ms.

5. Desgaste

Se registra un evento cada 10 s en la misma celda de EEPROM (100 000 escrituras de vida). ¿Cuánto dura? ¿Y repartido en 64 celdas?

Ver solución

100 000 × 10 s = 1 000 000 s ≈ 11,6 días; con 64 celdas, 64 veces más: ~740 días (2 años). Mejor aún, escribir solo si el dato cambia.

6. Diagnóstico

Un termostato con un relé de estado sólido sigue calentando aunque el programa le ordene apagar; el límite por software, a 55 °C, se dispara varias veces sin efecto. ¿Qué pasa y qué agregás?

Ver solución

El SSR está en cortocircuito (falla típica) y no se puede abrir por software. Se agrega una protección independiente en serie con la carga: un termostato de seguridad o un contactor electromecánico que no dependa del microcontrolador, y se detecta la falla porque la temperatura sube con la salida apagada.

16 · Síntesis

Ideas para recordar

  • Se diseña desde la falla: ¿qué es lo peor que puede pasar? Cada falla debe llevar a un estado seguro (calefactor apagado, válvula cerrada, motor frenado), y se comienza por las que dejan una salida activa.
  • Los sensores fallan abiertos, en corto, congelados, con picos, con deriva o con dato viejo: se detectan con rango, tasa, congelamiento, discrepancia y edad; ningún detector atrapa todo y los umbrales van entre lo normal y lo peligroso.
  • La redundancia (2 comparados, 3 con votación 2 de 3, mejor si son disímiles) detecta la deriva; la causa común fija su límite.
  • Las protecciones son capas independientes: un límite por software con el mismo sensor o el mismo relé no ve ni puede cortar la falla de ninguno; la capa final es de hardware, en serie con la carga, y enclavada.
  • Los actuadores fallan hacia lo seguro por diseño (normalmente abierto o cerrado, freno por resorte), con tiempo máximo de marcha y verificación de respuesta; un SSR suele fallar en corto.
  • El perro guardián (≥ 4 veces el lazo, < tiempo de daño menos el de arranque) se alimenta en un solo punto, condicionado a todas las tareas, nunca desde una interrupción; los reinicios repetidos llevan al modo falla.
  • El arranque seguro: pull-down, reposo antes de ser salida, autoprueba, detección de baja tensión y causa del reinicio registrada.
  • Una máquina de modos (inicio, normal, degradado, seguro, falla) con estados enclavados, código defensivo (validación, tiempos límite, CRC) y pruebas con fallas inyectadas: una protección que nunca se vio actuar no está probada.

¿Listo para el tema 45?

Antes de avanzar, explicá por qué un límite de temperatura por software con el mismo sensor no protege de un sensor que lee frío, elegí el timeout del perro guardián para un lazo máximo de 40 ms y decí qué ventaja tiene votar 2 de 3 sobre comparar dos sensores. Si podés justificar las tres respuestas, ya sabés diseñar para la falla.

En el próximo tema usamos todo lo del curso en un proyecto completo: el control climático de un invernadero, con temperatura, humedad, luz, ventilador, relé y riego automático.