docs(simulation): record polygon experiments and bounded route acceptance

This commit is contained in:
DCCONSTRUCTIONS
2026-09-25 16:40:46 +03:00
parent e627500295
commit dad11b47d7
8 changed files with 1962 additions and 0 deletions
+327
View File
@@ -0,0 +1,327 @@
# AI-полигон на Worker 006
Актуальная схема после миграции 21.09.2026: Worker исполняет мир, физику,
камеры, AI и команды виртуального ровера. Mission Core на Mac принимает видео,
компактную телеметрию и передаёт команды оператора. В AI-профиле нет локального
3D-движка, загрузки PLY в браузер или передачи RGB через Mac для inference.
LCC Gaussian Mirror и AI Inference остаются отдельными профилями.
## Установка и постоянный запуск
- Единственный Core: `http://127.0.0.1:8000`.
- Worker: существующий Windows / RTX 4090 / Docker Desktop, SSH `mission-gpu`.
- Native Isaac 6.1.0: `D:\NDC_MISSIONCORE\runtime\simulation\isaac-sim-6.1.0`.
- Служба: Windows Scheduled Task `ndc-ai-polygon-worker`, запускается при входе
текущего пользователя и восстанавливается после аварийного выхода. Это запуск
**при пользовательском входе**, не headless-запуск до входа в Windows.
- Управление использует существующий постоянный reverse tunnel:
Worker `127.0.0.1:18080` → Core `127.0.0.1:8000`. Старый foreground launcher
`start_worker.py` и дополнительный туннель 18081 больше не нужны.
- Поток: официальный NVIDIA Omniverse Web SDK 6.7.0, native livestream Isaac,
1280×720, запрос 30 FPS. TCP49100 / UDP47998 идут напрямую по Tailscale;
Windows Firewall разрешает только текущий приватный адрес операторского Mac.
Публичного доступа нет. Сам Isaac endpoint не предоставляет pairing/auth:
доверенная граница здесь — Tailscale и ограничение firewall. Один viewer.
`build_bundle.py --output <private-directory>` создаёт архив и манифест хешей.
Доставить их в `simulation/releases`, проверить SHA-256 архива и каждого файла,
распаковать в новый `ai-polygon-<16-hex-release>`. Из SSH-сеанса с приватного
операторского адреса выполнить поставляемый установщик:
```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\simulation\ai-polygon\Install-RealtimeWorker.ps1 -Release <16-hex-release>
```
Установщик отказывается менять службу при `state/active.json`. Он сохраняет
исходные Windows Kit Block rules в `private/stream-firewall-backup.json`,
ограничивает исключение двумя портами и одним операторским адресом, оставляя
остальные подключения заблокированными. Ошибка firewall откатывает изменения.
Обновление выполняется только при отсутствии активного прогона; после него
проверить регистрацию актуальных `runtime_sources` перед новым Start.
Откат: установить предыдущий проверенный release тем же установщиком. Удаление
службы: его параметр `-Remove` при отсутствии активного прогона. Он также
восстанавливает исходные Block rules и удаляет собственные исключения.
Isaac на новом Worker устанавливает `Prepare-IsaacRuntime.ps1`. Модельные
пакеты предварительно готовятся штатным AI Inference workflow. При старте
проверяются закреплённые images/checkpoints/runners/labels из
`models.worker-006.json`; существующие профили не заменяются. Новый realtime
ровер использует метрическую геометрию `rover_profile.py`, Jetbot не требуется.
Токен существует только в защищённых файлах: `ai-polygon/worker.token` текущего
Core data directory и `simulation/private/worker.token` на Worker. Не выводить
его и не передавать аргументом командной строки.
## Работа оператора
1. LAB → «Симуляции» → «AI-полигон» → «Доступные локации» → «Открыть».
Выбрать настройки и состав AI, затем «Открыть симуляцию».
Worker подготавливает выбранный мир; открывается настоящая удалённая сцена
с состоянием «Сцена открыта · AI выключен».
2. В «Старт и масштаб» задаются подготовка сцены и состав AI через общий
конструктор модулей. «Запустить AI» поднимает три временных контейнера
и включает локальные физику/камеру/inference. Пока модели не готовы,
виртуальный привод получает нулевую команду.
3. «За ровером», «Обзор», «Камера AI» переключают **камеру на Worker**.
Камера AI в потоке показывает тот же ракурс; модели получают локальный
несжатый RGB800×600 до операторского видеокодека.
4. «Пауза» после подтверждения Worker останавливает физику и новые inference-
запросы. Уже выполнявшийся запрос не может вернуть команду после паузы.
Контейнеры остаются готовы к продолжению. После продолжения сбрасываются
локальная визуальная цель и причинное состояние ROS-планировщика; требуется
новое наблюдение. Номер точки маршрута и зафиксированный отказ сохраняются.
5. «Завершить симуляцию» останавливает native runtime и удаляет только собственные
временные контейнеры по точным ID. Терминальный статус появляется после
подтверждения освобождения ресурсов.
6. Круглая стрелка возвращает к локациям и отсоединяет видео. **Сам прогон
продолжает работать на Worker**. Повторное «Открыть» присоединяет тот же run.
Для завершения нужен отдельный явный Stop. Развёрнутый viewer сохраняет
управление; Escape возвращает обычный размер.
Частоты разделены: «Видео» — реально декодируемые кадры браузера; «Камера» —
кадры сенсора, переданные очереди AI; «AI» — завершённые решения; «Симуляция» —
отношение физического времени к реальному. 30 FPS видео не означают AI30Hz.
Интерфейс также показывает inference и возраст кадра. Очередь хранит только
последний кадр. При возрасте наблюдения более800мс или готовой команды более500мс привод получает
ноль, но физический мир продолжает идти. Горизонт проверки корпуса включает те же
800мс, запас500мс и торможение; эти пределы нельзя менять независимо.
## Жизненный цикл и архив
Один coordinator владеет episode. Windows Job Object завершает его native
потомков при аварийном выходе coordinator. Сведения об exact container IDs
сохраняются до ожидания готовности моделей. После перезапуска coordinator
сверяет владельца, очищает собственные остатки и подтверждает завершение Core;
старое движение не воспроизводится заново.
Потеря Core/viewer не блокирует физический tick. При потере управляющей связи
Worker продолжает **ограниченный по времени лабораторный прогон** по последней
команде; локальный watchdog inference остаётся активен. UI показывает отсутствие
связи, а Core удерживает reservation до явного finish. После reconnect возвращается
тот же run, без повторного Start. Stop без связи не считается подтверждённым.
Стандартная длительность — 30 минут, API допускает 10 секунд–2 часа. Это политика
только виртуального полигона, не политика физического аппарата.
Журналы хранятся на Worker: `simulation/state/<run_id>/`:
- `run.json`, `robot-profile.json`, `motion.jsonl`, `result.json`, `worker-result.json`;
- `camera/decisions.jsonl`: monotonic и simulation timestamps, решения, boxes,
ссылки и SHA-256 сохранённых кадров;
- `camera/*.jpg`: кадры, использованные для решений, JPEG quality90. Это архивные
копии, не lossless RGB. Inference получает исходный массив до JPEG-кодирования.
- `composition.json`: точная композиция, контракты и идентичности модулей;
- `camera/*.labels.png`, `*.surface.png`, `*.range.npz`: исходная таксономия модели,
кандидаты поверхности, наблюдённый лидар и калибровка камеры;
- `terrain.json`, `initial-contact.json`: идентичность collision proxy и размещение;
- `local-state.sqlite3`: оперативный IPC coordinator/Isaac, WAL, не архив кадров.
Core получает только последний ограниченный snapshot, команды и итог. Полного
автоматического переноса архива на Mac в этом этапе нет. Прежний lockstep-архив
остаётся историческим и не является источником текущего видео.
## Миры и границы проверки
Forest Scan (draftmode, CC BY4.0): 2 142 439 splats, 505 617 082 bytes.
Bamboo Trail (luckysplat, CC BY4.0): LOD0, 5 818 957 splats, 325 861 955 bytes.
Оба PLY скачаны, проверены и кэшируются на Worker по SHA-256. Открытие не
пересылает их повторно при совпавшем кэше. Импорт дополнительных авторизованных
PLY остаётся отдельной операцией; author/license/source URL сохраняются.
Ровер имеет явный footprint1×1м и независимые левый/правый приводы. Радиус колёс
0.25м, база0.5м, колея0.9м, масса24кг и коэффициенты трения — лабораторные
допущения, не калибровка настоящего аппарата. Масштаб Gaussian-сцен пока не
подтверждён измеренной опорой. Скрытая плоскость заменена collision mesh,
полученным SplatTransform3.4.0: voxel0.06м, opacity0.25, floor-fill0.3м.
Загрузка сверяет источник, преобразование, охват тайла и SHA-256 меша.
Старт проверяет поддержку footprint, локальную плоскость и остаточную неровность.
Изменение камеры/старта внутри готового тайла не пересобирает коллизии.
Gaussian collision proxy не имеет семантики мягкой растительности: часть травы
и листвы может попасть в геометрию. Это известное ограничение, а не проверенная
модель деформируемой травы. Полное прохождение тропы, реальный тормозной путь,
скользкий грунт и динамические люди/животные требуют отдельной сценарной приёмки.
## Композиция восприятия и движения
Используется тот же `ModuleRegistry/ModuleSpec/CompositionSpec`, что в AI Inference,
с режимом `worker-local-simulation` и изолированным пространством портов pinhole.
Контракты recorded K1 не переиспользуются под другим смыслом. Выбор хранит
module id, SHA-256 и параметры; произвольный код в выборе не принимается.
По умолчанию: NVIDIA SegFormer B2 ADE150 → кандидаты грунта/камня/дороги,
RF-DETR → люди/животные, «Маршрут · контроль продвижения» → локальная цель
и состояние миссии, CMU terrain_analysis/localPlanner/pathFollower → путь
и скорость/поворот. DDRNet GOOSE64 остаётся доступной альтернативой; его прежний
image/checkpoint и профили не меняются. Два независимых провайдера исполняются
параллельно, навигация — после их результата. Исходные class IDs сохраняются.
SegFormer использует официальный pinned checkpoint и лицензию NVIDIA для
research/evaluation; этот профиль предназначен для лабораторных испытаний.
Виртуальный лидар: 15 вертикальных колец ×144 азимута, дальность8м, первый
физический контакт, наблюдения около5Гц. Дополнительные кольца −80/−75/−70°
наблюдают ближний грунт перед корпусом. Меш/карта мира не передаются AI.
Необязательные операторские точки XY задают задачу, но не разрешённую траекторию.
Семантический waypoint выбирается по RGB и диапазону,
готовый CMU-планировщик проверяет рельеф. Дополнительный монитор проверяет
квадратный корпус на дуге текущей команды с горизонтом watchdog и торможения.
Пределы лабораторного профиля: ступень0.10м, уклон25°, аварийный наклон30°.
Ступени0.15м и выше не прошли отдельную физическую проверку. Нулевая команда
удерживает физические колёсные шарниры приводом положения, без фиксации корпуса
или телепортации. На ровных уклонах10–25° проверено удержание после остановки.
Параметры solver/contact и привода фиксируются в `robot-profile.json`.
Колёса используют штатную выпуклую аппроксимацию цилиндров PhysX:
`SETTING_COLLISION_APPROXIMATE_CYLINDERS=true`. Точная форма цилиндра вызывала
зависание контакта с Forest; размеры колёс сохранены. Для новой формы повторены
проверки прямого/обратного движения, торможения, ступеней и уклонов.
В pinned localPlanner image добавлена проверка метрового прямоугольного корпуса
с запасом5см при выборе примитива и начального поворота. Если наблюдаемая точка
уже находится в запасе, допускается только сохранение или увеличение расстояния
от неё. Пересечение самого корпуса запрещено; отдельный монитор команды сохранён.
Это объявленное изменение upstream C++, воспроизводимое через
`navigation/Prepare-RectangleNavigation.ps1`, а не неизменённый CMU бинарник.
`terrain_costs.py` нормализует ложную высоту препятствия только для достаточно
наблюдённого гладкого уклона2–25°. Резкие ступени и неподтверждённые поверхности
остаются заблокированными; геометрия сцены не меняется.
Оценка грунта CMU использует штатный `quantileZ=0.25`. Экспериментальная медиана
0.5 отклонена: стены искажали оценку опоры в узком коридоре. Штатная настройка
прошла23 сценария, включая уступы12/15см и обрыв40см.
CMU сохраняет наблюдённые точки ближе4м, пока они скрыты корпусом; исчезновение
возврата не означает свободный путь. Это консервативная память статического
рельефа; очистка следов динамических участников отдельно не квалифицирована.
Наблюдения и решения должны быть свежими, иначе привод получает ноль.
Маршрут задаётся до открытия симуляции через существующую форму подготовки
сцены (до32точек XY). Пустой маршрут оставляет режим видимой тропы. После8с без продвижения к цели хотя бы0.10м модуль поведения проверяет
короткий отход назад по наблюдаемой опоре и выбирает другую цель. Отход ограничен
6с и скоростью0.1м/с; CMU и проверка корпуса сохраняют право остановки. Максимум
три попытки. Отход от цели не обновляет бюджет попыток. Это локальное восстановление,
не готовый глобальный объезд. Достижение последней точки, исчерпание попыток или
опасный наклон завершают прогон с явной причиной и освобождением ресурсов.
Физическое время используется для контроля продвижения; пауза его не расходует.
Подготовка новых зависимостей выполняется версионированными
`segformer/Prepare-Segformer.ps1`, `navigation/Prepare-Navigation.ps1`,
`navigation/Prepare-RectangleNavigation.ps1`, `navigation/Prepare-Terrain.ps1`. Образы и checkpoints закреплены в
`models.worker-006.json`. ROS-обмен остаётся внутри собственного контейнера;
его Fast DDS профиль использует loopback UDP и не зависит от старых SHM-сегментов.
Core резервирует существующую AI Inference queue. Другие Gaussian GPU jobs
пока не используют общий reservation: их нельзя запускать параллельно с этой
симуляцией. Не запускать второй coordinator, не удалять markers вручную и не
делать `docker system prune` или `compose down` чужих стеков.
Планировщик сокращает локальный путь шагом0.1м до минимальных0.2м, чтобы не
пропускать короткие манёвры на изгибе тропы. Дистанция остановки follower0.08м
относится к этому локальному отрезку; достижение маршрутной точки и полный
тормозной контур проверяются независимо. Простое снижение минимальной длины
при штатном шаге0.5м не включает эти короткие кандидаты.
Наблюдённые низкие точки уже внутри корпуса (отступ5см от краёв) сверяются с
измеренной позой и высотой опоры. Полоса±8см не расширяет предел ступени10см.
Точки впереди, высокие препятствия и провалы сохраняются; исходная память CMU
не изменяется. Поза должна принадлежать той же транзакции наблюдения, с допуском
округления ROS не более1000нс. Число коррекций записывается в журнал решений.
Последний установленный release `0d4c0a73bbbe2066` (2026-09-23 07:34:31 UTC); предыдущие версии сохранены
для воспроизводимости. Версии до `0ad2b4bf9b3dcfa6` используют неверное совпадение визуальной
и физической сцены; откат к ним не является рабочим режимом для Gaussian-навигации. При изменении Python registry композиции нужно
согласованно перезапустить Core8000 перед новым прогоном, затем проверить
health, Worker registration и module identities. Не выполнять перезапуск
во время активных операций других операторских задач.
Текущие проверки и ограничения (результаты каждой локации отдельно):
[Route recovery audit](../audits/2026-09-22-ai-polygon-route-recovery.md).
Исходная интеграция композиции и UI:
[Composed terrain navigation audit](../audits/2026-09-22-ai-polygon-composed-terrain-navigation.md).
Предыдущие результаты миграции:
[Realtime audit](../audits/2026-09-21-ai-polygon-realtime-placement.md).
Ранние lockstep-измерения остаются в integration/operator-revision audits и не
должны трактоваться как текущая архитектура.
### Совпадение Gaussian-изображения и коллизий
SplatTransform 3.4.0 присваивает входному PLY поворот Rz(180). Подготовка сначала
отменяет его, применяет пользовательское XYZ-вращение и масштаб, затем Rx(-90)
для glTF. Загрузка физики выполняет обратный переход `(x,y,z) → (x,-z,y)`.
Версионный `qualify_terrain_coordinates.py` проверяет реальный генератор на
контрольном объекте с известными координатами.
Только известный старый генератор и точная ориентация `[-90,0,180]` допускают
миграцию готового меша поворотом на180° по горизонтали. Это точное преобразование
всех вершин, без изменения препятствий; оригинал остаётся неизменным. SHA обоих
мешей и исходный manifest сохраняются в `coordinate-correction.json`. Область
подготовленной геометрии также переносится в правильные координаты. Прежние
стартовые положения и маршруты необходимо проверить заново.
### Готовая пара Gaussian и collision mesh на Worker
`register_paired_scene.py` принимает `--root`, `--source`, `--collider` и
`--descriptor` в подготовленном Python Worker. Descriptor соответствует
`WorkerWorldCreate`: происхождение и лицензия, размер, SHA-256 обоих файлов,
число splats и настройки сцены. После проверки реальных байтов инструмент
сохраняет исходник в `state/worlds/<sha>.ply`, collision manifest — в
`assets/prepared-worlds/<sha>/terrain.json`. В Core передаётся только описание.
Регистрация требует токен и текущий Worker-Instance. В этой ветке нет загрузки
больших файлов через операторскую машину; повреждённый локальный исходник
приводит к ошибке, а не к сетевому fallback.
Перед стартом проверяется весь метровый объём, включая узкие стволы между
лучами определения грунта. Старые стартовые точки Forest/Bamboo эту проверку
не проходят. Не отключать проверку и не повышать предел ступени ради запуска.
Riverside Path использует готовую пару Habitat-GS scene62; её физическая
проверка прошла4.68м. Полный маршрут R29 завершён по трём точкам с остановкой
у цели; ограничения и дальнейшие замеры зафиксированы в route audit.
Ожидание одной транзакции CMU —600мс: накопленная карта реальной сцены
может обрабатываться дольше300мс. Независимые deadman800мс для камеры и500мс
для команды сохраняются; это не разрешение исполнять просроченные результаты.
Когда заданная маршрутная точка подтверждена семантическими и дальномерными
наблюдениями, локальная цель сохраняет её XY. Уже наблюдённая точка может
войти в слепую полосу камеры; её граница определяется реальной проекцией,
а не фиксированной дистанцией. Текущая видимая поверхность, причинная карта
CMU и контроль полного корпуса продолжают ограничивать команды. Новая локальная
цель не должна уводить ровер дальше от пропущенной маршрутной точки.
Предыдущая проверка: R30 прошёл три точки Riverside Path и остановился у цели,
4.675м за32.67с. Медиана полного inference234мс, AI3.77решения/с,
рендер16.54FPS. Оптимизация расчёта расстояний побитно совпала на130 картах,
все23 проверки опасных сценариев прошли; deadman и пределы проходимости сохранены.
Это подтверждение данного паркового маршрута, а не Forest/Bamboo или бездорожья.
### Непрерывное управление и полное задание — 23 сентября
Текущая сборка `22c28daad98da60b`; подробные изменения и receipts:
[Continuous motion audit](../audits/2026-09-23-ai-polygon-continuous-motion.md).
Привод обновляется в native physics pre-step на 60 Гц, с ограничением
нарастания скорости поверхности колёс 0.2 м/с². Защитное снижение/остановка
не задерживаются. Камера и калибровка обновляются после физики; скорость берётся
из articulation velocity. `physics-motion.jsonl` и `motion-control.json`
остаются на Worker. Пауза останавливает физику и inference; продолжение требует
свежих наблюдений и сохраняет уже наблюдённую маршрутную цель.
Для CPU-ускорения существующего анализа связности используется отдельный образ
`ndc-ai-polygon-cmu:connectivity-v1`, image digest
`sha256:698228d0d378b166ceaf299aa86ab95b5e74179837532f2378c036c7f7621dcc`.
Подготовка — `navigation/Prepare-Connectivity.ps1` поверх проверенного
`rectangle-v3`. Не подменять numerical thresholds, не включать fast-math.
NumPy-эквивалентность и hazard qualification обязательны для новой сборки.
Полные paired-source коллайдеры допускают старт по всему исходному мешу;
ограничение 30-метрового generated tile к ним не применяется. Hash/calibration
и физическая проверка полной опоры/объёма сохраняются. `route_author` использует
готовый Detour для чтения Habitat navmesh; маршрут задаёт миссию и не передаёт
привилегированную геометрию в runtime inference.
Сейчас Riverside Path настроен на полное задание 97: шесть точек, путь около
11 м. R34 достиг исходного конечного положения в допуске миссии 0.4 м
(ошибка 0.344 м), перемещение 10.59 м за 86.2 с мира. Медиана inference125мс,
AI4.57Гц, рендер17.12FPS. Пять кратких остановок из-за семантической
неуверенности остаются; пауза/продолжение проверены. Это не подтверждение
всей карты, исходного задания3, бездорожья или реального привода.