[Перевод] О протоколе Modbus и Intel Edison
Modbus — это широко известный коммуникационный протокол, который нашёл применение и в промышленности, и в любительских проектах. На физическом уровне для организации связи между устройствами по этому протоколу могут использоваться последовательные интерфейсы (RS232 или RS485) или Ethernet (здесь задействованы протоколы TCP или UDP). Сегодня мы поговорим о том, как организовать взаимодействие Intel Edison с другими устройствами с помощью Modbus.
Библиотеки
Существует немало Linux-библиотек, которые позволяют пользоваться Modbus. Среди них следующие:
- C/C++, например, libmodbus.
- Node, например, «modbus» — обёртка для libmodbus.
- Python, например, pymodbus
Установка
Процедура установки зависит от выбранной библиотеки. Рассмотрим установку для трёх вышеупомянутых библиотек.
- Libmodbus. Нужно либо собрать библиотеку из исходных текстов, либо — установить пакет, например, с repo.opkg.net с помощью команды «opkg install libmodbus».
- Для установки node modbus понадобится команда «npm install modbus»
- Для pymodbus — команда «pip install pymodbus». Pip можно взять, например, с repo.opkg.net.
Тестирование
Для тестов мы используем pymodbus, который поставляется с примерами клиентского и серверного кода.
Тестирование при использовании последовательного интерфейса
Для начала нужно установить дополнительный пакет, «pyserial». Сделать это можно с помощью такой команды:
pip install pyserial
Для того, чтобы протестировать связь по последовательному интерфейсу, используем две коммутационные платы Intel Edison Arduino. TX и RX которых перекрёстно соединены, то есть, IO-выход 0 первой платы подключён к IO-выходу 1 второй платы и наоборот. Для того, чтобы эту конструкцию протестировать, используем слегка модифицированный код примера «синхронный сервер» на одной плате, а на другой — код из примера «синхронный клиент».
Вот изменения, внесённые в серверный код.
# запустите нужный сервер
# ----------------
# Tcp:
# StartTcpServer(context, identity=identity, address=("localhost", 5020))
# Udp:
# StartUdpServer(context, identity=identity, address=("localhost", 502))
# Ascii:
# StartSerialServer(context, identity=identity, port='/dev/pts/3', timeout=1)
# RTU:
import mraa, serial as s
mraa.Uart(0)
StartSerialServer(context, identity, port='/dev/ttyMFD1', stopbits=s.STOPBITS_ONE, bytesize=s.EIGHTBITS, baudrate=115200, parity=s.PARITY_NONE)
А вот — наш код клиента:
[...]
# client = ModbusClient('localhost', retries=3, retry_on_empty=True)
# ---------------------------------------------------------------------------#
# client = ModbusClient('localhost', port=502)
# client = ModbusClient(method='ascii', port='/dev/pts/2', timeout=1)
# client = ModbusClient(method='rtu', port='/dev/pts/2', timeout=1)
import mraa, serial as s
mraa.Uart(0)
client = ModbusClient(method='rtu', port='/dev/ttyMFD1', stopbits=1, bytesize=8, baudrate=115200, parity=s.PARITY_NONE)
client.connect()
[...]
Последовательный порт инициализируется посредством MRAA. После этого Modbus может работать с »/dev/ttyMFD1».
Если всё настроено правильно, то можно будет на сервере увидеть сообщения Modbus, приходящие от клиента.
TCP/IP через Ethernet (например, WiFi)
Для того, чтобы протестировать взаимодействие по протоколу modbus через Ethernet, мы воспользовались примерами «асинхронный сервер» и «асинхронный клиент», снова слегка отредактировав их код.
Серверу назначен IPv4-адрес xxx.xxx.xxx.xxx и некий порт (5020 в нашем случае).
[...]
StartTcpServer(context, identity=identity, address=("xxx.xxx.xxx.xxx", 5020))
А вот аналогичные настройки клиента:
[...]
#---------------------------------------------------------------------------#
defer = protocol.ClientCreator(reactor, ModbusClientProtocol
).connectTCP("xxx.xxx.xxx.xxx", 5020)
defer.addCallback(beginAsynchronousTest)
reactor.run()
Если всё, опять же, настроено верно, можно будет увидеть сообщения от клиентской части системы, приходящие на сервер. Например, они могут выглядеть так:
# python AsynchronousServerExample.py
INFO:pymodbus.server.async:Starting Modbus TCP Server on 192.168.178.72:5020
DEBUG:pymodbus.server.async:Client Connected [IPv4Address(TCP, '192.168.178.72', 5020)]
DEBUG:pymodbus.server.async:0x0 0x1 0x0 0x0 0x0 0x6 0x0 0x5 0x0 0x1 0xff 0x0 0x0 0x2 0x0 0x0 0x0 0x6 0x0 0x1 0x0 0x1 0x0 0x1 0x0 0x3 0x0 0x0 0x0 0x8 0x0 0xf 0x0 0x1 0x0 0x8 0x1 0xff 0x0 0x4 0x0 0x0 0x0 0x6 0x0 0x1 0x0 0x1 0x0 0x8 0x0 0x5 0x0 0x0 0x0 0x8 0x0 0xf 0x0 0x1 0x0 0x8 0x1 0x0 0x0 0x6 0x0 0x0 0x0 0x6 0x0 0x2 0x0 0x1 0x0 0x8 0x0 0x7 0x0 0x0 0x0 0x6 0x0 0x6 0x0 0x1 0x0 0xa 0x0 0x8 0x0 0x0 0x0 0x6 0x0 0x3 0x0 0x1 0x0 0x1 0x0 0x9 0x0 0x0 0x0 0x17 0x0 0x10 0x0 0x1 0x0 0x8 0x10 0x0 0xa 0x0 0xa 0x0 0xa 0x0 0xa 0x0 0xa 0x0 0xa 0x0 0xa 0x0 0xa 0x0 0xa 0x0 0x0 0x0 0x6 0x0 0x4 0x0 0x1 0x0 0x8 0x0 0xb 0x0 0x0 0x0 0x1b 0x0 0x17 0x0 0x1 0x0 0x8 0x0 0x1 0x0 0x8 0x10 0x0 0x14 0x0 0x14 0x0 0x14 0x0 0x14 0x0 0x14 0x0 0x14 0x0 0x14 0x0 0x14 0x0 0xc 0x0 0x0 0x0 0x6 0x0 0x4 0x0 0x1 0x0 0x8
DEBUG:pymodbus.transaction:0x0 0x1 0x0 0x0 0x0 0x6 0x0 0x5 0x0 0x1 0xff 0x0 0x0 0x2 0x0 0x0 0x0 0x6 0x0 0x1 0x0 0x1 0x0 0x1 0x0 0x3 0x0 0x0 0x0 0x8 0x0 0xf 0x0 0x1 0x0 0x8 0x1 0xff 0x0 0x4 0x0 0x0 0x0 0x6 0x0 0x1 0x0 0x1 0x0 0x8 0x0 0x5 0x0 0x0 0x0 0x8 0x0 0xf 0x0 0x1 0x0 0x8 0x1 0x0 0x0 0x6 0x0 0x0 0x0 0x6 0x0 0x2 0x0 0x1 0x0 0x8 0x0 0x7 0x0 0x0 0x0 0x6 0x0 0x6 0x0 0x1 0x0 0xa 0x0 0x8 0x0 0x0 0x0 0x6 0x0 0x3 0x0 0x1 0x0 0x1 0x0 0x9 0x0 0x0 0x0 0x17 0x0 0x10 0x0 0x1 0x0 0x8 0x10 0x0 0xa 0x0 0xa 0x0 0xa 0x0 0xa 0x0 0xa 0x0 0xa 0x0 0xa 0x0 0xa 0x0 0xa 0x0 0x0 0x0 0x6 0x0 0x4 0x0 0x1 0x0 0x8 0x0 0xb 0x0 0x0 0x0 0x1b 0x0 0x17 0x0 0x1 0x0 0x8 0x0 0x1 0x0 0x8 0x10 0x0 0x14 0x0 0x14 0x0 0x14 0x0 0x14 0x0 0x14 0x0 0x14 0x0 0x14 0x0 0x14 0x0 0xc 0x0 0x0 0x0 0x6 0x0 0x4 0x0 0x1 0x0 0x8
DEBUG:pymodbus.factory:Factory Request[5]
DEBUG:pymodbus.datastore.context:validate[5] 2:1
DEBUG:pymodbus.datastore.context:setValues[5] 2:1
DEBUG:pymodbus.datastore.context:getValues[5] 2:1
DEBUG:pymodbus.server.async:send: 00010000000600050001ff00
DEBUG:pymodbus.factory:Factory Request[1]
DEBUG:pymodbus.datastore.context:validate[1] 2:1
DEBUG:pymodbus.datastore.context:getValues[1] 2:1
DEBUG:pymodbus.server.async:send: 00020000000400010101
Итоги
Приведённый здесь пример позволит наладить взаимодействие по протоколу Modbus между Intel Edison и различными устройствами, используя в качестве среды передачи данных последовательные интерфейсы или Ethernet. Решение это весьма популярное и универсальное, поэтому, уверены, вы найдёте ему полезное применение.