En primer lugar hay que saber que si uno usa pymodbus3 no hay manera de que funcione la conexión al PLC usando un puerto serial. Funciona muy bien en modo TCP pero serial nada. La solución a este problema es instalar el branch python3 de pymodbus 1.2.0. Podemos bajar el archivo zip de esta página e instalarlo con pip.
Una vez hecho esto estaremos listos siempre que tengamos un dispositivo conectado a uno de nuestros puertos seriales. Si no lo tenemos podemos usar un simulador de PLC como Mod_RSSIM y un emulador de conexión de puertos seriales como Com0Com. Este emulador nos crea dos puertos seriales virtuales interconectados que usaremos uno para nuestro PLC virtual y otro para nuestro programa usando pymodbus.
Ya una vez que tengamos nuestro PLC de prueba conectado y nuestros puertos seriales funcionando procedemos a programar el cliente Modbus en python.
from pymodbus.client.sync import ModbusSerialClient as ModbusClient client = ModbusClient(method='rtu', port='COM6', stopbits=1, bytesize=8, parity='N', baudrate=19200, timeout=0.4) client.connect()La primera línea importa la clase que necesito de pymodbus. La segunda instancia el objeto client usando el COM6 ya que uso una máquina en windows y tengo este puerto libre. Los otros parámetros que paso al constructor son el método, rtu en este caso, y las características típicas como tasa de baudios, bit de parada y paridad. Finalmente le paso un parámetro importante que es el timeout, este dato impacta grandemente la velocidad conque los datos son leídos o escritos al PLC.
Una vez instanciado client procedo a leer o escribir datos al PLC. Por ejemplo una lectura de holding registers sería:
lecturas = client.read_holding_registers(10, 16, unit=0x01)Aquí el programa estaría leyendo 16 registros a partir del registro 10. La unidad 0x01 indica la dirección del PLC en caso de estar usando RS-485 y que tenga varios PLC's en la misma línea. Si hay un solo PLC podemos usar 0x00 por ejemplo.
Si ponemos al programa a leer y escribir datos al PLC de manera periódica lo mejor es crear un thread diferente para esta función de lectura/escritura de manera que permita que el hilo correspondiente a la interfaz de usuario corra sin trabarse. No olvidemos tampoco englobar estas lecturas/escrituras en bloques try/except para atrapar cualquier error proveniente de malas lecturas o desconexión del PLC.