ГлавнаяАкадемияNode-RED: установка, flows, msg/JSON, отладка → Работа с шиной RS-485: основы Modbus RTU

Работа с шиной RS-485: основы Modbus RTU

Урок 5 · Node-RED: установка, flows, msg/JSON, отладка · 30 мин · theory

Введение в RS-485 и Modbus RTU: Физический и Протокольный Уровни

Промышленная автоматизация и системы "умного дома" часто требуют подключения устройств, расположенных на значительном удалении друг от друга. Стандартные интерфейсы, такие как I2C или SPI, не подходят для этих задач из-за их малой дальности. Здесь на сцену выходит RS-485 — надежный стандарт физического уровня для последовательной передачи данных.

> ℹ️ Информация: RS-485 определяет только физический уровень (как передавать биты по проводам), а Modbus RTU — протокольный (что означают эти биты). Они работают в паре, как конверт и письмо: RS-485 — это почтовая служба, доставляющая конверт, а Modbus — это язык, на котором написано письмо внутри.

Что такое RS-485?

RS-485 (Recommended Standard 485) — это стандарт, описывающий электрические характеристики драйверов и приёмников для использования в сбалансированных цифровых многоточечных системах.

📋 Ключевые понятия:

Что такое Modbus?

Если RS-485 — это "дорога", то Modbus — это "правила дорожного движения" для устройств. Modbus — это открытый коммуникационный протокол, работающий по принципу "Master-Slave" (Ведущий-Ведомый).

Для того чтобы Master мог обратиться к конкретному Slave-устройству, каждое из них должно иметь уникальный адрес — Slave ID. Это число в диапазоне от 1 до 247. Адрес устанавливается на самом устройстве (с помощью DIP-переключателей или программно).

Структура сообщения (кадра) в Modbus RTU предельно проста и эффективна:

  • Адрес устройства (Slave ID): 1 байт. Указывает, какому устройству предназначен пакет.
  • Код функции (Function Code): 1 байт. Определяет, какое действие нужно выполнить (например, "прочитать данные" или "записать данные").
  • Данные (Data): N байт. Содержат адрес регистра для чтения/записи, количество регистров или сами данные для записи.
  • Контрольная сумма (CRC): 2 байта. Служит для проверки целостности пакета. Если при передаче хоть один бит исказится, CRC на приемной стороне не совпадет, и пакет будет отброшен как ошибочный.
  • Эта простая и надежная архитектура сделала Modbus RTU стандартом де-факто в промышленной автоматизации.

    ---

    Настройка порта RS-485 в контроллере HI

    Правильная настройка физического уровня — залог стабильной работы всей системы. Ошибки, допущенные на этом этапе, являются самой распространенной причиной проблем с Modbus.

    > ⚠️ Внимание: Неправильные параметры порта (скорость, четность) — самая частая причина, почему Modbus-устройства не отвечают. Все устройства на одной шине должны иметь одинаковые настройки.

    Физическое подключение

    На корпусе контроллера HI присутствуют клеммы для подключения шины RS-485, обозначенные как `RS485-A` и `RS485-B`.

  • Соблюдение полярности: Для подключения используется кабель типа "витая пара". Проводник, подключенный к клемме `A` контроллера, должен подключаться к клемме `A` на всех Slave-устройствах. Соответственно, проводник `B` контроллера соединяется с клеммами `B` всех устройств. Путаница в полярности (A -> B, B -> A) приведет к полной неработоспособности шины.
  • Топология "шина": Избегайте топологии "звезда", когда от контроллера идет несколько лучей к разным устройствам. Правильная топология — это одна магистральная линия, к которой короткими отводами подключаются устройства.
  • Настройка параметров порта

    Перед тем как начать обмен данными, необходимо сконфигурировать последовательный порт контроллера. Эти настройки должны быть идентичны настройкам на всех подключенных Modbus-устройствах.

    | Параметр | Описание | Типовые значения |

    | ------------------- | ------------------------------------------------------------------------------------------------------- | -------------------------------------------- |

    | Скорость (Baud Rate) | Скорость передачи данных, измеряется в битах в секунду. | 9600, 19200, 38400, 57600, 115200 |

    | Биты данных (Data Bits) | Количество бит в "полезной" части каждого байта. Для Modbus RTU это всегда 8. | 8 |

    | Четность (Parity) | Механизм проверки на наличие ошибок в одном байте. Может быть 'None' (нет), 'Even' (чет), 'Odd' (нечет). | None (N), Even (E), Odd (O) |

    | Стоп-биты (Stop Bits) | Количество бит, указывающих на окончание передачи одного байта. | 1, 2 |

    Самой распространенной конфигурацией, поддерживаемой большинством устройств по умолчанию, является "9600 8N1":

    Терминирующий резистор (120 Ом)

    На высоких скоростях и длинных линиях (более 50 метров) возникает физический эффект отражения сигнала от концов кабеля. Отраженный сигнал накладывается на основной и искажает его, что приводит к ошибкам передачи данных (ошибки CRC).

    Для подавления этого эффекта на двух физически крайних устройствах шины устанавливается терминирующий резистор номиналом 120 Ом. Он подключается между клеммами A и B.

    > 💡 Подсказка: Если у вас короткая шина (до 10-20 метров) и низкая скорость (9600), система может работать и без терминаторов. Однако их установка является правилом хорошего тона и гарантирует стабильность в будущем.

    ---

    Обзор узлов Node-RED для работы с Modbus

    Для взаимодействия с Modbus-устройствами из Node-RED мы будем использовать популярную и мощную палитру `node-red-contrib-modbus`. Предполагается, что она уже установлена в вашей системе. Если нет, ее можно установить через `Manage Palette` в интерфейсе Node-RED.

    Эта палитра предоставляет набор узлов для выполнения всех необходимых операций.

    Узел `Modbus-Client` (конфигурационный)

    Это не узел потока, а узел конфигурации. Он определяет параметры подключения к шине или устройству и используется затем во всех остальных Modbus-узлах.

  • Создание: `Modbus-Client` создается внутри любого узла (например, `Modbus-Read`) при нажатии на кнопку редактирования сервера.
  • Основные настройки:
  • * Type: Тип подключения. Для работы по RS-485 необходимо выбрать `Serial`.

    * Serial Port: Путь к последовательному порту контроллера. В системе HI это обычно `/dev/ttyS1` или `/dev/ttyS2` (зависит от модели контроллера).

    * Serial Type: Тип протокола. Мы выбираем `RTU`.

    * Baud Rate, Data Bits, Parity, Stop Bits: Здесь задаются параметры порта, которые мы обсуждали в предыдущем разделе (например, `9600`, `8`, `None`, `1`).

    * Unit-ID: Это не адрес Slave-устройства. Это поле в клиенте можно оставить пустым, так как ID конкретного устройства мы будем указывать в каждом узле-запросе.

    Узлы для чтения данных: `Modbus-Read` и `Modbus-Getter`

    Эти узлы отправляют Master-запрос на чтение данных из Slave-устройства.

    Коды функций для чтения:

    Узлы для записи данных: `Modbus-Write`

    Этот узел отправляет Master-запрос на запись данных в Slave-устройство.

    * FC 5 (Write Single Coil): Запись одного бита (включить/выключить реле).

    * FC 6 (Write Single Register): Запись значения в один 16-битный регистр.

    * FC 15 (Write Multiple Coils): Запись состояний сразу нескольких реле.

    * FC 16 (Write Multiple Registers): Запись значений в несколько регистров подряд.

    Выбор узла и кода функции зависит от задачи и от того, что поддерживает конкретное оконечное устройство. Вся эта информация содержится в его документации.

    ---

    Практика: Чтение температуры с Modbus-датчика

    Рассмотрим самый распространенный сценарий: периодическое получение данных с датчика.

    Задача: Каждые 10 секунд считывать значение температуры с комнатного датчика, у которого `Slave ID = 15`. Температура хранится в регистре типа "Input Register" с адресом `0`. Устройство отдает значение в виде целого числа, умноженного на 10 (т.е. значение `253` означает `25.3 °C`).

    > 💡 Подсказка: Всегда изучайте карту регистров (Register Map) вашего устройства. Без нее невозможно понять, по какому адресу находится нужная информация и как ее интерпретировать. Ошибка на единицу в адресе (`off-by-one error`) — очень частое явление. Если в документации указан регистр 30001, его адрес в запросе будет `0`.

    Создание потока

  • Создайте на холсте Node-RED следующую цепочку узлов: `Inject` -> `Modbus-Getter` -> `Function` -> `Debug`.
  • Настройте узел `Inject`:
  • * `Payload`: `timestamp`

    * `Repeat`: `interval`

    * `every`: `10` seconds

  • Настройте узел `Modbus-Getter`:
  • * `Name`: `Read Room Temperature`

    * `Server`: Выберите или создайте `Modbus-Client` с параметрами вашего порта RS-485 (например, `/dev/ttyS1`, `9600`, `8N1`).

    * `Unit-ID`: `15` (адрес нашего датчика).

    * `FC`: `FC 4: Read Input Registers`.

    * `Address`: `0` (адрес регистра температуры).

    * `Quantity`: `1` (мы читаем один 16-битный регистр).

  • Подключите выход `Modbus-Getter` к входу узла `Debug` и разверните поток. В панели отладки вы увидите сообщения.
  • Анализ и обработка ответа

    После успешного опроса `Modbus-Getter` вернет `msg` со сложной структурой. Нас интересует `msg.payload`. Он будет выглядеть примерно так:

    {
    

    "data": [253],

    "buffer": ""

    }

    `data` — это массив полученных значений. В нашем случае это одно значение `253`. Это "сырое" значение (raw value).

    Теперь наша задача — превратить его в понятные градусы Цельсия. Для этого используем узел `Function`.

  • Настройте узел `Function`:
  • * `Name`: `Format Temperature`

    * Добавьте следующий код:

    // Получаем сырое значение из массива
    

    const rawValue = msg.payload.data[0];

    // Согласно документации, делим значение на 10

    const temperature = rawValue / 10.0;

    // Формируем новый, чистый msg.payload в соответствии

    // с "Контрактом сообщения", принятым в нашей академии.

    msg.payload = {

    "value": temperature,

    "unit": "°C",

    "source": "modbus-sensor-room1",

    "ts": Date.now()

    };

    // Для наглядной диагностики выводим статус на узле

    node.status({fill:"green", shape:"dot", text: temperature + " °C"});

    return msg;

    Теперь, если вы подключите выход `Function` к узлу `Debug`, вы будете получать аккуратные JSON-объекты, готовые для дальнейшей обработки — отображения на дашборде, отправки в базу данных или использования в сценариях автоматизации.

    ---

    Практика: Управление Modbus-реле

    Теперь рассмотрим обратную задачу — отправку команды на исполнительное устройство.

    Задача: Включить свет, подключенный к Modbus-релейному модулю с `Slave ID = 20`. Управление происходит через регистр типа "Coil" с адресом `2`. Для включения в него нужно записать `1` (true), для выключения — `0` (false).

    > 🔗 Связанный материал: Принципы формирования объекта `msg` и работы с JSON были подробно рассмотрены в модуле `COURSE-06-M03`. Здесь мы активно их используем для формирования запросов к Modbus-устройствам.

    Создание потока

  • Создайте цепочку: `Inject` -> `Function` -> `Modbus-Write` -> `Debug`.
  • Настройте узел `Inject` так, чтобы он отправлял простое строковое сообщение. Мы сделаем два узла:
  • * Первый `Inject` с `msg.payload` (string) = `ON`.

    * Второй `Inject` с `msg.payload` (string) = `OFF`.

  • Настройте узел `Modbus-Write`:
  • * `Name`: `Control Light Relay`

    * `Server`: Выберите тот же `Modbus-Client`, что и в предыдущем примере.

    * `Unit-ID`: `20`.

    * `FC`: `FC 5: Force Single Coil`.

    * `Address`: `2` (адрес нашего реле).

    * Поле `Value` оставьте пустым — узел будет брать значение из `msg.payload`.

    Формирование команды

    Узел `Modbus-Write` ожидает получить данные для записи в определенном формате. Для записи одного бита (Coil) ему нужен `msg.payload` равный `true` или `false`. Наша задача — преобразовать строки "ON" и "OFF" в булевы значения.

    Можно использовать для этого `Switch` + `Change` узлы, но для простоты сделаем это в одном узле `Function`.

  • Настройте узел `Function`:
  • * `Name`: `Prepare ON/OFF Command`

    * Добавьте код:

    // Команда для записи передается в msg.payload
    

    // Для FC5 это должно быть true или false.

    if (msg.payload === "ON") {

    msg.payload = true;

    } else if (msg.payload === "OFF") {

    msg.payload = false;

    } else {

    // Если пришла неизвестная команда, останавливаем поток.

    node.warn("Неизвестная команда: " + msg.payload);

    return null;

    }

    // Узел Modbus-Write также можно сконфигурировать динамически,

    // передав ему объект с параметрами.

    // Например, так можно управлять разными реле из одного потока.

    /*

    msg.payload = {

    'value': true, // Что пишем

    'fc': 5, // Код функции

    'unitid': 20, // Адрес устройства

    'address': 2, // Адрес регистра

    'quantity': 1 // Количество

    };

    */

    // В нашем простом случае достаточно передать только value.

    return msg;

    Теперь, нажимая на узлы `Inject`, вы будете отправлять команды `true` или `false` на `Modbus-Write`, который, в свою очередь, будет включать или выключать реле. Узел `Debug`, подключенный к выходу `Modbus-Write`, покажет вам ответ от устройства после успешной записи.

    ---

    Итоги и решение типичных проблем

    На этом уроке мы сделали большой шаг от простых дискретных сигналов к полноценной промышленной шине данных. Мы научились подключать, настраивать и взаимодействовать с Modbus RTU устройствами.

    > ⚠️ Внимание: На одной шине RS-485 может быть только один Master. В нашем случае Master — это контроллер HI. Одновременное подключение второго Master (например, ПК с конфигурационной утилитой для настройки устройств) к работающей шине вызовет коллизии (конфликты) и отказ всей шины. Для настройки устройств отключайте их от основной шины или останавливайте опрос в Node-RED.

    Краткое повторение: * `Modbus-Client` — для настройки параметров порта.

    * `Modbus-Getter` — для простого чтения данных.

    * `Modbus-Write` — для отправки команд.

    Чек-лист для отладки "Modbus не работает"

    Если устройства не отвечают, пройдитесь по этому списку:

  • Физическое подключение: Проверьте полярность A/B. Убедитесь в надежности контактов.
  • Настройки порта: Убедитесь, что скорость, четность и стоп-биты в `Modbus-Client` точно совпадают с настройками на всех устройствах.
  • Slave ID: Проверьте, что `Unit-ID` в узле Node-RED соответствует адресу, установленному на самом устройстве.
  • Адрес регистра: Перепроверьте карту регистров. Не забыли ли вы про ошибку "off-by-one"? Правильный ли тип регистра вы читаете (Input vs Holding)?
  • Терминирующие резисторы: Если шина длинная или работает на высокой скорости, убедитесь, что на двух крайних устройствах установлены терминаторы 120 Ом.
  • Питание: Убедитесь, что на оконечное устройство подано питание. Это банально, но часто является причиной проблем.
  • В следующем уроке мы рассмотрим более сложные сценарии работы с Modbus, включая чтение нескольких регистров за раз, обработку 32-битных чисел и float-значений.