ГлавнаяАкадемияNode-RED: установка, flows, msg/JSON, отладка → Чтение аналоговых входов (4-20мА / 0-10В)

Чтение аналоговых входов (4-20мА / 0-10В)

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

Введение в аналоговые сигналы: 0-10В и 4-20мА

В предыдущих уроках, например, при рассмотрении чтения дискретных входов, мы работали с сигналами, которые имеют всего два состояния: "включено" или "выключено", "есть контакт" или "нет контакта", логическая "1" или "0". Однако для измерения плавно меняющихся физических величин — таких как температура, давление, влажность или уровень освещенности — дискретных сигналов недостаточно. Здесь на сцену выходят аналоговые сигналы.

Аналоговый сигнал — это сигнал, который может принимать любое значение в заданном непрерывном диапазоне. В отличие от дискретного "да/нет", аналоговый сигнал говорит "насколько": не просто "жарко", а "+25.3 °C"; не просто "светло", а "освещенность 500 люкс".

В современной автоматизации зданий и промышленности доминируют два основных стандарта аналоговых сигналов: 0-10В (по напряжению) и 4-20мА (по току).

Области применения и ключевые отличия

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

| Характеристика | Стандарт 0-10В | Стандарт 4-20мА (Токовая петля) |

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

| Принцип работы | Измеряемая величина кодируется уровнем напряжения от 0 до 10 Вольт. | Измеряемая величина кодируется силой тока от 4 до 20 миллиампер. |

| Типовые применения | Управление диммируемыми светильниками, управление клапанами и заслонками в системах вентиляции (HVAC), управление скоростью вентиляторов. | Промышленные датчики давления, расхода, уровня, температуры, влажности. Датчики для ответственных систем и длинных линий. |

| Помехоустойчивость | Средняя. Напряжение чувствительно к электромагнитным наводкам от силовых кабелей, что может приводить к искажению показаний. | Высокая. Токовый сигнал значительно менее подвержен влиянию внешних помех, что делает его идеальным для промышленных сред. |

| Длина линии | Ограничена. На длинных линиях (>15-20 м) падение напряжения на сопротивлении кабеля может вносить существенную погрешность. | Может достигать сотен метров без значительной потери точности, так как ток в последовательной цепи одинаков в любой точке. |

| Диагностика обрыва | Сложная. Уровень сигнала 0В может означать как 0% измеряемой величины, так и обрыв провода. Невозможно различить эти состояния. | Простая и надежная. Уровень сигнала 4мА соответствует 0% измеряемой величины. Если же контроллер измеряет ток близкий к 0мА, это однозначно указывает на обрыв линии или неисправность датчика. |

| Питание датчика | Обычно требует отдельной линии питания (3 или 4 провода). | Часто датчик может питаться непосредственно от самой токовой петли (2-проводная схема), что упрощает монтаж. |

> ℹ️ Информация: Сигнал 4-20мА часто называют "живым нулем" (live zero). Это свойство — когда минимальное значение измеряемой величины (например, 0 бар давления) соответствует ненулевому сигналу (4мА) — является его ключевым преимуществом. Оно позволяет системе мониторинга мгновенно отличить штатную работу на нулевой отметке от аварийной ситуации, такой как обрыв кабеля или выход датчика из строя.

Физическое подключение к контроллеру HI

Контроллер HI оснащен универсальными входами (UI), которые могут быть сконфигурированы для работы с различными типами сигналов, включая 0-10В и 4-20мА.

  • Настройка оборудования: Прежде чем программировать вход, необходимо подготовить его физически. На плате контроллера рядом с клеммной колодкой каждого универсального входа расположены перемычки (джамперы). Для работы с аналоговыми сигналами их нужно установить в соответствующее положение согласно инструкции к контроллеру.
  • * Режим 0-10В: Джампер устанавливается в положение "V" (Voltage).

    * Режим 4-20мА: Джампер устанавливается в положение "I" (Current). Это физически подключает к входу прецизионный шунтирующий резистор, который преобразует ток в напряжение для дальнейшего измерения аналого-цифровым преобразователем.

  • Подключение проводов:
  • * Для сигнала 0-10В используется два провода: сигнальный провод от датчика подключается к клемме UI, а общий провод (GND) датчика — к клемме GND контроллера.

    * Для сигнала 4-20мА также используются два провода, образующие "петлю". Схема подключения зависит от типа датчика (с внешним питанием или с питанием от петли). В простейшем случае выход датчика `Iout` подключается к клемме UI, а второй провод петли замыкается на GND источника питания датчика, который должен быть также соединен с GND контроллера.

    > ⚠️ Внимание: Всегда сверяйтесь со схемой подключения конкретного датчика и инструкцией к контроллеру HI. Неправильное подключение или неверно установленный джампер может привести к выходу из строя как входа контроллера, так и самого датчика.

    ---

    Конфигурация универсальных входов контроллера HI

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

    > ⚠️ Внимание: Перед программной сменой режима входа на '4-20мА' или '0-10В' ОБЯЗАТЕЛЬНО убедитесь, что соответствующие джамперы на плате контроллера установлены в правильное положение. Несоответствие аппаратной и программной конфигурации может привести к некорректным измерениям, а в худшем случае — к выходу из строя порта или подключенного датчика.

    Работа с картой регистров контроллера

    Контроллер HI, помимо управления внешними устройствами, предоставляет доступ к своим собственным настройкам и данным через протокол Modbus TCP. Вся информация о доступных параметрах содержится в документе "Карта регистров" (Register Map), который является главным справочником для интегратора.

    В этой карте для каждого универсального входа (UI) обычно есть как минимум два важных адреса:

  • Регистр конфигурации: Это Holding Register (обычно функция FC6/FC16), в который мы записываем код, соответствующий желаемому режиму работы (например, `0` - дискретный вход, `1` - 0-10В, `2` - 4-20мА, `3` - NTC датчик температуры и т.д.).
  • Регистр данных: Это Input Register (обычно функция FC4), из которого мы читаем измеренное значение.
  • 'Сырое' значение АЦП

    Важно понимать, что контроллер не отдает нам сразу готовые градусы Цельсия или бары. Он отдает 'сырое' значение (raw value) — это целочисленный результат работы внутреннего Аналого-Цифрового Преобразователя (АЦП). АЦП измеряет напряжение на входе и представляет его в виде числа.

    Разрядность АЦП определяет диапазон 'сырых' значений. Например, для 12-битного АЦП диапазон составляет от 0 до 4095 (2^12 - 1).

    Наша задача как инженеров — сначала прочитать это 'сырое' число, а затем, зная характеристики датчика, преобразовать его в понятную физическую величину.

    Пример конфигурации входа

    Предположим, согласно карте регистров контроллера HI (Unit-ID 1), универсальный вход №3 (UI-03) настраивается через Holding Register с адресом `102`. Значения для режимов следующие:

    Чтобы перевести UI-03 в режим измерения напряжения 0-10В, нам нужно в Node-RED отправить Modbus-команду на наш же контроллер.

  • Создаем поток: Используем узел `Inject` (для разовой отправки) и `Modbus-Write`.
  • Настраиваем `Modbus-Write`:
  • * Server: Создаем новый Modbus TCP клиент с IP-адресом `127.0.0.1` (или `localhost`) и портом `502`. Это указывает, что мы обращаемся к самому контроллеру.

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

    * FC: `FC 6: Write Single Register`.

    * Address: `102` (адрес регистра конфигурации для UI-03).

    * Value: `1` (код режима 0-10В).

    После нажатия на узел `Inject` контроллер получит команду и переконфигурирует свой универсальный вход UI-03 для измерения напряжения. Теперь он готов к приему данных от датчика.

    ---

    Чтение 'сырых' значений в Node-RED

    После того как вход сконфигурирован, следующим шагом является организация периодического чтения 'сырых' значений с этого входа. Для этого мы снова будем использовать протокол Modbus и палитру `node-red-contrib-modbus`.

    > 💡 Подсказка: Для большинства задач периодического опроса датчиков (раз в 1-10 секунд) удобнее использовать встроенную в узел `Modbus-Read` функцию 'Poll', а не создавать отдельный поток с `Inject`. Это делает поток более читаемым, компактным и избавляет от лишних узлов.

    Настройка узла Modbus-Read

    Предположим, мы хотим каждые 5 секунд читать 'сырое' значение с нашего входа UI-03, который мы ранее настроили. Согласно карте регистров, измеренное значение АЦП для UI-03 находится в Input Register с адресом `202`.

    Построим поток:
    // Простой поток для чтения аналогового входа
    

    [Modbus-Read: Читать UI-03] ----> [Debug: Сырое значение]

    Конфигурация узла `Modbus-Read`:
  • Name: "Читать UI-03 Raw" (осмысленное имя крайне важно для читаемости потока).
  • Topic: Можно оставить пустым или указать, например, `raw/ui-03`.
  • Poll: Устанавливаем галочку `Poll` и вводим интервал `5 seconds`. Это активирует встроенный механизм периодического опроса.
  • Unit-ID: `1` (адрес нашего контроллера).
  • FC: `FC 4: Read Input Registers` (так как мы читаем измеренное значение).
  • Address: `202` (адрес регистра данных для UI-03).
  • Quantity: `1` (мы читаем одно 16-битное значение).
  • Server: Выбираем тот же Modbus-сервер (`127.0.0.1:502`), который мы создали ранее.
  • После развертывания этого потока узел `Modbus-Read` будет автоматически каждые 5 секунд отправлять запрос контроллеру, получать ответ и передавать его дальше.

    Анализ выходного сообщения

    Давайте посмотрим, что именно узел `Modbus-Read` отправляет на выход. Если мы подключим к нему узел `Debug`, настроенный на отображение всего объекта `msg`, мы увидим примерно следующее:

    {
    

    "topic": "raw/ui-03",

    "payload": [ 2048 ],

    "responseBuffer": {

    "type": "Buffer",

    "data": [ 8, 0 ]

    },

    "_msgid": "a1b2c3d4.e5f6g7"

    }

    Ключевой для нас является часть `msg.payload`. По умолчанию узел `Modbus-Read` возвращает 'сырые' значения в виде массива чисел. В данном случае `[2048]` означает, что АЦП измерил значение, соответствующее середине своего диапазона (так как 2048 ≈ 4095 / 2).

    > 🔗 Связанный материал: Как мы уже обсуждали в рамках паттерна "Контракт сообщения", работа с такими "сырыми" форматами напрямую в логике является плохой практикой. Следующим шагом всегда должно быть преобразование этого значения в стандартизированный JSON-объект.

    На этом этапе мы добились главного: система автоматически и периодически получает 'сырые' данные с аналогового входа. Теперь нам предстоит превратить эти абстрактные цифры в реальные физические величины.

    ---

    Масштабирование 'сырых' значений в физические величины

    Мы получили 'сырое' значение `2048`, но что оно означает? Это 5В? +50°C? Давление в 4 бара? Без масштабирования это просто число. Масштабирование (или калибровка) — это процесс преобразования значения из одного диапазона (диапазон АЦП) в другой (диапазон физической величины датчика) с помощью математической функции.

    Для большинства аналоговых датчиков эта зависимость является линейной, поэтому мы можем использовать простую формулу линейной интерполяции:

    `Output = Output_start + (Input - Input_start) * (Output_end - Output_start) / (Input_end - Input_start)`

    Где:

    Определение диапазонов

    Чтобы применить эту формулу, нам нужно знать четыре ключевых параметра, которые мы берем из документации на датчик и контроллер:

  • Выходной диапазон (Output Range): Указан в паспорте датчика. Например, "датчик давления 0...10 бар" или "датчик температуры -20...+80 °C". Отсюда мы берем `Output_start` и `Output_end`.
  • Входной диапазон (Input Range): Это диапазон 'сырых' значений АЦП, который соответствует диапазону сигнала датчика.
  • * Для 0-10В: Если АЦП 12-битный, то `Input_start = 0` (для 0В) и `Input_end = 4095` (для 10В).

    * Для 4-20мА: Здесь сложнее. Мы должны знать, какому 'сырому' значению соответствуют 4мА и 20мА. Эти значения зависят от номинала шунтирующего резистора и настроек АЦП контроллера. Предположим, в документации на контроллер HI указано, что для 12-битного АЦП в режиме 4-20мА диапазон 'сырых' значений составляет 819...4095. Тогда `Input_start = 819`, `Input_end = 4095`.

    Пример расчета

    Давайте рассчитаем показания для датчика давления 0-10 бар, подключенного по стандарту 4-20мА.

    Предположим, мы прочитали 'сырое' значение (`Input`) равное `3000`.

    Подставляем в формулу:

  • `(Input - Input_start)` = 3000 - 819 = 2181
  • `(Output_end - Output_start)` = 10 - 0 = 10
  • `(Input_end - Input_start)` = 4095 - 819 = 3276
  • `Output = 0 + 2181 * 10 / 3276`
  • `Output = 21810 / 3276` ≈ `6.657` бар
  • Таким образом, 'сырое' значение `3000` соответствует давлению примерно 6.66 бар. Эту логику мы и будем реализовывать в Node-RED.

    ---

    Практика: Flow для датчика температуры 4-20мА

    Теперь соберем все воедино и создадим полноценный поток для чтения данных с канального датчика температуры в системе вентиляции.

    Задача:

    > 💡 Подсказка: Для простого линейного масштабирования можно использовать узел `node-red-contrib-range`. Он работает как функция `map()` в Arduino и позволяет настроить входной и выходной диапазоны в графическом интерфейсе, что избавляет от написания кода в узле `Function`. Однако для полного контроля над логикой (обработка ошибок, валидация) узел `Function` является более мощным инструментом.

    Построение потока:
    // Поток считывания и масштабирования данных с датчика температуры
    

    [Modbus-Read: Читать T-датчик] --> [Function: Масштабировать] --> [Debug: Температура °C]

    1. Узел `Modbus-Read`

    Настраиваем его так, как было описано ранее, для чтения одного Input Register (например, с адресом `202`) с интервалом `10 seconds`.

    2. Узел `Function`

    Это сердце нашего преобразования. В нем мы напишем JavaScript-код, реализующий формулу масштабирования.

    // 1. Получаем 'сырое' значение из входящего сообщения
    

    // msg.payload от Modbus-Read узла приходит как массив, например [2500]

    const rawValue = msg.payload[0];

    // 2. Определяем константы для масштабирования

    // Входной диапазон (сырые значения АЦП)

    const INPUT_MIN = 819; // для 4мА

    const INPUT_MAX = 4095; // для 20мА

    // Выходной диапазон (физические значения датчика)

    const OUTPUT_MIN = -20.0; // для 4мА

    const OUTPUT_MAX = 80.0; // для 20мА

    // 3. Валидация 'сырого' значения

    // Проверяем на обрыв линии (значение сильно ниже минимального)

    if (rawValue < 200) { // Порог для детекции обрыва

    node.status({ fill: "red", shape: "dot", text: "Обрыв линии. Raw: " + rawValue });

    node.error("Обрыв линии датчика. Получено значение: " + rawValue, msg);

    return null; // Прерываем поток

    }

    // Проверяем, что значение в рабочем диапазоне. Если нет, возможно, короткое замыкание или неисправность.

    if (rawValue < INPUT_MIN || rawValue > INPUT_MAX) {

    node.status({ fill: "yellow", shape: "ring", text: "Вне диапазона. Raw: " + rawValue });

    node.warn("Значение вне рабочего диапазона: " + rawValue, msg);

    // Можно прервать поток или продолжить обработку, ограничив значение.

    // В данном случае, мы ограничим его для стабильности.

    if (rawValue < INPUT_MIN) rawValue = INPUT_MIN;

    if (rawValue > INPUT_MAX) rawValue = INPUT_MAX;

    }

    // 4. Выполняем масштабирование по линейной формуле

    const inputRange = INPUT_MAX - INPUT_MIN;

    const outputRange = OUTPUT_MAX - OUTPUT_MIN;

    let temperature = OUTPUT_MIN + (rawValue - INPUT_MIN) * outputRange / inputRange;

    // Округляем до одного знака после запятой для аккуратности

    temperature = Math.round(temperature * 10) / 10;

    // 5. Формируем исходящее сообщение в соответствии с 'Контрактом сообщения'

    msg.payload = {

    value: temperature,

    unit: "°C",

    source: "temp-sensor-duct-01", // Уникальный ID источника

    ts: Date.now()

    };

    // 6. Обновляем статус узла для визуальной диагностики

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

    return msg;

    3. Узел `Debug`

    Подключаем его к выходу узла `Function`. После развертывания потока мы увидим в панели отладки сообщения следующего вида:

    {
    

    "value": 25.4,

    "unit": "°C",

    "source": "temp-sensor-duct-01",

    "ts": 1678886400000

    }

    Это и есть конечный результат нашей работы: понятное, готовое к использованию значение температуры, которое теперь можно отправлять в базы данных (MySQL), системы визуализации (Grafana), использовать в логике управления климатом и так далее. Мы успешно прошли весь путь от аналогового сигнала на клемме контроллера до цифровых данных в нашей системе автоматизации.

    ---

    Итоги и дальнейшие шаги

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

    Ключевые этапы, которые мы прошли:
  • Теоретическая подготовка: Поняли разницу между стандартами 0-10В и 4-20мА, их преимущества и недостатки.
  • Аппаратная конфигурация: Научились устанавливать перемычки (джамперы) на контроллере для выбора режима работы универсального входа.
  • Программная конфигурация: Разобрались, как с помощью Modbus-команд настроить контроллер на чтение аналогового сигнала.
  • Чтение 'сырых' данных: Создали поток в Node-RED, который периодически опрашивает контроллер и получает 'сырые' значения от АЦП.
  • Масштабирование: Освоили важнейший навык — преобразование абстрактных 'сырых' значений в реальные, понятные физические величины с помощью линейной функции.
  • Теперь вы умеете подключать и обрабатывать данные с подавляющего большинства промышленных и бытовых датчиков, что открывает широкие возможности для построения сложных систем автоматизации.

    Продвинутые сценарии

    На базе полученных знаний можно реализовывать более сложные сценарии:

    Что дальше?

    Мы научились получать аналоговые данные. Логичным продолжением является научиться отдавать аналоговые команды. В следующем уроке мы рассмотрим работу с аналоговыми выходами контроллера. Вы научитесь, используя тот же стандарт 0-10В, управлять яркостью светильников (диммирование) и плавно регулировать положение приводов клапанов в системах отопления и вентиляции.