mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-04-23 01:06:36 +00:00
docs: update README and next_steps with sprint 1 VO migration results
README: - Stack table: VO row shows CuVSLAMMonoDepthVisualOdometry (Mono-Depth mode) - Test coverage: 195+8 → 216+8 (new mono_depth tests, AnyLoc markers, GPS_INPUT encoding) - Added test_gps_input_encoding.py row - F07 component table: dev/prod shows Mono-Depth variants - "Next steps" rewritten: sprint 1 complete, sprint 2 queued next_steps.md: - New §5.1a documenting sprint 1 execution (7 commits, 3 decisions recorded) - §5.3 week-1 marked numpy pin / Mono-Depth class / GPS_INPUT encoding as done - Week-2 updated with harness wiring and CuVSLAMVisualOdometry deletion tasks Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -43,12 +43,12 @@ NORMAL ──(VO fail)──▶ LOST ──▶ RECOVERY ──(GPR+Metric ok)─
|
|||||||
|
|
||||||
| Підсистема | Dev/CI | Jetson (production) |
|
| Підсистема | Dev/CI | Jetson (production) |
|
||||||
|-----------|--------|---------------------|
|
|-----------|--------|---------------------|
|
||||||
| **Visual Odometry** | ORBVisualOdometry (OpenCV) | CuVSLAMVisualOdometry (PyCuVSLAM v15) |
|
| **Visual Odometry** | ORBVisualOdometry / CuVSLAMMonoDepthVisualOdometry (scaled ORB fallback) | CuVSLAMMonoDepthVisualOdometry (PyCuVSLAM v15 Mono-Depth — barometer as synthetic depth) |
|
||||||
| **AI Inference** | MockInferenceEngine | TRTInferenceEngine (TensorRT FP16) |
|
| **AI Inference** | MockInferenceEngine | TRTInferenceEngine (TensorRT FP16; INT8 disabled — broken for ViT on Jetson) |
|
||||||
| **Place Recognition** | numpy L2 fallback | Faiss GPU index |
|
| **Place Recognition** | numpy L2 fallback (AnyLoc-VLAD-DINOv2 baseline) | Faiss GPU index + DINOv2-VLAD TRT FP16 |
|
||||||
| **MAVLink** | MockMAVConnection | pymavlink over UART |
|
| **MAVLink** | MockMAVConnection | pymavlink over UART |
|
||||||
| **ESKF** | numpy (15-state) | numpy (15-state) |
|
| **ESKF** | numpy (15-state) | numpy (15-state) |
|
||||||
| **Factor Graph** | Mock poses | GTSAM 4.3 ISAM2 |
|
| **Factor Graph** | Mock poses | GTSAM 4.3 ISAM2 (sprint 2 — ESKF-only sufficient for sprint 1) |
|
||||||
| **API** | FastAPI + Pydantic v2 + SSE | FastAPI + Pydantic v2 + SSE |
|
| **API** | FastAPI + Pydantic v2 + SSE | FastAPI + Pydantic v2 + SSE |
|
||||||
| **БД** | SQLite + SQLAlchemy 2 async | SQLite |
|
| **БД** | SQLite + SQLAlchemy 2 async | SQLite |
|
||||||
| **Тести** | pytest + pytest-asyncio | — |
|
| **Тести** | pytest + pytest-asyncio | — |
|
||||||
@@ -181,7 +181,7 @@ E2E-харнес гонить `FlightProcessor` як black-box через спі
|
|||||||
EuRoC: `vo_success=99/100`, `eskf_initialized=100/100`. GPS estimate xfail — indoor, satellite tiles не релевантні.
|
EuRoC: `vo_success=99/100`, `eskf_initialized=100/100`. GPS estimate xfail — indoor, satellite tiles не релевантні.
|
||||||
VPAIR: ESKF не активний (немає raw IMU), VO без якоря розходиться. Outdoor — потенційно satellite matching допоможе.
|
VPAIR: ESKF не активний (немає raw IMU), VO без якоря розходиться. Outdoor — потенційно satellite matching допоможе.
|
||||||
|
|
||||||
### Покриття тестами (70 e2e passed / 1 skipped / 2 xfailed; 195 passed / 8 skipped — unit/component)
|
### Покриття тестами (216 passed / 8 skipped — unit/component; EuRoC MH_01–05 e2e PASS)
|
||||||
|
|
||||||
| Файл тесту | Компонент | К-сть |
|
| Файл тесту | Компонент | К-сть |
|
||||||
|-------------|-----------|-------|
|
|-------------|-----------|-------|
|
||||||
@@ -195,8 +195,8 @@ VPAIR: ESKF не активний (немає raw IMU), VO без якоря р
|
|||||||
| `test_pipeline.py` | Image queue | 5 |
|
| `test_pipeline.py` | Image queue | 5 |
|
||||||
| `test_rotation.py` | 360° ротації | 4 |
|
| `test_rotation.py` | 360° ротації | 4 |
|
||||||
| `test_models.py` | Model Manager + TRT | 6 |
|
| `test_models.py` | Model Manager + TRT | 6 |
|
||||||
| `test_vo.py` | VO (ORB + cuVSLAM) | 8 |
|
| `test_vo.py` | VO (ORB + cuVSLAM + Mono-Depth) | 16 |
|
||||||
| `test_gpr.py` | Place Recognition (Faiss) | 7 |
|
| `test_gpr.py` | Place Recognition + AnyLoc markers | 9 |
|
||||||
| `test_metric.py` | Metric Refinement + GSD | 6 |
|
| `test_metric.py` | Metric Refinement + GSD | 6 |
|
||||||
| `test_graph.py` | Factor Graph (GTSAM) | 4 |
|
| `test_graph.py` | Factor Graph (GTSAM) | 4 |
|
||||||
| `test_chunk_manager.py` | Chunk lifecycle | 3 |
|
| `test_chunk_manager.py` | Chunk lifecycle | 3 |
|
||||||
@@ -204,10 +204,11 @@ VPAIR: ESKF не активний (немає raw IMU), VO без якоря р
|
|||||||
| `test_processor_full.py` | State Machine | 4 |
|
| `test_processor_full.py` | State Machine | 4 |
|
||||||
| `test_processor_pipe.py` | PIPE wiring (Phase 5) | 13 |
|
| `test_processor_pipe.py` | PIPE wiring (Phase 5) | 13 |
|
||||||
| `test_mavlink.py` | MAVLink I/O bridge | 19 |
|
| `test_mavlink.py` | MAVLink I/O bridge | 19 |
|
||||||
|
| `test_gps_input_encoding.py` | GPS_INPUT field encoding (MAVLink #232) | 12 |
|
||||||
| `test_acceptance.py` | AC сценарії + perf | 6 |
|
| `test_acceptance.py` | AC сценарії + perf | 6 |
|
||||||
| `test_accuracy.py` | Accuracy validation | 23 |
|
| `test_accuracy.py` | Accuracy validation | 23 |
|
||||||
| `test_sitl_integration.py` | SITL (skip без ArduPilot) | 8 |
|
| `test_sitl_integration.py` | SITL (skip без ArduPilot) | 8 |
|
||||||
| | **Всього** | **195+8** |
|
| | **Всього** | **216+8** |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -276,7 +277,7 @@ gps-denied-onboard/
|
|||||||
| F04 | Satellite Data Manager | `core/satellite.py` | local tiles | local tiles |
|
| F04 | Satellite Data Manager | `core/satellite.py` | local tiles | local tiles |
|
||||||
| F05 | Image Input Pipeline | `core/pipeline.py` | ✅ | ✅ |
|
| F05 | Image Input Pipeline | `core/pipeline.py` | ✅ | ✅ |
|
||||||
| F06 | Image Rotation Manager | `core/rotation.py` | ✅ | ✅ |
|
| F06 | Image Rotation Manager | `core/rotation.py` | ✅ | ✅ |
|
||||||
| F07 | Sequential Visual Odometry | `core/vo.py` | ORB | cuVSLAM |
|
| F07 | Sequential Visual Odometry | `core/vo.py` | ORB / Mono-Depth (scaled ORB) | cuVSLAM Mono-Depth |
|
||||||
| F08 | Global Place Recognition | `core/gpr.py` | numpy | Faiss GPU |
|
| F08 | Global Place Recognition | `core/gpr.py` | numpy | Faiss GPU |
|
||||||
| F09 | Metric Refinement | `core/metric.py` | Mock | LiteSAM/XFeat TRT |
|
| F09 | Metric Refinement | `core/metric.py` | Mock | LiteSAM/XFeat TRT |
|
||||||
| F10 | Factor Graph Optimizer | `core/graph.py` | Mock | GTSAM ISAM2 |
|
| F10 | Factor Graph Optimizer | `core/graph.py` | Mock | GTSAM ISAM2 |
|
||||||
@@ -291,12 +292,25 @@ gps-denied-onboard/
|
|||||||
|
|
||||||
## Що залишилось (наступні кроки)
|
## Що залишилось (наступні кроки)
|
||||||
|
|
||||||
### Dev pipeline (захищений e2e-харнесом)
|
### Sprint 1 — виконано (2026-04-18)
|
||||||
1. **cuVSLAM Mono-Depth** — замінити `ORBVisualOdometry` на cuVSLAM Mono + барометричний depth (`scale = altitude / focal_length`). Mono-Inertial потребує stereo hardware (нема). Mono-Depth — правильний шлях для одиничної nadir-камери. Research: `docs/superpowers/specs/2026-04-18-oss-stack-tech-audit-design.md`.
|
|
||||||
2. **DINOv2-VLAD (AnyLoc) для GPR** — замінити numpy L2 fallback. Satellite tiles через MapTiler MBTiles (offline). Fixed FP16, без INT8 (broken для ViT на Jetson).
|
Див. план `docs/superpowers/plans/2026-04-18-sprint1-vo-migration.md` і design doc `docs/superpowers/specs/2026-04-18-oss-stack-tech-audit-design.md`.
|
||||||
3. **VPAIR unblock** — xfail (1770 км ATE) блокований відсутністю raw IMU + mock satellite index. Реальні MapTiler tiles **АБО** cuVSLAM Mono-Depth з GT-altitude розблокують.
|
|
||||||
4. **Аудит solution.md** — звірити імплементацію з `_docs/01_solution/solution.md`.
|
- [x] **numpy pin** `>=1.26,<2.0` — NumPy 2.0 silently breaks GTSAM bindings (issue #2264)
|
||||||
5. **Реструктуризація** — `src/gps_denied/*` → `src/*` (зайвий неймспейс).
|
- [x] **CuVSLAMMonoDepthVisualOdometry** додано поряд з Inertial-варіантом. Dev/CI: ORB translation scaled by `depth_hint_m / 600.0`. Jetson: cuVSLAM Mono-Depth mode з barometric altitude як synthetic depth.
|
||||||
|
- [x] **GlobalPlaceRecognition** явно маркований як AnyLoc-VLAD-DINOv2 baseline з selection rationale в docstring
|
||||||
|
- [x] **GPS_INPUT encoding** покритий 12 unit-тестами проти `_eskf_to_gps_input` (degE7 lat/lon, ENU→NED velocity, ConfidenceTier → fix_type)
|
||||||
|
- [x] **E2E regression guard** на EuRoC MH_01 для Mono-Depth (ATE 0.2046м, baseline незмінний)
|
||||||
|
|
||||||
|
### Sprint 2 — далі (захищений e2e-харнесом)
|
||||||
|
|
||||||
|
1. **Wire CuVSLAMMonoDepthVisualOdometry через E2EHarness** — harness зараз хардкодить `ORBVisualOdometry()`; додати `vo_backend` параметр щоб прогнати Mono-Depth через pipeline
|
||||||
|
2. **Колапс дуплікатного коду з `CuVSLAMVisualOdometry`** (Inertial варіант) — видалити Inertial mode після Jetson validation
|
||||||
|
3. **VPAIR unblock** — xfail (1770 км ATE) блокований відсутністю raw IMU + mock satellite index. Реальні MapTiler tiles + Mono-Depth з GT-altitude розблокують.
|
||||||
|
4. **DINOv2-VLAD TRT FP16 engine** — реальний descriptor замість numpy L2 fallback. Satellite tiles через MapTiler MBTiles (offline).
|
||||||
|
5. **aero-vloc benchmark** на наших nadir кадрах — підтвердити R@1 DINOv2-VLAD перед фіксацією Faiss index design
|
||||||
|
6. **Аудит solution.md** — звірити `_docs/01_solution/solution.md` з реальним кодом (Inertial → Mono-Depth)
|
||||||
|
7. **Реструктуризація** — `src/gps_denied/*` → `src/*`
|
||||||
|
|
||||||
### Критичні блокери (перевірити до наступного коду)
|
### Критичні блокери (перевірити до наступного коду)
|
||||||
- **Flight Controller processor**: H743 ✅ / F405 ❌ (silently ignores GPS_INPUT). Запитати постачальника.
|
- **Flight Controller processor**: H743 ✅ / F405 ❌ (silently ignores GPS_INPUT). Запитати постачальника.
|
||||||
|
|||||||
+21
-5
@@ -136,6 +136,20 @@ Research документ `docs/superpowers/specs/2026-04-18-oss-stack-tech-audi
|
|||||||
- Результат не залежить від scale: ESKF ATE ≈ 1236-1343 м, GPS ATE ≈ 1770 км.
|
- Результат не залежить від scale: ESKF ATE ≈ 1236-1343 м, GPS ATE ≈ 1770 км.
|
||||||
- [decision 2026-04-18: VPAIR **не можна зробити PASS на поточному стеку**. Фундаментальні блокери: (а) немає raw IMU → ESKF дрейфує за рахунок тільки VO; (б) Mock satellite index повертає координати «в іншій півкулі світу» (не реальні tiles України), тому Mahalanobis gate відхиляє satellite estimates як outliers (Δ²~10⁹). Залишаємо xfail із задокументованою причиною. Розблокувати зможе: реальні satellite tiles (MapTiler MBTiles) **АБО** cuVSLAM Mono-Depth з барометром (dataset-level synthetic IMU).]
|
- [decision 2026-04-18: VPAIR **не можна зробити PASS на поточному стеку**. Фундаментальні блокери: (а) немає raw IMU → ESKF дрейфує за рахунок тільки VO; (б) Mock satellite index повертає координати «в іншій півкулі світу» (не реальні tiles України), тому Mahalanobis gate відхиляє satellite estimates як outliers (Δ²~10⁹). Залишаємо xfail із задокументованою причиною. Розблокувати зможе: реальні satellite tiles (MapTiler MBTiles) **АБО** cuVSLAM Mono-Depth з барометром (dataset-level synthetic IMU).]
|
||||||
|
|
||||||
|
### 5.1a Sprint 1 VO migration — виконано (2026-04-18 ніч)
|
||||||
|
|
||||||
|
Plan: `docs/superpowers/plans/2026-04-18-sprint1-vo-migration.md`. 7 комітів, 216 passed / 8 skipped.
|
||||||
|
|
||||||
|
- [x] **CuVSLAMMonoDepthVisualOdometry** додано (`src/gps_denied/core/vo.py`). Приймає `depth_hint_m` (барометрична висота) як параметр, dev/CI fallback масштабує ORB translation на `depth_hint_m / 600.0`. Клас чітко вказує у docstring що `solution.md` говорить `INERTIAL mode` — але цей режим потребує stereo, тому фактично використовується `MONO_DEPTH`.
|
||||||
|
- [x] **`create_vo_backend()`** оновлено з параметрами `prefer_mono_depth` і `depth_hint_m`.
|
||||||
|
- [x] **GlobalPlaceRecognition** маркований як AnyLoc-VLAD-DINOv2 baseline. Selection rationale (NetVLAD deprecated, SP+LG не валідований для cross-view) — в docstring. 2 marker-тести: 4096-d descriptor + DINOv2 engine name через mock.
|
||||||
|
- [x] **GPS_INPUT field encoding** — 12 unit-тестів в `tests/test_gps_input_encoding.py` проти `_eskf_to_gps_input` (degE7 lat/lon, ENU→NED velocity, ConfidenceTier→fix_type, synthetic satellites_visible=10, hdop floor).
|
||||||
|
- [x] **EuRoC Mono-Depth regression guard** (`test_euroc_mh01_mono_depth_within_ceiling`) — smoke test + ORB pipeline ceiling 0.5 м. Baseline незмінний: 0.2046 м.
|
||||||
|
- [x] **`update_depth_hint` tests** — clamp at 1.0 м і per-call scale update через mock.
|
||||||
|
- [decision 2026-04-18: **не переписуємо solution.md** (Inertial → Mono-Depth). Це окрема задача з §1. Поточний код явно документує розходження в docstring класу + design doc + next_steps.md §5.1a. Аудит `solution.md` — окремий спринт.]
|
||||||
|
- [decision 2026-04-18: **не створюємо новий AnyLocGPR клас** — `GlobalPlaceRecognition` у docstring вже стверджував «AnyLoc (DINOv2)». Замість дублювання — розширили docstring і додали marker-тести.]
|
||||||
|
- [decision 2026-04-18: **E2E harness поки не wireує Mono-Depth через pipeline** — harness хардкодить `ORBVisualOdometry()`. Додати `vo_backend` параметр і прогнати Mono-Depth через pipeline — sprint 2 task. TODO marker у vo.py.]
|
||||||
|
|
||||||
### 5.2 Відкореговано в плані (наступні дії)
|
### 5.2 Відкореговано в плані (наступні дії)
|
||||||
|
|
||||||
**cuVSLAM стратегія** (research §1, §2):
|
**cuVSLAM стратегія** (research §1, §2):
|
||||||
@@ -167,19 +181,21 @@ Research документ `docs/superpowers/specs/2026-04-18-oss-stack-tech-audi
|
|||||||
|
|
||||||
**Тиждень 1 (починається 2026-04-19):**
|
**Тиждень 1 (починається 2026-04-19):**
|
||||||
- [x] numpy pin ← зроблено 2026-04-18
|
- [x] numpy pin ← зроблено 2026-04-18
|
||||||
|
- [x] Prototype CuVSLAMMonoDepthVisualOdometry class з dev/CI scaled ORB fallback ← зроблено 2026-04-18 (§5.1a)
|
||||||
|
- [x] GPS_INPUT field encoding tests ← зроблено 2026-04-18 (§5.1a)
|
||||||
- [ ] Перевірити FC processor (H743 vs F405) — спитати постачальника
|
- [ ] Перевірити FC processor (H743 vs F405) — спитати постачальника
|
||||||
- [ ] Перевірити поточний IMU rate через MAVLink (за замовчуванням ArduPilot шле 50 Hz, треба ≥100 Hz для Mono-Inertial; для Mono-Depth не критично)
|
- [ ] Перевірити поточний IMU rate через MAVLink (за замовчуванням ArduPilot шле 50 Hz, треба ≥100 Hz для Mono-Inertial; для Mono-Depth не критично)
|
||||||
- [ ] Prototype cuVSLAM Mono-Depth з барометром як synthetic depth (на EuRoC — IMU дає altitude, нема барометра, але можна подавати GT altitude як proxy)
|
|
||||||
- [ ] Прогнати [aero-vloc](https://github.com/prime-slam/aero-vloc) benchmark на VPAIR nadir кадрах до того як фіксувати Faiss index дизайн
|
- [ ] Прогнати [aero-vloc](https://github.com/prime-slam/aero-vloc) benchmark на VPAIR nadir кадрах до того як фіксувати Faiss index дизайн
|
||||||
|
|
||||||
**Тиждень 2:**
|
**Тиждень 2:**
|
||||||
- [ ] cuVSLAM Mono-Depth інтеграція в E2EHarness (новий `_ScaledVO` analog, але scale береться per-frame з GT altitude)
|
- [ ] Wire CuVSLAMMonoDepthVisualOdometry через E2EHarness (додати `vo_backend` параметр, прогнати Mono-Depth через pipeline замість хардкоду ORB)
|
||||||
- [ ] Порівняти ATE: ORB (поточний baseline 0.205 м на MH_01) vs cuVSLAM Mono-Depth
|
- [ ] Порівняти ATE: ORB (поточний baseline 0.2046 м на MH_01) vs CuVSLAMMonoDepthVisualOdometry через pipeline
|
||||||
- [ ] AnyLoc offline setup + перший тест на satellite tiles
|
- [ ] Колапс дуплікатного коду між `CuVSLAMVisualOdometry` (Inertial) і `CuVSLAMMonoDepthVisualOdometry` — видалити Inertial варіант
|
||||||
|
- [ ] AnyLoc offline setup + перший тест на реальних MapTiler tiles
|
||||||
|
|
||||||
**Тиждень 3:**
|
**Тиждень 3:**
|
||||||
- [ ] XFeat TRT export для satellite matching (окремий трек від VO — не VO fallback)
|
- [ ] XFeat TRT export для satellite matching (окремий трек від VO — не VO fallback)
|
||||||
- [ ] MAVLink GPS_INPUT injection тест на SITL
|
- [ ] MAVLink GPS_INPUT injection тест на SITL (docker-compose.sitl.yml)
|
||||||
- [ ] Визначити чи варто піднімати IMU rate для майбутнього Mono-Inertial
|
- [ ] Визначити чи варто піднімати IMU rate для майбутнього Mono-Inertial
|
||||||
|
|
||||||
### 5.4 Відкриті питання (research §7)
|
### 5.4 Відкриті питання (research §7)
|
||||||
|
|||||||
Reference in New Issue
Block a user