¿Por qué usar protocolos Modbus en automatización industrial con Raspberry Pi?
Modbus es un protocolo de comunicación maestro-esclavo utilizado a nivel mundial con PLCs (Controladores Lógicos Programables). El protocolo Modbus emplea líneas de comunicación serial por caracteres o Ethernet como capa de transporte. Admite comunicación desde y hacia múltiples dispositivos conectados al mismo cable o red Ethernet. El PLC Raspberry PI admite Modbus RTU (Unidad Terminal Remota) a través de RS-485 y Modbus TCP vía Ethernet.
En este post, exploraremos cómo utilizar los protocolos de comunicación Modbus RTU y TCP con un Raspberry Pi PLC empleando Python 3 y Node-RED.
Requisitos previos: Configuración del entorno para tu PLC Industrial Shields
Para poder seguir estos ejemplos, puede que necesites información adicional enlazada en estos posts:
Cómo trabajar con RS485 con un Raspberry PLC
Implementación de Modbus RTU (Serie) en Raspberry Pi
El siguiente ejemplo muestra cómo se realiza la comunicación maestro/esclavo utilizando la librería pyModbus . Para probarlo necesitarás dos Raspberry Pi PLC: uno actuará como maestro y el otro como esclavo.
Para implementar el esclavo, programa el siguiente código en un Raspberry Pi PLC:
from pymodbus.server import StartSerialServer
from pymodbus.transaction import ModbusRtuFramer
from pymodbus.datastore import (
ModbusServerContext,
ModbusSequentialDataBlock,
ModbusSlaveContext
)
# Define a simple data block with 10 registers
store = ModbusSlaveContext(
di = ModbusSequentialDataBlock(0, [0x0]*10000),
co = ModbusSequentialDataBlock(0, [0x0]*10000),
hr = ModbusSequentialDataBlock(0, [0x0]*10000),
ir = ModbusSequentialDataBlock(0, [0x0]*10000))
context = ModbusServerContext(slaves=store, single=True)
# Start the Modbus RTU server on a serial port
# In this case using ’/dev/ttySC0’ port from Raspberry PLC 21
StartSerialServer(context=context,
port=’/dev/ttySC0’,
framer=ModbusRtuFramer,
baudrate=9600
)
Por otro lado, programa el siguiente código en el otro Raspberry Pi PLC para implementar el maestro:
from pymodbus.client import ModbusSerialClient
from pymodbus.transaction import ModbusRtuFramer
# Create a Modbus RTU client
client = ModbusSerialClient(method=’rtu’,
port=’/dev/ttySC0’,
baudrate=9600,
framer=ModbusRtuFramer)
# Connect to the Modbus RTU slave
client.connect()
# Define the slave address
slave_address = 0x00
# Write to holding registers
register_address = 0
num_registers = 5
data_to_write = [10, 20, 30, 40, 50]
response = client.write_registers(register_address,
data_to_write,
unit=slave_address)
if not response.isError():
print("Write successful")
else:
print("Error writing registers:", response)
# Read 5 holding registers starting from address 0
response = client.read_holding_registers(register_address,
num_registers,
unit=slave_address)
if not response.isError():
print("Read successful:", response.registers)
else:
print("Error reading registers:", response)
# Close the connection
client.close()
Antes de ejecutar ambos códigos, asegúrate de que los PLC estén alimentados correctamente y conectados vía puertos RS485 (A+ con A+ y B- con B-). Ten en cuenta que en el código de ejemplo se usan los puertos ttySC0 en ambos dispositivos.
Esta implementación es un ejemplo simple para probar la escritura y lectura de algunos registros desde el maestro hacia el esclavo. Si la comunicación funciona correctamente, deberías ver este resultado:
Write successful
Read successful: [10, 20, 30, 40, 50]
Integración de Modbus TCP en Dashboards con Node-RED
Este programa utiliza Node-RED para implementar un maestro Modbus RTU y emplea el código en Python anterior como esclavo.
Para probar el ejemplo, sigue estos pasos:
- Instala el nodo node-red-contrib-modbus . Verás los nodos de Modbus a la izquierda.
- Para implementar el maestro, coloca los nodos y conéctalos como en la siguiente figura (no incluida en el texto).

- Configura el nodo "Inject" para enviar datos cada 5 segundos y escribe este código en el nodo "Function":
if (context.hasOwnProperty('num')) {
context.num = context.num + 1;
} else {
context.num = 0;
}
msg.payload = context.num;
return msg;
- En el nodo "Modbus Write":
- Configura el "Server": "Type: Serial", "Serial port: /dev/ttySC0", "Serial type: RTU" y "Baud rate: 9600".
- Ajusta el FC (Function Code) a "FC 6: Preset Single Register" en la dirección 0.
- En el nodo "Modbus Read":
- Configura el "Server" igual que en el "Modbus Write".
- Ajusta el FC (Function Code) a "FC 3: Read Holding Registers" en la dirección 0, con una cantidad de 1 registro y una frecuencia de 5 segundos de sondeo (poll rate).
Este programa actuará como maestro y estará escribiendo y leyendo valores del registro 0 del esclavo. Como esclavo, puedes usar el código Python del ejemplo anterior.
Scripts en Python para comunicación Modbus TCP
Este es un programa para probar Modbus TCP usando la librería PyModbus. Tanto el código del maestro como del esclavo son muy similares al ejemplo de Modbus RTU con Python mostrado anteriormente, y el programa consiste en escribir y leer registros del maestro al esclavo.
Se necesitan dos Raspberry Pi PLC y tres cables Ethernet para ejecutar esta prueba. Cada PLC debe conectarse a un PC para poder cargar el código, y los PLC deben conectarse entre sí. Es importante tener en cuenta que, en el caso de los Raspberry Pi PLC, existen diferencias entre eth0 y eth1, por lo que es indispensable conectar ambos PLC a través del conector Ethernet superior (o realizar las conexiones Ethernet equivalentes con los cambios necesarios).
Este es el código del esclavo, que creará un servidor TCP en una dirección "IP_ADDRESS" y un puerto "PORT". Cámbialos según tu configuración de red:
from pymodbus.server import StartTcpServer
from pymodbus.datastore import (
ModbusServerContext,
ModbusSequentialDataBlock,
ModbusSlaveContext
)
# Define a simple data block with 10 registers
store = ModbusSlaveContext(
di = ModbusSequentialDataBlock(0, [0x0]*10000),
co = ModbusSequentialDataBlock(0, [0x0]*10000),
hr = ModbusSequentialDataBlock(0, [0x0]*10000),
ir = ModbusSequentialDataBlock(0, [0x0]*10000))
context = ModbusServerContext(slaves=store, single=True)
# Start the Modbus TCP server
# Change parameters to your host and port
StartTcpServer(context=context, address("IP_ADDRESS", PORT))
Por otro lado, este es el código del maestro, que escribirá y leerá algunos datos del esclavo. Antes de ejecutar el código, recuerda establecer el host y puerto según tu configuración de red:
from pymodbus.client import ModbusTcpClient
# Create a Modbus RTU client
# Change parameters to your host and port
client = ModbusTcpClient(host='IP_ADDRESS', port=PORT)
# Connect to the Modbus RTU slave
client.connect()
# Define the slave address
slave_address = 0x00
# Write to holding registers
register_address = 0
num_registers = 5
data_to_write = [10, 20, 30, 40, 50]
response = client.write_registers(register_address, data_to_write, unit=slave_address)
if not response.isError():
print("Write successful")
else:
print("Error writing registers:", response)
# Read 5 holding registers starting from address 0
response = client.read_holding_registers(register_address, num_registers, unit=slave_address)
if not response.isError():
print("Read successful:", response.registers)
else:
print("Error reading registers:", response)
# Close the connection
client.close()
Ejemplo de Modbus TCP con Node-RED
Para comunicarte con Modbus TCP usando Node-RED, puedes tomar el ejemplo anterior de RTU con Node-RED y modificar la configuración de los nodos "Modbus Write" y "Modbus Read" a TCP, con la dirección IP y el puerto correspondientes. Puedes usar el código del ejemplo de Modbus TCP con Python anterior como esclavo.

Guía Modbus TCP y RTU para PLCs Raspberry Pi: ejemplos con Python y Node-RED