Prototipos con Modbus

Programmer coding python, java script, html code on notebook screen
Alex Pohjanpelto
Alex Pohjanpelto
Published:
Manufactura Industrial y Procesos
Mediciones industriales
Biología

¿Está creando prototipos o buscando una forma asequible de medir la humedad y la temperatura en su aplicación sin comprometer la calidad de las mediciones? ¿También tienes algunos conocimientos básicos sobre lenguajes de programación, como Python? Si es así, espero mostrarle cómo usted mismo puede registrar fácilmente datos durante largos períodos de tiempo con solo una sonda HMP110, un cable de servicio USB (219690) y una computadora con Python 3 instalado. Lo guiaré a través de las diferentes secciones del código, pero si no le interesa una explicación, puede pasar al final del código completo. También me gustaría señalar que este es solo un script de ejemplo que demuestra la comunicación Modbus.

Bibliotecas

Antes de llegar al código, primero presentemos las bibliotecas que aprovecharemos, siendo la más importante pymodbus. Lo usamos para comunicarnos con la sonda a través de Modbus RTU, más específicamente importaremos ModbusSerialClient desde pymodbus.client.sync. Usamos la biblioteca struct para manipular bits en diferentes tipos de variables, la biblioteca time para cambiar la tasa de sondeo, la biblioteca datetime para obtener la hora y la fecha de las lecturas de datos e importamos argparse para pasar argumentos desde la línea de comando al código .

from pymodbus.client.sync import ModbusSerialClient as ModbusClient
import struct
import time
import datetime
import argparse

Parámetros

He agregado algunos argumentos para ayudar con la flexibilidad del código. Los usamos para que podamos cambiar fácilmente los valores de las variables desde la línea de comando sin tener que alterar el código. Los argumentos que pensé que podrían ser útiles son el puerto de comunicación, el nombre del archivo donde se almacenan los datos, la dirección esclava de la sonda, la tasa de sondeo y la duración del registro de datos.

parser = argparse.ArgumentParser(
    description="Modbus data logger"
)
parser.add_argument('port', help="The COM port where the probe is attached")
parser.add_argument('-f', '--file', help="The file name to store the data (default data.csv)", default="data.csv")
parser.add_argument('-a', '--address', help="The address of the probe (default 240)", default=240, type=int)
parser.add_argument('-r', "--rate", help="The poll rate in seconds (default 1)", default=1, type=float)
parser.add_argument('-l', '--length', help="The length of time in hours to data log (default 9999999)", type=float, default=9999999)
args = parser.parse_args()
 

Conexión Modbus

Primero debemos inicializar un nuevo cliente Modbus serial con la configuración correcta para nuestra sonda. El conjunto de parámetros de este ejemplo debe incluir el método de comunicación, el puerto de comunicación, el tiempo de espera de respuesta, la velocidad en baudios, los bits de parada y la paridad. El método es 'rtu' para Modbus RTU, el puerto depende de su computadora, por lo que explicaré en una sección a continuación, cómo identificar el correcto. Los otros parámetros están determinados por la configuración de la sonda, por lo que deberá consultar su hoja de datos para obtener los valores apropiados. Por lo general, para las sondas Vaisala, la velocidad en baudios es 19200, los bits de parada son 2 y la paridad es ninguna.

probe = ModbusClient(method='rtu', port=args.port, timeout=1, baudrate=19200, stopbits=2, parity='N')

 

Lectura de los registros de tenencia

Ahora vamos a crear una función para leer los registros de espera de la sonda. Llamamos al método read_holding_registers() de la instancia de cliente Modbus que creamos en la sección anterior para leer los registros. Necesitamos especificar la dirección inicial del registro de retención, el número de registros y la dirección esclava de la sonda. Recibiremos los datos de los registros en palabras de 16 bits en formato little-endian, que luego debemos convertir a valores de coma flotante de 32 bits. 

def holding_registers_data():
    try:        
        registers = probe.read_holding_registers(address=0,count=10, unit=args.address).registers
            except Exception as e:
        print(e)
        return False, None, None, None
    try:
        rh = data_from_register(registers, 1)
        t = data_from_register(registers, 3)  
        dp = data_from_register(registers,9)   
       
    except Exception as e:
        print(e)
        return False, None, None, None
        return True, rh, t, dp
 

Convertir los registros en valores de 32 bits

Los registros se almacenan como enteros de 16 bits y necesitamos convertirlos en flotantes de 32 bits. Creé una función que toma los valores de registro y el índice de registro y devuelve un valor de coma flotante de 32 bits de los datos en ese índice. Hacemos uso de la estructura del módulo para realizar esta conversión.

def data_from_register(registers, i):
    return struct.unpack('!f', bytes.fromhex('{0:04x}'.format(registers[i]) + '{0:04x}'.format(registers[i-1])))[0]

 

Registrando los datos

Ahora que podemos leer los registros de retención y convertir los valores en valores de punto flotante de 32 bits, necesitamos crear una función que almacene los valores en un archivo .csv. Creé una función llamada data_logger() para ese propósito. Llama a la función holding_registers_data() y agrega los datos recibidos a un archivo con el formato de fecha, hora, humedad relativa, temperatura, punto de rocío.

def data_logger():
    probe.connect()
    successful, rh, t, dp = holding_registers_data()
    if (successful):
        dt = datetime.datetime.now()
        
        try:
            with open(args.file, "a") as f:
                line = f"{dt},{rh},{t},{dp}\n"
                print(line)
                f.write(line)   
        except Exception as e:
            print(e)
        probe.close()
        time.sleep(args.rate)
        
    else:
        probe.close()
        time.sleep(0.5)
 

 

Determinación del puerto de comunicación de la sonda

Primero, asegúrese de que su sonda esté correctamente conectada a su computadora.

WindowsEn el sistema operativo Windows, puede encontrar el puerto COM del dispositivo en el Administrador de dispositivos. Para abrir la ventana del Administrador de dispositivos, abra el menú Inicio en la parte inferior izquierda de la pantalla y escriba "Administrador de dispositivos". Debería aparecer como el resultado superior en "Mejor coincidencia", ábralo haciendo clic en el icono o presionando Entrar en su teclado. Haga clic en la flecha junto a Puertos (COM y LPT) para expandir los puertos. Debe haber un dispositivo listado como “Dispositivo USB de Vaisala” con el puerto COM listado al lado, en nuestro caso COM6.

Image
Determining the communication port of the probe

Linux 

En Linux puede determinar el puerto de comunicación escribiendo el comando “dmesg | grep tty” en la terminal. Debería devolver, entre otras cosas, una declaración similar a 'cp210x converter now added to ttyUSBn', donde ttyUSBn es el puerto.

Ejecutando el código

Para ejecutar el script, debe tener todas las bibliotecas instaladas. Si es necesario, puede usar el comando pip

pip3 install -U pymodbus 
to install pymodbus. The other libraries should already come with the python 3 package.
In a command prompt, navigate to the directory where they python script is stored and type 
    python Modbus_RTU -h 

por ayuda con los argumentos. Esto debería aparecer en el símbolo del sistema. A continuación se muestra una captura de pantalla de la salida.

Image
Terminal

 

 

 

El único parámetro que se requiere es el puerto de comunicación, mientras que los demás argumentos tienen un valor predeterminado que se puede cambiar según sus preferencias. El argumento del puerto de comunicación no requiere identificador y se puede colocar en cualquier lugar después del nombre del archivo. Los otros argumentos que son opcionales, requieren un identificador.


 Aquí hay un ejemplo de un comando típico en forma larga y corta:

    Python .\Modbus_RTU  --file datalog.csv --address 240 --rate 10 --length 48 COM6
    Python .\Modbus_RTU -f datalog.csv -a 240 -r 10 -l 48 COM6 
 

 

Descargue el código completo y vea el webinar Modbus 101.

 

Comment

Guillermo Hernández Hernández

oct. 7, 2023
Magnífico ejemplo, muchas gracias por su trabajo, y sus explicaciones, solamente me falta probarlo utilizando una Raspberry Pi 4B y un instrumento marca Select para medir variables eléctricas. Saludos desde la Ciudad de Mérida Yucatán México.

Vaisala

oct. 12, 2023
¡Gracias Guillermo Hernández por tus amables comentarios!

Enviar nuevo comentario