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.
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.
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:
- 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
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.
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?