Mostrando las entradas con la etiqueta python. Mostrar todas las entradas
Mostrando las entradas con la etiqueta python. Mostrar todas las entradas

viernes, noviembre 18, 2016

Pymodbus3 usando puertos seriales

Estas son algunas de las lecciones aprendidas usando la librería pymodbus con python 3.4 y puertos seriales en lugar de usar una conexión TCP/IP.

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.



miércoles, octubre 05, 2016

Leyendo datos con pymodbus3

Uno de los protocolos más populares y viejos del mundo de la automatización industrial es Modbus. Es un protocolo sencillo que nos permite leer datos de una miríada de dispositivos industriales tales como controladores de procesos, PLC's y sensores y medidores de todo tipo. Modbus ha estado ya unas cuantas décadas y ha evolucionado en lo que yo llamo tres sabores principales: ASCII, RTU y TCP. Los dos primeros funcionan sobre conexiones seriales tipo RS-232, RS-422 o RS-485 y el último, el TCP, funciona usando Ethernet como medio de conexión.

Pymodbus3 es una biblioteca, o librería como también la llamamos, de Python que nos permite usar el protocolo a alto nivel sin entrar en los detalles de programación de bajo nivel.

Supongo que si están leyendo esto ya de alguna manera conocen el protocolo y saben algo de Python. Así que al grano. Vamos a hacer un pequeño programa que lea datos y los escriba a algún lugar, por ejemplo un archivo texto.

Lo primero es asegurarnos que tengamos Python instalado, por ejemplo python 3.4 para que sea compatible con pymodbus3. Luego instalamos pymodbus3 con pip de la manera usual.

Las primeras líneas del programa serían algo así:

from pymodbus3.client.sync import ModbusTcpClient as ModbusClient

client = ModbusClient('localhost', port=502)
client.connect()

El script supone que estoy usando el protocolo ModbusTCP, por lo que el cliente en cuestión estaría leyendo de un PLC, o servidor Modbus, ubicado en este caso en mi pc (localhost). ModbusTCP usa el puerto TCP 502, así que eso es lo que significa el segundo parámetro del constructor de la clase.

Para poder simular una conexión ModbusTCP uso mod_RSsim. Este simulador si lo instale en mi pc puede emular un PLC sin problemas y me conecto vía el puerto 502.

Luego de creado el cliente podemos leer de esta manera.

lectura = client.read_holding_registers(450, 10)

Esto guardaría en la variable lectura una lista de 10 valores a partir del holding register con dirección 450. Pymodbus3 tiene funciones para leer y escribir todo tipo de variables Modbus y podemos ver un ejemplo para un cliente asíncrono en la documentación.

Quedaría empaquetar el código de manera que podamos interactuar con el programa, guardar los datos en algún lado y añadir el manejo de excepciones por si hay algún problema de comunicaciones. Pero eso sería materia de otro post.



Python en automatización industrial, un caso concreto

Una de las cosas que hago para ganarme la vida es servir de consultor en automatización industrial. Justo estaba en esos menesteres hace poco cuando me topé con un problema de esos a que nos tiene acostumbrados la crisis económica de nuestros golpeados clientes. Nuestro cliente en cuestión sufrió una falla irrecuperable de un pequeño sistema scada que tenían conectado a una red de controladores PLC en su planta de energía. Sin el scada funcionando, sin recursos como para poner en funcionamiento el ahora muy costoso sistema de adquisición de datos se vieron en la necesidad de empezar a buscar alternativas que al menos pudieran devolverles algo de la funcionalidad perdida. Y aquí es donde la imaginación y tecnologías libres como la de python vienen a jugar un papel importante.

El problema se centraba en leer datos a través de una interfaz serial RS-232 usando el protocolo Modbus RTU, luego guardar esos datos, o más bien guardarlos solamente si alguno de esos datos cambiaba de estado, y finalmente tener alguna herramienta que pudiera analizar los datos guardados para graficar algunas cosas y hacer algunos cálculos de índices de mantenimiento que tenían que ver con las máquinas que controlaban los PLC.

Debido a que no eran muchos los datos a leer y a que era solamente una tabla de un solo PLC decidimos desarrollar unos scripts en python para rapidamente tener un prototipo funcional para mostrarlo al cliente.

Un rato en google y desarrollamos un ambiente de desarrollo en una laptop en windows de esta manera:
  1. instalamos python 3.4 (esta versión es la que mejor funciona con todo lo que uso en este proyecto)
  2. con pip le agregamos virtualenv para crear un ambiente virtual limpio, en mi caso tengo varias versiones de python instaladas y lo más sano es usar virtualenv.
  3. ya con virtualenv creamos el directorio de trabajo y activamos.
  4. instalamos pymodbus3 usando pip.
  5. instalamos también pymongo para la base de datos usando pip
  6. finalmente instalamos PyGObject for Windows que por cierto a la fecha solamente funciona con python 3.4, por eso es que uso esta versión y no la última.
La arquitectura de mi pequeño sistema es muy sencilla. No es más que un script que interroga al PLC usando pymodbus3 y que escribe a MongoDB si detecta algún cambio. En MongoDB lo que se guardarán son eventos, es decir documentos con la información del estado de la variable y la fecha y hora del evento. Siendo MongoDB una base de datos NoSQL facilita la interacción rápida con los eventos sin mucho esfuerzo.

La otra parte de la ecuación es una pequeña aplicación que me permita leer los eventos almacenados en MongoDB y que le permita a los operadores interactuar con los datos. Hay dos caminos para hacer dicha aplicación. Pudiera ser una aplicación con una interfaz web, lo cual requiere alguito más de esfuerzo en el desarrollo gráfico y todo eso, o pudiéramos usar una clásica aplicación de ventanas lo cual es más rápido. Nos decidimos por lo segundo por aquello de la rapidez.

De todos los entornos gráficos de ventanas para python que hay por ahí el que nos parece más sólido es el que usa Glade para desarrollar las ventanas y Gtk+ para cargarlas al script python. Hay en la red muchos tutoriales, aunque creo que el mejor es el Python Gtk+3 Tutorial. El tutorial es bastante claro sobre como usar Gtk+ primero y por último como usar Glade. Lo bueno es que podemos tener Glade abierto y hacer cambios en la ventana y correr el script y de inmediato ver que pasó. Glade solamente crea un archivo xml que lo lee el script para crear los objetos que le pasará a Gtk+ para que los dibuje en pantalla y maneje los eventos.

En resumen, Python ofrece un sistema rápido de desarrollo para problemas como el descrito. Las librerías de funciones son extensas y el soporte en la red por parte de los desarrolladores es bastante bueno. Los scripts desarrollados en este proyecto en particular son bastante sólidos, manejan todo tipo de excepciones que sabemos que pueden presentarse (como fallas de comunicación porque se rompió el cable que va al PLC) y pueden modificarse en la misma planta ya que el código es abierto y un buen programador debiera poder entenderlo sin mucho problema por su gran legibilidad.

Hasta aquí por hoy. Si tienen dudas pónganlas en los comentarios.