Files
gps-denied-onboard/README.md
T
Yuzviak 094895b21b feat(phases 2-7): implement full GPS-denied navigation pipeline
Phase 2 — Visual Odometry:
  - ORBVisualOdometry (dev/CI), CuVSLAMVisualOdometry (Jetson)
  - TRTInferenceEngine (TensorRT FP16, conditional import)
  - create_vo_backend() factory

Phase 3 — Satellite Matching + GPR:
  - SatelliteDataManager: local z/x/y tiles, ESKF ±3σ tile selection
  - GSD normalization (SAT-03), RANSAC inlier-ratio confidence (SAT-04)
  - GlobalPlaceRecognition: Faiss index + numpy fallback

Phase 4 — MAVLink I/O:
  - MAVLinkBridge: GPS_INPUT 15+ fields, IMU callback, 1Hz telemetry
  - 3-consecutive-failure reloc request
  - MockMAVConnection for CI

Phase 5 — Pipeline Wiring:
  - ESKF wired into process_frame: VO update → satellite update
  - CoordinateTransformer + SatelliteDataManager via DI
  - MAVLink state push per frame (PIPE-07)
  - Real pixel_to_gps via ray-ground projection (PIPE-06)
  - GTSAM ISAM2 update when available (PIPE-03)

Phase 6 — Docker + CI:
  - Multi-stage Dockerfile (python:3.11-slim)
  - docker-compose.yml (dev), docker-compose.sitl.yml (ArduPilot SITL)
  - GitHub Actions: ci.yml (lint+pytest+docker smoke), sitl.yml (nightly)
  - tests/test_sitl_integration.py (8 tests, skip without SITL)

Phase 7 — Accuracy Validation:
  - AccuracyBenchmark + SyntheticTrajectory
  - AC-PERF-1: 80% within 50m 
  - AC-PERF-2: 60% within 20m 
  - AC-PERF-3: p95 latency < 400ms 
  - AC-PERF-4: VO drift 1km < 100m  (actual ~11m)
  - scripts/benchmark_accuracy.py CLI

Tests: 195 passed / 8 skipped

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 17:00:41 +03:00

11 KiB
Raw Blame History

GPS-Denied Onboard

Бортова система GPS-denied навігації для фіксованого крила БПЛА на Jetson Orin Nano Super.

Замінює GPS-сигнал власною оцінкою позиції на основі відеопотоку (cuVSLAM), IMU та супутникових знімків. Позиція подається у польотний контролер ArduPilot у форматі GPS_INPUT через MAVLink при 5–10 Гц.


Архітектура

IMU (MAVLink RAW_IMU) ──────────────────────────────────────────▶ ESKF.predict()
                                                                        │
ADTI 20L V1 ──▶ ImageInputPipeline ──▶ ImageRotationManager            │
                                              │                         │
                              ┌───────────────┼───────────────┐         │
                              ▼               ▼               ▼         │
                   cuVSLAM/ORB VO    GlobalPlaceRecog    SatelliteData  │
                       (F07)            (F08/Faiss)         (F04)       │
                              │               │               │         │
                              ▼               ▼               ▼         │
                         ESKF.update_vo()   GSD norm    MetricRefinement│
                              │                              (F09)       │
                              └──────────────────────▶ ESKF.update_sat()│
                                                                        │
                                                         ESKF state ◀──┘
                                                              │
                                              ┌───────────────┼──────────────┐
                                              ▼               ▼              ▼
                                      MAVLinkBridge    FactorGraph     SSE Stream
                                      GPS_INPUT 5-10Hz  (GTSAM ISAM2)  → Ground Station
                                      → ArduPilot FC

State Machine (process_frame):

NORMAL ──(VO fail)──▶ LOST ──▶ RECOVERY ──(GPR+Metric ok)──▶ NORMAL

Стек

Підсистема Dev/CI Jetson (production)
Visual Odometry ORBVisualOdometry (OpenCV) CuVSLAMVisualOdometry (PyCuVSLAM v15)
AI Inference MockInferenceEngine TRTInferenceEngine (TensorRT FP16)
Place Recognition numpy L2 fallback Faiss GPU index
MAVLink MockMAVConnection pymavlink over UART
ESKF numpy (15-state) numpy (15-state)
Factor Graph Mock poses GTSAM 4.3 ISAM2
API FastAPI + Pydantic v2 + SSE FastAPI + Pydantic v2 + SSE
БД SQLite + SQLAlchemy 2 async SQLite
Тести pytest + pytest-asyncio

Швидкий старт

Вимоги

  • Python ≥ 3.11
  • ~500 MB дискового простору (GTSAM wheel)

Встановлення

git clone https://github.com/azaion/gps-denied-onboard.git
cd gps-denied-onboard
git checkout stage1

python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

Запуск

# Пряме запуск
python -m gps_denied

# Docker
docker compose up --build

Сервер: http://127.0.0.1:8000

Змінні середовища

GPS_DENIED_DB_PATH=/data/flights.db
GPS_DENIED_TILE_DIR=/data/satellite_tiles   # локальні тайли z/x/y.png
GPS_DENIED_LOG_LEVEL=INFO
MAVLINK_CONNECTION=serial:/dev/ttyTHS1:57600  # UART на Jetson

API

Endpoint Метод Опис
/health GET Health check
/flights POST Створити політ
/flights/{id} GET Деталі польоту
/flights/{id} DELETE Видалити політ
/flights/{id}/images/batch POST Батч зображень
/flights/{id}/fix POST GPS-якір від оператора
/flights/{id}/status GET Статус обробки
/flights/{id}/events GET SSE стрім (позиція + confidence)
/flights/{id}/object-gps POST Pixel → GPS (ray-ground проекція)

Тести

# Всі тести
python -m pytest -q

# Конкретний модуль
python -m pytest tests/test_eskf.py -v
python -m pytest tests/test_mavlink.py -v
python -m pytest tests/test_accuracy.py -v

# SITL (потребує ArduPilot SITL)
docker compose -f docker-compose.sitl.yml up -d
ARDUPILOT_SITL_HOST=localhost pytest tests/test_sitl_integration.py -v

Покриття тестами (195 passed / 8 skipped)

Файл тесту Компонент К-сть
test_schemas.py Pydantic схеми 12
test_database.py SQLAlchemy CRUD 9
test_api_flights.py REST endpoints 5
test_health.py Health check 1
test_eskf.py ESKF 15-state 17
test_coordinates.py ENU/GPS/pixel 4
test_satellite.py Тайли + Mercator 8
test_pipeline.py Image queue 5
test_rotation.py 360° ротації 4
test_models.py Model Manager + TRT 6
test_vo.py VO (ORB + cuVSLAM) 8
test_gpr.py Place Recognition (Faiss) 7
test_metric.py Metric Refinement + GSD 6
test_graph.py Factor Graph (GTSAM) 4
test_chunk_manager.py Chunk lifecycle 3
test_recovery.py Recovery coordinator 2
test_processor_full.py State Machine 4
test_processor_pipe.py PIPE wiring (Phase 5) 13
test_mavlink.py MAVLink I/O bridge 19
test_acceptance.py AC сценарії + perf 6
test_accuracy.py Accuracy validation 23
test_sitl_integration.py SITL (skip без ArduPilot) 8
Всього 195+8

Benchmark валідації (Phase 7)

python scripts/benchmark_accuracy.py --frames 50

Результати на синтетичній траєкторії (20 м/с, 0.7 fps, шум VO 0.3 м, супутник кожні 5 кадрів):

Критерій Результат Ліміт
80% кадрів ≤ 50 м 100% ≥ 80%
60% кадрів ≤ 20 м 100% ≥ 60%
p95 затримка ~9 мс < 400 мс
VO дрейф за 1 км ~11 м < 100 м

Структура проєкту

gps-denied-onboard/
├── src/gps_denied/
│   ├── app.py                     # FastAPI factory + lifespan
│   ├── config.py                  # Pydantic Settings
│   ├── api/routers/flights.py     # REST + SSE endpoints
│   ├── core/
│   │   ├── eskf.py                # 15-state ESKF (IMU+VO+satellite fusion)
│   │   ├── processor.py           # FlightProcessor + process_frame
│   │   ├── vo.py                  # ORBVisualOdometry / CuVSLAMVisualOdometry
│   │   ├── mavlink.py             # MAVLinkBridge → GPS_INPUT → ArduPilot
│   │   ├── satellite.py           # SatelliteDataManager (local z/x/y tiles)
│   │   ├── gpr.py                 # GlobalPlaceRecognition (Faiss/numpy)
│   │   ├── metric.py              # MetricRefinement (LiteSAM/XFeat + GSD)
│   │   ├── graph.py               # FactorGraphOptimizer (GTSAM ISAM2)
│   │   ├── coordinates.py         # CoordinateTransformer (ENU↔GPS↔pixel)
│   │   ├── models.py              # ModelManager + TRTInferenceEngine
│   │   ├── benchmark.py           # AccuracyBenchmark + SyntheticTrajectory
│   │   ├── pipeline.py            # ImageInputPipeline
│   │   ├── rotation.py            # ImageRotationManager
│   │   ├── recovery.py            # FailureRecoveryCoordinator
│   │   └── chunk_manager.py       # RouteChunkManager
│   ├── schemas/                   # Pydantic схеми (eskf, mavlink, vo, ...)
│   ├── db/                        # SQLAlchemy ORM + async repository
│   └── utils/mercator.py          # Web Mercator tile utilities
├── tests/                         # 22 test модулі
├── scripts/
│   └── benchmark_accuracy.py      # CLI валідація точності
├── Dockerfile                     # Multi-stage Python 3.11 image
├── docker-compose.yml             # Local dev
├── docker-compose.sitl.yml        # ArduPilot SITL harness
├── .github/workflows/
│   ├── ci.yml                     # lint + pytest + docker smoke (кожен push)
│   └── sitl.yml                   # SITL integration (нічний / ручний)
└── pyproject.toml

Компоненти

ID Назва Файл Dev Jetson
F04 Satellite Data Manager core/satellite.py local tiles local tiles
F05 Image Input Pipeline core/pipeline.py
F06 Image Rotation Manager core/rotation.py
F07 Sequential Visual Odometry core/vo.py ORB cuVSLAM
F08 Global Place Recognition core/gpr.py numpy Faiss GPU
F09 Metric Refinement core/metric.py Mock LiteSAM/XFeat TRT
F10 Factor Graph Optimizer core/graph.py Mock GTSAM ISAM2
F11 Failure Recovery core/recovery.py
F12 Route Chunk Manager core/chunk_manager.py
F13 Coordinate Transformer core/coordinates.py
F16 Model Manager core/models.py Mock TRT engines
F17 ESKF Sensor Fusion core/eskf.py
F18 MAVLink I/O Bridge core/mavlink.py Mock pymavlink

Що залишилось (on-device)

  1. Офлайн завантаження тайлів для зони місії → {tile_dir}/z/x/y.png
  2. Конвертація моделей: LiteSAM/XFeat PyTorch → ONNX → TRT FP16
  3. Запуск SITL: docker compose -f docker-compose.sitl.yml up
  4. Польотні дані: записати GPS + відео → порівняти ESKF-траєкторію з ground truth
  5. Калібрування: camera intrinsics + IMU noise density для конкретного апарату

Ліцензія

Приватний репозиторій. Усі права захищено.