# 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) — коли і чи потрібен взагалі