Open source Modbus TCP — RTU конвертор

от автора

Добрый день коллеги, поговорим о прозрачном конверторе Modbus TCP в Modbus RTU.

Казалось бы, что выбор ограничен несколькими проприетарными продуктами, которые не всегда удовлетворяют нашим потребностям.

Мы предложим свободно программируемый контроллер AntexGate с помощью которого можно получить конвертер Modbus tcp – Modbus rtu – can – profitnet – bacnet – mqtt – http – opc UA – другой протокол.

Итак, рассмотрим первую связку Modbus TCP – Modbus RTU, нам понадобится сам контроллер AntexGate либо другой компьютер с linux/windows на борту и периферией RS485.

Первое, что необходимо – это установить программный продукт Node-Red, это делается одним скриптом:

bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)

Сделать Node-red после установки сервисом:

sudo systemctl enable nodered.service

Перезагружаем железяку:

sudo reboot

Теперь попадаем в среду нашего программного конвертора Node-red через web браузер по ссылке ip шлюза:1880

Далее настроим скрипт, который конвертирует посылку Modbus TCP в RTU, посылает в RS485 порт, ждет ответ и тут же преобразует ответ обратно в Modbus TCP.

Заходим в «меню» > «импорт»

Проект конвертора Modbus TCP <> RTU
[     {         "id": "22ff3060.54da6",         "type": "function",         "z": "de082ac2.4b8bf8",         "name": "Convert TCP to RTU",         "func": "var MBAPHeader = [5];\nvar crc = 0xFFFF;\n\nMBAPHeader[0]= msg.payload[0];\nMBAPHeader[1]= msg.payload[1];\nMBAPHeader[2]= msg.payload[2];\nMBAPHeader[3]= msg.payload[3];\nMBAPHeader[4]= msg.payload[4];\nflow.set('MBAP_HEADER', MBAPHeader);\n\nvar ReqLen = msg.payload[5];\nvar MBLen = (msg.payload.length)-ReqLen;\nvar MBReq = [MBLen];\n\nfor (let x=0; x < MBLen;x++){\n  MBReq[x] = msg.payload[x+ReqLen];\n}\n\nfor (var req = 0; req < ReqLen; req++) {\n  crc ^= MBReq[req];          // XOR byte into least sig. byte of crc\n  \n  for (var i = 8; i !== 0; i--) {    // Loop over each bit\n    if ((crc & 0x0001) !== 0) {      // If the LSB is set\n        crc >>= 1;                   // Shift right and XOR 0xA001\n        crc ^= 0xA001;\n    } else {                          // Else LSB is not set\n      crc >>= 1;                     // Just shift right\n    }\n  }\n}\n\nvar MyCRC = crc.toString(16);\nMBReq[MBLen+1] = parseInt(MyCRC.substring(0,2),16);\nMBReq[MBLen] = parseInt(MyCRC.substring(2,4),16);\n\nvar buf = new Buffer(MBReq);\nmsg.payload = buf;\nreturn msg;",         "outputs": 1,         "noerr": 0,         "initialize": "",         "finalize": "",         "libs": [],         "x": 300,         "y": 100,         "wires": [             [                 "7e62bbbc.bd8ea4"             ]         ],         "outputLabels": [             "XO"         ]     },     {         "id": "7e62bbbc.bd8ea4",         "type": "serial request",         "z": "de082ac2.4b8bf8",         "name": "",         "serial": "27dabad398437b7e",         "x": 490,         "y": 100,         "wires": [             [                 "db79ee80.1d792",                 "9e53f02d0a4e04fb"             ]         ]     },     {         "id": "db79ee80.1d792",         "type": "function",         "z": "de082ac2.4b8bf8",         "name": "Convert RTU to TCP",         "func": "if (msg.payload.length > 0) {\n  var resLen = msg.payload.length - 2;\n  var respond = [];\n  respond[0] = flow.get('MBAP_HEADER')[0];\n  respond[1] = flow.get('MBAP_HEADER')[1];\n  respond[2] = flow.get('MBAP_HEADER')[2];\n  respond[3] = flow.get('MBAP_HEADER')[3];\n  respond[4] = flow.get('MBAP_HEADER')[4];\n  respond[5] = resLen;\n\n  for (let req = 6; req < resLen+6; req++) {\n    respond[req]= msg.payload[req-6];\n  }\n  msg.payload = new Buffer(respond);\n  return msg;\n} else {\n   return null;\n}\n",         "outputs": 1,         "noerr": 0,         "initialize": "",         "finalize": "",         "libs": [],         "x": 640,         "y": 60,         "wires": [             [                 "2622a1e893f52bed",                 "140a62f5366490d9"             ]         ]     },     {         "id": "55423964225fa869",         "type": "comment",         "z": "de082ac2.4b8bf8",         "name": "Convert Modbus TCP to Modbus RTU",         "info": "",         "x": 170,         "y": 40,         "wires": []     },     {         "id": "cbd6e86861af643d",         "type": "tcp in",         "z": "de082ac2.4b8bf8",         "name": "Modbus TCP - IN",         "server": "server",         "host": "",         "port": "5002",         "datamode": "stream",         "datatype": "buffer",         "newline": "",         "topic": "",         "trim": false,         "base64": false,         "tls": "",         "x": 100,         "y": 100,         "wires": [             [                 "22ff3060.54da6",                 "48471bdeae3a1d30"             ]         ]     },     {         "id": "2622a1e893f52bed",         "type": "tcp out",         "z": "de082ac2.4b8bf8",         "name": "Modbus TCP - OUT",         "host": "127.0.0.1",         "port": "502",         "beserver": "reply",         "base64": false,         "end": false,         "x": 850,         "y": 100,         "wires": []     },     {         "id": "9e53f02d0a4e04fb",         "type": "debug",         "z": "de082ac2.4b8bf8",         "name": "debug 17",         "active": true,         "tosidebar": true,         "console": false,         "tostatus": false,         "complete": "false",         "statusVal": "",         "statusType": "auto",         "x": 640,         "y": 220,         "wires": []     },     {         "id": "140a62f5366490d9",         "type": "debug",         "z": "de082ac2.4b8bf8",         "name": "debug 18",         "active": true,         "tosidebar": true,         "console": false,         "tostatus": false,         "complete": "false",         "statusVal": "",         "statusType": "auto",         "x": 820,         "y": 200,         "wires": []     },     {         "id": "48471bdeae3a1d30",         "type": "debug",         "z": "de082ac2.4b8bf8",         "name": "debug 19",         "active": true,         "tosidebar": true,         "console": false,         "tostatus": false,         "complete": "false",         "statusVal": "",         "statusType": "auto",         "x": 260,         "y": 200,         "wires": []     },     {         "id": "27dabad398437b7e",         "type": "serial-port",         "serialport": "/dev/ttyUSB0",         "serialbaud": "115200",         "databits": "8",         "parity": "none",         "stopbits": "1",         "waitfor": "",         "dtr": "none",         "rts": "none",         "cts": "none",         "dsr": "none",         "newline": "5",         "bin": "bin",         "out": "time",         "addchar": "",         "responsetimeout": "1000"     } ] 

Копируем скрипт, нажимаем «Импорт»

 

Настраиваем порт для просушки в узле Modbus TCP IN, рекомендуем не использовать стандартный 502, а использовать нестандартный порт более 1024, для них не нужны дополнительные разрешения в Linux.

Настраиваем последовательный порт RS485/232 на скорость конечного железа, поддерживающего протокол Modbus RTU.

Жмем «Развернуть» и спустя 20 минут наш конвертер готов!

Настраиваем Ваш инструмент верхнего уровня, например Modbus TCP OPC сервер стандартно: ip_адре_ шлюза:5002:id_RTU_устройства.

Все работает стабильно — чтение и запись! Посылки как видим между запросом и ответом 100-200мс, что равно пингу. Удаленный шлюз AntexGate работает на встроенном LTE модеме.

Замер пинга до шлюза, доступ через VPN WireGuard.

Замер пинга до шлюза, доступ через VPN WireGuard.

Бонусом, для тех, у кого софт верхнего уровня поддерживает функцию Modbus RTU поверх TCP включаем это правило.

В Node-Red упрощаем поток и исключаем функции RTU TCP обработки, и наш проект в Node-Red становится без единой строчки кода.

Контроллер AntexGate в связке с Node-red является отличным универсальным решением для обработки, пересылки и хранения данных. Прошу прощения за рекламу, однако выше представленный проект Вы можете реализовать на любом железе и любой ОС.

Присоединяйтесь к нашему сообществу в Telegram

Железо можно получить на тесты, пишите на почту: info@antexcloud.ru (на три месяца для ЮР лиц и ИП)

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Какой конвертер вы часто используете?

12.5% Modbus TCP — Modbus RTU1
25% Modbus — MQTT2
12.5% CAN — TCP1
0% Modbus — Profinet0
12.5% Modbus — BacNet1
50% Другой4

Проголосовали 8 пользователей. Воздержались 5 пользователей.

ссылка на оригинал статьи https://habr.com/ru/articles/820281/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *