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)
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.
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
- Sensor de nivel bajo en tanque 1 (X0) activa el bloque
TON1(retardo 2s para evitar oscilaciones). - Salida de
TON1conectada a la entrada de un biestable SR (bloqueSR) que pone en marcha la bomba. - La bomba llena el tanque 2; un sensor de nivel alto (X1) resetea el biestable y detiene la bomba.
- 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.
# 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.
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.
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.
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.
- ✅ Comprender activamente cada línea de código generada
- ✅ Personalizar la solución según tus necesidades específicas
- ✅ Iterar y refinar el código hasta dominar la lógica
- ✅ Desarrollar habilidades de comunicación técnica con IA
📋 Instrucciones de Uso:
- Copia el prompt completo del recuadro superior.
- Personaliza los campos entre corchetes [CAMPO] con tu información específica.
- Pega el prompt en una nueva conversación con tu IA favorita.
- Itera y refina: Pide aclaraciones, modificaciones o añade requisitos adicionales.
- Prueba el código en Thonny primero, luego en tu Raspberry Pi y ajusta según resultados.
💼 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?
| Característica | Ladder (LD) | FBD | ST (texto) |
|---|---|---|---|
| Paradigma | Eléctrico (contactos/bobinas) | Flujo de datos (bloques) | Alto nivel, estructurado |
| Mejor para | Lógica discreta, enclavamientos | Procesamiento de señales, PID, matemáticas | Algoritmos complejos, manejo de arrays |
| Reutilización | Subrutinas, pero poco modular | DFB (bloques de usuario) muy modulares | Funciones y bloques |
| Curva de aprendizaje | Baja (para electricistas) | Media (concepto de flujo de datos) | Alta (similar a Pascal) |
📚 Recursos Técnicos y Normativos 2026
Normativas y Estándares
- IEC 61131-3:2013 + enmiendas 2025 - Programmable controllers — Part 3: Programming languages
- PLCopen - Base de conocimiento y librerías de bloques