В первой и второй статьях мы заставили крутиться 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) выполняется по официальным инструкциям:
- Node-RED — Running on Raspberry Pi / Orange Pi (скрипт-установщик, настройка systemd-сервиса)
- Mosquitto — официальная документация и руководство по установке на Debian/Ubuntu
Автоматический запуск интерфейса CAN bus
Чтобы интерфейс can0 поднимался при загрузке Orange Pi, используйте systemd или конфигурационные файлы сетевых интерфейсов.
- Создайте файл:
sudo nano /etc/systemd/network/80-can0.network - Вставьте содержимое:
[Match] Name=can0 [CAN] BitRate=500KПримечание:
500Kсоответствует скорости 500 кбит/с, настроенной ранее для платы управления PMSM. - Включите службу:
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— индикаторы для HMInode-red-contrib-modbus— работа с Modbusnode-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. Исходный код проекта доступен в репозитории.