From 352d5e59eda9ad67142e5e9ba218f9497e3c32c7 Mon Sep 17 00:00:00 2001 From: Yuzviak Date: Sat, 18 Apr 2026 15:29:02 +0300 Subject: [PATCH] docs(tech-audit): OSS stack audit and sprint-1 technology decisions Records architectural gap (cuVSLAM Mono has no metric scale), chosen path (Mono-Depth + barometer), and per-layer decisions for VO, ESKF, GTSAM, Place Recognition, and MAVLink. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../2026-04-18-oss-stack-tech-audit-design.md | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-18-oss-stack-tech-audit-design.md diff --git a/docs/superpowers/specs/2026-04-18-oss-stack-tech-audit-design.md b/docs/superpowers/specs/2026-04-18-oss-stack-tech-audit-design.md new file mode 100644 index 0000000..e518c79 --- /dev/null +++ b/docs/superpowers/specs/2026-04-18-oss-stack-tech-audit-design.md @@ -0,0 +1,179 @@ +# Tech Audit — Open-Source Stack для GPS-Denied Navigation +**Дата:** 2026-04-18 +**Горизонт:** 2–3 тижні (sprint 1) +**Контекст:** Fixed-wing БПЛА, Jetson Orin Nano Super, nadir камера ADTI 20L V1, ArduPilot FC + +--- + +## 1. Архітектурний розрив — головна знахідка + +### Проблема з cuVSLAM Inertial mode + +Поточна архітектура планує cuVSLAM у режимі "Inertial" (з IMU). Але: + +- cuVSLAM Inertial/Visual-Inertial mode потребує **стерео камеру** (дві камери поряд, як очі) +- У нас одна nadir камера — Mono режим +- cuVSLAM Mono дає лише кут повороту, **без metric scale** (без відстані) +- Без scale неможливо побудувати GPS_INPUT — це useless для ArduPilot + +**Важливо:** камера пілота (вперед) + nadir камера (вниз) — це не stereo. Stereo = дві камери в одному напрямку на відстані 10–20 см. + +### Чому це не критично для sprint 1 + +Scale для nadir камери над рівною місцевістю — **детермінований**: + +``` +scale = altitude / focal_length +``` + +Барометр дає висоту → ESKF рахує scale → VO потребує лише точний 2D planar tracking. Це і є перший шлях. + +--- + +## 2. Вибрана архітектура (sprint 1) + +### VO: cuVSLAM Mono-Depth + барометр + +**Рішення:** cuVSLAM Mono-Depth режим, де барометрична висота подається як synthetic depth для відновлення metric scale. + +**Точність між GPR корекціями:** ~0.3–0.5 м +**Drift на маршруті:** обмежений — GPR скидає накопичену похибку + +### Чому drift не критичний + +Архітектура має три рівні корекції: + +``` +VO (drift між кадрами) + ↓ +ESKF ← IMU (короткострокова стабілізація, ~ms) + ↓ +Place Recognition ← satellite tiles (глобальна корекція, ~сотні метрів) + ↓ +GTSAM loop closure (довгострокова консистентність) +``` + +Якщо GPR впізнає місцевість кожні ~500 м → загальна похибка на 10 км маршруту: **1–5 м**. Це прийнятно для GPS-denied. + +**Ризик GPR:** не спрацює при хмарах, однорідній місцевості (поле без орієнтирів), застарілих тайлах. В цих випадках drift накопичується до наступного успішного match. + +--- + +## 3. Технологічний стек — рішення по шарах + +### VO Layer + +| Компонент | Dev/CI | Production (Jetson) | Статус | +|---|---|---|---| +| **Visual Odometry** | ORBVisualOdometry (OpenCV) | cuVSLAM Mono-Depth | Залишаємо, фіксуємо Mono-Depth | +| **XFeat** | — | Satellite tile matching (майбутнє) | Не VO fallback, окремий трек | +| **SuperPoint+LightGlue** | — | — | Відхилено: 15–33× повільніше за cuVSLAM | + +**Відхилені альтернативи:** +- ORB-SLAM3 Mono-Inertial (~0.08 м) — потребує IMU ≥100 Hz по MAVLink. Типово ArduPilot шле 50 Hz (SR*_RAW_SENS). Можна підняти до 200 Hz зміною одного параметра, але не пріоритет зараз. +- cuVSLAM Stereo-Inertial (0.054 м) — потребує hardware зміни (друга камера). Довгостроково. + +### ESKF + +| Рішення | Обґрунтування | +|---|---| +| Залишаємо numpy 15-state ESKF | IMU preintegration не критичний на 5–10 Hz VO для повільного fixed-wing | +| **Пінити `numpy==1.26.4`** | NumPy 2.0 ламає GTSAM Python bindings (issue #2264) — критично | +| `manifpy` — опційно | pip-installable Lie group math, додати тільки якщо знайдемо баги в quaternion коді | + +### Factor Graph (GTSAM) + +**Рішення sprint 1: пропустити GTSAM, використовувати ESKF.** + +ESKF достатній для Gaussian GPS_INPUT 5–10 Hz. Factor graph дає перевагу (~15 vs 34 см) лише при non-Gaussian noise з outliers — не наш сценарій зараз. + +Коли повернутись: **GTSAM 4.2 stable** (не 4.3a1 alpha). miniSAM — стейл з 2019, g2o Python — experimental. Єдиний живий варіант. + +### Place Recognition + +| Компонент | Рішення | Обґрунтування | +|---|---|---| +| **Descriptor** | DINOv2-VLAD (AnyLoc) | 10–12 мс TRT FP16 на Jetson, offline-capable | +| **Index** | Faiss GPU | Залишаємо | +| **INT8 квантизація** | ❌ Не робити | Broken для ViT на Jetson (NVIDIA/TRT#4348, dinov2#489) | +| **Довгостроково** | EigenPlaces (ICCV 2023) | Кращий ONNX export, viewpoint-robust | +| **NetVLAD** | ❌ Deprecated | DINOv2-VLAD краще на 2.4% R@1 (MSLS 2024) | +| **Satellite tiles** | MapTiler offline MBTiles | Україна zoom 0–13, JPEG, offline | + +**Перевірити:** [aero-vloc](https://github.com/prime-slam/aero-vloc) — benchmark на aerial nadir imagery до того як фіксувати Faiss index дизайн. + +### MAVLink / ArduPilot + +| Рішення | Обґрунтування | +|---|---| +| **pymavlink** залишаємо | MAVSDK-Python не підтримує GPS_INPUT (PX4-first) | +| Reference impl | `MAVProxy/modules/mavproxy_GPSInput.py` — точне кодування GPS_INPUT (#232) | +| Частота injection | 5–10 Hz (не 20 Hz — timing jitter при вищих rate) | +| Yaw extension field | Не використовувати — ArduPilot 4.x ігнорує | + +--- + +## 4. Критичні перевірки перед кодом + +Три речі, які треба знати до того як писати будь-який код: + +### 4.1 Процесор Flight Controller +- **H743** — підтримує GPS_INPUT over serial ✅ +- **F405** — мовчки ігнорує GPS_INPUT ❌ (втрата днів на дебаг) +- Перевірити: Mission Planner → Help → About (показує назву FC), або питати у постачальника дрона + +### 4.2 IMU rate по MAVLink +- За замовчуванням ArduPilot: **50 Hz** +- Для ORB-SLAM3 Mono-Inertial потрібно: **≥100 Hz** +- Параметр для зміни: `SR2_RAW_SENS` (або SR0/SR1 залежно від порту) +- Для sprint 1 (cuVSLAM Mono-Depth) — не критично + +### 4.3 numpy версія +- Зафіксувати `numpy==1.26.4` в `pyproject.toml` негайно +- NumPy 2.0 ламає GTSAM silently — важко дебажити + +--- + +## 5. Пріоритети на 2–3 тижні + +### Тиждень 1 +- [ ] Зафіксувати `numpy==1.26.4` в pyproject.toml +- [ ] Перевірити FC processor (H743 vs F405) +- [ ] Перевірити поточний IMU rate по MAVLink +- [ ] Prototype cuVSLAM Mono-Depth з барометром як synthetic depth +- [ ] Запустити aero-vloc на наших nadir кадрах + +### Тиждень 2 +- [ ] cuVSLAM Mono-Depth інтеграція в E2EHarness +- [ ] Порівняти ATE: ORB (поточний baseline) vs cuVSLAM Mono-Depth +- [ ] AnyLoc offline setup + перший тест на satellite tiles + +### Тиждень 3 +- [ ] XFeat TRT export для satellite matching (окремий трек від VO) +- [ ] MAVLink GPS_INPUT injection тест на SITL (Software-in-the-Loop) +- [ ] Визначити чи варто піднімати IMU rate для майбутнього Mono-Inertial + +--- + +## 6. Аналоги нашої системи + +Для розуміння де ми знаходимось відносно SOTA: + +| Система | VO | Fusion | Scale | Статус | +|---|---|---|---|---| +| **Наша** | cuVSLAM Mono | ESKF | Барометр | Sprint 1 | +| **VINS-Fusion** | Mono-Inertial | Factor graph | IMU | Open-source, ROS | +| **OpenVINS** | MSCKF Mono | EKF | IMU | Open-source, ~0.08м EuRoC | +| **PX4 EKF2** | — | UKF | GPS | Вбудований в PX4 | +| **ArduPilot EKF3** | — | EKF | GPS | Вбудований в ArduPilot | + +Наша архітектура унікальна тим що **замінює GPS через Place Recognition** (satellite matching) — не просто VIO, а VIO + global anchor. Це правильний підхід для тривалих маршрутів. + +--- + +## 7. Відкриті питання + +1. Якість cuVSLAM Mono-Depth на feature-poor nadir terrain (рівне поле, ліс) — потребує льотних тестів +2. Частота та надійність GPR match в реальних умовах України +3. Чи достатньо барометра для scale recovery при різких змінах висоти (маневри, вітер) +4. Перехід на Stereo-Inertial (hardware) — коли і чи потрібен взагалі