Cómo utilizar PyModbus con Raspberry Pi PLC

Cómo comunicarse a través de Modbus utilizando un PLC RPI y PyModbus library
25 de septiembre de 2023 por
Cómo utilizar PyModbus con Raspberry Pi PLC
Boot & Work Corp. S.L., Ricard Franch Argullol

¿Qué es la comunicación Modbus?

La comunicación Modbus juega un papel crucial en la automatización industrial, permitiendo a los dispositivos intercambiar datos sin problemas. En esta entrada del blog, vamos a explorar cómo implementar la comunicación Modbus utilizando la biblioteca pymodbus en nuestros PLCs Raspberry Pi. Vamos a cubrir ambos enfoques síncronos y asíncronos para escribir alternando valores Verdadero/Falso a una bobina en un dispositivo esclavo y leer el estado de la bobina.

¿Cómo instalar PyModbus library?

Raspberry Pi PLC

PyModbus install

 PyModbus library puede instalarse con el comando "pip install pymodbus". Además, puede ser beneficioso configurar un entorno virtual Python (venv).

Modbus comunicación: modbus síncrono vs asíncrono

El objetivo del código "synchronous master" es demostrar cómo establecer un enlace de comunicación Modbus como maestro utilizando la librería Pymodbus. Se centra en escribir valores alternos Verdadero/Falso en la primera bobina del esclavo, y lo lee para asegurarse de que el valor es alterno.

En cuanto al código "the asynchronous slave"  es para demostrar cómo configurar un servidor Modbus slave, utilizando la librería PyModbus. Incluye la creación de entradas discretas, bobinas, registros de retención, y los registros de entrada, que se puede acceder por Modbus master.

¿Cuál es la diferencia entre el enfoque asíncrono y el síncrono?

Cuando se trata de implementar la comunicación Modbus utilizando la librería PyModbus en tu Raspberry PLC, te encontrarás con dos enfoques diferentes para estructurar tu programa: síncrono y asíncrono. Cada enfoque tiene su propio conjunto de ventajas y consideraciones. Y la comprensión de las diferencias entre ellos, te permitirá tomar decisiones informadas basadas en los requisitos de tu proyecto.

Comunicación Modbus Sincrónica: Comprendiendo el flujo de ejecución lineal con PyModbus

La comunicación síncrona implica un flujo de ejecución lineal y directo. Cada tarea se completa antes de pasar a la siguiente, lo que facilita su seguimiento y comprensión. En el contexto de nuestro ejemplo de comunicación Modbus, el código síncrono permite escribir y leer valores de bobina secuencialmente, sin necesidad de gestionar complejos bucles de eventos o contextos asíncronos.

Ventajas de la comunicación síncrona::
  • Simplicidad y Legibilidad: El código síncrono tiende a ser más fácil de leer y entender, lo que lo convierte en un punto de partida ideal para aquellos nuevos en la programación.
  • Tiempo predecible: La comunicación síncrona ofrece un tiempo y secuenciación de operaciones más predecibles, lo cual puede ser ventajoso para aplicaciones que requieren una coordinación precisa.
  • Menos desafíos de concurrencia: El código síncrono simplifica la gestión de la concurrencia, reduciendo el potencial para condiciones de carrera y bugs relacionados.
  • Depuración más fácil: Depurar código síncrono suele ser más simple debido a su flujo de ejecución lineal, ayudando a identificar y resolver problemas de manera eficiente.

Sin embargo, aunque el enfoque síncrono proporciona simplicidad y facilidad de comprensión, es importante ser consciente de sus limitaciones de rendimiento, especialmente en escenarios con aplicaciones de alta demanda o sensibles al tiempo. Los clientes síncronos no son inherentemente seguros, y no se recomienda utilizar un único cliente desde múltiples hilos, debido a los conflictos que surgen de la naturaleza del protocolo Modbus. Aunque es posible (con mecanismos de bloqueo adecuados) es más fácil implementar programas complejos siguiendo el paradigma asíncrono.


¿Qué es la comunicación asíncrona?

La comunicación asíncrona, por otro lado, abraza el paralelismo y la capacidad de respuesta, ofreciendo una herramienta poderosa para escenarios donde tu programa está fuertemente limitado por E/S, como en el caso de la comunicación Modbus. Este enfoque permite que las tareas se ejecuten de manera concurrente. Llevando a una utilización más eficiente de los recursos del sistema y una mayor capacidad de respuesta a eventos externos. Este nivel de eficiencia puede ser particularmente ventajoso al trabajar con tareas intensivas en E/S como Modbus, ya que asegura que los recursos del sistema se utilicen al máximo, resultando en un rendimiento optimizado.

Ventajas de la comunicación asíncrona
  • Mejor respuesta: La comunicación asíncrona permite que tu aplicación responda prontamente a eventos externos, haciéndola adecuada para escenarios en tiempo real o interactivos.
  • Eficiencia de Recursos: El código asíncrono puede utilizar los recursos del sistema más eficientemente al permitir que las tareas se ejecuten de manera concurrente, mejorando potencialmente el rendimiento general del sistema.
  • Concurrencia: La comunicación asíncrona soporta múltiples tareas ejecutándose de manera concurrente, haciéndola bien adecuada para aplicaciones con altos niveles de paralelismo.
  • Escalabilidad: La programación asíncrona puede proporcionar una mejor escalabilidad para aplicaciones que necesitan manejar un gran número de clientes o tareas simultáneamente.

¿Cómo configurar un servidor Modbus síncrono con PyModbus en Raspberry Pi?

Echemos un vistazo rápido a un programa básico de servidor (esclavo) que adopta el enfoque síncrono, utilizando la librería PyModbus

El script comienza importando las librerías necesarias. Luego, tiene lugar la configuración del servidor y la configuración del contexto: Se crean bloques de datos (entradas discretas, bobinas, registros de retención, registros de entrada) así como el contexto esclavo Modbus. A este esclavo se le asigna la dirección 0x01. A continuación, el servidor se configura adecuadamente y se inicia. Se pueden utilizar ModbusTCP (TCP) y ModbusRTU (serial). Finalmente, en la ejecución principal, el servidor se inicia utilizando la función run_sync_server.

Ten en cuenta que este script proporciona una configuración básica para un servidor Modbus, y podrías necesitar modificarlo de acuerdo a tus requisitos específicos.

#!/usr/bin/env python3
import logging
logging.basicConfig()
_logger = logging.getLogger(__file__)
_logger.setLevel("INFO")
# Enable pymodbus information
from pymodbus import pymodbus_apply_logging_config
pymodbus_apply_logging_config("INFO")

# --------------------------------------------------------------------------- #
# import the various client implementations
# --------------------------------------------------------------------------- #
from pymodbus.server import (
StartSerialServer,
StartTcpServer,
)

from pymodbus.transaction import ModbusRtuFramer, ModbusSocketFramer
from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSlaveContext, ModbusServerContext

def run_sync_server(server_type="tcp", ip="127.0.0.1", port=5020):
# Create 10 discrete inputs, 10 coils, 10 holding registers and 10 input registers at slave address 0x01
di = ModbusSequentialDataBlock(0, [0]*10)
co = ModbusSequentialDataBlock(0, [0]*10)
hr = ModbusSequentialDataBlock(0, [0]*10)
ir = ModbusSequentialDataBlock(0, [0]*10)
context = { 0x01: ModbusSlaveContext(di=di, co=co, hr=hr, ir=ir) }
context = ModbusServerContext(slaves=context, single=False)
try:
if server_type == "tcp":
_logger.info(f"Starting synchronous server, listening on {ip} - {port}")
StartTcpServer(
context = context, # Data storage
# identity = identity, # server identify
address = (ip, port), # listen address
# custom_functions=[], # allow custom handling
framer = ModbusSocketFramer, # The framer strategy to use
# broadcast_enable = True, # treat slave_id 0 as broadcast address,
# timeout=1, # waiting time for request to complete
)
elif server_type == "serial":
_logger.info( f"Starting synchronous server, using serial {port}")
StartSerialServer(
context = context,
# identity = identity, # server identify
framer = ModbusRtuFramer,
port = port,
baudrate = 38400,
bytesize = 8,
parity = 'N',
stopbits = 1,
timeout = 10,
)
_logger.info("Stopped server")
else:
_logger.error(f"Invalid server type selected ({server_type}), cannot start pymodbus server")
return
except KeyboardInterrupt:
print()

if __name__ == "__main__":
run_sync_server("tcp", "localhost", 5020)
# run_sync_server("serial", port="/dev/ttySC0")

¿Cómo crear un cliente Modbus asíncrono?

En el ejemplo del programa cliente (maestro), se adopta un enfoque asíncrono utilizando PyModbus junto con la librería asyncio para el código concurrente. 

Tras importar las librerías necesarias, se define la función run_async_client compatible tanto con TCP, como con RTU. Dentro de esta función, se crea un cliente Modbus asíncrono, se conecta al servidor especificado y se verifican las conexiones exitosas con assert. El script alterna el valor de una bobina Modbus cada 5 segundos, verifica la operación de escritura leyendo y mostrando el valor de la bobina. Finalmente, se define y llama una función principal usando asyncio.run para ejecutar el código asíncrono.

Este script es un punto de partida para crear un cliente Modbus asíncrono y puede requerir modificaciones para ajustarse a requisitos específicos.

#!/usr/bin/env python3
import logging
logging.basicConfig()
_logger = logging.getLogger(__file__)
_logger.setLevel("INFO")
# Enable pymodbus information
from pymodbus import pymodbus_apply_logging_config
pymodbus_apply_logging_config("INFO")

import asyncio
from pymodbus.client import AsyncModbusTcpClient, AsyncModbusSerialClient
from pymodbus.transaction import ModbusSocketFramer, ModbusRtuFramer
from pymodbus.exceptions import ModbusException

async def run_async_client(client_type="tcp", host="127.0.0.1", port=5020):
global client
if client_type == "tcp":
client = AsyncModbusTcpClient(
host = host,
port = port,
framer = ModbusSocketFramer,
)
elif client_type == "serial":
client = AsyncModbusSerialClient(
port = port,
framer = ModbusRtuFramer,
baudrate = 38400,
bytesize = 8,
parity = 'N',
stopbits = 1,
# timeout = 1, # waiting time for request to complete
)
else:
_logger.error(f"Invalid client type selected ({client_type}), cannot start pymodbus client")
return -1

_logger.info("Connecting to the server...")
await client.connect()
assert client.connected
_logger.info("Connected!")

return_code = 0
a = False
_logger.info("Starting with coil[0] = False")
while True:
a = not a
await asyncio.sleep(5)
try:
await client.write_coil(0, a, 0x01)
response = await client.read_coils(0, 1, 0x01)
assert not response.isError()
assert len(response.bits) == 8
_logger.info(f"coil[0] has value {response.bits[0]}")
except ModbusException as exc:
_logger.error(f"Received ModbusException({exc}) from library")
return_code = -1
break;
return return_code;

async def main():
global client
status = 0
try:
status = await run_async_client("tcp", "localhost", 5020)
# status = await run_async_client("serial", port="/dev/ttySC0")
except KeyboardInterrupt:
print()
except Exception as e:
status = -1
_logger.error(f"Unknown exception ocurred: {e}")
finally:
client.close()
return status;

if __name__ == "__main__":
exit(asyncio.run(main(), debug=True))


Desbloqueando el potencial de los PLCs Raspberry Pi con la poderosa comunicación Modbus

Aprovechar el poder de la comunicación Modbus con un PLC Raspberry Pi puede simplificar significativamente el intercambio de datos en entornos de automatización industrial. El uso de la librería pymodbus permite integrar la comunicación Modbus de manera robusta y eficiente, ya sea mediante un enfoque síncrono o asíncrono.


Cada método tiene sus ventajas únicas: la simplicidad y previsibilidad del síncrono, y la eficiencia y escalabilidad del asíncrono, ideal para tareas intensivas de E/S. La elección depende de las demandas específicas del proyecto y el nivel de familiaridad con los paradigmas de programación.


Los scripts de ejemplo proporcionados son una base que puede necesitar modificaciones personalizadas. Comprendiendo los conceptos clave y la estructura de estos scripts, estarás en camino de construir sistemas de comunicación Modbus potentes y fiables para tus PLCs Raspberry Pi.


Recuerda siempre, ya sea que estés manejando un teclado virtual o estableciendo complejas comunicaciones Modbus, el PLC Raspberry Pi ofrece una versatilidad inmensa. Mantente curioso, sigue experimentando y ¡aprovecha al máximo el potencial de tus dispositivos!

Buscar en nuestro blog

Cómo utilizar PyModbus con Raspberry Pi PLC
Boot & Work Corp. S.L., Ricard Franch Argullol 25 de septiembre de 2023
Compartir

¿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.


Industrial PLC comparison >>>