← Índice del curso

Robótica y Automatización · Tema 35

Qué es la automatización: procesos, lógica secuencial y PLC

Un robot decide qué hacer mientras se mueve por un entorno. Un proceso automatizado, en cambio, repite una operación definida —llenar un tanque, mover una cinta, clasificar una pieza— de forma confiable y segura. Es otro tipo de problema, con sus propias reglas: señales discretas, lógica con memoria, un ciclo de ejecución y mucho cuidado con lo que pasa cuando algo falla.

01 · Punto de partida

Del robot al proceso

Los primeros 34 temas del curso trataron de robots: máquinas que se mueven, perciben y deciden en un entorno incierto. La segunda parte trata de la automatización: hacer que un proceso se ejecute solo, de manera repetible, con la menor intervención humana posible. Un riego programado, el ascensor de un edificio, una línea de embotellado y la bomba de un tanque de agua son ejemplos.

Las dos disciplinas comparten sensores, actuadores y controladores, pero difieren en el énfasis. Un robot móvil enfrenta incertidumbre y suele tomar decisiones continuas. Un proceso automatizado enfrenta repetición, secuencia y seguridad: lo importante es que haga lo mismo cada vez, que arranque y pare en el orden correcto y que ante una falla termine en un estado seguro. Su lenguaje natural es el de la lógica con memoria y el de las máquinas de estados (temas 36 a 39).

Usaremos un hilo conductor: una estación de bombeo que mantiene el nivel de un tanque entre dos sensores, con arranque y paro, y una protección contra marcha en falla.

02 · Definiciones

Qué es automatizar

Un proceso es una transformación de materia, energía o información: llenar, calentar, mezclar, transportar, clasificar. Automatizar es delegar en un sistema técnico la ejecución, y en parte la supervisión, de ese proceso. Se distingue por cuánto hace la máquina:

Grados de automatización de un riego.
NivelQuién decide y quién actúaEjemplo
ManualLa persona decide y accionaAbrir la canilla cuando la planta parece seca
AsistidoLa persona decide; la máquina ejecutaPulsar un botón que abre la válvula durante 10 minutos
AutomáticoLa máquina decide con reglas y sensoresRegar si la humedad baja de un umbral y no llovió

Automatizar tiene ventajas (repetibilidad, productividad, seguridad frente a tareas peligrosas, registro de datos) y costos (inversión, mantenimiento, dependencia de la correcta programación y de los sensores). No todo conviene automatizarlo: una tarea que ocurre pocas veces, que requiere juicio humano o cuyo costo de falla es alto puede ser mejor manual o asistida. Y automatizar un proceso mal entendido solo produce errores más rápido.

Un sistema automático típico se organiza en capas: en el campo, los sensores y actuadores; en el control, un controlador (PLC o microcontrolador) que ejecuta la lógica; en la supervisión, una interfaz con operadores (pulsadores, luces, pantallas) y el registro de datos. En este tema trabajamos sobre todo la capa de control.

03 · El vocabulario del controlador

Entradas, salidas y señales

El controlador ve el mundo a través de sus entradas y lo modifica a través de sus salidas. Para la estación de bombeo:

Entradas y salidas de la estación de bombeo.
NombreDirecciónDispositivoSignificado del 1
STARTEntradaPulsador normalmente abierto (NA)Pulsado
STOP_OKEntradaPulsador normalmente cerrado (NC)En reposo: el circuito está cerrado. 0 = pulsado o cable cortado
N_BAJOEntradaSensor de nivel bajoHay líquido a la altura del sensor
N_ALTOEntradaSensor de nivel altoHay líquido a la altura del sensor
TERM_OKEntradaRelé térmico del motor (NC)Motor sin sobrecarga
BOMBASalidaContactor de la bombaBomba encendida
LUZ_FALLASalidaLámparaFalla enclavada

Las señales pueden ser discretas (todo o nada: un pulsador, un final de carrera, un contactor) o analógicas (una magnitud continua: la temperatura, un nivel medido, la apertura de una válvula). En la industria las señales discretas suelen ser de 24 V de continua y las analógicas, de 0 a 10 V o de 4 a 20 mA. Esas tensiones y corrientes no son las de un microcontrolador (3,3 o 5 V, pocos miliamperios); por eso hacen falta interfaces (sección 7).

Un detalle que ahorra errores: el programa trabaja con bits lógicos («hay líquido», «está habilitado»), no con tensiones. La correspondencia entre el estado físico y el bit se decide en el diseño. En el pulsador de parada se elige que el 1 signifique «no apretado» (contacto NC): así, un cable cortado se lee como parada (sección 6).

04 · Decisiones con y sin memoria

Lógica combinacional y secuencial

La lógica combinacional calcula las salidas solo a partir de las entradas actuales: Y (AND), O (OR), NO (NOT) y sus combinaciones, que se describen con una tabla de verdad. «La bomba funciona si está habilitada y hay demanda de llenado» es BOMBA = HAB ∧ LLENANDO. No recuerda nada: si cambian las entradas, cambia la salida.

La lógica secuencial agrega memoria: la salida depende también de lo que pasó antes. Los bloques básicos son:

  • Enclavamiento (seal-in). Un pulsador momentáneo mantiene una salida encendida gracias a un contacto de la propia salida en paralelo: HAB = (START ∨ HAB) ∧ STOP_OK. Se enciende con un toque de START y se apaga al abrirse STOP.
  • Biestable set–reset. Dos condiciones (poner y reponer) y una salida que recuerda: LLENANDO = (¬N_BAJO ∨ LLENANDO) ∧ ¬N_ALTO. Si ambas condiciones coinciden, hay que decidir quién gana; aquí gana el reset.
  • Histéresis. El set–reset entre dos sensores (el bajo para arrancar y el alto para detener) evita que la bomba arranque y pare continuamente cerca de un único umbral. Es la histéresis del tema 7 con otro nombre.
  • Temporizadores. TON (retardo a la conexión): la salida se activa cuando la entrada estuvo activa durante un tiempo dado. TOF (retardo a la desconexión) y los pulsos temporizados son variantes.
  • Contadores de piezas, ciclos o eventos, y la detección de flancos (reaccionar solo en el instante del cambio de 0 a 1).

Con eso se programa una gran parte de la automatización discreta. Cuando las secuencias se complican (un ciclo con varias etapas), se organiza la lógica como máquina de estados, que es el tema de las siguientes unidades.

05 · Cómo se ejecuta

El ciclo de scan

Un PLC no ejecuta el programa en respuesta a eventos, sino en un ciclo periódico llamado scan:

  1. Leer las entradas y guardarlas en una imagen (una copia congelada para todo el ciclo).
  2. Ejecutar la lógica, de arriba hacia abajo, usando la imagen de las entradas y la memoria interna.
  3. Escribir las salidas todas juntas.
  4. Tareas de comunicación y diagnóstico; volver al paso 1.

Es el mismo esquema del loop() de un Arduino sin bloqueos que venimos usando. Tiene consecuencias que conviene entender:

  • Hay un retardo de hasta un ciclo entre un cambio de entrada y su efecto en la salida. Con ciclos de 1 a 20 ms suele ser irrelevante; con 1 s, no.
  • Un pulso más corto que el ciclo puede perderse. Un sensor que da un pulso de 20 ms puede pasar inadvertido con un scan de 100 ms. Se resuelve acelerando el ciclo, con entradas con memoria (latch) o con interrupciones.
  • El orden de las líneas importa. Si la línea de la bomba se escribe antes que la de habilitación, la bomba reacciona con un ciclo de retraso. Y una condición puede usar el valor de la memoria de la vuelta anterior.
  • Determinismo. Si no hay esperas ni bucles largos, el tiempo de ciclo es acotado y predecible. Un delay() en el programa rompe esa propiedad.
  • Los contactos mecánicos rebotan (tema 7): se filtran en la entrada, con un antirrebote por tiempo.

Pensar en términos de scan evita los errores típicos de quien viene de la programación por eventos: la lógica no «espera» nada; en cada vuelta evalúa todo de nuevo.

06 · Lo que importa cuando algo sale mal

Diseñar para fallar bien

En una máquina automática, el programa que funciona cuando todo anda bien es la mitad del trabajo. La otra mitad es qué pasa cuando algo falla. Criterios básicos:

  • Seguridad intrínseca en los contactos de parada. Los pulsadores de parada y los relés térmicos se cablean normalmente cerrados: un cable cortado o un contacto suelto se interpreta como parada, no como funcionamiento. Un pulsador de parada NA dejaría la máquina sin forma de detenerla si se corta el cable.
  • Parada de emergencia cableada y independiente. La emergencia no puede depender solo del programa: corta la energía de potencia por un circuito propio, de acuerdo con las normas de seguridad (tema 4). El controlador la lee para informar, pero no es quien la ejecuta.
  • Estado al energizar. Tras un corte de luz, la máquina no debe arrancar sola. En el estado inicial todo está apagado y deshabilitado, y un pulso de START explícito rearma el sistema. Es la razón por la que la habilitación es enclavada y no se retiene en una memoria no volátil.
  • Fallas enclavadas. Una falla detectada se mantiene hasta que una persona la reconoce y la reinicia (con STOP, en el ejemplo). Una falla que se borra sola puede repetirse en silencio.
  • Límites de tiempo. Una bomba que marcha demasiado sin lograr su objetivo indica una fuga, un filtro tapado o un sensor roto. Un temporizador de supervisión la detiene.
  • Sensores con falla detectable. Si el nivel alto indica «lleno» y nunca se activa, hay que prever qué hace el sistema (la protección por tiempo cubre este caso).

Y una advertencia sobre la elección de los límites: una protección con un umbral mal calculado dispara sin que haya falla (falsa alarma) o no dispara cuando debía. El tiempo máximo de la bomba debe ser claramente mayor que el llenado normal, con margen, y menor que el tiempo en que se produciría un daño. El laboratorio 1 lo muestra.

07 · Dónde corre el programa

PLC y microcontrolador

Un PLC (controlador lógico programable) es una computadora industrial diseñada para ejecutar este tipo de lógica en ambientes difíciles. Un microcontrolador como el de un Arduino ejecuta el mismo tipo de programa, con otras características:

Comparación de orientación general; los detalles dependen de cada producto.
AspectoPLCMicrocontrolador (Arduino)
Entradas y salidasAisladas, de 24 V (o más), protegidas, con borneras y módulos intercambiablesDe 3,3 o 5 V, sin aislamiento: requieren optoacopladores, relés o drivers
RobustezDiseñado para ruido eléctrico, vibración y temperatura de planta; vida útil de añosUna placa de desarrollo no está pensada para ese ambiente
ProgramaciónEstándar IEC 61131-3: escalera (ladder), bloques de función, texto estructurado y otrosC/C++ con libertad total
EjecuciónCiclo de scan gestionado por el sistema, con tiempo de ciclo supervisadoEl programador arma su propio ciclo
CertificaciónExisten equipos certificados para seguridad funcionalSin certificación para seguridad; no es adecuado para cadenas de seguridad
MantenimientoDiagnóstico estandarizado, repuestos, soporte, personal formadoDepende del autor del programa
CostoMayorMuy bajo
FlexibilidadLimitada a lo que ofrece la plataformaTotal, y también total responsabilidad

Las reglas de decisión son prácticas: para una máquina productiva, con cargas de 24 V o de potencia, personal de mantenimiento ajeno al autor, exigencias de seguridad o una vida útil larga, un PLC (o equipos industriales equivalentes). Para un prototipo, un proyecto educativo, una aplicación de bajo riesgo o un producto de gran volumen con electrónica propia, un microcontrolador. En todos los casos, el programa de un microcontrolador puede escribirse con mentalidad de PLC: ciclo de scan, imagen de entradas, lógica de arriba abajo y salidas al final. Es lo que hacemos aquí.

El lenguaje de escalera (ladder) representa la lógica como un esquema de contactos y bobinas entre dos rieles. Los contactos son entradas o memorias; las bobinas, salidas o memorias. Una cosa que confunde al comienzo: «contacto normalmente abierto» en el programa significa «examinar si el bit vale 1», con independencia de si el pulsador físico es NA o NC. En nuestro ejemplo STOP_OK es una entrada que vale 1 en reposo (pulsador NC) y se usa como contacto normal en el programa.

Las interfaces entre un microcontrolador y el mundo industrial son un tema en sí: optoacopladores para entradas de 24 V, módulos de relé o transistores para salidas, protecciones contra picos inductivos (tema 11), fuentes separadas y tierras bien resueltas (tema 4). Nunca se conecta una entrada de 24 V directamente a un pin de la placa.

08 · Todo junto

Un ejemplo completo: una estación de bombeo

Un tanque con dos sensores de nivel y una bomba. El programa de cinco líneas, en escalera:

Diagrama de escalera de la estación de bombeo Cinco líneas entre dos rieles. La primera habilita el sistema con un enclavamiento. La segunda mantiene el llenado con histéresis. La tercera enciende la bomba cuando el sistema está habilitado y hay demanda de llenado. La cuarta mide con un temporizador cuánto lleva la bomba funcionando. La quinta enclava una falla si el temporizador vence, y se borra con el pulsador de parada. STARTHABSTOP_OKTERM_OKFALLAHAB1 · habilitación con enclavamientoN_BAJOLLENANDON_ALTOLLENANDO2 · histéresis del nivelHABLLENANDOBOMBA3 · salida a la bombaBOMBATONT_MAX = 30 sT_OK4 · temporizador de marchaT_OKFALLASTOP_OKFALLA5 · falla enclavada: se borra al abrirse STOP_OK

Cómo se lee, de arriba hacia abajo y en cada scan:

  1. HAB se activa con un pulso de START (o si ya estaba activa) siempre que STOP_OK y TERM_OK estén en 1 y no haya falla. Es el enclavamiento: START es momentáneo.
  2. LLENANDO se activa cuando falta el nivel bajo y se mantiene hasta que aparece el nivel alto: la histéresis.
  3. BOMBA funciona si el sistema está habilitado y hay que llenar.
  4. El temporizador cuenta mientras la bomba esté encendida.
  5. FALLA se enclava si el temporizador llegó a su límite, y se borra al apretar STOP. Al activarse, deshabilita el sistema en el scan siguiente (línea 1) y la bomba se detiene.

Notá cómo el orden y la memoria juegan juntos: la línea 1 usa el valor de FALLA de la vuelta anterior, de modo que la bomba se detiene un scan después de enclavarse la falla. Con un scan de 100 ms es irrelevante, y es el comportamiento que muestra el laboratorio 2.

09 · Código para la placa

El programa de scan en Arduino

El sketch escribe el programa como una función scan() de cinco líneas y la prueba contra un tanque simulado dentro del mismo sketch, en cuatro escenarios. El nivel se maneja en enteros (centésimas de por ciento) para que los resultados sean exactos. En un equipo real, scan() se llamaría cada 10 a 100 ms desde loop() con millis(), alimentada con las entradas reales; los comentarios indican cómo leer los pulsadores.

// Estación de bombeo programada con el estilo de un PLC: ciclo de scan (leer entradas, ejecutar la lógica, escribir salidas).
// El tanque se simula dentro del sketch para probar el programa sin hardware; la lógica de scan() es la que se conserva en un equipo real.
// Nivel en centésimas de por ciento y tiempo en ciclos de 0,1 s: todo con enteros, sin errores de redondeo.
const int DT_MS = 100;                         // período del scan en un equipo real: loop() con millis()
struct Programa {
  bool hab, llenando, falla, bomba;
  int temporizador, tMax;                      // en scans
};

void scan(Programa &p, bool start, bool stopOk, bool nBajo, bool nAlto, bool termOk) {
  p.hab = (start || p.hab) && stopOk && termOk && !p.falla;           // 1) habilitación enclavada
  p.llenando = (!nBajo || p.llenando) && !nAlto;                      // 2) histéresis de nivel
  p.bomba = p.hab && p.llenando;                                      // 3) salida a la bomba
  p.temporizador = p.bomba ? p.temporizador + 1 : 0;                  // 4) temporizador de marcha (TON)
  p.falla = (p.temporizador >= p.tMax || p.falla) && stopOk;          // 5) falla enclavada, se borra con STOP
}

// En un equipo real: start = digitalRead(PIN_START) == LOW (pulsador NA a GND con INPUT_PULLUP);
// stopOk = digitalRead(PIN_STOP) == LOW (pulsador NC: en reposo cerrado, un cable cortado cuenta como STOP);
// nBajo / nAlto vienen de los sensores de nivel y termOk del relé térmico; la salida bomba maneja un relé con su driver.

void simular(const char *titulo, long consumoCenti, long caudalCenti, int tMaxScans, long paroT, long reinicioT) {
  Programa p = {false, false, false, false, 0, tMaxScans};
  long nivel = 5000;                                                  // 50 %
  const long BAJO = 2000, ALTO = 8000;
  long arranques = 0, encendidos = 0, eventos = 0;
  bool bombaPrev = false, fallaPrev = false;
  Serial.println(titulo);
  for (long k = 0; k < 2400; k++) {                                   // 240 s simulados
    const bool start = (k >= 10 && k < 15) || (reinicioT > 0 && k >= reinicioT && k < reinicioT + 5);
    const bool stopOk = !(paroT > 0 && k >= paroT && k < paroT + 5);
    scan(p, start, stopOk, nivel >= BAJO, nivel >= ALTO, true);
    nivel = constrain(nivel + (p.bomba ? caudalCenti : 0) - consumoCenti, 0, 10000);
    const char *texto = nullptr;
    if (p.bomba && !bombaPrev) { arranques++; texto = "arranca la bomba"; }
    else if (!p.bomba && bombaPrev) texto = "se detiene la bomba";
    else if (p.falla && !fallaPrev) texto = "FALLA enclavada";
    if (texto && eventos < 6) {
      eventos++;
      Serial.print("   t="); Serial.print(k / 10.0, 1); Serial.print(" s: "); Serial.print(texto);
      Serial.print(" (nivel "); Serial.print(nivel / 100.0, 1); Serial.println(" %)");
    }
    if (p.bomba) encendidos++;
    bombaPrev = p.bomba; fallaPrev = p.falla;
  }
  Serial.print("   arranques="); Serial.print(arranques);
  Serial.print("; bomba encendida "); Serial.print(encendidos / 24.0, 1);
  Serial.print(" % del tiempo; nivel final "); Serial.print(nivel / 100.0, 1);
  Serial.print(" %; falla="); Serial.println(p.falla ? "si" : "no");
}

void setup() {
  Serial.begin(115200);
  simular("Funcionamiento normal (consumo 1 %/s)", 10, 40, 300, 0, 0);
  simular("Consumo de 2 %/s (llenado de 30 s = tiempo maximo)", 20, 40, 300, 0, 0);
  simular("Fuga (consumo 5 %/s)", 50, 40, 300, 0, 0);
  simular("STOP a los 100 s y nuevo START a los 130 s", 10, 40, 300, 1000, 1300);
}

void loop() {}

La salida esperada es, para el funcionamiento normal: t=30.1 s: arranca la bomba (nivel 20.2 %), t=50.2 s: se detiene la bomba (nivel 80.1 %) y los ciclos siguientes, con arranques=3; bomba encendida 25.1 % del tiempo; nivel final 51.2 %; falla=no. Con un consumo de 2 %/s se produce una falla a los 45,0 s (nivel 79,8 %) aunque no hay avería. Con una fuga de 5 %/s, a los 36,0 s. Con el paro a los 100 s y el nuevo START a los 130 s, la bomba arranca recién a los 130,0 s con el tanque casi vacío (0,7 %).

Probalo en un entorno real así: reemplazá la simulación por la lectura de dos sensores de nivel, un pulsador de arranque NA con INPUT_PULLUP y uno de parada NC, e implementá la salida con un módulo de relé que maneje un contactor de una carga de prueba (una lámpara, un motor pequeño), nunca de una bomba de red sin las protecciones eléctricas adecuadas. Los detalles de potencia son parte del tema 4.

10 · Exploración interactiva

Laboratorios: el tanque y el scan

1. El proceso completo en 240 segundos

El tanque se vacía por el consumo y se llena con la bomba. El programa de cinco líneas corre con un scan de 100 ms; el primer START llega al segundo 1. La curva es el nivel; las líneas punteadas, los sensores bajo (naranja) y alto (celeste); las barras lima, los intervalos con la bomba encendida.

Nivel del tanque en el tiempoCurva del nivel durante 240 segundos que sube cuando la bomba está encendida y baja por el consumo, con los dos umbrales de los sensores y barras que marcan cuándo funciona la bomba.100 %0 %0 s240 s
Arranques de la bomba—
Bomba encendida—
Nivel final—
Llenado normal (de bajo a alto)—
¿Falla enclavada?—

Elegí los parámetros del proceso.

Con los valores iniciales hay 3 arranques en 240 s, la bomba trabaja el 25 % del tiempo y un llenado dura 20 s (el 67 % del tiempo máximo de 30 s). Subí el consumo a 2 %/s: el llenado pasa a 30 s, igual al tiempo máximo, y el sistema declara una falla a los 45 s sin que haya avería: una falsa alarma. Subí el tiempo máximo a 40 s y desaparece. Con 5 %/s (una fuga) la falla es correcta. Probá los sensores en 40 % y 60 %: más arranques (9) y ciclos más cortos; con 10 % y 90 %, apenas 2. Poné el STOP a los 100 s: la bomba no vuelve hasta un nuevo START 30 s después.

2. Ejecutar la lógica un scan por vez

Cambiá las entradas y ejecutá scans. Cada scan equivale a 1 s (el tiempo máximo de marcha es de 30 scans). La tabla muestra las cinco líneas evaluadas con la memoria del scan anterior y el resultado. START es un pulsador: se mantiene tildado solo si lo dejás tildado.

Las cinco líneas del programa en el último scan.
LíneaInstrucciónCon los valoresResultado
BOMBA—
Luz de marcha—
Luz de falla—
Temporizador—

Ejecutá un scan.

Una secuencia para probar: tildá START y ejecutá un scan (HAB pasa a 1); destildá START y ejecutá otro (HAB sigue en 1: es el enclavamiento). Destildá N_BAJO para pedir llenado: la bomba se enciende. Ejecutá 10 scans y el temporizador sube a 10; tildá N_ALTO y ejecutá un scan: LLENANDO cae y la bomba se detiene. Dejá la demanda de llenado sin llegar al nivel alto y ejecutá 30 scans: la falla se enclava y la bomba se detiene un scan después. Para borrarla, destildá STOP_OK, ejecutá un scan y volvé a tildarlo.

11 · Código ejecutable

Simular el proceso en Python

El mismo programa de cinco líneas, escrito como una clase con un método scan(), y el tanque simulado con enteros. Permite probar escenarios y comprobar que los números coinciden con los del sketch y los de los laboratorios.

Probalo en el navegador. Python se descarga con Pyodide la primera vez y requiere conexión. El código es editable y no controla ningún equipo.

DT = 0.1                                   # s por ciclo de scan
CENTI = 100                                # el nivel se guarda en centésimas de por ciento (enteros)

class Programa:
    """Programa de la estación de bombeo: se ejecuta una vez por scan, de arriba hacia abajo."""
    def __init__(self, t_max_s=30.0):
        self.hab = self.llenando = self.falla = False
        self.temporizador = 0                  # scans con la bomba encendida
        self.t_max = round(t_max_s / DT)
        self.bomba = False

    def scan(self, start, stop_ok, n_bajo, n_alto, term_ok):
        # 1) Habilitación con enclavamiento (los pulsadores son momentáneos)
        self.hab = (start or self.hab) and stop_ok and term_ok and not self.falla
        # 2) Llenado con histéresis: arranca al faltar nivel bajo, se corta al llegar al alto
        self.llenando = ((not n_bajo) or self.llenando) and not n_alto
        # 3) Salida a la bomba
        self.bomba = self.hab and self.llenando
        # 4) Temporizador de marcha (TON): cuenta mientras la bomba está encendida
        self.temporizador = self.temporizador + 1 if self.bomba else 0
        # 5) Falla enclavada: la bomba corrió demasiado sin llegar al nivel alto; se borra con STOP
        self.falla = (self.temporizador >= self.t_max or self.falla) and stop_ok
        return self.bomba

def simular(consumo=1.0, caudal=4.0, bajo=20.0, alto=80.0, t_max=30.0, nivel0=50.0, paro=None, duracion=240.0, t_start=1.0):
    prog = Programa(t_max)
    nivel = round(nivel0 * CENTI)
    consumo_c, caudal_c = round(consumo * CENTI * DT), round(caudal * CENTI * DT)
    umbral_bajo, umbral_alto = round(bajo * CENTI), round(alto * CENTI)
    eventos, ciclos, encendidos, bomba_prev, falla_prev = [], 0, 0, False, False
    serie = []
    for k in range(round(duracion / DT)):
        t = k * DT
        start = t_start <= t < t_start + 0.5 or (paro is not None and paro[1] <= t < paro[1] + 0.5)
        stop_ok = not (paro is not None and paro[0] <= t < paro[0] + 0.5)
        prog.scan(start, stop_ok, nivel >= umbral_bajo, nivel >= umbral_alto, True)
        nivel = max(0, min(10000, nivel + (caudal_c if prog.bomba else 0) - consumo_c))
        if prog.bomba and not bomba_prev:
            ciclos += 1; eventos.append((round(t, 1), "arranca la bomba", nivel / CENTI))
        if (not prog.bomba) and bomba_prev:
            eventos.append((round(t, 1), "se detiene la bomba", nivel / CENTI))
        if prog.falla and not falla_prev:
            eventos.append((round(t, 1), "FALLA enclavada", nivel / CENTI))
        encendidos += 1 if prog.bomba else 0
        bomba_prev, falla_prev = prog.bomba, prog.falla
        serie.append((t, nivel / CENTI, prog.bomba))
    return {"eventos": eventos, "ciclos": ciclos, "ciclo_util": encendidos / len(serie) * 100, "nivel_final": serie[-1][1], "falla": prog.falla, "serie": serie}

def informe(titulo, **kw):
    r = simular(**kw)
    print(f"{titulo}: arranques={r['ciclos']}; bomba encendida {r['ciclo_util']:.1f} % del tiempo; nivel final {r['nivel_final']:.1f} %; falla={r['falla']}")
    for t, texto, nivel in r["eventos"][:6]:
        print(f"   t={t:6.1f} s: {texto} (nivel {nivel:5.1f} %)")

informe("Funcionamiento normal (consumo 1 %/s)")
informe("Consumo de 2 %/s", consumo=2.0)
informe("Fuga (consumo 5 %/s, mas que el caudal)", consumo=5.0)
informe("STOP a los 100 s y nuevo START a los 130 s", paro=(100.0, 130.0))

En funcionamiento normal: 3 arranques, la bomba encendida el 25,1 % del tiempo y ningún evento de falla. Con 2 %/s de consumo el llenado tarda 30 s, igual que el tiempo máximo, y el programa enclava una falla a los 45,0 s (nivel 79,8 %) sin avería. Con 5 %/s de consumo, la falla llega a los 36,0 s. Con un STOP a los 100 s y un nuevo START a los 130 s, la bomba no arranca hasta los 130,0 s, con el tanque en 0,7 %.

Probá t_max_s=45 con el consumo de 2 %/s y mirá que la falsa alarma desaparece. Cambiá bajo y alto para ver el efecto en el número de arranques. Un buen ejercicio: agregar un estado de «bomba en descanso» que impida más de un arranque por minuto (un temporizador TOF).

12 · Método y diagnóstico

Pruebas y diagnóstico

  1. Escribí una tabla de entradas y salidas con el significado físico de cada bit y el estado en reposo.
  2. Probá la lógica sin energía de potencia: cambiá las entradas a mano (o con una simulación) y verificá las salidas contra una tabla de resultados esperados.
  3. Probá cada estado límite: nivel justo en el umbral, STOP durante la marcha, corte y vuelta de la alimentación.
  4. Cortá un cable de STOP o de un sensor y verificá que el sistema queda en estado seguro.
  5. Forzá la falla (bloqueando el nivel alto) y comprobá que se enclava, que se informa y que solo se borra con STOP.
  6. Medí el tiempo de scan real y comprobalo contra la duración mínima de los pulsos de entrada.
  7. Registrá los eventos con su hora: la mayoría de los problemas de una máquina se entienden mirando la secuencia.
«Un pulsador de parada NA es lo mismo, solo cambia el cableado»

No: con un NA, un cable cortado hace imposible parar la máquina. El NC convierte esa falla en una parada. Es una decisión de seguridad, no de comodidad.

«La parada de emergencia puede ser una entrada del programa»

La emergencia debe cortar la potencia por un circuito independiente del software. El programa puede leerla, pero no depender de él para ejecutarla.

«Con un solo sensor de nivel alcanza»

Con un solo umbral la bomba arranca y para continuamente cerca del límite. Dos sensores (histéresis) dan ciclos limpios y menos desgaste.

«El tiempo máximo de marcha lo pongo de 30 s porque el llenado es de 20»

Con poco margen, un consumo algo mayor dispara la protección en falso. Elegí un valor claramente superior al llenado normal (digamos 1,5 veces) pero inferior al que causaría daño.

«Si cambio el orden de las líneas, no pasa nada»

Cambia el momento en que se ven los valores nuevos: una línea que usa una memoria ya actualizada reacciona en el mismo scan; si va antes, un scan después.

«Tras un corte de luz, que siga donde estaba»

Arrancar solo sin que nadie lo ordene es peligroso. Lo normal es volver a un estado apagado y esperar un START explícito. Los casos en que se decide lo contrario se diseñan con cuidado.

13 · Práctica guiada

Predecí antes de comprobar

1. Lógica combinacional

Si BOMBA = HAB ∧ LLENANDO, ¿cuál es la salida para las cuatro combinaciones de HAB y LLENANDO?

Ver solución

Solo es 1 cuando ambas valen 1. Con HAB = 0 la bomba está apagada aunque haga falta llenar; con LLENANDO = 0, apagada aunque esté habilitada.

2. Enclavamiento

START dura 0,5 s y el scan es de 100 ms. Con STOP_OK, TERM_OK en 1 y sin falla, ¿en qué valor queda HAB cuando se suelta START? ¿Y tras presionar STOP?

Ver solución

HAB se pone en 1 en el primer scan con START y se mantiene gracias a su propio contacto: sigue en 1 al soltarlo. Al presionar STOP, STOP_OK = 0 y HAB cae a 0; queda en 0 aunque se suelte STOP, hasta un nuevo START.

3. Orden de las líneas

Si la línea 3 (BOMBA) se escribiera antes de la línea 1 (HAB), ¿cuántos scans tardaría en encenderse la bomba después de START, y cuánto sería con un scan de 100 ms?

Ver solución

La bomba usaría el HAB del scan anterior: un scan de retraso, 100 ms. Con un scan de 1 s serían 1 s. En el orden correcto, la bomba se enciende en el mismo scan.

4. Tiempo máximo

El consumo es de 2 %/s, la bomba entrega 4 %/s y los sensores están en 20 % y 80 %. ¿Cuánto tarda un llenado normal y qué tiempo máximo elegirías con 50 % de margen?

Ver solución

Caudal neto 2 %/s; 60 % de recorrido: 60/2 = 30 s. Con 50 % de margen: 45 s. Con 30 s, la protección dispara en cada llenado.

5. Fallo seguro

¿Por qué el pulsador de parada y el relé térmico se leen como «1 = circuito cerrado»?

Ver solución

Si un cable se corta o un contacto se afloja, la entrada pasa a 0 y el programa lo interpreta como parada o sobrecarga: la falla lleva a un estado seguro. Con la lógica inversa, la misma falla dejaría la máquina sin protección.

6. Pulsos y scan

Un sensor entrega un pulso de 20 ms y el scan es de 100 ms. ¿Qué riesgo hay y cómo se resuelve?

Ver solución

El pulso puede ocurrir entre dos lecturas y perderse. Se resuelve con un scan más corto (menos de la mitad de la duración del pulso), con un latch de hardware o con una interrupción que registre el evento.

7. ¿PLC o Arduino?

Una línea de envasado con 50 salidas de 24 V a electroválvulas, 10 años de servicio y personal de mantenimiento propio; y un prototipo de laboratorio con 6 señales de 5 V. ¿Qué elegís en cada caso?

Ver solución

Línea de envasado: un PLC (E/S industriales aisladas, robustez, diagnóstico estándar, soporte). Prototipo: un microcontrolador (bajo costo, flexibilidad, señales compatibles). En ambos conviene el mismo estilo de programa: ciclo de scan y lógica de arriba hacia abajo.

14 · Síntesis

Ideas para recordar

  • Automatizar es delegar en un sistema la ejecución repetible de un proceso; no todo conviene automatizarlo.
  • El controlador ve el mundo por sus entradas (discretas o analógicas) y actúa por sus salidas; el programa trabaja con bits cuyo significado se define en el diseño.
  • La lógica combinacional no tiene memoria; la secuencial sí: enclavamientos, set–reset con histéresis, temporizadores, contadores y flancos.
  • Un controlador ejecuta ciclos de scan: leer entradas, ejecutar la lógica de arriba abajo, escribir salidas. El orden de las líneas importa y los pulsos cortos pueden perderse.
  • Se diseña para fallar bien: parada y térmico NC, emergencia cableada e independiente, arranque solo con orden explícita, fallas enclavadas y límites de tiempo con margen razonable.
  • Un PLC aporta robustez industrial, E/S aisladas, estándares y soporte; un microcontrolador, bajo costo y flexibilidad, y exige interfaces y responsabilidad propia.
  • Se puede programar un Arduino con mentalidad de PLC: imagen de entradas, lógica secuencial y salidas al final.
  • Un tiempo máximo de protección mal elegido produce falsas alarmas; se calcula con el proceso normal y se deja margen.

¿Listo para el tema 36?

Antes de avanzar, elegí un proceso cotidiano (un portón, un riego, un lavarropas) y escribí su tabla de entradas y salidas, con el significado de cada bit y su estado de seguridad. Identificá qué partes son lógica combinacional y cuáles necesitan memoria o un temporizador.

En el próximo tema estudiamos las máquinas de estados finitos: estados, eventos, transiciones y diagramas, la herramienta natural para procesos con secuencias.