Modbus TCP
Modbus TCP, introduction
Modbus TCP ou Modbus TCP/IP hérite de la simplicité et de la robustesse (en conservant la structure des messages, la communication basée sur les registres, etc.) du protocole Modbus original, en y ajoutant la fiabilité et l’interopérabilité de TCP/IP.
TCP assure une livraison fiable et ordonnée des messages Modbus sur le réseau en fournissant des fonctions telles que la segmentation des données, l’accusé de réception et la retransmission.
La couche IP assure l’adressage, le routage et la livraison des paquets. Il utilise les adresses IP pour identifier les dispositifs source et destination dans un réseau.
L’adressage des appareils dans Modbus TCP/IP est géré au niveau IP du réseau. Contrairement à Modbus RTU ou Modbus ASCII, où chaque appareil se voit attribuer un numéro d’esclave unique compris entre 1 et 247, les appareils d’un réseau Modbus TCP/IP sont adressés à l’aide de leur adresse IP.
Modbus TCP utilise le port : 502 .
Modèle Client - Serveur
Modbus TCP utilise un modèle de communication de type Client - Serveur entre des appareillages (devices) connectés sur un réseau Ethernet. Ce modèle désigne un appareil comme Client qui initie des requêtes, tandis que d’autres appareils agissent comme des Serveurs qui traitent ces requêtes et envoient des réponses.
Le modèle Client - Serveur est basé sur 4 types de messages :
- Modbus Request : le message est envoyé sur le réseau par le Client pour initier la transaction
- Modbus Indication : le message est reçu du côté Serveur
- Modbus Response : la réponse est renvoyée par le Serveur
- Modbus Confirmation : la réponse est reçue côté Client
Les termes Client et Serveur sont souvent la source de confusions. Un moyen mémotechnique simple est de penser à une commande dans un bar.
En tant que Client, je fais une requête au Serveur (Request) qui m’apporte la boisson demandée (Response).
Si l’on fait l’analogie avec le Protocole Master / Slave de Modbus RTU, le Client correspond au Master tandis que le Serveur correspond au Slave. Dans un modèle Client - Serveur, on peut avoir plusieurs clients.
Architecture d’un réseau Modbus
Sur ce schéma, nous observons :
- 2 Clients ModBus TCP
- 2 Serveurs Modbus reliés en Ethernet
- 2 Serveurs en Modbus série RTU (2 Slaves) reliés vers Modbus TCP avec une Gateway (passerelle) de type Server TCP/IP
- 1 Client en Modbus série RTU (1 Master) relié vers Modbus TCP avec une Gateway (paserelle) de type Client TCP/IP
Sur une architecture Modbus TCP, il peut y avoir plusieurs clients. Les Gateways permettent de faire la liaison entre les “devices” en Modbus série RTU avec le réseau Modbus TCP.
Trame Modbus TCP
Contrairement au Modbus RTU, Modbus TCP ne nécessite pas de code de correction d’erreur (CRC) car les couches basses Ethernet assurent déjà cette fonction.
La structure de base Modbus Function Code et Data reste identique.
Le Slave Address et le CRC du Modbus RTU disparaissent au profit du MBAP Header, le ModBus Application Protocol. L’ensemble MBPA Header + Function Code + Date forment l’ADU pour Application Data Unit.
Le MBAP Header contient les champs suivants :
Name | Length (bytes) | Function |
---|---|---|
Transaction identifier | 2 | Pour la synchronisation des messages entre le serveur et le client |
Protocol identifier | 2 | 0 pour Modbus/TCP |
Length field | 2 | Nombre d’octets contenus dans le message Modbus |
Unit identifier | 1 | Adresse du Serveur (255 if not used), traité comme l’adresse de Slave dans une liaison Modbus série (RTU) |
On remarque que le Unit ID remplace le Slave Address du protocole RTU. Le Unit identifier est utilisé dans Modbus TCP dans le cas ou les “devices” sont de type composite, comme une passerelle Modbus/TCP qui communique avec des élements Modbus RTU. La spécification Modbus TCP précise:
Unit ID : Use it only with serial gateway. The Modbus TCP server ignore this value
Exemple Modbus TCP et Modbus Serial
Dans cet exemple, deux centrales de mesure d’énergie Socomec M-50 sont utilisées. Il s’agit de Gateway type Server TCP/IP qui permettent de remonter les données des modules de mesure U-10 et I-35, qui eux, communiquent en Modbus Serial (RTU). Les modules I35 et U10 ont les adresses Modbus @6 et @5 respectivement.
Si l’on souhaite récupérer les données du module I-35 du TGBT 1, il faudra :
- faire une requête Modbus TCP sur l’@IP 192.168.1.4 de la Gateway M-50 sur le port 502
- mettre
06
dans Unit identifier pour communiquer avec le module I-35
Les trames Modbus TCP
Exemple d’analyse d’une trame Modbus TCP/IP en hexadecimal
La structure de trame Modbus TCP suivante :
Transaction identifier | Protocol identifier | Length | Unit identifier | Function code | Data |
---|---|---|---|---|---|
2 bytes | 2 bytes | 2 bytes | 1 byte | 1byte | n bytes |
12 34 00 00 00 06 01 03 00 01 00 02
0x12
et0x34
: Transaction ID = 0x1234 (2 bytes), c’est un numéro unique pour indentifier la transaction entre le client Modbus TCP et le serveur. L’octet de poids fort (High byte) du transaction ID est 0x12 et l’octet de poids faible (Low byte) est 0x340x00
et0x00
: Protocol identifier, octet de poids fort (high byte) et octet de poids faible (low byte)0x00
et0x06
: Longueur (Length high byte and low byte). La longueur du message Modbus est de 6 octets qui incluent: unit identifier (slave address) (1 octet), function code (1 octet), octet de poids fort du registre d’adresse à lire (1 octet), octet de poids faible du registre d’adresse à lire (1 octet) et le nombre de registres de données (2 octets = octets de poids fort (high) et faible (low) du nombre de registres à lire / écrire)0x01
: Unit identifier = adresse du slave0x03
: Function code (ici : Read Multiple Holding Registers)0x00
et0x01
: high byte et low byte du registre d’adresse à lire. Le registre d’adresse à lire dans notre cas est0x0001
.0x00
and0x02
: high byte and low byte du nombre de registres à lire. Le nombre de registres à lire est0x0002
. (càd on lit 2 registres (soit 2 Word))
Encodage des données
Modbus utilise la représentation “Big-Endian” pour les adresses et données. Cela signifie que lorsqu’une quantité numérique plus grande qu’un octet est transmise, l’octet le plus significatif est envoyé en premier. Par exemple :
Register size | value | |
---|---|---|
16 bits | 0x1234 | The first byte sent is 0x12 then 0x34 |
Analyse de “Function Code” Modbus
On trouveras ci dessous les données (data) associées à quelques Function Code Modbus. L’objectif n’est pas d’être exhaustif mais d’étudier le fonctionnement de quelques fonctions pour être capable de s’adapter facilement aux autres.
FC 03
(0x03
) Read Holding Register
La fonction FC 03
permet de lire le contenu de registres. Les registres correspondent à des zones mémoire du Serveur (Slave) dont les données sont représentées sur 16 bits (Word)
Pour une requête (Query ou Request) de type FC 03
, 2 octets serviront à définir l’adresse de départ de la zone mémoire à lire et 2 octets servent à indiquer le nombre de registres que l’on souhaite lire à partir de l’adresse de départ. Ces 4 octets sont contenus dans le champs Data.
Dans le champs Data de la réponse (Response), on trouvera un octet qui indiquera le nombre de données en octets contenu dans le message et 2*n octets des valeurs mémoire que l’on souhaitait lire.
Exemple QModMaster pour FC 03
Avec le logiciel QModMaster, je génère une requête Modbus TCP sur le Unit-ID 1 (Slave Addr), avec la Function Code 0x03
, à partir de l’adresse de départ 2
et un nombre de registres de 4
Le logiciel QModMaster génère la trame (Tx) : 00 01 00 00 00 06 01 03 00 02 00 04
. L’analyse de l’encart ADU de la trame de Requête permet de retrouver les informations.
En réponse (Rx), le logiciel reçoit du device interrogé la trame suivante : 00 01 00 00 00 0B 01 03 08 00 00 00 00 00 00 00 00
- Length =
000B
ce qui donne 11 en décimal. Si l’on compte, on à bien 11 octets qui suivent01 03 08 00 00 00 00 00 00 00 00
- Byte Count =
08
. Comme on a demandé de lire le contenu de 4 Registres (4 Word), on a bien 8 bytes (octets) en réponse.00 00 00 00 00 00 00 00
(Les valeurs sont toutes à 0 car la plage mémoire lue était à 0)
FC 15
(0x0F
) Write Multiple Coils
La fonction FC 15
(ou 0x0F
) permet d’écrire sur de multiples Coils (bit).
Pour une requête (Query) de type FC 15
, 2 octets servirons à définir l’adresse de départ de la zone mémoire à lire et 2 octets servent à indiquer le nombre de Coils (bits) que l’on souhaite lire à partir de l’adresse de départ. Ces 4 octets sont contenus dans le champs Data.
Exemple QModMaster pour FC 15
(0x0F
)
Avec le logiciel QModMaster, je génère une requête Modbus TCP sur le Unit-ID 1 (Slave Addr), avec la Function Code 0x0F
, à partir de l’adresse de départ 6
et un nombre de Coils de 12
. J’ai affecté aux 12 Coils la valeur binaire suivante : 0101 1111 0001
En analysant la contenu de l’ADU de la trame générée par QModMaster, on remarque plusieurs choses :
- Quantity of register :
000C
-> bug du logiciel, il devrait y avoir écrit Quantity of Coils - Byte Count :
02
, pour les 12 Coils sont codés sur 2 octets (Byte). Si l’on avait voulu écrire 18 Coils, on aurait eu besoin de 3 octets, etc.
Plus étrange est la Valeur de Output Values :
- Output Values =
FA 08
alors qu’on aurait pu s’attendre à 5F 10
pour qu’on soit sur les 2 octets !
Explications :
Pour chaque octet, on envoie d’abord le bit de poids le plus faible. Si l’on reprend les valeurs des 12 coils à envoyer
0101 1111 0001
- la première étape est déjà de coder les valeurs sur 2 octets :
0101 1111 0001 0000
- ensuite, on sépare les 2 octets :
01011111 00010000
- on envoie les bits du LSB au MSB pour chaque octet ce qui donne
11111010 00001000
- si l’on traduit en hexa
FA 08
: ce qui correspond au contenu de l’encart ADU.
La trame de réponse est la suivante : 00 01 00 00 00 06 01 0F 00 06 00 0C
Rien de particulier à décoder, on retrouve :
- Start Address =
00 06
- Length =
00 0C
soit les 12 Coils
Analyse Réseau Modbus
Encapsulation d’une trame Modbus TCP dans une trame Ethernet TCP / IP
La trame Modbus est ensuite encapsulée dans une trame Ethernet. Des champs supplémentaires s’ajoutent, le Ethernet Header qui va contenir les adresses MAC, le IP Header qui va contenir les adresses IP de source et de destination ainsi que les numéros de port, le TCP Header qui contient les paramètres permettant la transmission en mode connecté et le Ehernet CRC qui permet de vérifier la transmission sans erreur de la trame Ethernet.
Etablissement de la connexion Modbus
La messagerie Modbus doit fournir une “socket” d’écoute sur le port 502, qui permet d’accepter une nouvelle connexion et d’échanger des données avec d’autres appareils.
Lorsque le service de messagerie doit échanger des données avec un serveur distant, il doit ouvrir une nouvelle connexion client avec un Port 502 distant afin d’échanger des données avec celui-ci. Le port local doit être supérieur à 1024 et différent pour chaque connexion client.
Capture Wireshark et analyse
Pour analyser les trames Ethernet, j’utilise l’analyserur de paquets Wireshark. J’utilise QModMaster comme Client Modbus TCP sur un PC portable et un automate Wago 750-880 comme serveur Modbus. Cet automate est associé à une carte à 4 entrées TOR 750-423 et une carte à 4 sorties TOR 750-504. Le montage est le suivant :
L’idée est de générer les requêtes avec QModMaster pour lire les entrées TOR et écrire sur les sorties TOR et d’analyser les trames Ethernet associées au protocole Modbus TCP avec Wireshark.
Configuration de QModMaster
Configuration de l’adresse IP | Configuration du Base Address |
---|---|
On configure ici l’adresse IP du Server avec lequel on souhaite communiquer, ici le PLC Wago 750-880 qui à l’@IP 192.168.1.128 | Ici on configure l’adresse mémoire de départ du Serveur à 0. Certains modules commencent leurs plages mémoire à l’adresse 1, il faut donc modifier la valeur ici |
192.168.001.128
et non 192.168.0.128
C’est une contrainte du logiciel QModMaster, il faut penser à l’écrire de la sorte sinon cela ne fonctionne pas.
La carte Wago à 4 entrées digitales a été adressée à %IW0. La documentation nous indique que nous pouvons lire la valeur en Modbus à l’adresse de registre 0
avec un Read Holding Register (0x03
).
La carte Wago à 4 sorties digitales a été adressée à %QW0. La documentation nous indique que nous pouvons lire la valeur en Modbus à l’adresse de registre 0
avec un Write Single Register (0x06
).
Read Holding Register FC 0x03
Sur l’automate Wago 750-880, j’ai placé les 4 Digital-Input à 1. J’ai lancé une requête avec QModMaster
QModMaster nous retourne la valeur 15 en décimal, ce qui est correct car cela correspond aux 4 bits placés à 1 1111 . |
L’analyse au moniteur de QModMaster nous indique dans Register Value : 00 0F ce qui correspond à la valeur 15 codée sur un Word |
Analyse de la requête avec Wireshark
La capture avec Wireshark donne :
Pour la trame de requête (Query) avec le décodage de la trame suivant :
Frame 943: 66 bytes on wire (528 bits), 66 bytes captured (528 bits) on interface \Device\NPF_{D296DD04-C873-4280-A194-BD27AE8C4C2C}, id 0
Ethernet II, Src: 80:6d:97:4b:a4:7a (80:6d:97:4b:a4:7a), Dst: WAGOKontaktt_08:57:c9 (00:30:de:08:57:c9)
Destination: WAGOKontaktt_08:57:c9 (00:30:de:08:57:c9)
Source: 80:6d:97:4b:a4:7a (80:6d:97:4b:a4:7a)
Type: IPv4 (0x0800)
Internet Protocol Version 4, Src: 192.168.1.123, Dst: 192.168.1.128
Transmission Control Protocol, Src Port: 50518, Dst Port: 502, Seq: 1, Ack: 1, Len: 12
Modbus/TCP
Modbus
La trame en format hexa et Ascii Dump est la suivante :
0000 00 30 de 08 57 c9 80 6d 97 4b a4 7a 08 00 45 00 .0..W..m.K.z..E.
0010 00 34 7d 85 40 00 80 06 f8 f2 c0 a8 01 7b c0 a8 .4}.@........{..
0020 01 80 c5 56 01 f6 1e f5 91 b3 09 aa 49 55 50 18 ...V........IUP.
0030 fa f0 64 84 00 00 00 01 00 00 00 06 01 03 00 00 ..d.............
0040 00 01 ..
Si l’on analyse cette trame, on observe que :
- les 6 premiers octets correspondent à l’adresse MAC de la destination, càd, celle de l’automate Wago :
00 30 de 08 57 c9
- les 6 octets suivants correspondent à l’adresse MAC de la source (le PC) :
80 6d 97 4b a4 7a
08 00
indique qu’il s’agit d’une adresse IPv4
on saute quelques octets pour arriver à c0 a8 01 7b
c0 a8 01 7b
correspond à l’@IP de la source (le PC). Il suffit de convertir chaque octet en binaire pour retrouver l’adresse IP en décimal pointé :192.168.1.123
- les 4 octets suivants correspondent à l’adresse IP de la destination (l’automate Wago).
c0 a8 01 80
qui donnent192.168.1.128
- les deux octets suivants correspondent au numéro du port de la source (PC) :
c5 56
soit en décimal50518
- les deux octets suivants correspondent au numéro du port de la destination (Wago):
01 f6
ce qui donne502
soit le port d’écoute du protocole Modbus TCP ;)
on saute quelques octets pour arriver à 00 01 00 00 00 06 01 03 00 00 00 01
qui correspond à la trame Modbus TCP que dont on a déjà décoder un exemple plus haut.
00 01
Transaction ID00 00
Protocol ID -> Modbus TCP00 06
Length01
Unit ID03
Function ID -> Read Holding Register ;)00 00
Adresse de départ -> 000 01
Nombre de registres à lire -> 1
Analyse de la réponse avec Wireshark
Cette fois-ci c’est la trame correspond à la réponse (Response) du Server (l’automate Wago)
Pour la trame de réponse (Response) avec le décodage de la trame suivant :
Frame 944: 65 bytes on wire (520 bits), 65 bytes captured (520 bits) on interface \Device\NPF_{D296DD04-C873-4280-A194-BD27AE8C4C2C}, id 0
Ethernet II, Src: WAGOKontaktt_08:57:c9 (00:30:de:08:57:c9), Dst: 80:6d:97:4b:a4:7a (80:6d:97:4b:a4:7a)
Internet Protocol Version 4, Src: 192.168.1.128, Dst: 192.168.1.123
Transmission Control Protocol, Src Port: 502, Dst Port: 50518, Seq: 1, Ack: 13, Len: 11
Modbus/TCP
Modbus
La trame en format hexa et Ascii Dump est la suivante :
0000 80 6d 97 4b a4 7a 00 30 de 08 57 c9 08 00 45 00 .m.K.z.0..W...E.
0010 00 33 00 e3 40 00 40 06 b5 96 c0 a8 01 80 c0 a8 .3..@.@.........
0020 01 7b 01 f6 c5 56 09 aa 49 55 1e f5 91 bf 50 18 .{...V..IU....P.
0030 3e 80 0f ec 00 00 00 01 00 00 00 05 01 03 02 00 >...............
0040 0f .
Si l’on analyse cette trame, on observe que :
- les 6 premiers octets correspondent à l’adresse MAC de la destination, càd, celle de du PC maintenant !
80 6d 97 4b a4 7a
- les 6 octets suivants correspondent à l’adresse MAC de la source, càd l’automate maintenant :
00 30 de 08 57 c9
Pour les adresses IP, le principe restera identique et les adresses IP de source et de destination seront inversées.
De même pour les numéros de ports, le port de destination côté PC sera également le 502
Pour le plaisir, nous allons encore analyser la trame Modbus TCP 00 01 00 00 00 05 01 03 02 00 0F
00 01
Transaction ID00 00
Protocol ID -> Modbus TCP00 05
Length01
Unit ID03
Function ID -> Read Holding Register ;)02
Size of data in byte (2 byte = 1 Word)00 0F
-> valeur contenu dans le Word, ce qui donne 15 en décimal, càd, ce qu’il fallait trouver !
Remarques sur les captures Wireshark
Faire des analyses Wireshark ne constituent pas le quotidien de l’automaticien. Il est cependant intéressant de comprendre la structure d’une trame et des informations qui y sont codées, notamment quand on se retrouve face à des problématiques de communication pour voir si les trames sont générées correctement ou si c’est le Serveur Modbus qui est défectueux.
Conclusion :
Avantages de Modbus
- Bien que le protocole soit ancien, de nouveaux produits continuent de l’intégrer car c’est efficace et facile à intégrer.
- De très nombreux fabricants l’intègrent dans leurs gammes produits. On retrouve également beaucoup ModBus dans la gestion technique du bâtiment.
- De nombreux logiciels permettent de communiquer en ModBus: Node-Red, LabView, Matlab, tous les SCADA, … ce qui permet une excellente inter-opérabilité.
- Il n’y a pas de drivers spécifiques à installer, pas de logiciel propriétaire qui est associé, pas de versions de firmware non-compatibles. On est toujours capable de piloter une machine Modbus de 30 ans aujourd’hui avec des logiciels à jour !
Remarque Perso : C’est un protocole que j’apprécie beaucoup. C’est du Low-Tech fiable dont on maîtrise toutes les couches logicielles et dont je peux maîtriser la perennité pour de nombreuses années.
Les limitations de Modbus
- Modbus est un protocole de la fin des années 1970 pour communiquer avec des PLC/ Le nombre de types de données est réduit (coil, register) et les structures ou grands objets binaires ne sont pas supportés.
- Il n’y a pas de standard pour connaître la description d’un objet. Par exemple savoir qu’une valeur de registre représente une donnée entre de température et 0 et 150°C.
- Modbus est basé sur le mode Client/Server (Master/Slave) avec un accès en Polling, il n’y a pas de mécanisme pour que le Slave (Server) envoie des données au Master (Client) suite à un évenement ou par publication/abonnement comme le MQTT. Cela consomme de la bande passante inutilement.
- Modbus a été conçu à une époque où la cybersécurité n’était pas encore une préoccupation majeure, et il ne dispose pas de fonctions de sécurité intégrées. Le protocole ne prend pas en charge le cryptage ou l’authentification, ce qui signifie que les données transmises via Modbus TCP/IP peuvent être facilement interceptées et modifiées. Il est également facile pour des appareils non autorisés de rejoindre un réseau Modbus et de commencer à envoyer des commandes.
- Modbus TCP/IP ne prend pas en charge certaines fonctions modernes de mise en réseau. Par exemple, il ne prend pas en charge la découverte automatique des appareils, ce qui signifie que lorsqu’un nouvel appareil est ajouté à un réseau, son adresse et d’autres détails doivent être configurés manuellement.
- Comme Modbus TCP est basé sur la couche TCP, cela génère des latences et de la gigue incompatible avec le contrôle de processus temps réel (Motion Control par exemple)
Bilan
Comme pour tous les choix techniques, la clé est de comprendre les forces, les faiblesses et l’adéquation du Modbus TCP/IP aux besoins spécifiques de l’application envisagée.
Pour de la surveillance de paramètres du pilotage basique de machine, Modbus TCP reste pertinent aujourd’hui (et demain). Si l’on souhaite synchroniser des mouvements de machines et réaliser du Motion Control, il faut considérer d’autres bus de terrain comme EtherCAT ou Profinet IRT.