Commit Graph

129 Commits

Author SHA1 Message Date
Yuzviak 1bf8b2a684 docs: record EuRoC MH_01 real-run baseline across all doc surfaces
Updates README, testing/README, next_steps.md, and ADR 0001 with the
first real EuRoC MH_01 e2e run (100 frames, ~30s wall-time, ATE RMSE
~10.9 km → xfail). Places the EuRoC result alongside the prior VPAIR
baseline (~1770 km) so future-reader can see both failure modes at a
glance:

- VPAIR diverges because no raw IMU → ESKF never engages
- EuRoC diverges because indoor scene has no satellite anchor, so
  VO+ESKF drift without an external correction

Also records the branching policy (rename ``euroc_mh01`` →
``euroc_machine_hall``; empty URL due to DSpace UI gate; manual
fetch via DOI 10.3929/ethz-b-000690084).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 17:52:06 +03:00
Yuzviak b57187e1b8 test(e2e): rename registry entry to euroc_machine_hall with real SHA256
The prior registry entry was speculative: ``euroc_mh01`` pointing at an
old ``robotics.ethz.ch`` URL that no longer resolves (TCP timeout).
The dataset moved to ETH Research Collection (DOI 10.3929/ethz-b-000690084)
as a single 12.6 GB ``machine_hall.zip`` bundle containing MH_01…MH_05.
There's no stable direct download URL — DSpace gates behind a UI —
so:

- Renamed entry: ``euroc_mh01`` → ``euroc_machine_hall`` (matches the
  actual artifact).
- SHA256 set to the real bundle hash 5ed7d07…
- URL left empty (same pattern as ``vpair_sample``); the CLI now
  exits 3 and prints fetch instructions for empty-URL entries instead
  of crashing on ``urllib.request.urlretrieve("")``.
- Adapter ``DatasetNotAvailableError`` message and conftest skip-reason
  updated to tell engineers how to fetch/unpack manually.
- ``test_registry_has_euroc_machine_hall`` pin test replaces the old
  pin; asserts real hash (not the ``"0"*64`` placeholder).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 17:52:06 +03:00
Yuzviak f2f278bc09 test(e2e): run EuRoC MH_01 on first 100 frames; document real ATE baseline
First real e2e run on EuRoC MH_01 (indoor micro-MAV, ASL format from
machine_hall bundle, SHA256 5ed7d07…). 100-frame CI-tier completes in
~30s end-to-end. Pipeline emits GPS estimates (raw IMU present in
EuRoC so ESKF path is active), but ATE RMSE ≈ 10.9 km on an indoor
trajectory that physically spans ~20 m — satellite-anchoring path is
not yet wired for indoor data, so VO+ESKF drift dominates.

Test gates via xfail (same pattern as VPAIR) until VO/ESKF tuning is
done. Constant EUROC_MH01_MAX_FRAMES is explicit so the cap is
discoverable and easy to raise when full-sequence runs become
worthwhile.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 17:52:06 +03:00
Yuzviak fd54af2d9f feat(testing): add max_frames parameter to E2EHarness
Caps the iteration length (and the matching GT slice) when set, so CI
tiers can stay fast on multi-thousand-frame sequences like EuRoC MH_01
(3682 frames ≈ 3+ hours at 3-5s/frame). Also useful for eyeballing a
new adapter's first N frames before committing to a full run.

Three new harness tests cover truncation, explicit None, and over-large
limits. No change to existing adapters or downstream tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 17:52:06 +03:00
Yuzviak 5128ac17ba docs(solution): reference e2e harness + ADR 0001 from testing strategy
Adds an "E2E Test Harness (Public UAV Datasets)" subsection to
§Testing Strategy explaining the three-tier adapter layout and
pointing readers at testing/README.md for architecture and ADR 0001
for selection rationale. Updates Related Artifacts to list the new
in-repo docs. next_steps.md cross-links the ADR as the authoritative
decision record (brainstorm drafts stay local).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 13:55:29 +03:00
Yuzviak 560dc38f0a docs(adr): record ADR 0001 — e2e validation on public UAV datasets
First Architecture Decision Record for this project. Captures the
rationale for building the e2e harness on VPAIR / MARS-LVIG / EuRoC
rather than blocking on proprietary Mavic data collection; lists
three alternatives considered and why rejected; records the first
real-run baseline (VPAIR ATE ~1770 km) as a measurable starting
point for future VO+ESKF tuning regressions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 13:55:22 +03:00
Yuzviak be7eb338c1 docs(testing): add architecture guide for the e2e harness subpackage
Explains the DatasetAdapter contract (name/capabilities/iter_*),
capability-flag semantics (has_raw_imu, has_rtk_gt, platform_class),
the recipe for adding a new adapter (fabricated fixture → adapter →
conftest fixture → integration test → registry SHA256), and the
current state of each shipped adapter including the VPAIR ~1770 km
ATE real-run baseline. Lives next to the code so it stays in sync.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 13:55:17 +03:00
Yuzviak 97aa4d1cbe ci: trigger workflow on PRs to stage* branches too
The comment above `on:` says "push and PR to main/dev/stage*" but the
pull_request trigger only listed [main, dev]. Result: PRs into stage
branches got no automated lint/test run — we noticed when PR #1
(into stage1) showed "no checks reported".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:28:57 +03:00
Yuzviak f66b266219 style(e2e): ruff auto-fix import sorting in coord + vpair + tests
Four I001 violations surfaced when running ruff over the full src/
tests/ tree (the CI command) rather than just the testing subpath:
- src/gps_denied/testing/coord.py
- src/gps_denied/testing/datasets/vpair.py
- tests/e2e/test_coord.py
- tests/e2e/test_vpair_adapter.py

All auto-fixable; no behavioural change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:24:41 +03:00
Yuzviak 51ca357234 docs: expand next_steps.md with checklists and decision log
Converts the raw notes into a living roadmap:
- checklist items for each of the 4 top-level tasks
- [decision] annotations that record WHY we chose each path
  (public datasets vs proprietary capture; VPAIR first vs EuRoC;
  DJI Mavic deprioritised; EuRoC URL migration)
- current status of e2e harness (section 3) with real-run numbers
- chronology section so future-you can trace the timeline

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:24:41 +03:00
Yuzviak 03e617de63 docs(e2e): document VPAIR sample download + real-run status
Record first real e2e run on VPAIR sample (fixed-wing, 300-400 m
nadir): pipeline completes, ATE RMSE ~1770 km → xfail. VO without
IMU/satellite anchoring diverges on fixed-wing. Covered by xfail
branch; expected to flip to strict assert after VO+GPR tuning for
high-altitude nadir imagery.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:24:41 +03:00
Yuzviak d91dee8a63 test(e2e): register vpair_sample SHA256 in dataset registry
URL left empty because VPAIR sample is form-gated on Zenodo.
Registry records the known-good SHA256 for manual downloads; the
download_dataset() helper refuses empty URLs so this cannot be used
to auto-fetch a changed artifact.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:24:41 +03:00
Yuzviak bbc19c0b25 test(e2e): rewrite VPAIRAdapter for real sample format
Real VPAIR sample layout differs from the prior speculative adapter:
- poses_query.txt (not poses.csv) with ECEF xyz + Euler roll/pitch/yaw
- no native timestamps — synthesised at 5 Hz
- PNG images referenced by relative filepath
Adapter now uses coord helpers (ecef_to_wgs84, euler_to_quaternion).
Test fixture and conftest skip-reason updated to match.
Integration test xfail condition extended to cover large ATE values
when VO+GPR is not yet tuned for 300-400m nadir aerial imagery.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:24:41 +03:00
Yuzviak 8a577d4295 fix(e2e): correct test_coord Munich expectations to match ECEF inputs
Previous commit 56d2e98 asserted lat=48.1351/lon=11.5820/alt=520 for
ECEF (4177789.3, 855098.1, 4727807.9) — those numbers were a
copy-paste guess from an external converter, not consistent with the
stated ECEF input. Both Heikkinen closed-form and Bowring iterative
independently give lat≈48.1414°, lon≈11.5674°, alt≈570.75 m from that
input. Implementation was correct; test data was wrong.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:24:41 +03:00
Yuzviak 13d156eaac test(e2e): add ECEF→WGS84 and Euler→quaternion helpers
Closed-form Heikkinen method for ECEF conversion (centimetre accuracy,
no iteration). ZYX aerospace-convention Euler → quaternion. Both needed
by upcoming VPAIRAdapter rewrite; reusable for other datasets shipping
ECEF or Euler poses (e.g. some MARS-LVIG releases).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:24:41 +03:00
Yuzviak 0062323d0a docs(e2e): point README at dataset setup and test tiers
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 22:03:14 +03:00
Yuzviak 1b069e2bb3 style(e2e): ruff auto-fix imports and remove unused imports in e2e suite
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 22:02:29 +03:00
Yuzviak 9173e8d386 test(e2e): wire MARS-LVIG stress tier with completion-rate gate
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 22:00:38 +03:00
Yuzviak d42e6e546c test(e2e): add MARSLVIGAdapter (rotary, RTK, raw IMU)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:59:34 +03:00
Yuzviak 58192f5d73 test(e2e): wire VPAIR nominal tier; pose-only harness path
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:57:52 +03:00
Yuzviak 4822ddd30f test(e2e): add VPAIRAdapter (pose-only; fixed-wing capability)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:56:40 +03:00
Yuzviak 65e18e8c59 test(e2e): wire EuRoC CI-tier test with skip-when-absent fixture
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:54:57 +03:00
Yuzviak c26aa3bcaf test(e2e): add EuRoCAdapter with local fabricated fixture tests
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:53:17 +03:00
Yuzviak 669d8e5653 test(e2e): add SHA256-verified dataset downloader + EuRoC registry entry
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:51:06 +03:00
Yuzviak 95accb8f7a test(e2e): implement harness skeleton + synthetic smoke test + pytest markers
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:48:41 +03:00
Yuzviak 568939cd35 test(e2e): add trajectory RMSE/ATE/RPE metrics
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:45:28 +03:00
Yuzviak 337176eb70 test(e2e): add SyntheticAdapter for harness self-tests
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:43:50 +03:00
Yuzviak 2f87621926 test(e2e): add DatasetAdapter base interface + capability dataclass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:41:58 +03:00
Yuzviak a2620aee6c test(e2e): scaffold testing subpackage and tests/e2e/
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:40:25 +03:00
Yuzviak 6ff14a1a7d chore: import .claude command skills, CLAUDE.md, .gitignore, next_steps.md
- Vendor local .claude/ command skills (autopilot, plan, implement, etc.)
- Add CLAUDE.md pointing slash commands to .claude/commands/*/SKILL.md
- Untrack docs-Lokal/ and ignore .planning/ for local-only planning docs
- Include next_steps.md pulled from upstream

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:39:43 +03:00
Oleksandr Bezdieniezhnykh f7c8154a6f short audit 2026-04-10 03:54:12 +03:00
Yuzviak 78dcf7b4e7 fix: post-audit — runtime bugs, functional gaps, docs, hardening
Phase A — Runtime bugs:
  - SSE: add push_event() method to SSEEventStreamer (was missing, masked by mocks)
  - MAVLink: satellites_visible=10 (was 0, triggers ArduPilot failsafe)
  - MAVLink: horiz_accuracy=sqrt(P[0,0]+P[1,1]) per spec (was sqrt(avg))
  - MAVLink: MEDIUM confidence → fix_type=3 per solution.md (was 2)

Phase B — Functional gaps:
  - handle_user_fix() injects operator GPS into ESKF with noise=500m
  - app.py uses create_vo_backend() factory (was hardcoded SequentialVO)
  - ESKF: Mahalanobis gating on satellite updates (rejects outliers >5σ)
  - ESKF: public accessors (position, quaternion, covariance, last_timestamp)
  - Processor: no more private ESKF field access

Phase C — Documentation:
  - README: correct API endpoints, CLI command, 40+ env vars documented
  - Dockerfile: ENV prefixes match pydantic-settings (DB_, SATELLITE_, MAVLINK_)
  - tech_stack.md marked ARCHIVED (contradicts solution.md)

Phase D — Hardening:
  - JWT auth middleware (AUTH_ENABLED=false default, verify_token on /flights)
  - TLS config env vars (AUTH_SSL_CERTFILE, AUTH_SSL_KEYFILE)
  - SHA-256 tile manifest verification in SatelliteDataManager
  - AuthConfig, ESKFSettings, MAVLinkConfig, SatelliteConfig in config.py

Also: conftest.py shared fixtures, download_tiles.py, convert_to_trt.py scripts,
config wiring into app.py lifespan, config-driven ESKF, calculate_precise_angle fix.

Tests: 196 passed / 8 skipped. Ruff clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 18:27:35 +03:00
Yuzviak d0009f012b fix(ci): remove --timeout flag (pytest-timeout not in dev deps)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 17:11:31 +03:00
Yuzviak dd9835c0cd fix(lint): resolve all ruff errors — trailing whitespace, E501, F401
- ruff --fix: removed trailing whitespace (W293), sorted imports (I001)
- Manual: broke long lines (E501) in eskf, rotation, vo, gpr, metric, pipeline, rotation tests
- Removed unused imports (F401) in models.py, schemas/__init__.py
- pyproject.toml: line-length 100→120, E501 ignore for abstract interfaces

ruff check: 0 errors. pytest: 195 passed / 8 skipped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 17:09:47 +03:00
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
Yuzviak a15bef5c01 docs(phase-01): complete Phase 1 — ESKF Core execution
Phase 1 status: Complete (3/3 plans, 35/35 tests)
- ESKF-01: 15-state IMU prediction ✓
- ESKF-02: VO measurement update ✓
- ESKF-03: Satellite measurement update ✓
- ESKF-04: GPS initialization ✓
- ESKF-05: Confidence tier computation ✓
- ESKF-06: Coordinate chain (pixel→GPS→pixel) ✓

Next: Phase 2 — Visual Odometry Pipeline

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:53:47 +03:00
Yuzviak ba00065e1d docs(phase-01): add test summary for plan 01-03
35 tests pass covering ESKF-01..06 (initialization, IMU prediction,
VO/satellite updates, confidence tiers, coordinate chain).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:53:18 +03:00
Yuzviak 2e5436a6c7 feat(tests): add comprehensive ESKF + coordinate chain tests (ESKF-01..06)
test_eskf.py: 18 tests covering initialization, IMU prediction, VO/satellite
updates, confidence tiers, and full fusion integration.
test_coordinates.py: 17 new tests for K matrix, ray-ground intersection,
pixel-GPS roundtrips, and cv2.perspectiveTransform homography.

All 35 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:52:58 +03:00
Yuzviak dccadd4bf4 feat(coordinates): implement real pixel-to-GPS projection chain (ESKF-06)
Replace FAKE Math stubs with:
- K^-1 unprojection (camera intrinsics)
- R_cam_body rotation (nadir-pointing camera)
- Quaternion body-to-ENU rotation
- Ray-ground intersection at altitude
- cv2.perspectiveTransform for homography

gps_to_pixel is the exact inverse. Backward compatible defaults.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:48:22 +03:00
Yuzviak 9d5337ad72 feat(eskf): implement 15-state ESKF core algorithm (ESKF-01..05)
IMU prediction (F/Q matrices, bias propagation), VO measurement
update, satellite measurement update, GPS initialization, and
confidence tier computation. NumPy only, ENU convention.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:38:47 +03:00
Yuzviak 57c7a6b80a feat(eskf): add ESKF schema contracts (ESKF-01, ESKF-04, ESKF-05)
ConfidenceTier, IMUMeasurement, ESKFConfig, ESKFState Pydantic models.
Re-exported from schemas/__init__.py.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:37:14 +03:00
Yuzviak bf9bef19c8 docs(01-eskf-core): create phase plan — 3 plans in 2 waves 2026-04-01 22:11:57 +03:00
Yuzviak d2b431f17f docs: add project STATE.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 20:53:01 +03:00
Yuzviak 659050f20b docs: add requirements and roadmap
36 v1 requirements across 6 categories (ESKF, VO, SAT, GPR, MAV, PIPE, TEST).
7-phase roadmap ordered by dependency: ESKF → VO → Satellite → MAVLink → Pipeline → SITL → Validation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 20:52:42 +03:00
Yuzviak 06f9ccd28f chore: add project config 2026-04-01 20:48:56 +03:00
Yuzviak b3d2f8e5a2 docs: initialize project 2026-04-01 20:48:56 +03:00
Yuzviak 2dd60a0e37 Add codebase map to .planning/codebase/
7 structured documents covering stack, integrations, architecture,
structure, conventions, testing, and concerns.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 20:26:52 +03:00
Yuzviak 91047c5f19 Merge branch 'dev' into stage1 2026-04-01 20:14:22 +03:00
Oleksandr Bezdieniezhnykh 531a1301d5 Revise skills documentation to incorporate updated directory structure and terminology. Replace references to integration tests with blackbox tests in SKILL.md files and templates. Adjust paths in planning and deployment documentation to align with the new _docs/02_document/ structure, ensuring consistency and clarity throughout the documentation. 2026-03-25 06:35:41 +02:00
Oleksandr Bezdieniezhnykh 1c6e8f47b1 Update skills documentation to reflect changes in directory structure and terminology. Replace references to integration tests with blackbox tests across various SKILL.md files and templates. Revise paths in planning and deployment documentation to align with the updated _docs/02_document/ structure. Enhance clarity in task management processes and ensure consistency in terminology throughout the documentation. 2026-03-25 06:08:05 +02:00