Introducción al diagrama de funciones lógicas (FBD)

El diagrama de funciones lógicas (Function Block Diagram, FBD) es uno de los lenguajes gráficos definidos por la norma IEC 61131-3. Se basa en la interconexión de bloques funcionales (FBs) mediante líneas de señal, lo que permite representar sistemas de control complejos de forma modular y visual. Su origen se encuentra en los diagramas de circuitos electrónicos y de automática, y es especialmente útil para procesos con tratamiento de señales analógicas, regulación PID, lógica combinacional y secuencial.

A diferencia del Ladder, que simula un esquema eléctrico, FBD enfatiza el flujo de datos entre bloques. Cada bloque realiza una operación específica (temporización, conteo, comparación, operaciones aritméticas o lógicas) y puede ser reutilizado en múltiples partes del programa. Esta característica, junto con la claridad visual, hace de FBD una herramienta ideal para sistemas de automatización modulares y para el trabajo en equipo.

Ejemplo industrial: en una planta de tratamiento de aguas, un bloque funcional puede calcular el pH medio, otro comparar con un setpoint y un tercero activar una bomba de dosificación. La interconexión refleja directamente la estrategia de control.

Bloques funcionales (FBs): el corazón de FBD

Un bloque funcional es una unidad de software encapsulada que posee entradas, salidas y un algoritmo interno. Se representa gráficamente como un rectángulo con el nombre del bloque en la parte superior y los terminales de entrada a la izquierda y salida a la derecha. Los FBs pueden ser estándar (temporizadores, contadores, operadores aritméticos) o definidos por el usuario (DFB), creados para encapsular lógica repetitiva.

Ejemplo de bloque estándar: TON (Timer ON-Delay)

TON
IN Q
PT ET

Entradas: IN (activación), PT (tiempo preset). Salidas: Q (salida temporizada), ET (tiempo transcurrido). Internamente, cuando IN pasa a TRUE, el temporizador cuenta hasta alcanzar PT y entonces activa Q.

Ejemplo de bloque de usuario: un bloque ControlMotor que agrupe la lógica de arranque, paro, protección térmica y realimentación, con entradas Marcha, Paro, Sobrecalentamiento y salida Motor.

Entradas y salidas gráficas

Las entradas pueden ser variables físicas (sensores, pulsadores) o señales procedentes de otros bloques. Las salidas se conectan a actuadores o a entradas de bloques posteriores. Esta representación gráfica facilita la comprensión del flujo de información. Por ejemplo:

   Sensor_Nivel ---|    |
                    |TON |--- Temporizado ---| CTU |--- Bobina_Alarma
   Constante_5s ----|____|                    |_____|

Así, el valor de Sensor_Nivel y la constante 5s entran al temporizador; su salida se conecta al contador, y la salida de éste activa una alarma.

Conexiones lógicas y flujo de señales

Las líneas de conexión representan el flujo de datos (variables booleanas, enteras, reales, etc.). En FBD, a diferencia de Ladder, no hay concepto de "corriente", sino de transferencia de valores. Esto permite manejar tipos de datos complejos de forma natural. Las conexiones se dibujan como trazos orientativos; los entornos de programación suelen auto‑enrutarlas.

Consejo de nomenclatura: asigna nombres significativos a las señales (por ejemplo, Nivel_Alto, Tiempo_Estabilizacion) para mejorar la legibilidad y el mantenimiento.

Editor FBD en CODESYS V3.5 con cuatro bloques interconectados mediante líneas azules: bloque GE (comparador ≥) que compara Sensor_Temp con Temp_Max, bloque TON (timer on-delay, PT=T#5s) cuya entrada IN recibe la señal Marcha, bloque CTU (contador ascendente, PV=100) que cuenta ciclos de motor, y bloque AND de tres entradas que combina TON.Q, NOT GE.Q y Marcha para activar la bobina Motor_ON. La bobina Alarma_Temp se activa directamente desde GE.Q.
Figura 3: Red FBD (Function Block Diagram) en CODESYS V3.5 con cuatro bloques interconectados: ① GE (comparador ≥ de temperatura), ② TON (temporizador on-delay, PT:=T#5s), ③ CTU (contador ascendente de ciclos, PV:=100) y ④ AND (lógica de habilitación del motor). Las entradas proceden de variables de sensor (Sensor_Temp, Marcha); las salidas se conectan a bobinas Motor_ON y Alarma_Temp. Las líneas de conexión en azul representan el flujo de datos entre bloques. Fuente: Elaboración propia. Licencia: CC BY-NC 4.0

Modularidad y reutilización

Una de las grandes ventajas de FBD es la posibilidad de crear bloques funcionales propios (DFB). Una vez creado y probado un DFB (por ejemplo, un bloque que gestiona una válvula con temporizadores de seguridad), puede ser utilizado en distintos proyectos o múltiples veces dentro del mismo programa, simplemente arrastrando una nueva instancia. Esto reduce drásticamente el tiempo de desarrollo y los errores.

Datos técnicos: los DFB pueden tener variables internas (estado) que se conservan entre ciclos de scan, permitiendo implementar máquinas de estado, contadores, etc. La norma IEC 61131-3 establece la sintaxis tanto para FBD como para los DFB en lenguajes textuales (ST) que luego se empaquetan como bloques.

Ejemplo de reutilización: en una línea de envasado, cada estación de llenado utiliza el mismo DFB ControlLlenado con parámetros diferentes (tiempo de llenado, altura de sensor). Simplemente se instancia el bloque con distintos nombres y se conectan las entradas/salidas específicas.

Aplicación a procesos secuenciales y sistemas complejos

Los procesos secuenciales (una sucesión de pasos que se activan bajo condiciones) se modelan fácilmente en FBD mediante la interconexión de bloques que representan etapas, temporizadores y condiciones. A menudo se combina con SFC (Sequential Function Chart), pero dentro de un mismo bloque FBD se pueden implementar máquinas de estado.

Ejemplo paso a paso: sistema de dos tanques

  1. Sensor de nivel bajo en tanque 1 (X0) activa el bloque TON1 (retardo 2s para evitar oscilaciones).
  2. Salida de TON1 conectada a la entrada de un biestable SR (bloque SR) que pone en marcha la bomba.
  3. La bomba llena el tanque 2; un sensor de nivel alto (X1) resetea el biestable y detiene la bomba.
  4. Todo ello se representa con tres bloques y dos conexiones, mucho más compacto que en Ladder.

Además, gracias a la modularidad, podemos agrupar toda la lógica de un tanque en un DFB y replicarlo para varios tanques.

🐍 Implementación de un bloque funcional TON en Python (clase reutilizable)
# fb_timer.py - Clase para simular un temporizador TON (IEC 61131-3)
# Se puede probar en Thonny y luego integrar en un bucle de control en Raspberry Pi
import time

class TON:
    """
    Bloque funcional TON: retardo a la conexión.
    - IN: bool  (entrada)
    - PT: float (tiempo preset en segundos)
    - Q: bool   (salida, True después del retardo)
    - ET: float (tiempo transcurrido desde flanco de IN)
    """
    def __init__(self, PT):
        self.PT = PT                # tiempo preset (s)
        self.IN_prev = False        # estado anterior de IN
        self.start_time = None       # momento de activación
        self.Q = False
        self.ET = 0.0

    def evaluate(self, IN):
        """Llámese a este método en cada ciclo de scan con el valor actual de IN."""
        # Detectar flanco de subida
        if IN and not self.IN_prev:
            self.start_time = time.time()
            self.ET = 0.0
        # Si IN sigue activo, actualizar ET y Q
        if IN:
            if self.start_time is not None:
                self.ET = time.time() - self.start_time
                if self.ET >= self.PT:
                    self.Q = True
                else:
                    self.Q = False
        else:
            # IN falso: resetear
            self.Q = False
            self.ET = 0.0
            self.start_time = None

        self.IN_prev = IN
        return self.Q, self.ET

# Ejemplo de uso: simular un ciclo con retardo de 2 segundos
if __name__ == "__main__":
    import time
    timer = TON(2.0)   # PT = 2 segundos
    # Simulamos entrada que se activa durante 3 segundos
    for segundo in range(5):
        IN = (segundo >= 1 and segundo <= 3)   # activo en t=1,2,3
        q, et = timer.evaluate(IN)
        print(f"t={segundo}: IN={IN}, Q={q}, ET={et:.2f}")
        time.sleep(1)   # simula tiempo real
    # Salida esperada: Q se activa en t=3 (cuando ET>=2)

Esta clase TON puede instanciarse múltiples veces, imitando la reutilización de los FBs en FBD. Se puede probar en Thonny y después usar en un bucle de control sobre Raspberry Pi leyendo GPIO como entradas y actuando sobre salidas.

Tendencias Actuales 2026

La edición 4 de la IEC 61131-3 (prevista para 2026) introduce mejoras en FBD para el manejo de tipos de datos compuestos y bloques de comunicación en red (OPC UA, MQTT) directamente integrados. Además, los entornos de desarrollo incorporan asistentes IA que sugieren conexiones entre bloques basándose en bibliotecas estándar, acelerando el diseño. En el ámbito industrial, FBD es el lenguaje preferido para regulación continua (PID, control difuso) y para librerías de ciberseguridad en PLC.

Aplicaciones con Raspberry Pi

Podemos implementar un entorno FBD ligero en Python sobre Raspberry Pi. Por ejemplo, definir clases para los bloques estándar (TON, CTU, AND, OR, PID) y luego conectarlos en un script principal que se ejecuta cíclicamente. Las entradas se leen de GPIO y las salidas se escriben. Además, existen proyectos como OpenPLC que soportan FBD y pueden ejecutarse en Raspberry Pi, permitiendo cargar programas creados en CODESYS o en su propio editor.

Aplicaciones con Arduino

Con el Arduino PLC IDE es posible programar en FBD sobre placas como Arduino Opta, Portenta y otros. Los bloques funcionales se arrastran y conectan gráficamente, y el IDE genera el código C++ subyacente. También hay librerías como Arduino_FBD que permiten construir diagramas de bloques en código, aunque la experiencia gráfica es limitada.

💼 Caso Práctico Industrial

Contexto: En una celda de pintura, se utiliza un bloque funcional TON (temporizador a la conexión) y un contador CTU. El temporizador recibe la señal de un sensor de presencia (X0) y tiene un PT de 10 segundos. La salida del temporizador (Q) se conecta a la entrada de conteo (CU) del CTU. El contador tiene un valor preset de 5 (PV). Cuando el contador alcanza 5, su salida (Q) enciende una lámpara (Y0).

Pregunta: ¿Cuánto tiempo debe permanecer el sensor activado para que la lámpara se encienda (considerando que se reinicia cada vez que el sensor se desactiva)?

🍓 Raspberry Pi + Python

Contexto: Se ha creado una clase Python CTU que simula un contador ascendente. Su método evaluate(CU, RESET) incrementa cuando detecta un flanco de subida en CU, y devuelve el valor actual y la salida Q (activa cuando CV >= PV). Se usa en un bucle que cada 0.1s lee un GPIO (entrada) y llama a evaluate.

ctu = CTU(PV=3)
while True:
    pulso = GPIO.input(17)
    ctu.evaluate(pulso, False)
    if ctu.Q:
        GPIO.output(27, True)

Pregunta: Si se dan 3 pulsos en el GPIO17, ¿cuándo se pondrá a TRUE la salida GPIO27?

🐍 Lógica de bloques

Contexto: Se tienen dos bloques funcionales: un biestable SR (entradas S y R, salida Q1) y una puerta AND (entradas A y B, salida Q2). Las conexiones son: A = Q1, B = X0 (variable externa). La salida AND se realimenta a la entrada S del SR. La entrada R del SR es X1. Inicialmente Q1 = False.

Pregunta: ¿Qué valor debe tener X0 para que cuando se active X1 (R=True) el SR pueda volver a ponerse a TRUE después de que X1 desaparezca?

Tabla 1: Comparativa de lenguajes IEC 61131-3
CaracterísticaLadder (LD)FBDST (texto)
ParadigmaEléctrico (contactos/bobinas)Flujo de datos (bloques)Alto nivel, estructurado
Mejor paraLógica discreta, enclavamientosProcesamiento de señales, PID, matemáticasAlgoritmos complejos, manejo de arrays
ReutilizaciónSubrutinas, pero poco modularDFB (bloques de usuario) muy modularesFunciones y bloques
Curva de aprendizajeBaja (para electricistas)Media (concepto de flujo de datos)Alta (similar a Pascal)

📚 Recursos Técnicos y Normativos 2026

Normativas y Estándares

Recursos Raspberry Pi y Python