Laboratorio Protocolo ModBus

Sitio: Facultad de Ingeniería U.Na.M.
Curso: REDES I - IC412
Libro: Laboratorio Protocolo ModBus
Imprimido por: Invitado
Día: miércoles, 4 de diciembre de 2024, 23:27

Descripción

Comprender la utilización del protocolo ModBus, poder entender la conexion de los dispositivos y las tramas que se envian/reciben en la comunicación.

1. Objetivos

Los objetivos del presente laboratorio son los siguientes:

  • Mostrar al alumno el funcionamiento práctico del Protocolo Modbus, tanto RTU como TCP/IP
  • Familiarizar respecto a el contenido de tramas que se comparten y como es el accionar
  • Utilizar scripts simples para poder comunicar dispositivos  o realizar consultas simples.

2. Introduccion

En el presente laboratorio se realizará una practica utilizando ModBus TCP/IP sobre ethernet. Recordemos que también es ampliamente utilizado Modbus RTU sobre RS-485 (es decir ModBus serial). Pudiendo interconectar los mismos mediante gateways (pasarelas)

Recordemos que el protocolo ModBus esta basado en petición/respuesta (cliente /servidor). Es decir que cada vez que enviemos una trama vamos a estar recibiendo una trama de respuesta. Anteriormente el protocolo adoptaba la denominación de Master y esclavos para los dispositivos, pero cambió en el año 2020.

El maestro puede hacer peticiones a un esclavo. Las peticiones de lectura y escritura que envía un maestro mediante un código de función. Según ese código, el esclavo interpretará los datos recibidos del maestro y decidirá qué datos debe devolver. Los códigos de función dependen de los dispositivos y de las tareas que estos pueden realizar.

Conexión de esclavos al bus (half duplex)

3. Materiales

  • Notebooks, PC
  • Cable de Red
  • Switch

4. Trama RTU Serial

Analisis de trama RTU

 Recordando la trama para RTU tenemos los siguiente campos:

Las funciones más comunes utilizadas pueden ser las siguientes:

Para la lista completa y descripción de cada una así como el manejo de respuestas de errores. referirse a Modbus Application Protocol, que se encuentra disponible además en el Aula Virtual

 

Como ejemplo vamos a analizar la siguiente trama enviada:

0A 06 00 11 AA 00 14 A6

Analizando tenemos, que va dirigida al esclavo 0A (Esclavo 10)

La función es la 06 (Escribir 1 registro). Con este dato ya podemos segmentar los bytes de la trama para identificar cada parte. Si vamos al manual del protocolo tenemos que los próximos 2 bytes serán la dirección en cuestión del registro que vamos a escribir, seguido de 2 bytes con el valor que queremos que tome el registro.

ESCLAVO FUNC REGISTRO VALORES CRC
0x0A 0x06 0x00 0x11 0xAA 0x00 0x14 0xA6

entonces lo que se quiere hacer es: escribir AA00 ( 43520 en decimal) en el registro 0011 (Registro 17)

Por ultimo siguiendo la trama del protocolo, tenemos que los últimos 2 bytes corresponden al CRC calculado en base al algoritmo CRC-16/MODBUS. Para comprobar el mismo podemos ir a este sitio

Si el registro fue modificado correctamente vamos a recibir como respuesta la misma trama enviada (de acuerdo a lo especificado en el protocolo para dicha función). De otra forma recibiremos un código de error.

 

Ahora analicemos una trama algo más compleja:

0A 10 00 05 00 02 04 00 01 00 02 B5 C6

Nuevamente la petición va dirigida al esclavo 10. La función ahora es la 0x10 (Función 16) Escribir en múltiples registros. Cabe aclarar que estos registros deben ser contiguos.

Teniendo esta información ya podemos segmentar la trama:

ESCLAVO FUNC REG IN NRO REG N BYTES VALORES CRC
0x0A 0x10 0x00 0x05 0x00 0x02 0x04 0x00 0x01 0x00 0x02 0xB5 0xC6

Según el protocolo tenemos 2 bytes que indican la dirección del primer registro a escribir (0x0005) registro 5. Los próximos 2 bytes serán la cantidad de registros a escribir (0x0002) 2 registros

Luego tenemos la cantidad de bytes de datos que vamos a escribir. En este caso si vamos a modificar 2 registros tenemos 2 x 2 =4, a modo general este campo será entonces N registros x 2.

Luego vienen los valores de los registros en paquetes de 2 bytes.

Entonces tendremos que

el registro 0x0005 tomará el valor 0x0001 y el registro 0x0006 tomará el valor 0x0002

Como parte final tenemos nuevamente el CRC calculado.

En este caso si todo sale correcto la respuesta recibida será la siguiente

ESCLAVO FUNC REG IN NRO REG CRC
0x0A 0x10 0x00 0x05 0x00 0x02 0xB2 0x50

5. Practica 1: analisis de trama

Consultando la documentación del protocolo, analice cuidadosamente la siguiente comunicación

Petición de cliente: 03 03 00 00 00 05 2B 84

Respuesta del Servidor: 03 03 0A 21 64 21 65 21 45 2E 87 0A 0F 23 6A

1) Identifique el numero de Servidor(esclavo) y la petición en la trama

2) Que registros son solicitados en la petición?

3) Es correcto afirmar que el Holding Register 5 tiene un valor de 0x0A0F?

5.1. Resolucion

Petición: 03 03 00 00 00 05 EB 45

03 (dirección de esclavo)

03 (Función de lectura)

00 00 (Registro de inicio para lectura)

00 05 (Cantidad de registros a leer)

EB 45 (CRC)

Respuesta: 03 03 10 21 64 21 65 21 45 2E 87 0A 0F 23 6A

03 (dirección de esclavo)

03 (Función de lectura)

10 (Byte count = 10, 5 registros recibidos)

21 64 (Registro 1)

21 65 (Registro 2)

21 45 (Registro 3)

2E 87 (Registro 4)

0A 0F (Registro 5)

23 6A (CRC)

1) Identifique el numero de esclavo y la petición en la trama

se comunica al esclavo 03, con la funcion 03 , read holding register (lectura de registro)

2) Que registros son solicitados en la petición?

se solicitan 5 registros desde la posicion 0x0000 (registro 0 al registro 4 ) , entonces

0x0000 (holding reg 1)

0x0001 (holding reg 2)

0x0002 (holding reg 3)

0x0003 (holding reg 4)

0x0004 (holding reg 5)

3) Es correcto afirmar que el Holding Register 5 tiene un valor de 0x0A0F?

Si estudiamos la trama recibida, vemos que en la posición del registro 5 tenemos los datos 0A0F   , pero si analizamos el CRC de la trama vemos que el mismo no se corresponde a lo recibido, así que no podemos afirmar que ese dato sea correcto.

Ver Calculo de CRC

6. Trama TCP/IP

Como se comento anteriormente básicamente Modbus TCP encapsula la trama RTU para poder mandarla por ethernet, como vemos tiene algunas modificaciones.


MODBUS message frame

7. Practica 2

Practica de protocolo Modbus sobre TCP/IP

Para la practica vamos a implementar una red Modbus sobre TCP, para ello se realizará el siguiente esquema de conexión, varias computadoras interconectadas a un switch en donde asignaremos IP manuales en el rango 192.168.0.X. ( 192.168.0.1 ... 192.168.0.2...192.168.0.3)

Una de las PC se convertirá en Cliente (Master), preferentemente la PC con el IP 192.168.0.1 que es la que realizará las peticiones a los servidores (Esclavos) 

Una vez configurado todo, realizaremos consultas de lectura/escritura y verificaremos que las mismas se estén ejecutando correctamente. Luego podremos correr wireshark en la PC y analizar la trama del protocolo




Cuestionario:

  1. Analizando con wireshark, pudo identificar los campos?. que campos en cuestión se agregan o quitan de la trama de Modbus serial

Librería PyModbusTCP

La liberia PyModbusTCP nos permitirá montar tanto un servidor como un cliente modbus. Para ello consultando la documentación de la misma primero para interiorizarnos. vemos que es muy fácil utilizarla. Los scripts subidos a la plataforma son extraídos de los ejemplos de la documentación. (recordar instalar primero la librería antes de correr el script)

Configuración SERVIDOR

Ver scripts a continuación.
Nota: Los scripts tanto de servidor como cliente tiene por defecto host = localhost. Si ejecutamos en nuestra PC los mismos ,podemos realizar las consultas y análisis de paquetes sin necesidad de contar con otra pc.

Configuración CLIENTE

Para hacer un testeo podemos instalar el programa qModMaster o qModbus que posee una GUI para realizar consultas de lectura/escritura tanto para modbus TCP como para modbus Serial.

qModmaster

qModbus


en qModMaster debemos configurar la dirección IP del cliente a comunicar, desde el menú Opciones->Modbus TCP en este caso, escribimos la dirección del cliente y el puerto lo dejamos por defecto. Al configurar el puerto, debemos hacer click en el botón conectar Luego debemos configurar Address o ID, y la función que queremos consultar y click en el botón de lectura/escritura (ejecutar comando)


8. Script Servidor

Para ejecutar el script si utilizamos el puerto por defecto (502) debemos ejecutarlo como superusuario debido a que los puertos menores a 1024 son de sistema.

_____________________________________________________________________________________________________

#SCRIPT REDES I. Servidor MODBUS TCP
#es necesario ejecutar como root para utilizar puerto 502,
#no obstante qmodmaster puede ser ejecutado como usuario normal.

from pyModbusTCP.server import ModbusServer, DataBank
import time
import random

#Modificar por IP de la interface a la que estamos conectados para tener salida.
server = ModbusServer('localhost', 502, no_block=True)

try:
print("Inicia servidor")
server.start()
#rellenamos los holding reg 0, 1 ,2 ,3
server.data_bank.set_holding_registers(0, [100, 200 ,300, 400], None)
#rellenamos los input 0, 1 ,2 ,3
server.data_bank.set_input_registers(0, [1, 2 ,3, 4])
print("Servidor Online")
while True:
hreg=random.randint(0,100)
#holding reg 0: cada 1 segundo cambia.
server.data_bank.set_holding_registers(0, [hreg], None)
time.sleep(1)

except:
print("Desconectando servidor")
server.stop()
print("Servidor Offline")


_____________________________________________________________________________________________________

Si ejecutamos el comando netstat -an | grep 502 podemos observar que el puerto se encuentra escuchando:


9. Script Cliente Consulta

El siguiente script realiza una consulta a servidor, solicitando los primeros 4 registros, es decir del 0 al 3.

Utilizamos primero el script como se encuentra y luego descomentamos la linea

client.debug=True

Para poder observar las tramas enviadas y recibidas.

_____________________________________________________________________________________________________

from pyModbusTCP.client import ModbusClient
import time

#Modificar por IP de la interface a la que estamos conectados para tener salida.

try:
    client = ModbusClient(host='localhost', port=502, auto_open=True, auto_close=True)
    client.open()
    #client.debug=True
    print("Cliente ok")
    while True:
        regs_list=client.read_holding_registers(0,4)
        print(regs_list)
        time.sleep(1)
       
except ValueError:
    print("Error iniciando cliente")

10. Script Cliente gráfica

El siguiente script realiza una lectura cada 2 segundos del holding reg 0 y lo grafica. Debemos cambiar el host por la dirección del host que vamos a consultar.



_____________________________________________________________________________________________________


import datetime as dt
import random
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from pyModbusTCP.client import ModbusClient

# Create figure for plotting
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
xs = []
ys = []

# This function is called periodically from FuncAnimation
def animate(i, xs, ys):

    # Read temperature (Celsius) from TMP102
    temp_c=regs_list=client.read_holding_registers(0,1)
    print("registro leido:")
    print(temp_c)
    #round(5, 2)
    
    # Add x and y to lists
    xs.append(dt.datetime.now().strftime('%H:%M:%S'))
    ys.append(temp_c)

    # Limit x and y lists to 20 items
    xs = xs[-20:]
    ys = ys[-20:]

    # Draw x and y lists
    ax.clear()
    ax.plot(xs, ys)

    # Format plot
    plt.xticks(rotation=45, ha='right')
    plt.subplots_adjust(bottom=0.30)
    plt.title('Lectura de Servidor Modbus TCP ')
    plt.ylabel('Temperature (deg C)')

# Set up plot to call animate() function periodically
ani = animation.FuncAnimation(fig, animate, fargs=(xs, ys), interval=2000)
client = ModbusClient(host='localhost', port=502, auto_open=True, auto_close=True)
client.open()
plt.show()

11. Preguntas

  • ¿Por qué el software Qmodmaster incluye un campo de Slave ID en modbus TCP?
  • ¿Qué consideraciones no se tuvieron en cuenta en el servidor creado?
  • Pudo identificar correctamente que se agrega en TCP/IP?
  • ¿Por qué la trama modbus TCP/IP no manda CRC?