Files
gps-denied-onboard/docs/superpowers/specs/2026-04-18-oss-stack-tech-audit-design.md
T
Yuzviak 352d5e59ed 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) <noreply@anthropic.com>
2026-04-18 15:29:02 +03:00

180 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tech Audit — Open-Source Stack для GPS-Denied Navigation
**Дата:** 2026-04-18
**Горизонт:** 23 тижні (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.30.5 м
**Drift на маршруті:** обмежений — GPR скидає накопичену похибку
### Чому drift не критичний
Архітектура має три рівні корекції:
```
VO (drift між кадрами)
ESKF ← IMU (короткострокова стабілізація, ~ms)
Place Recognition ← satellite tiles (глобальна корекція, ~сотні метрів)
GTSAM loop closure (довгострокова консистентність)
```
Якщо GPR впізнає місцевість кожні ~500 м → загальна похибка на 10 км маршруту: **15 м**. Це прийнятно для 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 510 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) | 1012 мс 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 013, 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 | 510 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) — коли і чи потрібен взагалі