От PLC к HMI и AI-анализу

От PLC к HMI и AI-анализу

В первой и второй статьях мы заставили крутиться PMSM-мотор под управлением комплекта P-NUCLEO-IHM03, внедрив в прошивку поддержку FDCAN. Чтобы превратить DIY-проект в нечто более серьёзное, нужен верхний уровень: наглядный интерфейс, интеграция с промышленными стандартами и немного современных LLM для диагностики.

Сегодня мы построим распределённую систему управления, где OpenPLC отвечает за логику, Node-RED — за визуализацию, а AI-агент — за диагностику, как инженер-аналитик.

HMI на стероидах: когда консоли уже недостаточно

Вывод сырых данных в терминал — не самый удобный способ управления. Для мониторинга и контроля привода нужен дашборд, простой в использовании. Node-RED идеально подходит: он лёгкий, работает на Orange Pi и поддерживает все необходимые протоколы.

Наша цель — не просто отображение графиков, а создание моста между CAN bus, Modbus и IP-протоколами.

Установка и настройка Node-RED на Orange Pi

Node-RED — визуальная IoT-платформа с потоковой моделью программирования. В проекте он выполняет несколько задач: считывает CAN-фреймы через SocketCAN, опрашивает OpenPLC по Modbus TCP, отображает данные на HMI-дашборде и инициирует AI-анализ телеметрии.

Альтернативы вроде Grafana или самописного веб-интерфейса потребовали бы больше усилий при той же функциональности.

Mosquitto — лёгкий MQTT-брокер. Он служит шиной между Node-RED и n8n: Node-RED публикует телеметрию в топик node-red/request, n8n подписывается на него, выполняет RAG + LLM-анализ и возвращает результат в node-red/data. MQTT предпочтительнее HTTP: компоненты работают асинхронно и не зависят от порядка запуска.

Оба инструмента хорошо документированы. Установка на Orange Pi (на базе Debian/Ubuntu) выполняется по официальным инструкциям:

Автоматический запуск интерфейса CAN bus

Чтобы интерфейс can0 поднимался при загрузке Orange Pi, используйте systemd или конфигурационные файлы сетевых интерфейсов.

  1. Создайте файл: sudo nano /etc/systemd/network/80-can0.network
  2. Вставьте содержимое:
    [Match]
    Name=can0
    
    [CAN]
    BitRate=500K

    Примечание: 500K соответствует скорости 500 кбит/с, настроенной ранее для платы управления PMSM.

  3. Включите службу:
    sudo systemctl enable systemd-networkd
    sudo systemctl restart systemd-networkd

Для ручного запуска интерфейса CAN выполните соответствующую команду в терминале.

Установка плагинов Node-RED

Плагины устанавливаются через меню «Управление палитрой» или командой npm install. Для проекта требуются:

  • @flowfuse/node-red-dashboard — компоненты визуализации HMI
  • @flowfuse/node-red-dashboard-2-ui-led — индикаторы для HMI
  • node-red-contrib-modbus — работа с Modbus
  • node-red-contrib-socketcan — работа с CAN bus

Установка Ollama, n8n и Qdrant через Docker Compose

AI-агент требует три сервиса: Ollama (локальный LLM-сервер с моделью эмбеддингов), n8n (платформа для AI-агентов) и Qdrant (векторная БД для RAG). Их удобно запустить через Docker Compose. Готовый файл docker-compose.yml доступен в репозитории.

Модель эмбеддингов qllama/bge-small-en-v1.5

При запуске Ollama автоматически загружает модель qllama/bge-small-en-v1.5 — компактную (~33 МБ) модель для векторных эмбеддингов, оптимизированную под семантический поиск. Она используется в RAG-пайплайне: при индексации данных в Qdrant и поиске релевантных документов в n8n.

Сервисы доступны по адресам:

  • n8n: http://<IP>:5678
  • Ollama API: http://<IP>:11434
  • Qdrant: http://<IP>:6333

При первом запуске Ollama загрузит модель. Проверить её наличие можно командой в терминале.

Описание HMI-интерфейса

Для доступа к интерфейсу откройте в браузере: http://<IP_ADDRESS>:1880/dashboard

Speed dashboard

Панель для мониторинга и управления PMSM-двигателем. Данные передаются через компоненты socketcan.

SocketCAN — набор open-source драйверов и сетевой стек CAN-протокола в ядре Linux. Он превращает CAN-интерфейс в стандартное сетевое устройство, аналогичное Ethernet, позволяя работать с CAN через сокеты.

Верхняя группа индикаторов

  • Круговая диаграмма — текущая скорость двигателя
  • State — индикатор состояния (описан в предыдущих статьях)
  • График Speed_chart — сравнивает заданную и текущую скорость. Активен при включённом слайдере Analyze

Группа ручного управления

  • Ползунок Speed — ручная установка скорости
  • Кнопки:
    • Start — запуск двигателя с минимальной скоростью
    • Stop — остановка
    • ACK — сброс ошибок

Группа анализа телеметрии

  • Индикатор Analyzing — горит зелёным при активном анализе
  • Слайдер Analyze — включает сбор и анализ телеметрии
  • Текстовое поле Result — вывод результата анализа

Чтобы запустить анализ, включите слайдер Analyze и нажмите кнопку START на панели FLOW. Функция collect соберёт данные и отправит их через MQTT-топик node-red/request. Результат приходит в node-red/data и отображается в поле Result.

Flow dashboard

Панель управления автоматическим циклом (см. раздел OpenPLC).

  • Слайдер Manual — переключает режим управления
  • State — индикатор состояния цикла (переменная CYRCLE_STATE %MW1 в OpenPLC)
  • Кнопка Start — запуск цикла

K1 dashboard

Панель контроля реле К1.

  • Индикатор состояния: красный — выключено, зелёный — включено
  • Кнопки:
    • Coil ON — включить реле
    • Coil OFF — выключить

AI-агент: ваш личный дежурный инженер на n8n

Представьте: двигатель работает по FOC, датчики каждую секунду передают данные — скорость, токи d/q, температуру, параметры PID. Иногда двигатель ведёт себя странно: скорость скачет или долго выходит на заданное значение. Как автоматически понять причину, не привлекая инженера?

Классический подход: ETL → ML → правила

Традиционное решение включает:

  • Сбор и разметку данных — но их часто нет до первых аварий
  • Обучение модели — которая не объясняет вывод: «аномалия с вероятностью 0.83» — это не диагноз
  • Поддержку всего пайплайна как отдельного проекта
  • Устаревание модели при изменении конфигурации двигателя или PID-параметров

Наш подход: стриминг → анализ на месте → LLM с контекстом

Мы заменили обучение модели на инженерный здравый смысл и LLM с контекстом.

Что делает Node-RED: детектор событий

Node-RED не просто собирает данные — он анализирует их в реальном времени.

При запуске двигателя начинается сессия. Каждый CAN-фрейм обновляет состояние: speed_rpm, iq, id, motor_state, pid_*. Фиксируется также target_rpm — целевая скорость от оператора.

Когда двигатель возвращается в IDLE или истекает тайм-аут, сессия «флашится»: вычисляется аналитический блок.

Хитрость с осевшими сэмплами

Среднее значение скорости по всей сессии вводит в заблуждение: если двигатель разгонялся от 0 до 1000 об/мин, среднее будет ~500, и LLM решит, что он не достиг цели. На самом деле — просто разгонялся.

Поэтому мы отделяем переходный процесс от установившегося режима. Только на втором подмножестве считаем settled_speed_avg, settled_speed_std и ошибку регулирования. Рампа разгона не влияет на оценку качества ПИД.

Автоматический выбор RAG-запроса

Вместо передачи LLM сырого JSON и просьбы «придумать запрос» — Node-RED детерминированно формирует поисковую фразу по правилам:

  • Нет состояния RUN → FOC startup failure alignment revup current
  • Пик Iq > 1 А → FOC current saturation anti-windup Iq limit
  • std_dev > 30 об/мин (в settled) → FOC speed loop PI oscillation gain tuning
  • Ошибка > 50 об/мин → FOC speed steady-state error PI gain integral
  • Нулевые момент и мощность → FOC zero torque Iq reference power loss
  • Нормальная работа → PMSM FOC speed control normal operation

Такая фраза устойчива к некорректным данным. Попытки использовать LLM для генерации запросов (с моделями Llama, Qwen, Gemini Flash) не дали стабильных результатов.

Что делает n8n: RAG + LLM как эксперт без учителя

n8n берёт подготовленный пакет данных и добавляет контекст из базы знаний.

RAG — зачем это нужно

LLM хорошо рассуждает, но не знает специфики вашего SDK. Документация STM32 Motor Control Workbench была загружена в Qdrant с помощью скрипта ingest_rag.py. Теперь при каждом диагнозе автоматически подбираются 4–5 релевантных фрагментов — например, описание параметров pid_speed_kp/ki и последствий их неправильной настройки.

Модель получает не просто «pid_speed_kp = 2730», а инженерный контекст: когда этот параметр важен, какую проблему решает, что с ним делать.

Временной ряд в промпте

В промпт вставляется таблица временного ряда (до 60 строк). Это позволяет модели видеть динамику: как менялось задание, как реагировала скорость, как вёл себя ток.

Пример реального вывода

Двигатель разогнался с 100 до 1000 об/мин за 10 секунд и вышел на установившийся режим.

Ответ LLM:

Без коррекции settled_speed модель увидела бы avg=626, std_dev=404 и сделала бы вывод о «нестабильности» и «недостаточном усилении ПИД».

Код, написанный с помощью промпта

Часть кода создана не вручную. Функция-коллектор в Node-RED (с парсингом CAN, логикой сессий, вычислением settledSamples и генерацией симптомов) сгенерирована через промпт в GitHub Copilot. То же — узлы Extract Telemetry Summary и Build Prompt в n8n.

Это не «нажал и получил». Это итеративный процесс: сформулировал требование — получил черновик — указал на ошибку — уточнил поведение — перегенерировал. Разница в распределении времени: модель пишет черновик, инженер проверяет логику.

Время на «написание кода» сокращается в разы. Время на «понимание, что код должен делать» — остаётся. Это правильное распределение усилий.

Промпт как документация

Промпт, по которому сгенерирован код, сам становится спецификацией. В проекте рядом с кодом лежат файлы node-red-collect.md и n8n-PMSM_Diagnostic.md — не просто документация, а полные промпты. Через полгода, чтобы изменить логику, достаточно отредактировать промпт и перегенерировать фрагмент.

Где это не работает

Генерация по промпту эффективна для структурированных задач с чёткими правилами. Она слаба там, где правильный ответ неочевиден — например, выбор порогов детекции осцилляций или архитектурные решения с долгосрочными последствиями. Там нужен человек. Модель — инструмент, а не замена экспертизе.

Что можно улучшить

Адаптивный порог анализа

Сейчас двигатель считается «в режиме», если скорость ≥ 90% от цели. Это фиксированный порог. Для инерционных нагрузок он слишком мягкий, для лёгких — слишком жёсткий. Лучше вычислять его динамически, например, на основе времени разгона предыдущих сессий.

Накопление истории сессий

Сейчас сессии анализируются независимо. Если сохранять историю (хотя бы последние 50 сессий в SQLite или InfluxDB), LLM мог бы выявлять тренды: «settled_std растёт последние 3 дня — возможна деградация подшипника или рост нагрузки».

Обратная связь по диагнозу

LLM может ошибаться. Сейчас результат уходит в MQTT без проверки. Можно добавить в Node-RED UI-панель с кнопками «диагноз верный / неверный». Эти оценки будут накапливаться и улучшать RAG-базу без переобучения.

Несколько LLM для консенсуса

Модель gemma4:31b работает хорошо, но у LLM бывают галлюцинации. Для критичных случаев (state=unstable, confidence < 0.7) можно отправить промпт второй модели. При расхождении — фиксировать «спорный диагноз» и передавать его инженеру.

Основная идея проста: предоставьте инструменту правильно обработанные данные — и он объяснит, что происходит, без обучения на исторических авариях.

Node-RED здесь — не просто шина данных. Это уровень инженерной интерпретации: он различает переходный и установившийся режимы. n8n добавляет контекст через RAG. LLM формирует читаемый диагноз. Такой стек можно развернуть локально на обычном сервере или на Orange Pi. Исходный код проекта доступен в репозитории.

Читать оригинал