ГлавнаяАкадемияИсполнительные устройства: интерлоки, таймауты → Калибровка: определение времени полного хода привода

Калибровка: определение времени полного хода привода

Урок 3 · Исполнительные устройства: интерлоки, таймауты · 30 мин · theory

Введение в калибровку приводов

В современных системах автоматизации мы часто сталкиваемся с исполнительными механизмами, которые не предоставляют точной информации о своем текущем положении. К таким устройствам относятся приводы рулонных штор, роллет, гаражных ворот или некоторых типов клапанов. В отличие от сервоприводов с абсолютными энкодерами, которые всегда "знают" свою позицию, эти более простые и распространенные механизмы управляются подачей питания для движения в одном из двух направлений: 'Открыть' или 'Закрыть'. Как же в таком случае реализовать команду "открыть штору на 50%"?

Ответ кроется в процедуре калибровки. Поскольку у нас нет прямого способа измерить положение, мы используем единственный доступный нам параметр — время. Идея проста: если мы знаем, сколько времени требуется приводу для перемещения из одного крайнего положения в другое, мы можем с высокой точностью управлять его промежуточными состояниями.

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

> * Калибровка привода: Процесс измерения и сохранения временных характеристик работы механизма для последующего точного управления его положением.

> * Время полного хода (ВПХ): Фундаментальный параметр, представляющий собой время в миллисекундах, необходимое приводу для полного перемещения из положения "Полностью закрыто" в положение "Полностью открыто" (или наоборот).

Цель данного урока — научиться измерять, автоматически вычислять и надежно сохранять ВПХ для приводов с реверсивным двигателем с помощью контроллера HI и среды Node-RED. Этот процесс является обязательным подготовительным этапом для реализации сценариев позиционирования, например, «Установить жалюзи на 75%» или «Приоткрыть ворота для проветривания». Без точного значения ВПХ любая попытка процентного управления будет основана на догадках и приведет к накоплению ошибки с каждым циклом работы.

Мы рассмотрим как ручной метод замера, который поможет понять физику процесса, так и создание полностью автоматического сценария калибровки, который может быть запущен инсталлятором на объекте или даже удаленно.

---

Ручной замер ВПХ: основа для автоматизации

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

Для ручного замера нам потребуется простейший сценарий в Node-RED, который будет выполнять роль удобного секундомера, а также интерфейс для ручного управления приводом (например, из предыдущих уроков).

Пошаговая инструкция по ручному замеру

  • Создайте "секундомер" в Node-RED.
  • Вам понадобятся всего два узла: `inject` и `debug`. Узел `inject` по умолчанию отправляет текущую временную метку (timestamp).

    * Создайте узел `inject` с `payload` = `timestamp`.

    * Соедините его с узлом `debug`.

    * Разверните (Deploy) сценарий. Каждое нажатие на кнопку узла `inject` будет выводить в панель отладки точное время в формате Unix.

  • Переведите привод в исходное положение.
  • С помощью вашего сценария управления (или временных кнопок) отправьте команду "Закрыть". Дождитесь, пока привод полностью закроется. Вы должны услышать характерный щелчок встроенного концевого выключателя (Limit Switch) или увидеть сигнал от него, как мы рассматривали в уроке `COURSE-05-M06-L03`. Это гарантирует, что мы начинаем движение из положения 0%.

  • Проведите замер времени открытия.
  • * Приготовьтесь одновременно нажать на кнопку нашего "секундомера" (`inject`) и подать команду "Открыть" на привод.

    * Нажмите обе кнопки. В панели `debug` появится первая временная метка.

    * Внимательно следите за приводом. Как только он достигнет крайнего открытого положения и остановится (сработает второй концевой выключатель), немедленно нажмите на кнопку "секундомера" еще раз.

    * В панели `debug` появится вторая временная метка. Разница между второй и первой метками и есть измеренное время полного хода.

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

    * Первая метка (старт): `1678886401000`

    * Вторая метка (финиш): `1678886423500`

    * ВПХ = `1678886423500` - `1678886401000` = `22500` миллисекунд, или 22.5 секунды.

  • Проведите замер в обратном направлении.
  • Теперь повторите шаг 3, но для движения из положения "Полностью открыто" в положение "Полностью закрыто".

  • Усредните и зафиксируйте результат.
  • Проведите замеры как минимум 2-3 раза в каждом направлении. Значения могут незначительно отличаться из-за особенностей механики (например, движение вверх под действием силы тяжести может быть чуть быстрее, чем вниз). Вычислите среднее значение. Например:

    * Закрытие -> Открытие: 22.5 с, 22.6 с, 22.4 с (среднее: 22.5 с)

    * Открытие -> Закрытие: 22.8 с, 22.7 с, 22.8 с (среднее: 22.76 с)

    В качестве итогового ВПХ можно взять большее из двух средних значений. Это гарантирует, что привод всегда успеет дойти до крайнего положения. В нашем случае, мы бы взяли `22760` миллисекунд.

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

    ---

    Сценарий автоматической калибровки в Node-RED

    Ручной замер хорош для первоначальной оценки, но для production-ready системы нам нужен автоматизированный, повторяемый и точный процесс. Создадим сценарий, который будет выполнять калибровку по одной команде.

    > 💡 Подсказка: Для хранения калибровочных значений используйте контекст с типом хранилища `file`. Это гарантирует, что данные не будут потеряны после перезагрузки или сбоя питания контроллера HI. Настроить это можно в файле `settings.js` вашего Node-RED.

    Логика автоматического сценария

    Алгоритм работы сценария будет следующим:

  • Инициация: Сценарий запускается по получению специального сообщения (например, от узла `inject` или MQTT-команды).
  • Движение в начальную точку: Привод получает команду двигаться в стартовое положение (например, "Полностью закрыть") и движется до срабатывания соответствующего концевого выключателя.
  • Запуск таймера и реверс: Как только сигнал от концевика получен, сценарий сохраняет текущую временную метку (timestamp), немедленно останавливает привод и подает команду на движение в противоположном направлении ("Полностью открыть").
  • Ожидание конечной точки: Сценарий ожидает сигнала от второго концевого выключателя.
  • Расчет и сохранение ВПХ: При получении сигнала от второго концевика, сценарий останавливает привод, получает вторую временную метку, вычисляет разницу и сохраняет результат в персистентный контекст.
  • Реализация в Node-RED

    Для реализации нам понадобятся узлы для отслеживания сигналов с концевых выключателей (например, `rpi gpio in`), узлы для управления реле (`rpi gpio out`), а также узлы для реализации логики.

    Пример потока (Flow):
    // Запуск калибровки
    

    [Inject: Start Calib.] --> [Function: Init & Close] --> [Relay Out: Close]

    // Отслеживание концевиков

    [Limit SW In: Close] --> [rbe] --+

    |

    [Limit SW In: Open] --> [rbe] --+--> [Function: Calibration Logic] --+--> [Debug: Result]

    |

    +--> [Relay Out: Open]

    +--> [Relay Out: Stop]

    Настройка узлов:
  • `Inject: Start Calibration`: Узел для ручного запуска. Отправляет сообщение, например `msg.payload = {"command": "start_calibration"}`.
  • `rpi gpio in` / `Limit SW In`: Два узла, настроенные на чтение универсальных входов (UI), к которым подключены концевые выключатели "Открыто" и "Закрыто". Важно добавить им осмысленные `msg.topic` для идентификации, например `limitswitch/close` и `limitswitch/open`.
  • `rbe` (report by exception): Критически важные узлы. Они ставятся после каждого входа от концевика и пропускают сообщение только тогда, когда значение входа меняется (например, с `0` на `1` при срабатывании). Это защищает от "дребезга" и повторных срабатываний.
  • `Function: Calibration Logic`: Сердце нашего сценария. Здесь сосредоточена вся логика.
  • Код для узла `Function: Calibration Logic`:
    // Получаем состояние калибровки из контекста потока
    

    let state = flow.get('calibration_state') || 'idle';

    const topic = msg.topic;

    // Если пришла команда на запуск калибровки

    if (msg.payload && msg.payload.command === 'start_calibration' && state === 'idle') {

    node.warn('Запуск автоматической калибровки...');

    flow.set('calibration_state', 'moving_to_close');

    node.status({fill:"yellow", shape:"ring", text:"Движение к 0%..."});

    // Возвращаем сообщение для запуска движения на закрытие

    // Это сообщение пойдет на узел управления реле 'Close'

    return { payload: 1, topic: 'relay/close' };

    }

    // Машина состояний (State Machine) для процесса калибровки

    switch (state) {

    case 'moving_to_close':

    // Мы двигались на закрытие и сработал концевик 'Закрыто'

    if (topic === 'limitswitch/close' && msg.payload == 1) {

    node.warn('Достигнуто положение "Закрыто". Начинаем замер ВПХ.');

    // 1. Сохраняем время старта

    flow.set('start_ts', Date.now());

    // 2. Меняем состояние

    flow.set('calibration_state', 'measuring');

    node.status({fill:"blue", shape:"dot", text:"Идет замер..."});

    // 3. Возвращаем сообщение для запуска движения на открытие

    return { payload: 1, topic: 'relay/open' };

    }

    break;

    case 'measuring':

    // Мы замеряли время и сработал концевик 'Открыто'

    if (topic === 'limitswitch/open' && msg.payload == 1) {

    const startTime = flow.get('start_ts');

    const endTime = Date.now();

    const travelTime = endTime - startTime;

    node.warn(`Замер ВПХ завершен. Результат: ${travelTime} мс.`);

    // 1. Сохраняем результат в персистентный контекст

    // 'file' указывает на хранение в файловой системе контроллера

    flow.set('full_travel_time_ms', travelTime, 'file');

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

    flow.set('calibration_state', 'idle');

    node.status({fill:"green", shape:"dot", text:`Готово: ${travelTime} мс`});

    // 3. Возвращаем два сообщения: одно с результатом, другое для остановки

    const resultMsg = {

    topic: "calibration/result",

    payload: {

    status: "success",

    value_ms: travelTime

    }

    };

    const stopMsg = { payload: 0, topic: 'relay/stop' }; // Останавливаем все реле

    return [resultMsg, stopMsg];

    }

    break;

    }

    // В остальных случаях ничего не делаем

    return null;

    Теперь, после развертывания этого потока, однократное нажатие на кнопку `Inject` запустит полный цикл: штора закроется, затем откроется, а в контексте `flow.full_travel_time_ms` будет сохранено точное время полного хода.

    ---

    Обработка и хранение калибровочного значения

    Получить "сырое" значение ВПХ — это только половина дела. Чтобы система была по-настоящему надежной и отказоустойчивой (production-ready), это значение нужно правильно обработать и сохранить.

    > ⚠️ Внимание: Не используйте измеренное время 'миллисекунда в миллисекунду'. Всегда добавляйте запас в 5-10% для компенсации возможных изменений в скорости работы привода или механического сопротивления. Это гарантирует, что привод всегда достигнет конечного положения, даже если напряжение в сети немного "просело" или механизм со временем стал двигаться туже.

    Добавление запаса времени (Safety Margin)

    Измеренное значение `travelTime` — это идеальное время в текущих условиях. Однако условия меняются. Чтобы команда "Открыть на 100%" гарантированно приводила к срабатыванию концевого выключателя, а не останавливала привод в 1 см от него, мы вводим запас времени.

    Это можно сделать прямо в `function` узле перед сохранением:

    // ... внутри блока 'case 'measuring''
    

    const travelTime = endTime - startTime;

    const safetyMarginFactor = 1.05; // Запас 5%

    const finalTravelTime = Math.round(travelTime * safetyMarginFactor);

    node.warn(`Сырое ВПХ: ${travelTime} мс. Итоговое (с запасом 5%): ${finalTravelTime} мс.`);

    // Сохраняем итоговое значение

    flow.set('full_travel_time_ms', finalTravelTime, 'file');

    // ...

    Способы хранения калибровочных данных

    Выбор способа хранения ВПХ влияет на надежность и гибкость всей системы.

    | Способ хранения | Преимущества | Недостатки | Рекомендация |

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

    | Переменная `flow.context` | Просто, быстро, изолировано в рамках одной вкладки (flow). | Теряется при перезагрузке, если не настроено персистентное хранилище. | Только для временных данных или быстрой отладки. |

    | Контекст в файле (`file`) | Надежно. Значение сохраняется между перезагрузками контроллера HI. Просто в настройке. | Привязано к конкретному экземпляру Node-RED. Сложно для доступа извне. | Основной рекомендуемый способ. |

    | MQTT-топик с `retain=true` | Гибко. Значение доступно всей системе, другим контроллерам, системам мониторинга. | Требует работающего MQTT-брокера. Легко случайно перезаписать извне. | Идеально для интеграции и системного мониторинга. |

    | База данных MySQL | Максимальная надежность. Возможность хранения истории калибровок, ведение логов. | Сложнее в настройке, требует дополнительных узлов (`node-red-node-mysql`). | Для крупных, сложных объектов с аудитом. |

    Для большинства задач на объектах (квартиры, офисы, коттеджи) связка "измерение в Node-RED -> сохранение в контекст `file`" является золотым стандартом, сочетающим надежность и простоту.

    Создание сервисного сценария

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

  • Создайте отдельную вкладку в Node-RED под названием "Сервисные сценарии".
  • Перенесите туда весь поток автоматической калибровки.
  • Замените узел `Inject` на `mqtt in`. Настройте его на уникальный топик, например `hi/service/living_room_shutter/calibrate/run`.
  • Когда на этот топик приходит любое сообщение (например, `1`), запускается процесс калибровки.
  • Результат калибровки также можно публиковать в отдельный MQTT-топик со статусом, например `hi/service/living_room_shutter/calibrate/result`.
  • Такой подход позволяет инженеру по обслуживанию или даже продвинутому пользователю запустить повторную калибровку (например, после замены привода) удаленно, не трогая основной код и не рискуя нарушить его работу.

    ---

    Итоги и следующие шаги

    В этом уроке мы сделали критически важный шаг на пути к созданию интеллектуальных систем управления приводами. Мы深入-рассмотрели концепцию калибровки и ее необходимость для устройств без обратной связи по положению.

    Ключевые результаты:
  • Мы научились определять Время полного хода (ВПХ) — основной параметр для точного позиционирования.
  • Мы освоили как ручной метод замера с помощью простых инструментов Node-RED, так и разработали полноценный сценарий автоматической калибровки, использующий сигналы с концевых выключателей.
  • Мы поняли важность "запаса времени" (safety margin) для повышения надежности системы и научились применять его.
  • Мы изучили и сравнили различные методы персистентного хранения калибровочных данных, выделив сохранение в файловый контекст как наиболее сбалансированное решение.
  • Теперь в арсенале нашего контроллера есть точное и надежно сохраненное знание о том, сколько времени требуется конкретной шторе, воротам или клапану для полного цикла работы. Это знание — фундамент, на котором мы построим более сложную и удобную для пользователя логику.

    🔗 Связанный материал: В следующем уроке, COURSE-05-M06-L05: Управление позицией в процентах, мы будем активно использовать полученное значение ВПХ для реализации команд вида "установить штору на 30%" или "плавно закрыть на 80%". Мы превратим абстрактные миллисекунды в интуитивно понятные проценты.