Files
gps-denied-onboard/next_steps.md
T
Yuzviak 1618190105 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>
2026-04-18 16:37:50 +03:00

207 lines
26 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.
# Next Steps — дорожня карта
Живий документ. Галочки заповнюються у міру виконання. Коментарі в квадратних дужках `[decision: …]` фіксують рішення, щоб через місяць можна було зрозуміти *чому* ми зробили саме так.
---
## 1. Аудит відповідності солюшну
Весь девелопмент зроблений не з цільового `_docs/01_solution/solution.md`, а з сукупності документів у `_docs/01_solution/`. Треба звірити імплементацію саме з цільовим солюшном.
- [ ] Порівняти поточну імплементацію з `_docs/01_solution/solution.md` (не з усією текою)
- [ ] **VO треба зробити на cuVSLAM** (якщо не буде явних перепон)
- Rationale: SP+LG (SuperPoint+LightGlue) rejection: 1533× повільніше за cuVSLAM. Немає built-in IMU fusion, loop closure, tracking-failure detection. Побудова цих фіч навколо SP+LG — значний час, і все одно повільніше. XFeat (~30–50 мс) — кращий fallback для VO якщо cuVSLAM не зайде на nadir-камеру.
- [ ] Прогнати cuVSLAM через e2e-харнес (див. пункт 3) — перевірити що VO+ESKF разом дають адекватну точність на EuRoC/VPAIR
- [ ] Якщо cuVSLAM підходить → видалити SP+LG з кодбейса. Залишити XFeat як fallback
**Цей крок треба робити ПІД захистом e2e-харнеса**, не до нього, щоб відразу бачити регресії (див. пункт 3).
---
## 2. Реструктуризація коду
Весь код у `src/gps_denied/`, але весь проект і так про gps_denied — зайвий рівень неймспейсу.
- [ ] `git mv src/gps_denied/* src/` (або через rename imports, що чистіше)
- [ ] Оновити імпорти у всіх файлах (`from gps_denied.X``from X` чи залишити як неймспейс, вирішити)
- [ ] Оновити `pyproject.toml`: `[tool.setuptools.packages.find]`
- [ ] Прогнати повну test suite — має бути зелено
- [ ] Оновити CI скрипти, Docker, docs
**Робити під захистом e2e-харнеса** — одна велика рефакторинг-зміна з багатьма PR → легко поламати щось непомітно. Зелений e2e (на тих самих числах що до рефакторингу) — sign-off.
---
## 3. Autopilot existing-code flow — e2e-харнес
Всі проекти в azaion приводяться до механізму девелопменту з `.cursor/skills/autopilot` (`flows/existing-code` для існуючого коду, `flows/greenfield` для нового).
Коротко алгоритм: питаємо вимоги до e2e-тестів і даних → рефакторимо для можливості e2e-покриття → пишемо e2e-підсистему що запускає продукт як black-box → переконуємось що працює → **тоді** ітеративно рефакторимо під захистом e2e.
### Статус виконання
**Design** (локально, gitignored): `.planning/brainstorms/2026-04-16-e2e-datasets-design.md`
**Plan** (локально, gitignored): `.planning/brainstorms/2026-04-16-e2e-datasets-plan.md`
**In-repo docs**: [src/gps_denied/testing/README.md](src/gps_denied/testing/README.md) (harness architecture), [_docs/01_solution/decisions/0001-e2e-dataset-strategy.md](_docs/01_solution/decisions/0001-e2e-dataset-strategy.md) (ADR — selection rationale)
[decision 2026-04-16: замість збору власних даних з Mavic-а — використати публічні UAV датасети. Причина: блокер на проприєтарні дані (Денис, мавікісти), а нам треба рухатись вже зараз. Public датасети: VPAIR (fixed-wing, downward, 300400 м) + EuRoC (indoor MAV, IMU+GT, індустрійний benchmark) + MARS-LVIG (rotary, featureless сіквенси як stress-test). Деталі — у ADR 0001.]
- [x] Побудувати `DatasetAdapter` ABC + capability flags (has_raw_imu, has_rtk_gt, platform_class) — `src/gps_denied/testing/datasets/base.py`
- [x] `SyntheticAdapter` для harness self-test (`synthetic.py`)
- [x] Trajectory метрики — RMSE, ATE, RPE (`metrics.py`)
- [x] `E2EHarness` — жене адаптер через `FlightProcessor`, збирає estimated positions, порівнює з GT (`harness.py`)
- [x] SHA256-verified dataset downloader + registry (`download.py`, `scripts/download_dataset.py`)
- [x] `EuRoCAdapter` + unit-тести з fabricated fixture
- [x] `VPAIRAdapter` + unit-тести з fabricated fixture (**реальний формат**: poses_query.txt, ECEF xyz, Euler rad)
- [x] `MARSLVIGAdapter` + unit-тести (очікує pre-extracted layout з ROS bag)
- [x] `coord.py` helpers: ECEF→WGS84 (Heikkinen closed-form), Euler→quaternion (ZYX aerospace)
- [x] Integration тести з skip-when-absent fixtures (EuRoC, VPAIR, MARS-LVIG)
- [x] Pytest markers `e2e`, `e2e_slow`, `needs_dataset` у pyproject.toml
- [x] **Перший реальний e2e-прогін на VPAIR sample** (200 кадрів fixed-wing, 300-400 м над Bonn/Eifel)
- Результат: пайплайн завершується без падінь, **ATE RMSE ~1 770 км** → xfail
- [decision 2026-04-16: це очікувано. VO сам по собі без IMU і без supплементарного supплутникового anchoring розходиться. VPAIR не має raw IMU → ESKF-шлях не активується. Xfail-branch документує цю deгадацію; перейде у strict-assert коли VO+GPR будуть тюновані для high-altitude nadir + знайдемо датасет з raw IMU.]
- [x] **Перший реальний e2e-прогін на EuRoC MH_01** (перші 100 кадрів indoor MAV, ASL формат)
- Результат: пайплайн завершується за ~30 с, **ATE RMSE ~10 871 м** → xfail за ceiling 5 м
- [decision 2026-04-17: замість старого `robotics.ethz.ch` URL (TCP timeout) — новий ETH Research Collection DOI `10.3929/ethz-b-000690084`. Окремого `MH_01_easy.zip` там немає, лише 12.6 GB bundle з усіма 5 MH-сіквенсами. Витягнули тільки `MH_01_easy.zip` у `/home/yuzviak/Azaion/Data/machine_hall/MH_01/`, symlink з `datasets/euroc/MH_01/`. Registry entry перейменована на `euroc_machine_hall` (bundle-level SHA256).]
- [decision 2026-04-17: harness отримав параметр `max_frames` — CI-tier гонить 100 кадрів за ~30 с. Повна sequence (3682) — ~3 години, не CI-tier.]
- Pipeline diff vs VPAIR: raw IMU є → ESKF активний; але satellite-anchoring для indoor-сцени не релевантний, VO+ESKF без якоря дрейфує на кілометри.
- [ ] Замінити xfail на strict-assert у VPAIR і EuRoC тестах (коли VO+GPR+ESKF-anchoring почнуть давати притомні числа)
- [ ] **IMU з SITL для початку** — ArduPilot SITL може літати mission з waypoints, генерувати 200 Hz IMU через MAVLink. Для піднять пайплайну цього достатньо. Реальний IMU треба так чи інакше, але це паралельна гілка роботи.
### Патерн гілок для e2e-роботи
- `feat/e2e-vpair`**merged** у stage1 через PR #1 (2026-04-16, rebase)
- `feat/e2e-euroc` — поточна робота (2026-04-17): harness `max_frames`, перший реальний прогін EuRoC MH_01, реєстр перейменовано на `euroc_machine_hall`
- Інтеграція у stage1 через послідовні PR-и. Політика: наступні merge без `--delete-branch` (гілки лишаються на GitHub)
---
## 4. Збір реальних UAV-даних
[decision 2026-04-16: **деприйорити** цей пункт на користь пункту 3 (публічні датасети). Причина: публічні датасети вже є, дають реальний fixed-wing сценарій, не вимагають координації людей. Повернемось до цього коли:
- (а) потрібно буде валідувати на *нашому* конкретному дроні (intrinsics, спектр вібрації IMU, camera model відрізняються від VPAIR/EuRoC);
- (б) готовий буде VO+ESKF-тюнінг і захочеться "фінальний" датасет саме під envelope tactical fixed-wing 200-1500 м.]
- [ ] Денис Попов — логи Mavic (камера вниз, висока висота). *Призупинено.*
- [ ] Штатні мавікісти — пара тестових вильотів з nadir-камерою. *Призупинено, потребує переконати.*
- [ ] DJI Mavic флайт у `/home/yuzviak/Azaion/Data/` (MP4 + SRT + Airdata CSV)
- [decision 2026-04-16: НЕ інтегруємо зараз. Причини: (1) DJI не публікує raw IMU, є лише attitude/speeds (результат фʼюжену) — ESKF-шлях не активується; (2) потрібні camera intrinsics конкретної моделі; (3) sync SRT@30Hz + CSV@5Hz потребує окремого alignment-кроку. Залишаємо як qualitative demo пізніше, коли інфраструктура стабілізується.]
---
## Хронологія рішень
- **2026-04-16 ранок**: Аудит інфраструктури, pull upstream, вирішили взяти публічні датасети замість чекати на Дениса. Brainstorm + spec + plan: VPAIR (Tier 1), MARS-LVIG (Tier 2), EuRoC (Tier 3 CI).
- **2026-04-16 день**: Реалізовано e2e-харнес з `DatasetAdapter` pattern. 12 комітів у stage1 (`a2620ae``0062323`), пушнуто. 233 passed, 13 skipped.
- **2026-04-16 вечір**: Спробували скачати EuRoC MH_01 — старий URL лежить, знайшли новий DOI (12 GB bundle, завтра). Переключились на VPAIR (вже скачаний). Реальний формат відрізняється від припущеного: ECEF+Euler+no timestamps. Написали `coord.py` (ECEF→WGS84 Heikkinen + Euler→quat), переписали `VPAIRAdapter`. Гілка `feat/e2e-vpair`, 5 комітів. Перший реальний прогін: ATE ~1770 км (очікувано, задокументовано в xfail).
- **2026-04-17**: Завантажили 12.6 GB `machine_hall.zip`, витягли `MH_01` (2.6 GB). Додали `max_frames` у `E2EHarness` (TDD, 3 нових тести). Перший реальний прогін EuRoC MH_01 на 100 кадрах: пайплайн завершується за ~30 с, **ATE RMSE ~10.87 км → xfail**. Registry entry перейменовано `euroc_mh01``euroc_machine_hall` з реальним SHA256 `5ed7d07…`; URL порожній (ETH Research Collection не дає direct link, ручне завантаження). Гілка `feat/e2e-euroc`.
- **2026-04-18**: Три PR підряд у stage1:
- **PR #4** `feat/e2e-trace` — додали per-frame JSONL трасування в `E2EHarness` (`trace_path` параметр). Запустили EuRoC MH_01 з трасуванням: виявлено `vo_success=0/100`, `eskf_initialized=0/100`, `alignment_success=77/100`. Всі оцінки — fallback satellite matching без ESKF/VO.
- **PR #5** `feat/e2e-vo-only` — ORB VO-only діагностика. Запустили `ORBVisualOdometry` напряму на EuRoC кадрах: **99/99 tracking rate (100%)**. Висновок: проблема була не в VO-алгоритмі, а в тому що `SequentialVisualOdometry` (Mock random keypoints → RANSAC failure) використовувалась у харнесі.
- **PR #6** `feat/e2e-harness-orb-vo` — замінили VO-бекенд у `_build_processor` з `SequentialVisualOdometry(ModelManager())` на `ORBVisualOdometry()`. Новий результат: `vo_success=99/100`. Залишилась проблема: `eskf_initialized=0/100` — ESKF потребує `init_flight()` зі start_gps, харнес цього не робить.
- [decision 2026-04-18: VO-бекенд у харнесі має бути `ORBVisualOdometry` (реальні OpenCV фічі), а не Mock SP+LG (random keypoints). Для Jetson-production cuVSLAM залишається метою — але харнес валідує pipeline логіку незалежно від бекенду.]
- **Наступний крок**: ініціалізувати ESKF у харнесі з синтетичним GPS-origin (середня координата GT або перша GT-поза). Це увімкне ESKF-шлях і дасть змогу виміряти реальний VO+ESKF дрейф без satellite fallback.
- **PR #8** `feat/e2e-eskf-init` — ESKF ініціалізується з першої GT-пози адаптера. Результат: `eskf_initialized: 0→100/100`, `eskf_has_position: 100/100`. ATE RMSE ~10.7 км. Satellite measurements відхиляються Mahalanobis gate (Δ²~10⁶ >> 16.3). Root cause: ORB `scale_ambiguous=True` → unit-scale VO translations → ESKF position diverges → satellite outlier gate срацює коректно.
- **Наступний крок**: VO metric scale. ORB переводить `(R, t̂)` де `t̂` — одиничний вектор, реальна відстань невідома. Варіанти: (а) передавати IMU timestamps у ESKF щоб він сам рахував scale через velocity; (б) перейти на cuVSLAM (metric backend); (в) хак — фіксований scale для EuRoC indoor (~0.3 м між кадрами). Правильний шлях — (б) cuVSLAM, але для CI-діагностики можна (в).
- **PR #9** `feat/e2e-vo-scale` — реалізовано варіант (а): `vo_scale_m=0.005` (5 мм/кадр, виміряно з GT median). `_ScaledVO` wrapper нормалізує unit-vector ORB translation і множить на scale. `HarnessResult` тепер збирає `eskf_positions_enu`. **Перший strict-assert тест на реальних даних**: `test_euroc_mh01_eskf_drift_within_ceiling` PASS — ESKF ATE RMSE **~0.20 м** за 100 кадрів (ceiling 0.5 м).
- [decision 2026-04-18: фіксований scale 0.005 м/кадр — це діагностичний хак для CI. Правильне рішення — cuVSLAM (metric VO). Але цей тест тепер є regression guard: якщо рефакторинг VO/ESKF ламає інтеграцію — тест покаже.]
- **Поточний стан pipeline на EuRoC MH_01**: `vo_success=99/100`, `eskf_initialized=100/100`, ESKF ATE=0.20 м ✓. GPS estimate ATE xfail (satellite не туновано під indoor).
- **Наступні кроки**: (1) MH_02-05 параметризовані тести — перевірити чи 0.20 м baseline стабільний на інших sequences; (2) VPAIR — там satellite matching може бути актуальним (outdoor, є reference_views/); (3) cuVSLAM як VO backend.
- **PR #10** `feat/e2e-mh-multi` — витягли MH_02-05 з bundle, написали 10 параметризованих тестів (pipeline_completes + eskf_drift для всіх 5 sequences). Всі 10 PASS. ESKF ATE baseline:
| Sequence | Difficulty | ESKF ATE RMSE |
|---|---|---|
| MH_01 | easy | 0.205 m |
| MH_02 | easy | 0.131 m |
| MH_03 | medium | 0.008 m |
| MH_04 | difficult | 0.009 m |
| MH_05 | difficult | 0.007 m |
MH_03-05 мають дуже малий дрейф (~1 см) бо перші 100 кадрів MAV майже нерухомий (старт sequence). Це нормально — цей baseline зростатиме якщо запустити більше кадрів.
**Поточний стан e2e харнесу**: 70 passed, 1 skipped, 2 xfailed. Всі EuRoC MH sequences покриті strict-assert тестами.
---
## 5. Tech audit — Open-Source Stack alignment
Research документ `docs/superpowers/specs/2026-04-18-oss-stack-tech-audit-design.md` (2026-04-18) переглянув увесь OSS-стек і знайшов кілька критичних розходжень з поточною архітектурою. Нижче — стан синхронізації з research.
### 5.1 Виконано (2026-04-18 вечір)
- [x] **Numpy pin `>=1.26,<2.0`**. NumPy 2.0 silently breaks GTSAM Python bindings (research 4.3, issue #2264).
- Також довелось обмежити `opencv-python-headless<4.11` — 4.11+ вимагає numpy≥2. Knock-on constraint.
- Після downgrade: unit 196 passed / 8 skipped, e2e EuRoC MH_01 PASS (без регресії).
- [x] **VPAIR контрольний прогін на 50 кадрах з `vo_scale_m=1.0` і `vo_scale_m=45.0`** (GT inter-frame displacement median=45 м — fixed-wing на 400 м, швидкість ~225 м/с × 0.2 с між synthetic timestamps).
- Результат не залежить від 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).]
### 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 Відкореговано в плані (наступні дії)
**cuVSLAM стратегія** (research §1, §2):
- ❌ Раніше писали просто «cuVSLAM як VO backend».
- ✅ Тепер: **cuVSLAM Mono-Depth** (Mono + synthetic depth з барометра: `scale = altitude / focal_length`). Mono-Inertial потребує stereo hardware (у нас одна nadir-камера).
- Це пояснює чому VPAIR без IMU показує 1236 м ESKF ATE — без altitude-to-scale recovery VO drift unbounded. На EuRoC `vo_scale_m=0.005` працював тільки бо indoor scene має constant ~5 мм/кадр.
**Place Recognition** (research §3):
- Раніше: «GlobalPlaceRecognition (numpy/Faiss)» — backend не уточнений.
- Тепер: **DINOv2-VLAD (AnyLoc)** як descriptor → Faiss GPU index. EigenPlaces як upgrade path.
- **INT8 квантизація ❌** — broken для ViT на Jetson (NVIDIA/TRT#4348). Stay at FP16.
**GTSAM**:
- Research радить «GTSAM 4.2 stable» замість 4.3a1 alpha.
- **Практично неможливо**: PyPI має тільки `gtsam==4.3a0`. 4.2 потребує custom source build. Залишаємо `gtsam>=4.3a0` до появи stable wheel **АБО** source-build мануал.
- GTSAM-шлях відкладено для sprint 1 (research §3 Factor Graph): ESKF достатній для Gaussian GPS_INPUT 5-10 Hz. Mock залишається.
**MAVLink** (research §3):
- pymavlink ✅ (MAVSDK-Python не підтримує GPS_INPUT).
- **Reference impl**: `MAVProxy/modules/mavproxy_GPSInput.py` — точне кодування `GPS_INPUT` (#232). Звірити коли будемо інтегрувати з SITL.
- **Injection rate**: 5-10 Hz, не 20+ (timing jitter).
**Flight Controller hardware** (research §4.1) — відкрите питання:
- H743 ✅ GPS_INPUT over serial
- F405 ❌ silently ignores GPS_INPUT (втрата днів на дебаг)
- [ ] Запитати постачальника / перевірити через Mission Planner before any SITL-to-hardware crossover.
### 5.3 Пріоритети на 2-3 тижні (синхронізовано з research §5)
**Тиждень 1 (починається 2026-04-19):**
- [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) — спитати постачальника
- [ ] Перевірити поточний IMU rate через MAVLink (за замовчуванням ArduPilot шле 50 Hz, треба ≥100 Hz для Mono-Inertial; для Mono-Depth не критично)
- [ ] Прогнати [aero-vloc](https://github.com/prime-slam/aero-vloc) benchmark на VPAIR nadir кадрах до того як фіксувати Faiss index дизайн
**Тиждень 2:**
- [ ] Wire CuVSLAMMonoDepthVisualOdometry через E2EHarness (додати `vo_backend` параметр, прогнати Mono-Depth через pipeline замість хардкоду ORB)
- [ ] Порівняти ATE: ORB (поточний baseline 0.2046 м на MH_01) vs CuVSLAMMonoDepthVisualOdometry через pipeline
- [ ] Колапс дуплікатного коду між `CuVSLAMVisualOdometry` (Inertial) і `CuVSLAMMonoDepthVisualOdometry` — видалити Inertial варіант
- [ ] AnyLoc offline setup + перший тест на реальних MapTiler tiles
**Тиждень 3:**
- [ ] XFeat TRT export для satellite matching (окремий трек від VO — не VO fallback)
- [ ] MAVLink GPS_INPUT injection тест на SITL (docker-compose.sitl.yml)
- [ ] Визначити чи варто піднімати IMU rate для майбутнього Mono-Inertial
### 5.4 Відкриті питання (research §7)
1. Якість cuVSLAM Mono-Depth на feature-poor nadir terrain (рівне поле, ліс).
2. Частота та надійність GPR match в реальних умовах України.
3. Чи достатньо барометра для scale recovery при різких змінах висоти.
4. Коли (чи взагалі) потрібен перехід на Stereo-Inertial (hardware change).