Ir al contenido

Modbus TCP y RTU con PLCs Raspberry Pi: ejemplos en Python y Node-RED

Guía práctica para implementar Modbus RTU y TCP en PLCs Raspberry Pi con Python (pymodbus 3.x) y Node-RED — con ejemplos funcionales para configuraciones de uno y dos dispositivos.
1 de junio de 2026 por
Modbus TCP y RTU con PLCs Raspberry Pi: ejemplos en Python y Node-RED
Joan F. Aubets - Industrial Shields

Modbus es un protocolo de comunicación maestro-esclavo utilizado en todo el mundo en la automatización industrial. Funciona sobre dos transportes: líneas serie (Modbus RTU, vía RS-485) y Ethernet (Modbus TCP). Ambos están soportados de forma nativa en los PLCs Raspberry Pi de Industrial Shields — RTU a través del puerto RS-485 y TCP a través de la interfaz Ethernet.

En esta guía encontrarás ejemplos funcionales en Python y Node-RED para ambos protocolos, probados en hardware PLC Raspberry Pi con pymodbus 3.x.

Nota sobre versiones de pymodbus: pymodbus 3.x introdujo cambios de API incompatibles con la versión 2.x. Todos los ejemplos de esta guía utilizan la API actual de la versión 3.x. Si tienes una instalación más antigua, ejecuta pip install --upgrade pymodbus antes de continuar.

Requisitos previos

Antes de ejecutar estos ejemplos, asegúrate de tener lo siguiente configurado:

Instala pymodbus si aún no está disponible:

pip install pymodbus

Modbus RTU con Python

Esclavo (servidor)

Ejecuta este código en el Raspberry Pi PLC que actuará como esclavo. Inicia un servidor Modbus RTU en el puerto RS-485.

Modbus RTU con Python

from pymodbus.server import StartSerialServer
from pymodbus.framer import FramerType
from pymodbus.datastore import (
    ModbusServerContext,
    ModbusSequentialDataBlock,
    ModbusSlaveContext
)

store = ModbusSlaveContext(
    di=ModbusSequentialDataBlock(0, [0] * 10000),
    co=ModbusSequentialDataBlock(0, [0] * 10000),
    hr=ModbusSequentialDataBlock(0, [0] * 10000),
    ir=ModbusSequentialDataBlock(0, [0] * 10000)
)
context = ModbusServerContext(slaves=store, single=True)

StartSerialServer(
    context=context,
    port='/dev/ttySC0',       # RS-485 port on Raspberry PLC 21. Use /dev/ttySC2 for other models.
    framer=FramerType.RTU,
    baudrate=9600
)

Maestro (cliente)

Ejecuta este código en el segundo Raspberry Pi PLC. Se conecta al esclavo y lee y escribe registros holding.

from pymodbus.client import ModbusSerialClient
from pymodbus.framer import FramerType

client = ModbusSerialClient(
    port='/dev/ttySC0',
    framer=FramerType.RTU,
    baudrate=9600,
    timeout=3
)

if not client.connect():
    print("Connection failed. Check RS-485 wiring and port.")
    exit()

SLAVE_ID = 1
REGISTER_ADDRESS = 0
data_to_write = [10, 20, 30, 40, 50]

# Write registers
response = client.write_registers(REGISTER_ADDRESS, data_to_write, slave=SLAVE_ID)
if not response.isError():
    print("Write successful")
else:
    print("Write error:", response)

# Read registers
response = client.read_holding_registers(REGISTER_ADDRESS, count=5, slave=SLAVE_ID)
if not response.isError():
    print("Read successful:", response.registers)
else:
    print("Read error:", response)

client.close()

Cableado: Conecta RS-485 A+ con A+ y B- con B- entre las dos unidades. Ambos PLCs utilizan /dev/ttySC0 en este ejemplo.

Salida esperada cuando la comunicación funciona correctamente:

Write successful
Read successful: [10, 20, 30, 40, 50]

Modbus RTU con Node-RED

Este ejemplo utiliza Node-RED como maestro y el esclavo Python del apartado anterior como servidor.

  1. Instala el paquete node-red-contrib-modbus desde el gestor de paletas de Node-RED.
  2. Construye el siguiente flujo: Inject → Function → Modbus Write y Modbus Read → Debug
  3. Configura el nodo Function para incrementar un contador en cada activación:
if (context.hasOwnProperty('num')) {
    context.num = context.num + 1;
} else {
    context.num = 0;
}
msg.payload = context.num;
return msg;
  1. Configura el nodo Modbus Write:
    • Tipo de servidor: Serial
    • Puerto serie: /dev/ttySC0
    • Tipo serie: RTU
    • Velocidad en baudios: 9600
    • Código de función: FC 6: Preset Single Register
    • Dirección de registro: 0
  2. Configura el nodo Modbus Read con los mismos ajustes de servidor:
    • Código de función: FC 3: Read Holding Registers
    • Dirección: 0, Cantidad: 1
    • Intervalo de lectura: 5000 ms

El flujo escribirá y leerá el registro 0 cada 5 segundos. Utiliza el esclavo Python de la sección anterior como servidor.

Modbus TCP con Python

Prueba con un solo dispositivo

No necesitas dos PLCs Raspberry Pi para probar Modbus TCP. Puedes ejecutar tanto el esclavo como el maestro en la misma unidad usando localhost como dirección.

Abre dos sesiones de terminal en el mismo PLC. Ejecuta el esclavo en la primera y el maestro en la segunda.

Esclavo (servidor)

from pymodbus.server import StartTcpServer
from pymodbus.datastore import (
    ModbusServerContext,
    ModbusSequentialDataBlock,
    ModbusSlaveContext
)

store = ModbusSlaveContext(
    di=ModbusSequentialDataBlock(0, [0] * 10000),
    co=ModbusSequentialDataBlock(0, [0] * 10000),
    hr=ModbusSequentialDataBlock(0, [0] * 10000),
    ir=ModbusSequentialDataBlock(0, [0] * 10000)
)
context = ModbusServerContext(slaves=store, single=True)

# Listens on all interfaces, port 502
# For single-device testing, use address=("localhost", 502)
StartTcpServer(context=context, address=("0.0.0.0", 502))

Maestro (cliente)

from pymodbus.client import ModbusTcpClient

# Replace with the slave IP, or use "localhost" for single-device testing
client = ModbusTcpClient(host="192.168.1.100", port=502, timeout=3)

if not client.connect():
    print("Connection failed. Check IP address and network configuration.")
    exit()

SLAVE_ID = 1
REGISTER_ADDRESS = 0
data_to_write = [10, 20, 30, 40, 50]

# Write registers
response = client.write_registers(REGISTER_ADDRESS, data_to_write, slave=SLAVE_ID)
if not response.isError():
    print("Write successful")
else:
    print("Write error:", response)

# Read registers
response = client.read_holding_registers(REGISTER_ADDRESS, count=5, slave=SLAVE_ID)
if not response.isError():
    print("Read successful:", response.registers)
else:
    print("Read error:", response)

client.close()

Nota sobre los puertos Ethernet: Los PLCs Raspberry Pi tienen dos interfaces Ethernet (eth0 y eth1). Para conexiones entre dispositivos, utiliza el conector Ethernet superior en ambas unidades, o ajusta la configuración IP según tu cableado.

Modbus TCP con Python

Modbus TCP con Node-RED

Este flujo utiliza Node-RED como maestro TCP. Puedes usar el esclavo Python anterior como servidor.

  1. Instala node-red-contrib-modbus si aún no está instalado.
  2. Construye el mismo flujo que en el ejemplo RTU: Inject → Function → Modbus Write y Modbus Read → Debug
  3. Configura el nodo Modbus Write:
    • Tipo de servidor: TCP
    • Host: dirección IP del esclavo Modbus TCP (o localhost para pruebas en un solo dispositivo)
    • Puerto: 502
    • Código de función: FC 6: Preset Single Register
    • Dirección de registro: 0
  4. Configura el nodo Modbus Read con los mismos ajustes de servidor TCP:
    • Código de función: FC 3: Read Holding Registers
    • Dirección: 0, Cantidad: 1
    • Intervalo de lectura: 5000 ms

El flujo lee y escribe el registro 0 cada 5 segundos desde el esclavo TCP.

Gestión de errores y robustez de la conexión

En entornos de producción, las conexiones se pierden y los dispositivos se reinician. Los ejemplos anteriores incluyen un parámetro básico timeout y una comprobación explícita de la conexión. Para aplicaciones críticas, añade un bucle de reintento:

import time
from pymodbus.client import ModbusTcpClient

MAX_RETRIES = 5
RETRY_DELAY = 2  # seconds

client = ModbusTcpClient(host="192.168.1.100", port=502, timeout=3)

for attempt in range(MAX_RETRIES):
    if client.connect():
        print("Connected")
        break
    print(f"Connection attempt {attempt + 1} failed. Retrying in {RETRY_DELAY}s...")
    time.sleep(RETRY_DELAY)
else:
    print("Could not connect after maximum retries.")
    exit()

# ... your read/write logic ...

client.close()

Posts relacionados

Explora la gama completa de PLCs Raspberry Pi en industrialshields.com

Buscar en nuestro blog

Modbus TCP y RTU con PLCs Raspberry Pi: ejemplos en Python y Node-RED
Joan F. Aubets - Industrial Shields 1 de junio de 2026
Compartir esta publicación
Etiquetas

¿Estás buscando tu Controlador Lógico Programable ideal?

Echa un vistazo a esta comparativa de producto de varios controladores industriales basados en Arduino.

Comparamos entradas, salidas, comunicaciones y otras especificaciones con las de los equipos de otras marcas destacadas.

Comparativa de PLCs