docs(rover): record calibration control acceptance and operating boundaries

This commit is contained in:
DCCONSTRUCTIONS
2026-09-25 16:39:19 +03:00
parent bc55901d4d
commit 6bbbd5bf7d
12 changed files with 4603 additions and 0 deletions
@@ -0,0 +1,331 @@
# Rover 006 — VESC: аудит кода и план реализации
Исторический план, составленный до реализации 23 сентября 2026. Текущий статус
см. `../node/17_VESC_INSTALLATION_LEDGER.md` и MISSIONCOR-84.
Результат первоначального аудита — исследование, свежий read-only
baseline и план. Плагин ещё не реализован; конфиги контроллеров не прочитаны,
моторы не запускались. Исторические команды и планы приложенного документа
рассматривались как источники, а не как поручения на исполнение.
## 1. Целевой пользовательский результат
После подключения контроллеров к USB бортового Mac Mini они появляются в
«Устройствах» Node и в «Парк → Rover 006 → Устройства» основного Core.
В карточке выбранного контроллера есть вход **«VESC Tool»**. Через него доступны
настройка, диагностика, калибровка и остальные применимые функции Tool.
Исполнение принадлежит борту; обе UI используют одну реализацию предметного
интерфейса и одни операции. Полнота Tool остаётся целевым требованием,
первый read-only выпуск является отдельным промежуточным результатом.
Ближайшая физическая задача — разобраться с потерей оборотов одного мотора.
Слова владельца о левом канале остаются предположением до сопоставления.
Предыдущие наблюдения: плавный старт возможен, резкий может давать короткий
рывок и остановку; конфигурация, датчики и управление — приоритетная ветка
диагностики. Причина пока не измерена.
## 2. Что проверено сейчас
| Объект | Факт 23.09 | Ограничение |
| --- | --- | --- |
| Core | Канонический localhost:8000 отвечает; Rover 006 paired/online | Не означает доступность каждого устройства |
| SSH | Вход `dcsudo` с существующим персональным ключом работает | Старая запись `nodedc-edge` использовала `ndcsudo`; sudo не проверялся и не нужен для чтения |
| Борт | Ubuntu 24.04.4, kernel 7.0.0-31-generic, i7-3615QM, 4 ядра/8 потоков | CPU поддерживает AVX, но AVX2 в полученном наборе флагов нет |
| Память/диск | Около 8 GB RAM, около 6.3 GiB available; swap не занят; root 457 GiB, свободно 381 GiB | Это короткий idle-срез, не совместная нагрузочная приёмка |
| Установка | Node 0.8.21-3, K1 0.1.14, X4 0.1.3-9 | Старый Node README с 0.6.11 не является installed baseline |
| Службы | Node, K1, X4 broker, D455, monitor, PostgreSQL active/running, NRestarts=0 в проверенном наборе | Активный драйвер не доказывает подключение камеры |
| База | PostgreSQL 16, cluster `ndcmonitor` online; Timescale 2.29.2 установлен | База системного мониторинга, не готовый motor recorder |
| Реплика мониторинга | available/fresh=true, storage=ready, backlog=0; sample interval 1 s | Срез около 11:02 UTC; полевая задержка управления не измерена |
| USB контроллеров | Два кандидата `0483:5740`, ChibiOS/RT Virtual COM Port, cdc_acm, два ttyACM | USB-дескриптор ещё не доказательство HW/FW VESC |
| Identity | У двух кандидатов одинаковый USB serial; одна конфликтующая by-id ссылка | Нельзя использовать USB serial, by-id, tty или порядок включения как постоянную личность |
| Права | tty принадлежат root:dialout, 0660; dcsudo не имеет read/write | Права будущего runtime поставляются профилем модели |
| Конкурирующий опрос | ModemManager active; кандидаты имеют ID_MM_CANDIDATE=1 | Не доказано, что он уже посылал команды; нужен адресный udev ignore при подготовке модели |
| Камеры | D455/X4 в свежем paired inventory offline | Сохранность их потоков под VESC-нагрузкой сейчас проверить нельзя |
Портов serial не открывали; firmware/UUID, моторные и application configs,
CAN/RC topology и физические стороны остаются неизвестными. VESC Tool не найден
через проверенное имя `vesc_tool` в PATH; это не полный поиск всех установок.
Подробный путь доступа: [ROVER_006_ENGINEERING_ACCESS.md](../runbooks/ROVER_006_ENGINEERING_ACCESS.md).
Raw fleet/monitor snapshots и приватный SSH-профиль находятся вне Git в
операторском `outputs/rover-006-vesc-context-20260923`.
## 3. Источники и границы исследования
Прочитаны основной актуальный срез и VESC-handoff приложенного документа,
профильные Node/SDK/UI материалы и релевантная история приложений. Большой
архив планировщика/Rerun использован для контекста владельцев; повторной
квалификации всех старых экспериментов не выполнялось.
Через прямой Ops MCP получены живые проекты/контекст/карточки, в том числе
MISSIONCOR-84, 76, 77, 50, 5, 2, и история комментариев 76/77/84; изучен
архив ROBOT2B-5. Профильная карта —
[MISSIONCOR-84](https://ops.nodedc.ru/nodedc/browse/MISSIONCOR-84), Node —
[MISSIONCOR-76](https://ops.nodedc.ru/nodedc/browse/MISSIONCOR-76).
Поиск GPIO в других четырёх доступных Ops-проектах совпадений не вернул;
среди полученных Mission Core/ROBOT2B карточек подтверждённой схемы GPIO
для этого привода не найдено. Это пробел найденных источников, не утверждение
об отсутствии такой схемы вообще. USB достаточно для первого этапа;
GPIO/UART/RC/аварийная цепь требуют конкретной аппаратной схемы до motor tests.
Основная кодовая база: `NODEDC_MISSION_CORE_m5_observatory`, HEAD `2e5d525`.
Соседние base/node checkout остаются detached `76dc9f1`. В main есть чужая
незавершённая работа SIM/AI polygon и service recovery. Для реализации нужен
отдельный checkout от проверенного commit; не включать эти изменения в пакет.
Design Guideline прочитан по реестрам и документации, текущий HEAD
`8dd9190573d6616024ef01b9b34bf90b72960f44`, рабочее дерево чистое в проверке.
Node build_linux_source.py закреплён на `8c53f73...` и отклоняет другой HEAD.
Перед выпуском выбрать проверенную ревизию DG и квалифицировать её в сборке;
не снимать проверку и не брать случайные локальные dist.
## 4. Реальные точки расширения
| Код | Что уже есть | Что нужно VESC |
| --- | --- | --- |
| `apps/node-agent/internal/node/sensor_models.go` | Registry, model actions, отдельные IPC sockets, USB discovery, provisional identity при дублях | Новый model profile; разделение attachment и protocol UUID; discovery двух плат с одинаковым USB serial |
| `sensors.go` | Durable fsync journal, dedup, action allowlist, deadline, unknown после restart, local API | Точные VESC actions и параметры; проверка session непосредственно в адаптере; bounded результаты; не прятать моторные функции за camera `start`/`option` |
| `sensor_preparation.go` | Профиль на модель и проверка отдельного экземпляра, shared preparation job | Device-neutral подписи и безопасная identity verification. Нельзя трактовать `verify` как motor detection |
| `sensor_events.go` | udev events, coalescing, полные SSE snapshots | Reconnect создаёт новый session; stale GUI не получает authority над новым контроллером |
| `pairing_transport.go` | mTLS heartbeat, commands/results/acks; периодический tick 5 s и пробуждение от событий | Существующий путь для service operations; отдельная доставка частой telemetry и будущего realtime control |
| `src/k1link/fleet/sensors.py` | Проверки pairing/freshness/session, очередь, receipts, ограниченные payloads | Добавить явные actions; не превращать whitelist в arbitrary protocol passthrough |
| `packages/plugin-sdk/.../v0alpha2` | Identity/session, safety/idempotency policies, commands/events | Использовать существующие contracts; motor authority/lease и конфиг revision оформить узким дополнением |
| `packages/sensor-ui` | Общий SensorWorkspace, transport, Detail contribution, status/preparation | VESC Detail в том же slot; camera-specific поля/подписи нормализовать ровно там, где нужно |
| `apps/node-agent/ui/src/NodeSensors.tsx` | Локальная композиция общих plugins | Зарегистрировать ту же VESC contribution |
| `apps/control-station/src/core/fleet/sensorTransport.ts` и composition | Remote adapter общего UI | Повторно использовать; новая предметная логика в plugin, не App.tsx |
| `plugins/insta360-x4/runtime/operations.py` | fsync receipt до физического действия, отсутствие replay, readback settings | Проверенный пример lifecycle, но motor safety проектируется отдельно |
| Node monitor/storage и fleet monitor replica | 1 s host samples → Timescale → bounded Core replica | Не использовать этот период как осциллограф или контур stop; моторная сессия пишет данные на борту с собственной частотой |
В этих действующих реестрах и каталогах VESC runtime отсутствует. Архитектурные
документы старого этапа местами описывают gRPC как целевой вариант; текущая
проверенная реализация использует JSON HTTP/Unix sockets и HTTPS heartbeat.
## 5. Интеграция VESC Tool
Для аудита закреплён официальный upstream:
[`dc53c658cbb89a947246034f7a00149cf79abdfc`](https://github.com/vedderb/vesc_tool/tree/dc53c658cbb89a947246034f7a00149cf79abdfc).
Сохранены 17 исходных файлов с SHA-256. Этот snapshot объявляет **7.01,
test version 1**; это исследовательская точка, не автоматически выбранный
production release для неизвестной firmware наших плат.
Исходники показывают:
- `main.cpp`: CLI умеет конкретные чтения/записи config, выбор port/CAN,
offscreen и TCP. Это не готовый полный web API.
- `vescinterface.cpp`: autoconnect обходит serial ports и заканчивает поиск
на первом ответе. Для инвентаризации двух плат нужен наш ограниченный поиск.
- `commands.cpp`/`datatypes.h`: FW response содержит version, HW name, UUID
и дополнительные признаки; набор полей зависит от ответа. HW name нельзя
автоматически считать точной коммерческой моделью платы.
- `configparams.cpp`/`utility.cpp`: schema выбирается по firmware, сериализация
использует signature. Парсить конфиг произвольной новой firmware старой
схемой и затем сохранять его нельзя.
- `packet.cpp`: length/framing/CRC и размер пакета ограничены. Нужны tests на
fragmented/combined/corrupt packets и truncation полей ответа.
- `tcpserversimple.h`: default bind — все адреса. Штатный TCP server нельзя
просто включить как удалённый продуктовый интерфейс.
- `setupwizardmotor.cpp`: wizard содержит реальные записи конфигурации по
ходу шагов. Его запуск/отмена не являются только локальным редактированием.
### Сравнение реализаций
| Вариант | Польза | Цена/ограничение |
| --- | --- | --- |
| Официальный Qt Tool + локальный launcher и трансляция его окна в Core | Самый прямой путь к исходному GUI и широкому набору функций | Новый remote-app runtime, конкуренция ввода двух UI, Qt UI вне DG, передача port ownership; интерфейс сам умеет опасные команды |
| Собственный минимальный protocol adapter | Быстрое read-only discovery/telemetry | Поддержка всех конфигов/wizards потребует дублирования большого firmware-specific слоя |
| Бортовой service plugin с переиспользованием закреплённого upstream protocol/config engine + общий React UI | Наш UI, один owner, применимые функции Tool расширяются без второй модели состояния | Требуется проверить headless сборку/зависимости и адаптировать операции; полного готового API нет |
**Рекомендация:** третий вариант как целевая архитектура. Первый технический
spike проверяет сборку и выделение engine без desktop UI; fallback на
ограниченный собственный reader допустим для первого чтения, но не отменяет
требование функционального паритета. Оригинальный Tool полезен как инструмент
сравнения с эксклюзивной передачей владения портом. В текущем плане нельзя
объявить «все функции готовы», открыв только несколько полей или удалённое окно.
Нужно отдельно различать паритет функций и показ неизменённого Qt GUI. Здесь
принято рабочее предположение из запроса про наш интерфейс и DG: единая
предметная UI внутри Mission Core. Если нужен именно исходный Qt GUI, меняется
способ его доставки, а не требование единственного hardware owner.
Upstream содержит GPL-3.0-or-later notices и отдельные правила бренда. При
упаковке выбранного кода/бинарника проверить состав, notices, исходники и
название распространяемого продукта. Этот аудит не делает юридического вывода
о допустимости конкретного способа распространения.
## 6. Runtime и модель данных
```mermaid
flowchart TD
L[Node UI: Устройства → VESC Tool] --> N[Node API и журнал операций]
R[Core: Парк → Rover 006 → VESC Tool] --> C[Core fleet API]
C -->|Существующее pairing и mTLS| N
N --> V[VESC plugin на борту: owner и арбитраж]
V --> U[USB attachment → protocol UUID → controller/channel]
U --> M[Мотор и подтверждённая роль]
V --> D[Конфиги, telemetry и diagnostic session на борту]
D --> C
```
Предлагаемый bounded каталог `plugins/vesc/`: `runtime/`, `frontend/`,
`profiles/`, `packaging/`, `tests/`, upstream lock/notice manifest.
Названия здесь — план, каталог ещё не создан.
Один service владеет serial. Открывает только подтверждённые candidates;
проверяет отсутствие конкурирующего владельца и сохраняет связь порта с
attachment generation. До FW query attachment имеет provisional identity.
После ответа UUID связывается со стабильным controller instance. Смена порта
не меняет подтверждённый UUID; USB/CAN aliases одной платы не создают двойник.
Неоднозначный protocol UUID оставляет устройство без write authority.
Особенно важно для текущих двух плат: общий Node discovery уже считает
duplicate USB serial неинициализируемым. Нельзя просто добавить VID/PID:
обе кнопки подготовки окажутся заблокированы. Нужен отдельный безопасный путь
подготовки модели/identity query для provisional attachments; он разрешает
только ограниченное чтение личности. Общую защиту камер не ослаблять.
Role Left/Right и metadata мотора хранятся отдельно от UUID. Отключение владельцем
одного USB при обесточенном приводе может сопоставить плату с кабелем; это само
по себе не доказывает, какой мотор подключён к её силовым выходам. Сопоставление
по проводке/маркировке предпочтительно; активный тест — отдельная операция.
Конфиг имеет исходный blob, decoded fields, firmware/schema signature, hash,
revision и timestamp. Запись использует ожидаемую revision и свежий session,
сохраняет before/after, выполняет readback. Потеря ACK даёт unknown и
reconciliation, а не слепой retry.
Калибровка — бортовая операция с этапами, результатом и явно проверенной
семантикой отмены. HTTP timeout не доказывает прекращение электрического
измерения. Motor control дополнительно требует одного владельца управления,
локального watchdog, известных timeout/stop свойств firmware и арбитража RC.
Точные токи/обороты/частота не выбираются до hardware baseline.
## 7. Полнота функций и порядок включения
| Группа Tool | Предметный результат | Этап и условие |
| --- | --- | --- |
| Discovery, FW/HW/UUID, USB/CAN topology | Независимые экземпляры и совместимость | Первый read-only slice |
| Live values, faults, decoded PPM/ADC/Chuk input | Напряжение, токи, ERPM, температура, вход, timeout/kill flags по поддержке FW | Первый read-only slice; измерить реальную частоту |
| Motor/app/custom configs, backup/export, сравнение | Полный применимый набор параметров по schema, неизменяемый backup | Read-only до первой записи |
| Import, defaults, apply/restore | Предпросмотр diff и проверенный readback | После identity, backup и compatibility; restore/defaults — записи |
| FOC/BLDC/DC setup, R/L/flux, Hall/encoder | Калибровочный workflow с результатом | Активный допуск на конкретный мотор; один шаг может подавать ток |
| App/input setup, direction, limits | Настройка RC/ADC/UART/CAN по реальной схеме | Сначала прочитать существующий input/timeout/RC ownership |
| Duty/current/brake/RPM/position, motor tests | Управляемый стендовый опыт | Быстрый бортовой контур; не heartbeat 5 s |
| Samples, logging, plotting | Синхронная диагностическая запись реакции | Bounded board recorder; сводки через Core |
| Firmware/bootloader/recovery | Exact-HW image, версия, progress и recovery | Отдельная поздняя ветка; не «обновить на всякий случай» |
| CAN forwarding/multi-controller setup | Явный target и topology | Никаких автоматических detect-all/broadcast writes |
| Terminal, Lisp/QML/packages, custom application | Сервисные функции выбранного устройства | Отдельный maintenance scope; чтение кода и его выполнение различаются |
| BMS, IMU, power switch, NRF/GPD и расширения | Применимые к конкретному hardware возможности | Capability-driven; отсутствие аппаратуры не маскировать как готовую функцию |
Перед реализацией широкой сервисной поверхности матрица уточняется по страницам
выбранного релиза Tool и реальной HW/FW. Для каждого пункта фиксируются:
supported/unsupported/not-implemented, операция, side effects, schema,
readback, cancel/recovery и аппаратная приёмка. Старые настройки firmware
не переименовываются в поддержанные только ради единого красивого UI.
## 8. UI brief и Design Guideline
Задача оператора: выбрать конкретный контроллер, понять состояние, настроить
его и проверить итог. Первичная сущность — выбранный controller/channel;
мотор и роль — связанный контекст. Вход из существующего списка устройств.
Выбран **plugin Detail slot** общего `SensorWorkspace`, с текстовой кнопкой
«VESC Tool» в карточке. Внутри — обзор/диагностика, параметры и сервисные
операции, основанные на capabilities. Нового root или LAB не требуется.
Длинный motor workflow остаётся полноценным detail-view; компактный editor
может использовать существующий `FeatureSettingsWindow`.
Альтернатива отдельного глобального workspace создаёт второй вход к тем же
устройствам и отрывает инструмент от адресной identity. Модальное окно на весь
долгий workflow неудобно для контроля результата и закрытия/recovery.
Показ исходного Qt GUI — иной вариант интеграции, описанный выше.
Уже есть `ResourceRow/List`, `Button/IconButton`, `StatusBadge`,
`SettingsCard`, `Window`, `FeatureSettingsWindow`, `SegmentedControl`,
`TextField`, `Select`, `RangeControl`, `ConfirmationModal`, `ProgressBar`,
`LoadingRegion`, `ToastStack`. Подходящие существующие icons: settings,
activity, network, download, upload, refresh, alert, eye, play/stop.
Отдельной motor-icon в просмотренном registry нет; новая не нужна для первого
slice. Domain graph/plot остаётся кодом плагина с этими controls.
`RangeControl.min/max` ограничивает drag, но не всякий ручной ввод: для токов
и других bounded величин нужны `exactValueBounds` и серверная валидация.
Safety check нельзя делегировать только форме.
Состояния: поиск; не обнаружено; найден кандидат; требуется подготовка;
чтение личности; unsupported/ambiguous; готов к чтению; fault; занят;
операция выполняется; outcome unknown; связь потеряна. Свежесть контроллера
проверяется отдельно от online борта. Браузер не принимает unknown за failed
и не предлагает повтор опасного действия как универсальное восстановление.
Это новое доменное содержимое существующей принятой list/detail композиции.
Изменения global navigation и новые общие визуальные сущности не предлагаются.
## 9. Упаковка с первого бортового опыта
Versioned пакет/profile устанавливает бинарник, pinned зависимости, отдельного
непривилегированного service user, Unix socket для Node, systemd limits,
узкие udev rules доступа и ModemManager ignore для квалифицированного профиля.
Не добавлять весь Node или пользователя в общий dialout, не делать chmod 666,
не отключать ModemManager глобально. Runtime не должен читать произвольные tty.
Node сохраняет `PrivateDevices=yes`; аппаратные права принадлежат отдельному
адаптеру. Verify после установки означает protocol identity/read capability,
а не автокалибровку. Package qualification: повторная установка, конфликт
портов, rollback бинарника при сохранении data/backup, холодный старт и чистая
Ubuntu. Компилятор/Qt dev packages не становятся скрытым требованием runtime.
## 10. Реализация по проверяемым результатам
1. **Контракт и build spike.** Изолированный checkout, выбранный upstream
release/commit, DG pin, headless engine build, firmware schema closure;
synthetic packets, IPC/action contracts. Никакого доступа к моторам.
2. **Discovery на борту и две UI.** Поставляемый profile, два кандидата с
одинаковым USB serial, FW/UUID handshake, session transitions, одна
VESC contribution в Node/Core. Итог — оба контроллера видны независимо.
3. **Read-only сервисная поверхность.** Версии/capabilities, telemetry,
faults/input, motor/app/custom backups и semantic diff. Это первый полезный
завершённый выпуск; статусы неподдержанной FW честные.
4. **Диагностика проблемного канала.** Сначала сравнить конфиги, затем на
подготовленном стенде записать плавный/резкий старт по конкретному сценарию.
Сопоставить command/input, ERPM, currents, voltage, fault и timeout. Выбрать
измеренную гипотезу; рабочий конфиг не копировать целиком.
5. **Адресная настройка/калибровка.** Backup, effect preview, необходимые
ограничения hardware, исключение конкурирующего управления, конкретная
операция, cancel/recovery, readback и повтор исходного теста.
6. **Остальная матрица Tool.** Дополнять функции вместе с соответствующей
упаковкой и аппаратными критериями; FW/terminal/scripts выделены по эффекту.
До физического теста требуются аппаратные факты о моторах/датчиках/питании,
проводке RC/CAN и доступном аварийном останове. Выбор «левый/правый» владельцем
выполняется позже; он не блокирует initial inventory.
## 11. Приёмка и тесты
- Parser: CRC, partial/multiple packets, неверные длины/концы, timeout,
несовместимая FW/config signature, отсутствующие optional fields.
- Identity: одинаковые USB serial, пустой/дублированный UUID, два независимых
контроллера, unplug/replug/reorder, замена платы, USB/CAN duplicate alias.
- Operations: общий local/remote journal, stale session, conflict/lease,
crash до/после dispatch, unknown outcome, readback mismatch, отсутствие
повторного исполнения после reconnect и reboot.
- Packaging: clean Ubuntu, narrow permissions, targeted ModemManager rule,
занятый port, idempotency/rollback, pinned binaries/firmware schemas/DG.
- UI: обе поверхности на одном экземпляре, одинаковые capabilities/results,
empty/offline/fault/unknown, сохранение draft, keyboard/Escape/expand, без
новых local controls или моторной логики в App.tsx.
- Hardware: версии и backup обеих плат; измеренный fault/поведение;
отдельная проверка stop/timeout на стенде до ручного управления.
- Совместная работа: вернуть реальные D455/X4/K1 в согласованный сценарий и
измерить ресурсы/USB/latency вместе с VESC. Их текущий offline не считается
успешной regression-проверкой.
Проверки кода выполнять последовательно с учётом памяти операторского Mac.
Текущая задача не меняла runtime-код, поэтому тесты/сборки приложения не
запускались. HTTP/SSH/API чтения и анализ исходников не являются калибровкой.
## 12. Следующее конкретное действие
Реализовать и упаковать **двухэкземплярное VESC discovery + read-only identity,
config backup и общую detail-поверхность**. Первый бортовой запуск обязан
учесть уже обнаруженный duplicate USB serial. Это снимает неизвестность
HW/FW и даёт основание выбирать реальную настройку проблемного мотора.