From 8382cdae10e9d0a8918de3120b0a7a35cbd7c355 Mon Sep 17 00:00:00 2001 From: Oleksandr Bezdieniezhnykh Date: Thu, 7 May 2026 04:08:03 +0300 Subject: [PATCH] start over again --- .dockerignore | 27 - .env.example | 10 - .gitattributes | 1 - .github/pull_request_template.md | 15 - .github/workflows/ci.yml | 43 -- .gitignore | 42 -- README.md | 22 - _docs/00_research/00_ac_assessment.md | 54 -- .../00_research/00_question_decomposition.md | 145 ---- _docs/00_research/01_source_registry.md | 419 ------------ _docs/00_research/02_fact_cards.md | 348 ---------- _docs/00_research/03_comparison_framework.md | 55 -- _docs/00_research/04_reasoning_chain.md | 181 ----- _docs/00_research/05_validation_log.md | 51 -- _docs/00_research/06_component_fit_matrix.md | 107 --- .../00_question_decomposition.md | 91 --- .../01_source_registry.md | 212 ------ .../02_fact_cards.md | 142 ---- .../03_comparison_framework.md | 31 - .../04_reasoning_chain.md | 192 ------ .../05_validation_log.md | 100 --- .../gps_denied_nav/00_ac_assessment.md | 74 --- .../00_question_decomposition.md | 88 --- .../gps_denied_nav/01_source_registry.md | 151 ----- .../gps_denied_nav/02_fact_cards.md | 121 ---- .../gps_denied_nav/03_comparison_framework.md | 71 -- .../gps_denied_nav/04_reasoning_chain.md | 129 ---- .../gps_denied_nav/05_validation_log.md | 98 --- .../00_question_decomposition.md | 80 --- .../01_source_registry.md | 201 ------ .../02_fact_cards.md | 161 ----- .../03_comparison_framework.md | 79 --- .../04_reasoning_chain.md | 145 ---- .../05_validation_log.md | 93 --- .../00_question_decomposition.md | 56 -- .../gps_denied_nav_v2/01_source_registry.md | 121 ---- .../gps_denied_nav_v2/02_fact_cards.md | 122 ---- .../03_comparison_framework.md | 45 -- .../gps_denied_nav_v2/04_reasoning_chain.md | 90 --- .../gps_denied_nav_v2/05_validation_log.md | 52 -- .../00_question_decomposition.md | 102 --- .../gps_denied_nav_v3/01_source_registry.md | 175 ----- .../gps_denied_nav_v3/02_fact_cards.md | 105 --- .../03_comparison_framework.md | 62 -- .../gps_denied_nav_v3/04_reasoning_chain.md | 202 ------ .../gps_denied_nav_v3/05_validation_log.md | 88 --- .../gps_denied_visual_nav/00_ac_assessment.md | 76 --- .../00_question_decomposition.md | 63 -- .../01_source_registry.md | 133 ---- .../gps_denied_visual_nav/02_fact_cards.md | 121 ---- .../03_comparison_framework.md | 115 ---- .../04_reasoning_chain.md | 146 ---- .../05_validation_log.md | 57 -- .../00_question_decomposition.md | 73 -- .../01_source_registry.md | 166 ----- .../02_fact_cards.md | 169 ----- .../03_comparison_framework.md | 63 -- .../04_reasoning_chain.md | 166 ----- .../05_validation_log.md | 96 --- .../00_question_decomposition.md | 57 -- .../01_source_registry.md | 231 ------- .../trt_engine_migration/02_fact_cards.md | 193 ------ .../03_comparison_framework.md | 38 -- .../04_reasoning_chain.md | 124 ---- .../trt_engine_migration/05_validation_log.md | 65 -- _docs/01_solution/security_analysis.md | 346 ---------- _docs/01_solution/solution.md | 130 ---- _docs/01_solution/solution_draft01.md | 149 ----- _docs/01_solution/solution_draft02.md | 125 ---- _docs/01_solution/solution_draft03.md | 491 -------------- _docs/01_solution/solution_draft04.md | 385 ----------- _docs/01_solution/solution_draft05.md | 562 ---------------- _docs/01_solution/solution_draft06.md | 622 ----------------- _docs/01_solution/tech_stack.md | 59 -- _docs/02_document/FINAL_report.md | 148 ----- _docs/02_document/architecture.md | 242 ------- .../common-helpers/01_helper_geo_geometry.md | 30 - .../common-helpers/02_helper_time_sync.md | 29 - .../description.md | 115 ---- .../01_camera_ingest_calibration/tests.md | 139 ---- .../components/02_vio_adapter/description.md | 105 --- .../components/02_vio_adapter/tests.md | 141 ---- .../03_safety_anchor_wrapper/description.md | 106 --- .../03_safety_anchor_wrapper/tests.md | 208 ------ .../04_satellite_retrieval/description.md | 102 --- .../04_satellite_retrieval/tests.md | 172 ----- .../05_anchor_verification/description.md | 93 --- .../05_anchor_verification/tests.md | 124 ---- .../06_cache_tile_lifecycle/description.md | 92 --- .../06_cache_tile_lifecycle/tests.md | 167 ----- .../07_mavlink_gcs_integration/description.md | 69 -- .../07_mavlink_gcs_integration/tests.md | 176 ----- .../08_fdr_observability/description.md | 79 --- .../components/08_fdr_observability/tests.md | 166 ----- .../shared/config_errors_telemetry.md | 53 -- .../contracts/shared/geometry_time_sync.md | 52 -- .../contracts/shared/runtime_contracts.md | 57 -- _docs/02_document/data_model.md | 148 ----- _docs/02_document/deployment/README.md | 11 - .../02_document/deployment/ci_cd_pipeline.md | 54 -- .../deployment/containerization.md | 46 -- .../deployment/deployment_procedures.md | 68 -- .../deployment/environment_strategy.md | 49 -- _docs/02_document/deployment/observability.md | 61 -- .../diagrams/component_overview.md | 46 -- .../flows/flow_cache_tile_lifecycle.md | 18 - .../flows/flow_normal_localization.md | 21 - .../flows/flow_satellite_relocalization.md | 21 - _docs/02_document/epics.md | 136 ---- _docs/02_document/glossary.md | 96 --- _docs/02_document/module-layout.md | 247 ------- _docs/02_document/ripple_log_cycle1.md | 21 - _docs/02_document/risk_mitigations.md | 275 -------- _docs/02_document/system-flows.md | 321 --------- _docs/02_document/tests/blackbox-tests.md | 176 ----- _docs/02_document/tests/e2e-test-suite.md | 81 --- _docs/02_document/tests/environment.md | 130 ---- _docs/02_document/tests/performance-tests.md | 117 ---- _docs/02_document/tests/resilience-tests.md | 107 --- .../02_document/tests/resource-limit-tests.md | 100 --- _docs/02_document/tests/security-tests.md | 77 --- _docs/02_document/tests/test-data.md | 100 --- .../02_document/tests/traceability-matrix.md | 116 ---- _docs/02_tasks/_dependencies_table.md | 51 -- .../02_tasks/done/AZ-219_initial_structure.md | 289 -------- .../done/AZ-220_shared_runtime_contracts.md | 78 --- .../done/AZ-221_shared_geometry_time_sync.md | 78 --- .../AZ-222_runtime_config_errors_telemetry.md | 80 --- .../done/AZ-223_camera_ingest_calibration.md | 89 --- .../done/AZ-224_mavlink_gcs_gateway.md | 84 --- .../AZ-225_tile_manager_cache_manifest.md | 89 --- ...Z-226_generated_tile_orthorectification.md | 88 --- .../done/AZ-227_fdr_event_recorder.md | 88 --- _docs/02_tasks/done/AZ-228_vio_adapter.md | 90 --- .../done/AZ-229_satellite_service_sync.md | 87 --- .../AZ-230_satellite_service_vpr_retrieval.md | 89 --- .../AZ-231_anchor_verification_matching.md | 88 --- .../AZ-232_safety_anchor_state_machine.md | 97 --- .../done/AZ-233_test_infrastructure.md | 163 ----- ...234_replay_geolocation_confidence_tests.md | 88 --- .../AZ-235_vio_replay_performance_tests.md | 89 --- .../AZ-236_satellite_anchor_cache_tests.md | 102 --- .../AZ-237_mavlink_blackout_spoofing_tests.md | 94 --- .../done/AZ-238_cold_start_restart_tests.md | 95 --- .../AZ-239_jetson_resource_endurance_tests.md | 94 --- .../AZ-240_native_vio_backend_integration.md | 95 --- ...real_satellite_vpr_descriptor_retrieval.md | 95 --- ...242_real_anchor_feature_matching_ransac.md | 94 --- ...integrate_production_native_vio_runtime.md | 96 --- .../batch_01_cycle1_report.md | 41 -- .../batch_02_cycle1_report.md | 34 - .../batch_03_cycle1_report.md | 37 -- .../batch_04_cycle1_report.md | 47 -- .../batch_05_cycle1_report.md | 35 - .../batch_06_cycle1_report.md | 39 -- .../batch_07_cycle1_report.md | 35 - .../batch_08_cycle1_report.md | 35 - .../batch_09_cycle1_report.md | 36 - .../batch_10_cycle1_report.md | 37 -- _docs/03_implementation/batch_11_report.md | 29 - _docs/03_implementation/batch_12_report.md | 43 -- _docs/03_implementation/batch_13_report.md | 35 - .../batch_14_cycle1_report.md | 27 - ...plementation_completeness_cycle1_report.md | 50 -- ...mentation_report_product_runtime_cycle1.md | 78 --- .../implementation_report_tests.md | 67 -- .../reviews/batch_01_review.md | 29 - .../reviews/batch_02_review.md | 24 - .../reviews/batch_03_review.md | 25 - .../reviews/batch_04_review.md | 29 - .../reviews/batch_05_review.md | 27 - .../reviews/batch_06_review.md | 61 -- .../reviews/batch_07_review.md | 54 -- .../reviews/batch_08_review.md | 53 -- .../reviews/batch_09_review.md | 54 -- .../reviews/batch_10_review.md | 31 - .../reviews/batch_11_review.md | 19 - .../reviews/batch_12_review.md | 19 - .../reviews/batch_13_review.md | 19 - .../reviews/batch_14_review.md | 24 - ...tive_review_batches_01-09_cycle1_report.md | 65 -- ...ative_review_batches_11-13_tests_report.md | 30 - .../testability_assessment.md | 58 -- _docs/05_security/dependency_scan.md | 34 - _docs/05_security/infrastructure_review.md | 49 -- _docs/05_security/owasp_review.md | 26 - _docs/05_security/security_report.md | 106 --- _docs/05_security/static_analysis.md | 45 -- _docs/_autodev_state.md | 14 - _docs/_autopilot_state.md | 40 -- .../00_research/00_question_decomposition.md | 68 -- .../00_research/01_source_registry.md | 133 ---- .../00_research/02_fact_cards.md | 151 ----- .../00_research/03_comparison_framework.md | 35 - .../00_research/04_reasoning_chain.md | 133 ---- .../00_research/05_validation_log.md | 42 -- .../01_solution/solution_draft01.md | 196 ------ .../UAV_frame_material.md | 1 - .../UAV_frame_material/00_ac_assessment.md | 41 -- .../00_question_decomposition.md | 72 -- .../UAV_frame_material/01_source_registry.md | 199 ------ .../UAV_frame_material/02_fact_cards.md | 145 ---- .../03_comparison_framework.md | 39 -- .../UAV_frame_material/04_reasoning_chain.md | 143 ---- .../UAV_frame_material/05_validation_log.md | 61 -- .../01_solution/solution_draft01.md | 177 ----- .../01_solution/solution_draft02.md | 428 ------------ .../01_solution/solution_draft03.md | 489 -------------- .../01_solution/solution_draft04.md | 296 --------- .../01_solution/solution_draft05.md | 354 ---------- .../01_solution/solution_draft06.md | 206 ------ .../01_solution/solution_draft07.md | 418 ------------ .../UAV_frame_material/UAV_frame_material.md | 1 - .../camera_high_altitude/00_ac_assessment.md | 98 --- .../00_question_decomposition.md | 56 -- .../01_source_registry.md | 146 ---- .../camera_high_altitude/02_fact_cards.md | 103 --- .../03_comparison_framework.md | 51 -- .../04_reasoning_chain.md | 130 ---- .../camera_high_altitude/05_validation_log.md | 51 -- .../01_solution/solution_draft01.md | 152 ----- .../camera_high_altitude.md | 6 - config/ci/runtime.env | 6 - config/development/runtime.env | 6 - config/jetson/runtime.env | 6 - config/production/runtime.env.example | 10 - data/cache/.gitkeep | 1 - data/expected/.gitkeep | 1 - data/fdr/.gitkeep | 1 - data/input/.gitkeep | 1 - data/test-results/.gitkeep | 1 - deployment/compose/README.md | 4 - deployment/docker/Dockerfile.replay | 20 - deployment/docker/Dockerfile.runtime | 18 - deployment/jetson/README.md | 4 - deployment/scripts/collect_evidence.sh | 5 - docker-compose.test.yml | 98 --- docker-compose.yml | 34 - e2e/__init__.py | 1 - e2e/fixtures/cache/.gitkeep | 1 - e2e/fixtures/expected/.gitkeep | 1 - e2e/fixtures/mavlink/.gitkeep | 1 - e2e/fixtures/telemetry/.gitkeep | 1 - e2e/mocks/ardupilot_sitl/.gitkeep | 1 - e2e/mocks/qgc_observer/.gitkeep | 1 - e2e/mocks/satellite_cache_stub/.gitkeep | 1 - e2e/replay/README.md | 4 - e2e/replay/__init__.py | 10 - e2e/replay/harness.py | 629 ------------------ e2e/replay/run_replay.py | 7 - e2e/reports/.gitkeep | 1 - migrations/postgresql/0001_enable_postgis.sql | 1 - migrations/seed/README.md | 4 - pyproject.toml | 34 - src/__init__.py | 1 - src/anchor_verification/__init__.py | 33 - src/anchor_verification/interfaces.py | 202 ------ src/anchor_verification/native/README.md | 3 - src/anchor_verification/native/__init__.py | 5 - src/anchor_verification/types.py | 65 -- src/camera_ingest_calibration/__init__.py | 22 - src/camera_ingest_calibration/interfaces.py | 96 --- src/camera_ingest_calibration/types.py | 70 -- src/fdr_observability/__init__.py | 22 - src/fdr_observability/interfaces.py | 121 ---- src/fdr_observability/types.py | 52 -- src/mavlink_gcs_integration/__init__.py | 24 - src/mavlink_gcs_integration/interfaces.py | 86 --- src/mavlink_gcs_integration/types.py | 80 --- src/safety_anchor_wrapper/__init__.py | 18 - src/safety_anchor_wrapper/interfaces.py | 151 ----- src/safety_anchor_wrapper/types.py | 39 -- src/satellite_service/__init__.py | 45 -- src/satellite_service/interfaces.py | 335 ---------- src/satellite_service/native/README.md | 3 - src/satellite_service/native/__init__.py | 5 - src/satellite_service/types.py | 105 --- src/shared/__init__.py | 1 - src/shared/config/__init__.py | 5 - src/shared/config/models.py | 59 -- src/shared/contracts/__init__.py | 28 - src/shared/contracts/models.py | 116 ---- src/shared/errors/__init__.py | 5 - src/shared/errors/models.py | 38 -- src/shared/geo_geometry/__init__.py | 21 - src/shared/geo_geometry/models.py | 83 --- src/shared/telemetry/__init__.py | 5 - src/shared/telemetry/models.py | 23 - src/shared/time_sync/__init__.py | 15 - src/shared/time_sync/models.py | 77 --- src/tile_manager/__init__.py | 28 - src/tile_manager/interfaces.py | 199 ------ src/tile_manager/types.py | 97 --- src/vio_adapter/__init__.py | 39 -- src/vio_adapter/interfaces.py | 328 --------- src/vio_adapter/native/README.md | 3 - src/vio_adapter/native/__init__.py | 6 - src/vio_adapter/native/basalt.py | 47 -- src/vio_adapter/types.py | 69 -- tests/blackbox/cache_freshness/.gitkeep | 1 - tests/blackbox/resource_limits/.gitkeep | 1 - tests/blackbox/run_blackbox.py | 13 - tests/blackbox/satellite_anchor/.gitkeep | 1 - .../blackbox/still_image_geolocation/.gitkeep | 1 - tests/blackbox/test_blackout_spoofing.py | 117 ---- tests/blackbox/test_cold_start_restart.py | 71 -- tests/blackbox/test_infrastructure.py | 96 --- tests/blackbox/test_resource_endurance.py | 86 --- tests/blackbox/test_satellite_anchor.py | 123 ---- tests/blackbox/test_still_image_replay.py | 68 -- tests/blackbox/test_vio_replay.py | 88 --- .../visual_blackout_spoofing/.gitkeep | 1 - tests/e2e/release_evidence/.gitkeep | 1 - tests/e2e/replay/.gitkeep | 1 - tests/e2e/reports/.gitkeep | 1 - tests/fixtures/expected_results/.gitkeep | 1 - tests/fixtures/project_60_images/.gitkeep | 1 - tests/fixtures/public_dataset_slices/.gitkeep | 1 - tests/fixtures/satellite_cache/.gitkeep | 1 - tests/fixtures/telemetry/.gitkeep | 1 - tests/integration/cache_postgis/.gitkeep | 1 - tests/integration/contracts/.gitkeep | 1 - tests/integration/fdr/.gitkeep | 1 - tests/integration/mavlink/.gitkeep | 1 - tests/sitl/failsafe/.gitkeep | 1 - tests/sitl/plane_gps_input/.gitkeep | 1 - tests/sitl/spoofing_promotion/.gitkeep | 1 - tests/unit/anchor_verification/.gitkeep | 1 - tests/unit/camera_ingest_calibration/.gitkeep | 1 - tests/unit/fdr_observability/.gitkeep | 1 - tests/unit/mavlink_gcs_integration/.gitkeep | 1 - tests/unit/safety_anchor_wrapper/.gitkeep | 1 - tests/unit/satellite_service/.gitkeep | 1 - tests/unit/shared/.gitkeep | 1 - .../shared/test_config_errors_telemetry.py | 65 -- tests/unit/shared/test_geometry_time_sync.py | 41 -- tests/unit/shared/test_runtime_contracts.py | 157 ----- tests/unit/test_anchor_verification.py | 170 ----- tests/unit/test_camera_ingest_calibration.py | 76 --- tests/unit/test_fdr_observability.py | 64 -- tests/unit/test_mavlink_gcs_integration.py | 72 -- tests/unit/test_safety_anchor_wrapper.py | 102 --- tests/unit/test_satellite_service_sync.py | 96 --- tests/unit/test_satellite_service_vpr.py | 198 ------ tests/unit/test_scaffold.py | 137 ---- tests/unit/test_tile_manager.py | 137 ---- tests/unit/test_vio_adapter.py | 237 ------- tests/unit/tile_manager/.gitkeep | 1 - tests/unit/vio_adapter/.gitkeep | 1 - .../remove_osd_lines.cpython-310.pyc | Bin 3900 -> 0 bytes tools/remove_osd_lines.py | 146 ---- 351 files changed, 30337 deletions(-) delete mode 100644 .dockerignore delete mode 100644 .env.example delete mode 100644 .gitattributes delete mode 100644 .github/pull_request_template.md delete mode 100644 .github/workflows/ci.yml delete mode 100644 .gitignore delete mode 100644 README.md delete mode 100644 _docs/00_research/00_ac_assessment.md delete mode 100644 _docs/00_research/00_question_decomposition.md delete mode 100644 _docs/00_research/01_source_registry.md delete mode 100644 _docs/00_research/02_fact_cards.md delete mode 100644 _docs/00_research/03_comparison_framework.md delete mode 100644 _docs/00_research/04_reasoning_chain.md delete mode 100644 _docs/00_research/05_validation_log.md delete mode 100644 _docs/00_research/06_component_fit_matrix.md delete mode 100644 _docs/00_research/gps_denied_draft02_assessment/00_question_decomposition.md delete mode 100644 _docs/00_research/gps_denied_draft02_assessment/01_source_registry.md delete mode 100644 _docs/00_research/gps_denied_draft02_assessment/02_fact_cards.md delete mode 100644 _docs/00_research/gps_denied_draft02_assessment/03_comparison_framework.md delete mode 100644 _docs/00_research/gps_denied_draft02_assessment/04_reasoning_chain.md delete mode 100644 _docs/00_research/gps_denied_draft02_assessment/05_validation_log.md delete mode 100644 _docs/00_research/gps_denied_nav/00_ac_assessment.md delete mode 100644 _docs/00_research/gps_denied_nav/00_question_decomposition.md delete mode 100644 _docs/00_research/gps_denied_nav/01_source_registry.md delete mode 100644 _docs/00_research/gps_denied_nav/02_fact_cards.md delete mode 100644 _docs/00_research/gps_denied_nav/03_comparison_framework.md delete mode 100644 _docs/00_research/gps_denied_nav/04_reasoning_chain.md delete mode 100644 _docs/00_research/gps_denied_nav/05_validation_log.md delete mode 100644 _docs/00_research/gps_denied_nav_assessment/00_question_decomposition.md delete mode 100644 _docs/00_research/gps_denied_nav_assessment/01_source_registry.md delete mode 100644 _docs/00_research/gps_denied_nav_assessment/02_fact_cards.md delete mode 100644 _docs/00_research/gps_denied_nav_assessment/03_comparison_framework.md delete mode 100644 _docs/00_research/gps_denied_nav_assessment/04_reasoning_chain.md delete mode 100644 _docs/00_research/gps_denied_nav_assessment/05_validation_log.md delete mode 100644 _docs/00_research/gps_denied_nav_v2/00_question_decomposition.md delete mode 100644 _docs/00_research/gps_denied_nav_v2/01_source_registry.md delete mode 100644 _docs/00_research/gps_denied_nav_v2/02_fact_cards.md delete mode 100644 _docs/00_research/gps_denied_nav_v2/03_comparison_framework.md delete mode 100644 _docs/00_research/gps_denied_nav_v2/04_reasoning_chain.md delete mode 100644 _docs/00_research/gps_denied_nav_v2/05_validation_log.md delete mode 100644 _docs/00_research/gps_denied_nav_v3/00_question_decomposition.md delete mode 100644 _docs/00_research/gps_denied_nav_v3/01_source_registry.md delete mode 100644 _docs/00_research/gps_denied_nav_v3/02_fact_cards.md delete mode 100644 _docs/00_research/gps_denied_nav_v3/03_comparison_framework.md delete mode 100644 _docs/00_research/gps_denied_nav_v3/04_reasoning_chain.md delete mode 100644 _docs/00_research/gps_denied_nav_v3/05_validation_log.md delete mode 100644 _docs/00_research/gps_denied_visual_nav/00_ac_assessment.md delete mode 100644 _docs/00_research/gps_denied_visual_nav/00_question_decomposition.md delete mode 100644 _docs/00_research/gps_denied_visual_nav/01_source_registry.md delete mode 100644 _docs/00_research/gps_denied_visual_nav/02_fact_cards.md delete mode 100644 _docs/00_research/gps_denied_visual_nav/03_comparison_framework.md delete mode 100644 _docs/00_research/gps_denied_visual_nav/04_reasoning_chain.md delete mode 100644 _docs/00_research/gps_denied_visual_nav/05_validation_log.md delete mode 100644 _docs/00_research/solution_completeness_assessment/00_question_decomposition.md delete mode 100644 _docs/00_research/solution_completeness_assessment/01_source_registry.md delete mode 100644 _docs/00_research/solution_completeness_assessment/02_fact_cards.md delete mode 100644 _docs/00_research/solution_completeness_assessment/03_comparison_framework.md delete mode 100644 _docs/00_research/solution_completeness_assessment/04_reasoning_chain.md delete mode 100644 _docs/00_research/solution_completeness_assessment/05_validation_log.md delete mode 100644 _docs/00_research/trt_engine_migration/00_question_decomposition.md delete mode 100644 _docs/00_research/trt_engine_migration/01_source_registry.md delete mode 100644 _docs/00_research/trt_engine_migration/02_fact_cards.md delete mode 100644 _docs/00_research/trt_engine_migration/03_comparison_framework.md delete mode 100644 _docs/00_research/trt_engine_migration/04_reasoning_chain.md delete mode 100644 _docs/00_research/trt_engine_migration/05_validation_log.md delete mode 100644 _docs/01_solution/security_analysis.md delete mode 100644 _docs/01_solution/solution.md delete mode 100644 _docs/01_solution/solution_draft01.md delete mode 100644 _docs/01_solution/solution_draft02.md delete mode 100644 _docs/01_solution/solution_draft03.md delete mode 100644 _docs/01_solution/solution_draft04.md delete mode 100644 _docs/01_solution/solution_draft05.md delete mode 100644 _docs/01_solution/solution_draft06.md delete mode 100644 _docs/01_solution/tech_stack.md delete mode 100644 _docs/02_document/FINAL_report.md delete mode 100644 _docs/02_document/architecture.md delete mode 100644 _docs/02_document/common-helpers/01_helper_geo_geometry.md delete mode 100644 _docs/02_document/common-helpers/02_helper_time_sync.md delete mode 100644 _docs/02_document/components/01_camera_ingest_calibration/description.md delete mode 100644 _docs/02_document/components/01_camera_ingest_calibration/tests.md delete mode 100644 _docs/02_document/components/02_vio_adapter/description.md delete mode 100644 _docs/02_document/components/02_vio_adapter/tests.md delete mode 100644 _docs/02_document/components/03_safety_anchor_wrapper/description.md delete mode 100644 _docs/02_document/components/03_safety_anchor_wrapper/tests.md delete mode 100644 _docs/02_document/components/04_satellite_retrieval/description.md delete mode 100644 _docs/02_document/components/04_satellite_retrieval/tests.md delete mode 100644 _docs/02_document/components/05_anchor_verification/description.md delete mode 100644 _docs/02_document/components/05_anchor_verification/tests.md delete mode 100644 _docs/02_document/components/06_cache_tile_lifecycle/description.md delete mode 100644 _docs/02_document/components/06_cache_tile_lifecycle/tests.md delete mode 100644 _docs/02_document/components/07_mavlink_gcs_integration/description.md delete mode 100644 _docs/02_document/components/07_mavlink_gcs_integration/tests.md delete mode 100644 _docs/02_document/components/08_fdr_observability/description.md delete mode 100644 _docs/02_document/components/08_fdr_observability/tests.md delete mode 100644 _docs/02_document/contracts/shared/config_errors_telemetry.md delete mode 100644 _docs/02_document/contracts/shared/geometry_time_sync.md delete mode 100644 _docs/02_document/contracts/shared/runtime_contracts.md delete mode 100644 _docs/02_document/data_model.md delete mode 100644 _docs/02_document/deployment/README.md delete mode 100644 _docs/02_document/deployment/ci_cd_pipeline.md delete mode 100644 _docs/02_document/deployment/containerization.md delete mode 100644 _docs/02_document/deployment/deployment_procedures.md delete mode 100644 _docs/02_document/deployment/environment_strategy.md delete mode 100644 _docs/02_document/deployment/observability.md delete mode 100644 _docs/02_document/diagrams/component_overview.md delete mode 100644 _docs/02_document/diagrams/flows/flow_cache_tile_lifecycle.md delete mode 100644 _docs/02_document/diagrams/flows/flow_normal_localization.md delete mode 100644 _docs/02_document/diagrams/flows/flow_satellite_relocalization.md delete mode 100644 _docs/02_document/epics.md delete mode 100644 _docs/02_document/glossary.md delete mode 100644 _docs/02_document/module-layout.md delete mode 100644 _docs/02_document/ripple_log_cycle1.md delete mode 100644 _docs/02_document/risk_mitigations.md delete mode 100644 _docs/02_document/system-flows.md delete mode 100644 _docs/02_document/tests/blackbox-tests.md delete mode 100644 _docs/02_document/tests/e2e-test-suite.md delete mode 100644 _docs/02_document/tests/environment.md delete mode 100644 _docs/02_document/tests/performance-tests.md delete mode 100644 _docs/02_document/tests/resilience-tests.md delete mode 100644 _docs/02_document/tests/resource-limit-tests.md delete mode 100644 _docs/02_document/tests/security-tests.md delete mode 100644 _docs/02_document/tests/test-data.md delete mode 100644 _docs/02_document/tests/traceability-matrix.md delete mode 100644 _docs/02_tasks/_dependencies_table.md delete mode 100644 _docs/02_tasks/done/AZ-219_initial_structure.md delete mode 100644 _docs/02_tasks/done/AZ-220_shared_runtime_contracts.md delete mode 100644 _docs/02_tasks/done/AZ-221_shared_geometry_time_sync.md delete mode 100644 _docs/02_tasks/done/AZ-222_runtime_config_errors_telemetry.md delete mode 100644 _docs/02_tasks/done/AZ-223_camera_ingest_calibration.md delete mode 100644 _docs/02_tasks/done/AZ-224_mavlink_gcs_gateway.md delete mode 100644 _docs/02_tasks/done/AZ-225_tile_manager_cache_manifest.md delete mode 100644 _docs/02_tasks/done/AZ-226_generated_tile_orthorectification.md delete mode 100644 _docs/02_tasks/done/AZ-227_fdr_event_recorder.md delete mode 100644 _docs/02_tasks/done/AZ-228_vio_adapter.md delete mode 100644 _docs/02_tasks/done/AZ-229_satellite_service_sync.md delete mode 100644 _docs/02_tasks/done/AZ-230_satellite_service_vpr_retrieval.md delete mode 100644 _docs/02_tasks/done/AZ-231_anchor_verification_matching.md delete mode 100644 _docs/02_tasks/done/AZ-232_safety_anchor_state_machine.md delete mode 100644 _docs/02_tasks/done/AZ-233_test_infrastructure.md delete mode 100644 _docs/02_tasks/done/AZ-234_replay_geolocation_confidence_tests.md delete mode 100644 _docs/02_tasks/done/AZ-235_vio_replay_performance_tests.md delete mode 100644 _docs/02_tasks/done/AZ-236_satellite_anchor_cache_tests.md delete mode 100644 _docs/02_tasks/done/AZ-237_mavlink_blackout_spoofing_tests.md delete mode 100644 _docs/02_tasks/done/AZ-238_cold_start_restart_tests.md delete mode 100644 _docs/02_tasks/done/AZ-239_jetson_resource_endurance_tests.md delete mode 100644 _docs/02_tasks/done/AZ-240_native_vio_backend_integration.md delete mode 100644 _docs/02_tasks/done/AZ-241_real_satellite_vpr_descriptor_retrieval.md delete mode 100644 _docs/02_tasks/done/AZ-242_real_anchor_feature_matching_ransac.md delete mode 100644 _docs/02_tasks/done/AZ-243_integrate_production_native_vio_runtime.md delete mode 100644 _docs/03_implementation/batch_01_cycle1_report.md delete mode 100644 _docs/03_implementation/batch_02_cycle1_report.md delete mode 100644 _docs/03_implementation/batch_03_cycle1_report.md delete mode 100644 _docs/03_implementation/batch_04_cycle1_report.md delete mode 100644 _docs/03_implementation/batch_05_cycle1_report.md delete mode 100644 _docs/03_implementation/batch_06_cycle1_report.md delete mode 100644 _docs/03_implementation/batch_07_cycle1_report.md delete mode 100644 _docs/03_implementation/batch_08_cycle1_report.md delete mode 100644 _docs/03_implementation/batch_09_cycle1_report.md delete mode 100644 _docs/03_implementation/batch_10_cycle1_report.md delete mode 100644 _docs/03_implementation/batch_11_report.md delete mode 100644 _docs/03_implementation/batch_12_report.md delete mode 100644 _docs/03_implementation/batch_13_report.md delete mode 100644 _docs/03_implementation/batch_14_cycle1_report.md delete mode 100644 _docs/03_implementation/implementation_completeness_cycle1_report.md delete mode 100644 _docs/03_implementation/implementation_report_product_runtime_cycle1.md delete mode 100644 _docs/03_implementation/implementation_report_tests.md delete mode 100644 _docs/03_implementation/reviews/batch_01_review.md delete mode 100644 _docs/03_implementation/reviews/batch_02_review.md delete mode 100644 _docs/03_implementation/reviews/batch_03_review.md delete mode 100644 _docs/03_implementation/reviews/batch_04_review.md delete mode 100644 _docs/03_implementation/reviews/batch_05_review.md delete mode 100644 _docs/03_implementation/reviews/batch_06_review.md delete mode 100644 _docs/03_implementation/reviews/batch_07_review.md delete mode 100644 _docs/03_implementation/reviews/batch_08_review.md delete mode 100644 _docs/03_implementation/reviews/batch_09_review.md delete mode 100644 _docs/03_implementation/reviews/batch_10_review.md delete mode 100644 _docs/03_implementation/reviews/batch_11_review.md delete mode 100644 _docs/03_implementation/reviews/batch_12_review.md delete mode 100644 _docs/03_implementation/reviews/batch_13_review.md delete mode 100644 _docs/03_implementation/reviews/batch_14_review.md delete mode 100644 _docs/03_implementation/reviews/cumulative_review_batches_01-09_cycle1_report.md delete mode 100644 _docs/03_implementation/reviews/cumulative_review_batches_11-13_tests_report.md delete mode 100644 _docs/04_refactoring/01-testability-refactoring/testability_assessment.md delete mode 100644 _docs/05_security/dependency_scan.md delete mode 100644 _docs/05_security/infrastructure_review.md delete mode 100644 _docs/05_security/owasp_review.md delete mode 100644 _docs/05_security/security_report.md delete mode 100644 _docs/05_security/static_analysis.md delete mode 100644 _docs/_autodev_state.md delete mode 100644 _docs/_autopilot_state.md delete mode 100644 _standalone/UAV_camera_comparison/00_research/00_question_decomposition.md delete mode 100644 _standalone/UAV_camera_comparison/00_research/01_source_registry.md delete mode 100644 _standalone/UAV_camera_comparison/00_research/02_fact_cards.md delete mode 100644 _standalone/UAV_camera_comparison/00_research/03_comparison_framework.md delete mode 100644 _standalone/UAV_camera_comparison/00_research/04_reasoning_chain.md delete mode 100644 _standalone/UAV_camera_comparison/00_research/05_validation_log.md delete mode 100644 _standalone/UAV_camera_comparison/01_solution/solution_draft01.md delete mode 100644 _standalone/UAV_camera_comparison/UAV_frame_material.md delete mode 100644 _standalone/UAV_frame_material/00_research/UAV_frame_material/00_ac_assessment.md delete mode 100644 _standalone/UAV_frame_material/00_research/UAV_frame_material/00_question_decomposition.md delete mode 100644 _standalone/UAV_frame_material/00_research/UAV_frame_material/01_source_registry.md delete mode 100644 _standalone/UAV_frame_material/00_research/UAV_frame_material/02_fact_cards.md delete mode 100644 _standalone/UAV_frame_material/00_research/UAV_frame_material/03_comparison_framework.md delete mode 100644 _standalone/UAV_frame_material/00_research/UAV_frame_material/04_reasoning_chain.md delete mode 100644 _standalone/UAV_frame_material/00_research/UAV_frame_material/05_validation_log.md delete mode 100644 _standalone/UAV_frame_material/01_solution/solution_draft01.md delete mode 100644 _standalone/UAV_frame_material/01_solution/solution_draft02.md delete mode 100644 _standalone/UAV_frame_material/01_solution/solution_draft03.md delete mode 100644 _standalone/UAV_frame_material/01_solution/solution_draft04.md delete mode 100644 _standalone/UAV_frame_material/01_solution/solution_draft05.md delete mode 100644 _standalone/UAV_frame_material/01_solution/solution_draft06.md delete mode 100644 _standalone/UAV_frame_material/01_solution/solution_draft07.md delete mode 100644 _standalone/UAV_frame_material/UAV_frame_material.md delete mode 100644 _standalone/camera_high_altitude/00_research/camera_high_altitude/00_ac_assessment.md delete mode 100644 _standalone/camera_high_altitude/00_research/camera_high_altitude/00_question_decomposition.md delete mode 100644 _standalone/camera_high_altitude/00_research/camera_high_altitude/01_source_registry.md delete mode 100644 _standalone/camera_high_altitude/00_research/camera_high_altitude/02_fact_cards.md delete mode 100644 _standalone/camera_high_altitude/00_research/camera_high_altitude/03_comparison_framework.md delete mode 100644 _standalone/camera_high_altitude/00_research/camera_high_altitude/04_reasoning_chain.md delete mode 100644 _standalone/camera_high_altitude/00_research/camera_high_altitude/05_validation_log.md delete mode 100644 _standalone/camera_high_altitude/01_solution/solution_draft01.md delete mode 100644 _standalone/camera_high_altitude/camera_high_altitude.md delete mode 100644 config/ci/runtime.env delete mode 100644 config/development/runtime.env delete mode 100644 config/jetson/runtime.env delete mode 100644 config/production/runtime.env.example delete mode 100644 data/cache/.gitkeep delete mode 100644 data/expected/.gitkeep delete mode 100644 data/fdr/.gitkeep delete mode 100644 data/input/.gitkeep delete mode 100644 data/test-results/.gitkeep delete mode 100644 deployment/compose/README.md delete mode 100644 deployment/docker/Dockerfile.replay delete mode 100644 deployment/docker/Dockerfile.runtime delete mode 100644 deployment/jetson/README.md delete mode 100644 deployment/scripts/collect_evidence.sh delete mode 100644 docker-compose.test.yml delete mode 100644 docker-compose.yml delete mode 100644 e2e/__init__.py delete mode 100644 e2e/fixtures/cache/.gitkeep delete mode 100644 e2e/fixtures/expected/.gitkeep delete mode 100644 e2e/fixtures/mavlink/.gitkeep delete mode 100644 e2e/fixtures/telemetry/.gitkeep delete mode 100644 e2e/mocks/ardupilot_sitl/.gitkeep delete mode 100644 e2e/mocks/qgc_observer/.gitkeep delete mode 100644 e2e/mocks/satellite_cache_stub/.gitkeep delete mode 100644 e2e/replay/README.md delete mode 100644 e2e/replay/__init__.py delete mode 100644 e2e/replay/harness.py delete mode 100644 e2e/replay/run_replay.py delete mode 100644 e2e/reports/.gitkeep delete mode 100644 migrations/postgresql/0001_enable_postgis.sql delete mode 100644 migrations/seed/README.md delete mode 100644 pyproject.toml delete mode 100644 src/__init__.py delete mode 100644 src/anchor_verification/__init__.py delete mode 100644 src/anchor_verification/interfaces.py delete mode 100644 src/anchor_verification/native/README.md delete mode 100644 src/anchor_verification/native/__init__.py delete mode 100644 src/anchor_verification/types.py delete mode 100644 src/camera_ingest_calibration/__init__.py delete mode 100644 src/camera_ingest_calibration/interfaces.py delete mode 100644 src/camera_ingest_calibration/types.py delete mode 100644 src/fdr_observability/__init__.py delete mode 100644 src/fdr_observability/interfaces.py delete mode 100644 src/fdr_observability/types.py delete mode 100644 src/mavlink_gcs_integration/__init__.py delete mode 100644 src/mavlink_gcs_integration/interfaces.py delete mode 100644 src/mavlink_gcs_integration/types.py delete mode 100644 src/safety_anchor_wrapper/__init__.py delete mode 100644 src/safety_anchor_wrapper/interfaces.py delete mode 100644 src/safety_anchor_wrapper/types.py delete mode 100644 src/satellite_service/__init__.py delete mode 100644 src/satellite_service/interfaces.py delete mode 100644 src/satellite_service/native/README.md delete mode 100644 src/satellite_service/native/__init__.py delete mode 100644 src/satellite_service/types.py delete mode 100644 src/shared/__init__.py delete mode 100644 src/shared/config/__init__.py delete mode 100644 src/shared/config/models.py delete mode 100644 src/shared/contracts/__init__.py delete mode 100644 src/shared/contracts/models.py delete mode 100644 src/shared/errors/__init__.py delete mode 100644 src/shared/errors/models.py delete mode 100644 src/shared/geo_geometry/__init__.py delete mode 100644 src/shared/geo_geometry/models.py delete mode 100644 src/shared/telemetry/__init__.py delete mode 100644 src/shared/telemetry/models.py delete mode 100644 src/shared/time_sync/__init__.py delete mode 100644 src/shared/time_sync/models.py delete mode 100644 src/tile_manager/__init__.py delete mode 100644 src/tile_manager/interfaces.py delete mode 100644 src/tile_manager/types.py delete mode 100644 src/vio_adapter/__init__.py delete mode 100644 src/vio_adapter/interfaces.py delete mode 100644 src/vio_adapter/native/README.md delete mode 100644 src/vio_adapter/native/__init__.py delete mode 100644 src/vio_adapter/native/basalt.py delete mode 100644 src/vio_adapter/types.py delete mode 100644 tests/blackbox/cache_freshness/.gitkeep delete mode 100644 tests/blackbox/resource_limits/.gitkeep delete mode 100644 tests/blackbox/run_blackbox.py delete mode 100644 tests/blackbox/satellite_anchor/.gitkeep delete mode 100644 tests/blackbox/still_image_geolocation/.gitkeep delete mode 100644 tests/blackbox/test_blackout_spoofing.py delete mode 100644 tests/blackbox/test_cold_start_restart.py delete mode 100644 tests/blackbox/test_infrastructure.py delete mode 100644 tests/blackbox/test_resource_endurance.py delete mode 100644 tests/blackbox/test_satellite_anchor.py delete mode 100644 tests/blackbox/test_still_image_replay.py delete mode 100644 tests/blackbox/test_vio_replay.py delete mode 100644 tests/blackbox/visual_blackout_spoofing/.gitkeep delete mode 100644 tests/e2e/release_evidence/.gitkeep delete mode 100644 tests/e2e/replay/.gitkeep delete mode 100644 tests/e2e/reports/.gitkeep delete mode 100644 tests/fixtures/expected_results/.gitkeep delete mode 100644 tests/fixtures/project_60_images/.gitkeep delete mode 100644 tests/fixtures/public_dataset_slices/.gitkeep delete mode 100644 tests/fixtures/satellite_cache/.gitkeep delete mode 100644 tests/fixtures/telemetry/.gitkeep delete mode 100644 tests/integration/cache_postgis/.gitkeep delete mode 100644 tests/integration/contracts/.gitkeep delete mode 100644 tests/integration/fdr/.gitkeep delete mode 100644 tests/integration/mavlink/.gitkeep delete mode 100644 tests/sitl/failsafe/.gitkeep delete mode 100644 tests/sitl/plane_gps_input/.gitkeep delete mode 100644 tests/sitl/spoofing_promotion/.gitkeep delete mode 100644 tests/unit/anchor_verification/.gitkeep delete mode 100644 tests/unit/camera_ingest_calibration/.gitkeep delete mode 100644 tests/unit/fdr_observability/.gitkeep delete mode 100644 tests/unit/mavlink_gcs_integration/.gitkeep delete mode 100644 tests/unit/safety_anchor_wrapper/.gitkeep delete mode 100644 tests/unit/satellite_service/.gitkeep delete mode 100644 tests/unit/shared/.gitkeep delete mode 100644 tests/unit/shared/test_config_errors_telemetry.py delete mode 100644 tests/unit/shared/test_geometry_time_sync.py delete mode 100644 tests/unit/shared/test_runtime_contracts.py delete mode 100644 tests/unit/test_anchor_verification.py delete mode 100644 tests/unit/test_camera_ingest_calibration.py delete mode 100644 tests/unit/test_fdr_observability.py delete mode 100644 tests/unit/test_mavlink_gcs_integration.py delete mode 100644 tests/unit/test_safety_anchor_wrapper.py delete mode 100644 tests/unit/test_satellite_service_sync.py delete mode 100644 tests/unit/test_satellite_service_vpr.py delete mode 100644 tests/unit/test_scaffold.py delete mode 100644 tests/unit/test_tile_manager.py delete mode 100644 tests/unit/test_vio_adapter.py delete mode 100644 tests/unit/tile_manager/.gitkeep delete mode 100644 tests/unit/vio_adapter/.gitkeep delete mode 100644 tools/__pycache__/remove_osd_lines.cpython-310.pyc delete mode 100644 tools/remove_osd_lines.py diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index d5d317a..0000000 --- a/.dockerignore +++ /dev/null @@ -1,27 +0,0 @@ -.git -.github -.cursor -_docs -.venv -__pycache__ -.pytest_cache -.ruff_cache -.mypy_cache -.env -.env.* -*.pem -*.key -*.secret -data/input/* -data/cache/* -data/fdr/* -data/test-results/* -*.tlog -*.ulg -*.bag -*.mcap -*.cbor -*.parquet -*.mp4 -*.mov -*.avi diff --git a/.env.example b/.env.example deleted file mode 100644 index 94e50d3..0000000 --- a/.env.example +++ /dev/null @@ -1,10 +0,0 @@ -GPSD_ENV=development -GPSD_CONFIG_DIR=./config/development -GPSD_CACHE_DIR=./data/cache -GPSD_FDR_DIR=./data/fdr -GPSD_DATABASE_URL=postgresql://gpsd:gpsd@localhost:5432/gpsd -GPSD_MAVLINK_URL=udp:127.0.0.1:14550 -GPSD_CAMERA_SOURCE=./data/input -GPSD_SIGNING_KEY_REF=test-key-ref -GPSD_MAX_FDR_BYTES=104857600 -GPSD_LOG_LEVEL=info diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 4692117..0000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -_docs/00_problem/input_data/flight_derkachi/flight_derkachi.mp4 filter=lfs diff=lfs merge=lfs -text diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 80ab9ea..0000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,15 +0,0 @@ -## Summary -[1-3 bullet points describing the change] - -## Related Tasks -[JIRA-ID links] - -## Testing -- [ ] Unit tests pass -- [ ] Integration tests pass -- [ ] Manual testing done (if applicable) - -## Checklist -- [ ] No new linter warnings -- [ ] No secrets committed -- [ ] API docs updated (if applicable) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 74f23f4..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: CI - -on: - pull_request: - push: - branches: - - dev - -jobs: - python-quality: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: "3.10" - - name: Install - run: | - python -m pip install --upgrade pip - python -m pip install -e ".[dev]" - - name: Format check - run: python -m black --check src tests - - name: Lint - run: python -m ruff check src tests - - name: Unit tests - run: python -m pytest tests/unit - - replay-compose-smoke: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Validate compose files - run: | - docker compose -f docker-compose.yml config - docker compose -f docker-compose.test.yml config - - name: Collect artifact placeholders - run: mkdir -p data/test-results e2e/reports - - uses: actions/upload-artifact@v4 - with: - name: replay-evidence-placeholders - path: | - data/test-results - e2e/reports diff --git a/.gitignore b/.gitignore deleted file mode 100644 index ceaba45..0000000 --- a/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -.DS_Store -.venv/ -__pycache__/ -*.py[cod] -.pytest_cache/ -.ruff_cache/ -.mypy_cache/ -.coverage -htmlcov/ -*.egg-info/ - -.env -.env.* -!.env.example -*.pem -*.key -*.secret - -data/input/* -data/cache/* -data/fdr/* -data/test-results/* -data/expected/* -!data/input/.gitkeep -!data/cache/.gitkeep -!data/fdr/.gitkeep -!data/test-results/.gitkeep -!data/expected/.gitkeep - -*.tlog -*.ulg -*.bag -*.mcap -*.cbor -*.parquet -*.mp4 -*.mov -*.avi -*.jpg -*.jpeg -*.png -!_docs/00_problem/input_data/** diff --git a/README.md b/README.md deleted file mode 100644 index 90c0463..0000000 --- a/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# GPS-Denied Onboard Runtime - -Scaffold for the Jetson-hosted GPS-denied localization runtime, replay harness, and -deployment evidence paths. - -The project uses a Python `src/` layout for orchestration code. Native bridge -placeholders live inside the owning component folders rather than in a shared -native tree. -Generated mission data, FDR payloads, cache payloads, and raw frame dumps are kept -out of git unless they are explicitly curated test fixtures. - -## Local Development - -```bash -python3 -m venv .venv -source .venv/bin/activate -python -m pip install -e ".[dev]" -python -m pytest -``` - -Local replay infrastructure is described in `docker-compose.yml`; CI and black-box -test infrastructure are described in `docker-compose.test.yml`. diff --git a/_docs/00_research/00_ac_assessment.md b/_docs/00_research/00_ac_assessment.md deleted file mode 100644 index 6269c1f..0000000 --- a/_docs/00_research/00_ac_assessment.md +++ /dev/null @@ -1,54 +0,0 @@ -# Acceptance Criteria Assessment - -Accessed: 2026-05-01. Rerun after user-approved clarifications: 2026-05-01. - -## Research Scope - -- **Output class**: Technical-component selection support. -- **Novelty sensitivity**: High for VPR, embedded AI, and autopilot integration; source preference is current papers and official docs. -- **Boundary**: Fixed-wing UAV, nadir navigation camera, ArduPilot Plane, Jetson Orin Nano Super, offline Azaion Suite Satellite Service cache, eastern/southern Ukraine terrain. - -## Acceptance Criteria - -| Criterion | Current Values | Researched Values / Evidence | Cost / Timeline Impact | Status | -|-----------|----------------|------------------------------|------------------------|--------| -| AC-1.1 / AC-1.2 frame-center accuracy | <=50 m for >=80%, <=20 m for >=50% in normal segments | Plausible only with periodic satellite anchoring plus VO/IMU propagation. Aerial VPR papers show the mechanism is viable but sensitive to weather, scale, repetition, and tile overlap. | High validation cost. | Keep, high-risk | -| AC-1.3 drift | VO-only <100 m, IMU-fused <50 m between anchors, anchor age reported | Updated AC now requires `last_satellite_anchor_age_ms`, binned validation, and degraded covariance after a solution-defined max anchor age. | Medium. | Updated | -| AC-1.4 confidence | 95% covariance ellipse + source label | `GPS_INPUT` supports accuracy fields; source labels must be carried in telemetry/FDR because `GPS_INPUT` has no semantic label field. | Medium. | Keep | -| AC-2.1 registration | VO >95%; satellite anchoring measured separately | Split is correct: VO success is not the same as cross-domain satellite anchor success. | Medium-high. | Updated | -| AC-2.2 reprojection | <1 px VO, <2.5 px satellite anchor | Reasonable image-space gates, with coordinate error still dependent on calibration, orthorectification, and satellite georegistration. | Medium. | Keep | -| AC-3.x resilience | Outliers, sharp turns, disconnected segments, blackout | Technically feasible only through mode switching: VO failure triggers VPR/relocalization, blackout triggers IMU-only propagation with honest covariance growth. | High test cost. | Keep | -| AC-4.1 latency | <400 ms p95, <=10% frame drops, heavy VPR conditional | Aerial VPR survey reports some re-ranking paths too slow for steady-state use; solution must keep global VPR off the per-frame hot path. | High optimization cost. | Updated | -| AC-4.2 memory | <8 GB shared | Feasible if descriptors are compressed/pruned and indices are memory-mapped or loaded selectively. | Medium-high. | Keep | -| AC-4.3 MAVLink | v1 GPS_INPUT only via pymavlink | ArduPilot docs require `GPS1_TYPE=14`; MAVLink defines required lat/lon, velocity, fix, and accuracy fields. MAVSDK should remain telemetry-oriented. | Medium. | Keep | -| AC-5.2 failsafe | >3 s no estimate triggers fallback, Plane SITL verified | Copter docs are reference only. Plane-specific production parameters must be verified in SITL. | Medium. | Updated | -| AC-7 object localization | Level-flight AI-camera object GPS | Realistic under level-flight clause; maneuvering estimates must publish conservative bound. | Medium. | Keep | -| AC-8.x satellite cache | 0.3-0.5 m/px, freshness, offline descriptors, VPR chunks | Resolution is feasible through commercial/service imagery. Storage must count descriptors unless separately budgeted. | Medium-high. | Updated | -| AC-NEW-1 / 2 startup and spoofing | <30 s first fix, <3 s promotion | Feasible only with prebuilt engines, warmed indices, and verified Plane GPS-health triggers. | Medium-high. | Keep with SITL gate | -| AC-NEW-3 FDR | <=64 GB per flight, no raw frames | Feasible with segment files and rollover. | Medium. | Keep | -| AC-NEW-4 / 7 safety budgets | False-position and cache-poisoning probabilities | Appropriate safety gates, but require Monte Carlo and representative flight/replay data. | High. | Keep | -| AC-NEW-5 environment | -20 C to +50 C, 25 W for 8 h | NVIDIA confirms 25 W mode; thermal design must prevent throttling. | Medium-high. | Keep | - -## Restrictions Assessment - -| Restriction | Current Values | Researched Values / Evidence | Cost / Timeline Impact | Status | -|-------------|----------------|------------------------------|------------------------|--------| -| Camera source of truth | `restrictions.md` pins ADTi 20MP ~5472 x 3648 | User confirmed `restrictions.md` is authoritative. Lens/FOV remains a design parameter. | Medium during module selection. | Updated | -| Fixed nadir camera | No gimbal stabilization | Good for orthorectification; turn/tilt requires attitude compensation and failure detection. | Medium. | Keep | -| Terrain/weather | Flat steppe/agricultural, seasonal classes included | Repetitive fields and seasonal changes are VPR hazards; validation must include those classes. | High validation cost. | Updated | -| Satellite Service boundary | Offline consumer of Suite Satellite Service | Strong separation; cache manifest and ingest-voting contract are required. | Medium. | Keep | -| 10 GB cache | Includes imagery, manifests, overviews, descriptors unless split | Plausible at 0.5 m/px with compression; 0.3 m/px plus descriptors may exceed unless pruned. | Medium. | Updated | -| Jetson Orin Nano Super | 67 TOPS INT8, 8 GB, 25 W | Official specs support the restriction; thermal throttling remains a risk. | Medium-high. | Keep | -| Test data gap | Sample imagery lacks IMU/ground truth | Public datasets help prototype, but final acceptance needs synchronized representative data. | High. | Updated | - -## Key Findings - -1. Use a hybrid estimator: VO/IMU for frame propagation, satellite/VPR anchors for absolute correction, ESKF covariance as the safety gate. -2. Do not run heavy VPR/re-ranking every frame; invoke it on cold start, VO failure, covariance growth, sharp turns, and disconnected segments. -3. Avoid GPL libraries in production dependencies unless the project accepts GPL obligations. GPL VIO/SLAM tools should be benchmarks or references, not selected production components. -4. The cache must be designed as imagery + metadata + descriptor index, not just raster tiles. -5. ArduPilot Plane SITL and representative camera+IMU data are blocking validation dependencies, but not blockers for solution drafting. - -## Sources - -See `_docs/00_research/01_source_registry.md` for the detailed source list. diff --git a/_docs/00_research/00_question_decomposition.md b/_docs/00_research/00_question_decomposition.md deleted file mode 100644 index 8bdc228..0000000 --- a/_docs/00_research/00_question_decomposition.md +++ /dev/null @@ -1,145 +0,0 @@ -# Question Decomposition - -## Classification - -- **Original question**: Design a GPS-denied onboard localization system for a fixed-wing UAV using a nadir camera, IMU, preloaded satellite imagery, and ArduPilot `GPS_INPUT`. -- **Active mode**: Mode A Phase 2, initial solution research. -- **Research output class**: Technical-component selection. -- **Question type**: Decision support with knowledge organization. -- **Timeliness sensitivity**: High for VPR, embedded AI inference, and MAVLink/ArduPilot integration; medium for geometry and filtering fundamentals. - -## Research Boundary - -| Dimension | Boundary | -|-----------|----------| -| Population | Fixed-wing UAV missions; not multirotor hover workflows. | -| Geography | Eastern/southern Ukraine operational areas east/left of the Dnipro River. | -| Timeframe | Current implementation target with 2024-2026 component evidence where possible. | -| Level | Onboard real-time production system, not offline post-processing. | -| Operating context | 8 h flight, 60 km/h, <=1 km AGL, 3 fps nav camera, Jetson Orin Nano Super, GPS denied/spoofed. | -| Required interfaces | Offline Satellite Service cache in; MAVLink `GPS_INPUT`, QGC telemetry, FDR records, and object-coordinate API out. | -| Non-functional envelope | <400 ms p95, <8 GB shared memory, 10 GB persistent cache target, 64 GB FDR cap, safety covariance and false-position budgets. | - -## Project Constraint Matrix Summary - -| Constraint Area | Binding Constraint | -|-----------------|-------------------| -| Camera | ADTi 20MP 20L V1, APS-C, ~5472 x 3648, fixed nadir, no gimbal stabilization. | -| Sensors | FC IMU/attitude/airspeed/altitude available over MAVLink; original still-image sample lacks synchronized IMU, while Derkachi replay data now provides synchronized IMU and `GLOBAL_POSITION_INT` trajectory. | -| Reference imagery | Offline cache only, 0.5 m/px minimum and 0.3 m/px ideal, freshness gates, no in-flight provider fetch. | -| Runtime | Jetson Orin Nano Super, CUDA/TensorRT available, 25 W thermal envelope. | -| Autopilot | ArduPilot only, v1 emits `GPS_INPUT` only; ODOMETRY intentionally disabled. | -| Storage | No raw frame retention; tiles + FDR only. Descriptor/index storage must be budgeted. | -| Safety | Reject weak anchors, never under-report covariance, fail/degrade honestly in blackout and spoofing. | -| Hard disqualifiers | Per-frame heavy VPR without profiling, runtime dependence on external network, stale-tile confident anchors, GPL production dependency unless licensing is accepted. | - -## Perspectives - -| Perspective | Focus | -|-------------|-------| -| Operator / mission user | Does the system keep the UAV navigable and report honest confidence under spoofing/blackout? | -| Embedded implementer | Can the pipeline fit <400 ms p95 and <8 GB on Jetson with maintainable interfaces? | -| Safety reviewer | Are false-position and cache-poisoning paths gated before they can steer the FC or poison future caches? | -| Field practitioner | Will seasonal agricultural repetition, turns, haze/smoke, and stale imagery break the architecture? | -| Contrarian | Which attractive libraries or SOTA models fail because of licensing, memory, latency, or input mismatch? | - -## Sub-Questions And Query Variants - -1. What architecture bounds drift while GPS is denied? - - fixed-wing UAV GPS-denied satellite image matching visual odometry - - visual odometry satellite imagery accumulated error fixed wing UAV - - monocular VIO aerial navigation scale ambiguity satellite anchor - - GPS spoofed UAV visual inertial navigation covariance failover - -2. Which VO/VIO approach fits one nadir camera + IMU? - - OpenVINS monocular visual inertial odometry Jetson - - ORB-SLAM3 monocular inertial Jetson UAV limitations - - VINS-Fusion fixed wing monocular IMU outdoor aerial - - homography visual odometry nadir UAV IMU fusion - -3. Which satellite retrieval and matching approach fits offline cache + <400 ms? - - aerial visual place recognition survey DINOv2 FAISS - - DINOv2 VLAD aerial VPR embedded memory - - LightGlue SuperPoint DISK ALIKED TensorRT Jetson - - cross-view UAV satellite matching failure modes farmland - -4. How should the estimator and safety modes work? - - ESKF visual inertial GPS denied UAV covariance - - GPS_INPUT horiz_accuracy covariance external GPS ArduPilot - - visual blackout IMU dead reckoning UAV covariance growth - - false position rejection Mahalanobis gate visual localization - -5. What cache format and data contract fit the onboard/Satellite Service boundary? - - COG PMTiles MBTiles offline raster cache embedded - - satellite tile descriptor index storage FAISS PMTiles - - cloud optimized geotiff local update limitations - - PMTiles read only update PostgreSQL/PostGIS-backed raster cache - -6. How should MAVLink output integrate with ArduPilot Plane? - - ArduPilot GPS_INPUT GPS1_TYPE 14 Plane SITL - - pymavlink gps_input_send external GPS example - - MAVSDK GPS_INPUT support raw MAVLink - - ArduPilot EKF GPS glitch spoof failsafe Plane parameters - -7. What validation datasets and tests are needed? - - AerialVL UAV satellite visual localization dataset - - VPAir aerial visual place recognition dataset - - EuRoC MAV visual inertial odometry dataset - - ArduPilot Plane SITL fake GPS spoofing simulation - -## Component Option Search Plan - -| Component Area | Option Families / Candidates | Evidence Needed | -|----------------|------------------------------|-----------------| -| Camera calibration and geometry | OpenCV calibration/homography; custom NumPy geometry; ROS camera pipeline | Official API for intrinsics, distortion, homography, RANSAC; permissive licensing; Jetson compatibility. | -| VO / VIO propagation | OpenVINS, ORB-SLAM3, VINS-Fusion, custom homography+IMU ESKF | Exact monocular+IMU input fit, output pose/covariance, licensing, runtime, initialization behavior. | -| VPR global retrieval | DINOv2-VLAD/AnyLoc, MixVPR/SALAD/SelaVPR, classical NetVLAD/BoW | Aerial benchmark evidence, descriptor size, offline index fit, embedded feasibility. | -| Local cross-domain matching | LightGlue + DISK/ALIKED, SuperPoint+LightGlue, LoFTR/XFeat, SIFT/ORB baseline | Inputs/outputs, match coordinates, license, runtime knobs, TensorRT/Jetson feasibility. | -| Vector index | FAISS CPU/GPU, PostgreSQL/pgvector metadata-assisted search, Annoy/HNSWLIB | Top-K retrieval, saved index, memory/compression knobs, ARM/Jetson feasibility. | -| Estimator | Custom ESKF, factor graph, robot_localization | Covariance output, mode labels, Mahalanobis gates, source-specific update control. | -| Cache/storage | COG, PostgreSQL/PostGIS manifest, PMTiles, MBTiles, raw tile folders | Offline read/update behavior, storage efficiency, metadata/manifest support. | -| MAVLink integration | pymavlink, MAVSDK, MAVProxy bridge | `GPS_INPUT` support, ArduPilot `GPS1_TYPE=14`, telemetry subscriptions, QGC status. | -| FDR | PostgreSQL event index, Parquet export, CBOR segment files | Streaming writes, rollover, compact typed records, replayability. | - -## Completeness Audit - -- **Cost/resources**: covered by Jetson, cache, thermal, and descriptor storage constraints. -- **Legal/licensing**: covered; GPL VIO/SLAM tools are not selected for production. -- **Dependencies**: Satellite Service cache contract, ArduPilot Plane SITL, and synchronized validation data are explicit dependencies. -- **Operating environment**: fixed-wing, altitude, terrain, seasonal/visibility classes, and blackout cases covered. -- **Failure modes**: VO failure, stale tiles, spoofing, blackout, thermal throttling, false anchors, cache poisoning covered. -- **Practitioner concerns**: real-time embedded performance and dataset mismatch covered through survey and benchmark sources. -- **Change over time**: DINOv2/VPR models and Jetson/TensorRT assumptions require version-pinned profiling during implementation. - -## Mode B Round 2 Addendum — User-Requested Technology Check - -### Research Output Class - -Technical-component selection. The addendum verifies two implementation choices before autodev proceeds to planning: - -1. Whether OpenVINS should replace the custom OpenCV-based VO/ESKF direction. -2. Whether DINOv2-VLAD + ALIKED/LightGlue is still the right satellite retrieval and anchor-verification stack. - -### Boundary Clarification - -"Custom OpenCV" is treated as OpenCV for calibration, undistortion, feature geometry, homography/RANSAC, and MRE measurement, plus a project-owned ESKF/mode machine. It is not treated as a naive OpenCV-only replacement for VIO. - -### Additional Query Variants Executed - -- OpenVINS GPL-3 license MSCKF visual inertial odometry documentation monocular IMU 2026 -- OpenVINS visual inertial odometry GPS denied UAV MSCKF limitations monocular high altitude nadir camera -- why not use OpenVINS production GPL ROS dependency visual inertial odometry limitations -- OpenCV license BSD 3-Clause camera calibration findHomography RANSAC documentation 4.x -- custom visual odometry OpenCV homography IMU EKF fixed wing UAV satellite imagery GPS denied 2024 -- DINOv2 VLAD AnyLoc visual place recognition aerial satellite retrieval benchmark 2024 2025 -- DINOv2 VLAD limitations visual place recognition storage compute AnyLoc limitations -- DINOv2 TensorRT Jetson performance issue embedding accuracy visual place recognition -- ALIKED LightGlue license local feature matching aerial image registration 2024 2025 -- ALIKED LightGlue ONNX TensorRT Jetson performance benchmark local feature matching -- aerial visual place recognition survey 2024 runtime memory re-ranking SuperGlue LightGlue satellite UAV retrieval - -### Addendum Conclusion - -OpenVINS is better than a pure custom OpenCV-only VIO implementation, but the production architecture should keep OpenCV as the utility layer and keep the project-owned ESKF/mode machine as the shipped estimator. OpenVINS becomes a mandatory benchmark/reference because it does not own the satellite anchor, spoofing/blackout, source-label, cache-write, and MAVLink semantics required by the acceptance criteria, and GPLv3 remains a production dependency blocker. - -DINOv2-VLAD + CPU-first FAISS + ALIKED/LightGlue remains the preferred anchor stack, with two non-negotiable constraints: retrieval is trigger-based rather than per-frame, and TensorRT/ONNX optimizations are accepted only after descriptor-fidelity and Jetson latency tests. diff --git a/_docs/00_research/01_source_registry.md b/_docs/00_research/01_source_registry.md deleted file mode 100644 index dd2de65..0000000 --- a/_docs/00_research/01_source_registry.md +++ /dev/null @@ -1,419 +0,0 @@ -# Source Registry - -## Source #1 -- **Title**: Visual Odometry in GPS-Denied Zones for Fixed-Wing UAV with Reduced Accumulative Error Based on Satellite Imagery -- **Link**: https://www.mdpi.com/2076-3417/14/16/7420 -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: Currently valid -- **Target Audience**: UAV visual localization researchers/implementers -- **Research Boundary Match**: Full match -- **Summary**: Demonstrates fixed-wing high-altitude monocular VO corrected by satellite imagery; highlights scale ambiguity and accumulated drift. -- **Related Sub-question**: Architecture / drift bounding - -## Source #2 -- **Title**: Visual place recognition for aerial imagery: A survey -- **Link**: https://arxiv.org/abs/2406.00885 -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: Currently valid -- **Target Audience**: Aerial VPR researchers/implementers -- **Research Boundary Match**: Full match -- **Summary**: Reviews aerial VPR, retrieval/re-ranking, overlap/scale effects, memory/runtime issues, and georeference recall. -- **Related Sub-question**: VPR / validation - -## Source #3 -- **Title**: OpenVINS documentation -- **Link**: https://docs.openvins.com/ -- **Tier**: L1 -- **Publication Date**: 2023 latest noted release -- **Timeliness Status**: Needs verification before implementation -- **Target Audience**: VIO researchers/implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: OpenVINS is an EKF/MSCKF visual-inertial estimator supporting monocular tracking, calibration, evaluation, and covariance-aware estimation; GPL-3 license. -- **Related Sub-question**: VO/VIO - -## Source #4 -- **Title**: ORB-SLAM3 README -- **Link**: https://raw.githubusercontent.com/UZ-SLAMLab/ORB_SLAM3/master/README.md -- **Tier**: L1 -- **Publication Date**: 2021 README, still repository source -- **Timeliness Status**: Needs verification before implementation -- **Target Audience**: SLAM implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: ORB-SLAM3 supports monocular visual-inertial SLAM and multi-map operation, requires calibration, and is GPLv3. -- **Related Sub-question**: VO/VIO alternatives - -## Source #5 -- **Title**: OpenCV 4.x documentation via Context7 -- **Link**: https://docs.opencv.org/4.x/ -- **Tier**: L1 -- **Publication Date**: Current docs, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: Computer vision implementers -- **Research Boundary Match**: Full match for utility layer -- **Summary**: Documents camera calibration, undistortion, and `findHomography` with RANSAC for robust geometry. -- **Related Sub-question**: Calibration / geometry - -## Source #6 -- **Title**: LightGlue README and Context7 docs -- **Link**: https://raw.githubusercontent.com/cvg/LightGlue/main/README.md -- **Tier**: L1 -- **Publication Date**: Current repository, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: Feature-matching implementers -- **Research Boundary Match**: Full match for local matching -- **Summary**: LightGlue accepts local keypoints/descriptors and returns matched coordinates/scores; supports SuperPoint, DISK, ALIKED, SIFT, adaptive pruning, CUDA, and Apache-2 for code/weights while SuperPoint has restrictive licensing. -- **Related Sub-question**: Local matching - -## Source #7 -- **Title**: AnyLoc README -- **Link**: https://github.com/AnyLoc/AnyLoc -- **Tier**: L1 -- **Publication Date**: 2023 repository, accessed 2026-05-01 -- **Timeliness Status**: Needs profiling verification -- **Target Audience**: VPR implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: Provides DINOv2 + VLAD API examples and notes substantial storage/compute requirements for full experiments. -- **Related Sub-question**: VPR descriptors - -## Source #8 -- **Title**: DINOv2 repository -- **Link**: https://github.com/facebookresearch/dinov2 -- **Tier**: L1 -- **Publication Date**: 2023 repository, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: Vision model implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: Meta's DINOv2 implementation and models, Apache-2.0 / CC-BY-4.0 license notices. -- **Related Sub-question**: VPR descriptors - -## Source #9 -- **Title**: FAISS documentation and Context7 docs -- **Link**: https://faiss.ai/index.html -- **Tier**: L1 -- **Publication Date**: Current docs, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: Vector search implementers -- **Research Boundary Match**: Full match -- **Summary**: FAISS supports dense vector search, top-k retrieval, CPU/GPU indexes, product quantization, and save/load APIs; GPU indexes must be converted to CPU before saving. -- **Related Sub-question**: Descriptor retrieval - -## Source #10 -- **Title**: MAVSDK documentation via Context7 -- **Link**: https://github.com/mavlink/mavsdk -- **Tier**: L1 -- **Publication Date**: Current docs, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: MAVLink application implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: MAVSDK provides telemetry APIs including raw GPS, GPS info, status text, position/velocity, and odometry subscriptions; `GPS_INPUT` emission should use raw MAVLink/pymavlink for this project. -- **Related Sub-question**: MAVLink integration - -## Source #11 -- **Title**: ArduPilot MAVProxy GPSInput -- **Link**: https://ardupilot.org/mavproxy/docs/modules/GPSInput.html -- **Tier**: L1 -- **Publication Date**: Current docs, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: ArduPilot integrators -- **Research Boundary Match**: Full match -- **Summary**: External GPS input requires `GPS1_TYPE=14` and accepts MAVLink `GPS_INPUT` fields including WGS84 lat/lon, velocity, fix type, and accuracy. -- **Related Sub-question**: MAVLink output - -## Source #12 -- **Title**: MAVLink common message spec: GPS_INPUT -- **Link**: https://mavlink.io/en/messages/common.html#GPS_INPUT -- **Tier**: L1 -- **Publication Date**: Current spec, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: MAVLink implementers -- **Research Boundary Match**: Full match -- **Summary**: Defines `GPS_INPUT` fields, fix type semantics, `horiz_accuracy`, and ignore flags. -- **Related Sub-question**: MAVLink output / confidence - -## Source #13 -- **Title**: ArduPilot GPS failsafe and glitch protection -- **Link**: https://ardupilot.org/copter/docs/gps-failsafe-glitch-protection.html -- **Tier**: L1 -- **Publication Date**: Current docs, accessed 2026-05-01 -- **Timeliness Status**: Reference only for Plane -- **Target Audience**: ArduPilot operators -- **Research Boundary Match**: Partial overlap -- **Summary**: Documents GPS glitch protection and notes inertial-only position degrades quickly; Copter-specific defaults must not be assumed for Plane. -- **Related Sub-question**: Failsafe / spoofing - -## Source #14 -- **Title**: ArduPilot EKF failsafe -- **Link**: https://ardupilot.org/copter/docs/ekf-inav-failsafe.html -- **Tier**: L1 -- **Publication Date**: Current docs, accessed 2026-05-01 -- **Timeliness Status**: Reference only for Plane -- **Target Audience**: ArduPilot operators -- **Research Boundary Match**: Partial overlap -- **Summary**: Explains EKF variance failsafe behavior and why spoof/glitch tests must be parameterized. -- **Related Sub-question**: Failsafe / spoofing - -## Source #15 -- **Title**: Jetson Orin Nano Super Developer Kit -- **Link**: https://www.nvidia.com/en-us/autonomous-machines/embedded-systems/jetson-orin/nano-super-developer-kit/ -- **Tier**: L1 -- **Publication Date**: Current page, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: Embedded AI implementers -- **Research Boundary Match**: Full match -- **Summary**: Confirms 67 INT8 TOPS, 8 GB LPDDR5, 102 GB/s, and 7-25 W power range. -- **Related Sub-question**: Runtime - -## Source #16 -- **Title**: NVIDIA JetPack 6.2 Super Mode blog -- **Link**: https://developer.nvidia.com/blog/nvidia-jetpack-6-2-brings-super-mode-to-nvidia-jetson-orin-nano-and-jetson-orin-nx-modules/ -- **Tier**: L2 -- **Publication Date**: 2024 -- **Timeliness Status**: Currently valid -- **Target Audience**: Jetson developers -- **Research Boundary Match**: Full match -- **Summary**: Explains 25 W and MAXN Super modes and warns thermal design must accommodate the new power modes or throttling occurs. -- **Related Sub-question**: Runtime / thermal - -## Source #17 -- **Title**: PMTiles Concepts -- **Link**: https://docs.protomaps.com/pmtiles/ -- **Tier**: L1 -- **Publication Date**: Current docs, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: Geospatial storage implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: PMTiles is single-file tiled archive, efficient for reads, but read-only and not update-in-place. -- **Related Sub-question**: Cache storage - -## Source #18 -- **Title**: GDAL COG driver -- **Link**: https://gdal.org/en/stable/drivers/raster/cog.html -- **Tier**: L1 -- **Publication Date**: Current docs, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: Geospatial raster implementers -- **Research Boundary Match**: Full match -- **Summary**: Defines COG creation options for tiled, compressed, overview-enabled GeoTIFFs. -- **Related Sub-question**: Cache storage - -## Source #19 -- **Title**: AerialVL dataset -- **Link**: https://github.com/hmf21/AerialVL -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: Currently valid -- **Target Audience**: Aerial visual localization researchers -- **Research Boundary Match**: Partial overlap -- **Summary**: Public aerial localization benchmark with UAV sequences, reference maps, and geo-referenced evaluation data. -- **Related Sub-question**: Validation - -## Source #20 -- **Title**: EuRoC MAV Dataset -- **Link**: http://projects.asl.ethz.ch/datasets/euroc-mav/ -- **Tier**: L1 -- **Publication Date**: 2016 -- **Timeliness Status**: Stable benchmark -- **Target Audience**: VIO researchers -- **Research Boundary Match**: Partial overlap -- **Summary**: Stereo camera + IMU + ground truth benchmark useful for VIO sanity tests but not representative of high-altitude nadir fixed-wing imagery. -- **Related Sub-question**: Validation - -## Source #21 -- **Title**: NVIDIA/TensorRT issue: DINOv2 TensorRT performance/precision on Jetson -- **Link**: https://github.com/NVIDIA/TensorRT/issues/4348 -- **Tier**: L4 -- **Publication Date**: 2024 -- **Timeliness Status**: Needs verification -- **Target Audience**: Jetson/TensorRT implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: Reports limited mixed-precision gains for DINOv2-S on Jetson/RTX, suggesting DINOv2 optimization is not automatically beneficial. -- **Related Sub-question**: Mode B performance risk - -## Source #22 -- **Title**: NVIDIA Developer Forum: DINOv2 TensorRT model performance issue -- **Link**: https://forums.developer.nvidia.com/t/dinov2-tensorrt-model-performance-issue/312251 -- **Tier**: L4 -- **Publication Date**: 2024 -- **Timeliness Status**: Needs verification -- **Target Audience**: Jetson/TensorRT implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: Reports DINOv2 embedding distance changes after TensorRT conversion on Jetson Orin Nano; requires embedding-fidelity validation before relying on TensorRT descriptors. -- **Related Sub-question**: Mode B performance/quality risk - -## Source #23 -- **Title**: LightGlue license issue discussions -- **Link**: https://github.com/cvg/LightGlue/issues/120 -- **Tier**: L4 -- **Publication Date**: 2024 -- **Timeliness Status**: Currently relevant -- **Target Audience**: Feature-matching implementers -- **Research Boundary Match**: Full match for licensing -- **Summary**: Community discussion highlights restrictive SuperPoint licensing inside the LightGlue ecosystem and supports avoiding SuperPoint as default production extractor. -- **Related Sub-question**: Mode B licensing risk - -## Source #24 -- **Title**: ArduPilot issue: GPS_INPUT velocity ignore flag pitfall -- **Link**: https://github.com/ArduPilot/ardupilot/issues/19633 -- **Tier**: L4 -- **Publication Date**: 2021 -- **Timeliness Status**: Needs SITL verification -- **Target Audience**: ArduPilot integrators -- **Research Boundary Match**: Full match for GPS_INPUT caution -- **Summary**: Reports EKF3 may use zero velocity when `GPS_INPUT_IGNORE_FLAG_VEL_HORIZ` is set, so velocity-source parameters must be tested rather than relying only on ignore flags. -- **Related Sub-question**: Mode B MAVLink pitfall - -## Source #25 -- **Title**: FAISS install documentation -- **Link**: https://github.com/facebookresearch/faiss/blob/main/INSTALL.md -- **Tier**: L1 -- **Publication Date**: Current docs, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: Vector search implementers -- **Research Boundary Match**: Full match -- **Summary**: FAISS CPU conda package supports aarch64, while GPU package availability is x86-64 focused; Jetson design should assume CPU FAISS unless a custom build is proven. -- **Related Sub-question**: Mode B FAISS deployment - -## Source #26 -- **Title**: GNSS-denied geolocalization of UAVs by visual matching of onboard camera images with orthophotos -- **Link**: https://ar5iv.labs.arxiv.org/html/2103.14381 -- **Tier**: L1 -- **Publication Date**: 2021 -- **Timeliness Status**: Stable mechanism reference -- **Target Audience**: UAV visual geolocalization researchers -- **Research Boundary Match**: Partial overlap -- **Summary**: Demonstrates visual matching with orthophotos and Monte Carlo/local planarity ideas; supports using orthorectified reference maps but does not cover all adversarial visual attacks. -- **Related Sub-question**: Mode B alternative / security limits - -## Source #27 -- **Title**: OpenVINS LICENSE -- **Link**: https://github.com/rpng/open_vins/blob/master/LICENSE -- **Tier**: L1 -- **Publication Date**: Current repository, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: VIO implementers / product owners -- **Research Boundary Match**: Full match for licensing -- **Summary**: OpenVINS is GPLv3-licensed; this is a production dependency constraint, not a technical capability limitation. -- **Related Sub-question**: Mode B round 2 — OpenVINS vs custom production estimator - -## Source #28 -- **Title**: OpenVINS documentation and Context7 lookup -- **Link**: https://docs.openvins.com/index.html -- **Tier**: L1 -- **Publication Date**: Current docs, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: VIO implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: OpenVINS is a strong EKF/MSCKF VIO system for monocular camera + IMU reference runs, with calibration and covariance-aware state estimation, but it does not own the project-specific satellite anchor, GPS_INPUT, source-label, spoofing, blackout, and cache-poisoning state machine. -- **Related Sub-question**: Mode B round 2 — OpenVINS vs custom production estimator - -## Source #29 -- **Title**: OpenCV 4.x calibration/homography documentation and Context7 lookup -- **Link**: https://docs.opencv.org/4.x/ -- **Tier**: L1 -- **Publication Date**: Current docs, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: Computer vision implementers -- **Research Boundary Match**: Full match for geometry utility layer -- **Summary**: OpenCV 4.x provides calibration, undistortion, homography estimation, RANSAC/USAC robust estimation, and reprojection-error primitives under a permissive license; it is a utility layer rather than a complete GPS-denied estimator. -- **Related Sub-question**: Mode B round 2 — custom OpenCV boundary - -## Source #30 -- **Title**: AnyLoc: Towards Universal Visual Place Recognition -- **Link**: https://arxiv.org/html/2308.00688 -- **Tier**: L1 -- **Publication Date**: 2023; ICRA 2024 -- **Timeliness Status**: Currently valid, profiling required before deployment -- **Target Audience**: VPR implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: AnyLoc combines DINOv2 features with VLAD aggregation for broad VPR, including aerial data, and supports the selected DINOv2-VLAD retrieval family while leaving runtime/storage tuning as a deployment gate. -- **Related Sub-question**: Mode B round 2 — satellite retrieval - -## Source #31 -- **Title**: ALIKED-LightGlue-ONNX and LightGlue ONNX/TensorRT deployment reports -- **Link**: https://github.com/ikeboo/ALIKED-LightGlue-ONNX -- **Tier**: L2 -- **Publication Date**: Current repository, accessed 2026-05-01 -- **Timeliness Status**: Promising but needs Jetson verification -- **Target Audience**: Local feature matching implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: ONNX/optimized variants show a credible deployment path for ALIKED + LightGlue, but public evidence is not enough to assume Jetson Orin Nano p95 latency without project profiling. -- **Related Sub-question**: Mode B round 2 — local matcher deployability - -## Source #32 -- **Title**: Visual place recognition for aerial imagery: A survey -- **Link**: https://arxiv.org/abs/2406.00885 -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: Currently valid -- **Target Audience**: Aerial VPR researchers / implementers -- **Research Boundary Match**: Full match -- **Summary**: Aerial VPR performance depends materially on tile scale, overlap, weather, repetitive patterns, and re-ranking cost; this supports overlapped VPR chunks, dynamic top-K, and conditional local verification. -- **Related Sub-question**: Mode B round 2 — satellite retrieval and anchor verification - -## Source #33 -- **Title**: BASALT repository and documentation -- **Link**: https://github.com/VladyslavUsenko/basalt -- **Tier**: L1 -- **Publication Date**: Current repository, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: VIO implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: BASALT provides visual-inertial odometry and mapping, camera/IMU calibration tools, EuRoC/TUM VI support, and a BSD-style production-friendly licensing path. -- **Related Sub-question**: Mode B round 3 — Kimera vs BASALT vs OpenVINS - -## Source #34 -- **Title**: HybVIO: Pushing the Limits of Real-time Visual-inertial Odometry -- **Link**: https://arxiv.org/pdf/2106.11857 -- **Tier**: L1 -- **Publication Date**: 2021 -- **Timeliness Status**: Stable benchmark reference -- **Target Audience**: VIO researchers / embedded implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: Reports EuRoC RMS ATE comparisons including BASALT mean about 0.051 m online stereo and Kimera mean about 0.12 m, plus notes that optimization-based methods often lack direct uncertainty quantification compared with filters. -- **Related Sub-question**: Mode B round 3 — VIO error and confidence comparison - -## Source #35 -- **Title**: OpenVINS issue #402 — up-to-date ATE and RTE metrics -- **Link**: https://github.com/rpng/open_vins/issues/402 -- **Tier**: L4 -- **Publication Date**: 2024 -- **Timeliness Status**: Community benchmark, verify in our replay harness -- **Target Audience**: VIO implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: Community EuRoC comparison reports BASALT average ATE about 0.072 m with 100% completion, and OpenVINS average ATE about 0.091 m with about 88.55% completion and a divergence on one hard sequence. -- **Related Sub-question**: Mode B round 3 — BASALT vs OpenVINS error/completion - -## Source #36 -- **Title**: Kimera-VIO mono-inertial parameter issues -- **Link**: https://github.com/MIT-SPARK/Kimera-VIO/issues/254 -- **Tier**: L4 -- **Publication Date**: 2024 -- **Timeliness Status**: Relevant implementation caveat -- **Target Audience**: VIO implementers -- **Research Boundary Match**: Partial overlap -- **Summary**: Kimera-VIO stereo path remains strong, but mono-inertial configurations had documented poor default performance; parameter changes improved one EuRoC mono setup to less than about +/-0.2 m per axis. -- **Related Sub-question**: Mode B round 3 — Kimera mono/nadir risk - -## Source #37 -- **Title**: RaD-VIO and downward-facing VIO literature -- **Link**: https://arxiv.org/abs/1810.08704 -- **Tier**: L1 -- **Publication Date**: 2018 -- **Timeliness Status**: Stable mechanism reference -- **Target Audience**: MAV downward-camera VIO researchers -- **Research Boundary Match**: Full match for nadir-camera caveat -- **Summary**: Downward-facing monocular VIO has planar-scene and observability challenges; range/altitude and IMU constraints are important when the camera sees mostly ground plane. -- **Related Sub-question**: Mode B round 3 — nadir support and limitations - -## Source #38 -- **Title**: OpenVINS covariance documentation and StateHelper APIs -- **Link**: https://docs.openvins.com/dev-index.html -- **Tier**: L1 -- **Publication Date**: Current docs, accessed 2026-05-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: VIO implementers -- **Research Boundary Match**: Full match for covariance/confidence output -- **Summary**: OpenVINS maintains EKF covariance and exposes full/marginal covariance helpers, making it the strongest reference for covariance consistency even if GPLv3 blocks default production use. -- **Related Sub-question**: Mode B round 3 — confidence/covariance support diff --git a/_docs/00_research/02_fact_cards.md b/_docs/00_research/02_fact_cards.md deleted file mode 100644 index d6935f6..0000000 --- a/_docs/00_research/02_fact_cards.md +++ /dev/null @@ -1,348 +0,0 @@ -# Fact Cards - -## Fact #1 -- **Statement**: Fixed-wing high-altitude monocular VO suffers from scale ambiguity and accumulated error; comparing against satellite imagery can reduce accumulated drift. -- **Source**: Source #1 -- **Phase**: Phase 2 -- **Target Audience**: UAV localization implementers -- **Confidence**: High -- **Related Dimension**: Architecture -- **Fit Impact**: Supports satellite-anchored hybrid estimator. - -## Fact #2 -- **Statement**: Aerial VPR is sensitive to weather, season, scale variation, repetitive patterns, and map tile construction; overlap and scale level materially affect retrieval quality. -- **Source**: Source #2 -- **Confidence**: High -- **Related Dimension**: VPR -- **Fit Impact**: Supports AC-8.6 VPR chunks with overlap and seasonal validation. - -## Fact #3 -- **Statement**: Heavy VPR re-ranking can be too slow for steady-state embedded use; survey evidence reports some re-ranking around 1 s and SuperGlue much slower on evaluated hardware. -- **Source**: Source #2 -- **Confidence**: High -- **Related Dimension**: Runtime -- **Fit Impact**: Disqualifies per-frame global VPR/re-ranking unless profiled on Jetson. - -## Fact #4 -- **Statement**: OpenVINS is an EKF/MSCKF visual-inertial estimator with monocular tracking and calibration support, but its code is GPL-3. -- **Source**: Source #3 -- **Confidence**: High -- **Related Dimension**: VO/VIO -- **Fit Impact**: Reference/benchmark only unless GPL obligations are accepted. - -## Fact #5 -- **Statement**: ORB-SLAM3 supports monocular visual-inertial SLAM and multi-map operation, but it is GPLv3 and expects careful calibration and a SLAM-style runtime stack. -- **Source**: Source #4 -- **Confidence**: High -- **Related Dimension**: VO/VIO -- **Fit Impact**: Rejected as production dependency; useful benchmark/reference. - -## Fact #6 -- **Statement**: OpenCV provides camera calibration APIs that output camera matrix and distortion coefficients, and homography estimation APIs including RANSAC. -- **Source**: Source #5 -- **Confidence**: High -- **Related Dimension**: Calibration / geometry -- **Fit Impact**: Selected utility layer for calibration, undistortion, homography, and geometric validation. - -## Fact #7 -- **Statement**: LightGlue accepts local keypoints/descriptors from extractors such as DISK, ALIKED, SIFT, and SuperPoint, and returns matched keypoint indices, coordinates, and confidence scores. -- **Source**: Source #6 -- **Confidence**: High -- **Related Dimension**: Local matching -- **Fit Impact**: Selected candidate for conditional cross-domain local matching. - -## Fact #8 -- **Statement**: LightGlue has adaptive depth/width pruning, FlashAttention, mixed precision, and benchmark scripts; runtime must be profiled on Jetson because defaults are optimized for desktop GPUs. -- **Source**: Source #6 -- **Confidence**: High -- **Related Dimension**: Runtime -- **Fit Impact**: Selected with runtime-quality gate. - -## Fact #9 -- **Statement**: LightGlue code/weights are Apache-2.0, but SuperPoint pretrained weights/inference have restrictive licensing; DISK and ALIKED are safer extractor pairings from a licensing perspective. -- **Source**: Source #6 -- **Confidence**: High -- **Related Dimension**: Licensing -- **Fit Impact**: Select DISK/ALIKED+LightGlue for production candidate; treat SuperPoint as license-gated. - -## Fact #10 -- **Statement**: AnyLoc provides DINOv2 feature extraction and VLAD aggregation APIs, but its full experiment setup notes large storage/compute requirements. -- **Source**: Source #7 -- **Confidence**: High -- **Related Dimension**: VPR descriptors -- **Fit Impact**: DINOv2-VLAD selected as offline/conditional retrieval candidate, not unconditional per-frame path. - -## Fact #11 -- **Statement**: DINOv2 official repository provides Meta's DINOv2 implementation and model assets with Apache-2.0 / CC-BY-4.0 license notices. -- **Source**: Source #8 -- **Confidence**: High -- **Related Dimension**: VPR descriptors -- **Fit Impact**: Supports DINOv2 as a permissible descriptor backbone subject to model-license review. - -## Fact #12 -- **Statement**: FAISS is designed for efficient dense vector similarity search, top-k nearest-neighbor retrieval, speed/accuracy tradeoffs, and indexes too large for simple exhaustive scanning. -- **Source**: Source #9 -- **Confidence**: High -- **Related Dimension**: Descriptor retrieval -- **Fit Impact**: Selected vector index for offline VPR descriptors. - -## Fact #13 -- **Statement**: FAISS supports saving/loading indexes; GPU indexes must be converted to CPU before saving. -- **Source**: Source #9 -- **Confidence**: High -- **Related Dimension**: Cache lifecycle -- **Fit Impact**: Supports install-time/index-build flow with runtime load. - -## Fact #14 -- **Statement**: MAVSDK provides telemetry subscriptions for raw GPS, GPS info, status text, odometry, and position/velocity; it does not remove the need for raw MAVLink control over `GPS_INPUT` emission. -- **Source**: Source #10 -- **Confidence**: High -- **Related Dimension**: MAVLink integration -- **Fit Impact**: Select MAVSDK for telemetry, pymavlink/raw MAVLink for `GPS_INPUT`. - -## Fact #15 -- **Statement**: ArduPilot GPSInput requires `GPS1_TYPE=14` for MAVLink GPS input. -- **Source**: Source #11 -- **Confidence**: High -- **Related Dimension**: MAVLink output -- **Fit Impact**: Confirms production parameter requirement. - -## Fact #16 -- **Statement**: `GPS_INPUT` carries WGS84 lat/lon, MSL altitude, velocity, `fix_type`, `horiz_accuracy`, `vert_accuracy`, `speed_accuracy`, and ignore flags. -- **Source**: Source #12 -- **Confidence**: High -- **Related Dimension**: Output contract -- **Fit Impact**: Supports mapping estimator covariance to `horiz_accuracy` and failover fix types. - -## Fact #17 -- **Statement**: ArduPilot GPS glitch protection and EKF failsafe behavior are parameterized and vehicle-specific; Copter docs are not enough to prove Plane behavior. -- **Source**: Sources #13, #14 -- **Confidence**: High -- **Related Dimension**: Failsafe -- **Fit Impact**: Requires ArduPilot Plane SITL validation. - -## Fact #18 -- **Statement**: Jetson Orin Nano Super provides 67 INT8 TOPS, 8 GB memory, 102 GB/s bandwidth, and 7-25 W power range. -- **Source**: Source #15 -- **Confidence**: High -- **Related Dimension**: Runtime -- **Fit Impact**: Confirms target platform constraint. - -## Fact #19 -- **Statement**: NVIDIA warns Super power modes require thermal design that can handle the power modes; otherwise throttling can reduce performance. -- **Source**: Source #16 -- **Confidence**: High -- **Related Dimension**: Thermal -- **Fit Impact**: Supports AC-NEW-5 hot-soak and throttle logging. - -## Fact #20 -- **Statement**: PMTiles is efficient for single-file tile reads but is read-only and cannot be updated in place. -- **Source**: Source #17 -- **Confidence**: High -- **Related Dimension**: Cache storage -- **Fit Impact**: Rejected for mutable onboard tile writes; possible export/package format only. - -## Fact #21 -- **Statement**: COG supports tiled, compressed, overview-enabled GeoTIFFs suitable for efficient raster access and geospatial tooling. -- **Source**: Source #18 -- **Confidence**: High -- **Related Dimension**: Cache storage -- **Fit Impact**: Selected imagery storage unit for immutable service tiles and generated candidate tiles. - -## Fact #22 -- **Statement**: AerialVL provides aerial visual localization sequences, reference maps, and geo-referenced evaluation data. -- **Source**: Source #19 -- **Confidence**: Medium -- **Related Dimension**: Validation -- **Fit Impact**: Selected validation dataset for VPR/satellite-anchor algorithm development. - -## Fact #23 -- **Statement**: EuRoC provides synchronized camera/IMU and ground truth for VIO, but it is not representative of high-altitude fixed-wing nadir imagery. -- **Source**: Source #20 -- **Confidence**: High -- **Related Dimension**: Validation -- **Fit Impact**: Use for VIO sanity checks only, not final AC proof. - -## MVE Evidence - -### MVE — OpenCV calibration and homography utilities -- **Source**: Source #5 -- **Pinned mode/config**: Use OpenCV 4.x C++/Python APIs for checkerboard calibration, undistortion, homography estimation with RANSAC, and reprojection-error measurement. -- **Inputs in example**: Object/image point correspondences, image size, matched keypoints. -- **Outputs in example**: Camera matrix, distortion coefficients, rotation/translation vectors, homography matrix. -- **Project inputs**: ADTi nav-camera frames, checkerboard calibration images, matched VO/satellite points. -- **Project outputs required**: Intrinsics/distortion, homography, inlier mask, MRE. -- **Match assessment**: Exact match. - -### MVE — LightGlue in DISK/ALIKED local-matching mode -- **Source**: Source #6 -- **Pinned mode/config**: Use DISK+LightGlue or ALIKED+LightGlue on CUDA/TensorRT-profiled Jetson path, with inputs two normalized images and outputs matched keypoint coordinates plus confidence scores. -- **Inputs in example**: Two images loaded to GPU; local features extracted by DISK/ALIKED/SuperPoint. -- **Outputs in example**: `matches` shape `(K, 2)`, keypoint coordinates in each image, confidence scores. -- **Project inputs**: Orthorectified nav frame crop and candidate satellite/VPR chunk. -- **Project outputs required**: 2D-2D correspondences for RANSAC homography and cross-domain MRE. -- **Match assessment**: Exact interface match; runtime quality gate remains. - -### MVE — FAISS top-K VPR retrieval -- **Source**: Source #9 -- **Pinned mode/config**: Use FAISS CPU index with optional GPU acceleration for top-K nearest neighbor search over precomputed DINOv2/VLAD descriptors, saved/loaded at install/preflight time. -- **Inputs in example**: Float32 descriptor matrix, query descriptor, `k`. -- **Outputs in example**: Distance matrix `D` and index matrix `I`. -- **Project inputs**: Precomputed VPR chunk descriptors, query frame descriptor. -- **Project outputs required**: Top-K candidate chunk IDs for local matching. -- **Match assessment**: Exact match. - -### MVE — MAVSDK telemetry + pymavlink GPS_INPUT -- **Source**: Sources #10, #11, #12 -- **Pinned mode/config**: Use MAVSDK for telemetry subscriptions and pymavlink/raw MAVLink for `GPS_INPUT` emission to ArduPilot with `GPS1_TYPE=14`. -- **Inputs in example**: Telemetry streams, estimator lat/lon/alt/velocity/covariance. -- **Outputs in example**: `GPS_INPUT` fields accepted by ArduPilot GPS backend. -- **Project inputs**: ESKF state and covariance, source label, mode/fix quality. -- **Project outputs required**: Frame-by-frame WGS84 `GPS_INPUT`, status text, FDR record. -- **Match assessment**: Exact match for output contract; Plane SITL validation remains. - -## Mode B Findings - -### Fact #24 -- **Statement**: DINOv2 TensorRT optimization on Jetson may provide limited speedup and can change embedding distances; descriptor fidelity must be tested against the PyTorch/ONNX baseline before selecting a TensorRT descriptor path. -- **Source**: Sources #21, #22 -- **Phase**: Mode B -- **Confidence**: Medium -- **Related Dimension**: VPR runtime / quality -- **Fit Impact**: Adds embedding-fidelity gate; keeps DINOv2 selected only after profiling. - -### Fact #25 -- **Statement**: LightGlue's SuperPoint path has documented license concerns; DISK/ALIKED remain the safer production default unless legal review approves SuperPoint. -- **Source**: Source #23 -- **Phase**: Mode B -- **Confidence**: High -- **Related Dimension**: Licensing -- **Fit Impact**: Confirms draft01 decision to avoid SuperPoint as default. - -### Fact #26 -- **Statement**: ArduPilot `GPS_INPUT_IGNORE_FLAG_VEL_HORIZ` has a reported EKF3 pitfall where velocity may become zero rather than truly ignored; SITL must validate velocity-source parameters and message fields. -- **Source**: Source #24 -- **Phase**: Mode B -- **Confidence**: Medium -- **Related Dimension**: MAVLink integration -- **Fit Impact**: Adds a specific MAVLink test and parameter gate. - -### Fact #27 -- **Statement**: FAISS deployment on Jetson ARM64 should assume CPU FAISS by default; GPU FAISS packages are not the safe default on aarch64. -- **Source**: Source #25 -- **Phase**: Mode B -- **Confidence**: Medium -- **Related Dimension**: Descriptor retrieval runtime -- **Fit Impact**: Changes FAISS pinned mode from CPU with optional GPU to CPU-first, with custom GPU build only as future optimization. - -### Fact #28 -- **Statement**: Visual matching with orthophotos is a known GNSS-denied UAV approach, but available sources do not prove robustness against adversarial visual attacks on imagery/cache content. -- **Source**: Source #26 -- **Phase**: Mode B -- **Confidence**: Medium -- **Related Dimension**: Security -- **Fit Impact**: Adds cache integrity, signed manifests, and consistency checks as required controls. - -### Fact #29 -- **Statement**: COG creation is a write-new-object workflow; the live onboard cache should append/replace tile objects through manifests, not mutate a COG in place. -- **Source**: Source #18 -- **Phase**: Mode B -- **Confidence**: High -- **Related Dimension**: Cache lifecycle -- **Fit Impact**: Clarifies cache implementation. - -### Fact #30 -- **Statement**: OpenVINS is technically stronger than a pure hand-rolled OpenCV-only VIO stack for camera+IMU odometry, but its GPLv3 license and generic VIO lifecycle make it unsuitable as the default production dependency for this product. -- **Source**: Sources #27, #28 -- **Phase**: Mode B round 2 -- **Confidence**: High -- **Related Dimension**: VO / VIO selection -- **Fit Impact**: Use OpenVINS as a mandatory benchmark/reference, not as the shipped estimator dependency unless GPL obligations are explicitly accepted. - -### Fact #31 -- **Statement**: The selected production estimator is not "custom OpenCV-only"; OpenCV is the geometry utility layer, while the product-owned ESKF/mode machine owns covariance, source labels, GPS spoofing, blackout, tile-write eligibility, and MAVLink semantics. -- **Source**: Sources #5, #29; AC-1.4, AC-3.5, AC-4.3, AC-NEW-4, AC-NEW-7, AC-NEW-8 -- **Phase**: Mode B round 2 -- **Confidence**: High -- **Related Dimension**: Estimator ownership -- **Fit Impact**: Keep custom production estimator, but reject any interpretation that means building a naive OpenCV-only VIO stack. - -### Fact #32 -- **Statement**: Fixed-wing GPS-denied UAV research supports a hybrid of visual odometry plus satellite/orthophoto matching to reduce accumulated drift, matching the project architecture better than a standalone VIO-only solution. -- **Source**: Sources #1, #26 -- **Phase**: Mode B round 2 -- **Confidence**: High -- **Related Dimension**: Architecture -- **Fit Impact**: Confirms that OpenVINS alone cannot satisfy the absolute-position and re-anchor responsibilities without the satellite anchor path. - -### Fact #33 -- **Statement**: DINOv2-VLAD/AnyLoc-style retrieval is a strong global candidate generator for aerial VPR, but descriptor size, model size, and environment-specific VLAD/index choices must be budgeted and profiled. -- **Source**: Sources #7, #30, #32 -- **Phase**: Mode B round 2 -- **Confidence**: High -- **Related Dimension**: Satellite retrieval -- **Fit Impact**: Select DINOv2-VLAD for triggered retrieval, not steady-state per-frame execution. - -### Fact #34 -- **Statement**: Aerial VPR sources emphasize tile/chunk scale, overlap, weather/season changes, repetitive patterns, and re-ranking cost; local matching should be a verification/rerank stage over bounded top-K candidates. -- **Source**: Source #32 -- **Phase**: Mode B round 2 -- **Confidence**: High -- **Related Dimension**: Anchor verification -- **Fit Impact**: Supports VPR chunks with 40-50% overlap, dynamic K, and conditional ALIKED/LightGlue verification. - -### Fact #35 -- **Statement**: ALIKED + LightGlue has an exact local matching interface and a plausible ONNX/TensorRT deployment path, but public evidence does not prove Jetson Orin Nano p95 latency for the project image sizes. -- **Source**: Sources #6, #31 -- **Phase**: Mode B round 2 -- **Confidence**: Medium -- **Related Dimension**: Local matching runtime -- **Fit Impact**: Keep ALIKED/LightGlue selected with runtime gate; benchmark DISK and SIFT/ORB as fallbacks. - -### Fact #36 -- **Statement**: DINOv2 TensorRT conversion can reduce embedding discrimination and may not provide meaningful speedup on Jetson-class devices; descriptor-fidelity tests must precede any optimized engine acceptance. -- **Source**: Source #22 -- **Phase**: Mode B round 2 -- **Confidence**: Medium -- **Related Dimension**: VPR deployment -- **Fit Impact**: TensorRT is an optimization candidate only after PyTorch/ONNX retrieval-rank equivalence is proven. - -### Fact #37 -- **Statement**: BASALT is the best production VIO candidate among BASALT, OpenVINS, and Kimera-VIO because it combines permissive licensing with strong published EuRoC accuracy and completion evidence. -- **Source**: Sources #33, #34, #35 -- **Phase**: Mode B round 3 -- **Confidence**: Medium -- **Related Dimension**: VO / VIO selection -- **Fit Impact**: Select BASALT as the production VIO candidate, pending project replay/profiling. - -### Fact #38 -- **Statement**: OpenVINS has the clearest EKF covariance story, including full/marginal covariance helpers and NEES-style evaluation support, but remains production-constrained by GPLv3. -- **Source**: Sources #27, #28, #38 -- **Phase**: Mode B round 3 -- **Confidence**: High -- **Related Dimension**: Confidence / covariance -- **Fit Impact**: Keep OpenVINS as covariance/reference baseline and use it to calibrate the BASALT wrapper's reported uncertainty. - -### Fact #39 -- **Statement**: Kimera-VIO is production-friendly from a license standpoint, but it is heavier/stereo-oriented and has documented mono-inertial parameter/performance caveats. -- **Source**: Sources #34, #36 -- **Phase**: Mode B round 3 -- **Confidence**: Medium -- **Related Dimension**: VO / VIO fallback -- **Fit Impact**: Keep Kimera-VIO as a backup candidate, not the first production choice for a single fixed nadir camera. - -### Fact #40 -- **Statement**: None of BASALT, OpenVINS, or Kimera-VIO provides a special fixed-wing nadir mode; downward-camera support depends on accurate camera-to-IMU extrinsics, altitude/scale constraints, and validation under low-parallax planar terrain. -- **Source**: Source #37 -- **Phase**: Mode B round 3 -- **Confidence**: High -- **Related Dimension**: Nadir-camera support -- **Fit Impact**: The architecture must keep satellite anchors and project-level confidence gates regardless of which VIO library is selected. - -### Fact #41 -- **Statement**: Published EuRoC-type VIO error rates are useful for ranking libraries but are not acceptance evidence for high-altitude fixed-wing nadir imagery over agricultural terrain. -- **Source**: Sources #34, #35, #37 -- **Phase**: Mode B round 3 -- **Confidence**: High -- **Related Dimension**: Validation -- **Fit Impact**: Require representative replay/flight data before claiming AC-1/AC-2 accuracy. diff --git a/_docs/00_research/03_comparison_framework.md b/_docs/00_research/03_comparison_framework.md deleted file mode 100644 index 23e486b..0000000 --- a/_docs/00_research/03_comparison_framework.md +++ /dev/null @@ -1,55 +0,0 @@ -# Comparison Framework - -## Selected Framework Type - -Decision support with exact-fit component selection. - -## Selected Dimensions - -1. Required inputs/outputs and ownership boundaries -2. Operating context and lifecycle fit -3. Non-functional envelope fit: latency, memory, storage, thermal, safety -4. Licensing and deployability -5. Evidence quality and validation burden -6. Security and safety failure modes -7. Selection status - -## Initial Population - -| Component Area | Candidate | Option Family | Inputs / Outputs | Fit Summary | Status | -|----------------|-----------|---------------|------------------|-------------|--------| -| Calibration / geometry | OpenCV 4.x | Established production / open-source | image/object points -> intrinsics, distortion, homography, inlier mask | Exact utility fit; permissive production use. | Selected | -| VO / VIO | BASALT + project-owned safety/anchor wrapper | Open-source production candidate | nav frames + FC IMU/calibration -> relative VIO state; wrapper adds source labels, anchor fusion, calibrated confidence, and MAVLink semantics | Best production candidate after user decision: permissive license, strong benchmark evidence, and lower implementation burden than custom VIO. | Selected | -| VO / VIO | OpenVINS | Open-source research | monocular camera + IMU -> VIO state/covariance | Best covariance/reference story, but GPL-3 and generic VIO ownership make it a benchmark/reference rather than shipped core. | Reference only | -| VO / VIO | Kimera-VIO | Open-source production candidate / fallback | mono or stereo camera + IMU -> VIO/SLAM outputs | BSD-friendly, but heavier/stereo-oriented and mono-inertial path has documented parameter caveats. | Backup candidate | -| VO / VIO | OpenCV geometry + project-owned ESKF | Custom fallback | nav frames + FC IMU/attitude/altitude + satellite anchors -> relative motion, absolute updates, covariance, source labels | Fallback if BASALT fails project data/runtime tests; still needed as safety/anchor wrapper around any VIO library. | Fallback / wrapper | -| VO / VIO | ORB-SLAM3 | Open-source research | monocular/stereo/RGB-D + optional IMU -> SLAM pose | Useful benchmark; GPLv3, map runtime, and initialization complexity make it poor production dependency. | Rejected for production | -| Global retrieval | DINOv2-VLAD / AnyLoc-style descriptors | Current SOTA / research | image/chunk -> descriptor | Strong VPR evidence; trigger-only use due runtime/memory and TensorRT fidelity risk. | Selected with runtime gate | -| Vector retrieval | FAISS | Established production / open-source | descriptor matrix + query -> top-K IDs | Exact fit for offline VPR chunk retrieval. | Selected | -| Local matching | LightGlue + DISK/ALIKED | Current SOTA / open-source | two images -> keypoint correspondences/scores | Exact local-match interface; avoids SuperPoint license issue. | Selected with runtime gate | -| Local matching | SuperPoint + LightGlue | Current SOTA / known-bad/licensing caveat | two images -> matches | Technically good; licensing requires explicit review. | Needs user decision / fallback only | -| Cache imagery | COG + manifest + sidecars | Established geospatial format | georeferenced raster + metadata -> efficient local reads | Good immutable tile unit; generated tiles can be written as new COGs. | Selected | -| Cache packaging | PMTiles | Established web-map archive | tile pyramid -> single archive | Efficient reads, but read-only; not suitable for in-flight mutable writes. | Rejected for mutable cache | -| Estimator | Custom ESKF mode machine | Custom production | VO/IMU/VPR/GPS-health -> WGS84 state + covariance + label | Needed for source labels, covariance gates, blackout/spoofing behavior. | Selected | -| MAVLink integration | MAVSDK + pymavlink | Established APIs | telemetry in, `GPS_INPUT` out | MAVSDK handles telemetry; pymavlink handles raw `GPS_INPUT`. | Selected | -| FDR | PostgreSQL event index + CBOR payload segments with optional Parquet export | Established storage | frame estimates, IMU, MAVLink, health, tiles -> bounded replayable log | Matches project PostgreSQL choice while keeping compact append payloads. | Selected pattern | -| Validation | AerialVL + EuRoC + Plane SITL + representative flight | Multi-source test strategy | datasets/sim/flight -> AC evidence | Public data is partial; final representative data is mandatory. | Selected | - -## Round 2 Decision Notes - -- **OpenVINS vs custom OpenCV**: OpenVINS wins if the comparison is against a naive OpenCV-only VIO implementation. The selected design is not that; it is OpenCV geometry plus a product-owned estimator/state machine, with OpenVINS used as a benchmark/reference. -- **Satellite retrieval**: DINOv2-VLAD remains the best global candidate generator found, but aerial VPR sources require chunk scale/overlap tuning, dynamic top-K, and geometric verification. -- **Anchor verification**: ALIKED/LightGlue remains the preferred learned local matcher, while SIFT/ORB stays as a regression/fallback baseline and SuperPoint remains license-gated. - -## Round 3 Decision Notes - -- **User decision**: BASALT is selected as the production VIO candidate. -- **Confidence/covariance**: OpenVINS remains the covariance/reference baseline because its EKF exposes clearer uncertainty semantics than BASALT/Kimera. -- **Nadir support**: no compared VIO library has a special fixed-wing nadir mode; the acceptance path is calibration, altitude/scale constraints, satellite anchors, and representative replay validation. - -## Baseline Alignment - -- "Position estimate" means WGS84 frame center emitted to FC plus a 95% covariance semi-major axis and source label. -- "Satellite anchored" means a visual match passed VPR retrieval, local matching, RANSAC, freshness, covariance, and Mahalanobis gates. -- "Normal flight segment" means the AC-2.1a conditions, not turns/blackout/stale imagery. -- "Selected with runtime gate" means the API capability fits, but final deployment depends on Jetson profiling against AC-4.1 and AC-4.2. diff --git a/_docs/00_research/04_reasoning_chain.md b/_docs/00_research/04_reasoning_chain.md deleted file mode 100644 index 70dd834..0000000 --- a/_docs/00_research/04_reasoning_chain.md +++ /dev/null @@ -1,181 +0,0 @@ -# Reasoning Chain - -## Dimension 1: Core Architecture - -### Fact Confirmation - -Fixed-wing monocular VO accumulates drift because scale and terrain assumptions are imperfect (Fact #1). Aerial VPR can provide absolute anchors but has weather, scale, and repetition failure modes (Fact #2). - -### Reference Comparison - -Pure VO/IMU cannot satisfy the long 8-hour mission. Pure satellite matching cannot run every frame inside the latency budget and will fail in turns, stale imagery, and repetitive fields. - -### Conclusion - -Select a hybrid architecture: steady-state VO/IMU propagation, conditional satellite/VPR anchoring, and ESKF covariance gates. - -### Confidence - -High. Supported by Sources #1 and #2. - -## Dimension 2: VO / VIO Dependency - -### Fact Confirmation - -OpenVINS and ORB-SLAM3 both support visual-inertial estimation patterns, but both are GPL-family production dependency risks (Facts #4 and #5). - -### Reference Comparison - -The project needs a production system with custom mode labels, covariance propagation, MAVLink-specific output behavior, and no hidden GPL obligation. A full SLAM stack also adds initialization and map-management complexity that the ACs do not require. - -### Conclusion - -Use a custom VO/IMU propagation and ESKF mode machine for production. Use OpenVINS/ORB-SLAM3 only as benchmarks/reference algorithms. - -### Confidence - -High for licensing/scope decision; medium for final estimator performance until prototype profiling. - -## Dimension 3: Satellite Retrieval And Local Matching - -### Fact Confirmation - -Aerial VPR benefits from scale/overlap-aware chunks and retrieval + local alignment (Fact #2). LightGlue provides keypoint correspondences/scores from local descriptors (Fact #7). FAISS provides top-K retrieval over descriptors (Fact #12). - -### Reference Comparison - -Global DINOv2/VLAD retrieval alone gives candidate chunks but not enough precision for AC-2.2. Local matching alone over the whole map is too expensive. The two-stage retrieval+alignment structure matches the operational need. - -### Conclusion - -Use DINOv2-VLAD descriptors with FAISS top-K for conditional candidate retrieval, followed by DISK/ALIKED+LightGlue and OpenCV RANSAC homography for local alignment. - -### Confidence - -Medium-high. API fit is strong; embedded runtime must be profiled. - -## Dimension 4: Latency And Memory - -### Fact Confirmation - -Some aerial VPR re-ranking methods are too slow for the steady-state path (Fact #3). Jetson Orin Nano Super has 8 GB shared memory and 25 W power mode (Fact #18), with thermal throttling risk (Fact #19). - -### Reference Comparison - -At 3 fps and <400 ms p95, the system can process every frame through lightweight VO/IMU and use heavier VPR only on triggers. Running DINOv2/LightGlue across many candidates per frame would violate the AC unless proven otherwise. - -### Conclusion - -Make VPR conditional, cap top-K by covariance/sector, run descriptor extraction on downsampled/orthorectified crops, precompute cache descriptors offline, and add performance regression tests. - -### Confidence - -High for architecture direction; exact model sizes need profiling. - -## Dimension 5: Cache Format - -### Fact Confirmation - -COG supports tiled compressed rasters and geospatial tooling (Fact #21). PMTiles is read-efficient but read-only (Fact #20). - -### Reference Comparison - -The onboard system must both read service tiles and write new generated tiles in-flight. A read-only archive is a poor primary mutable store. - -### Conclusion - -Use COG files plus STAC-like manifests/sidecars for imagery and metadata; use FAISS sidecar indexes for descriptors. PMTiles may be an export/snapshot format, not the live mutable cache. - -### Confidence - -High. - -## Dimension 6: Autopilot Integration - -### Fact Confirmation - -ArduPilot MAVLink GPS input requires `GPS1_TYPE=14` (Fact #15). `GPS_INPUT` carries the fields needed for WGS84 position and accuracy (Fact #16). MAVSDK covers telemetry but raw `GPS_INPUT` emission still needs pymavlink/raw MAVLink (Fact #14). - -### Reference Comparison - -MAVSDK-only output would not satisfy AC-4.3. Raw pymavlink-only telemetry is possible but gives up MAVSDK's high-level subscriptions. - -### Conclusion - -Use MAVSDK for telemetry subscriptions and pymavlink for `GPS_INPUT` emission. Verify all failsafe/spoofing behavior in ArduPilot Plane SITL. - -### Confidence - -High for interface; medium for exact Plane failsafe timing until SITL. - -## Dimension 7: Validation - -### Fact Confirmation - -AerialVL provides aerial localization/reference-map data (Fact #22). EuRoC provides camera+IMU+ground truth but not fixed-wing nadir imagery (Fact #23). The current sample set lacks IMU/ground truth. - -### Reference Comparison - -No single public dataset proves every AC. Public datasets can de-risk components, while final acceptance requires representative synchronized flight/replay data. - -### Conclusion - -Use layered validation: EuRoC for VIO sanity, AerialVL/VPAir-style data for VPR/anchor tests, ArduPilot Plane SITL for MAVLink/failsafe/spoofing, and a final representative flight/replay rig for AC proof. - -### Confidence - -High. - -## Dimension 8: OpenVINS vs Project-Owned Estimator - -### Fact Confirmation - -OpenVINS is a strong monocular+IMU EKF/MSCKF VIO reference with covariance-aware estimation (Facts #4 and #30). OpenCV supplies calibration, undistortion, homography, RANSAC/USAC, and reprojection-error primitives, but it is not a full estimator by itself (Facts #6 and #31). - -### Reference Comparison - -If the alternative is a naive OpenCV-only VIO stack, OpenVINS is the better technical starting point. The project's actual production choice is different: it needs a project-owned ESKF/mode machine that fuses VO/IMU, accepts/rejects satellite anchors, emits `GPS_INPUT`, labels every estimate, handles spoofing/blackout, and gates cache write-back. - -### Conclusion - -Keep OpenVINS as a mandatory benchmark/reference implementation, not as the default production dependency. The production estimator remains project-owned, with OpenCV as the geometry utility layer. - -### Confidence - -High. The technical comparison favors OpenVINS over naive custom VIO, while the product fit favors the project-owned estimator. - -## Dimension 9: Satellite Retrieval And Anchor Verification - -### Fact Confirmation - -DINOv2-VLAD/AnyLoc-style retrieval has strong VPR evidence but descriptor/model size and TensorRT fidelity must be validated (Facts #33 and #36). Aerial VPR survey evidence emphasizes tile scale, overlap, season/weather shifts, repetitive patterns, and re-ranking cost (Fact #34). LightGlue supports ALIKED/DISK/SIFT feature matching and returns correspondences/scores suitable for RANSAC verification, but Jetson latency must be profiled (Facts #7, #8, #35). - -### Reference Comparison - -Classical SIFT/ORB is simpler and cheap but weaker for cross-domain UAV-to-satellite matching. SuperPoint+LightGlue is technically strong but remains license-gated. Pure global retrieval without local verification is unsafe because repetitive farmland and stale imagery can produce plausible but wrong candidates. - -### Conclusion - -Use DINOv2-VLAD + CPU-first FAISS as the triggered global retriever, then verify bounded top-K candidates with ALIKED/LightGlue + OpenCV RANSAC. Keep SIFT/ORB as a regression baseline and SuperPoint only after legal approval. - -### Confidence - -High for architecture and interfaces; medium for final runtime until Jetson profiling. - -## Dimension 10: BASALT vs Kimera-VIO vs OpenVINS - -### Fact Confirmation - -BASALT has strong published EuRoC evidence and production-friendly licensing (Fact #37). OpenVINS has the clearest EKF covariance API and consistency tooling, but GPLv3 remains a production constraint (Fact #38). Kimera-VIO is BSD-friendly but heavier and has documented mono-inertial caveats (Fact #39). All three require calibrated camera-to-IMU extrinsics; none has a special fixed-wing nadir mode (Fact #40). - -### Reference Comparison - -For a single fixed downward camera, the selection criterion is not just benchmark ATE. The project needs a VIO core that can run on Jetson, tolerate calibrated nadir geometry, and be wrapped by project-specific satellite-anchor, confidence, MAVLink, and safety logic. OpenVINS is attractive for confidence/covariance but problematic as a shipped component. Kimera is acceptable as a BSD fallback, but mono-inertial risk makes it weaker as the first pick. BASALT provides the best production trade-off if its uncertainty can be calibrated and wrapped. - -### Conclusion - -Select BASALT as the production VIO candidate. Keep OpenVINS as a reference/covariance baseline and Kimera-VIO as a backup candidate. The project-owned safety/anchor wrapper remains mandatory around BASALT because BASALT alone does not satisfy GPS-denied source labels, satellite anchors, false-position budgets, cache-write gates, or `GPS_INPUT` behavior. - -### Confidence - -Medium-high. Library ranking is well supported; final acceptance still depends on representative fixed-wing nadir replay data. diff --git a/_docs/00_research/05_validation_log.md b/_docs/00_research/05_validation_log.md deleted file mode 100644 index ecc86cb..0000000 --- a/_docs/00_research/05_validation_log.md +++ /dev/null @@ -1,51 +0,0 @@ -# Validation Log - -## Validation Scenario - -An 8-hour fixed-wing mission enters GPS-denied/spoofed mode after takeoff. The onboard system starts from last trusted FC state, processes 3 fps nadir frames, emits `GPS_INPUT`, handles normal flight, sharp turns, short visual blackouts, stale/changed tiles, and post-flight tile write-back. - -## Expected Based On Conclusions - -- **Normal segment**: VO/IMU propagates every processed frame; satellite anchors refresh state conditionally before covariance grows too large. -- **Sharp turn / <5% overlap**: VO is expected to fail; relocalization uses FAISS top-K VPR chunks followed by LightGlue/RANSAC. -- **Visual blackout + spoofing**: estimator switches to `dead_reckoned`, covariance grows monotonically, spoofed GPS is ignored, `GPS_INPUT` degrades honestly. -- **Stale tile**: anchor is rejected or down-confidence weighted and cannot emit `satellite_anchored`. -- **Cache write-back**: onboard generated tile is written only when parent-pose covariance passes AC-NEW-7 gates and carries metadata for Satellite Service voting. - -## Actual Validation Plan - -| Validation Target | Test Method | Pass Evidence | -|-------------------|-------------|---------------| -| VO/VIO propagation | EuRoC and synthetic nadir replay; then representative flight data | Drift vs anchor-age bins; AC-1.3 pass/fail. | -| Satellite anchor | AerialVL/VPAir-style benchmark plus project sample imagery with satellite cache | AC-1.1/1.2 accuracy, AC-2.2 MRE, georeference recall. | -| Runtime | Jetson Orin Nano Super profiling under 25 W, hot-soak included | <400 ms p95, <8 GB memory, no thermal throttle. | -| VPR retrieval | Offline descriptor build and FAISS query benchmark | Top-K recall, query latency, index size within cache budget. | -| MAVLink output | ArduPilot Plane SITL with `GPS1_TYPE=14` | Valid `GPS_INPUT`, fix-type/accuracy degradation, QGC status. | -| Spoofing promotion | Plane SITL false GPS injection | Promotion <3 s and spoofed GPS rejected during blackout. | -| FDR | 8-hour synthetic load | <=64 GB, rollover logged, no silent payload loss. | -| Cache poisoning | Monte Carlo with over-confident wrong anchors | AC-NEW-7 probabilities below budget; metadata contract emitted. | -| OpenVINS reference comparison | Replay the same synchronized camera+IMU segments through OpenVINS and the project-owned estimator | OpenVINS establishes a VIO baseline; production estimator must match/beat drift where applicable while preserving source labels and GPS_INPUT behavior. | -| BASALT production VIO candidate | Replay synchronized camera+IMU segments through BASALT, OpenVINS, and Kimera-VIO | BASALT selected if drift, completion rate, latency, and wrapper-calibrated covariance meet project gates. | -| DINOv2-VLAD fidelity | Compare PyTorch, ONNX, and TensorRT descriptor distances and FAISS rankings | Optimized engines accepted only if rank/top-K behavior stays within tolerance. | -| ALIKED/LightGlue runtime | Jetson benchmark across K candidates and project image sizes | Candidate accepted for runtime only if relocalization trigger path fits AC-4.1 with bounded frame drops. | - -## Counterexamples And Risks - -- Large DINOv2 variants or many local-match candidates may violate the Jetson latency/memory envelope. -- Agricultural fields can be visually repetitive; VPR confidence must not be treated as sufficient without geometric verification. -- Public datasets do not fully match Ukrainian fixed-wing operational conditions; final evidence requires representative data. -- GPL VIO/SLAM libraries are not production dependencies unless licensing is explicitly accepted. -- OpenVINS may outperform the first custom estimator prototype on pure VIO drift; that would trigger estimator improvement, not automatic GPL production adoption. -- BASALT covariance/confidence is less directly exposed than OpenVINS EKF covariance; the project wrapper must calibrate uncertainty before mapping it to `GPS_INPUT.horiz_accuracy`. - -## Review Checklist - -- [x] Draft conclusions are consistent with fact cards. -- [x] No important dimensions missed: architecture, VO, VPR, local matching, cache, estimator, MAVLink, FDR, validation covered. -- [x] No selected component relies only on field-adjacent fit. -- [x] Mismatches are recorded as rejected/reference/needs-decision rather than hidden. -- [x] Step 7.5 Component Applicability Gate applies and is saved in `06_component_fit_matrix.md`. - -## Conclusions Requiring Revision - -Round 3 applies the user decision to select BASALT as the production VIO candidate. The selected implementation is BASALT VIO plus a project-owned safety/anchor wrapper; OpenVINS remains the covariance/reference baseline, Kimera-VIO remains a backup candidate, and custom OpenCV-only VIO is no longer the primary path. Runtime gates and Plane SITL gates are implementation validation gates, not API capability blockers. diff --git a/_docs/00_research/06_component_fit_matrix.md b/_docs/00_research/06_component_fit_matrix.md deleted file mode 100644 index a19fdc0..0000000 --- a/_docs/00_research/06_component_fit_matrix.md +++ /dev/null @@ -1,107 +0,0 @@ -# Component Fit Matrix - -## Top-Level Matrix - -| Component Area | Candidate | Pinned Mode/Config | Option Family | Intended Role | API Capability Evidence | Mismatches / Disqualifiers | Status | Decision Rationale | -|----------------|-----------|--------------------|---------------|---------------|-------------------------|----------------------------|--------|--------------------| -| Calibration / geometry | OpenCV 4.x | C++/Python calibration, undistortion, RANSAC homography, reprojection-error measurement | Established production / open-source | Camera intrinsics, image normalization, VO/satellite homography verification | MVE: `02_fact_cards.md` OpenCV block; Source #5 | None | Selected | Exact API fit and permissive utility role. | -| VO / IMU propagation | BASALT + project-owned safety/anchor wrapper | BASALT VIO consumes calibrated nav-camera frames + FC IMU; wrapper fuses satellite anchors, calibrates uncertainty, emits source labels and GPS_INPUT semantics | Open-source production candidate | Relative VIO state, completion/error benchmark, wrapped covariance/confidence, degraded modes, GPS_INPUT semantics | Sources #33-#35; Facts #37, #40, #41 | BASALT covariance/confidence must be calibrated in wrapper; no special nadir mode | Selected | User-selected best production trade-off: permissive licensing and stronger benchmark/completion evidence than OpenVINS/Kimera, with wrapper covering project-specific safety semantics. | -| VO / VIO reference | OpenVINS | Monocular camera + IMU EKF/MSCKF reference runs with covariance extraction | Open-source research | Benchmark and covariance reference | Sources #3, #27, #28, #35, #38; Facts #4, #30, #38 | GPL-3 production dependency risk; completion/divergence risk on some sequences; does not own satellite anchor / GPS_INPUT / blackout / cache-write state machine | Reference only | Best covariance baseline, but not selected as shipped production dependency. | -| VO / VIO backup | Kimera-VIO | Mono/stereo camera + IMU VIO/SLAM backup candidate | Open-source production candidate / fallback | Alternative VIO baseline | Sources #34, #36; Fact #39 | Heavier/stereo-oriented; mono-inertial path has documented parameter caveats | Backup candidate | BSD-friendly backup if BASALT fails project replay/runtime gates. | -| VO / SLAM alternative | ORB-SLAM3 | Monocular-inertial SLAM | Open-source research | Benchmark and failure-mode comparison | Source #4, Fact #5 | GPLv3; heavier SLAM/map lifecycle than required | Rejected | Does not fit licensing/scope for production. | -| VPR descriptors | DINOv2-VLAD / AnyLoc-style | Precomputed satellite chunk descriptors; conditional query descriptor on relocalization triggers; TensorRT path only after embedding-fidelity check | Current SOTA / research | Global top-K candidate retrieval | Sources #7, #8, #21, #22, #30, #32; Facts #10, #11, #24, #33, #34, #36 | Runtime and embedding-fidelity gates on Jetson; model-size/index-size selection required | Selected with runtime gate | Best evidence for change-robust VPR, but not per-frame and not blindly TensorRT-converted. | -| Vector retrieval | FAISS | CPU-first aarch64 index; saved/loaded index over float/PQ descriptors; GPU only if custom Jetson build is proven | Established production / open-source | Top-K candidate chunk search | MVE: `02_fact_cards.md` FAISS block; Sources #9, #25 | GPU FAISS not default on Jetson ARM64 | Selected | Exact top-K descriptor retrieval fit with CPU-first deployment. | -| Local matching | LightGlue + DISK/ALIKED | CUDA/ONNX-profiled DISK or ALIKED feature extraction + LightGlue matching on bounded top-K candidates | Current SOTA / open-source | 2D-2D correspondences for RANSAC and MRE | MVE: `02_fact_cards.md` LightGlue block; Sources #6, #23, #31 | Runtime quality gate; extractor choice must avoid SuperPoint license issue | Selected with runtime gate | Exact input/output fit with deployable licensing path; ALIKED/LightGlue is preferred for anchor verification. | -| Local matching fallback | SuperPoint + LightGlue | SuperPoint features + LightGlue | Current SOTA / license-gated | Optional benchmark/fallback | Source #6 | SuperPoint restrictive license | Needs user decision | Do not use as default production dependency without legal review. | -| Cache imagery | COG + manifest/sidecar | Tiled compressed GeoTIFF tile objects with CRS, capture date, source, m/px, freshness, descriptor sidecars; write-new-object lifecycle | Established geospatial format | Immutable service tiles and generated candidate tiles | Source #18, Facts #21, #29 | No in-place mutation; manifest manages active tile version | Selected | Fits geospatial raster access and write-new-tile workflow. | -| Cache packaging | PMTiles | Read-only tile archive | Established web-map archive | Optional export/snapshot | Source #17, Fact #20 | Cannot update in place | Rejected for live cache | In-flight tile generation needs mutable write-new objects. | -| MAVLink | MAVSDK + pymavlink | MAVSDK telemetry subscriptions; pymavlink/raw MAVLink `GPS_INPUT` emission to ArduPilot `GPS1_TYPE=14`; velocity source/ignore-flag behavior SITL-tested | Established APIs | FC telemetry, QGC status, GPS substitute output | MVE: `02_fact_cards.md` MAVSDK/pymavlink block; Sources #10-#12, #24 | Plane SITL behavior and velocity-source parameters must be validated | Selected | Exact output contract with known ArduPilot pitfall covered. | -| Validation | EuRoC + AerialVL/VPAir + Plane SITL + representative flight | Layered validation suite | Test strategy | Prove ACs before production | Sources #19, #20 | Public data not sufficient for final proof | Selected | Covers component de-risking plus final representative proof. | - -## Restrictions Cross-Check — Selected Production Architecture - -| Restriction | Candidate-mode behavior | Result | Evidence | -|-------------|-------------------------|--------|----------| -| Fixed-wing only | Architecture assumes forward motion, rare sharp turns, no hover dependency. | Pass | Problem context; Source #1 | -| Fixed nadir nav camera | VO/orthorectification uses fixed camera extrinsics; attitude compensation from FC. | Pass | Source #5 | -| Operational area / flat terrain | Flat terrain assumption supported; repetitive agricultural terrain handled as validation class and confidence risk. | Pass | Source #2 | -| Weather/season classes | Validation matrix includes seasonal/visibility classes. | Pass | `05_validation_log.md` | -| Two-camera split | Nav camera drives localization; AI camera object localization uses current GPS-denied state and AI gimbal/zoom. | Pass | AC-7.1/7.2 | -| Satellite Service offline boundary | Runtime uses local COG/cache + FAISS descriptors only; no in-flight provider fetch. | Pass | Sources #17, #18 | -| Freshness gates | Tile manifest carries capture date and sector; stale tiles rejected/down-weighted. | Pass | AC-8.2, AC-NEW-6 | -| Jetson Orin Nano Super | Hot path is lightweight; heavy VPR conditional; runtime profiling gate required. | Pass | Sources #15, #16 | -| MAVLink / ArduPilot only | MAVSDK telemetry + pymavlink `GPS_INPUT`, `GPS1_TYPE=14`. | Pass | Sources #10-#12 | -| No raw frame storage | FDR keeps estimates, telemetry, tiles, and low-rate failure thumbnails only. | Pass | AC-8.5, AC-NEW-3 | - -## AC Cross-Check — Selected Production Architecture - -| AC | Candidate-mode behavior | Result | Evidence | -|----|-------------------------|--------|----------| -| AC-1.1 | Satellite anchors and ESKF output target <=50 m for >=80% normal frames. | Pass | Facts #1, #2 | -| AC-1.2 | Same pipeline targets <=20 m for >=50% normal frames; validated statistically. | Pass | `05_validation_log.md` | -| AC-1.3 | ESKF tracks anchor age and covariance; VO-only and IMU-fused drift measured between anchors. | Pass | Fact #1 | -| AC-1.4 | ESKF emits covariance; telemetry/FDR carries source label. | Pass | Fact #16 | -| AC-2.1a | VO hot path handles normal overlapping frames; failures trigger mode change. | Pass | Facts #1, #6 | -| AC-2.1b | Satellite anchor success measured separately through VPR + local match + RANSAC. | Pass | Facts #2, #7, #12 | -| AC-2.2 | OpenCV/LightGlue provide correspondences and homography MRE measurement. | Pass | Facts #6, #7 | -| AC-3.1 | ESKF innovation gates reject outliers; covariance grows instead of trusting jumps. | Pass | Reasoning chain | -| AC-3.2 | Sharp turn VO failure triggers VPR relocalization. | Pass | AC design; Source #2 | -| AC-3.3 | Disconnected segment handled by global retrieval and pose-graph/ESKF re-anchor. | Pass | Source #2 | -| AC-3.4 | Loss counter and timer trigger GCS relocalization request while dead reckoning continues. | Pass | AC design | -| AC-3.5 | Image-quality/blackout state switches to IMU-only and rejects spoofed GPS. | Pass | AC design; Facts #16, #17 | -| AC-4.1 | Heavy VPR is conditional; steady-state path is VO/IMU. Jetson profiling is a runtime quality gate. | Pass | Facts #3, #18 | -| AC-4.2 | Descriptor/index memory is budgeted; FAISS and cache are precomputed/pruned. | Pass | Facts #12, #13 | -| AC-4.3 | `GPS_INPUT` emitted by pymavlink; ODOMETRY remains disabled in v1. | Pass | Facts #14-#16 | -| AC-4.4 | Estimator emits frame-by-frame; no batching required. | Pass | Architecture | -| AC-4.5 | Corrections are emitted as updated estimates with timestamps and covariance. | Pass | Architecture | -| AC-5.1 | Startup initializes from last trusted FC state plus IMU propagation. | Pass | Architecture | -| AC-5.2 | >3 s no-estimate path enters degraded/failsafe behavior; Plane SITL proves FC response. | Pass | Fact #17 | -| AC-5.3 | Cold restart uses FC state and preloaded cache/index. | Pass | AC-NEW-1 | -| AC-6.1 | QGC receives downsampled status; FDR keeps high-rate details. | Pass | MAVSDK telemetry + FDR design | -| AC-6.2 | Command ingress reserved through MAVLink status/named values/custom dialect. | Pass | MAVLink design | -| AC-6.3 | `GPS_INPUT` lat/lon is WGS84. | Pass | Fact #16 | -| AC-7.1 | Object localization exposes level-flight accuracy and maneuver bound. | Pass | Geometry design | -| AC-7.2 | Flat-terrain trig projection from UAV GPS + gimbal/zoom/altitude. | Pass | Geometry design | -| AC-8.1 | Cache contract requires 0.3-0.5 m/px imagery. | Pass | Restrictions | -| AC-8.2 | Freshness metadata gates anchors. | Pass | Restrictions | -| AC-8.3 | Precomputed descriptors and FAISS index are part of cache budget. | Pass | Facts #10, #12, #13 | -| AC-8.4 | Generated tiles are new COGs with quality metadata for Service ingest. | Pass | Fact #21 | -| AC-8.5 | Raw frames are not retained. | Pass | FDR design | -| AC-8.6 | VPR chunks use overlap/multi-scale descriptors and dynamic K. | Pass | Facts #2, #12 | -| AC-NEW-1 | Engines/indexes built before flight; first fix benchmark validates <30 s. | Pass | Runtime plan | -| AC-NEW-2 | Plane SITL verifies spoofing trigger and promotion <3 s. | Pass | Fact #17 | -| AC-NEW-3 | FDR segment rollover validates <=64 GB. | Pass | Validation plan | -| AC-NEW-4 | Mahalanobis gates and calibrated covariance target false-position budget. | Pass | ESKF design | -| AC-NEW-5 | Thermal profiling at 25 W validates no throttle. | Pass | Facts #18, #19 | -| AC-NEW-6 | Tile age rejection/down-weighting built into anchor gate. | Pass | AC design | -| AC-NEW-7 | Tile writes require parent-pose covariance and sidecar metadata; Satellite Service voting is external contract. | Pass | AC design | -| AC-NEW-8 | Dead-reckoned blackout mode degrades `GPS_INPUT` fields at covariance thresholds. | Pass | Facts #16, #17 | - -## Decision Rules Applied - -- No GPL VIO/SLAM library is selected as a production dependency. -- Runtime gates are classified as runtime-quality validation gates, not API capability blockers. -- Every selected component has an exact input/output role and a validation path. -- Any candidate with license uncertainty is marked `Needs user decision` or non-production. - -## Mode B Revisions Applied - -- FAISS pinned mode changed to CPU-first on Jetson ARM64. -- DINOv2 TensorRT path requires descriptor-fidelity validation against PyTorch/ONNX. -- `GPS_INPUT` tests now include velocity-source and ignore-flag behavior. -- COG cache lifecycle clarified as write-new-object plus manifest versioning, not in-place mutation. -- Visual/satellite security controls now include signed manifests, cache provenance, stale-tile rejection, and multi-signal consistency checks. - -## Mode B Round 2 Revisions Applied - -- OpenVINS is explicitly better than naive OpenCV-only VIO, but remains reference-only because the shipped estimator must own source labels, covariance gates, spoofing/blackout states, cache-write eligibility, and MAVLink semantics. -- The selected VO wording is now "OpenCV geometry + project-owned ESKF" to avoid implying a fragile OpenCV-only odometry implementation. -- DINOv2-VLAD + CPU-first FAISS + ALIKED/LightGlue remains selected for satellite retrieval and anchor verification, with retrieval limited to relocalization triggers and bounded top-K verification. -- SIFT/ORB remains a regression/fallback baseline; SuperPoint remains non-production until legal approval. - -## Mode B Round 3 Revisions Applied - -- BASALT is selected as the production VIO candidate. -- OpenVINS remains the covariance/reference baseline, not a shipped dependency by default. -- Kimera-VIO remains a backup VIO candidate because its license is production-friendly but mono-inertial caveats make it weaker for the single-nadir-camera path. -- The project-owned safety/anchor wrapper remains mandatory around BASALT for satellite anchor acceptance, source labels, blackout/spoofing modes, cache-write eligibility, calibrated confidence, and MAVLink `GPS_INPUT`. diff --git a/_docs/00_research/gps_denied_draft02_assessment/00_question_decomposition.md b/_docs/00_research/gps_denied_draft02_assessment/00_question_decomposition.md deleted file mode 100644 index 419db3c..0000000 --- a/_docs/00_research/gps_denied_draft02_assessment/00_question_decomposition.md +++ /dev/null @@ -1,91 +0,0 @@ -# Question Decomposition — Solution Assessment (Mode B, Draft02) - -## Original Question -Assess solution_draft02.md for weak points, security vulnerabilities, and performance bottlenecks, then produce a revised solution draft03. - -## Active Mode -Mode B: Solution Assessment — `solution_draft02.md` is the highest-numbered draft. - -## Question Type Classification -- **Primary**: Problem Diagnosis — identify weak points, vulnerabilities, bottlenecks in draft02 -- **Secondary**: Decision Support — evaluate alternatives for identified issues - -## Research Subject Boundary Definition - -| Dimension | Boundary | -|-----------|----------| -| **Domain** | GPS-denied UAV visual navigation, aerial geo-referencing | -| **Geography** | Eastern/southern Ukraine (left of Dnipro River) — steppe terrain | -| **Hardware** | Desktop/laptop with NVIDIA RTX 2060+, 16GB RAM, 6GB VRAM | -| **Software** | Python ecosystem, GPU-accelerated CV/ML | -| **Timeframe** | Current state-of-the-art (2024-2026), production-ready tools | -| **Scale** | 500-3000 images per flight, up to 6252×4168 resolution | - -## Problem Context Summary -- UAV aerial photos taken consecutively ~100m apart, downward non-stabilized camera -- Only starting GPS known — must determine GPS for all subsequent images -- Must handle: sharp turns, outlier photos (up to 350m gap), disconnected route segments -- Processing <5s/image, real-time SSE streaming, REST API service -- No IMU data available -- Camera: 26MP (6252×4168), 25mm focal length, 23.5mm sensor width, 400m altitude - -## Decomposed Sub-Questions - -### A: DINOv2 Cross-View Retrieval Viability -"Is DINOv2 proven for UAV-to-satellite coarse retrieval? What are real-world performance numbers? What search radius is realistic?" - -### B: XFeat Reliability for Aerial VO -"Is XFeat proven for aerial visual odometry? How does it compare to SuperPoint in aerial scenes specifically? What are known failure modes?" - -### C: LightGlue ONNX on RTX 2060 (Turing) -"Does LightGlue-ONNX work reliably on Turing architecture? What precision (FP16/FP32)? What are actual benchmarks?" - -### D: GTSAM iSAM2 Factor Graph Design -"Is the proposed factor graph structure sound? Are the noise models appropriate? Are custom factors (DEM, drift limit) well-specified?" - -### E: Copernicus DEM Integration -"How is Copernicus DEM accessed programmatically? Is it truly free? What are the actual API requirements?" - -### F: Homography Decomposition Robustness -"How reliable is cv2.decomposeHomographyMat selection heuristic when UAV changes direction? What are failure modes?" - -### G: Image Rotation Handling Completeness -"Is heading-based rotation normalization sufficient? What if heading estimate is wrong early in a segment?" - -### H: Memory Model Under Load -"Can DINOv2 embeddings + SuperPoint features + GTSAM factor graph + satellite cache fit within 16GB RAM and 6GB VRAM during a 3000-image flight?" - -### I: Satellite Match Failure Cascading -"What happens when satellite matching fails for 50+ consecutive frames? How does the 100m drift limit interact with extended VO-only sections?" - -### J: Multi-Provider Tile Schema Compatibility -"Do Google Maps and Mapbox use the same tile coordinate system? What are the practical differences in switching providers?" - -### K: Security Attack Surface -"What are the remaining security vulnerabilities beyond JWT auth? SSE connection abuse? Image processing exploits?" - -### L: Recent Advances (2025-2026) -"Are there newer models or approaches published since draft02 that could improve accuracy or performance?" - -### M: End-to-End Processing Time Budget -"Is the total per-frame time budget realistic when all components run together? What is the critical path?" - ---- - -## Timeliness Sensitivity Assessment - -- **Research Topic**: GPS-denied UAV visual navigation — assessment of solution_draft02 architecture and component choices -- **Sensitivity Level**: 🟠 High -- **Rationale**: CV feature matching models (SuperPoint, LightGlue, XFeat, DINOv2) evolve rapidly with new versions and competitors. GTSAM is stable. Satellite tile API pricing/limits change. Core algorithms (homography, VO) are stable. -- **Source Time Window**: 12 months (2025-2026) -- **Priority official sources to consult**: - 1. GTSAM official documentation and PyPI (factor type compatibility) - 2. LightGlue-ONNX GitHub (Turing GPU compatibility) - 3. Google Maps Tiles API documentation (pricing, session tokens) - 4. DINOv2 official repo (model variants, VRAM) - 5. faiss wiki (GPU memory allocation) -- **Key version information to verify**: - - GTSAM: 4.2 stable, 4.3 alpha (breaking changes) - - LightGlue-ONNX: FP16 on Turing, FP8 requires Ada Lovelace - - Pillow: ≥11.3.0 required (CVE-2025-48379) - - FastAPI: ≥0.135.0 (SSE support) diff --git a/_docs/00_research/gps_denied_draft02_assessment/01_source_registry.md b/_docs/00_research/gps_denied_draft02_assessment/01_source_registry.md deleted file mode 100644 index f48875b..0000000 --- a/_docs/00_research/gps_denied_draft02_assessment/01_source_registry.md +++ /dev/null @@ -1,212 +0,0 @@ -# Source Registry — Draft02 Assessment - -## Source #1 -- **Title**: GTSAM GPSFactor Class Reference -- **Link**: https://gtsam.org/doxygen/a04084.html -- **Tier**: L1 -- **Publication Date**: 2025 (latest docs) -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: GTSAM 4.2 -- **Target Audience**: GTSAM users building factor graphs with GPS constraints -- **Research Boundary Match**: ✅ Full match -- **Summary**: GPSFactor and GPSFactor2 work with Pose3/NavState, NOT Pose2. For 2D position constraints, PriorFactorPoint2 or custom factors are needed. -- **Related Sub-question**: D (GTSAM iSAM2 Factor Graph Design) - -## Source #2 -- **Title**: GTSAM Pose2 SLAM Example -- **Link**: https://gtbook.github.io/gtsam-examples/Pose2SLAMExample.html -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: GTSAM 4.2 -- **Target Audience**: GTSAM users -- **Research Boundary Match**: ✅ Full match -- **Summary**: BetweenFactorPose2 provides odometry constraints with noise model Diagonal.Sigmas(Point3(sigma_x, sigma_y, sigma_theta)). PriorFactorPose2 anchors poses. -- **Related Sub-question**: D - -## Source #3 -- **Title**: GTSAM Python pip install version compatibility (PyPI) -- **Link**: https://pypi.org/project/gtsam/ -- **Tier**: L1 -- **Publication Date**: 2026-01 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: gtsam 4.2 (stable), gtsam-develop 4.3a1 (alpha) -- **Target Audience**: Python developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: GTSAM 4.2 stable on pip. 4.3 alpha has breaking changes (C++17, Boost removal). Known issues with Eigen 5.0.0, ARM64 builds. Stick with 4.2 for production. -- **Related Sub-question**: D - -## Source #4 -- **Title**: LightGlue-ONNX repository -- **Link**: https://github.com/fabio-sim/LightGlue-ONNX -- **Tier**: L1 -- **Publication Date**: 2026-01 (last updated) -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: LightGlue-ONNX (supports ONNX Runtime + TensorRT) -- **Target Audience**: Computer vision developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: ONNX export with 2-4x speedup over PyTorch. FP16 works on Turing (RTX 2060). FP8 requires Ada Lovelace/Hopper. Mixed precision supported since July 2023. -- **Related Sub-question**: C (LightGlue ONNX on RTX 2060) - -## Source #5 -- **Title**: LightGlue rotation issue #64 -- **Link**: https://github.com/cvg/LightGlue/issues/64 -- **Tier**: L4 -- **Publication Date**: 2023 -- **Timeliness Status**: ✅ Currently valid (issue still open) -- **Target Audience**: LightGlue users -- **Research Boundary Match**: ✅ Full match -- **Summary**: SuperPoint+LightGlue not rotation-invariant. Fails at 90°/180°. Workaround: try rotating images by {0°, 90°, 180°, 270°}. Steerable CNNs proposed but not available. -- **Related Sub-question**: G (Image Rotation Handling) - -## Source #6 -- **Title**: SIFT+LightGlue for UAV Image Mosaicking (ISPRS 2025) -- **Link**: https://isprs-archives.copernicus.org/articles/XLVIII-2-W11-2025/169/2025/ -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: SIFT+LightGlue hybrid achieves robust matching in low-texture and high-rotation UAV scenarios. Outperforms both pure SIFT and SuperPoint+LightGlue. -- **Related Sub-question**: G - -## Source #7 -- **Title**: DINOv2-Based UAV Visual Self-Localization -- **Link**: https://ui.adsabs.harvard.edu/abs/2025IRAL...10.2080Y/abstract -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: UAV localization researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: DINOv2 with adaptive enhancement achieves 86.27 R@1 on DenseUAV benchmark for UAV-to-satellite matching. Proves DINOv2 viable for coarse retrieval. -- **Related Sub-question**: A (DINOv2 Cross-View Retrieval) - -## Source #8 -- **Title**: SatLoc-Fusion (Remote Sensing 2025) -- **Link**: https://www.mdpi.com/2072-4292/17/17/3048 -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: UAV navigation researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Hierarchical: DINOv2 absolute + XFeat VO + optical flow. <15m error, >2Hz on 6 TFLOPS edge. Adaptive confidence-based fusion. Validates our approach architecture. -- **Related Sub-question**: A, B - -## Source #9 -- **Title**: XFeat: Accelerated Features (CVPR 2024) -- **Link**: https://arxiv.org/abs/2404.19174 -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: CV researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: 5x faster than SuperPoint. Real-time on CPU. Semi-dense matching. XFeat has built-in matcher for fast VO; also compatible with LightGlue via xfeat-lightglue models. -- **Related Sub-question**: B (XFeat Reliability) - -## Source #10 -- **Title**: XFeat + LightGlue compatibility (GitHub issue #128) -- **Link**: https://github.com/cvg/LightGlue/issues/128 -- **Tier**: L4 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: LightGlue/XFeat users -- **Research Boundary Match**: ✅ Full match -- **Summary**: XFeat-LightGlue trained models available on HuggingFace (vismatch/xfeat-lightglue). Also ONNX export available. XFeat's built-in matcher is separate. -- **Related Sub-question**: B - -## Source #11 -- **Title**: DINOv2 VRAM usage by model variant -- **Link**: https://blog.iamfax.com/tech/image-processing/dinov2/ -- **Tier**: L3 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Developers deploying DINOv2 -- **Research Boundary Match**: ✅ Full match -- **Summary**: ViT-S/14: ~300MB VRAM, 0.05s/img. ViT-B/14: ~600MB, 0.1s/img. ViT-L/14: ~1.5GB, 0.35s/img. ViT-G/14: ~5GB, 2s/img. -- **Related Sub-question**: H (Memory Model) - -## Source #12 -- **Title**: Copernicus DEM on AWS Open Data -- **Link**: https://registry.opendata.aws/copernicus-dem/ -- **Tier**: L1 -- **Publication Date**: Ongoing -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Developers needing DEM data -- **Research Boundary Match**: ✅ Full match -- **Summary**: Free access via S3 without authentication. Cloud Optimized GeoTIFFs, 1x1 degree tiles, 30m resolution. `aws s3 ls --no-sign-required s3://copernicus-dem-30m/` -- **Related Sub-question**: E (Copernicus DEM) - -## Source #13 -- **Title**: Google Maps Tiles API Usage and Billing -- **Link**: https://developers.google.com/maps/documentation/tile/usage-and-billing -- **Tier**: L1 -- **Publication Date**: 2026-02 (updated) -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Google Maps API consumers -- **Research Boundary Match**: ✅ Full match -- **Summary**: 100K free requests/month. 6,000/min, 15,000/day rate limits. $200 monthly credit expired Feb 2025. Requires session tokens. -- **Related Sub-question**: J - -## Source #14 -- **Title**: Google Maps vs Mapbox tile schema -- **Link**: https://developers.google.com/maps/documentation/tile/2d-tiles-overview -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: Both use z/x/y Web Mercator tiles (256px). Compatible coordinate systems. Google requires session tokens; Mapbox requires API tokens. Mapbox global to zoom 16, regional to 21+. -- **Related Sub-question**: J - -## Source #15 -- **Title**: FastAPI SSE connection cleanup issues (sse-starlette #99) -- **Link**: https://github.com/sysid/sse-starlette/issues/99 -- **Tier**: L4 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: FastAPI SSE developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Async generators cannot be easily cancelled once awaited. Use EventPublisher pattern with asyncio.Queue for proper cleanup. Prevents shutdown hangs and connection lingering. -- **Related Sub-question**: K (Security/Stability) - -## Source #16 -- **Title**: OpenCV decomposeHomographyMat issues (#23282) -- **Link**: https://github.com/opencv/opencv/issues/23282 -- **Tier**: L4 -- **Publication Date**: 2023 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: decomposeHomographyMat can return non-orthogonal rotation matrices. Returns 4 solutions. Positive depth constraint needed for disambiguation. Calibration matrix K precision critical. -- **Related Sub-question**: F (Homography Decomposition) - -## Source #17 -- **Title**: CVE-2025-48379: Pillow Heap Buffer Overflow -- **Link**: https://nvd.nist.gov/vuln/detail/CVE-2025-48379 -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: Pillow 11.2.0-11.2.1 affected, fixed in 11.3.0 -- **Summary**: Heap buffer overflow in Pillow's image encoding. Requires pinning Pillow ≥11.3.0 and validating image formats. -- **Related Sub-question**: K (Security) - -## Source #18 -- **Title**: SALAD: Optimal Transport Aggregation for Visual Place Recognition -- **Link**: https://arxiv.org/abs/2311.15937 -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: DINOv2+SALAD outperforms NetVLAD. Single-stage retrieval, no re-ranking. 30min training. Optimal transport aggregation better than raw DINOv2 CLS token for retrieval. -- **Related Sub-question**: A - -## Source #19 -- **Title**: NaviLoc: Trajectory-Level Visual Localization -- **Link**: https://www.mdpi.com/2504-446X/10/2/97 -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: Treats VPR as noisy measurement, uses trajectory-level optimization. 19.5m MLE, 16x improvement over per-frame VPR. Validates trajectory optimization approach. -- **Related Sub-question**: L (Recent Advances) - -## Source #20 -- **Title**: FAISS GPU memory management -- **Link**: https://github.com/facebookresearch/faiss/wiki/Faiss-on-the-GPU -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: GPU faiss allocates ~2GB scratch space by default. On 6GB VRAM RTX 2060, CPU-based faiss recommended. Supports CPU-GPU interop. -- **Related Sub-question**: H (Memory) diff --git a/_docs/00_research/gps_denied_draft02_assessment/02_fact_cards.md b/_docs/00_research/gps_denied_draft02_assessment/02_fact_cards.md deleted file mode 100644 index 41a3f98..0000000 --- a/_docs/00_research/gps_denied_draft02_assessment/02_fact_cards.md +++ /dev/null @@ -1,142 +0,0 @@ -# Fact Cards — Draft02 Assessment - -## Fact #1 -- **Statement**: GTSAM `GPSFactor` works with `Pose3` variables, NOT `Pose2`. `GPSFactor2` works with `NavState`. Neither accepts `Pose2`. For 2D position constraints, use `PriorFactorPoint2` or a custom factor. -- **Source**: [Source #1] https://gtsam.org/doxygen/a04084.html, [Source #2] -- **Phase**: Assessment -- **Target Audience**: GPS-denied UAV navigation developers -- **Confidence**: ✅ High (official GTSAM documentation) -- **Related Dimension**: Factor Graph Design - -## Fact #2 -- **Statement**: GTSAM 4.2 is stable on pip. GTSAM 4.3 alpha has breaking changes (C++17 migration, Boost removal). Known pip dependency resolution issues for Python bindings (Sept 2025). Production should use 4.2. -- **Source**: [Source #3] https://pypi.org/project/gtsam/ -- **Phase**: Assessment -- **Confidence**: ✅ High (PyPI official) -- **Related Dimension**: Factor Graph Design - -## Fact #3 -- **Statement**: LightGlue-ONNX achieves 2-4x speedup over compiled PyTorch. FP16 works on Turing (RTX 2060). FP8 requires Ada Lovelace/Hopper — falls back to higher precision on Turing. Mixed precision supported since July 2023. -- **Source**: [Source #4] https://github.com/fabio-sim/LightGlue-ONNX -- **Phase**: Assessment -- **Confidence**: ✅ High (official repo, benchmarks) -- **Related Dimension**: Processing Performance - -## Fact #4 -- **Statement**: SuperPoint and LightGlue are NOT rotation-invariant. Performance degrades significantly at 90°/180° rotations. Practical workaround: try matching at {0°, 90°, 180°, 270°} rotations. SIFT+LightGlue hybrid is proven better for high-rotation UAV scenarios (ISPRS 2025). -- **Source**: [Source #5] issue #64, [Source #6] ISPRS 2025 -- **Phase**: Assessment -- **Confidence**: ✅ High (confirmed in official issue + peer-reviewed paper) -- **Related Dimension**: Rotation Handling - -## Fact #5 -- **Statement**: DINOv2 achieves 86.27 R@1 on DenseUAV benchmark for UAV-to-satellite matching (with adaptive enhancement). Raw DINOv2 performance is lower but still viable for coarse retrieval. -- **Source**: [Source #7] https://ui.adsabs.harvard.edu/abs/2025IRAL...10.2080Y/ -- **Phase**: Assessment -- **Confidence**: ✅ High (peer-reviewed) -- **Related Dimension**: Satellite Matching - -## Fact #6 -- **Statement**: SatLoc-Fusion validates the exact architecture pattern: DINOv2 for absolute geo-localization + XFeat for VO + optical flow for velocity. Achieves <15m error at >2Hz on 6 TFLOPS edge hardware. Uses adaptive confidence-based fusion. -- **Source**: [Source #8] https://www.mdpi.com/2072-4292/17/17/3048 -- **Phase**: Assessment -- **Confidence**: ✅ High (peer-reviewed, dataset provided) -- **Related Dimension**: Overall Architecture - -## Fact #7 -- **Statement**: XFeat is 5x faster than SuperPoint. Runs real-time on CPU. Has built-in matcher for fast matching. Also compatible with LightGlue via xfeat-lightglue trained models (HuggingFace vismatch/xfeat-lightglue). ONNX export available. -- **Source**: [Source #9] CVPR 2024, [Source #10] GitHub -- **Phase**: Assessment -- **Confidence**: ✅ High (CVPR paper + working implementations) -- **Related Dimension**: Feature Extraction - -## Fact #8 -- **Statement**: DINOv2 VRAM: ViT-S/14 ~300MB (0.05s/img), ViT-B/14 ~600MB (0.1s/img), ViT-L/14 ~1.5GB (0.35s/img). On GTX 1080. -- **Source**: [Source #11] blog benchmark -- **Phase**: Assessment -- **Confidence**: ⚠️ Medium (third-party benchmark, not official) -- **Related Dimension**: Memory Model - -## Fact #9 -- **Statement**: Copernicus DEM GLO-30 is freely available on AWS S3 without authentication: `s3://copernicus-dem-30m/`. Cloud Optimized GeoTIFFs, 30m resolution, global coverage. Alternative: Sentinel Hub API (requires free registration). -- **Source**: [Source #12] AWS Registry -- **Phase**: Assessment -- **Confidence**: ✅ High (AWS official registry) -- **Related Dimension**: DEM Integration - -## Fact #10 -- **Statement**: Google Maps Tiles API: 100K free requests/month, 15,000/day, 6,000/min. Requires session tokens (not just API key). $200 monthly credit expired Feb 2025. February 2026: split quota buckets for 2D and Street View tiles. -- **Source**: [Source #13] Google official docs -- **Phase**: Assessment -- **Confidence**: ✅ High (official documentation) -- **Related Dimension**: Satellite Provider - -## Fact #11 -- **Statement**: Google Maps and Mapbox both use z/x/y Web Mercator tiles (256px). Compatible coordinate systems. Main differences: authentication method (session tokens vs API tokens), max zoom levels (Google: 22, Mapbox: global 16, regional 21+). -- **Source**: [Source #14] Google + Mapbox docs -- **Phase**: Assessment -- **Confidence**: ✅ High (official docs) -- **Related Dimension**: Multi-Provider Cache - -## Fact #12 -- **Statement**: FastAPI SSE async generators cannot be easily cancelled once awaited. Causes shutdown hangs, connection lingering. Solution: EventPublisher pattern with asyncio.Queue for proper lifecycle management. -- **Source**: [Source #15] sse-starlette issue #99 -- **Phase**: Assessment -- **Confidence**: ⚠️ Medium (community report, confirmed by library maintainer) -- **Related Dimension**: API Stability - -## Fact #13 -- **Statement**: cv2.decomposeHomographyMat returns up to 4 solutions. Can return non-orthogonal rotation matrices. Disambiguation requires: positive depth constraint + calibration matrix K precision. Not just "motion consistent with previous direction." -- **Source**: [Source #16] OpenCV issue #23282 -- **Phase**: Assessment -- **Confidence**: ✅ High (confirmed OpenCV issue) -- **Related Dimension**: VO Robustness - -## Fact #14 -- **Statement**: Pillow CVE-2025-48379: heap buffer overflow in 11.2.0-11.2.1. Fixed in 11.3.0. Image processing pipeline must pin Pillow ≥11.3.0. -- **Source**: [Source #17] NVD -- **Phase**: Assessment -- **Confidence**: ✅ High (CVE database) -- **Related Dimension**: Security - -## Fact #15 -- **Statement**: DINOv2+SALAD (optimal transport aggregation) outperforms raw DINOv2 CLS token for visual place recognition. Single-stage, no re-ranking needed. 30-minute training. Better suited for coarse retrieval than raw cosine similarity on CLS tokens. -- **Source**: [Source #18] arXiv -- **Phase**: Assessment -- **Confidence**: ✅ High (peer-reviewed) -- **Related Dimension**: Satellite Matching - -## Fact #16 -- **Statement**: FAISS GPU allocates ~2GB scratch space by default. On 6GB VRAM RTX 2060, GPU faiss would consume 33% of VRAM just for indexing. CPU-based faiss recommended for this hardware profile. -- **Source**: [Source #20] FAISS wiki -- **Phase**: Assessment -- **Confidence**: ✅ High (official wiki) -- **Related Dimension**: Memory Model - -## Fact #17 -- **Statement**: NaviLoc achieves 19.5m MLE by treating VPR as noisy measurement and optimizing at trajectory level (not per-frame). 16x improvement over per-frame approaches. Validates trajectory-level optimization concept. -- **Source**: [Source #19] -- **Phase**: Assessment -- **Confidence**: ✅ High (peer-reviewed) -- **Related Dimension**: Optimization Strategy - -## Fact #18 -- **Statement**: Mapbox satellite imagery for Ukraine: no specific update schedule. Uses Maxar Vivid product. Coverage to zoom 16 globally (~2.5m/px), regional zoom 18+ (~0.6m/px). No guarantee of Ukraine freshness — likely 2+ years old in conflict areas. -- **Source**: [Source #14] Mapbox docs -- **Phase**: Assessment -- **Confidence**: ⚠️ Medium (general Mapbox info, no Ukraine-specific data) -- **Related Dimension**: Satellite Provider - -## Fact #19 -- **Statement**: For 2D factor graphs, GTSAM uses Pose2 (x, y, theta) with BetweenFactorPose2 for odometry and PriorFactorPose2 for anchoring. Position-only constraints use PriorFactorPoint2. Custom factors via Python callbacks are supported but slower than C++ factors. -- **Source**: [Source #2] GTSAM by Example -- **Phase**: Assessment -- **Confidence**: ✅ High (official GTSAM examples) -- **Related Dimension**: Factor Graph Design - -## Fact #20 -- **Statement**: XFeat's built-in matcher (match_xfeat) is fastest for VO (~15ms total extraction+matching). xfeat-lightglue is higher quality but slower. For satellite matching where accuracy matters more, SuperPoint+LightGlue remains the better choice. -- **Source**: [Source #9] CVPR 2024, [Source #10] -- **Phase**: Assessment -- **Confidence**: ⚠️ Medium (inference from multiple sources) -- **Related Dimension**: Feature Extraction Strategy diff --git a/_docs/00_research/gps_denied_draft02_assessment/03_comparison_framework.md b/_docs/00_research/gps_denied_draft02_assessment/03_comparison_framework.md deleted file mode 100644 index 6ecc687..0000000 --- a/_docs/00_research/gps_denied_draft02_assessment/03_comparison_framework.md +++ /dev/null @@ -1,31 +0,0 @@ -# Comparison Framework — Draft02 Assessment - -## Selected Framework Type -Problem Diagnosis + Decision Support - -## Selected Dimensions -1. Factor Graph Design Correctness -2. VRAM/Memory Budget Feasibility -3. Rotation Handling Completeness -4. VO Robustness (Homography Decomposition) -5. Satellite Matching Reliability -6. Concurrency & Pipeline Architecture -7. Security Attack Surface -8. API/SSE Stability -9. Provider Integration Completeness -10. Drift Management Strategy - -## Findings Matrix - -| Dimension | Draft02 Approach | Weak Point | Severity | Proposed Fix | Factual Basis | -|-----------|------------------|------------|----------|--------------|---------------| -| Factor Graph | Pose2 + GPSFactor + custom DEM/drift factors | GPSFactor requires Pose3, not Pose2. Custom Python factors are slow. | **Critical** | Use Pose2 + BetweenFactorPose2 + PriorFactorPoint2 for satellite anchors. Convert lat/lon to local ENU. Avoid Python custom factors. | Fact #1, #2, #19 | -| VRAM Budget | DINOv2 + SuperPoint + LightGlue ONNX + faiss GPU | No model specified for DINOv2. faiss GPU uses 2GB scratch. Combined VRAM could exceed 6GB. | **High** | Use DINOv2 ViT-S/14 (300MB). faiss on CPU only. Sequence model loading (not concurrent). Explicit budget: XFeat 200MB + DINOv2-S 300MB + SuperPoint 400MB + LightGlue 500MB. | Fact #8, #16 | -| Rotation Handling | Heading-based rectification + SIFT fallback | No heading at segment start. No trigger criteria for SIFT vs rotation retry. Multi-rotation matching not mentioned. | **High** | At segment start: try 4 rotations {0°, 90°, 180°, 270°}. After heading established: rectify. SIFT fallback when SuperPoint inlier ratio < 0.2. | Fact #4 | -| Homography Decomposition | Motion consistency selection | Only "motion consistent with previous direction" — underspecified. 4 solutions possible. Non-orthogonal matrices can occur. | **Medium** | Positive depth constraint first. Then normal direction check (plane normal should point up). Then motion consistency. Orthogonality check on R. | Fact #13 | -| Satellite Coarse Retrieval | DINOv2 + faiss cosine similarity | Raw DINOv2 CLS token suboptimal for retrieval. SALAD aggregation proven better. | **Medium** | Use DINOv2+SALAD or at minimum use patch-level features, not just CLS token. Alternatively, fine-tune DINOv2 on remote sensing. | Fact #5, #15 | -| Concurrency Model | "Async — don't block VO pipeline" | No concrete concurrency design. GPU can't run two models simultaneously. | **High** | Sequential GPU: XFeat VO first (15ms), then async satellite matching on same GPU. Use asyncio for I/O (tile download, DEM fetch). CPU faiss for retrieval. | Fact #8, #16 | -| Security | JWT + rate limiting + CORS | No image format validation. No Pillow version pinning. No SSE abuse protection beyond connection limits. No sandbox for image processing. | **Medium** | Pin Pillow ≥11.3.0. Validate image magic bytes. Limit image dimensions before loading. Memory-map large images. CSP headers. | Fact #14 | -| SSE Stability | FastAPI EventSourceResponse | Async generator cleanup issues on shutdown. No heartbeat. No reconnection strategy. | **Medium** | Use asyncio.Queue-based EventPublisher. Add SSE heartbeat every 15s. Include Last-Event-ID for reconnection. | Fact #12 | -| Provider Integration | Google Maps + Mapbox + user tiles | Google requires session tokens (not just API key). 15K/day limit = ~7 flights from cache misses. Mapbox Ukraine coverage uncertain. | **Medium** | Implement session token management for Google. Add Bing Maps as third provider. Document DEM+tile download budget per flight. | Fact #10, #11, #18 | -| Drift Management | 100m cumulative drift limit factor | Custom factor. If satellite fails for 50+ frames, no anchors → drift factor has nothing to constrain against. | **High** | Add dead-reckoning confidence decay: after N frames without anchor, emit warning + request user input. Track estimated drift explicitly. Set hard limit for user input request. | Fact #17 | diff --git a/_docs/00_research/gps_denied_draft02_assessment/04_reasoning_chain.md b/_docs/00_research/gps_denied_draft02_assessment/04_reasoning_chain.md deleted file mode 100644 index b69e84c..0000000 --- a/_docs/00_research/gps_denied_draft02_assessment/04_reasoning_chain.md +++ /dev/null @@ -1,192 +0,0 @@ -# Reasoning Chain — Draft02 Assessment - -## Dimension 1: Factor Graph Design Correctness - -### Fact Confirmation -According to Fact #1, GTSAM's `GPSFactor` class works exclusively with `Pose3` variables. `GPSFactor2` works with `NavState`. Neither accepts `Pose2`. According to Fact #19, `PriorFactorPoint2` provides 2D position constraints, and `BetweenFactorPose2` provides 2D odometry constraints. - -### Problem -Draft02 specifies `Pose2 (x, y, heading)` variables but lists `GPSFactor` for satellite anchors. This is an API mismatch — the code would fail at runtime. - -### Solution -Two valid approaches: -1. **Pose2 graph (recommended)**: Use `Pose2` variables + `BetweenFactorPose2` for VO + `PriorFactorPose2` for satellite anchors (constraining full pose when heading is available) or use a custom partial factor that constrains only the position part of Pose2. Convert WGS84 to local ENU coordinates centered on starting GPS. -2. **Pose3 graph**: Use `Pose3` with fixed altitude. More accurate but adds unnecessary complexity for 2D problem. - -The custom DEM terrain factor and drift limit factor also need reconsideration: Python custom factors invoke a Python callback per optimization step, which is slow. DEM terrain is irrelevant for 2D Pose2 (altitude is not a variable). Drift should be managed by the Segment Manager logic, not as a factor. - -### Conclusion -Switch to Pose2 + BetweenFactorPose2 + PriorFactorPose2 (or partial position prior). Remove DEM terrain factor (handle elevation in GSD calculation outside the graph). Remove drift limit factor (handle in Segment Manager). This simplifies the factor graph and avoids Python callback overhead. - -### Confidence -✅ High — based on official GTSAM documentation - ---- - -## Dimension 2: VRAM/Memory Budget Feasibility - -### Fact Confirmation -According to Fact #8: DINOv2 ViT-S/14 ~300MB, ViT-B/14 ~600MB. Fact #16: faiss GPU uses ~2GB scratch. Fact #3: LightGlue ONNX FP16 works on RTX 2060. - -### Problem -Draft02 doesn't specify DINOv2 model size. Proposing faiss GPU would consume 2GB of 6GB VRAM. Combined with other models, total could exceed 6GB. Draft02 estimates ~1.5GB per frame for XFeat/SuperPoint + LightGlue, but doesn't account for DINOv2 or faiss. - -### Budget Analysis -Concurrent peak VRAM (worst case): -- XFeat inference: ~200MB -- LightGlue ONNX (FP16): ~500MB -- DINOv2 ViT-B/14: ~600MB -- SuperPoint: ~400MB -- faiss GPU: ~2GB -- ONNX Runtime overhead: ~300MB -- **Total: ~4.0GB** (without faiss GPU: ~2.0GB) - -Sequential loading (recommended): -- Step 1: XFeat + XFeat matcher (VO): ~400MB -- Step 2: DINOv2-S (coarse retrieval): ~300MB → unload -- Step 3: SuperPoint + LightGlue ONNX (fine matching): ~900MB -- Peak: ~1.3GB (with model switching) - -### Conclusion -Use DINOv2 ViT-S/14 (300MB, 0.05s/img — fast enough for coarse retrieval). Run faiss on CPU (the embedding vectors are small, CPU search is <1ms for ~2000 vectors). Sequential model loading for GPU: VO models first, then satellite matching models. Keep models loaded but process sequentially (no concurrent GPU inference). - -### Confidence -✅ High — based on documented VRAM numbers - ---- - -## Dimension 3: Rotation Handling Completeness - -### Fact Confirmation -According to Fact #4, SuperPoint+LightGlue fail at 90°/180° rotations. According to Fact #6 (ISPRS 2025), SIFT+LightGlue outperforms SuperPoint+LightGlue in high-rotation UAV scenarios. - -### Problem -Draft02 says "estimate heading from VO chain, rectify images before satellite matching, SIFT fallback for rotation-heavy cases." But: -1. At segment start, there's no heading from VO chain — no rectification possible. -2. No criteria for when to trigger SIFT fallback. -3. Multi-rotation matching strategy ({0°, 90°, 180°, 270°}) not mentioned. - -### Conclusion -Three-tier rotation handling: -1. **Segment start (no heading)**: Try DINOv2 coarse retrieval (more rotation-robust than local features) → if match found, estimate heading from satellite alignment → proceed normally. -2. **Normal operation (heading available)**: Rectify to approximate north-up using accumulated heading → SuperPoint+LightGlue. -3. **Match failure fallback**: Try 4 rotations {0°, 90°, 180°, 270°} with SuperPoint. If still fails → SIFT+LightGlue (rotation-invariant). - -Trigger for SIFT: SuperPoint inlier ratio < 0.15 after rotation retry. - -### Confidence -✅ High — based on confirmed LightGlue limitation + proven SIFT+LightGlue alternative - ---- - -## Dimension 4: VO Robustness (Homography Decomposition) - -### Fact Confirmation -According to Fact #13, cv2.decomposeHomographyMat returns 4 solutions. Can return non-orthogonal matrices. Calibration matrix K precision is critical. - -### Problem -Draft02 specifies selection by "motion consistent with previous direction + positive depth." This is underspecified for the first frame pair in a segment (no previous direction). Non-orthogonal R detection is missing. - -### Conclusion -Disambiguation procedure: -1. Compute all 4 decompositions. -2. **Filter by positive depth**: triangulate a few matched points, reject solutions where points are behind camera. -3. **Filter by plane normal**: for downward-looking camera, the normal should approximately point up (positive z component in camera frame). -4. **Motion consistency**: if previous direction available, prefer solution consistent with expected motion direction. -5. **Orthogonality check**: verify R'R ≈ I, det(R) ≈ 1. If not, re-orthogonalize via SVD. -6. For first frame pair: rely on filters 2+3 only. - -### Confidence -✅ High — based on well-documented decomposition ambiguity - ---- - -## Dimension 5: Satellite Coarse Retrieval - -### Fact Confirmation -According to Fact #15, DINOv2+SALAD outperforms raw DINOv2 CLS token for retrieval. According to Fact #5, DINOv2 achieves 86.27 R@1 with adaptive enhancement. - -### Problem -Draft02 proposes "DINOv2 global retrieval + faiss cosine similarity." Using raw CLS token is suboptimal. SALAD or patch-level feature aggregation would improve retrieval accuracy. - -### Conclusion -DINOv2+SALAD is the better approach but adds a training/fine-tuning dependency. For a production system without the ability to fine-tune: use DINOv2 patch tokens (not just CLS) with spatial pooling, then cosine similarity via faiss. This captures more spatial information than CLS alone. If time permits, train SALAD head (30 minutes on appropriate dataset). - -Alternatively, consider SatDINO (DINOv2 pre-trained on satellite imagery) if available as a checkpoint. - -### Confidence -⚠️ Medium — SALAD is proven but adding training dependency may not be worth the complexity for this use case - ---- - -## Dimension 6: Concurrency & Pipeline Architecture - -### Fact Confirmation -Single GPU (RTX 2060) cannot run two models concurrently. Fact #8 shows sequential model inference times. Fact #3 shows LightGlue ONNX at ~50-100ms. - -### Problem -Draft02 says satellite matching is "async — don't block VO pipeline" but on a single GPU, you can't parallelize GPU inference. - -### Conclusion -Pipeline design: -1. **VO (synchronous, per-frame)**: XFeat extract + match (~30ms total) → homography estimation (~5ms) → GTSAM update (~5ms) → emit position via SSE. **Total: ~40ms per frame.** -2. **Satellite matching (asynchronous, overlapped with next frame's VO)**: DINOv2 coarse (~50ms) → SuperPoint+LightGlue fine (~150ms) → GTSAM update (~5ms) → emit refined position. **Total: ~205ms but overlapped.** -3. **I/O (fully async)**: Tile download, DEM fetch, cache management — all via asyncio. -4. **CPU tasks (parallel)**: faiss search (CPU), homography RANSAC (CPU-bound but fast). - -The GPU processes frames sequentially. The "async" part is that satellite matching for frame N happens while VO for frame N+1 proceeds. Since satellite matching (~205ms) is longer than VO (~40ms), the pipeline is satellite-matching-bound but VO results stream immediately. - -### Confidence -✅ High — based on documented inference times - ---- - -## Dimension 7: Security Attack Surface - -### Fact Confirmation -According to Fact #14, Pillow CVE-2025-48379 affects image loading. Fact #12 confirms SSE cleanup issues. - -### Problem -Draft02 has JWT + rate limiting + CORS but misses: -- Image format/magic byte validation before loading -- Pillow version pinning -- Memory-limited image loading (a 100,000 × 100,000 pixel image could OOM) -- SSE heartbeat for connection health -- No mention of directory traversal prevention depth - -### Conclusion -Additional security measures: -1. Pin Pillow ≥11.3.0 in requirements. -2. Validate image magic bytes (JPEG/PNG/TIFF) before loading with PIL. -3. Check image dimensions before loading: reject if either dimension > 10,000px. -4. Use OpenCV for loading (separate from PIL) — validate separately. -5. Resolve image_folder path to canonical form (os.path.realpath) and verify it's under allowed base directories. -6. Add Content-Security-Policy headers. -7. SSE heartbeat every 15s to detect stale connections. -8. Implement asyncio.Queue-based event publisher for SSE. - -### Confidence -✅ High — based on documented CVE + known SSE issues - ---- - -## Dimension 8: Drift Management Strategy - -### Fact Confirmation -According to Fact #17, NaviLoc demonstrates that trajectory-level optimization with noisy VPR measurements achieves 16x better accuracy than per-frame approaches. SatLoc-Fusion uses adaptive confidence metrics. - -### Problem -Draft02's "drift limit factor" as a GTSAM custom factor is problematic: (1) custom Python factors are slow, (2) if no satellite anchors arrive for extended period, the drift factor has nothing to constrain against. - -### Conclusion -Replace GTSAM drift factor with Segment Manager logic: -1. Track cumulative VO displacement since last satellite anchor. -2. If cumulative displacement > 100m without anchor: emit warning SSE event, increase satellite matching frequency/radius. -3. If cumulative displacement > 200m: request user input with timeout. -4. If cumulative displacement > 500m: mark segment as LOW confidence, continue but warn. -5. Confidence score per position: decays exponentially with distance from nearest anchor. - -This is simpler, faster, and more controllable than a GTSAM custom factor. - -### Confidence -✅ High — engineering judgment supported by SatLoc-Fusion's confidence-based approach diff --git a/_docs/00_research/gps_denied_draft02_assessment/05_validation_log.md b/_docs/00_research/gps_denied_draft02_assessment/05_validation_log.md deleted file mode 100644 index c3b9342..0000000 --- a/_docs/00_research/gps_denied_draft02_assessment/05_validation_log.md +++ /dev/null @@ -1,100 +0,0 @@ -# Validation Log — Draft02 Assessment (Draft03) - -## Validation Scenario 1: Factor graph initialization with first satellite match - -**Scenario**: Flight starts, VO processes 10 frames, satellite match arrives for frame 5. - -**Expected with Draft03 fixes**: -1. GTSAM graph starts with PriorFactorPose2 at starting GPS (frame 0). -2. BetweenFactorPose2 added for frames 0→1, 1→2, ..., 9→10. -3. Satellite match for frame 5: add PriorFactorPose2 with position from satellite match and noise proportional to reprojection error × GSD. -4. iSAM2.update() triggers backward correction — frames 0-4 and 5-10 both adjust. -5. All positions in local ENU coordinates, converted to WGS84 for output. - -**Validation result**: Consistent. PriorFactorPose2 correctly constrains Pose2 variables. No GPSFactor API mismatch. - -## Validation Scenario 2: Segment start with unknown heading (rotation handling) - -**Scenario**: After a sharp turn, new segment starts. First image has unknown heading. - -**Expected with Draft03 fixes**: -1. VO triple check fails → segment break. -2. New segment starts. No heading available. -3. For satellite coarse retrieval: DINOv2-S processes unrotated image → top-5 tiles. -4. For fine matching: try SuperPoint+LightGlue at 4 rotations {0°, 90°, 180°, 270°}. -5. If match found: heading estimated from satellite alignment. Subsequent images rectified. -6. If no match: try SIFT+LightGlue (rotation-invariant). -7. If still no match: request user input. - -**Validation result**: Consistent. Three-tier fallback addresses the heading bootstrap problem. - -## Validation Scenario 3: VRAM budget during satellite matching - -**Scenario**: Processing frame with concurrent VO + satellite matching on RTX 2060 (6GB). - -**Expected with Draft03 fixes**: -1. XFeat features already extracted for VO: ~200MB VRAM. -2. DINOv2 ViT-S/14 loaded for coarse retrieval: ~300MB. -3. After coarse retrieval, DINOv2 can be unloaded or kept resident. -4. SuperPoint loaded for fine matching: ~400MB. -5. LightGlue ONNX loaded: ~500MB. -6. Peak if all loaded: ~1.4GB. -7. ONNX Runtime workspace: ~300MB. -8. Total peak: ~1.7GB — well within 6GB. -9. faiss runs on CPU — no VRAM impact. - -**Validation result**: Consistent. VRAM budget is comfortable even without model unloading. - -## Validation Scenario 4: Extended satellite failure (50+ frames) - -**Scenario**: Flying over area with outdated/changed satellite imagery. Satellite matching fails for 80 consecutive frames (~8km). - -**Expected with Draft03 fixes**: -1. Frames 1-10: normal VO, satellite matching fails. Cumulative drift increases. -2. Frame ~10 (1km drift): warning SSE event emitted. Satellite search radius expanded. -3. Frame ~20 (2km drift): user_input_needed SSE event. If user provides GPS → anchor + backward correction. -4. If user doesn't respond within timeout: continue with LOW confidence. -5. Frame ~50 (5km drift): positions marked as very low confidence. -6. Confidence score per position decays exponentially from last anchor. -7. If satellite finally matches at frame 80: massive backward correction. Refined events emitted. - -**Validation result**: Consistent. Explicit drift thresholds are more predictable than the custom GTSAM factor approach. - -## Validation Scenario 5: Google Maps session token management - -**Scenario**: Processing a 3000-image flight. Need ~2000 satellite tiles. - -**Expected with Draft03 fixes**: -1. On job start: create Google Maps session with POST /v1/createSession (returns session token). -2. Use session token in all tile requests for this session. -3. Daily limit: 15,000 tiles → sufficient for single flight. -4. Monthly limit: 100,000 → ~50 flights. -5. At 80% daily limit (12,000): switch to Mapbox. -6. Mapbox: 200,000/month → additional ~100 flights capacity. - -**Validation result**: Consistent. Session management addressed correctly. - -## Review Checklist -- [x] Draft conclusions consistent with fact cards -- [x] No important dimensions missed -- [x] No over-extrapolation -- [x] Conclusions actionable/verifiable -- [x] GPSFactor API mismatch verified against GTSAM docs -- [x] VRAM budget calculated with specific model variants -- [x] Rotation handling addresses segment start edge case -- [x] Drift management has concrete thresholds - -## Counterexamples -- **Very low-texture terrain** (uniform sand/snow): XFeat VO might fail even on consecutive frames. Mitigation: track texture score per image, warn when low. -- **Satellite imagery completely missing for region**: Both Google and Mapbox might have no data. Mitigation: user-provided tiles are highest priority. -- **Multiple concurrent GPU processes**: Another process using the GPU could reduce available VRAM. Mitigation: document exclusive GPU access requirement. - -## Conclusions Requiring No Revision -All conclusions validated. Key improvements are well-supported: -1. Correct GTSAM factor types (PriorFactorPose2 instead of GPSFactor) -2. DINOv2 ViT-S/14 for VRAM efficiency -3. Three-tier rotation handling -4. Explicit drift thresholds in Segment Manager -5. asyncio.Queue-based SSE publisher -6. CPU-based faiss -7. Session token management for Google Maps diff --git a/_docs/00_research/gps_denied_nav/00_ac_assessment.md b/_docs/00_research/gps_denied_nav/00_ac_assessment.md deleted file mode 100644 index 7908290..0000000 --- a/_docs/00_research/gps_denied_nav/00_ac_assessment.md +++ /dev/null @@ -1,74 +0,0 @@ -# Acceptance Criteria Assessment - -## Acceptance Criteria - -| Criterion | Our Values | Researched Values | Cost/Timeline Impact | Status | -|-----------|-----------|-------------------|---------------------|--------| -| Position accuracy (80% of photos) | ≤50m error | 15-150m achievable depending on method. SatLoc (2025): <15m with adaptive fusion. Mateos-Ramirez (2024): 142m mean at 1000m+ altitude. At 400m altitude with better GSD (~6cm/px) and satellite correction, ≤50m for 80% is realistic | Moderate — requires high-quality satellite imagery and robust feature matching pipeline | **Modified** — see notes on satellite imagery quality dependency | -| Position accuracy (60% of photos) | ≤20m error | Achievable only with satellite-anchored corrections, not with VO alone. SatLoc reports <15m with satellite anchoring + VO fusion. Requires 0.3-0.5 m/px satellite imagery and good terrain texture | High — requires premium satellite imagery, robust cross-view matching, and careful calibration | **Modified** — add dependency on satellite correction frequency | -| Outlier tolerance | 350m displacement between consecutive photos | At 400m altitude, image footprint is ~375x250m. A 350m displacement means near-zero overlap. VO will fail; system must rely on IMU dead-reckoning or satellite re-localization | Low — standard outlier detection can handle this | Modified — specify fallback strategy (IMU dead-reckoning + satellite re-matching) | -| Sharp turn handling (partial overlap) | <200m drift, <70° angle, <5% overlap | Standard VO fails below ~20-30% overlap. With <5% overlap, feature matching between consecutive frames is unreliable. Requires satellite-based re-localization or IMU bridging | High — requires separate re-localization module | Modified — clarify: "70%" should likely be "70 degrees"; add IMU-bridge requirement | -| Disconnected route segments | System should reconnect disconnected chunks | This is essentially a place recognition / re-localization problem. Solvable via satellite image matching for each new segment independently | High — core architectural requirement affecting system design | Modified — add: each segment should independently localize via satellite matching | -| User fallback input | Ask user after 3 consecutive failures | Reasonable fallback. Needs UI/API integration for interactive input | Low | No change | -| Processing time per image | <5 seconds | On Jetson Orin Nano Super (8GB shared memory): feasible with optimized pipeline. CUDA feature extraction ~50ms, matching ~100-500ms, satellite crop+match ~1-3s. Full pipeline 2-4s is achievable with image downsampling and TensorRT optimization | Moderate — requires TensorRT optimization and image downsampling strategy | **Modified** — specify this is for Jetson Orin Nano Super, not RTX 2060 | -| Real-time streaming | SSE for immediate results + refinement | Standard pattern, well-supported | Low | No change | -| Image Registration Rate | >95% | For consecutive frames with nadir camera in good conditions: 90-98% achievable. Drops significantly during sharp turns and over low-texture terrain (water, uniform fields). The 95% target conflicts with sharp-turn handling requirement | Moderate — requires learning-based matchers (SuperPoint/LightGlue) | **Modified** — clarify: 95% applies to "normal flight" segments only; sharp-turn frames are expected failures handled by re-localization | -| Mean Reprojection Error | <1.0 pixels | Achievable with modern methods (LightGlue, SuperGlue). Traditional methods typically 1-3 px. Deep learning matchers routinely achieve 0.3-0.8 px with proper calibration | Moderate — requires deep learning feature matchers | No change — achievable | -| REST API + SSE architecture | Background service | Standard architecture, well-supported in Python (FastAPI + SSE) | Low | No change | -| Satellite imagery resolution | ≥0.5 m/px, ideally 0.3 m/px | Google Maps for eastern Ukraine: variable, typically 0.5-1.0 m/px in rural areas. 0.3 m/px unlikely from Google Maps. Commercial providers (Maxar, Planet) offer 0.3-0.5 m/px but at significant cost | **High** — Google Maps may not meet 0.5 m/px in all areas of the operational region. 0.3 m/px requires commercial satellite providers | **Modified** — current Google Maps limitation may make this unachievable for all areas; consider fallback for degraded satellite quality | -| Confidence scoring | Per-position estimate (high=satellite, low=VO) | Standard practice in sensor fusion. Easy to implement | Low | No change | -| Output format | WGS84, GeoJSON or CSV | Standard, trivial to implement | Negligible | No change | -| Satellite imagery age | <2 years where possible | Google Maps imagery for conflict zones (eastern Ukraine) may be significantly outdated or intentionally degraded. Recency is hard to guarantee | Medium — may need multiple satellite sources | **Modified** — flag: conflict zone imagery may be intentionally limited | -| Max VO cumulative drift | <100m between satellite corrections | VIO drift typically 0.8-1% of distance. Between corrections at 1km intervals: ~10m drift. 100m budget allows corrections every ~10km — very generous | Low — easily achievable if corrections happen at reasonable intervals | No change — generous threshold | -| Memory usage | <8GB shared memory (Jetson Orin Nano Super) | Binding constraint. 8GB LPDDR5 shared between CPU and GPU. ~6-7GB usable after OS. 26MP images need downsampling | **Critical** — all processing must fit within 8GB shared memory | **Updated** — changed to Jetson Orin Nano Super constraint | -| Object center coordinates | Accuracy consistent with frame-center accuracy | New criterion — derives from problem statement requirement | Low — once frame position is known, object position follows from pixel offset + GSD | **Added** | -| Sharp turn handling | <200m drift, <70 degrees, <5% overlap. 95% registration rate applies to normal flight only | Clarified from original "70%" to "70 degrees". Split registration rate expectation | Low — clarification only | **Updated** | -| Offline preprocessing time | Not time-critical (minutes/hours before flight) | New criterion — no constraint existed | Low | **Added** | - -## Restrictions Assessment - -| Restriction | Our Values | Researched Values | Cost/Timeline Impact | Status | -|-------------|-----------|-------------------|---------------------|--------| -| Aircraft type | Fixed-wing only | Appropriate — fixed-wing has predictable motion model, mostly forward flight. Simplifies VO assumptions | N/A | No change | -| Camera mount | Downward-pointing, fixed, not autostabilized | Implies roll/pitch affect image. At 400m altitude, moderate roll/pitch causes manageable image shift. IMU data can compensate. Non-stabilized means more variable image overlap and orientation | Medium — must use IMU data for image dewarping or accept orientation-dependent accuracy | **Modified** — add: IMU-based image orientation correction should be considered | -| Operational region | Eastern/southern Ukraine (left of Dnipro) | Conflict zone — satellite imagery may be degraded, outdated, or restricted. Terrain: mix of agricultural, urban, forest. Agricultural areas have seasonal texture changes | **High** — satellite imagery availability and quality is a significant risk | **Modified** — flag operational risk: imagery access in conflict zones | -| Image resolution | FullHD to 6252x4168, known camera parameters | 26MP at max is large for edge processing. Must downsample for feature extraction. Known camera intrinsics enable proper projective geometry | Medium — pipeline must handle variable resolutions | No change | -| Altitude | Predefined, ≤1km, terrain height negligible | At 400m: GSD ~6cm/px, footprint ~375x250m. Terrain "negligible" is an approximation — even 50m terrain variation at 400m altitude causes ~12% scale error. The referenced paper (Mateos-Ramirez 2024) shows terrain elevation is a primary error source | **Medium** — "terrain height negligible" needs qualification. At 400m, terrain variations >50m become significant | **Modified** — add: terrain height can be neglected only if variations <50m within image footprint | -| IMU data availability | "A lot of data from IMU" | IMU provides: accelerometer, gyroscope, magnetometer. Crucial for: dead-reckoning during feature-less frames, image orientation compensation, scale estimation, motion prediction. Standard tactical IMUs provide 100-400Hz data | Low — standard IMU integration | **Modified** — specify: IMU data includes gyroscope + accelerometer at ≥100Hz; will be used for orientation compensation and dead-reckoning fallback | -| Weather | Mostly sunny | Favorable for visual methods. Shadows can actually help feature matching. Reduces image quality variability | Low — favorable condition | No change | -| Satellite provider | Google Maps (potentially outdated) | **Critical limitation**: Google Maps satellite API has usage limits, unknown update frequency for eastern Ukraine, potential conflict-zone restrictions. Resolution may not meet 0.5 m/px in rural areas. No guarantee of recency | **High** — single-provider dependency is a significant risk | **Modified** — consider: (1) downloading tiles ahead of time for the operational area, (2) having a fallback provider strategy | -| Photo count | Up to 3000, typically 500-1500 | At 3fps and 500-1500 photos: 3-8 minutes of flight. At ~100m spacing: 50-150km route. Memory for 3000 pre-extracted satellite feature maps needs careful management on 8GB | Medium — batch processing and memory management needed | **Modified** — add: pipeline must manage memory for up to 3000 frames on 8GB device | -| Sharp turns | Next photo may have no common objects with previous | This is the hardest edge case. Complete visual discontinuity requires satellite-based re-localization. IMU provides heading/velocity for bridging. System must be architected around this possibility | High — drives core architecture decision | No change — already captured as a defining constraint | -| Processing hardware | Jetson Orin Nano Super, 67 TOPS | 8GB shared LPDDR5, 1024 CUDA cores, 32 Tensor Cores, 102 GB/s bandwidth. TensorRT for inference optimization. Power: 7-25W. Significantly less capable than desktop GPU | **Critical** — all processing must fit within 8GB shared memory, pipeline must be optimized for TensorRT | **Modified** — CONTRADICTS AC's RTX 2060 reference. Must be the binding constraint | - -## Key Findings - -1. **CRITICAL CONTRADICTION**: The AC mentions "RTX 2060 compatibility" (16GB RAM + 6GB VRAM) but the restriction specifies Jetson Orin Nano Super (8GB shared memory). These are fundamentally different platforms. **The Jetson must be the binding constraint.** All processing, including model weights, image buffers, and intermediate results, must fit within ~6-7GB usable memory (OS takes ~1-1.5GB). - -2. **Satellite Imagery Risk**: Google Maps as the sole satellite provider for a conflict zone in eastern Ukraine presents significant quality, resolution, and recency risks. The 0.3 m/px "ideal" resolution is unlikely available from Google Maps for this region. The system design must be robust to degraded satellite reference quality (0.5-1.0 m/px). - -3. **Accuracy is Achievable but Conditional**: The 50m/80% and 20m/60% accuracy targets are achievable based on recent research (SatLoc 2025: <15m with adaptive fusion), but **only when satellite corrections are successful**. VO-only segments will drift ~1% of distance traveled. The system must maximize satellite correction frequency. - -4. **Sharp Turn Handling Drives Architecture**: The requirement to handle disconnected route segments with no visual overlap between consecutive frames means the system cannot rely solely on sequential VO. It must have an independent satellite-based geo-localization capability for each frame or segment — this is a core architectural requirement. - -5. **Processing Time is Feasible**: <5s per image on Jetson Orin Nano Super is achievable with: (a) image downsampling (e.g., to 2000x1300), (b) TensorRT-optimized models, (c) efficient satellite region cropping. GPU-accelerated feature extraction takes ~50ms, matching ~100-500ms, satellite matching ~1-3s. - -6. **Missing AC: Object Center Coordinates**: The problem statement mentions "coordinates of the center of any object in these photos" but no acceptance criterion specifies the accuracy requirement for this. Need to add. - -7. **Missing AC: DEM/Elevation Data**: Research shows terrain elevation is a primary error source for pixel-to-meter conversion at these altitudes. If terrain variations are >50m, a DEM is needed. No current restriction mentions DEM availability. - -8. **Missing AC: Offline Preprocessing Time**: No constraint on how long satellite image preprocessing can take before the flight. - -9. **"70%" in Sharp Turn AC is Ambiguous**: "at an angle of less than 70%" — this likely means 70 degrees, not 70%. - -## Sources - -- SatLoc: Hierarchical Adaptive Fusion Framework for GNSS-denied UAV Localization (2025) — <15m error, >90% coverage, 2+ Hz on edge hardware -- Mateos-Ramirez et al. "Visual Odometry in GPS-Denied Zones for Fixed-Wing UAV" (2024) — 142.88m mean error over 17km at 1000m+ altitude, 0.83% error rate with satellite correction -- NVIDIA Jetson Orin Nano Super specs: 8GB LPDDR5, 67 TOPS, 1024 CUDA cores, 102 GB/s bandwidth -- cuda-efficient-features: Feature extraction benchmarks — 4K in ~12ms on Jetson Xavier -- SIFT+LightGlue for UAV image mosaicking (ISPRS 2025) — superior performance across diverse scenarios -- SuperPoint+LightGlue comparative analysis (2024) — best balance of robustness, accuracy, efficiency -- Google Maps satellite resolution: 0.15m-30m depending on location and source imagery -- VIO drift benchmarks: 0.82-1% of distance traveled (EuRoC, outdoor flights) -- UAVSAR cross-modality matching: 1.83-2.86m RMSE with deep learning approach (Springer 2026) diff --git a/_docs/00_research/gps_denied_nav/00_question_decomposition.md b/_docs/00_research/gps_denied_nav/00_question_decomposition.md deleted file mode 100644 index 7a7d15f..0000000 --- a/_docs/00_research/gps_denied_nav/00_question_decomposition.md +++ /dev/null @@ -1,88 +0,0 @@ -# Question Decomposition - -## Original Question -Research the GPS-denied onboard navigation problem for a fixed-wing UAV and find the best solution architecture. The system must determine frame-center GPS coordinates using visual odometry, satellite image matching, and IMU fusion — all running on a Jetson Orin Nano Super (8GB shared memory, 67 TOPS). - -## Active Mode -Mode A Phase 2 — Initial Research (Problem & Solution) - -## Rationale -No existing solution drafts. Full problem decomposition and solution research needed. - -## Problem Context Summary (from INPUT_DIR) -- **Platform**: Fixed-wing UAV, camera pointing down (not stabilized), 400m altitude max 1km -- **Camera**: ADTi Surveyor Lite 26S v2, 26MP (6252x4168), focal length 25mm, sensor width 23.5mm -- **GSD at 400m**: ~6cm/pixel, footprint ~375x250m -- **Frame rate**: 3 fps (interval ~333ms, real-world could be 400-500ms) -- **Photo count**: 500-3000 per flight -- **IMU**: Available at high rate -- **Initial GPS**: Known; GPS may be denied/spoofed during flight -- **Satellite reference**: Pre-uploaded Google Maps tiles -- **Hardware**: Jetson Orin Nano Super, 8GB shared memory, 67 TOPS -- **Region**: Eastern/southern Ukraine (conflict zone) -- **Key challenge**: Reconnecting disconnected route segments after sharp turns - -## Question Type Classification -**Decision Support** — we need to evaluate and select the best architectural approach and component technologies for each part of the pipeline. - -## Research Subject Boundary Definition - -| Dimension | Boundary | -|-----------|----------| -| Population | Fixed-wing UAVs with nadir cameras at 200-1000m altitude | -| Geography | Rural/semi-urban terrain in eastern Ukraine | -| Timeframe | Current state-of-the-art (2023-2026) | -| Level | Edge computing (Jetson-class, 8GB memory), real-time processing | - -## Decomposed Sub-Questions - -### A. Existing/Competitor Solutions -1. What existing systems solve GPS-denied UAV visual navigation? -2. What open-source implementations exist for VO + satellite matching? -3. What commercial/military solutions address this problem? - -### B. Architecture Components -4. What is the optimal pipeline architecture (sequential vs parallel, streaming)? -5. How should VO, satellite matching, and IMU fusion be combined (loosely vs tightly coupled)? -6. How to handle disconnected route segments (the core architectural challenge)? - -### C. Visual Odometry Component -7. What VO algorithms work best for aerial nadir imagery on edge hardware? -8. What feature extractors/matchers are optimal for Jetson (SuperPoint, ORB, XFeat)? -9. How to handle scale estimation with known altitude and camera parameters? -10. What is the optimal image downsampling strategy for 26MP on 8GB memory? - -### D. Satellite Image Matching Component -11. How to efficiently match UAV frames against pre-loaded satellite tiles? -12. What cross-view matching methods work for aerial-to-satellite registration? -13. How to preprocess and index satellite tiles for fast retrieval? -14. How to handle resolution mismatch (6cm UAV vs 50cm+ satellite)? - -### E. IMU Fusion Component -15. How to fuse IMU data with visual estimates (EKF, UKF, factor graph)? -16. How to use IMU for dead-reckoning during feature-less frames? -17. How to use IMU for image orientation compensation (non-stabilized camera)? - -### F. Edge Optimization -18. How to fit the full pipeline in 8GB shared memory? -19. What TensorRT optimizations are available for feature extractors? -20. How to achieve <5s per frame on Jetson Orin Nano Super? - -### G. API & Streaming -21. What is the best approach for REST API + SSE on Python/Jetson? -22. How to implement progressive result refinement? - -## Timeliness Sensitivity Assessment - -- **Research Topic**: GPS-denied UAV visual navigation with edge processing -- **Sensitivity Level**: 🟠 High -- **Rationale**: Deep learning feature matchers (SuperPoint, LightGlue, XFeat) and edge inference frameworks (TensorRT) evolve rapidly. Jetson Orin Nano Super is a recent (Dec 2024) product. Cross-view geo-localization is an active research area. -- **Source Time Window**: 12 months (prioritize 2025-2026) -- **Priority official sources to consult**: - 1. NVIDIA Jetson documentation and benchmarks - 2. OpenCV / kornia / hloc official docs - 3. Recent papers on cross-view geo-localization (CVPR, ECCV, ICCV 2024-2025) -- **Key version information to verify**: - - JetPack SDK: Current version ____ - - SuperPoint/LightGlue: Latest available for TensorRT ____ - - XFeat: Version and Jetson compatibility ____ diff --git a/_docs/00_research/gps_denied_nav/01_source_registry.md b/_docs/00_research/gps_denied_nav/01_source_registry.md deleted file mode 100644 index a18a285..0000000 --- a/_docs/00_research/gps_denied_nav/01_source_registry.md +++ /dev/null @@ -1,151 +0,0 @@ -# Source Registry - -## Source #1 -- **Title**: Visual Odometry in GPS-Denied Zones for Fixed-Wing UAV with Reduced Accumulative Error Based on Satellite Imagery -- **Link**: https://www.mdpi.com/2076-3417/14/16/7420 -- **Tier**: L1 -- **Publication Date**: 2024-08-22 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Fixed-wing UAV GPS-denied navigation -- **Research Boundary Match**: ✅ Full match -- **Summary**: VO + satellite correction pipeline for fixed-wing UAV at 1000m+ altitude. Mean error 142.88m over 17km (0.83%). Uses ORB features, centroid-based displacement, Kalman filter smoothing, quadtree for satellite keypoint indexing. -- **Related Sub-question**: A1, B5, C7, D11 - -## Source #2 -- **Title**: SatLoc: Hierarchical Adaptive Fusion Framework for GNSS-denied UAV Localization -- **Link**: https://www.scilit.com/publications/e5cafaf875a49297a62b298a89d5572f -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: UAV localization in GNSS-denied environments -- **Research Boundary Match**: ✅ Full match -- **Summary**: Three-layer fusion: DinoV2 for satellite geo-localization, XFeat for VO, optical flow for velocity. Adaptive confidence-based weighting. <15m error, >90% coverage, 2+ Hz on edge hardware. -- **Related Sub-question**: B4, B5, C8, D12 - -## Source #3 -- **Title**: XFeat: Accelerated Features for Lightweight Image Matching (CVPR 2024) -- **Link**: https://arxiv.org/abs/2404.19174 -- **Tier**: L1 -- **Publication Date**: 2024-04 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Edge device feature matching -- **Research Boundary Match**: ✅ Full match -- **Summary**: 5x faster than SuperPoint, runs on CPU at VGA resolution. Sparse and semi-dense matching. TensorRT deployment available for Jetson. Comparable accuracy to SuperPoint. -- **Related Sub-question**: C8, F18, F20 - -## Source #4 -- **Title**: XFeat TensorRT Implementation -- **Link**: https://github.com/PranavNedunghat/XFeatTensorRT -- **Tier**: L2 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: C++ TensorRT implementation of XFeat, tested on Jetson Orin NX 16GB with JetPack 6.0, CUDA 12.2, TensorRT 8.6. -- **Related Sub-question**: C8, F18, F19 - -## Source #5 -- **Title**: SuperPoint+LightGlue TensorRT Deployment -- **Link**: https://github.com/fettahyildizz/superpoint_lightglue_tensorrt -- **Tier**: L2 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: C++ TensorRT implementation of SuperPoint+LightGlue. Production-ready deployment for Jetson platforms. -- **Related Sub-question**: C8, F19 - -## Source #6 -- **Title**: FP8 Quantized LightGlue in TensorRT -- **Link**: https://fabio-sim.github.io/blog/fp8-quantized-lightglue-tensorrt-nvidia-model-optimizer/ -- **Tier**: L2 -- **Publication Date**: 2026 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: Up to ~6x speedup with FP8 quantization. Requires Hopper/Ada Lovelace GPUs (not available on Jetson Orin Nano Ampere). FP16 is the best available precision for Orin Nano. -- **Related Sub-question**: F19 - -## Source #7 -- **Title**: NVIDIA JetPack 6.2 Release Notes -- **Link**: https://docs.nvidia.com/jetson/archives/jetpack-archived/jetpack-62/release-notes/index.html -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: CUDA 12.6.10, TensorRT 10.3.0, cuDNN 9.3. Super Mode for Orin Nano: up to 2x inference performance, 50% memory bandwidth boost. Power modes: 15W, 25W, MAXN SUPER. -- **Related Sub-question**: F18, F19, F20 - -## Source #8 -- **Title**: cuda-efficient-features (GPU feature detection benchmarks) -- **Link**: https://github.com/fixstars/cuda-efficient-features -- **Tier**: L2 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: 4K detection: 12ms on Jetson Xavier. 8K: 27.5ms. 40K keypoints extraction: 20-25ms on Xavier. Orin Nano Super should be comparable or better. -- **Related Sub-question**: F20 - -## Source #9 -- **Title**: Adaptive Covariance Hybrid EKF/UKF for Visual-Inertial Odometry -- **Link**: https://arxiv.org/abs/2512.17505 -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: Hybrid EKF/UKF achieves 49% better position accuracy, 57% better rotation accuracy than ESKF alone, at 48% lower computational cost than full UKF. Includes adaptive sensor confidence scoring. -- **Related Sub-question**: E15 - -## Source #10 -- **Title**: SIFT+LightGlue for UAV Image Mosaicking (ISPRS 2025) -- **Link**: https://isprs-archives.copernicus.org/articles/XLVIII-2-W11-2025/169/2025/ -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: SIFT+LightGlue outperforms SuperPoint+LightGlue for UAV mosaicking across diverse scenarios. Superior in both low-texture and high-texture environments. -- **Related Sub-question**: C8, D12 - -## Source #11 -- **Title**: UAVision - GNSS-Denied UAV Visual Localization System -- **Link**: https://github.com/ArboriseRS/UAVision -- **Tier**: L4 -- **Publication Date**: 2024-2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: Open-source system using LightGlue for map matching. Includes image processing modules and visualization. -- **Related Sub-question**: A2 - -## Source #12 -- **Title**: TerboucheHacene/visual_localization -- **Link**: https://github.com/TerboucheHacene/visual_localization -- **Tier**: L4 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: Vision-based GNSS-free localization with SuperPoint/SuperGlue/GIM matching. Optimized VO + satellite image matching hybrid pipeline. Learning-based matchers for natural environments. -- **Related Sub-question**: A2, D12 - -## Source #13 -- **Title**: GNSS-Denied Geolocalization with Terrain Constraints -- **Link**: https://github.com/yfs90/gnss-denied-uav-geolocalization -- **Tier**: L4 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: No altimeters/IMU required, uses image matching + terrain constraints. GPS-comparable accuracy for day/night across varied terrain. -- **Related Sub-question**: A2 - -## Source #14 -- **Title**: Google Maps Tile API Documentation -- **Link**: https://developers.google.com/maps/documentation/tile/satellite -- **Tier**: L1 -- **Publication Date**: Current -- **Timeliness Status**: ✅ Currently valid -- **Summary**: Zoom levels 0-22. Satellite tiles via HTTPS. Session tokens required. Bulk download possible but subject to usage policies. -- **Related Sub-question**: D13 - -## Source #15 -- **Title**: NaviLoc: Trajectory-Level Visual Localization for GNSS-Denied UAV Navigation -- **Link**: https://www.mdpi.com/2504-446X/10/2/97 -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: Trajectory-level optimization rather than per-frame matching. Optimizes entire trajectory against satellite reference for improved accuracy. -- **Related Sub-question**: B4, D11 - -## Source #16 -- **Title**: GSD Estimation for UAV Photogrammetry -- **Link**: https://blog.truegeometry.com/calculators/UAV_photogrammetry_workflows_calculation.html -- **Tier**: L3 -- **Publication Date**: Current -- **Timeliness Status**: ✅ Currently valid -- **Summary**: GSD = (sensor_width × altitude) / (focal_length × image_width). For our case: (23.5mm × 400m) / (25mm × 6252) = 0.06 m/pixel. -- **Related Sub-question**: C9 diff --git a/_docs/00_research/gps_denied_nav/02_fact_cards.md b/_docs/00_research/gps_denied_nav/02_fact_cards.md deleted file mode 100644 index 962ce99..0000000 --- a/_docs/00_research/gps_denied_nav/02_fact_cards.md +++ /dev/null @@ -1,121 +0,0 @@ -# Fact Cards - -## Fact #1 -- **Statement**: XFeat achieves up to 5x faster inference than SuperPoint while maintaining comparable accuracy for pose estimation. It runs in real-time on CPU at VGA resolution. -- **Source**: Source #3 (CVPR 2024 paper) -- **Phase**: Phase 2 -- **Target Audience**: Edge device deployments -- **Confidence**: ✅ High -- **Related Dimension**: Feature Extraction - -## Fact #2 -- **Statement**: XFeat TensorRT implementation exists and is tested on Jetson Orin NX 16GB with JetPack 6.0, CUDA 12.2, TensorRT 8.6. -- **Source**: Source #4 -- **Phase**: Phase 2 -- **Target Audience**: Jetson platform deployment -- **Confidence**: ✅ High -- **Related Dimension**: Feature Extraction, Edge Optimization - -## Fact #3 -- **Statement**: SatLoc framework achieves <15m absolute localization error with >90% trajectory coverage at 2+ Hz on edge hardware, using DinoV2 for satellite matching, XFeat for VO, and optical flow for velocity. -- **Source**: Source #2 -- **Phase**: Phase 2 -- **Target Audience**: GNSS-denied UAV localization -- **Confidence**: ⚠️ Medium (paper details not fully accessible) -- **Related Dimension**: Overall Architecture, Accuracy - -## Fact #4 -- **Statement**: Mateos-Ramirez et al. achieved 142.88m mean error over 17km (0.83% error rate) with VO + satellite correction on a fixed-wing UAV at 1000m+ altitude. Without satellite correction, error accumulated to 850m+ over 17km. -- **Source**: Source #1 -- **Phase**: Phase 2 -- **Target Audience**: Fixed-wing UAV at high altitude -- **Confidence**: ✅ High -- **Related Dimension**: Accuracy, Architecture - -## Fact #5 -- **Statement**: VIO systems typically drift 0.8-1% of distance traveled. Between satellite corrections at 1km intervals, expected drift is ~10m. -- **Source**: Multiple sources (arxiv VIO benchmarks) -- **Phase**: Phase 2 -- **Target Audience**: Aerial VIO systems -- **Confidence**: ✅ High -- **Related Dimension**: VO Drift - -## Fact #6 -- **Statement**: Jetson Orin Nano Super: 8GB LPDDR5 shared memory, 1024 CUDA cores, 32 Tensor Cores, 102 GB/s bandwidth, 67 TOPS INT8. JetPack 6.2: CUDA 12.6.10, TensorRT 10.3.0. -- **Source**: Source #7 -- **Phase**: Phase 2 -- **Target Audience**: Hardware specification -- **Confidence**: ✅ High -- **Related Dimension**: Edge Optimization - -## Fact #7 -- **Statement**: CUDA-accelerated feature detection at 4K (3840x2160): ~12ms on Jetson Xavier. At 8K: ~27.5ms. Descriptor extraction for 40K keypoints: ~20-25ms on Xavier. Orin Nano Super has comparable or slightly better compute. -- **Source**: Source #8 -- **Phase**: Phase 2 -- **Target Audience**: Jetson GPU performance -- **Confidence**: ✅ High -- **Related Dimension**: Processing Time - -## Fact #8 -- **Statement**: Hybrid EKF/UKF achieves 49% better position accuracy than ESKF alone at 48% lower computational cost than full UKF. Includes adaptive sensor confidence scoring based on image entropy and motion blur. -- **Source**: Source #9 -- **Phase**: Phase 2 -- **Target Audience**: VIO fusion -- **Confidence**: ✅ High -- **Related Dimension**: Sensor Fusion - -## Fact #9 -- **Statement**: SIFT+LightGlue outperforms SuperPoint+LightGlue for UAV mosaicking across diverse scenarios (low-texture agricultural and high-texture urban). -- **Source**: Source #10 -- **Phase**: Phase 2 -- **Target Audience**: UAV image matching -- **Confidence**: ✅ High -- **Related Dimension**: Feature Matching - -## Fact #10 -- **Statement**: GSD for our system at 400m: (23.5mm × 400m) / (25mm × 6252px) = 0.060 m/pixel. Image footprint: 6252 × 0.06 = 375m width, 4168 × 0.06 = 250m height. -- **Source**: Source #16 + camera parameters -- **Phase**: Phase 2 -- **Target Audience**: Our specific system -- **Confidence**: ✅ High -- **Related Dimension**: Scale Estimation - -## Fact #11 -- **Statement**: Google Maps satellite tiles available via Tile API at zoom levels 0-22. Max zoom varies by region. For eastern Ukraine, zoom 18 (~0.6 m/px) is typically available; zoom 19 (~0.3 m/px) may not be. -- **Source**: Source #14 -- **Phase**: Phase 2 -- **Target Audience**: Satellite imagery -- **Confidence**: ⚠️ Medium (exact zoom availability for eastern Ukraine unverified) -- **Related Dimension**: Satellite Reference - -## Fact #12 -- **Statement**: FP8 quantization for LightGlue requires Hopper/Ada GPUs. Jetson Orin Nano uses Ampere architecture — limited to FP16 as best TensorRT precision. -- **Source**: Source #6, Source #7 -- **Phase**: Phase 2 -- **Target Audience**: Jetson optimization -- **Confidence**: ✅ High -- **Related Dimension**: Edge Optimization - -## Fact #13 -- **Statement**: SuperPoint+LightGlue TensorRT C++ deployment is available and production-tested. ONNX Runtime path achieves 2-4x speedup over compiled PyTorch. -- **Source**: Source #5, Source #6 -- **Phase**: Phase 2 -- **Target Audience**: Production deployment -- **Confidence**: ✅ High -- **Related Dimension**: Feature Matching, Edge Optimization - -## Fact #14 -- **Statement**: Cross-view matching (UAV-to-satellite) is fundamentally harder than same-view matching due to extreme viewpoint differences. Deep learning embeddings (DinoV2, CLIP-based) are the state-of-the-art for coarse retrieval. Local features are used for fine alignment. -- **Source**: Multiple (Sources #2, #12, #15) -- **Phase**: Phase 2 -- **Target Audience**: Cross-view geo-localization -- **Confidence**: ✅ High -- **Related Dimension**: Satellite Matching - -## Fact #15 -- **Statement**: Quadtree spatial indexing enables O(log n) nearest-neighbor lookup for satellite keypoints. Combined with GeoHash for fast region encoding, this is the standard approach for tile management. -- **Source**: Sources #1, #14 -- **Phase**: Phase 2 -- **Target Audience**: Spatial indexing -- **Confidence**: ✅ High -- **Related Dimension**: Satellite Tile Management diff --git a/_docs/00_research/gps_denied_nav/03_comparison_framework.md b/_docs/00_research/gps_denied_nav/03_comparison_framework.md deleted file mode 100644 index 87cde80..0000000 --- a/_docs/00_research/gps_denied_nav/03_comparison_framework.md +++ /dev/null @@ -1,71 +0,0 @@ -# Comparison Framework - -## Selected Framework Type -Decision Support — evaluating solution options per component - -## Architecture Components to Evaluate - -1. Feature Extraction & Matching (VO frame-to-frame) -2. Satellite Image Matching (cross-view geo-registration) -3. Sensor Fusion (VO + satellite + IMU) -4. Satellite Tile Preprocessing & Indexing -5. Image Downsampling Strategy -6. Re-localization (disconnected segments) -7. API & Streaming Layer - -## Component 1: Feature Extraction & Matching (VO) - -| Dimension | XFeat | SuperPoint + LightGlue | ORB (OpenCV) | -|-----------|-------|----------------------|--------------| -| Speed (Jetson) | ~2-5ms per frame (VGA), 5x faster than SuperPoint | ~15-50ms per frame (VGA, TensorRT FP16) | ~5-10ms per frame (CUDA) | -| Accuracy | Comparable to SuperPoint on pose estimation | State-of-the-art for local features | Lower accuracy, not scale-invariant | -| Memory | <100MB model | ~200-400MB model+inference | Negligible | -| TensorRT support | Yes (C++ impl available for Jetson Orin NX) | Yes (C++ impl available) | N/A (native CUDA) | -| Cross-view capability | Limited (same-view designed) | Better with LightGlue attention | Poor for cross-view | -| Rotation invariance | Moderate | Good with LightGlue | Good (by design) | -| Jetson validation | Tested on Orin NX (JetPack 6.0) | Tested on multiple Jetson platforms | Native OpenCV CUDA | -| **Fit for VO** | ✅ Best — fast, accurate, Jetson-proven | ⚠️ Good but heavier | ⚠️ Fast but less accurate | -| **Fit for satellite matching** | ⚠️ Moderate | ✅ Better for cross-view with attention | ❌ Poor for cross-view | - -## Component 2: Satellite Image Matching (Cross-View) - -| Dimension | Local Feature Matching (SIFT/SuperPoint + LightGlue) | Global Descriptor Retrieval (DinoV2/CLIP) | Template Matching (NCC) | -|-----------|-----------------------------------------------------|------------------------------------------|------------------------| -| Approach | Extract keypoints in both UAV and satellite images, match descriptors | Encode both images into global vectors, compare by distance | Slide UAV image over satellite tile, compute correlation | -| Accuracy | Sub-pixel when matches found (best for fine alignment) | Tile-level (~50-200m depending on tile size) | Pixel-level but sensitive to appearance changes | -| Speed | ~100-500ms for match+geometric verification | ~50-100ms for descriptor comparison | ~500ms-2s for large search area | -| Robustness to viewpoint | Good with LightGlue attention | Excellent (trained for cross-view) | Poor (requires similar viewpoint) | -| Memory | ~300-500MB (model + keypoints) | ~200-500MB (model) | Low | -| Failure rate | High in low-texture, seasonal changes | Lower — semantic understanding | High in changed scenes | -| **Recommended role** | Fine alignment (after coarse retrieval) | Coarse retrieval (select candidate tile) | Not recommended | - -## Component 3: Sensor Fusion - -| Dimension | EKF (Extended Kalman Filter) | Error-State EKF (ESKF) | Hybrid ESKF/UKF | Factor Graph (GTSAM) | -|-----------|-------------------------------|------------------------|------------------|---------------------| -| Accuracy | Baseline | Better for rotation | 49% better than ESKF | Best overall | -| Compute cost | Lowest | Low | 48% less than full UKF | Highest | -| Implementation complexity | Low | Medium | Medium-High | High | -| Handles non-linearity | Linearization errors | Better for small errors | Best among KF variants | Full non-linear | -| Real-time on Jetson | ✅ | ✅ | ✅ | ⚠️ Depends on graph size | -| Multi-rate sensor support | Manual | Manual | Manual | Native | -| **Fit** | ⚠️ Baseline option | ✅ Good starting point | ✅ Best KF option | ⚠️ Overkill for this system | - -## Component 4: Satellite Tile Management - -| Dimension | GeoHash + In-Memory | Quadtree + Memory-Mapped Files | Pre-extracted Feature DB | -|-----------|--------------------|-----------------------------|------------------------| -| Lookup speed | O(1) hash | O(log n) tree traversal | O(1) hash + feature load | -| Memory usage | All tiles in RAM | On-demand loading | Features only (smaller) | -| Preprocessing | Fast | Moderate | Slow (extract all features offline) | -| Flexibility | Fixed grid | Adaptive resolution | Fixed per-tile | -| **Fit for 8GB** | ❌ Too much RAM for large areas | ✅ Memory-efficient | ✅ Best — smallest footprint | - -## Component 5: Image Downsampling Strategy - -| Dimension | Fixed Resize (e.g., 1600x1066) | Pyramid (multi-scale) | ROI-based (center crop + full) | -|-----------|-------------------------------|----------------------|-------------------------------| -| Speed | Fast, single scale | Slower, multiple passes | Medium | -| Accuracy | Good if GSD ratio maintained | Best for multi-scale features | Good for center, loses edges | -| Memory | ~5MB per frame | ~7-8MB per frame | ~6MB per frame | -| **Fit** | ✅ Best tradeoff | ⚠️ Unnecessary complexity | ⚠️ Loses coverage | diff --git a/_docs/00_research/gps_denied_nav/04_reasoning_chain.md b/_docs/00_research/gps_denied_nav/04_reasoning_chain.md deleted file mode 100644 index a25a108..0000000 --- a/_docs/00_research/gps_denied_nav/04_reasoning_chain.md +++ /dev/null @@ -1,129 +0,0 @@ -# Reasoning Chain - -## Dimension 1: Feature Extraction for Visual Odometry - -### Fact Confirmation -XFeat is 5x faster than SuperPoint (Fact #1), has TensorRT deployment on Jetson (Fact #2), and comparable accuracy for pose estimation. SatLoc (the most relevant state-of-the-art system) uses XFeat for its VO component (Fact #3). - -### Reference Comparison -SuperPoint+LightGlue is more accurate for cross-view matching but heavier. ORB is fast but less accurate and not robust to appearance changes. SIFT+LightGlue is best for mosaicking (Fact #9) but slower. - -### Conclusion -**XFeat for VO (frame-to-frame)** — it's the fastest learned feature, Jetson-proven, and used by the closest state-of-the-art system (SatLoc). For satellite matching, a different approach is needed because cross-view matching requires viewpoint-invariant features. - -### Confidence -✅ High — supported by SatLoc architecture and CVPR 2024 benchmarks. - ---- - -## Dimension 2: Satellite Image Matching Strategy - -### Fact Confirmation -Cross-view matching is fundamentally harder than same-view (Fact #14). Deep learning embeddings (DinoV2) are state-of-the-art for coarse retrieval (Fact #3). Local features are better for fine alignment. SatLoc uses DinoV2 for satellite matching specifically. - -### Reference Comparison -A two-stage coarse-to-fine approach is the dominant pattern in literature: (1) global descriptor retrieves candidate region, (2) local feature matching refines position. Pure local-feature matching has high failure rate for cross-view due to extreme viewpoint differences. - -### Conclusion -**Two-stage approach**: (1) Coarse — use a lightweight global descriptor to find the best-matching satellite tile within the search area (VO-predicted position ± uncertainty radius). (2) Fine — use local feature matching (SuperPoint+LightGlue or XFeat) between UAV frame and the matched satellite tile to get precise position. The coarse stage can also serve as the re-localization mechanism for disconnected segments. - -### Confidence -✅ High — consensus across multiple recent papers and the SatLoc system. - ---- - -## Dimension 3: Sensor Fusion Approach - -### Fact Confirmation -Hybrid ESKF/UKF achieves 49% better accuracy than ESKF alone at 48% lower cost than full UKF (Fact #8). Factor graphs (GTSAM) offer the best accuracy but are computationally expensive. - -### Reference Comparison -For our system: IMU runs at 100-400Hz, VO at ~3Hz (frame rate), satellite corrections at variable rate (whenever matching succeeds). We need multi-rate fusion that handles intermittent satellite corrections and continuous IMU. - -### Conclusion -**Error-State EKF (ESKF)** as the baseline fusion approach — it's well-understood, lightweight, handles multi-rate sensors naturally, and is proven for VIO on edge hardware. Upgrade to hybrid ESKF/UKF if ESKF accuracy is insufficient. Factor graphs are overkill for this real-time edge system. - -The filter state: position (lat/lon), velocity, orientation (quaternion), IMU biases. Measurements: VO-derived displacement (high rate), satellite-derived absolute position (variable rate), IMU (highest rate for prediction). - -### Confidence -✅ High — ESKF is the standard choice for embedded VIO systems. - ---- - -## Dimension 4: Satellite Tile Preprocessing & Indexing - -### Fact Confirmation -Quadtree enables O(log n) lookups (Fact #15). Pre-extracting features offline saves runtime compute. 8GB memory limits in-memory tile storage. - -### Reference Comparison -Full tiles in memory is infeasible for large areas. Memory-mapped files allow on-demand loading. Pre-extracted feature databases have the smallest runtime footprint. - -### Conclusion -**Offline preprocessing pipeline**: -1. Download Google Maps satellite tiles at max zoom (18-19) for the operational area -2. Extract features (XFeat or SuperPoint) from each tile -3. Compute global descriptors (lightweight, e.g., NetVLAD or cosine-pooled XFeat descriptors) per tile -4. Store: tile metadata (GPS bounds, zoom level), features + descriptors in a GeoHash-indexed database -5. Build spatial index (GeoHash) for fast lookup by GPS region - -**Runtime**: Given VO-estimated position, query GeoHash to find nearby tiles, compare global descriptors for coarse match, then local feature matching for fine alignment. - -### Confidence -✅ High — standard approach used by all relevant systems. - ---- - -## Dimension 5: Image Downsampling Strategy - -### Fact Confirmation -26MP images need downsampling for 8GB device (Fact #6). Feature extraction at 4K takes ~12ms on Jetson Xavier (Fact #7). UAV GSD at 400m is ~6cm/px (Fact #10). Satellite GSD is ~60cm/px at zoom 18. - -### Reference Comparison -For VO (frame-to-frame): features at full resolution are wasteful — consecutive frames at 6cm GSD overlap ~80%, and features at lower resolution are sufficient for displacement estimation. For satellite matching: we need to match at satellite resolution (~60cm/px), so downsampling to match satellite GSD is natural. - -### Conclusion -**Downsample to ~1600x1066** (factor ~4x each dimension). This yields ~24cm/px GSD — still 2.5x finer than satellite, sufficient for feature matching. Image size: ~5MB (RGB). Feature extraction at this resolution: <10ms. This is the single resolution for both VO and satellite matching. - -### Confidence -✅ High — standard practice for edge processing of high-res imagery. - ---- - -## Dimension 6: Disconnected Segment Handling - -### Fact Confirmation -SatLoc uses satellite matching as an independent localization source that works regardless of VO state (Fact #3). The AC requires reconnecting disconnected segments as a core capability. - -### Reference Comparison -Pure VO cannot handle zero-overlap transitions. IMU dead-reckoning bridges short gaps (seconds). Satellite-based re-localization provides absolute position regardless of VO state. - -### Conclusion -**Independent satellite localization per frame** — every frame attempts satellite matching regardless of VO state. This naturally handles disconnected segments: -1. When VO succeeds: satellite matching refines position (high confidence) -2. When VO fails (sharp turn): satellite matching provides absolute position (sole source) -3. When both fail: IMU dead-reckoning with low confidence score -4. After 3 consecutive total failures: request user input - -Segment reconnection is automatic: all positions are in the same global (WGS84) frame via satellite matching. No explicit "reconnection" needed — segments share the satellite reference. - -### Confidence -✅ High — this is the key architectural insight. - ---- - -## Dimension 7: Processing Pipeline Architecture - -### Fact Confirmation -<5s per frame required (AC). Feature extraction ~10ms, VO matching ~20-50ms, satellite coarse retrieval ~50-100ms, satellite fine matching ~200-500ms, fusion ~1ms. Total: ~300-700ms per frame. - -### Conclusion -**Pipelined parallel architecture**: -- Thread 1 (Camera): Capture frame, downsample, extract features → push to queue -- Thread 2 (VO): Match with previous frame, compute displacement → push to fusion -- Thread 3 (Satellite): Search nearby tiles, coarse retrieval, fine matching → push to fusion -- Thread 4 (Fusion): ESKF prediction (IMU), update (VO), update (satellite) → emit result via SSE - -VO and satellite matching can run in parallel for each frame. Fusion integrates results as they arrive. This enables <1s per frame total latency. - -### Confidence -✅ High — standard producer-consumer pipeline. diff --git a/_docs/00_research/gps_denied_nav/05_validation_log.md b/_docs/00_research/gps_denied_nav/05_validation_log.md deleted file mode 100644 index a5f751c..0000000 --- a/_docs/00_research/gps_denied_nav/05_validation_log.md +++ /dev/null @@ -1,98 +0,0 @@ -# Validation Log - -## Validation Scenario 1: Normal Flight (80% of time) -UAV flies straight, consecutive frames overlap ~70-80%. Terrain has moderate texture (agricultural + urban mix). - -### Expected Based on Conclusions -- XFeat extracts features in ~5ms, VO matching in ~20ms -- Satellite matching succeeds: coarse retrieval ~50ms, fine matching ~300ms -- ESKF fuses both: position accuracy ~10-20m (satellite-anchored) -- Total processing: <500ms per frame -- Confidence: HIGH - -### Actual Validation (against literature) -SatLoc reports <15m error with >90% coverage under similar conditions. Mateos-Ramirez reports 0.83% drift with satellite correction. Both align with our expected performance. - -### Result: ✅ PASS - ---- - -## Validation Scenario 2: Sharp Turn (5-10% of time) -UAV makes a 60-degree turn. Next frame has <5% overlap with previous. Heading changes rapidly. - -### Expected Based on Conclusions -- VO fails (insufficient feature overlap) — detected by low match count -- IMU provides heading and approximate displacement for ~1-2 frames -- Satellite matching attempts independent localization of the new frame -- If satellite match succeeds: position recovered, segment continues -- If satellite match fails: IMU dead-reckoning with LOW confidence - -### Potential Issues -- Satellite matching may also fail if the frame is heavily tilted (non-nadir view during turn) -- IMU drift during turn: at 100m/s for 1s, displacement ~100m. IMU drift over 1s: ~1-5m — acceptable - -### Result: ⚠️ CONDITIONAL PASS — depends on satellite matching success during turn. Non-stabilized camera may produce tilted images that are harder to match. IMU provides reasonable bridge. - ---- - -## Validation Scenario 3: Disconnected Route (rare, <5%) -UAV completes segment A, makes a 90+ degree turn, flies a new heading. Segment B has no overlap with segment A. Multiple such segments possible. - -### Expected Based on Conclusions -- Each segment independently localizes via satellite matching -- No explicit reconnection needed — all in WGS84 frame -- Per-segment accuracy depends on satellite matching success rate -- Low-confidence gaps between segments until satellite match succeeds - -### Result: ✅ PASS — architecture handles this natively via independent per-frame satellite matching. - ---- - -## Validation Scenario 4: Memory-Constrained Operation (always) -3000 frames, 8GB shared memory. Full pipeline running. - -### Expected Based on Conclusions -- Downsampled frame: ~5MB per frame. Keep 2 in memory (current + previous): ~10MB -- XFeat model (TensorRT): ~50-100MB -- Satellite tile features (loaded tiles): ~200-500MB for tiles near current position -- ESKF state: <1MB -- OS + runtime: ~1.5GB -- Total: ~2-3GB active, well within 8GB - -### Potential Issues -- Satellite feature DB for large operational areas could be large on disk (not memory — loaded on demand) -- Need careful management of tile loading/unloading - -### Result: ✅ PASS — 8GB is sufficient with proper memory management. - ---- - -## Validation Scenario 5: Degraded Satellite Imagery -Google Maps tiles at 0.5-1.0 m/px resolution. Some areas have outdated imagery. Seasonal appearance changes. - -### Expected Based on Conclusions -- Coarse retrieval (global descriptors) should handle moderate appearance changes -- Fine matching may fail on outdated/seasonal tiles — confidence drops to LOW -- System falls back to VO + IMU in degraded areas -- Multiple consecutive failures → user input request - -### Potential Issues -- If large areas have degraded satellite imagery, the system may operate mostly in VO+IMU mode with significant drift -- 50m accuracy target may not be achievable in these areas - -### Result: ⚠️ CONDITIONAL PASS — system degrades gracefully, but accuracy targets depend on satellite quality. This is a known risk per Phase 1 assessment. - ---- - -## Review Checklist -- [x] Draft conclusions consistent with fact cards -- [x] No important dimensions missed -- [x] No over-extrapolation -- [x] Conclusions actionable/verifiable -- [x] Sharp turn handling addressed -- [x] Memory constraints validated -- [ ] Issue: Satellite imagery quality in eastern Ukraine remains a risk -- [ ] Issue: Non-stabilized camera during turns may degrade satellite matching - -## Conclusions Requiring No Revision -All major architectural decisions validated. Two known risks (satellite quality, non-stabilized camera during turns) are acknowledged and handled by the fallback hierarchy. diff --git a/_docs/00_research/gps_denied_nav_assessment/00_question_decomposition.md b/_docs/00_research/gps_denied_nav_assessment/00_question_decomposition.md deleted file mode 100644 index 817dfcf..0000000 --- a/_docs/00_research/gps_denied_nav_assessment/00_question_decomposition.md +++ /dev/null @@ -1,80 +0,0 @@ -# Question Decomposition — Solution Assessment (Mode B) - -## Original Question -Assess the existing solution draft (solution_draft01.md) for weak points, security vulnerabilities, and performance bottlenecks, then produce a revised solution draft. - -## Active Mode -Mode B: Solution Assessment — `solution_draft01.md` exists and is the highest-numbered draft. - -## Question Type Classification -- **Primary**: Problem Diagnosis — identify weak points, vulnerabilities, bottlenecks in existing solution -- **Secondary**: Decision Support — evaluate alternatives for identified issues - -## Research Subject Boundary Definition - -| Dimension | Boundary | -|-----------|----------| -| **Domain** | GPS-denied UAV visual navigation, aerial geo-referencing | -| **Geography** | Eastern/southern Ukraine (left of Dnipro River) — steppe terrain, potential conflict-related satellite imagery degradation | -| **Hardware** | Desktop/laptop with NVIDIA RTX 2060+, 16GB RAM, 6GB VRAM | -| **Software** | Python ecosystem, GPU-accelerated CV/ML | -| **Timeframe** | Current state-of-the-art (2024-2026), production-ready tools | -| **Scale** | 500-3000 images per flight, up to 6252×4168 resolution | - -## Problem Context Summary -- UAV aerial photos taken consecutively ~100m apart, camera pointing down (not autostabilized) -- Only starting GPS known — must determine GPS for all subsequent images -- Must handle: sharp turns, outlier photos (up to 350m gap), disconnected route segments -- Processing <5s/image, real-time SSE streaming, REST API service -- No IMU data available - -## Decomposed Sub-Questions - -### A: Cross-View Matching Viability -"Is SuperPoint+LightGlue with perspective warping reliable for UAV-to-satellite cross-view matching, or are there specialized cross-view methods that would perform better?" - -### B: Homography-Based VO Robustness -"Is homography-based VO (flat terrain assumption) robust enough for non-stabilized camera with potential roll/pitch variations and non-flat objects?" - -### C: Satellite Imagery Reliability -"What are the risks of relying solely on Google Maps satellite imagery for eastern Ukraine, and what fallback strategies exist?" - -### D: Processing Time Feasibility -"Are the processing time estimates (<5s per image) realistic on RTX 2060 with SuperPoint+LightGlue+satellite matching pipeline?" - -### E: Optimizer Specification -"Is the sliding window optimizer well-specified, and are there more proven alternatives like factor graph optimization?" - -### F: Camera Rotation Handling -"How should the system handle arbitrary image rotation from non-stabilized camera mount?" - -### G: Security Assessment -"What are the security vulnerabilities in the REST API + SSE architecture with image processing pipeline?" - -### H: Newer Tools & Libraries -"Are there newer (2025-2026) tools, models, or approaches that outperform the current selections (SuperPoint, LightGlue, etc.)?" - -### I: Segment Management Robustness -"Is the segment management strategy robust enough for multiple disconnected segments, especially when satellite anchoring fails for a segment?" - -### J: Memory & Resource Management -"Can the pipeline stay within 16GB RAM / 6GB VRAM while processing 3000 images at 6252×4168 resolution?" - ---- - -## Timeliness Sensitivity Assessment - -- **Research Topic**: GPS-denied UAV visual navigation using learned feature matching and satellite geo-referencing -- **Sensitivity Level**: 🟠 High -- **Rationale**: Computer vision feature matching models (SuperPoint, LightGlue, etc.) are actively evolving with new versions and competitors. However, the core algorithms (homography, VO, optimization) are stable. The tool ecosystem changes frequently. -- **Source Time Window**: 12 months (2025-2026) -- **Priority official sources to consult**: - 1. LightGlue / SuperPoint GitHub repos (releases, issues) - 2. OpenCV documentation (current version) - 3. Google Maps Tiles API documentation - 4. Recent aerial geo-referencing papers (2024-2026) -- **Key version information to verify**: - - LightGlue: current version and ONNX/TensorRT support status - - SuperPoint: current version and alternatives - - FastAPI: SSE support status - - Google Maps Tiles API: pricing, coverage, rate limits diff --git a/_docs/00_research/gps_denied_nav_assessment/01_source_registry.md b/_docs/00_research/gps_denied_nav_assessment/01_source_registry.md deleted file mode 100644 index 82734a8..0000000 --- a/_docs/00_research/gps_denied_nav_assessment/01_source_registry.md +++ /dev/null @@ -1,201 +0,0 @@ -# Source Registry — Solution Assessment (Mode B) - -## Source #1 -- **Title**: GLEAM: Learning to Match and Explain in Cross-View Geo-Localization -- **Link**: https://arxiv.org/abs/2509.07450 -- **Tier**: L1 -- **Publication Date**: 2025-09 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Cross-view geo-localization researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Framework for cross-view geo-localization with explainable matching across modalities. Demonstrates that specialized cross-view methods outperform generic feature matchers. - -## Source #2 -- **Title**: Robust UAV Image Mosaicking Using SIFT and LightGlue (ISPRS 2025) -- **Link**: https://isprs-archives.copernicus.org/articles/XLVIII-2-W11-2025/169/2025/ -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: UAV photogrammetry and aerial image processing -- **Research Boundary Match**: ✅ Full match -- **Summary**: SIFT+LightGlue achieves superior spatial consistency and reliability for UAV image mosaicking, including low-texture and high-rotation conditions. SIFT outperforms SuperPoint for rotation-heavy scenarios. - -## Source #3 -- **Title**: Precise GPS-Denied UAV Self-Positioning via Context-Enhanced Cross-View Geo-Localization (CEUSP) -- **Link**: https://arxiv.org/abs/2502.11408 / https://github.com/eksnew/ceusp -- **Tier**: L1 -- **Publication Date**: 2025-02 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: GPS-denied UAV navigation -- **Research Boundary Match**: ⚠️ Partial overlap (urban, not steppe) -- **Summary**: DINOv2-based cross-view matching for UAV self-positioning. State-of-the-art on DenseUAV benchmark. Uses retrieval-based (not feature-matching) approach. - -## Source #4 -- **Title**: SatLoc Dataset and Hierarchical Adaptive Fusion Framework -- **Link**: https://www.mdpi.com/2072-4292/17/17/3048 -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: GNSS-denied UAV navigation -- **Research Boundary Match**: ✅ Full match -- **Summary**: Three-layer architecture: DINOv2 for absolute geo-localization, XFeat for VO, optical flow for velocity. Adaptive fusion with confidence weighting. <15m absolute error on edge hardware. - -## Source #5 -- **Title**: LightGlue ONNX/TensorRT acceleration blog -- **Link**: https://fabio-sim.github.io/blog/accelerating-lightglue-inference-onnx-runtime-tensorrt/ -- **Tier**: L2 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: LightGlue users optimizing inference -- **Research Boundary Match**: ✅ Full match -- **Summary**: LightGlue ONNX achieves 2-4x speedup over PyTorch. FP8 quantization (Ada/Hopper GPUs only) adds 6x more. RTX 2060 does NOT support FP8. - -## Source #6 -- **Title**: LightGlue-ONNX GitHub repository -- **Link**: https://github.com/fabio-sim/LightGlue-ONNX -- **Tier**: L2 -- **Publication Date**: 2024-2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: LightGlue deployment engineers -- **Research Boundary Match**: ✅ Full match -- **Summary**: ONNX export for LightGlue with FlashAttention-2 support. TopK-trick for ~30% speedup. Pre-exported models available. - -## Source #7 -- **Title**: LightGlue GitHub Issue #64 — Rotation sensitivity -- **Link**: https://github.com/cvg/LightGlue/issues/64 -- **Tier**: L4 -- **Publication Date**: 2023-2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: LightGlue users -- **Research Boundary Match**: ✅ Full match -- **Summary**: LightGlue (with SuperPoint/DISK) is NOT rotation-invariant. 90° or 180° rotation causes matching failure. Manual rectification needed. - -## Source #8 -- **Title**: LightGlue GitHub Issue #13 — No-match handling -- **Link**: https://github.com/cvg/LightGlue/issues/13 -- **Tier**: L4 -- **Publication Date**: 2023 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: LightGlue users -- **Research Boundary Match**: ✅ Full match -- **Summary**: LightGlue lacks explicit training on unmatchable pairs. May produce geometrically meaningless matches instead of rejecting non-overlapping views. - -## Source #9 -- **Title**: YFS90/GNSS-Denied-UAV-Geolocalization GitHub -- **Link**: https://github.com/yfs90/gnss-denied-uav-geolocalization -- **Tier**: L1 -- **Publication Date**: 2024-2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: GPS-denied UAV navigation -- **Research Boundary Match**: ✅ Full match -- **Summary**: <7m MAE using terrain-weighted constraint optimization + 2D-3D geo-registration. Uses DEM data. Validated across 20 complex scenarios. Works with publicly available satellite maps. - -## Source #10 -- **Title**: Efficient image matching for UAV visual navigation via DALGlue (Scientific Reports 2025) -- **Link**: https://www.nature.com/articles/s41598-025-21602-5 -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: UAV visual navigation -- **Research Boundary Match**: ✅ Full match -- **Summary**: 11.8% MMA improvement over LightGlue. Uses dual-tree complex wavelet transform + adaptive spatial feature fusion + linear attention. Designed for UAV dynamic flight. - -## Source #11 -- **Title**: XFeat: Accelerated Features for Lightweight Image Matching (CVPR 2024) -- **Link**: https://arxiv.org/html/2404.19174v1 / https://github.com/verlab/accelerated_features -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Real-time feature matching applications -- **Research Boundary Match**: ✅ Full match -- **Summary**: 5x faster than SuperPoint. Runs real-time on CPU. Sparse + semi-dense matching. Used by SatLoc-Fusion for VO. 1500+ GitHub stars. - -## Source #12 -- **Title**: An Oblique-Robust Absolute Visual Localization Method (IEEE TGRS 2024) -- **Link**: https://ieeexplore.ieee.org/iel7/36/10354519/10356107.pdf -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: GPS-denied UAV localization -- **Research Boundary Match**: ✅ Full match -- **Summary**: SE(2)-steerable network for rotation-equivariant features. Handles drastic perspective changes, non-perpendicular camera angles. No additional training for new scenes. - -## Source #13 -- **Title**: Google Maps Tiles API Usage and Billing -- **Link**: https://developers.google.com/maps/documentation/tile/usage-and-billing -- **Tier**: L1 -- **Publication Date**: 2025-2026 (continuously updated) -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Google Maps API users -- **Research Boundary Match**: ✅ Full match -- **Summary**: 100,000 free tile requests/month. Rate limit: 6,000/min, 15,000/day for 2D tiles. $200/month free credit expired Feb 2025. Now pay-as-you-go only. - -## Source #14 -- **Title**: GTSAM Python API and Factor Graph examples -- **Link**: https://github.com/borglab/gtsam / https://pypi.org/project/gtsam-develop/ -- **Tier**: L1 -- **Publication Date**: 2025-2026 (v4.2 stable, v4.3a1 dev) -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Robot navigation, SLAM -- **Research Boundary Match**: ✅ Full match -- **Summary**: Python bindings for factor graph optimization. GPSFactor for absolute position constraints. iSAM2 for incremental optimization. Stable v4.2 for production use. - -## Source #15 -- **Title**: Copernicus DEM documentation -- **Link**: https://documentation.dataspace.copernicus.eu/APIs/SentinelHub/Data/DEM.html -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: DEM data users -- **Research Boundary Match**: ✅ Full match -- **Summary**: Free 30m DEM (GLO-30) covering Ukraine. API access via Sentinel Hub Process API. Registration required. - -## Source #16 -- **Title**: Homography Decomposition Revisited (IJCV 2025) -- **Link**: https://link.springer.com/article/10.1007/s11263-025-02680-4 -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Computer vision researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Existing homography decomposition methods can be unstable in certain configurations. Proposes hybrid framework for improved stability. - -## Source #17 -- **Title**: Sliding window factor graph optimization for visual/inertial navigation (Cambridge 2020) -- **Link**: https://www.cambridge.org/core/services/aop-cambridge-core/content/view/523C7C41D18A8D7C159C59235DF502D0/ -- **Tier**: L1 -- **Publication Date**: 2020 -- **Timeliness Status**: ✅ Currently valid (foundational method) -- **Target Audience**: Navigation system designers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Sliding-window factor graph optimization combines accuracy of graph optimization with efficiency of windowed approach. Superior to separate filtering or full batch optimization. - -## Source #18 -- **Title**: SuperPoint feature extraction and matching benchmarks -- **Link**: https://preview-www.nature.com/articles/s41598-024-59626-y/tables/3 -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Feature matching benchmarking -- **Research Boundary Match**: ✅ Full match -- **Summary**: SuperPoint+LightGlue: ~0.36±0.06s per image pair for extraction+matching on GPU. Competitive accuracy for satellite stereo scenarios. - -## Source #19 -- **Title**: DINOv2-Based UAV Visual Self-Localization in Low-Altitude Urban Environments -- **Link**: https://ui.adsabs.harvard.edu/abs/2025IRAL...10.2080Y/ -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: UAV visual localization researchers -- **Research Boundary Match**: ⚠️ Partial overlap (urban, not steppe) -- **Summary**: DINOv2-based method achieves 86.27 R@1 on DenseUAV benchmark for cross-view matching. Integrates global-local feature enhancement. - -## Source #20 -- **Title**: Mapbox Satellite Tiles and Pricing -- **Link**: https://docs.mapbox.com/data/tilesets/reference/mapbox-satellite/ / https://mapbox.com/pricing -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Map tile consumers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Mapbox offers satellite tiles up to 0.3m resolution (zoom 16+). 200,000 free vector tile requests/month. Unlimited offline downloads on pay-as-you-go. Multi-provider imagery (Maxar, Landsat, Sentinel). diff --git a/_docs/00_research/gps_denied_nav_assessment/02_fact_cards.md b/_docs/00_research/gps_denied_nav_assessment/02_fact_cards.md deleted file mode 100644 index cee4ae8..0000000 --- a/_docs/00_research/gps_denied_nav_assessment/02_fact_cards.md +++ /dev/null @@ -1,161 +0,0 @@ -# Fact Cards — Solution Assessment (Mode B) - -## Fact #1 -- **Statement**: LightGlue (with SuperPoint/DISK descriptors) is NOT rotation-invariant. Image pairs with 90° or 180° rotation produce very few or zero matches. Manual image rectification is required before matching. -- **Source**: Source #7 (LightGlue GitHub Issue #64) -- **Phase**: Assessment -- **Target Audience**: UAV systems with non-stabilized cameras -- **Confidence**: ✅ High (confirmed by LightGlue maintainers) -- **Related Dimension**: Cross-view matching robustness, camera rotation handling - -## Fact #2 -- **Statement**: LightGlue lacks explicit training on unmatchable image pairs. When given non-overlapping views (e.g., after sharp turn), it may return semantically correct but geometrically meaningless matches instead of correctly rejecting the pair. -- **Source**: Source #8 (LightGlue GitHub Issue #13) -- **Phase**: Assessment -- **Target Audience**: Systems requiring segment detection (VO failure detection) -- **Confidence**: ✅ High (confirmed by LightGlue maintainers) -- **Related Dimension**: Segment management, VO failure detection - -## Fact #3 -- **Statement**: SatLoc-Fusion achieves <15m absolute localization error using a three-layer hierarchical approach: DINOv2 for coarse absolute geo-localization, XFeat for high-frequency VO, optical flow for velocity estimation. Runs real-time on 6 TFLOPS edge hardware. -- **Source**: Source #4 (SatLoc-Fusion, Remote Sensing 2025) -- **Phase**: Assessment -- **Target Audience**: GPS-denied UAV systems -- **Confidence**: ✅ High (peer-reviewed, with dataset) -- **Related Dimension**: Architecture, localization accuracy, hierarchical matching - -## Fact #4 -- **Statement**: XFeat is 5x faster than SuperPoint with comparable accuracy. Runs real-time on CPU. Supports both sparse and semi-dense matching. 1500+ GitHub stars, actively maintained. -- **Source**: Source #11 (CVPR 2024) -- **Phase**: Assessment -- **Target Audience**: Real-time feature extraction -- **Confidence**: ✅ High (peer-reviewed, CVPR 2024) -- **Related Dimension**: Processing speed, feature extraction - -## Fact #5 -- **Statement**: SIFT+LightGlue achieves superior spatial consistency and reliability for UAV image mosaicking, including in low-texture and high-rotation conditions. SIFT is rotation-invariant unlike SuperPoint. -- **Source**: Source #2 (ISPRS 2025) -- **Phase**: Assessment -- **Target Audience**: UAV image matching -- **Confidence**: ✅ High (peer-reviewed) -- **Related Dimension**: Feature extraction, rotation handling - -## Fact #6 -- **Statement**: SuperPoint+LightGlue extraction+matching takes ~0.36±0.06s per image pair on GPU (unspecified GPU model). This is for standard resolution images, not 6000+ pixel width. -- **Source**: Source #18 -- **Phase**: Assessment -- **Target Audience**: Performance planning -- **Confidence**: ⚠️ Medium (GPU model not specified, may not be RTX 2060) -- **Related Dimension**: Processing time - -## Fact #7 -- **Statement**: LightGlue ONNX/TensorRT achieves 2-4x speedup over compiled PyTorch. FP8 quantization adds 6x more but requires Ada Lovelace or newer GPUs. RTX 2060 (Turing) does NOT support FP8 — limited to FP16/INT8 acceleration. -- **Source**: Source #5, #6 (LightGlue-ONNX blog and repo) -- **Phase**: Assessment -- **Target Audience**: RTX 2060 deployment -- **Confidence**: ✅ High (benchmarked by repo maintainer) -- **Related Dimension**: Processing time, hardware constraints - -## Fact #8 -- **Statement**: YFS90 achieves <7m MAE using terrain-weighted constraint optimization + 2D-3D geo-registration with DEM data. Validated across 20 complex scenarios including plains, hilly terrain, urban/rural. Works with publicly available satellite maps and DEM data. Re-localization capability after failures. -- **Source**: Source #9 (YFS90 GitHub) -- **Phase**: Assessment -- **Target Audience**: GPS-denied UAV navigation -- **Confidence**: ✅ High (peer-reviewed, open source, 69★) -- **Related Dimension**: Optimization approach, DEM integration, accuracy - -## Fact #9 -- **Statement**: Google Maps $200/month free credit expired February 28, 2025. Current free tier is 100,000 tile requests/month. Rate limits: 6,000 requests/min, 15,000 requests/day for 2D tiles. -- **Source**: Source #13 (Google Maps official docs) -- **Phase**: Assessment -- **Target Audience**: Cost planning -- **Confidence**: ✅ High (official documentation) -- **Related Dimension**: Cost, satellite imagery access - -## Fact #10 -- **Statement**: Google Maps satellite imagery for eastern Ukraine is likely updated only every 3-5+ years due to: conflict zone (lower priority), geopolitical challenges, limited user demand. This may not meet the AC requirement of "less than 2 years old." -- **Source**: Multiple web sources on Google Maps update frequency -- **Phase**: Assessment -- **Target Audience**: Satellite imagery reliability -- **Confidence**: ⚠️ Medium (general guidelines, not Ukraine-specific confirmation) -- **Related Dimension**: Satellite imagery reliability - -## Fact #11 -- **Statement**: Mapbox Satellite offers imagery up to 0.3m resolution at zoom 16+, sourced from Maxar, Landsat, Sentinel. 200,000 free vector tile requests/month. Unlimited offline downloads on pay-as-you-go. Potentially more diverse and recent imagery for Ukraine than Google Maps alone. -- **Source**: Source #20 (Mapbox docs) -- **Phase**: Assessment -- **Target Audience**: Alternative satellite providers -- **Confidence**: ✅ High (official documentation) -- **Related Dimension**: Satellite imagery reliability, cost - -## Fact #12 -- **Statement**: Copernicus DEM GLO-30 provides free 30m resolution global elevation data including Ukraine. Accessible via Sentinel Hub API. Can be used for terrain-weighted optimization like YFS90. -- **Source**: Source #15 (Copernicus docs) -- **Phase**: Assessment -- **Target Audience**: DEM integration -- **Confidence**: ✅ High (official documentation) -- **Related Dimension**: Position optimizer, terrain constraints - -## Fact #13 -- **Statement**: GTSAM v4.2 (stable) provides Python bindings with GPSFactor for absolute position constraints and iSAM2 for incremental optimization. Can model VO constraints, satellite anchor constraints, and drift limits in a unified factor graph. -- **Source**: Source #14 (GTSAM docs) -- **Phase**: Assessment -- **Target Audience**: Optimizer design -- **Confidence**: ✅ High (widely used in robotics) -- **Related Dimension**: Position optimizer - -## Fact #14 -- **Statement**: DALGlue achieves 11.8% MMA improvement over LightGlue on MegaDepth benchmark. Specifically designed for UAV visual navigation with wavelet transform preprocessing for handling dynamic flight blur. -- **Source**: Source #10 (Scientific Reports 2025) -- **Phase**: Assessment -- **Target Audience**: Feature matching selection -- **Confidence**: ✅ High (peer-reviewed) -- **Related Dimension**: Feature matching - -## Fact #15 -- **Statement**: The oblique-robust AVL method (IEEE TGRS 2024) uses SE(2)-steerable networks for rotation-equivariant features. Handles drastic perspective changes and non-perpendicular camera angles for UAV-to-satellite matching. No retraining needed for new scenes. -- **Source**: Source #12 (IEEE TGRS 2024) -- **Phase**: Assessment -- **Target Audience**: Cross-view matching -- **Confidence**: ✅ High (peer-reviewed, IEEE) -- **Related Dimension**: Cross-view matching, rotation handling - -## Fact #16 -- **Statement**: Homography decomposition can be unstable in certain configurations (2025 IJCV study). Non-planar objects (buildings, trees) violate planar assumption. For aerial images, dominant ground plane exists but RANSAC inlier ratio drops with non-planar content. -- **Source**: Source #16 (IJCV 2025) -- **Phase**: Assessment -- **Target Audience**: VO design -- **Confidence**: ✅ High (peer-reviewed) -- **Related Dimension**: VO robustness - -## Fact #17 -- **Statement**: Sliding-window factor graph optimization combines the accuracy of full graph optimization with the efficiency of windowed processing. Superior to either pure filtering or full batch optimization for real-time navigation. -- **Source**: Source #17 (Cambridge 2020) -- **Phase**: Assessment -- **Target Audience**: Optimizer design -- **Confidence**: ✅ High (peer-reviewed) -- **Related Dimension**: Position optimizer - -## Fact #18 -- **Statement**: SuperPoint is a fully-convolutional model — GPU memory scales linearly with image resolution. 6252×4168 input would require significant VRAM. Standard practice is to downscale to 1024-2048 long edge for feature extraction. -- **Source**: Source #18, SuperPoint docs -- **Phase**: Assessment -- **Target Audience**: Memory management -- **Confidence**: ✅ High (architectural fact) -- **Related Dimension**: Memory management, processing pipeline - -## Fact #19 -- **Statement**: For GPS-denied UAV localization, hierarchical coarse-to-fine approaches (image retrieval → local feature matching) are state-of-the-art. Direct local feature matching alone fails when the search area is too large or viewpoint difference is too high. -- **Source**: Source #3, #4, #12 (CEUSP, SatLoc, Oblique-robust AVL) -- **Phase**: Assessment -- **Target Audience**: Architecture design -- **Confidence**: ✅ High (consensus across multiple papers) -- **Related Dimension**: Architecture, satellite matching - -## Fact #20 -- **Statement**: Google Maps Tiles API daily rate limit of 15,000 requests would be hit when processing a 3000-image flight requiring ~2000 satellite tiles plus expansion tiles. Need to either pre-cache or use the per-minute limit (6,000/min) strategically across multiple days. -- **Source**: Source #13 (Google Maps docs) -- **Phase**: Assessment -- **Target Audience**: System design -- **Confidence**: ✅ High (official rate limits) -- **Related Dimension**: Satellite tile management, rate limiting diff --git a/_docs/00_research/gps_denied_nav_assessment/03_comparison_framework.md b/_docs/00_research/gps_denied_nav_assessment/03_comparison_framework.md deleted file mode 100644 index 70a5059..0000000 --- a/_docs/00_research/gps_denied_nav_assessment/03_comparison_framework.md +++ /dev/null @@ -1,79 +0,0 @@ -# Comparison Framework — Solution Assessment (Mode B) - -## Selected Framework Type -Problem Diagnosis + Decision Support - -## Identified Weak Points and Assessment Dimensions - -### Dimension 1: Cross-View Matching Strategy (UAV→Satellite) - -| Aspect | Draft01 Approach | Identified Problem | Alternative | Factual Basis | -|--------|-----------------|-------------------|------------|---------------| -| Strategy | Direct SuperPoint+LightGlue matching with perspective warping | No coarse localization stage. Fails when VO drift is large. LightGlue not rotation-invariant. | Hierarchical: DINOv2/global retrieval → SuperPoint+LightGlue refinement | Fact #1, #2, #15, #19 | -| Rotation handling | Not addressed | Non-stabilized camera = rotated images. SuperPoint/LightGlue fail at 90°/180° | Image rectification via VO-estimated heading, or rotation-invariant features (SIFT for fallback) | Fact #1, #5 | -| Domain gap | Perspective warping only | Insufficient for seasonal/illumination/resolution differences | Multi-scale matching, DINOv2 for semantic retrieval, warping + matched features | Fact #3, #15 | - -### Dimension 2: Feature Extraction & Matching - -| Aspect | Draft01 Approach | Identified Problem | Alternative | Factual Basis | -|--------|-----------------|-------------------|------------|---------------| -| VO features | SuperPoint (~80ms) | Adequate but not optimized for speed | XFeat (5x faster, CPU-capable) for VO; keep SuperPoint for satellite matching | Fact #4 | -| Matching | LightGlue | Good baseline. DALGlue 11.8% better MMA. | LightGlue with ONNX optimization as primary. DALGlue for evaluation. | Fact #7, #14 | -| Non-match detection | Not addressed | LightGlue returns false matches on non-overlapping pairs | Inlier ratio + match count threshold + geometric consistency check | Fact #2 | - -### Dimension 3: Visual Odometry Robustness - -| Aspect | Draft01 Approach | Identified Problem | Alternative | Factual Basis | -|--------|-----------------|-------------------|------------|---------------| -| Geometric model | Homography (planar assumption) | Unstable for non-planar objects. Decomposition instability in certain configs. | Homography with RANSAC + high inlier ratio requirement. Essential matrix as fallback. | Fact #16 | -| Scale estimation | GSD from altitude | Valid if altitude is constant. Terrain elevation changes not accounted for. | Integrate Copernicus DEM for terrain-corrected GSD | Fact #12 | -| Camera rotation | Not addressed | Non-stabilized camera introduces roll/pitch | Estimate rotation from VO, apply rectification before satellite matching | Fact #1, #5 | - -### Dimension 4: Position Optimizer - -| Aspect | Draft01 Approach | Identified Problem | Alternative | Factual Basis | -|--------|-----------------|-------------------|------------|---------------| -| Algorithm | scipy.optimize sliding window | Generic optimizer, no proper uncertainty modeling, no factor types | GTSAM factor graph with iSAM2 incremental optimization | Fact #13, #17 | -| Terrain constraints | Not used | YFS90 achieves <7m with terrain weighting | Integrate DEM-based terrain constraints via Copernicus DEM | Fact #8, #12 | -| Drift modeling | Max 100m between anchors | Single hard constraint, no probabilistic modeling | Per-VO-step uncertainty based on inlier ratio, propagated through factor graph | Fact #17 | - -### Dimension 5: Satellite Imagery Reliability - -| Aspect | Draft01 Approach | Identified Problem | Alternative | Factual Basis | -|--------|-----------------|-------------------|------------|---------------| -| Provider | Google Maps only | Eastern Ukraine: 3-5 year update cycle. $200 credit expired. 15K/day rate limit. | Multi-provider: Google Maps primary + Mapbox fallback + pre-cached tiles | Fact #9, #10, #11, #20 | -| Freshness | Assumed adequate | May not meet AC "< 2 years old" for conflict zone | Provider selection per-area. User can provide custom imagery. | Fact #10 | -| Rate limiting | Not addressed | 15,000/day cap could block large flights | Progressive download with request budgeting. Pre-cache for known areas. | Fact #20 | - -### Dimension 6: Processing Time Budget - -| Aspect | Draft01 Approach | Identified Problem | Alternative | Factual Basis | -|--------|-----------------|-------------------|------------|---------------| -| Target | <5s (claim <2s) | Per-frame pipeline: VO match + satellite match + optimization. Total could exceed budget. | XFeat for VO (~20ms). LightGlue ONNX for satellite (~100ms). Async satellite matching. | Fact #4, #6, #7 | -| Image downscaling | Not specified | 6252×4168 cannot be processed at full resolution | Downscale to 1600 long edge for features. Keep full resolution for GSD calculation. | Fact #18 | -| Parallelism | Not specified | Sequential pipeline wastes GPU idle time | Async: extract features while satellite tile downloads. Pipeline overlap. | — | - -### Dimension 7: Memory Management - -| Aspect | Draft01 Approach | Identified Problem | Alternative | Factual Basis | -|--------|-----------------|-------------------|------------|---------------| -| Image loading | Not specified | 6252×4168 × 3ch = 78MB per raw image. 3000 images = 234GB. | Stream images one at a time. Keep only current + previous features in memory. | Fact #18 | -| VRAM budget | Not specified | SuperPoint on full resolution could exceed 6GB VRAM | Downscale images. Batch size 1. Clear GPU cache between frames. | Fact #18 | -| Feature storage | Not specified | 3000 images × features = significant RAM | Store only features needed for sliding window. Disk-backed for older frames. | — | - -### Dimension 8: Security - -| Aspect | Draft01 Approach | Identified Problem | Alternative | Factual Basis | -|--------|-----------------|-------------------|------------|---------------| -| Authentication | API key mentioned | No implementation details. API key in query params = insecure. | JWT tokens for session auth. Short-lived tokens for SSE connections. | SSE security research | -| Path traversal | Mentioned in testing | image_folder parameter could be exploited | Whitelist base directories. Validate path doesn't escape allowed root. | — | -| DoS protection | Not addressed | Large image uploads, SSE connection exhaustion | Max file size limits. Connection pool limits. Request rate limiting. | — | -| API key storage | env var mentioned | Adequate baseline | .env file + secrets manager in production. Never log API keys. | — | - -### Dimension 9: Segment Management - -| Aspect | Draft01 Approach | Identified Problem | Alternative | Factual Basis | -|--------|-----------------|-------------------|------------|---------------| -| Re-connection | Via satellite anchoring only | If satellite matching fails, segment stays floating | Attempt cross-segment matching when new anchors arrive. DEM-based constraint stitching. | Fact #8 | -| Multi-segment handling | Described conceptually | No detail on how >2 segments are managed | Explicit segment graph with pending connections. Priority queue for unresolved segments. | — | -| User input fallback | POST /jobs/{id}/anchor | Good design. Needs timeout/escalation for when user doesn't respond. | Add configurable timeout before continuing with VO-only estimate. | — | diff --git a/_docs/00_research/gps_denied_nav_assessment/04_reasoning_chain.md b/_docs/00_research/gps_denied_nav_assessment/04_reasoning_chain.md deleted file mode 100644 index 9e04359..0000000 --- a/_docs/00_research/gps_denied_nav_assessment/04_reasoning_chain.md +++ /dev/null @@ -1,145 +0,0 @@ -# Reasoning Chain — Solution Assessment (Mode B) - -## Dimension 1: Cross-View Matching Strategy - -### Fact Confirmation -According to Fact #1, LightGlue is not rotation-invariant and fails on rotated images. According to Fact #2, it returns false matches on non-overlapping pairs. According to Fact #19, state-of-the-art GPS-denied localization uses hierarchical coarse-to-fine approaches. SatLoc-Fusion (Fact #3) achieves <15m with DINOv2 + XFeat + optical flow. - -### Reference Comparison -Draft01 uses direct SuperPoint+LightGlue matching with perspective warping. This is a single-stage approach — it assumes the VO-estimated position is close enough to fetch the right satellite tile, then matches directly. But: (a) when VO drift accumulates between satellite anchors, the estimated position may be wrong enough to fetch the wrong tile; (b) the domain gap between UAV oblique images and satellite nadir is significant; (c) rotation from non-stabilized camera is not handled. - -State-of-the-art approaches add a coarse localization stage (DINOv2 image retrieval over a wider area) before fine matching. This makes satellite matching robust to larger VO drift. - -### Conclusion -**Replace single-stage with two-stage satellite matching**: (1) DINOv2-based coarse retrieval over a search area (e.g., 500m radius around VO estimate) to find the best-matching satellite tile, (2) SuperPoint+LightGlue for precise alignment on the selected tile. Add image rotation normalization before matching. This is the most critical improvement. - -### Confidence -✅ High — multiple independent sources confirm hierarchical approach superiority. - ---- - -## Dimension 2: Feature Extraction & Matching - -### Fact Confirmation -According to Fact #4, XFeat is 5x faster than SuperPoint with comparable accuracy and is used in SatLoc-Fusion for real-time VO. According to Fact #5, SIFT+LightGlue is more robust for high-rotation conditions. According to Fact #14, DALGlue improves LightGlue MMA by 11.8% for UAV scenarios. - -### Reference Comparison -Draft01 uses SuperPoint for all feature extraction (both VO and satellite matching). This is simpler (unified pipeline) but suboptimal: VO needs speed (processed every frame), while satellite matching needs accuracy (processed periodically). - -### Conclusion -**Dual-extractor strategy**: XFeat for VO (fast, adequate accuracy for frame-to-frame), SuperPoint for satellite matching (higher accuracy needed for cross-view). LightGlue with ONNX/TensorRT optimization as matcher. SIFT as fallback for rotation-heavy scenarios. DALGlue is promising but too new for production — monitor. - -### Confidence -✅ High — XFeat benchmarks are from CVPR 2024, well-established. - ---- - -## Dimension 3: Visual Odometry Robustness - -### Fact Confirmation -According to Fact #16, homography decomposition can be unstable and non-planar objects degrade results. According to Fact #12, Copernicus DEM provides free 30m elevation data for terrain-corrected GSD. - -### Reference Comparison -Draft01's homography-based VO is valid for flat terrain but doesn't account for: (a) terrain elevation changes affecting GSD calculation, (b) non-planar objects in the scene, (c) camera roll/pitch from non-stabilized mount. The terrain in eastern Ukraine is mostly steppe but has settlements, forests, and infrastructure. - -### Conclusion -**Keep homography VO as primary** (valid for dominant ground plane), but: (1) add RANSAC inlier ratio check — if below threshold, fall back to essential matrix estimation; (2) integrate Copernicus DEM for terrain-corrected altitude in GSD calculation; (3) estimate and track camera rotation (roll/pitch/yaw) from consecutive VO estimates and use it for image rectification before satellite matching. - -### Confidence -✅ High — homography with RANSAC and fallback is well-established. - ---- - -## Dimension 4: Position Optimizer - -### Fact Confirmation -According to Fact #13, GTSAM provides Python bindings with GPSFactor and iSAM2 incremental optimization. According to Fact #17, sliding-window factor graph optimization is superior to either pure filtering or full batch optimization. According to Fact #8, YFS90 achieves <7m MAE with terrain-weighted constraints + DEM. - -### Reference Comparison -Draft01 proposes scipy.optimize with a custom sliding window. While functional, this is reinventing the wheel — GTSAM's iSAM2 already implements incremental smoothing with proper uncertainty propagation. GTSAM's factor graph naturally supports: BetweenFactor for VO constraints (with uncertainty), GPSFactor for satellite anchors, custom factors for terrain constraints, drift limit constraints. - -### Conclusion -**Replace scipy.optimize with GTSAM iSAM2 factor graph**. Use BetweenFactor for VO relative motion, GPSFactor for satellite anchors (with uncertainty based on match quality), and a custom terrain factor using Copernicus DEM. This provides: proper uncertainty propagation, incremental updates (fits SSE streaming), backwards smoothing when new anchors arrive. - -### Confidence -✅ High — GTSAM is production-proven, stable v4.2 available via pip. - ---- - -## Dimension 5: Satellite Imagery Reliability - -### Fact Confirmation -According to Fact #9, Google Maps $200/month free credit expired Feb 2025. Current free tier is 100K tiles/month. According to Fact #10, eastern Ukraine imagery may be 3-5+ years old. According to Fact #20, 15,000/day rate limit could be hit on large flights. According to Fact #11, Mapbox offers alternative satellite tiles at comparable resolution. - -### Reference Comparison -Draft01 relies solely on Google Maps. Single-provider dependency creates multiple risk points: outdated imagery, rate limits, cost, API changes. - -### Conclusion -**Multi-provider satellite tile manager**: Google Maps as primary, Mapbox as secondary, user-provided tiles as override. Implement: provider fallback when matching confidence is low, request budgeting to stay within rate limits, tile freshness metadata logging, pre-caching mode for known operational areas. - -### Confidence -✅ High — multi-provider is standard practice for production systems. - ---- - -## Dimension 6: Processing Time Budget - -### Fact Confirmation -According to Fact #6, SuperPoint+LightGlue takes ~0.36s per pair on GPU. According to Fact #7, ONNX optimization adds 2-4x speedup (on RTX 2060, limited to FP16). According to Fact #4, XFeat is 5x faster than SuperPoint for VO. - -### Reference Comparison -Draft01's per-frame pipeline: (1) feature extraction, (2) VO matching, (3) satellite tile fetch, (4) satellite matching, (5) optimization, (6) SSE emit. Total estimated without optimization: ~1-2s for VO + ~0.5-1s for satellite + overhead = 2-4s. With ONNX optimization for matching and XFeat for VO, this drops to ~0.5-1.5s. - -### Conclusion -**Budget is achievable with optimizations**: XFeat for VO (~20ms extraction + ~50ms matching), LightGlue ONNX for satellite (~100ms extraction + ~100ms matching), async satellite tile download (overlapped with VO), GTSAM incremental update (~10ms). Total: ~0.5-1s per frame. Satellite matching can be async — not every frame needs satellite match. Image downscaling to 1600 long edge is essential. - -### Confidence -⚠️ Medium — depends on actual RTX 2060 benchmarks, which are extrapolated from general numbers. - ---- - -## Dimension 7: Memory Management - -### Fact Confirmation -According to Fact #18, SuperPoint is fully-convolutional and VRAM scales with resolution. 6252×4168 images would require significant VRAM and RAM. - -### Reference Comparison -Draft01 doesn't specify memory management. With 3000 images at max resolution, naive processing would exceed 16GB RAM. - -### Conclusion -**Strict memory management**: (1) Downscale all images to max 1600 long edge before feature extraction; (2) stream images one at a time — only keep current + previous frame features in GPU memory; (3) store features for sliding window in CPU RAM, older features to disk; (4) limit satellite tile cache to 500MB in RAM, overflow to disk; (5) batch size 1 for all GPU operations; (6) explicit torch.cuda.empty_cache() between frames if VRAM pressure detected. - -### Confidence -✅ High — standard memory management patterns. - ---- - -## Dimension 8: Security - -### Fact Confirmation -JWT tokens are recommended for SSE endpoint security. API keys in query parameters are insecure (persist in logs, browser history). - -### Reference Comparison -Draft01 mentions API key auth but no implementation details. SSE connections need proper authentication and resource limits. - -### Conclusion -**Security improvements**: (1) JWT-based authentication for all endpoints; (2) short-lived tokens for SSE connections; (3) image folder whitelist (not just path traversal prevention — explicit whitelist of allowed base directories); (4) max concurrent SSE connections per client; (5) request rate limiting; (6) max image size validation; (7) all API keys in environment variables, never logged. - -### Confidence -✅ High — standard security practices. - ---- - -## Dimension 9: Segment Management - -### Fact Confirmation -According to Fact #8, YFS90 has re-localization capability after positioning failures. According to Fact #2, LightGlue may return false matches on non-overlapping pairs. - -### Reference Comparison -Draft01's segment management relies on satellite matching to anchor each segment independently. If satellite matching fails, the segment stays "floating." No mechanism for cross-segment matching or delayed resolution. - -### Conclusion -**Enhanced segment management**: (1) Explicit VO failure detection using match count + inlier ratio + geometric consistency (not just match count); (2) when a new segment gets satellite-anchored, attempt to connect to nearby floating segments using satellite-based position proximity; (3) DEM-based constraint: position must be consistent with terrain elevation; (4) configurable timeout for user input request — if no response within N frames, continue with best estimate and flag. - -### Confidence -⚠️ Medium — cross-segment connection is logical but needs careful implementation to avoid false connections. diff --git a/_docs/00_research/gps_denied_nav_assessment/05_validation_log.md b/_docs/00_research/gps_denied_nav_assessment/05_validation_log.md deleted file mode 100644 index 8f757ce..0000000 --- a/_docs/00_research/gps_denied_nav_assessment/05_validation_log.md +++ /dev/null @@ -1,93 +0,0 @@ -# Validation Log — Solution Assessment (Mode B) - -## Validation Scenario 1: Normal flight over steppe with gradual turns - -**Scenario**: 1000-image flight over flat agricultural steppe. FullHD resolution. Starting GPS known. Gradual turns every 200 frames. Satellite imagery 2 years old. - -**Expected with Draft02 improvements**: -1. XFeat VO processes frames at ~70ms each → well under 5s budget -2. DINOv2 coarse retrieval finds correct satellite area despite 50-100m VO drift -3. SuperPoint+LightGlue ONNX refines position to ~10-20m accuracy -4. GTSAM iSAM2 smooths trajectory, reduces drift between anchors -5. At gradual turns, VO continues working (overlap >30%) -6. Processing stays under 1GB VRAM with 1600px downscale - -**Actual validation result**: Consistent with expectations. This is the "happy path" — both draft01 and draft02 would work. Draft02 advantage: faster processing, better optimizer. - -## Validation Scenario 2: Sharp turn with no overlap - -**Scenario**: After 500 normal frames, UAV makes a 90° sharp turn. Next 3 images have zero overlap with previous route. Then normal flight continues. - -**Expected with Draft02 improvements**: -1. VO detects failure: match count drops below threshold → segment break -2. LightGlue false-match protection: geometric consistency check rejects bad matches -3. New segment starts. DINOv2 coarse retrieval searches wider area for satellite match -4. If satellite match succeeds: new segment anchored, connected to previous via shared coordinate frame -5. If satellite match fails: segment marked floating, user input requested (with timeout) -6. After turn, if UAV returns near previous route, cross-segment connection attempted - -**Draft01 comparison**: Draft01 would also detect VO failure and create new segment, but lacks coarse retrieval → satellite matching depends entirely on VO estimate which may be wrong after turn. Higher risk of satellite match failure. - -## Validation Scenario 3: High-resolution images (6252×4168) - -**Scenario**: 500 images at full 6252×4168 resolution. RTX 2060 (6GB VRAM). - -**Expected with Draft02 improvements**: -1. Images downscaled to 1600×1066 for feature extraction -2. Full resolution preserved for GSD calculation only -3. Per-frame VRAM: ~1.5GB for XFeat/SuperPoint + LightGlue -4. RAM per frame: ~78MB raw + ~5MB features → manageable with streaming -5. Total peak RAM: sliding window (50 frames × 5MB features) + satellite cache (500MB) + overhead ≈ 1.5GB pipeline -6. Well within 16GB RAM budget - -**Actual validation result**: Consistent. Downscaling strategy is essential and was missing from draft01. - -## Validation Scenario 4: Outdated satellite imagery - -**Scenario**: Flight over area where Google Maps imagery is 4 years old. Significant changes: new buildings, removed forests, changed roads. - -**Expected with Draft02 improvements**: -1. DINOv2 coarse retrieval: partial success (terrain structure still recognizable) -2. SuperPoint+LightGlue fine matching: lower match count on changed areas -3. Confidence score drops for affected frames → flagged in output -4. Multi-provider fallback: try Mapbox tiles if Google matches are poor -5. System falls back to VO-only for sections with no good satellite match -6. User can provide custom satellite imagery for specific areas - -**Draft01 comparison**: Draft01 would also fail on changed areas but has no alternative provider and no coarse retrieval to help. - -## Validation Scenario 5: 3000-image flight hitting API rate limits - -**Scenario**: First flight in a new area. No cached tiles. 3000 images need ~2000 satellite tiles. - -**Expected with Draft02 improvements**: -1. Initial download: 300 tiles around starting GPS (within rate limits) -2. Progressive download as route extends: 5-20 tiles per frame -3. Daily limit (15,000): sufficient for tiles but tight if multiple flights -4. Request budgeting: prioritize tiles around current position, defer expansion -5. Per-minute limit (6,000): no issue -6. Monthly limit (100,000): covers ~50 flights at 2000 tiles each -7. Mapbox fallback if Google budget exhausted - -**Draft01 comparison**: Draft01 assumed $200 free credit (expired). Rate limit analysis was incorrect. - -## Review Checklist -- [x] Draft conclusions consistent with fact cards -- [x] No important dimensions missed -- [x] No over-extrapolation -- [x] Conclusions actionable/verifiable -- [x] All scenarios plausible for the operational context - -## Counterexamples -- **Night flight**: Not addressed (out of scope — restriction says "mostly sunny weather") -- **Very low altitude (<100m)**: Satellite matching would have poor GSD match — not addressed but within restrictions (altitude ≤1km) -- **Urban area with tall buildings**: Homography VO degradation — mitigated by essential matrix fallback but not fully addressed - -## Conclusions Requiring No Revision -All conclusions validated against scenarios. Key improvements are well-supported: -1. Hierarchical satellite matching (coarse + fine) -2. GTSAM factor graph optimization -3. Multi-provider satellite tiles -4. XFeat for VO speed -5. Image downscaling for memory -6. Proper security (JWT, rate limiting) diff --git a/_docs/00_research/gps_denied_nav_v2/00_question_decomposition.md b/_docs/00_research/gps_denied_nav_v2/00_question_decomposition.md deleted file mode 100644 index 49ae6be..0000000 --- a/_docs/00_research/gps_denied_nav_v2/00_question_decomposition.md +++ /dev/null @@ -1,56 +0,0 @@ -# Question Decomposition - -## Original Question -Assess current solution draft. Additionally: -1. Try SuperPoint + LightGlue for visual odometry -2. Can LiteSAM be SO SLOW because of big images? If we reduce size to 1280p, would that work faster? - -## Active Mode -Mode B: Solution Assessment — `solution_draft01.md` exists in OUTPUT_DIR. - -## Question Type -Problem Diagnosis + Decision Support - -## Research Subject Boundary -- **Population**: GPS-denied UAV navigation systems on edge hardware -- **Geography**: Eastern Ukraine conflict zone -- **Timeframe**: Current (2025-2026), using latest available tools -- **Level**: Jetson Orin Nano Super (8GB, 67 TOPS) — edge deployment - -## Decomposed Sub-Questions - -### Q1: SuperPoint + LightGlue for Visual Odometry -- What is SP+LG inference speed on Jetson-class hardware? -- How does it compare to cuVSLAM (116fps on Orin Nano)? -- Is SP+LG suitable for frame-to-frame VO at 3fps? -- What is SP+LG accuracy vs cuVSLAM for VO? - -### Q2: LiteSAM Speed vs Image Resolution -- What resolution was LiteSAM benchmarked at? (1184px on AGX Orin) -- How does LiteSAM speed scale with resolution? -- What would 1280px achieve on Orin Nano Super vs AGX Orin? -- Is the bottleneck image size or compute power gap? - -### Q3: General Weak Points in solution_draft01 -- Are there functional weak points? -- Are there performance bottlenecks? -- Are there security gaps? - -### Q4: SP+LG for Satellite Matching (alternative to LiteSAM/XFeat) -- How does SP+LG perform on cross-view satellite-aerial matching? -- What does the LiteSAM paper say about SP+LG accuracy? - -## Timeliness Sensitivity Assessment -- **Research Topic**: Edge-deployed visual odometry and satellite-aerial matching -- **Sensitivity Level**: 🟠 High -- **Rationale**: cuVSLAM v15.0.0 released March 2026; LiteSAM published October 2025; LightGlue TensorRT optimizations actively evolving -- **Source Time Window**: 12 months -- **Priority official sources**: - 1. LiteSAM paper (MDPI Remote Sensing, October 2025) - 2. cuVSLAM / PyCuVSLAM v15.0.0 (March 2026) - 3. LightGlue-ONNX / TensorRT benchmarks (2024-2026) - 4. Intermodalics cuVSLAM benchmark (2025) -- **Key version information**: - - cuVSLAM: v15.0.0 (March 2026) - - LightGlue: ICCV 2023, TensorRT via fabio-sim/LightGlue-ONNX - - LiteSAM: Published October 2025, code at boyagesmile/LiteSAM diff --git a/_docs/00_research/gps_denied_nav_v2/01_source_registry.md b/_docs/00_research/gps_denied_nav_v2/01_source_registry.md deleted file mode 100644 index 516a5ca..0000000 --- a/_docs/00_research/gps_denied_nav_v2/01_source_registry.md +++ /dev/null @@ -1,121 +0,0 @@ -# Source Registry - -## Source #1 -- **Title**: LiteSAM: Lightweight and Robust Feature Matching for Satellite and Aerial Imagery -- **Link**: https://www.mdpi.com/2072-4292/17/19/3349 -- **Tier**: L1 -- **Publication Date**: 2025-10-01 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: LiteSAM v1.0; benchmarked on Jetson AGX Orin (JetPack 5.x era) -- **Target Audience**: UAV visual localization researchers and edge deployers -- **Research Boundary Match**: ✅ Full match -- **Summary**: LiteSAM (opt) achieves 497.49ms on Jetson AGX Orin at 1184px input. 6.31M params. RMSE@30 = 17.86m on UAV-VisLoc. Paper directly compares with SP+LG, stating "SP+LG achieves the fastest inference speed but at the expense of accuracy." Section 4.9 shows resolution vs speed tradeoff on RTX 3090Ti. -- **Related Sub-question**: Q2 (LiteSAM speed), Q4 (SP+LG for satellite matching) - -## Source #2 -- **Title**: cuVSLAM: CUDA accelerated visual odometry and mapping -- **Link**: https://arxiv.org/abs/2506.04359 -- **Tier**: L1 -- **Publication Date**: 2025-06 (paper), v15.0.0 released 2026-03-10 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: cuVSLAM v15.0.0 / PyCuVSLAM v15.0.0 -- **Target Audience**: Robotics/UAV visual odometry on NVIDIA Jetson -- **Research Boundary Match**: ✅ Full match -- **Summary**: CUDA-accelerated VO+SLAM, supports mono+IMU. 116fps on Jetson Orin Nano 8GB at 720p. <1% trajectory error on KITTI. <5cm on EuRoC. -- **Related Sub-question**: Q1 (SP+LG vs cuVSLAM) - -## Source #3 -- **Title**: Intermodalics — NVIDIA Isaac ROS In-Depth: cuVSLAM and the DP3.1 Release -- **Link**: https://www.intermodalics.ai/blog/nvidia-isaac-ros-in-depth-cuvslam-and-the-dp3-1-release -- **Tier**: L2 -- **Publication Date**: 2025 (DP3.1 release) -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: cuVSLAM v11 (DP3.1), benchmark data applicable to later versions -- **Target Audience**: Robotics developers using Isaac ROS -- **Research Boundary Match**: ✅ Full match -- **Summary**: 116fps on Orin Nano 8GB, 232fps on AGX Orin, 386fps on RTX 4060 Ti. Outperforms ORB-SLAM2 on KITTI. -- **Related Sub-question**: Q1 - -## Source #4 -- **Title**: Accelerating LightGlue Inference with ONNX Runtime and TensorRT -- **Link**: https://fabio-sim.github.io/blog/accelerating-lightglue-inference-onnx-runtime-tensorrt/ -- **Tier**: L2 -- **Publication Date**: 2024-07-17 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: torch 2.4.0, TensorRT 10.2.0, RTX 4080 benchmarks -- **Target Audience**: ML engineers deploying LightGlue -- **Research Boundary Match**: ⚠️ Partial (desktop GPU, not Jetson) -- **Summary**: TensorRT achieves 2-4x speedup over compiled PyTorch for SuperPoint+LightGlue. Full pipeline benchmarks on RTX 4080. TensorRT has 3840 keypoint limit. No Jetson-specific benchmarks provided. -- **Related Sub-question**: Q1 - -## Source #5 -- **Title**: LightGlue-with-FlashAttentionV2-TensorRT (Jetson Orin NX 8GB) -- **Link**: https://github.com/qdLMF/LightGlue-with-FlashAttentionV2-TensorRT -- **Tier**: L4 -- **Publication Date**: 2025-02 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: TensorRT 8.5.2, Jetson Orin NX 8GB -- **Target Audience**: Edge ML deployers -- **Research Boundary Match**: ✅ Full match (similar hardware) -- **Summary**: CUTLASS-based FlashAttention V2 TensorRT plugin for LightGlue, tested on Jetson Orin NX 8GB. No published latency numbers, but confirms LightGlue TensorRT deployment on Orin-class hardware is feasible. -- **Related Sub-question**: Q1 - -## Source #6 -- **Title**: vo_lightglue — Visual Odometry with LightGlue -- **Link**: https://github.com/himadrir/vo_lightglue -- **Tier**: L4 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: N/A -- **Target Audience**: VO researchers -- **Research Boundary Match**: ⚠️ Partial (desktop, KITTI dataset) -- **Summary**: SP+LG achieves 10fps on KITTI dataset (desktop GPU). Odometric error ~1% vs 3.5-4.1% for FLANN-based matching. Much slower than cuVSLAM. -- **Related Sub-question**: Q1 - -## Source #7 -- **Title**: ForestVO: Enhancing Visual Odometry in Forest Environments through ForestGlue -- **Link**: https://arxiv.org/html/2504.01261v1 -- **Tier**: L1 -- **Publication Date**: 2025-04 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: N/A -- **Target Audience**: VO researchers -- **Research Boundary Match**: ⚠️ Partial (forest environment, not nadir UAV) -- **Summary**: SP+LG VO pipeline achieves 1.09m avg relative pose error, KITTI score 2.33%. Uses 512 keypoints (reduced from 2048) to cut compute. Outperforms DSO by 40%. -- **Related Sub-question**: Q1 - -## Source #8 -- **Title**: SuperPoint-SuperGlue-TensorRT (C++ deployment) -- **Link**: https://github.com/yuefanhao/SuperPoint-SuperGlue-TensorRT -- **Tier**: L4 -- **Publication Date**: 2023-2024 -- **Timeliness Status**: ⚠️ Needs verification (SuperGlue, not LightGlue) -- **Version Info**: TensorRT 8.x -- **Target Audience**: Edge deployers -- **Research Boundary Match**: ⚠️ Partial -- **Summary**: SuperPoint TensorRT extraction ~40ms on Jetson for 200 keypoints. C++ implementation. -- **Related Sub-question**: Q1 - -## Source #9 -- **Title**: Comparative Analysis of Advanced Feature Matching Algorithms in HSR Satellite Stereo -- **Link**: https://arxiv.org/abs/2405.06246 -- **Tier**: L1 -- **Publication Date**: 2024-05 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: N/A -- **Target Audience**: Remote sensing researchers -- **Research Boundary Match**: ⚠️ Partial (satellite stereo, not UAV-satellite cross-view) -- **Summary**: SP+LG shows "overall superior performance in balancing robustness, accuracy, distribution, and efficiency" for satellite stereo matching. But this is same-view satellite-satellite, not cross-view UAV-satellite. -- **Related Sub-question**: Q4 - -## Source #10 -- **Title**: PyCuVSLAM with reComputer (Seeed Studio) -- **Link**: https://wiki.seeedstudio.com/pycuvslam_recomputer_robotics/ -- **Tier**: L3 -- **Publication Date**: 2026 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: PyCuVSLAM v15.0.0, JetPack 6.2 -- **Target Audience**: Robotics developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Tutorial for deploying PyCuVSLAM on Jetson Orin NX. Confirms mono+IMU mode, pip install from aarch64 wheel, EuRoC dataset examples. -- **Related Sub-question**: Q1 diff --git a/_docs/00_research/gps_denied_nav_v2/02_fact_cards.md b/_docs/00_research/gps_denied_nav_v2/02_fact_cards.md deleted file mode 100644 index a8b9a6d..0000000 --- a/_docs/00_research/gps_denied_nav_v2/02_fact_cards.md +++ /dev/null @@ -1,122 +0,0 @@ -# Fact Cards - -## Fact #1 -- **Statement**: cuVSLAM achieves 116fps on Jetson Orin Nano 8GB at 720p resolution (~8.6ms/frame). 232fps on AGX Orin. 386fps on RTX 4060 Ti. -- **Source**: [Source #3] Intermodalics benchmark -- **Phase**: Assessment -- **Confidence**: ✅ High -- **Related Dimension**: VO speed comparison - -## Fact #2 -- **Statement**: SuperPoint+LightGlue VO achieves ~10fps on KITTI dataset on desktop GPU (~100ms/frame). With 274 keypoints on RTX 2080Ti, LightGlue matching alone takes 33.9ms. -- **Source**: vo_lightglue, LG issue #36 -- **Confidence**: ⚠️ Medium (desktop GPU, not Jetson) -- **Related Dimension**: VO speed comparison - -## Fact #3 -- **Statement**: SuperPoint feature extraction takes ~40ms on Jetson (TensorRT, 200 keypoints). -- **Source**: SuperPoint-SuperGlue-TensorRT -- **Confidence**: ⚠️ Medium (older Jetson) -- **Related Dimension**: VO speed comparison - -## Fact #4 -- **Statement**: LightGlue TensorRT with FlashAttention V2 has been deployed on Jetson Orin NX 8GB. No published latency numbers. -- **Source**: qdLMF/LightGlue-with-FlashAttentionV2-TensorRT -- **Confidence**: ⚠️ Medium -- **Related Dimension**: VO speed comparison - -## Fact #5 -- **Statement**: LiteSAM (opt) inference: 61.98ms on RTX 3090, 497.49ms on Jetson AGX Orin at 1184px input. 6.31M params. -- **Source**: LiteSAM paper, abstract + Section 4.10 -- **Confidence**: ✅ High -- **Related Dimension**: Satellite matcher speed - -## Fact #6 -- **Statement**: Jetson AGX Orin has 275 TOPS INT8, 2048 CUDA cores. Orin Nano Super has 67 TOPS INT8, 1024 CUDA cores. AGX Orin is ~3-4x more powerful. -- **Source**: NVIDIA official specs -- **Confidence**: ✅ High -- **Related Dimension**: Hardware scaling - -## Fact #7 -- **Statement**: LiteSAM processes at 1/8 scale internally. Coarse matching is O(N²) where N = (H/8 × W/8). For 1184px: ~21,904 tokens. For 1280px: ~25,600. For 480px: ~3,600. -- **Source**: LiteSAM paper, Sections 3.1-3.3 -- **Confidence**: ✅ High -- **Related Dimension**: LiteSAM speed vs resolution - -## Fact #8 -- **Statement**: LiteSAM paper Figure 1 states: "SP+LG achieves the fastest inference speed but at the expense of accuracy" vs LiteSAM on satellite-aerial benchmarks. -- **Source**: LiteSAM paper -- **Confidence**: ✅ High -- **Related Dimension**: SP+LG vs LiteSAM - -## Fact #9 -- **Statement**: LiteSAM achieves RMSE@30 = 17.86m on UAV-VisLoc. SP+LG is worse on same benchmark. -- **Source**: LiteSAM paper -- **Confidence**: ✅ High -- **Related Dimension**: Satellite matcher accuracy - -## Fact #10 -- **Statement**: cuVSLAM uses Shi-Tomasi corners ("Good Features to Track") for keypoint detection, divided into NxM grid patches. Uses Lucas-Kanade optical flow for tracking. When tracked keypoints fall below threshold, creates new keyframe. -- **Source**: cuVSLAM paper (arXiv:2506.04359), Section 2.1 -- **Confidence**: ✅ High -- **Related Dimension**: cuVSLAM on difficult terrain - -## Fact #11 -- **Statement**: cuVSLAM automatically switches to IMU when visual tracking fails (dark lighting, long solid surfaces). IMU integrator provides ~1 second of acceptable tracking. After IMU, constant-velocity integrator provides ~0.5 seconds more. -- **Source**: Isaac ROS cuVSLAM docs -- **Confidence**: ✅ High -- **Related Dimension**: cuVSLAM on difficult terrain - -## Fact #12 -- **Statement**: cuVSLAM does NOT guarantee correct pose recovery after losing track. External algorithms required for global re-localization after tracking loss. Cannot fuse GNSS, wheel odometry, or LiDAR. -- **Source**: Intermodalics blog -- **Confidence**: ✅ High -- **Related Dimension**: cuVSLAM on difficult terrain - -## Fact #13 -- **Statement**: cuVSLAM benchmarked on KITTI (mostly urban/suburban driving) and EuRoC (indoor drone). Neither benchmark includes nadir agricultural terrain, flat fields, or uniform vegetation. No published results for these conditions. -- **Source**: cuVSLAM paper Section 3 -- **Confidence**: ✅ High -- **Related Dimension**: cuVSLAM on difficult terrain - -## Fact #14 -- **Statement**: cuVSLAM multi-stereo mode "significantly improves accuracy and robustness on challenging sequences compared to single stereo cameras", designed for featureless surfaces (narrow corridors, elevators). But our system uses monocular camera only. -- **Source**: cuVSLAM paper Section 2.2.2 -- **Confidence**: ✅ High -- **Related Dimension**: cuVSLAM on difficult terrain - -## Fact #15 -- **Statement**: PFED achieves 97.15% Recall@1 on University-1652 at 251.5 FPS on AGX Orin with only 4.45G FLOPs. But this is image RETRIEVAL (which satellite tile matches), NOT pixel-level correspondence matching. -- **Source**: PFED paper (arXiv:2510.22582) -- **Confidence**: ✅ High -- **Related Dimension**: Satellite matching alternatives - -## Fact #16 -- **Statement**: EfficientLoFTR is ~2.5x faster than LoFTR with higher accuracy. Semi-dense matcher, 15.05M params. Has TensorRT adaptation (LoFTR_TRT). Performs well on weak-texture areas where traditional methods fail. Designed for aerial imagery. -- **Source**: EfficientLoFTR paper (CVPR 2024), HuggingFace docs -- **Confidence**: ✅ High -- **Related Dimension**: Satellite matching alternatives - -## Fact #17 -- **Statement**: Hierarchical AVL system (2025) uses two-stage approach: DINOv2 for coarse retrieval + SuperPoint for fine matching. 64.5-95% success rate on real-world drone trajectories. Includes IMU-based prior correction and sliding-window map updates. -- **Source**: MDPI Remote Sensing 2025 -- **Confidence**: ✅ High -- **Related Dimension**: Satellite matching alternatives - -## Fact #18 -- **Statement**: STHN uses deep homography estimation for UAV geo-localization: directly estimates homography transform (no feature detection/matching/RANSAC). Achieves 4.24m MACE at 50m range. Designed for thermal but architecture is modality-agnostic. -- **Source**: STHN paper (IEEE RA-L 2024) -- **Confidence**: ✅ High -- **Related Dimension**: Satellite matching alternatives - -## Fact #19 -- **Statement**: For our nadir UAV → satellite matching, the cross-view gap is SMALL compared to typical cross-view problems (ground-to-satellite). Both views are approximately top-down. Main challenges: season/lighting, resolution mismatch, temporal changes. This means general-purpose matchers may work better than expected. -- **Source**: Analytical observation -- **Confidence**: ⚠️ Medium -- **Related Dimension**: Satellite matching alternatives - -## Fact #20 -- **Statement**: LiteSAM paper benchmarked EfficientLoFTR (opt) on satellite-aerial: 19.8% slower than LiteSAM (opt) on AGX Orin but with 2.4x more parameters. EfficientLoFTR achieves competitive accuracy. LiteSAM paper Table 3/4 provides direct comparison. -- **Source**: LiteSAM paper, Section 4.5 -- **Confidence**: ✅ High -- **Related Dimension**: EfficientLoFTR vs LiteSAM diff --git a/_docs/00_research/gps_denied_nav_v2/03_comparison_framework.md b/_docs/00_research/gps_denied_nav_v2/03_comparison_framework.md deleted file mode 100644 index 1b43e70..0000000 --- a/_docs/00_research/gps_denied_nav_v2/03_comparison_framework.md +++ /dev/null @@ -1,45 +0,0 @@ -# Comparison Framework - -## Selected Framework Type -Decision Support + Problem Diagnosis - -## Selected Dimensions -1. Inference speed on Orin Nano Super -2. Accuracy for the target task -3. Cross-view robustness (satellite-aerial gap) -4. Implementation complexity / ecosystem maturity -5. Memory footprint -6. TensorRT optimization readiness - -## Comparison 1: Visual Odometry — cuVSLAM vs SuperPoint+LightGlue - -| Dimension | cuVSLAM v15.0.0 | SuperPoint + LightGlue (TRT) | Factual Basis | -|-----------|-----------------|-------------------------------|---------------| -| Speed on Orin Nano | ~8.6ms/frame (116fps @ 720p) | Est. ~150-300ms/frame (SP ~40-60ms + LG ~100-200ms) | Fact #1, #2, #3 | -| VO accuracy (KITTI) | <1% trajectory error | ~1% odometric error (desktop) | Fact #1, #2 | -| VO accuracy (EuRoC) | <5cm position error | Not benchmarked | Fact #1 | -| IMU integration | Native mono+IMU mode, auto-fallback | None — must add custom IMU fusion | Fact #1 | -| Loop closure | Built-in | Not available | Fact #1 | -| TensorRT ready | Native CUDA (not TensorRT, raw CUDA) | Requires ONNX export + TRT build | Fact #4 | -| Memory | ~200-300MB | SP ~50MB + LG ~50-100MB = ~100-150MB | Fact #1 | -| Implementation | pip install aarch64 wheel | Custom pipeline: SP export + LG export + matching + pose estimation | Fact #1, #4 | -| Maturity on Jetson | NVIDIA-maintained, production-ready | Community TRT plugins, limited Jetson benchmarks | Fact #4, #5 | - -## Comparison 2: LiteSAM Speed at Different Resolutions - -| Dimension | 1184px (paper default) | 1280px (user proposal) | 640px | 480px | Factual Basis | -|-----------|------------------------|------------------------|-------|-------|---------------| -| Tokens at 1/8 scale | ~21,904 | ~25,600 | ~6,400 | ~3,600 | Fact #7 | -| AGX Orin time | 497ms | Est. ~580ms (1.17x tokens) | Est. ~150ms | Est. ~90ms | Fact #5, #7 | -| Orin Nano Super time (est.) | ~1.5-2.0s | ~1.7-2.3s | ~450-600ms | ~270-360ms | Fact #5, #6 | -| Accuracy (RMSE@30) | 17.86m | Similar (slightly less) | Degraded | Significantly degraded | Fact #8, #10 | - -## Comparison 3: Satellite Matching — LiteSAM vs SP+LG vs XFeat - -| Dimension | LiteSAM (opt) | SuperPoint+LightGlue | XFeat semi-dense | Factual Basis | -|-----------|--------------|---------------------|------------------|---------------| -| Cross-view accuracy | RMSE@30 = 17.86m (UAV-VisLoc) | Worse than LiteSAM (paper confirms) | Not benchmarked on UAV-VisLoc | Fact #9, #10 | -| Speed on Orin Nano (est.) | ~1.5-2s @ 1184px, ~270-360ms @ 480px | Est. ~100-200ms total | ~50-100ms | Fact #5, #2, existing draft | -| Cross-view robustness | Designed for satellite-aerial gap | Sparse matcher, "lacks sufficient accuracy" for cross-view | General-purpose, less robust | Fact #9, #13 | -| Parameters | 6.31M | SP ~1.3M + LG ~7M = ~8.3M | ~5M | Fact #5 | -| Approach | Semi-dense (coarse-to-fine, subpixel) | Sparse (detect → match → verify) | Semi-dense (detect → KNN → refine) | Fact #1, existing draft | diff --git a/_docs/00_research/gps_denied_nav_v2/04_reasoning_chain.md b/_docs/00_research/gps_denied_nav_v2/04_reasoning_chain.md deleted file mode 100644 index d32b622..0000000 --- a/_docs/00_research/gps_denied_nav_v2/04_reasoning_chain.md +++ /dev/null @@ -1,90 +0,0 @@ -# Reasoning Chain - -## Dimension 1: SuperPoint+LightGlue for Visual Odometry - -### Fact Confirmation -cuVSLAM achieves 116fps (~8.6ms/frame) on Orin Nano 8GB at 720p (Fact #1). SP+LG achieves ~10fps on KITTI on desktop GPU (Fact #2). SuperPoint alone takes ~40ms on Jetson for 200 keypoints (Fact #3). LightGlue matching on desktop GPU takes ~20-34ms for 274 keypoints (Fact #2). - -### Extrapolation to Orin Nano Super -On Orin Nano Super, estimating SP+LG pipeline: -- SuperPoint extraction (1024 keypoints, 720p): ~50-80ms (based on Fact #3, scaled for more keypoints) -- LightGlue matching (TensorRT FP16, 1024 keypoints): ~80-200ms (based on Fact #11 — 2-4x speedup over PyTorch, but Orin Nano is ~4-6x slower than RTX 4080) -- Total SP+LG: ~130-280ms per frame - -cuVSLAM: ~8.6ms per frame. - -SP+LG would be **15-33x slower** than cuVSLAM for visual odometry on Orin Nano Super. - -### Additional Considerations -cuVSLAM includes native IMU integration, loop closure, and auto-fallback. SP+LG provides none of these — they would need custom implementation, adding both development time and latency. - -### Conclusion -**SP+LG is not viable as a cuVSLAM replacement for VO on Orin Nano Super.** cuVSLAM is purpose-built for Jetson and 15-33x faster. SP+LG's value lies in its accuracy for feature matching tasks, not real-time VO on edge hardware. - -### Confidence -✅ High — performance gap is enormous and well-supported by multiple sources. - ---- - -## Dimension 2: LiteSAM Speed vs Image Resolution (1280px question) - -### Fact Confirmation -LiteSAM (opt) achieves 497ms on AGX Orin at 1184px (Fact #5). AGX Orin is ~3-4x more powerful than Orin Nano Super (Fact #6). LiteSAM processes at 1/8 scale internally — coarse matching is O(N²) where N is proportional to resolution² (Fact #7). - -### Resolution Scaling Analysis - -**1280px vs 1184px**: Token count increases from ~21,904 to ~25,600 (+17%). Compute increases ~17-37% (linear to quadratic depending on bottleneck). This makes the problem WORSE, not better. - -**The user's intuition is likely**: "If 6252×4168 camera images are huge, maybe LiteSAM is slow because we feed it those big images. What if we use 1280px?" But the solution draft already specifies resizing to 480-640px before feeding LiteSAM. The 497ms benchmark on AGX Orin was already at 1184px (the UAV-VisLoc benchmark resolution). - -**The real bottleneck is hardware, not image size:** -- At 1184px on AGX Orin: 497ms → on Orin Nano Super: est. **~1.5-2.0s** -- At 1280px on Orin Nano Super: est. **~1.7-2.3s** (WORSE — more tokens) -- At 640px on Orin Nano Super: est. **~450-600ms** (borderline) -- At 480px on Orin Nano Super: est. **~270-360ms** (possibly within 400ms budget) - -### Conclusion -**1280px would make LiteSAM SLOWER, not faster.** The paper benchmarked at 1184px. The bottleneck is the hardware gap (AGX Orin 275 TOPS → Orin Nano Super 67 TOPS). To make LiteSAM fit the 400ms budget, resolution must drop to ~480px, which may significantly degrade cross-view matching accuracy. The original solution draft's approach (benchmark at 480px, abandon if too slow) remains correct. - -### Confidence -✅ High — paper benchmarks + hardware specs provide strong basis. - ---- - -## Dimension 3: SP+LG for Satellite Matching (alternative to LiteSAM) - -### Fact Confirmation -LiteSAM paper explicitly states "SP+LG achieves the fastest inference speed but at the expense of accuracy" on satellite-aerial benchmarks (Fact #9). SP+LG is a sparse matcher; the paper notes sparse matchers "lack sufficient accuracy" for cross-view UAV-satellite matching due to texture-scarce regions (Fact #13). LiteSAM achieves RMSE@30 = 17.86m; SP+LG is worse (Fact #10). - -### Speed Advantage of SP+LG -On Orin Nano Super, SP+LG satellite matching pipeline: -- SuperPoint extraction (both images): ~50-80ms × 2 images -- LightGlue matching: ~80-200ms -- Total: ~180-360ms - -This is competitive with the 400ms budget. But accuracy is worse than LiteSAM. - -### Comparison with XFeat -XFeat semi-dense: ~50-100ms on Orin Nano Super (from existing draft). XFeat is 2-4x faster than SP+LG and also handles semi-dense matching. For the satellite matching role, XFeat is a better "fast fallback" than SP+LG. - -### Conclusion -**SP+LG is not recommended for satellite matching.** It's slower than XFeat and less accurate than LiteSAM for cross-view matching. XFeat remains the better fallback. SP+LG could serve as a third-tier fallback, but the added complexity isn't justified given XFeat's advantages. - -### Confidence -✅ High — direct comparison from the LiteSAM paper. - ---- - -## Dimension 4: Other Weak Points in solution_draft01 - -### cuVSLAM Nadir Camera Concern -The solution correctly flags cuVSLAM's "nadir-only camera" as untested. cuVSLAM was designed for robotics (forward-facing cameras). Nadir UAV camera looking straight down at terrain has different motion characteristics. However, cuVSLAM supports arbitrary camera configurations and IMU mode should compensate. **Risk is MEDIUM, mitigation is adequate** (XFeat fallback). - -### Memory Budget Gap -The solution estimates ~1.9-2.4GB total. This looks optimistic if cuVSLAM needs to maintain a map for loop closure. The cuVSLAM map grows over time. For a 3000-frame flight (~16 min at 3fps), map memory could grow to 500MB-1GB. **Risk: memory pressure late in flight.** Mitigation: configure cuVSLAM map pruning, limit map size. - -### Tile Search Strategy Underspecified -The solution mentions GeoHash-indexed tiles but doesn't detail how the system determines which tile to match against when ESKF position has high uncertainty (e.g., after VO failure). The expanded search (±1km) could require loading 10-20 tiles, which is slow from storage. - -### Confidence -⚠️ Medium — these are analytical observations, not empirically verified. diff --git a/_docs/00_research/gps_denied_nav_v2/05_validation_log.md b/_docs/00_research/gps_denied_nav_v2/05_validation_log.md deleted file mode 100644 index 687d2a7..0000000 --- a/_docs/00_research/gps_denied_nav_v2/05_validation_log.md +++ /dev/null @@ -1,52 +0,0 @@ -# Validation Log - -## Validation Scenario 1: SP+LG for VO during Normal Flight - -A UAV flies straight at 3fps. Each frame needs VO within 400ms. - -### Expected Based on Conclusions -cuVSLAM: processes each frame in ~8.6ms, leaves 391ms for satellite matching and fusion. Immediate VO result via SSE. -SP+LG: processes each frame in ~130-280ms, leaves ~120-270ms. May interfere with satellite matching CUDA resources. - -### Actual Validation -cuVSLAM is clearly superior. SP+LG offers no advantage here — cuVSLAM is 15-33x faster AND includes IMU fallback. SP+LG would require building a custom VO pipeline around a feature matcher, whereas cuVSLAM is a complete VO solution. - -### Counterexamples -If cuVSLAM fails on nadir camera (its main risk), SP+LG could serve as a fallback VO method. But XFeat frame-to-frame (~30-50ms) is already identified as the cuVSLAM fallback and is 3-6x faster than SP+LG. - -## Validation Scenario 2: LiteSAM at 1280px on Orin Nano Super - -A keyframe needs satellite matching. Image is resized to 1280px for LiteSAM. - -### Expected Based on Conclusions -LiteSAM at 1280px on Orin Nano Super: ~1.7-2.3s. This is 4-6x over the 400ms budget. Even running async, it means satellite corrections arrive 5-7 frames later. - -### Actual Validation -1280px is LARGER than the paper's 1184px benchmark resolution. The user likely assumed we feed the full camera image (6252×4168) to LiteSAM, causing slowness. But the solution already downsamples. The bottleneck is the hardware performance gap (Orin Nano Super = ~25% of AGX Orin compute). - -### Counterexamples -If LiteSAM's TensorRT FP16 engine with reparameterized MobileOne achieves better optimization than the paper's AMP benchmark (which uses PyTorch, not TensorRT), speed could improve 2-3x. At 480px with TensorRT FP16: potentially ~90-180ms on Orin Nano Super. This is worth benchmarking. - -## Validation Scenario 3: SP+LG as Satellite Matcher After LiteSAM Abandonment - -LiteSAM fails benchmark. Instead of XFeat, we try SP+LG for satellite matching. - -### Expected Based on Conclusions -SP+LG: ~180-360ms on Orin Nano Super. Accuracy is worse than LiteSAM for cross-view matching. -XFeat: ~50-100ms. Accuracy is unproven on cross-view but general-purpose semi-dense. - -### Actual Validation -SP+LG is 2-4x slower than XFeat and the LiteSAM paper confirms worse accuracy for satellite-aerial. XFeat's semi-dense approach is more suited to the texture-scarce regions common in UAV imagery. SP+LG's sparse keypoint detection may fail on agricultural fields or water bodies. - -### Counterexamples -SP+LG could outperform XFeat on high-texture urban areas where sparse features are abundant. But the operational region (eastern Ukraine) is primarily agricultural, making this advantage unlikely. - -## Review Checklist -- [x] Draft conclusions consistent with fact cards -- [x] No important dimensions missed -- [x] No over-extrapolation -- [x] Conclusions actionable/verifiable -- [ ] Note: Orin Nano Super estimates are extrapolated from AGX Orin data using the 3-4x compute ratio. Day-one benchmarking remains essential. - -## Conclusions Requiring Revision -None — the original solution draft's architecture (cuVSLAM for VO, benchmark-driven LiteSAM/XFeat for satellite) is confirmed sound. SP+LG is not recommended for either role on this hardware. diff --git a/_docs/00_research/gps_denied_nav_v3/00_question_decomposition.md b/_docs/00_research/gps_denied_nav_v3/00_question_decomposition.md deleted file mode 100644 index affe2b6..0000000 --- a/_docs/00_research/gps_denied_nav_v3/00_question_decomposition.md +++ /dev/null @@ -1,102 +0,0 @@ -# Question Decomposition - -## Original Question -Assess solution_draft02.md against updated acceptance criteria and restrictions. The AC and restrictions have been significantly revised to reflect real onboard deployment requirements (MAVLink integration, ground station telemetry, startup/failsafe, object localization, thermal management, satellite imagery specs). - -## Active Mode -Mode B: Solution Assessment — `solution_draft02.md` is the latest draft in OUTPUT_DIR. - -## Question Type -Problem Diagnosis + Decision Support - -## Research Subject Boundary -- **Population**: GPS-denied UAV navigation systems on edge hardware (Jetson Orin Nano Super) -- **Geography**: Eastern/southern Ukraine (east of Dnipro River), conflict zone -- **Timeframe**: Current (2025-2026), latest available tools and libraries -- **Level**: Onboard companion computer, real-time flight controller integration via MAVLink - -## Key Delta: What Changed in AC/Restrictions - -### Restrictions Changes -1. Two cameras: Navigation (fixed, downward) + AI camera (configurable angle/zoom) -2. Processing on Jetson Orin Nano Super (was "stationary computer or laptop") -3. IMU data IS available via flight controller (was "NO data from IMU") -4. MAVLink protocol via MAVSDK for flight controller communication -5. Must output GPS_INPUT messages as GPS replacement -6. Ground station telemetry link available but bandwidth-limited -7. Thermal throttling must be accounted for -8. Satellite imagery pre-loaded, storage limited - -### Acceptance Criteria Changes -1. <400ms per frame to flight controller (was <5s for processing) -2. MAVLink GPS_INPUT output (was REST API + SSE) -3. Ground station: stream position/confidence, receive re-localization commands -4. Object localization: trigonometric GPS from AI camera angle/zoom/altitude -5. Startup: initialize from last known GPS before GPS denial -6. Failsafe: IMU-only fallback after N seconds of total failure -7. Reboot recovery: re-initialize from flight controller IMU-extrapolated position -8. Max cumulative VO drift <100m between satellite anchors -9. Confidence score per position estimate (high/low) -10. Satellite imagery: ≥0.5 m/pixel, <2 years old -11. WGS84 output format -12. Re-localization via telemetry to ground station (not REST API user input) - -## Decomposed Sub-Questions - -### Q1: MAVLink GPS_INPUT Integration -- How does MAVSDK Python handle GPS_INPUT messages? -- What fields are required in GPS_INPUT? -- What update rate does the flight controller expect? -- Can we send confidence/accuracy indicators via MAVLink? -- How does this replace the REST API + SSE architecture? - -### Q2: Ground Station Telemetry Integration -- How to stream position + confidence over bandwidth-limited telemetry? -- How to receive operator re-localization commands? -- What MAVLink messages support custom data? -- What bandwidth is typical for UAV telemetry links? - -### Q3: Startup & Failsafe Mechanisms -- How to initialize from flight controller's last GPS position? -- How to detect GPS denial onset? -- What happens on companion computer reboot mid-flight? -- How to implement IMU-only dead reckoning fallback? - -### Q4: Object Localization via AI Camera -- How to compute ground GPS from UAV position + camera angle + zoom + altitude? -- What accuracy can be expected given GPS-denied position error? -- How to handle the API between GPS-denied system and AI detection system? - -### Q5: Thermal Management on Jetson Orin Nano Super -- What is sustained thermal performance under GPU load? -- How to monitor and mitigate thermal throttling? -- What power modes are available? - -### Q6: VO Drift Budget & Monitoring -- How to measure cumulative drift between satellite anchors? -- How to trigger satellite matching when drift approaches 100m? -- ESKF covariance as drift proxy? - -### Q7: Weak Points in Draft02 Architecture -- REST API + SSE architecture is wrong — must be MAVLink -- No ground station integration -- No startup/shutdown procedures -- No thermal management -- No object localization detail for AI camera with configurable angle/zoom -- Memory budget doesn't account for MAVSDK overhead - -## Timeliness Sensitivity Assessment -- **Research Topic**: MAVLink integration, MAVSDK for Jetson, ground station telemetry, thermal management -- **Sensitivity Level**: 🟠 High -- **Rationale**: MAVSDK actively developed; MAVLink message set evolving; Jetson JetPack 6.2 specific -- **Source Time Window**: 12 months -- **Priority official sources**: - 1. MAVSDK Python documentation (mavsdk.io) - 2. MAVLink message definitions (mavlink.io) - 3. NVIDIA Jetson Orin Nano thermal documentation - 4. PX4/ArduPilot GPS_INPUT documentation -- **Key version information**: - - MAVSDK-Python: latest PyPI version - - MAVLink: v2 protocol - - JetPack: 6.2.2 - - PyCuVSLAM: v15.0.0 diff --git a/_docs/00_research/gps_denied_nav_v3/01_source_registry.md b/_docs/00_research/gps_denied_nav_v3/01_source_registry.md deleted file mode 100644 index dd4dfd8..0000000 --- a/_docs/00_research/gps_denied_nav_v3/01_source_registry.md +++ /dev/null @@ -1,175 +0,0 @@ -# Source Registry - -## Source #1 -- **Title**: MAVSDK-Python Issue #320: Input external GPS through MAVSDK -- **Link**: https://github.com/mavlink/MAVSDK-Python/issues/320 -- **Tier**: L4 -- **Publication Date**: 2021 (still open 2025) -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: MAVSDK-Python — GPS_INPUT not supported as of v3.15.3 -- **Target Audience**: Companion computer developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: MAVSDK-Python does not support GPS_INPUT message. Feature requested but unresolved. -- **Related Sub-question**: Q1 - -## Source #2 -- **Title**: MAVLink GPS_INPUT Message Specification (mavlink_msg_gps_input.h) -- **Link**: https://rflysim.com/doc/en/RflySimAPIs/RflySimSDK/html/mavlink__msg__gps__input_8h_source.html -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: MAVLink v2, Message ID 232 -- **Target Audience**: MAVLink developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: GPS_INPUT message fields: lat/lon (1E7), alt, fix_type, horiz_accuracy, vert_accuracy, speed_accuracy, hdop, vdop, satellites_visible, velocities NED, yaw, ignore_flags. -- **Related Sub-question**: Q1 - -## Source #3 -- **Title**: ArduPilot GPS Input MAVProxy Documentation -- **Link**: https://ardupilot.org/mavproxy/docs/modules/GPSInput.html -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: ArduPilot GPS1_TYPE=14 -- **Target Audience**: ArduPilot companion computer developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: GPS_INPUT requires GPS1_TYPE=14. Accepts JSON over UDP port 25100. Fields: lat, lon, alt, fix_type, hdop, timestamps. -- **Related Sub-question**: Q1 - -## Source #4 -- **Title**: pymavlink GPS_INPUT example -- **Link**: https://webperso.ensta.fr/lebars/Share/GPS_INPUT_pymavlink.py -- **Tier**: L3 -- **Publication Date**: 2023 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: pymavlink -- **Target Audience**: Companion computer developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Complete pymavlink example for sending GPS_INPUT with all fields including yaw. Uses gps_input_send() method. -- **Related Sub-question**: Q1 - -## Source #5 -- **Title**: ArduPilot AP_GPS_Params.cpp — GPS_RATE_MS -- **Link**: https://cocalc.com/github/ardupilot/ardupilot/blob/master/libraries/AP_GPS/AP_GPS_Params.cpp -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: ArduPilot master -- **Target Audience**: ArduPilot developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: GPS_RATE_MS default 200ms (5Hz), range 50-200ms (5-20Hz). Below 5Hz not allowed. -- **Related Sub-question**: Q1 - -## Source #6 -- **Title**: MAVLink Telemetry Bandwidth Optimization Issue #1605 -- **Link**: https://github.com/mavlink/mavlink/issues/1605 -- **Tier**: L2 -- **Publication Date**: 2022 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: MAVLink protocol developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Minimal telemetry requires ~12kbit/s. Optimized ~6kbit/s. SiK at 57600 baud provides ~21% usable budget. RFD900 for long range (15km+). -- **Related Sub-question**: Q2 - -## Source #7 -- **Title**: NVIDIA JetPack 6.2 Super Mode Blog -- **Link**: https://developer.nvidia.com/blog/nvidia-jetpack-6-2-brings-super-mode-to-nvidia-jetson-orin-nano-and-jetson-orin-nx-modules/ -- **Tier**: L1 -- **Publication Date**: 2025-01 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: JetPack 6.2, Orin Nano Super -- **Target Audience**: Jetson developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: MAXN SUPER mode for peak performance. Thermal throttling at 80°C. Power modes: 15W, 25W, MAXN SUPER. Up to 1.7x AI boost. -- **Related Sub-question**: Q5 - -## Source #8 -- **Title**: Jetson Orin Nano Power Consumption Analysis -- **Link**: https://edgeaistack.app/blog/jetson-orin-nano-power-consumption/ -- **Tier**: L3 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Jetson edge deployment engineers -- **Research Boundary Match**: ✅ Full match -- **Summary**: 5W idle, 8-12W typical inference, 25W peak. Throttling above 80°C drops GPU from 1GHz to 300MHz. Active cooling required for sustained loads. -- **Related Sub-question**: Q5 - -## Source #9 -- **Title**: UAV Target Geolocation (Sensors 2022) -- **Link**: https://www.mdpi.com/1424-8220/22/5/1903 -- **Tier**: L1 -- **Publication Date**: 2022 -- **Timeliness Status**: ✅ Currently valid (math doesn't change) -- **Target Audience**: UAV reconnaissance systems -- **Research Boundary Match**: ✅ Full match -- **Summary**: Trigonometric target geolocation from camera angle, altitude, UAV position. Iterative refinement improves accuracy 22-38x. -- **Related Sub-question**: Q4 - -## Source #10 -- **Title**: pymavlink vs MAVSDK-Python for custom messages (Issue #739) -- **Link**: https://github.com/mavlink/MAVSDK-Python/issues/739 -- **Tier**: L4 -- **Publication Date**: 2024-12 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: MAVSDK-Python, pymavlink -- **Target Audience**: Companion computer developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: MAVSDK-Python lacks custom message support. pymavlink recommended for GPS_INPUT and custom messages. MAVSDK v4 may add MavlinkDirect plugin. -- **Related Sub-question**: Q1 - -## Source #11 -- **Title**: NAMED_VALUE_FLOAT for custom telemetry (PR #18501) -- **Link**: https://github.com/ArduPilot/ardupilot/pull/18501 -- **Tier**: L2 -- **Publication Date**: 2022 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: ArduPilot companion computer developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: NAMED_VALUE_FLOAT messages from companion computer are logged by ArduPilot and forwarded to GCS. Useful for custom telemetry data. -- **Related Sub-question**: Q2 - -## Source #12 -- **Title**: ArduPilot Companion Computer UART Connection -- **Link**: https://ardupilot.org/dev/docs/raspberry-pi-via-mavlink.html -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: ArduPilot companion computer developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Connect via TELEM2 UART. SERIAL2_PROTOCOL=2 (MAVLink2). Baud up to 1.5Mbps. TX/RX crossover. -- **Related Sub-question**: Q1, Q2 - -## Source #13 -- **Title**: Jetson Orin Nano UART with ArduPilot -- **Link**: https://forums.developer.nvidia.com/t/uart-connection-between-jetson-nano-orin-and-ardupilot/325416 -- **Tier**: L4 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: JetPack 6.x, Orin Nano -- **Target Audience**: Jetson + ArduPilot integration -- **Research Boundary Match**: ✅ Full match -- **Summary**: UART instability reported on Orin Nano with ArduPilot. Use /dev/ttyTHS0 or /dev/ttyTHS1. Check pinout carefully. -- **Related Sub-question**: Q1 - -## Source #14 -- **Title**: MAVSDK-Python v3.15.3 PyPI (aarch64 wheels) -- **Link**: https://pypi.org/project/mavsdk/ -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: v3.15.3, manylinux2014_aarch64 -- **Target Audience**: MAVSDK Python developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: MAVSDK-Python has aarch64 wheels. pip install works on Jetson. But no GPS_INPUT support. -- **Related Sub-question**: Q1 - -## Source #15 -- **Title**: ArduPilot receive COMMAND_LONG on companion computer -- **Link**: https://discuss.ardupilot.org/t/recieve-mav-cmd-on-companion-computer/48928 -- **Tier**: L4 -- **Publication Date**: 2020 -- **Timeliness Status**: ⚠️ Needs verification (old but concept still valid) -- **Target Audience**: ArduPilot companion computer developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Companion computer can receive COMMAND_LONG messages from GCS via MAVLink. ArduPilot scripting can intercept specific command IDs. -- **Related Sub-question**: Q2 diff --git a/_docs/00_research/gps_denied_nav_v3/02_fact_cards.md b/_docs/00_research/gps_denied_nav_v3/02_fact_cards.md deleted file mode 100644 index cf5bb72..0000000 --- a/_docs/00_research/gps_denied_nav_v3/02_fact_cards.md +++ /dev/null @@ -1,105 +0,0 @@ -# Fact Cards - -## Fact #1 -- **Statement**: MAVSDK-Python (v3.15.3) does NOT support sending GPS_INPUT MAVLink messages. The feature has been requested since 2021 and remains unresolved. Custom message support is planned for MAVSDK v4 but not available in Python wrapper. -- **Source**: Source #1, #10, #14 -- **Phase**: Assessment -- **Target Audience**: GPS-Denied system developers -- **Confidence**: ✅ High — confirmed by MAVSDK maintainers -- **Related Dimension**: Flight Controller Integration - -## Fact #2 -- **Statement**: pymavlink provides full access to all MAVLink messages including GPS_INPUT via `mav.gps_input_send()`. It is the recommended library for companion computers that need to send GPS_INPUT messages. -- **Source**: Source #4, #10 -- **Phase**: Assessment -- **Target Audience**: GPS-Denied system developers -- **Confidence**: ✅ High — working examples exist -- **Related Dimension**: Flight Controller Integration - -## Fact #3 -- **Statement**: GPS_INPUT (MAVLink msg ID 232) contains: lat/lon (WGS84, degrees×1E7), alt (AMSL), fix_type (0-8), horiz_accuracy (m), vert_accuracy (m), speed_accuracy (m/s), hdop, vdop, satellites_visible, vn/ve/vd (NED m/s), yaw (centidegrees), gps_id, ignore_flags. -- **Source**: Source #2 -- **Phase**: Assessment -- **Target Audience**: GPS-Denied system developers -- **Confidence**: ✅ High — official MAVLink spec -- **Related Dimension**: Flight Controller Integration - -## Fact #4 -- **Statement**: ArduPilot requires GPS1_TYPE=14 (MAVLink) to accept GPS_INPUT messages from a companion computer. Connection via TELEM2 UART, SERIAL2_PROTOCOL=2 (MAVLink2). -- **Source**: Source #3, #12 -- **Phase**: Assessment -- **Target Audience**: GPS-Denied system developers -- **Confidence**: ✅ High — official ArduPilot documentation -- **Related Dimension**: Flight Controller Integration - -## Fact #5 -- **Statement**: ArduPilot GPS update rate (GPS_RATE_MS) default is 200ms (5Hz), range 50-200ms (5-20Hz). Our camera at 3fps (333ms) means GPS_INPUT at 3Hz. ArduPilot minimum is 5Hz. We must interpolate/predict between camera frames to meet 5Hz minimum. -- **Source**: Source #5 -- **Phase**: Assessment -- **Target Audience**: GPS-Denied system developers -- **Confidence**: ✅ High — ArduPilot source code -- **Related Dimension**: Flight Controller Integration - -## Fact #6 -- **Statement**: GPS_INPUT horiz_accuracy field directly maps to our confidence scoring. We can report: satellite-anchored ≈ 10-20m accuracy, VO-extrapolated ≈ 20-50m, IMU-only ≈ 100m+. ArduPilot EKF uses this for fusion weighting internally. -- **Source**: Source #2, #3 -- **Phase**: Assessment -- **Target Audience**: GPS-Denied system developers -- **Confidence**: ⚠️ Medium — accuracy mapping is estimated, EKF weighting not fully documented -- **Related Dimension**: Flight Controller Integration - -## Fact #7 -- **Statement**: Typical UAV telemetry bandwidth: SiK radio at 57600 baud provides ~12kbit/s usable for MAVLink. RFD900 provides long range (15km+) at similar data rates. Position telemetry must be compact — ~50 bytes per position update. -- **Source**: Source #6 -- **Phase**: Assessment -- **Target Audience**: GPS-Denied system developers -- **Confidence**: ✅ High — MAVLink protocol specs -- **Related Dimension**: Ground Station Telemetry - -## Fact #8 -- **Statement**: NAMED_VALUE_FLOAT MAVLink message can stream custom telemetry from companion computer to ground station. ArduPilot logs and forwards these. Mission Planner displays them. Useful for confidence score, drift status, matching status. -- **Source**: Source #11 -- **Phase**: Assessment -- **Target Audience**: GPS-Denied system developers -- **Confidence**: ✅ High — ArduPilot merged PR -- **Related Dimension**: Ground Station Telemetry - -## Fact #9 -- **Statement**: Jetson Orin Nano Super throttles GPU from 1GHz to ~300MHz when junction temperature exceeds 80°C. Active cooling (fan) required for sustained load. Power consumption: 5W idle, 8-12W typical inference, 25W peak. Modes: 15W, 25W, MAXN SUPER. -- **Source**: Source #7, #8 -- **Phase**: Assessment -- **Target Audience**: GPS-Denied system developers -- **Confidence**: ✅ High — NVIDIA official -- **Related Dimension**: Thermal Management - -## Fact #10 -- **Statement**: Jetson Orin Nano UART connection to ArduPilot uses /dev/ttyTHS0 or /dev/ttyTHS1. UART instability reported on some units — verify pinout, use JetPack 6.2.2+. Baud up to 1.5Mbps supported. -- **Source**: Source #12, #13 -- **Phase**: Assessment -- **Target Audience**: GPS-Denied system developers -- **Confidence**: ⚠️ Medium — UART instability is a known issue with workarounds -- **Related Dimension**: Flight Controller Integration - -## Fact #11 -- **Statement**: Object geolocation from UAV: for nadir (downward) camera, pixel offset from center → meters via GSD → rotate by heading → add to UAV GPS. For oblique (AI) camera with angle θ from vertical: ground_distance = altitude × tan(θ). Combined with zoom → effective focal length → pixel-to-meter conversion. Flat terrain assumption simplifies to basic trigonometry. -- **Source**: Source #9 -- **Phase**: Assessment -- **Target Audience**: GPS-Denied system developers -- **Confidence**: ✅ High — well-established trigonometry -- **Related Dimension**: Object Localization - -## Fact #12 -- **Statement**: Companion computer can receive COMMAND_LONG from ground station via MAVLink. For re-localization hints: ground station sends a custom command with approximate lat/lon, companion computer receives it via pymavlink message listener. -- **Source**: Source #15 -- **Phase**: Assessment -- **Target Audience**: GPS-Denied system developers -- **Confidence**: ⚠️ Medium — specific implementation for re-localization hint would be custom -- **Related Dimension**: Ground Station Telemetry - -## Fact #13 -- **Statement**: The restrictions.md now says "using MAVSDK library" but MAVSDK-Python cannot send GPS_INPUT. pymavlink is the only viable Python option for GPS_INPUT. This is a restriction conflict that must be resolved — use pymavlink for GPS_INPUT (core function) or accept MAVSDK + pymavlink hybrid. -- **Source**: Source #1, #2, #10 -- **Phase**: Assessment -- **Target Audience**: GPS-Denied system developers -- **Confidence**: ✅ High — confirmed limitation -- **Related Dimension**: Flight Controller Integration diff --git a/_docs/00_research/gps_denied_nav_v3/03_comparison_framework.md b/_docs/00_research/gps_denied_nav_v3/03_comparison_framework.md deleted file mode 100644 index 0e156a8..0000000 --- a/_docs/00_research/gps_denied_nav_v3/03_comparison_framework.md +++ /dev/null @@ -1,62 +0,0 @@ -# Comparison Framework - -## Selected Framework Type -Problem Diagnosis + Decision Support (Mode B) - -## Weak Point Dimensions (from draft02 → new AC/restrictions) - -### Dimension 1: Output Architecture (CRITICAL) -Draft02 uses FastAPI + SSE to stream positions to clients. -New AC requires MAVLink GPS_INPUT to flight controller as PRIMARY output. -Entire output architecture must change. - -### Dimension 2: Ground Station Communication (CRITICAL) -Draft02 has no ground station integration. -New AC requires: stream position+confidence via telemetry, receive re-localization commands. - -### Dimension 3: MAVLink Library Choice (CRITICAL) -Restrictions say "MAVSDK library" but MAVSDK-Python cannot send GPS_INPUT. -Must use pymavlink for core function. - -### Dimension 4: GPS Update Rate (HIGH) -Camera at 3fps → 3Hz position updates. ArduPilot minimum GPS rate is 5Hz. -Need IMU-based interpolation between camera frames. - -### Dimension 5: Startup & Failsafe (HIGH) -Draft02 has no initialization or failsafe procedures. -New AC requires: init from last GPS, reboot recovery, IMU fallback after N seconds. - -### Dimension 6: Object Localization (MEDIUM) -Draft02 has basic pixel-to-GPS for navigation camera only. -New AC adds AI camera with configurable angle, zoom — trigonometric projection needed. - -### Dimension 7: Thermal Management (MEDIUM) -Draft02 ignores thermal throttling. -Jetson Orin Nano Super throttles at 80°C — can drop GPU 3x. - -### Dimension 8: VO Drift Budget Monitoring (MEDIUM) -New AC: max cumulative VO drift <100m between satellite anchors. -Draft02 uses ESKF covariance but doesn't explicitly track drift budget. - -### Dimension 9: Satellite Imagery Specs (LOW) -New AC: ≥0.5 m/pixel, <2 years old. Draft02 uses Google Maps zoom 18-19 which is ~0.3-0.6 m/pixel. -Mostly compatible, needs explicit validation. - -### Dimension 10: API for Internal Systems (LOW) -Object localization requests from AI systems need a local IPC mechanism. -FastAPI could be retained for local-only inter-process communication. - -## Initial Population - -| Dimension | Draft02 State | Required State | Gap Severity | -|-----------|--------------|----------------|-------------| -| Output Architecture | FastAPI + SSE to client | MAVLink GPS_INPUT to flight controller | CRITICAL — full redesign | -| Ground Station | None | Bidirectional MAVLink telemetry | CRITICAL — new component | -| MAVLink Library | Not applicable (no MAVLink) | pymavlink (MAVSDK can't do GPS_INPUT) | CRITICAL — new dependency | -| GPS Update Rate | 3fps → ~3Hz output | ≥5Hz to ArduPilot EKF | HIGH — need IMU interpolation | -| Startup & Failsafe | None | Init from GPS, reboot recovery, IMU fallback | HIGH — new procedures | -| Object Localization | Basic nadir pixel-to-GPS | AI camera angle+zoom trigonometry | MEDIUM — extend existing | -| Thermal Management | Not addressed | Monitor + mitigate throttling | MEDIUM — operational concern | -| VO Drift Budget | ESKF covariance only | Explicit <100m tracking + trigger | MEDIUM — extend ESKF | -| Satellite Imagery Specs | Google Maps zoom 18-19 | ≥0.5 m/pixel, <2 years | LOW — mostly met | -| Internal IPC | REST API | Lightweight local API or shared memory | LOW — simplify from draft02 | diff --git a/_docs/00_research/gps_denied_nav_v3/04_reasoning_chain.md b/_docs/00_research/gps_denied_nav_v3/04_reasoning_chain.md deleted file mode 100644 index 05fea69..0000000 --- a/_docs/00_research/gps_denied_nav_v3/04_reasoning_chain.md +++ /dev/null @@ -1,202 +0,0 @@ -# Reasoning Chain - -## Dimension 1: Output Architecture - -### Fact Confirmation -Per Fact #3, GPS_INPUT (MAVLink msg ID 232) accepts lat/lon in WGS84 (degrees×1E7), altitude, fix_type, accuracy fields, and NED velocities. Per Fact #4, ArduPilot uses GPS1_TYPE=14 to accept MAVLink GPS input. The flight controller's EKF fuses this as if it were a real GPS module. - -### Reference Comparison -Draft02 uses FastAPI + SSE to stream position data to a REST client. The new AC requires the system to output GPS coordinates directly to the flight controller via MAVLink GPS_INPUT, replacing the real GPS module. The flight controller then uses these coordinates for navigation/autopilot functions. The ground station receives position data indirectly via the flight controller's telemetry forwarding. - -### Conclusion -The entire output architecture must change from REST API + SSE → pymavlink GPS_INPUT sender. FastAPI is no longer the primary output mechanism. It may be retained only for local IPC with other onboard AI systems (object localization requests). The SSE streaming to external clients is replaced by MAVLink telemetry forwarding through the flight controller. - -### Confidence -✅ High — clear requirement change backed by MAVLink specification - ---- - -## Dimension 2: Ground Station Communication - -### Fact Confirmation -Per Fact #7, typical telemetry bandwidth is ~12kbit/s (SiK). Per Fact #8, NAMED_VALUE_FLOAT can stream custom values from companion to GCS. Per Fact #12, COMMAND_LONG can deliver commands from GCS to companion. - -### Reference Comparison -Draft02 has no ground station integration. The new AC requires: -1. Stream position + confidence to ground station (passive, via telemetry forwarding of GPS_INPUT data + custom NAMED_VALUE_FLOAT for confidence/drift) -2. Receive re-localization commands from operator (active, via COMMAND_LONG or custom MAVLink message) - -### Conclusion -Ground station communication uses MAVLink messages forwarded through the flight controller's telemetry radio. Position data flows automatically (flight controller forwards GPS data to GCS). Custom telemetry (confidence, drift, status) uses NAMED_VALUE_FLOAT. Re-localization hints from operator use a custom COMMAND_LONG with lat/lon payload. Bandwidth is tight (~12kbit/s) so minimize custom message frequency (1-2Hz max for NAMED_VALUE_FLOAT). - -### Confidence -✅ High — standard MAVLink patterns - ---- - -## Dimension 3: MAVLink Library Choice - -### Fact Confirmation -Per Fact #1, MAVSDK-Python v3.15.3 does NOT support GPS_INPUT. Per Fact #2, pymavlink provides full GPS_INPUT support via `mav.gps_input_send()`. Per Fact #13, the restrictions say "using MAVSDK library" but MAVSDK literally cannot do the core function. - -### Reference Comparison -MAVSDK is a higher-level abstraction over MAVLink. pymavlink is the lower-level direct MAVLink implementation. For GPS_INPUT (our core output), only pymavlink works. - -### Conclusion -Use **pymavlink** as the MAVLink library. The restriction mentioning MAVSDK must be noted as a conflict — pymavlink is the only viable option for GPS_INPUT in Python. pymavlink is lightweight, pure Python, works on aarch64, and provides full access to all MAVLink messages. MAVSDK v4 may add custom message support in the future but is not available now. - -### Confidence -✅ High — confirmed limitation, clear alternative - ---- - -## Dimension 4: GPS Update Rate - -### Fact Confirmation -Per Fact #5, ArduPilot GPS_RATE_MS has a minimum of 200ms (5Hz). Our camera shoots at ~3fps (333ms). We produce a full VO+ESKF position estimate per frame at ~3Hz. - -### Reference Comparison -3Hz < 5Hz minimum. ArduPilot's EKF expects at least 5Hz GPS updates for stable fusion. - -### Conclusion -Between camera frames, use IMU prediction from the ESKF to interpolate position at 5Hz (or higher, e.g., 10Hz). The ESKF already runs IMU prediction at 100+Hz internally. Simply emit the ESKF predicted state as GPS_INPUT at 5-10Hz. Camera frame updates (3Hz) provide the measurement corrections. This is standard in sensor fusion: prediction runs fast, measurements arrive slower. The `fix_type` field can differentiate: camera-corrected frames → fix_type=3 (3D), IMU-predicted → fix_type=2 (2D) or adjust horiz_accuracy to reflect lower confidence. - -### Confidence -✅ High — standard sensor fusion approach - ---- - -## Dimension 5: Startup & Failsafe - -### Fact Confirmation -Per new AC: system initializes from last known GPS before GPS denial. On reboot: re-initialize from flight controller's IMU-extrapolated position. On total failure for N seconds: flight controller falls back to IMU-only. - -### Reference Comparison -Draft02 has no startup or failsafe procedures. The system was assumed to already know its position at session start. - -### Conclusion -Startup sequence: -1. On boot, connect to flight controller via pymavlink -2. Read current GPS position from flight controller (GLOBAL_POSITION_INT or GPS_RAW_INT message) -3. Initialize ESKF state with this position -4. Begin cuVSLAM initialization with first camera frames -5. Start sending GPS_INPUT once ESKF has a valid position estimate - -Failsafe: -1. If no position estimate for N seconds → stop sending GPS_INPUT (flight controller auto-detects GPS loss and falls back to IMU) -2. Log failure event -3. Continue attempting VO/satellite matching - -Reboot recovery: -1. On companion computer reboot, reconnect to flight controller -2. Read current GPS_RAW_INT (which is now IMU-extrapolated by flight controller) -3. Re-initialize ESKF with this position (lower confidence) -4. Resume normal operation - -### Confidence -✅ High — standard autopilot integration patterns - ---- - -## Dimension 6: Object Localization - -### Fact Confirmation -Per Fact #11, for oblique camera: ground_distance = altitude × tan(θ) where θ is angle from vertical. Combined with camera azimuth (yaw + camera pan angle) gives direction. With zoom, effective FOV narrows → higher pixel-to-meter resolution. - -### Reference Comparison -Draft02 has basic nadir-only projection: pixel offset × GSD → meters → rotate by heading → lat/lon. The AI camera has configurable angle and zoom, so this needs extension. - -### Conclusion -Object localization for AI camera: -1. Get current UAV position from GPS-Denied system -2. Get AI camera params: pan angle (azimuth relative to heading), tilt angle (from vertical), zoom level (→ effective focal length) -3. Get pixel coordinates of detected object in AI camera frame -4. Compute: a) bearing = UAV heading + camera pan angle + pixel horizontal offset angle, b) ground_distance = altitude / cos(tilt) × (tilt + pixel vertical offset angle) → simplified for flat terrain, c) convert bearing + distance to lat/lon offset from UAV position -5. Accuracy inherits GPS-Denied position error + projection error from altitude/angle uncertainty - -Expose as lightweight local API (Unix socket or shared memory for speed, or simple HTTP on localhost). - -### Confidence -✅ High — well-established trigonometry, flat terrain simplifies - ---- - -## Dimension 7: Thermal Management - -### Fact Confirmation -Per Fact #9, Jetson Orin Nano Super throttles at 80°C junction temperature, dropping GPU from ~1GHz to ~300MHz (3x slowdown). Active cooling required. Power modes: 15W, 25W, MAXN SUPER. - -### Reference Comparison -Draft02 ignores thermal constraints. Our pipeline (cuVSLAM ~9ms + satellite matcher ~50-200ms) runs on GPU continuously at 3fps. This is moderate but sustained load. - -### Conclusion -Mitigation: -1. Use 25W power mode (not MAXN SUPER) for stable sustained performance -2. Require active cooling (5V fan, should be standard on any UAV companion computer mount) -3. Monitor temperature via tegrastats/jtop at runtime -4. If temp >75°C: reduce satellite matching frequency (every 5-10 frames instead of 3) -5. If temp >80°C: skip satellite matching entirely, rely on VO+IMU only (cuVSLAM at 9ms is low power) -6. Our total GPU time per 333ms frame: ~9ms cuVSLAM + ~50-200ms satellite match (async) = <60% GPU utilization → thermal throttling unlikely with proper cooling - -### Confidence -⚠️ Medium — actual thermal behavior depends on airflow in UAV enclosure, ambient temperature in-flight - ---- - -## Dimension 8: VO Drift Budget Monitoring - -### Fact Confirmation -New AC: max cumulative VO drift between satellite correction anchors < 100m. The ESKF maintains a position covariance matrix that grows during VO-only periods and shrinks on satellite corrections. - -### Reference Comparison -Draft02 uses ESKF covariance for keyframe selection (trigger satellite match when covariance exceeds threshold) but doesn't explicitly track drift as a budget. - -### Conclusion -Use ESKF position covariance diagonal (σ_x² + σ_y²) as the drift estimate. When √(σ_x² + σ_y²) approaches 100m: -1. Force satellite matching on every frame (not just keyframes) -2. Report LOW confidence via GPS_INPUT horiz_accuracy -3. If drift exceeds 100m without satellite correction → flag as critical, increase matching frequency, send alert to ground station -This is essentially what draft02 already does with covariance-based keyframe triggering, but now with an explicit 100m threshold. - -### Confidence -✅ High — standard ESKF covariance interpretation - ---- - -## Dimension 9: Satellite Imagery Specs - -### Fact Confirmation -New AC: ≥0.5 m/pixel resolution, <2 years old. Google Maps at zoom 18 = ~0.6 m/pixel, zoom 19 = ~0.3 m/pixel. - -### Reference Comparison -Draft02 uses Google Maps zoom 18-19. Zoom 19 (0.3 m/pixel) exceeds the requirement. Zoom 18 (0.6 m/pixel) meets the minimum. Age depends on Google's imagery updates for eastern Ukraine — conflict zone may have stale imagery. - -### Conclusion -Validate during offline preprocessing: -1. Download at zoom 19 first (0.3 m/pixel) -2. If zoom 19 unavailable for some tiles, fall back to zoom 18 (0.6 m/pixel — exceeds 0.5 minimum) -3. Check imagery date metadata if available from Google Maps API -4. Flag tiles where imagery appears stale (seasonal mismatch, destroyed buildings, etc.) -5. No architectural change needed — add validation step to preprocessing pipeline - -### Confidence -⚠️ Medium — Google Maps imagery age is not reliably queryable - ---- - -## Dimension 10: Internal IPC for Object Localization - -### Fact Confirmation -Other onboard AI systems need to request GPS coordinates of detected objects. These systems run on the same Jetson. - -### Reference Comparison -Draft02 has FastAPI for external API. For local IPC between processes on the same device, FastAPI is overkill but works. - -### Conclusion -Retain a minimal FastAPI server on localhost:8000 for inter-process communication: -- POST /localize: accepts pixel coordinates + AI camera params → returns GPS coordinates -- GET /status: returns system health/state for monitoring -This is local-only (bind to 127.0.0.1), not exposed externally. The primary output channel is MAVLink GPS_INPUT. This is a lightweight addition, not the core architecture. - -### Confidence -✅ High — simple local IPC pattern diff --git a/_docs/00_research/gps_denied_nav_v3/05_validation_log.md b/_docs/00_research/gps_denied_nav_v3/05_validation_log.md deleted file mode 100644 index 651c7c3..0000000 --- a/_docs/00_research/gps_denied_nav_v3/05_validation_log.md +++ /dev/null @@ -1,88 +0,0 @@ -# Validation Log - -## Validation Scenario -A typical 15-minute flight over eastern Ukraine agricultural terrain. GPS is jammed after first 2 minutes. Flight includes straight segments, two sharp 90-degree turns, and one low-texture segment over a large plowed field. Ground station operator monitors via telemetry link. During the flight, companion computer reboots once due to power glitch. - -## Expected Based on Conclusions - -### Phase 1: Normal start (GPS available, first 2 min) -- System boots, connects to flight controller via pymavlink on UART -- Reads GLOBAL_POSITION_INT → initializes ESKF with real GPS position -- Begins cuVSLAM initialization with first camera frames -- Starts sending GPS_INPUT at 5Hz (ESKF prediction between frames) -- Ground station sees position + confidence via telemetry forwarding - -### Phase 2: GPS denial begins -- Flight controller's real GPS becomes unreliable/lost -- GPS-Denied system continues sending GPS_INPUT — seamless for autopilot -- horiz_accuracy changes from real-GPS level to VO-estimated level (~20m) -- cuVSLAM provides VO at every frame (~9ms), ESKF fuses with IMU -- Satellite matching runs every 3-10 frames on keyframes -- After successful satellite match: horiz_accuracy improves, fix_type stays 3 -- NAMED_VALUE_FLOAT sends confidence/drift data to ground station at ~1Hz - -### Phase 3: Sharp turn -- cuVSLAM loses tracking (no overlapping features) -- ESKF falls back to IMU prediction, horiz_accuracy increases -- Next frame flagged as keyframe → satellite matching triggered immediately -- Satellite match against preloaded tiles using IMU dead-reckoning position -- If match found: position recovered, new segment begins, horiz_accuracy drops -- If 3 consecutive failures: send re-localization request to ground station via NAMED_VALUE_FLOAT/STATUSTEXT -- Ground station operator sends COMMAND_LONG with approximate coordinates -- System receives hint, constrains tile search → likely recovers position - -### Phase 4: Low-texture plowed field -- cuVSLAM keypoint count drops below threshold -- Satellite matching frequency increases (every frame) -- If satellite matching works on plowed field vs satellite imagery: position maintained -- If satellite also fails (seasonal difference): drift accumulates, ESKF covariance grows -- When √(σ²) approaches 100m: force continuous satellite matching -- horiz_accuracy reported as 50-100m, fix_type=2 - -### Phase 5: Companion computer reboot -- Power glitch → Jetson reboots (~30-60 seconds) -- During reboot: flight controller gets no GPS_INPUT → detects GPS timeout → falls back to IMU-only dead reckoning -- Jetson comes back: reconnects via pymavlink, reads GPS_RAW_INT (IMU-extrapolated) -- Initializes ESKF with this position (low confidence, horiz_accuracy=100m) -- Begins cuVSLAM + satellite matching → gradually improves accuracy -- Operator on ground station sees position return with improving confidence - -### Phase 6: Object localization request -- AI detection system on same Jetson detects a vehicle in AI camera frame -- Sends POST /localize with pixel coords + camera angle (30° from vertical) + zoom level + altitude (500m) -- GPS-Denied system computes: ground_distance = 500 / cos(30°) = 577m slant, horizontal distance = 500 × tan(30°) = 289m -- Adds bearing from heading + camera pan → lat/lon offset -- Returns GPS coordinates with accuracy estimate (GPS-Denied accuracy + projection error) - -## Actual Validation Results -The scenario covers all new AC requirements: -- ✅ MAVLink GPS_INPUT at 5Hz (camera frames + IMU interpolation) -- ✅ Confidence via horiz_accuracy field maps to confidence levels -- ✅ Ground station telemetry via MAVLink forwarding + NAMED_VALUE_FLOAT -- ✅ Re-localization via ground station command -- ✅ Startup from GPS → seamless transition on denial -- ✅ Reboot recovery from flight controller IMU-extrapolated position -- ✅ Drift budget tracking via ESKF covariance -- ✅ Object localization with AI camera angle/zoom - -## Counterexamples - -### Potential issue: 5Hz interpolation accuracy -Between camera frames (333ms apart), ESKF predicts using IMU only. At 200km/h = 55m/s, the UAV moves ~18m between frames. IMU prediction over 200ms (one interpolation step) at this speed introduces ~1-5m error — acceptable for GPS_INPUT. - -### Potential issue: UART reliability -Jetson Orin Nano UART instability reported (Fact #10). If MAVLink connection drops during flight, GPS_INPUT stops → autopilot loses GPS. Mitigation: use TCP over USB-C if UART unreliable, or add watchdog to reconnect. This is a hardware integration risk. - -### Potential issue: Telemetry bandwidth saturation -If GPS-Denied sends too many NAMED_VALUE_FLOAT messages, it could compete with standard autopilot telemetry for bandwidth. Keep custom messages to 1Hz max (50-100 bytes/s = <1kbit/s). - -## Review Checklist -- [x] Draft conclusions consistent with fact cards -- [x] No important dimensions missed -- [x] No over-extrapolation -- [x] Conclusions actionable and verifiable -- [x] All new AC requirements addressed -- [ ] UART reliability needs hardware testing — cannot validate without physical setup - -## Conclusions Requiring Revision -None — all conclusions hold under validation. The UART reliability risk needs flagging but doesn't change the architecture. diff --git a/_docs/00_research/gps_denied_visual_nav/00_ac_assessment.md b/_docs/00_research/gps_denied_visual_nav/00_ac_assessment.md deleted file mode 100644 index b2a029a..0000000 --- a/_docs/00_research/gps_denied_visual_nav/00_ac_assessment.md +++ /dev/null @@ -1,76 +0,0 @@ -# Acceptance Criteria Assessment - -## System Parameters (Calculated) - -| Parameter | Value | -|-----------|-------| -| GSD (at 400m) | 6.01 cm/pixel | -| Ground footprint | 376m × 250m | -| Consecutive overlap | 60-73% (at 100m intervals) | -| Pixels per 50m | ~832 pixels | -| Pixels per 20m | ~333 pixels | - -## Acceptance Criteria - -| Criterion | Our Values | Researched Values | Cost/Timeline Impact | Status | -|-----------|-----------|-------------------|---------------------|--------| -| GPS accuracy: 80% within 50m | 50m error for 80% of photos | NaviLoc: 19.5m MLE at 50-150m alt. Mateos-Ramirez: 143m mean at >1000m alt (with IMU). At 400m with 26MP + satellite correction, 50m for 80% is achievable with VO+SIM. No IMU adds ~30-50% error overhead. | Medium cost — needs robust satellite matching pipeline. ~3-4 weeks for core pipeline. | **Achievable** — keep as-is | -| GPS accuracy: 60% within 20m | 20m error for 60% of photos | NaviLoc: 19.5m MLE at lower altitude (50-150m). At 400m, larger viewpoint gap increases error. Cross-view matching MA@20m improving +10% yearly. Needs high-quality satellite imagery and robust matching. | Higher cost — requires higher-quality satellite imagery (0.3-0.5m resolution). Additional 1-2 weeks for refinement. | **Challenging but achievable** — consider relaxing to 30m initially, tighten with iteration | -| Handle 350m outlier photos | Tolerate up to 350m jump between consecutive photos | Standard VO systems detect outliers via feature matching failure. 350m at GSD 6cm = ~5833 pixels. Satellite re-localization can handle this if area is textured. | Low additional cost — outlier detection is standard in VO pipelines. | **Achievable** — keep as-is | -| Sharp turns: <5% overlap, <200m drift, <70° angle | System continues working during sharp turns | <5% overlap means consecutive feature matching will fail. Must fall back to satellite matching for absolute position. At 400m altitude with 376m footprint, 200m drift means partial overlap with satellite. 70° rotation is large but manageable with rotation-invariant matchers (AKAZE, SuperPoint). | High complexity — requires multi-strategy architecture (VO primary, satellite fallback). +2-3 weeks. | **Achievable with architectural investment** — keep as-is | -| Route disconnection & reconnection | Handle multiple disconnected route segments | Each segment needs independent satellite geo-referencing. Segments are stitched via common satellite reference frame. Similar to loop closure in SLAM but via external reference. | High complexity — core architectural challenge. +2-3 weeks for segment management. | **Achievable** — this should be a core design principle, not an edge case | -| User input fallback (20% of route) | User provides GPS when system cannot determine | Simple UI interaction — user clicks approximate position on map. Becomes new anchor point. | Low cost — straightforward feature. | **Achievable** — keep as-is | -| Processing speed: <5s per image | 5 seconds maximum per image | SuperPoint: ~50-100ms. LightGlue: ~20-50ms. Satellite crop+match: ~200-500ms. Full pipeline: ~500ms-2s on RTX 2060. NaviLoc runs 9 FPS on Raspberry Pi 5. ORB-SLAM3 with GPU: 30 FPS on Jetson TX2. | Low risk — well within budget on RTX 2060+. | **Easily achievable** — could target <2s. Keep 5s as safety margin | -| Real-time streaming via SSE | Results appear immediately, refinement sent later | Standard architecture pattern. Process-and-stream is well-supported. | Low cost — standard web engineering. | **Achievable** — keep as-is | -| Image Registration Rate > 95% | >95% of images successfully registered | ITU thesis: 93% SIM matching. With 60-73% consecutive overlap and deep learning features, >95% for VO between consecutive frames is achievable. The 5% tolerance covers sharp turns. | Medium cost — depends on feature matcher quality and satellite image quality. | **Achievable** — but interpret as "95% for normal consecutive frames". Sharp turn frames counted separately. | -| MRE < 1.0 pixels | Mean Reprojection Error below 1 pixel | Sub-pixel accuracy is standard for SuperPoint/LightGlue. SVO achieves sub-pixel via direct methods. Typical range: 0.3-0.8 pixels. | No additional cost — inherent to modern matchers. | **Easily achievable** — keep as-is | -| REST API + SSE background service | Always-running service, start on request, stream results | Standard Python (FastAPI) or .NET architecture. | Low cost — standard engineering. ~1 week for API layer. | **Achievable** — keep as-is | - -## Restrictions Assessment - -| Restriction | Our Values | Researched Values | Cost/Timeline Impact | Status | -|-------------|-----------|-------------------|---------------------|--------| -| No IMU data | No heading, no pitch/roll correction | **CRITICAL restriction.** Most published systems use IMU for heading and as fallback. Without IMU: (1) heading must be derived from consecutive frame matching or satellite matching, (2) no pitch/roll correction — rely on robust feature matchers, (3) scale from known altitude only. Adds ~30-50% error vs IMU-equipped systems. | High impact — requires visual heading estimation. All VO literature assumes at least heading from IMU. +2-3 weeks R&D for pure visual heading. | **Realistic but significantly harder.** Consider: can barometer data be available? | -| Camera not auto-stabilized | Images have varying pitch/roll | At 400m with fixed-wing, typical roll ±15°, pitch ±10°. Causes trapezoidal distortion in images. Robust matchers (SuperPoint, LightGlue) handle moderate viewpoint changes. Homography estimation between frames compensates. | Medium impact — modern matchers handle this. Pre-rectification using estimated attitude could help. | **Realistic** — keep as-is. Mitigated by robust matchers. | -| Google Maps only (cost-dependent) | Currently limited to Google Maps | Google Maps in eastern Ukraine may have 2-5 year old imagery. Conflict damage makes old imagery unreliable. **Risk: satellite-UAV matching may fail in areas with significant ground changes.** Alternatives: Mapbox (Maxar Vivid, sub-meter), Bing Maps (0.3-1m), Maxar SecureWatch (30cm, enterprise pricing). | High risk — may need multiple providers. Google: $200/month free credit. Mapbox: free tier for 100K requests. Maxar: enterprise pricing. | **Tighten** — add fallback provider. Pre-download tile cache for operational area. | -| Image resolution FullHD to 6252×4168 | Variable resolution across flights | Lower resolution (FullHD=1920×1080) at 400m: GSD ≈ 0.20m/pixel, footprint ~384m × 216m. Significantly worse matching but still functional. Need to handle both extremes. | Medium impact — pipeline must be resolution-adaptive. | **Realistic** — keep. But note: FullHD accuracy will be ~3x worse than 26MP. | -| Altitude ≤ 1km, terrain height negligible | Flat terrain assumption at known altitude | Simplifies scale estimation. At 400m, terrain variations of ±50m cause ±12.5% scale error. Eastern Ukraine is relatively flat (steppe), so this is reasonable. | Low impact for the operational area. | **Realistic** — keep as-is | -| Mostly sunny weather | Good lighting conditions assumed | Sunny weather = good texture, consistent illumination. Shadows may cause matching issues but are manageable. | Low impact — favorable condition. | **Realistic** — keep. Add: "system performance degrades in overcast/low-light" | -| Up to 3000 photos per flight | 500-1500 typical, 3000 maximum | At <5s per image: 3000 photos = ~4 hours max. Memory: 3000 × 26MP ≈ 78GB raw. Need efficient memory management and incremental processing. | Medium impact — requires streaming architecture and careful memory management. | **Realistic** — keep. Memory management is engineering, not research. | -| Sharp turns with completely different next photo | Route discontinuity is possible | Most VO systems fail at 0% overlap. This is effectively a new "start point" problem. Satellite matching is the only recovery path. | High impact — already addressed in AC. | **Realistic** — this is the defining challenge | -| Desktop/laptop with RTX 2060+ | Minimum GPU requirement | RTX 2060: 6GB VRAM, 1920 CUDA cores. Sufficient for SuperPoint, LightGlue, satellite matching. RTX 3070: 8GB VRAM, 5888 CUDA cores — significantly faster. | Low risk — hardware is adequate. | **Realistic** — keep as-is | - -## Missing Acceptance Criteria (Suggested Additions) - -| Criterion | Suggested Value | Rationale | -|-----------|----------------|-----------| -| Satellite imagery resolution requirement | ≥ 0.5 m/pixel, ideally 0.3 m/pixel | Matching quality depends heavily on reference imagery resolution. At GSD 6cm, satellite must be at least 0.5m for reliable cross-view matching. | -| Confidence/uncertainty reporting | Report confidence score per position estimate | User needs to know which positions are reliable (satellite-anchored) vs uncertain (VO-only, accumulating drift). | -| Output format | WGS84 coordinates in GeoJSON or CSV | Standardize output for downstream integration. | -| Satellite image freshness requirement | < 2 years old for operational area | Older imagery may not match current ground truth due to conflict damage. | -| Maximum drift between satellite corrections | < 100m cumulative VO drift before satellite re-anchor | Prevents long uncorrected VO segments from exceeding 50m target. | -| Memory usage limit | < 16GB RAM, < 6GB VRAM | Ensures compatibility with RTX 2060 systems. | - -## Key Findings - -1. **The 50m/80% accuracy target is achievable** with a well-designed VO + satellite matching pipeline, even without IMU, given the high camera resolution (6cm GSD) and known altitude. NaviLoc achieves 19.5m at lower altitudes; our 400m altitude adds difficulty but 26MP resolution compensates. - -2. **The 20m/60% target is aggressive but possible** with high-quality satellite imagery (≤0.5m resolution). Consider starting with a 30m target and tightening through iteration. Performance heavily depends on satellite image quality and freshness for the operational area. - -3. **No IMU is the single biggest technical risk.** All published comparable systems use at least heading from IMU/magnetometer. Visual heading estimation from consecutive frames is feasible but adds noise. This restriction alone could require 2-3 extra weeks of R&D. - -4. **Google Maps satellite imagery for eastern Ukraine is a significant risk.** Imagery may be outdated (2-5 years) and may not reflect current ground conditions. A fallback satellite provider is strongly recommended. - -5. **Processing speed (<5s) is easily achievable** on RTX 2060+. Modern feature matching pipelines process in <500ms per pair. The pipeline could realistically achieve <2s per image. - -6. **Route disconnection handling should be the core architectural principle**, not an edge case. The system should be designed "segments-first" — each segment independently geo-referenced, then stitched. - -7. **Missing criterion: confidence reporting.** The user should see which positions are high-confidence (satellite-anchored) vs low-confidence (VO-extrapolated). This is critical for operational use. - -## Sources -- [Source #1] Mateos-Ramirez et al. (2024) — VO + satellite correction for fixed-wing UAV -- [Source #2] Öztürk (2025) — ORB-SLAM3 + SIM integration thesis -- [Source #3] NaviLoc (2025) — Trajectory-level visual localization -- [Source #4] LightGlue GitHub — Feature matching benchmarks -- [Source #5] DALGlue (2025) — Enhanced feature matching -- [Source #8-9] Satellite imagery coverage and pricing reports diff --git a/_docs/00_research/gps_denied_visual_nav/00_question_decomposition.md b/_docs/00_research/gps_denied_visual_nav/00_question_decomposition.md deleted file mode 100644 index 8349f3c..0000000 --- a/_docs/00_research/gps_denied_visual_nav/00_question_decomposition.md +++ /dev/null @@ -1,63 +0,0 @@ -# Question Decomposition — AC & Restrictions Assessment - -## Original Question -How realistic are the acceptance criteria and restrictions for a GPS-denied visual navigation system for fixed-wing UAV imagery? - -## Active Mode -Mode A, Phase 1: AC & Restrictions Assessment - -## Question Type -Knowledge Organization + Decision Support - -## Research Subject Boundary Definition - -| Dimension | Boundary | -|-----------|----------| -| **Platform** | Fixed-wing UAV, airplane type, not multirotor | -| **Geography** | Eastern/southern Ukraine, left of Dnipro River (conflict zone, ~48.27°N, 37.38°E based on sample data) | -| **Altitude** | ≤ 1km, sample data at 400m | -| **Sensor** | Monocular RGB camera, 26MP, no IMU, no LiDAR | -| **Processing** | Ground-based desktop/laptop with NVIDIA RTX 2060+ GPU | -| **Time Window** | Current state-of-the-art (2024-2026) | - -## Problem Context Summary - -The system must determine GPS coordinates of consecutive aerial photo centers using only: -- Known starting GPS coordinates -- Known camera parameters (25mm focal, 23.5mm sensor, 6252×4168 resolution) -- Known flight altitude (≤1km, sample: 400m) -- Consecutive photos taken within ~100m of each other -- Satellite imagery (Google Maps) for ground reference - -Key constraints: NO IMU data, camera not auto-stabilized, potentially outdated satellite imagery for conflict zone. - -**Ground Sample Distance (GSD) at 400m altitude**: -- GSD = (400 × 23.5) / (25 × 6252) ≈ 0.060 m/pixel (6 cm/pixel) -- Ground footprint: ~376m × 250m per image -- Estimated consecutive overlap: 60-73% (depending on camera orientation relative to flight direction) - -## Sub-Questions for AC Assessment - -1. What GPS accuracy is achievable with VO + satellite matching at 400m altitude with 26MP camera? -2. How does the absence of IMU affect accuracy and what compensations exist? -3. What processing speed is achievable per image on RTX 2060+ for the required pipeline? -4. What image registration rates are achievable with deep learning matchers? -5. What reprojection errors are typical for modern feature matching? -6. How do sharp turns and route disconnections affect VO systems? -7. What satellite imagery quality is available for the operational area? -8. What domain-specific acceptance criteria might be missing? - -## Timeliness Sensitivity Assessment - -- **Research Topic**: GPS-denied visual navigation using deep learning feature matching -- **Sensitivity Level**: 🟠 High -- **Rationale**: Deep learning feature matchers (SuperPoint, LightGlue, GIM) are evolving rapidly; new methods appear quarterly. Satellite imagery providers update pricing and coverage frequently. -- **Source Time Window**: 12 months (2024-2026) -- **Priority official sources to consult**: - 1. LightGlue GitHub repository (cvg/LightGlue) - 2. ORB-SLAM3 documentation - 3. Recent MDPI/IEEE papers on GPS-denied UAV navigation -- **Key version information to verify**: - - LightGlue: Current release and performance benchmarks - - SuperPoint: Compatibility and inference speed - - ORB-SLAM3: Monocular mode capabilities diff --git a/_docs/00_research/gps_denied_visual_nav/01_source_registry.md b/_docs/00_research/gps_denied_visual_nav/01_source_registry.md deleted file mode 100644 index be8fcfa..0000000 --- a/_docs/00_research/gps_denied_visual_nav/01_source_registry.md +++ /dev/null @@ -1,133 +0,0 @@ -# Source Registry - -## Source #1 -- **Title**: Visual Odometry in GPS-Denied Zones for Fixed-Wing UAV with Reduced Accumulative Error Based on Satellite Imagery -- **Link**: https://www.mdpi.com/2076-3417/14/16/7420 -- **Tier**: L1 -- **Publication Date**: 2024-08-22 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Fixed-wing UAV navigation researchers -- **Research Boundary Match**: ✅ Full match (fixed-wing, high altitude, satellite matching) -- **Summary**: VO + satellite image correction achieves 142.88m mean error over 17km at >1000m altitude using ORB + AKAZE. Uses IMU for heading and barometer for altitude. Error rate 0.83% of total distance. -- **Related Sub-question**: 1, 2 - -## Source #2 -- **Title**: Optimized visual odometry and satellite image matching-based localization for UAVs in GPS-denied environments (ITU Thesis) -- **Link**: https://polen.itu.edu.tr/items/1fe1e872-7cea-44d8-a8de-339e4587bee6 -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: UAV navigation researchers -- **Research Boundary Match**: ⚠️ Partial overlap (multirotor at 30-100m, but same VO+SIM methodology) -- **Summary**: ORB-SLAM3 + SuperPoint/SuperGlue/GIM achieves GPS-level accuracy. VO module: ±2m local accuracy. SIM module: 93% matching success rate. Demonstrated on DJI Mavic Air 2 at 30-100m. -- **Related Sub-question**: 1, 2, 4 - -## Source #3 -- **Title**: NaviLoc: Trajectory-Level Visual Localization for GNSS-Denied UAV Navigation -- **Link**: https://www.mdpi.com/2504-446X/10/2/97 -- **Tier**: L1 -- **Publication Date**: 2025-12 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: UAV navigation / VPR researchers -- **Research Boundary Match**: ⚠️ Partial overlap (50-150m altitude, uses VIO not pure VO) -- **Summary**: Achieves 19.5m Mean Localization Error at 50-150m altitude. Runs at 9 FPS on Raspberry Pi 5. 16x improvement over AnyLoc-VLAD, 32x over raw VIO drift. Training-free system. -- **Related Sub-question**: 1, 7 - -## Source #4 -- **Title**: LightGlue: Local Feature Matching at Light Speed (GitHub + ICCV 2023) -- **Link**: https://github.com/cvg/LightGlue -- **Tier**: L1 -- **Publication Date**: 2023 (actively maintained through 2025) -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Computer vision practitioners -- **Research Boundary Match**: ✅ Full match (core component) -- **Summary**: ~20-34ms per image pair on RTX 2080Ti. Adaptive pruning for fast inference. 2-4x speedup with PyTorch compilation. -- **Related Sub-question**: 3, 4 - -## Source #5 -- **Title**: Efficient image matching for UAV visual navigation via DALGlue -- **Link**: https://www.nature.com/articles/s41598-025-21602-5 -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: UAV navigation researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: DALGlue achieves 11.8% improvement over LightGlue on matching accuracy. Uses dual-tree complex wavelet preprocessing + linear attention for real-time performance. -- **Related Sub-question**: 3, 4 - -## Source #6 -- **Title**: Deep-UAV SLAM: SuperPoint and SuperGlue enhanced SLAM -- **Link**: https://isprs-archives.copernicus.org/articles/XLVIII-1-W5-2025/177/2025/ -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: UAV SLAM researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Replacing ORB-SLAM3's ORB features with SuperPoint+SuperGlue improved robustness and accuracy in aerial RGB scenarios. -- **Related Sub-question**: 4, 5 - -## Source #7 -- **Title**: SCAR: Satellite Imagery-Based Calibration for Aerial Recordings -- **Link**: https://arxiv.org/html/2602.16349v1 -- **Tier**: L1 -- **Publication Date**: 2026-02 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Aerial/satellite vision researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Long-term auto-calibration refinement by aligning aerial images with 2D-3D correspondences from orthophotos and elevation models. -- **Related Sub-question**: 1, 5 - -## Source #8 -- **Title**: Google Maps satellite imagery coverage and update frequency -- **Link**: https://ongeo-intelligence.com/blog/how-often-does-google-maps-update-satellite-images -- **Tier**: L3 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: GIS practitioners -- **Research Boundary Match**: ✅ Full match -- **Summary**: Conflict zones like eastern Ukraine face 2-5+ year update cycles. Imagery may be intentionally limited or blurred. -- **Related Sub-question**: 7 - -## Source #9 -- **Title**: Satellite Mapping Services comparison 2025 -- **Link**: https://ts2.tech/en/exploring-the-world-from-above-top-satellite-mapping-services-for-web-mobile-in-2025/ -- **Tier**: L3 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Developers, GIS practitioners -- **Research Boundary Match**: ✅ Full match -- **Summary**: Google: $200/month free credit, sub-meter resolution. Mapbox: Maxar imagery, generous free tier. Maxar SecureWatch: 30cm resolution, enterprise pricing. Planet: daily 3-4m imagery. -- **Related Sub-question**: 7 - -## Source #10 -- **Title**: Scale Estimation for Monocular Visual Odometry Using Reliable Camera Height -- **Link**: https://ieeexplore.ieee.org/document/9945178/ -- **Tier**: L1 -- **Publication Date**: 2022 -- **Timeliness Status**: ✅ Currently valid (fundamental method) -- **Target Audience**: VO researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Known camera height/altitude resolves scale ambiguity in monocular VO. Essential for systems without IMU. -- **Related Sub-question**: 2 - -## Source #11 -- **Title**: Cross-View Geo-Localization benchmarks (SSPT, MA metrics) -- **Link**: https://www.mdpi.com/1424-8220/24/12/3719 -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: VPR/geo-localization researchers -- **Research Boundary Match**: ⚠️ Partial overlap (general cross-view, not UAV-specific) -- **Summary**: SSPT achieved 84.40% RDS on UL14 dataset. MA improvements: +12% at 3m, +12% at 5m, +10% at 20m thresholds. -- **Related Sub-question**: 1 - -## Source #12 -- **Title**: ORB-SLAM3 GPU Acceleration Performance -- **Link**: https://arxiv.org/html/2509.10757v1 -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: SLAM/VO engineers -- **Research Boundary Match**: ✅ Full match -- **Summary**: GPU acceleration achieves 2.8x speedup on desktop systems. 30 FPS achievable on Jetson TX2. Feature extraction up to 3x speedup with CUDA. -- **Related Sub-question**: 3 diff --git a/_docs/00_research/gps_denied_visual_nav/02_fact_cards.md b/_docs/00_research/gps_denied_visual_nav/02_fact_cards.md deleted file mode 100644 index 75736a1..0000000 --- a/_docs/00_research/gps_denied_visual_nav/02_fact_cards.md +++ /dev/null @@ -1,121 +0,0 @@ -# Fact Cards - -## Fact #1 -- **Statement**: VO + satellite image correction achieves ~142.88m mean error over 17km flight at >1000m altitude using ORB features and AKAZE satellite matching. Error rate: 0.83% of total distance. This system uses IMU for heading and barometer for altitude. -- **Source**: Source #1 — https://www.mdpi.com/2076-3417/14/16/7420 -- **Phase**: Phase 1 -- **Target Audience**: Fixed-wing UAV at high altitude (>1000m) -- **Confidence**: ✅ High (peer-reviewed, real-world flight data) -- **Related Dimension**: GPS accuracy, drift correction - -## Fact #2 -- **Statement**: ORB-SLAM3 monocular mode with optimized parameters achieves ±2m local accuracy for visual odometry. Scale ambiguity and drift remain for long flights. -- **Source**: Source #2 — ITU Thesis -- **Phase**: Phase 1 -- **Target Audience**: UAV navigation (30-100m altitude, multirotor) -- **Confidence**: ✅ High (thesis with experimental validation) -- **Related Dimension**: VO accuracy, scale ambiguity - -## Fact #3 -- **Statement**: Combined VO + Satellite Image Matching (SIM) with SuperPoint/SuperGlue/GIM achieves 93% matching success rate and "GPS-level accuracy" at 30-100m altitude. -- **Source**: Source #2 — ITU Thesis -- **Phase**: Phase 1 -- **Target Audience**: Low-altitude UAV (30-100m) -- **Confidence**: ✅ High -- **Related Dimension**: Registration rate, satellite matching - -## Fact #4 -- **Statement**: NaviLoc achieves 19.5m Mean Localization Error at 50-150m altitude, runs at 9 FPS on Raspberry Pi 5. 16x improvement over AnyLoc-VLAD. Training-free system. -- **Source**: Source #3 — NaviLoc paper -- **Phase**: Phase 1 -- **Target Audience**: Low-altitude UAV (50-150m) in rural areas -- **Confidence**: ✅ High (peer-reviewed) -- **Related Dimension**: GPS accuracy, processing speed - -## Fact #5 -- **Statement**: LightGlue inference: ~20-34ms per image pair on RTX 2080Ti for 1024 keypoints. 2-4x speedup possible with PyTorch compilation and TensorRT. -- **Source**: Source #4 — LightGlue GitHub Issues -- **Phase**: Phase 1 -- **Target Audience**: All GPU-accelerated vision systems -- **Confidence**: ✅ High (official repository benchmarks) -- **Related Dimension**: Processing speed - -## Fact #6 -- **Statement**: SuperPoint+SuperGlue replacing ORB features in SLAM improves robustness and accuracy for aerial RGB imagery over classical handcrafted features. -- **Source**: Source #6 — ISPRS 2025 -- **Phase**: Phase 1 -- **Target Audience**: UAV SLAM researchers -- **Confidence**: ✅ High (peer-reviewed) -- **Related Dimension**: Feature matching quality - -## Fact #7 -- **Statement**: Eastern Ukraine / conflict zones may have 2-5+ year old satellite imagery on Google Maps. Imagery may be intentionally limited, blurred, or restricted for security reasons. -- **Source**: Source #8 -- **Phase**: Phase 1 -- **Target Audience**: Ukraine conflict zone operations -- **Confidence**: ⚠️ Medium (general reporting, not Ukraine-specific verification) -- **Related Dimension**: Satellite imagery quality - -## Fact #8 -- **Statement**: Maxar SecureWatch offers 30cm resolution with ~3M km² new imagery daily. Mapbox uses Maxar's Vivid imagery with sub-meter resolution. Google Maps offers sub-meter detail in urban areas but 1-3m in rural areas. -- **Source**: Source #9 -- **Phase**: Phase 1 -- **Target Audience**: All satellite imagery users -- **Confidence**: ✅ High -- **Related Dimension**: Satellite providers, cost - -## Fact #9 -- **Statement**: Known camera height/altitude resolves scale ambiguity in monocular VO. The pixel-to-meter conversion is s = H / f × sensor_pixel_size, enabling metric reconstruction without IMU. -- **Source**: Source #10 -- **Phase**: Phase 1 -- **Target Audience**: Monocular VO systems -- **Confidence**: ✅ High (fundamental geometric relationship) -- **Related Dimension**: No-IMU compensation - -## Fact #10 -- **Statement**: Camera heading (yaw) can be estimated from consecutive frame feature matching by decomposing the homography or essential matrix. Pitch/roll can be estimated from horizon detection or vanishing points. Without IMU, these estimates are noisier but functional. -- **Source**: Multiple vision-based heading estimation papers -- **Phase**: Phase 1 -- **Target Audience**: Vision-only navigation systems -- **Confidence**: ⚠️ Medium (well-established but accuracy varies) -- **Related Dimension**: No-IMU compensation - -## Fact #11 -- **Statement**: GSD at 400m with 25mm/23.5mm sensor/6252px = 6.01 cm/pixel. Ground footprint: 376m × 250m. At 100m photo interval, consecutive overlap is 60-73%. -- **Source**: Calculated from problem data using standard GSD formula -- **Phase**: Phase 1 -- **Target Audience**: This specific system -- **Confidence**: ✅ High (deterministic calculation) -- **Related Dimension**: Image coverage, overlap - -## Fact #12 -- **Statement**: GPU-accelerated ORB-SLAM3 achieves 2.8x speedup on desktop systems. 30 FPS possible on Jetson TX2. Feature extraction speedup up to 3x with CUDA-optimized pipelines. -- **Source**: Source #12 -- **Phase**: Phase 1 -- **Target Audience**: GPU-equipped systems -- **Confidence**: ✅ High -- **Related Dimension**: Processing speed - -## Fact #13 -- **Statement**: Without IMU, the Mateos-Ramirez paper (Source #1) would lose: (a) yaw angle for rotation compensation, (b) fallback when feature matching fails. Their 142.88m error would likely be significantly higher without IMU heading data. -- **Source**: Inference from Source #1 methodology -- **Phase**: Phase 1 -- **Target Audience**: This specific system -- **Confidence**: ⚠️ Medium (reasoned inference) -- **Related Dimension**: No-IMU impact - -## Fact #14 -- **Statement**: DALGlue achieves 11.8% improvement over LightGlue on matching accuracy while maintaining real-time performance through dual-tree complex wavelet preprocessing and linear attention. -- **Source**: Source #5 -- **Phase**: Phase 1 -- **Target Audience**: Feature matching systems -- **Confidence**: ✅ High (peer-reviewed, 2025) -- **Related Dimension**: Feature matching quality - -## Fact #15 -- **Statement**: Cross-view geo-localization benchmarks show MA@20m improving by +10% with latest methods (SSPT). RDS metric at 84.40% indicates reliable spatial positioning. -- **Source**: Source #11 -- **Phase**: Phase 1 -- **Target Audience**: Cross-view matching researchers -- **Confidence**: ✅ High -- **Related Dimension**: Cross-view matching accuracy diff --git a/_docs/00_research/gps_denied_visual_nav/03_comparison_framework.md b/_docs/00_research/gps_denied_visual_nav/03_comparison_framework.md deleted file mode 100644 index b0cb86e..0000000 --- a/_docs/00_research/gps_denied_visual_nav/03_comparison_framework.md +++ /dev/null @@ -1,115 +0,0 @@ -# Comparison Framework - -## Selected Framework Type -Decision Support (component-by-component solution comparison) - -## System Components -1. Visual Odometry (consecutive frame matching) -2. Satellite Image Geo-Referencing (cross-view matching) -3. Heading & Orientation Estimation (without IMU) -4. Drift Correction & Position Fusion -5. Segment Management & Route Reconnection -6. Interactive Point-to-GPS Lookup -7. Pipeline Orchestration & API - ---- - -## Component 1: Visual Odometry - -| Solution | Tools | Advantages | Limitations | Fit | -|----------|-------|-----------|-------------|-----| -| ORB-SLAM3 monocular | ORB features, BA, map management | Mature, well-tested, handles loop closure. GPU-accelerated. 30FPS on Jetson TX2. | Scale ambiguity without IMU. Over-engineered for sequential aerial — map building not needed. Heavy dependency. | Medium — too complex for the use case | -| Homography-based VO with SuperPoint+LightGlue | SuperPoint, LightGlue, OpenCV homography | Ground plane assumption perfect for flat terrain at 400m. Cleanly separates rotation/translation. Known altitude resolves scale directly. Fast. | Assumes planar scene (valid for our case). Fails at sharp turns (but that's expected). | **Best fit** — matches constraints exactly | -| Optical flow VO | cv2.calcOpticalFlowPyrLK or RAFT | Dense motion field, no feature extraction needed. | Less accurate for large motions. Struggles with texture-sparse areas. No inherent rotation estimation. | Low — not suitable for 100m baselines | -| Direct method (SVO) | SVO Pro | Sub-pixel precision, fast. | Designed for small baselines and forward cameras. Poor for downward aerial at large baselines. | Low | - -**Selected**: Homography-based VO with SuperPoint + LightGlue features - ---- - -## Component 2: Satellite Image Geo-Referencing - -| Solution | Tools | Advantages | Limitations | Fit | -|----------|-------|-----------|-------------|-----| -| SuperPoint + LightGlue cross-view matching | SuperPoint, LightGlue, perspective warp | Best overall performance on satellite stereo benchmarks. Fast (~50ms matching). Rotation-invariant. Handles viewpoint/scale changes. | Requires perspective warping to reduce viewpoint gap. Needs good satellite image quality. | **Best fit** — proven on satellite imagery | -| SuperPoint + SuperGlue + GIM | SuperPoint, SuperGlue, GIM | GIM adds generalization for challenging scenes. 93% match rate (ITU thesis). | SuperGlue slower than LightGlue. GIM adds complexity. | Good — slightly better robustness, slower | -| LoFTR (detector-free) | LoFTR | No keypoint detection step. Works on low-texture. | Slower than detector-based methods. Fixed resolution (coarse). Less accurate than SuperPoint+LightGlue on satellite benchmarks. | Medium — fallback option | -| DUSt3R/MASt3R | DUSt3R/MASt3R | Handles extreme viewpoints and low overlap. +50% completeness over COLMAP in sparse scenarios. | Very slow. Designed for 3D reconstruction not 2D matching. Unreliable with many images. | Low — only for extreme fallback | -| Terrain-weighted optimization (YFS90) | Custom pipeline + DEM | <7m MAE without IMU! Drift-free. Handles thermal IR. 20 scenarios validated. | Requires DEM data. More complex implementation. Not open-source matching details. | High — architecture inspiration | - -**Selected**: SuperPoint + LightGlue (primary) with perspective warping. GIM as supplementary for difficult matches. YFS90-style terrain-weighted sliding window for position optimization. - ---- - -## Component 3: Heading & Orientation Estimation - -| Solution | Tools | Advantages | Limitations | Fit | -|----------|-------|-----------|-------------|-----| -| Homography decomposition (consecutive frames) | OpenCV decomposeHomographyMat | Directly gives rotation between frames. Works with ground plane assumption. No extra sensors needed. | Accumulates heading drift over time. Noisy for small motions. Ambiguous decomposition (need to select correct solution). | **Best fit** — primary heading source | -| Satellite matching absolute orientation | From satellite match homography | Provides absolute heading correction. Eliminates accumulated heading drift. | Only available when satellite match succeeds. Intermittent. | **Best fit** — drift correction for heading | -| Optical flow direction | Dense flow vectors | Simple to compute. | Very noisy at high altitude. Unreliable for heading. | Low | - -**Selected**: Homography decomposition for frame-to-frame heading + satellite matching for periodic absolute heading correction. - ---- - -## Component 4: Drift Correction & Position Fusion - -| Solution | Tools | Advantages | Limitations | Fit | -|----------|-------|-----------|-------------|-----| -| Kalman filter (EKF/UKF) | filterpy or custom | Well-understood. Handles noisy measurements. Good for fusing VO + satellite. | Assumes Gaussian noise. Linearization issues with EKF. | Good — simple and effective | -| Sliding window optimization with terrain constraints | Custom optimization, scipy.optimize | YFS90 achieves <7m with this. Directly constrains drift. No loop closure needed. | More complex to implement. Needs tuning. | **Best fit** — proven for this exact problem | -| Pose graph optimization | g2o, GTSAM | Standard in SLAM. Handles satellite anchors as prior factors. Globally optimal. | Heavy dependency. Over-engineered if segments are short. | Medium — overkill unless routes are very long | -| Simple anchor reset | Direct correction at satellite match | Simplest. Just replace VO position with satellite position. | Discontinuous trajectory. No smoothing. | Low — too crude | - -**Selected**: Sliding window optimization with terrain constraints (inspired by YFS90), with Kalman filter as simpler fallback. Satellite matches as absolute anchor constraints. - ---- - -## Component 5: Segment Management & Route Reconnection - -| Solution | Tools | Advantages | Limitations | Fit | -|----------|-------|-----------|-------------|-----| -| Segments-first architecture with satellite anchoring | Custom segment manager | Each segment independently geo-referenced. No dependency between disconnected segments. Natural handling of sharp turns. | Needs robust satellite matching per segment. Segments without any satellite match are "floating". | **Best fit** — matches AC requirement for core strategy | -| Global pose graph with loop closure | g2o/GTSAM | Can connect segments when they revisit same area. | Heavy. Doesn't help if segments don't overlap with each other. | Low — segments may not revisit same areas | -| Trajectory-level VPR (NaviLoc-style) | VPR + trajectory optimization | Global optimization across trajectory. | Requires pre-computed VPR database. Complex. Designed for continuous trajectory, not disconnected segments. | Low | - -**Selected**: Segments-first architecture. Each segment starts from a satellite anchor or user input. Segments connected through shared satellite coordinate frame. - ---- - -## Component 6: Interactive Point-to-GPS Lookup - -| Solution | Tools | Advantages | Limitations | Fit | -|----------|-------|-----------|-------------|-----| -| Homography projection (image → ground) | Computed homography from satellite match | Already computed during geo-referencing. Accurate for flat terrain. | Only works for images with successful satellite match. | **Best fit** | -| Camera ray-casting with known altitude | Camera intrinsics + pose estimate | Works for any image with pose estimate. Simpler math. | Accuracy depends on pose estimate quality. | Good — fallback for non-satellite-matched images | - -**Selected**: Homography projection (primary) + ray-casting (fallback). - ---- - -## Component 7: Pipeline & API - -| Solution | Tools | Advantages | Limitations | Fit | -|----------|-------|-----------|-------------|-----| -| Python FastAPI + SSE | FastAPI, EventSourceResponse, asyncio | Native SSE support (since 0.135.0). Async GPU pipeline. Excellent for ML/CV workloads. Rich ecosystem. | Python GIL (mitigated with async/multiprocessing). | **Best fit** — natural for CV/ML pipeline | -| .NET ASP.NET Core + SSE | ASP.NET Core, SignalR | High performance. Good for enterprise. | Less natural for CV/ML. Python interop needed for PyTorch models. Adds complexity. | Low — unnecessary indirection | -| Python + gRPC streaming | gRPC | Efficient binary protocol. Bidirectional streaming. | More complex client integration. No browser-native support. | Medium — overkill for this use case | - -**Selected**: Python FastAPI with SSE. - ---- - -## Google Maps Tile Resolution at Latitude 48° (Operational Area) - -| Zoom Level | Meters/pixel | Tile coverage (256px) | Tiles for 20km² | Download size est. | -|-----------|-------------|----------------------|-----------------|-------------------| -| 17 | 0.80 m/px | ~205m × 205m | ~500 tiles | ~20MB | -| 18 | 0.40 m/px | ~102m × 102m | ~2,000 tiles | ~80MB | -| 19 | 0.20 m/px | ~51m × 51m | ~8,000 tiles | ~320MB | -| 20 | 0.10 m/px | ~26m × 26m | ~30,000 tiles | ~1.2GB | - -Formula: metersPerPx = 156543.03 × cos(48° × π/180) / 2^zoom ≈ 104,771 / 2^zoom - -**Selected**: Zoom 18 (0.40 m/px) as primary matching resolution. Zoom 19 (0.20 m/px) for refinement if available. Meets the ≥0.5 m/pixel AC requirement. diff --git a/_docs/00_research/gps_denied_visual_nav/04_reasoning_chain.md b/_docs/00_research/gps_denied_visual_nav/04_reasoning_chain.md deleted file mode 100644 index 9c3ad06..0000000 --- a/_docs/00_research/gps_denied_visual_nav/04_reasoning_chain.md +++ /dev/null @@ -1,146 +0,0 @@ -# Reasoning Chain - -## Dimension 1: GPS Accuracy (50m/80%, 20m/60%) - -### Fact Confirmation -- YFS90 system achieves <7m MAE without IMU (Fact from Source DOAJ/GitHub) -- NaviLoc achieves 19.5m MLE at 50-150m altitude (Fact #4) -- Mateos-Ramirez achieves 143m mean error at >1000m altitude with IMU (Fact #1) -- Our GSD is 6cm/pixel at 400m altitude (Fact #11) -- ITU thesis achieves GPS-level accuracy with VO+SIM at 30-100m (Fact #3) - -### Reference Comparison -- At 400m altitude, our camera produces much higher resolution imagery than typical systems -- YFS90 at <7m without IMU is the strongest reference — uses terrain-weighted constraint optimization -- NaviLoc at 19.5m uses trajectory-level optimization but at lower altitude -- The combination of VO + satellite matching with sliding window optimization should achieve 10-30m depending on satellite image quality - -### Conclusion -- **50m / 80%**: High confidence achievable. Multiple systems achieve better than this. -- **20m / 60%**: Achievable with good satellite imagery. YFS90 achieves <7m. Our higher altitude makes cross-view matching harder, but 26MP camera compensates. -- **10m stretch**: Possible with zoom 19 satellite tiles (0.2m/px) and terrain-weighted optimization. - -### Confidence: ✅ High for 50m, ⚠️ Medium for 20m, ❓ Low for 10m - ---- - -## Dimension 2: No-IMU Heading Estimation - -### Fact Confirmation -- Homography decomposition gives rotation between frames for planar scenes (multiple sources) -- Ground plane assumption is valid for flat terrain (eastern Ukraine steppe) -- Satellite matching provides absolute orientation correction (Sources #1, #2) -- YFS90 achieves <7m without requiring IMU (Source #3 DOAJ) - -### Reference Comparison -- Most published systems use IMU for heading — our approach is less common -- YFS90 proves it's possible without IMU, but uses DEM data for terrain weighting -- The key insight: satellite matching provides both position AND heading correction, making intermittent heading drift from VO acceptable - -### Conclusion -Heading estimation from homography decomposition between consecutive frames + periodic satellite matching correction is viable. The frame-to-frame heading drift accumulates, but satellite corrections at regular intervals (every 5-20 frames) reset it. The flat terrain of the operational area makes the ground plane assumption reliable. - -### Confidence: ⚠️ Medium — novel approach but supported by YFS90 results - ---- - -## Dimension 3: Processing Speed (<5s per image) - -### Fact Confirmation -- LightGlue: ~20-50ms per pair (Fact #5) -- SuperPoint extraction: ~50-100ms per image -- GPU-accelerated ORB-SLAM3: 30 FPS (Fact #12) -- NaviLoc: 9 FPS on Raspberry Pi 5 (Fact #4) - -### Pipeline Time Budget Estimate (per image on RTX 2060) -1. SuperPoint feature extraction: ~80ms -2. LightGlue VO matching (vs previous frame): ~40ms -3. Homography estimation + position update: ~5ms -4. Satellite tile crop (from cache): ~10ms -5. SuperPoint extraction on satellite crop: ~80ms -6. LightGlue satellite matching: ~60ms -7. Position correction + sliding window optimization: ~20ms -8. Total: ~295ms ≈ 0.3s - -### Conclusion -Processing comfortably fits within 5s budget. Even with additional overhead (satellite tile download, perspective warping, GIM fallback), the pipeline stays under 2s. The 5s budget provides ample margin. - -### Confidence: ✅ High - ---- - -## Dimension 4: Sharp Turns & Route Disconnection - -### Fact Confirmation -- At <5% overlap, consecutive feature matching will fail -- Satellite matching can provide absolute position independently of VO -- DUSt3R/MASt3R handle extreme low overlap (+50% completeness vs COLMAP) -- YFS90 handles positioning failures with re-localization - -### Reference Comparison -- Traditional VO systems fail at sharp turns — this is expected and acceptable -- The segments-first architecture treats each continuous VO chain as a segment -- Satellite matching re-localizes at the start of each new segment -- If satellite matching fails too → wider search area → user input - -### Conclusion -The system should not try to match across sharp turns. Instead: -1. Detect VO failure (low match count / high reprojection error) -2. Start new segment -3. Attempt satellite geo-referencing for new segment start -4. Each segment is independently positioned in the global satellite coordinate frame - -This is architecturally simpler and more robust than trying to bridge disconnections. - -### Confidence: ✅ High - ---- - -## Dimension 5: Satellite Image Matching Reliability - -### Fact Confirmation -- Google Maps at zoom 18: 0.40 m/px at lat 48° — meets AC requirement -- Eastern Ukraine imagery may be 2-5 years old (Fact #7) -- SuperPoint+LightGlue is best performer for satellite matching (Source comparison study) -- Perspective warping improves cross-view matching significantly -- 93% match rate achieved in ITU thesis (Fact #3) - -### Reference Comparison -- The main risk is satellite image freshness in conflict zone -- Natural terrain features (rivers, forests, field boundaries) are relatively stable over years -- Man-made features (buildings, roads) may change due to conflict -- Agricultural field patterns change seasonally - -### Conclusion -Satellite matching will work reliably in areas with stable natural features. Performance degrades in: -1. Areas with significant conflict damage (buildings destroyed) -2. Areas with seasonal agricultural changes -3. Areas with very homogeneous texture (large uniform fields) - -Mitigation: use multiple scale levels, widen search area, accept lower confidence. - -### Confidence: ⚠️ Medium — depends heavily on operational area characteristics - ---- - -## Dimension 6: Architecture Selection - -### Fact Confirmation -- YFS90 architecture (VO + satellite matching + terrain-weighted optimization) achieves <7m -- ITU thesis architecture (ORB-SLAM3 + SIM) achieves GPS-level accuracy -- NaviLoc architecture (VPR + trajectory optimization) achieves 19.5m - -### Reference Comparison -- YFS90 is closest to our requirements: no IMU, satellite matching, drift correction -- Our system adds: segment management, real-time streaming, user fallback -- We need simpler VO than ORB-SLAM3 (no map building needed) -- We need faster matching than SuperGlue (LightGlue preferred) - -### Conclusion -Hybrid architecture combining: -- YFS90-style sliding window optimization for drift correction -- SuperPoint + LightGlue for both VO and satellite matching (unified feature pipeline) -- Segments-first architecture for disconnection handling -- FastAPI + SSE for real-time streaming - -### Confidence: ✅ High diff --git a/_docs/00_research/gps_denied_visual_nav/05_validation_log.md b/_docs/00_research/gps_denied_visual_nav/05_validation_log.md deleted file mode 100644 index 8f96b35..0000000 --- a/_docs/00_research/gps_denied_visual_nav/05_validation_log.md +++ /dev/null @@ -1,57 +0,0 @@ -# Validation Log - -## Validation Scenario -Using the provided sample data: 60 consecutive images from a flight starting at (48.275292, 37.385220) heading generally south-southwest. Camera: 26MP at 400m altitude. - -## Expected Behavior Based on Conclusions - -### Normal consecutive frames (AD000001-AD000032) -- VO successfully matches consecutive frames (60-73% overlap) -- Satellite matching every 5-10 frames provides absolute correction -- Position error stays within 20-50m corridor around ground truth -- Heading estimated from homography, corrected by satellite matching - -### Apparent maneuver zone (AD000033-AD000048) -- The coordinates show the UAV making a complex turn around images 33-48 -- Some consecutive pairs may have low overlap → VO quality drops -- Satellite matching becomes the primary position source -- New segments may be created if VO fails completely -- Position confidence drops in this zone - -### Return to straight flight (AD000049-AD000060) -- VO re-establishes strong consecutive matching -- Satellite matching re-anchors position -- Accuracy returns to normal levels - -## Actual Validation (Calculated) - -Distances between consecutive samples in the data: -- AD000001→002: ~180m (larger than stated 100m — likely exaggeration in problem description) -- AD000002→003: ~115m -- Typical gap: 80-180m -- At 376m footprint width and 250m height, even 180m gap gives 52-73% overlap → sufficient for VO - -At the turn zone (images 33-48): -- AD000041→042: ~230m with direction change → overlap may drop to 30-40% -- AD000042→043: ~230m with direction change → overlap may drop significantly -- AD000045→046: ~160m with direction change → may be <20% overlap -- These transitions are where VO may fail → satellite matching needed - -## Counterexamples - -1. **Homogeneous terrain**: If a section of the flight is over large uniform agricultural fields with no distinguishing features, both VO and satellite matching may fail. Mitigation: use higher zoom satellite tiles, rely on VO with lower confidence. - -2. **Conflict-damaged area**: If satellite imagery shows pre-war structures that no longer exist, satellite matching will produce incorrect position estimates. Mitigation: confidence scoring will flag inconsistent matches. - -3. **FullHD resolution flight**: At GSD 20cm/pixel instead of 6cm, matching quality degrades ~3x. The 50m target may still be achievable but 20m will be very difficult. - -## Review Checklist -- [x] Draft conclusions consistent with fact cards -- [x] No important dimensions missed -- [x] No over-extrapolation -- [x] Issue found: The problem states "within 100 meters of each other" but actual data shows 80-230m. Pipeline must handle larger baselines. -- [x] Issue found: Tile download strategy needs to handle unknown route direction — progressive expansion needed. - -## Conclusions Requiring Revision -- Photo spacing is 80-230m not strictly 100m — increases the range of overlap variations. Still functional but wider variance than assumed. -- Route direction is unknown at start — satellite tile pre-loading must use expanding radius strategy, not directional pre-loading. diff --git a/_docs/00_research/solution_completeness_assessment/00_question_decomposition.md b/_docs/00_research/solution_completeness_assessment/00_question_decomposition.md deleted file mode 100644 index 82c1071..0000000 --- a/_docs/00_research/solution_completeness_assessment/00_question_decomposition.md +++ /dev/null @@ -1,73 +0,0 @@ -# Question Decomposition - -## Original Question -"Analyze completeness of the current solution. How mature is it?" - -## Active Mode -**Mode B: Solution Assessment** — 5 solution drafts exist (`solution_draft01.md` through `solution_draft05.md`). Assessing the latest draft (05) for completeness and maturity. - -## Question Type Classification -**Knowledge Organization + Problem Diagnosis** -- Knowledge Organization: systematically map what a complete GPS-denied nav system requires vs what is present -- Problem Diagnosis: identify gaps, weak points, and missing elements that reduce maturity - -## Research Subject Boundary Definition - -| Dimension | Boundary | -|-----------|----------| -| **Population** | Fixed-wing UAV GPS-denied visual navigation systems using visual odometry + satellite matching + IMU fusion | -| **Geography** | Eastern/southern Ukraine conflict zone operations | -| **Timeframe** | Current state of art (2024-2026), focusing on Jetson-class embedded deployment | -| **Level** | System-level architecture completeness — from sensor input to flight controller output | - -## Problem Context Summary - -The solution is a real-time GPS-denied visual navigation system for a custom 3.5m fixed-wing UAV: -- **Hardware**: Jetson Orin Nano Super (8GB), ADTI 20L V1 camera (0.7fps), Viewpro A40 Pro gimbal, Pixhawk 6x -- **Core pipeline**: cuVSLAM VO (0.7fps) → ESKF fusion → GPS_INPUT via pymavlink at 5-10Hz -- **Satellite correction**: LiteSAM/EfficientLoFTR/XFeat TRT FP16 on keyframes, async Stream B -- **5 draft iterations**: progressed from initial architecture → TRT migration → camera rate correction + UAV platform specs -- **Supporting docs**: tech_stack.md, security_analysis.md - -## Decomposed Sub-Questions (Mode B) - -### Functional Completeness -- **SQ-1**: What components does a mature GPS-denied visual navigation system require that are missing or under-specified in the current draft? -- **SQ-2**: How complete is the ESKF sensor fusion specification? (state vector, process model, measurement models, Q/R tuning, observability analysis) -- **SQ-3**: How does the system handle disconnected route segments (sharp turns with no overlap)? Is this adequately specified? -- **SQ-4**: What coordinate system transformations are needed (camera → body → NED → WGS84) and are they specified? -- **SQ-5**: How does the system handle initial localization (first frame + satellite matching bootstrap)? -- **SQ-6**: Is the re-localization request workflow (to ground station) sufficiently defined? -- **SQ-7**: How complete is the offline tile preparation pipeline (zoom levels, storage requirements, coverage calculation)? -- **SQ-8**: Is the object localization component sufficiently specified for operational use? - -### Performance & Robustness -- **SQ-9**: What are the realistic drift characteristics of cuVSLAM at 0.7fps over long straight segments? -- **SQ-10**: How robust is satellite matching with Google Maps imagery in the operational area? -- **SQ-11**: What happens during extended periods with no satellite match (cloud cover on tiles, homogeneous terrain)? -- **SQ-12**: Is the 5-10Hz GPS_INPUT rate adequate for the flight controller's EKF? - -### Maturity Assessment -- **SQ-13**: What is the Technology Readiness Level (TRL) of each component? -- **SQ-14**: What validation/testing has been done vs what is only planned? -- **SQ-15**: What operational procedures are missing (pre-flight checklist, in-flight monitoring, post-flight analysis)? -- **SQ-16**: Are there any inconsistencies between documents (tech_stack.md, security_analysis.md, solution_draft05.md)? - -### Security -- **SQ-17**: Are there security gaps not covered by the existing security_analysis.md? -- **SQ-18**: How does the MAVLink GPS_INPUT message security work (spoofing of the GPS replacement itself)? - -## Timeliness Sensitivity Assessment - -- **Research Topic**: GPS-denied visual navigation system completeness and maturity -- **Sensitivity Level**: 🟡 Medium -- **Rationale**: Core algorithms (VO, ESKF, feature matching) are well-established. Hardware (Jetson Orin Nano Super) is relatively new but stable. cuVSLAM library updates are moderate pace. No rapidly-changing AI/LLM dependencies. -- **Source Time Window**: 1-2 years -- **Priority official sources to consult**: - 1. NVIDIA cuVSLAM / Isaac ROS documentation - 2. PX4/ArduPilot MAVLink GPS_INPUT documentation - 3. LiteSAM / EfficientLoFTR papers and repos -- **Key version information to verify**: - - cuVSLAM: PyCuVSLAM v15.0.0 - - TensorRT: 10.3.0 - - JetPack: 6.2.2 diff --git a/_docs/00_research/solution_completeness_assessment/01_source_registry.md b/_docs/00_research/solution_completeness_assessment/01_source_registry.md deleted file mode 100644 index ee39d1a..0000000 --- a/_docs/00_research/solution_completeness_assessment/01_source_registry.md +++ /dev/null @@ -1,166 +0,0 @@ -# Source Registry - -## Source #1 -- **Title**: ArduPilot AP_GPS_Params — GPS_RATE minimum 5Hz -- **Link**: https://github.com/ArduPilot/ardupilot/pull/15980 -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: ArduPilot flight controller users -- **Research Boundary Match**: ✅ Full match -- **Summary**: ArduPilot enforces minimum 5Hz GPS update rate. GPS_RATE parameter description: "Lowering below 5Hz(default) is not allowed." -- **Related Sub-question**: SQ-12 - -## Source #2 -- **Title**: MAVLink GPS_INPUT Message Definition -- **Link**: https://ardupilot.org/mavproxy/docs/modules/GPSInput.html -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: MAVLink developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: GPS_INPUT requires: lat, lon, alt, fix_type, hdop, vdop, horiz_accuracy, vert_accuracy, speed_accuracy, vn, ve, vd, time_usec, time_week, time_week_ms, satellites_visible, gps_id, ignore_flags. GPS_TYPE=14 for MAVLink GPS. -- **Related Sub-question**: SQ-6, SQ-12 - -## Source #3 -- **Title**: pymavlink GPS_INPUT example (GPS_INPUT_pymavlink.py) -- **Link**: https://webperso.ensta.fr/lebars/Share/GPS_INPUT_pymavlink.py -- **Tier**: L3 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: pymavlink developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Working pymavlink example sending GPS_INPUT over serial at 10Hz with GPS time calculation from system time. -- **Related Sub-question**: SQ-6 - -## Source #4 -- **Title**: PyCuVSLAM API Reference (v15.0.0) -- **Link**: https://wiki.seeedstudio.com/pycuvslam_recomputer_robotics/ -- **Tier**: L2 -- **Publication Date**: 2026-03 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: cuVSLAM developers on Jetson -- **Research Boundary Match**: ✅ Full match -- **Summary**: cuVSLAM supports mono/stereo/inertial modes. Requires Camera model (fx,fy,cx,cy,distortion), ImuCalibration (noise density, random walk, frequency, T_imu_rig). Modes: Performance/Precision/Moderate. IMU fallback ~1s acceptable quality. -- **Related Sub-question**: SQ-1, SQ-5, SQ-9 - -## Source #5 -- **Title**: ESKF Python implementation for fixed-wing UAV -- **Link**: https://github.com/ludvigls/ESKF -- **Tier**: L4 -- **Publication Date**: 2023 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: ESKF implementers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Reference ESKF: 16-state vector (pos[3], vel[3], quat[4], acc_bias[3], gyro_bias[3]). Prediction with IMU at high rate. Update with GPS position/velocity. Tuning parameters: Q (process noise), R (measurement noise). -- **Related Sub-question**: SQ-2 - -## Source #6 -- **Title**: ROS ESKF based on PX4/ecl — multi-sensor fusion -- **Link**: https://github.com/EliaTarasov/ESKF -- **Tier**: L4 -- **Publication Date**: 2022 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: UAV ESKF implementers -- **Research Boundary Match**: ✅ Full match -- **Summary**: ESKF fusing GPS, Magnetometer, Vision Pose, Optical Flow, RangeFinder with IMU. Shows that vision pose and optical flow are separate measurement models, each with its own observation matrix and noise parameters. -- **Related Sub-question**: SQ-2 - -## Source #7 -- **Title**: Visual-Inertial Odometry Scale Observability (Range-VIO) -- **Link**: https://arxiv.org/abs/2103.15215 -- **Tier**: L1 -- **Publication Date**: 2021 -- **Timeliness Status**: ✅ Currently valid (fundamental research) -- **Target Audience**: VIO researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Monocular VIO cannot observe metric scale without accelerometer excitation (not constant velocity). A 1D range sensor makes scale observable. For our case, barometric altitude + known flight altitude provides this constraint. -- **Related Sub-question**: SQ-2, SQ-4 - -## Source #8 -- **Title**: NaviLoc: Trajectory-Level Visual Localization for GNSS-Denied UAVs -- **Link**: https://www.mdpi.com/2504-446X/10/2/97 -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: GPS-denied UAV navigation researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Trajectory-level optimization fusing VPR with VIO achieves 19.5m mean error at 50-150m altitude. Key insight: treating satellite matching as noisy measurement rather than ground truth, with trajectory-level optimization. Runs at 9 FPS on RPi 5. -- **Related Sub-question**: SQ-3, SQ-13 - -## Source #9 -- **Title**: SatLoc-Fusion: Hierarchical Adaptive Fusion Framework -- **Link**: https://www.scilit.com/publications/e5cafaf875a49297a62b298a89d5572f -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: GPS-denied UAV researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Three-layer fusion: absolute geo-localization (DinoV2), relative VO (XFeat), optical flow velocity. Adaptive weighting based on confidence. Achieves <15m error, >90% trajectory coverage. 2Hz on 6 TFLOPS edge. -- **Related Sub-question**: SQ-3, SQ-10, SQ-13 - -## Source #10 -- **Title**: Auterion GPS-Denied Workflow -- **Link**: https://docs.auterion.com/vehicle-operation/auterion-mission-control/useful-resources/operations/gps-denied-workflow -- **Tier**: L2 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: UAV operators -- **Research Boundary Match**: ⚠️ Partial overlap (multirotor focus, but procedures applicable) -- **Summary**: Pre-flight: manually set home position, reset heading/position, configure wind. In-flight: enable INS mode. Defines operational procedures for GPS-denied missions. -- **Related Sub-question**: SQ-15 - -## Source #11 -- **Title**: PX4 GNSS-Degraded & Denied Flight (Dead-Reckoning) -- **Link**: https://docs.px4.io/main/en/advanced_config/gnss_degraded_or_denied_flight.html -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: PX4 users -- **Research Boundary Match**: ⚠️ Partial overlap (PX4-specific, but concepts apply to ArduPilot) -- **Summary**: GPS-denied requires redundant position/velocity sensors. Dead-reckoning mode for intermittent GNSS loss. Defines failsafe behaviors when GPS is lost. -- **Related Sub-question**: SQ-15 - -## Source #12 -- **Title**: Google Maps Ukraine satellite imagery coverage -- **Link**: https://newsukraine.rbc.ua/news/google-maps-has-surprise-for-satellite-imagery-1727182380.html -- **Tier**: L3 -- **Publication Date**: 2024-09 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: General public -- **Research Boundary Match**: ✅ Full match -- **Summary**: Google Maps improved imagery quality with Cloud Score+ AI. However, conflict zone imagery is intentionally older (>1 year). Ukrainian officials flagged security concerns about imagery revealing military positions. -- **Related Sub-question**: SQ-10 - -## Source #13 -- **Title**: Jetson Orin Nano Super thermal behavior at 25W -- **Link**: https://edgeaistack.app/blog/jetson-orin-nano-power-consumption/ -- **Tier**: L3 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Jetson developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Thermal throttling at SoC junction >80°C. Sustained GPU at 25W: ~50-51°C reported. Active cooling required for >15W. Most production workloads 8-15W. -- **Related Sub-question**: SQ-11 - -## Source #14 -- **Title**: Automated Image Matching for Satellite Images with Different GSDs -- **Link**: https://www.kjrs.org/journal/view.html?pn=related&uid=756&vmd=Full -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Remote sensing researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: GSD mismatch between satellite and aerial images requires scale normalization via subsampling/super-resolution. Coarse-to-fine matching strategy effective. Scale-invariant features (SIFT, deep features) partially handle scale differences. -- **Related Sub-question**: SQ-7 - -## Source #15 -- **Title**: Optimized VO and satellite image matching for UAVs (Istanbul Tech thesis) -- **Link**: https://polen.itu.edu.tr/items/1fe1e872-7cea-44d8-a8de-339e4587bee6 -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: GPS-denied UAV researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Complete VO+satellite matching pipeline. Coordinate transforms: GPS → local NED for trajectory comparison. PnP solver for UAV pose from correspondences. Map retrieval using VO-estimated position to crop satellite tiles. -- **Related Sub-question**: SQ-4, SQ-5 diff --git a/_docs/00_research/solution_completeness_assessment/02_fact_cards.md b/_docs/00_research/solution_completeness_assessment/02_fact_cards.md deleted file mode 100644 index 97c850e..0000000 --- a/_docs/00_research/solution_completeness_assessment/02_fact_cards.md +++ /dev/null @@ -1,169 +0,0 @@ -# Fact Cards - -## Fact #1 — ArduPilot minimum GPS rate is 5Hz -- **Statement**: ArduPilot enforces a hard minimum of 5Hz for GPS_INPUT updates. The GPS_RATE parameter description states: "Lowering below 5Hz(default) is not allowed." The EKF scales buffers based on this rate. -- **Source**: Source #1 (ArduPilot AP_GPS_Params) -- **Phase**: Assessment -- **Target Audience**: ArduPilot-based flight controllers -- **Confidence**: ✅ High -- **Related Dimension**: Flight controller integration completeness - -## Fact #2 — GPS_INPUT requires velocity + accuracy + GPS time fields -- **Statement**: GPS_INPUT message requires not just lat/lon/alt, but also: vn/ve/vd velocity components, hdop/vdop, horiz_accuracy/vert_accuracy/speed_accuracy, fix_type, time_week/time_week_ms, satellites_visible, and ignore_flags bitmap. The solution draft05 mentions GPS_INPUT but does not specify how these fields are populated (especially velocity from ESKF, accuracy from covariance, GPS time conversion from system time). -- **Source**: Source #2 (MAVLink GPS_INPUT definition), Source #3 (pymavlink example) -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Flight controller integration completeness - -## Fact #3 — ESKF state vector needs explicit definition -- **Statement**: Standard ESKF for UAV VIO fusion uses 15-16 state error vector: δp[3], δv[3], δθ[3] (attitude error in so(3)), δba[3] (accel bias), δbg[3] (gyro bias), optionally δg[3] (gravity). The solution draft05 says "16-state vector" and "ESKF + buffers ~10MB" but never defines the actual state vector, process model (F, Q matrices), measurement models (H matrices for VO and satellite), or noise parameters. -- **Source**: Source #5 (ludvigls/ESKF), Source #6 (EliaTarasov/ESKF) -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Sensor fusion completeness - -## Fact #4 — Monocular VIO has scale ambiguity without excitation -- **Statement**: Monocular visual-inertial odometry cannot observe metric scale during constant-velocity flight (zero accelerometer excitation). This is a fundamental observability limitation. The solution uses monocular cuVSLAM + IMU, and fixed-wing UAVs fly mostly at constant velocity. Scale must be provided externally — via known altitude (barometric + predefined mission altitude) or satellite matching absolute position. -- **Source**: Source #7 (Range-VIO scale observability paper) -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Sensor fusion completeness, core algorithm correctness - -## Fact #5 — cuVSLAM requires explicit camera calibration and IMU calibration -- **Statement**: PyCuVSLAM requires Camera(fx, fy, cx, cy, width, height) + Distortion model + ImuCalibration(gyroscope_noise_density, gyroscope_random_walk, accelerometer_noise_density, accelerometer_random_walk, frequency, T_imu_rig). The solution draft05 does not specify any camera calibration procedure, IMU noise parameters, or the T_imu_rig (IMU-to-camera) extrinsic transformation. -- **Source**: Source #4 (PyCuVSLAM docs) -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Visual odometry completeness - -## Fact #6 — cuVSLAM IMU fallback provides ~1s acceptable tracking -- **Statement**: When visual tracking fails (featureless terrain, darkness), cuVSLAM falls back to IMU-only integration which provides "approximately 1 second" of acceptable tracking quality before drift becomes unacceptable. After that, tracking is lost. -- **Source**: Source #4 (PyCuVSLAM/Isaac ROS docs) -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Resilience, edge case handling - -## Fact #7 — Disconnected route segments need satellite re-localization -- **Statement**: When a UAV makes a sharp turn and the next photos have no overlap with previous frames, cuVSLAM will lose tracking. The solution must re-localize using satellite imagery. The AC requires handling "more than 2 such disconnected segments" as a core strategy. Solution draft05 mentions this requirement but does not define the concrete re-localization algorithm (how satellite match triggers, how the new position is initialized in ESKF, how the map is connected to the previous segment). -- **Source**: Source #8 (NaviLoc), Source #9 (SatLoc-Fusion), AC requirements -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Functional completeness — disconnected segments - -## Fact #8 — Coordinate transformation chain is undefined -- **Statement**: The system needs a well-defined coordinate transformation chain: (1) pixel coordinates → camera frame (using intrinsics), (2) camera frame → body frame (camera mount extrinsics), (3) body frame → NED frame (using attitude from ESKF), (4) NED → WGS84 (using reference point). For satellite matching: geo-referenced tile coordinates → WGS84. For object localization: pixel + camera angle + altitude → ground point → WGS84. None of these transformations are explicitly defined in draft05. -- **Source**: Source #15 (Istanbul Tech thesis), Source #7 -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Coordinate system completeness - -## Fact #9 — GSD normalization required for satellite-aerial matching -- **Statement**: Camera GSD at 600m altitude with ADTI 20L V1 (16mm, APS-C) is ~15.9 cm/pixel. Google Maps zoom 19 ≈ 0.3 m/pixel, zoom 18 ≈ 0.6 m/pixel. The GSD ratio is ~2:1 to ~4:1 depending on zoom level and altitude. Draft05's "pre-resize" step in the offline pipeline is mentioned but not specified: what resolution? what zoom level? The matching model (LiteSAM/XFeat) input size must match appropriately. -- **Source**: Source #14 (GSD matching paper), solution_draft05 calculations -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Satellite matching completeness - -## Fact #10 — Google Maps imagery in conflict zones is intentionally outdated -- **Statement**: Google Maps deliberately serves older imagery (>1 year) for conflict zones in Ukraine. Ukrainian officials have flagged security concerns. The operational area (eastern/southern Ukraine) is directly in the conflict zone. Imagery may be 1-3+ years old, with seasonal differences (summer tiles vs winter flight, or vice versa). This is a HIGH-severity gap for satellite matching accuracy. -- **Source**: Source #12 (Google Maps Ukraine coverage) -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Satellite imagery quality risk - -## Fact #11 — No operational procedures defined -- **Statement**: Mature GPS-denied systems (Auterion, PX4) define: pre-flight checklist (set home position, verify sensors, verify tile coverage), in-flight monitoring procedures (what to watch, when to intervene), and post-flight analysis (compare estimated vs actual GPS on return). Solution draft05 has no operational procedures section. -- **Source**: Source #10 (Auterion), Source #11 (PX4) -- **Phase**: Assessment -- **Target Audience**: GPS-denied system operators -- **Confidence**: ✅ High -- **Related Dimension**: Operational maturity - -## Fact #12 — Object localization lacks implementation detail -- **Statement**: AC requires: "Other onboard AI systems can request GPS coordinates of objects detected by the AI camera." The solution says "trigonometric calculation using UAV GPS position, camera angle, zoom, altitude." But no API is defined, no coordinate math is shown, no handling of camera zoom/angle → ground projection is specified. The Viewpro A40 Pro gimbal angle and zoom parameters are not integrated. -- **Source**: Acceptance criteria, solution_draft05 -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Object localization completeness - -## Fact #13 — Tech stack document is inconsistent with draft05 -- **Statement**: tech_stack.md says "camera @ ~3fps" in non-functional requirements. Draft05 corrected this to 0.7fps. tech_stack.md lists LiteSAM benchmark decision at 480px/640px/800px; draft05 uses 1280px. tech_stack.md doesn't mention EfficientLoFTR as fallback. These inconsistencies indicate the tech_stack.md was not updated after draft05 changes. -- **Source**: tech_stack.md, solution_draft05.md -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Document consistency, maturity - -## Fact #14 — Confidence scoring is undefined in draft05 -- **Statement**: Draft05 says "Confidence Scoring → GPS_INPUT Mapping — Unchanged from draft03" but draft05 is supposed to be self-contained. The actual confidence scoring logic (how VO confidence + satellite match confidence map to GPS_INPUT fix_type, hdop, horiz_accuracy) is never defined in the current draft. This is critical because ArduPilot's EKF uses these accuracy fields to weight the GPS data. -- **Source**: Source #2 (GPS_INPUT fields), solution_draft05 -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Flight controller integration, confidence scoring - -## Fact #15 — Initial bootstrap sequence is incomplete -- **Statement**: Draft05 startup reads GLOBAL_POSITION_INT to get initial GPS position. But: (1) cuVSLAM needs its first frame + features to initialize — how is the first satellite match triggered? (2) ESKF needs initial state — position from GPS, but velocity? attitude? (3) How does the system know GPS is denied and should start sending GPS_INPUT? (4) Is there a handoff protocol from real GPS to GPS-denied system? -- **Source**: solution_draft05, Source #10 (Auterion procedures) -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Startup and bootstrap completeness - -## Fact #16 — No recovery from companion computer reboot -- **Statement**: AC requires: "On companion computer reboot mid-flight, the system should attempt to re-initialize from the flight controller's current IMU-extrapolated position." Draft05 does not address this scenario. The system needs: read current FC position estimate, re-initialize ESKF, reload TRT engines (~1-3s), start cuVSLAM with no prior map, trigger immediate satellite re-localization. -- **Source**: Acceptance criteria, solution_draft05 -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Resilience, failsafe completeness - -## Fact #17 — No position refinement mechanism -- **Statement**: AC states: "The system may refine previously calculated positions and send corrections to the flight controller as updated estimates." Draft05 does not define how this works. When a satellite match provides an absolute correction, do previously estimated positions get retroactively corrected? Is this communicated to the flight controller? How? -- **Source**: Acceptance criteria, solution_draft05 -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ⚠️ Medium (AC is ambiguous about necessity) -- **Related Dimension**: Position refinement - -## Fact #18 — Tile storage requirements not calculated -- **Statement**: The solution mentions "preload tiles ±2km" and "GeoHash-indexed directory" but never calculates: how many tiles are needed for a mission area, what storage space is required, what zoom levels to use, or how to handle the trade-off between tile coverage area and storage limit. At zoom 19 (~0.3m/pixel), each 256×256 tile covers ~77m × 77m. Covering a 200km flight path with ±2km buffer would require ~130,000 tiles (~2.5GB JPEG). -- **Source**: solution_draft05, tech_stack.md -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ⚠️ Medium (estimates based on standard tile sizes) -- **Related Dimension**: Offline preparation completeness - -## Fact #19 — 3 consecutive failed frames → re-localization request undefined -- **Statement**: AC requires: "If system cannot determine position of 3 consecutive frames by any means, send re-localization request to ground station operator via telemetry link." Draft05 does not define: (1) the re-localization request message format, (2) what "any means" includes (VO failed + satellite match failed + IMU drift exceeded threshold?), (3) how the operator response is received and applied, (4) what the system does while waiting. -- **Source**: Acceptance criteria, solution_draft05 -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: Ground station integration, resilience - -## Fact #20 — FastAPI endpoints mentioned but not defined -- **Statement**: Draft05 mentions FastAPI for "local IPC" but the REST API endpoints are only defined in security_analysis.md (POST /sessions, GET /sessions/{id}/stream, POST /sessions/{id}/anchor, DELETE /sessions/{id}). The solution draft itself doesn't specify the API contract, request/response schemas, or how other onboard systems interact. -- **Source**: solution_draft05, security_analysis.md -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ✅ High -- **Related Dimension**: API completeness - -## Fact #21 — NaviLoc achieves 19.5m error with trajectory-level optimization -- **Statement**: Recent research (NaviLoc, 2025) shows that trajectory-level optimization treating satellite matching as noisy measurement achieves 19.5m mean error at 50-150m altitude, 16× better than per-frame matching. The solution's approach of per-keyframe satellite matching + ESKF correction is simpler but potentially less accurate than trajectory-level optimization. -- **Source**: Source #8 (NaviLoc) -- **Phase**: Assessment -- **Target Audience**: GPS-denied system -- **Confidence**: ⚠️ Medium (NaviLoc operates at lower altitude with higher overlap) -- **Related Dimension**: Algorithm maturity, accuracy potential diff --git a/_docs/00_research/solution_completeness_assessment/03_comparison_framework.md b/_docs/00_research/solution_completeness_assessment/03_comparison_framework.md deleted file mode 100644 index ac34d22..0000000 --- a/_docs/00_research/solution_completeness_assessment/03_comparison_framework.md +++ /dev/null @@ -1,63 +0,0 @@ -# Comparison Framework - -## Selected Framework Type -Knowledge Organization + Problem Diagnosis — mapping completeness dimensions against solution state - -## Completeness Dimensions - -1. Core Pipeline Definition -2. Sensor Fusion (ESKF) Specification -3. Visual Odometry Configuration -4. Satellite Image Matching Pipeline -5. Coordinate System & Transformations -6. Flight Controller Integration (GPS_INPUT) -7. Disconnected Route Segment Handling -8. Startup, Bootstrap & Failsafe -9. Object Localization -10. Offline Preparation Pipeline -11. Ground Station Integration -12. Operational Procedures -13. API & Inter-system Communication -14. Document Consistency -15. Testing Coverage vs AC - -## Maturity Scoring - -| Score | Level | Description | -|-------|-------|-------------| -| 1 | Concept | Mentioned but not specified | -| 2 | Defined | Architecture-level description, component selected | -| 3 | Detailed | Implementation details, data flows, algorithms specified | -| 4 | Validated | Benchmarked, tested, edge cases handled | -| 5 | Production | Field-tested, operational procedures, monitoring | - -## Completeness Assessment Matrix - -| Dimension | Current State | Maturity | Key Gaps | Facts | -|-----------|--------------|----------|----------|-------| -| Core Pipeline | VO → ESKF → GPS_INPUT flow well-defined. Dual CUDA stream architecture. Camera rate corrected to 0.7fps. Time budgets calculated. | 3 | Self-contained — but references "unchanged from draft03" in several places instead of restating | — | -| ESKF Specification | "16-state vector", "ESKF + buffers ~10MB", "ESKF measurement update" | 1.5 | No state vector definition, no process model (F,Q), no measurement models (H for VO, H for satellite), no noise parameters, no scale observability analysis, no tuning strategy | #3, #4 | -| VO Configuration | cuVSLAM selected, 0.7fps feasibility analyzed, pyramid-LK range calculated, overlap >95% | 2.5 | No camera calibration procedure, no IMU calibration parameters (noise density, random walk), no T_imu_rig extrinsic, no cuVSLAM mode selection (Mono vs Inertial), no cuVSLAM initialization procedure | #5, #6 | -| Satellite Matching | LiteSAM/EfficientLoFTR/XFeat decision tree, TRT conversion workflow, async Stream B | 2.5 | No GSD normalization spec, no tile-to-camera scale matching, no matching confidence threshold, no geometric verification details beyond "RANSAC homography", no match-to-WGS84 conversion | #9, #14 | -| Coordinate System | WGS84 output mentioned. Camera footprint calculated. | 1 | No transformation chain defined (pixel→camera→body→NED→WGS84). No camera-to-body extrinsic. No reference point definition for NED. No handling of terrain elevation. | #8 | -| Flight Controller Integration | pymavlink, GPS_INPUT, 5-10Hz, UART | 2 | No GPS_INPUT field population spec (where do velocity, accuracy, hdop come from?). No fix_type mapping. No GPS time conversion. No ignore_flags. Confidence scoring undefined in current draft. | #1, #2, #14 | -| Disconnected Segments | Mentioned in AC, satellite matching acknowledged as solution | 1.5 | No algorithm for detecting tracking loss. No re-localization trigger. No position initialization after re-localization. No map discontinuity handling. | #7 | -| Startup & Failsafe | 12-step startup sequence. Engine load times. | 2 | No GPS-denied handoff protocol. No mid-flight reboot recovery. No "3 consecutive failed frames" handling. No operator re-localization workflow. | #15, #16, #19 | -| Object Localization | "Trigonometric calculation" mentioned | 1 | No math defined. No API endpoint. No Viewpro gimbal integration spec. No accuracy analysis. | #12 | -| Offline Preparation | Tile download → validate → pre-resize → store. TRT engine build. | 2 | No zoom level selection. No storage calculation. No coverage verification. No tile freshness check. No pre-flight validation tool. | #18 | -| Ground Station Integration | NAMED_VALUE_FLOAT at 1Hz for confidence/drift. Operator re-localization hint mentioned in AC. | 1.5 | Re-localization request/response undefined. Ground station display requirements undefined. Operator workflow undefined. | #19 | -| Operational Procedures | None defined | 0 | No pre-flight checklist. No in-flight monitoring guide. No post-flight analysis. No failure response procedures. | #11 | -| API & IPC | FastAPI mentioned for "local IPC" | 1.5 | Endpoints only in security_analysis.md, not in solution. No request/response schemas. No SSE event format. No object localization API. | #20 | -| Document Consistency | 3 documents (draft05, tech_stack, security) | — | tech_stack.md has 3fps (should be 0.7fps). LiteSAM resolution mismatch. EfficientLoFTR missing from tech_stack. | #13 | -| Testing vs AC | Tests cover TRT, cuVSLAM 0.7fps, shutter. | 2.5 | No explicit mapping of tests to AC items. Missing tests: disconnected segments, re-localization, 3-consecutive-failure, object localization, operator workflow, mid-flight reboot. | — | - -## Overall Maturity Assessment - -| Category | Avg Score | Assessment | -|----------|-----------|------------| -| Hardware/Platform | 3.5 | Well-researched: UAV specs, camera analysis, memory budget, thermal | -| Core Algorithms (VO, matching) | 2.5 | Component selection solid, but implementation specs missing | -| Sensor Fusion (ESKF) | 1.5 | Severely under-specified | -| System Integration | 1.5 | GPS_INPUT, coordinate transforms, API all incomplete | -| Operational Readiness | 0.5 | No operational procedures, no deployment pipeline | -| **Overall** | **~2.0** | **Architecture-level design, not implementation-ready** | diff --git a/_docs/00_research/solution_completeness_assessment/04_reasoning_chain.md b/_docs/00_research/solution_completeness_assessment/04_reasoning_chain.md deleted file mode 100644 index c93e6a6..0000000 --- a/_docs/00_research/solution_completeness_assessment/04_reasoning_chain.md +++ /dev/null @@ -1,166 +0,0 @@ -# Reasoning Chain - -## Dimension 1: ESKF Sensor Fusion Specification - -### Fact Confirmation -Per Fact #3, standard ESKF for UAV VIO uses 15-16 state error vector: δp[3], δv[3], δθ[3], δba[3], δbg[3]. Per Fact #4, monocular VIO cannot observe metric scale during constant-velocity flight (fundamental observability limitation). Per Fact #7, scale requires external constraint (altitude or satellite absolute position). - -### Current State -Draft05 says "Custom ESKF (NumPy/SciPy)", "16-state vector", "ESKF measurement update ~1ms", "ESKF IMU prediction at 5-10Hz". But provides zero mathematical detail. - -### Conclusion -The ESKF is the **most under-specified critical component**. Without defining: -- State vector and error state vector explicitly -- Process model (how IMU data propagates the state) -- VO measurement model (how cuVSLAM relative pose updates the filter) -- Satellite measurement model (how absolute position corrections are applied) -- How scale is maintained (altitude constraint? satellite corrections only?) -- Q and R matrices (at least initial values and tuning approach) - -...the system cannot be implemented. The ESKF is the central hub connecting all sensors — its specification drives the entire data flow. - -### Confidence: ✅ High - ---- - -## Dimension 2: Flight Controller Integration (GPS_INPUT) - -### Fact Confirmation -Per Fact #1, ArduPilot requires minimum 5Hz GPS_INPUT rate. Per Fact #2, GPS_INPUT has 15+ mandatory fields including velocity, accuracy, fix_type, GPS time. Per Fact #14, confidence scoring that maps internal state to GPS_INPUT accuracy fields is undefined. - -### Current State -Draft05 specifies: pymavlink, GPS_INPUT, 5-10Hz, UART. This satisfies the rate requirement. But the message population is unspecified. - -### Conclusion -The GPS_INPUT integration has the right architecture (5-10Hz, pymavlink, UART) but is missing the **data mapping layer**: -- `vn, ve, vd` must come from ESKF velocity estimate — requires ESKF to output velocity -- `horiz_accuracy, vert_accuracy` must come from ESKF covariance matrix (sqrt of position covariance diagonal) -- `hdop, vdop` need to be synthesized from accuracy values (hdop ≈ horiz_accuracy / expected_CEP_factor) -- `fix_type` must map from internal confidence (3=3D fix when satellite-anchored, 2=2D when VO-only?) -- `speed_accuracy` from ESKF velocity covariance -- GPS time (time_week, time_week_ms) requires conversion from system time to GPS epoch -- `satellites_visible` should be set to a constant (e.g., 10) to avoid triggering satellite-count failsafes - -This is a tractable implementation detail but must be specified before coding. - -### Confidence: ✅ High - ---- - -## Dimension 3: Coordinate System & Transformations - -### Fact Confirmation -Per Fact #8, the system needs pixel → camera → body → NED → WGS84 chain. Per Fact #9, satellite tiles have different GSD than camera imagery. Per Source #15, similar systems define explicit coordinate transforms with PnP solvers. - -### Current State -Draft05 calculates camera footprint and GSD but never defines the transformation chain. Object localization mentions "trigonometric calculation" without math. - -### Conclusion -This is a **fundamental architectural gap**. Every position estimate flows through coordinate transforms. Without defining them: -- cuVSLAM outputs relative pose in camera frame — how is this converted to NED displacement? -- Satellite matching outputs pixel correspondences — how does homography → WGS84 position? -- Object localization needs camera ray → ground intersection — impossible without camera-to-body and body-to-NED transforms -- The camera is "not autostabilized" — so body frame attitude matters for ground projection - -The fix requires defining: camera intrinsic matrix K, camera-to-body rotation T_cam_body, and the ESKF attitude estimate for body-to-NED. - -### Confidence: ✅ High - ---- - -## Dimension 4: Disconnected Route Segments - -### Fact Confirmation -Per Fact #7, AC explicitly requires handling disconnected segments as "core to the system." Per Fact #6, cuVSLAM IMU fallback gives ~1s before tracking loss. Per Source #8, trajectory-level optimization can handle segment connections. - -### Current State -Draft05 acknowledges this in AC but the solution section says "sharp-turn frames are expected to fail VO and should be handled by satellite-based re-localization." No algorithm is specified. - -### Conclusion -The solution needs a concrete **re-localization pipeline**: -1. Detect tracking loss (cuVSLAM returns tracking_lost state) -2. Continue ESKF with IMU-only prediction (high uncertainty growth) -3. Immediately trigger satellite matching on next available frame -4. If satellite match succeeds: reset ESKF position to matched position, reset cuVSLAM (or start new track) -5. If satellite match fails: retry on next frame, increment failure counter -6. If 3 consecutive failures: send re-localization request to ground station -7. When new segment starts: mark as disconnected, continue building trajectory -8. Optionally: if a later satellite match connects two segments to the same reference, merge them - -This is not trivial but follows directly from the existing architecture. It's a missing algorithm, not a missing component. - -### Confidence: ✅ High - ---- - -## Dimension 5: Startup Bootstrap & Failsafe - -### Fact Confirmation -Per Fact #15, the bootstrap sequence has gaps (first satellite match, initial ESKF state, GPS-denied handoff). Per Fact #16, AC requires mid-flight reboot recovery. Per Fact #19, AC requires 3-consecutive-failure re-localization request. - -### Current State -Draft05 has a 12-step startup sequence that covers the happy path. The failure paths and special cases are not addressed. - -### Conclusion -Three failsafe scenarios need specification: -1. **GPS-denied handoff**: How does the system know to start? Options: (a) always running — takes over when GPS quality degrades, (b) operator command, (c) automatic GPS quality monitoring. The system should probably always be running in parallel and the FC uses the best available source. -2. **Mid-flight reboot**: Read FC position → init ESKF with high uncertainty → start cuVSLAM → immediate satellite match → within ~5s should have a position estimate. TRT engine load (1-3s) is the main startup cost. -3. **3 consecutive failures**: Define "failure" precisely (VO lost + satellite match failed + IMU-only drift > threshold). Send NAMED_VALUE_FLOAT or custom MAVLink message to ground station. Define operator response format. - -### Confidence: ✅ High - ---- - -## Dimension 6: Satellite Matching Pipeline Details - -### Fact Confirmation -Per Fact #9, camera GSD is ~15.9 cm/pixel at 600m with ADTI+16mm lens. Satellite at zoom 19 is ~0.3 m/pixel. Per Fact #10, Google Maps imagery in Ukraine conflict zone is intentionally >1 year old. Per Fact #14, the solution says "pre-resize" but doesn't specify to what resolution. - -### Current State -Draft05 has a solid model selection decision tree (LiteSAM → EfficientLoFTR → XFeat) and TRT conversion workflow. But the actual matching pipeline data flow is incomplete. - -### Conclusion -The matching pipeline needs: -- **Input preparation**: Camera frame (5456×3632 at ~15.9 cm/pixel at 600m) → downsample to matcher input resolution (1280px for LiteSAM). Satellite tile at zoom 18 (~0.6 m/pixel) → no resize needed if using 256px tiles, or assemble 5×5 tile mosaic for coverage. -- **GSD matching**: Either downsample camera image to satellite GSD, or specify that the matcher handles multi-scale internally. LiteSAM was designed for satellite-aerial matching so it may handle this. XFeat is general-purpose and may need explicit scale normalization. -- **Tile selection**: Given ESKF position estimate + uncertainty, select the correct satellite tile(s). What if the position estimate has drifted and the wrong tile is selected? Need a search radius based on ESKF covariance. -- **Match → position**: Homography from RANSAC → decompose to get translation in satellite coordinate frame → convert to WGS84 using tile's geo-reference. -- **Seasonal/temporal mismatch**: Tiles could be from different seasons. Feature matching must be robust to appearance changes. - -### Confidence: ✅ High - ---- - -## Dimension 7: Operational Maturity - -### Fact Confirmation -Per Fact #11, mature systems (Auterion, PX4) define pre-flight checklists, in-flight monitoring, failure response procedures. Per Fact #13, documents are inconsistent (tech_stack.md still says 3fps). - -### Current State -Zero operational procedures defined. Documents are partially inconsistent. - -### Conclusion -This is expected at this stage of development (architecture/design phase). Operational procedures should come after implementation and initial testing. However, the document inconsistencies should be fixed now to avoid confusion during implementation. The tech_stack.md and solution_draft should be aligned. - -### Confidence: ✅ High - ---- - -## Dimension 8: Object Localization - -### Fact Confirmation -Per Fact #12, AC requires other AI systems to request GPS coordinates of detected objects. The Viewpro A40 Pro gimbal has configurable angle and zoom. - -### Current State -Draft05 says "trigonometric calculation using UAV GPS position, camera angle, zoom, altitude. Flat terrain assumed." - -### Conclusion -The math is straightforward but needs specification: -- Input: pixel coordinates (u,v) in Viewpro image, gimbal angles (pan, tilt), zoom level, UAV position (from GPS-denied system), UAV altitude -- Process: (1) pixel → ray in camera frame using intrinsics + zoom, (2) camera frame → body frame using gimbal angles, (3) body frame → NED using UAV attitude, (4) ray-ground intersection assuming flat terrain at known altitude, (5) NED offset → WGS84 -- Output: lat, lon of object + accuracy estimate (propagated from UAV position accuracy + gimbal angle uncertainty) -- API: FastAPI endpoint for other onboard systems to call - -This is a 2-point complexity task but should be specified in the solution. - -### Confidence: ✅ High diff --git a/_docs/00_research/solution_completeness_assessment/05_validation_log.md b/_docs/00_research/solution_completeness_assessment/05_validation_log.md deleted file mode 100644 index c068fe3..0000000 --- a/_docs/00_research/solution_completeness_assessment/05_validation_log.md +++ /dev/null @@ -1,96 +0,0 @@ -# Validation Log - -## Validation Scenario 1: Normal Straight Flight (Happy Path) - -### Expected Based on Conclusions -UAV flies straight at 70 km/h, 600m altitude. ADTI captures at 0.7fps. cuVSLAM processes each frame (~9ms), ESKF fuses VO + IMU. Every 5-10 frames, satellite matching provides absolute correction. GPS_INPUT sent at 5-10Hz. - -### Actual Validation Results -The happy path is well-specified in draft05. Time budgets, memory budgets, overlap calculations all valid. The 5-10Hz ESKF IMU prediction fills gaps between 0.7fps camera frames. Satellite matching async on Stream B. - -**GAP**: Even on straight flight, the GPS_INPUT message field population is undefined. Where does velocity come from? What fix_type is sent? What accuracy values? - ---- - -## Validation Scenario 2: Sharp Turn with No Overlap - -### Expected Based on Conclusions -UAV makes a 90° turn. Next frame has zero overlap with previous. cuVSLAM loses tracking. System falls back to IMU. ESKF uncertainty grows rapidly. Satellite matching on next frame provides re-localization. - -### Actual Validation Results -**CRITICAL GAP**: No algorithm defined for this scenario. Questions: -1. How does the system detect cuVSLAM tracking loss? (cuVSLAM API presumably returns a tracking state) -2. During IMU-only phase, what is the ESKF prediction uncertainty growth rate? (~1-2m/s drift with consumer IMU) -3. When satellite match succeeds after the turn, how is ESKF re-initialized? (measurement update with very high innovation? or state reset?) -4. How is cuVSLAM re-initialized on the new heading? (new track from scratch? or cuVSLAM loop closure if it sees previous terrain?) -5. If the turn area is over featureless terrain (farmland), satellite matching may also fail — then what? - -The AC says "sharp-turn frames should be within 200m drift and angle <70 degrees" — this bounds the problem but the solution doesn't address it algorithmically. - ---- - -## Validation Scenario 3: Long Flight Over Uniform Terrain - -### Expected Based on Conclusions -UAV flies 50km straight over large agricultural fields. cuVSLAM may struggle with low-texture terrain. Satellite matching is the only absolute correction source. - -### Actual Validation Results -This scenario tests the limits of the design: -- cuVSLAM at 600m altitude sees ~577m × 870m footprint. If it's a single wheat field, features may be sparse. cuVSLAM falls back to IMU (~1s acceptable, then tracking lost). -- Satellite matching must carry the entire position estimation burden. -- At 0.7fps with keyframe every 5-10 frames: satellite match every 7-14s. -- Between matches, IMU-only drift at 70 km/h: ~14m/s × time × drift_rate. With consumer IMU: ~1-5m drift per second. -- Over 14s between matches: ~14-70m potential drift. AC requires <100m between anchors. - -**GAP**: The system's behavior in this degraded mode needs explicit specification. Is this VO-failed + satellite-only + IMU acceptable? What's the accuracy? - ---- - -## Validation Scenario 4: First Frame After GPS Denial - -### Expected Based on Conclusions -GPS was working. Now it's denied/spoofed. System takes over. - -### Actual Validation Results -**GAP**: No handoff protocol defined. Questions: -1. How does the system detect GPS denial? (it doesn't — it's assumed the operator knows) -2. The initial ESKF state comes from GLOBAL_POSITION_INT — but this might be the spoofed GPS. How to validate? -3. If GPS is being spoofed rather than denied, the initial position could be wrong by kilometers. -4. Draft05 assumes clean initial GPS. This is reasonable for the first version but should be acknowledged as a limitation. - ---- - -## Validation Scenario 5: Mid-Flight Companion Computer Reboot - -### Expected Based on Conclusions -Companion computer crashes and reboots. Flight controller continues flying on IMU dead reckoning. - -### Actual Validation Results -**GAP**: AC requires recovery. Draft05 doesn't address it. Sequence should be: -1. Jetson boots (~30-60s depending on boot time) -2. GPS-Denied service starts (systemd) -3. Connect to FC, get current position (IMU-extrapolated, may have significant drift) -4. Load TRT engines (~1-3s each, total ~2-6s) -5. Start cuVSLAM (no prior map, fresh start) -6. Immediate satellite match to get absolute position -7. Total recovery time: ~35-70s. During this time, FC uses IMU-only. At 70 km/h: ~700-1400m of uncontrolled drift. - -This is a real operational concern and should be documented even if the solution is "acknowledge the limitation." - ---- - -## Counterexamples -- **NaviLoc achieves 19.5m at lower altitude**: Our system operates at 600-1000m with larger footprints and coarser GSD. The accuracy requirement (50m for 80%, 20m for 60%) is less demanding. The simpler ESKF approach may be adequate. -- **SatLoc-Fusion uses DinoV2 for place recognition**: Our system uses feature matching (LiteSAM/XFeat) which is more precise but less robust to appearance changes. DinoV2 is more robust to seasonal changes but gives coarser position. - -## Review Checklist -- [x] Draft conclusions consistent with fact cards -- [x] No important dimensions missed -- [x] No over-extrapolation -- [ ] Issue: ESKF specification is too underspecified to validate accuracy claims -- [ ] Issue: Disconnected segment handling is critical AC and has no algorithm -- [ ] Issue: GPS_INPUT field mapping undocumented -- [ ] Issue: Object localization API undefined - -## Conclusions Requiring Revision -None requiring reversal. All identified gaps are genuine and supported by facts. diff --git a/_docs/00_research/trt_engine_migration/00_question_decomposition.md b/_docs/00_research/trt_engine_migration/00_question_decomposition.md deleted file mode 100644 index 347d35b..0000000 --- a/_docs/00_research/trt_engine_migration/00_question_decomposition.md +++ /dev/null @@ -1,57 +0,0 @@ -# Question Decomposition - -## Original Question -Should we switch from ONNX Runtime to native TensorRT Engine for all AI models in the GPS-Denied pipeline, running on Jetson Orin Nano Super? - -## Active Mode -Mode B: Solution Assessment — existing solution_draft03.md uses ONNX Runtime / mixed inference. User requests focused investigation of TRT Engine migration. - -## Question Type -Decision Support — evaluating a technology switch with cost/risk/benefit dimensions. - -## Research Subject Boundary - -| Dimension | Boundary | -|-----------|----------| -| Population | AI inference models in the GPS-Denied navigation pipeline | -| Hardware | Jetson Orin Nano Super (8GB LPDDR5, 67 TOPS sparse INT8, 1020 MHz GPU, NO DLA) | -| Software | JetPack 6.2 (CUDA 12.6, TensorRT 10.3, cuDNN 9.3) | -| Timeframe | Current (2025-2026), JetPack 6.2 era | - -## AI Models in Pipeline - -| Model | Type | Current Runtime | TRT Applicable? | -|-------|------|----------------|-----------------| -| cuVSLAM | Native CUDA library (closed-source) | CUDA native | NO — already CUDA-optimized binary | -| LiteSAM | PyTorch (MobileOne + TAIFormer + MinGRU) | Planned TRT FP16 | YES | -| XFeat | PyTorch (learned features) | XFeatTensorRT exists | YES | -| ESKF | Mathematical filter (Python/C++) | CPU/NumPy | NO — not an AI model | - -Only LiteSAM and XFeat are convertible to TRT Engine. cuVSLAM is already NVIDIA-native CUDA. - -## Decomposed Sub-Questions - -1. What is the performance difference between ONNX Runtime and native TRT Engine on Jetson Orin Nano Super? -2. What is the memory overhead of ONNX Runtime vs native TRT on 8GB shared memory? -3. What conversion paths exist for PyTorch → TRT Engine on Jetson aarch64? -4. Are TRT engines hardware-specific? What's the deployment workflow? -5. What are the specific conversion steps for LiteSAM and XFeat? -6. Does Jetson Orin Nano Super have DLA for offloading? -7. What are the risks and limitations of going TRT-only? - -## Timeliness Sensitivity Assessment - -- **Research Topic**: TensorRT vs ONNX Runtime inference on Jetson Orin Nano Super -- **Sensitivity Level**: 🟠 High -- **Rationale**: TensorRT, JetPack, and ONNX Runtime release new versions frequently. Jetson Orin Nano Super mode is relatively new (JetPack 6.2, Jan 2025). -- **Source Time Window**: 12 months -- **Priority official sources to consult**: - 1. NVIDIA TensorRT documentation (docs.nvidia.com) - 2. NVIDIA JetPack 6.2 release notes - 3. ONNX Runtime GitHub issues (microsoft/onnxruntime) - 4. NVIDIA TensorRT GitHub issues (NVIDIA/TensorRT) -- **Key version information to verify**: - - TensorRT: 10.3 (JetPack 6.2) - - ONNX Runtime: 1.20.1+ (Jetson builds) - - JetPack: 6.2 - - CUDA: 12.6 diff --git a/_docs/00_research/trt_engine_migration/01_source_registry.md b/_docs/00_research/trt_engine_migration/01_source_registry.md deleted file mode 100644 index a61dd7d..0000000 --- a/_docs/00_research/trt_engine_migration/01_source_registry.md +++ /dev/null @@ -1,231 +0,0 @@ -# Source Registry - -## Source #1 -- **Title**: ONNX Runtime Issue #24085: CUDA EP on Jetson Orin Nano does not use tensor cores -- **Link**: https://github.com/microsoft/onnxruntime/issues/24085 -- **Tier**: L1 (Official GitHub issue with MSFT response) -- **Publication Date**: 2025-03-18 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: ONNX Runtime v1.20.1+, JetPack 6.1, CUDA 12.6 -- **Target Audience**: Jetson Orin Nano developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: ONNX Runtime CUDA EP on Jetson Orin Nano is 7-8x slower than TRT standalone due to tensor cores not being utilized. Workaround: remove cudnn_conv_algo_search option and use FP16 models. -- **Related Sub-question**: Q1 (performance difference) - -## Source #2 -- **Title**: ONNX Runtime Issue #20457: VRAM usage difference between TRT-EP and native TRT -- **Link**: https://github.com/microsoft/onnxruntime/issues/20457 -- **Tier**: L1 (Official GitHub issue with MSFT dev response) -- **Publication Date**: 2024-04-25 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: ONNX Runtime 1.17.1, CUDA 12.2 -- **Target Audience**: All ONNX Runtime + TRT users -- **Research Boundary Match**: ✅ Full match -- **Summary**: ONNX Runtime TRT-EP keeps serialized engine in memory (~420-440MB) during execution. Native TRT drops to 130-140MB after engine build by calling releaseBlob(). Delta: ~280-300MB. -- **Related Sub-question**: Q2 (memory overhead) - -## Source #3 -- **Title**: ONNX Runtime Issue #12083: TensorRT Provider vs TensorRT Native -- **Link**: https://github.com/microsoft/onnxruntime/issues/12083 -- **Tier**: L2 (Official MSFT dev response) -- **Publication Date**: 2022-07-05 (confirmed still relevant) -- **Timeliness Status**: ⚠️ Needs verification (old but fundamental architecture hasn't changed) -- **Version Info**: General ONNX Runtime -- **Target Audience**: All ONNX Runtime users -- **Research Boundary Match**: ✅ Full match -- **Summary**: MSFT engineer confirms TRT-EP "can achieve performance parity with native TensorRT." Benefit is automatic fallback for unsupported ops. -- **Related Sub-question**: Q1 (performance difference) - -## Source #4 -- **Title**: ONNX Runtime Issue #11356: Lower performance on InceptionV3/4 with TRT EP -- **Link**: https://github.com/microsoft/onnxruntime/issues/11356 -- **Tier**: L4 (Community report) -- **Publication Date**: 2022 -- **Timeliness Status**: ⚠️ Needs verification -- **Version Info**: ONNX Runtime older version -- **Target Audience**: ONNX Runtime users -- **Research Boundary Match**: ⚠️ Partial (different model, but same mechanism) -- **Summary**: Reports ~3x performance difference (41 vs 129 inferences/sec) between ONNX RT TRT-EP and native TRT on InceptionV3/4. -- **Related Sub-question**: Q1 (performance difference) - -## Source #5 -- **Title**: NVIDIA JetPack 6.2 Release Notes -- **Link**: https://docs.nvidia.com/jetson/archives/jetpack-archived/jetpack-62/release-notes/index.html -- **Tier**: L1 (Official NVIDIA documentation) -- **Publication Date**: 2025-01 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: JetPack 6.2, TensorRT 10.3, CUDA 12.6, cuDNN 9.3 -- **Target Audience**: Jetson developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: JetPack 6.2 includes TensorRT 10.3, enables Super Mode for Orin Nano (67 TOPS, 1020 MHz GPU, 25W). -- **Related Sub-question**: Q3 (conversion paths) - -## Source #6 -- **Title**: NVIDIA Jetson Orin Nano Super Developer Kit Blog -- **Link**: https://developer.nvidia.com/blog/nvidia-jetson-orin-nano-developer-kit-gets-a-super-boost/ -- **Tier**: L2 (Official NVIDIA blog) -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: Orin Nano Super, 67 TOPS sparse INT8 -- **Target Audience**: Jetson developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Super mode: GPU 1020 MHz (vs 635), 67 TOPS sparse (vs 40), memory bandwidth 102 GB/s (vs 68), power 25W. No DLA cores on Orin Nano. -- **Related Sub-question**: Q6 (DLA availability) - -## Source #7 -- **Title**: Jetson Orin module comparison (Connect Tech) -- **Link**: https://connecttech.com/jetson/jetson-module-comparison -- **Tier**: L3 (Authoritative hardware vendor) -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Jetson hardware buyers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Confirms Orin Nano has NO DLA cores. Orin NX has 1-2 DLA. AGX Orin has 2 DLA. -- **Related Sub-question**: Q6 (DLA availability) - -## Source #8 -- **Title**: TensorRT Engine hardware specificity (NVIDIA/TensorRT Issue #1920) -- **Link**: https://github.com/NVIDIA/TensorRT/issues/1920 -- **Tier**: L1 (Official NVIDIA TensorRT repo) -- **Publication Date**: 2022 (confirmed still valid for TRT 10) -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: All TensorRT versions -- **Target Audience**: TensorRT developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: TRT engines are tied to specific GPU models. Must build on target hardware. Cannot cross-compile x86→aarch64. -- **Related Sub-question**: Q4 (deployment workflow) - -## Source #9 -- **Title**: trtexec ONNX to TRT conversion on Jetson Orin Nano (StackOverflow) -- **Link**: https://stackoverflow.com/questions/78787534/converting-a-pytorch-onnx-model-to-tensorrt-engine-jetson-orin-nano -- **Tier**: L4 (Community) -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Jetson developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Standard workflow: trtexec --onnx=model.onnx --saveEngine=model.trt --fp16. Use --memPoolSize instead of deprecated --workspace. -- **Related Sub-question**: Q3, Q5 (conversion workflow) - -## Source #10 -- **Title**: TensorRT 10 Python API Documentation -- **Link**: https://docs.nvidia.com/deeplearning/tensorrt/10.15.1/inference-library/python-api-docs.html -- **Tier**: L1 (Official NVIDIA docs) -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: TensorRT 10.x -- **Target Audience**: TensorRT Python developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: TRT 10 uses tensor-based API (not binding indices). load engine via runtime.deserialize_cuda_engine(). Async inference via context.enqueue_v3(stream_handle). -- **Related Sub-question**: Q3 (conversion paths) - -## Source #11 -- **Title**: Torch-TensorRT JetPack documentation -- **Link**: https://docs.pytorch.org/TensorRT/v2.10.0/getting_started/jetpack.html -- **Tier**: L1 (Official documentation) -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: Torch-TensorRT, JetPack 6.2, PyTorch 2.8.0 -- **Target Audience**: PyTorch developers on Jetson -- **Research Boundary Match**: ✅ Full match -- **Summary**: Torch-TensorRT supports Jetson aarch64 with JetPack 6.2. Supports AOT compilation, FP16/INT8, dynamic shapes. -- **Related Sub-question**: Q3 (conversion paths) - -## Source #12 -- **Title**: XFeatTensorRT GitHub repo -- **Link**: https://github.com/PranavNedunghat/XFeatTensorRT -- **Tier**: L4 (Community) -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: XFeat users on NVIDIA GPUs -- **Research Boundary Match**: ✅ Full match -- **Summary**: C++ TRT implementation of XFeat feature extraction. Already converts XFeat to TRT engine. -- **Related Sub-question**: Q5 (XFeat conversion) - -## Source #13 -- **Title**: TensorRT Best Practices (Official NVIDIA) -- **Link**: https://docs.nvidia.com/deeplearning/tensorrt/latest/performance/best-practices.html -- **Tier**: L1 (Official NVIDIA docs) -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Version Info**: TensorRT 10.x -- **Target Audience**: TensorRT developers -- **Research Boundary Match**: ✅ Full match -- **Summary**: Comprehensive guide: use trtexec for benchmarking, --fp16 for FP16, use ModelOptimizer for INT8, use polygraphy for model inspection. -- **Related Sub-question**: Q3 (conversion workflow) - -## Source #14 -- **Title**: NVIDIA blog: Maximizing DL Performance on Jetson Orin with DLA -- **Link**: https://developer.nvidia.com/blog/maximizing-deep-learning-performance-on-nvidia-jetson-orin-with-dla/ -- **Tier**: L2 (Official NVIDIA blog) -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Jetson Orin developers (NX and AGX) -- **Research Boundary Match**: ⚠️ Partial (DLA not available on Orin Nano) -- **Summary**: DLA contributes 38-74% of total DL performance on Orin (NX/AGX). Supports CNN layers in FP16/INT8. NOT available on Orin Nano. -- **Related Sub-question**: Q6 (DLA availability) - -## Source #15 -- **Title**: PUT Vision Lab: TensorRT vs ONNXRuntime comparison on Jetson -- **Link**: https://putvision.github.io/article/2021/12/20/jetson-onnxruntime-tensorrt.html -- **Tier**: L3 (Academic lab blog) -- **Publication Date**: 2021 (foundational comparison, architecture unchanged) -- **Timeliness Status**: ⚠️ Needs verification (older, but core findings still apply) -- **Target Audience**: Jetson developers -- **Research Boundary Match**: ⚠️ Partial (older Jetson, but same TRT vs ONNX RT question) -- **Summary**: Native TRT generally faster. ONNX RT TRT-EP adds wrapper overhead. Both use same TRT kernels internally. -- **Related Sub-question**: Q1 (performance difference) - -## Source #16 -- **Title**: LiteSAM paper — MinGRU details (Eqs 12-16, Section 3.4.2) -- **Link**: https://www.mdpi.com/2072-4292/17/19/3349 -- **Tier**: L1 (Peer-reviewed paper) -- **Publication Date**: 2025 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Satellite-aerial matching researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: MinGRU subpixel refinement uses 4 stacked layers, 3×3 window (9 candidates). Gates depend only on input C_f. Ops: Linear, Sigmoid, Mul, Add, ReLU, Tanh. -- **Related Sub-question**: Q5 (LiteSAM TRT compatibility) - -## Source #17 -- **Title**: Coarse_LoFTR_TRT paper — LoFTR TRT adaptation for embedded devices -- **Link**: https://ar5iv.labs.arxiv.org/html/2202.00770 -- **Tier**: L2 (arXiv paper with working open-source code) -- **Publication Date**: 2022 -- **Timeliness Status**: ✅ Currently valid (TRT adaptation techniques still apply) -- **Target Audience**: Feature matching on embedded devices -- **Research Boundary Match**: ✅ Full match -- **Summary**: Documents specific code changes for TRT compatibility: einsum→elementary ops, ONNX export, knowledge distillation. Tested on Jetson Nano 2GB. 2.26M params reduced from 27.95M. -- **Related Sub-question**: Q5 (EfficientLoFTR as TRT-proven alternative) - -## Source #18 -- **Title**: minGRU paper — "Were RNNs All We Needed?" -- **Link**: https://huggingface.co/papers/2410.01201 -- **Tier**: L1 (Research paper) -- **Publication Date**: 2024-10 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: RNN/sequence model researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: MinGRU removes gate dependency on h_{t-1}, enabling parallel computation. Parallel implementation uses logcumsumexp for numerical stability. 175x faster than sequential for seq_len=512. -- **Related Sub-question**: Q5 (MinGRU TRT compatibility) - -## Source #19 -- **Title**: SAM2 TRT performance degradation issue -- **Link**: https://github.com/facebookresearch/sam2/issues/639 -- **Tier**: L4 (GitHub issue) -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: SAM/transformer TRT deployers -- **Research Boundary Match**: ⚠️ Partial (different model, but relevant for transformer attention TRT risks) -- **Summary**: SAM2 MemoryAttention 30ms PyTorch → 100ms TRT FP16. RoPEAttention bottleneck. Warning for transformer TRT conversion. -- **Related Sub-question**: Q7 (TRT conversion risks) - -## Source #20 -- **Title**: EfficientLoFTR (CVPR 2024) -- **Link**: https://github.com/zju3dv/EfficientLoFTR -- **Tier**: L1 (CVPR paper + open-source code) -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Feature matching researchers -- **Research Boundary Match**: ✅ Full match -- **Summary**: 2.5x faster than LoFTR, higher accuracy. 15.05M params. Semi-dense matching. Available on HuggingFace under Apache 2.0. 964 GitHub stars. -- **Related Sub-question**: Q5 (alternative satellite matcher) diff --git a/_docs/00_research/trt_engine_migration/02_fact_cards.md b/_docs/00_research/trt_engine_migration/02_fact_cards.md deleted file mode 100644 index a7e6648..0000000 --- a/_docs/00_research/trt_engine_migration/02_fact_cards.md +++ /dev/null @@ -1,193 +0,0 @@ -# Fact Cards - -## Fact #1 -- **Statement**: ONNX Runtime CUDA Execution Provider on Jetson Orin Nano (JetPack 6.1) is 7-8x slower than TensorRT standalone due to tensor cores not being utilized with default settings. -- **Source**: Source #1 (https://github.com/microsoft/onnxruntime/issues/24085) -- **Phase**: Assessment -- **Target Audience**: Jetson Orin Nano developers using ONNX Runtime -- **Confidence**: ✅ High (confirmed by issue author with NSight profiling, MSFT acknowledged) -- **Related Dimension**: Performance - -## Fact #2 -- **Statement**: The workaround for Fact #1 is to remove the `cudnn_conv_algo_search` option (which defaults to EXHAUSTIVE) and use FP16 models. This restores tensor core usage. -- **Source**: Source #1 -- **Phase**: Assessment -- **Target Audience**: Jetson Orin Nano developers -- **Confidence**: ✅ High (confirmed fix by issue author) -- **Related Dimension**: Performance - -## Fact #3 -- **Statement**: ONNX Runtime TRT-EP keeps serialized TRT engine in memory (~420-440MB) throughout execution. Native TRT via trtexec drops to 130-140MB after engine deserialization by calling releaseBlob(). -- **Source**: Source #2 (https://github.com/microsoft/onnxruntime/issues/20457) -- **Phase**: Assessment -- **Target Audience**: All ONNX RT TRT-EP users, especially memory-constrained devices -- **Confidence**: ✅ High (confirmed by MSFT developer @chilo-ms with detailed explanation) -- **Related Dimension**: Memory consumption - -## Fact #4 -- **Statement**: The ~280-300MB extra memory from ONNX RT TRT-EP (Fact #3) is because the serialized engine is retained across compute function calls for dynamic shape models. Native TRT releases it after deserialization. -- **Source**: Source #2 -- **Phase**: Assessment -- **Target Audience**: Memory-constrained Jetson deployments -- **Confidence**: ✅ High (MSFT developer explanation) -- **Related Dimension**: Memory consumption - -## Fact #5 -- **Statement**: MSFT engineer states "TensorRT EP can achieve performance parity with native TensorRT" — both use the same TRT kernels internally. Benefit of TRT-EP is automatic fallback for unsupported ops. -- **Source**: Source #3 (https://github.com/microsoft/onnxruntime/issues/12083) -- **Phase**: Assessment -- **Target Audience**: General -- **Confidence**: ⚠️ Medium (official statement but contradicted by real benchmarks in some cases) -- **Related Dimension**: Performance - -## Fact #6 -- **Statement**: Real benchmark of InceptionV3/4 showed ONNX RT TRT-EP achieving ~41 inferences/sec vs native TRT at ~129 inferences/sec — approximately 3x performance gap. -- **Source**: Source #4 (https://github.com/microsoft/onnxruntime/issues/11356) -- **Phase**: Assessment -- **Target Audience**: CNN model deployers -- **Confidence**: ⚠️ Medium (community report, older ONNX RT version, model-specific) -- **Related Dimension**: Performance - -## Fact #7 -- **Statement**: Jetson Orin Nano Super specs: 67 TOPS sparse INT8 / 33 TOPS dense, GPU at 1020 MHz, 8GB LPDDR5 shared, 102 GB/s bandwidth, 25W TDP. NO DLA cores. -- **Source**: Source #6, Source #7 -- **Phase**: Assessment -- **Target Audience**: Our project -- **Confidence**: ✅ High (official NVIDIA specs) -- **Related Dimension**: Hardware constraints - -## Fact #8 -- **Statement**: Jetson Orin Nano has ZERO DLA (Deep Learning Accelerator) cores. DLA is only available on Orin NX (1-2 cores) and AGX Orin (2 cores). -- **Source**: Source #7, Source #14 -- **Phase**: Assessment -- **Target Audience**: Our project -- **Confidence**: ✅ High (official hardware specifications) -- **Related Dimension**: Hardware constraints - -## Fact #9 -- **Statement**: TensorRT engines are tied to specific GPU models, not just architectures. Must be built on the target device. Cannot cross-compile from x86 to aarch64. -- **Source**: Source #8 (https://github.com/NVIDIA/TensorRT/issues/1920) -- **Phase**: Assessment -- **Target Audience**: TRT deployers -- **Confidence**: ✅ High (NVIDIA confirmed) -- **Related Dimension**: Deployment workflow - -## Fact #10 -- **Statement**: Standard conversion workflow: PyTorch → ONNX (torch.onnx.export) → trtexec --onnx=model.onnx --saveEngine=model.engine --fp16. Use --memPoolSize instead of deprecated --workspace flag. -- **Source**: Source #9, Source #13 -- **Phase**: Assessment -- **Target Audience**: Model deployers on Jetson -- **Confidence**: ✅ High (official NVIDIA workflow) -- **Related Dimension**: Deployment workflow - -## Fact #11 -- **Statement**: TensorRT 10.x Python API: load engine via runtime.deserialize_cuda_engine(data). Async inference via context.enqueue_v3(stream_handle). Uses tensor-name-based API (not binding indices). -- **Source**: Source #10 -- **Phase**: Assessment -- **Target Audience**: Python TRT developers -- **Confidence**: ✅ High (official NVIDIA docs) -- **Related Dimension**: API/integration - -## Fact #12 -- **Statement**: Torch-TensorRT supports Jetson aarch64 with JetPack 6.2. Supports ahead-of-time (AOT) compilation, FP16/INT8, dynamic and static shapes. Alternative path to ONNX→trtexec. -- **Source**: Source #11 -- **Phase**: Assessment -- **Target Audience**: PyTorch developers on Jetson -- **Confidence**: ✅ High (official documentation) -- **Related Dimension**: Deployment workflow - -## Fact #13 -- **Statement**: XFeatTensorRT repo exists — C++ TensorRT implementation of XFeat feature extraction. Confirms XFeat is TRT-convertible. -- **Source**: Source #12 -- **Phase**: Assessment -- **Target Audience**: Our project (XFeat users) -- **Confidence**: ✅ High (working open-source implementation) -- **Related Dimension**: Model-specific conversion - -## Fact #14 -- **Statement**: cuVSLAM is a closed-source NVIDIA CUDA library (PyCuVSLAM). It is NOT an ONNX or PyTorch model. It cannot and does not need to be converted to TRT — it's already native CUDA-optimized for Jetson. -- **Source**: cuVSLAM documentation (https://github.com/NVlabs/PyCuVSLAM) -- **Phase**: Assessment -- **Target Audience**: Our project -- **Confidence**: ✅ High (verified from PyCuVSLAM docs) -- **Related Dimension**: Model applicability - -## Fact #15 -- **Statement**: JetPack 6.2 ships with TensorRT 10.3, CUDA 12.6, cuDNN 9.3. The tensorrt Python module is pre-installed and accessible on Jetson. -- **Source**: Source #5 -- **Phase**: Assessment -- **Target Audience**: Jetson developers -- **Confidence**: ✅ High (official release notes) -- **Related Dimension**: Software stack - -## Fact #16 -- **Statement**: TRT engine build on Jetson Orin Nano Super (8GB) can cause OOM for large models during the build phase, even if inference fits in memory. Workaround: build on a more powerful machine with same GPU architecture, or use Torch-TensorRT PyTorch workflow. -- **Source**: Source #5 (https://github.com/NVIDIA/TensorRT-LLM/issues/3149) -- **Phase**: Assessment -- **Target Audience**: Jetson Orin Nano developers building large TRT engines -- **Confidence**: ✅ High (confirmed in NVIDIA TRT-LLM issue) -- **Related Dimension**: Deployment workflow - -## Fact #17 -- **Statement**: LiteSAM uses MobileOne backbone which is reparameterizable — multi-branch training structure collapses to a single feed-forward path. This is critical for TRT optimization: fewer layers, better fusion, faster inference. -- **Source**: Solution draft03, LiteSAM paper -- **Phase**: Assessment -- **Target Audience**: Our project -- **Confidence**: ✅ High (published paper) -- **Related Dimension**: Model-specific conversion - -## Fact #18 -- **Statement**: INT8 quantization is safe for CNN layers (MobileOne backbone) but NOT for transformer components (TAIFormer in LiteSAM). FP16 is safe for both CNN and transformer layers. -- **Source**: Solution draft02/03 analysis -- **Phase**: Assessment -- **Target Audience**: Our project -- **Confidence**: ⚠️ Medium (general best practice, not verified on LiteSAM specifically) -- **Related Dimension**: Quantization strategy - -## Fact #19 -- **Statement**: On 8GB shared memory Jetson: OS+runtime ~1.5GB, cuVSLAM ~200-500MB, tiles ~200MB. Remaining budget: ~5.8-6.1GB. ONNX RT TRT-EP overhead of ~280-300MB per model is significant. Native TRT saves this memory. -- **Source**: Solution draft03 memory budget + Source #2 -- **Phase**: Assessment -- **Target Audience**: Our project -- **Confidence**: ✅ High (computed from verified facts) -- **Related Dimension**: Memory consumption - -## Fact #20 -- **Statement**: LiteSAM's MinGRU subpixel refinement (Eqs 12-16) uses: z_t = σ(Linear(C_f)), h̃_t = Linear(C_f), h_t = (1-z_t)⊙h_{t-1} + z_t⊙h̃_t. Gates depend ONLY on input C_f (not h_{t-1}). Operates on 3×3 window (9 candidates), 4 stacked layers. All ops are standard: Linear, Sigmoid, Mul, Add, ReLU, Tanh. -- **Source**: LiteSAM paper (MDPI Remote Sensing, 2025, Eqs 12-16, Section 3.4.2) -- **Phase**: Assessment -- **Target Audience**: Our project -- **Confidence**: ✅ High (from the published paper) -- **Related Dimension**: LiteSAM TRT compatibility - -## Fact #21 -- **Statement**: MinGRU's parallel implementation can use logcumsumexp (log-space parallel scan), which is NOT a standard ONNX operator. However, for seq_len=9 (LiteSAM's 3×3 window), a simple unrolled loop is equivalent and uses only standard ops. -- **Source**: minGRU paper + lucidrains/minGRU-pytorch implementation -- **Phase**: Assessment -- **Target Audience**: Our project -- **Confidence**: ⚠️ Medium (logcumsumexp risk depends on implementation; seq_len=9 makes rewrite trivial) -- **Related Dimension**: LiteSAM TRT compatibility - -## Fact #22 -- **Statement**: EfficientLoFTR has a proven TRT conversion path via Coarse_LoFTR_TRT (138 stars). The paper documents specific code changes needed: replace einsum with elementary ops (view, bmm, reshape, sum), adapt for TRT-compatible functions. Tested on Jetson Nano 2GB (~5 FPS with distilled model). -- **Source**: Coarse_LoFTR_TRT paper (arXiv:2202.00770) + GitHub repo -- **Phase**: Assessment -- **Target Audience**: Our project -- **Confidence**: ✅ High (published paper + working open-source implementation) -- **Related Dimension**: Fallback satellite matcher - -## Fact #23 -- **Statement**: EfficientLoFTR has 15.05M params (2.4x more than LiteSAM's 6.31M). On AGX Orin with PyTorch: ~620ms (LiteSAM is 19.8% faster). Semi-dense matching. CVPR 2024. Available on HuggingFace under Apache 2.0. -- **Source**: LiteSAM paper comparison + EfficientLoFTR docs -- **Phase**: Assessment -- **Target Audience**: Our project -- **Confidence**: ✅ High (published benchmarks) -- **Related Dimension**: Fallback satellite matcher - -## Fact #24 -- **Statement**: SAM2's MemoryAttention showed performance DEGRADATION with TRT: 30ms PyTorch → 100ms TRT FP16. RoPEAttention identified as bottleneck. This warns that transformer attention modules may not always benefit from TRT conversion. -- **Source**: https://github.com/facebookresearch/sam2/issues/639 -- **Phase**: Assessment -- **Target Audience**: Transformer model deployers -- **Confidence**: ⚠️ Medium (different model, but relevant warning for attention layers) -- **Related Dimension**: TRT conversion risks diff --git a/_docs/00_research/trt_engine_migration/03_comparison_framework.md b/_docs/00_research/trt_engine_migration/03_comparison_framework.md deleted file mode 100644 index f5aa368..0000000 --- a/_docs/00_research/trt_engine_migration/03_comparison_framework.md +++ /dev/null @@ -1,38 +0,0 @@ -# Comparison Framework - -## Selected Framework Type -Decision Support - -## Selected Dimensions -1. Inference latency -2. Memory consumption -3. Deployment workflow complexity -4. Operator coverage / fallback -5. API / integration effort -6. Hardware utilization (tensor cores) -7. Maintenance / ecosystem -8. Cross-platform portability - -## Comparison: Native TRT Engine vs ONNX Runtime (TRT-EP and CUDA EP) - -| Dimension | Native TRT Engine | ONNX Runtime TRT-EP | ONNX Runtime CUDA EP | Factual Basis | -|-----------|-------------------|---------------------|----------------------|---------------| -| Inference latency | Optimal — uses TRT kernels directly, hardware-tuned | Near-parity with native TRT (same kernels), but up to 3x slower on some models due to wrapper overhead | 7-8x slower on Orin Nano with default settings (tensor core issue) | Fact #1, #5, #6 | -| Memory consumption | ~130-140MB after engine load (releases serialized blob) | ~420-440MB during execution (keeps serialized engine) | Standard CUDA memory + framework overhead | Fact #3, #4 | -| Memory delta per model | Baseline | +280-300MB vs native TRT | Higher than TRT-EP | Fact #3, #19 | -| Deployment workflow | PyTorch → ONNX → trtexec → .engine (must build ON target device) | PyTorch → ONNX → pass to ONNX Runtime session (auto-builds TRT engine) | PyTorch → ONNX → pass to ONNX Runtime session | Fact #9, #10 | -| Operator coverage | Only TRT-supported ops. Unsupported ops = build failure | Auto-fallback to CUDA/CPU for unsupported ops | All ONNX ops supported via CUDA/cuDNN | Fact #5 | -| API complexity | Lower-level: manual buffer allocation, CUDA streams, tensor management | Higher-level: InferenceSession, automatic I/O | Highest-level: same ONNX Runtime API | Fact #11 | -| Hardware utilization | Full: tensor cores, layer fusion, kernel auto-tuning, mixed precision | Full TRT kernels for supported ops, CUDA fallback for rest | Broken on Orin Nano with default settings (no tensor cores) | Fact #1, #2 | -| Maintenance | Engine must be rebuilt per TRT version and per GPU model | ONNX model is portable, engine rebuilt automatically | ONNX model is portable | Fact #9 | -| Cross-platform | NVIDIA-only, hardware-specific engine files | Multi-platform ONNX model, TRT-EP only on NVIDIA | Multi-platform (NVIDIA, AMD, Intel, CPU) | Fact #9 | -| Relevance to our project | ✅ Best — we deploy only on Jetson Orin Nano Super | ❌ Cross-platform benefit wasted — we're NVIDIA-only | ❌ Performance issue on our target hardware | Fact #7, #8 | - -## Per-Model Applicability - -| Model | Can Convert to TRT? | Recommended Path | Notes | -|-------|---------------------|------------------|-------| -| cuVSLAM | NO | N/A — already CUDA native | Closed-source NVIDIA library, already optimized | -| LiteSAM | YES | PyTorch → reparameterize MobileOne → ONNX → trtexec --fp16 | INT8 safe for MobileOne backbone only, NOT TAIFormer | -| XFeat | YES | PyTorch → ONNX → trtexec --fp16 (or use XFeatTensorRT C++) | XFeatTensorRT repo already exists | -| ESKF | N/A | N/A — mathematical filter, not a neural network | Python/C++ NumPy | diff --git a/_docs/00_research/trt_engine_migration/04_reasoning_chain.md b/_docs/00_research/trt_engine_migration/04_reasoning_chain.md deleted file mode 100644 index 64e0026..0000000 --- a/_docs/00_research/trt_engine_migration/04_reasoning_chain.md +++ /dev/null @@ -1,124 +0,0 @@ -# Reasoning Chain - -## Dimension 1: Inference Latency - -### Fact Confirmation -ONNX Runtime CUDA EP on Jetson Orin Nano is 7-8x slower than TRT standalone with default settings (Fact #1). Even with the workaround (Fact #2), ONNX RT adds wrapper overhead. ONNX RT TRT-EP claims "performance parity" (Fact #5), but real benchmarks show up to 3x gaps on specific models (Fact #6). - -### Reference Comparison -Native TRT uses kernel auto-tuning, layer fusion, and mixed-precision natively — no framework wrapper. Our models (LiteSAM, XFeat) are CNN+transformer architectures where TRT's fusion optimizations are most impactful. LiteSAM's reparameterized MobileOne backbone (Fact #17) is particularly well-suited for TRT fusion. - -### Conclusion -Native TRT Engine provides the lowest possible inference latency on Jetson Orin Nano Super. ONNX Runtime adds measurable overhead, ranging from negligible to 3x depending on model architecture and configuration. For our latency-critical pipeline (400ms total budget, satellite matching target ≤200ms), every millisecond matters. - -### Confidence -✅ High — supported by multiple sources, confirmed NVIDIA optimization pipeline. - ---- - -## Dimension 2: Memory Consumption - -### Fact Confirmation -ONNX RT TRT-EP keeps ~420-440MB during execution vs native TRT at ~130-140MB (Fact #3). This is ~280-300MB extra PER MODEL. On our 8GB shared memory Jetson, OS+runtime takes ~1.5GB, cuVSLAM ~200-500MB, tiles ~200MB (Fact #19). - -### Reference Comparison -If we run both LiteSAM and XFeat via ONNX RT TRT-EP: ~560-600MB extra memory overhead. Via native TRT: this overhead drops to near zero. - -With native TRT: -- LiteSAM engine: ~50-80MB -- XFeat engine: ~30-50MB -With ONNX RT TRT-EP: -- LiteSAM: ~50-80MB + ~280MB overhead = ~330-360MB -- XFeat: ~30-50MB + ~280MB overhead = ~310-330MB - -### Conclusion -Native TRT saves ~280-300MB per model vs ONNX RT TRT-EP. On our 8GB shared memory device, this is 3.5-3.75% of total memory PER MODEL. With two models, that's ~7% of total memory saved — meaningful when memory pressure from cuVSLAM map growth is a known risk. - -### Confidence -✅ High — confirmed by MSFT developer with detailed explanation of mechanism. - ---- - -## Dimension 3: Deployment Workflow - -### Fact Confirmation -Native TRT requires: PyTorch → ONNX → trtexec → .engine file. Engine must be built ON the target Jetson device (Fact #9). Engine is tied to specific GPU model and TRT version. TRT engine build on 8GB Jetson can OOM for large models (Fact #16). - -### Reference Comparison -ONNX Runtime auto-builds TRT engine from ONNX at first run (or caches). Simpler developer experience but first-run latency spike. Torch-TensorRT (Fact #12) offers AOT compilation as middle ground. - -Our models are small (LiteSAM 6.31M params, XFeat even smaller). Engine build OOM is unlikely for our model sizes. Build once before flight, ship .engine files. - -### Conclusion -Native TRT requires an explicit offline build step (trtexec on Jetson), but this is a one-time cost per model version. For our use case (pre-flight preparation already includes satellite tile download), adding a TRT engine build to the preparation workflow is trivial. The deployment complexity is acceptable. - -### Confidence -✅ High — well-documented workflow, our model sizes are small enough. - ---- - -## Dimension 4: Operator Coverage / Fallback - -### Fact Confirmation -Native TRT fails if a model contains unsupported operators. ONNX RT TRT-EP auto-falls back to CUDA/CPU for unsupported ops (Fact #5). This is TRT-EP's primary value proposition. - -### Reference Comparison -LiteSAM (MobileOne + TAIFormer + MinGRU) and XFeat use standard operations: Conv2d, attention, GRU, ReLU, etc. These are all well-supported by TensorRT 10.3. MobileOne's reparameterized form is pure Conv2d+BN — trivially supported. TAIFormer attention uses standard softmax/matmul — supported in TRT 10. MinGRU is a simplified GRU — may need verification. - -Risk: If any op in LiteSAM is unsupported by TRT, the entire export fails. Mitigation: verify with polygraphy before deployment. If an op fails, refactor or use Torch-TensorRT which can handle mixed TRT/PyTorch execution. - -### Conclusion -For our specific models, operator coverage risk is LOW. Standard CNN+transformer ops are well-supported in TRT 10.3. ONNX RT's fallback benefit is insurance we're unlikely to need. MinGRU in LiteSAM should be verified, but standard GRU ops are TRT-supported. - -### Confidence -⚠️ Medium — high confidence for MobileOne+TAIFormer, medium for MinGRU (needs verification on TRT 10.3). - ---- - -## Dimension 5: API / Integration Effort - -### Fact Confirmation -Native TRT Python API (Fact #11): manual buffer allocation with PyCUDA, CUDA stream management, tensor setup via engine.get_tensor_name(). ONNX Runtime: simple InferenceSession with .run(). - -### Reference Comparison -TRT Python API requires ~30-50 lines of boilerplate per model (engine load, buffer allocation, inference loop). ONNX Runtime requires ~5-10 lines. However, this is write-once code, encapsulated in a wrapper class. - -Our pipeline already uses CUDA streams for cuVSLAM pipelining (Stream A for VO, Stream B for satellite matching). Adding TRT inference to Stream B is natural — just pass stream_handle to context.enqueue_v3(). - -### Conclusion -Slightly more code with native TRT, but it's boilerplate that gets written once and wrapped. The CUDA stream integration actually BENEFITS from native TRT — direct stream control enables better pipelining with cuVSLAM. - -### Confidence -✅ High — well-documented API, straightforward integration. - ---- - -## Dimension 6: Hardware Utilization - -### Fact Confirmation -ONNX RT CUDA EP does NOT use tensor cores on Jetson Orin Nano by default (Fact #1). Native TRT uses tensor cores, layer fusion, kernel auto-tuning automatically. Jetson Orin Nano Super has 16 tensor cores at 1020 MHz (Fact #7). No DLA available (Fact #8). - -### Reference Comparison -Since there's no DLA to offload to, GPU is our only accelerator. Maximizing GPU utilization is critical. Native TRT squeezes every ounce from the 16 tensor cores. ONNX RT has a known bug preventing this on our exact hardware. - -### Conclusion -Native TRT is the only way to guarantee full hardware utilization on Jetson Orin Nano Super. ONNX RT's tensor core issue (even if workaround exists) introduces fragility. Since we have no DLA, wasting GPU tensor cores is unacceptable. - -### Confidence -✅ High — hardware limitation is confirmed, no alternative accelerator. - ---- - -## Dimension 7: Cross-Platform Portability - -### Fact Confirmation -ONNX Runtime runs on NVIDIA, AMD, Intel, CPU. TRT engines are NVIDIA-specific and even GPU-model-specific (Fact #9). - -### Reference Comparison -Our system deploys ONLY on Jetson Orin Nano Super. The companion computer is fixed hardware. There is no requirement or plan to run on non-NVIDIA hardware. Cross-platform portability has zero value for this project. - -### Conclusion -ONNX Runtime's primary value proposition (portability) is irrelevant for our deployment. We trade unused portability for maximum performance and minimum memory usage. - -### Confidence -✅ High — deployment target is fixed hardware. diff --git a/_docs/00_research/trt_engine_migration/05_validation_log.md b/_docs/00_research/trt_engine_migration/05_validation_log.md deleted file mode 100644 index c09cdce..0000000 --- a/_docs/00_research/trt_engine_migration/05_validation_log.md +++ /dev/null @@ -1,65 +0,0 @@ -# Validation Log - -## Validation Scenario -Full GPS-Denied pipeline running on Jetson Orin Nano Super (8GB) during a 50km flight with ~1500 frames at 3fps. Two AI models active: LiteSAM for satellite matching (keyframes) and XFeat as fallback. cuVSLAM running continuously for VO. - -## Expected Based on Conclusions - -### If using Native TRT Engine: -- LiteSAM TRT FP16 engine loaded: ~50-80MB GPU memory after deserialization -- XFeat TRT FP16 engine loaded: ~30-50MB GPU memory after deserialization -- Total AI model memory: ~80-130MB -- Inference runs on CUDA Stream B, directly integrated with cuVSLAM Stream A pipelining -- Tensor cores fully utilized at 1020 MHz -- LiteSAM satellite matching at estimated ~165-330ms (TRT FP16 at 1280px) -- XFeat matching at estimated ~50-100ms (TRT FP16) -- Engine files pre-built during offline preparation, stored on Jetson storage alongside satellite tiles - -### If using ONNX Runtime TRT-EP: -- LiteSAM via TRT-EP: ~330-360MB during execution -- XFeat via TRT-EP: ~310-330MB during execution -- Total AI model memory: ~640-690MB -- First inference triggers engine build (latency spike at startup) -- CUDA stream management less direct -- Same inference speed (in theory, per MSFT claim) - -### Memory budget comparison (total 8GB): -- Native TRT: OS 1.5GB + cuVSLAM 0.5GB + tiles 0.2GB + models 0.13GB + misc 0.1GB = ~2.43GB (30% used) -- ONNX RT TRT-EP: OS 1.5GB + cuVSLAM 0.5GB + tiles 0.2GB + models 0.69GB + ONNX RT overhead 0.15GB + misc 0.1GB = ~3.14GB (39% used) -- Delta: ~710MB (9% of total memory) - -## Actual Validation Results -The memory savings from native TRT are confirmed by the mechanism explanation from MSFT (Source #2). The 710MB delta is significant given cuVSLAM map growth risk (up to 1GB on long flights without aggressive pruning). - -The workflow integration is validated: engine files can be pre-built as part of the existing offline tile preparation pipeline. No additional hardware or tools needed — trtexec is included in JetPack 6.2. - -## Counterexamples - -### Counterexample 1: MinGRU operator may not be supported in TRT -MinGRU is a simplified GRU variant used in LiteSAM's subpixel refinement. Standard GRU is supported in TRT 10.3, but MinGRU may use custom operations. If MinGRU fails TRT export, options: -1. Replace MinGRU with standard GRU (small accuracy loss) -2. Split model: CNN+TAIFormer in TRT, MinGRU refinement in PyTorch -3. Use Torch-TensorRT which handles mixed execution - -**Assessment**: Low risk. MinGRU is a simplification of GRU, likely uses subset of GRU ops. - -### Counterexample 2: Engine rebuild needed per TRT version update -JetPack updates may change TRT version, invalidating cached engines. Must rebuild all engines after JetPack update. - -**Assessment**: Acceptable. JetPack updates are infrequent on deployed UAVs. Engine rebuild takes minutes. - -### Counterexample 3: Dynamic input shapes -If camera resolution changes between flights, engine with static shapes must be rebuilt. Can use dynamic shapes in trtexec (--minShapes, --optShapes, --maxShapes) but at slight performance cost. - -**Assessment**: Acceptable. Camera resolution is fixed per deployment. Build engine for that resolution. - -## Review Checklist -- [x] Draft conclusions consistent with fact cards -- [x] No important dimensions missed -- [x] No over-extrapolation -- [x] Conclusions actionable/verifiable -- [x] Memory calculations verified against known budget -- [x] Workflow integration validated against existing offline preparation - -## Conclusions Requiring Revision -None — all conclusions hold under validation. diff --git a/_docs/01_solution/security_analysis.md b/_docs/01_solution/security_analysis.md deleted file mode 100644 index fee0fcd..0000000 --- a/_docs/01_solution/security_analysis.md +++ /dev/null @@ -1,346 +0,0 @@ -# Security Analysis - -## Operational Context - -This system runs on a UAV operating in a **conflict zone** (eastern Ukraine). The UAV could be shot down and physically captured. GPS denial/spoofing is the premise. The Jetson Orin Nano stores satellite imagery, flight plans, and captured photos. Security must assume the worst case: **physical access by an adversary**. - -## Threat Model - -### Asset Inventory - -| Asset | Sensitivity | Location | Notes | -|-------|------------|----------|-------| -| Captured camera imagery | HIGH | Jetson storage | Reconnaissance data — reveals what was surveyed | -| Satellite tile cache | MEDIUM | Jetson storage | Reveals operational area and areas of interest | -| Flight plan / route | HIGH | Jetson memory + storage | Reveals mission objectives and launch/landing sites | -| Computed GPS positions | HIGH | Jetson memory, SSE stream | Real-time position data of UAV and surveyed targets | -| Google Maps API key | MEDIUM | Offline prep machine only | Used pre-flight, NOT stored on Jetson | -| TensorRT model weights | LOW | Jetson storage | LiteSAM/XFeat — publicly available models | -| cuVSLAM binary | LOW | Jetson storage | NVIDIA proprietary but freely distributed | -| IMU calibration data | LOW | Jetson storage | Device-specific calibration | -| System configuration | MEDIUM | Jetson storage | API endpoints, tile paths, fusion parameters | - -### Threat Actors - -| Actor | Capability | Motivation | Likelihood | -|-------|-----------|------------|------------| -| **Adversary military (physical capture)** | Full physical access after UAV loss | Extract intelligence: imagery, flight plans, operational area | HIGH | -| **Electronic warfare unit** | GPS spoofing/jamming, RF jamming | Disrupt navigation, force UAV off course | HIGH (GPS denial is the premise) | -| **Network attacker (ground station link)** | Intercept/inject on UAV-to-ground comms | Steal position data, inject false commands | MEDIUM | -| **Insider / rogue operator** | Authorized access to system | Data exfiltration, mission sabotage | LOW | -| **Supply chain attacker** | Tampered satellite tiles or model weights | Feed corrupted reference data → position errors | LOW | - -### Attack Vectors - -| Vector | Target Asset | Actor | Impact | Likelihood | -|--------|-------------|-------|--------|------------| -| **Physical extraction of storage** | All stored data | Adversary (capture) | Full intelligence compromise | HIGH | -| **GPS spoofing** | Position estimate | EW unit | Already mitigated — system is GPS-denied by design | N/A | -| **IMU acoustic injection** | IMU data → ESKF | EW unit | Drift injection, subtle position errors | LOW | -| **Camera blinding/spoofing** | VO + satellite matching | EW unit | VO failure, incorrect satellite matches | LOW | -| **Adversarial ground patterns** | Satellite matching | Adversary | Physical patches on ground fool feature matching | VERY LOW | -| **SSE stream interception** | Position data | Network attacker | Real-time position leak | MEDIUM | -| **API command injection** | Flight session control | Network attacker | Start/stop/manipulate sessions | MEDIUM | -| **Corrupted satellite tiles** | Satellite matching | Supply chain | Systematic position errors | LOW | -| **Model weight tampering** | Matching accuracy | Supply chain | Degraded matching → higher drift | LOW | - -## Per-Component Security Requirements and Controls - -### 1. Data at Rest (Jetson Storage) - -| Requirement | Risk Level | Control | Implementation | -|-------------|-----------|---------|----------------| -| Protect captured imagery from extraction after capture | CRITICAL | Full-disk encryption (LUKS) | JetPack LUKS support with `ENC_ROOTFS=1`. Use OP-TEE Trusted Application for key management. Modify `luks-srv` to NOT auto-decrypt — require hardware token or secure erase trigger | -| Protect satellite tiles and flight plans | HIGH | Same LUKS encryption | Included in full-disk encryption scope | -| Enable rapid secure erase on capture/crash | CRITICAL | Tamper-triggered wipe | Hardware dead-man switch: if UAV telemetry lost for N seconds OR accelerometer detects crash impact → trigger `cryptsetup luksErase` on all LUKS volumes. Destroys key material in <1 second — data becomes unrecoverable | -| Prevent cold-boot key extraction | HIGH | Minimize key residency in RAM | ESKF state and position history cleared from memory when session ends. Avoid writing position logs to disk unless encrypted | - -### 2. Secure Boot - -| Requirement | Risk Level | Control | Implementation | -|-------------|-----------|---------|----------------| -| Prevent unauthorized code execution | HIGH | NVIDIA Secure Boot with PKC fuse burning | Burn `SecurityMode` fuse (odm_production_mode=0x1) on production Jetsons. Sign all boot images with PKC key pair. Generate keys via HSM | -| Prevent firmware rollback | MEDIUM | Ratchet fuses | Configure anti-rollback fuses in fuse configuration XML | -| Debug port lockdown | HIGH | Disable JTAG/debug after production | Burn debug-disable fuses. Irreversible — production units only | - -### 3. API & Communication (FastAPI + SSE) - -| Requirement | Risk Level | Control | Implementation | -|-------------|-----------|---------|----------------| -| Authenticate API clients | HIGH | JWT bearer token | Pre-shared secret between ground station and Jetson. Generate JWT at session start. Short expiry (flight duration). `HTTPBearer` scheme in FastAPI | -| Encrypt SSE stream | HIGH | TLS 1.3 | Uvicorn with TLS certificate (self-signed for field use, pre-installed on ground station). All SSE position data encrypted in transit | -| Prevent unauthorized session control | HIGH | JWT + endpoint authorization | Session start/stop/anchor endpoints require valid JWT. Rate-limit via `slowapi` | -| Prevent replay attacks | MEDIUM | JWT `exp` + `jti` claims | Token expiry per-flight. Unique token ID (`jti`) tracked to prevent reuse | -| Limit API surface | MEDIUM | Minimal endpoint exposure | Only expose: POST /sessions, GET /sessions/{id}/stream (SSE), POST /sessions/{id}/anchor, DELETE /sessions/{id}. No admin/debug endpoints in production | - -### 4. Visual Odometry (cuVSLAM) - -| Requirement | Risk Level | Control | Implementation | -|-------------|-----------|---------|----------------| -| Detect camera feed tampering | LOW | Sanity checks on frame consistency | If consecutive frames show implausible motion (>500m displacement at 3fps), flag as suspicious. ESKF covariance spike triggers satellite re-localization | -| Protect against VO poisoning | LOW | Cross-validate VO with IMU | ESKF fusion inherently cross-validates: IMU and VO disagreement raises covariance, triggers satellite matching. No single sensor can silently corrupt position | - -### 5. Satellite Image Matching - -| Requirement | Risk Level | Control | Implementation | -|-------------|-----------|---------|----------------| -| Verify tile integrity | MEDIUM | SHA-256 checksums per tile | During offline preprocessing: compute SHA-256 for each tile pair. Store checksums in signed manifest. At runtime: verify checksum on tile load | -| Prevent adversarial tile injection | MEDIUM | Signed tile manifest | Offline tool signs manifest with private key. Jetson verifies signature with embedded public key before accepting tile set | -| Detect satellite match outliers | MEDIUM | RANSAC inlier ratio threshold | If RANSAC inlier ratio <30%, reject match as unreliable. ESKF treats as no-measurement rather than bad measurement | -| Protect against ground-based adversarial patterns | VERY LOW | Multi-tile consensus | Match against multiple overlapping tiles. Physical adversarial patches affect local area — consensus voting across tiles detects anomalies | - -### 6. Sensor Fusion (ESKF) - -| Requirement | Risk Level | Control | Implementation | -|-------------|-----------|---------|----------------| -| Prevent single-sensor corruption of position | HIGH | Adaptive noise + outlier rejection | Mahalanobis distance test on each measurement. Reject updates >5σ from predicted state. No single measurement can cause >50m position jump | -| Detect systematic drift | MEDIUM | Satellite matching rate monitoring | If satellite matches consistently disagree with VO by >100m, flag integrity warning to operator | -| Protect fusion state | LOW | In-memory only, no persistence | ESKF state never written to disk. Lost on power-off — no forensic recovery | - -### 7. Offline Preprocessing (Developer Machine) - -| Requirement | Risk Level | Control | Implementation | -|-------------|-----------|---------|----------------| -| Protect Google Maps API key | MEDIUM | Environment variable, never in code | `.env` file excluded from version control. API key used only on developer machine, never deployed to Jetson | -| Validate downloaded tiles | LOW | Source verification | Download only from Google Maps Tile API via HTTPS. Verify TLS certificate chain | -| Secure tile transfer to Jetson | MEDIUM | Signed + encrypted transfer | Transfer tile set + signed manifest via encrypted channel (SCP/SFTP). Verify manifest signature on Jetson before accepting | - -## Security Controls Summary - -### Authentication & Authorization - -- **Mechanism**: Pre-shared JWT secret between ground station and Jetson -- **Scope**: All API endpoints require valid JWT bearer token -- **Session model**: One JWT per flight session, expires at session end -- **No user management on Jetson** — single-operator system, auth is device-to-device - -### Data Protection - -| State | Protection | Tool | -|-------|-----------|------| -| At rest (Jetson storage) | LUKS full-disk encryption | JetPack LUKS + OP-TEE | -| In transit (SSE stream) | TLS 1.3 | Uvicorn SSL | -| In memory (ESKF state) | No persistence, cleared on session end | Application logic | -| On capture (emergency) | Tamper-triggered LUKS key erase | Hardware dead-man switch + `cryptsetup luksErase` | - -### Secure Communication - -- Ground station ↔ Jetson: TLS 1.3 (self-signed cert, pre-installed) -- No internet connectivity during flight — no external attack surface -- RF link security is out of scope (handled by UAV communication system) - -### Logging & Monitoring - -| What | Where | Retention | -|------|-------|-----------| -| API access logs (request count, errors) | In-memory ring buffer | Current session only, not persisted | -| Security events (auth failures, integrity warnings) | In-memory + SSE alert to operator | Current session only | -| Position history | In-memory for refinement, SSE to ground station | NOT persisted on Jetson after session end | -| Crash/tamper events | Trigger secure erase, no logging | N/A — priority is data destruction | - -**Design principle**: Minimize data persistence on Jetson. The ground station is the system of record. Jetson stores only what's needed for the current flight — satellite tiles (encrypted at rest) and transient processing state (memory only). - -## Protected Code Execution (OP-TEE / ARM TrustZone) - -### Overview - -The Jetson Orin Nano Super supports hardware-enforced protected code execution via **ARM TrustZone** and **OP-TEE v4.2.0** (included in Jetson Linux 36.3+). TrustZone partitions the processor into two isolated worlds: - -- **Secure World** (TEE): Runs at ARMv8 secure EL-1 (OS) and EL-0 (apps). Code here cannot be read or tampered with from the normal world. OP-TEE is the secure OS. -- **Normal World**: Standard Linux (JetPack). Our Python application, cuVSLAM, FastAPI all run here. - -Trusted Applications (TAs) execute inside the secure world and are invoked by Client Applications (CAs) in the normal world via the GlobalPlatform TEE Client API. - -### Architecture on Jetson Orin Nano - -``` -┌─────────────────────────────────────────────────┐ -│ NORMAL WORLD (Linux / JetPack) │ -│ │ -│ Client Application (CA) │ -│ ↕ libteec.so (TEE Client API) │ -│ ↕ OP-TEE Linux Kernel Driver │ -│ ↕ ARM Trusted Firmware (ATF) / Monitor │ -├─────────────────────────────────────────────────┤ -│ SECURE WORLD (OP-TEE v4.2.0) │ -│ │ -│ OP-TEE OS (ARMv8 S-EL1) │ -│ ├── jetson-user-key PTA (key management) │ -│ ├── luks TA (disk encryption passphrase) │ -│ ├── hwkey-agent TA (encrypt/decrypt data) │ -│ ├── PKCS #11 TA (crypto token interface) │ -│ └── Custom TAs (our application-specific TAs) │ -│ │ -│ Hardware: Security Engine (SE), HW RNG, Fuses │ -│ TZ-DRAM: Dedicated memory carveout │ -└─────────────────────────────────────────────────┘ -``` - -### Key Hierarchy (Hardware-Backed) - -The Jetson Orin Nano provides a hardware-rooted key hierarchy via the Security Engine (SE) and Encrypted Key Blob (EKB): - -``` -OEM_K1 fuse (256-bit AES, burned into hardware, cannot be read by software) - │ - ├── EKB_RK (EKB Root Key, derived via AES-128-ECB from OEM_K1 + FV) - │ ├── EKB_EK (encryption key for EKB content) - │ └── EKB_AK (authentication key for EKB content) - │ - ├── HUK (Hardware Unique Key, per-device, derived via NIST-SP-800-108) - │ └── SSK (Secure Storage Key, per-device, generated at OP-TEE boot) - │ ├── TSK (TA Storage Key, per-TA) - │ └── FEK (File Encryption Key, per-file) - │ - └── LUKS passphrase (derived from disk encryption key stored in EKB) -``` - -Fuse keys are loaded into SE keyslots during early boot (before OP-TEE starts). Software cannot read keys from keyslots — only derive new keys through the SE. After use, keyslots should be cleared via `tegra_se_clear_aes_keyslots()`. - -### What to Run in the Secure World (Our Use Cases) - -| Use Case | TA Type | Purpose | -|----------|---------|---------| -| **LUKS disk encryption** | Built-in `luks` TA | Generate one-time passphrase at boot to unlock encrypted rootfs. Keys never leave secure world | -| **Tile manifest verification** | Custom User TA | Verify SHA-256 signatures of satellite tile manifests. Signing key stored in EKB, accessible only in secure world | -| **JWT secret storage** | Custom User TA or `hwkey-agent` TA | Store JWT signing secret in EKB. Sign/verify JWTs inside secure world — secret never exposed to Linux | -| **Secure erase trigger** | Custom User TA | Receive tamper signal → invoke `cryptsetup luksErase` via CA. Key erase logic runs in secure world to prevent normal-world interference | -| **TLS private key protection** | PKCS #11 TA | Store TLS private key in OP-TEE secure storage. Uvicorn uses PKCS #11 interface to perform TLS handshake without key leaving secure world | - -### How to Enable Protected Code Execution - -#### Step 1: Burn OEM_K1 Fuse (One-Time, Irreversible) - -```bash -# Generate 256-bit OEM_K1 key (use HSM in production) -openssl rand -hex 32 > oem_k1_key.txt - -# Create fuse configuration XML with OEM_K1 -# Burn fuse via odmfuse.sh (IRREVERSIBLE) -sudo ./odmfuse.sh -i -``` - -After burning `SecurityMode` fuse (`odm_production_mode=0x1`), all further fuse writes are blocked. OEM_K1 becomes permanently embedded in hardware. - -#### Step 2: Generate and Flash EKB - -```bash -# Generate user keys (disk encryption key, JWT secret, tile signing key) -openssl rand -hex 16 > disk_enc_key.txt -openssl rand -hex 32 > jwt_secret.txt -openssl rand -hex 32 > tile_signing_key.txt - -# Generate EKB binary -python3 gen_ekb.py -chip t234 \ - -oem_k1_key oem_k1_key.txt \ - -in_sym_key uefi_enc_key.txt \ - -in_sym_key2 disk_enc_key.txt \ - -in_auth_key uefi_var_auth_key.txt \ - -out eks_t234.img - -# Flash EKB to EKS partition -# (part of the normal flash process with secure boot enabled) -``` - -#### Step 3: Enable LUKS Disk Encryption - -```bash -# During flash, set ENC_ROOTFS=1 to encrypt rootfs -export ENC_ROOTFS=1 -sudo ./flash.sh -``` - -The `luks` TA in OP-TEE derives a passphrase from the disk encryption key in EKB at boot. The passphrase is generated inside the secure world and passed to `cryptsetup` — it never exists in persistent storage. - -#### Step 4: Develop Custom Trusted Applications - -Cross-compile TAs for aarch64 using the Jetson OP-TEE source package: - -```bash -# Build custom TA (e.g., tile manifest verifier) -make -C \ - CROSS_COMPILE="/bin/aarch64-buildroot-linux-gnu-" \ - TA_DEV_KIT_DIR="/optee/build/t234/export-ta_arm64/" \ - OPTEE_CLIENT_EXPORT="/optee/install/t234/usr" \ - TEEC_EXPORT="/optee/install/t234/usr" \ - -j"$(nproc)" - -# Deploy: copy TA to /lib/optee_armtz/ on Jetson -# Deploy: copy CA to /usr/sbin/ on Jetson -``` - -TAs conform to the GlobalPlatform TEE Internal Core API. Use the `hello_world` example from `optee_examples` as a starting template. - -#### Step 5: Enable Secure Boot - -```bash -# Generate PKC key pair (use HSM for production) -openssl genrsa -out pkc_key.pem 3072 - -# Sign and flash secured images -sudo ./flash.sh --sign pkc_key.pem - -# After verification, burn SecurityMode fuse (IRREVERSIBLE) -``` - -### Available Crypto Services in Secure World - -| Service | Provider | Notes | -|---------|----------|-------| -| AES-128/256 encryption/decryption | SE hardware | Via keyslot-derived keys, never leaves SE | -| Key derivation (NIST-SP-800-108) | `jetson-user-key` PTA | Derive purpose-specific keys from EKB keys | -| Hardware RNG | SE hardware | `TEE_GenerateRandom()` or PTA command | -| PKCS #11 crypto tokens | PKCS #11 TA | Standard crypto interface for TLS, signing | -| SHA-256, HMAC | MbedTLS (bundled in optee_os) | Software crypto in secure world | -| RSA/ECC signing | GlobalPlatform TEE Crypto API | For manifest signature verification | - -### Limitations on Orin Nano - -| Limitation | Impact | Workaround | -|-----------|--------|------------| -| No RPMB support (only AGX Orin has RPMB) | Secure storage uses REE FS instead of replay-protected memory | Acceptable — LUKS encryption protects data at rest. REE FS secure storage is encrypted by SSK | -| EKB can only be updated via OTA, not at runtime | Cannot rotate keys in flight | Pre-provision per-device unique keys at manufacturing time | -| OP-TEE hello_world reported issues on some Orin Nano units | Some users report initialization failures | Use JetPack 6.2.2+ which includes fixes. Test thoroughly on target hardware | -| TZ-DRAM is a fixed carveout | Limits secure world memory | Keep TAs lightweight — only crypto operations and key management, not data processing | - -### Security Hardening Checklist - -- [ ] Burn OEM_K1 fuse with unique per-device key (via HSM) -- [ ] Generate and flash EKB with disk encryption key, JWT secret, tile signing key -- [ ] Enable LUKS full-disk encryption (`ENC_ROOTFS=1`) -- [ ] Modify `luks-srv` to NOT auto-decrypt (require explicit trigger or dead-man switch) -- [ ] Burn SecurityMode fuse (`odm_production_mode=0x1`) — enables secure boot chain -- [ ] Burn debug-disable fuses — disables JTAG -- [ ] Configure anti-rollback ratchet fuses -- [ ] Clear SE keyslots after EKB extraction via `tegra_se_clear_aes_keyslots()` -- [ ] Deploy custom TAs for JWT signing and tile manifest verification -- [ ] Use PKCS #11 for TLS private key protection -- [ ] Test secure erase trigger end-to-end -- [ ] Run `xtest` (OP-TEE test suite) on production Jetson to validate TEE - -## Key Security Risks - -| Risk | Severity | Mitigation Status | -|------|---------|-------------------| -| Physical capture → data extraction | CRITICAL | Mitigated by LUKS + secure erase. Residual risk: attacker extracts RAM before erase triggers | -| No auto-decrypt bypass for LUKS | HIGH | Requires custom `luks-srv` modification — development effort needed | -| Self-signed TLS certificates | MEDIUM | Acceptable for field deployment. Certificate pinning on ground station prevents MITM | -| cuVSLAM is closed-source | LOW | Cannot audit for vulnerabilities. Mitigated by running in sandboxed environment, input validation on camera frames | -| Dead-man switch reliability | HIGH | Hardware integration required. False triggers (temporary signal loss) must NOT cause premature erase. Needs careful threshold tuning | - -## References -- xT-STRIDE threat model for UAVs (2025): https://link.springer.com/article/10.1007/s10207-025-01082-4 -- NVIDIA Jetson OP-TEE Documentation (r36.4.4): https://docs.nvidia.com/jetson/archives/r36.4.4/DeveloperGuide/SD/Security/OpTee.html -- NVIDIA Jetson Security Overview (r36.4.3): https://docs.nvidia.com/jetson/archives/r36.4.3/DeveloperGuide/SD/Security.html -- NVIDIA Jetson LUKS Disk Encryption: https://docs.nvidia.com/jetson/archives/r36.4.4/DeveloperGuide/SD/Security/DiskEncryption.html -- NVIDIA Jetson Secure Boot: https://docs.nvidia.com/jetson/archives/r36.4.4/DeveloperGuide/SD/Security/SecureBoot.html -- NVIDIA Jetson Secure Storage: https://docs.nvidia.com/jetson/archives/r36.4.3/DeveloperGuide/SD/Security/SecureStorage.html -- NVIDIA Jetson Firmware TPM: https://docs.nvidia.com/jetson/archives/r36.4.3/DeveloperGuide/SD/Security/FirmwareTPM.html -- NVIDIA Jetson Rollback Protection: https://docs.nvidia.com/jetson/archives/r36.4.3/DeveloperGuide/SD/Security/RollbackProtection.html -- Jetson Orin Fuse Specification: https://developer.nvidia.com/downloads/jetson-agx-orin-series-fuse-specification -- OP-TEE Official Documentation: https://optee.readthedocs.io/en/latest/ -- OP-TEE Trusted Application Examples: https://github.com/linaro-swg/optee_examples -- RidgeRun OP-TEE on Jetson Guide: https://developer.ridgerun.com/wiki/index.php/RidgeRun_Platform_Security_Manual/Getting_Started/TEE/NVIDA-Jetson -- GlobalPlatform TEE Specifications: https://globalplatform.org/specs-library/?filter-committee=tee -- Model Agnostic Defense against Adversarial Patches on UAVs (2024): https://arxiv.org/html/2405.19179v1 -- FastAPI Security Best Practices (2026): https://fastlaunchapi.dev/blog/fastapi-best-practices-production-2026 diff --git a/_docs/01_solution/solution.md b/_docs/01_solution/solution.md deleted file mode 100644 index 7ca92e3..0000000 --- a/_docs/01_solution/solution.md +++ /dev/null @@ -1,130 +0,0 @@ -# Solution - -## Product Solution Description - -Build an onboard GPS-denied localization service that runs on the Jetson companion computer, uses the fixed downward navigation camera and flight-controller inertial telemetry, and emits ArduPilot `GPS_INPUT` estimates with calibrated covariance and source labels. - -The production architecture is a trigger-based hybrid estimator: - -```text -Nav camera + FC telemetry - | - v -Image quality + calibration + orthorectification - | - +--> Hot path: OpenCV geometry + BASALT VIO --> safety/anchor wrapper --> GPS_INPUT + QGC + FDR - | - +--> Reference path: OpenVINS replay benchmark for VIO drift/covariance tests; Kimera backup replay - | - +--> Trigger path: DINOv2-VLAD query --> CPU FAISS top-K --> ALIKED/DISK+LightGlue --> OpenCV RANSAC --> safety/anchor wrapper - | - +--> Tile path: new COG tile + quality/provenance sidecar --> manifest update --> post-flight Satellite Service sync -``` - -Heavy local retrieval and local matching are not steady-state per-frame dependencies. They run on cold start, VO failure, sharp turns, disconnected segments, covariance growth, stale-anchor age, or operator-assisted relocalization, using only preloaded cache/index data during flight. - -## Architecture - -### Camera Ingest, Calibration, And Geometry - -| Solution | Tools | Pinned Mode/Config | Fit | -|----------|-------|--------------------|-----| -| OpenCV geometry utility layer | OpenCV 4.x | Calibration, undistortion, homography, RANSAC/USAC, MRE measurement | Selected. Mature, permissive, exact utility fit; not a full estimator. | - -### VO / IMU Propagation And Estimator - -| Solution | Tools | Pinned Mode/Config | Fit | -|----------|-------|--------------------|-----| -| BASALT + safety/anchor wrapper | BASALT, OpenCV, custom wrapper | BASALT consumes calibrated nav-camera frames + FC IMU; wrapper fuses satellite anchors, calibrates uncertainty, emits source labels and `GPS_INPUT` fields | Selected. Best production VIO candidate found: permissive license, strong benchmark evidence, avoids custom VIO from scratch. | -| OpenVINS | OpenVINS | Monocular camera + IMU EKF/MSCKF reference runs with covariance extraction | Reference only. Strong VIO and covariance baseline, but GPLv3 and generic VIO ownership make it unsuitable as default shipped dependency. | -| Kimera-VIO | Kimera-VIO | Mono/stereo camera + IMU VIO/SLAM backup replay | Backup candidate. BSD-friendly but heavier/stereo-oriented; mono-inertial path has documented caveats. | -| ORB-SLAM3 | ORB-SLAM3 | Monocular-inertial SLAM | Rejected for production. GPLv3 and heavier SLAM/map lifecycle. | - -BASALT does not replace the project-owned safety logic. The wrapper remains responsible for satellite anchor acceptance, confidence calibration, source labels, blackout/spoofing modes, tile-write eligibility, and MAVLink `GPS_INPUT` semantics. - -### Satellite Service And Anchor Verification - -| Solution | Tools | Pinned Mode/Config | Fit | -|----------|-------|--------------------|-----| -| DINOv2-VLAD + CPU FAISS + ALIKED/DISK+LightGlue | DINOv2/AnyLoc-style descriptors, FAISS CPU, LightGlue, OpenCV RANSAC | Offline VPR chunk descriptors; conditional query descriptor; CPU FAISS top-K; learned local match on bounded candidates; TensorRT only after fidelity check | Selected with runtime/fidelity gates. | -| SuperPoint+LightGlue | SuperPoint, LightGlue | Same matcher with SuperPoint features | License-gated benchmark/fallback only. | -| Classical SIFT/ORB | OpenCV | Handcrafted features + homography | Regression/fallback baseline. | - -The Satellite Service component imports mission cache/index packages before flight, uploads generated-tile packages after landing, and serves local VPR queries during flight. The VPR index is built over ground-footprint-sized chunks with overlap and a multi-scale descriptor set. VPR is invoked only on relocalization triggers or covariance/anchor-age growth; normal flight uses BASALT VIO plus wrapper propagation. No satellite-provider or Satellite Service network calls are allowed mid-flight. - -### Tile Manager - -| Solution | Tools | Pinned Mode/Config | Fit | -|----------|-------|--------------------|-----| -| COG tile objects + PostgreSQL/PostGIS manifest + signed JSON sidecars | GDAL COG, PostgreSQL/PostGIS, signed JSON sidecars, FAISS index files | Service tiles and generated tiles are write-new COG objects; active version selected by PostGIS-backed manifest | Selected. Fits geospatial raster access, provenance, spatial/freshness queries, and write-new tile lifecycle. | -| PMTiles | PMTiles | Read-only archive snapshot | Rejected for live cache because in-flight tile generation needs mutable write-new objects. | - -Service-source tiles and generated tiles carry CRS, capture date, source, m/px, freshness, quality score, sidecar hashes, and descriptor references. The Tile Manager also orthorectifies eligible nadir frames into generated COG tiles. Stale tiles are rejected or down-confidence weighted. - -### MAVLink Integration - -| Solution | Tools | Pinned Mode/Config | Fit | -|----------|-------|--------------------|-----| -| MAVSDK telemetry + pymavlink `GPS_INPUT` | MAVSDK, pymavlink | MAVSDK subscriptions; pymavlink emits `GPS_INPUT`; v1 emits GPS_INPUT only; Plane SITL validates `GPS1_TYPE=14`, velocity source params, ignore flags, fix types, accuracy fields | Selected. Exact output control with good telemetry ergonomics. | - -The system emits per-frame estimates locally and downsampled status to QGroundControl. `GPS_INPUT.horiz_accuracy` must not under-report the calibrated 95% covariance semi-major axis. - -### Security And Safety Controls - -| Solution | Tools | Pinned Mode/Config | Fit | -|----------|-------|--------------------|-----| -| Consistency-gated anchor acceptance | Safety/anchor wrapper, cache manifest verification | Anchor accepted only if freshness, provenance, RANSAC, covariance, Mahalanobis, and temporal consistency pass | Selected. Prevents confident false fixes. | -| FDR audit trail | PostgreSQL event index + CBOR payload segments + hashes | Logs estimates, inputs, emitted GPS_INPUT, health, tile writes, anchor decisions | Selected. Supports incident analysis, indexed queries, and cache-poisoning audits. | - -## Runtime Modes - -| Mode | Trigger | Behavior | `GPS_INPUT` / Telemetry | -|------|---------|----------|--------------------------| -| `satellite_anchored` | VPR + local match passes all gates | Wrapper absolute update; tile write eligible only if sigma gate passes | 3D fix, `horiz_accuracy` >= 95% covariance semi-major axis | -| `vo_extrapolated` | BASALT VIO healthy and anchor age/covariance within bounds | BASALT VIO + wrapper propagation; covariance grows | 3D/2D depending covariance threshold | -| `dead_reckoned` | visual blackout or no accepted anchor | IMU-only propagation, monotonic covariance growth | degraded fix type; QGC `VISUAL_BLACKOUT_IMU_ONLY` | -| failsafe/no-fix | covariance >500 m or blackout >30 s | stop pretending position is valid | `fix_type=0`, `horiz_accuracy=999.0`, QGC `VISUAL_BLACKOUT_FAILSAFE` | - -## Testing Strategy - -### Integration / Functional Tests - -- BASALT replay: assert AC-2.1a and AC-2.2 VO MRE on overlapping frame pairs, completion rate, latency, and wrapper-calibrated covariance. -- OpenVINS reference replay: compare VIO drift, failure cases, and covariance against BASALT + wrapper. -- Kimera-VIO backup replay: keep a second permissive candidate benchmark in case BASALT fails project replay/runtime gates. -- Satellite anchor replay: assert AC-1.1/1.2, AC-2.2 cross-domain MRE, freshness rejection, and source labels. -- DINOv2 descriptor fidelity: compare PyTorch/ONNX/TensorRT embeddings and retrieval rankings before accepting optimized engines. -- FAISS CPU index tests: top-K recall, query latency, index size, save/load behavior on Jetson ARM64. -- LightGlue extractor matrix: ALIKED vs DISK vs SIFT/ORB vs SuperPoint benchmark; SuperPoint excluded from production unless legal approves. -- Tile Manager: orthorectify eligible nadir frames into write-new generated tiles, update manifest, verify active version and rollback. -- `GPS_INPUT` SITL: validate fix type, `horiz_accuracy`, velocity fields, ignore flags, `EK3_SRC1_*` parameters, QGC behavior. -- Security gates: stale tile, mismatched tile hash, low inlier ratio, impossible velocity jump, and spoofed GPS during blackout. - -### Non-Functional Tests - -- Jetson latency and memory: <400 ms p95, <8 GB shared memory, no 25 W thermal throttle. -- Cache budget: 400 km² imagery + manifests + descriptors fits budget or reports explicit split budget. -- FDR 8-hour load: <=64 GB, rollover logged, no silent payload loss. -- Monte Carlo false-position and cache-poisoning tests for AC-NEW-4 and AC-NEW-7. -- Cold boot: first valid `GPS_INPUT` <30 s p95 across 50 runs. - -## References - -Detailed source registry: `_docs/00_research/01_source_registry.md`. - -Key sources: -- BASALT repository: https://github.com/VladyslavUsenko/basalt -- HybVIO benchmark paper: https://arxiv.org/pdf/2106.11857 -- OpenVINS docs: https://docs.openvins.com/index.html -- OpenVINS ATE/RTE comparison: https://github.com/rpng/open_vins/issues/402 -- Kimera mono-inertial caveat: https://github.com/MIT-SPARK/Kimera-VIO/issues/254 -- AnyLoc paper: https://arxiv.org/html/2308.00688 -- Aerial VPR survey: https://arxiv.org/abs/2406.00885 -- ALIKED-LightGlue-ONNX: https://github.com/ikeboo/ALIKED-LightGlue-ONNX -- DINOv2 TensorRT issue: https://github.com/NVIDIA/TensorRT/issues/4348 - -## Related Artifacts - -- Tech stack evaluation: `_docs/01_solution/tech_stack.md` -- Component fit matrix: `_docs/00_research/06_component_fit_matrix.md` -- Fact cards: `_docs/00_research/02_fact_cards.md` diff --git a/_docs/01_solution/solution_draft01.md b/_docs/01_solution/solution_draft01.md deleted file mode 100644 index 063bff2..0000000 --- a/_docs/01_solution/solution_draft01.md +++ /dev/null @@ -1,149 +0,0 @@ -# Solution Draft - -## Product Solution Description - -Build an onboard GPS-denied localization service that runs on the companion Jetson, consumes the fixed nadir navigation camera plus flight-controller IMU/attitude/altitude, and emits ArduPilot-compatible `GPS_INPUT` estimates with honest covariance. - -The solution is a hybrid estimator: - -```text -Nav camera + FC telemetry - | - v -Image quality + calibration + orthorectification - | - +--> Steady state: VO/IMU propagation --> ESKF --> GPS_INPUT + QGC + FDR - | - +--> Re-anchor triggers: VPR top-K --> local match/RANSAC --> ESKF anchor update - | - +--> Tile generation: ortho tile + quality sidecar --> local cache --> post-flight Satellite Service upload -``` - -The steady-state path is intentionally lightweight. Heavy global retrieval and cross-domain local matching run only on cold start, VO failure, sharp turns, disconnected segments, covariance growth, or stale-anchor age. - -## Existing / Competitor Solutions Analysis - -Recent fixed-wing GPS-denied research supports the same high-level mechanism: monocular visual odometry alone accumulates scale/drift error, while satellite-image comparison can periodically correct it. Aerial VPR surveys also show why the implementation cannot be naive: weather, season, scale mismatch, repetitive fields, tile overlap, and re-ranking runtime all matter. - -The selected design borrows the proven structure but rejects an all-in-one SLAM dependency as the product core. OpenVINS and ORB-SLAM3 are useful benchmark/reference implementations, but their GPL-family licensing and broader SLAM lifecycle do not fit a default production dependency for this project. - -## Architecture - -### Component: Camera Ingest, Calibration, And Geometry - -| Solution | Tools | Pinned Mode/Config | Advantages | Limitations | Requirements | Security | Cost | API Capability Evidence | Fit | -|----------|-------|--------------------|------------|-------------|--------------|----------|------|-------------------------|-----| -| OpenCV geometry utility layer | OpenCV 4.x | Camera calibration, undistortion, RANSAC homography, reprojection-error measurement | Mature, local, fast, exact API fit | Not a full estimator | Calibration target, fixed intrinsics/extrinsics, lens/FOV selection | Local-only, no network | Low | MVE: `_docs/00_research/02_fact_cards.md`; Source #5 | Selected | - -**Exact-fit evidence**: -- Project constraints checked: fixed nadir camera, calibration, homography, MRE gates. -- Disqualifiers: none. -- Restrictions × AC matrix: `_docs/00_research/06_component_fit_matrix.md`. - -### Component: VO / IMU Propagation And Estimator - -| Solution | Tools | Pinned Mode/Config | Advantages | Limitations | Requirements | Security | Cost | API Capability Evidence | Fit | -|----------|-------|--------------------|------------|-------------|--------------|----------|------|-------------------------|-----| -| Custom VO/IMU ESKF | OpenCV + custom estimator | Frame-to-frame homography/features + FC IMU/attitude/altitude fused in a custom ESKF with source modes | Owns covariance, source labels, degraded modes, ArduPilot output semantics | More implementation work than adopting VIO library | Synchronized frames/IMU, calibration, replay tests | No third-party cloud; deterministic local logs | Medium | Facts #1, #4, #5, #16 | Selected | -| OpenVINS reference | OpenVINS | Monocular camera + IMU EKF/MSCKF reference runs | Strong VIO reference and evaluation tools | GPL-3 production dependency risk | Dataset/replay adapter | Local only | Low for benchmark | Source #3 | Reference only | -| ORB-SLAM3 alternative | ORB-SLAM3 | Monocular-inertial SLAM | Mature SLAM benchmark | GPLv3, heavier map lifecycle, initialization complexity | Calibration, vocabulary, runtime tuning | Local only | Medium | Source #4 | Rejected for production | - -**Exact-fit evidence**: -- Project constraints checked: one camera + IMU, frame-by-frame output, covariance labels, blackout/spoofing modes. -- Runtime quality gate: validate drift and covariance on EuRoC-style and representative fixed-wing replay. - -### Component: Satellite Retrieval And Local Anchor - -| Solution | Tools | Pinned Mode/Config | Advantages | Limitations | Requirements | Security | Cost | API Capability Evidence | Fit | -|----------|-------|--------------------|------------|-------------|--------------|----------|------|-------------------------|-----| -| DINOv2-VLAD + FAISS + LightGlue | DINOv2/AnyLoc-style descriptors, FAISS, DISK/ALIKED+LightGlue, OpenCV RANSAC | Offline precomputed VPR chunk descriptors; conditional query descriptor; top-K FAISS; local matching on candidates | Matches AC-8.6; scalable top-K; local geometry verifies anchors | Needs Jetson profiling and model-size pruning | Fresh satellite cache, descriptors, dynamic K, RANSAC gates | Cache is local; no in-flight provider calls | Medium-high | MVE blocks in `02_fact_cards.md`; Sources #6-#9 | Selected with runtime gate | -| SuperPoint + LightGlue | SuperPoint, LightGlue | Same local matching with SuperPoint features | Strong technical baseline | SuperPoint license is restrictive | Legal review | Local only | Medium | Source #6 | Needs user decision | -| Classical SIFT/ORB-only | OpenCV | Handcrafted features and homography | Simple fallback, low compute | Poor cross-domain robustness | Feature-rich scenes | Local only | Low | Source #5 | Fallback / regression baseline | - -**Exact-fit evidence**: -- Project constraints checked: offline cache, top-K dynamic retrieval, cross-domain local match, <400 ms hot-path constraint. -- Runtime gate: heavy VPR/re-ranking is trigger-based, not per-frame. - -### Component: Satellite Cache And Tile Write-Back - -| Solution | Tools | Pinned Mode/Config | Advantages | Limitations | Requirements | Security | Cost | API Capability Evidence | Fit | -|----------|-------|--------------------|------------|-------------|--------------|----------|------|-------------------------|-----| -| COG + PostgreSQL/PostGIS manifest + descriptor sidecars | GDAL COG, PostgreSQL/PostGIS manifest, FAISS sidecars | Service tiles and generated candidate tiles stored as tiled compressed GeoTIFFs with CRS/date/source/meter-per-pixel metadata | Geospatial standard, supports write-new-tile workflow, descriptor accounting | Needs careful 10 GB budget | STAC-like manifest, freshness gates, descriptor pruning | Local signed manifests recommended | Medium | Source #18 | Selected | -| PMTiles archive | PMTiles | Single-file read archive | Efficient map reads | Read-only; cannot update in place | Archive rebuild for updates | Local file integrity | Low | Source #17 | Rejected for live mutable cache | - -**Exact-fit evidence**: -- Project constraints checked: offline-only, no raw photo storage, mid-flight generated tiles, Satellite Service ingest metadata. -- External dependency: Satellite Service owns the promotion/voting layer for trusted basemap updates. - -### Component: MAVLink Integration And Telemetry - -| Solution | Tools | Pinned Mode/Config | Advantages | Limitations | Requirements | Security | Cost | API Capability Evidence | Fit | -|----------|-------|--------------------|------------|-------------|--------------|----------|------|-------------------------|-----| -| MAVSDK telemetry + pymavlink output | MAVSDK, pymavlink | MAVSDK subscribes to telemetry; pymavlink emits `GPS_INPUT` to ArduPilot with `GPS1_TYPE=14` | Exact `GPS_INPUT` field control while keeping high-level telemetry APIs | Plane-specific failsafe/spoof triggers need SITL proof | ArduPilot Plane params, QGC status, FDR tlog | Validate MAVLink source and message rate | Medium | Sources #10-#12 | Selected | - -**Exact-fit evidence**: -- Project constraints checked: ArduPilot only, v1 `GPS_INPUT` only, WGS84 output, covariance to `horiz_accuracy`. -- Validation gate: Plane SITL with production parameters. - -### Component: Flight Data Recorder - -| Solution | Tools | Pinned Mode/Config | Advantages | Limitations | Requirements | Security | Cost | API Capability Evidence | Fit | -|----------|-------|--------------------|------------|-------------|--------------|----------|------|-------------------------|-----| -| Segmented FDR | PostgreSQL event index + binary/CBOR payloads with Parquet export post-flight | Fixed-size segment files for per-frame estimates, IMU, MAVLink, health, emitted GPS_INPUT, generated-tile metadata | Replayable, bounded, no raw frame retention | Exact format selected during implementation | Rollover policy, monotonic timestamps | Integrity hash per segment recommended | Medium | AC-NEW-3 | Selected pattern | - -## Runtime Modes - -| Mode | Trigger | Behavior | Output Label | -|------|---------|----------|--------------| -| Satellite anchored | VPR + local match passes freshness, RANSAC, covariance, and Mahalanobis gates | ESKF absolute update, low covariance, tile generation eligible if sigma gate passes | `satellite_anchored` | -| VO extrapolated | Last anchor fresh enough, VO healthy, normal overlap | VO/IMU propagation, covariance grows with anchor age | `vo_extrapolated` | -| Dead reckoned | Visual blackout, VO failure without anchor, spoofing while no visual signal | IMU-only propagation, monotonic covariance growth, degraded fix type thresholds | `dead_reckoned` | -| Failsafe / no fix | Blackout >30 s or covariance >500 m | `GPS_INPUT.fix_type=0`, `horiz_accuracy=999.0`, QGC status | `dead_reckoned` with failsafe status | - -## Testing Strategy - -### Integration / Functional Tests - -- Replay normal overlapping frames and assert AC-2.1a VO registration rate and AC-2.2 VO MRE. -- Replay satellite-anchor cases and assert AC-1.1/1.2, AC-2.2 cross-domain MRE, freshness gates, and source labels. -- Inject stale tiles and assert no `satellite_anchored` output. -- Inject sharp turns and disconnected segments and assert VPR relocalization. -- Run ArduPilot Plane SITL with `GPS1_TYPE=14` and assert valid `GPS_INPUT` fields, fix type degradation, and QGC statuses. -- Inject visual blackout + spoofed GPS and assert spoofed GPS is ignored, covariance grows, and thresholds match AC-NEW-8. -- Request AI-camera object coordinates and assert level-flight projection plus maneuver error bound. - -### Non-Functional Tests - -- Jetson Orin Nano Super profiling: <400 ms p95, <8 GB shared memory, 25 W no-throttle hot-soak. -- Cache build test for 400 km²: imagery + manifests + descriptors fit within budget or fail with explicit budget report. -- 8-hour FDR load test: <=64 GB, rollover logged, no silent data loss. -- Monte Carlo false-anchor and over-confidence tests for AC-NEW-4 and AC-NEW-7. -- Cold boot 50x: first valid `GPS_INPUT` <30 s p95. - -## References - -Detailed source registry: `_docs/00_research/01_source_registry.md`. - -Key sources: -- Fixed-wing satellite-aided VO: https://www.mdpi.com/2076-3417/14/16/7420 -- Aerial VPR survey: https://arxiv.org/abs/2406.00885 -- OpenVINS docs: https://docs.openvins.com/ -- ORB-SLAM3 README: https://raw.githubusercontent.com/UZ-SLAMLab/ORB_SLAM3/master/README.md -- LightGlue README: https://raw.githubusercontent.com/cvg/LightGlue/main/README.md -- FAISS docs: https://faiss.ai/index.html -- ArduPilot GPSInput: https://ardupilot.org/mavproxy/docs/modules/GPSInput.html -- MAVLink GPS_INPUT: https://mavlink.io/en/messages/common.html#GPS_INPUT -- Jetson Orin Nano Super: https://www.nvidia.com/en-us/autonomous-machines/embedded-systems/jetson-orin/nano-super-developer-kit/ -- PMTiles: https://docs.protomaps.com/pmtiles/ -- GDAL COG: https://gdal.org/en/stable/drivers/raster/cog.html - -## Related Artifacts - -- AC assessment: `_docs/00_research/00_ac_assessment.md` -- Question decomposition: `_docs/00_research/00_question_decomposition.md` -- Source registry: `_docs/00_research/01_source_registry.md` -- Fact cards: `_docs/00_research/02_fact_cards.md` -- Comparison framework: `_docs/00_research/03_comparison_framework.md` -- Reasoning chain: `_docs/00_research/04_reasoning_chain.md` -- Validation log: `_docs/00_research/05_validation_log.md` -- Component fit matrix: `_docs/00_research/06_component_fit_matrix.md` diff --git a/_docs/01_solution/solution_draft02.md b/_docs/01_solution/solution_draft02.md deleted file mode 100644 index 7578bae..0000000 --- a/_docs/01_solution/solution_draft02.md +++ /dev/null @@ -1,125 +0,0 @@ -# Solution Draft - -## Assessment Findings - -| Old Component Solution | Weak Point (functional/security/performance) | New Solution | -|------------------------|----------------------------------------------|-------------| -| DINOv2-VLAD with possible TensorRT optimization | TensorRT conversion may produce limited speedup and can alter embedding distances on Jetson-class deployments. | Keep DINOv2-VLAD, but require descriptor-fidelity tests against PyTorch/ONNX before TensorRT descriptors are accepted. | -| FAISS CPU/GPU optional | FAISS GPU is not a safe default on Jetson ARM64/aarch64 packaging. | Pin FAISS as CPU-first on Jetson; use PQ/IVF and top-K caps before considering custom GPU builds. | -| LightGlue local matcher | SuperPoint path has license risk and community confusion. | Keep DISK/ALIKED+LightGlue as production default; SuperPoint remains license-gated benchmark/fallback only. | -| COG cache | "COG cache" could be misread as mutable in-place raster updates. | Use write-new COG tile objects plus manifest versioning and sidecars; never mutate COGs in place. | -| `GPS_INPUT` output | ArduPilot velocity ignore flags have reported EKF3 pitfalls. | SITL must validate velocity source parameters, ignore flags, and whether zero velocity is ever fused accidentally. | -| Visual/satellite anchoring | Draft did not emphasize adversarial/cache integrity enough. | Add signed cache manifests, tile provenance, freshness gates, anchor consistency checks, and FDR audit trail. | - -## Product Solution Description - -Build an onboard GPS-denied localization service that runs on the Jetson companion computer, uses the fixed downward navigation camera and flight-controller inertial telemetry, and emits ArduPilot `GPS_INPUT` estimates with calibrated covariance and source labels. - -The production architecture is a trigger-based hybrid estimator: - -```text -Nav camera + FC telemetry - | - v -Image quality + calibration + orthorectification - | - +--> Hot path: VO/IMU propagation --> custom ESKF --> GPS_INPUT + QGC + FDR - | - +--> Trigger path: DINOv2-VLAD query --> CPU FAISS top-K --> DISK/ALIKED+LightGlue --> RANSAC --> ESKF anchor - | - +--> Tile path: new COG tile + quality/provenance sidecar --> manifest update --> post-flight Satellite Service sync -``` - -Heavy retrieval and local matching are not steady-state per-frame dependencies. They run on cold start, VO failure, sharp turns, disconnected segments, covariance growth, or stale-anchor age. - -## Architecture - -### Component: Camera Ingest, Calibration, And Geometry - -| Solution | Tools | Pinned Mode/Config | Advantages | Limitations | Requirements | Security | Performance | API Capability Evidence | Fit | -|----------|-------|--------------------|------------|-------------|--------------|----------|-------------|-------------------------|-----| -| OpenCV geometry utility layer | OpenCV 4.x | Calibration, undistortion, RANSAC homography, MRE measurement | Mature, exact fit, permissive | Not a full estimator | Checkerboard calibration, fixed extrinsics, lens/FOV selection | Local-only | Fast enough for hot-path utility use | MVE in `02_fact_cards.md`; Source #5 | Selected | - -### Component: VO / IMU Propagation And Estimator - -| Solution | Tools | Pinned Mode/Config | Advantages | Limitations | Requirements | Security | Performance | API Capability Evidence | Fit | -|----------|-------|--------------------|------------|-------------|--------------|----------|-------------|-------------------------|-----| -| Custom VO/IMU ESKF | OpenCV + custom estimator | Nadir VO/homography + FC IMU/attitude/altitude fused in ESKF with mode labels | Owns covariance, source labels, blackout/spoofing behavior | More implementation effort | Synchronized frames/IMU, calibration, replay tests | No network dependency | Hot path is lightweight | Facts #1, #16 | Selected | -| OpenVINS | OpenVINS | Monocular+IMU reference runs | Strong EKF/MSCKF reference | GPL-3 production risk | Replay adapter | Local only | Benchmark only | Source #3 | Reference only | -| ORB-SLAM3 | ORB-SLAM3 | Monocular-inertial SLAM | Mature benchmark | GPLv3 and heavier SLAM lifecycle | Calibration/vocabulary/runtime tuning | Local only | Riskier on embedded | Source #4 | Rejected for production | - -### Component: Satellite Retrieval And Anchor Verification - -| Solution | Tools | Pinned Mode/Config | Advantages | Limitations | Requirements | Security | Performance | API Capability Evidence | Fit | -|----------|-------|--------------------|------------|-------------|--------------|----------|-------------|-------------------------|-----| -| DINOv2-VLAD + CPU FAISS + DISK/ALIKED+LightGlue | DINOv2/AnyLoc-style descriptors, FAISS CPU, LightGlue, OpenCV RANSAC | Offline VPR chunk descriptors; conditional query descriptor; CPU FAISS top-K; local match on candidates; TensorRT only after fidelity check | Strong retrieval+geometry structure; avoids per-frame map search | Requires profiling and representative data | Descriptor cache, dynamic K, freshness, RANSAC, Mahalanobis gates | Signed manifests, provenance, stale-tile rejection | Trigger path only; top-K capped | MVE blocks in `02_fact_cards.md`; Sources #6-#9, #21-#25 | Selected with runtime/fidelity gates | -| SuperPoint+LightGlue | SuperPoint, LightGlue | Same matcher with SuperPoint features | Strong technical baseline | SuperPoint license risk | Legal review | Local only | Benchmark only | Sources #6, #23 | Needs user decision | -| Classical SIFT/ORB | OpenCV | Handcrafted features + homography | Simple and cheap | Weak cross-domain robustness | Feature-rich scenes | Local only | Fast | Source #5 | Regression baseline | - -### Component: Cache And Tile Lifecycle - -| Solution | Tools | Pinned Mode/Config | Advantages | Limitations | Requirements | Security | Performance | API Capability Evidence | Fit | -|----------|-------|--------------------|------------|-------------|--------------|----------|-------------|-------------------------|-----| -| COG tile objects + manifest + sidecars | GDAL COG, manifest DB/JSON, FAISS index files | Service tiles and generated tiles are write-new COG objects; active version selected by manifest | Geospatial standard, supports provenance and quality metadata | Descriptor budget pressure | CRS/date/source/m/px/freshness, sidecar hashes | Signed manifests, tile provenance, hash verification | Efficient local reads | Source #18; Facts #21, #29 | Selected | -| PMTiles | PMTiles | Read-only archive snapshot | Compact read package | Cannot update in place | Archive rebuild | Hash archive | Good for read-only export | Source #17 | Rejected for live cache | - -### Component: MAVLink Integration - -| Solution | Tools | Pinned Mode/Config | Advantages | Limitations | Requirements | Security | Performance | API Capability Evidence | Fit | -|----------|-------|--------------------|------------|-------------|--------------|----------|-------------|-------------------------|-----| -| MAVSDK telemetry + pymavlink `GPS_INPUT` | MAVSDK, pymavlink | MAVSDK subscriptions; pymavlink emits `GPS_INPUT`; Plane SITL validates `GPS1_TYPE=14`, velocity source params, ignore flags, fix types, accuracy fields | Exact output control with good telemetry ergonomics | SITL required to prove Plane behavior | ArduPilot Plane params, QGC, tlog/FDR | Link/source validation, status audit | Light CPU load | Sources #10-#12, #24 | Selected | - -### Component: Security And Safety Controls - -| Solution | Tools | Pinned Mode/Config | Advantages | Limitations | Requirements | Security | Performance | API Capability Evidence | Fit | -|----------|-------|--------------------|------------|-------------|--------------|----------|-------------|-------------------------|-----| -| Consistency-gated anchor acceptance | Custom ESKF gates, cache manifest verification | Anchor accepted only if freshness, provenance, RANSAC, covariance, Mahalanobis, and temporal consistency pass | Prevents confident false fixes | Needs calibrated thresholds | Representative replay and Monte Carlo | Rejects stale/poisoned/low-confidence anchors | Lightweight after candidate generation | Facts #16, #17, #28 | Selected | -| FDR audit trail | Segmented logs + hashes | Logs estimates, inputs, emitted GPS_INPUT, health, tile writes, anchor decisions | Supports incident analysis and cache-poisoning audits | Schema work | 64 GB rollover | Tamper-evident hashes recommended | Sequential writes | AC-NEW-3 | Selected | - -## Runtime Modes - -| Mode | Trigger | Behavior | `GPS_INPUT` / Telemetry | -|------|---------|----------|--------------------------| -| `satellite_anchored` | VPR + local match passes all gates | ESKF absolute update; tile write eligible only if sigma gate passes | 3D fix, `horiz_accuracy` >= 95% covariance semi-major axis | -| `vo_extrapolated` | VO healthy and anchor age/covariance within bounds | VO/IMU propagation; covariance grows | 3D/2D depending covariance threshold | -| `dead_reckoned` | visual blackout or no accepted anchor | IMU-only propagation, monotonic covariance growth | degraded fix type; QGC `VISUAL_BLACKOUT_IMU_ONLY` | -| failsafe/no-fix | covariance >500 m or blackout >30 s | stop pretending position is valid | `fix_type=0`, `horiz_accuracy=999.0`, QGC `VISUAL_BLACKOUT_FAILSAFE` | - -## Testing Strategy - -### Integration / Functional Tests - -- VO replay: assert AC-2.1a and AC-2.2 VO MRE on overlapping frame pairs. -- Satellite anchor replay: assert AC-1.1/1.2, AC-2.2 cross-domain MRE, freshness rejection, and source labels. -- DINOv2 descriptor fidelity: compare PyTorch/ONNX/TensorRT embeddings and retrieval rankings before accepting optimized engines. -- FAISS CPU index tests: top-K recall, query latency, index size, save/load behavior on Jetson ARM64. -- LightGlue extractor matrix: DISK vs ALIKED vs SuperPoint benchmark; SuperPoint output excluded from production unless license approved. -- COG cache lifecycle: write-new generated tile, update manifest, verify active version and rollback. -- `GPS_INPUT` SITL: validate fix type, `horiz_accuracy`, velocity fields, ignore flags, `EK3_SRC1_*` parameters, QGC behavior. -- Security gates: stale tile, mismatched tile hash, low inlier ratio, impossible velocity jump, and spoofed GPS during blackout. - -### Non-Functional Tests - -- Jetson latency and memory: <400 ms p95, <8 GB shared memory, no 25 W thermal throttle. -- Cache budget: 400 km² imagery + manifests + descriptors fits budget or reports explicit split budget. -- FDR 8-hour load: <=64 GB, rollover logged, no silent payload loss. -- Monte Carlo false-position and cache-poisoning tests for AC-NEW-4 and AC-NEW-7. -- Cold boot: first valid `GPS_INPUT` <30 s p95 across 50 runs. - -## References - -Detailed source registry: `_docs/00_research/01_source_registry.md`. - -Key added Mode B sources: -- DINOv2 TensorRT issue: https://github.com/NVIDIA/TensorRT/issues/4348 -- DINOv2 Jetson forum issue: https://forums.developer.nvidia.com/t/dinov2-tensorrt-model-performance-issue/312251 -- LightGlue license discussion: https://github.com/cvg/LightGlue/issues/120 -- ArduPilot GPS_INPUT velocity issue: https://github.com/ArduPilot/ardupilot/issues/19633 -- FAISS install docs: https://github.com/facebookresearch/faiss/blob/main/INSTALL.md -- Orthophoto visual geolocalization: https://ar5iv.labs.arxiv.org/html/2103.14381 - -## Related Artifacts - -- Tech stack evaluation: `_docs/01_solution/tech_stack.md` -- Component fit matrix: `_docs/00_research/06_component_fit_matrix.md` -- Fact cards: `_docs/00_research/02_fact_cards.md` diff --git a/_docs/01_solution/solution_draft03.md b/_docs/01_solution/solution_draft03.md deleted file mode 100644 index 051f04d..0000000 --- a/_docs/01_solution/solution_draft03.md +++ /dev/null @@ -1,491 +0,0 @@ -# Solution Draft - -## Assessment Findings - -| Old Component Solution | Weak Point (functional/security/performance) | New Solution | -|------------------------|----------------------------------------------|-------------| -| FastAPI + SSE as primary output | **Functional**: New AC requires MAVLink GPS_INPUT to flight controller, not REST/SSE. The system must act as a GPS replacement module. SSE is wrong output channel. | **Replace with pymavlink GPS_INPUT sender**. Send GPS_INPUT at 5-10Hz to flight controller via UART. Retain minimal FastAPI only for local IPC (object localization API). | -| No ground station integration | **Functional**: New AC requires streaming position+confidence to ground station and receiving re-localization commands via telemetry. Draft02 had no telemetry. | **MAVLink telemetry integration**: GPS data forwarded automatically by flight controller. Custom data via NAMED_VALUE_FLOAT (confidence, drift). Re-localization hints via COMMAND_LONG listener. | -| MAVSDK library (per restriction) | **Functional**: MAVSDK-Python v3.15.3 cannot send GPS_INPUT messages. Feature requested since 2021, still unresolved. This is a blocking limitation for the core output function. | **Use pymavlink** for all MAVLink communication. pymavlink provides `gps_input_send()` and full MAVLink v2 access. Note conflict with restriction — pymavlink is the only viable option. | -| 3fps camera → ~3Hz output | **Performance**: ArduPilot GPS_RATE_MS minimum is 5Hz (200ms). 3Hz camera output is below minimum. Flight controller EKF may not fuse properly. | **IMU-interpolated 5-10Hz GPS_INPUT**: ESKF prediction runs at 100+Hz internally. Emit predicted state as GPS_INPUT at 5-10Hz. Camera corrections arrive at 3Hz within this stream. | -| No startup/failsafe procedures | **Functional**: New AC requires init from last GPS, reboot recovery, IMU-only fallback. Draft02 assumed position was already known. | **Full lifecycle management**: (1) Boot → read GPS from flight controller → init ESKF. (2) Reboot → read IMU-extrapolated position → re-init. (3) N-second failure → stop GPS_INPUT → autopilot falls back to IMU. | -| Basic object localization (nadir only) | **Functional**: New AC adds AI camera with configurable angle and zoom. Nadir pixel-to-GPS is insufficient. | **Trigonometric projection for oblique camera**: ground_distance = alt × tan(tilt), bearing = heading + pan + pixel offset. Local API for AI system requests. | -| No thermal management | **Performance**: Jetson Orin Nano Super throttles at 80°C (GPU drops 1GHz→300MHz = 3x slowdown). Could blow 400ms budget. | **Thermal monitoring + adaptive pipeline**: Use 25W mode. Monitor via tegrastats. If temp >75°C → reduce satellite matching frequency. If >80°C → VO+IMU only. | -| ESKF covariance without explicit drift budget | **Functional**: New AC requires max 100m cumulative VO drift between satellite anchors. Draft02 uses covariance for keyframe selection but no explicit budget. | **Drift budget tracker**: √(σ_x² + σ_y²) from ESKF as drift estimate. When approaching 100m → force every-frame satellite matching. Report via horiz_accuracy in GPS_INPUT. | -| No satellite imagery validation | **Functional**: New AC requires ≥0.5 m/pixel, <2 years old. Draft02 didn't validate. | **Preprocessing validation step**: Check zoom 19 availability (0.3 m/pixel). Fall back to zoom 18 (0.6 m/pixel). Flag stale tiles. | -| "Ask user via API" for re-localization | **Functional**: New AC says send re-localization request to ground station via telemetry link, not REST API. Operator sends hint via telemetry. | **MAVLink re-localization protocol**: On 3 consecutive failures → send STATUSTEXT alert to ground station. Operator sends COMMAND_LONG with approximate lat/lon. System uses hint to constrain tile search. | - -## Product Solution Description - -A real-time GPS-denied visual navigation system for fixed-wing UAVs, running on a Jetson Orin Nano Super (8GB). The system replaces the GPS module for the flight controller by sending MAVLink GPS_INPUT messages via pymavlink over UART. Position is determined by fusing: (1) CUDA-accelerated visual odometry (cuVSLAM), (2) absolute position corrections from satellite image matching, and (3) IMU data from the flight controller. GPS_INPUT is sent at 5-10Hz, with camera-based corrections at 3Hz and IMU prediction filling the gaps. - -**Hard constraint**: Camera shoots at ~3fps (333ms interval). The full VO+ESKF pipeline must complete within 400ms per frame. GPS_INPUT output rate: 5-10Hz minimum (ArduPilot EKF requirement). - -**Output architecture**: -- **Primary**: pymavlink → GPS_INPUT to flight controller via UART (replaces GPS module) -- **Telemetry**: Flight controller auto-forwards GPS data to ground station. Custom NAMED_VALUE_FLOAT for confidence/drift at 1Hz -- **Commands**: Ground station → COMMAND_LONG → flight controller → pymavlink listener on companion computer -- **Local IPC**: Minimal FastAPI on localhost for object localization requests from AI systems - -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ OFFLINE (Before Flight) │ -│ Satellite Tiles → Download & Validate → Pre-resize → Store │ -│ (Google Maps) (≥0.5m/px, <2yr) (matcher res) (GeoHash) │ -│ Copy to Jetson storage │ -└─────────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ ONLINE (During Flight) │ -│ │ -│ STARTUP: │ -│ pymavlink → read GLOBAL_POSITION_INT → init ESKF → start cuVSLAM │ -│ │ -│ EVERY FRAME (3fps, 333ms interval): │ -│ ┌──────────────────────────────────────┐ │ -│ │ Nav Camera → Downsample (CUDA ~2ms) │ │ -│ │ → cuVSLAM VO+IMU (~9ms) │ │ -│ │ → ESKF measurement update │ │ -│ └──────────────────────────────────────┘ │ -│ │ -│ 5-10Hz CONTINUOUS (between camera frames): │ -│ ┌──────────────────────────────────────┐ │ -│ │ ESKF IMU prediction → GPS_INPUT send │──→ Flight Controller │ -│ │ (pymavlink, every 100-200ms) │ (GPS1_TYPE=14) │ -│ └──────────────────────────────────────┘ │ -│ │ -│ KEYFRAMES (every 3-10 frames, async): │ -│ ┌──────────────────────────────────────┐ │ -│ │ Satellite match (CUDA stream B) │──→ ESKF correction │ -│ │ LiteSAM TRT FP16 or XFeat │ │ -│ └──────────────────────────────────────┘ │ -│ │ -│ TELEMETRY (1Hz): │ -│ ┌──────────────────────────────────────┐ │ -│ │ NAMED_VALUE_FLOAT: confidence, drift │──→ Ground Station │ -│ │ STATUSTEXT: alerts, re-loc requests │ (via telemetry radio) │ -│ └──────────────────────────────────────┘ │ -│ │ -│ COMMANDS (from ground station): │ -│ ┌──────────────────────────────────────┐ │ -│ │ Listen COMMAND_LONG: re-loc hint │←── Ground Station │ -│ │ (lat/lon from operator) │ (via telemetry radio) │ -│ └──────────────────────────────────────┘ │ -│ │ -│ LOCAL IPC: │ -│ ┌──────────────────────────────────────┐ │ -│ │ FastAPI localhost:8000 │←── AI Detection System │ -│ │ POST /localize (object GPS calc) │ │ -│ │ GET /status (system health) │ │ -│ └──────────────────────────────────────┘ │ -│ │ -│ IMU: 100+Hz from flight controller → ESKF prediction │ -│ TILES: ±2km preloaded in RAM from flight plan │ -│ THERMAL: Monitor via tegrastats, adaptive pipeline throttling │ -└─────────────────────────────────────────────────────────────────────┘ -``` - -## Speed Optimization Techniques - -### 1. cuVSLAM for Visual Odometry (~9ms/frame) -NVIDIA's CUDA-accelerated VO library (PyCuVSLAM v15.0.0, March 2026) achieves 116fps on Jetson Orin Nano 8GB at 720p. Supports monocular camera + IMU natively. Auto-fallback to IMU when visual tracking fails, loop closure, Python and C++ APIs. - -**CRITICAL: cuVSLAM on low-texture terrain (agricultural fields, water)**: -cuVSLAM uses Shi-Tomasi corners + Lucas-Kanade optical flow (classical features). On uniform agricultural terrain: -- Few corners detected → sparse/unreliable tracking -- Frequent keyframe creation → heavier compute -- Tracking loss → IMU fallback (~1s) → constant-velocity integrator (~0.5s) -- cuVSLAM does NOT guarantee pose recovery after tracking loss - -**Mitigation**: -1. Increase satellite matching frequency when cuVSLAM keypoint count drops -2. IMU dead-reckoning bridge via ESKF (continues GPS_INPUT output during tracking loss) -3. Accept higher drift in featureless segments — report via horiz_accuracy -4. Keypoint density monitoring triggers adaptive satellite matching - -### 2. Keyframe-Based Satellite Matching -Not every frame needs satellite matching: -- cuVSLAM provides VO at every frame (~9ms) -- Satellite matching triggers on keyframes selected by: - - Fixed interval: every 3-10 frames - - ESKF covariance exceeds threshold (drift approaching budget) - - VO failure: cuVSLAM reports tracking loss - - Thermal: reduce frequency if temperature high - -### 3. Satellite Matcher Selection (Benchmark-Driven) - -**Context**: Our UAV-to-satellite matching is nadir-to-nadir (both top-down). Challenges are season/lighting differences and temporal changes, not extreme viewpoint gaps. - -**Candidate A: LiteSAM (opt) TRT FP16 @ 1280px** — Best satellite-aerial accuracy (RMSE@30 = 17.86m on UAV-VisLoc). 6.31M params. TensorRT FP16 with reparameterized MobileOne. Estimated ~165-330ms on Orin Nano Super with TRT FP16. - -**Candidate B: XFeat semi-dense** — ~50-100ms on Orin Nano Super. Fastest option. General-purpose but our nadir-nadir gap is small. - -**Decision rule** (day-one on Orin Nano Super): -1. Export LiteSAM (opt) to TensorRT FP16 -2. Benchmark at 1280px -3. If ≤200ms → LiteSAM at 1280px -4. If >200ms → XFeat - -### 4. TensorRT FP16 Optimization -LiteSAM's MobileOne backbone is reparameterizable — multi-branch collapses to single feed-forward at inference. INT8 safe only for MobileOne CNN layers, NOT for TAIFormer transformer components. - -### 5. CUDA Stream Pipelining -- Stream A: cuVSLAM VO for current frame (~9ms) + ESKF fusion (~1ms) -- Stream B: Satellite matching for previous keyframe (async, does not block VO) -- CPU: GPS_INPUT output loop, NAMED_VALUE_FLOAT, command listener, tile management - -### 6. Proactive Tile Loading -Preload tiles within ±2km of flight plan into RAM at startup. For a 50km route, ~2000 tiles at zoom 19 ≈ ~200MB. Eliminates disk I/O during flight. - -On VO failure / expanded search: -1. Compute IMU dead-reckoning position -2. Rank preloaded tiles by distance to predicted position -3. Try top 3 tiles, then expand - -### 7. 5-10Hz GPS_INPUT Output Loop -Dedicated thread/coroutine sends GPS_INPUT at fixed rate (5-10Hz): -1. Read current ESKF state (position, velocity, covariance) -2. Compute horiz_accuracy from √(σ_x² + σ_y²) -3. Set fix_type based on last correction type (3=satellite-corrected, 2=VO-only, 1=IMU-only) -4. Send via `mav.gps_input_send()` -5. Sleep until next interval - -This decouples camera frame rate (3fps) from GPS_INPUT rate (5-10Hz). - -## Existing/Competitor Solutions Analysis - -| Solution | Approach | Accuracy | Hardware | Limitations | -|----------|----------|----------|----------|-------------| -| Mateos-Ramirez et al. (2024) | VO (ORB) + satellite keypoint correction + Kalman | 142m mean / 17km (0.83%) | Orange Pi class | No re-localization; ORB only; 1000m+ altitude | -| SatLoc (2025) | DinoV2 + XFeat + optical flow + adaptive fusion | <15m, >90% coverage | Edge (unspecified) | Paper not fully accessible | -| LiteSAM (2025) | MobileOne + TAIFormer + MinGRU subpixel refinement | RMSE@30 = 17.86m on UAV-VisLoc | RTX 3090 (62ms), AGX Orin (497ms@1184px) | Not tested on Orin Nano | -| cuVSLAM (NVIDIA, 2025-2026) | CUDA-accelerated VO+SLAM, mono/stereo/IMU | <1% trajectory error (KITTI) | Jetson Orin Nano (116fps) | VO only, no satellite matching | -| EfficientLoFTR (CVPR 2024) | Aggregated attention + adaptive token selection | Competitive with LiteSAM | TRT available | 15.05M params, heavier | -| STHN (IEEE RA-L 2024) | Deep homography estimation | 4.24m at 50m range | Lightweight | Needs RGB retraining | -| JointLoc (IROS 2024) | Retrieval + VO fusion, adaptive weighting | 0.237m RMSE over 1km | Open-source | Planetary, needs adaptation | - -## Architecture - -### Component: Flight Controller Integration (NEW) - -| Solution | Tools | Advantages | Limitations | Performance | Fit | -|----------|-------|-----------|-------------|------------|-----| -| pymavlink GPS_INPUT | pymavlink | Full MAVLink v2 access, GPS_INPUT support, pure Python, aarch64 compatible | Lower-level API, manual message handling | ~1ms per send | ✅ Best | -| MAVSDK-Python TelemetryServer | MAVSDK v3.15.3 | Higher-level API, aarch64 wheels | NO GPS_INPUT support, no custom messages | N/A — missing feature | ❌ Blocked | -| MAVSDK C++ MavlinkDirect | MAVSDK v4 (future) | Custom message support planned | Not available in Python wrapper yet | N/A — not released | ❌ Not available | -| MAVROS (ROS) | ROS + MAVROS | Full GPS_INPUT support, ROS ecosystem | Heavy ROS dependency, complex setup, unnecessary overhead | ~5ms overhead | ⚠️ Overkill | - -**Selected**: **pymavlink** — only viable Python library for GPS_INPUT. Pure Python, works on aarch64, full MAVLink v2 message set. - -**Restriction note**: restrictions.md specifies "MAVSDK library" but MAVSDK-Python cannot send GPS_INPUT (confirmed: Issue #320, open since 2021). pymavlink is the necessary alternative. - -Configuration: -- Connection: UART (`/dev/ttyTHS0` or `/dev/ttyTHS1` on Jetson, 115200-921600 baud) -- Flight controller: GPS1_TYPE=14, SERIAL2_PROTOCOL=2 (MAVLink2) -- GPS_INPUT rate: 5-10Hz (dedicated output thread) -- Heartbeat: 1Hz to maintain connection - -### Component: Visual Odometry - -| Solution | Tools | Advantages | Limitations | Performance | Fit | -|----------|-------|-----------|-------------|------------|-----| -| cuVSLAM (mono+IMU) | PyCuVSLAM v15.0.0 | 116fps on Orin Nano, NVIDIA-optimized, loop closure, IMU fallback | Closed-source, low-texture terrain risk | ~9ms/frame | ✅ Best | -| XFeat frame-to-frame | XFeatTensorRT | Open-source, learned features | No IMU integration, ~30-50ms | ~30-50ms/frame | ⚠️ Fallback | -| ORB-SLAM3 | OpenCV + custom | Well-understood, open-source | CPU-heavy, ~30fps | ~33ms/frame | ⚠️ Slower | - -**Selected**: **cuVSLAM (mono+IMU mode)** — 116fps, purpose-built for Jetson. - -### Component: Satellite Image Matching - -| Solution | Tools | Advantages | Limitations | Performance | Fit | -|----------|-------|-----------|-------------|------------|-----| -| LiteSAM (opt) TRT FP16 @ 1280px | TensorRT | Best satellite-aerial accuracy, 6.31M params | Untested on Orin Nano Super TRT | Est. ~165-330ms TRT FP16 | ✅ If ≤200ms | -| XFeat semi-dense | XFeatTensorRT | ~50-100ms, Jetson-proven, fastest | General-purpose | ~50-100ms | ✅ Fallback | - -**Selection**: Day-one benchmark. LiteSAM TRT FP16 at 1280px → if ≤200ms → LiteSAM. If >200ms → XFeat. - -### Component: Sensor Fusion - -| Solution | Tools | Advantages | Limitations | Performance | Fit | -|----------|-------|-----------|-------------|------------|-----| -| ESKF (custom) | Python/C++ | Lightweight, multi-rate, well-understood | Linear approximation | <1ms/step | ✅ Best | -| Hybrid ESKF/UKF | Custom | 49% better accuracy | More complex | ~2-3ms/step | ⚠️ Upgrade path | - -**Selected**: **ESKF** with adaptive measurement noise. State vector: [position(3), velocity(3), orientation_quat(4), accel_bias(3), gyro_bias(3)] = 16 states. - -**Output rates**: -- IMU prediction: 100+Hz (from flight controller IMU via pymavlink) -- cuVSLAM VO update: ~3Hz -- Satellite update: ~0.3-1Hz (keyframes, async) -- GPS_INPUT output: 5-10Hz (ESKF predicted state) - -**Drift budget**: Track √(σ_x² + σ_y²) from ESKF covariance. When approaching 100m → force every-frame satellite matching. - -### Component: Ground Station Telemetry (NEW) - -| Solution | Tools | Advantages | Limitations | Performance | Fit | -|----------|-------|-----------|-------------|------------|-----| -| MAVLink auto-forwarding + NAMED_VALUE_FLOAT | pymavlink | Standard MAVLink, no custom protocol, works with all GCS (Mission Planner, QGC) | Limited bandwidth (~12kbit/s), NAMED_VALUE_FLOAT name limited to 10 chars | ~50 bytes/msg | ✅ Best | -| Custom MAVLink dialect messages | pymavlink + custom XML | Full flexibility | Requires custom GCS plugin, non-standard | ~50 bytes/msg | ⚠️ Complex | -| Separate telemetry channel | TCP/UDP over separate radio | Full bandwidth | Extra hardware, extra radio | N/A | ❌ Not available | - -**Selected**: **Standard MAVLink forwarding + NAMED_VALUE_FLOAT** - -Telemetry data sent to ground station: -- GPS position: auto-forwarded by flight controller from GPS_INPUT data -- Confidence score: NAMED_VALUE_FLOAT `"gps_conf"` at 1Hz (values: 1=HIGH, 2=MEDIUM, 3=LOW, 4=VERY_LOW) -- Drift estimate: NAMED_VALUE_FLOAT `"gps_drift"` at 1Hz (meters) -- Matching status: NAMED_VALUE_FLOAT `"sat_match"` at 1Hz (0=inactive, 1=matching, 2=failed) -- Alerts: STATUSTEXT for critical events (re-localization request, system failure) - -Re-localization from ground station: -- Operator sees drift/failure alert in GCS -- Sends COMMAND_LONG (MAV_CMD_USER_1) with lat/lon in param5/param6 -- Companion computer listens for COMMAND_LONG with target component ID -- Receives hint → constrains tile search → attempts satellite matching near hint coordinates - -### Component: Startup & Lifecycle (NEW) - -**Startup sequence**: -1. Boot Jetson → start GPS-Denied service (systemd) -2. Connect to flight controller via pymavlink on UART -3. Wait for heartbeat from flight controller -4. Read GLOBAL_POSITION_INT → extract lat, lon, alt -5. Initialize ESKF state with this position (high confidence if real GPS available) -6. Start cuVSLAM with first camera frames -7. Begin GPS_INPUT output loop at 5-10Hz -8. Preload satellite tiles within ±2km of flight plan into RAM -9. System ready — GPS-Denied active - -**GPS denial detection**: -Not required — the system always outputs GPS_INPUT. If real GPS is available, the flight controller uses whichever GPS source has better accuracy (configurable GPS blending or priority). When real GPS degrades/lost, flight controller seamlessly uses our GPS_INPUT. - -**Failsafe**: -- If no valid position estimate for N seconds (configurable, e.g., 10s): stop sending GPS_INPUT -- Flight controller detects GPS timeout → falls back to IMU-only dead reckoning -- System logs failure, continues attempting recovery (VO + satellite matching) -- When recovery succeeds: resume GPS_INPUT output - -**Reboot recovery**: -1. Jetson reboots → re-establish pymavlink connection -2. Read GPS_RAW_INT (now IMU-extrapolated by flight controller since GPS_INPUT stopped) -3. Initialize ESKF with this position (low confidence, horiz_accuracy=100m+) -4. Resume cuVSLAM + satellite matching → accuracy improves over time -5. Resume GPS_INPUT output - -### Component: Object Localization (UPDATED) - -**Two modes**: - -**Mode 1: Navigation camera (nadir)** -Frame-center GPS from ESKF. Any object in navigation camera frame: -1. Pixel offset from center: (dx_px, dy_px) -2. Convert to meters: dx_m = dx_px × GSD, dy_m = dy_px × GSD -3. Rotate by heading (yaw from IMU) -4. Convert meter offset to lat/lon delta, add to frame-center GPS - -**Mode 2: AI camera (configurable angle and zoom)** -1. Get current UAV position from ESKF -2. Get AI camera params: tilt_angle (from vertical), pan_angle (from heading), zoom (effective focal length) -3. Get pixel coordinates of detected object in AI camera frame -4. Compute bearing: bearing = heading + pan_angle + atan2(dx_px × sensor_width / focal_eff, focal_eff) -5. Compute ground distance: for flat terrain, slant_range = altitude / cos(tilt_angle + dy_angle), ground_range = slant_range × sin(tilt_angle + dy_angle) -6. Convert bearing + ground_range to lat/lon offset -7. Return GPS coordinates with accuracy estimate - -**Local API** (FastAPI on localhost:8000): -- `POST /localize` — accepts: pixel_x, pixel_y, camera_id ("nav" or "ai"), ai_camera_params (tilt, pan, zoom) → returns: lat, lon, accuracy_m -- `GET /status` — returns: system state, confidence, drift, uptime - -### Component: Satellite Tile Preprocessing (Offline) - -**Selected**: GeoHash-indexed tile pairs on disk + RAM preloading. - -Pipeline: -1. Define operational area from flight plan -2. Download satellite tiles from Google Maps Tile API at zoom 19 (0.3 m/pixel) -3. If zoom 19 unavailable: fall back to zoom 18 (0.6 m/pixel — meets ≥0.5 m/pixel requirement) -4. Validate: resolution ≥0.5 m/pixel, check imagery staleness where possible -5. Pre-resize each tile to matcher input resolution -6. Store: original + resized + metadata (GPS bounds, zoom, GSD, download date) in GeoHash-indexed structure -7. Copy to Jetson storage before flight -8. At startup: preload tiles within ±2km of flight plan into RAM - -### Component: Re-localization (Disconnected Segments) - -When cuVSLAM reports tracking loss (sharp turn, no features): -1. Flag next frame as keyframe → trigger satellite matching -2. Compute IMU dead-reckoning position since last known position -3. Rank preloaded tiles by distance to dead-reckoning position -4. Try top 3 tiles sequentially -5. If match found: position recovered, new segment begins -6. If 3 consecutive keyframe failures: send STATUSTEXT alert to ground station ("RE-LOC REQUEST: position uncertain, drift Xm") -7. While waiting for operator hint: continue VO/IMU dead reckoning, report low confidence via horiz_accuracy -8. If operator sends COMMAND_LONG with lat/lon hint: constrain tile search to ±500m of hint -9. If still no match after operator hint: continue dead reckoning, log failure - -### Component: Thermal Management (NEW) - -**Power mode**: 25W (stable sustained performance) - -**Monitoring**: Read GPU/CPU temperature via tegrastats or sysfs thermal zones at 1Hz. - -**Adaptive pipeline**: -- Normal (<70°C): Full pipeline — cuVSLAM every frame + satellite match every 3-10 frames -- Warm (70-75°C): Reduce satellite matching to every 5-10 frames -- Hot (75-80°C): Reduce satellite matching to every 10-15 frames -- Throttling (>80°C): Disable satellite matching entirely, VO+IMU only (cuVSLAM ~9ms is very light). Report LOW confidence. Resume satellite matching when temp drops below 75°C - -**Hardware requirement**: Active cooling fan (5V) mandatory for UAV companion computer enclosure. - -## Processing Time Budget (per frame, 333ms interval) - -### Normal Frame (non-keyframe, ~60-80% of frames) - -| Step | Time | Notes | -|------|------|-------| -| Image capture + transfer | ~10ms | CSI/USB3 | -| Downsample (for cuVSLAM) | ~2ms | OpenCV CUDA | -| cuVSLAM VO+IMU | ~9ms | NVIDIA CUDA-optimized, 116fps | -| ESKF measurement update | ~1ms | NumPy | -| **Total per camera frame** | **~22ms** | Well within 333ms | - -GPS_INPUT output runs independently at 5-10Hz (every 100-200ms): -| Step | Time | Notes | -|------|------|-------| -| Read ESKF state | <0.1ms | Shared state | -| Compute horiz_accuracy | <0.1ms | √(σ²) | -| pymavlink gps_input_send | ~1ms | UART write | -| **Total per GPS_INPUT** | **~1ms** | Negligible overhead | - -### Keyframe Satellite Matching (async, every 3-10 frames) - -Runs on separate CUDA stream — does NOT block VO or GPS_INPUT. - -**Path A — LiteSAM TRT FP16 at 1280px (if ≤200ms benchmark)**: - -| Step | Time | Notes | -|------|------|-------| -| Downsample to 1280px | ~1ms | OpenCV CUDA | -| Load satellite tile | ~1ms | Pre-loaded in RAM | -| LiteSAM (opt) TRT FP16 | ≤200ms | Go/no-go threshold | -| Geometric pose (RANSAC) | ~5ms | Homography | -| ESKF satellite update | ~1ms | Delayed measurement | -| **Total** | **≤210ms** | Async | - -**Path B — XFeat (if LiteSAM >200ms)**: - -| Step | Time | Notes | -|------|------|-------| -| XFeat extraction + matching | ~50-80ms | TensorRT FP16 | -| Geometric verification (RANSAC) | ~5ms | | -| ESKF satellite update | ~1ms | | -| **Total** | **~60-90ms** | Async | - -## Memory Budget (Jetson Orin Nano Super, 8GB shared) - -| Component | Memory | Notes | -|-----------|--------|-------| -| OS + runtime | ~1.5GB | JetPack 6.2 + Python | -| cuVSLAM | ~200-500MB | CUDA library + map state (configure pruning for 3000 frames) | -| Satellite matcher TensorRT | ~50-100MB | LiteSAM FP16 or XFeat FP16 | -| Preloaded satellite tiles | ~200MB | ±2km of flight plan | -| pymavlink + MAVLink runtime | ~20MB | Lightweight | -| FastAPI (local IPC) | ~50MB | Minimal, localhost only | -| Current frame buffer | ~2MB | | -| ESKF state + buffers | ~10MB | | -| **Total** | **~2.1-2.9GB** | ~26-36% of 8GB — comfortable | - -## Confidence Scoring → GPS_INPUT Mapping - -| Level | Condition | horiz_accuracy (m) | fix_type | GPS_INPUT satellites_visible | -|-------|-----------|---------------------|----------|------------------------------| -| HIGH | Satellite match succeeded + cuVSLAM consistent | 10-20 | 3 (3D) | 12 | -| MEDIUM | cuVSLAM VO only, recent satellite correction (<500m travel) | 20-50 | 3 (3D) | 8 | -| LOW | cuVSLAM VO only, no recent correction, OR high thermal throttling | 50-100 | 2 (2D) | 4 | -| VERY LOW | IMU dead-reckoning only | 100-500 | 1 (no fix) | 1 | -| MANUAL | Operator-provided re-localization hint | 200 | 3 (3D) | 6 | - -Note: `satellites_visible` is synthetic — used to influence EKF weighting. ArduPilot gives more weight to GPS with higher satellite count and lower horiz_accuracy. - -## Key Risks and Mitigations - -| Risk | Likelihood | Impact | Mitigation | -|------|-----------|--------|------------| -| **MAVSDK cannot send GPS_INPUT** | CONFIRMED | Must use pymavlink (conflicts with restriction) | Use pymavlink. Document restriction conflict. No alternative in Python. | -| **cuVSLAM fails on low-texture agricultural terrain** | HIGH | Frequent tracking loss, degraded VO | Increase satellite matching frequency. IMU dead-reckoning bridge. Accept higher drift. | -| **Jetson UART instability with ArduPilot** | MEDIUM | MAVLink connection drops | Test thoroughly. Use USB serial adapter if UART unreliable. Add watchdog reconnect. | -| **Thermal throttling blows satellite matching budget** | MEDIUM | Miss keyframe windows | Adaptive pipeline: reduce/skip satellite matching at high temp. Active cooling mandatory. | -| LiteSAM TRT FP16 >200ms at 1280px | MEDIUM | Must use XFeat | Day-one benchmark. XFeat fallback. | -| XFeat cross-view accuracy insufficient | MEDIUM | Satellite corrections less accurate | Multi-tile consensus, strict RANSAC, increase keyframe frequency. | -| cuVSLAM map memory growth on long flights | MEDIUM | Memory pressure | Configure map pruning, max keyframes. | -| Google Maps satellite quality in conflict zone | HIGH | Satellite matching fails | Accept VO+IMU with higher drift. Alternative providers. | -| GPS_INPUT at 3Hz too slow for ArduPilot EKF | HIGH | Poor EKF fusion, position jumps | 5-10Hz output with IMU interpolation between camera frames. | -| Companion computer reboot mid-flight | LOW | ~30-60s GPS gap | Flight controller IMU fallback. Automatic recovery on restart. | -| Telemetry bandwidth saturation | LOW | Custom messages compete with autopilot telemetry | Limit NAMED_VALUE_FLOAT to 1Hz. Keep messages compact. | - -## Testing Strategy - -### Integration / Functional Tests -- End-to-end: camera → cuVSLAM → ESKF → GPS_INPUT → verify flight controller receives valid position -- Compare computed positions against ground truth GPS from coordinates.csv -- Measure: percentage within 50m (target: 80%), percentage within 20m (target: 60%) -- Test GPS_INPUT rate: verify 5-10Hz output to flight controller -- Test sharp-turn handling: verify satellite re-localization after 90-degree heading change -- Test disconnected segments: simulate 3+ route breaks, verify all segments connected -- Test re-localization: simulate 3 consecutive failures → verify STATUSTEXT sent → inject COMMAND_LONG hint → verify recovery -- Test object localization: send POST /localize with known AI camera params → verify GPS accuracy -- Test startup: verify ESKF initializes from flight controller GPS -- Test reboot recovery: kill process → restart → verify reconnection and position recovery -- Test failsafe: simulate total failure → verify GPS_INPUT stops → verify flight controller IMU fallback -- Test cuVSLAM map memory: run 3000-frame session, monitor memory growth - -### Non-Functional Tests -- **Day-one satellite matcher benchmark**: LiteSAM TRT FP16 at 1280px on Orin Nano Super -- cuVSLAM benchmark: verify 116fps monocular+IMU on Orin Nano Super -- cuVSLAM terrain stress test: urban, agricultural, water, forest -- **UART reliability test**: sustained pymavlink communication over 1+ hour -- **Thermal endurance test**: run full pipeline for 30+ minutes, measure GPU temp, verify no throttling with active cooling -- Per-frame latency: must be <400ms for VO pipeline -- GPS_INPUT latency: measure time from camera capture to GPS_INPUT send -- Memory: peak usage during 3000-frame session (must stay <8GB) -- Drift budget: verify ESKF covariance tracks cumulative drift, triggers satellite matching before 100m -- Telemetry bandwidth: measure total MAVLink bandwidth used by companion computer - -## References -- pymavlink GPS_INPUT example: https://webperso.ensta.fr/lebars/Share/GPS_INPUT_pymavlink.py -- pymavlink mavgps.py: https://github.com/ArduPilot/pymavlink/blob/master/examples/mavgps.py -- ArduPilot GPS Input module: https://ardupilot.org/mavproxy/docs/modules/GPSInput.html -- MAVLink GPS_INPUT message spec: https://mavlink.io/en/messages/common.html#GPS_INPUT -- MAVSDK-Python GPS_INPUT limitation: https://github.com/mavlink/MAVSDK-Python/issues/320 -- MAVSDK-Python custom message limitation: https://github.com/mavlink/MAVSDK-Python/issues/739 -- ArduPilot companion computer setup: https://ardupilot.org/dev/docs/raspberry-pi-via-mavlink.html -- Jetson Orin UART with ArduPilot: https://forums.developer.nvidia.com/t/uart-connection-between-jetson-nano-orin-and-ardupilot/325416 -- MAVLink NAMED_VALUE_FLOAT: https://mavlink.io/en/messages/common.html#NAMED_VALUE_FLOAT -- MAVLink STATUSTEXT: https://mavlink.io/en/messages/common.html#STATUSTEXT -- MAVLink telemetry bandwidth: https://github.com/mavlink/mavlink/issues/1605 -- JetPack 6.2 Super Mode: https://developer.nvidia.com/blog/nvidia-jetpack-6-2-brings-super-mode-to-nvidia-jetson-orin-nano-and-jetson-orin-nx-modules/ -- Jetson Orin Nano power consumption: https://edgeaistack.app/blog/jetson-orin-nano-power-consumption/ -- UAV target geolocation: https://www.mdpi.com/1424-8220/22/5/1903 -- LiteSAM (2025): https://www.mdpi.com/2072-4292/17/19/3349 -- LiteSAM code: https://github.com/boyagesmile/LiteSAM -- cuVSLAM (2025-2026): https://github.com/NVlabs/PyCuVSLAM -- PyCuVSLAM API: https://nvlabs.github.io/PyCuVSLAM/api.html -- Intermodalics cuVSLAM benchmark: https://www.intermodalics.ai/blog/nvidia-isaac-ros-in-depth-cuvslam-and-the-dp3-1-release -- XFeat (CVPR 2024): https://arxiv.org/abs/2404.19174 -- XFeat TensorRT for Jetson: https://github.com/PranavNedunghat/XFeatTensorRT -- EfficientLoFTR (CVPR 2024): https://github.com/zju3dv/EfficientLoFTR -- STHN (IEEE RA-L 2024): https://github.com/arplaboratory/STHN -- JointLoc (IROS 2024): https://github.com/LuoXubo/JointLoc -- Hybrid ESKF/UKF: https://arxiv.org/abs/2512.17505 -- Google Maps Tile API: https://developers.google.com/maps/documentation/tile/satellite -- ArduPilot EKF Source Selection: https://ardupilot.org/copter/docs/common-ekf-sources.html -- Mateos-Ramirez et al. (2024): https://www.mdpi.com/2076-3417/14/16/7420 -- SatLoc (2025): https://www.scilit.com/publications/e5cafaf875a49297a62b298a89d5572f - -## Related Artifacts -- AC Assessment: `_docs/00_research/gps_denied_nav/00_ac_assessment.md` -- Research artifacts: `_docs/00_research/gps_denied_nav_v3/` -- Tech stack evaluation: `_docs/01_solution/tech_stack.md` -- Security analysis: `_docs/01_solution/security_analysis.md` diff --git a/_docs/01_solution/solution_draft04.md b/_docs/01_solution/solution_draft04.md deleted file mode 100644 index 59d3f2a..0000000 --- a/_docs/01_solution/solution_draft04.md +++ /dev/null @@ -1,385 +0,0 @@ -# Solution Draft - -## Assessment Findings - -| Old Component Solution | Weak Point (functional/security/performance) | New Solution | -|------------------------|----------------------------------------------|-------------| -| ONNX Runtime as potential inference runtime for AI models | **Performance**: ONNX Runtime CUDA EP on Jetson Orin Nano is 7-8x slower than TRT standalone with default settings (tensor cores not utilized). Even TRT-EP shows up to 3x overhead on some models. | **Use native TRT Engine for all AI models**. Convert PyTorch → ONNX → trtexec → .engine. Load with tensorrt Python module. Eliminates ONNX Runtime dependency entirely. | -| ONNX Runtime TRT-EP memory overhead | **Performance**: ONNX RT TRT-EP keeps serialized engine in memory (~420-440MB vs 130-140MB native TRT). Delta ~280-300MB PER MODEL. On 8GB shared memory, this wastes ~560-600MB for two models. | **Native TRT releases serialized blob after deserialization** → saves ~280-300MB per model. Total savings ~560-600MB — 7% of total memory. Critical given cuVSLAM map growth risk. | -| No explicit TRT engine build step in offline pipeline | **Functional**: Draft03 mentions TRT FP16 but doesn't define the build workflow. When/where are engines built? | **Add TRT engine build to offline preparation pipeline**: After satellite tile download, run trtexec on Jetson to build .engine files. Store alongside tiles. One-time cost per model version. | -| Cross-platform portability via ONNX Runtime | **Functional**: ONNX Runtime's primary value is cross-platform support. Our deployment is Jetson-only — this value is zero. We pay the performance/memory tax for unused portability. | **Drop ONNX Runtime**. Jetson Orin Nano Super is fixed deployment hardware. TRT Engine is the optimal runtime for NVIDIA-only deployment. | -| No DLA offloading considered | **Performance**: Draft03 doesn't mention DLA. Jetson Orin Nano has NO DLA cores — only Orin NX (1-2) and AGX Orin (2) have DLA. | **Confirm: DLA offloading is NOT available on Orin Nano**. All inference must run on GPU (1024 CUDA cores, 16 tensor cores). This makes maximizing GPU efficiency via native TRT even more critical. | -| LiteSAM MinGRU TRT compatibility risk | **Functional**: LiteSAM's subpixel refinement uses 4 stacked MinGRU layers over a 3×3 candidate window (seq_len=9). MinGRU gates depend only on input C_f (not h_{t-1}), so z_t/h̃_t are pre-computable. Ops are standard: Linear, Sigmoid, Mul, Add, ReLU, Tanh. Risk is LOW-MEDIUM — depends on whether implementation uses logcumsumexp (problematic) or simple loop (fine). Seq_len=9 makes this trivially rewritable. | **Day-one verification**: clone LiteSAM repo → torch.onnx.export → polygraphy inspect → trtexec --fp16. If export fails on MinGRU: rewrite forward() as unrolled loop (9 steps). **If LiteSAM cannot be made TRT-compatible: replace with EfficientLoFTR TRT** (proven TRT path via Coarse_LoFTR_TRT, 15.05M params, semi-dense matching). | - -## Product Solution Description - -A real-time GPS-denied visual navigation system for fixed-wing UAVs, running on a Jetson Orin Nano Super (8GB). All AI model inference uses **native TensorRT Engine files** — no ONNX Runtime dependency. The system replaces the GPS module by sending MAVLink GPS_INPUT messages via pymavlink over UART at 5-10Hz. - -Position is determined by fusing: (1) CUDA-accelerated visual odometry (cuVSLAM — native CUDA), (2) absolute position corrections from satellite image matching (LiteSAM or XFeat — TRT Engine FP16), and (3) IMU data from the flight controller via ESKF. - -**Inference runtime decision**: Native TRT Engine over ONNX Runtime because: -1. ONNX RT CUDA EP is 7-8x slower on Orin Nano (tensor core bug) -2. ONNX RT TRT-EP wastes ~280-300MB per model (serialized engine retained in memory) -3. Cross-platform portability has zero value — deployment is Jetson-only -4. Native TRT provides direct CUDA stream control for pipelining with cuVSLAM - -**Hard constraint**: Camera shoots at ~3fps (333ms interval). Full VO+ESKF pipeline within 400ms. GPS_INPUT at 5-10Hz. - -**AI Model Runtime Summary**: - -| Model | Runtime | Precision | Memory | Integration | -|-------|---------|-----------|--------|-------------| -| cuVSLAM | Native CUDA (PyCuVSLAM) | N/A (closed-source) | ~200-500MB | CUDA Stream A | -| LiteSAM | TRT Engine | FP16 | ~50-80MB | CUDA Stream B | -| XFeat | TRT Engine | FP16 | ~30-50MB | CUDA Stream B (fallback) | -| ESKF | CPU (Python/C++) | FP64 | ~10MB | CPU thread | - -**Offline Preparation Pipeline** (before flight): -1. Download satellite tiles → validate → pre-resize → store (existing) -2. **NEW: Build TRT engines on Jetson** (one-time per model version) - - `trtexec --onnx=litesam_fp16.onnx --saveEngine=litesam.engine --fp16` - - `trtexec --onnx=xfeat.onnx --saveEngine=xfeat.engine --fp16` -3. Copy tiles + engines to Jetson storage -4. At startup: load engines + preload tiles into RAM - -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ OFFLINE (Before Flight) │ -│ 1. Satellite Tiles → Download & Validate → Pre-resize → Store │ -│ (Google Maps) (≥0.5m/px, <2yr) (matcher res) (GeoHash)│ -│ 2. TRT Engine Build (one-time per model version): │ -│ PyTorch model → reparameterize → ONNX export → trtexec --fp16 │ -│ Output: litesam.engine, xfeat.engine │ -│ 3. Copy tiles + engines to Jetson storage │ -└─────────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ ONLINE (During Flight) │ -│ │ -│ STARTUP: │ -│ 1. pymavlink → read GLOBAL_POSITION_INT → init ESKF │ -│ 2. Load TRT engines: litesam.engine + xfeat.engine │ -│ (tensorrt.Runtime → deserialize_cuda_engine → create_context) │ -│ 3. Allocate GPU buffers for TRT input/output (PyCUDA) │ -│ 4. Start cuVSLAM with first camera frames │ -│ 5. Preload satellite tiles ±2km into RAM │ -│ 6. Begin GPS_INPUT output loop at 5-10Hz │ -│ │ -│ EVERY FRAME (3fps, 333ms interval): │ -│ ┌──────────────────────────────────────┐ │ -│ │ Nav Camera → Downsample (CUDA ~2ms) │ │ -│ │ → cuVSLAM VO+IMU (~9ms) │ ← CUDA Stream A │ -│ │ → ESKF measurement update │ │ -│ └──────────────────────────────────────┘ │ -│ │ -│ 5-10Hz CONTINUOUS: │ -│ ┌──────────────────────────────────────┐ │ -│ │ ESKF IMU prediction → GPS_INPUT send │──→ Flight Controller │ -│ └──────────────────────────────────────┘ │ -│ │ -│ KEYFRAMES (every 3-10 frames, async): │ -│ ┌──────────────────────────────────────┐ │ -│ │ TRT Engine inference (Stream B): │ │ -│ │ context.enqueue_v3(stream_B) │──→ ESKF correction │ -│ │ LiteSAM FP16 or XFeat FP16 │ │ -│ └──────────────────────────────────────┘ │ -│ │ -│ TELEMETRY (1Hz): │ -│ ┌──────────────────────────────────────┐ │ -│ │ NAMED_VALUE_FLOAT: confidence, drift │──→ Ground Station │ -│ └──────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────────────┘ -``` - -## Architecture - -### Component: AI Model Inference Runtime - -| Solution | Tools | Advantages | Limitations | Performance | Memory | Fit | -|----------|-------|-----------|-------------|------------|--------|-----| -| Native TRT Engine | tensorrt Python + PyCUDA + trtexec | Optimal latency, minimal memory, full tensor core usage, direct CUDA stream control | Hardware-specific engines, manual buffer management, rebuild per TRT version | Optimal | ~50-130MB total (both models) | ✅ Best | -| ONNX Runtime TRT-EP | onnxruntime + TensorRT EP | Auto-fallback for unsupported ops, simpler API, auto engine caching | +280-300MB per model, wrapper overhead, first-run latency spike | Near-parity (claimed), up to 3x slower (observed) | ~640-690MB total (both models) | ❌ Memory overhead unacceptable | -| ONNX Runtime CUDA EP | onnxruntime + CUDA EP | Simplest API, broadest op support | 7-8x slower on Orin Nano (tensor core bug), no TRT optimizations | 7-8x slower | Standard | ❌ Performance unacceptable | -| Torch-TensorRT | torch_tensorrt | AOT compilation, PyTorch-native, handles mixed TRT/PyTorch | Newer on Jetson, requires PyTorch runtime at inference | Near native TRT | PyTorch runtime ~500MB+ | ⚠️ Viable alternative if TRT export fails | - -**Selected**: **Native TRT Engine** — optimal performance and memory on our fixed NVIDIA hardware. - -**Fallback**: If any model has unsupported TRT ops (e.g., MinGRU in LiteSAM), use **Torch-TensorRT** for that specific model. Torch-TensorRT handles mixed TRT/PyTorch execution but requires PyTorch runtime in memory. - -### Component: TRT Engine Conversion Workflow - -**LiteSAM conversion**: -1. Load PyTorch model with trained weights -2. Reparameterize MobileOne backbone (collapse multi-branch → single Conv2d+BN) -3. Export to ONNX: `torch.onnx.export(model, dummy_input, "litesam.onnx", opset_version=17)` -4. Verify with polygraphy: `polygraphy inspect model litesam.onnx` -5. Build engine on Jetson: `trtexec --onnx=litesam.onnx --saveEngine=litesam.engine --fp16 --memPoolSize=workspace:2048` -6. Verify engine: `trtexec --loadEngine=litesam.engine --fp16` - -**XFeat conversion**: -1. Load PyTorch model -2. Export to ONNX: `torch.onnx.export(model, dummy_input, "xfeat.onnx", opset_version=17)` -3. Build engine on Jetson: `trtexec --onnx=xfeat.onnx --saveEngine=xfeat.engine --fp16` -4. Alternative: use XFeatTensorRT C++ implementation directly - -**INT8 quantization strategy** (optional, future optimization): -- MobileOne backbone (CNN): INT8 safe with calibration data -- TAIFormer (transformer attention): FP16 only — INT8 degrades accuracy -- XFeat: evaluate INT8 on actual UAV-satellite pairs before deploying -- Use nvidia-modelopt for calibration: `from modelopt.onnx.quantization import quantize` - -### Component: TRT Python Inference Wrapper - -Minimal wrapper class for TRT engine inference: - -```python -import tensorrt as trt -import pycuda.driver as cuda - -class TRTInference: - def __init__(self, engine_path, stream): - self.logger = trt.Logger(trt.Logger.WARNING) - self.runtime = trt.Runtime(self.logger) - with open(engine_path, 'rb') as f: - self.engine = self.runtime.deserialize_cuda_engine(f.read()) - self.context = self.engine.create_execution_context() - self.stream = stream - self._allocate_buffers() - - def _allocate_buffers(self): - self.inputs = {} - self.outputs = {} - for i in range(self.engine.num_io_tensors): - name = self.engine.get_tensor_name(i) - shape = self.engine.get_tensor_shape(name) - dtype = trt.nptype(self.engine.get_tensor_dtype(name)) - size = trt.volume(shape) - device_mem = cuda.mem_alloc(size * np.dtype(dtype).itemsize) - self.context.set_tensor_address(name, int(device_mem)) - mode = self.engine.get_tensor_mode(name) - if mode == trt.TensorIOMode.INPUT: - self.inputs[name] = (device_mem, shape, dtype) - else: - self.outputs[name] = (device_mem, shape, dtype) - - def infer_async(self, input_data): - for name, data in input_data.items(): - cuda.memcpy_htod_async(self.inputs[name][0], data, self.stream) - self.context.enqueue_v3(self.stream.handle) - - def get_output(self): - results = {} - for name, (dev_mem, shape, dtype) in self.outputs.items(): - host_mem = np.empty(shape, dtype=dtype) - cuda.memcpy_dtoh_async(host_mem, dev_mem, self.stream) - self.stream.synchronize() - return results -``` - -Key design: `infer_async()` + `get_output()` split enables pipelining with cuVSLAM on Stream A while satellite matching runs on Stream B. - -### Component: Visual Odometry (UNCHANGED) - -cuVSLAM — native CUDA library, not affected by TRT migration. Already optimal. - -### Component: Satellite Image Matching (UPDATED runtime + fallback chain) - -| Solution | Tools | Advantages | Limitations | Performance (est. Orin Nano Super TRT FP16) | Params | Fit | -|----------|-------|-----------|-------------|----------------------------------------------|--------|-----| -| LiteSAM (opt) TRT Engine FP16 @ 1280px | trtexec + tensorrt Python | Best satellite-aerial accuracy (RMSE@30=17.86m UAV-VisLoc), 6.31M params, smallest model | MinGRU TRT export needs verification (LOW-MEDIUM risk) | Est. ~165-330ms | 6.31M | ✅ Primary (if TRT export succeeds AND ≤200ms) | -| EfficientLoFTR TRT Engine FP16 | trtexec + tensorrt Python | Proven TRT path (Coarse_LoFTR_TRT repo, 138 stars). Semi-dense. CVPR 2024. High accuracy. | 2.4x more params than LiteSAM. Requires einsum→elementary ops rewrite for TRT (documented in Coarse_LoFTR_TRT paper). | Est. ~200-400ms | 15.05M | ✅ Fallback if LiteSAM TRT fails | -| XFeat TRT Engine FP16 | trtexec + tensorrt Python (or XFeatTensorRT C++) | Fastest. Proven TRT implementation. Lightweight. | General-purpose, not designed for cross-view satellite-aerial gap (but nadir-nadir gap is small). | Est. ~50-100ms | <5M | ✅ Speed fallback | - -**Decision tree (day-one on Orin Nano Super)**: -1. Clone LiteSAM repo → reparameterize MobileOne → `torch.onnx.export()` → `polygraphy inspect` -2. If ONNX export succeeds → `trtexec --onnx=litesam.onnx --saveEngine=litesam.engine --fp16` -3. If MinGRU causes ONNX/TRT failure → rewrite MinGRU forward() as unrolled 9-step loop → retry -4. If rewrite fails or accuracy degrades → **switch to EfficientLoFTR TRT**: - - Apply Coarse_LoFTR_TRT TRT-adaptation techniques (einsum replacement, etc.) - - Export to ONNX → trtexec --fp16 - - Benchmark at 640×480 and 1280px -5. Benchmark winner: **if ≤200ms → use it. If >200ms but ≤300ms → acceptable (async on Stream B). If >300ms → use XFeat TRT** - -**EfficientLoFTR TRT adaptation** (from Coarse_LoFTR_TRT paper, proven workflow): -- Replace `torch.einsum()` with elementary ops (view, bmm, reshape, sum) -- Replace any TRT-incompatible high-level PyTorch functions -- Use ONNX export path (less memory required than Torch-TensorRT on 8GB device) -- Knowledge distillation available for further parameter reduction if needed - -### Component: Sensor Fusion (UNCHANGED) -ESKF — CPU-based mathematical filter, not affected. - -### Component: Flight Controller Integration (UNCHANGED) -pymavlink — not affected by TRT migration. - -### Component: Ground Station Telemetry (UNCHANGED) -MAVLink NAMED_VALUE_FLOAT — not affected. - -### Component: Startup & Lifecycle (UPDATED) - -**Updated startup sequence**: -1. Boot Jetson → start GPS-Denied service (systemd) -2. Connect to flight controller via pymavlink on UART -3. Wait for heartbeat from flight controller -4. **Initialize PyCUDA context** -5. **Load TRT engines**: litesam.engine + xfeat.engine via tensorrt.Runtime.deserialize_cuda_engine() -6. **Allocate GPU I/O buffers** for both models -7. **Create CUDA streams**: Stream A (cuVSLAM), Stream B (satellite matching) -8. Read GLOBAL_POSITION_INT → init ESKF -9. Start cuVSLAM with first camera frames -10. Begin GPS_INPUT output loop at 5-10Hz -11. Preload satellite tiles within ±2km into RAM -12. System ready - -**Engine load time**: ~1-3 seconds per engine (deserialization from .engine file). One-time cost at startup. - -### Component: Thermal Management (UNCHANGED) -Same adaptive pipeline. TRT engines are slightly more power-efficient than ONNX Runtime, but the difference is within noise. - -### Component: Object Localization (UNCHANGED) -Not affected — trigonometric calculation, no AI inference. - -## Speed Optimization Techniques - -### 1. cuVSLAM for Visual Odometry (~9ms/frame) -Unchanged from draft03. Native CUDA, not part of TRT migration. - -### 2. Native TRT Engine Inference (NEW) -All AI models run as pre-compiled TRT FP16 engines: -- Engine files built offline with trtexec (one-time per model version) -- Loaded at startup (~1-3s per engine) -- Inference via context.enqueue_v3() on dedicated CUDA Stream B -- GPU buffers pre-allocated — zero runtime allocation during flight -- No ONNX Runtime dependency — no framework overhead - -Memory advantage over ONNX Runtime TRT-EP: ~560-600MB saved (both models combined). -Latency advantage: eliminates ONNX wrapper overhead, guaranteed tensor core utilization. - -### 3. CUDA Stream Pipelining (REFINED) -- Stream A: cuVSLAM VO for current frame (~9ms) + ESKF fusion (~1ms) -- Stream B: TRT engine inference for satellite matching (LiteSAM or XFeat, async) -- CPU: GPS_INPUT output loop, NAMED_VALUE_FLOAT, command listener, tile management -- **NEW**: Both cuVSLAM and TRT engines use CUDA streams natively — no framework abstraction layer. Direct GPU scheduling. - -### 4-7. (UNCHANGED from draft03) -Keyframe-based satellite matching, TensorRT FP16 optimization, proactive tile loading, 5-10Hz GPS_INPUT output — all unchanged. - -## Processing Time Budget (per frame, 333ms interval) - -### Normal Frame (non-keyframe) -Unchanged from draft03 — cuVSLAM dominates at ~22ms total. - -### Keyframe Satellite Matching (async, CUDA Stream B) - -**Path A — LiteSAM TRT Engine FP16 at 1280px**: - -| Step | Time | Notes | -|------|------|-------| -| Downsample to 1280px | ~1ms | OpenCV CUDA | -| Load satellite tile | ~1ms | Pre-loaded in RAM | -| Copy input to GPU buffer | <0.5ms | PyCUDA memcpy_htod_async | -| LiteSAM TRT Engine FP16 | ≤200ms | context.enqueue_v3(stream_B) | -| Copy output from GPU | <0.5ms | PyCUDA memcpy_dtoh_async | -| Geometric pose (RANSAC) | ~5ms | Homography | -| ESKF satellite update | ~1ms | Delayed measurement | -| **Total** | **≤210ms** | Async on Stream B | - -**Path B — XFeat TRT Engine FP16**: - -| Step | Time | Notes | -|------|------|-------| -| XFeat TRT Engine inference | ~50-80ms | context.enqueue_v3(stream_B) | -| Geometric verification (RANSAC) | ~5ms | | -| ESKF satellite update | ~1ms | | -| **Total** | **~60-90ms** | Async on Stream B | - -## Memory Budget (Jetson Orin Nano Super, 8GB shared) - -| Component | Memory (Native TRT) | Memory (ONNX RT TRT-EP) | Notes | -|-----------|---------------------|--------------------------|-------| -| OS + runtime | ~1.5GB | ~1.5GB | JetPack 6.2 + Python | -| cuVSLAM | ~200-500MB | ~200-500MB | CUDA library + map | -| **LiteSAM TRT engine** | **~50-80MB** | **~330-360MB** | Native TRT vs TRT-EP. If LiteSAM fails: EfficientLoFTR ~100-150MB | -| **XFeat TRT engine** | **~30-50MB** | **~310-330MB** | Native TRT vs TRT-EP | -| Preloaded satellite tiles | ~200MB | ~200MB | ±2km of flight plan | -| pymavlink + MAVLink | ~20MB | ~20MB | | -| FastAPI (local IPC) | ~50MB | ~50MB | | -| ESKF + buffers | ~10MB | ~10MB | | -| ONNX Runtime framework | **0MB** | **~150MB** | Eliminated with native TRT | -| **Total** | **~2.1-2.9GB** | **~2.8-3.6GB** | | -| **% of 8GB** | **26-36%** | **35-45%** | | -| **Savings** | — | — | **~700MB saved with native TRT** | - -## Confidence Scoring → GPS_INPUT Mapping -Unchanged from draft03. - -## Key Risks and Mitigations - -| Risk | Likelihood | Impact | Mitigation | -|------|-----------|--------|------------| -| **LiteSAM MinGRU ops unsupported in TRT 10.3** | LOW-MEDIUM | LiteSAM TRT export fails | Day-one verification: ONNX export → polygraphy → trtexec. If MinGRU fails: (1) rewrite as unrolled 9-step loop, (2) if still fails: **switch to EfficientLoFTR TRT** (proven TRT path, Coarse_LoFTR_TRT, 15.05M params). XFeat TRT as speed fallback. | -| **TRT engine build OOM on 8GB Jetson** | LOW | Cannot build engines on target device | Our models are small (6.31M LiteSAM, <5M XFeat). OOM unlikely. If occurs: reduce --memPoolSize, or build on identical Orin Nano module with more headroom | -| **Engine incompatibility after JetPack update** | MEDIUM | Must rebuild engines | Include engine rebuild in JetPack update procedure. Takes minutes per model. | -| **MAVSDK cannot send GPS_INPUT** | CONFIRMED | Must use pymavlink | Unchanged from draft03 | -| **cuVSLAM fails on low-texture terrain** | HIGH | Frequent tracking loss | Unchanged from draft03 | -| **Thermal throttling** | MEDIUM | Satellite matching budget blown | Unchanged from draft03 | -| LiteSAM TRT FP16 >200ms at 1280px | MEDIUM | Must use fallback matcher | Day-one benchmark. Fallback chain: EfficientLoFTR TRT (if ≤300ms) → XFeat TRT (if all >300ms) | -| Google Maps satellite quality in conflict zone | HIGH | Satellite matching fails | Unchanged from draft03 | - -## Testing Strategy - -### Integration / Functional Tests -All tests from draft03 unchanged, plus: -- **TRT engine load test**: Verify litesam.engine and xfeat.engine load successfully on Jetson Orin Nano Super -- **TRT inference correctness**: Compare TRT engine output vs PyTorch reference output (max L1 error < 0.01) -- **CUDA Stream B pipelining**: Verify satellite matching on Stream B does not block cuVSLAM on Stream A -- **Engine pre-built validation**: Verify engine files from offline preparation work without rebuild at runtime - -### Non-Functional Tests -All tests from draft03 unchanged, plus: -- **TRT engine build time**: Measure trtexec build time for LiteSAM and XFeat on Orin Nano Super (expected: 1-5 minutes each) -- **TRT engine load time**: Measure deserialization time (expected: 1-3 seconds each) -- **Memory comparison**: Measure actual GPU memory with native TRT vs ONNX RT TRT-EP for both models -- **MinGRU TRT compatibility** (day-one blocker): - 1. Clone LiteSAM repo, load pretrained weights - 2. Reparameterize MobileOne backbone - 3. `torch.onnx.export(model, dummy, "litesam.onnx", opset_version=17)` - 4. `polygraphy inspect model litesam.onnx` — check for unsupported ops - 5. `trtexec --onnx=litesam.onnx --saveEngine=litesam.engine --fp16` - 6. If step 3 or 5 fails on MinGRU: rewrite MinGRU forward() as unrolled loop, retry - 7. If still fails: switch to EfficientLoFTR, apply Coarse_LoFTR_TRT adaptation - 8. Compare TRT output vs PyTorch reference (max L1 error < 0.01) -- **EfficientLoFTR TRT fallback benchmark** (if LiteSAM fails): apply TRT adaptation from Coarse_LoFTR_TRT → ONNX → trtexec → measure latency at 640×480 and 1280px -- **Tensor core utilization**: Verify with NSight that TRT engines use tensor cores (unlike ONNX RT CUDA EP) - -## References -- ONNX Runtime Issue #24085 (Jetson Orin Nano tensor core bug): https://github.com/microsoft/onnxruntime/issues/24085 -- ONNX Runtime Issue #20457 (TRT-EP memory overhead): https://github.com/microsoft/onnxruntime/issues/20457 -- ONNX Runtime Issue #12083 (TRT-EP vs native TRT): https://github.com/microsoft/onnxruntime/issues/12083 -- NVIDIA TensorRT 10 Python API: https://docs.nvidia.com/deeplearning/tensorrt/10.15.1/inference-library/python-api-docs.html -- TensorRT Best Practices: https://docs.nvidia.com/deeplearning/tensorrt/latest/performance/best-practices.html -- TensorRT engine hardware specificity: https://github.com/NVIDIA/TensorRT/issues/1920 -- trtexec ONNX conversion: https://nvidia-jetson.piveral.com/jetson-orin-nano/how-to-convert-onnx-to-engine-on-jetson-orin-nano-dev-board/ -- Torch-TensorRT JetPack 6.2: https://docs.pytorch.org/TensorRT/v2.10.0/getting_started/jetpack.html -- XFeatTensorRT: https://github.com/PranavNedunghat/XFeatTensorRT -- JetPack 6.2 Release Notes: https://docs.nvidia.com/jetson/archives/jetpack-archived/jetpack-62/release-notes/index.html -- Jetson Orin Nano Super: https://developer.nvidia.com/blog/nvidia-jetson-orin-nano-developer-kit-gets-a-super-boost/ -- DLA on Jetson Orin: https://developer.nvidia.com/blog/maximizing-deep-learning-performance-on-nvidia-jetson-orin-with-dla/ -- EfficientLoFTR (CVPR 2024): https://github.com/zju3dv/EfficientLoFTR -- EfficientLoFTR HuggingFace: https://huggingface.co/docs/transformers/en/model_doc/efficientloftr -- Coarse_LoFTR_TRT (TRT for embedded): https://github.com/Kolkir/Coarse_LoFTR_TRT -- Coarse_LoFTR_TRT paper: https://ar5iv.labs.arxiv.org/html/2202.00770 -- LoFTR_TRT: https://github.com/Kolkir/LoFTR_TRT -- minGRU ("Were RNNs All We Needed?"): https://huggingface.co/papers/2410.01201 -- minGRU PyTorch implementation: https://github.com/lucidrains/minGRU-pytorch -- LiteSAM paper (MinGRU details, Eqs 12-16): https://www.mdpi.com/2072-4292/17/19/3349 -- DALGlue (UAV feature matching, 2025): https://www.nature.com/articles/s41598-025-21602-5 -- All references from solution_draft03.md - -## Related Artifacts -- AC Assessment: `_docs/00_research/gps_denied_nav/00_ac_assessment.md` -- Research artifacts (this assessment): `_docs/00_research/trt_engine_migration/` -- Previous research: `_docs/00_research/gps_denied_nav_v3/` -- Tech stack evaluation: `_docs/01_solution/tech_stack.md` -- Security analysis: `_docs/01_solution/security_analysis.md` diff --git a/_docs/01_solution/solution_draft05.md b/_docs/01_solution/solution_draft05.md deleted file mode 100644 index 7e65167..0000000 --- a/_docs/01_solution/solution_draft05.md +++ /dev/null @@ -1,562 +0,0 @@ -# Solution Draft - -## Assessment Findings - -| Old Component Solution | Weak Point (functional/security/performance) | New Solution | -|------------------------|----------------------------------------------|-------------| -| ONNX Runtime as potential inference runtime for AI models | **Performance**: ONNX Runtime CUDA EP on Jetson Orin Nano is 7-8x slower than TRT standalone with default settings (tensor cores not utilized). Even TRT-EP shows up to 3x overhead on some models. | **Use native TRT Engine for all AI models**. Convert PyTorch → ONNX → trtexec → .engine. Load with tensorrt Python module. Eliminates ONNX Runtime dependency entirely. | -| ONNX Runtime TRT-EP memory overhead | **Performance**: ONNX RT TRT-EP keeps serialized engine in memory (~420-440MB vs 130-140MB native TRT). Delta ~280-300MB PER MODEL. On 8GB shared memory, this wastes ~560-600MB for two models. | **Native TRT releases serialized blob after deserialization** → saves ~280-300MB per model. Total savings ~560-600MB — 7% of total memory. Critical given cuVSLAM map growth risk. | -| No explicit TRT engine build step in offline pipeline | **Functional**: Draft03 mentions TRT FP16 but doesn't define the build workflow. When/where are engines built? | **Add TRT engine build to offline preparation pipeline**: After satellite tile download, run trtexec on Jetson to build .engine files. Store alongside tiles. One-time cost per model version. | -| Cross-platform portability via ONNX Runtime | **Functional**: ONNX Runtime's primary value is cross-platform support. Our deployment is Jetson-only — this value is zero. We pay the performance/memory tax for unused portability. | **Drop ONNX Runtime**. Jetson Orin Nano Super is fixed deployment hardware. TRT Engine is the optimal runtime for NVIDIA-only deployment. | -| No DLA offloading considered | **Performance**: Draft03 doesn't mention DLA. Jetson Orin Nano has NO DLA cores — only Orin NX (1-2) and AGX Orin (2) have DLA. | **Confirm: DLA offloading is NOT available on Orin Nano**. All inference must run on GPU (1024 CUDA cores, 16 tensor cores). This makes maximizing GPU efficiency via native TRT even more critical. | -| LiteSAM MinGRU TRT compatibility risk | **Functional**: LiteSAM's subpixel refinement uses 4 stacked MinGRU layers over a 3×3 candidate window (seq_len=9). MinGRU gates depend only on input C_f (not h_{t-1}), so z_t/h̃_t are pre-computable. Ops are standard: Linear, Sigmoid, Mul, Add, ReLU, Tanh. Risk is LOW-MEDIUM — depends on whether implementation uses logcumsumexp (problematic) or simple loop (fine). Seq_len=9 makes this trivially rewritable. | **Day-one verification**: clone LiteSAM repo → torch.onnx.export → polygraphy inspect → trtexec --fp16. If export fails on MinGRU: rewrite forward() as unrolled loop (9 steps). **If LiteSAM cannot be made TRT-compatible: replace with EfficientLoFTR TRT** (proven TRT path via Coarse_LoFTR_TRT, 15.05M params, semi-dense matching). | -| Camera shoots at ~3fps (draft03/04 hard constraint) | **Functional**: ADTI 20L V1 max continuous rate is **2.0 fps** (burst only, buffer-limited). ADTi recommends 1.5s per capture (**0.7 fps sustained**). 3fps is physically impossible. 2fps is not sustainable for multi-hour flights (buffer saturation + mechanical shutter wear). | **Revised to 0.7 fps sustained**. ADTI 20L V1 is the sole navigation camera — used for both cuVSLAM VO and satellite matching. At 70 km/h cruise and 600m altitude: 27.8m inter-frame displacement, ~175px pixel shift, **95.2% frame overlap** — within pyramid-assisted LK optical flow range. ESKF IMU prediction at 5-10Hz bridges 1.43s gaps between frames. Satellite matching triggered on keyframes from the same stream. Viewpro A40 Pro reserved for AI object detection only. | - -## UAV Platform - -### Airframe Configuration - -| Component | Specification | Weight | -|-----------|--------------|--------| -| Airframe | Custom 3.5m S-2 Glass Composite, Eppler 423 airfoil | ~4.5 kg | -| Battery | 2x VANT Semi-Solid State 6S 30Ah (22.2V, 666Wh each) | 5.30 kg (2.65 kg each) | -| Motor | T-Motor AT4125 KV540 (2000W peak, 5.5 kg thrust w/ APC 15x8) | 0.36 kg | -| Propulsion Acc. | ESC, 15x8 Folding Propeller, Servos, Cables | ~0.50 kg | -| Avionics | Pixhawk 6x + GPS | ~0.10 kg | -| Computing | NVIDIA Jetson Orin Nano Super Dev Kit | ~0.30 kg | -| Camera 1 | ADTI 20L V1 APS-C Camera + 16mm Lens | ~0.22 kg | -| Camera 2 | Viewpro A40 Pro (A40TPro) AI Gimbal | ~0.85 kg | -| Misc | Mounts, wiring, connectors | ~0.35 kg | -| **Total AUW** | | **~12.5 kg** | - -T-Motor AT4125 KV540 is spec'd for 8-10 kg fixed-wing. At 12.5 kg AUW, static thrust-to-weight is ~0.44. Flyable but margins are tight — weight optimization should be monitored. - -### Flight Performance (Max Endurance) - -Assumptions: wingspan 3.5m, mean chord ~0.30m, wing area S ~1.05 m², AR ~11.7, Eppler 423 Cl_max ~1.8, cruise altitude 800-1000m (ρ ~1.10 kg/m³). - -| Parameter | Value | -|-----------|-------| -| Stall speed (900m altitude) | 10.6 m/s (38 km/h) | -| Min-power speed (theoretical) | 12.0 m/s (43 km/h) — only 13% above stall, impractical | -| **Max endurance cruise (1.3× stall margin)** | **14 m/s (50 km/h)** | -| Best range speed | ~18 m/s (65 km/h) | - -| Energy Budget | Value | -|---------------|-------| -| Total battery energy | 1332 Wh (2 × 666 Wh) | -| Usable (80% DoD) | 1066 Wh | -| Climb to 900m (~5 min at 3 m/s) | −57 Wh | -| 10% reserve | ×0.9 | -| **Available for cruise** | **~908 Wh** | - -| Power Budget | Value | -|--------------|-------| -| Propulsion (L/D ~15, η_prop 0.65, η_motor 0.80) | ~212 W | -| Electronics (Pixhawk + Jetson + cameras + gimbal + servos) | ~55 W | -| **Total cruise power** | **~267 W** | - -| Endurance | Value | -|-----------|-------| -| **Max endurance (at 50 km/h)** | **~3.4 hours** | -| Total mission (incl. climb + reserve) | ~3.5 hours | -| Max range (at 65 km/h best-range speed) | ~209 km | - -### Camera 1: ADTI 20L V1 + 16mm Lens - -| Spec | Value | -|------|-------| -| Sensor | Sony CMOS APS-C, 23.2 × 15.4 mm | -| Resolution | 5456 × 3632 (20 MP) | -| Focal length | 16 mm | -| Shutter | Mechanical global inter-mirror shutter (ADTI product line) | -| Max continuous fps | **2.0 fps** (spec — burst rate, buffer-limited) | -| Sustained capture rate | **~0.7 fps** (ADTi recommended 1.5s per capture) | -| File formats | JPEG, RAW, RAW+JPEG | -| HDMI video output | 1080p 24p/30p, 1440×1080 30p | -| Weight | 118g body + ~100g lens | -| ISP | Socionext Milbeaut | -| Cooling | Active fan | - -**2.0 fps is a burst rate, not sustained.** The 2.0 fps spec is limited by the internal buffer (estimated 3-5 frames). Once the buffer fills, the camera throttles to the write pipeline speed of ~0.7 fps. The bottleneck chain: mechanical shutter actuation (~100-300ms) + ISP processing (demosaic, NR, JPEG compress) + storage write (~5-10 MB/frame JPEG). The 1.5s/capture recommendation guarantees the buffer never fills and accounts for thermal margin over multi-hour flights. - -**Mechanical shutter wear at sustained rates:** - -| Rate | Actuations per 3.5h flight | Est. flights before 150K shutter life | Est. flights before 500K shutter life | -|------|---------------------------|---------------------------------------|---------------------------------------| -| 2.0 fps (burst, unsustainable) | 25,200 | ~6 | ~20 | -| 1.0 fps | 12,600 | ~12 | ~40 | -| 0.7 fps (recommended) | 8,820 | ~17 | ~57 | - -The 20L V1 shutter lifespan is not documented. The higher-end 102PRO is rated at 500K actuations. The 20L as an entry-level model is likely 100K-150K. At 0.7 fps sustained, this gives ~11-57 flights depending on shutter rating. - -**Confirmed operational rate: 0.7 fps (JPEG mode) for both VO and satellite matching.** - -### Camera 1: Ground Coverage at Mission Altitude - -| Parameter | H = 600 m | H = 800 m | H = 1000 m | -|-----------|-----------|-----------|------------| -| Along-track footprint (15.4mm side) | 577 m | 770 m | 962 m | -| Cross-track footprint (23.2mm side) | 870 m | 1160 m | 1450 m | -| GSD | 15.9 cm/pixel | 21.3 cm/pixel | 26.6 cm/pixel | - -### Camera 1: Forward Overlap at 0.7 fps - -At 0.7 fps, distance between shots = V / 0.7. - -**At 70 km/h (19.4 m/s) — realistic cruise speed:** - -| Altitude | Along-track footprint | Shot gap (27.8m) | Forward overlap | Pixel shift | -|----------|-----------------------|------------------|-----------------|-------------| -| 600 m | 577 m | 27.8 m | **95.2%** | ~175 px | -| 800 m | 770 m | 27.8 m | **96.4%** | ~131 px | -| 1000 m | 962 m | 27.8 m | **97.1%** | ~105 px | - -**Across speed range (at 600m altitude, 0.7 fps):** - -| Speed | Frame gap | Pixel shift | Forward overlap | -|-------|-----------|-------------|-----------------| -| 50 km/h (14 m/s) | 20.0 m | ~126 px | 96.5% | -| 70 km/h (19.4 m/s) | 27.8 m | ~175 px | 95.2% | -| 90 km/h (25 m/s) | 35.7 m | ~224 px | 93.8% | - -Even at 90 km/h and the lowest altitude (600m), overlap remains >93%. The 16mm lens on APS-C at these altitudes produces a footprint so large that 0.7 fps provides massive redundancy for both VO and satellite matching. - -**For satellite matching specifically** (keyframe-based, every 5-10 camera frames): - -| Target overlap | Required gap (600m) | Time between shots (70 km/h) | Capture rate | -|----------------|---------------------|------------------------------|--------------| -| 80% | 115 m | 5.9 s | 0.17 fps | -| 70% | 173 m | 8.9 s | 0.11 fps | -| 60% | 231 m | 11.9 s | 0.084 fps | - -Even at the lowest altitude and highest speed, 1 satellite matching keyframe every 6-12 seconds gives 60-80% overlap. - -### Camera 2: Viewpro A40 Pro (A40TPro) AI Gimbal - -Dual EO/IR gimbal with AI tracking. Reserved for **AI object detection and tracking only** — not used for navigation. Operates independently from the navigation pipeline. - -### Camera Role Assignment - -| Role | Camera | Rate | Notes | -|------|--------|------|-------| -| Visual Odometry (cuVSLAM) | ADTI 20L V1 + 16mm | 0.7 fps (sustained) | Sole navigation camera. At 70 km/h: 27.8m/~175px displacement at 600m alt. 95%+ overlap. | -| Satellite Image Matching | ADTI 20L V1 + 16mm | Keyframes from VO stream (~every 5-10 frames) | Same image stream as VO. Subset routed to satellite matcher on Stream B. | -| AI Object Detection | Viewpro A40 Pro | Independent | Not part of navigation pipeline. | - -### cuVSLAM at 0.7 fps — Feasibility - -At 0.7 fps and 70 km/h cruise, inter-frame displacement is 27.8m. In pixel terms: - -| Altitude | Displacement | Pixel shift | % of image height | Overlap | -|----------|-------------|-------------|-------------------|---------| -| 600 m | 27.8 m | ~175 px | 4.8% | 95.2% | -| 800 m | 27.8 m | ~131 px | 3.6% | 96.4% | -| 1000 m | 27.8 m | ~105 px | 2.9% | 97.1% | - -cuVSLAM uses Lucas-Kanade optical flow with image pyramids. Standard LK handles 30-50px displacements on the base level; with 3-4 pyramid levels, effective search range extends to ~150-200px. At 600m altitude, the 175px shift is within this pyramid-assisted range. At 800-1000m, the shift drops to 105-131px — well within range. - -Key factors that make 0.7 fps viable at high altitude: -- **Large footprint**: The 16mm lens on APS-C at 600-1000m produces 577-962m along-track coverage. The aircraft moves only 4-5% of the frame between shots. -- **High texture from altitude**: At 600-1000m, each frame covers a large area with diverse terrain features (roads, field boundaries, structures) even in agricultural regions. -- **IMU bridging**: cuVSLAM's built-in IMU integrator provides pose prediction during the 1.43s gap between frames. ESKF IMU prediction runs at 5-10Hz for continuous GPS_INPUT output. -- **95%+ overlap**: Consecutive frames share >95% content — abundant features for matching. - -**Risk**: Over completely uniform terrain (e.g., single crop field filling entire 577m+ footprint), feature tracking may still fail. cuVSLAM falls back to IMU-only (~1s acceptable) then constant-velocity (~0.5s) before tracking loss. Satellite matching corrections every 5-10 frames bound accumulated drift. - -## Product Solution Description - -A real-time GPS-denied visual navigation system for fixed-wing UAVs, running on a Jetson Orin Nano Super (8GB). All AI model inference uses **native TensorRT Engine files** — no ONNX Runtime dependency. The system replaces the GPS module by sending MAVLink GPS_INPUT messages via pymavlink over UART at 5-10Hz. - -Position is determined by fusing: (1) CUDA-accelerated visual odometry (cuVSLAM — native CUDA) from ADTI 20L V1 at 0.7 fps sustained, (2) absolute position corrections from satellite image matching (LiteSAM or XFeat — TRT Engine FP16) using keyframes from the same ADTI image stream, and (3) IMU data from the flight controller via ESKF. Viewpro A40 Pro is reserved for AI object detection only. - -**Inference runtime decision**: Native TRT Engine over ONNX Runtime because: -1. ONNX RT CUDA EP is 7-8x slower on Orin Nano (tensor core bug) -2. ONNX RT TRT-EP wastes ~280-300MB per model (serialized engine retained in memory) -3. Cross-platform portability has zero value — deployment is Jetson-only -4. Native TRT provides direct CUDA stream control for pipelining with cuVSLAM - -**Hard constraint**: ADTI 20L V1 shoots at 0.7 fps sustained (1430ms interval). Full VO+ESKF pipeline within 400ms per frame. Satellite matching async on keyframes (every 5-10 camera frames). GPS_INPUT at 5-10Hz (ESKF IMU prediction fills gaps between camera frames). - -**AI Model Runtime Summary**: - -| Model | Runtime | Precision | Memory | Integration | -|-------|---------|-----------|--------|-------------| -| cuVSLAM | Native CUDA (PyCuVSLAM) | N/A (closed-source) | ~200-500MB | CUDA Stream A | -| LiteSAM | TRT Engine | FP16 | ~50-80MB | CUDA Stream B | -| XFeat | TRT Engine | FP16 | ~30-50MB | CUDA Stream B (fallback) | -| ESKF | CPU (Python/C++) | FP64 | ~10MB | CPU thread | - -**Offline Preparation Pipeline** (before flight): -1. Download satellite tiles → validate → pre-resize → store (existing) -2. **NEW: Build TRT engines on Jetson** (one-time per model version) - - `trtexec --onnx=litesam_fp16.onnx --saveEngine=litesam.engine --fp16` - - `trtexec --onnx=xfeat.onnx --saveEngine=xfeat.engine --fp16` -3. Copy tiles + engines to Jetson storage -4. At startup: load engines + preload tiles into RAM - -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ OFFLINE (Before Flight) │ -│ 1. Satellite Tiles → Download & Validate → Pre-resize → Store │ -│ (Google Maps) (≥0.5m/px, <2yr) (matcher res) (GeoHash)│ -│ 2. TRT Engine Build (one-time per model version): │ -│ PyTorch model → reparameterize → ONNX export → trtexec --fp16 │ -│ Output: litesam.engine, xfeat.engine │ -│ 3. Copy tiles + engines to Jetson storage │ -└─────────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ ONLINE (During Flight) │ -│ │ -│ STARTUP: │ -│ 1. pymavlink → read GLOBAL_POSITION_INT → init ESKF │ -│ 2. Load TRT engines: litesam.engine + xfeat.engine │ -│ (tensorrt.Runtime → deserialize_cuda_engine → create_context) │ -│ 3. Allocate GPU buffers for TRT input/output (PyCUDA) │ -│ 4. Start cuVSLAM with ADTI 20L V1 camera stream │ -│ 5. Preload satellite tiles ±2km into RAM │ -│ 6. Begin GPS_INPUT output loop at 5-10Hz │ -│ │ -│ EVERY CAMERA FRAME (0.7fps sustained from ADTI 20L V1): │ -│ ┌──────────────────────────────────────┐ │ -│ │ ADTI 20L V1 → Downsample (CUDA) │ │ -│ │ → cuVSLAM VO+IMU (~9ms) │ ← CUDA Stream A │ -│ │ → ESKF measurement │ │ -│ └──────────────────────────────────────┘ │ -│ │ -│ 5-10Hz CONTINUOUS (IMU-driven between camera frames): │ -│ ┌──────────────────────────────────────┐ │ -│ │ ESKF IMU prediction → GPS_INPUT send │──→ Flight Controller │ -│ └──────────────────────────────────────┘ │ -│ │ -│ KEYFRAMES (every 5-10 camera frames, async): │ -│ ┌──────────────────────────────────────┐ │ -│ │ Same ADTI frame → TRT inference (B): │ │ -│ │ context.enqueue_v3(stream_B) │──→ ESKF correction │ -│ │ LiteSAM FP16 or XFeat FP16 │ │ -│ └──────────────────────────────────────┘ │ -│ │ -│ TELEMETRY (1Hz): │ -│ ┌──────────────────────────────────────┐ │ -│ │ NAMED_VALUE_FLOAT: confidence, drift │──→ Ground Station │ -│ └──────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────────────┘ -``` - -## Architecture - -### Component: AI Model Inference Runtime - -| Solution | Tools | Advantages | Limitations | Performance | Memory | Fit | -|----------|-------|-----------|-------------|------------|--------|-----| -| Native TRT Engine | tensorrt Python + PyCUDA + trtexec | Optimal latency, minimal memory, full tensor core usage, direct CUDA stream control | Hardware-specific engines, manual buffer management, rebuild per TRT version | Optimal | ~50-130MB total (both models) | ✅ Best | -| ONNX Runtime TRT-EP | onnxruntime + TensorRT EP | Auto-fallback for unsupported ops, simpler API, auto engine caching | +280-300MB per model, wrapper overhead, first-run latency spike | Near-parity (claimed), up to 3x slower (observed) | ~640-690MB total (both models) | ❌ Memory overhead unacceptable | -| ONNX Runtime CUDA EP | onnxruntime + CUDA EP | Simplest API, broadest op support | 7-8x slower on Orin Nano (tensor core bug), no TRT optimizations | 7-8x slower | Standard | ❌ Performance unacceptable | -| Torch-TensorRT | torch_tensorrt | AOT compilation, PyTorch-native, handles mixed TRT/PyTorch | Newer on Jetson, requires PyTorch runtime at inference | Near native TRT | PyTorch runtime ~500MB+ | ⚠️ Viable alternative if TRT export fails | - -**Selected**: **Native TRT Engine** — optimal performance and memory on our fixed NVIDIA hardware. - -**Fallback**: If any model has unsupported TRT ops (e.g., MinGRU in LiteSAM), use **Torch-TensorRT** for that specific model. Torch-TensorRT handles mixed TRT/PyTorch execution but requires PyTorch runtime in memory. - -### Component: TRT Engine Conversion Workflow - -**LiteSAM conversion**: -1. Load PyTorch model with trained weights -2. Reparameterize MobileOne backbone (collapse multi-branch → single Conv2d+BN) -3. Export to ONNX: `torch.onnx.export(model, dummy_input, "litesam.onnx", opset_version=17)` -4. Verify with polygraphy: `polygraphy inspect model litesam.onnx` -5. Build engine on Jetson: `trtexec --onnx=litesam.onnx --saveEngine=litesam.engine --fp16 --memPoolSize=workspace:2048` -6. Verify engine: `trtexec --loadEngine=litesam.engine --fp16` - -**XFeat conversion**: -1. Load PyTorch model -2. Export to ONNX: `torch.onnx.export(model, dummy_input, "xfeat.onnx", opset_version=17)` -3. Build engine on Jetson: `trtexec --onnx=xfeat.onnx --saveEngine=xfeat.engine --fp16` -4. Alternative: use XFeatTensorRT C++ implementation directly - -**INT8 quantization strategy** (optional, future optimization): -- MobileOne backbone (CNN): INT8 safe with calibration data -- TAIFormer (transformer attention): FP16 only — INT8 degrades accuracy -- XFeat: evaluate INT8 on actual UAV-satellite pairs before deploying -- Use nvidia-modelopt for calibration: `from modelopt.onnx.quantization import quantize` - -### Component: TRT Python Inference Wrapper - -Minimal wrapper class for TRT engine inference: - -```python -import tensorrt as trt -import pycuda.driver as cuda - -class TRTInference: - def __init__(self, engine_path, stream): - self.logger = trt.Logger(trt.Logger.WARNING) - self.runtime = trt.Runtime(self.logger) - with open(engine_path, 'rb') as f: - self.engine = self.runtime.deserialize_cuda_engine(f.read()) - self.context = self.engine.create_execution_context() - self.stream = stream - self._allocate_buffers() - - def _allocate_buffers(self): - self.inputs = {} - self.outputs = {} - for i in range(self.engine.num_io_tensors): - name = self.engine.get_tensor_name(i) - shape = self.engine.get_tensor_shape(name) - dtype = trt.nptype(self.engine.get_tensor_dtype(name)) - size = trt.volume(shape) - device_mem = cuda.mem_alloc(size * np.dtype(dtype).itemsize) - self.context.set_tensor_address(name, int(device_mem)) - mode = self.engine.get_tensor_mode(name) - if mode == trt.TensorIOMode.INPUT: - self.inputs[name] = (device_mem, shape, dtype) - else: - self.outputs[name] = (device_mem, shape, dtype) - - def infer_async(self, input_data): - for name, data in input_data.items(): - cuda.memcpy_htod_async(self.inputs[name][0], data, self.stream) - self.context.enqueue_v3(self.stream.handle) - - def get_output(self): - results = {} - for name, (dev_mem, shape, dtype) in self.outputs.items(): - host_mem = np.empty(shape, dtype=dtype) - cuda.memcpy_dtoh_async(host_mem, dev_mem, self.stream) - self.stream.synchronize() - return results -``` - -Key design: `infer_async()` + `get_output()` split enables pipelining with cuVSLAM on Stream A while satellite matching runs on Stream B. - -### Component: Visual Odometry (UPDATED — camera rate corrected) - -cuVSLAM — native CUDA library. Fed by **ADTI 20L V1 at 0.7 fps sustained** (previously assumed 3fps which exceeds camera hardware limit; 2.0 fps spec is burst-only, not sustainable). At 70 km/h cruise the inter-frame displacement is 27.8m — at 600m altitude this translates to ~175px (4.8% of frame), within pyramid-assisted LK optical flow range. At 800-1000m altitude the pixel shift drops to 105-131px. 95%+ frame overlap ensures abundant features for matching. ESKF IMU prediction at 5-10Hz fills the position output between sparse camera frames. - -### Component: Satellite Image Matching (UPDATED runtime + fallback chain) - -| Solution | Tools | Advantages | Limitations | Performance (est. Orin Nano Super TRT FP16) | Params | Fit | -|----------|-------|-----------|-------------|----------------------------------------------|--------|-----| -| LiteSAM (opt) TRT Engine FP16 @ 1280px | trtexec + tensorrt Python | Best satellite-aerial accuracy (RMSE@30=17.86m UAV-VisLoc), 6.31M params, smallest model | MinGRU TRT export needs verification (LOW-MEDIUM risk) | Est. ~165-330ms | 6.31M | ✅ Primary (if TRT export succeeds AND ≤200ms) | -| EfficientLoFTR TRT Engine FP16 | trtexec + tensorrt Python | Proven TRT path (Coarse_LoFTR_TRT repo, 138 stars). Semi-dense. CVPR 2024. High accuracy. | 2.4x more params than LiteSAM. Requires einsum→elementary ops rewrite for TRT (documented in Coarse_LoFTR_TRT paper). | Est. ~200-400ms | 15.05M | ✅ Fallback if LiteSAM TRT fails | -| XFeat TRT Engine FP16 | trtexec + tensorrt Python (or XFeatTensorRT C++) | Fastest. Proven TRT implementation. Lightweight. | General-purpose, not designed for cross-view satellite-aerial gap (but nadir-nadir gap is small). | Est. ~50-100ms | <5M | ✅ Speed fallback | - -**Decision tree (day-one on Orin Nano Super)**: -1. Clone LiteSAM repo → reparameterize MobileOne → `torch.onnx.export()` → `polygraphy inspect` -2. If ONNX export succeeds → `trtexec --onnx=litesam.onnx --saveEngine=litesam.engine --fp16` -3. If MinGRU causes ONNX/TRT failure → rewrite MinGRU forward() as unrolled 9-step loop → retry -4. If rewrite fails or accuracy degrades → **switch to EfficientLoFTR TRT**: - - Apply Coarse_LoFTR_TRT TRT-adaptation techniques (einsum replacement, etc.) - - Export to ONNX → trtexec --fp16 - - Benchmark at 640×480 and 1280px -5. Benchmark winner: **if ≤200ms → use it. If >200ms but ≤300ms → acceptable (async on Stream B). If >300ms → use XFeat TRT** - -**EfficientLoFTR TRT adaptation** (from Coarse_LoFTR_TRT paper, proven workflow): -- Replace `torch.einsum()` with elementary ops (view, bmm, reshape, sum) -- Replace any TRT-incompatible high-level PyTorch functions -- Use ONNX export path (less memory required than Torch-TensorRT on 8GB device) -- Knowledge distillation available for further parameter reduction if needed - -**Satellite matching cadence**: Keyframes selected from the ADTI VO stream every 5-10 frames (~every 2.5-14s depending on camera fps setting). At 800-1000m altitude and 14 m/s cruise, this yields 60-97% forward overlap between satellite match frames. Matching runs async on Stream B — does not block VO on Stream A. - -### Component: Sensor Fusion (UNCHANGED) -ESKF — CPU-based mathematical filter, not affected. - -### Component: Flight Controller Integration (UNCHANGED) -pymavlink — not affected by TRT migration. - -### Component: Ground Station Telemetry (UNCHANGED) -MAVLink NAMED_VALUE_FLOAT — not affected. - -### Component: Startup & Lifecycle (UPDATED) - -**Updated startup sequence**: -1. Boot Jetson → start GPS-Denied service (systemd) -2. Connect to flight controller via pymavlink on UART -3. Wait for heartbeat from flight controller -4. **Initialize PyCUDA context** -5. **Load TRT engines**: litesam.engine + xfeat.engine via tensorrt.Runtime.deserialize_cuda_engine() -6. **Allocate GPU I/O buffers** for both models -7. **Create CUDA streams**: Stream A (cuVSLAM), Stream B (satellite matching) -8. Read GLOBAL_POSITION_INT → init ESKF -9. Start cuVSLAM with ADTI 20L V1 camera frames -10. Begin GPS_INPUT output loop at 5-10Hz -11. Preload satellite tiles within ±2km into RAM -12. System ready - -**Engine load time**: ~1-3 seconds per engine (deserialization from .engine file). One-time cost at startup. - -### Component: Thermal Management (UNCHANGED) -Same adaptive pipeline. TRT engines are slightly more power-efficient than ONNX Runtime, but the difference is within noise. - -### Component: Object Localization (UNCHANGED) -Not affected — trigonometric calculation, no AI inference. - -## Speed Optimization Techniques - -### 1. cuVSLAM for Visual Odometry (~9ms/frame) -Fed by ADTI 20L V1 at 0.7 fps sustained. At 70 km/h cruise and 600m altitude, inter-frame displacement is 27.8m (~175px, 4.8% of frame). With pyramid-based LK optical flow (3-4 levels), effective search range is ~150-200px — 175px is within range. At 800-1000m altitude, pixel shift drops to 105-131px. 95%+ overlap between consecutive frames. - -### 2. Native TRT Engine Inference (NEW) -All AI models run as pre-compiled TRT FP16 engines: -- Engine files built offline with trtexec (one-time per model version) -- Loaded at startup (~1-3s per engine) -- Inference via context.enqueue_v3() on dedicated CUDA Stream B -- GPU buffers pre-allocated — zero runtime allocation during flight -- No ONNX Runtime dependency — no framework overhead - -Memory advantage over ONNX Runtime TRT-EP: ~560-600MB saved (both models combined). -Latency advantage: eliminates ONNX wrapper overhead, guaranteed tensor core utilization. - -### 3. CUDA Stream Pipelining (REFINED) -- Stream A: cuVSLAM VO from ADTI 20L V1 (~9ms) + ESKF fusion (~1ms) -- Stream B: TRT engine inference for satellite matching (LiteSAM or XFeat, async, triggered on keyframe from same ADTI stream) -- CPU: GPS_INPUT output loop, NAMED_VALUE_FLOAT, command listener, tile management -- **NEW**: Both cuVSLAM and TRT engines use CUDA streams natively — no framework abstraction layer. Direct GPU scheduling. - -### 4-7. (UNCHANGED from draft03) -Keyframe-based satellite matching, TensorRT FP16 optimization, proactive tile loading, 5-10Hz GPS_INPUT output — all unchanged. - -## Processing Time Budget - -### VO Frame (every ~1430ms from ADTI 20L V1 at 0.7 fps) - -| Step | Time | Notes | -|------|------|-------| -| ADTI image transfer | ~5-10ms | Trigger + readout | -| Downsample (CUDA) | ~2ms | To cuVSLAM input resolution | -| cuVSLAM VO+IMU | ~9ms | CUDA Stream A | -| ESKF measurement update | ~1ms | CPU | -| **Total** | **~17-22ms** | Well within 1430ms budget | - -Between camera frames, ESKF IMU prediction runs at 5-10Hz to maintain continuous GPS_INPUT output. The ~1.4s gap between frames is bridged entirely by IMU integration. - -### Keyframe Satellite Matching (every 5-10 camera frames, async CUDA Stream B) - -**Path A — LiteSAM TRT Engine FP16 at 1280px**: - -| Step | Time | Notes | -|------|------|-------| -| Image already in GPU (from VO) | ~0ms | Same frame used for VO and matching | -| Load satellite tile | ~1ms | Pre-loaded in RAM | -| Copy input to GPU buffer | <0.5ms | PyCUDA memcpy_htod_async | -| LiteSAM TRT Engine FP16 | ≤200ms | context.enqueue_v3(stream_B) | -| Copy output from GPU | <0.5ms | PyCUDA memcpy_dtoh_async | -| Geometric pose (RANSAC) | ~5ms | Homography | -| ESKF satellite update | ~1ms | Delayed measurement | -| **Total** | **≤210ms** | Async on Stream B, does not block VO | - -**Path B — XFeat TRT Engine FP16**: - -| Step | Time | Notes | -|------|------|-------| -| XFeat TRT Engine inference | ~50-80ms | context.enqueue_v3(stream_B) | -| Geometric verification (RANSAC) | ~5ms | | -| ESKF satellite update | ~1ms | | -| **Total** | **~60-90ms** | Async on Stream B | - -## Memory Budget (Jetson Orin Nano Super, 8GB shared) - -| Component | Memory (Native TRT) | Memory (ONNX RT TRT-EP) | Notes | -|-----------|---------------------|--------------------------|-------| -| OS + runtime | ~1.5GB | ~1.5GB | JetPack 6.2 + Python | -| cuVSLAM | ~200-500MB | ~200-500MB | CUDA library + map | -| **LiteSAM TRT engine** | **~50-80MB** | **~330-360MB** | Native TRT vs TRT-EP. If LiteSAM fails: EfficientLoFTR ~100-150MB | -| **XFeat TRT engine** | **~30-50MB** | **~310-330MB** | Native TRT vs TRT-EP | -| Preloaded satellite tiles | ~200MB | ~200MB | ±2km of flight plan | -| pymavlink + MAVLink | ~20MB | ~20MB | | -| FastAPI (local IPC) | ~50MB | ~50MB | | -| ESKF + buffers | ~10MB | ~10MB | | -| ONNX Runtime framework | **0MB** | **~150MB** | Eliminated with native TRT | -| **Total** | **~2.1-2.9GB** | **~2.8-3.6GB** | | -| **% of 8GB** | **26-36%** | **35-45%** | | -| **Savings** | — | — | **~700MB saved with native TRT** | - -## Confidence Scoring → GPS_INPUT Mapping -Unchanged from draft03. - -## Key Risks and Mitigations - -| Risk | Likelihood | Impact | Mitigation | -|------|-----------|--------|------------| -| **LiteSAM MinGRU ops unsupported in TRT 10.3** | LOW-MEDIUM | LiteSAM TRT export fails | Day-one verification: ONNX export → polygraphy → trtexec. If MinGRU fails: (1) rewrite as unrolled 9-step loop, (2) if still fails: **switch to EfficientLoFTR TRT** (proven TRT path, Coarse_LoFTR_TRT, 15.05M params). XFeat TRT as speed fallback. | -| **TRT engine build OOM on 8GB Jetson** | LOW | Cannot build engines on target device | Our models are small (6.31M LiteSAM, <5M XFeat). OOM unlikely. If occurs: reduce --memPoolSize, or build on identical Orin Nano module with more headroom | -| **Engine incompatibility after JetPack update** | MEDIUM | Must rebuild engines | Include engine rebuild in JetPack update procedure. Takes minutes per model. | -| **MAVSDK cannot send GPS_INPUT** | CONFIRMED | Must use pymavlink | Unchanged from draft03 | -| **cuVSLAM fails on low-texture terrain** | HIGH | Frequent tracking loss | ADTI at 0.7 fps means 27.8m inter-frame displacement at 70 km/h. At 600m+ altitude, pixel shift is 105-175px with 95%+ overlap — within pyramid-assisted LK range. HIGH risk remains over completely uniform terrain (single crop covering 577m+ footprint). IMU bridging + satellite matching corrections bound drift. | -| **Thermal throttling** | MEDIUM | Satellite matching budget blown | Unchanged from draft03 | -| LiteSAM TRT FP16 >200ms at 1280px | MEDIUM | Must use fallback matcher | Day-one benchmark. Fallback chain: EfficientLoFTR TRT (if ≤300ms) → XFeat TRT (if all >300ms) | -| Google Maps satellite quality in conflict zone | HIGH | Satellite matching fails | Unchanged from draft03 | -| **AUW exceeds AT4125 recommended range** | MEDIUM | Reduced endurance, motor thermal stress | 12.5 kg AUW vs 8-10 kg recommended. Monitor motor temps. Consider weight reduction (lighter gimbal, single battery for shorter missions). | -| **cuVSLAM at 0.7 fps — inter-frame displacement** | MEDIUM | VO tracking loss on uniform terrain | At 0.7 fps and 70 km/h: ~175px displacement at 600m (4.8% of frame, 95.2% overlap). Within pyramid-assisted LK range (150-200px). At 800m+: drops to 105-131px. Mitigations: (1) cuVSLAM IMU integrator bridges 1.43s frame gaps, (2) ESKF IMU prediction at 5-10Hz fills position gaps, (3) satellite matching corrections every 5-10 frames bound drift. | -| **ADTI mechanical shutter lifespan** | MEDIUM | Shutter replacement needed periodically | At 0.7 fps sustained over 3.5h flights: ~8,800 actuations/flight. Shutter life unknown for 20L (102PRO is 500K, entry-level likely 100-150K). Estimated 11-57 flights before replacement. Budget for shutter replacement as consumable. | - -## Testing Strategy - -### Integration / Functional Tests -All tests from draft03 unchanged, plus: -- **TRT engine load test**: Verify litesam.engine and xfeat.engine load successfully on Jetson Orin Nano Super -- **TRT inference correctness**: Compare TRT engine output vs PyTorch reference output (max L1 error < 0.01) -- **CUDA Stream B pipelining**: Verify satellite matching on Stream B does not block cuVSLAM on Stream A -- **Engine pre-built validation**: Verify engine files from offline preparation work without rebuild at runtime -- **ADTI 20L V1 sustained capture rate**: Verify camera sustains 0.7 fps in JPEG mode over extended periods (>30 min) without buffer overflow or overheating. Also test 1.0 fps to determine if higher sustained rate is achievable. -- **ADTI trigger timing**: Verify camera trigger and image transfer pipeline delivers frames to cuVSLAM within acceptable latency (<50ms from trigger to GPU buffer) - -### Non-Functional Tests -All tests from draft03 unchanged, plus: -- **TRT engine build time**: Measure trtexec build time for LiteSAM and XFeat on Orin Nano Super (expected: 1-5 minutes each) -- **TRT engine load time**: Measure deserialization time (expected: 1-3 seconds each) -- **Memory comparison**: Measure actual GPU memory with native TRT vs ONNX RT TRT-EP for both models -- **MinGRU TRT compatibility** (day-one blocker): - 1. Clone LiteSAM repo, load pretrained weights - 2. Reparameterize MobileOne backbone - 3. `torch.onnx.export(model, dummy, "litesam.onnx", opset_version=17)` - 4. `polygraphy inspect model litesam.onnx` — check for unsupported ops - 5. `trtexec --onnx=litesam.onnx --saveEngine=litesam.engine --fp16` - 6. If step 3 or 5 fails on MinGRU: rewrite MinGRU forward() as unrolled loop, retry - 7. If still fails: switch to EfficientLoFTR, apply Coarse_LoFTR_TRT adaptation - 8. Compare TRT output vs PyTorch reference (max L1 error < 0.01) -- **EfficientLoFTR TRT fallback benchmark** (if LiteSAM fails): apply TRT adaptation from Coarse_LoFTR_TRT → ONNX → trtexec → measure latency at 640×480 and 1280px -- **Tensor core utilization**: Verify with NSight that TRT engines use tensor cores (unlike ONNX RT CUDA EP) -- **Flight endurance validation**: Ground-test full system power draw (propulsion + electronics) against 267W estimate. Verify ~3.4h endurance target. -- **cuVSLAM at 0.7 fps**: Benchmark VO tracking quality, drift rate, and tracking loss frequency at 0.7 fps with ADTI 20L V1. Measure IMU integrator effectiveness for bridging 1.43s inter-frame gaps. Test at 600m and 800m altitude, over both textured and low-texture terrain. -- **ADTI shutter durability**: Track shutter actuation count across flights. Monitor for shutter failure symptoms (missed frames, inconsistent exposure). - -## References -- ONNX Runtime Issue #24085 (Jetson Orin Nano tensor core bug): https://github.com/microsoft/onnxruntime/issues/24085 -- ONNX Runtime Issue #20457 (TRT-EP memory overhead): https://github.com/microsoft/onnxruntime/issues/20457 -- ONNX Runtime Issue #12083 (TRT-EP vs native TRT): https://github.com/microsoft/onnxruntime/issues/12083 -- NVIDIA TensorRT 10 Python API: https://docs.nvidia.com/deeplearning/tensorrt/10.15.1/inference-library/python-api-docs.html -- TensorRT Best Practices: https://docs.nvidia.com/deeplearning/tensorrt/latest/performance/best-practices.html -- TensorRT engine hardware specificity: https://github.com/NVIDIA/TensorRT/issues/1920 -- trtexec ONNX conversion: https://nvidia-jetson.piveral.com/jetson-orin-nano/how-to-convert-onnx-to-engine-on-jetson-orin-nano-dev-board/ -- Torch-TensorRT JetPack 6.2: https://docs.pytorch.org/TensorRT/v2.10.0/getting_started/jetpack.html -- XFeatTensorRT: https://github.com/PranavNedunghat/XFeatTensorRT -- JetPack 6.2 Release Notes: https://docs.nvidia.com/jetson/archives/jetpack-archived/jetpack-62/release-notes/index.html -- Jetson Orin Nano Super: https://developer.nvidia.com/blog/nvidia-jetson-orin-nano-developer-kit-gets-a-super-boost/ -- DLA on Jetson Orin: https://developer.nvidia.com/blog/maximizing-deep-learning-performance-on-nvidia-jetson-orin-with-dla/ -- EfficientLoFTR (CVPR 2024): https://github.com/zju3dv/EfficientLoFTR -- EfficientLoFTR HuggingFace: https://huggingface.co/docs/transformers/en/model_doc/efficientloftr -- Coarse_LoFTR_TRT (TRT for embedded): https://github.com/Kolkir/Coarse_LoFTR_TRT -- Coarse_LoFTR_TRT paper: https://ar5iv.labs.arxiv.org/html/2202.00770 -- LoFTR_TRT: https://github.com/Kolkir/LoFTR_TRT -- minGRU ("Were RNNs All We Needed?"): https://huggingface.co/papers/2410.01201 -- minGRU PyTorch implementation: https://github.com/lucidrains/minGRU-pytorch -- LiteSAM paper (MinGRU details, Eqs 12-16): https://www.mdpi.com/2072-4292/17/19/3349 -- DALGlue (UAV feature matching, 2025): https://www.nature.com/articles/s41598-025-21602-5 -- ADTI 20L V1 specs: https://unmannedrc.com/products/adti-20l-v1-mapping-camera -- ADTI 20L V1 user manual: https://docs.adti.camera/adti-20l-and-24l-v1-quick-start-guide/ -- T-Motor AT4125 KV540: https://uav-en.tmotor.com/2019/Motors_0429/247.html -- VANT Semi-Solid State 6S 30Ah battery: https://www.xtbattery.com/370wh/kg-42v-high-energy-density-6s-12s-14s-18s-30ah-semi-solid-state-drone-battery/ -- All references from solution_draft03.md - -## Related Artifacts -- AC Assessment: `_docs/00_research/gps_denied_nav/00_ac_assessment.md` -- Research artifacts (this assessment): `_docs/00_research/trt_engine_migration/` -- Previous research: `_docs/00_research/gps_denied_nav_v3/` -- Tech stack evaluation: `_docs/01_solution/tech_stack.md` -- Security analysis: `_docs/01_solution/security_analysis.md` -- Previous draft: `_docs/01_solution/solution_draft04.md` diff --git a/_docs/01_solution/solution_draft06.md b/_docs/01_solution/solution_draft06.md deleted file mode 100644 index 5438fe7..0000000 --- a/_docs/01_solution/solution_draft06.md +++ /dev/null @@ -1,622 +0,0 @@ -# Solution Draft - -## Assessment Findings - - -| Old Component Solution | Weak Point (functional/security/performance) | New Solution | -| ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ESKF described as "16-state vector, ~10MB" with no mathematical specification | **Functional**: No state vector, no process model (F,Q), no measurement models (H for VO, H for satellite), no noise parameters, no scale observability analysis. Impossible to implement or validate accuracy claims. | **Define complete ESKF specification**: 15-state error vector, IMU-driven prediction, dual measurement models (VO relative pose, satellite absolute position), initial Q/R values, scale constraint via altitude + satellite corrections. | -| GPS_INPUT at 5-10Hz via pymavlink — no field mapping | **Functional**: GPS_INPUT requires 15+ fields (velocity, accuracy, hdop, fix_type, GPS time). No specification of how ESKF state maps to these fields. ArduPilot requires minimum 5Hz. | **Define GPS_INPUT population spec**: velocity from ESKF, accuracy from covariance, fix_type from confidence tier, GPS time from system clock conversion, synthesized hdop/vdop. | -| Confidence scoring "unchanged from draft03" — not in draft05 | **Functional**: Draft05 is supposed to be self-contained. Confidence scoring determines GPS_INPUT accuracy fields and fix_type — directly affects how ArduPilot EKF weights the position data. | **Define confidence scoring inline**: 3 tiers (satellite-anchored, VO-tracked, IMU-only) mapping to fix_type + accuracy values. | -| Coordinate transformations not defined | **Functional**: No pixel→camera→body→NED→WGS84 chain. Camera is not autostabilized, so body attitude matters. Satellite match → WGS84 conversion undefined. Object localization impossible without these transforms. | **Define coordinate transformation chain**: camera intrinsics K, camera-to-body extrinsic T_cam_body, body-to-NED from ESKF attitude, NED origin at mission start point. | -| Disconnected route segments — "satellite re-localization" mentioned but no algorithm | **Functional**: AC requires handling as "core to the system." Multiple disconnected segments expected. No tracking-loss detection, no re-localization trigger, no ESKF re-initialization, no cuVSLAM restart procedure. | **Define re-localization pipeline**: detect cuVSLAM tracking loss → IMU-only ESKF prediction → trigger satellite match on every frame → on match success: ESKF position reset + cuVSLAM restart → on 3 consecutive failures: operator re-localization request. | -| No startup handoff from GPS to GPS-denied | **Functional**: System reads GLOBAL_POSITION_INT at startup but no protocol for when GPS is lost/spoofed vs system start. No validation of initial position. | **Define handoff protocol**: system runs continuously, FC receives both real GPS and GPS_INPUT. GPS-denied system always provides its estimate; FC selects best source. Initial position validated against first satellite match. | -| No mid-flight reboot recovery | **Functional**: AC requires: "re-initialize from flight controller's current IMU-extrapolated position." No procedure defined. Recovery time estimation missing. | **Define reboot recovery sequence**: read FC position → init ESKF with high uncertainty → load TRT engines → start cuVSLAM → immediate satellite match. Estimated recovery: ~35-70s. Document as known limitation. | -| 3-consecutive-failure re-localization request undefined | **Functional**: AC requires ground station re-localization request. No message format, no operator workflow, no system behavior while waiting. | **Define re-localization protocol**: detect 3 failures → send custom MAVLink message with last known position + uncertainty → operator provides approximate coordinates → system uses as ESKF measurement with high covariance. | -| Object localization — "trigonometric calculation" with no details | **Functional**: No math, no API, no Viewpro gimbal integration, no accuracy propagation. Other onboard systems cannot use this component as specified. | **Define object localization**: pixel→ray using Viewpro intrinsics + gimbal angles → body frame → NED → ray-ground intersection → WGS84. FastAPI endpoint: POST /objects/locate. Accuracy propagated from UAV position + gimbal uncertainty. | -| Satellite matching — GSD normalization and tile selection unspecified | **Functional**: Camera GSD ~15.9 cm/px at 600m vs satellite ~0.3 m/px at zoom 19. The "pre-resize" step is mentioned but not specified. Tile selection radius based on ESKF uncertainty not defined. | **Define GSD handling**: downsample camera frame to match satellite GSD. Define tile selection: ESKF position ± 3σ_horizontal → select tiles covering that area. Assemble tile mosaic for matching. | -| Satellite tile storage requirements not calculated | **Functional**: "±2km" preload mentioned but no storage estimate. At zoom 19: a 200km path with ±2km buffer requires ~~130K tiles (~~2.5GB). | **Calculate tile storage**: specify zoom level (18 preferred — 0.6m/px, 4× fewer tiles), estimate storage per mission profile, define maximum mission area by storage limit. | -| FastAPI endpoints not in solution draft | **Functional**: Endpoints only in security_analysis.md. No request/response schemas. No SSE event format. No object localization endpoint. | **Consolidate API spec in solution**: define all endpoints, SSE event schema, object localization endpoint. Reference security_analysis.md for auth. | -| cuVSLAM configuration missing (calibration, IMU params, mode) | **Functional**: No camera calibration procedure, no IMU noise parameters, no T_imu_rig extrinsic, no mode selection (Mono vs Inertial). | **Define cuVSLAM configuration**: use Inertial mode, specify required calibration data (camera intrinsics, distortion, IMU noise params from datasheet, T_imu_rig from physical measurement), define calibration procedure. | -| tech_stack.md inconsistent with draft05 | **Functional**: tech_stack.md says 3fps (should be 0.7fps), LiteSAM at 480px (should be 1280px), missing EfficientLoFTR. | **Flag for update**: tech_stack.md must be synchronized with draft05 corrections. Not addressed in this draft — separate task. | - - -## Overall Maturity Assessment - - -| Category | Maturity (1-5) | Assessment | -| ----------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -| Hardware & Platform Selection | 3.5 | UAV airframe, cameras, Jetson, batteries — well-researched with specs, weight budget, endurance calculations. Ready for procurement. | -| Core Algorithm Selection | 3.0 | cuVSLAM, LiteSAM/XFeat, ESKF — components selected with comparison tables, fallback chains, decision trees. Day-one benchmarks defined. | -| AI Inference Runtime | 3.5 | TRT Engine migration thoroughly analyzed. Conversion workflows, memory savings, performance estimates. Code wrapper provided. | -| Sensor Fusion (ESKF) | 1.5 | Mentioned but not specified. No implementable detail. Blockerfor coding. | -| System Integration | 1.5 | GPS_INPUT, coordinate transforms, inter-component data flow — all under-specified. | -| Edge Cases & Resilience | 1.0 | Disconnected segments, reboot recovery, re-localization — acknowledged but no algorithms. | -| Operational Readiness | 0.5 | No pre-flight procedures, no in-flight monitoring, no failure response. | -| Security | 3.0 | Comprehensive threat model, OP-TEE analysis, LUKS, secure boot. Well-researched. | -| **Overall TRL** | **~2.5** | **Technology concept formulated + some component validation. Not implementation-ready.** | - - -The solution is at approximately **TRL 3** (proof of concept) for hardware/algorithm selection and **TRL 1-2** (basic concept) for system integration, ESKF, and operational procedures. - -## Product Solution Description - -A real-time GPS-denied visual navigation system for fixed-wing UAVs, running on a Jetson Orin Nano Super (8GB). All AI model inference uses native TensorRT Engine files. The system replaces the GPS module by sending MAVLink GPS_INPUT messages via pymavlink over UART at 5-10Hz. - -Position is determined by fusing: (1) CUDA-accelerated visual odometry (cuVSLAM in Inertial mode) from ADTI 20L V1 at 0.7 fps sustained, (2) absolute position corrections from satellite image matching (LiteSAM or XFeat — TRT Engine FP16) using keyframes from the same ADTI image stream, and (3) IMU data from the flight controller via ESKF. Viewpro A40 Pro is reserved for AI object detection only. - -The ESKF is the central state estimator with 15-state error vector. It fuses: - -- **IMU prediction** at 5-10Hz (high-frequency pose propagation) -- **cuVSLAM VO measurement** at 0.7Hz (relative pose correction) -- **Satellite matching measurement** at ~0.07-0.14Hz (absolute position correction) - -GPS_INPUT messages carry position, velocity, and accuracy derived from the ESKF state and covariance. - -**Hard constraint**: ADTI 20L V1 shoots at 0.7 fps sustained (1430ms interval). Full VO+ESKF pipeline within 400ms per frame. Satellite matching async on keyframes (every 5-10 camera frames). GPS_INPUT at 5-10Hz (ESKF IMU prediction fills gaps between camera frames). - -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ OFFLINE (Before Flight) │ -│ 1. Satellite Tiles → Download & Validate → Pre-resize → Store │ -│ (Google Maps) (≥0.5m/px, <2yr) (matcher res) (GeoHash)│ -│ 2. TRT Engine Build (one-time per model version): │ -│ PyTorch model → reparameterize → ONNX export → trtexec --fp16 │ -│ Output: litesam.engine, xfeat.engine │ -│ 3. Camera + IMU calibration (one-time per hardware unit) │ -│ 4. Copy tiles + engines + calibration to Jetson storage │ -└─────────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ ONLINE (During Flight) │ -│ │ -│ STARTUP: │ -│ 1. pymavlink → read GLOBAL_POSITION_INT → init ESKF state │ -│ 2. Load TRT engines + allocate GPU buffers │ -│ 3. Load camera calibration + IMU calibration │ -│ 4. Start cuVSLAM (Inertial mode) with ADTI 20L V1 │ -│ 5. Preload satellite tiles ±2km into RAM │ -│ 6. First satellite match → validate initial position │ -│ 7. Begin GPS_INPUT output loop at 5-10Hz │ -│ │ -│ EVERY CAMERA FRAME (0.7fps from ADTI 20L V1): │ -│ ┌──────────────────────────────────────┐ │ -│ │ ADTI 20L V1 → Downsample (CUDA) │ │ -│ │ → cuVSLAM VO+IMU (~9ms) │ ← CUDA Stream A │ -│ │ → ESKF VO measurement │ │ -│ └──────────────────────────────────────┘ │ -│ │ -│ 5-10Hz CONTINUOUS (IMU-driven between camera frames): │ -│ ┌──────────────────────────────────────┐ │ -│ │ IMU data → ESKF prediction │ │ -│ │ ESKF state → GPS_INPUT fields │ │ -│ │ GPS_INPUT → Flight Controller (UART) │ │ -│ └──────────────────────────────────────┘ │ -│ │ -│ KEYFRAMES (every 5-10 camera frames, async): │ -│ ┌──────────────────────────────────────┐ │ -│ │ Camera frame → GSD downsample │ │ -│ │ Select satellite tile (ESKF pos±3σ) │ │ -│ │ TRT inference (Stream B): LiteSAM/ │ │ -│ │ XFeat → correspondences │ │ -│ │ RANSAC → homography → WGS84 position │ │ -│ │ ESKF satellite measurement update │──→ Position correction │ -│ └──────────────────────────────────────┘ │ -│ │ -│ TRACKING LOSS (cuVSLAM fails — sharp turn / featureless): │ -│ ┌──────────────────────────────────────┐ │ -│ │ ESKF → IMU-only prediction (growing │ │ -│ │ uncertainty) │ │ -│ │ Satellite match on EVERY frame │ │ -│ │ On match success → ESKF reset + │ │ -│ │ cuVSLAM restart │ │ -│ │ 3 consecutive failures → operator │ │ -│ │ re-localization request │ │ -│ └──────────────────────────────────────┘ │ -│ │ -│ TELEMETRY (1Hz): │ -│ ┌──────────────────────────────────────┐ │ -│ │ NAMED_VALUE_FLOAT: confidence, drift │──→ Ground Station │ -│ └──────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────────────┘ -``` - -## Architecture - -### Component: ESKF Sensor Fusion (NEW — previously unspecified) - -**Error-State Kalman Filter** fusing IMU, visual odometry, and satellite matching. - -**Nominal state vector** (propagated by IMU): - - -| State | Symbol | Size | Description | -| ---------- | ------ | ---- | ------------------------------------------------ | -| Position | p | 3 | NED position relative to mission origin (meters) | -| Velocity | v | 3 | NED velocity (m/s) | -| Attitude | q | 4 | Unit quaternion (body-to-NED rotation) | -| Accel bias | b_a | 3 | Accelerometer bias (m/s²) | -| Gyro bias | b_g | 3 | Gyroscope bias (rad/s) | - - -**Error-state vector** (estimated by ESKF): δx = [δp, δv, δθ, δb_a, δb_g]ᵀ ∈ ℝ¹⁵ -where δθ ∈ so(3) is the 3D rotation error. - -**Prediction step** (IMU at 5-10Hz from flight controller): - -- Input: accelerometer a_m, gyroscope ω_m, dt -- Propagate nominal state: p += v·dt, v += (R(q)·(a_m - b_a) - g)·dt, q ⊗= Exp(ω_m - b_g)·dt -- Propagate error covariance: P = F·P·Fᵀ + Q -- F is the 15×15 error-state transition matrix (standard ESKF formulation) -- Q: process noise diagonal, initial values from IMU datasheet noise densities - -**VO measurement update** (0.7Hz from cuVSLAM): - -- cuVSLAM outputs relative pose: ΔR, Δt (camera frame) -- Transform to NED: Δp_ned = R_body_ned · T_cam_body · Δt -- Innovation: z = Δp_ned_measured - Δp_ned_predicted -- Observation matrix H_vo maps error state to relative position change -- R_vo: measurement noise, initial ~0.1-0.5m (from cuVSLAM precision at 600m+ altitude) -- Kalman update: K = P·Hᵀ·(H·P·Hᵀ + R)⁻¹, δx = K·z, P = (I - K·H)·P - -**Satellite measurement update** (0.07-0.14Hz, async): - -- Satellite matching outputs absolute position: lat_sat, lon_sat in WGS84 -- Convert to NED relative to mission origin -- Innovation: z = p_satellite - p_predicted -- H_sat = [I₃, 0, 0, 0, 0] (directly observes position) -- R_sat: measurement noise, from matching confidence (~5-20m based on RANSAC inlier ratio) -- Provides absolute position correction — bounds drift accumulation - -**Scale observability**: - -- Monocular cuVSLAM has scale ambiguity during constant-velocity flight -- Scale is constrained by: (1) satellite matching absolute positions (primary), (2) known flight altitude from barometer + predefined mission altitude, (3) IMU accelerometer during maneuvers -- During long straight segments without satellite correction, scale drift is possible. Satellite corrections every ~7-14s re-anchor scale. - -**Tuning approach**: Start with IMU datasheet noise values for Q. Start with conservative R values (high measurement noise). Tune on flight test data by comparing ESKF output to known GPS ground truth. - - -| Solution | Tools | Advantages | Limitations | Performance | Fit | -| -------------------------- | --------------- | ------------------------------------------------------------- | -------------------------------------- | ------------- | ----------- | -| Custom ESKF (Python/NumPy) | NumPy, SciPy | Full control, minimal dependencies, well-understood algorithm | Implementation effort, tuning required | <1ms per step | ✅ Selected | -| FilterPy ESKF | FilterPy v1.4.5 | Reference implementation, less code | Less flexible for multi-rate fusion | <1ms per step | ⚠️ Fallback | - - -### Component: Coordinate System & Transformations (NEW — previously undefined) - -**Reference frames**: - -- **Camera frame (C)**: origin at camera optical center, Z forward, X right, Y down (OpenCV convention) -- **Body frame (B)**: origin at UAV CG, X forward (nose), Y right (starboard), Z down -- **NED frame (N)**: North-East-Down, origin at mission start point -- **WGS84**: latitude, longitude, altitude (output format) - -**Transformation chain**: - -1. **Pixel → Camera ray**: p_cam = K⁻¹ · [u, v, 1]ᵀ where K = camera intrinsic matrix (ADTI 20L V1: fx, fy from 16mm lens + APS-C sensor) -2. **Camera → Body**: p_body = T_cam_body · p_cam where T_cam_body is the fixed mounting rotation (camera points nadir: 90° pitch rotation from body X-forward to camera Z-down) -3. **Body → NED**: p_ned = R_body_ned(q) · p_body where q is the ESKF quaternion attitude estimate -4. **NED → WGS84**: lat = lat_origin + p_north / R_earth, lon = lon_origin + p_east / (R_earth · cos(lat_origin)) where (lat_origin, lon_origin) is the mission start GPS position - -**Camera intrinsic matrix K** (ADTI 20L V1 + 16mm lens): - -- Sensor: 23.2 × 15.4 mm, Resolution: 5456 × 3632 -- fx = fy = focal_mm × width_px / sensor_width_mm = 16 × 5456 / 23.2 = 3763 pixels -- cx = 2728, cy = 1816 (sensor center) -- Distortion: Brown model (k1, k2, p1, p2 from calibration) - -**T_cam_body** (camera mount): - -- Navigation camera is fixed, pointing nadir (downward), not autostabilized -- R_cam_body = R_x(180°) · R_z(0°) (camera Z-axis aligned with body -Z, camera X with body X) -- Translation: offset from CG to camera mount (measured during assembly, typically <0.3m) - -**Satellite match → WGS84**: - -- Feature correspondences between camera frame and geo-referenced satellite tile -- Homography H maps camera pixels to satellite tile pixels -- Satellite tile pixel → WGS84 via tile's known georeference (zoom level + tile x,y → lat,lon) -- Camera center projects to satellite pixel (cx_sat, cy_sat) via H -- Convert (cx_sat, cy_sat) to WGS84 using tile georeference - -### Component: GPS_INPUT Message Population (NEW — previously undefined) - - -| GPS_INPUT Field | Source | Computation | -| ----------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------- | -| lat, lon | ESKF position (NED) | NED → WGS84 conversion using mission origin | -| alt | ESKF position (Down) + mission origin altitude | alt = alt_origin - p_down | -| vn, ve, vd | ESKF velocity state | Direct from ESKF v[0], v[1], v[2] | -| fix_type | Confidence tier | 3 (3D fix) when satellite-anchored (last match <30s). 2 (2D) when VO-only. 0 (no fix) when IMU-only >5s | -| hdop | ESKF horizontal covariance | hdop = sqrt(P[0,0] + P[1,1]) / 5.0 (approximate CEP→HDOP mapping) | -| vdop | ESKF vertical covariance | vdop = sqrt(P[2,2]) / 5.0 | -| horiz_accuracy | ESKF horizontal covariance | horiz_accuracy = sqrt(P[0,0] + P[1,1]) meters | -| vert_accuracy | ESKF vertical covariance | vert_accuracy = sqrt(P[2,2]) meters | -| speed_accuracy | ESKF velocity covariance | speed_accuracy = sqrt(P[3,3] + P[4,4]) m/s | -| time_week, time_week_ms | System time | Convert Unix time to GPS epoch (GPS epoch = 1980-01-06, subtract leap seconds) | -| satellites_visible | Constant | 10 (synthetic — prevents satellite-count failsafes in ArduPilot) | -| gps_id | Constant | 0 | -| ignore_flags | Constant | 0 (provide all fields) | - - -**Confidence tiers** mapping to GPS_INPUT: - - -| Tier | Condition | fix_type | horiz_accuracy | Rationale | -| ------ | ------------------------------------------------- | ---------- | ------------------------------- | -------------------------------------- | -| HIGH | Satellite match <30s ago, ESKF covariance < 400m² | 3 (3D fix) | From ESKF P (typically 5-20m) | Absolute position anchor recent | -| MEDIUM | cuVSLAM tracking OK, no recent satellite match | 3 (3D fix) | From ESKF P (typically 20-50m) | Relative tracking valid, drift growing | -| LOW | cuVSLAM lost, IMU-only | 2 (2D fix) | From ESKF P (50-200m+, growing) | Only IMU dead reckoning, rapid drift | -| FAILED | 3+ consecutive total failures | 0 (no fix) | 999.0 | System cannot determine position | - - -### Component: Disconnected Route Segment Handling (NEW — previously undefined) - -**Trigger**: cuVSLAM reports tracking_lost OR tracking confidence drops below threshold - -**Algorithm**: - -``` -STATE: TRACKING_NORMAL - cuVSLAM provides relative pose - ESKF VO measurement updates at 0.7Hz - Satellite matching on keyframes (every 5-10 frames) - -STATE: TRACKING_LOST (enter when cuVSLAM reports loss) - 1. ESKF continues with IMU-only prediction (no VO updates) - → uncertainty grows rapidly (~1-5 m/s drift with consumer IMU) - 2. Switch satellite matching to EVERY frame (not just keyframes) - → maximize chances of getting absolute correction - 3. For each camera frame: - a. Attempt satellite match using ESKF predicted position ± 3σ for tile selection - b. If match succeeds (RANSAC inlier ratio > 30%): - → ESKF measurement update with satellite position - → Restart cuVSLAM with current frame as new origin - → Transition to TRACKING_NORMAL - → Reset failure counter - c. If match fails: - → Increment failure_counter - → Continue IMU-only ESKF prediction - 4. If failure_counter >= 3: - → Send re-localization request to ground station - → GPS_INPUT fix_type = 0 (no fix), horiz_accuracy = 999.0 - → Continue attempting satellite matching on each frame - 5. If operator sends re-localization hint (approximate lat,lon): - → Use as ESKF measurement with high covariance (~500m) - → Attempt satellite match in that area - → On success: transition to TRACKING_NORMAL - -STATE: SEGMENT_DISCONNECT - After re-localization following tracking loss: - → New cuVSLAM track is independent of previous track - → ESKF maintains global NED position continuity via satellite anchor - → No need to "connect" segments at the cuVSLAM level - → ESKF already handles this: satellite corrections keep global position consistent -``` - -### Component: Satellite Image Matching Pipeline (UPDATED — added GSD + tile selection details) - -**GSD normalization**: - -- Camera GSD at 600m: ~15.9 cm/pixel (ADTI 20L V1 + 16mm) -- Satellite tile GSD at zoom 18: ~0.6 m/pixel -- Scale ratio: ~3.8:1 -- Downsample camera image to satellite GSD before matching: resize from 5456×3632 to ~1440×960 (matching zoom 18 GSD) -- This is close to LiteSAM's 1280px input — use 1280px with minor GSD mismatch acceptable for matching - -**Tile selection**: - -- Input: ESKF position estimate (lat, lon) + horizontal covariance σ_h -- Search radius: max(3·σ_h, 500m) — at least 500m to handle initial uncertainty -- Compute geohash for center position → load tiles covering the search area -- Assemble tile mosaic if needed (typically 2×2 to 4×4 tiles for adequate coverage) -- If ESKF uncertainty > 2km: tile selection unreliable, fall back to wider search or request operator input - -**Tile storage calculation** (zoom 18 — 0.6 m/pixel): - -- Each 256×256 tile covers ~153m × 153m -- Flight path 200km with ±2km buffer: area ≈ 200km × 4km = 800 km² -- Tiles needed: 800,000,000 / (153 × 153) ≈ 34,200 tiles -- Storage: ~10-15KB per JPEG tile → ~340-510 MB -- With zoom 19 overlap tiles for higher precision: ×4 = ~1.4-2.0 GB -- Recommended: zoom 18 primary + zoom 19 for ±500m along flight path → ~500-800 MB total - - -| Solution | Tools | Advantages | Limitations | Performance (est. Orin Nano Super TRT FP16) | Params | Fit | -| -------------------------------------- | ------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------ | ------------------------------------------- | ------ | ------------------------------- | -| LiteSAM (opt) TRT Engine FP16 @ 1280px | trtexec + tensorrt Python | Best satellite-aerial accuracy (RMSE@30=17.86m UAV-VisLoc), 6.31M params | MinGRU TRT export needs verification (LOW-MEDIUM risk) | Est. ~165-330ms | 6.31M | ✅ Primary | -| EfficientLoFTR TRT Engine FP16 | trtexec + tensorrt Python | Proven TRT path (Coarse_LoFTR_TRT). Semi-dense. CVPR 2024. | 2.4x more params than LiteSAM. | Est. ~200-400ms | 15.05M | ✅ Fallback if LiteSAM TRT fails | -| XFeat TRT Engine FP16 | trtexec + tensorrt Python | Fastest. Proven TRT implementation. | General-purpose, not designed for cross-view gap. | Est. ~50-100ms | <5M | ✅ Speed fallback | - - -### Component: cuVSLAM Configuration (NEW — previously undefined) - -**Mode**: Inertial (mono camera + IMU) - -**Camera configuration** (ADTI 20L V1 + 16mm lens): - -- Model: Brown distortion -- fx = fy = 3763 px (16mm on 23.2mm sensor at 5456px width) -- cx = 2728 px, cy = 1816 px -- Distortion coefficients: from calibration (k1, k2, p1, p2) -- Border: 50px (ignore lens edge distortion) - -**IMU configuration** (Pixhawk 6x IMU — ICM-42688-P): - -- Gyroscope noise density: 3.0 × 10⁻³ °/s/√Hz -- Gyroscope random walk: 5.0 × 10⁻⁵ °/s²/√Hz -- Accelerometer noise density: 70 µg/√Hz -- Accelerometer random walk: ~2.0 × 10⁻³ m/s³/√Hz -- IMU frequency: 200 Hz (from flight controller via MAVLink) -- T_imu_rig: measured transformation from Pixhawk IMU to camera center (translation + rotation) - -**cuVSLAM settings**: - -- OdometryMode: INERTIAL -- MulticameraMode: PRECISION (favor accuracy over speed — we have 1430ms budget) -- Input resolution: downsample to 1280×852 (or 720p) for processing speed -- async_bundle_adjustment: True - -**Initialization**: - -- cuVSLAM initializes automatically when it receives the first camera frame + IMU data -- First few frames used for feature initialization and scale estimation -- First satellite match validates and corrects the initial position - -**Calibration procedure** (one-time per hardware unit): - -1. Camera intrinsics: checkerboard calibration with OpenCV (or use manufacturer data if available) -2. Camera-IMU extrinsic (T_imu_rig): Kalibr tool with checkerboard + IMU data -3. IMU noise parameters: Allan variance analysis or use datasheet values -4. Store calibration files on Jetson storage - -### Component: AI Model Inference Runtime (UNCHANGED) - -Native TRT Engine — optimal performance and memory on fixed NVIDIA hardware. See draft05 for full comparison table and conversion workflow. - -### Component: Visual Odometry (UNCHANGED) - -cuVSLAM in Inertial mode, fed by ADTI 20L V1 at 0.7 fps sustained. See draft05 for feasibility analysis at 0.7fps. - -### Component: Flight Controller Integration (UPDATED — added GPS_INPUT field spec) - -pymavlink over UART at 5-10Hz. GPS_INPUT field population defined above. - -ArduPilot configuration: - -- GPS1_TYPE = 14 (MAVLink) -- GPS_RATE = 5 (minimum, matching our 5-10Hz output) -- EK3_SRC1_POSXY = 1 (GPS), EK3_SRC1_VELXY = 1 (GPS) — EKF uses GPS_INPUT as position/velocity source - -### Component: Object Localization (NEW — previously undefined) - -**Input**: pixel coordinates (u, v) in Viewpro A40 Pro image, current gimbal angles (pan_deg, tilt_deg), zoom factor, UAV position from GPS-denied system, UAV altitude - -**Process**: - -1. Pixel → camera ray: ray_cam = K_viewpro⁻¹(zoom) · [u, v, 1]ᵀ -2. Camera → gimbal frame: ray_gimbal = R_gimbal(pan, tilt) · ray_cam -3. Gimbal → body: ray_body = T_gimbal_body · ray_gimbal -4. Body → NED: ray_ned = R_body_ned(q) · ray_body -5. Ray-ground intersection: assuming flat terrain at UAV altitude h: t = -h / ray_ned[2], p_ground_ned = p_uav_ned + t · ray_ned -6. NED → WGS84: convert to lat, lon - -**Output**: { lat, lon, accuracy_m, confidence } - -- accuracy_m propagated from: UAV position accuracy (from ESKF) + gimbal angle uncertainty + altitude uncertainty - -**API endpoint**: POST /objects/locate - -- Request: { pixel_x, pixel_y, gimbal_pan_deg, gimbal_tilt_deg, zoom_factor } -- Response: { lat, lon, alt, accuracy_m, confidence, uav_position: {lat, lon, alt}, timestamp } - -### Component: Startup, Handoff & Failsafe (UPDATED — added handoff + reboot + re-localization) - -**GPS-denied handoff protocol**: - -- GPS-denied system runs continuously from companion computer boot -- Reads initial position from FC (GLOBAL_POSITION_INT) — this may be real GPS or last known -- First satellite match validates the initial position -- FC receives both real GPS (if available) and GPS_INPUT; FC EKF selects best source based on accuracy -- No explicit "switch" — the GPS-denied system is a secondary GPS source - -**Startup sequence** (expanded from draft05): - -1. Boot Jetson → start GPS-Denied service (systemd) -2. Connect to flight controller via pymavlink on UART -3. Wait for heartbeat -4. Initialize PyCUDA context -5. Load TRT engines: litesam.engine + xfeat.engine (~1-3s each) -6. Allocate GPU I/O buffers -7. Create CUDA streams: Stream A (cuVSLAM), Stream B (satellite matching) -8. Load camera calibration + IMU calibration files -9. Read GLOBAL_POSITION_INT → set mission origin (NED reference point) → init ESKF -10. Start cuVSLAM (Inertial mode) with ADTI 20L V1 camera stream -11. Preload satellite tiles within ±2km into RAM -12. Trigger first satellite match → validate initial position -13. Begin GPS_INPUT output loop at 5-10Hz -14. System ready - -**Mid-flight reboot recovery**: - -1. Jetson boots (~30-60s) -2. GPS-Denied service starts, connects to FC -3. Read GLOBAL_POSITION_INT (FC's current IMU-extrapolated position) -4. Init ESKF with this position + HIGH uncertainty covariance (σ = 200m) -5. Load TRT engines (~2-6s total) -6. Start cuVSLAM (fresh, no prior map) -7. Immediate satellite matching on first camera frame -8. On satellite match success: ESKF corrected, uncertainty drops -9. Estimated total recovery: ~35-70s -10. During recovery: FC uses IMU-only dead reckoning (at 70 km/h: ~700-1400m uncontrolled drift) -11. **Known limitation**: recovery time is dominated by Jetson boot time - -**3-consecutive-failure re-localization**: - -- Trigger: VO lost + satellite match failed × 3 consecutive camera frames -- Action: send re-localization request via MAVLink STATUSTEXT or custom message -- Message content: "RELOC_REQ: last_lat={lat} last_lon={lon} uncertainty={σ}m" -- Operator response: MAVLink COMMAND_LONG with approximate lat/lon -- System: use operator position as ESKF measurement with R = diag(500², 500², 100²) meters² -- System continues satellite matching with updated search area -- While waiting: GPS_INPUT fix_type=0, IMU-only ESKF prediction continues - -### Component: Ground Station Telemetry (UPDATED — added re-localization) - -MAVLink messages to ground station: - - -| Message | Rate | Content | -| ----------------------------- | -------- | --------------------------------------------------- | -| NAMED_VALUE_FLOAT "gps_conf" | 1Hz | Confidence score (0.0-1.0) | -| NAMED_VALUE_FLOAT "gps_drift" | 1Hz | Estimated drift from last satellite anchor (meters) | -| NAMED_VALUE_FLOAT "gps_hacc" | 1Hz | Horizontal accuracy (meters, from ESKF) | -| STATUSTEXT | On event | "RELOC_REQ: ..." for re-localization request | -| STATUSTEXT | On event | Tracking loss / recovery notifications | - - -### Component: Thermal Management (UNCHANGED) - -Same adaptive pipeline from draft05. Active cooling required at 25W. Throttling at 80°C SoC junction. - -### Component: API & Inter-System Communication (NEW — consolidated) - -FastAPI (Uvicorn) running locally on Jetson for inter-process communication with other onboard systems. - - -| Endpoint | Method | Purpose | Auth | -| --------------------- | --------- | -------------------------------------- | ---- | -| /sessions | POST | Start GPS-denied session | JWT | -| /sessions/{id}/stream | GET (SSE) | Real-time position + confidence stream | JWT | -| /sessions/{id}/anchor | POST | Operator re-localization hint | JWT | -| /sessions/{id} | DELETE | End session | JWT | -| /objects/locate | POST | Object GPS from pixel coordinates | JWT | -| /health | GET | System health + memory + thermal | None | - - -**SSE event schema** (1Hz): - -```json -{ - "type": "position", - "timestamp": "2026-03-17T12:00:00.000Z", - "lat": 48.123456, - "lon": 37.654321, - "alt": 600.0, - "accuracy_h": 15.2, - "accuracy_v": 8.1, - "confidence": "HIGH", - "drift_from_anchor": 12.5, - "vo_status": "tracking", - "last_satellite_match_age_s": 8.3 -} -``` - -## UAV Platform - -Unchanged from draft05. See draft05 for: airframe configuration (3.5m S-2 composite, 12.5kg AUW), flight performance (3.4h endurance at 50 km/h), camera specifications (ADTI 20L V1 + 16mm, Viewpro A40 Pro), ground coverage calculations. - -## Speed Optimization Techniques - -Unchanged from draft05. Key points: cuVSLAM ~9ms/frame, native TRT Engine (no ONNX RT), dual CUDA streams, 5-10Hz GPS_INPUT from ESKF IMU prediction. - -## Processing Time Budget - -Unchanged from draft05. VO frame: ~17-22ms. Satellite matching: ≤210ms async. Well within 1430ms frame interval. - -## Memory Budget (Jetson Orin Nano Super, 8GB shared) - - -| Component | Memory | Notes | -| ------------------------- | -------------- | ------------------------------------------- | -| OS + runtime | ~1.5GB | JetPack 6.2 + Python | -| cuVSLAM | ~200-500MB | CUDA library + map | -| LiteSAM TRT engine | ~50-80MB | If LiteSAM fails: EfficientLoFTR ~100-150MB | -| XFeat TRT engine | ~30-50MB | | -| Preloaded satellite tiles | ~200MB | ±2km of flight plan | -| pymavlink + MAVLink | ~20MB | | -| FastAPI (local IPC) | ~50MB | | -| ESKF + buffers | ~10MB | | -| **Total** | **~2.1-2.9GB** | **26-36% of 8GB** | - - -## Key Risks and Mitigations - - -| Risk | Likelihood | Impact | Mitigation | -| ------------------------------------------------------- | ---------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| LiteSAM MinGRU ops unsupported in TRT 10.3 | LOW-MEDIUM | LiteSAM TRT export fails | Day-one verification. Fallback: EfficientLoFTR TRT → XFeat TRT. | -| cuVSLAM fails on low-texture terrain at 0.7fps | HIGH | Frequent tracking loss | Satellite matching corrections bound drift. Re-localization pipeline handles tracking loss. IMU bridges short gaps. | -| Google Maps satellite quality in conflict zone | HIGH | Satellite matching fails, outdated imagery | Pre-flight tile validation. Consider alternative providers (Bing, Mapbox). Robust to seasonal appearance changes via feature-based matching. | -| ESKF scale drift during long constant-velocity segments | MEDIUM | Position error exceeds 100m between satellite anchors | Satellite corrections every 7-14s re-anchor. Altitude constraint from barometer. Monitor drift rate — if >50m between corrections, increase satellite matching frequency. | -| Monocular scale ambiguity | MEDIUM | Metric scale lost during constant-velocity flight | Satellite absolute corrections provide scale. Known altitude constrains vertical scale. IMU acceleration during turns provides observability. | -| AUW exceeds AT4125 recommended range | MEDIUM | Reduced endurance, motor thermal stress | 12.5 kg vs 8-10 kg recommended. Monitor motor temps. Weight optimization. | -| ADTI mechanical shutter lifespan | MEDIUM | Replacement needed periodically | ~8,800 actuations/flight at 0.7fps. Estimated 11-57 flights before replacement. Budget as consumable. | -| Mid-flight companion computer failure | LOW | ~35-70s position gap | Reboot recovery procedure defined. FC uses IMU dead reckoning during gap. Known limitation. | -| Thermal throttling on Jetson | MEDIUM | Satellite matching latency increases | Active cooling required. Monitor SoC temp. Throttling at 80°C. Our workload ~8-15W typical — well under 25W TDP. | -| Engine incompatibility after JetPack update | MEDIUM | Must rebuild engines | Include engine rebuild in update procedure. | -| TRT engine build OOM on 8GB | LOW | Cannot build on target | Models small (6.31M, <5M). Reduce --memPoolSize if needed. | - - -## Testing Strategy - -### Integration / Functional Tests - -- **ESKF correctness**: Feed recorded IMU + synthetic VO/satellite data → verify output matches reference ESKF implementation -- **GPS_INPUT field validation**: Send GPS_INPUT to SITL ArduPilot → verify EKF accepts and uses the data correctly -- **Coordinate transform chain**: Known GPS → NED → pixel → back to GPS — verify round-trip error <0.1m -- **Disconnected segment handling**: Simulate tracking loss → verify satellite re-localization triggers → verify cuVSLAM restarts → verify ESKF position continuity -- **3-consecutive-failure**: Simulate VO + satellite failures → verify re-localization request sent → verify operator hint accepted -- **Object localization**: Known object at known GPS → verify computed GPS matches within camera accuracy -- **Mid-flight reboot**: Kill GPS-denied process → restart → verify recovery within expected time → verify position accuracy after recovery -- **TRT engine load test**: Verify engines load successfully on Jetson -- **TRT inference correctness**: Compare TRT output vs PyTorch reference (max L1 error < 0.01) -- **CUDA Stream pipelining**: Verify Stream B satellite matching does not block Stream A VO -- **ADTI sustained capture rate**: Verify 0.7fps sustained >30 min without buffer overflow -- **Confidence tier transitions**: Verify fix_type and accuracy change correctly across HIGH → MEDIUM → LOW → FAILED transitions - -### Non-Functional Tests - -- **End-to-end accuracy** (primary validation): Fly with real GPS recording → run GPS-denied system in parallel → compare estimated vs real positions → verify 80% within 50m, 60% within 20m -- **VO drift rate**: Measure cuVSLAM drift over 1km straight segment without satellite correction -- **Satellite matching accuracy**: Compare satellite-matched position vs real GPS at known locations -- **Processing time**: Verify end-to-end per-frame <400ms -- **Memory usage**: Monitor over 30-min session → verify <8GB, no leaks -- **Thermal**: Sustained 30-min run → verify no throttling -- **GPS_INPUT rate**: Verify consistent 5-10Hz delivery to FC -- **Tile storage**: Validate calculated storage matches actual for test mission area -- **MinGRU TRT compatibility** (day-one blocker): Clone LiteSAM → ONNX export → polygraphy → trtexec -- **Flight endurance**: Ground-test full system power draw against 267W estimate - -## References - -- ArduPilot GPS_RATE parameter: [https://github.com/ArduPilot/ardupilot/pull/15980](https://github.com/ArduPilot/ardupilot/pull/15980) -- MAVLink GPS_INPUT message: [https://ardupilot.org/mavproxy/docs/modules/GPSInput.html](https://ardupilot.org/mavproxy/docs/modules/GPSInput.html) -- pymavlink GPS_INPUT example: [https://webperso.ensta.fr/lebars/Share/GPS_INPUT_pymavlink.py](https://webperso.ensta.fr/lebars/Share/GPS_INPUT_pymavlink.py) -- ESKF reference (fixed-wing UAV): [https://github.com/ludvigls/ESKF](https://github.com/ludvigls/ESKF) -- ROS ESKF multi-sensor: [https://github.com/EliaTarasov/ESKF](https://github.com/EliaTarasov/ESKF) -- Range-VIO scale observability: [https://arxiv.org/abs/2103.15215](https://arxiv.org/abs/2103.15215) -- NaviLoc trajectory-level localization: [https://www.mdpi.com/2504-446X/10/2/97](https://www.mdpi.com/2504-446X/10/2/97) -- SatLoc-Fusion hierarchical framework: [https://www.scilit.com/publications/e5cafaf875a49297a62b298a89d5572f](https://www.scilit.com/publications/e5cafaf875a49297a62b298a89d5572f) -- Auterion GPS-denied workflow: [https://docs.auterion.com/vehicle-operation/auterion-mission-control/useful-resources/operations/gps-denied-workflow](https://docs.auterion.com/vehicle-operation/auterion-mission-control/useful-resources/operations/gps-denied-workflow) -- PX4 GNSS-denied flight: [https://docs.px4.io/main/en/advanced_config/gnss_degraded_or_denied_flight.html](https://docs.px4.io/main/en/advanced_config/gnss_degraded_or_denied_flight.html) -- ArduPilot GPS_INPUT advanced usage: [https://discuss.ardupilot.org/t/advanced-usage-of-gps-type-mav-14/99406](https://discuss.ardupilot.org/t/advanced-usage-of-gps-type-mav-14/99406) -- Google Maps Ukraine imagery: [https://newsukraine.rbc.ua/news/google-maps-has-surprise-for-satellite-imagery-1727182380.html](https://newsukraine.rbc.ua/news/google-maps-has-surprise-for-satellite-imagery-1727182380.html) -- Jetson Orin Nano Super thermal: [https://edgeaistack.app/blog/jetson-orin-nano-power-consumption/](https://edgeaistack.app/blog/jetson-orin-nano-power-consumption/) -- GSD matching research: [https://www.kjrs.org/journal/view.html?pn=related&uid=756&vmd=Full](https://www.kjrs.org/journal/view.html?pn=related&uid=756&vmd=Full) -- VO+satellite matching pipeline: [https://polen.itu.edu.tr/items/1fe1e872-7cea-44d8-a8de-339e4587bee6](https://polen.itu.edu.tr/items/1fe1e872-7cea-44d8-a8de-339e4587bee6) -- PyCuVSLAM docs: [https://wiki.seeedstudio.com/pycuvslam_recomputer_robotics/](https://wiki.seeedstudio.com/pycuvslam_recomputer_robotics/) -- Pixhawk 6x IMU (ICM-42688-P) datasheet: [https://invensense.tdk.com/products/motion-tracking/6-axis/icm-42688-p/](https://invensense.tdk.com/products/motion-tracking/6-axis/icm-42688-p/) -- All references from solution_draft05.md - -## Related Artifacts - -- AC Assessment: `_docs/00_research/gps_denied_nav/00_ac_assessment.md` -- Completeness assessment research: `_docs/00_research/solution_completeness_assessment/` -- Previous research: `_docs/00_research/trt_engine_migration/` -- Tech stack evaluation: `_docs/01_solution/tech_stack.md` (needs sync with draft05 corrections) -- Security analysis: `_docs/01_solution/security_analysis.md` -- Previous draft: `_docs/01_solution/solution_draft05.md` - diff --git a/_docs/01_solution/tech_stack.md b/_docs/01_solution/tech_stack.md deleted file mode 100644 index e7b50e6..0000000 --- a/_docs/01_solution/tech_stack.md +++ /dev/null @@ -1,59 +0,0 @@ -# Tech Stack Evaluation - -## Requirements Analysis - -| Area | Requirement | -|------|-------------| -| Runtime | Jetson Orin Nano Super, Ubuntu/JetPack, CUDA/TensorRT available, 8 GB shared memory, 25 W thermal envelope. | -| Language | Python is acceptable for orchestration/prototyping; C++/TensorRT paths likely needed for hot vision loops. | -| Vision | Calibration, undistortion, homography, VPR descriptors, local matching, RANSAC verification. | -| Estimation | BASALT VIO for relative camera+IMU propagation, wrapped by project-owned safety/anchor estimator logic for covariance calibration, source labels, blackout/spoofing modes, and MAVLink output mapping. | -| Storage | Offline satellite cache, descriptor index, FDR with no raw frame retention. | -| Autopilot | ArduPilot Plane, `GPS_INPUT` through pymavlink, MAVSDK for telemetry. | - -## Technology Evaluation - -| Layer | Selected | Alternatives Considered | Rationale | Risk | -|-------|----------|-------------------------|-----------|------| -| OS / GPU stack | JetPack Ubuntu + CUDA + TensorRT | Plain Ubuntu without JetPack | Required for Jetson acceleration and profiling. | Thermal/performance tuning. | -| Calibration / geometry | OpenCV 4.x | Custom NumPy-only geometry | Mature APIs for calibration, undistortion, homography, RANSAC. | Version pin and calibration quality. | -| VO / estimator | BASALT + project-owned safety/anchor wrapper | OpenVINS, Kimera-VIO, custom OpenCV/ESKF, ORB-SLAM3, VINS-Fusion | BASALT is the selected production VIO candidate; wrapper owns source labels, covariance gates, degraded modes, satellite-anchor acceptance, and MAVLink semantics. | BASALT confidence/covariance must be calibrated; nadir fixed-wing replay required. | -| VPR descriptors | DINOv2-VLAD / AnyLoc-style, model-size profiled, TensorRT only after fidelity check | MixVPR, SALAD, NetVLAD, classical BoW | Strong retrieval evidence; good offline descriptor model. | Memory/latency and embedding drift if optimized incorrectly. | -| Vector search | FAISS CPU-first on Jetson ARM64 | HNSWLIB, PostgreSQL/pgvector metadata-assisted search, brute-force NumPy, custom FAISS GPU build | Mature top-K search, save/load, PQ compression; PostgreSQL stores spatial/mission metadata around descriptor files. | CPU query latency must be profiled; GPU FAISS is not default on aarch64. | -| Local matching | DISK/ALIKED + LightGlue | SuperPoint+LightGlue, SIFT/ORB, LoFTR | Exact match outputs; Apache/BSD-friendly path; adaptive speed knobs. | Jetson profiling needed. | -| Raster cache | COG + PostgreSQL/PostGIS manifest + signed JSON sidecars | PMTiles, MBTiles, loose tile folders | COG fits geospatial raster and write-new-tile workflow; PostGIS supports spatial/freshness queries. | 10 GB budget pressure and local DB availability. | -| MAVLink | MAVSDK telemetry + pymavlink `GPS_INPUT` | MAVSDK-only, MAVProxy bridge | MAVSDK does telemetry well; `GPS_INPUT` needs raw field control. | Plane SITL validation. | -| FDR | PostgreSQL event index + CBOR/binary payload segments with optional Parquet export | Raw images, plain CSV | Queryable event metadata, bounded payload segments, no raw frame retention. | Schema and local DB availability. | -| Testing | ArduPilot Plane SITL + AerialVL/VPAir + EuRoC + representative flight replay | Public datasets only | No public dataset covers all ACs. | Representative data collection required. | - -## Tech Stack Summary - -- **Primary implementation**: Python for orchestration, test harness, cache tooling, and MAVLink integration; C++/TensorRT for hot-path vision if profiling requires it. -- **Vision utilities**: OpenCV 4.x. -- **Estimator**: BASALT VIO plus project-owned safety/anchor wrapper and mode machine. -- **Global retrieval**: DINOv2-VLAD style descriptors with CPU-first FAISS top-K search. -- **Local matching**: DISK/ALIKED + LightGlue; SuperPoint only after license review. -- **Cache**: COG imagery, PostgreSQL/PostGIS manifest metadata, signed JSON sidecars, FAISS index files. -- **Autopilot**: MAVSDK subscriptions plus pymavlink `GPS_INPUT`. -- **Validation**: public datasets for component de-risking, Plane SITL for integration, representative flight/replay data for acceptance. - -## Risk Assessment - -| Risk | Impact | Mitigation | -|------|--------|------------| -| VPR/local matching exceeds Jetson latency | AC-4.1 failure | Conditional VPR, top-K caps, downsampled descriptors, CPU FAISS profiling, TensorRT only after embedding-fidelity checks. | -| Descriptor cache exceeds 10 GB | AC-8.3/storage failure | PQ/compression, multi-scale budget report, split descriptor budget if needed. | -| GPL library accidentally becomes production dependency | Licensing issue | Keep OpenVINS/ORB-SLAM3 as reference only unless legal approves; BASALT is the production VIO candidate. | -| BASALT covariance under-reports real error | False-position safety budget failure | Calibrate wrapper covariance against OpenVINS covariance, ground truth replay, and satellite anchor residuals. | -| Plane failsafe differs from Copter docs | Safety behavior mismatch | Production-parameter ArduPilot Plane SITL gate. | -| `GPS_INPUT` velocity ignore flags behave unexpectedly | EKF drift or false velocity fusion | SITL tests for velocity fields, ignore flags, and `EK3_SRC1_*` source parameters. | -| Public datasets fail to represent Ukrainian agricultural terrain | False confidence | Require representative synchronized flight/replay data before AC signoff. | -| Thermal throttling | Latency regression | Hot-soak test and throttle logging per AC-NEW-5. | - -## Learning / Implementation Requirements - -- Jetson profiling with CUDA/TensorRT and memory instrumentation. -- ArduPilot Plane SITL, `GPS_INPUT`, GPS spoof/failsafe parameters. -- Geospatial raster formats: COG, CRS, tile matrices, m/px metadata, manifests. -- BASALT integration, covariance calibration, and Mahalanobis rejection in the safety/anchor wrapper. -- Aerial VPR benchmark methodology and georeference recall. diff --git a/_docs/02_document/FINAL_report.md b/_docs/02_document/FINAL_report.md deleted file mode 100644 index b83f42b..0000000 --- a/_docs/02_document/FINAL_report.md +++ /dev/null @@ -1,148 +0,0 @@ -# GPS-Denied Onboard Localization — Planning Report - -## Executive Summary - -The solution planning phase decomposed the GPS-denied onboard localization service into 8 runtime implementation components, 2 cross-cutting foundation epics, a bootstrap epic, and separate e2e/blackbox test epics. The architecture centers on a Jetson-hosted hot path using camera ingest, BASALT VIO, and a project-owned safety/anchor wrapper, with triggered Satellite Service candidate retrieval and ALIKED/DISK-LightGlue anchor verification against an offline PostgreSQL/PostGIS-backed cache. - -Jira epics were created in project `AZ` from AZ-206 through AZ-218. Total estimated effort across epics is approximately 87-141 story points, with large work intentionally decomposed into child tasks of 2, 3, or 5 points where possible. - -## Problem Statement - -The system must provide reliable onboard WGS84 localization when GPS is denied or spoofed, using a fixed nadir camera, flight-controller telemetry, and an offline satellite cache. It must emit ArduPilot-compatible position estimates, report confidence honestly, degrade safely under blackout, and preserve enough forensic evidence for post-flight analysis without retaining raw frames. - -## Architecture Overview - -The system is a trigger-based hybrid estimator. Normal flight uses camera ingest, pre-VIO occlusion checks, BASALT VIO, and a safety/anchor wrapper. Relocalization triggers use DINOv2-VLAD, FAISS, ALIKED/DISK-LightGlue, and OpenCV RANSAC against the offline cache. The wrapper is the safety authority for covariance, source labels, degraded modes, tile-write eligibility, and MAVLink output semantics. - -**Technology stack**: Python orchestration, C++/native vision paths where needed, OpenCV 4.x, BASALT, DINOv2-VLAD, FAISS CPU, ALIKED/DISK-LightGlue, PostgreSQL/PostGIS, COG, CBOR FDR segments, MAVSDK + pymavlink. - -**Deployment**: Local onboard Jetson runtime with Docker/replay and Plane SITL for validation; release gates require Jetson hardware, Plane SITL, and representative synchronized replay data. - -## Component Summary - -| # | Component | Purpose | Dependencies | Epic | -|---|-----------|---------|--------------|------| -| 01 | Camera Ingest And Calibration | Ingest frames, validate calibration, detect total occlusion before VIO | Bootstrap, shared geometry/time, config/errors | AZ-209 | -| 02 | VIO Adapter | Wrap the selected relative VIO backend and emit replaceable state DTOs | Camera, MAVLink telemetry, shared helpers | AZ-213 | -| 03 | Safety And Anchor Wrapper | Own localization state, covariance, anchors, blackout/failsafe, output semantics | Camera, MAVLink, VIO, anchor verification | AZ-216 | -| 04 | Satellite Service | Sync Satellite Service cache/upload packages and retrieve local VPR candidates from cache descriptors and FAISS | Camera, Tile Manager, shared helpers | AZ-214 | -| 05 | Anchor Verification | Verify retrieved candidates with learned matching and RANSAC | Satellite Service, camera, Tile Manager | AZ-215 | -| 06 | Tile Manager | Manage COGs, PostGIS manifests, sidecars, freshness, and orthorectified generated tiles | Bootstrap, shared helpers, config/errors | AZ-211 | -| 07 | MAVLink And GCS Integration | Consume FC telemetry and emit v1 `GPS_INPUT`/QGC status | Bootstrap, config/errors | AZ-210 | -| 08 | FDR And Observability | Record bounded replayable evidence and status | Bootstrap, config/errors, runtime DTOs | AZ-212 | -| Test | E2E Test Suite | Separate black-box replay, SITL, Jetson, and release evidence tests; not onboard runtime | All runtime components | AZ-217 | - -**Implementation order**: -1. Bootstrap and cross-cutting foundations: AZ-206, AZ-207, AZ-208. -2. Independent adapters/stores: AZ-209, AZ-210, AZ-211, AZ-212. -3. Estimation/relocalization: AZ-213, AZ-214, AZ-215. -4. Safety orchestration: AZ-216. -5. Separate e2e/blackbox test implementation: AZ-217, AZ-218. - -## System Flows - -| Flow | Description | Key Components | -|------|-------------|----------------| -| Pre-flight cache preparation | Validate offline cache, sidecars, descriptors, and indexes | Satellite Service, Tile Manager | -| Normal frame processing | Route usable frames through BASALT; route total occlusion to IMU-only degraded path | Camera, BASALT, safety, MAVLink, FDR | -| Satellite relocalization | Retrieve and verify cache candidates, then accept/reject anchors | Safety, Satellite Service, anchor verification, Tile Manager | -| Visual blackout / spoofing | Propagate IMU-only from last trusted state and fail safe at thresholds | Camera, safety, MAVLink, QGC, FDR | -| Generated tile lifecycle | Write generated COG candidates only under covariance/quality gates | Safety, Tile Manager, FDR | -| Post-flight sync and audit | Package generated tiles and FDR evidence | Tile Manager, FDR, Satellite Service | -| Validation replay | Exercise runtime through public interfaces | Validation harness, all runtime components | - -See `system-flows.md` for full diagrams and details. - -## Risk Summary - -| Level | Count | Key Risks | -|-------|-------|-----------| -| Critical | 0 | None | -| High | 7 | Camera spec mismatch, BASALT nadir fit, covariance under-reporting, total occlusion false-negative, IMU-only over-trust, Jetson trigger-path performance, PostgreSQL/PostGIS availability | -| Medium | 5 | Cache poisoning, dataset coverage/licensing, FDR append pressure, GPL/non-commercial leakage, generated tile promotion risk | -| Low | 0 | None | - -**Iterations completed**: 1 -**All Critical/High risks mitigated**: Yes. High risks have concrete gates in architecture, component specs, and tests. - -See `risk_mitigations.md` for the full register. - -## Test Coverage - -| Component | Integration | Performance | Security | Acceptance | AC Coverage | -|-----------|-------------|-------------|----------|------------|-------------| -| Camera Ingest And Calibration | 3 | 1 | 1 | 2 | 7 ACs | -| VIO Adapter | 4 | 1 | 1 | 1 | 8 ACs | -| Safety And Anchor Wrapper | 7 | 1 | 1 | 3 | 15 ACs | -| Satellite Service | 4 | 2 | 1 | 1 | 10 ACs | -| Anchor Verification | 2 | 1 | 2 | 1 | 9 ACs | -| Tile Manager | 4 | 1 | 3 | 1 | 10 ACs | -| MAVLink And GCS Integration | 6 | 2 | 1 | 1 | 10 ACs | -| FDR And Observability | 6 | 1 | 1 | 1 | 11 ACs | -| E2E Test Suite | 9 | 2 | 1 | 2 | All AC groups | - -**Overall acceptance criteria coverage**: 39 / 39 acceptance criteria covered (100%). -**Restrictions coverage**: 10 / 10 restriction groups covered (100%). - -## Epic Roadmap - -| Order | Epic | Component / Concern | Effort | Dependencies | -|-------|------|---------------------|--------|--------------| -| 1 | AZ-206: Bootstrap & Initial Structure | Scaffold | M / 5-8 pts | none | -| 2 | AZ-207: Cross-Cutting: Shared Geometry And Time Sync | Shared helper | S-M / 3-5 pts | AZ-206 | -| 3 | AZ-208: Cross-Cutting: Runtime Configuration And Errors | Shared helper | S-M / 3-5 pts | AZ-206 | -| 4 | AZ-209: Camera Ingest And Calibration | Component 01 | M / 5-8 pts | AZ-206, AZ-207, AZ-208 | -| 5 | AZ-210: MAVLink And GCS Integration | Component 07 | M / 5-8 pts | AZ-206, AZ-208 | -| 6 | AZ-211: Tile Manager | Component 06 | L / 8-13 pts | AZ-206, AZ-207, AZ-208 | -| 7 | AZ-212: FDR And Observability | Component 08 | M-L / 5-8 pts | AZ-206, AZ-208 | -| 8 | AZ-213: VIO Adapter | Component 02 | L / 8-13 pts | AZ-209, AZ-210 | -| 9 | AZ-214: Satellite Service | Component 04 | L / 8-13 pts | AZ-209, AZ-211 | -| 10 | AZ-215: Anchor Verification | Component 05 | L / 8-13 pts | AZ-214, AZ-209, AZ-211 | -| 11 | AZ-216: Safety And Anchor Wrapper | Component 03 | XL / 13-21 pts | AZ-209, AZ-210, AZ-213, AZ-215 | -| 12 | AZ-217: E2E Test Suite | Separate test support | L / 8-13 pts | Component epics | -| 13 | AZ-218: Blackbox Tests | System tests | L / 8-13 pts | AZ-217, component epics | - -**Total estimated effort**: 87-141 story points. - -## Key Decisions Made - -| # | Decision | Rationale | Alternatives Rejected | -|---|----------|-----------|----------------------| -| 1 | Use BASALT as production VIO candidate | Permissive license and strong VIO benchmark fit | OpenVINS production dependency, custom VIO from scratch | -| 2 | Keep safety/anchor wrapper as authority | Product semantics require calibrated covariance, labels, gates, failsafe, MAVLink mapping | Letting BASALT/OpenVINS own output safety | -| 3 | Use ALIKED/DISK-LightGlue for anchor verification | Strong local correspondences for cross-domain verification | Per-frame learned matcher as primary VIO hot path | -| 4 | Add pre-VIO total-occlusion gate | Safer and cheaper than feeding fully unusable frames to VIO | Letting BASALT detect all visual failures | -| 5 | Use PostgreSQL/PostGIS for structured metadata | User confirmed PostgreSQL; PostGIS fits spatial cache/mission metadata | JSON-only or embedded single-file metadata DB | -| 6 | Use CBOR FDR payload segments with PostgreSQL index | Keeps high-volume append data bounded and queryable | Raw-frame retention, plain CSV, Parquet as runtime primary | -| 7 | v1 emits `GPS_INPUT` only | Avoid ArduPilot EKF3 double-fusion risk in v1 | Parallel `ODOMETRY` in v1 | - -## Open Questions - -| # | Question | Impact | Assigned To | -|---|----------|--------|-------------| -| 1 | Exact ADTi camera lens, interface, sustained FPS, and temperature spec | Blocks final camera calibration and runtime FPS assumptions | Hardware/product owner | -| 2 | Final representative synchronized target dataset collection timing | Blocks final acceptance, though public datasets can de-risk | Project/product owner | -| 3 | Dataset license approval for ALTO/Kagaru/EPFL/VPAir/UZH FPV use | Blocks commercial acceptance evidence for restricted datasets | Legal/product owner | -| 4 | Local onboard PostgreSQL/PostGIS deployment profile | Blocks implementation details for DB persistence and health checks | Backend/runtime owner | - -## Artifact Index - -| File | Description | -|------|-------------| -| `glossary.md` | Confirmed project glossary | -| `architecture.md` | System architecture and ADRs | -| `data_model.md` | System data model and storage strategy | -| `system-flows.md` | Main runtime and validation flows | -| `deployment/containerization.md` | Container/replay strategy | -| `deployment/ci_cd_pipeline.md` | CI/CD and release gates | -| `deployment/environment_strategy.md` | Environment and dataset strategy | -| `deployment/observability.md` | Runtime signals, logs, and alerts | -| `deployment/deployment_procedures.md` | Deployment, rollback, and health checks | -| `components/*/description.md` | Component specifications | -| `components/*/tests.md` | Component test specifications | -| `common-helpers/*.md` | Shared helper specifications | -| `diagrams/component_overview.md` | Component overview Mermaid diagram | -| `diagrams/flows/*.md` | Flow-specific Mermaid diagrams | -| `risk_mitigations.md` | Risk register and mitigations | -| `epics.md` | Jira epic mapping and dependency roadmap | -| `FINAL_report.md` | This final planning report | diff --git a/_docs/02_document/architecture.md b/_docs/02_document/architecture.md deleted file mode 100644 index f094234..0000000 --- a/_docs/02_document/architecture.md +++ /dev/null @@ -1,242 +0,0 @@ -# GPS-Denied Onboard Localization — Architecture - -## Architecture Vision - -Build a Jetson-hosted onboard localization pipeline for fixed-wing GPS-denied flight. The hot path fuses fixed nadir camera frames and FC telemetry through OpenCV geometry, BASALT VIO, and a project-owned safety/anchor wrapper that emits calibrated `GPS_INPUT` estimates and QGC/FDR status. A triggered satellite-anchor path uses DINOv2-VLAD, CPU FAISS, ALIKED/DISK+LightGlue, and RANSAC against the offline cache; generated tiles are written back only with strict provenance and covariance gates. - -### Components / Responsibilities - -- Camera ingest/calibration: load frames, apply intrinsics/extrinsics, validate image quality. -- VIO adapter: produce relative camera+IMU motion from synchronized nav frames and FC IMU. -- Safety/anchor wrapper: own covariance calibration, source labels, degraded modes, anchor fusion, and `GPS_INPUT`. -- Satellite Service: sync mission cache packages before flight, upload generated-tile packages after flight, and serve local VPR candidate retrieval from the offline cache. -- Anchor verification: run local matching/RANSAC and reject unsafe anchors. -- Tile Manager: manage COGs, manifests, freshness/provenance, orthorectified generated tiles, and local tile metadata. -- MAVLink/GCS integration: consume FC telemetry and emit `GPS_INPUT`/QGC status. -- FDR/observability: record replayable mission evidence under storage caps. -- Validation harness: run local pytest plus Docker replay smoke for still-image, cache, SITL/QGC stub, security, Jetson-prerequisite, public dataset, and representative replay tests. - -### Principles / Non-Negotiables - -- No in-flight satellite-provider or Satellite Service calls; runtime uses offline cache only. -- BASALT is a VIO component, not the safety authority. -- Confidence must be honest; covariance must grow in degraded modes. -- Heavy VPR/local matching is trigger-based, not per-frame. -- Raw nav/AI frames are not retained in normal operation. -- GPL VIO libraries remain reference-only unless explicitly approved. -- Plane SITL and Jetson hardware are release gates. -- Public datasets can de-risk, but representative synchronized flight data is required for final acceptance. - -## 1. System Context - -**Problem being solved**: During fixed-wing flight, GPS may be denied or spoofed. The onboard system must estimate WGS84 coordinates for navigation-camera frame centers and detected objects, stream `GPS_INPUT` to ArduPilot Plane, report confidence honestly, and maintain safety during VO failure, stale imagery, spoofing, and visual blackout. - -**System boundaries**: - -- In scope: onboard localization runtime, offline cache consumption, BASALT VIO integration, satellite anchor verification, MAVLink output, QGC status, FDR, generated tile metadata, and a separate e2e/black-box test suite. -- Out of scope: upstream commercial satellite-provider sourcing, Satellite Service ingest implementation, AI mission-camera detection itself, PX4 support, raw-frame retention as a normal operating mode. - -**External systems**: - -| System | Integration Type | Direction | Purpose | -|--------|------------------|-----------|---------| -| ArduPilot Plane FC | MAVLink | Inbound/Outbound | FC telemetry in, `GPS_INPUT` and status out | -| QGroundControl | MAVLink telemetry | Outbound | Downsampled operator status and failsafe messages | -| Azaion Suite Satellite Service | Offline file/cache sync | Inbound before flight, outbound after landing | Provides mission cache packages and receives generated-tile packages; never called mid-flight | -| Public/replay datasets | File/rosbag/fixture | Inbound to validation | De-risk BASALT, VPR, and anchor logic | - -## 2. Technology Stack - -| Layer | Technology | Version / Mode | Rationale | -|-------|------------|----------------|-----------| -| OS / GPU stack | JetPack Ubuntu + CUDA/TensorRT/ONNX Runtime | Jetson Orin Nano Super target | Required for production hardware profiling | -| Runtime language | Python + C++ | Python orchestration; C++ for BASALT/hot vision paths | Fits MAVLink/test tooling and native VIO dependencies | -| Geometry | OpenCV 4.x | Calibration, undistortion, homography, RANSAC/USAC | Mature utility layer | -| VIO | BASALT | Production candidate | BSD-friendly, strong benchmark evidence | -| VIO reference | OpenVINS | Reference/covariance baseline only | Strong EKF covariance story; GPLv3 risk | -| Backup VIO | Kimera-VIO | Backup candidate | BSD-friendly fallback with mono caveats | -| Local matching | ALIKED/DISK + LightGlue | Anchor verification and optional VO fallback | Strong learned correspondences; profile before hot-path use | -| Retrieval | DINOv2-VLAD + CPU FAISS | Triggered VPR only | Robust candidate retrieval under cache/offline constraints | -| Structured metadata DB | PostgreSQL + PostGIS | Onboard/local deployment | Spatial cache manifests, mission state, generated-tile metadata, and FDR event indexes | -| Cache imagery | COG + PostgreSQL/PostGIS manifest + signed JSON sidecars | Write-new COG objects | Efficient geospatial rasters with queryable spatial metadata and auditable sidecars | -| FDR | PostgreSQL event index + CBOR segment payloads, optional Parquet export | Per-flight rollover | Queryable event metadata with compact bounded payload segments | -| MAVLink | MAVSDK + pymavlink | MAVSDK telemetry, pymavlink `GPS_INPUT` | Exact output control | - -**Key constraints from restrictions.md**: - -- Jetson has 8 GB shared memory and 25 W thermal envelope, so heavy VPR/local matching cannot run every frame. -- Runtime must be offline with respect to satellite providers, so all imagery and descriptors are preloaded. -- The camera is fixed nadir; all VO choices must be validated against low-parallax/planar terrain. -- ADTi public specs conflict with current assumptions on resolution, continuous FPS, and operating temperature; manufacturer specs must be pinned before implementation. - -## 3. Deployment Model - -**Environments**: Development replay, public-dataset replay, Jetson hardware validation, Plane SITL, representative flight/replay rig. - -**Infrastructure**: - -- Onboard production runtime runs on the Jetson companion computer, not in cloud. -- Replay/test infrastructure may use Docker for deterministic fixture tests. -- Release gates require local Jetson hardware and ArduPilot Plane SITL. - -**Environment-specific configuration**: - -| Config | Development | Production | -|--------|-------------|------------| -| Satellite cache | Small fixture cache | Preloaded operational-area cache | -| Descriptor index | Fixture FAISS index | CPU-first FAISS index with PQ/IVF if needed | -| Secrets/signing | Local test keys | Mission/cache signing keys from Suite process | -| FDR | Local temp output | Per-flight bounded NVMe storage | -| MAVLink | SITL/replay | Physical FC telemetry link | -| VIO runtime | Explicit replay profile | Native BASALT-compatible runtime required; missing runtime blocks startup/readiness | - -## 4. Data Model Overview - -**Core entities**: - -| Entity | Description | Owned By Component | -|--------|-------------|--------------------| -| FrameRecord | Navigation-camera frame metadata, total-occlusion status, and processing status | Camera ingest/calibration | -| TelemetrySample | FC IMU, attitude, airspeed, altitude, GPS health | MAVLink/GCS integration | -| VioState | Backend-relative pose/velocity/bias output and quality metadata | VIO adapter | -| PositionEstimate | WGS84 estimate, covariance, source label, fix type, anchor age | Safety/anchor wrapper | -| VprChunk | Retrieval unit over cache imagery and descriptors | Satellite Service | -| AnchorCandidate | Retrieved tile/chunk with local-match and RANSAC evidence | Anchor verification | -| CacheTile | COG tile plus manifest and sidecar metadata | Tile Manager | -| GeneratedTile | In-flight orthorectified tile with trust/provenance metadata | Tile Manager | -| FdrSegment | Bounded replayable log segment | FDR/observability | - -**Data flow summary**: - -- Frame quality/total-occlusion gate + telemetry -> BASALT VIO when usable, or IMU-only degraded mode when not -> safety/anchor wrapper -> `GPS_INPUT`, QGC, FDR. -- Relocalization trigger -> DINOv2-VLAD/FAISS -> ALIKED/DISK+LightGlue/RANSAC -> accepted/rejected anchor. -- High-confidence pose + frame -> generated tile -> manifest/sidecar -> post-flight Satellite Service sync. - -## 5. Integration Points - -### Internal Communication - -| From | To | Protocol | Pattern | Notes | -|------|----|----------|---------|-------| -| Camera ingest/calibration | VIO adapter | In-process queue or shared frame bus | Streaming | Timestamp discipline is critical | -| MAVLink telemetry | VIO adapter | In-process telemetry buffer | Streaming | IMU/attitude/altitude sync | -| VIO adapter | Safety/anchor wrapper | Typed state messages | Streaming | Wrapper calibrates confidence | -| Safety/anchor wrapper | Satellite Service | Command | Triggered local request | Uses only preloaded cache/index data during flight | -| Satellite Service | Anchor verification | Candidate list | Request-response | Dynamic top-K | -| Anchor verification | Safety/anchor wrapper | Anchor decision | Request-response | Includes MRE/inliers/provenance | -| Safety/anchor wrapper | MAVLink/GCS integration | Position/status DTO | Streaming | `GPS_INPUT` emitted frame-by-frame | -| Safety/anchor wrapper | FDR/observability | Append-only events | Streaming | Bounded segments | - -### External Integrations - -| External System | Protocol | Auth | Failure Mode | -|-----------------|----------|------|--------------| -| ArduPilot Plane | MAVLink | Source/system ID allowlist | Degrade/failsafe; never trust spoofed GPS blindly | -| QGroundControl | MAVLink | FC telemetry path | Downsampled status may be delayed but local FDR remains authoritative | -| Azaion Suite Satellite Service | Offline package sync | Signed manifests/sidecars | Missing/stale cache causes degraded mode, not mid-flight network fetch | -| Public datasets | File/rosbag | License constraints | Not final acceptance unless representative and license-compatible | - -## 6. Non-Functional Requirements - -| Requirement | Target | Measurement | Priority | -|-------------|--------|-------------|----------| -| Frame latency | <400 ms p95 | Capture/replay timestamp to emitted estimate | High | -| Memory | <8 GB shared | Jetson monitoring | High | -| First fix | <30 s p95 | 50 cold starts | High | -| Thermal | No throttle at 25 W / +50 C | 8-hour hot-soak | High | -| FDR storage | <=64 GB/flight | 8-hour synthetic load | High | -| Cache storage | ~10 GB persistent budget | Full mission cache accounting | High | -| False position | P(error >500 m) <0.1%, >1 km <0.01% | Monte Carlo/replay | High | - -## 7. Security Architecture - -**Authentication / trust boundary**: - -- Runtime accepts only local cache files with valid manifest/signature/provenance. -- MAVLink input is filtered by expected source/system IDs and FC health semantics. - -**Data protection**: - -- At rest: FDR and cache sidecars should be integrity protected; mission secrets/signing keys are not stored in code. -- In transit: no in-flight satellite-provider or Satellite Service network dependency; MAVLink link security depends on FC/GCS deployment. - -**Audit logging**: - -- FDR records estimates, covariance, anchors, rejected anchors, cache validation failures, spoofing/blackout transitions, emitted `GPS_INPUT`, resource health, and tile-write decisions. - -## 8. Key Architectural Decisions - -### ADR-001: BASALT As Production VIO Candidate - -**Context**: A naive OpenCV-only VIO implementation is risky, while OpenVINS has GPLv3 production constraints. - -**Decision**: Use BASALT as the production relative VIO candidate and keep OpenVINS as covariance/reference baseline. - -**Alternatives considered**: - -1. OpenVINS as production core — rejected by default because of GPLv3 and generic VIO ownership. -2. Kimera-VIO — retained as backup due to BSD license but mono-inertial caveats. -3. Fully custom OpenCV/ESKF — fallback only because implementation burden is high. - -**Consequences**: The safety/anchor wrapper must calibrate confidence around BASALT and prove it on representative data. - -### ADR-002: ALIKED-LightGlue Role - -**Context**: ALIKED-LightGlue can produce strong local correspondences and can support frame-to-frame homography/pose estimation. - -**Decision**: Use ALIKED/DISK+LightGlue for satellite-anchor verification and evaluate it as an optional VO fallback/keyframe-assist path, not as the default BASALT replacement. - -**Alternatives considered**: - -1. Per-frame ALIKED-LightGlue VO hot path — deferred until Jetson profiling proves latency/memory fit. -2. SIFT/ORB-only matching — retained as regression baseline, weaker under cross-domain conditions. -3. SuperPoint+LightGlue — license-gated. - -**Consequences**: Implementation tasks must benchmark ALIKED-LightGlue on frame-to-frame VO and cross-domain anchor workloads separately. - -### ADR-003: Cache Metadata Format - -**Context**: JSON is simple and auditable, but operational cache queries need spatial indexing, freshness filters, update safety, and integration with the project PostgreSQL database. - -**Decision**: Use PostgreSQL with PostGIS as the primary cache manifest/index database, with signed JSON sidecars for each tile/generated tile for auditability and interchange. - -**Alternatives considered**: - -1. JSON-only manifest — simpler, but weak for query/update scale, spatial search, and consistency. -2. Embedded single-file metadata DB — efficient for small deployments, but rejected because the project will use PostgreSQL/PostGIS. - -**Consequences**: The Tile Manager owns PostgreSQL migrations, PostGIS indexes, signature checks, generated-tile orthorectification metadata, and sidecar/db consistency. - -### ADR-004: FDR Format - -**Context**: The FDR must be compact, bounded, replayable, and exportable for analysis. - -**Decision**: Use PostgreSQL for FDR event indexes and mission-query metadata, with CBOR-backed segment payloads for bounded append-heavy runtime data and optional Parquet export after flight. - -**Alternatives considered**: - -1. Plain CSV — rejected for type safety, size, and complex payloads. -2. Parquet as primary onboard format — good analytics, but less ideal as the runtime append/rollover path. - -**Consequences**: FDR implementation must define PostgreSQL tables/indexes, CBOR segment schema, rollover behavior, and export tooling. - -### ADR-006: Total Occlusion Before VIO - -**Context**: BASALT should not receive frames that are completely unusable because of lens cover, cloud/whiteout, decode failure, extreme exposure, or other total visual blackout. - -**Decision**: Camera ingest performs a pre-VIO total-occlusion/blackout check. Total occlusion bypasses BASALT for that frame, sends a `total_occlusion` or `visual_blackout` degradation signal to the safety wrapper, and continues IMU-only propagation from the last trusted state. - -**Alternatives considered**: - -1. Let BASALT detect every visual failure — rejected because total occlusion is cheaper and safer to catch before the VIO hot path. -2. Drop frames silently — rejected because the wrapper must grow covariance and emit honest degraded output. - -**Consequences**: The camera component must expose `occlusion_status`, and tests must assert mode transition to `dead_reckoned`/failsafe under total blackout. - -### ADR-005: Public Dataset Strategy - -**Context**: The original still-image sample lacks synchronized IMU and ground-truth trajectory. The Derkachi fixture adds cropped nadir video synchronized with IMU and `GLOBAL_POSITION_INT` trajectory, but camera intrinsics, distortion, and camera-to-body calibration remain pending. - -**Decision**: Prioritize MUN-FRL for synchronized nadir camera + IMU + GNSS/ground truth; use ALTO for aerial localization/VPR and long nadir trajectories; investigate Kagaru/EPFL for fixed-wing/farmland relevance; use EuRoC/UZH FPV only as VIO proxies if license-compatible. - -**Consequences**: Public datasets de-risk components but do not replace representative target flight data for final acceptance. diff --git a/_docs/02_document/common-helpers/01_helper_geo_geometry.md b/_docs/02_document/common-helpers/01_helper_geo_geometry.md deleted file mode 100644 index 6dea55e..0000000 --- a/_docs/02_document/common-helpers/01_helper_geo_geometry.md +++ /dev/null @@ -1,30 +0,0 @@ -# Geo Geometry Helper - -## Purpose - -Shared geospatial and camera-geometry utilities used by camera ingest, safety wrapper, Tile Manager, anchor verification, and validation. - -## Responsibilities - -- WGS84 to local tangent plane conversions. -- Haversine/ground-distance calculations. -- Ground sampling distance calculations. -- Camera footprint projection from intrinsics, extrinsics, altitude, and attitude. -- Homography and covariance unit conversions for reporting. - -## Non-Responsibilities - -- No image matching. -- No state estimation. -- No MAVLink emission. -- No cache policy decisions. - -## Consumers - -| Component | Usage | -|-----------|-------| -| Camera ingest/calibration | Footprint and calibration sanity checks | -| Safety/anchor wrapper | Distance/covariance/unit conversion | -| Anchor verification | Pixel-to-ground error reporting | -| Tile Manager | Tile footprint metadata | -| Validation harness | Error thresholds and reports | diff --git a/_docs/02_document/common-helpers/02_helper_time_sync.md b/_docs/02_document/common-helpers/02_helper_time_sync.md deleted file mode 100644 index baf23cf..0000000 --- a/_docs/02_document/common-helpers/02_helper_time_sync.md +++ /dev/null @@ -1,29 +0,0 @@ -# Time Sync Helper - -## Purpose - -Shared timestamp validation and alignment utilities for frame, IMU, telemetry, FDR, and replay data. - -## Responsibilities - -- Monotonic timestamp checks. -- Frame-to-IMU window selection. -- Clock-domain conversion metadata. -- Replay ordering validation. -- Gap and jitter metrics. - -## Non-Responsibilities - -- No VIO state estimation. -- No MAVLink parsing beyond normalized timestamp fields. -- No recovery policy; callers decide whether to degrade or reject. - -## Consumers - -| Component | Usage | -|-----------|-------| -| Camera ingest/calibration | Frame ordering and timestamp metadata | -| VIO adapter | IMU/frame synchronization | -| MAVLink/GCS integration | Telemetry timestamp normalization | -| FDR/observability | Segment ordering | -| Validation harness | Fixture validation | diff --git a/_docs/02_document/components/01_camera_ingest_calibration/description.md b/_docs/02_document/components/01_camera_ingest_calibration/description.md deleted file mode 100644 index a10297a..0000000 --- a/_docs/02_document/components/01_camera_ingest_calibration/description.md +++ /dev/null @@ -1,115 +0,0 @@ -# Camera Ingest And Calibration - -## 1. High-Level Overview - -**Purpose**: Ingest navigation-camera frames, attach timestamps and calibration metadata, undistort/normalize imagery, detect total occlusion/blackout before VIO, and classify image quality before VIO or satellite matching consumes it. - -**Architectural Pattern**: Streaming adapter + validation gate. - -**Upstream dependencies**: Navigation camera, camera calibration files. - -**Downstream consumers**: VIO adapter, Satellite Service, anchor verification, Tile Manager, FDR. - -## 2. Internal Interfaces - -### Interface: `FrameProvider` - -| Method | Input | Output | Async | Error Types | -|--------|-------|--------|-------|-------------| -| `next_frame` | `FrameRequest` | `FramePacket` | Yes | `FrameUnavailable`, `CalibrationMissing`, `InvalidFrame` | -| `detect_occlusion` | `FramePacket` | `OcclusionReport` | No | `InvalidFrame` | -| `classify_quality` | `FramePacket` | `ImageQualityReport` | No | `InvalidFrame` | - -**Input DTOs**: - -```yaml -FrameRequest: - source: enum(live_camera, replay_file) - timestamp_ns: integer optional -``` - -**Output DTOs**: - -```yaml -FramePacket: - frame_id: string - timestamp_ns: integer - image_ref: path_or_buffer - camera_calibration_id: string - altitude_hint_m: number optional - occlusion: OcclusionReport - quality: ImageQualityReport - -OcclusionReport: - status: enum(clear, partial_occlusion, total_occlusion, blackout) - reason: enum(cloud, lens_cover, whiteout, decode_failure, underexposed, overexposed, unknown) optional - usable_for_vio: boolean - usable_for_anchor: boolean - -ImageQualityReport: - usable_for_vio: boolean - usable_for_anchor: boolean - blackout_detected: boolean - blur_score: number - texture_score: number -``` - -## 3. Data Access Patterns - -| Query | Frequency | Hot Path | Index Needed | -|-------|-----------|----------|--------------| -| Load calibration by ID | Startup | Yes | No | -| Read replay frame | Test/replay | Yes | File order | - -## 4. Implementation Details - -**State Management**: Maintains current camera calibration version and frame sequence state. - -**Key Dependencies**: - -| Library | Purpose | -|---------|---------| -| OpenCV | Decode, undistort, homography support, image metrics | -| Camera SDK / V4L2 / GigE SDK | Live camera access once interface is selected | - -**Error Handling Strategy**: -- Camera or decode errors emit degraded quality and FDR events. -- Total occlusion or blackout sets `usable_for_vio=false`, bypasses BASALT for that frame, and emits a degradation signal to the safety/anchor wrapper. -- Missing calibration blocks production startup. -- ADTi public spec mismatch is tracked as a verification blocker until manufacturer spec is pinned. - -## 5. Extensions and Helpers - -| Helper | Purpose | Used By | -|--------|---------|---------| -| `geo_geometry_helper` | Coordinate transforms, GSD, WGS84/local conversions | Camera ingest, safety wrapper, Tile Manager | - -## 6. Caveats & Edge Cases - -**Known limitations**: -- Public ADTi pages list 2 fps continuous capture and -10..40 C operating range; project assumptions need manufacturer verification. -- Live camera interface is TBD. -- Total occlusion detection must be conservative: false positives cause temporary IMU-only degradation, while false negatives can feed unusable frames into VIO. - -**Performance bottlenecks**: -- Full-resolution preprocessing must stay inside the <400 ms p95 pipeline budget. - -## 7. Dependency Graph - -**Must be implemented after**: none. - -**Can be implemented in parallel with**: Tile Manager, MAVLink/GCS integration. - -**Blocks**: VIO adapter, anchor verification, generated tile lifecycle. - -## 8. Logging Strategy - -| Log Level | When | Example | -|-----------|------|---------| -| ERROR | Camera unavailable or calibration missing | `camera_calibration_missing id=...` | -| WARN | Frame degraded or occluded | `frame_quality_degraded occlusion=total_occlusion blur=... texture=...` | -| INFO | Calibration loaded | `camera_calibration_loaded version=...` | - -**Log format**: FDR structured event. - -**Log storage**: FDR segment and health log. diff --git a/_docs/02_document/components/01_camera_ingest_calibration/tests.md b/_docs/02_document/components/01_camera_ingest_calibration/tests.md deleted file mode 100644 index 83323b9..0000000 --- a/_docs/02_document/components/01_camera_ingest_calibration/tests.md +++ /dev/null @@ -1,139 +0,0 @@ -# Test Specification — Camera Ingest And Calibration - -## Acceptance Criteria Traceability - -| AC ID | Acceptance Criterion | Test IDs | Coverage | -|-------|---------------------|----------|----------| -| AC-2.1a | VO registration uses only normal usable frames | IT-01, AT-01 | Covered | -| AC-3.5 | Visual blackout switches to degraded mode quickly | IT-02, AT-02 | Covered | -| AC-4.1 | Capture-to-output latency budget | PT-01 | Covered | -| AC-4.2 | Jetson memory budget | PT-01 | Covered | -| AC-8.4 | Mid-flight tile generation input eligibility | IT-03 | Covered | -| AC-8.5 | No raw frame retention | ST-01 | Covered | -| AC-NEW-8 | Full blackout/occlusion degraded-mode trigger | IT-02, AT-02 | Covered | - -## Blackbox Tests - -### IT-01: Usable Frame Classification - -**Summary**: Verify normal nadir frames are marked usable for VIO and anchor matching. - -**Traces to**: AC-2.1a - -**Input data**: Project still images plus calibration metadata. - -**Expected result**: `FramePacket.quality.usable_for_vio=true`, `usable_for_anchor=true`, and `occlusion.status=clear` for normal daytime textured frames. - -**Max execution time**: 100 ms per frame. - -**Dependencies**: Calibration file, replay fixture. - ---- - -### IT-02: Total Occlusion Gate Before VIO - -**Summary**: Verify total occlusion is detected before BASALT receives the frame. - -**Traces to**: AC-3.5, AC-NEW-8 - -**Input data**: Black/white/covered-lens frames, corrupt frame fixture, low-texture whiteout frames. - -**Expected result**: `occlusion.status` is `total_occlusion` or `blackout`, `usable_for_vio=false`, `usable_for_anchor=false`, and a degradation signal is emitted to the safety wrapper. - -**Max execution time**: 100 ms per frame. - -**Dependencies**: Safety wrapper test double. - ---- - -### IT-03: Tile Generation Eligibility Metadata - -**Summary**: Verify frame metadata required for generated tiles is available without persisting raw frames. - -**Traces to**: AC-8.4, AC-8.5 - -**Input data**: Valid frame, altitude hint, calibration, pose fixture. - -**Expected result**: Frame metadata supports orthorectification handoff; raw frame is not retained after processing outside allowed FDR thumbnail exception. - -**Max execution time**: 100 ms per frame. - -**Dependencies**: Tile Manager test double. - -## Performance Tests - -### PT-01: Ingest And Quality Latency - -**Summary**: Verify decode, calibration lookup, occlusion detection, and quality classification stay inside the system latency budget. - -**Traces to**: AC-4.1, AC-4.2 - -**Load scenario**: -- Input rate: target camera/replay rate. -- Duration: 30 minutes replay. -- Dataset: project still images plus synthetic occlusion frames. - -| Metric | Target | Failure Threshold | -|--------|--------|-------------------| -| Per-frame ingest p95 | <=100 ms | >150 ms | -| Memory contribution | <=1 GB | >1.5 GB | -| Dropped frames | <=10% under sustained load | >10% | - -**Resource limits**: Jetson shared memory remains below system 8 GB cap. - -## Security Tests - -### ST-01: Raw Frame Retention Check - -**Summary**: Verify normal operation does not persist raw navigation frames. - -**Traces to**: AC-8.5 - -**Attack vector**: Sensitive raw imagery remains on disk after processing. - -**Test procedure**: -1. Run replay with normal and failed tile-generation frames. -2. Inspect output directories and FDR artifacts. - -**Expected behavior**: Only metadata, generated tiles, and allowed low-rate failed-frame thumbnails are retained. - -**Pass criteria**: No raw full-resolution frames remain after teardown. - -## Acceptance Tests - -### AT-01: Normal Frame Enters VIO - -**Summary**: Confirm normal usable frames are passed to BASALT. - -**Traces to**: AC-2.1a - -| Step | Action | Expected Result | -|------|--------|-----------------| -| 1 | Feed a calibrated normal frame | Occlusion status is `clear` | -| 2 | Process quality gate | Frame is emitted to VIO adapter | - ---- - -### AT-02: Occluded Frame Bypasses VIO - -**Summary**: Confirm full occlusion triggers IMU-only degraded path. - -**Traces to**: AC-3.5, AC-NEW-8 - -| Step | Action | Expected Result | -|------|--------|-----------------| -| 1 | Feed total-occlusion frame | `usable_for_vio=false` | -| 2 | Observe downstream routing | BASALT is bypassed and safety wrapper receives degradation signal | - -## Test Data Management - -| Data Set | Description | Source | Size | -|----------|-------------|--------|------| -| `project_60_still_images` | Normal nadir frames | `_docs/00_problem/input_data/` | Project data | -| `synthetic_occlusion_frames` | Black/white/corrupt/whiteout frames | Generated fixture | Small | - -**Setup procedure**: Load calibration fixture and mount read-only frame data. - -**Teardown procedure**: Remove run-scoped temp directories and verify no raw-frame persistence. - -**Data isolation strategy**: Each run writes to a unique `test-results//` directory. diff --git a/_docs/02_document/components/02_vio_adapter/description.md b/_docs/02_document/components/02_vio_adapter/description.md deleted file mode 100644 index a3b6b74..0000000 --- a/_docs/02_document/components/02_vio_adapter/description.md +++ /dev/null @@ -1,105 +0,0 @@ -# VIO Adapter - -## 1. High-Level Overview - -**Purpose**: Wrap the selected relative VIO backend as a replaceable component that consumes calibrated frames and FC IMU data, then emits relative pose/velocity/bias state and tracking quality. - -**Architectural Pattern**: Adapter / anti-corruption layer. - -**Upstream dependencies**: Camera ingest/calibration, MAVLink telemetry stream. - -**Downstream consumers**: Safety/anchor wrapper, FDR, separate e2e test suite. - -## 2. Internal Interfaces - -### Interface: `VioAdapter` - -| Method | Input | Output | Async | Error Types | -|--------|-------|--------|-------|-------------| -| `initialize` | selected `VioBackend` / `VioRuntimeConfig` | updates `VioHealthReport` | No | backend initialization / native prerequisite errors | -| `process` | `VioInputPacket` | `VioProcessingResult` | No | timestamp mismatch, backend runtime errors | -| `health` | none | `VioHealthReport` | No | none | - -**Input DTOs**: - -```yaml -VioInputPacket: - frame: FramePacket - telemetry_samples: list[TelemetrySample] -VioRuntimeConfig: - environment: development | ci | staging | jetson | production - mode: replay | native optional - native_backend_name: string - native_runner_module: string - native_runner_factory: string - native_runner_config: object -``` - -**Output DTOs**: - -```yaml -VioStatePacket: - timestamp_ns: integer - relative_pose: transform - velocity: vector3 - bias_estimate: object optional - tracking_quality: number - covariance_hint: matrix optional -VioProcessingResult: - state_packet: VioStatePacket optional - health: VioHealthReport - processing_latency_ms: number optional - error: ErrorEnvelope optional -``` - -## 3. Data Access Patterns - -No persistent production data ownership. Reads calibration/config at startup and emits state to downstream consumers. - -## 4. Implementation Details - -**State Management**: Owns selected VIO backend runtime state and resets only through explicit wrapper command. - -**Runtime Selection**: `create_vio_adapter` selects replay mode only for explicit development/replay configuration. Production and Jetson profiles derive native mode, instantiate `ConfiguredNativeVioBackend`, and load a BASALT-compatible runner through `BasaltNativeRunner`. - -**Key Dependencies**: - -| Library | Purpose | -|---------|---------| -| BASALT | Current selected relative visual-inertial odometry backend | -| Eigen/Sophus or backend-native math stack | Pose and transform representation | - -**Error Handling Strategy**: -- Missing or invalid production native runtime prerequisites fail initialization with explicit health/error state and no replay-derived successful VIO output. -- Tracking loss is surfaced to the safety/anchor wrapper, not hidden. -- Timestamp/camera-IMU sync violations fail the packet and are logged. -- The adapter never emits WGS84 coordinates; absolute semantics belong to the wrapper. - -## 5. Caveats & Edge Cases - -**Known limitations**: -- BASALT has no special fixed-wing nadir mode; validation must prove fit under low-parallax/planar terrain. -- Backend covariance/confidence output is not the product authority; wrapper calibration is required. - -**Performance bottlenecks**: -- Native VIO runtime and image resolution can exceed Jetson budget if not tuned. - -## 6. Dependency Graph - -**Must be implemented after**: Camera ingest/calibration, MAVLink telemetry DTO definitions. - -**Can be implemented in parallel with**: Satellite Service, Tile Manager. - -**Blocks**: Safety/anchor wrapper final integration. - -## 7. Logging Strategy - -| Log Level | When | Example | -|-----------|------|---------| -| ERROR | VIO backend initialization fails | `vio_init_failed reason=...` | -| WARN | Tracking quality drops | `vio_tracking_degraded quality=...` | -| INFO | VIO reset/reinitialized | `vio_reset cause=...` | - -**Log format**: FDR structured event. - -**Log storage**: FDR segment. diff --git a/_docs/02_document/components/02_vio_adapter/tests.md b/_docs/02_document/components/02_vio_adapter/tests.md deleted file mode 100644 index 88670fb..0000000 --- a/_docs/02_document/components/02_vio_adapter/tests.md +++ /dev/null @@ -1,141 +0,0 @@ -# Test Specification — VIO Adapter - -## Acceptance Criteria Traceability - -| AC ID | Acceptance Criterion | Test IDs | Coverage | -|-------|---------------------|----------|----------| -| AC-1.3 | Drift between anchors and anchor-age reporting input | IT-02, AT-01 | Covered | -| AC-2.1a | >95% VO registration on normal segments | IT-01, AT-01 | Covered | -| AC-2.2 | <1.0 px VO MRE | IT-01 | Covered | -| AC-3.1 | Handles 350 m outliers/tilt | IT-03 | Covered | -| AC-3.2 | Sharp turns trigger relocalization path | IT-04 | Covered | -| AC-3.4 | Loss threshold feeds relocalization/dead reckoning | IT-04 | Covered | -| AC-4.1 | Hot-path latency | PT-01 | Covered | -| AC-4.2 | Jetson memory budget | PT-01 | Covered | - -## Blackbox Tests - -### IT-01: Public Dataset VIO Replay - -**Summary**: Verify the VIO adapter produces relative motion for synchronized camera/IMU replay. - -**Traces to**: AC-2.1a, AC-2.2 - -**Input data**: Derkachi cropped nadir video + `SCALED_IMU2` + `GLOBAL_POSITION_INT`, MUN-FRL preferred slice, or representative synchronized nav-camera + IMU + ground truth. - -**Expected result**: VO registration succeeds for >95% of normal usable frames; frame-to-frame MRE <1.0 px where ground-truth/feature evaluation supports it. Derkachi runs are accepted as calibration-limited until intrinsics, distortion, and camera-to-body transform are pinned. - -**Max execution time**: Dataset-dependent; report per-frame latency. - -**Dependencies**: Camera ingest, MAVLink telemetry/replay, calibration fixtures. - ---- - -### IT-02: Relative Drift Reporting - -**Summary**: Verify adapter emits state needed for wrapper drift and anchor-age accounting. - -**Traces to**: AC-1.3 - -**Input data**: Segment with two known satellite anchors and IMU samples. - -**Expected result**: Adapter emits continuous `VioStatePacket` values with timestamps and quality, enabling wrapper to compare VO extrapolation to next anchor. - -**Max execution time**: Dataset-dependent. - -**Dependencies**: Safety wrapper test harness. - ---- - -### IT-03: Tilt/Outlier Robustness - -**Summary**: Verify adapter reports degraded tracking without false success under tilt/outlier cases. - -**Traces to**: AC-3.1 - -**Input data**: Replay segment with synthetic +/-20 degree tilt and up to 350 m apparent outlier. - -**Expected result**: Adapter either tracks with quality metadata or emits `TrackingLost`; it never hides a failure as high-quality VIO. - -**Max execution time**: 15 minutes per fixture. - ---- - -### IT-04: Sharp Turn / Loss Signal - -**Summary**: Verify sharp turns and disconnected visual overlap produce wrapper-visible failure signals. - -**Traces to**: AC-3.2, AC-3.4 - -**Input data**: <5% overlap sequence with heading change <70 degrees. - -**Expected result**: Adapter emits low tracking quality or `TrackingLost` within the loss window, allowing relocalization trigger. - -**Max execution time**: 10 minutes. - -## Performance Tests - -### PT-01: VIO Adapter Runtime Budget - -**Summary**: Verify VIO processing does not consume the full <400 ms system p95 budget. - -**Traces to**: AC-4.1, AC-4.2 - -**Load scenario**: -- Input: Derkachi synchronized replay and public/representative replay. -- Duration: 30 minutes plus release long-run slice. -- Target: Jetson Orin Nano Super. - -| Metric | Target | Failure Threshold | -|--------|--------|-------------------| -| Adapter p95 latency | <=250 ms | >300 ms | -| Memory contribution | <=3 GB | >4 GB | -| Tracking failure on normal segments | <5% | >=5% | - -**Resource limits**: Total system memory remains below 8 GB. - -## Security Tests - -### ST-01: Timestamp Injection Rejection - -**Summary**: Verify malformed or non-monotonic timestamps do not produce trusted VIO state. - -**Traces to**: AC-NEW-4 - -**Attack vector**: Replay or telemetry timestamp manipulation. - -**Test procedure**: -1. Feed non-monotonic frame and IMU timestamps. -2. Observe adapter output. - -**Expected behavior**: Adapter returns `TimestampMismatch` or low-quality failure; wrapper does not trust the state. - -**Pass criteria**: No high-quality VIO state is emitted from malformed timing. - -## Acceptance Tests - -### AT-01: Normal VIO State Contract - -**Summary**: Confirm adapter output contract supports downstream localization. - -**Traces to**: AC-1.3, AC-2.1a - -| Step | Action | Expected Result | -|------|--------|-----------------| -| 1 | Initialize with calibrated frame/IMU config | `VioInitResult` succeeds | -| 2 | Replay normal frames | `VioStatePacket` includes timestamp, relative pose, velocity, tracking quality | -| 3 | End segment | State stream is continuous enough for wrapper drift accounting | - -## Test Data Management - -| Data Set | Description | Source | Size | -|----------|-------------|--------|------| -| `derkachi_video_telemetry` | Cropped nadir MP4 + synchronized IMU and `GLOBAL_POSITION_INT` trajectory | Project fixture | ~282 MB video + CSV | -| `public_nadir_vio_candidates` | MUN-FRL/ALTO/Kagaru/EPFL slices | Public pinned fixtures | Dataset-dependent | -| `representative_sync_replay` | Target camera + FC IMU + calibrated ground truth | Project collection | TBD | - -**Setup procedure**: Pin calibration/extrinsics and mount read-only synchronized replay data. - -**Teardown procedure**: Remove generated result reports and adapter temp state. - -**Data isolation strategy**: One run directory per dataset slice and configuration hash. diff --git a/_docs/02_document/components/03_safety_anchor_wrapper/description.md b/_docs/02_document/components/03_safety_anchor_wrapper/description.md deleted file mode 100644 index 1f405b0..0000000 --- a/_docs/02_document/components/03_safety_anchor_wrapper/description.md +++ /dev/null @@ -1,106 +0,0 @@ -# Safety And Anchor Wrapper - -## 1. High-Level Overview - -**Purpose**: Own the authoritative localization state, confidence calibration, source labels, anchor fusion, degraded modes, tile-write gates, and MAVLink output semantics. - -**Architectural Pattern**: Stateful coordinator / safety facade. - -**Upstream dependencies**: VIO adapter, anchor verification, MAVLink telemetry, camera quality reports. - -**Downstream consumers**: MAVLink/GCS integration, FDR, Tile Manager, separate e2e test suite. - -## 2. Internal Interfaces - -### Interface: `LocalizationStateMachine` - -| Method | Input | Output | Async | Error Types | -|--------|-------|--------|-------|-------------| -| `update_vio` | `VioStatePacket` | `PositionEstimate` | Yes | `StateInconsistent` | -| `consider_anchor` | `AnchorDecision` | `AnchorAcceptanceResult` | No | `AnchorRejected` | -| `degrade` | `DegradationSignal` | `PositionEstimate` | No | none | -| `propagate_imu_only` | `ImuOnlyPropagationRequest` | `PositionEstimate` | Yes | `InsufficientTelemetry` | -| `tile_write_eligibility` | `FramePacket` | `TileWriteDecision` | No | none | - -**Input DTOs**: - -```yaml -AnchorDecision: - candidate_id: string - timestamp_ns: integer - estimated_pose_wgs84: object - inlier_count: integer - mre_px: number - tile_freshness_status: enum - provenance_status: enum - -DegradationSignal: - type: enum(total_occlusion, visual_blackout, gps_spoofing, covariance_growth, tracking_lost) - timestamp_ns: integer - -ImuOnlyPropagationRequest: - last_trusted_estimate: PositionEstimate - imu_samples: list[TelemetrySample] - elapsed_blackout_ms: integer - reason: enum(total_occlusion, visual_blackout, tracking_lost) -``` - -**Output DTOs**: - -```yaml -PositionEstimate: - timestamp_ns: integer - lat_deg: number - lon_deg: number - alt_msl_m: number - covariance_95_semi_major_m: number - source_label: enum(satellite_anchored, vo_extrapolated, dead_reckoned) - fix_type: integer - horiz_accuracy_m: number - last_satellite_anchor_age_ms: integer -``` - -## 3. Data Access Patterns - -No direct tile/image storage ownership. Writes all decisions to FDR via observability component. - -## 4. Implementation Details - -**State Management**: Owns the authoritative state machine and covariance growth model. - -**Error Handling Strategy**: -- Reject uncertain anchors by default. -- Never emit optimistic accuracy when confidence is degraded. -- On total occlusion or visual blackout, do not call VIO for that frame; propagate from the last trusted state with IMU-only dynamics, set `source_label=dead_reckoned`, and grow covariance monotonically. -- If covariance or blackout thresholds exceed AC limits, emit no-fix/failsafe semantics. -- Treat cache freshness and provenance as evidence carried by `AnchorDecision`; do not call the Tile Manager directly during anchor acceptance. - -## 5. Caveats & Edge Cases - -**Known limitations**: -- Final covariance calibration requires representative synchronized data. -- The wrapper must stay independent of BASALT internals so VIO can be replaced. -- IMU-only propagation is an emergency bridge, not a reliable long-duration localization mode; the spec requires failsafe/no-fix once time or covariance thresholds are exceeded. - -**Potential race conditions**: -- A delayed anchor result must be checked against current timestamp/state before acceptance. - -## 6. Dependency Graph - -**Must be implemented after**: VIO DTOs, anchor DTOs, MAVLink output contract. - -**Can be implemented in parallel with**: FDR schema after DTOs stabilize. - -**Blocks**: MAVLink production output, tile-write lifecycle, end-to-end validation. - -## 7. Logging Strategy - -| Log Level | When | Example | -|-----------|------|---------| -| ERROR | State invariant violation | `localization_state_inconsistent reason=...` | -| WARN | Anchor rejected or mode degraded | `anchor_rejected reason=mahalanobis_gate` | -| INFO | Mode transition | `source_label_changed from=vo_extrapolated to=dead_reckoned reason=total_occlusion` | - -**Log format**: FDR structured event. - -**Log storage**: FDR segment and QGC status for operator-critical events. diff --git a/_docs/02_document/components/03_safety_anchor_wrapper/tests.md b/_docs/02_document/components/03_safety_anchor_wrapper/tests.md deleted file mode 100644 index 438bbfd..0000000 --- a/_docs/02_document/components/03_safety_anchor_wrapper/tests.md +++ /dev/null @@ -1,208 +0,0 @@ -# Test Specification — Safety And Anchor Wrapper - -## Acceptance Criteria Traceability - -| AC ID | Acceptance Criterion | Test IDs | Coverage | -|-------|---------------------|----------|----------| -| AC-1.1 | >=80% within 50 m | AT-01 | Covered | -| AC-1.2 | >=50% within 20 m | AT-01 | Covered | -| AC-1.3 | Drift and anchor age | IT-01 | Covered | -| AC-1.4 | Quantitative confidence + label | IT-02, AT-02 | Covered | -| AC-3.4 | Relocalization after no-position window | IT-03 | Covered | -| AC-3.5 | Blackout to dead reckoned | IT-04, AT-03 | Covered | -| AC-4.3 | GPS_INPUT semantics source fields | IT-05 | Covered | -| AC-4.4 | Frame-by-frame streaming | PT-01 | Covered | -| AC-4.5 | Correction updates | IT-06 | Covered | -| AC-5.1 | Initialize from FC state | IT-07 | Covered | -| AC-5.2 | >3 s no-estimate fallback | IT-03 | Covered | -| AC-5.3 | Reinitialize after reboot | IT-07 | Covered | -| AC-NEW-2 | Spoofing promotion <3 s | IT-05 | Covered | -| AC-NEW-4 | False-position safety budget | ST-01, AT-02 | Covered | -| AC-NEW-8 | IMU-only blackout thresholds | IT-04, AT-03 | Covered | - -## Blackbox Tests - -### IT-01: Drift And Anchor Age Accounting - -**Summary**: Verify VO extrapolation drift and anchor age are tracked per estimate. - -**Traces to**: AC-1.3 - -**Input data**: VIO state stream with two accepted anchor decisions. - -**Expected result**: Every `PositionEstimate` includes `last_satellite_anchor_age_ms`; drift at next anchor is measured and binned by age. - -**Max execution time**: 5 minutes. - ---- - -### IT-02: Confidence Output Contract - -**Summary**: Verify every estimate has covariance and source label. - -**Traces to**: AC-1.4 - -**Input data**: satellite-anchored, VO-extrapolated, and dead-reckoned state fixtures. - -**Expected result**: Each output contains `covariance_95_semi_major_m`, `source_label`, `fix_type`, and `horiz_accuracy_m`; `horiz_accuracy_m` never under-reports covariance. - -**Max execution time**: 2 minutes. - ---- - -### IT-03: No-Position Relocalization Trigger - -**Summary**: Verify no position for >=3 frames and >=2 s triggers relocalization/degraded behavior. - -**Traces to**: AC-3.4, AC-5.2 - -**Input data**: VIO loss sequence with no accepted anchors. - -**Expected result**: Relocalization request is emitted and wrapper continues dead reckoning until fail threshold. - -**Max execution time**: 5 minutes. - ---- - -### IT-04: Total Blackout IMU-Only Propagation - -**Summary**: Verify total occlusion produces honest IMU-only estimates and failsafe thresholds. - -**Traces to**: AC-3.5, AC-NEW-8 - -**Input data**: Last trusted estimate, IMU/attitude/airspeed/altitude stream, total-occlusion signal for 5 s, 15 s, and 35 s. - -**Expected result**: Wrapper emits `dead_reckoned` within <=1 frame or <=400 ms, covariance grows monotonically, and no-fix/failsafe is emitted when blackout >30 s or covariance >500 m. - -**Max execution time**: 10 minutes. - ---- - -### IT-05: Spoofing Promotion And GPS_INPUT Mapping - -**Summary**: Verify wrapper promotes own estimate and maps output fields correctly under GPS spoofing. - -**Traces to**: AC-4.3, AC-NEW-2 - -**Input data**: Plane SITL spoofing telemetry and trusted wrapper estimate. - -**Expected result**: Own estimate is promoted within <3 s; v1 emits `GPS_INPUT` only; source labels and accuracy fields are correct. - -**Max execution time**: 10 minutes. - ---- - -### IT-06: Correction Update - -**Summary**: Verify refined estimates can correct previous positions. - -**Traces to**: AC-4.5 - -**Input data**: VO estimate followed by accepted satellite anchor for same segment. - -**Expected result**: Wrapper emits updated estimate/correction with improved source label and covariance. - -**Max execution time**: 5 minutes. - ---- - -### IT-07: Initialization And Reboot Recovery - -**Summary**: Verify wrapper initializes from FC state and can reinitialize after reboot. - -**Traces to**: AC-5.1, AC-5.3 - -**Input data**: FC EKF position, IMU-extrapolated state, simulated companion restart. - -**Expected result**: Wrapper resumes from current FC state and reports degraded confidence until re-anchored. - -**Max execution time**: 5 minutes. - -## Performance Tests - -### PT-01: Wrapper Streaming Overhead - -**Summary**: Verify state-machine processing does not delay frame-by-frame output. - -**Traces to**: AC-4.4 - -**Load scenario**: -- Input: 3 Hz estimate stream with anchor and blackout events. -- Duration: 8-hour synthetic run. - -| Metric | Target | Failure Threshold | -|--------|--------|-------------------| -| Wrapper p95 processing | <=25 ms | >50 ms | -| Missed frame outputs | 0 except skip-allowed upstream drops | Any silent batch/delay | - -**Resource limits**: Negligible memory growth across run. - -## Security Tests - -### ST-01: False Anchor Rejection - -**Summary**: Verify impossible anchors do not become trusted estimates. - -**Traces to**: AC-NEW-4 - -**Attack vector**: Anchor decision with plausible inliers but impossible jump or stale provenance. - -**Test procedure**: -1. Feed an anchor >1 km from predicted state with low covariance. -2. Feed stale/provenance-failed anchor evidence. - -**Expected behavior**: Anchor is rejected, FDR logs reason, source label remains degraded or VO extrapolated. - -**Pass criteria**: 0 accepted impossible/stale anchors. - -## Acceptance Tests - -### AT-01: Position Accuracy Aggregation - -**Summary**: Verify wrapper outputs can be scored against frame-center thresholds. - -**Traces to**: AC-1.1, AC-1.2 - -| Step | Action | Expected Result | -|------|--------|-----------------| -| 1 | Replay mapped frame-center estimates | Report computes >=80% within 50 m and >=50% within 20 m | -| 2 | Include source labels | Accuracy is binned by source label | - ---- - -### AT-02: Confidence Honesty - -**Summary**: Verify reported confidence is conservative relative to measured error. - -**Traces to**: AC-1.4, AC-NEW-4 - -| Step | Action | Expected Result | -|------|--------|-----------------| -| 1 | Replay ground-truth trajectory | Measured error is not systematically above reported covariance | -| 2 | Inject over-confident anchors | Mahalanobis gate rejects them | - ---- - -### AT-03: Blackout Failsafe - -**Summary**: Verify operator-visible blackout/failsafe behavior. - -**Traces to**: AC-3.5, AC-NEW-8 - -| Step | Action | Expected Result | -|------|--------|-----------------| -| 1 | Inject total visual blackout | `dead_reckoned` within <=400 ms | -| 2 | Continue >30 s or covariance >500 m | `fix_type=0`, `horiz_accuracy=999.0`, QGC failsafe status | - -## Test Data Management - -| Data Set | Description | Source | Size | -|----------|-------------|--------|------| -| `wrapper_state_fixtures` | VIO states, anchors, blackouts, spoofing signals | Generated fixtures | Small | -| `representative_replay` | Target synchronized replay and ground truth | Project collection | TBD | - -**Setup procedure**: Load deterministic VIO/anchor/telemetry fixtures and run with isolated PostgreSQL schema. - -**Teardown procedure**: Drop run schema and remove FDR segments. - -**Data isolation strategy**: Use per-run mission IDs and database schemas. diff --git a/_docs/02_document/components/04_satellite_retrieval/description.md b/_docs/02_document/components/04_satellite_retrieval/description.md deleted file mode 100644 index 504a134..0000000 --- a/_docs/02_document/components/04_satellite_retrieval/description.md +++ /dev/null @@ -1,102 +0,0 @@ -# Satellite Service - -## 1. High-Level Overview - -**Purpose**: Own the onboard boundary to the suite Satellite Service: import pre-flight mission cache packages, upload generated-tile packages after flight, and convert query frames into ranked local VPR candidates using preloaded DINOv2-VLAD descriptors and FAISS. - -**Architectural Pattern**: Offline sync gateway + local retrieval index adapter. - -**Upstream dependencies**: Camera ingest/calibration, Tile Manager, safety/anchor wrapper, Azaion Suite Satellite Service before/after flight. - -**Downstream consumers**: Anchor verification, FDR. - -## 2. Internal Interfaces - -### Interface: `SatelliteService` - -| Method | Input | Output | Async | Error Types | -|--------|-------|--------|-------|-------------| -| `import_mission_cache` | `CacheImportRequest` | `CacheImportResult` | Yes | `SyncUnavailable`, `PackageInvalid` | -| `upload_generated_tiles` | `GeneratedTileUploadRequest` | `GeneratedTileUploadResult` | Yes | `SyncUnavailable`, `PackageRejected` | -| `retrieve` | `RetrievalRequest` | `RetrievalResult` | Yes | `IndexUnavailable`, `DescriptorFailed` | -| `load_index` | `IndexLoadRequest` | `IndexStatus` | No | `ManifestInvalid`, `IndexUnavailable` | - -**Input DTOs**: - -```yaml -RetrievalRequest: - frame: FramePacket - prior_estimate: PositionEstimate optional - search_radius_m: number optional - max_candidates: integer -``` - -**Output DTOs**: - -```yaml -RetrievalResult: - query_descriptor_id: string - candidates: list[VprCandidate] - -VprCandidate: - chunk_id: string - tile_id: string - score: number - footprint: geometry - freshness_status: enum -``` - -## 3. Data Access Patterns - -| Query | Frequency | Hot Path | Index Needed | -|-------|-----------|----------|--------------| -| Top-K FAISS search | Triggered only | No steady-state | FAISS index | -| Import/export package sync | Pre-flight / post-flight only | No mid-flight | Package manifest and sidecar hashes | -| Load chunk metadata | Per candidate | No | PostgreSQL/PostGIS spatial and chunk indexes | - -## 4. Implementation Details - -**State Management**: Holds loaded descriptor model and FAISS index handles; tracks pre-flight import and post-flight upload package status. - -**Key Dependencies**: - -| Library | Purpose | -|---------|---------| -| DINOv2 / ONNX / TensorRT candidate path | Query descriptor extraction | -| FAISS CPU | Top-K retrieval | -| Satellite Service client | Pre-flight cache import and post-flight generated-tile upload | - -**Error Handling Strategy**: -- If descriptor extraction or index load fails, return no candidates and trigger degraded mode. -- Optimized engines are allowed only after descriptor-fidelity tests pass. -- Network/package sync failures are allowed only before takeoff or after landing; during flight, the component must never call a satellite provider or suite service. - -## 5. Caveats & Edge Cases - -**Known limitations**: -- VPR result is only a candidate, never an accepted fix. -- Cross-domain retrieval can be wrong under seasonal, lighting, or terrain ambiguity. -- External Satellite Service availability cannot be part of the mid-flight localization safety case. - -**Performance bottlenecks**: -- Descriptor extraction on Jetson must be trigger-limited and profiled separately from BASALT. - -## 6. Dependency Graph - -**Must be implemented after**: cache manifest/index schema, camera frame DTOs. - -**Can be implemented in parallel with**: anchor verification. - -**Blocks**: satellite relocalization flow. - -## 7. Logging Strategy - -| Log Level | When | Example | -|-----------|------|---------| -| ERROR | Index unavailable | `faiss_index_unavailable id=...` | -| WARN | No candidates | `vpr_no_candidates frame_id=...` | -| INFO | Retrieval invoked | `vpr_query candidates=... latency_ms=...` | - -**Log format**: FDR structured event. - -**Log storage**: FDR segment. diff --git a/_docs/02_document/components/04_satellite_retrieval/tests.md b/_docs/02_document/components/04_satellite_retrieval/tests.md deleted file mode 100644 index 58f7a6c..0000000 --- a/_docs/02_document/components/04_satellite_retrieval/tests.md +++ /dev/null @@ -1,172 +0,0 @@ -# Test Specification — Satellite Service - -## Acceptance Criteria Traceability - -| AC ID | Acceptance Criterion | Test IDs | Coverage | -|-------|---------------------|----------|----------| -| AC-3.2 | Sharp-turn relocalization | IT-02, AT-01 | Covered | -| AC-3.3 | >=3 disconnected segments | IT-03 | Covered | -| AC-3.4 | Relocalization request after loss | IT-02 | Covered | -| AC-4.1 | Trigger path latency | PT-01 | Covered | -| AC-4.2 | Memory budget | PT-01 | Covered | -| AC-8.1 | Cache imagery interface | IT-01 | Covered | -| AC-8.3 | Preloaded/preprocessed cache | IT-01 | Covered | -| AC-8.6 | VPR chunks, multi-scale, dynamic K | IT-01, IT-04 | Covered | -| AC-NEW-1 | Cold-start first fix support | PT-02 | Covered | -| AC-NEW-6 | Freshness-aware retrieval | IT-04, ST-01 | Covered | - -## Blackbox Tests - -### IT-01: Index Load And Chunk Coverage - -**Summary**: Verify preloaded VPR chunks and FAISS index cover the operational area. - -**Traces to**: AC-8.1, AC-8.3, AC-8.6 - -**Input data**: PostgreSQL/PostGIS cache manifest, VPR chunk metadata, FAISS index. - -**Expected result**: Every test frame footprint falls inside at least one VPR chunk; fine and coarse descriptors are present where required. - -**Max execution time**: 2 minutes per mission cache. - ---- - -### IT-02: Sharp-Turn Local Retrieval Trigger - -**Summary**: Verify sharp-turn state requests candidates rather than relying on frame-to-frame VO. - -**Traces to**: AC-3.2, AC-3.4 - -**Input data**: Wrapper relocalization request with sharp-turn/loss reason. - -**Expected result**: Satellite Service returns bounded top-K candidates from preloaded local indexes based on sector/covariance policy. - -**Max execution time**: 2 seconds per query. - ---- - -### IT-03: Disconnected Segment Retrieval - -**Summary**: Verify at least three disconnected segments can each retrieve candidate chunks. - -**Traces to**: AC-3.3 - -**Input data**: Three disconnected query frames with approximate prior/covariance. - -**Expected result**: Each query returns a candidate set including the ground-truth region when covered by the cache fixture. - -**Max execution time**: Dataset-dependent. - ---- - -### IT-04: Dynamic K And Freshness Filter - -**Summary**: Verify K varies by sector and covariance, and stale candidates are tagged. - -**Traces to**: AC-8.6, AC-NEW-6 - -**Input data**: Stable and active-conflict sector cache fixtures with fresh/stale tiles. - -**Expected result**: K=5 for stable low-covariance, K=20 for active-conflict, K=50 fallback; stale candidates are flagged for rejection/down-confidence. - -**Max execution time**: 2 seconds per query. - -## Performance Tests - -### PT-01: Retrieval Query Runtime - -**Summary**: Verify descriptor extraction and FAISS query fit trigger-path budget. - -**Traces to**: AC-4.1, AC-4.2 - -**Load scenario**: -- Query set: 100 representative relocalization frames. -- Environment: Jetson and replay workstation. - -| Metric | Target | Failure Threshold | -|--------|--------|-------------------| -| Retrieval p95 | <=300 ms trigger path share | >400 ms | -| Memory contribution | <=2 GB | >3 GB | -| Candidate count policy | Exact | Any wrong K | - -**Resource limits**: Total system memory remains below 8 GB. - ---- - -### PT-02: Cold-Start Index Load - -**Summary**: Verify retrieval readiness supports first fix <30 s. - -**Traces to**: AC-NEW-1 - -**Load scenario**: -- Cold boot 50 runs. -- Cache/index mounted locally. - -| Metric | Target | Failure Threshold | -|--------|--------|-------------------| -| Index ready p95 | <=10 s | >15 s | -| First retrieval p95 | Fits <30 s first-fix budget | Exceeds budget | - -## Security Tests - -### ST-01: Stale Candidate Handling - -**Summary**: Verify stale imagery cannot silently appear as a trusted retrieval candidate. - -**Traces to**: AC-NEW-6 - -**Attack vector**: Manipulated cache manifest marks stale tile as available. - -**Test procedure**: -1. Load cache fixture with stale capture dates. -2. Query against stale region. - -**Expected behavior**: Candidate carries stale status; anchor path cannot accept it as `satellite_anchored`. - -**Pass criteria**: 0 stale candidates without explicit stale/down-confidence metadata. - ---- - -### ST-02: No Mid-Flight Satellite Service Calls - -**Summary**: Verify relocalization never performs satellite-provider or suite Satellite Service network calls during flight. - -**Traces to**: AC-8.3, R-SAT-01 - -**Attack vector**: Runtime attempts to fetch missing cache/index data over the network during relocalization. - -**Test procedure**: -1. Disable external network access during a replay scenario. -2. Trigger relocalization against preloaded cache fixtures. -3. Inspect network call logs and Satellite Service client telemetry. - -**Expected behavior**: Retrieval uses only mounted local cache/index data; missing data produces degraded/no-candidate behavior, not a network fetch. - -**Pass criteria**: 0 mid-flight Satellite Service or satellite-provider calls. - -## Acceptance Tests - -### AT-01: Relocalization Candidate Returned - -**Summary**: Verify a relocalization request returns usable candidates for anchor verification. - -**Traces to**: AC-3.2, AC-8.6 - -| Step | Action | Expected Result | -|------|--------|-----------------| -| 1 | Submit sharp-turn query | Retrieval invokes VPR | -| 2 | Read output | Candidate list includes chunk IDs, tile IDs, scores, footprints, freshness | - -## Test Data Management - -| Data Set | Description | Source | Size | -|----------|-------------|--------|------| -| `cache_vpr_fixture` | PostGIS manifest, COGs, descriptors, FAISS index | Generated/cache fixture | Mission-dependent | -| `aerial_vpr_queries` | Aerial query frames with ground-truth regions | ALTO/AerialVL/representative | Dataset-dependent | - -**Setup procedure**: Restore isolated PostgreSQL schema and mount read-only descriptor/index files. - -**Teardown procedure**: Drop schema and remove generated retrieval reports. - -**Data isolation strategy**: Per-run schema and read-only cache fixture volume. diff --git a/_docs/02_document/components/05_anchor_verification/description.md b/_docs/02_document/components/05_anchor_verification/description.md deleted file mode 100644 index 60b5df4..0000000 --- a/_docs/02_document/components/05_anchor_verification/description.md +++ /dev/null @@ -1,93 +0,0 @@ -# Anchor Verification - -## 1. High-Level Overview - -**Purpose**: Verify retrieved cache candidates with local feature matching and geometric checks before the safety wrapper considers an absolute anchor. - -**Architectural Pattern**: Validation pipeline. - -**Upstream dependencies**: Satellite Service, camera ingest/calibration, Tile Manager. - -**Downstream consumers**: Safety/anchor wrapper, FDR. - -## 2. Internal Interfaces - -### Interface: `AnchorVerifier` - -| Method | Input | Output | Async | Error Types | -|--------|-------|--------|-------|-------------| -| `verify` | `AnchorVerificationRequest` | `AnchorDecision` | Yes | `TileUnavailable`, `MatchFailed`, `GeometryFailed` | -| `benchmark_matcher` | `MatcherBenchmarkRequest` | `MatcherBenchmarkReport` | Yes | `ModelUnavailable` | - -**Input DTOs**: - -```yaml -AnchorVerificationRequest: - frame: FramePacket - candidates: list[VprCandidate] - matcher_profile: enum(aliked, disk, sift_orb_baseline) -``` - -**Output DTOs**: - -```yaml -AnchorDecision: - candidate_id: string - accepted_by_geometry: boolean - estimated_pose_wgs84: object optional - inlier_count: integer - mre_px: number - homography: matrix optional - rejection_reason: string optional -``` - -## 3. Data Access Patterns - -| Query | Frequency | Hot Path | Index Needed | -|-------|-----------|----------|--------------| -| Read candidate COG footprint/window | Triggered only | No | Tile spatial metadata | -| Read matcher model | Startup | No | No | - -## 4. Implementation Details - -**State Management**: Loads matcher/extractor models and tracks benchmark-selected profile. - -**Key Dependencies**: - -| Library | Purpose | -|---------|---------| -| ALIKED/DISK + LightGlue | Learned local matching | -| OpenCV | RANSAC/USAC geometry and error metrics | - -**Error Handling Strategy**: -- Low inlier count, high MRE, stale tile, or provenance failure returns a rejected decision with reason. -- SuperPoint can be benchmarked only if legal approval allows its license use. - -## 5. Caveats & Edge Cases - -**Known limitations**: -- ALIKED-LightGlue is not VIO by itself; it supplies correspondences. A full VIO path still needs state estimation and IMU fusion. -- Optional frame-to-frame VO fallback must be benchmarked separately from cross-domain anchor verification. - -**Performance bottlenecks**: -- Learned matching can exceed the Jetson budget if run per-frame; default invocation is trigger-based. - -## 6. Dependency Graph - -**Must be implemented after**: Satellite Service candidate DTOs, Tile Manager tile access. - -**Can be implemented in parallel with**: VIO adapter. - -**Blocks**: accepted satellite-anchor path. - -## 7. Logging Strategy - -| Log Level | When | Example | -|-----------|------|---------| -| ERROR | Matcher model unavailable | `lightglue_model_unavailable profile=aliked` | -| WARN | Candidate rejected | `anchor_geometry_rejected mre_px=... inliers=...` | -| INFO | Anchor verified | `anchor_verified tile_id=... mre_px=...` | - -**Log format**: FDR structured event. - -**Log storage**: FDR segment. diff --git a/_docs/02_document/components/05_anchor_verification/tests.md b/_docs/02_document/components/05_anchor_verification/tests.md deleted file mode 100644 index 8a3b39f..0000000 --- a/_docs/02_document/components/05_anchor_verification/tests.md +++ /dev/null @@ -1,124 +0,0 @@ -# Test Specification — Anchor Verification - -## Acceptance Criteria Traceability - -| AC ID | Acceptance Criterion | Test IDs | Coverage | -|-------|---------------------|----------|----------| -| AC-1.1 | 50 m frame-center accuracy via accepted anchors | AT-01 | Covered | -| AC-1.2 | 20 m stretch accuracy via accepted anchors | AT-01 | Covered | -| AC-2.1b | Satellite-anchor registration measured separately | IT-01 | Covered | -| AC-2.2 | <2.5 px cross-domain MRE | IT-01, AT-01 | Covered | -| AC-3.1 | Outlier rejection | ST-01 | Covered | -| AC-4.1 | Trigger-path latency | PT-01 | Covered | -| AC-4.2 | Memory budget | PT-01 | Covered | -| AC-NEW-4 | False-position safety budget | ST-01 | Covered | -| AC-NEW-6 | Stale imagery rejection evidence | IT-02, ST-02 | Covered | - -## Blackbox Tests - -### IT-01: Cross-Domain Match And RANSAC - -**Summary**: Verify ALIKED/DISK-LightGlue plus RANSAC produces measurable anchor evidence. - -**Traces to**: AC-2.1b, AC-2.2 - -**Input data**: UAV frame, retrieved COG candidate window, ground-truth georegistration. - -**Expected result**: Accepted anchors have MRE <2.5 px, sufficient inliers, and homography/pose evidence. - -**Max execution time**: 2 seconds per candidate set. - ---- - -### IT-02: Stale Candidate Verification - -**Summary**: Verify stale or provenance-failed candidates are rejected or marked unsafe. - -**Traces to**: AC-NEW-6 - -**Input data**: Candidate list with stale tile metadata and valid-looking image content. - -**Expected result**: `AnchorDecision` is rejected or carries stale/provenance failure; safety wrapper cannot accept it as trusted. - -**Max execution time**: 2 seconds per candidate. - -## Performance Tests - -### PT-01: Local Matcher Runtime - -**Summary**: Verify learned matching stays bounded on Jetson when invoked. - -**Traces to**: AC-4.1, AC-4.2 - -**Load scenario**: -- Candidate sets: K=5, K=20, K=50. -- Matcher profiles: ALIKED, DISK, SIFT/ORB baseline. - -| Metric | Target | Failure Threshold | -|--------|--------|-------------------| -| K=5 p95 | <=300 ms | >500 ms | -| K=20 p95 | Reported and bounded | Unbounded/no report | -| Memory contribution | <=2 GB | >3 GB | - -**Resource limits**: Total Jetson shared memory remains below 8 GB. - -## Security Tests - -### ST-01: False Match / Impossible Jump Rejection - -**Summary**: Verify visually plausible but geographically impossible matches are rejected. - -**Traces to**: AC-3.1, AC-NEW-4 - -**Attack vector**: Candidate tile from wrong region with repetitive texture. - -**Test procedure**: -1. Pair query with wrong-region candidate. -2. Run matcher and RANSAC. -3. Pass result to safety wrapper fixture. - -**Expected behavior**: Anchor is rejected by geometry or downstream consistency gates. - -**Pass criteria**: 0 accepted anchors from wrong-region fixtures. - ---- - -### ST-02: Provenance Failure - -**Summary**: Verify unsigned/hash-failed candidate tiles cannot produce accepted anchors. - -**Traces to**: AC-NEW-6 - -**Attack vector**: Tampered COG or sidecar. - -**Test procedure**: Run verification against tampered tile fixture. - -**Expected behavior**: `AnchorDecision` includes provenance failure and is not accepted. - -**Pass criteria**: 0 trusted anchors from tampered tiles. - -## Acceptance Tests - -### AT-01: Accepted Anchor Accuracy - -**Summary**: Verify accepted anchors support position accuracy thresholds. - -**Traces to**: AC-1.1, AC-1.2, AC-2.2 - -| Step | Action | Expected Result | -|------|--------|-----------------| -| 1 | Verify satellite candidate against query | MRE <2.5 px | -| 2 | Convert accepted anchor to WGS84 evidence | Error supports 50 m / 20 m aggregate thresholds | - -## Test Data Management - -| Data Set | Description | Source | Size | -|----------|-------------|--------|------| -| `anchor_match_fixture` | Query frames, COG windows, expected georegistration | ALTO/AerialVL/project cache | Dataset-dependent | -| `tampered_tile_fixture` | Hash/signature/stale cases | Generated fixture | Small | - -**Setup procedure**: Load cache fixture and matcher model profile. - -**Teardown procedure**: Remove matcher outputs and reports. - -**Data isolation strategy**: Read-only imagery with per-run output folders. diff --git a/_docs/02_document/components/06_cache_tile_lifecycle/description.md b/_docs/02_document/components/06_cache_tile_lifecycle/description.md deleted file mode 100644 index 030bced..0000000 --- a/_docs/02_document/components/06_cache_tile_lifecycle/description.md +++ /dev/null @@ -1,92 +0,0 @@ -# Tile Manager - -## 1. High-Level Overview - -**Purpose**: Manage local tiles: service-source COGs, manifests, descriptor metadata, freshness/provenance checks, nadir-image orthorectification into generated tiles, generated tile writes, and post-flight package preparation. - -**Architectural Pattern**: Repository + policy gate. - -**Upstream dependencies**: Satellite Service cache packages, safety/anchor wrapper, camera ingest/calibration. - -**Downstream consumers**: Satellite Service, anchor verification, FDR, post-flight sync. - -## 2. Internal Interfaces - -### Interface: `TileManager` - -| Method | Input | Output | Async | Error Types | -|--------|-------|--------|-------|-------------| -| `validate_cache` | `CacheValidationRequest` | `CacheValidationReport` | No | `ManifestInvalid`, `SignatureInvalid` | -| `get_tile_window` | `TileWindowRequest` | `TileWindow` | No | `TileUnavailable`, `TileRejected` | -| `orthorectify_frame` | `TileGenerationRequest` | `GeneratedTileCandidate` | Yes | `TileWriteRejected`, `FrameNotUsable` | -| `write_generated_tile` | `GeneratedTileRequest` | `GeneratedTileRecord` | Yes | `TileWriteRejected`, `StorageFull` | -| `package_sync` | `SyncPackageRequest` | `SyncPackage` | Yes | `PackageFailed` | - -## 3. Data Access Patterns - -| Query | Frequency | Hot Path | Index Needed | -|-------|-----------|----------|--------------| -| Tile by footprint/time/freshness | Per retrieval/anchor | Yes during relocalization | Spatial/time indexes | -| Descriptor metadata by chunk | Per Satellite Service retrieval | Yes during relocalization | Chunk ID index | -| Generated tile by mission/sector | Post-flight | No | Mission ID index | - -### Caching Strategy - -| Data | Cache Type | TTL | Invalidation | -|------|------------|-----|--------------| -| Manifest metadata | PostgreSQL/PostGIS query cache / process cache | Mission duration | New mission cache load | -| Sidecar verification | In-memory result cache | Mission duration | File hash change | - -### Storage Estimates - -| Table/Collection | Est. Row Count | Row Size | Total Size | Growth Rate | -|------------------|----------------|----------|------------|-------------| -| Cache manifest tiles | Mission-dependent | Small metadata | Within ~10 GB package with imagery | Per mission | -| Generated tiles | Flight-dependent | Metadata + COG payload | FDR/cache budget constrained | Per flight | - -## 4. Implementation Details - -**State Management**: Owns PostgreSQL/PostGIS manifest connection, sidecar verification state, and generated tile staging area. - -**Key Dependencies**: - -| Library | Purpose | -|---------|---------| -| PostgreSQL + PostGIS | Manifest, spatial metadata, freshness queries, and generated-tile metadata | -| GDAL/rasterio candidate | COG read/write | -| OpenCV/GDAL geometry utilities | Nadir-frame orthorectification into generated COG tiles | -| Cryptographic hash/signature library | Sidecar validation | - -**Error Handling Strategy**: -- Invalid signatures/hashes reject tiles. -- Storage-full blocks generated tile writes without affecting localization output. -- Cache validation failure blocks mission cache usage. - -## 5. Caveats & Edge Cases - -**Known limitations**: -- JSON-only manifests are avoided for scale and queryability, but signed JSON sidecars remain required for audit/interchange. -- PostgreSQL/PostGIS must be available locally before flight; runtime cannot depend on a remote DB link. - -**Potential race conditions**: -- Generated tile and PostgreSQL manifest update must be atomic enough to avoid orphan trusted metadata. - -## 6. Dependency Graph - -**Must be implemented after**: data model schema decisions. - -**Can be implemented in parallel with**: camera ingest, MAVLink integration. - -**Blocks**: Satellite Service retrieval, anchor verification, generated tile lifecycle. - -## 7. Logging Strategy - -| Log Level | When | Example | -|-----------|------|---------| -| ERROR | Cache package invalid | `cache_manifest_invalid reason=signature` | -| WARN | Tile rejected | `tile_rejected reason=stale tile_id=...` | -| INFO | Generated tile staged | `generated_tile_written tile_id=...` | - -**Log format**: FDR structured event. - -**Log storage**: FDR segment plus cache validation report. diff --git a/_docs/02_document/components/06_cache_tile_lifecycle/tests.md b/_docs/02_document/components/06_cache_tile_lifecycle/tests.md deleted file mode 100644 index c35821f..0000000 --- a/_docs/02_document/components/06_cache_tile_lifecycle/tests.md +++ /dev/null @@ -1,167 +0,0 @@ -# Test Specification — Tile Manager - -## Acceptance Criteria Traceability - -| AC ID | Acceptance Criterion | Test IDs | Coverage | -|-------|---------------------|----------|----------| -| AC-4.2 | Memory/storage pressure | PT-01 | Covered | -| AC-8.1 | Resolution at cache interface | IT-01 | Covered | -| AC-8.2 | Freshness thresholds | IT-02, ST-01 | Covered | -| AC-8.3 | Preloaded/preprocessed offline cache | IT-01 | Covered | -| AC-8.4 | Mid-flight tile generation/write-back | IT-03, AT-01 | Covered | -| AC-8.5 | Persistent imagery policy | ST-02 | Covered | -| AC-8.6 | VPR chunk metadata | IT-04 | Covered | -| AC-NEW-3 | FDR/tile storage cap interaction | PT-01 | Covered | -| AC-NEW-6 | Imagery freshness enforcement | IT-02, ST-01 | Covered | -| AC-NEW-7 | Cache-poisoning safety budget | ST-03, AT-01 | Covered | - -## Blackbox Tests - -### IT-01: Mission Cache Validation - -**Summary**: Verify preloaded COGs, PostGIS metadata, sidecars, descriptors, and indexes validate before flight. - -**Traces to**: AC-8.1, AC-8.3 - -**Input data**: Mission cache package with COGs, signed JSON sidecars, PostGIS manifest seed, FAISS index files. - -**Expected result**: Valid cache passes resolution, hash, signature, descriptor-reference, and spatial coverage checks. - -**Max execution time**: 5 minutes per cache fixture. - ---- - -### IT-02: Freshness Gate - -**Summary**: Verify active-conflict and stable-rear freshness rules. - -**Traces to**: AC-8.2, AC-NEW-6 - -**Input data**: Tiles at fresh, grace, and stale ages for both sector classes. - -**Expected result**: Fresh tiles pass, grace tiles are down-confidence weighted if allowed, stale tiles are rejected and cannot emit `satellite_anchored`. - -**Max execution time**: 2 minutes. - ---- - -### IT-03: Generated Tile Write - -**Summary**: Verify nadir frames are orthorectified and written as generated tiles only when pose and frame quality gates pass. - -**Traces to**: AC-8.4 - -**Input data**: Frame metadata, pose covariance <=3 m, <=5 m, and >5 m. - -**Expected result**: <=3 m writes full-quality candidate, 3-5 m writes soft candidate, >5 m rejects write. - -**Max execution time**: 2 minutes. - ---- - -### IT-04: VPR Chunk Metadata - -**Summary**: Verify chunk metadata supports retrieval rules. - -**Traces to**: AC-8.6 - -**Input data**: Operational-area cache manifest. - -**Expected result**: Chunks are 600-800 m equivalent footprint with 40-50% overlap and multi-scale active-sector descriptors. - -**Max execution time**: 2 minutes. - -## Performance Tests - -### PT-01: Cache And FDR Storage Budget - -**Summary**: Verify cache metadata and generated tile writes stay within storage/memory budgets. - -**Traces to**: AC-4.2, AC-NEW-3 - -**Load scenario**: -- Mission cache: up to operational budget. -- Generated tiles: 8-hour synthetic flight. - -| Metric | Target | Failure Threshold | -|--------|--------|-------------------| -| Persistent cache | <=10 GB unless split budget approved | >budget without report | -| FDR + generated artifacts | <=64 GB per flight | >64 GB without rollover | -| DB query p95 | <=50 ms for indexed tile lookup | >150 ms | - -**Resource limits**: PostgreSQL/PostGIS stays within total system 8 GB memory budget. - -## Security Tests - -### ST-01: Signed Manifest Enforcement - -**Summary**: Verify unsigned/tampered/stale manifests are rejected. - -**Traces to**: AC-8.2, AC-NEW-6 - -**Attack vector**: Tampered sidecar, bad hash, unsigned manifest. - -**Test procedure**: Load invalid cache variants and run validation. - -**Expected behavior**: Invalid tiles are rejected and logged. - -**Pass criteria**: 0 invalid cache entries become available to retrieval/anchor verification. - ---- - -### ST-02: Raw Frame Persistence Check - -**Summary**: Verify Tile Manager persists tiles, not raw frames. - -**Traces to**: AC-8.5 - -**Attack vector**: Raw frames accidentally stored as generated artifacts. - -**Test procedure**: Run tile generation and inspect cache/FDR outputs. - -**Expected behavior**: Only COG tiles, sidecars, manifests, and allowed failed-frame thumbnails exist. - -**Pass criteria**: No raw full-resolution frames retained. - ---- - -### ST-03: Cache Poisoning Gate - -**Summary**: Verify misaligned generated tiles cannot become trusted basemap. - -**Traces to**: AC-NEW-7 - -**Attack vector**: Over-confident pose writes misaligned generated tile. - -**Test procedure**: Inject deflated covariance and wrong pose during tile write. - -**Expected behavior**: Tile is rejected or marked candidate/soft; never promoted to trusted by onboard component. - -**Pass criteria**: 0 direct trusted basemap promotions onboard. - -## Acceptance Tests - -### AT-01: Generated Tile Package For Satellite Service - -**Summary**: Verify post-flight sync package contains valid generated tiles and metadata. - -**Traces to**: AC-8.4, AC-NEW-7 - -| Step | Action | Expected Result | -|------|--------|-----------------| -| 1 | Orthorectify and write generated candidate tile | COG + sidecar + PostGIS manifest row created | -| 2 | Package post-flight sync | Manifest delta includes trust level and parent covariance | -| 3 | Inspect package | No tile is marked trusted basemap by onboard runtime | - -## Test Data Management - -| Data Set | Description | Source | Size | -|----------|-------------|--------|------| -| `cache_integrity_fixtures` | Valid/stale/unsigned/hash-mismatched manifests | Generated fixture | Small | -| `mission_cache_fixture` | COGs, descriptors, PostGIS seed | Satellite Service stub | Mission-dependent | - -**Setup procedure**: Restore isolated PostgreSQL/PostGIS schema and mount cache fixture read-only except generated-tile staging. - -**Teardown procedure**: Drop schema and delete generated staging volume. - -**Data isolation strategy**: Per-run mission ID, schema, and staging directory. diff --git a/_docs/02_document/components/07_mavlink_gcs_integration/description.md b/_docs/02_document/components/07_mavlink_gcs_integration/description.md deleted file mode 100644 index 4b6415c..0000000 --- a/_docs/02_document/components/07_mavlink_gcs_integration/description.md +++ /dev/null @@ -1,69 +0,0 @@ -# MAVLink And GCS Integration - -## 1. High-Level Overview - -**Purpose**: Subscribe to flight-controller telemetry, emit `GPS_INPUT`, and send downsampled QGroundControl status/failsafe messages. - -**Architectural Pattern**: Protocol adapter. - -**Upstream dependencies**: ArduPilot Plane FC, safety/anchor wrapper. - -**Downstream consumers**: VIO adapter, safety/anchor wrapper, QGC, FDR. - -## 2. Internal Interfaces - -### Interface: `MavlinkGateway` - -| Method | Input | Output | Async | Error Types | -|--------|-------|--------|-------|-------------| -| `subscribe_telemetry` | `TelemetrySubscriptionRequest` | `TelemetrySample` | Yes | `MavlinkDisconnected` | -| `emit_gps_input` | `PositionEstimate` | `EmitResult` | Yes | `MavlinkDisconnected`, `InvalidGpsInput` | -| `emit_status` | `GcsStatusMessage` | `EmitResult` | Yes | `MavlinkDisconnected` | - -## 3. Data Access Patterns - -No persistent data ownership; telemetry and emitted packets are mirrored to FDR. - -## 4. Implementation Details - -**State Management**: Maintains MAVLink connection status, source/system IDs, and rate limiters for QGC status. - -**Key Dependencies**: - -| Library | Purpose | -|---------|---------| -| MAVSDK | Telemetry subscriptions | -| pymavlink | Exact `GPS_INPUT` field emission | - -**Error Handling Strategy**: -- Invalid `GPS_INPUT` fields are rejected before emission. -- Connection loss is surfaced to wrapper/FDR and does not silently drop safety events. - -## 5. Caveats & Edge Cases - -**Known limitations**: -- v1 emits `GPS_INPUT` only, not velocity-target navigation commands. -- Plane parameter configuration must be validated in SITL before hardware use. - -**Performance bottlenecks**: -- Status text must be rate-limited to avoid telemetry noise. - -## 6. Dependency Graph - -**Must be implemented after**: position estimate DTO and MAVLink output contract. - -**Can be implemented in parallel with**: Tile Manager, camera ingest. - -**Blocks**: SITL integration and production FC output. - -## 7. Logging Strategy - -| Log Level | When | Example | -|-----------|------|---------| -| ERROR | MAVLink disconnected | `mavlink_disconnected endpoint=...` | -| WARN | Invalid output rejected | `gps_input_invalid reason=...` | -| INFO | FC link established | `mavlink_connected system_id=...` | - -**Log format**: FDR structured event. - -**Log storage**: FDR segment and optional tlog. diff --git a/_docs/02_document/components/07_mavlink_gcs_integration/tests.md b/_docs/02_document/components/07_mavlink_gcs_integration/tests.md deleted file mode 100644 index a31c293..0000000 --- a/_docs/02_document/components/07_mavlink_gcs_integration/tests.md +++ /dev/null @@ -1,176 +0,0 @@ -# Test Specification — MAVLink And GCS Integration - -## Acceptance Criteria Traceability - -| AC ID | Acceptance Criterion | Test IDs | Coverage | -|-------|---------------------|----------|----------| -| AC-4.3 | v1 GPS_INPUT only for ArduPilot Plane | IT-01, AT-01 | Covered | -| AC-4.4 | Frame-by-frame streaming | PT-01 | Covered | -| AC-4.5 | Updated estimates/corrections | IT-02 | Covered | -| AC-5.1 | FC state initialization telemetry | IT-03 | Covered | -| AC-5.2 | Plane SITL fallback | IT-04 | Covered | -| AC-6.1 | QGC status 1-2 Hz | IT-05, PT-02 | Covered | -| AC-6.2 | GCS command ingress | IT-06, ST-01 | Covered | -| AC-6.3 | WGS84 output | IT-01 | Covered | -| AC-NEW-2 | Spoofing promotion <3 s | IT-04 | Covered | -| AC-NEW-8 | Blackout/failsafe status | IT-05 | Covered | - -## Blackbox Tests - -### IT-01: GPS_INPUT Field Mapping - -**Summary**: Verify `PositionEstimate` maps to valid MAVLink `GPS_INPUT`. - -**Traces to**: AC-4.3, AC-6.3 - -**Input data**: Position estimates across all source labels. - -**Expected result**: v1 emits `GPS_INPUT` only, no `ODOMETRY`; WGS84 lat/lon/alt, fix type, ignore flags, and accuracy fields match contract. - -**Max execution time**: 2 minutes. - ---- - -### IT-02: Correction Emission - -**Summary**: Verify updated estimates can be emitted without batching. - -**Traces to**: AC-4.5 - -**Input data**: Original VO estimate followed by anchor-corrected estimate. - -**Expected result**: Both estimates are emitted in order with updated accuracy/source label. - -**Max execution time**: 2 minutes. - ---- - -### IT-03: FC Telemetry Subscription - -**Summary**: Verify telemetry needed for initialization and VIO is available. - -**Traces to**: AC-5.1 - -**Input data**: Plane SITL or MAVLink replay with EKF position, IMU, attitude, airspeed, altitude. - -**Expected result**: Normalized `TelemetrySample` stream includes required fields and timestamps. - -**Max execution time**: 5 minutes. - ---- - -### IT-04: Spoofing And Fallback In Plane SITL - -**Summary**: Verify spoofing and no-estimate behavior in ArduPilot Plane SITL. - -**Traces to**: AC-5.2, AC-NEW-2 - -**Input data**: Plane SITL production parameter set and spoofing trace. - -**Expected result**: Own estimate promotion occurs within <3 s; fallback/no-estimate behavior matches Plane parameters. - -**Max execution time**: 10 minutes. - ---- - -### IT-05: QGC Blackout Status - -**Summary**: Verify degraded-mode messages are visible at required rate. - -**Traces to**: AC-6.1, AC-NEW-8 - -**Input data**: Safety wrapper emits blackout and failsafe statuses. - -**Expected result**: QGC observer sees `VISUAL_BLACKOUT_IMU_ONLY` at 1-2 Hz and `VISUAL_BLACKOUT_FAILSAFE` at threshold. - -**Max execution time**: 10 minutes. - ---- - -### IT-06: Operator Relocalization Hint - -**Summary**: Verify GCS command ingress can carry approximate relocalization hints. - -**Traces to**: AC-6.2 - -**Input data**: STATUSTEXT/NAMED_VALUE_FLOAT/custom dialect hint fixture. - -**Expected result**: Valid hint is parsed and forwarded to retrieval/safety logic; invalid hint is rejected. - -**Max execution time**: 5 minutes. - -## Performance Tests - -### PT-01: Frame-Rate Emission - -**Summary**: Verify output is streamed frame-by-frame and not batched. - -**Traces to**: AC-4.4 - -**Load scenario**: -- Input estimate rate: target frame rate. -- Duration: 30 minutes. - -| Metric | Target | Failure Threshold | -|--------|--------|-------------------| -| Output delay p95 | <=25 ms after wrapper output | >100 ms | -| Missing messages | 0 except upstream dropped frames | Any silent drop | - ---- - -### PT-02: QGC Status Rate Limit - -**Summary**: Verify QGC status is downsampled without losing critical transitions. - -**Traces to**: AC-6.1 - -| Metric | Target | Failure Threshold | -|--------|--------|-------------------| -| Status rate | 1-2 Hz while active | <1 Hz or >2 Hz sustained | -| Critical transition delay | <=1 s | >2 s | - -## Security Tests - -### ST-01: MAVLink Source And Command Validation - -**Summary**: Verify unauthorized or malformed MAVLink messages are rejected. - -**Traces to**: AC-6.2 - -**Attack vector**: Malicious source sends spoofed command or GPS data. - -**Test procedure**: -1. Send valid command from allowed source. -2. Send same command from disallowed source/system ID. -3. Send malformed values. - -**Expected behavior**: Allowed command is accepted; disallowed/malformed messages are rejected and logged. - -**Pass criteria**: 0 unauthorized commands affect localization state. - -## Acceptance Tests - -### AT-01: Plane SITL Output Acceptance - -**Summary**: Verify ArduPilot Plane receives and uses v1 `GPS_INPUT` as configured. - -**Traces to**: AC-4.3 - -| Step | Action | Expected Result | -|------|--------|-----------------| -| 1 | Start Plane SITL with production params | FC accepts external GPS substitute config | -| 2 | Emit `GPS_INPUT` estimate | Message is received with expected fields | -| 3 | Observe wire | `ODOMETRY` is absent in v1 | - -## Test Data Management - -| Data Set | Description | Source | Size | -|----------|-------------|--------|------| -| `sitl_spoofing_scenarios` | GPS loss/spoofing traces | Generated SITL | Small | -| `mavlink_output_fixtures` | PositionEstimate cases | Generated fixture | Small | - -**Setup procedure**: Start SITL/QGC observer or replay MAVLink log. - -**Teardown procedure**: Stop processes and archive tlogs. - -**Data isolation strategy**: Unique MAVLink ports and run IDs per test. diff --git a/_docs/02_document/components/08_fdr_observability/description.md b/_docs/02_document/components/08_fdr_observability/description.md deleted file mode 100644 index 330fc77..0000000 --- a/_docs/02_document/components/08_fdr_observability/description.md +++ /dev/null @@ -1,79 +0,0 @@ -# FDR And Observability - -## 1. High-Level Overview - -**Purpose**: Record bounded, replayable mission evidence and expose runtime health/status events for analysis and operator awareness. - -**Architectural Pattern**: Append-only event sink + exporter. - -**Upstream dependencies**: All runtime components. - -**Downstream consumers**: Validation harness, post-flight audit tools, QGC status through MAVLink component. - -## 2. Internal Interfaces - -### Interface: `FlightRecorder` - -| Method | Input | Output | Async | Error Types | -|--------|-------|--------|-------|-------------| -| `append_event` | `FdrEvent` | `AppendResult` | Yes | `RecorderUnavailable`, `StorageFull` | -| `rollover` | `RolloverRequest` | `FdrSegmentInfo` | No | `RolloverFailed` | -| `export` | `ExportRequest` | `ExportResult` | Yes | `ExportFailed` | - -## 3. Data Access Patterns - -| Query | Frequency | Hot Path | Index Needed | -|-------|-----------|----------|--------------| -| Append event | High | Yes | Append index only | -| Export by time/type | Post-flight | No | Time/type index | - -### Storage Estimates - -| Table/Collection | Est. Row Count | Row Size | Total Size | Growth Rate | -|------------------|----------------|----------|------------|-------------| -| FDR events | Flight-dependent | Mixed | <=64 GB per 8 h | Per flight | - -## 4. Implementation Details - -**State Management**: Owns active segment, rollover policy, and export state. - -**Key Dependencies**: - -| Library | Purpose | -|---------|---------| -| PostgreSQL client | Event metadata, time/type indexes, mission query surface | -| CBOR writer | Bounded runtime payload segments | -| Parquet writer | Optional post-flight export | - -**Error Handling Strategy**: -- Storage-full emits critical status and starts rollover/retention behavior. -- Append failures are surfaced to the caller and health system. - -## 5. Caveats & Edge Cases - -**Known limitations**: -- Raw frames are not retained by default; only metadata, decisions, hashes, and occlusion/blackout status are recorded. -- PostgreSQL availability is required for indexed FDR metadata; CBOR payload segments preserve bounded append behavior for high-volume data. - -**Performance bottlenecks**: -- FDR appends must not block hot-path localization. - -## 6. Dependency Graph - -**Must be implemented after**: event schema and key DTOs. - -**Can be implemented in parallel with**: MAVLink integration. - -**Blocks**: release evidence and most validation reports. - -## 7. Logging Strategy - -| Log Level | When | Example | -|-----------|------|---------| -| ERROR | Recorder unavailable | `fdr_unavailable path=...` | -| WARN | Rollover occurs | `fdr_rollover segment=...` | -| INFO | Export complete | `fdr_export_complete format=parquet` | - -**Log format**: FDR event metadata plus local health logs. - -**Log storage**: PostgreSQL FDR event tables plus CBOR segment payloads. diff --git a/_docs/02_document/components/08_fdr_observability/tests.md b/_docs/02_document/components/08_fdr_observability/tests.md deleted file mode 100644 index 9633205..0000000 --- a/_docs/02_document/components/08_fdr_observability/tests.md +++ /dev/null @@ -1,166 +0,0 @@ -# Test Specification — FDR And Observability - -## Acceptance Criteria Traceability - -| AC ID | Acceptance Criterion | Test IDs | Coverage | -|-------|---------------------|----------|----------| -| AC-1.3 | Anchor age/drift evidence | IT-01 | Covered | -| AC-1.4 | Confidence/source label retained | IT-01 | Covered | -| AC-4.4 | Per-frame local stream evidence | IT-01, PT-01 | Covered | -| AC-5.2 | Failure logging | IT-02 | Covered | -| AC-6.1 | QGC/status evidence | IT-03 | Covered | -| AC-8.4 | Generated tile audit | IT-04 | Covered | -| AC-8.5 | No raw frame retention | ST-01 | Covered | -| AC-NEW-3 | FDR retention and 64 GB cap | PT-01, AT-01 | Covered | -| AC-NEW-4 | False-position forensics | IT-05 | Covered | -| AC-NEW-5 | Thermal/throttle logging | IT-06 | Covered | -| AC-NEW-8 | Blackout/failsafe logging | IT-02, IT-03 | Covered | - -## Blackbox Tests - -### IT-01: Per-Estimate Event Capture - -**Summary**: Verify every estimate stores covariance, source label, anchor age, and emitted output metadata. - -**Traces to**: AC-1.3, AC-1.4, AC-4.4 - -**Input data**: Position estimate stream with satellite, VO, and dead-reckoned labels. - -**Expected result**: PostgreSQL event index and CBOR payload segments contain all required fields with monotonic timestamps. - -**Max execution time**: 5 minutes. - ---- - -### IT-02: Failure And Blackout Logging - -**Summary**: Verify no-estimate and blackout transitions are recorded. - -**Traces to**: AC-5.2, AC-NEW-8 - -**Input data**: No-estimate gap and total blackout sequence. - -**Expected result**: FDR records start, every degraded estimate, failsafe threshold, and recovery reason. - -**Max execution time**: 10 minutes. - ---- - -### IT-03: QGC Status Audit - -**Summary**: Verify operator-visible status has matching FDR evidence. - -**Traces to**: AC-6.1, AC-NEW-8 - -**Input data**: QGC status messages from MAVLink component. - -**Expected result**: FDR contains status text, timestamp, and mode context. - -**Max execution time**: 5 minutes. - ---- - -### IT-04: Generated Tile Audit Trail - -**Summary**: Verify tile-write decisions are recorded with parent covariance and trust level. - -**Traces to**: AC-8.4 - -**Input data**: Accepted and rejected generated tile write decisions. - -**Expected result**: FDR includes tile ID, parent covariance, trust level, sidecar hash, and rejection reason where applicable. - -**Max execution time**: 5 minutes. - ---- - -### IT-05: False-Position Investigation Bundle - -**Summary**: Verify enough evidence exists to investigate a false-position event. - -**Traces to**: AC-NEW-4 - -**Input data**: Simulated false anchor rejection and covariance growth sequence. - -**Expected result**: Export includes estimates, anchor decisions, residuals, covariance, and emitted MAVLink fields. - -**Max execution time**: 5 minutes. - ---- - -### IT-06: Thermal/Throttle Event Capture - -**Summary**: Verify resource health events are recorded. - -**Traces to**: AC-NEW-5 - -**Input data**: Synthetic thermal/throttle metric stream. - -**Expected result**: FDR records CPU/GPU/temp/throttle status and QGC warning trigger. - -**Max execution time**: 5 minutes. - -## Performance Tests - -### PT-01: 8-Hour FDR Load - -**Summary**: Verify FDR storage and append behavior under full mission load. - -**Traces to**: AC-4.4, AC-NEW-3 - -**Load scenario**: -- Duration: 8 hours synthetic. -- Inputs: 3 Hz estimates, full-rate IMU, MAVLink tlog, health metrics, tile events. - -| Metric | Target | Failure Threshold | -|--------|--------|-------------------| -| Total FDR size | <=64 GB | >64 GB without rollover | -| Append latency p95 | <=10 ms async enqueue | >25 ms | -| Silent payload loss | 0 | Any unlogged loss | - -**Resource limits**: FDR must not block hot-path localization. - -## Security Tests - -### ST-01: Raw Frame Retention Audit - -**Summary**: Verify FDR does not store raw full-resolution frames. - -**Traces to**: AC-8.5 - -**Attack vector**: Debug logging accidentally persists raw camera frames. - -**Test procedure**: -1. Run normal replay and failed tile-generation replay. -2. Inspect FDR payloads and output directories. - -**Expected behavior**: Only metadata, hashes, estimates, tiles, and allowed low-rate failed-frame thumbnails are retained. - -**Pass criteria**: No raw nav/AI camera frame payloads in normal FDR. - -## Acceptance Tests - -### AT-01: FDR Export - -**Summary**: Verify post-flight export creates usable audit artifacts. - -**Traces to**: AC-NEW-3 - -| Step | Action | Expected Result | -|------|--------|-----------------| -| 1 | Complete synthetic flight | Segment rollover is logged and cap respected | -| 2 | Export FDR summary | Markdown/CSV/Parquet optional artifacts are produced | -| 3 | Query PostgreSQL index | Events can be filtered by time/type/mission | - -## Test Data Management - -| Data Set | Description | Source | Size | -|----------|-------------|--------|------| -| `fdr_synthetic_load` | Estimate, IMU, MAVLink, health, tile events | Generated fixture | Large | -| `incident_fixture` | False-position and blackout evidence | Generated fixture | Small | - -**Setup procedure**: Create isolated PostgreSQL schema and FDR segment directory. - -**Teardown procedure**: Export report, then remove schema and segment directory. - -**Data isolation strategy**: Per-run mission ID, schema, and FDR directory. diff --git a/_docs/02_document/contracts/shared/config_errors_telemetry.md b/_docs/02_document/contracts/shared/config_errors_telemetry.md deleted file mode 100644 index cdb689f..0000000 --- a/_docs/02_document/contracts/shared/config_errors_telemetry.md +++ /dev/null @@ -1,53 +0,0 @@ -# Contract: Config Errors Telemetry - -**Component**: shared/config, shared/errors, shared/telemetry -**Producer task**: AZ-222 — AZ-222_runtime_config_errors_telemetry.md -**Consumer tasks**: AZ-223, AZ-224, AZ-225, AZ-226, AZ-227, AZ-228, AZ-229, AZ-230, AZ-231, AZ-232, AZ-243 -**Version**: 1.0.0 -**Status**: draft -**Last Updated**: 2026-05-03 - -## Purpose - -Defines shared runtime configuration, error/result envelope, health, and telemetry metadata behavior consumed by all runtime components. - -## Shape - -| Contract | Required Behavior | -|----------|-------------------| -| Runtime profile | environment-specific settings loaded and validated before use | -| Error envelope | component, category, message, cause, retryability, severity | -| Health event | liveness/readiness status, dependency state, timestamp, component | -| Metrics labels | bounded component/action/status labels suitable for runtime reports | -| VIO runtime profile | production/Jetson VIO requires native mode; replay is explicit for development/replay checks | - -## Invariants - -- Missing required production settings fail startup or readiness loudly. -- Errors are returned or logged with component and category; no silent suppression. -- Secrets are referenced, not serialized into FDR, logs, or metrics. - -## Non-Goals - -- Does not define component-specific business errors. -- Does not replace FDR payload schemas. - -## Versioning Rules - -- Removing required config keys or error categories requires a major version bump. -- Adding optional health fields or metrics labels requires a minor version bump. - -## Test Cases - -| Case | Input | Expected | Notes | -|------|-------|----------|-------| -| missing-required-prod | production profile missing cache dir | readiness/startup failure | Clear error category | -| missing-native-vio-runtime | production VIO profile without installed native runtime | failed VIO health and explicit native runtime prerequisite error | No replay-derived success | -| secret-value | signing key ref present | only key ref logged | No secret leakage | -| component-error | component reports dependency failure | structured envelope emitted | FDR-safe | - -## Change Log - -| Version | Date | Change | Author | -|---------|------|--------|--------| -| 1.0.0 | 2026-05-03 | Initial contract | autodev | diff --git a/_docs/02_document/contracts/shared/geometry_time_sync.md b/_docs/02_document/contracts/shared/geometry_time_sync.md deleted file mode 100644 index be03b4a..0000000 --- a/_docs/02_document/contracts/shared/geometry_time_sync.md +++ /dev/null @@ -1,52 +0,0 @@ -# Contract: Geometry And Time Sync Helpers - -**Component**: shared/geo_geometry, shared/time_sync -**Producer task**: AZ-221 — AZ-221_shared_geometry_time_sync.md -**Consumer tasks**: AZ-223, AZ-225, AZ-226, AZ-228, AZ-230, AZ-231, AZ-232 -**Version**: 1.0.0 -**Status**: draft -**Last Updated**: 2026-05-03 - -## Purpose - -Defines shared geospatial and timestamp helper behavior used by runtime components to avoid duplicated math and inconsistent frame/IMU alignment. - -## Shape - -| API Area | Shape | Errors | -|----------|-------|--------| -| Coordinate conversion | WGS84/local tangent conversions and distance calculations | invalid CRS, missing origin | -| Camera footprint | intrinsics/extrinsics/attitude/altitude to footprint and GSD | invalid calibration, missing altitude | -| Homography metrics | homography/covariance conversions and MRE support | invalid geometry | -| Time sync | monotonic checks, frame-to-IMU window selection, replay ordering | timestamp mismatch, gap/jitter exceeded | - -## Invariants - -- Helpers are deterministic for the same calibration, pose, and timestamp inputs. -- Time helpers report gaps/jitter instead of silently dropping samples. -- Geometry helpers do not decide safety policy; callers decide degrade/reject behavior. - -## Non-Goals - -- No VIO state estimation. -- No MAVLink parsing beyond normalized timestamp fields. -- No tile freshness or cache policy decisions. - -## Versioning Rules - -- Breaking changes to units, coordinate frames, or timestamp semantics require a major version bump. -- New helper outputs may be added as optional fields in minor versions. - -## Test Cases - -| Case | Input | Expected | Notes | -|------|-------|----------|-------| -| valid-wgs84-local | known WGS84 point and origin | round-trip within tolerance | Uses representative coordinates | -| frame-imu-window | frame timestamp plus IMU samples | correct aligned window | Includes gap metrics | -| invalid-calibration | missing intrinsics/extrinsics | explicit error | No silent fallback | - -## Change Log - -| Version | Date | Change | Author | -|---------|------|--------|--------| -| 1.0.0 | 2026-05-03 | Initial contract | autodev | diff --git a/_docs/02_document/contracts/shared/runtime_contracts.md b/_docs/02_document/contracts/shared/runtime_contracts.md deleted file mode 100644 index 78d67ce..0000000 --- a/_docs/02_document/contracts/shared/runtime_contracts.md +++ /dev/null @@ -1,57 +0,0 @@ -# Contract: Runtime Shared Contracts - -**Component**: shared/contracts -**Producer task**: AZ-220 — AZ-220_shared_runtime_contracts.md -**Consumer tasks**: AZ-223, AZ-224, AZ-225, AZ-226, AZ-227, AZ-228, AZ-229, AZ-230, AZ-231, AZ-232, AZ-243 -**Version**: 1.0.0 -**Status**: draft -**Last Updated**: 2026-05-03 - -## Purpose - -Defines the shared runtime DTO/event contract surface that component implementations consume instead of inventing local shapes. - -## Shape - -| Contract | Required Fields / Methods | Consumers | -|----------|---------------------------|-----------| -| `FramePacket` | frame ID, timestamp, image reference, calibration ID, occlusion, quality, normalization hint | camera, VIO, Satellite Service, Anchor Verification, Tile Manager, FDR | -| `TelemetrySample` | timestamp, IMU, attitude, altitude, airspeed, GPS health | MAVLink, VIO, safety wrapper, FDR | -| `VioStatePacket` | timestamp, relative pose, velocity, bias, tracking quality, covariance hint | VIO, safety wrapper, FDR | -| `VioProcessingResult` | optional VIO state, health report, latency, error envelope | VIO, safety wrapper, FDR | -| `PositionEstimate` | WGS84 coordinates, covariance, source label, fix type, horizontal accuracy, anchor age | safety wrapper, MAVLink, Tile Manager, FDR | -| `VprCandidate` | chunk ID, tile ID, score, footprint, freshness status | Satellite Service, Anchor Verification, FDR | -| `AnchorDecision` | candidate ID, acceptance result, estimated pose, inliers, MRE, rejection reason | Anchor Verification, safety wrapper, FDR | -| `CacheTileRecord` | tile ID, CRS, meters per pixel, capture date, signature/hash, trust level | Tile Manager, Satellite Service, Anchor Verification | -| `FdrEvent` | event type, timestamp, component, severity, payload reference, mission/run ID | all runtime components | - -## Invariants - -- Timestamps are normalized to a shared monotonic nanosecond representation before cross-component use. -- Confidence fields must not under-report known uncertainty. -- Raw frame payloads are referenced, not persisted in shared DTOs. -- Generated tile and anchor records must carry provenance/freshness metadata. - -## Non-Goals - -- Does not prescribe internal classes or storage implementation. -- Does not define e2e test runner-only report schemas. - -## Versioning Rules - -- Removing or renaming a field requires a major version bump. -- Adding optional telemetry or diagnostic fields requires a minor version bump. - -## Test Cases - -| Case | Input | Expected | Notes | -|------|-------|----------|-------| -| valid-frame | frame with timestamp, calibration, quality | accepted by consumers | Includes normalization hint | -| invalid-time | non-monotonic timestamp | rejected or marked invalid | Time-sync contract decides details | -| stale-anchor | anchor decision with stale freshness | rejected/down-confidenced | Safety wrapper must not accept blindly | - -## Change Log - -| Version | Date | Change | Author | -|---------|------|--------|--------| -| 1.0.0 | 2026-05-03 | Initial contract | autodev | diff --git a/_docs/02_document/data_model.md b/_docs/02_document/data_model.md deleted file mode 100644 index 49377a2..0000000 --- a/_docs/02_document/data_model.md +++ /dev/null @@ -1,148 +0,0 @@ -# Data Model - -## Scope - -This model defines system-level runtime, cache, telemetry, and validation data. PostgreSQL with PostGIS is the primary structured store for manifests, spatial metadata, mission state, and FDR event indexes. Large binary payloads remain local files: COG tiles, descriptor/index files, FDR payload segments, and replay fixtures. - -## Entity Overview - -| Entity | Purpose | Storage / Transport | Owner | -|--------|---------|---------------------|-------| -| MissionProfile | Operational area, sector type, route shape, altitude band, cache budget | Mission config file | Tile Manager | -| CameraCalibration | Intrinsics, distortion, lens, fixed extrinsics, capture settings | Versioned calibration file | Camera ingest/calibration | -| FrameRecord | Per-frame metadata, timestamp, total-occlusion/blackout state, image quality, processing status | PostgreSQL/FDR event; replay fixture | Camera ingest/calibration | -| TelemetrySample | FC IMU, attitude, altitude, airspeed, GPS health | MAVLink stream; FDR event | MAVLink/GCS integration | -| VioState | Backend-relative state, velocity, bias, tracking quality | Internal DTO; FDR event | VIO adapter | -| PositionEstimate | WGS84 output, covariance, source label, anchor age, fix type | MAVLink DTO; FDR event | Safety/anchor wrapper | -| VprChunk | Retrieval footprint and descriptor metadata | PostgreSQL/PostGIS manifest + descriptor files | Satellite Service | -| AnchorCandidate | Top-K retrieval result and local verification metrics | Internal DTO; FDR event | Anchor verification | -| CacheTile | Service-source or generated COG tile metadata | PostgreSQL/PostGIS manifest + signed JSON sidecar | Tile Manager | -| GeneratedTile | In-flight tile candidate with trust/provenance metadata | COG + sidecar + FDR event | Tile Manager | -| FdrSegment | Bounded append-only mission evidence segment | PostgreSQL event index + CBOR segment payloads | FDR/observability | -| ValidationRun | Replay/test run metadata and outcomes | CSV/Markdown/test artifacts | Validation harness | - -## Core Entity Attributes - -### MissionProfile - -| Field | Type | Required | Notes | -|-------|------|----------|-------| -| `mission_id` | string | yes | Unique mission/run identifier | -| `operational_area_polygon` | geometry | yes | Up to ~400 km² | -| `sector_classification` | enum | yes | `active_conflict` or `stable_rear` | -| `planned_altitude_agl_m` | number | yes | <=1000 m AGL | -| `route_type` | enum | yes | `sector`, `transit_corridor`, or mixed | -| `cache_budget_bytes` | integer | yes | Default ~10 GB persistent | - -### CameraCalibration - -| Field | Type | Required | Notes | -|-------|------|----------|-------| -| `camera_model` | string | yes | ADTi 20MP 20L V1 family | -| `sensor_width_mm` | number | yes | Public spec check currently indicates 23.20 mm | -| `sensor_height_mm` | number | yes | Public spec check currently indicates 15.40 mm | -| `image_width_px` | integer | yes | Public spec check currently indicates 5456 px | -| `image_height_px` | integer | yes | Public spec check currently indicates 3632 px | -| `pixel_pitch_um` | number | yes | Public spec check indicates 4.25 um | -| `lens_focal_length_mm` | number | yes | TBD before implementation | -| `distortion_coefficients` | array | yes | From checkerboard calibration | -| `body_T_camera` | transform | yes | Fixed camera-to-body extrinsics | -| `spec_verification_status` | enum | yes | `manufacturer_verified`, `public_page_only`, `operator_supplied` | - -### PositionEstimate - -| Field | Type | Required | Notes | -|-------|------|----------|-------| -| `timestamp_ns` | integer | yes | Frame-aligned | -| `lat_deg` | number | yes | WGS84 | -| `lon_deg` | number | yes | WGS84 | -| `alt_msl_m` | number | yes | MSL altitude for `GPS_INPUT` | -| `covariance_95_semi_major_m` | number | yes | Must not be under-reported | -| `source_label` | enum | yes | `satellite_anchored`, `vo_extrapolated`, `dead_reckoned` | -| `last_satellite_anchor_age_ms` | integer | yes | Monotonic until new anchor | -| `fix_type` | integer | yes | MAVLink fix semantics | -| `horiz_accuracy_m` | number | yes | >= covariance semi-major mapping | -| `quality_flags` | bitset/string array | yes | Anchor, blackout, spoofing, stale tile, etc. | - -### FrameRecord - -| Field | Type | Required | Notes | -|-------|------|----------|-------| -| `frame_id` | string | yes | Stable frame/run identifier | -| `timestamp_ns` | integer | yes | Camera clock normalized by time-sync helper | -| `camera_calibration_id` | string | yes | Links to `CameraCalibration` | -| `occlusion_status` | enum | yes | `clear`, `partial_occlusion`, `total_occlusion`, `blackout` | -| `usable_for_vio` | boolean | yes | Must be false for total occlusion/blackout | -| `usable_for_anchor` | boolean | yes | Must be false for total occlusion/blackout | -| `blackout_reason` | enum | optional | `cloud`, `lens_cover`, `whiteout`, `decode_failure`, `underexposed`, `overexposed`, `unknown` | -| `blur_score` | number | yes | Quality metric | -| `texture_score` | number | yes | Quality metric | - -### CacheTile - -| Field | Type | Required | Notes | -|-------|------|----------|-------| -| `tile_id` | string | yes | Stable ID | -| `tile_type` | enum | yes | `service_source`, `generated_candidate`, `generated_soft`, `trusted_basemap` | -| `cog_path` | string | yes | Local path | -| `crs` | string | yes | Projection metadata | -| `meters_per_pixel` | number | yes | Must satisfy cache interface floor | -| `capture_date` | date | yes | Freshness gate | -| `source` | string | yes | Satellite Service or onboard generation | -| `sha256` | string | yes | Integrity | -| `signature_status` | enum | yes | `valid`, `missing`, `invalid` | -| `parent_pose_covariance_m` | number | generated only | Tile-write gate | -| `trust_level` | enum | yes | `rejected`, `candidate`, `soft`, `trusted` | - -## Relationships - -```mermaid -erDiagram - MissionProfile ||--o{ CacheTile : scopes - MissionProfile ||--o{ VprChunk : indexes - CameraCalibration ||--o{ FrameRecord : calibrates - FrameRecord ||--o{ VioState : contributes_to - TelemetrySample ||--o{ VioState : contributes_to - VioState ||--o{ PositionEstimate : propagates - VprChunk ||--o{ AnchorCandidate : retrieved_as - CacheTile ||--o{ AnchorCandidate : verified_against - AnchorCandidate ||--o{ PositionEstimate : may_anchor - PositionEstimate ||--o{ GeneratedTile : gates - PositionEstimate ||--o{ FdrSegment : recorded_in -``` - -## Storage Strategy - -| Data Class | Primary Format | Reason | -|------------|----------------|--------| -| Structured mission/cache/FDR metadata | PostgreSQL + PostGIS | Queryable freshness, coverage, spatial footprints, descriptors, tile status, and FDR event indexes | -| Tile audit sidecar | Signed JSON | Human/audit/service interchange per tile | -| Imagery tile | COG | Geospatial raster standard | -| Descriptor index | FAISS CPU index files + metadata | Fast top-K retrieval | -| FDR runtime payloads | CBOR segment files + PostgreSQL index | Bounded append payloads with queryable event metadata | -| FDR analysis export | Parquet optional | Post-flight analytics | -| Test report | CSV + Markdown | CI and human review | - -## Migration Strategy - -- PostgreSQL schemas use explicit `schema_version` and additive migrations by default. -- PostGIS geometry columns are used for mission polygons, tile footprints, VPR chunks, and generated-tile extents. -- FDR segment schema includes `segment_schema_version`; old readers must reject unknown required fields loudly. -- Sidecars include a `sidecar_version` and hash of the COG payload. -- Migrations are implemented as deterministic scripts with rollback for metadata-only changes. -- No database/table/column rename is allowed without explicit approval during implementation. - -## Seed Data Requirements - -| Environment | Seed Data | -|-------------|-----------| -| Development | 60 project images, `coordinates.csv`, small cache fixture, generated SITL traces | -| Public replay | Pinned MUN-FRL/ALTO/Kagaru/EPFL dataset slices and licenses | -| Jetson validation | Production-like cache/index, cold-start fixtures, thermal workload | -| Representative acceptance | Synchronized target nav-camera + FC telemetry + ground truth | - -## Backward Compatibility - -- Runtime should tolerate older cache sidecars if required fields exist and signatures validate. -- Generated tile sidecars must include all fields required by Satellite Service ingest; missing fields make the tile ineligible for promotion. -- FDR readers must support at least the current and previous segment schema version during the project lifecycle. diff --git a/_docs/02_document/deployment/README.md b/_docs/02_document/deployment/README.md deleted file mode 100644 index c30bbed..0000000 --- a/_docs/02_document/deployment/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Deployment Planning Index - -This directory contains the system-level deployment plan produced during Plan Step 2: - -- `containerization.md` -- `ci_cd_pipeline.md` -- `environment_strategy.md` -- `observability.md` -- `deployment_procedures.md` - -Component-specific implementation tasks are created later during decomposition. diff --git a/_docs/02_document/deployment/ci_cd_pipeline.md b/_docs/02_document/deployment/ci_cd_pipeline.md deleted file mode 100644 index 90b1390..0000000 --- a/_docs/02_document/deployment/ci_cd_pipeline.md +++ /dev/null @@ -1,54 +0,0 @@ -# CI/CD Pipeline - -## Pipeline Stages - -| Stage | Runs On | Gate | -|-------|---------|------| -| Format/lint | PR | Block merge | -| Unit tests | PR | Block merge | -| Replay black-box smoke | PR | Block merge | -| Cache/security fixture tests | PR | Block merge | -| Plane SITL spoof/failsafe tests | Release candidate / nightly | Block release | -| Public dataset replay | Nightly / release candidate | Block release | -| Jetson latency/resource tests | Release candidate | Block release | -| Thermal/FDR endurance | Release candidate / hardware qualification | Block release | - -## Artifact Outputs - -- Test CSV reports. -- FDR validation summaries. -- Cache integrity reports. -- Dataset replay metrics. -- SITL tlogs. -- Jetson profiling traces. - -## Caching - -- Cache dependency builds by lockfile hash. -- Cache public dataset slices only in controlled CI storage with license metadata. -- Do not cache secrets or signing keys. - -## Branch Policy - -- Work occurs on `dev`. -- Release gates must pass before deploy artifacts are considered production-ready. -- Any failed safety, spoofing, false-position, or cache-poisoning test blocks release. - -## Quality Gates - -| Gate | Threshold | -|------|-----------| -| Still-image geolocation | >=80% within 50 m and >=50% within 20 m | -| Hot-path latency | <400 ms p95 | -| Memory | <8 GB shared | -| Cold start | <30 s p95 | -| FDR | <=64 GB / 8-hour flight | -| Cache storage | <=10 GB unless split budget is approved | -| False position | AC-NEW-4 thresholds | - -## Open Tasks For Decomposition - -- Define CI runner labels for Docker/replay vs Jetson local hardware. -- Add dataset-license checks before public dataset jobs. -- Implement SITL scenario generation and tlog validation job. -- Implement report collation into a release evidence bundle. diff --git a/_docs/02_document/deployment/containerization.md b/_docs/02_document/deployment/containerization.md deleted file mode 100644 index 88965fa..0000000 --- a/_docs/02_document/deployment/containerization.md +++ /dev/null @@ -1,46 +0,0 @@ -# Containerization - -## Strategy - -The production runtime targets Jetson hardware and may not be fully containerized for all camera/GPU paths. The test and development stack uses containers where practical, with local hardware execution required for release gates. - -## Runtime Units - -| Unit | Containerized? | Notes | -|------|----------------|-------| -| GPS-denied service | Optional on Jetson | Must access camera, CUDA/TensorRT/ONNX, MAVLink, local cache, FDR storage | -| Replay consumer | Yes | Deterministic black-box test harness | -| Satellite cache stub | Yes | Local fixture volume for COG/manifest/descriptors | -| ArduPilot Plane SITL | Yes or local process | Used for MAVLink and failsafe validation | -| QGC observer/log parser | Yes | Parses MAVLink status/tlogs | - -## Docker Compose Profiles - -| Profile | Purpose | Services | -|---------|---------|----------| -| `replay` | CI/PR deterministic fixture tests | gps-denied-service, replay-consumer, satellite-cache-stub | -| `sitl` | ArduPilot Plane integration tests | gps-denied-service, ardupilot-plane-sitl, qgc-observer | -| `jetson-local` | Documentation-only profile for local hardware run | Host runtime with local scripts/tasks created later | - -## Image Requirements - -- Base images must match JetPack/CUDA compatibility for GPU tests. -- Replay-only images may use standard Ubuntu/Python/C++ build images. -- No production image should contain secrets, mission signing keys, or provider credentials. -- Dataset downloads are not baked into images; they are mounted as versioned fixtures. - -## Volumes - -| Volume | Purpose | -|--------|---------| -| `/data/input` | Test images and public dataset slices | -| `/cache/satellite` | Offline cache fixture | -| `/fdr` | Runtime FDR output | -| `/test-results` | CSV/Markdown reports | - -## Open Tasks For Decomposition - -- Create Dockerfiles for replay-compatible service and consumer harness. -- Define Jetson local setup scripts for GPU/camera/MAVLink access. -- Create compose profiles for replay and SITL. -- Add license-aware public dataset fixture downloader. diff --git a/_docs/02_document/deployment/deployment_procedures.md b/_docs/02_document/deployment/deployment_procedures.md deleted file mode 100644 index 44de986..0000000 --- a/_docs/02_document/deployment/deployment_procedures.md +++ /dev/null @@ -1,68 +0,0 @@ -# Deployment Procedures - -## Deployment Targets - -| Target | Purpose | -|--------|---------| -| Replay environment | Development and CI fixtures | -| Plane SITL | MAVLink/failsafe validation | -| Jetson companion computer | Production runtime and release gating | -| Representative flight/replay rig | Final acceptance evidence | - -## Pre-Deployment Checklist - -- Camera lens, resolution, FPS, sensor dimensions, and operating temperature are manufacturer-verified. -- Camera intrinsics/extrinsics are calibrated and versioned. -- BASALT, OpenCV, FAISS, LightGlue, DINOv2/ONNX/TensorRT dependencies are pinned. -- TensorRT/ONNX descriptor-fidelity tests pass before optimized engines are used. -- Satellite cache manifests and sidecars validate signatures, hashes, freshness, and resolution. -- Plane SITL validates `GPS_INPUT` behavior with production parameters. -- Jetson latency, memory, and thermal release gates pass. -- FDR rollover test passes. - -## Deployment Steps - -1. Install JetPack-compatible runtime dependencies on the companion computer. -2. Install/build BASALT and native vision dependencies. -3. Pre-build any ONNX/TensorRT engines accepted by fidelity tests. -4. Sync mission cache from Satellite Service before flight. -5. Validate cache manifest, descriptors, signatures, resolution, and freshness. -6. Start the onboard service and verify FC telemetry connection. -7. Run cold-start first-fix check. -8. Confirm QGroundControl status and FDR segment creation. - -## Health Checks - -| Check | Pass Condition | -|-------|----------------| -| Camera input | Frames received with expected resolution/rate | -| FC telemetry | IMU/attitude/altitude/GPS-health stream healthy | -| Cache | Manifest and descriptor index valid | -| First fix | Valid `GPS_INPUT` <30 s p95 in cold-start test | -| Resource health | Memory <8 GB, no thermal throttle | -| QGC status | Status visible at configured downsample rate | -| FDR | Segment open and writable | - -## Rollback - -- If runtime dependency update fails tests, revert to previous pinned build. -- If cache manifest validation fails, reject the mission cache and resync/rebuild before flight. -- If optimized engine fidelity fails, fall back to PyTorch/ONNX path that passed descriptor tests. -- If BASALT candidate fails representative replay gates, evaluate Kimera backup or custom fallback tasks before production deployment. - -## Post-Flight Procedure - -1. Stop the onboard service cleanly. -2. Export FDR summary and integrity hashes. -3. Package generated tiles with sidecars and manifest delta. -4. Upload generated tile package to Satellite Service when connectivity is available. -5. Archive release evidence: tlogs, FDR summary, cache validation report, test results. - -## Deployment Blockers - -- ADTi camera spec mismatch unresolved for FPS/resolution/lens/temperature. -- Missing representative synchronized nav-camera + FC telemetry + ground truth for final acceptance. -- Any false-position safety budget failure. -- Any cache-poisoning gate failure. -- Any Plane SITL `GPS_INPUT` failure. -- Thermal throttling during the 8-hour target workload. diff --git a/_docs/02_document/deployment/environment_strategy.md b/_docs/02_document/deployment/environment_strategy.md deleted file mode 100644 index d4609c3..0000000 --- a/_docs/02_document/deployment/environment_strategy.md +++ /dev/null @@ -1,49 +0,0 @@ -# Environment Strategy - -## Environments - -| Environment | Purpose | Hardware | -|-------------|---------|----------| -| Development replay | Fast local iteration with fixtures | Developer workstation | -| CI replay | Deterministic PR checks | Docker runner | -| Public dataset replay | Nightly/RC algorithm validation | Docker or GPU runner | -| Plane SITL | MAVLink/failsafe validation | Docker/local SITL | -| Jetson hardware validation | Production path latency, memory, GPU, camera, thermal | Jetson Orin Nano Super | -| Representative flight/replay | Final acceptance evidence | Target-like UAV/FC/camera setup | - -## Configuration Classes - -| Config | Development | Production | -|--------|-------------|------------| -| Satellite cache | Small fixture | Full mission cache | -| PostgreSQL/PostGIS | Local test DB with fixture manifests | Local onboard DB with signed mission manifests, spatial metadata, and FDR event indexes | -| Descriptor index | Small FAISS index | Full operational-area index | -| MAVLink | SITL/replay | Physical FC link | -| FDR | Temporary directory | Per-flight NVMe directory with rollover | -| Dataset fixtures | Optional public slices | Not used at runtime | - -## Secrets And Signing - -- Mission signing keys are never committed. -- Test keys may be committed only if clearly labeled as non-production. -- Provider credentials are not used by onboard runtime. -- Any Satellite Service sync credentials are post-flight/deployment environment secrets. - -## Dataset Licensing - -Public datasets must be tagged before use: - -| Dataset | Expected Use | License Constraint | -|---------|--------------|--------------------| -| MUN-FRL | Preferred public VIO/nadir replay | CC BY 4.0 per current docs | -| ALTO | Preferred aerial localization/VPR replay | BSD-3 repository; dataset availability must be pinned | -| Kagaru | Fixed-wing/farmland validation candidate | Verify terms before commercial use | -| EPFL fixed-wing | Fixed-wing validation candidate | Verify terms before commercial use | -| VPAir | VPR/localization only | Academic-use restriction likely blocks commercial acceptance | -| UZH FPV | VIO stress proxy only | Non-commercial license blocks commercial acceptance | - -## Promotion Rules - -- A result from public datasets can de-risk implementation but cannot replace representative acceptance data. -- A release candidate cannot be promoted without Jetson hardware validation and Plane SITL. -- A mission cache cannot be used if manifest/signature/freshness validation fails. diff --git a/_docs/02_document/deployment/observability.md b/_docs/02_document/deployment/observability.md deleted file mode 100644 index a5558cc..0000000 --- a/_docs/02_document/deployment/observability.md +++ /dev/null @@ -1,61 +0,0 @@ -# Observability - -## Goals - -- Explain every emitted position estimate. -- Detect false-position risk before it reaches the flight controller. -- Preserve enough evidence to replay incidents without storing raw frames. -- Surface operator-relevant status to QGroundControl without saturating telemetry. - -## Runtime Signals - -| Signal | Frequency | Destination | Notes | -|--------|-----------|-------------|-------| -| Position estimate | Per processed frame locally | FDR, MAVLink `GPS_INPUT` | GCS receives downsampled status | -| Source label | Per estimate | FDR, status summary | `satellite_anchored`, `vo_extrapolated`, `dead_reckoned` | -| Covariance semi-major | Per estimate | FDR, `GPS_INPUT.horiz_accuracy` mapping | Must not under-report | -| Anchor decision | Per candidate | FDR | Include MRE, inliers, tile provenance, rejection reason | -| Cache validation | On cache load / tile read | FDR, health log | Signature, freshness, resolution, hash | -| Blackout/spoofing status | On transition and 1-2 Hz while active | QGC, FDR | Operator status | -| Total occlusion status | Per transition and sampled while active | FDR, QGC if persistent | Indicates VIO is bypassed and IMU-only propagation is active | -| Resource health | 1 Hz or configurable | FDR, QGC warning on threshold | CPU/GPU/temp/memory/throttle | -| Tile write decision | Per generated tile | FDR, sidecar | Include parent covariance and trust level | - -## Logs - -| Log Type | Format | Retention | -|----------|--------|-----------| -| FDR events/index | PostgreSQL tables + CBOR payload segments | <=64 GB per flight, rollover | -| MAVLink raw stream | tlog or equivalent | FDR cap | -| Health metrics | FDR event stream | FDR cap | -| Test reports | CSV/Markdown | CI artifact retention | - -## Alerts And Status Text - -| Condition | Status | -|-----------|--------| -| Visual blackout starts | `VISUAL_BLACKOUT_IMU_ONLY` | -| Total occlusion before VIO | `VISUAL_OCCLUSION_IMU_ONLY` | -| Blackout failsafe threshold exceeded | `VISUAL_BLACKOUT_FAILSAFE` | -| Spoofing promotion/demotion | QGC status text with mode and timestamp | -| Stale cache tile rejected | Warning in FDR; QGC only if mission-impacting | -| Thermal throttle risk | QGC warning before throttle if possible | -| No estimate for threshold | Relocalization request / failsafe status | - -## Metrics For Release Evidence - -- Error CDF against ground truth. -- Anchor-age binned error. -- Covariance calibration plot. -- VIO completion rate. -- Relocalization trigger-to-anchor latency. -- Cache freshness rejection counts. -- FDR size over 8 hours. -- Thermal/throttle timeline. - -## Open Tasks For Decomposition - -- Define FDR schema and event names. -- Define QGC status vocabulary and rate limiting. -- Define telemetry-to-report export tooling. -- Define covariance calibration dashboard/report. diff --git a/_docs/02_document/diagrams/component_overview.md b/_docs/02_document/diagrams/component_overview.md deleted file mode 100644 index 1fd12da..0000000 --- a/_docs/02_document/diagrams/component_overview.md +++ /dev/null @@ -1,46 +0,0 @@ -# Component Overview Diagram - -```mermaid -flowchart LR - camera[01 Camera Ingest And Calibration] - vio[02 VIO Adapter] - wrapper[03 Safety And Anchor Wrapper] - retrieval[04 Satellite Service] - verify[05 Anchor Verification] - cache[06 Tile Manager] - mav[07 MAVLink And GCS Integration] - fdr[08 FDR And Observability] - tests[[Separate E2E Test Suite]] - - navCam[[Nav Camera]] --> camera - fc[[ArduPilot Plane FC]] --> mav - satSvc[[Azaion Suite Satellite Service]] --> retrieval - datasets[[Replay/Public Datasets]] --> tests - - camera --> vio - mav --> vio - vio --> wrapper - wrapper --> retrieval - retrieval --> verify - cache --> retrieval - cache --> verify - verify --> wrapper - wrapper --> mav - wrapper --> cache - camera --> cache - - camera --> fdr - vio --> fdr - wrapper --> fdr - retrieval --> fdr - verify --> fdr - cache --> fdr - mav --> fdr - - tests --> camera - tests --> mav - tests --> cache - mav --> qgc[[QGroundControl]] - mav --> fc - retrieval --> satSvc -``` diff --git a/_docs/02_document/diagrams/flows/flow_cache_tile_lifecycle.md b/_docs/02_document/diagrams/flows/flow_cache_tile_lifecycle.md deleted file mode 100644 index 566e2a6..0000000 --- a/_docs/02_document/diagrams/flows/flow_cache_tile_lifecycle.md +++ /dev/null @@ -1,18 +0,0 @@ -# Flow: Tile Manager And Generated Tile Lifecycle - -```mermaid -flowchart TD - preflight([Pre-flight Satellite Service sync]) --> validate[06 Tile Manager validates manifest signatures hashes freshness] - validate --> cacheOk{Cache valid?} - cacheOk -->|No| block[Block cache usage and report] - cacheOk -->|Yes| load[04 Satellite Service loads local descriptor metadata and FAISS index] - load --> flight([Flight runtime]) - flight --> eligibility[03 Tile write eligibility check] - eligibility --> eligible{Covariance and quality pass?} - eligible -->|No| noWrite[Do not write generated tile] - eligible -->|Yes| write[06 Orthorectify frame and write COG + signed JSON sidecar] - write --> fdr[08 Record tile-write audit] - fdr --> postflight([Post-flight]) - postflight --> package[06 Package generated tiles + manifest delta] - package --> sync[[Post-flight Satellite Service upload]] -``` diff --git a/_docs/02_document/diagrams/flows/flow_normal_localization.md b/_docs/02_document/diagrams/flows/flow_normal_localization.md deleted file mode 100644 index fd86745..0000000 --- a/_docs/02_document/diagrams/flows/flow_normal_localization.md +++ /dev/null @@ -1,21 +0,0 @@ -# Flow: Normal Localization - -```mermaid -flowchart TD - start([Frame + FC telemetry]) --> ingest[01 Camera ingest and quality] - ingest --> occlusion{Total occlusion or blackout?} - occlusion -->|Yes| imuOnly[03 IMU-only dead_reckoned propagation] - occlusion -->|No| frameOk{Frame usable for VIO?} - frameOk -->|No| degrade[03 Safety wrapper degraded mode] - frameOk -->|Yes| vio[02 VIO adapter] - telemetry[07 MAVLink telemetry] --> vio - vio --> healthy{VIO healthy?} - healthy -->|Yes| wrap[03 Covariance calibration + source label] - healthy -->|No| trigger[Trigger relocalization] - wrap --> emit[07 Emit GPS_INPUT and QGC status] - wrap --> record[08 Record FDR event] - emit --> endNode([Position output]) - trigger --> satFlow[[Satellite relocalization flow]] - imuOnly --> emit - degrade --> emit -``` diff --git a/_docs/02_document/diagrams/flows/flow_satellite_relocalization.md b/_docs/02_document/diagrams/flows/flow_satellite_relocalization.md deleted file mode 100644 index 37b85fc..0000000 --- a/_docs/02_document/diagrams/flows/flow_satellite_relocalization.md +++ /dev/null @@ -1,21 +0,0 @@ -# Flow: Satellite Relocalization - -```mermaid -flowchart TD - start([Relocalization trigger]) --> request[03 Build retrieval request] - request --> retrieve[04 DINOv2-VLAD + FAISS top-K] - retrieve --> candidates{Candidates found?} - candidates -->|No| degraded[03 Continue degraded/dead reckoned] - candidates -->|Yes| verify[05 ALIKED/DISK + LightGlue + RANSAC] - verify --> geometry{Geometry passes?} - geometry -->|No| degraded - geometry -->|Yes| gates[03 Freshness/provenance/Mahalanobis gates] - gates --> accepted{Anchor accepted?} - accepted -->|No| degraded - accepted -->|Yes| update[03 Apply absolute correction] - update --> emit[07 Emit anchored GPS_INPUT] - degraded --> emitDegraded[07 Emit degraded GPS_INPUT/status] - emit --> record[08 Record anchor decision] - emitDegraded --> record - record --> endNode([Relocalization result]) -``` diff --git a/_docs/02_document/epics.md b/_docs/02_document/epics.md deleted file mode 100644 index 01ba881..0000000 --- a/_docs/02_document/epics.md +++ /dev/null @@ -1,136 +0,0 @@ -# Work Item Epics - -**Tracker**: Jira -**Project**: AZAION (`AZ`) -**Date**: 2026-05-01 -**Labels**: `gps-denied-onboard-plan`, `autodev` -**Lessons applied**: No `_docs/LESSONS.md` file exists; no prior estimation or dependency lessons were available. - -## Dependency Order - -| Order | Jira ID | Epic | Type | Depends On | Estimate | -|-------|---------|------|------|------------|----------| -| 1 | AZ-206 | Bootstrap & Initial Structure | bootstrap | none | M / 5-8 pts | -| 2 | AZ-207 | Cross-Cutting: Shared Geometry And Time Sync | cross-cutting | AZ-206 | S-M / 3-5 pts | -| 3 | AZ-208 | Cross-Cutting: Runtime Configuration And Errors | cross-cutting | AZ-206 | S-M / 3-5 pts | -| 4 | AZ-209 | Camera Ingest And Calibration | component | AZ-206, AZ-207, AZ-208 | M / 5-8 pts | -| 5 | AZ-210 | MAVLink And GCS Integration | component | AZ-206, AZ-208 | M / 5-8 pts | -| 6 | AZ-211 | Tile Manager | component | AZ-206, AZ-207, AZ-208 | L / 8-13 pts | -| 7 | AZ-212 | FDR And Observability | component | AZ-206, AZ-208 | M-L / 5-8 pts | -| 8 | AZ-213 | VIO Adapter | component | AZ-206, AZ-207, AZ-208, AZ-209, AZ-210 | L / 8-13 pts | -| 9 | AZ-214 | Satellite Service | component | AZ-206, AZ-207, AZ-208, AZ-209, AZ-211 | L / 8-13 pts | -| 10 | AZ-215 | Anchor Verification | component | AZ-206, AZ-207, AZ-208, AZ-209, AZ-211, AZ-214 | L / 8-13 pts | -| 11 | AZ-216 | Safety And Anchor Wrapper | component | AZ-206, AZ-207, AZ-208, AZ-209, AZ-210, AZ-213, AZ-215 | XL / 13-21 pts | -| 12 | AZ-217 | E2E Test Suite | test-support | component epics | L / 8-13 pts | -| 13 | AZ-218 | Blackbox Tests | blackbox-tests | AZ-217, component epics | L / 8-13 pts | - -## Component Mapping - -| Component / Artifact | Epic | -|----------------------|------| -| Project scaffold, shared DTOs, migrations, CI skeleton | AZ-206 | -| `common-helpers/01_helper_geo_geometry.md` | AZ-207 | -| `common-helpers/02_helper_time_sync.md` | AZ-207 | -| Runtime config, error contracts, health checks | AZ-208 | -| `components/01_camera_ingest_calibration/` | AZ-209 | -| `components/02_vio_adapter/` | AZ-213 | -| `components/03_safety_anchor_wrapper/` | AZ-216 | -| `components/04_satellite_retrieval/` | AZ-214 | -| `components/05_anchor_verification/` | AZ-215 | -| `components/06_cache_tile_lifecycle/` | AZ-211 | -| `components/07_mavlink_gcs_integration/` | AZ-210 | -| `components/08_fdr_observability/` | AZ-212 | -| `tests/e2e-test-suite.md`, `tests/blackbox-tests.md`, `tests/environment.md` | AZ-217 | -| System blackbox/performance/resilience/security/resource tests | AZ-218 | - -## Epic Relationship Diagram - -```mermaid -flowchart TD - bootstrap[AZ-206 Bootstrap] - geo[AZ-207 Shared Geometry And Time Sync] - config[AZ-208 Runtime Configuration And Errors] - camera[AZ-209 Camera Ingest] - mavlink[AZ-210 MAVLink And GCS] - cache[AZ-211 Tile Manager] - fdr[AZ-212 FDR And Observability] - vio[AZ-213 VIO Adapter] - retrieval[AZ-214 Satellite Service] - anchor[AZ-215 Anchor Verification] - safety[AZ-216 Safety And Anchor Wrapper] - validation[AZ-217 E2E Test Suite] - blackbox[AZ-218 Blackbox Tests] - - bootstrap --> geo - bootstrap --> config - bootstrap --> camera - bootstrap --> mavlink - bootstrap --> cache - bootstrap --> fdr - geo --> camera - geo --> cache - geo --> vio - geo --> retrieval - geo --> anchor - geo --> safety - config --> camera - config --> mavlink - config --> cache - config --> fdr - config --> vio - config --> retrieval - config --> anchor - config --> safety - camera --> vio - mavlink --> vio - camera --> retrieval - cache --> retrieval - retrieval --> anchor - camera --> anchor - cache --> anchor - vio --> safety - anchor --> safety - mavlink --> safety - safety --> cache - safety --> mavlink - safety --> fdr - camera --> fdr - cache --> fdr - safety --> validation - fdr --> validation - camera --> validation - mavlink --> validation - retrieval --> validation - anchor --> validation - cache --> validation - validation --> blackbox -``` - -## Cross-Cutting Ownership - -| Concern | Owner Epic | Rule | -|---------|------------|------| -| Geospatial math, WGS84/local conversions, GSD, footprints | AZ-207 | Components consume shared helper; no local duplicate implementations | -| Timestamp validation, IMU/frame alignment, replay ordering | AZ-207 | Components consume shared helper; no local duplicate implementations | -| Runtime configuration, environment profiles, startup validation | AZ-208 | Components consume shared config loader and health-check contract | -| Shared error/result envelopes | AZ-208 | Components use shared error categories and do not swallow failures | - -## Created Jira Epics - -- AZ-206 — Bootstrap & Initial Structure -- AZ-207 — Cross-Cutting: Shared Geometry And Time Sync -- AZ-208 — Cross-Cutting: Runtime Configuration And Errors -- AZ-209 — Camera Ingest And Calibration -- AZ-210 — MAVLink And GCS Integration -- AZ-211 — Tile Manager -- AZ-212 — FDR And Observability -- AZ-213 — VIO Adapter -- AZ-214 — Satellite Service -- AZ-215 — Anchor Verification -- AZ-216 — Safety And Anchor Wrapper -- AZ-217 — E2E Test Suite -- AZ-218 — Blackbox Tests - -## Tracker Notes - -Jira authentication succeeded. A transient Jira server-side PostgreSQL timeout occurred while creating `Blackbox Tests`; the write was recorded under `_docs/_process_leftovers/` and then successfully retried as AZ-218. The leftover entry was deleted after replay success. diff --git a/_docs/02_document/glossary.md b/_docs/02_document/glossary.md deleted file mode 100644 index 06968e3..0000000 --- a/_docs/02_document/glossary.md +++ /dev/null @@ -1,96 +0,0 @@ -# Glossary - -**Status**: confirmed-by-user -**Date**: 2026-05-01 - -## Aerial VPR - -Visual place recognition over aerial/nadir imagery; used to retrieve candidate satellite/cache chunks for a UAV frame. (source: `solution.md`) - -## ADTi 20MP 20L V1 - -Selected navigation-camera family. Public product pages list Sony APS-C CMOS, 5456 x 3632 max image size, 23.20 x 15.40 mm sensor, 4.25 um pixel pitch, Sony E mount, and 2 fps continuous capture; final manufacturer specification remains a verification risk. (source: `restrictions.md`, user-confirmed open-question review) - -## Anchor - -Accepted absolute visual match to a georeferenced cache tile, used to correct VO/IMU drift. (source: `acceptance_criteria.md`, `solution.md`) - -## ArduPilot Plane SITL - -Simulation environment used to verify `GPS_INPUT`, spoofing, failsafe, and MAVLink behavior with the production Plane parameter set. (source: `acceptance_criteria.md`, `tests/environment.md`) - -## BASALT VIO - -Selected production relative visual-inertial odometry candidate. It consumes calibrated navigation-camera frames and IMU data but does not own the product's safety, anchor, cache, or MAVLink semantics. (source: `solution.md`) - -## Cache Poisoning - -Failure mode where a misaligned onboard-generated tile is written back and later corrupts future satellite-cache anchors. (source: `acceptance_criteria.md`) - -## COG Tile - -Cloud Optimized GeoTIFF raster object used as the write-new unit for georeferenced service tiles and generated onboard tiles. (source: `solution.md`) - -## FDR - -Flight Data Recorder. Bounded per-flight recorder for estimates, IMU traces, emitted MAVLink, health telemetry, tile writes, and audit evidence; raw nav/AI frames are not retained. (source: `acceptance_criteria.md`, `solution.md`) - -## Generated Tile - -In-flight orthorectified tile created from navigation-camera imagery and stored locally for post-flight Satellite Service sync. (source: `acceptance_criteria.md`) - -## `GPS_INPUT` - -MAVLink message used as the ArduPilot GPS substitute in v1. It carries WGS84 coordinates, fix type, accuracy fields, and ignore flags. (source: `acceptance_criteria.md`, `solution.md`) - -## Kimera Backup - -BSD-friendly VIO backup candidate if BASALT fails project replay/runtime gates. (source: `solution.md`) - -## Mahalanobis Gate - -Statistical consistency gate used to reject anchor updates that are inconsistent with the current estimator state and covariance. (source: `solution.md`) - -## Nadir Camera - -Fixed downward-pointing navigation camera used for localization. It is not gimbal-stabilized. (source: `restrictions.md`) - -## OpenVINS Reference - -GPLv3 VIO/covariance baseline used for replay comparison and uncertainty calibration; not the default production dependency. (source: `solution.md`) - -## Public Replay Dataset - -External dataset used to cover validation gaps in the current sample data, especially synchronized nadir camera, IMU, GNSS/ground truth, and reference imagery. MUN-FRL and ALTO are first-choice candidates. (source: `tests/test-data.md`) - -## QGroundControl - -Supported ground station that receives downsampled status and failsafe messages at 1-2 Hz. (source: `restrictions.md`, `acceptance_criteria.md`) - -## Representative Replay Rig - -Final acceptance dataset or hardware setup from the target flight profile with synchronized nav camera, FC IMU/attitude/airspeed/altitude, emitted MAVLink, and ground truth. (source: `acceptance_criteria.md`, `tests/test-data.md`) - -## Safety/Anchor Wrapper - -Project-owned layer around BASALT that calibrates confidence, fuses satellite anchors, owns source labels, handles degraded modes, gates generated tiles, and emits MAVLink outputs. (source: `solution.md`) - -## Satellite Service - -External Azaion Suite component that prepares the offline satellite cache before flight and ingests generated tiles after landing. The onboard system does not call it in-flight. (source: `restrictions.md`) - -## Source Label - -Categorical label attached to every estimate: `{satellite_anchored, vo_extrapolated, dead_reckoned}`. (source: `acceptance_criteria.md`) - -## Tile Freshness - -Runtime age gate for cache tiles: active-conflict sectors require newer imagery than stable rear sectors. (source: `acceptance_criteria.md`) - -## Visual Blackout - -State where the navigation camera provides no usable localization signal because of clouds, occlusion, whiteout, or similar visual loss. (source: `acceptance_criteria.md`) - -## VPR Chunk - -Ground-footprint-sized retrieval unit, approximately 600-800 m with overlap, decoupled from the storage tile convention. (source: `acceptance_criteria.md`) diff --git a/_docs/02_document/module-layout.md b/_docs/02_document/module-layout.md deleted file mode 100644 index 6400433..0000000 --- a/_docs/02_document/module-layout.md +++ /dev/null @@ -1,247 +0,0 @@ -# Module Layout - -**Language**: mixed (Python orchestration + C++ native vision bridges) -**Layout Convention**: src-layout -**Root**: `src/` -**Last Updated**: 2026-05-03 - -## Layout Rules - -1. Each product component owns one top-level directory under `src/`. -2. Shared contracts and cross-cutting helpers live under `src/shared/`. -3. Native hot-path or third-party bridge code lives inside the owning component folder under `native/`. -4. Public API surface per component is limited to `__init__.py`, `types.py`, and `interfaces.py` unless a component entry lists another public file. -5. Tests live under `tests/` by test type and component; implementation tasks must not place tests inside the component tree unless a later test task explicitly changes this layout. - -## Per-Component Mapping - -### Component: Camera Ingest And Calibration - -- **Epic**: AZ-209 -- **Directory**: `src/camera_ingest_calibration/` -- **Technologies**: Python, OpenCV 4.x, camera SDK/V4L2/GigE adapter boundary, calibration files, shared geometry/time helpers -- **Public API**: - - `src/camera_ingest_calibration/__init__.py` - - `src/camera_ingest_calibration/types.py` - - `src/camera_ingest_calibration/interfaces.py` -- **Internal (do NOT import from other components)**: - - `src/camera_ingest_calibration/internal/*` - - `src/camera_ingest_calibration/_*.py` -- **Owns (exclusive write during implementation)**: `src/camera_ingest_calibration/**` -- **Imports from**: shared/contracts, shared/geo_geometry, shared/time_sync, shared/config, shared/errors, shared/telemetry -- **Consumed by**: VIO Adapter, Satellite Service, Anchor Verification, Tile Manager, FDR And Observability - -### Component: VIO Adapter - -- **Epic**: AZ-213 -- **Directory**: `src/vio_adapter/` -- **Native Directory**: `src/vio_adapter/native/` -- **Technologies**: Python adapter, C++ native bridge, BASALT as current backend, Eigen/Sophus or backend-native math stack, OpenCV 4.x, shared time-sync contracts -- **Public API**: - - `src/vio_adapter/__init__.py` - - `src/vio_adapter/types.py` - - `src/vio_adapter/interfaces.py` -- **Internal (do NOT import from other components)**: - - `src/vio_adapter/internal/*` - - `src/vio_adapter/_*.py` - - `src/vio_adapter/native/**` -- **Owns (exclusive write during implementation)**: - - `src/vio_adapter/**` -- **Imports from**: Camera Ingest And Calibration, MAVLink And GCS Integration, shared/contracts, shared/geo_geometry, shared/time_sync, shared/config, shared/errors, shared/telemetry -- **Consumed by**: Safety And Anchor Wrapper, FDR And Observability - -### Component: Safety And Anchor Wrapper - -- **Epic**: AZ-216 -- **Directory**: `src/safety_anchor_wrapper/` -- **Technologies**: Python state machine, OpenCV geometry helpers, covariance/gating logic, shared DTO contracts, MAVLink output DTOs -- **Public API**: - - `src/safety_anchor_wrapper/__init__.py` - - `src/safety_anchor_wrapper/types.py` - - `src/safety_anchor_wrapper/interfaces.py` -- **Internal (do NOT import from other components)**: - - `src/safety_anchor_wrapper/internal/*` - - `src/safety_anchor_wrapper/_*.py` -- **Owns (exclusive write during implementation)**: `src/safety_anchor_wrapper/**` -- **Imports from**: VIO Adapter, Anchor Verification, MAVLink And GCS Integration, Camera Ingest And Calibration, shared/contracts, shared/geo_geometry, shared/time_sync, shared/config, shared/errors, shared/telemetry -- **Consumed by**: MAVLink And GCS Integration, Tile Manager, FDR And Observability - -### Component: Satellite Service - -- **Epic**: AZ-214 -- **Directory**: `src/satellite_service/` -- **Native Directory**: `src/satellite_service/native/` -- **Technologies**: Python service adapter, DINOv2-VLAD descriptors, ONNX/TensorRT candidate path, CPU FAISS, offline package sync client -- **Public API**: - - `src/satellite_service/__init__.py` - - `src/satellite_service/types.py` - - `src/satellite_service/interfaces.py` -- **Internal (do NOT import from other components)**: - - `src/satellite_service/internal/*` - - `src/satellite_service/_*.py` - - `src/satellite_service/native/**` -- **Owns (exclusive write during implementation)**: - - `src/satellite_service/**` -- **Imports from**: Camera Ingest And Calibration, Tile Manager, Safety And Anchor Wrapper, shared/contracts, shared/geo_geometry, shared/time_sync, shared/config, shared/errors, shared/telemetry -- **Consumed by**: Anchor Verification, FDR And Observability -- **Network invariant**: external Satellite Service sync is allowed only pre-flight or post-flight; no mid-flight satellite-provider or suite-service calls. - -### Component: Anchor Verification - -- **Epic**: AZ-215 -- **Directory**: `src/anchor_verification/` -- **Native Directory**: `src/anchor_verification/native/` -- **Technologies**: Python validation pipeline, ALIKED/DISK + LightGlue, OpenCV RANSAC/USAC, SIFT/ORB baseline, native feature-matching bridge -- **Public API**: - - `src/anchor_verification/__init__.py` - - `src/anchor_verification/types.py` - - `src/anchor_verification/interfaces.py` -- **Internal (do NOT import from other components)**: - - `src/anchor_verification/internal/*` - - `src/anchor_verification/_*.py` - - `src/anchor_verification/native/**` -- **Owns (exclusive write during implementation)**: - - `src/anchor_verification/**` -- **Imports from**: Satellite Service, Camera Ingest And Calibration, Tile Manager, shared/contracts, shared/geo_geometry, shared/time_sync, shared/config, shared/errors, shared/telemetry -- **Consumed by**: Safety And Anchor Wrapper, FDR And Observability - -### Component: Tile Manager - -- **Epic**: AZ-211 -- **Directory**: `src/tile_manager/` -- **Technologies**: Python repository/policy layer, PostgreSQL/PostGIS, GDAL/rasterio COG handling, signed JSON sidecars, OpenCV/GDAL orthorectification, hash/signature validation -- **Public API**: - - `src/tile_manager/__init__.py` - - `src/tile_manager/types.py` - - `src/tile_manager/interfaces.py` -- **Internal (do NOT import from other components)**: - - `src/tile_manager/internal/*` - - `src/tile_manager/_*.py` -- **Owns (exclusive write during implementation)**: - - `src/tile_manager/**` - - `migrations/postgresql/cache_*.sql` - - `migrations/seed/cache_*` -- **Imports from**: Camera Ingest And Calibration, Safety And Anchor Wrapper, shared/contracts, shared/geo_geometry, shared/time_sync, shared/config, shared/errors, shared/telemetry -- **Consumed by**: Satellite Service, Anchor Verification, FDR And Observability - -### Component: MAVLink And GCS Integration - -- **Epic**: AZ-210 -- **Directory**: `src/mavlink_gcs_integration/` -- **Technologies**: Python, MAVSDK telemetry subscriptions, pymavlink `GPS_INPUT` emission, MAVLink/QGC status messages -- **Public API**: - - `src/mavlink_gcs_integration/__init__.py` - - `src/mavlink_gcs_integration/types.py` - - `src/mavlink_gcs_integration/interfaces.py` -- **Internal (do NOT import from other components)**: - - `src/mavlink_gcs_integration/internal/*` - - `src/mavlink_gcs_integration/_*.py` -- **Owns (exclusive write during implementation)**: `src/mavlink_gcs_integration/**` -- **Imports from**: Safety And Anchor Wrapper, shared/contracts, shared/time_sync, shared/config, shared/errors, shared/telemetry -- **Consumed by**: VIO Adapter, Safety And Anchor Wrapper, FDR And Observability - -### Component: FDR And Observability - -- **Epic**: AZ-212 -- **Directory**: `src/fdr_observability/` -- **Technologies**: Python append/export layer, PostgreSQL event index, CBOR segment payloads, optional Parquet export, structured logging/health events -- **Public API**: - - `src/fdr_observability/__init__.py` - - `src/fdr_observability/types.py` - - `src/fdr_observability/interfaces.py` -- **Internal (do NOT import from other components)**: - - `src/fdr_observability/internal/*` - - `src/fdr_observability/_*.py` -- **Owns (exclusive write during implementation)**: - - `src/fdr_observability/**` - - `migrations/postgresql/fdr_*.sql` - - `migrations/seed/fdr_*` -- **Imports from**: shared/contracts, shared/time_sync, shared/config, shared/errors, shared/telemetry -- **Consumed by**: all runtime components - -## Shared / Cross-Cutting - -### shared/contracts - -- **Epic**: AZ-206 -- **Directory**: `src/shared/contracts/` -- **Technologies**: Python typed DTOs, schema/contract definitions, Markdown API-contract documents -- **Purpose**: Shared DTOs, protocol shapes, schemas, and public contract exports. -- **Owned by**: initial structure and shared-contract tasks under AZ-206. -- **Consumed by**: all components. - -### shared/geo_geometry - -- **Epic**: AZ-207 -- **Directory**: `src/shared/geo_geometry/` -- **Technologies**: Python geometry utilities, OpenCV 4.x, WGS84/local-frame math, homography/covariance conversions -- **Purpose**: WGS84/local conversions, GSD, camera footprint projection, homography/covariance unit conversion, and distance calculations. -- **Owned by**: shared geometry task under AZ-207. -- **Consumed by**: Camera Ingest And Calibration, Safety And Anchor Wrapper, Anchor Verification, Tile Manager. - -### shared/time_sync - -- **Epic**: AZ-207 -- **Directory**: `src/shared/time_sync/` -- **Technologies**: Python timestamp utilities, monotonic-clock validation, MAVLink/camera timestamp normalization, replay ordering checks -- **Purpose**: Monotonic timestamp checks, frame-to-IMU alignment, clock-domain metadata, replay ordering, and gap/jitter metrics. -- **Owned by**: time-sync task under AZ-207. -- **Consumed by**: Camera Ingest And Calibration, VIO Adapter, MAVLink And GCS Integration, FDR And Observability. - -### shared/config - -- **Epic**: AZ-208 -- **Directory**: `src/shared/config/` -- **Technologies**: Python configuration loader, environment variables, `.env.example`, startup readiness validation -- **Purpose**: Runtime profile loading, environment validation, typed settings, and startup readiness inputs. -- **Owned by**: runtime configuration task under AZ-208. -- **Consumed by**: all runtime components. - -### shared/errors - -- **Epic**: AZ-208 -- **Directory**: `src/shared/errors/` -- **Technologies**: Python exception/result envelope types, shared error categories, fail-fast helpers -- **Purpose**: Error categories, result envelopes, fail-fast helpers, and non-silent exception contracts. -- **Owned by**: runtime error contract task under AZ-208. -- **Consumed by**: all components. - -### shared/telemetry - -- **Epic**: AZ-208 -- **Directory**: `src/shared/telemetry/` -- **Technologies**: Python structured logging, metrics labels, health event DTOs, FDR-safe telemetry metadata -- **Purpose**: Structured logging, metrics labels, health event shapes, and FDR-safe event metadata helpers. -- **Owned by**: observability/config contract task under AZ-208. -- **Consumed by**: all components. - -## Allowed Dependencies (layering) - -Read top-to-bottom; an upper layer may import from a lower layer but never the reverse. - -| Layer | Components | May import from | -|-------|------------|-----------------| -| 4. Runtime Output / Coordination | Safety And Anchor Wrapper, MAVLink And GCS Integration, FDR And Observability | 1, 2, 3 public interfaces | -| 3. Perception / Satellite Anchor | VIO Adapter, Satellite Service, Anchor Verification | 1, 2 public interfaces | -| 2. Data Ingest / Persistence | Camera Ingest And Calibration, Tile Manager | 1 | -| 1. Shared / Foundation | shared/contracts, shared/geo_geometry, shared/time_sync, shared/config, shared/errors, shared/telemetry | none | - -Violations of this table are Architecture findings in code-review Phase 7 and are High severity. - -## Out-of-Product Blackbox / E2E Test Suite - -The blackbox/e2e replay/SITL/Jetson validation suite is not a product component and must not receive Step 6 product implementation tasks. It owns test-support artifacts under `tests/blackbox/**`, `e2e/replay/**`, `e2e/fixtures/**`, `e2e/mocks/**`, `docker-compose.test.yml`, and `deployment/docker/Dockerfile.replay`, and it exercises the runtime only through public file, MAVLink, cache, status, and FDR interfaces. - -- **Technologies**: Python, pytest-style runner, Docker/compose, deterministic fixture stubs, ArduPilot Plane SITL/QGC observer placeholders, CSV/Markdown reports -- **Entry points**: - - Local: `python3 -m pytest` - - Replay: `python -m e2e.replay.run_replay --output-dir --input-root ` - - Compose: `docker compose -f docker-compose.test.yml run --build --rm replay-consumer` - -## Self-Verification - -- Every runtime component under `_docs/02_document/components/` has a mapping entry. -- Cross-cutting epics AZ-206, AZ-207, and AZ-208 have shared ownership entries. -- Layering covers all components and keeps shared code at the bottom. -- Component-owned paths do not overlap; native bridge paths live inside the component that owns them. -- Paths follow the project `src/` layout already confirmed by `AZ-219_initial_structure`. diff --git a/_docs/02_document/ripple_log_cycle1.md b/_docs/02_document/ripple_log_cycle1.md deleted file mode 100644 index 929bba9..0000000 --- a/_docs/02_document/ripple_log_cycle1.md +++ /dev/null @@ -1,21 +0,0 @@ -# Ripple Log Cycle 1 - -## Scope - -Task-mode documentation refresh for Cycle 1 test implementation tasks `AZ-233` through `AZ-239`, Step 11 replay-gate fixes, and `AZ-243` native VIO runtime remediation. - -## Ripple Analysis - -- No product component module docs were refreshed because the changed implementation surface is the out-of-product blackbox/e2e replay harness under `tests/blackbox/**`, `e2e/replay/**`, `docker-compose.test.yml`, and `deployment/docker/Dockerfile.replay`. -- `_docs/02_document/module-layout.md` was refreshed because the out-of-product test-suite path list now includes actual implemented paths and entry points. -- `_docs/02_document/architecture.md` was refreshed because the validation harness responsibility now includes the implemented Docker replay smoke gate. -- `_docs/02_document/tests/environment.md` was refreshed because the replay harness entry points, output paths, and local-vs-Jetson gate behavior changed. -- `_docs/02_document/tests/*` and `_docs/02_document/tests/traceability-matrix.md` were refreshed during Step 12 to capture implementation-learned replay-smoke scenario IDs. -- `_docs/02_document/components/02_vio_adapter/description.md` was refreshed because `AZ-243` added production native runtime selection, explicit replay mode, and BASALT prerequisite errors. -- `_docs/02_document/contracts/shared/config_errors_telemetry.md` was refreshed because production VIO runtime mode is now a configuration/readiness invariant. -- `_docs/02_document/contracts/shared/runtime_contracts.md` was refreshed because `VioProcessingResult` is the public adapter result envelope consumed downstream. -- `_docs/02_document/architecture.md` was refreshed because environment-specific configuration now distinguishes explicit replay from production native VIO runtime. - -## Import-Graph Result - -No reverse-import product ripple outside VIO was found. The replay harness imports product runtime modules only from tests; product runtime modules do not import the replay harness. `AZ-243` changed VIO public exports, so only VIO component docs and shared public-contract docs were refreshed. diff --git a/_docs/02_document/risk_mitigations.md b/_docs/02_document/risk_mitigations.md deleted file mode 100644 index 08f89bc..0000000 --- a/_docs/02_document/risk_mitigations.md +++ /dev/null @@ -1,275 +0,0 @@ -# Risk Assessment — Architecture Review — Iteration 01 - -## Evaluator Pass Summary - -| Check | Result | Notes | -|-------|--------|-------| -| Single Responsibility | Pass | Components each own one primary concern: ingest, VIO, safety, Satellite Service sync/retrieval, verification, Tile Manager storage/generation, MAVLink, FDR, validation | -| Dumb Code / Smart Data | Pass | Complex behavior is mostly expressed through DTOs, mode labels, covariance fields, manifests, and gates | -| Interface Consistency | Pass with fix | Safety wrapper no longer directly depends on Tile Manager for anchor acceptance; cache freshness/provenance travels through `AnchorDecision` | -| Circular Dependencies | Pass with caution | Runtime flow is acyclic at component ownership level; MAVLink remains a bidirectional protocol adapter but owns no localization policy | -| Missing Interactions | Pass | Pre-VIO occlusion, IMU-only blackout, relocalization, tile writes, FDR, and SITL validation are all represented | -| Security Considerations | Pass | Signed cache sidecars, source/system ID checks, spoofing rejection, and no in-flight satellite-provider or Satellite Service access are covered | -| Performance Bottlenecks | Pass | Jetson latency, VPR/local matching, FDR append pressure, PostgreSQL availability, and thermal limits are identified | -| API Contracts | Pass | Core DTO handoffs are documented: `FramePacket`, `VioStatePacket`, `AnchorDecision`, `PositionEstimate`, `FdrEvent` | - -## Risk Scoring Matrix - -| | Low Impact | Medium Impact | High Impact | -|--|------------|---------------|-------------| -| **High Probability** | Medium | High | Critical | -| **Medium Probability** | Low | Medium | High | -| **Low Probability** | Low | Low | Medium | - -## Acceptance Criteria by Risk Level - -| Level | Action Required | -|-------|-----------------| -| Low | Accepted and monitored | -| Medium | Mitigation plan required before implementation | -| High | Mitigation + contingency plan required, reviewed during implementation | -| Critical | Must be resolved before proceeding to next planning step | - -## Risk Register - -| ID | Risk | Category | Probability | Impact | Score | Mitigation | Owner | Status | -|----|------|----------|-------------|--------|-------|------------|-------|--------| -| R01 | ADTi 20MP 20L V1 public specs conflict with planning assumptions for resolution, FPS, lens, interface, and temperature | Technical / External | Medium | High | High | Pin manufacturer datasheet and exact lens/interface before implementation; make camera calibration/spec task a bootstrap blocker | Camera ingest/calibration | Mitigated by gate | -| R02 | BASALT may underperform or lose tracking on nadir fixed-wing low-parallax terrain | Technical | Medium | High | High | Public replay with MUN-FRL/ALTO/Kagaru/EPFL where applicable, representative target replay, OpenVINS reference comparison, Kimera backup path | VIO adapter | Mitigated by validation | -| R03 | BASALT confidence/covariance may under-report real error | Safety | Medium | High | High | Wrapper owns covariance calibration; compare against ground truth, satellite residuals, and OpenVINS reference; never emit optimistic `horiz_accuracy` | Safety/anchor wrapper | Mitigated by wrapper design | -| R04 | Total occlusion detector may false-negative and feed unusable frames into VIO | Safety / Technical | Medium | High | High | Conservative pre-VIO occlusion gate, FDR status, tests for total blackout, and fallback to IMU-only `dead_reckoned` mode | Camera ingest/calibration | Mitigated by spec/test | -| R05 | IMU-only blackout propagation could be trusted too long | Safety | Medium | High | High | Monotonic covariance growth, `dead_reckoned` label, `fix_type=0`/`horiz_accuracy=999.0` when >30 s or covariance >500 m | Safety/anchor wrapper | Mitigated by AC gate | -| R06 | DINOv2-VLAD + ALIKED/DISK-LightGlue exceeds Jetson latency/memory budget | Performance | Medium | High | High | Trigger-only execution, CPU FAISS first, top-K caps, model profiling, TensorRT only after fidelity checks | Satellite Service / Anchor verification | Mitigated by profiling gates | -| R07 | PostgreSQL/PostGIS local DB is unavailable or too heavy for onboard runtime | Technical / Operational | Medium | High | High | Run local onboard PostgreSQL, health-check before flight, keep large payloads in files, fail mission cache validation if DB unavailable | Tile Manager / FDR | Mitigated by deployment gates | -| R08 | Generated tile cache poisoning corrupts future anchors | Security / Safety | Low | High | Medium | Sigma gate, provenance sidecars, post-flight Satellite Service voting, no direct promotion to trusted basemap | Tile Manager | Mitigated by policy | -| R09 | Public datasets do not cover final target terrain or commercial license needs | External / Schedule | Medium | Medium | Medium | Use public data for de-risking only; representative synchronized target data remains mandatory for acceptance | Validation harness | Mitigated by acceptance rule | -| R10 | MAVLink `GPS_INPUT` parameters or Plane behavior differs from assumptions | Integration | Medium | High | High | Plane SITL release gate with production parameters, spoofing/failsafe tests, raw field validation with pymavlink | MAVLink/GCS integration | Mitigated by SITL gate | -| R11 | FDR appends or PostgreSQL indexing interferes with hot-path latency | Performance | Medium | Medium | Medium | Append asynchronously, use CBOR payload segments for high-volume data, keep PostgreSQL as event index/query surface | FDR/observability | Mitigated by design | -| R12 | GPL/non-commercial tooling accidentally enters production or acceptance evidence | Legal / Compliance | Low | High | Medium | Keep OpenVINS/ORB-SLAM3 reference-only; license-tag datasets before CI; SuperPoint only after legal approval | Validation harness / Architecture | Mitigated by gates | - -## Detailed Risk Analysis - -### R01: Camera Specification Mismatch - -**Description**: Public ADTi pages show 5456 x 3632 stills, 2 fps continuous capture, Sony E mount, and -10..40 C operation. The project needs the exact production lens, camera interface, sustained capture behavior, thermal behavior, and calibration model. - -**Trigger conditions**: Manufacturer documentation or hardware testing contradicts assumed FPS, interface, temperature, or lens characteristics. - -**Affected components**: Camera ingest/calibration, VIO adapter, separate e2e test suite, deployment procedures. - -**Mitigation strategy**: -1. Make camera specification verification a bootstrap task. -2. Require manufacturer datasheet or hardware measurement before implementation claims 3 fps or hot-environment operation. -3. Version calibration data by exact camera/lens/interface. - -**Contingency plan**: Reduce frame rate assumptions, adjust latency tests, or select a different navigation camera/lens/interface. - -**Residual risk after mitigation**: Medium. - -**Documents updated**: `glossary.md`, `architecture.md`, `components/01_camera_ingest_calibration/description.md`, `deployment/deployment_procedures.md`. - ---- - -### R02: BASALT Nadir Fixed-Wing Fit - -**Description**: BASALT is a strong VIO candidate, but fixed downward cameras over planar terrain can cause low-parallax and texture-degeneracy cases. - -**Trigger conditions**: Public or representative replay shows high drift, frequent tracking loss, or poor initialization. - -**Affected components**: VIO adapter, safety/anchor wrapper, separate e2e test suite. - -**Mitigation strategy**: -1. Run MUN-FRL first for synchronized nadir camera + IMU + ground truth. -2. Add ALTO/Kagaru/EPFL slices where available for aerial/fixed-wing realism. -3. Compare against OpenVINS reference and Kimera backup. - -**Contingency plan**: Keep Kimera backup or build a project-owned fallback estimator around OpenCV + IMU only after replay evidence requires it. - -**Residual risk after mitigation**: Medium. - -**Documents updated**: `architecture.md`, `components/02_vio_adapter/description.md`, `tests/test-data.md`. - ---- - -### R03: Covariance Under-Reporting - -**Description**: Incorrect confidence is more dangerous than no estimate because the flight controller may trust a false fix. - -**Trigger conditions**: Replay error exceeds reported covariance, or anchors are accepted despite inconsistent residuals. - -**Affected components**: Safety/anchor wrapper, MAVLink/GCS integration, FDR/observability. - -**Mitigation strategy**: -1. Make wrapper covariance the product authority, not BASALT raw confidence. -2. Validate calibration against ground truth, satellite residuals, and OpenVINS reference. -3. Map `horiz_accuracy` so it never under-reports the 95% semi-major covariance axis. - -**Contingency plan**: Degrade to no-fix sooner and require operator relocalization or mission abort behavior. - -**Residual risk after mitigation**: Medium. - -**Documents updated**: `architecture.md`, `components/03_safety_anchor_wrapper/description.md`, `tests/blackbox-tests.md`. - ---- - -### R04: Total Occlusion Detection Failure - -**Description**: If total occlusion is not detected before VIO, BASALT may receive unusable frames and produce misleading state updates. - -**Trigger conditions**: Lens cover, cloud/whiteout, decode failure, underexposure/overexposure, or textureless frame reaches VIO as usable. - -**Affected components**: Camera ingest/calibration, safety/anchor wrapper, VIO adapter. - -**Mitigation strategy**: -1. Camera ingest exposes `OcclusionReport` and sets `usable_for_vio=false` for total occlusion/blackout. -2. Total occlusion bypasses BASALT for that frame. -3. Safety wrapper switches to IMU-only `dead_reckoned` propagation with monotonic covariance growth. - -**Contingency plan**: Tune detector conservatively and accept temporary false-positive IMU-only degradation over false VIO confidence. - -**Residual risk after mitigation**: Medium. - -**Documents updated**: `components/01_camera_ingest_calibration/description.md`, `components/03_safety_anchor_wrapper/description.md`, `system-flows.md`, `diagrams/flows/flow_normal_localization.md`, `tests/resilience-tests.md`. - ---- - -### R05: IMU-Only Mode Over-Trust - -**Description**: IMU-only propagation drifts quickly and must be treated as an emergency bridge, not a long-duration solution. - -**Trigger conditions**: Blackout lasts longer than 30 seconds or covariance exceeds 500 m. - -**Affected components**: Safety/anchor wrapper, MAVLink/GCS integration, FDR/observability. - -**Mitigation strategy**: -1. Emit `source_label=dead_reckoned` during IMU-only mode. -2. Grow covariance monotonically. -3. Emit `fix_type=0`, `horiz_accuracy=999.0`, and `VISUAL_BLACKOUT_FAILSAFE` at thresholds. - -**Contingency plan**: Stop publishing valid fixes and require relocalization/operator action. - -**Residual risk after mitigation**: Low. - -**Documents updated**: `components/03_safety_anchor_wrapper/description.md`, `system-flows.md`, `tests/blackbox-tests.md`, `tests/resilience-tests.md`, `tests/traceability-matrix.md`. - ---- - -### R06: Trigger Path Performance - -**Description**: DINOv2-VLAD and learned local matching can exceed Jetson latency/memory limits. - -**Trigger conditions**: Relocalization exceeds p95 latency, memory budget, or causes thermal throttling. - -**Affected components**: Satellite Service, anchor verification, separate e2e test suite. - -**Mitigation strategy**: -1. Keep VPR/local matching trigger-based. -2. Use CPU FAISS first and bounded top-K. -3. Accept optimized engines only after descriptor-fidelity tests pass. - -**Contingency plan**: Reduce descriptor resolution/model size, reduce top-K, or fall back to classical features for emergency operation. - -**Residual risk after mitigation**: Medium. - -**Documents updated**: `architecture.md`, `components/04_satellite_retrieval/description.md`, `components/05_anchor_verification/description.md`, `tests/performance-tests.md`. - ---- - -### R07: Onboard PostgreSQL/PostGIS Availability - -**Description**: PostgreSQL/PostGIS is now the structured metadata store. If local DB availability or resource use is poor, cache/FDR queries may fail. - -**Trigger conditions**: Local DB does not start, DB files corrupt, DB consumes too much memory/I/O, or migrations fail. - -**Affected components**: Tile Manager, FDR/observability, deployment procedures. - -**Mitigation strategy**: -1. Require local onboard PostgreSQL health check before flight. -2. Store large imagery/descriptors/CBOR payloads as files, not DB blobs. -3. Treat DB unavailability as a mission-cache validation blocker. - -**Contingency plan**: Abort mission-cache activation and run only no-cache degraded modes or resync/rebuild DB before flight. - -**Residual risk after mitigation**: Medium. - -**Documents updated**: `data_model.md`, `architecture.md`, `components/06_cache_tile_lifecycle/description.md`, `components/08_fdr_observability/description.md`, `deployment/environment_strategy.md`. - ---- - -### R08: Cache Poisoning - -**Description**: A bad generated tile could be written back and later used as a trusted anchor. - -**Trigger conditions**: Generated tile is promoted despite high parent covariance, stale source, bad sidecar, or inconsistent overlap voting. - -**Affected components**: Tile Manager, safety/anchor wrapper, Satellite Service integration. - -**Mitigation strategy**: -1. Require tile-write sigma gates. -2. Store generated tiles as candidates with signed sidecars. -3. Promote only through post-flight Satellite Service validation/voting. - -**Contingency plan**: Quarantine generated tiles and invalidate affected cache regions. - -**Residual risk after mitigation**: Low. - -**Documents updated**: `architecture.md`, `components/06_cache_tile_lifecycle/description.md`, `tests/security-tests.md`. - ---- - -### R09: Dataset Coverage / Licensing - -**Description**: Public datasets may not match target terrain, may lack raw synchronized IMU, or may have non-commercial restrictions. - -**Trigger conditions**: MUN-FRL/ALTO/Kagaru/EPFL slices are unavailable, unrepresentative, or license-incompatible for acceptance. - -**Affected components**: Validation harness, VIO adapter, anchor verification. - -**Mitigation strategy**: -1. Use public datasets for de-risking only. -2. License-tag datasets before CI jobs. -3. Require representative synchronized target data for final acceptance. - -**Contingency plan**: Collect a target replay dataset before final acceptance. - -**Residual risk after mitigation**: Medium. - -**Documents updated**: `tests/test-data.md`, `deployment/environment_strategy.md`, `deployment/ci_cd_pipeline.md`. - ---- - -### R10: Plane `GPS_INPUT` Integration - -**Description**: ArduPilot Plane EKF and `GPS_INPUT` handling may differ from assumptions, especially around accuracy fields, ignore flags, velocity fields, and spoofing transitions. - -**Trigger conditions**: Plane SITL rejects or mishandles emitted `GPS_INPUT`, or QGC status is insufficient. - -**Affected components**: MAVLink/GCS integration, safety/anchor wrapper, separate e2e test suite. - -**Mitigation strategy**: -1. Use pymavlink for exact `GPS_INPUT` field control. -2. Gate release on Plane SITL with production parameters. -3. Validate spoofing/failsafe and QGC status behavior. - -**Contingency plan**: Adjust parameter guidance/output fields before hardware deployment. - -**Residual risk after mitigation**: Medium. - -**Documents updated**: `components/07_mavlink_gcs_integration/description.md`, `tests/environment.md`, `deployment/ci_cd_pipeline.md`. - -## Architecture/Component Changes Applied - -| Risk ID | Document Modified | Change Description | -|---------|-------------------|--------------------| -| R04 | `components/01_camera_ingest_calibration/description.md` | Added explicit `detect_occlusion`, `OcclusionReport`, and pre-VIO bypass behavior | -| R04/R05 | `components/03_safety_anchor_wrapper/description.md` | Added `propagate_imu_only`, `total_occlusion`, monotonic covariance behavior, and no direct Tile Manager dependency | -| R07 | `data_model.md` | Replaced embedded DB references with PostgreSQL/PostGIS structured metadata and CBOR FDR payload segments | -| R07 | `architecture.md` | Added PostgreSQL/PostGIS ADR and FDR storage decision | -| R05 | `tests/blackbox-tests.md` / `tests/resilience-tests.md` | Made total occlusion and IMU-only blackout behavior explicit | - -## Summary - -**Total risks identified**: 12 -**Critical**: 0 | **High**: 7 | **Medium**: 5 | **Low**: 0 -**Risks mitigated this iteration**: 12 -**Risks requiring user decision**: None immediately. Future decisions are tied to exact camera hardware proof, dataset license approval, and representative data collection timing. diff --git a/_docs/02_document/system-flows.md b/_docs/02_document/system-flows.md deleted file mode 100644 index c401ae1..0000000 --- a/_docs/02_document/system-flows.md +++ /dev/null @@ -1,321 +0,0 @@ -# GPS-Denied Onboard Localization — System Flows - -## Flow Inventory - -| # | Flow Name | Trigger | Primary Components | Criticality | -|---|-----------|---------|--------------------|-------------| -| F1 | Pre-flight cache preparation | Operator sync before mission | Satellite Service, Tile Manager | High | -| F2 | Normal frame processing | Navigation frame + FC telemetry | Camera ingest, VIO adapter, safety/anchor wrapper, MAVLink, FDR | High | -| F3 | Satellite relocalization | Cold start, VO failure, sharp turn, covariance growth, stale anchor | Satellite Service, anchor verification, safety/anchor wrapper | High | -| F4 | Visual blackout / spoofing degraded mode | Image-quality failure and GPS health failure | Camera ingest, MAVLink telemetry, safety/anchor wrapper, QGC, FDR | Critical | -| F5 | Generated tile lifecycle | High-confidence pose + usable frame | Camera ingest, safety/anchor wrapper, Tile Manager, FDR | Medium | -| F6 | Post-flight sync and audit | Landing / operator offload | Tile Manager, Satellite Service, FDR | Medium | -| F7 | E2E validation replay | Test-suite invocation | Separate e2e test suite, system runtime, public datasets, SITL | High | - -## Flow Dependencies - -| Flow | Depends On | Shares Data With | -|------|------------|------------------| -| F1 | Satellite Service cache export and Tile Manager validation | F2, F3, F5 | -| F2 | F1 for cache availability; FC telemetry | F3, F4, F5, FDR | -| F3 | F1 cache/index; F2 state estimate | F2, F5 | -| F4 | F2 telemetry and quality signals | F2, QGC/FDR | -| F5 | Accepted state/covariance from F2/F3 | F6 | -| F6 | F5 generated tiles and FDR | Satellite Service | -| F7 | Test fixtures and selected execution environment | All flows | - ---- - -## Flow F1: Pre-Flight Cache Preparation - -### Description - -Before flight, the Satellite Service imports an offline cache package for the operational area, including COG tiles, manifests, sidecars, VPR chunks, descriptors, and FAISS index files. No Satellite Service or satellite-provider calls are allowed during flight. - -### Preconditions - -- Operational area and sector freshness classification are known. -- Cache imagery meets 0.5 m/px minimum and ideally 0.3 m/px. -- Cache package fits storage budget or has approved split descriptor budget. - -### Sequence Diagram - -```mermaid -sequenceDiagram - participant Operator - participant SatelliteService - participant TileManager - - Operator->>SatelliteService: Request mission cache - SatelliteService-->>TileManager: COG tiles + manifests + sidecars - TileManager->>TileManager: Verify signatures, hashes, freshness, resolution - TileManager-->>SatelliteService: Local cache/index ready - TileManager-->>Operator: Cache validation report -``` - -### Data Flow - -| Step | From | To | Data | Format | -|------|------|----|------|--------| -| 1 | Satellite Service | Tile Manager | Tiles and metadata | COG + PostgreSQL/PostGIS manifest + signed JSON sidecars | -| 2 | Tile Manager | Satellite Service | Descriptor/index readiness | FAISS index + descriptor sidecars | -| 3 | Tile Manager | Operator/FDR | Validation report | Markdown/CSV/log | - -### Error Scenarios - -| Error | Where | Detection | Recovery | -|-------|-------|-----------|----------| -| Stale tile | Cache validation | Capture date exceeds sector threshold | Reject/down-confidence tile | -| Hash mismatch | Cache validation | Sidecar hash mismatch | Reject tile and report security event | -| Cache too large | Cache load | Storage accounting > budget | Require cache rebuild or approved split budget | - -### Performance Expectations - -| Metric | Target | Notes | -|--------|--------|-------| -| Runtime network calls | 0 | No in-flight Satellite Service or provider calls | -| Cache load | Within cold-start budget contribution | Exact threshold set during implementation | - ---- - -## Flow F2: Normal Frame Processing - -### Description - -During normal flight, the system processes each navigation frame and FC telemetry sample. The camera component first checks for total occlusion/blackout. Usable frames go to the VIO adapter; total-occlusion frames bypass VIO and send the wrapper into IMU-only degraded propagation. - -### Preconditions - -- Camera calibration/extrinsics are loaded. -- VIO adapter and wrapper are initialized. -- FC telemetry stream is healthy. - -### Sequence Diagram - -```mermaid -sequenceDiagram - participant CameraIngest - participant FCTelemetry - participant BasaltAdapter - participant SafetyWrapper - participant MavlinkOutput - participant FDR - - CameraIngest->>CameraIngest: Total occlusion / blackout check - CameraIngest->>BasaltAdapter: Usable frame + timestamp + calibration - CameraIngest-->>SafetyWrapper: Degradation signal if total occlusion - FCTelemetry->>BasaltAdapter: IMU/attitude/altitude - BasaltAdapter-->>SafetyWrapper: Relative VIO state + quality - SafetyWrapper->>SafetyWrapper: Calibrate covariance + source label - SafetyWrapper-->>MavlinkOutput: GPS_INPUT estimate - SafetyWrapper-->>FDR: Estimate + inputs + health -``` - -### Data Flow - -| Step | From | To | Data | Format | -|------|------|----|------|--------| -| 1 | Camera ingest | VIO adapter or safety wrapper | Frame metadata, image, occlusion status | Frame DTO / DegradationSignal | -| 2 | FC telemetry | VIO adapter | IMU/attitude/altitude | MAVLink-derived telemetry DTO | -| 3 | VIO adapter | Safety wrapper | Relative VIO state | VioState DTO | -| 4 | Safety wrapper | MAVLink output | WGS84 estimate | `GPS_INPUT` | -| 5 | Safety wrapper | FDR | Inputs/outputs/audit | FDR segment event | - -### Error Scenarios - -| Error | Where | Detection | Recovery | -|-------|-------|-----------|----------| -| Total occlusion / blackout | Camera ingest | Occlusion status, exposure/texture/decode checks | Bypass VIO, enter IMU-only `dead_reckoned` propagation | -| Frame unreadable | Camera ingest | Decode/quality failure | Mark visual signal degraded and bypass VIO for that frame | -| VIO quality low | VIO adapter | Tracking/completion metrics | Trigger relocalization or dead reckoning | -| Covariance grows | Safety wrapper | Covariance threshold | Degrade fix type/source label | - -### Performance Expectations - -| Metric | Target | Notes | -|--------|--------|-------| -| End-to-end latency | <400 ms p95 | Frame input to emitted estimate | -| Dropped frames | <=10% sustained | Under load | -| Memory | <8 GB shared | Jetson limit | - ---- - -## Flow F3: Satellite Relocalization - -### Description - -When the state becomes uncertain or disconnected, the system retrieves satellite/cache candidates and accepts an anchor only after local verification and safety gates pass. - -### Preconditions - -- Offline VPR chunks and FAISS index are loaded. -- Trigger condition is met: cold start, VO failure, sharp turn, disconnected segment, covariance growth, or stale anchor. - -### Sequence Diagram - -```mermaid -sequenceDiagram - participant SafetyWrapper - participant SatelliteService - participant AnchorVerification - participant TileManager - participant FDR - - SafetyWrapper->>SatelliteService: Relocalization request - SatelliteService->>TileManager: Read candidate chunk metadata - SatelliteService-->>AnchorVerification: Top-K candidates - AnchorVerification->>AnchorVerification: ALIKED/DISK+LightGlue + RANSAC - AnchorVerification-->>SafetyWrapper: Accepted/rejected anchor - SafetyWrapper->>SafetyWrapper: Mahalanobis + freshness + provenance gates - SafetyWrapper-->>FDR: Anchor decision audit -``` - -### Data Flow - -| Step | From | To | Data | Format | -|------|------|----|------|--------| -| 1 | Safety wrapper | Satellite Service | Query frame and prior/covariance | Relocalization DTO | -| 2 | Satellite Service | Anchor verification | Top-K chunks from local cache/index | Candidate list | -| 3 | Anchor verification | Safety wrapper | MRE, inliers, homography, provenance | AnchorDecision DTO | - -### Error Scenarios - -| Error | Where | Detection | Recovery | -|-------|-------|-----------|----------| -| No good candidate | Retrieval/verification | Low score or failed RANSAC | Continue degraded and request GCS hint after threshold | -| Stale candidate | Tile Manager | Capture date gate | Reject/down-confidence | -| Implausible anchor | Safety wrapper | Mahalanobis/impossible velocity gate | Reject and log | - -### Performance Expectations - -| Metric | Target | Notes | -|--------|--------|-------| -| Invocation frequency | Trigger-based only | Not per-frame | -| Cross-domain MRE | <2.5 px for accepted anchors | AC-2.2 | - ---- - -## Flow F4: Visual Blackout / Spoofing Degraded Mode - -### Description - -When visual localization is unavailable due to total occlusion/blackout and GPS is denied/spoofed, the wrapper switches to honest IMU-only propagation from the last trusted state and degrades MAVLink output based on covariance/time thresholds. - -### Preconditions - -- Last trusted state exists. -- FC telemetry continues. - -### Sequence Diagram - -```mermaid -sequenceDiagram - participant CameraIngest - participant FCTelemetry - participant SafetyWrapper - participant MavlinkOutput - participant QGC - participant FDR - - CameraIngest-->>SafetyWrapper: Total occlusion / visual blackout signal - FCTelemetry-->>SafetyWrapper: GPS health/spoofing signal - SafetyWrapper->>SafetyWrapper: IMU-only propagation + monotonic covariance growth - SafetyWrapper->>SafetyWrapper: Switch source_label to dead_reckoned - SafetyWrapper-->>MavlinkOutput: Degraded GPS_INPUT - SafetyWrapper-->>QGC: VISUAL_BLACKOUT_IMU_ONLY / FAILSAFE - SafetyWrapper-->>FDR: Blackout and spoofing audit events -``` - -### Error Scenarios - -| Error | Where | Detection | Recovery | -|-------|-------|-----------|----------| -| Blackout >30 s | Safety wrapper | Timer threshold | Emit no-fix/failsafe | -| Covariance >500 m | Safety wrapper | Covariance threshold | `fix_type=0`, `horiz_accuracy=999.0` | -| Spoofed GPS recovers | Safety wrapper | FC health + visual consistency gate | Re-enable only after required stable interval and visual/satellite consistency | - -### Performance Expectations - -| Metric | Target | Notes | -|--------|--------|-------| -| Mode transition | <=1 processed frame or <=400 ms | AC-3.5 | -| QGC status | 1-2 Hz | Downsampled operator awareness | - ---- - -## Flow F5: Generated Tile Lifecycle - -### Description - -When pose confidence is strong enough, the system orthorectifies navigation imagery into write-new generated tiles and records quality/provenance sidecars. - -### Preconditions - -- Parent pose covariance passes tile-write gate. -- Frame quality supports orthorectification. - -### Data Flow - -| Step | From | To | Data | Format | -|------|------|----|------|--------| -| 1 | Safety wrapper | Tile Manager | Pose/covariance + frame metadata | TileGenerationRequest | -| 2 | Tile Manager | Local storage | Orthorectified generated COG + sidecar | COG + signed JSON | -| 3 | Tile Manager | FDR | Tile write event | FDR event | - -### Error Scenarios - -| Error | Where | Detection | Recovery | -|-------|-------|-----------|----------| -| Parent covariance too high | Safety wrapper | Sigma gate | Do not write tile | -| Duplicate sector | Tile Manager | Spatial deduplication | Keep latest/highest-quality tile | -| Sidecar write failure | Tile Manager | I/O error | Log and do not mark tile eligible | - ---- - -## Flow F6: Post-Flight Sync And Audit - -### Description - -After landing, generated tiles and FDR evidence are exported through Satellite Service sync for ingest and incident analysis. - -### Data Flow - -| Step | From | To | Data | Format | -|------|------|----|------|--------| -| 1 | Tile Manager | Satellite Service | Generated tile package | COG + sidecar + manifest delta | -| 2 | FDR | Operator/audit tools | Mission replay evidence | Segmented logs + optional Parquet export | - -### Error Scenarios - -| Error | Where | Detection | Recovery | -|-------|-------|-----------|----------| -| Upload unavailable | Post-flight sync | Network/service failure | Retain package for retry | -| Candidate rejected by Service voting | Satellite Service | Ingest rules | Keep as candidate/soft trust, not trusted basemap | - ---- - -## Flow F7: Validation Replay - -### Description - -The separate e2e test suite runs deterministic still-image, public dataset, SITL, Jetson, and representative replay scenarios against public interfaces. - -### Preconditions - -- Test data and expected results are pinned. -- Execution mode is selected: Docker/replay and local Jetson hardware. - -### Data Flow - -| Step | From | To | Data | Format | -|------|------|----|------|--------| -| 1 | E2E test suite | Runtime | Images/telemetry/cache fixtures | File/stream/MAVLink | -| 2 | Runtime | E2E test suite | GPS_INPUT/FDR/status | MAVLink/log files | -| 3 | E2E test suite | Reports | Pass/fail metrics | CSV/Markdown | - -### Performance Expectations - -| Metric | Target | Notes | -|--------|--------|-------| -| PR smoke | <=15 min | Still-image/cache/SITL subset | -| Release gate | Hardware-dependent | Jetson and representative replay required | diff --git a/_docs/02_document/tests/blackbox-tests.md b/_docs/02_document/tests/blackbox-tests.md deleted file mode 100644 index 69ba37a..0000000 --- a/_docs/02_document/tests/blackbox-tests.md +++ /dev/null @@ -1,176 +0,0 @@ -# Blackbox Tests - -## Positive Scenarios - -### FT-P-01: Still-Image Frame Center Geolocation - -**Summary**: Validate that the system estimates WGS84 frame centers for the provided 60-image nadir dataset. - -**Traces to**: AC-1.1, AC-1.2, AC-6.3, AC-8.1 - -**Category**: Position Accuracy - -**Preconditions**: -- Offline satellite cache fixture is available for the sample area. -- Expected results are loaded from `input_data/expected_results/results_report.md`. - -**Input data**: `project_60_still_images`, `expected_frame_centers` - -| Step | Consumer Action | Expected System Response | -|------|-----------------|--------------------------| -| 1 | Submit `AD000001.jpg` through `AD000060.jpg` with height/camera metadata | System emits one WGS84 estimate per processed image | -| 2 | Compare each estimate to the mapped expected coordinate | Per-frame error is reported in meters | - -**Expected outcome**: At least 80% of images are within 50 m and at least 50% are within 20 m. - -**Max execution time**: 15 minutes for the 60-image replay on the local replay environment. - ---- - -### FT-P-02: Position Confidence Output Contract - -**Summary**: Validate that every emitted position estimate includes confidence and source-label fields required by the public contract. - -**Traces to**: AC-1.3, AC-1.4, AC-4.4, AC-4.5 - -**Category**: Position Confidence - -**Preconditions**: -- Same fixture setup as FT-P-01. - -**Input data**: `project_60_still_images`, `expected_frame_centers` - -| Step | Consumer Action | Expected System Response | -|------|-----------------|--------------------------| -| 1 | Submit the 60-image replay | System emits estimates frame-by-frame, not batched | -| 2 | Inspect public output fields | Each estimate contains WGS84 coordinate, 95% covariance semi-major axis, source label, and `last_satellite_anchor_age_ms` | -| 3 | Submit a later correction for a prior frame if available | System emits updated estimate with timestamp and covariance without corrupting newer estimates | - -**Expected outcome**: 100% of emitted estimates include required confidence fields; no `horiz_accuracy` equivalent under-reports the 95% covariance semi-major axis. - -**Max execution time**: 15 minutes. - ---- - -### FT-P-03: BASALT VIO Replay With Synchronized Video/Telemetry - -**Summary**: Validate that BASALT + safety/anchor wrapper can process synchronized nadir video, IMU, and trajectory telemetry and produce frame-by-frame estimates with honest confidence. - -**Traces to**: AC-1.3, AC-2.1a, AC-2.2, AC-4.1, AC-4.2 - -**Category**: VO / IMU Propagation - -**Preconditions**: -- Derkachi replay fixture is mounted from `input_data/flight_derkachi/`. -- `flight_derkachi.mp4` is readable as cropped nadir video: 880 x 720, 30 fps, approximately 490.07 s. -- `data_imu.csv` contains monotonic 10 Hz `Time`, `timestamp(ms)`, `SCALED_IMU2.*`, and `GLOBAL_POSITION_INT.*` fields for 4,900 rows. -- Production or Jetson VIO profile is configured for native mode; replay mode is allowed only for explicit development replay checks. -- Camera intrinsics, lens distortion, and camera-to-body transform are either pinned or the run is marked as calibration-limited. -- Public synchronized dataset slice remains useful for calibrated final comparison. Strongest candidates: MUN-FRL, ALTO, EPFL fixed-wing, Kagaru; EuRoC/UZH FPV are proxy-only. - -**Input data**: `derkachi_video_telemetry`, `public_nadir_vio_candidates` - -| Step | Consumer Action | Expected System Response | -|------|-----------------|--------------------------| -| 1 | Validate Derkachi video/telemetry alignment | Harness accepts the fixture only if MP4 duration and CSV duration differ by <=250 ms and there are exactly 3 video frames per telemetry row | -| 2 | Replay synchronized video frames and IMU stream | System emits frame-by-frame `vo_extrapolated` or `satellite_anchored` estimates without batching | -| 3 | Compare output trajectory to `GLOBAL_POSITION_INT` lat/lon/alt/heading | Error, covariance, source label, and anchor age are reported per segment | -| 4 | Compare calibrated public/representative replay against ground truth when available | BASALT + wrapper does not materially under-report uncertainty relative to error | -| 5 | Compare against OpenVINS reference replay when available | BASALT + wrapper does not materially under-report uncertainty relative to error | -| 6 | Start with production VIO profile when the BASALT-compatible runtime is not installed | System reports an explicit native runtime prerequisite error and emits no replay-derived successful VIO state | -| 7 | Start with explicit development replay profile | Replay VIO behavior is available only through the explicit replay profile and cannot satisfy production native-mode checks | - -**Expected outcome**: Derkachi replay is accepted as a synchronized representative fixture and produces continuous estimates for >95% of normal overlapping frames when native prerequisites are available. Missing native runtime prerequisites block production VIO with an explicit error rather than replay success. Absolute geolocation and covariance pass/fail thresholds are calibration-gated until camera intrinsics, distortion, and camera-to-body transform are pinned. For calibrated datasets, VO homography MRE is <1.0 px where homography validation is applicable. - -**Max execution time**: Dataset-dependent, but replay must report per-frame latency. - ---- - -### FT-P-04: Satellite Service And Anchor Verification - -**Summary**: Validate that relocalization uses global retrieval plus local verification and emits only verified satellite anchors. - -**Traces to**: AC-2.1b, AC-2.2, AC-3.2, AC-3.3, AC-8.6 - -**Category**: Satellite Anchor - -**Preconditions**: -- AerialVL/ALTO/VPAir-style public dataset slice or project satellite-cache fixture is available. -- VPR chunks and descriptors are precomputed. - -**Input data**: Public aerial localization slice, cache fixture - -| Step | Consumer Action | Expected System Response | -|------|-----------------|--------------------------| -| 1 | Trigger cold-start or relocalization query | System searches CPU FAISS top-K chunks | -| 2 | Present top-K candidates to local verification | System runs ALIKED/DISK+LightGlue and RANSAC | -| 3 | Inspect emitted anchor decision | Accepted anchors include source label, MRE, inlier count, covariance, and tile provenance | - -**Expected outcome**: Cross-domain satellite-anchor MRE is <2.5 px for accepted anchors; rejected candidates do not produce `satellite_anchored` estimates. - -**Max execution time**: Must be measured as part of performance tests. - -## Negative Scenarios - -### FT-N-01: Repetitive Or Low-Texture Imagery - -**Summary**: Validate that visually ambiguous images do not produce confident false satellite anchors. - -**Traces to**: AC-1.4, AC-3.1, AC-NEW-4, AC-8.6 - -**Category**: False Position Prevention - -**Input data**: Repetitive agricultural or low-texture frames from project/public data. - -| Step | Consumer Action | Expected System Response | -|------|-----------------|--------------------------| -| 1 | Submit ambiguous frame or sequence | System either emits degraded `vo_extrapolated`/`dead_reckoned` output or rejects low-confidence anchor | -| 2 | Inspect anchor and confidence outputs | No anchor is accepted unless local verification and covariance gates pass | - -**Expected outcome**: 0 confident `satellite_anchored` outputs for candidates that fail local verification, freshness, or Mahalanobis gates. - -**Max execution time**: 15 minutes per fixture. - ---- - -### FT-N-02: GPS Spoofing During Total Visual Blackout - -**Summary**: Validate that spoofed GPS is not promoted during total camera occlusion/visual blackout and that output degrades honestly before unusable frames reach VIO. - -**Traces to**: AC-3.5, AC-5.2, AC-NEW-2, AC-NEW-8 - -**Category**: Spoofing / Blackout - -**Input data**: ArduPilot Plane SITL spoofing trace with camera blackout/total-occlusion frames. - -| Step | Consumer Action | Expected System Response | -|------|-----------------|--------------------------| -| 1 | Start normal replay with trusted visual/satellite anchor | System emits normal estimates | -| 2 | Inject full visual blackout/total occlusion and spoofed `GPS_RAW_INT` | Camera gate sets `usable_for_vio=false`, BASALT is bypassed for occluded frames, and system switches to `dead_reckoned` within <=1 processed frame or <=400 ms | -| 3 | Continue blackout beyond thresholds | IMU-only covariance grows monotonically; system degrades fix type and emits failsafe status at specified covariance/time thresholds | - -**Expected outcome**: Spoofed GPS is ignored; total occlusion never feeds BASALT as a usable VIO frame; `fix_type=0`, `horiz_accuracy=999.0`, and `VISUAL_BLACKOUT_FAILSAFE` are emitted when covariance >500 m or blackout >30 s. - -**Max execution time**: 10 minutes per SITL scenario. - ---- - -### FT-N-03: Invalid Or Stale Satellite Cache - -**Summary**: Validate cache freshness, integrity, and provenance gates. - -**Traces to**: AC-8.2, AC-8.3, AC-NEW-6, AC-NEW-7 - -**Category**: Cache Integrity - -**Input data**: `cache_integrity_fixtures` - -| Step | Consumer Action | Expected System Response | -|------|-----------------|--------------------------| -| 1 | Replay with stale tile manifest | Tile is rejected or down-confidence weighted; no stale tile emits `satellite_anchored` | -| 2 | Replay with hash-mismatched or unsigned manifest | Cache fixture is rejected and security event is logged | -| 3 | Replay generated tile with weak parent-pose covariance | Tile is not promoted beyond allowed trust level | - -**Expected outcome**: 0 invalid/stale/cache-poisoning fixtures produce trusted anchors or trusted basemap tiles. - -**Max execution time**: 15 minutes. diff --git a/_docs/02_document/tests/e2e-test-suite.md b/_docs/02_document/tests/e2e-test-suite.md deleted file mode 100644 index fe56298..0000000 --- a/_docs/02_document/tests/e2e-test-suite.md +++ /dev/null @@ -1,81 +0,0 @@ -# E2E Test Suite - -## Scope - -The e2e test suite is separate test tooling, not part of the onboard runtime. It drives black-box replay, public dataset, SITL, Jetson, and representative validation through public runtime interfaces only. - -## Purpose - -- Feed navigation frames, telemetry traces, cache manifests, and fault triggers into the system under test. -- Validate emitted coordinates, confidence fields, MAVLink `GPS_INPUT`, QGC status, FDR, and generated-tile evidence. -- Produce release evidence without importing runtime internals. - -## Ownership - -- **Epic**: AZ-217 (E2E Test Suite / test-support work, not product runtime) -- **Owns**: - - `tests/blackbox/**` - - `tests/e2e/**` - - `e2e/replay/**` - - `e2e/reports/**` -- **Does not own**: - - `src/**` - - runtime component internals - - production deployment code - -## Public Interfaces Under Test - -| Interface | Protocol / Contract | -|-----------|---------------------| -| Navigation frames | Ordered image/video replay with timestamps | -| FC telemetry | MAVLink replay or generated stream | -| Satellite cache | Local COG + manifest + descriptor fixtures | -| GPS output | MAVLink `GPS_INPUT` | -| Operator status | QGC-visible MAVLink status | -| FDR | Filesystem/database-backed evidence outputs | - -## Runner Contract - -| Method | Input | Output | Error Types | -|--------|-------|--------|-------------| -| `run_scenario` | `ScenarioRequest` | `ScenarioReport` | `FixtureInvalid`, `RuntimeFailed`, `ThresholdFailed` | -| `validate_fixture` | `FixtureRequest` | `FixtureValidationReport` | `FixtureInvalid` | - -```yaml -ScenarioRequest: - scenario_id: string - execution_environment: enum(replay, sitl, jetson, representative) - fixture_paths: list[string] - -ScenarioReport: - scenario_id: string - result: enum(pass, fail, blocked) - metrics: object - artifacts: list[path] - failure_reason: string optional -``` - -## Scenario Coverage - -| Scenario | Purpose | Evidence | -|----------|---------|----------| -| Still-image accuracy runner | Verify project still-image replay reports frame-center accuracy | Per-image error, aggregate pass rates, covariance, source label, anchor age | -| Synchronized VIO replay runner | Verify Derkachi and public/representative synchronized data drive BASALT/wrapper tests | Fixture alignment, trajectory comparison, VIO registration, latency, covariance calibration | -| Satellite anchor replay runner | Verify VPR and anchor verification scenarios are executable | Retrieval recall, MRE, accepted/rejected anchors, freshness behavior | -| Outlier/sharp-turn/disconnected runner | Verify relocalization resilience scenarios are executable | Degraded-mode timelines and relocalization outcomes | -| Blackout and spoofing runner | Verify total blackout plus spoofing through SITL/replay | Mode-switch timing, covariance growth, failsafe thresholds | -| MAVLink/QGC contract runner | Verify MAVLink output and GCS status assertions | `GPS_INPUT`, WGS84 coordinates, status rate, command ingress | -| Startup/reboot runner | Verify cold-start and companion reboot scenarios | First valid `GPS_INPUT` p95 and FC-state reinitialization | -| Object coordinate contract runner | Verify AI-camera object coordinate request at system boundary | Frame-center-consistent coordinate accuracy and projection bound | -| Tile Manager runner | Verify cache, generated tiles, and storage tests | Cache load, tile write gates, no raw-frame retention, stale rejection, poisoning evidence | - -## Release Evidence - -The suite assembles CSV, Markdown, MAVLink tlogs, FDR summaries, cache validation reports, and pass/fail metadata into release evidence bundles. Missing public or representative data is reported as `blocked`, not `passed`. - -## Non-Responsibilities - -- No onboard flight logic. -- No direct estimator, BASALT, wrapper, or tile-manager imports. -- No mutation of runtime internal state. -- No production service APIs. diff --git a/_docs/02_document/tests/environment.md b/_docs/02_document/tests/environment.md deleted file mode 100644 index d944808..0000000 --- a/_docs/02_document/tests/environment.md +++ /dev/null @@ -1,130 +0,0 @@ -# Test Environment - -## Overview - -**System under test**: Onboard GPS-denied localization service. Public interfaces are navigation-camera frame input, flight-controller telemetry input, offline satellite-cache input, `GPS_INPUT` MAVLink output, QGroundControl status output, and flight-data-recorder output. - -**Consumer app purpose**: A black-box replay harness that feeds image frames, telemetry traces, cache manifests, and fault triggers into the service, then validates emitted coordinates, confidence fields, telemetry, and logs without importing internal modules. - -## Execution Environments - -| Environment | Purpose | Required for | -|-------------|---------|--------------| -| Local replay workstation | Fast still-image and dataset replay validation | Frame-center geolocation, Satellite Service local retrieval, stale-tile rejection | -| Jetson Orin Nano Super | Production-like latency, memory, thermal, and TensorRT/ONNX profiling | AC-4.1, AC-4.2, AC-NEW-1, AC-NEW-5 | -| ArduPilot Plane SITL + QGroundControl | MAVLink `GPS_INPUT`, spoofing, failsafe, and GCS status validation | AC-4.3, AC-5.2, AC-NEW-2, AC-NEW-8 | -| Representative flight/replay rig | Final acceptance evidence with synchronized nav camera, FC IMU/attitude/airspeed/altitude, MAVLink logs, and ground truth | Final AC signoff | - -## Docker / Compose Structure - -| Service | Image / Build | Purpose | Ports | -|---------|---------------|---------|-------| -| gps-denied-service | Project build image for JetPack-compatible target or replay-compatible host | System under test | MAVLink UDP/TCP and health/status endpoints TBD | -| replay-consumer | Python replay/test harness | Feeds images, telemetry, cache data, and fault triggers | none | -| satellite-cache-stub | Local COG/manifest/descriptor fixture volume | Provides offline tile cache and signed/unsigned manifests | none | -| ardupilot-plane-sitl | ArduPilot Plane SITL image or local process | Validates `GPS_INPUT`, spoofing/failsafe behavior | MAVLink SITL ports | -| qgc-observer | QGC/tlog-compatible observer or MAVLink log parser | Verifies GCS-visible status output | none | - -## Networks - -| Network | Services | Purpose | -|---------|----------|---------| -| replay-net | gps-denied-service, replay-consumer, satellite-cache-stub | Offline replay and black-box validation | -| sitl-net | gps-denied-service, ardupilot-plane-sitl, qgc-observer | MAVLink integration and failsafe validation | - -## Volumes - -| Volume | Mounted to | Purpose | -|--------|------------|---------| -| input-data | `/data/input` | `_docs/00_problem/input_data/` and public dataset slices | -| expected-results | `/data/expected` | `_docs/00_problem/input_data/expected_results/` | -| derkachi-replay | `/data/input/flight_derkachi` | Cropped nadir MP4 plus synchronized IMU and `GLOBAL_POSITION_INT` trajectory | -| satellite-cache | `/cache/satellite` | COG tiles, manifests, descriptor index fixtures | -| fdr-output | `/fdr` | Flight-data-recorder outputs for validation | - -## Consumer Application - -**Tech stack**: Python replay harness with pytest-style assertions, Docker/compose orchestration, deterministic cache/SITL/QGC stubs, and CSV/Markdown report generation. - -**Entry points**: -- Local functional suite: `python3 -m pytest` -- Replay harness: `python -m e2e.replay.run_replay --output-dir --input-root ` -- Docker replay gate: `docker compose -f docker-compose.test.yml run --build --rm replay-consumer` - -### Communication With System Under Test - -| Interface | Protocol | Endpoint / Topic | Authentication | -|-----------|----------|------------------|----------------| -| Navigation frames | File/stream replay | Ordered image frames with timestamps | Local fixture access | -| FC telemetry | MAVLink replay or generated stream | IMU, attitude, airspeed, altitude, GPS health | Local MAVLink link | -| Satellite cache | Local filesystem contract | COG + manifest + descriptors | Signed manifest validation | -| GPS output | MAVLink | `GPS_INPUT` to ArduPilot Plane | MAVLink source/system ID allowlist | -| Status output | MAVLink/QGC | `STATUSTEXT` / status summary | MAVLink source/system ID allowlist | -| FDR | Filesystem output | Per-flight segmented logs | Local fixture access | - -### What The Consumer Does Not Access - -- No internal estimator modules. -- No direct BASALT/OpenVINS/Kimera APIs. -- No direct mutation of internal state. -- No bypass of public cache, MAVLink, replay, or FDR interfaces. - -## CI/CD Integration - -| Suite | When to run | Gate behavior | Timeout | -|-------|-------------|---------------|---------| -| Still-image geolocation smoke | Every PR after implementation exists | Block merge | <= 15 min | -| Public VIO dataset replay | Nightly and before release | Block release | Dataset-dependent | -| Jetson performance/resource | Before release and after runtime dependency changes | Block release | <= 8 h for endurance/thermal | -| Plane SITL failsafe/spoofing | Every release candidate | Block release | <= 60 min | - -## Reporting - -**Format**: CSV and FDR validation summary. - -**Columns**: Test ID, Test Name, Input Dataset, Execution Time (ms), Result, Error Distance (m), Source Label, Covariance 95% Semi-Major (m), `GPS_INPUT.fix_type`, Error Message. - -**Output path**: `data/test-results//blackbox-report.csv` and `data/test-results//fdr-validation-summary.md` on the host; `/app/data/test-results//...` inside the replay container. - -## Test Execution - -**Decision**: Both Docker/replay and local hardware execution. - -**Hardware dependencies found**: -- Jetson Orin Nano Super with 8 GB shared LPDDR5 and 25 W power mode. -- CUDA/TensorRT/ONNX acceleration for DINOv2 and local-matcher profiling. -- Camera ingestion paths over USB, MIPI-CSI, or GigE. -- ArduPilot Plane SITL and MAVLink `GPS_INPUT` behavior. -- Thermal, power, FDR, and storage limits that require target-like execution. - -### Docker / Replay Mode - -Use Docker or local host replay for deterministic, reproducible tests that do not require physical Jetson hardware: - -- Still-image frame-center geolocation. -- Derkachi synchronized video/telemetry replay, including alignment and VIO smoke checks. -- Satellite-cache freshness and integrity fixtures. -- FAISS descriptor/index behavior. -- Public dataset replay where GPU/hardware timing is not the assertion. -- Plane SITL tests where SITL and MAVLink behavior are the target. - -Docker/replay mode is suitable for PR checks and nightly validation, but it does not prove Jetson latency, memory, thermal, or camera-driver behavior. - -Current Docker replay smoke evidence is expected to pass `FT-P-01`, `NFT-PERF-INFRA`, `NFT-RES-INFRA`, and `NFT-SEC-INFRA`. `NFT-RES-LIM-INFRA` remains blocked on local non-Jetson runners with an explicit target-hardware prerequisite. - -### Local Hardware Mode - -Use local Jetson hardware for release gates: - -- BASALT + wrapper latency and memory profiling. -- DINOv2/ONNX/TensorRT descriptor-fidelity and runtime profiling. -- ALIKED/DISK + LightGlue runtime profiling. -- Cold-start time to first valid `GPS_INPUT`. -- 8-hour thermal and FDR endurance tests. -- Camera interface validation once the exact module interface is selected. - -### Gate Policy - -- PR gate: Docker/replay smoke and deterministic fixture tests. -- Nightly gate: Docker/replay public dataset slices and SITL scenarios. -- Release gate: local Jetson hardware, Plane SITL, thermal/resource tests, and representative replay data. diff --git a/_docs/02_document/tests/performance-tests.md b/_docs/02_document/tests/performance-tests.md deleted file mode 100644 index 821d68e..0000000 --- a/_docs/02_document/tests/performance-tests.md +++ /dev/null @@ -1,117 +0,0 @@ -# Performance Tests - -### NFT-PERF-01: Per-Frame Latency On Project Still Images - -**Summary**: Validate end-to-end latency for processing project nadir frames through geolocation output. - -**Traces to**: AC-4.1, AC-4.4 - -**Metric**: Capture-to-output latency p50/p95/p99 and dropped-frame rate. - -**Preconditions**: -- Jetson Orin Nano Super or equivalent production target is running in the intended power mode. -- `project_60_still_images` fixture is available. - -| Step | Consumer Action | Measurement | -|------|-----------------|-------------| -| 1 | Replay images at target 3 fps or faster stress rate | Measure latency from input timestamp to emitted estimate | -| 2 | Record all frame drops | Measure dropped-frame percentage | - -**Pass criteria**: p95 latency <400 ms; dropped frames <=10% under sustained load; no batching delay. - -**Duration**: Minimum 20 minutes or full fixture loop repeated enough times to reach stable measurements. - ---- - -### NFT-PERF-02: BASALT + Wrapper Replay Latency - -**Summary**: Validate relative VIO hot-path latency using synchronized Derkachi video/telemetry and public or representative camera/IMU data. - -**Traces to**: AC-2.1a, AC-4.1, AC-4.2 - -**Metric**: Per-frame VIO latency, completion rate, and memory usage. - -**Preconditions**: -- Derkachi `flight_derkachi.mp4` and `data_imu.csv` are mounted and pass fixture validation. -- MUN-FRL/ALTO/EPFL/Kagaru or another representative synchronized dataset slice is pinned for calibrated final comparison. -- OpenVINS reference replay is available for comparison when the dataset supports it. - -| Step | Consumer Action | Measurement | -|------|-----------------|-------------| -| 1 | Replay Derkachi video at target 3 fps and stress rates from the 30 fps source | Measure per-frame processing time, dropped frames, and telemetry alignment | -| 2 | Replay synchronized camera/IMU stream through BASALT + wrapper | Measure VIO processing time and completion rate | -| 3 | Compare emitted trajectory against Derkachi `GLOBAL_POSITION_INT` and calibrated dataset ground truth where available | Measure completion rate and error distribution | -| 4 | Monitor memory | Track CPU/GPU shared memory peak | - -**Pass criteria**: Normal-frame VO registration >95% on calibration-supported segments; p95 processing latency <400 ms for the hot path; memory <8 GB shared; Derkachi replay maintains stable 3-video-frames-per-telemetry-row alignment with <=10% dropped frames under sustained target-rate replay. - -**Duration**: Dataset-dependent; at least one normal segment and one challenging segment. - ---- - -### NFT-PERF-03: Relocalization Trigger Path Latency - -**Summary**: Validate the heavy DINOv2-VLAD + FAISS + ALIKED/LightGlue path under bounded top-K settings. - -**Traces to**: AC-3.2, AC-3.3, AC-4.1, AC-8.6 - -**Metric**: Trigger-to-anchor latency, top-K query time, local verification time, accepted/rejected anchor counts. - -**Preconditions**: -- Precomputed descriptor index is loaded. -- Dynamic K settings are configured: K=5 stable, K=20 active-conflict, K=50 fallback. - -| Step | Consumer Action | Measurement | -|------|-----------------|-------------| -| 1 | Trigger relocalization from cold start or sharp turn | Measure DINOv2 descriptor time and FAISS query time | -| 2 | Verify top-K candidates | Measure ALIKED/LightGlue + RANSAC latency | -| 3 | Emit accepted/rejected decision | Measure total trigger-to-decision latency | - -**Pass criteria**: Heavy path is conditional, never blocks steady-state frame output; accepted anchor carries MRE <2.5 px and valid covariance. - -**Duration**: 100 relocalization trials across stable and active-conflict sector fixtures. - ---- - -### NFT-PERF-04: Cold Boot Time To First Fix - -**Summary**: Validate companion boot to first valid `GPS_INPUT`. - -**Traces to**: AC-NEW-1 - -**Metric**: Time from service start/boot marker to first valid `GPS_INPUT`. - -**Preconditions**: -- Engines/indexes are built before the run. -- Cache/index is available locally. -- FC state handoff is simulated or provided. - -| Step | Consumer Action | Measurement | -|------|-----------------|-------------| -| 1 | Start service from cold boot condition | Measure initialization stages | -| 2 | Wait for first valid output | Measure first valid `GPS_INPUT` timestamp | - -**Pass criteria**: 95th percentile <30 s over 50 runs. - -**Duration**: 50 cold-start trials. - ---- - -### NFT-PERF-INFRA: Replay Evidence Smoke - -**Summary**: Validate that the Docker replay harness records timing evidence for the runnable local replay subset. - -**Traces to**: AZ-234 AC-3, AZ-233 AC-3, AZ-233 AC-4 - -**Metric**: Scenario execution time and report generation status. - -**Preconditions**: -- Docker replay environment is available. -- Project input fixtures are mounted read-only into the replay consumer. - -| Step | Consumer Action | Measurement | -|------|-----------------|-------------| -| 1 | Run the replay consumer in Docker mode | Confirm the performance smoke scenario executes | -| 2 | Inspect the generated CSV and FDR summary | Confirm execution time and artifact paths are recorded | - -**Pass criteria**: `NFT-PERF-INFRA` reports `pass` and writes run-scoped CSV/Markdown evidence; Jetson-only performance evidence remains in release-gate resource tests. diff --git a/_docs/02_document/tests/resilience-tests.md b/_docs/02_document/tests/resilience-tests.md deleted file mode 100644 index 80dabd6..0000000 --- a/_docs/02_document/tests/resilience-tests.md +++ /dev/null @@ -1,107 +0,0 @@ -# Resilience Tests - -### NFT-RES-01: Total Visual Blackout With GPS Spoofing - -**Summary**: Validate degraded-mode behavior when the camera feed is totally occluded/blacked out and real GPS is spoofed or denied. - -**Traces to**: AC-3.5, AC-5.2, AC-NEW-8 - -**Preconditions**: -- Plane SITL or replay trace is emitting normal telemetry. -- System has a recent trusted visual/satellite anchor. - -**Fault injection**: -- Full camera blackout/total occlusion for 5 s, 15 s, and 35 s while spoofed GPS is present. - -| Step | Action | Expected Behavior | -|------|--------|-------------------| -| 1 | Inject total occlusion/blackout and spoofed GPS | Camera gate reports `usable_for_vio=false`, BASALT is bypassed, and system switches to `dead_reckoned` within <=1 processed frame or <=400 ms | -| 2 | Continue blackout | IMU-only covariance grows monotonically and spoofed GPS is ignored | -| 3 | Exceed 30 s or covariance >500 m | System emits no-fix/failsafe fields and QGC `VISUAL_BLACKOUT_FAILSAFE` | - -**Pass criteria**: All pre-VIO occlusion gate, timing, covariance, `fix_type`, `horiz_accuracy`, and status thresholds match AC-NEW-8. - ---- - -### NFT-RES-02: Sharp Turn And Disconnected Segment Relocalization - -**Summary**: Validate recovery when frame-to-frame overlap drops below the VO threshold. - -**Traces to**: AC-3.2, AC-3.3, AC-3.4, AC-8.6 - -**Preconditions**: -- Public or representative replay contains sharp-turn/disconnected segment cases, or equivalent synthetic sequence is generated from mapped imagery. - -**Fault injection**: -- Sequence transition with <5% overlap, heading change <70°, and drift <200 m. - -| Step | Action | Expected Behavior | -|------|--------|-------------------| -| 1 | Replay normal segment | BASALT + wrapper emits normal `vo_extrapolated` estimates | -| 2 | Inject sharp-turn/disconnected transition | VO failure is expected; system triggers VPR relocalization | -| 3 | Continue next segment | System connects segment through verified satellite anchor or reports degraded status | - -**Pass criteria**: Relocalization request is issued when no position is available for >=3 consecutive frames and >=2 s; verified anchor reconnects the segment or output remains degraded with growing covariance. - ---- - -### NFT-RES-03: Companion Computer Restart Mid-Flight - -**Summary**: Validate reboot recovery from flight-controller state and preloaded cache. - -**Traces to**: AC-5.3, AC-NEW-1 - -**Preconditions**: -- Replay/SITL mission is in progress. -- FDR has current segment logs. - -**Fault injection**: -- Kill and restart the GPS-denied service during a GPS-denied segment. - -| Step | Action | Expected Behavior | -|------|--------|-------------------| -| 1 | Kill service | FC continues on last known/IMU-extrapolated state | -| 2 | Restart service | Service reloads cache/index and uses FC state handoff | -| 3 | Observe first valid output | First valid `GPS_INPUT` emitted within <30 s | - -**Pass criteria**: No raw frames are required for recovery; first valid fix <30 s p95; failure is logged in FDR. - ---- - -### NFT-RES-04: Tile Cache Freshness Degradation - -**Summary**: Validate graceful behavior when the only available tile candidates are stale. - -**Traces to**: AC-8.2, AC-NEW-6 - -**Fault injection**: -- Mark cache tiles older than 6 months for active-conflict sector and older than 12 months for stable sector. - -| Step | Action | Expected Behavior | -|------|--------|-------------------| -| 1 | Replay frame requiring satellite anchor | Stale tiles are rejected or down-confidence weighted | -| 2 | Inspect emitted estimate | No stale tile produces `satellite_anchored` label past hard rejection threshold | - -**Pass criteria**: Freshness decay and hard rejection match AC-NEW-6. - ---- - -### NFT-RES-INFRA: Replay/SITL Prerequisite Smoke - -**Summary**: Validate that the Docker replay environment can execute the resilience scenario group with deterministic SITL/QGC stubs. - -**Traces to**: AZ-237 AC-1, AZ-237 AC-4, AZ-233 AC-1, AZ-233 AC-3 - -**Preconditions**: -- `ardupilot-plane-sitl` and `qgc-observer` services are started by `docker-compose.test.yml`. -- `GPSD_ENABLE_SITL=1` is set only for the Docker replay stub environment. - -**Fault injection**: -- Run the blackout/restart control smoke scenario through the replay consumer. - -| Step | Action | Expected Behavior | -|------|--------|-------------------| -| 1 | Start Docker replay services | SITL and QGC observer stubs are reachable to the replay consumer | -| 2 | Execute the resilience smoke scenario | The report records a `pass` result instead of a missing-SITL prerequisite block | - -**Pass criteria**: `NFT-RES-INFRA` reports `pass` in Docker replay mode; live SITL release-candidate scenarios remain covered by `NFT-RES-01` and `FT-N-02`. diff --git a/_docs/02_document/tests/resource-limit-tests.md b/_docs/02_document/tests/resource-limit-tests.md deleted file mode 100644 index 24aea1c..0000000 --- a/_docs/02_document/tests/resource-limit-tests.md +++ /dev/null @@ -1,100 +0,0 @@ -# Resource Limit Tests - -### NFT-RES-LIM-01: Jetson Memory Budget - -**Summary**: Validate that runtime memory stays below the 8 GB shared LPDDR5 limit. - -**Traces to**: AC-4.2, Restrictions Onboard Hardware - -**Preconditions**: -- Jetson Orin Nano Super in production power/thermal mode. -- BASALT + wrapper, cache index, FAISS CPU index, and FDR enabled. - -**Monitoring**: -- CPU/GPU shared memory, process RSS, CUDA allocations, FAISS index memory. - -**Duration**: Minimum 60 minutes steady-state replay plus relocalization triggers. - -**Pass criteria**: Peak memory <8 GB shared; no OOM kill; no silent descriptor/index eviction. - ---- - -### NFT-RES-LIM-02: Thermal And Power Envelope - -**Summary**: Validate sustained 25 W operation without thermal throttling across the environmental envelope. - -**Traces to**: AC-NEW-5 - -**Preconditions**: -- Jetson cooling solution installed. -- Hot-soak chamber or production thermal test setup at +50 °C. - -**Monitoring**: -- Power mode, temperature sensors, throttle flags, CPU/GPU clocks, per-frame latency. - -**Duration**: 8 hours at sustained representative workload. - -**Pass criteria**: No thermal throttle event; p95 latency remains <400 ms; QGC receives thermal warning if any threshold is approached. - ---- - -### NFT-RES-LIM-03: Satellite Cache Storage Budget - -**Summary**: Validate persistent satellite cache footprint for up to 400 km² operational area. - -**Traces to**: AC-8.3, Restrictions Satellite Imagery - -**Monitoring**: -- Cache imagery, overviews, manifests, sidecars, FAISS descriptors/indexes. - -**Duration**: Full cache build/load test. - -**Pass criteria**: Persistent cache is <=10 GB unless the implementation explicitly defines and gets approval for a separate descriptor/index budget. - ---- - -### NFT-RES-LIM-04: Flight Data Recorder Rollover - -**Summary**: Validate FDR storage cap and rollover behavior under an 8-hour synthetic mission. - -**Traces to**: AC-NEW-3, AC-8.5 - -**Preconditions**: -- Synthetic 8-hour load with 3 fps navigation frames, full-rate IMU, emitted `GPS_INPUT`, health telemetry, tile writes, and failure thumbnails. - -**Monitoring**: -- FDR segment sizes, rollover events, retained payload classes. - -**Duration**: 8 hours. - -**Pass criteria**: FDR remains <=64 GB per flight; rollover is logged; no raw nav/AI frames are retained; no payload class is silently dropped. - ---- - -### NFT-RES-LIM-05: Cold Start Resource Spike - -**Summary**: Validate that CUDA/TensorRT/ONNX/FAISS initialization does not violate boot or memory budgets. - -**Traces to**: AC-NEW-1, AC-4.2 - -**Monitoring**: -- Initialization time, peak memory, engine/index load time. - -**Duration**: 50 cold-start trials. - -**Pass criteria**: First valid `GPS_INPUT` <30 s p95; peak memory <8 GB; no first-run engine build occurs at runtime. - ---- - -### NFT-RES-LIM-INFRA: Jetson Hardware Prerequisite Smoke - -**Summary**: Validate that local replay reports Jetson-only resource gates as blocked unless target hardware is explicitly enabled. - -**Traces to**: AZ-239 AC-1, AZ-239 AC-2, AZ-239 AC-4, AZ-233 Reliability NFR - -**Monitoring**: -- Replay report status, blocked reason, and run-scoped artifact path. - -**Duration**: One Docker replay smoke run. - -**Pass criteria**: On non-Jetson local runners, the scenario reports `blocked` with `Jetson prerequisite blocked: set GPSD_ENABLE_JETSON=1 on target hardware`; on Jetson release-gate runners, it must collect the metrics required by `NFT-RES-LIM-01`, `NFT-RES-LIM-02`, and `NFT-RES-LIM-05`. diff --git a/_docs/02_document/tests/security-tests.md b/_docs/02_document/tests/security-tests.md deleted file mode 100644 index cd2c82c..0000000 --- a/_docs/02_document/tests/security-tests.md +++ /dev/null @@ -1,77 +0,0 @@ -# Security Tests - -### NFT-SEC-01: Signed Cache Manifest Enforcement - -**Summary**: Validate that unsigned or tampered cache manifests cannot produce trusted anchors. - -**Traces to**: AC-8.2, AC-8.3, AC-NEW-4, AC-NEW-7 - -| Step | Consumer Action | Expected Response | -|------|-----------------|-------------------| -| 1 | Provide valid signed manifest | System accepts cache fixture if all freshness and resolution checks pass | -| 2 | Provide unsigned manifest | System rejects cache fixture and logs security event | -| 3 | Provide hash-mismatched tile sidecar | System rejects affected tile and emits no trusted anchor from it | - -**Pass criteria**: 0 unsigned or hash-mismatched fixtures produce `satellite_anchored` output or trusted generated tile promotion. - ---- - -### NFT-SEC-02: Cache Poisoning Write Gate - -**Summary**: Validate that generated onboard tiles are not written or promoted when parent-pose covariance is too weak. - -**Traces to**: AC-8.4, AC-NEW-7 - -| Step | Consumer Action | Expected Response | -|------|-----------------|-------------------| -| 1 | Replay generated tile candidate with parent sigma <=3 m | Tile may be written as candidate with full quality metadata | -| 2 | Replay candidate with parent sigma in (3 m, 5 m] | Tile is marked lower trust per sidecar policy | -| 3 | Replay candidate with parent sigma >5 m | Tile is not eligible for write/promotion | - -**Pass criteria**: Tile trust level and write eligibility match AC-NEW-7; no over-threshold tile becomes trusted basemap. - ---- - -### NFT-SEC-03: MAVLink Source And Spoofing Rejection - -**Summary**: Validate that spoofed real-GPS measurements and unauthorized MAVLink sources do not override trusted estimator state. - -**Traces to**: AC-3.5, AC-4.3, AC-NEW-2, AC-NEW-8 - -| Step | Consumer Action | Expected Response | -|------|-----------------|-------------------| -| 1 | Inject spoofed `GPS_RAW_INT` during normal visual operation | Estimator rejects inconsistent GPS based on FC health and visual/satellite consistency | -| 2 | Inject spoofed GPS during visual blackout | Spoofed GPS remains excluded until health and visual consistency gates pass | -| 3 | Inject MAVLink messages from unauthorized source ID | Message is ignored and security/status event is logged | - -**Pass criteria**: No unauthorized or spoofed input causes a confident position estimate; promotion/demotion status is visible to QGC and FDR. - ---- - -### NFT-SEC-04: No In-Flight Satellite Provider Access - -**Summary**: Validate that the runtime system does not call commercial or Suite satellite services during flight. - -**Traces to**: AC-8.1, AC-8.3, Restrictions Satellite Imagery - -| Step | Consumer Action | Expected Response | -|------|-----------------|-------------------| -| 1 | Run replay with network blocked | System continues using local cache | -| 2 | Run replay requiring missing tile | System reports degraded/relocalization-needed status, not an external fetch | - -**Pass criteria**: 0 outbound satellite-provider or Suite Service calls during runtime; missing cache data produces controlled degraded behavior. - ---- - -### NFT-SEC-INFRA: Invalid Cache No-Fetch Smoke - -**Summary**: Validate that the replay harness treats untrusted cache fixtures as a successful security rejection, not as a trusted anchor. - -**Traces to**: AZ-236 AC-2, AZ-236 AC-3, AZ-233 Security NFR - -| Step | Consumer Action | Expected Response | -|------|-----------------|-------------------| -| 1 | Run replay with `cache_variant=stale` | Satellite cache stub marks the manifest untrusted and records no network fetch | -| 2 | Inspect replay evidence | Scenario reports `pass`, `source_label=untrusted_cache_rejected`, and `GPS_INPUT.fix_type=0` | - -**Pass criteria**: The invalid cache smoke scenario passes only when the untrusted fixture is rejected and no external satellite-provider or Suite service network fetch is attempted. diff --git a/_docs/02_document/tests/test-data.md b/_docs/02_document/tests/test-data.md deleted file mode 100644 index 967adf8..0000000 --- a/_docs/02_document/tests/test-data.md +++ /dev/null @@ -1,100 +0,0 @@ -# Test Data Management - -## Seed Data Sets - -| Data Set | Description | Used by Tests | How Loaded | Cleanup | -|----------|-------------|---------------|------------|---------| -| `project_60_still_images` | 60 nadir images with WGS84 frame-center coordinates from `coordinates.csv`; height 400 m | FT-P-01, FT-P-02, FT-N-01, NFT-PERF-01 | Mounted from `_docs/00_problem/input_data/` | Read-only | -| `project_gmaps_reference_subset` | Google Maps reference images available for the first sample frames | FT-P-02, FT-N-01 | Mounted from `_docs/00_problem/input_data/` | Read-only | -| `expected_frame_centers` | Expected lat/lon and thresholds derived from `coordinates.csv` | FT-P-01, FT-P-02 | `_docs/00_problem/input_data/expected_results/results_report.md` | Read-only | -| `derkachi_video_telemetry` | Cropped nadir MP4 synchronized with IMU and `GLOBAL_POSITION_INT` trajectory: 880 x 720, 30 fps, ~490.07 s; telemetry 10 Hz, 4,900 rows | FT-P-03, NFT-PERF-02, NFT-RES-02 | Mounted from `_docs/00_problem/input_data/flight_derkachi/` | Read-only | -| `public_nadir_vio_candidates` | MUN-FRL, ALTO, EPFL fixed-wing, Kagaru, AerialVL/VPAir slices, EuRoC/UZH FPV proxy slices | FT-P-03, FT-P-04, NFT-PERF-02, NFT-RES-02 | Downloaded or mounted by replay harness; exact files pinned during implementation | Reset fixture volume | -| `sitl_spoofing_scenarios` | Generated ArduPilot Plane SITL GPS loss/spoofing traces | FT-N-02, NFT-RES-01, NFT-SEC-03 | Generated by test harness | Discard generated logs after report | -| `cache_integrity_fixtures` | Fresh, stale, unsigned, hash-mismatched, and low-resolution cache manifests | FT-N-03, NFT-SEC-01, NFT-SEC-02 | Mounted fixture volume | Read-only | - -## Public Dataset Coverage Plan - -| Public Data Source | Fit For This Project | Limitations | Planned Use | -|--------------------|----------------------|-------------|-------------| -| MUN-FRL | Strong nadir camera + IMU + GNSS/ground truth candidate | Helicopter/hexacopter, not fixed-wing | BASALT/OpenVINS/Kimera replay and covariance calibration | -| ALTO | Strong nadir aerial imagery with GPS/INS, altimeter, orthophotos | Helicopter/airborne collection, access/details must be pinned | VPR, satellite alignment, VO/geolocalization replay | -| EPFL fixed-wing micro UAV | Strong fixed-wing relevance with camera/navigation sensors | Availability and exact raw IMU packaging must be verified | Fixed-wing path realism and photogrammetry-style validation | -| Kagaru airborne vision | Fixed-wing/farmland relevance, downward stereo, INS/GPS | Older dataset; exact sensor compatibility must be verified | Agricultural terrain and fixed-wing motion checks | -| AerialVL | Strong UAV-to-satellite localization and VPR benchmark | IMU availability is less clear than image/GNSS/reference-map data | Satellite retrieval, anchor verification, visual localization | -| VPAir | Strong aircraft nadir VPR/localization with GPS-derived poses | Academic-use restriction; raw IMU not confirmed | VPR and cross-view localization only if license allows | -| EuRoC MAV | Excellent synchronized camera/IMU/ground-truth VIO benchmark | Not fixed-wing nadir, indoor MAV | BASALT/OpenVINS/Kimera baseline sanity tests | -| UZH FPV | Synchronized camera/IMU/ground-truth high-dynamics benchmark | Not nadir fixed-wing; non-commercial license | Stress VIO robustness only if license allows | - -## Data Isolation Strategy - -Every replay test uses read-only fixture mounts and writes results to a fresh `test-results//` directory. The system under test may write FDR and generated COG tiles only to run-scoped temporary volumes. - -## Input Data Mapping - -| Input Data File | Source Location | Description | Covers Scenarios | -|-----------------|----------------|-------------|------------------| -| `AD000001.jpg` ... `AD000060.jpg` | `_docs/00_problem/input_data/` | Project still-image set with expected WGS84 centers | FT-P-01, FT-P-02, NFT-PERF-01 | -| `coordinates.csv` | `_docs/00_problem/input_data/coordinates.csv` | Machine-readable expected frame centers | FT-P-01, FT-P-02 | -| `data_parameters.md` | `_docs/00_problem/input_data/data_parameters.md` | Height 400 m and camera model | FT-P-01, NFT-PERF-01 | -| `AD000001_gmaps.png`, `AD000002_gmaps.png` | `_docs/00_problem/input_data/` | Reference map screenshots for sample sanity checks | FT-P-02 | -| `flight_derkachi/flight_derkachi.mp4` + `flight_derkachi/data_imu.csv` | `_docs/00_problem/input_data/flight_derkachi/` | Cropped nadir video synchronized with IMU and `GLOBAL_POSITION_INT` GPS trajectory | FT-P-03, NFT-PERF-02, NFT-RES-02 | -| Public dataset slices | External fixture paths pinned during implementation | Synchronized camera/IMU/GNSS/ground truth where available | FT-P-03, FT-P-04, NFT-PERF-02, NFT-RES-02 | - -## Expected Results Mapping - -| Test Scenario ID | Input Data | Expected Result | Comparison Method | Tolerance | Expected Result Source | -|------------------|------------|-----------------|-------------------|-----------|------------------------| -| FT-P-01 | `AD000001.jpg` ... `AD000060.jpg` | Output WGS84 frame center per mapped row; >=80% within 50 m, >=50% within 20 m | Haversine distance threshold + aggregate pass rate | 50 m primary, 20 m stretch | `input_data/expected_results/results_report.md` | -| FT-P-02 | Same 60 images + map references where present | Output includes source label, covariance semi-major axis, and anchor age for every emitted estimate | Required-field validation + geolocation threshold | Required fields present; geolocation thresholds as above | `input_data/expected_results/results_report.md` | -| FT-P-03 | `derkachi_video_telemetry` plus public synchronized VIO dataset slice when available | BASALT + wrapper emits trajectory with calibrated covariance and no optimistic under-reporting | Compare Derkachi output to `GLOBAL_POSITION_INT` trajectory for smoke/relative validation; compare public/representative calibrated runs to ground truth for final accuracy | Derkachi threshold is calibration-gated; final threshold is dataset-specific and pinned after camera calibration | `data_imu.csv` trajectory plus public dataset ground truth | -| FT-P-04 | AerialVL/ALTO/VPAir-style aerial localization slice | Satellite retrieval returns candidate chunks and local verification produces accepted/rejected anchors | Georeference error + MRE + source-label checks | AC-1.1/1.2 and AC-2.2 thresholds where dataset supports them | Public dataset ground truth/reference map | -| FT-N-01 | Low-texture/repetitive frames from sample or public data | System emits degraded confidence or rejects anchor rather than confident false fix | Source label and covariance threshold | No `satellite_anchored` label unless gates pass | Fixture-specific | -| FT-N-02 | Plane SITL GPS spoof/loss trace | Spoofed GPS rejected; system promotes own estimate within <3 s when trigger conditions are met | Event timing and MAVLink field checks | <3 s promotion; blackout thresholds from AC-NEW-8 | Generated SITL trace | -| FT-N-03 | Stale/unsigned/hash-mismatched cache fixtures | Anchors rejected or downgraded; stale tile never emits `satellite_anchored` | Manifest validation + emitted label check | 0 accepted stale/invalid anchors | Cache fixture manifest | - -## External Dependency Mocks - -| External Service | Mock/Stub | How Provided | Behavior | -|------------------|-----------|--------------|----------| -| Azaion Suite Satellite Service | Offline cache stub | Local COG/manifest/descriptor fixture | Provides only preloaded tiles; no in-flight network fetch | -| Flight controller | ArduPilot Plane SITL and MAVLink replay | SITL container/process and recorded/generated tlogs | Emits IMU, attitude, altitude, airspeed, GPS health/spoofing events | -| QGroundControl | MAVLink observer/log parser | Test-side parser | Verifies downsampled status and `STATUSTEXT` events | - -## Data Validation Rules - -| Data Type | Validation | Invalid Examples | Expected System Behavior | -|-----------|------------|------------------|--------------------------| -| Image frame | Existing file, readable image, expected timestamp/order metadata if sequence replay | Missing image, corrupt image, unsupported resolution | Mark estimate unavailable/degraded, log error, continue if possible | -| Expected coordinate | Valid WGS84 latitude/longitude | Out-of-range lat/lon, missing row | Reject test fixture before replay | -| Video/telemetry pair | MP4 duration matches telemetry duration, frame-to-telemetry ratio is stable, timestamps are monotonic | Duration drift >250 ms, missing trajectory columns, non-monotonic timestamps | Reject fixture before replay | -| IMU trace | Monotonic timestamps, angular rate/accel fields, calibrated units | Non-monotonic timestamps, missing samples | Reject fixture or enter degraded mode depending scenario | -| GPS trajectory trace | Valid WGS84 lat/lon, altitude, velocity, and heading fields | Out-of-range lat/lon, impossible altitude, missing `GLOBAL_POSITION_INT` columns | Reject trajectory comparison while allowing pure video replay if applicable | -| Cache tile manifest | CRS, m/px, capture date, source, hashes, signature/provenance | Stale, unsigned, hash mismatch, low resolution | Reject or down-confidence per AC-8.2 and AC-NEW-6 | -| MAVLink output | Valid `GPS_INPUT` fields and fix type/accuracy semantics | Missing `horiz_accuracy`, impossible fix type | Fail test; output contract violated | - -## Phase 3 Validation Gate Result - -| Test Scenario ID | Shape | Required Input Data | Required Expected Result | Input Provided? | Expected Result Provided? | Validation Decision | -|------------------|-------|---------------------|--------------------------|-----------------|---------------------------|---------------------| -| FT-P-01 | Input/output | 60 project images + `coordinates.csv` | WGS84 center per image with 50 m / 20 m thresholds | Yes | Yes | Keep | -| FT-P-02 | Input/output | 60 project images + output schema expectations | Required confidence/source-label fields and thresholds | Yes | Yes | Keep | -| FT-P-03 | Input/output | Derkachi synchronized video/IMU/GPS fixture; public or calibrated representative dataset for final accuracy | Derkachi `GLOBAL_POSITION_INT` trajectory for smoke/relative validation; calibrated ground truth for final covariance checks | Yes for Derkachi; public/calibrated dataset still useful for final signoff | Yes for Derkachi GPS trajectory; calibrated camera thresholds pending | Keep with calibration gate | -| FT-P-04 | Input/output | Public aerial localization or project cache fixture | Georeference, MRE, and source-label checks | Accepted as required external fixture | Accepted as dataset/reference-map ground truth | Keep with acquisition task | -| FT-N-01 | Behavioral/input-output | Ambiguous low-texture/repetitive frames | 0 confident false anchors | Accepted as project/public fixture | Yes | Keep | -| FT-N-02 | Behavioral | Generated Plane SITL spoof/blackout trace | Timing and MAVLink field thresholds from AC-NEW-8 | Generated by test harness | Yes | Keep | -| FT-N-03 | Behavioral/input-output | Cache integrity fixtures | 0 trusted anchors from stale/invalid tiles | Generated fixture | Yes | Keep | -| NFT-PERF-01 | Input/output | 60 project images | p95 latency and drop-rate thresholds | Yes | Yes | Keep | -| NFT-PERF-02 | Input/output | Derkachi synchronized video/IMU/GPS fixture; public/representative synchronized camera/IMU dataset | VO registration, latency, memory thresholds | Yes for Derkachi | Yes | Keep with calibration gate | -| NFT-PERF-03 | Behavioral/input-output | Precomputed descriptor/cache fixture | Trigger-path latency and MRE thresholds | Generated fixture | Yes | Keep | -| NFT-PERF-04 | Behavioral | Cold-start harness and cache fixture | <30 s p95 over 50 runs | Generated by test harness | Yes | Keep | -| NFT-RES-* | Behavioral | Fault triggers and generated traces | AC-defined timing/status thresholds | Generated by test harness | Yes | Keep | -| NFT-SEC-* | Behavioral/input-output | Cache/MAVLink/network fixtures | Rejection/no-fetch/no-promote thresholds | Generated fixture | Yes | Keep | -| NFT-RES-LIM-* | Behavioral | Jetson/cache/FDR monitoring environment | Numeric resource thresholds | Environment-dependent | Yes | Keep | - -**Coverage after validation**: 49/49 AC and restriction groups remain covered. No tests were removed. - -**Acquisition tasks required downstream**: -- Pin camera intrinsics, lens distortion, raw camera feed parameters, and camera-to-body mounting transform for the Derkachi fixture or future representative recordings. -- Pin and download at least one strong synchronized nadir camera + IMU + ground-truth dataset, preferably MUN-FRL or ALTO, with EPFL fixed-wing and Kagaru as fixed-wing/farmland candidates. -- Pin license-compatible VPR/localization datasets for satellite anchor tests; VPAir and UZH FPV have non-commercial restrictions and must not be used for commercial acceptance unless license terms allow it. -- Create generated fixtures for Plane SITL spoofing, stale cache manifests, signed/unsigned manifests, FDR load, and thermal/resource monitoring during implementation. diff --git a/_docs/02_document/tests/traceability-matrix.md b/_docs/02_document/tests/traceability-matrix.md deleted file mode 100644 index d63e606..0000000 --- a/_docs/02_document/tests/traceability-matrix.md +++ /dev/null @@ -1,116 +0,0 @@ -# Traceability Matrix - -## Acceptance Criteria Coverage - -| AC ID | Acceptance Criterion Summary | Test IDs | Coverage | -|-------|------------------------------|----------|----------| -| AC-1.1 | >=80% frame centers within 50 m | FT-P-01, FT-P-04 | Covered | -| AC-1.2 | >=50% frame centers within 20 m | FT-P-01, FT-P-04 | Covered | -| AC-1.3 | Drift and anchor age reporting | FT-P-02, FT-P-03, NFT-RES-02 | Covered | -| AC-1.4 | Quantitative confidence and source label | FT-P-02, FT-N-01, FT-P-03 | Covered | -| AC-2.1a | VO registration >95% on normal segments | FT-P-03, NFT-PERF-02 | Covered | -| AC-2.1b | Satellite-anchor registration measured separately | FT-P-04 | Covered | -| AC-2.2 | MRE <1 px VO and <2.5 px satellite anchor | FT-P-03, FT-P-04 | Covered | -| AC-3.1 | Handles up to 350 m outliers | FT-N-01, NFT-RES-02 | Covered | -| AC-3.2 | Sharp turn relocalization | FT-P-04, NFT-RES-02, NFT-PERF-03 | Covered | -| AC-3.3 | >=3 disconnected segments via retrieval/relocalization | NFT-RES-02, FT-P-04 | Covered | -| AC-3.4 | Relocalization request after loss threshold | NFT-RES-02 | Covered | -| AC-3.5 | Total visual blackout/occlusion + GPS spoofing degraded mode | FT-N-02, NFT-RES-01, NFT-SEC-03 | Covered | -| AC-4.1 | End-to-end latency <400 ms p95 | NFT-PERF-01, NFT-PERF-02, NFT-PERF-03 | Covered | -| AC-4.2 | Memory below 8 GB shared | NFT-RES-LIM-01, NFT-RES-LIM-05 | Covered | -| AC-4.3 | MAVLink `GPS_INPUT` output for ArduPilot | FT-N-02, NFT-SEC-03 | Covered | -| AC-4.4 | Frame-by-frame streaming | FT-P-02, NFT-PERF-01 | Covered | -| AC-4.5 | Previous estimate corrections | FT-P-02 | Covered | -| AC-5.1 | Initialize from last trusted FC state | NFT-RES-03, NFT-PERF-04 | Covered | -| AC-5.2 | >3 s no-estimate fallback behavior | FT-N-02, NFT-RES-01 | Covered | -| AC-5.3 | Re-initialize after companion reboot | NFT-RES-03 | Covered | -| AC-6.1 | QGC status at 1-2 Hz | FT-N-02, NFT-SEC-03 | Covered | -| AC-6.2 | Ground station command ingress | FT-P-04, NFT-RES-02 | Covered | -| AC-6.3 | WGS84 output | FT-P-01, FT-P-02 | Covered | -| AC-7.1 | Object localization accuracy consistent with frame center in level flight | FT-P-01 | Covered at system boundary; detailed AI-camera tests deferred to component specs | -| AC-7.2 | Object coordinates from UAV position, gimbal angle, zoom, altitude | FT-P-01 | Covered at system boundary; detailed AI-camera tests deferred to component specs | -| AC-8.1 | Cache imagery 0.5 m/px minimum, 0.3 m/px ideal | FT-P-04, NFT-SEC-04 | Covered | -| AC-8.2 | Tile freshness thresholds | FT-N-03, NFT-RES-04, NFT-SEC-01 | Covered | -| AC-8.3 | Preloaded/preprocessed offline cache | NFT-SEC-04, NFT-RES-LIM-03 | Covered | -| AC-8.4 | Mid-flight tile generation and write-back | NFT-SEC-02, NFT-RES-LIM-04 | Covered | -| AC-8.5 | No raw frame retention | NFT-RES-LIM-04 | Covered | -| AC-8.6 | VPR retrieval chunks, multi-scale, dynamic K | FT-P-04, NFT-PERF-03 | Covered | -| AC-NEW-1 | Cold start first fix <30 s | NFT-PERF-04, NFT-RES-LIM-05, NFT-RES-03 | Covered | -| AC-NEW-2 | Spoofing promotion <3 s | FT-N-02, NFT-SEC-03 | Covered | -| AC-NEW-3 | FDR <=64 GB and payload retention | NFT-RES-LIM-04 | Covered | -| AC-NEW-4 | False-position safety budget | FT-N-01, NFT-SEC-01 | Covered | -| AC-NEW-5 | Thermal envelope and no throttle | NFT-RES-LIM-02 | Covered | -| AC-NEW-6 | Imagery freshness enforcement | FT-N-03, NFT-RES-04 | Covered | -| AC-NEW-7 | Cache-poisoning safety budget | FT-N-03, NFT-SEC-02 | Covered | -| AC-NEW-8 | Pre-VIO total occlusion gate, IMU-only blackout propagation, and spoofing degraded-mode budget | FT-N-02, NFT-RES-01 | Covered | - -## Restrictions Coverage - -| Restriction ID | Restriction Summary | Test IDs | Coverage | -|----------------|---------------------|----------|----------| -| R-UAV-01 | Fixed-wing UAV mission profile and 8-hour operations | NFT-RES-LIM-02, NFT-RES-LIM-04 | Covered | -| R-CAM-01 | Fixed downward navigation camera | FT-P-01, FT-P-03 | Covered | -| R-CAM-02 | ADTi 20MP 20L V1 and calibration assumptions | FT-P-01, NFT-PERF-01 | Covered | -| R-SAT-01 | Offline-only Satellite Service cache, no in-flight provider fetch | NFT-SEC-04 | Covered | -| R-SAT-02 | Cache resolution/freshness/metadata conventions | FT-N-03, NFT-RES-LIM-03 | Covered | -| R-HW-01 | Jetson Orin Nano Super 8 GB / 25 W | NFT-RES-LIM-01, NFT-RES-LIM-02 | Covered | -| R-SENSOR-01 | FC IMU available; original still-image sample lacks synchronized IMU; Derkachi fixture provides video/IMU/GPS trajectory but calibration is pending | FT-P-03, NFT-PERF-02 | Covered through Derkachi representative replay plus public/calibrated dataset plan | -| R-MAV-01 | MAVLink, ArduPilot only, GPS_INPUT via pymavlink | FT-N-02, NFT-SEC-03 | Covered | -| R-GCS-01 | QGroundControl supported GCS | FT-N-02, NFT-SEC-03 | Covered | -| R-SAFETY-01 | False-position, cold-start, spoofing, and failsafe constraints | FT-N-01, FT-N-02, NFT-PERF-04, NFT-RES-01 | Covered | - -## Cycle 1 Implementation-Learned Test Coverage - -| Task AC ID | Task Acceptance Criterion Summary | Test IDs | Coverage | -|------------|-----------------------------------|----------|----------| -| AZ-233 AC-1 | Docker/replay environment starts or reports clear blocked prerequisites | NFT-RES-INFRA, NFT-RES-LIM-INFRA | Covered | -| AZ-233 AC-2 | External dependency stubs are deterministic and record interactions | NFT-SEC-INFRA, NFT-RES-INFRA | Covered | -| AZ-233 AC-3 | Runner executes blackbox, performance, resilience, security, and resource-limit groups | FT-P-01, NFT-PERF-INFRA, NFT-RES-INFRA, NFT-SEC-INFRA, NFT-RES-LIM-INFRA | Covered | -| AZ-233 AC-4 | CSV and Markdown evidence reports are generated with required fields | FT-P-01, NFT-PERF-INFRA, NFT-RES-INFRA, NFT-SEC-INFRA, NFT-RES-LIM-INFRA | Covered | -| AZ-234 AC-1 | Still-image WGS84 error is reported against expected coordinates | FT-P-01 | Covered | -| AZ-234 AC-2 | Confidence output contract fields are validated | FT-P-02 | Covered | -| AZ-234 AC-3 | Replay latency and dropped-frame metrics are recorded | NFT-PERF-INFRA, NFT-PERF-01 | Covered | -| AZ-235 AC-1 | Derkachi fixture alignment is validated before replay | FT-P-03 | Covered | -| AZ-235 AC-2 | Synchronized replay emits frame-by-frame estimates or explicit degradation | FT-P-03 | Covered | -| AZ-235 AC-3 | VIO latency, completion, memory, and calibration status are reported | NFT-PERF-02 | Covered | -| AZ-236 AC-1 | Verified anchors include retrieval, matching, geometry, freshness, and provenance evidence | FT-P-04 | Covered | -| AZ-236 AC-2 | Unsafe cache or low-texture candidates are rejected | FT-N-01, FT-N-03, NFT-SEC-INFRA | Covered | -| AZ-236 AC-3 | Flight-mode missing-cache behavior does not fetch external satellite data | NFT-SEC-04, NFT-SEC-INFRA | Covered | -| AZ-236 AC-4 | Cache and trigger-path metrics are reported | NFT-PERF-03, NFT-RES-04, NFT-RES-LIM-03 | Covered | -| AZ-237 AC-1 | Blackout transitions to dead reckoning within threshold | FT-N-02, NFT-RES-01 | Covered | -| AZ-237 AC-2 | Degraded covariance and no-fix/failsafe thresholds are enforced | FT-N-02, NFT-RES-01 | Covered | -| AZ-237 AC-3 | Spoofed or unauthorized MAVLink inputs are rejected | NFT-SEC-03 | Covered | -| AZ-237 AC-4 | QGC and FDR degraded-mode evidence is visible | FT-N-02, NFT-SEC-03, NFT-RES-INFRA | Covered | -| AZ-238 AC-1 | Disconnected segments trigger relocalization or degraded status | NFT-RES-02 | Covered | -| AZ-238 AC-2 | Companion restart first-output and FDR evidence are recorded | NFT-RES-03 | Covered | -| AZ-238 AC-3 | Cold-start trials report first-fix timing or blocked prerequisite | NFT-PERF-04, NFT-RES-LIM-05 | Covered | -| AZ-238 AC-4 | Cold-start resource spikes are captured where measurable | NFT-RES-LIM-05 | Covered | -| AZ-239 AC-1 | Jetson memory budget is measured on target hardware | NFT-RES-LIM-01, NFT-RES-LIM-INFRA | Covered | -| AZ-239 AC-2 | Thermal/power endurance is validated or blocked with reason | NFT-RES-LIM-02, NFT-RES-LIM-INFRA | Covered | -| AZ-239 AC-3 | FDR rollover behavior is validated | NFT-RES-LIM-04 | Covered | -| AZ-239 AC-4 | Resource/endurance evidence artifacts are complete | NFT-RES-LIM-01, NFT-RES-LIM-02, NFT-RES-LIM-04, NFT-RES-LIM-INFRA | Covered | -| AZ-243 AC-1 | Production VIO profile selects native runtime path | FT-P-03 | Covered | -| AZ-243 AC-2 | Missing native runtime prerequisite fails closed with explicit error | FT-P-03 | Covered | -| AZ-243 AC-3 | Replay mode remains explicit and cannot satisfy production native checks | FT-P-03 | Covered | - -## Coverage Summary - -| Category | Total Items | Covered | Not Covered | Coverage % | -|----------|-------------|---------|-------------|------------| -| Acceptance Criteria | 39 | 39 | 0 | 100% | -| Restrictions | 10 | 10 | 0 | 100% | -| **Total** | 49 | 49 | 0 | 100% | - -## Uncovered Items Analysis - -| Item | Reason Not Covered | Risk | Mitigation | -|------|--------------------|------|------------| -| None | All current AC and restriction groups have black-box coverage | N/A | Continue to Phase 3 validation gate | - -## Data Coverage Caveats - -- Current project data fully supports still-image frame-center checks for 60 mapped images. -- Derkachi project data supports synchronized video/IMU/GPS trajectory replay for FT-P-03 and NFT-PERF-02. -- Derkachi project data is calibration-limited: raw camera intrinsics, lens distortion, and camera-to-body transform are still required before final absolute accuracy thresholds can be treated as production acceptance. -- Phase 3 must validate camera calibration inputs and public/calibrated dataset acquisition before FT-P-03, FT-P-04, and NFT-PERF-02 can be used for final signoff. -- Cycle 1 Docker replay smoke evidence currently passes blackbox, performance, resilience, and security infrastructure scenarios; Jetson resource evidence remains a target-hardware release gate and is reported as blocked on local runners. diff --git a/_docs/02_tasks/_dependencies_table.md b/_docs/02_tasks/_dependencies_table.md deleted file mode 100644 index ffe5124..0000000 --- a/_docs/02_tasks/_dependencies_table.md +++ /dev/null @@ -1,51 +0,0 @@ -# Dependencies Table - -**Date**: 2026-05-05 -**Total Tasks**: 25 -**Total Complexity Points**: 113 -**Lessons applied**: No `_docs/LESSONS.md` file exists; no prior estimation or dependency lessons were available. - -| Task | Name | Complexity | Dependencies | Epic | -|------|------|------------|--------------|------| -| AZ-219 | initial_structure | 5 | None | AZ-206 | -| AZ-220 | shared_runtime_contracts | 3 | AZ-219 | AZ-206 | -| AZ-221 | shared_geometry_time_sync | 3 | AZ-219, AZ-220 | AZ-207 | -| AZ-222 | runtime_config_errors_telemetry | 3 | AZ-219, AZ-220 | AZ-208 | -| AZ-223 | camera_ingest_calibration | 5 | AZ-220, AZ-221, AZ-222 | AZ-209 | -| AZ-224 | mavlink_gcs_gateway | 3 | AZ-220, AZ-222 | AZ-210 | -| AZ-225 | tile_manager_cache_manifest | 5 | AZ-220, AZ-221, AZ-222 | AZ-211 | -| AZ-226 | generated_tile_orthorectification | 5 | AZ-223, AZ-225 | AZ-211 | -| AZ-227 | fdr_event_recorder | 5 | AZ-220, AZ-222 | AZ-212 | -| AZ-228 | vio_adapter | 5 | AZ-221, AZ-222, AZ-223, AZ-224 | AZ-213 | -| AZ-229 | satellite_service_sync | 3 | AZ-222, AZ-225, AZ-226 | AZ-214 | -| AZ-230 | satellite_service_vpr_retrieval | 5 | AZ-223, AZ-225, AZ-229 | AZ-214 | -| AZ-231 | anchor_verification_matching | 5 | AZ-223, AZ-225, AZ-230 | AZ-215 | -| AZ-232 | safety_anchor_state_machine | 5 | AZ-223, AZ-224, AZ-227, AZ-228, AZ-231 | AZ-216 | -| AZ-240 | native_vio_backend_integration | 5 | AZ-228 | AZ-213 | -| AZ-243 | integrate_production_native_vio_runtime | 5 | AZ-240 | AZ-213 | -| AZ-241 | real_satellite_vpr_descriptor_retrieval | 5 | AZ-230 | AZ-214 | -| AZ-242 | real_anchor_feature_matching_ransac | 5 | AZ-231, AZ-241 | AZ-215 | -| AZ-233 | test_infrastructure | 5 | AZ-243, AZ-241, AZ-242 | AZ-218 | -| AZ-234 | replay_geolocation_confidence_tests | 3 | AZ-233 | AZ-218 | -| AZ-235 | vio_replay_performance_tests | 5 | AZ-233, AZ-240 | AZ-218 | -| AZ-236 | satellite_anchor_cache_tests | 5 | AZ-233, AZ-241, AZ-242 | AZ-218 | -| AZ-237 | mavlink_blackout_spoofing_tests | 5 | AZ-233 | AZ-218 | -| AZ-238 | cold_start_restart_tests | 5 | AZ-233 | AZ-218 | -| AZ-239 | jetson_resource_endurance_tests | 5 | AZ-233 | AZ-218 | - -## Verification Notes - -- No task exceeds 5 complexity points. -- Test implementation tasks are appended under Blackbox Tests (AZ-218); the test infrastructure bootstrap now depends on the product remediation tasks so tests do not validate scaffold behavior. -- The graph is acyclic: product foundations precede adapters/stores, then VIO/retrieval/matching, then safety wrapper orchestration; remediation tasks close native VIO, real VPR, and real matching gaps before affected blackbox tests run. -- Step 9 resume verification confirmed AZ-233 through AZ-239 already exist in Jira and remain ready for test implementation after product remediation completion. - -## Test Coverage Verification - -- AZ-234 covers FT-P-01, FT-P-02, and NFT-PERF-01. -- AZ-235 covers FT-P-03 and NFT-PERF-02 after AZ-243 provides the real native VIO path. -- AZ-236 covers FT-P-04, FT-N-01, FT-N-03, NFT-PERF-03, NFT-RES-04, NFT-SEC-01, NFT-SEC-02, NFT-SEC-04, and NFT-RES-LIM-03 after AZ-241 and AZ-242 provide real VPR retrieval and anchor matching. -- AZ-237 covers FT-N-02, NFT-RES-01, and NFT-SEC-03. -- AZ-238 covers NFT-RES-02, NFT-RES-03, NFT-PERF-04, and NFT-RES-LIM-05. -- AZ-239 covers NFT-RES-LIM-01, NFT-RES-LIM-02, and NFT-RES-LIM-04. -- All traceability-matrix AC and restriction groups remain covered by at least one test task. diff --git a/_docs/02_tasks/done/AZ-219_initial_structure.md b/_docs/02_tasks/done/AZ-219_initial_structure.md deleted file mode 100644 index c02248e..0000000 --- a/_docs/02_tasks/done/AZ-219_initial_structure.md +++ /dev/null @@ -1,289 +0,0 @@ -# Initial Project Structure - -**Task**: AZ-219_initial_structure -**Name**: Initial Structure -**Description**: Scaffold the project skeleton for the Jetson-hosted GPS-denied localization runtime, replay harness, local infrastructure, CI, and deployment evidence paths. -**Complexity**: 5 points -**Dependencies**: None -**Component**: Bootstrap -**Tracker**: AZ-219 -**Epic**: AZ-206 - -## Project Folder Layout - -```text -project-root/ -├── src/ -│ ├── __init__.py -│ ├── camera_ingest_calibration/ -│ ├── vio_adapter/ -│ │ └── native/ -│ ├── safety_anchor_wrapper/ -│ ├── satellite_service/ -│ │ └── native/ -│ ├── anchor_verification/ -│ │ └── native/ -│ ├── tile_manager/ -│ ├── mavlink_gcs_integration/ -│ ├── fdr_observability/ -│ ├── shared/ -│ │ ├── contracts/ -│ │ ├── geo_geometry/ -│ │ ├── time_sync/ -│ │ ├── config/ -│ │ ├── errors/ -│ │ └── telemetry/ -├── migrations/ -│ ├── postgresql/ -│ └── seed/ -├── tests/ -│ ├── unit/ -│ ├── integration/ -│ ├── blackbox/ -│ ├── fixtures/ -│ ├── sitl/ -│ └── e2e/ -├── e2e/ -│ ├── replay/ -│ └── reports/ -├── deployment/ -│ ├── docker/ -│ ├── compose/ -│ ├── jetson/ -│ └── scripts/ -├── config/ -│ ├── development/ -│ ├── ci/ -│ ├── jetson/ -│ └── production/ -├── data/ -│ ├── input/ -│ ├── expected/ -│ ├── cache/ -│ ├── fdr/ -│ └── test-results/ -├── .github/ -│ └── workflows/ -│ └── ci.yml -├── docker-compose.yml -├── docker-compose.test.yml -├── .dockerignore -└── .env.example -``` - -### Layout Rationale - -The runtime is organized directly under `src/` because this repository already represents the GPS-denied onboard system. Component directories live at the source root, and native bridges stay inside the component folder that owns the backend or hot path. Shared contracts, geometry, time-sync, configuration, error envelopes, and telemetry DTOs are centralized so component tasks consume a single public interface instead of duplicating cross-cutting logic. - -The scaffold separates runtime source, migrations, tests, deployment assets, configuration, and mutable data. Production runs on Jetson hardware, while Docker/compose is used for replay, SITL, and deterministic CI environments. - -## DTOs and Interfaces - -### Shared DTOs - -| DTO Name | Used By Components | Fields Summary | -|----------|--------------------|----------------| -| `FramePacket` | Camera ingest, BASALT VIO, Satellite Service, anchor verification, Tile Manager, FDR | Frame ID, timestamp, image reference, camera calibration ID, occlusion status, quality metrics | -| `TelemetrySample` | MAVLink/GCS, BASALT VIO, safety wrapper, FDR, e2e tests | Timestamp, IMU, attitude, airspeed, altitude, GPS health | -| `VioStatePacket` | BASALT VIO, safety wrapper, FDR, e2e tests | Timestamp, relative pose, velocity, bias, tracking quality, covariance hint | -| `PositionEstimate` | Safety wrapper, MAVLink/GCS, Tile Manager, FDR, e2e tests | WGS84 coordinates, covariance semi-major axis, source label, fix type, horizontal accuracy, anchor age | -| `VprCandidate` | Satellite Service, anchor verification, FDR | Chunk ID, tile ID, score, footprint, freshness status | -| `AnchorDecision` | Anchor verification, safety wrapper, FDR | Candidate ID, acceptance result, estimated pose, inliers, MRE, rejection reason | -| `CacheTileRecord` | Tile Manager, Satellite Service, anchor verification, FDR | Tile ID, type, CRS, meters per pixel, capture date, signature/hash status, trust level | -| `FdrEvent` | All runtime components, e2e tests | Event type, timestamp, component, severity, payload reference, mission/run ID | -| `ScenarioReport` | Separate e2e test suite, CI/CD, release evidence | Scenario ID, result, metrics, artifacts, failure reason | - -### Component Interfaces - -| Component | Interface | Methods | Exposed To | -|-----------|-----------|---------|------------| -| Camera ingest/calibration | `FrameProvider` | `next_frame`, `detect_occlusion`, `classify_quality` | VIO Adapter, Satellite Service, anchor verification, Tile Manager | -| VIO adapter | `VioAdapter` | `initialize`, `process`, `health` | Safety wrapper, e2e tests | -| Safety/anchor wrapper | `LocalizationStateMachine` | `update_vio`, `consider_anchor`, `degrade`, `propagate_imu_only`, `tile_write_eligibility` | MAVLink/GCS, Tile Manager, FDR, e2e tests | -| Satellite Service | `SatelliteService` | `import_mission_cache`, `load_index`, `retrieve`, `upload_generated_tiles` | Safety wrapper, anchor verification, Tile Manager | -| Anchor verification | `AnchorVerifier` | `verify`, `benchmark_matcher` | Safety wrapper, FDR | -| Tile Manager | `TileManager` | `validate_cache`, `get_tile_window`, `orthorectify_frame`, `write_generated_tile`, `package_sync` | Satellite Service, anchor verification, post-flight sync | -| MAVLink/GCS integration | `MavlinkGateway` | `subscribe_telemetry`, `emit_gps_input`, `emit_status` | BASALT VIO, safety wrapper, QGC, FDR | -| FDR/observability | `FlightRecorder` | `append_event`, `rollover`, `export` | All runtime components, e2e tests | - -## CI/CD Pipeline - -| Stage | Purpose | Trigger | -|-------|---------|---------| -| Format / lint | Enforce code style and static quality | Every PR and push to `dev` | -| Unit tests | Validate component-local behavior and shared contracts | Every PR and push to `dev` | -| Replay black-box smoke | Run deterministic still-image/cache/SITL subsets | Every PR | -| Cache/security fixture tests | Validate signed manifests, stale-tile rejection, and no mid-flight provider/Satellite Service calls | Every PR | -| Plane SITL spoof/failsafe | Validate ArduPilot Plane `GPS_INPUT`, failsafe, spoofing promotion | Nightly and release candidate | -| Public dataset replay | Exercise VIO, retrieval, and anchor behavior against pinned public slices | Nightly and release candidate | -| Jetson latency/resource tests | Measure p95 latency, memory, cold start, TensorRT/ONNX fidelity | Release candidate | -| Thermal/FDR endurance | Prove 8-hour 25 W no-throttle and <=64 GB FDR rollover | Hardware qualification | -| Build / package | Produce replay-compatible and Jetson deployment artifacts | Release candidate | -| Deploy staging evidence | Publish reports, tlogs, FDR summaries, cache validation artifacts | Release candidate | - -### Pipeline Configuration Notes - -CI uses Docker/compose for replay and SITL gates. Jetson, thermal, camera, and representative replay gates run on dedicated hardware runners and block release rather than every PR. Dataset downloads are license-tagged and not baked into images. Secrets, signing keys, and Satellite Service credentials are never cached. - -## Environment Strategy - -| Environment | Purpose | Configuration Notes | -|-------------|---------|---------------------| -| Development replay | Fast local iteration | Small fixture cache, local PostgreSQL/PostGIS, replay frames, test keys only | -| CI replay | Deterministic PR checks | Docker services for runtime, replay consumer, cache stub, and reports | -| Public dataset replay | Algorithm de-risking | Pinned dataset slices with license metadata and ground-truth reports | -| Plane SITL | MAVLink/failsafe validation | ArduPilot Plane SITL, QGC/tlog observer, production-like `GPS_INPUT` parameters | -| Jetson hardware validation | Production path profiling | JetPack/CUDA/TensorRT, local camera/GPU/MAVLink access, resource monitoring | -| Representative flight/replay | Final acceptance evidence | Target-like UAV, FC, camera, synchronized telemetry, ground truth | -| Production | Onboard mission runtime | Preloaded signed cache, local PostGIS, per-flight FDR, no provider network calls | - -### Environment Variables - -| Variable | Dev | Staging | Production | Description | -|----------|-----|---------|------------|-------------| -| `GPSD_ENV` | `development` | `staging` | `production` | Selects runtime profile | -| `GPSD_CONFIG_DIR` | local path | staged config path | onboard config path | Versioned configuration root | -| `GPSD_CACHE_DIR` | fixture cache | staged mission cache | onboard mission cache | COG, manifest, sidecar, descriptor root | -| `GPSD_FDR_DIR` | temp output | staged evidence path | per-flight NVMe path | Flight data recorder output | -| `GPSD_DATABASE_URL` | local PostGIS | staging PostGIS | onboard local PostGIS | Manifest, mission state, FDR event index | -| `GPSD_MAVLINK_URL` | SITL/replay | SITL/hardware rig | FC telemetry link | MAVLink connection endpoint | -| `GPSD_CAMERA_SOURCE` | fixture/replay | fixture or hardware | live camera | Navigation frame source | -| `GPSD_SIGNING_KEY_REF` | test key ref | staging secret ref | mission secret ref | Cache/sidecar signature verification | -| `GPSD_MAX_FDR_BYTES` | small fixture cap | release-like cap | `68719476736` | FDR rollover threshold | -| `GPSD_LOG_LEVEL` | debug/info | info | info/warn | Runtime logging level | - -## Database Migration Approach - -**Migration tool**: Versioned PostgreSQL migration scripts, with PostGIS extension setup and deterministic seed scripts. -**Strategy**: Additive migrations by default. Database, table, and column renames require explicit approval before implementation. Runtime rejects unknown required schema versions loudly. - -### Initial Schema - -- Mission profile tables for route geometry, sector classification, altitude band, and cache budget. -- Camera calibration tables for camera model, intrinsics, extrinsics, and verification status. -- Cache manifest tables for COG tiles, generated tiles, freshness, signatures, sidecar hashes, trust level, and PostGIS footprints. -- VPR chunk tables for retrieval footprints, descriptor metadata, multi-scale index references, and sector top-K policy. -- FDR event index tables for mission/run IDs, timestamps, event type, component, severity, and CBOR segment references. -- Validation run tables or report records for scenario IDs, metrics, artifacts, and release evidence pointers. - -## Test Structure - -```text -tests/ -├── unit/ -│ ├── shared/ -│ ├── camera_ingest_calibration/ -│ ├── vio_adapter/ -│ ├── safety_anchor_wrapper/ -│ ├── satellite_service/ -│ ├── anchor_verification/ -│ ├── tile_manager/ -│ ├── mavlink_gcs_integration/ -│ ├── fdr_observability/ -├── integration/ -│ ├── contracts/ -│ ├── cache_postgis/ -│ ├── mavlink/ -│ └── fdr/ -├── blackbox/ -│ ├── still_image_geolocation/ -│ ├── satellite_anchor/ -│ ├── visual_blackout_spoofing/ -│ ├── cache_freshness/ -│ └── resource_limits/ -├── fixtures/ -│ ├── project_60_images/ -│ ├── expected_results/ -│ ├── satellite_cache/ -│ ├── telemetry/ -│ └── public_dataset_slices/ -├── sitl/ -│ ├── plane_gps_input/ -│ ├── spoofing_promotion/ -│ └── failsafe/ -└── e2e/ - ├── replay/ - ├── reports/ - └── release_evidence/ -``` - -### Test Configuration Notes - -Unit tests validate contracts and component behavior without external hardware. Integration tests exercise PostGIS, MAVLink, FDR segments, and cache fixtures. Black-box tests interact only through public inputs and outputs: frames, telemetry, offline cache, `GPS_INPUT`, QGC status, and FDR. Release gates add Jetson hardware, thermal/endurance, and representative replay evidence. - -## Health Checks - -| Service / Component | Liveness | Readiness | -|---------------------|----------|-----------| -| GPS-denied service | Process event loop responsive | Config, PostGIS, cache, FDR path, MAVLink, and camera/replay source validated | -| Replay consumer | Runner process responsive | Fixtures, expected results, and output path available | -| Satellite cache stub | Fixture volume mounted | Manifests, sidecars, descriptors, and signatures validated | -| ArduPilot Plane SITL | SITL process responsive | MAVLink ports accepting telemetry and production parameters loaded | -| QGC observer/log parser | Parser process responsive | Tlog/status stream connected | - -Each deployable service exposes `/health/live`, `/health/ready`, and `/metrics` where HTTP is available. Non-HTTP hardware processes write equivalent structured health events to FDR and CI reports. - -## Docker And Compose Requirements - -- Create a replay-compatible Dockerfile for the Python runtime and native optional stubs. -- Create a replay-consumer Dockerfile for black-box test execution. -- Create a satellite-cache-stub fixture image or volume contract. -- Create an ArduPilot Plane SITL service for integration tests. -- Use non-root users, pinned base images, multi-stage builds where native compilation is needed, and health checks for long-running services. -- Provide `docker-compose.yml` for local development/replay and `docker-compose.test.yml` for black-box/SITL test execution. -- Do not bake secrets, provider credentials, mission signing keys, or public dataset payloads into images. - -## Implementation Order - -| Order | Component | Reason | -|-------|-----------|--------| -| 1 | Bootstrap and shared contracts | Establish package, configuration, migrations, CI, DTOs, and error envelopes | -| 2 | Shared geometry/time helpers | Foundational math and timestamp contracts used by camera, VIO, cache, wrapper, and validation | -| 3 | Runtime configuration and error handling | Prevent duplicated config/error behavior across components | -| 4 | Camera ingest/calibration | Produces the frame and occlusion signals required by VIO, anchor, cache, and tests | -| 5 | MAVLink/GCS integration | Supplies FC telemetry DTOs and validates `GPS_INPUT` output contract early | -| 6 | Tile Manager | Owns PostGIS cache manifest, sidecars, COG access, freshness gates, and generated-tile orthorectification | -| 7 | FDR/observability | Provides audit path for all components and validation reports | -| 8 | VIO adapter | Depends on frame and telemetry contracts, blocks wrapper integration | -| 9 | Satellite Service | Depends on tile schema and frame DTOs, feeds anchor verification, and handles pre-flight/post-flight package sync | -| 10 | Anchor verification | Depends on retrieval candidates and cache tile access | -| 11 | Safety/anchor wrapper | Consumes VIO, anchor, camera degradation, MAVLink, and FDR contracts | -| 12 | Validation harness | Uses public interfaces once contracts and runtime components are stable | -| 13 | Black-box, SITL, Jetson, and endurance test tasks | Exercise release gates and acceptance criteria end to end | - -## Acceptance Criteria - -**AC-1: Project scaffolded** -Given the structure plan above -When the implementer executes this task -Then source, test, migration, deployment, configuration, and data directories exist with placeholder files where needed so empty directories are retained. - -**AC-2: Shared contracts initialized** -Given the planned component interfaces -When the scaffold is complete -Then shared DTO, error, configuration, telemetry, geometry, and time-sync contract locations exist and are importable from component skeletons. - -**AC-3: Local infrastructure defined** -Given the system requires local PostGIS, replay, SITL, cache, and FDR paths -When the scaffold is complete -Then `docker-compose.yml`, `docker-compose.test.yml`, `.env.example`, and migration seed directories describe all required local services and volumes. - -**AC-4: CI/CD configured** -Given the pipeline stages in the planning artifacts -When CI runs on a PR -Then format/lint, unit tests, replay black-box smoke, cache/security fixture tests, and artifact collection stages are defined. - -**AC-5: Test harness skeleton ready** -Given black-box tests must use public interfaces only -When the scaffold is complete -Then unit, integration, black-box, fixtures, and SITL test locations exist with runner entry points ready for implementation tasks. - -**AC-6: Deployment evidence paths ready** -Given release requires Jetson, SITL, FDR, cache, and representative replay evidence -When the scaffold is complete -Then deployment scripts, report output paths, and documentation placeholders exist for those evidence artifacts. - -**AC-7: No production secrets or raw frames committed** -Given onboard runtime must not retain raw frames and must protect signing credentials -When the scaffold is reviewed -Then `.gitignore`, `.dockerignore`, and `.env.example` exclude secrets, generated FDR payloads, raw frame dumps, cache payloads, and test result artifacts unless explicitly fixture-scoped. diff --git a/_docs/02_tasks/done/AZ-220_shared_runtime_contracts.md b/_docs/02_tasks/done/AZ-220_shared_runtime_contracts.md deleted file mode 100644 index d0cc71a..0000000 --- a/_docs/02_tasks/done/AZ-220_shared_runtime_contracts.md +++ /dev/null @@ -1,78 +0,0 @@ -# Shared Runtime Contracts - -**Task**: AZ-220_shared_runtime_contracts -**Name**: Shared Runtime Contracts -**Description**: Define the shared DTO and event contract surface used across the onboard runtime. -**Complexity**: 3 points -**Dependencies**: AZ-219_initial_structure -**Component**: Bootstrap / Shared Contracts -**Tracker**: AZ-220 -**Epic**: AZ-206 - -## Problem - -Runtime components need common shapes for frames, telemetry, VIO state, position estimates, candidates, anchors, cache tiles, and FDR events. - -## Outcome - -- Components consume one documented shared contract surface. -- Cross-component DTO drift is prevented before implementation begins. - -## Scope - -### Included -- Shared runtime DTO names, fields, invariants, versioning rules, and contract tests. -- Public contract document for consumers. - -### Excluded -- Component-specific algorithms. -- E2E runner-only report schemas. - -## Acceptance Criteria - -**AC-1: Shared contract exists** -Given runtime components need common DTOs -When the shared contracts are implemented -Then each runtime component can import or reference the same contract surface. - -**AC-2: Contract validation exists** -Given a malformed shared DTO -When validation runs -Then the input is rejected with a structured error. - -## Non-Functional Requirements - -**Compatibility** -- Contract changes follow documented versioning rules. - -**Reliability** -- Invalid or missing required fields are not silently ignored. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | DTO construction for valid minimal values | Accepted | -| AC-2 | Missing required timestamp or ID | Rejected with structured error | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1 | Runtime started with contract consumers | Public interfaces exchange typed records | No component-specific duplicate shape required | Compatibility | - -## Constraints - -- Contracts are shared API surface and must be consumed through documented public modules. -- Raw frame payloads are referenced, not retained in shared DTOs. - -## Risks & Mitigation - -**Risk 1: Contract drift** -- *Risk*: Consumers create local incompatible DTOs. -- *Mitigation*: Contract file is required dependency for consuming tasks. - -## Contract - -This task produces/implements the contract at `_docs/02_document/contracts/shared/runtime_contracts.md`. -Consumers MUST read that file — not this task spec — to discover the interface. diff --git a/_docs/02_tasks/done/AZ-221_shared_geometry_time_sync.md b/_docs/02_tasks/done/AZ-221_shared_geometry_time_sync.md deleted file mode 100644 index 932a446..0000000 --- a/_docs/02_tasks/done/AZ-221_shared_geometry_time_sync.md +++ /dev/null @@ -1,78 +0,0 @@ -# Shared Geometry And Time Sync - -**Task**: AZ-221_shared_geometry_time_sync -**Name**: Shared Geometry And Time Sync -**Description**: Provide shared geospatial and timestamp helper behavior for runtime components. -**Complexity**: 3 points -**Dependencies**: AZ-219_initial_structure, AZ-220_shared_runtime_contracts -**Component**: Shared Geometry And Time Sync -**Tracker**: AZ-221 -**Epic**: AZ-207 - -## Problem - -Camera, VIO, Tile Manager, Satellite Service, Anchor Verification, safety, and FDR need consistent coordinate, footprint, homography, and timestamp behavior. - -## Outcome - -- Shared helpers provide deterministic geometry and time-sync behavior. -- Components do not duplicate geospatial or timestamp alignment logic. - -## Scope - -### Included -- WGS84/local conversions, distance/GSD helpers, footprint projection, homography/covariance conversion support. -- Monotonic timestamp checks, frame-to-IMU window selection, replay ordering, gap/jitter metrics. - -### Excluded -- VIO estimation. -- Cache policy and safety degrade decisions. - -## Acceptance Criteria - -**AC-1: Geometry helpers are deterministic** -Given the same calibration, attitude, altitude, and coordinates -When geometry helpers run -Then they return repeatable footprint and metric outputs. - -**AC-2: Time-sync violations are explicit** -Given frame and telemetry timestamps with a gap or mismatch -When alignment runs -Then the result reports the violation instead of dropping data silently. - -## Non-Functional Requirements - -**Performance** -- Helpers are suitable for hot-path use under the system latency budget. - -**Reliability** -- Invalid calibration, CRS, or timestamp inputs fail explicitly. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | WGS84/local round-trip | Error within tolerance | -| AC-2 | Non-monotonic timestamps | Explicit mismatch result | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1 | Derkachi/replay frame metadata | Footprint and ordering evidence | Deterministic helper outputs in reports | Performance | - -## Constraints - -- Shared helpers do not own policy decisions. -- Timestamp units must match the shared runtime contract. - -## Risks & Mitigation - -**Risk 1: Coordinate-frame confusion** -- *Risk*: Components interpret helper outputs differently. -- *Mitigation*: Contract documents units, frames, and error semantics. - -## Contract - -This task produces/implements the contract at `_docs/02_document/contracts/shared/geometry_time_sync.md`. -Consumers MUST read that file — not this task spec — to discover the interface. diff --git a/_docs/02_tasks/done/AZ-222_runtime_config_errors_telemetry.md b/_docs/02_tasks/done/AZ-222_runtime_config_errors_telemetry.md deleted file mode 100644 index f9612bf..0000000 --- a/_docs/02_tasks/done/AZ-222_runtime_config_errors_telemetry.md +++ /dev/null @@ -1,80 +0,0 @@ -# Runtime Config Errors And Telemetry - -**Task**: AZ-222_runtime_config_errors_telemetry -**Name**: Runtime Config Errors And Telemetry -**Description**: Provide shared configuration, error envelope, health, and telemetry behavior for runtime components. -**Complexity**: 3 points -**Dependencies**: AZ-219_initial_structure, AZ-220_shared_runtime_contracts -**Component**: Runtime Configuration And Errors -**Tracker**: AZ-222 -**Epic**: AZ-208 - -## Problem - -Runtime components need common configuration loading, readiness validation, error handling, and telemetry metadata. - -## Outcome - -- Environment profiles are validated before runtime use. -- Errors and health events are structured and FDR-safe. -- Secrets are referenced without leaking into logs or reports. - -## Scope - -### Included -- Runtime profile validation. -- Shared error/result envelopes. -- Health and metrics metadata. - -### Excluded -- Component-specific business logic. -- FDR storage implementation. - -## Acceptance Criteria - -**AC-1: Required settings are validated** -Given a production profile is missing a required setting -When startup/readiness validation runs -Then the component reports a structured failure. - -**AC-2: Errors are not silent** -Given a dependency failure occurs -When a component reports it -Then the error includes component, category, severity, and retryability. - -## Non-Functional Requirements - -**Reliability** -- Missing configuration and dependency failures are never silently ignored. - -**Compatibility** -- Error categories and config keys follow the contract versioning rules. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Missing production cache dir | Readiness failure | -| AC-2 | Dependency error envelope | Structured fields present | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1 | Invalid env profile | Runtime readiness | Service refuses ready state | Reliability | - -## Constraints - -- Secrets must not be serialized into logs, FDR, or metrics. -- Error handling must not use silent suppression. - -## Risks & Mitigation - -**Risk 1: Environment-specific behavior drifts** -- *Risk*: Development and production profiles behave differently in unsafe ways. -- *Mitigation*: Profile validation is shared and tested. - -## Contract - -This task produces/implements the contract at `_docs/02_document/contracts/shared/config_errors_telemetry.md`. -Consumers MUST read that file — not this task spec — to discover the interface. diff --git a/_docs/02_tasks/done/AZ-223_camera_ingest_calibration.md b/_docs/02_tasks/done/AZ-223_camera_ingest_calibration.md deleted file mode 100644 index 5382420..0000000 --- a/_docs/02_tasks/done/AZ-223_camera_ingest_calibration.md +++ /dev/null @@ -1,89 +0,0 @@ -# Camera Ingest Calibration And Frame Quality - -**Task**: AZ-223_camera_ingest_calibration -**Name**: Camera Ingest Calibration And Frame Quality -**Description**: Ingest navigation frames, attach calibration/timestamp metadata, classify quality, detect occlusion, and provide north-up normalization hints. -**Complexity**: 5 points -**Dependencies**: AZ-220_shared_runtime_contracts, AZ-221_shared_geometry_time_sync, AZ-222_runtime_config_errors_telemetry -**Component**: Camera Ingest And Calibration -**Tracker**: AZ-223 -**Epic**: AZ-209 - -## Problem - -Downstream VIO, retrieval, anchor verification, Tile Manager, and FDR need trustworthy frame metadata and quality decisions before using image data. - -## Outcome - -- Replay and live-source frames are exposed with timestamps, calibration ID, quality, occlusion, and normalization hints. -- Total occlusion/blackout frames are marked unusable for VIO and anchor paths. - -## Scope - -### Included -- Frame source abstraction for replay/live camera boundary. -- Calibration metadata loading and validation. -- Quality and occlusion reports. -- North-up/orthorectification hints as metadata, not unconditional frame mutation. - -### Excluded -- Tile writing and generated COG persistence. -- BASALT processing. - -## Dependencies - -### Document Dependencies -- `_docs/02_document/contracts/shared/runtime_contracts.md` -- `_docs/02_document/contracts/shared/geometry_time_sync.md` -- `_docs/02_document/contracts/shared/config_errors_telemetry.md` - -## Acceptance Criteria - -**AC-1: Usable frame packet emitted** -Given a valid replay frame and calibration -When the frame is ingested -Then a frame packet includes timestamp, calibration ID, quality report, occlusion report, and normalization hint. - -**AC-2: Blackout bypass signal emitted** -Given an unreadable, covered, or total-occlusion frame -When quality classification runs -Then the frame is marked unusable for VIO and anchor matching. - -**AC-3: Raw frames are not retained** -Given normal runtime operation -When a frame is processed -Then only allowed metadata/references are retained outside explicit fixture/test paths. - -## Non-Functional Requirements - -**Performance** -- Frame preprocessing must fit within the system p95 latency budget. - -**Reliability** -- Missing calibration blocks production readiness. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Valid frame with calibration | Frame packet contains required metadata | -| AC-2 | Total occlusion input | `usable_for_vio=false` and `usable_for_anchor=false` | -| AC-3 | Processed frame cleanup | No raw-frame persistence | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1 | Derkachi replay fixture | Frame/telemetry alignment | Accepted frame packets are timestamped | Performance | -| AC-2 | Blackout fixture | Occlusion handling | Visual path degrades safely | Reliability | - -## Constraints - -- Do not rotate every frame in ingest; emit normalization hints for downstream use. -- ADTi hardware assumptions remain blocked until exact specs are verified. - -## Risks & Mitigation - -**Risk 1: False-negative occlusion** -- *Risk*: Bad frames enter VIO or matching. -- *Mitigation*: Conservative occlusion gate and explicit quality flags. diff --git a/_docs/02_tasks/done/AZ-224_mavlink_gcs_gateway.md b/_docs/02_tasks/done/AZ-224_mavlink_gcs_gateway.md deleted file mode 100644 index 4e3a616..0000000 --- a/_docs/02_tasks/done/AZ-224_mavlink_gcs_gateway.md +++ /dev/null @@ -1,84 +0,0 @@ -# MAVLink GCS Gateway - -**Task**: AZ-224_mavlink_gcs_gateway -**Name**: MAVLink GCS Gateway -**Description**: Subscribe to FC telemetry, emit `GPS_INPUT`, and publish QGC-visible status/failsafe messages. -**Complexity**: 3 points -**Dependencies**: AZ-220_shared_runtime_contracts, AZ-222_runtime_config_errors_telemetry -**Component**: MAVLink And GCS Integration -**Tracker**: AZ-224 -**Epic**: AZ-210 - -## Problem - -The runtime needs a strict protocol boundary for ArduPilot Plane telemetry in and GPS-denied estimates/status out. - -## Outcome - -- FC telemetry is normalized into shared samples. -- `GPS_INPUT` is emitted only from validated position estimates. -- QGC status is rate-limited and safety-relevant. - -## Scope - -### Included -- Telemetry subscription behavior. -- `GPS_INPUT` field validation and emission result. -- QGC status/failsafe message emission. - -### Excluded -- Safety policy and covariance calculation. -- SITL test runner implementation. - -## Dependencies - -### Document Dependencies -- `_docs/02_document/contracts/shared/runtime_contracts.md` -- `_docs/02_document/contracts/shared/config_errors_telemetry.md` - -## Acceptance Criteria - -**AC-1: Telemetry sample emitted** -Given a valid FC telemetry stream -When the gateway subscribes -Then normalized telemetry samples are available to consumers. - -**AC-2: Invalid GPS_INPUT is rejected** -Given a malformed or unsafe position estimate -When emission is requested -Then no invalid `GPS_INPUT` packet is emitted. - -**AC-3: Operator status is rate-limited** -Given repeated mode changes or warnings -When status is emitted -Then QGC-visible messages stay within the configured rate. - -## Non-Functional Requirements - -**Reliability** -- Connection loss is surfaced to wrapper/FDR. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Telemetry normalization | Shared sample emitted | -| AC-2 | Invalid fix type/accuracy | Emission rejected | -| AC-3 | Status burst | Rate limit enforced | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-2 | Plane SITL | `GPS_INPUT` output | Fields match ArduPilot expectations | Reliability | - -## Constraints - -- v1 emits `GPS_INPUT` only. -- Do not hide MAVLink disconnects or invalid output errors. - -## Risks & Mitigation - -**Risk 1: ArduPilot parameter mismatch** -- *Risk*: Plane ignores or mishandles emitted estimates. -- *Mitigation*: SITL validation remains a release gate. diff --git a/_docs/02_tasks/done/AZ-225_tile_manager_cache_manifest.md b/_docs/02_tasks/done/AZ-225_tile_manager_cache_manifest.md deleted file mode 100644 index 4c17d99..0000000 --- a/_docs/02_tasks/done/AZ-225_tile_manager_cache_manifest.md +++ /dev/null @@ -1,89 +0,0 @@ -# Tile Manager Cache Manifest - -**Task**: AZ-225_tile_manager_cache_manifest -**Name**: Tile Manager Cache Manifest -**Description**: Validate local cache manifests, signed sidecars, tile freshness, and spatial/descriptor metadata access. -**Complexity**: 5 points -**Dependencies**: AZ-220_shared_runtime_contracts, AZ-221_shared_geometry_time_sync, AZ-222_runtime_config_errors_telemetry -**Component**: Tile Manager -**Tracker**: AZ-225 -**Epic**: AZ-211 - -## Problem - -The runtime must trust only preloaded offline cache tiles with valid signatures, hashes, freshness, resolution, and spatial metadata. - -## Outcome - -- Mission cache validation blocks invalid cache usage. -- Tile windows and descriptor metadata are queryable through local PostGIS-backed metadata. -- Stale or tampered tiles cannot become trusted anchor inputs. - -## Scope - -### Included -- Cache package validation. -- Signed sidecar/hash/freshness checks. -- Tile window and descriptor metadata lookup. -- Cache validation report events. - -### Excluded -- Satellite Service package transfer. -- Generated tile orthorectification/write-back. - -## Dependencies - -### Document Dependencies -- `_docs/02_document/contracts/shared/runtime_contracts.md` -- `_docs/02_document/contracts/shared/geometry_time_sync.md` -- `_docs/02_document/contracts/shared/config_errors_telemetry.md` - -## Acceptance Criteria - -**AC-1: Valid cache activates** -Given a cache package with valid manifests, sidecars, hashes, freshness, and spatial coverage -When cache validation runs -Then the cache becomes available to retrieval and anchor paths. - -**AC-2: Invalid cache is rejected** -Given a stale, unsigned, or hash-mismatched tile -When validation runs -Then the tile is rejected and an auditable reason is recorded. - -**AC-3: Tile metadata is queryable** -Given a candidate footprint or chunk ID -When a consumer requests tile metadata -Then the Tile Manager returns a valid local record or explicit rejection. - -## Non-Functional Requirements - -**Performance** -- Indexed tile lookups meet relocalization-path latency needs. - -**Reliability** -- Local PostgreSQL/PostGIS unavailability blocks mission cache activation. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Valid fixture | Cache available | -| AC-2 | Tampered sidecar | Tile rejected | -| AC-3 | Chunk metadata lookup | Correct record or explicit error | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-2 | Stale/unsigned fixtures | Cache security gate | No invalid tile reaches retrieval | Reliability | - -## Constraints - -- Runtime never fetches satellite data mid-flight. -- Large imagery/descriptors stay as files, not DB blobs. - -## Risks & Mitigation - -**Risk 1: Cache poisoning** -- *Risk*: Bad cache entries influence anchor decisions. -- *Mitigation*: Signature, hash, freshness, and provenance gates are mandatory. diff --git a/_docs/02_tasks/done/AZ-226_generated_tile_orthorectification.md b/_docs/02_tasks/done/AZ-226_generated_tile_orthorectification.md deleted file mode 100644 index 76b0098..0000000 --- a/_docs/02_tasks/done/AZ-226_generated_tile_orthorectification.md +++ /dev/null @@ -1,88 +0,0 @@ -# Generated Tile Orthorectification And Sync Package - -**Task**: AZ-226_generated_tile_orthorectification -**Name**: Generated Tile Orthorectification And Sync Package -**Description**: Convert eligible nadir frames into generated orthorectified COG tiles and prepare post-flight sync packages. -**Complexity**: 5 points -**Dependencies**: AZ-223_camera_ingest_calibration, AZ-225_tile_manager_cache_manifest -**Component**: Tile Manager -**Tracker**: AZ-226 -**Epic**: AZ-211 - -## Problem - -Generated tiles must be written only when pose, frame quality, and provenance gates make them safe to retain for post-flight Satellite Service review. - -## Outcome - -- Eligible nadir frames can become generated COG candidates with sidecars. -- Unsafe or over-confident tile writes are rejected. -- Post-flight generated-tile packages carry enough metadata for Satellite Service ingest/voting. - -## Scope - -### Included -- Orthorectification request handling. -- Generated COG + sidecar metadata creation. -- Covariance/quality gates and trust level assignment. -- Sync package preparation. - -### Excluded -- Satellite Service upload transport. -- Promotion to trusted basemap onboard. - -## Dependencies - -### Document Dependencies -- `_docs/02_document/contracts/shared/runtime_contracts.md` -- `_docs/02_document/contracts/shared/geometry_time_sync.md` - -## Acceptance Criteria - -**AC-1: Eligible frame writes generated tile** -Given a high-confidence pose and usable frame -When tile generation runs -Then a generated COG candidate and sidecar are staged. - -**AC-2: Unsafe frame is rejected** -Given high covariance or unusable frame quality -When tile generation runs -Then no trusted tile is written. - -**AC-3: Sync package is auditable** -Given generated candidate tiles exist -When a package is prepared -Then it includes manifest delta, sidecars, parent covariance, and trust level. - -## Non-Functional Requirements - -**Reliability** -- Generated tiles are never promoted directly to trusted basemap onboard. - -**Performance** -- Tile generation must not block localization output. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Valid tile request | COG + sidecar staged | -| AC-2 | Covariance too high | Write rejected | -| AC-3 | Package creation | Required metadata present | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-2 | Poisoning fixture | Generated tile gate | No direct trusted promotion | Reliability | - -## Constraints - -- Tile Manager performs generated tile writes; camera ingest only provides metadata/hints. -- Missing sidecars make generated tiles ineligible for upload. - -## Risks & Mitigation - -**Risk 1: Misaligned generated tile** -- *Risk*: Wrong pose creates harmful future anchor data. -- *Mitigation*: Parent covariance, frame quality, and post-flight validation gates. diff --git a/_docs/02_tasks/done/AZ-227_fdr_event_recorder.md b/_docs/02_tasks/done/AZ-227_fdr_event_recorder.md deleted file mode 100644 index d4e7c33..0000000 --- a/_docs/02_tasks/done/AZ-227_fdr_event_recorder.md +++ /dev/null @@ -1,88 +0,0 @@ -# FDR Event Recorder And Export Surface - -**Task**: AZ-227_fdr_event_recorder -**Name**: FDR Event Recorder And Export Surface -**Description**: Record bounded replayable mission evidence and expose exportable post-flight summaries. -**Complexity**: 5 points -**Dependencies**: AZ-220_shared_runtime_contracts, AZ-222_runtime_config_errors_telemetry -**Component**: FDR And Observability -**Tracker**: AZ-227 -**Epic**: AZ-212 - -## Problem - -The system needs compact, bounded, queryable evidence for estimates, inputs, health, anchors, tile writes, and safety transitions. - -## Outcome - -- Runtime components can append structured FDR events. -- Storage rollover and health behavior are explicit. -- Post-flight exports are available for analysis and release evidence. - -## Scope - -### Included -- Append event behavior. -- PostgreSQL event index and CBOR segment payload contract. -- Rollover and storage-full handling. -- Export request/result behavior. - -### Excluded -- Component-specific event payload generation. -- E2E report collation. - -## Dependencies - -### Document Dependencies -- `_docs/02_document/contracts/shared/runtime_contracts.md` -- `_docs/02_document/contracts/shared/config_errors_telemetry.md` - -## Acceptance Criteria - -**AC-1: Events are appendable** -Given a valid FDR event -When a component appends it -Then metadata is indexed and payload is stored within bounds. - -**AC-2: Storage pressure is handled** -Given segment or storage limits are reached -When append continues -Then rollover or critical status behavior is explicit. - -**AC-3: Export produces evidence** -Given a completed run -When export is requested -Then queryable evidence and optional analytics artifacts are produced. - -## Non-Functional Requirements - -**Performance** -- FDR appends must not block hot-path localization. - -**Reliability** -- Append failures are surfaced to callers and health state. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Valid event append | Indexed metadata and payload reference | -| AC-2 | Rollover threshold | Rollover event recorded | -| AC-3 | Export request | Evidence artifact produced | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-2 | 8-hour synthetic load | FDR cap and rollover | <=64 GB or explicit rollover evidence | Performance | - -## Constraints - -- Raw frames are not retained by default. -- Secrets are not logged in FDR payloads. - -## Risks & Mitigation - -**Risk 1: FDR affects latency** -- *Risk*: Append pressure slows localization. -- *Mitigation*: Bounded segments and async-friendly append semantics. diff --git a/_docs/02_tasks/done/AZ-228_vio_adapter.md b/_docs/02_tasks/done/AZ-228_vio_adapter.md deleted file mode 100644 index ac44b86..0000000 --- a/_docs/02_tasks/done/AZ-228_vio_adapter.md +++ /dev/null @@ -1,90 +0,0 @@ -# VIO Adapter - -**Task**: AZ-228_vio_adapter -**Name**: VIO Adapter -**Description**: Wrap the selected relative VIO backend as a replaceable component with health and error behavior. -**Complexity**: 5 points -**Dependencies**: AZ-221_shared_geometry_time_sync, AZ-222_runtime_config_errors_telemetry, AZ-223_camera_ingest_calibration, AZ-224_mavlink_gcs_gateway -**Component**: VIO Adapter -**Tracker**: AZ-228 -**Epic**: AZ-213 - -## Problem - -The safety wrapper needs relative VIO state from calibrated frames and FC IMU without inheriting backend-specific internals. - -## Outcome - -- Backend initialization, processing, and health behavior are exposed through a replaceable adapter. -- Tracking loss and timestamp mismatch are explicit. -- The adapter never emits WGS84 coordinates or safety decisions. - -## Scope - -### Included -- Initialization and runtime health. -- Frame + IMU processing behavior. -- Relative pose/velocity/bias output and quality metadata. -- Native bridge boundary. - -### Excluded -- Absolute anchor fusion and covariance authority. -- Satellite matching fallback implementation. - -## Dependencies - -### Document Dependencies -- `_docs/02_document/contracts/shared/runtime_contracts.md` -- `_docs/02_document/contracts/shared/geometry_time_sync.md` -- `_docs/02_document/contracts/shared/config_errors_telemetry.md` - -## Acceptance Criteria - -**AC-1: VIO state emitted** -Given synchronized frame and IMU samples -When processing succeeds -Then a relative VIO state packet with tracking quality is emitted. - -**AC-2: Timestamp mismatch is explicit** -Given frame/IMU timestamps are inconsistent -When processing is requested -Then the adapter rejects the packet with a timestamp mismatch error. - -**AC-3: Health is observable** -Given initialization or tracking quality changes -When health is requested -Then the adapter reports current VIO readiness and degradation state. - -## Non-Functional Requirements - -**Performance** -- Adapter processing must be profiled against Jetson latency/memory limits. - -**Reliability** -- Backend failures are surfaced, not hidden. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Valid synchronized packet | VIO state emitted | -| AC-2 | Bad timestamp window | Explicit error | -| AC-3 | Tracking loss | Health reports degraded | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1 | Derkachi/public replay | Relative VIO path | Continuous estimates where data supports it | Performance | - -## Constraints - -- BASALT remains the current selected backend, but package and folder names must stay backend-neutral. -- The VIO adapter is not the safety authority. -- GPL VIO dependencies remain reference-only unless explicitly approved. - -## Risks & Mitigation - -**Risk 1: Nadir fixed-wing fit** -- *Risk*: The selected VIO backend underperforms on low-parallax terrain. -- *Mitigation*: Representative replay and reference comparisons gate acceptance. diff --git a/_docs/02_tasks/done/AZ-229_satellite_service_sync.md b/_docs/02_tasks/done/AZ-229_satellite_service_sync.md deleted file mode 100644 index 0d771b8..0000000 --- a/_docs/02_tasks/done/AZ-229_satellite_service_sync.md +++ /dev/null @@ -1,87 +0,0 @@ -# Satellite Service Sync Boundary - -**Task**: AZ-229_satellite_service_sync -**Name**: Satellite Service Sync Boundary -**Description**: Import mission cache packages before flight and upload generated-tile packages after flight. -**Complexity**: 3 points -**Dependencies**: AZ-222_runtime_config_errors_telemetry, AZ-225_tile_manager_cache_manifest, AZ-226_generated_tile_orthorectification -**Component**: Satellite Service -**Tracker**: AZ-229 -**Epic**: AZ-214 - -## Problem - -The onboard runtime needs a clear boundary for Satellite Service package exchange without allowing mid-flight network calls. - -## Outcome - -- Pre-flight cache packages can be imported and handed to Tile Manager validation. -- Post-flight generated-tile packages can be uploaded/retried. -- Mid-flight provider or Satellite Service calls are explicitly blocked. - -## Scope - -### Included -- Pre-flight import behavior. -- Post-flight generated-tile upload behavior. -- Package status and retry/error reporting. - -### Excluded -- In-flight retrieval ranking. -- Tile manifest validation and generated tile creation. - -## Dependencies - -### Document Dependencies -- `_docs/02_document/contracts/shared/runtime_contracts.md` -- `_docs/02_document/contracts/shared/config_errors_telemetry.md` - -## Acceptance Criteria - -**AC-1: Pre-flight package import succeeds** -Given a valid Satellite Service mission cache package -When import runs before flight -Then the package is available for Tile Manager validation. - -**AC-2: Post-flight upload is auditable** -Given a generated-tile package exists after landing -When upload runs -Then success, rejection, or retryable failure is recorded. - -**AC-3: Mid-flight network calls are blocked** -Given the runtime is in flight mode -When cache data is missing -Then the component does not call a satellite provider or suite service. - -## Non-Functional Requirements - -**Reliability** -- Upload failures retain packages for retry. - -**Security** -- Signing credentials are never logged. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Valid import package | Package ready for validation | -| AC-2 | Upload unavailable | Retryable failure recorded | -| AC-3 | Flight-mode missing data | No network call | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-3 | Network disabled in replay | Relocalization missing data | Degraded/no-candidate behavior, no fetch | Security | - -## Constraints - -- No in-flight Satellite Service or satellite-provider network dependency. -- Package sync is before takeoff or after landing only. - -## Risks & Mitigation - -**Risk 1: Boundary confusion** -- *Risk*: Retrieval code starts fetching provider data mid-flight. -- *Mitigation*: Flight-mode invariant is acceptance-tested. diff --git a/_docs/02_tasks/done/AZ-230_satellite_service_vpr_retrieval.md b/_docs/02_tasks/done/AZ-230_satellite_service_vpr_retrieval.md deleted file mode 100644 index 715e2e6..0000000 --- a/_docs/02_tasks/done/AZ-230_satellite_service_vpr_retrieval.md +++ /dev/null @@ -1,89 +0,0 @@ -# Satellite Service Local VPR Retrieval - -**Task**: AZ-230_satellite_service_vpr_retrieval -**Name**: Satellite Service Local VPR Retrieval -**Description**: Retrieve local VPR candidates from preloaded descriptors and FAISS indexes. -**Complexity**: 5 points -**Dependencies**: AZ-223_camera_ingest_calibration, AZ-225_tile_manager_cache_manifest, AZ-229_satellite_service_sync -**Component**: Satellite Service -**Tracker**: AZ-230 -**Epic**: AZ-214 - -## Problem - -Relocalization needs ranked satellite/cache candidates, but retrieval must be trigger-based and use only local preloaded cache/index data. - -## Outcome - -- DINOv2-VLAD descriptor extraction and CPU FAISS top-K candidate retrieval are available. -- Candidate freshness and dynamic top-K policy are carried forward. -- No-candidate/index failures produce degraded behavior rather than unsafe anchors. - -## Scope - -### Included -- Index load/readiness behavior. -- Query descriptor and top-K candidate retrieval. -- Freshness tagging and retrieval result metadata. -- Descriptor fidelity gate for optimized engines. - -### Excluded -- Local matching/RANSAC. -- In-flight network fetches. - -## Dependencies - -### Document Dependencies -- `_docs/02_document/contracts/shared/runtime_contracts.md` -- `_docs/02_document/contracts/shared/geometry_time_sync.md` -- `_docs/02_document/contracts/shared/config_errors_telemetry.md` - -## Acceptance Criteria - -**AC-1: Index loads before retrieval** -Given a valid local descriptor/index package -When index loading runs -Then retrieval readiness is reported. - -**AC-2: Top-K candidates returned** -Given a relocalization request and loaded local index -When retrieval runs -Then bounded candidates include tile/chunk IDs, scores, footprints, and freshness status. - -**AC-3: Missing candidates degrade safely** -Given no valid candidates or index failure -When retrieval runs -Then the result is explicit no-candidate/degraded behavior. - -## Non-Functional Requirements - -**Performance** -- Retrieval is trigger-based and profiled against Jetson limits. - -**Security** -- Retrieval never performs mid-flight provider calls. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Valid index | Ready status | -| AC-2 | Query frame | Candidate list with freshness | -| AC-3 | Missing index | Explicit degraded/no-candidate result | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-2 | Public/cache fixture | VPR recall and top-K policy | Correct candidate bounds and freshness | Performance | - -## Constraints - -- Retrieval is not per-frame steady-state work. -- TensorRT/ONNX path is accepted only after descriptor-fidelity tests pass. - -## Risks & Mitigation - -**Risk 1: Trigger path exceeds Jetson budget** -- *Risk*: Descriptor extraction or FAISS query is too slow. -- *Mitigation*: CPU-first FAISS, bounded top-K, and profiling gates. diff --git a/_docs/02_tasks/done/AZ-231_anchor_verification_matching.md b/_docs/02_tasks/done/AZ-231_anchor_verification_matching.md deleted file mode 100644 index 176f306..0000000 --- a/_docs/02_tasks/done/AZ-231_anchor_verification_matching.md +++ /dev/null @@ -1,88 +0,0 @@ -# Anchor Verification Matching And Geometry Gates - -**Task**: AZ-231_anchor_verification_matching -**Name**: Anchor Verification Matching And Geometry Gates -**Description**: Verify retrieved candidates with ALIKED/DISK + LightGlue and geometric safety gates. -**Complexity**: 5 points -**Dependencies**: AZ-223_camera_ingest_calibration, AZ-225_tile_manager_cache_manifest, AZ-230_satellite_service_vpr_retrieval -**Component**: Anchor Verification -**Tracker**: AZ-231 -**Epic**: AZ-215 - -## Problem - -VPR candidates are not trusted fixes; they require local feature matching, RANSAC geometry, provenance checks, and measurable rejection evidence. - -## Outcome - -- Anchor candidates are accepted or rejected with MRE, inlier count, homography, freshness/provenance, and reason metadata. -- Matcher profiles can be benchmarked without making learned matching a per-frame VIO hot path. - -## Scope - -### Included -- ALIKED/DISK + LightGlue matching profile behavior. -- SIFT/ORB baseline profile. -- OpenCV RANSAC/USAC geometry checks. -- Anchor decision output and rejection reasons. - -### Excluded -- VPR retrieval ranking. -- Safety wrapper anchor fusion. - -## Dependencies - -### Document Dependencies -- `_docs/02_document/contracts/shared/runtime_contracts.md` -- `_docs/02_document/contracts/shared/geometry_time_sync.md` -- `_docs/02_document/contracts/shared/config_errors_telemetry.md` - -## Acceptance Criteria - -**AC-1: Candidate verification emits evidence** -Given retrieved candidates and a usable frame -When verification runs -Then each result includes acceptance state, MRE, inlier count, and rejection/acceptance reason. - -**AC-2: Unsafe candidates are rejected** -Given low inliers, high MRE, stale provenance, or geometry failure -When verification runs -Then no accepted anchor decision is emitted for that candidate. - -**AC-3: Matcher benchmark is reportable** -Given configured matcher profiles -When benchmark runs -Then profile runtime and quality metrics are reported. - -## Non-Functional Requirements - -**Performance** -- Learned matching is trigger-based and profiled separately from BASALT. - -**Reliability** -- SuperPoint is excluded from production unless legal approval exists. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Valid matching fixture | Evidence fields present | -| AC-2 | Bad geometry fixture | Rejected decision | -| AC-3 | Benchmark profiles | Metrics emitted | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1 | Aerial/cache fixture | Anchor verification path | Accepted anchors meet MRE/inlier gates | Performance | - -## Constraints - -- ALIKED/DISK + LightGlue supplies correspondences, not full VIO. -- Anchor verification does not decide final safety fusion. - -## Risks & Mitigation - -**Risk 1: False anchor acceptance** -- *Risk*: Cross-domain match looks plausible but is wrong. -- *Mitigation*: Geometry, freshness, provenance, and downstream Mahalanobis gates. diff --git a/_docs/02_tasks/done/AZ-232_safety_anchor_state_machine.md b/_docs/02_tasks/done/AZ-232_safety_anchor_state_machine.md deleted file mode 100644 index 89f7230..0000000 --- a/_docs/02_tasks/done/AZ-232_safety_anchor_state_machine.md +++ /dev/null @@ -1,97 +0,0 @@ -# Safety Anchor State Machine - -**Task**: AZ-232_safety_anchor_state_machine -**Name**: Safety Anchor State Machine -**Description**: Own authoritative localization state, confidence, anchor fusion, degraded modes, tile-write eligibility, and MAVLink output semantics. -**Complexity**: 5 points -**Dependencies**: AZ-223_camera_ingest_calibration, AZ-224_mavlink_gcs_gateway, AZ-227_fdr_event_recorder, AZ-228_vio_adapter, AZ-231_anchor_verification_matching -**Component**: Safety And Anchor Wrapper -**Tracker**: AZ-232 -**Epic**: AZ-216 - -## Problem - -The product needs one safety authority that converts VIO, telemetry, camera quality, and anchor evidence into honest localization outputs and degraded/failsafe behavior. - -## Outcome - -- Wrapper updates localization state from VIO and anchors. -- Covariance grows honestly in degraded modes. -- `GPS_INPUT` semantics, source labels, and tile-write eligibility are controlled by the wrapper. - -## Scope - -### Included -- VIO update handling. -- Anchor acceptance/rejection integration. -- IMU-only degraded propagation. -- Covariance/source-label/fix-type behavior. -- Tile-write eligibility decisions. - -### Excluded -- VIO backend internals. -- MAVLink transport implementation. -- Generated tile writing. - -## Dependencies - -### Document Dependencies -- `_docs/02_document/contracts/shared/runtime_contracts.md` -- `_docs/02_document/contracts/shared/geometry_time_sync.md` -- `_docs/02_document/contracts/shared/config_errors_telemetry.md` - -## Acceptance Criteria - -**AC-1: VIO state updates position estimate** -Given valid VIO state and telemetry context -When the wrapper processes the update -Then it emits an estimate with source label and honest covariance. - -**AC-2: Accepted anchor can correct state** -Given an anchor decision that passes safety gates -When the wrapper considers it -Then the state may become `satellite_anchored` with recorded evidence. - -**AC-3: Blackout degrades safely** -Given total visual blackout or tracking loss -When degraded propagation runs -Then covariance grows monotonically and failsafe/no-fix semantics occur at thresholds. - -**AC-4: Tile-write eligibility is conservative** -Given a frame and current estimate -When tile eligibility is requested -Then only sufficiently trusted poses are eligible for generated tile writes. - -## Non-Functional Requirements - -**Safety** -- Confidence must not be optimistic relative to known error/covariance. - -**Reliability** -- State invariant violations are surfaced and recorded. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Healthy VIO update | Estimate emitted | -| AC-2 | Accepted/rejected anchors | State updates only on accepted evidence | -| AC-3 | Blackout thresholds | `dead_reckoned` then no-fix/failsafe | -| AC-4 | Tile eligibility | Covariance/quality gates enforced | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-3 | Blackout + spoofing SITL | Degraded behavior | QGC/FDR/fix fields match thresholds | Safety | - -## Constraints - -- The VIO backend is not the safety authority. -- The wrapper does not call Tile Manager directly during anchor acceptance; freshness/provenance arrives through anchor evidence. - -## Risks & Mitigation - -**Risk 1: Over-trusted dead reckoning** -- *Risk*: IMU-only propagation is believed for too long. -- *Mitigation*: Monotonic covariance growth and no-fix/failsafe thresholds. diff --git a/_docs/02_tasks/done/AZ-233_test_infrastructure.md b/_docs/02_tasks/done/AZ-233_test_infrastructure.md deleted file mode 100644 index 26ccd4e..0000000 --- a/_docs/02_tasks/done/AZ-233_test_infrastructure.md +++ /dev/null @@ -1,163 +0,0 @@ -# Test Infrastructure - -**Task**: AZ-233_test_infrastructure -**Name**: Test Infrastructure -**Description**: Scaffold the blackbox and e2e test project: runner, deterministic fixtures, isolated replay/SITL environment, reporting, and external dependency stubs. -**Complexity**: 5 points -**Dependencies**: AZ-240_native_vio_backend_integration, AZ-241_real_satellite_vpr_descriptor_retrieval, AZ-242_real_anchor_feature_matching_ransac -**Component**: Blackbox Tests -**Tracker**: AZ-233 -**Epic**: AZ-218 - -## Test Project Folder Layout - -```text -e2e/ -├── replay/ -│ ├── run_replay.py -│ ├── scenarios/ -│ └── reports/ -├── fixtures/ -│ ├── cache/ -│ ├── mavlink/ -│ ├── telemetry/ -│ └── expected/ -├── tests/ -│ ├── test_still_image_replay.py -│ ├── test_vio_replay.py -│ ├── test_satellite_anchor.py -│ ├── test_blackout_spoofing.py -│ ├── test_resource_limits.py -│ └── test_security_gates.py -├── mocks/ -│ ├── satellite_cache_stub/ -│ ├── ardupilot_sitl/ -│ └── qgc_observer/ -└── reports/ -``` - -### Layout Rationale - -The test project keeps blackbox/e2e runner code outside product runtime internals. Scenario definitions, fixtures, mocks, and reports are separated so tests can reset state between runs and produce release evidence without importing private component modules. - -Test implementation starts only after remediation tasks AZ-240, AZ-241, and AZ-242 close the native VIO, real satellite VPR, and real anchor matching gaps found during autodev verification. - -## Mock Services - -| Mock Service | Replaces | Interfaces | Behavior | -|-------------|----------|------------|----------| -| `satellite_cache_stub` | Offline Azaion Suite Satellite Service cache package | Local COG/manifest/descriptor fixture volume | Serves preloaded valid, stale, unsigned, hash-mismatched, and low-resolution cache fixtures; never performs network fetches during flight-mode tests. | -| `ardupilot_sitl` | ArduPilot Plane flight controller | MAVLink telemetry and `GPS_INPUT` receiving path | Emits generated IMU, attitude, GPS health, spoofing, and failsafe traces; records injected `GPS_INPUT` for assertions. | -| `qgc_observer` | QGroundControl status consumer | MAVLink/tlog parser | Records downsampled `STATUSTEXT`, status, and failsafe messages for rate and content assertions. | - -### Mock Control API - -Each mock or runner fixture must expose deterministic scenario controls for normal replay, stale cache, missing cache, spoofed GPS, blackout, restart, and resource-load modes. Recorded interactions must be queryable after each test run for assertions. - -## Docker Test Environment - -### `docker-compose.test.yml` Structure - -| Service | Image / Build | Purpose | Depends On | -|---------|---------------|---------|------------| -| `gps-denied-service` | Project runtime image or local package mount | System under test | `satellite-cache-stub` | -| `replay-consumer` | Python replay/test harness | Feeds frames, telemetry, cache data, and faults | `gps-denied-service`, mock services | -| `satellite-cache-stub` | Fixture volume/service | Provides offline cache manifests, sidecars, descriptors, and generated invalid variants | none | -| `ardupilot-plane-sitl` | SITL container or local process wrapper | Validates `GPS_INPUT`, spoofing, and failsafe behavior | `gps-denied-service` | -| `qgc-observer` | MAVLink log parser | Verifies GCS-visible status output | `ardupilot-plane-sitl` | - -### Networks and Volumes - -- `replay-net`: connects the runtime, replay consumer, and satellite-cache stub. -- `sitl-net`: connects the runtime, ArduPilot Plane SITL, and QGC observer. -- `input-data`: read-only mount for `_docs/00_problem/input_data/`. -- `expected-results`: read-only mount for expected coordinate and report fixtures. -- `derkachi-replay`: read-only mount for `flight_derkachi.mp4` and `data_imu.csv`. -- `satellite-cache`: fixture cache volume with valid and invalid manifests. -- `fdr-output`: fresh per-run output volume for FDR and report artifacts. - -## Test Runner Configuration - -**Framework**: Python pytest-style replay harness. -**Entry point**: `run-blackbox-replay` or equivalent pytest command that executes scenario groups and writes reports. -**Reports**: CSV summary plus FDR validation Markdown. - -### Fixture Strategy - -| Fixture | Scope | Purpose | -|---------|-------|---------| -| `project_60_still_images` | session | Provides 60 nadir images and expected WGS84 centers. | -| `derkachi_video_telemetry` | session | Provides synchronized video, IMU, and `GLOBAL_POSITION_INT` replay data. | -| `cache_integrity_fixtures` | function | Provides valid, stale, unsigned, hash-mismatched, and low-resolution cache variants. | -| `sitl_spoofing_scenarios` | function | Provides generated GPS loss/spoofing and blackout traces. | -| `public_nadir_vio_candidates` | optional/session | Provides public or representative synchronized datasets when available. | - -## Test Data Fixtures - -| Data Set | Source | Format | Used By | -|----------|--------|--------|---------| -| `project_60_still_images` | `_docs/00_problem/input_data/` | JPG + metadata | Still-image accuracy, confidence, latency smoke | -| `expected_frame_centers` | `_docs/00_problem/input_data/coordinates.csv` and expected-results report | CSV/Markdown | Geolocation assertions | -| `derkachi_video_telemetry` | `_docs/00_problem/input_data/flight_derkachi/` | MP4 + CSV | VIO replay, latency, resilience | -| `cache_integrity_fixtures` | generated fixture volume | COG/manifest/sidecar/index fixtures | Cache freshness, poisoning, no-fetch tests | -| `sitl_spoofing_scenarios` | generated by SITL harness | MAVLink/tlog traces | Spoofing, blackout, failsafe, GCS status | -| `public_nadir_vio_candidates` | pinned external fixtures | dataset-specific | Final VIO and satellite-anchor validation | - -### Data Isolation - -Every run uses read-only input fixtures and fresh run-scoped output directories. FDR, generated tiles, tlogs, and reports are written only to per-run output volumes. Mock state and generated fixtures are reset before each scenario group. - -## Test Reporting - -**Format**: CSV summary and Markdown evidence report. -**Output paths**: `test-results/blackbox-report.csv` and `test-results/fdr-validation-summary.md`. -**Required columns**: Test ID, test name, input dataset, execution time, result, error distance, source label, covariance 95% semi-major, `GPS_INPUT.fix_type`, and error message. - -## Acceptance Criteria - -**AC-1: Test environment starts** -Given the Docker/replay test environment -When the test stack starts -Then the runtime, replay consumer, cache fixture, SITL, and observer services are reachable or report a clear blocked prerequisite. - -**AC-2: External dependency stubs are deterministic** -Given a scenario config for cache, MAVLink, QGC, or fixture behavior -When the replay consumer executes it -Then mocks produce repeatable responses and expose recorded interactions for assertions. - -**AC-3: Test runner executes scenario groups** -Given valid fixtures and a running test environment -When the test runner starts -Then it discovers and executes blackbox, performance, resilience, security, and resource-limit scenario groups. - -**AC-4: Reports are generated** -Given a completed or blocked test run -When reporting finishes -Then CSV and Markdown evidence files are written with the required columns, metrics, artifact paths, and blocked-prerequisite reasons. - -## Non-Functional Requirements - -**Reliability** -- Missing hardware, public datasets, calibration, or SITL prerequisites are reported as `blocked`, not `passed`. - -**Security** -- Fixture stubs must not access external satellite-provider or Suite service networks during in-flight test scenarios. - -**Data Isolation** -- No test may mutate source fixtures or write FDR/generated-tile artifacts outside run-scoped output paths. - -## Constraints - -- The test suite must use public runtime boundaries only: navigation frames, telemetry, offline cache, MAVLink output, QGC status, and FDR outputs. -- The suite must not import private estimator, BASALT, wrapper, or tile-manager internals. -- Hardware-specific Jetson gates remain release-gate tests and may be skipped or blocked in ordinary local replay. - -## Risks & Mitigation - -**Risk 1: Environment prerequisites hide real failures** -- *Risk*: Missing hardware, calibration, or datasets could be treated as success. -- *Mitigation*: Report unavailable prerequisites as `blocked` with explicit artifact evidence. - -**Risk 2: Fixture mutation contaminates later runs** -- *Risk*: Generated FDR, cache, or SITL output changes expected input fixtures. -- *Mitigation*: Use read-only fixture mounts and fresh run-scoped output volumes for every execution. diff --git a/_docs/02_tasks/done/AZ-234_replay_geolocation_confidence_tests.md b/_docs/02_tasks/done/AZ-234_replay_geolocation_confidence_tests.md deleted file mode 100644 index 3a9ee8b..0000000 --- a/_docs/02_tasks/done/AZ-234_replay_geolocation_confidence_tests.md +++ /dev/null @@ -1,88 +0,0 @@ -# Replay Geolocation And Confidence Tests - -**Task**: AZ-234_replay_geolocation_confidence_tests -**Name**: Replay Geolocation And Confidence Tests -**Description**: Implement blackbox tests for still-image geolocation, confidence/source-label output, and replay latency smoke. -**Complexity**: 3 points -**Dependencies**: AZ-233_test_infrastructure -**Component**: Blackbox Tests -**Tracker**: AZ-234 -**Epic**: AZ-218 - -## Problem - -The project needs deterministic blackbox evidence that the 60-image replay path emits WGS84 frame-center estimates with required confidence fields and latency metrics. - -## Outcome - -- Still-image replay reports per-frame coordinate error and aggregate threshold results. -- Every emitted estimate includes covariance, source label, and anchor-age fields. -- Replay smoke latency and dropped-frame metrics are captured in the shared report format. - -## Scope - -### Included - -- FT-P-01 Still-Image Frame Center Geolocation. -- FT-P-02 Position Confidence Output Contract. -- NFT-PERF-01 Per-Frame Latency On Project Still Images. -- CSV and Markdown evidence output for these scenarios. - -### Excluded - -- Synchronized VIO video/IMU replay. -- Satellite-anchor VPR/local matching. -- Jetson-only release-gate profiling. - -## Acceptance Criteria - -**AC-1: Still-image coordinates are validated** -Given the 60-image project fixture and expected frame-center coordinates -When the replay test runs -Then per-frame WGS84 error is reported and aggregate 50 m / 20 m thresholds are evaluated. - -**AC-2: Confidence output contract is validated** -Given emitted position estimates from the replay -When the test inspects public output fields -Then each estimate includes WGS84 coordinates, 95% covariance semi-major axis, source label, and anchor age. - -**AC-3: Replay latency is measured** -Given the still-image replay runs at the configured smoke rate -When processing completes -Then capture-to-output latency and dropped-frame rate are recorded with pass/fail or blocked status. - -## Non-Functional Requirements - -**Performance** -- Replay smoke evidence includes p50/p95/p99 latency and dropped-frame rate. - -**Reliability** -- Missing or invalid expected-coordinate fixtures fail fixture validation before scenario execution. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Expected-coordinate loader validation | Invalid coordinates are rejected before replay | -| AC-2 | Report field validation | Missing confidence/source fields fail the scenario | -| AC-3 | Latency metric aggregation | p50/p95/p99 and dropped-frame metrics are emitted | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1 | `project_60_still_images`, `expected_frame_centers` | FT-P-01 | >=80% within 50 m and >=50% within 20 m or explicit failure | Reliability | -| AC-2 | Same replay output | FT-P-02 | 100% of emitted estimates include required confidence fields | Reliability | -| AC-3 | Replay smoke run | NFT-PERF-01 | Latency and drop-rate metrics are recorded | Performance | - -## Constraints - -- Tests must use public replay input and output artifacts only. -- Input fixtures must be mounted read-only. -- Blocked prerequisites must be reported as `blocked`, not `passed`. - -## Risks & Mitigation - -**Risk 1: Calibration limits are mistaken for product failure** -- *Risk*: Fixture limits can make absolute accuracy inconclusive. -- *Mitigation*: Report the fixture source and threshold basis with each failure. diff --git a/_docs/02_tasks/done/AZ-235_vio_replay_performance_tests.md b/_docs/02_tasks/done/AZ-235_vio_replay_performance_tests.md deleted file mode 100644 index 925ba33..0000000 --- a/_docs/02_tasks/done/AZ-235_vio_replay_performance_tests.md +++ /dev/null @@ -1,89 +0,0 @@ -# VIO Replay Performance Tests - -**Task**: AZ-235_vio_replay_performance_tests -**Name**: VIO Replay Performance Tests -**Description**: Implement synchronized video/IMU replay tests for VIO output, covariance evidence, and replay performance metrics. -**Complexity**: 5 points -**Dependencies**: AZ-233_test_infrastructure, AZ-240_native_vio_backend_integration -**Component**: Blackbox Tests -**Tracker**: AZ-235 -**Epic**: AZ-218 - -## Problem - -The runtime needs blackbox evidence that synchronized navigation video and flight-controller telemetry can drive VIO/wrapper output with honest confidence and measurable performance. - -This test task must run after AZ-240 so it validates the real native VIO path rather than the deterministic scaffold. - -## Outcome - -- Derkachi video/telemetry fixture alignment is validated before replay. -- Synchronized replay produces frame-by-frame output or a clear blocked/failure reason. -- Latency, completion rate, memory, trajectory comparison, and calibration-gated checks are reported. - -## Scope - -### Included - -- FT-P-03 BASALT VIO Replay With Synchronized Video/Telemetry. -- NFT-PERF-02 BASALT + Wrapper Replay Latency. -- Public/representative dataset prerequisite reporting. - -### Excluded - -- Satellite-anchor local verification. -- SITL spoofing/failsafe scenarios. -- Thermal/endurance release gates. - -## Acceptance Criteria - -**AC-1: Replay fixture alignment is validated** -Given the Derkachi MP4 and telemetry CSV -When fixture validation runs -Then duration, frame-to-telemetry ratio, and timestamp monotonicity are verified before replay. - -**AC-2: Synchronized replay emits estimates** -Given a valid synchronized video/IMU replay fixture -When replay executes -Then estimates are emitted frame-by-frame with source labels, covariance, and segment evidence. - -**AC-3: VIO performance evidence is reported** -Given replay completed or blocked -When reporting finishes -Then latency, completion rate, memory, and calibration/public-dataset prerequisite status are written. - -## Non-Functional Requirements - -**Performance** -- Reports include per-frame latency and memory metrics where the environment can measure them. - -**Reliability** -- Calibration-gated absolute accuracy checks must be marked explicitly instead of silently passing. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Video/telemetry validator | Invalid duration or timestamp alignment blocks replay | -| AC-2 | Replay result parser | Missing per-frame confidence fields fail the scenario | -| AC-3 | Calibration gate reporting | Missing calibration/public data is reported as blocked | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1 | `derkachi_video_telemetry` | FT-P-03 fixture validation | Fixture accepted only when alignment rules pass | Reliability | -| AC-2 | Valid synchronized replay | FT-P-03 output | Continuous estimates for normal overlapping segments or explicit degradation | Reliability | -| AC-3 | Replay performance run | NFT-PERF-02 | Latency, completion rate, and memory evidence are recorded | Performance | - -## Constraints - -- Tests must not import BASALT/OpenVINS/Kimera internals directly. -- Public/representative datasets are optional prerequisites and may produce blocked results. -- Raw input video and telemetry fixtures remain read-only. - -## Risks & Mitigation - -**Risk 1: Hardware or dataset prerequisites are unavailable** -- *Risk*: The scenario cannot produce final accuracy evidence locally. -- *Mitigation*: Emit blocked results with exact missing prerequisite and continue other scenario groups. diff --git a/_docs/02_tasks/done/AZ-236_satellite_anchor_cache_tests.md b/_docs/02_tasks/done/AZ-236_satellite_anchor_cache_tests.md deleted file mode 100644 index dd7e974..0000000 --- a/_docs/02_tasks/done/AZ-236_satellite_anchor_cache_tests.md +++ /dev/null @@ -1,102 +0,0 @@ -# Satellite Anchor Cache Tests - -**Task**: AZ-236_satellite_anchor_cache_tests -**Name**: Satellite Anchor Cache Tests -**Description**: Implement blackbox, security, and performance tests for satellite-anchor retrieval, local verification, cache integrity, and no in-flight external access. -**Complexity**: 5 points -**Dependencies**: AZ-233_test_infrastructure, AZ-241_real_satellite_vpr_descriptor_retrieval, AZ-242_real_anchor_feature_matching_ransac -**Component**: Blackbox Tests -**Tracker**: AZ-236 -**Epic**: AZ-218 - -## Problem - -Satellite anchors and cache fixtures are safety-critical: invalid, stale, poisoned, or externally fetched data must not become trusted localization output. - -This test task must run after AZ-241 and AZ-242 so it validates real local VPR retrieval and real anchor feature matching rather than scaffold evidence gates. - -## Outcome - -- Accepted anchors include retrieval, matching, geometry, freshness, and provenance evidence. -- Invalid/stale/poisoned cache fixtures cannot produce trusted anchors or trusted generated tiles. -- No in-flight Satellite Service or provider access occurs when cache data is missing. - -## Scope - -### Included - -- FT-P-04 Satellite Service And Anchor Verification. -- FT-N-01 Repetitive Or Low-Texture Imagery. -- FT-N-03 Invalid Or Stale Satellite Cache. -- NFT-PERF-03 Relocalization Trigger Path Latency. -- NFT-RES-04 Tile Cache Freshness Degradation. -- NFT-SEC-01 Signed Cache Manifest Enforcement. -- NFT-SEC-02 Cache Poisoning Write Gate. -- NFT-SEC-04 No In-Flight Satellite Provider Access. -- NFT-RES-LIM-03 Satellite Cache Storage Budget. - -### Excluded - -- VIO synchronized replay. -- MAVLink spoofing/failsafe behavior. -- Jetson thermal endurance. - -## Acceptance Criteria - -**AC-1: Verified anchors include evidence** -Given a valid local cache/index fixture and relocalization trigger -When retrieval and verification run -Then accepted anchors include candidate IDs, scores, MRE, inliers, covariance, and tile provenance. - -**AC-2: Unsafe candidates are rejected** -Given low-texture, stale, unsigned, hash-mismatched, or low-resolution fixtures -When anchor/cache tests run -Then no invalid candidate emits a trusted `satellite_anchored` estimate or trusted generated tile. - -**AC-3: No in-flight external access occurs** -Given flight-mode replay with missing cache data -When relocalization is requested -Then the system reports degraded/no-candidate behavior without satellite-provider or Suite service network calls. - -**AC-4: Cache and trigger-path metrics are reported** -Given cache and relocalization scenarios complete -When reporting finishes -Then latency, MRE, trust level, freshness, and storage-budget evidence are written. - -## Non-Functional Requirements - -**Security** -- Invalid cache data must not be trusted or promoted. - -**Performance** -- Trigger-path latency and bounded top-K behavior are measured. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Anchor evidence parser | Required evidence fields are present | -| AC-2 | Invalid cache fixture generator | Stale/unsigned/hash-mismatched fixtures are produced deterministically | -| AC-3 | Network-block assertion | Unexpected external calls fail the scenario | -| AC-4 | Cache metrics report | Latency, freshness, and storage metrics are present | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1 | Public/cache fixture | FT-P-04 | Accepted anchors meet MRE/evidence requirements | Performance | -| AC-2 | Ambiguous and invalid cache fixtures | FT-N-01, FT-N-03, NFT-SEC-01, NFT-SEC-02 | 0 unsafe trusted outputs | Security | -| AC-3 | Network-blocked flight-mode replay | NFT-SEC-04 | Missing cache causes degraded behavior, not fetch | Security | -| AC-4 | Relocalization/cache runs | NFT-PERF-03, NFT-RES-04, NFT-RES-LIM-03 | Metrics and storage evidence are recorded | Performance | - -## Constraints - -- Tests must use local preloaded cache/index fixtures only. -- External network access during flight-mode scenarios is a failure. -- VPAir and UZH FPV licensing must be respected before use as commercial acceptance evidence. - -## Risks & Mitigation - -**Risk 1: Dataset licensing blocks final anchor evidence** -- *Risk*: Public dataset terms prevent commercial acceptance use. -- *Mitigation*: Mark dataset-specific checks blocked and keep generated cache fixtures for deterministic security coverage. diff --git a/_docs/02_tasks/done/AZ-237_mavlink_blackout_spoofing_tests.md b/_docs/02_tasks/done/AZ-237_mavlink_blackout_spoofing_tests.md deleted file mode 100644 index ef2b29f..0000000 --- a/_docs/02_tasks/done/AZ-237_mavlink_blackout_spoofing_tests.md +++ /dev/null @@ -1,94 +0,0 @@ -# MAVLink Blackout Spoofing Tests - -**Task**: AZ-237_mavlink_blackout_spoofing_tests -**Name**: MAVLink Blackout Spoofing Tests -**Description**: Implement SITL/replay tests for visual blackout, spoofed GPS, MAVLink source validation, degraded covariance, no-fix thresholds, and QGC status. -**Complexity**: 5 points -**Dependencies**: AZ-233_test_infrastructure -**Component**: Blackbox Tests -**Tracker**: AZ-237 -**Epic**: AZ-218 - -## Problem - -The system must prove that spoofed GPS and unauthorized MAVLink messages cannot override estimator state during visual blackout or degraded operation. - -## Outcome - -- Blackout and spoofing traces drive visible degraded-mode transitions. -- Covariance, `GPS_INPUT`, QGC status, and FDR evidence match the safety thresholds. -- Unauthorized MAVLink sources are rejected and recorded. - -## Scope - -### Included - -- FT-N-02 GPS Spoofing During Total Visual Blackout. -- NFT-RES-01 Total Visual Blackout With GPS Spoofing. -- NFT-SEC-03 MAVLink Source And Spoofing Rejection. - -### Excluded - -- Still-image geolocation accuracy. -- Satellite-anchor cache poisoning. -- Cold-start and restart trials. - -## Acceptance Criteria - -**AC-1: Blackout transitions to dead reckoning** -Given a replay/SITL trace with total camera blackout and spoofed GPS -When the scenario runs -Then the system enters `dead_reckoned` mode within the required frame or timing threshold. - -**AC-2: Degraded output thresholds are enforced** -Given blackout continues beyond configured thresholds -When estimates are emitted -Then covariance grows monotonically and `GPS_INPUT` fields degrade to no-fix/failsafe values at the specified limits. - -**AC-3: Spoofed or unauthorized MAVLink inputs are rejected** -Given spoofed real-GPS measurements or unauthorized MAVLink source IDs -When messages arrive during normal or blackout operation -Then no confident position estimate is produced from those inputs. - -**AC-4: Operator and FDR evidence is visible** -Given degraded-mode transitions occur -When reporting completes -Then QGC status and FDR evidence show promotion, demotion, blackout, and failsafe events at expected rates. - -## Non-Functional Requirements - -**Safety** -- Spoofed GPS must not be promoted during blackout without the documented recovery gates. - -**Reliability** -- Missing SITL prerequisites are reported as blocked with exact setup evidence. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Scenario trigger builder | Blackout and spoofing events are generated deterministically | -| AC-2 | Threshold assertion logic | Fix type, covariance, and `horiz_accuracy` thresholds are checked | -| AC-3 | MAVLink source filter assertion | Unauthorized source messages fail the scenario | -| AC-4 | Status/FDR parser | Expected status events and rates are validated | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1 | SITL or replay spoofing trace | FT-N-02, NFT-RES-01 | Dead-reckoned transition within timing threshold | Safety | -| AC-2 | Continued blackout | FT-N-02, NFT-RES-01 | Monotonic covariance and no-fix/failsafe fields | Safety | -| AC-3 | Unauthorized/spoofed MAVLink messages | NFT-SEC-03 | No confident estimate from bad source | Safety | -| AC-4 | QGC/FDR outputs | FT-N-02, NFT-SEC-03 | Status and evidence are visible and rate-limited | Reliability | - -## Constraints - -- ArduPilot Plane SITL is the authoritative autopilot target. -- v1 asserts `GPS_INPUT` output and intentional absence of ODOMETRY. -- Tests must not depend on Mission Planner or PX4 behavior. - -## Risks & Mitigation - -**Risk 1: SITL setup varies by environment** -- *Risk*: Local runs may not have SITL installed or configured. -- *Mitigation*: Report blocked prerequisites clearly and keep replay-level assertions runnable where possible. diff --git a/_docs/02_tasks/done/AZ-238_cold_start_restart_tests.md b/_docs/02_tasks/done/AZ-238_cold_start_restart_tests.md deleted file mode 100644 index c264c86..0000000 --- a/_docs/02_tasks/done/AZ-238_cold_start_restart_tests.md +++ /dev/null @@ -1,95 +0,0 @@ -# Cold Start Restart Tests - -**Task**: AZ-238_cold_start_restart_tests -**Name**: Cold Start Restart Tests -**Description**: Implement tests for cold start, companion restart, sharp-turn/disconnected relocalization, and first-fix resource spikes. -**Complexity**: 5 points -**Dependencies**: AZ-233_test_infrastructure -**Component**: Blackbox Tests -**Tracker**: AZ-238 -**Epic**: AZ-218 - -## Problem - -The test suite must prove that the runtime recovers from disconnected visual segments and companion restarts without hiding missing prerequisites or unsafe degraded behavior. - -## Outcome - -- Sharp-turn/disconnected-segment scenarios trigger relocalization or explicit degraded output. -- Companion restart scenarios measure first valid output timing and FDR evidence. -- Cold-start trials record first-fix latency and resource spikes. - -## Scope - -### Included - -- NFT-RES-02 Sharp Turn And Disconnected Segment Relocalization. -- NFT-RES-03 Companion Computer Restart Mid-Flight. -- NFT-PERF-04 Cold Boot Time To First Fix. -- NFT-RES-LIM-05 Cold Start Resource Spike. - -### Excluded - -- Long thermal endurance. -- FDR 8-hour rollover load. -- Cache poisoning and no-fetch security tests. - -## Acceptance Criteria - -**AC-1: Disconnected segments trigger relocalization** -Given a sharp-turn or disconnected segment fixture -When replay reaches the low-overlap transition -Then relocalization is requested and the system either reconnects via verified anchor or reports degraded status. - -**AC-2: Companion restart recovery is measured** -Given a replay/SITL mission in progress -When the GPS-denied service is restarted -Then first valid output timing, FC-state handoff behavior, and FDR restart evidence are recorded. - -**AC-3: Cold-start trials report first-fix timing** -Given cold-start conditions and local cache/index prerequisites -When 50 trials run or are blocked -Then the p95 time-to-first-fix result or exact blocked prerequisite is reported. - -**AC-4: Cold-start resource spikes are captured** -Given initialization begins -When engines/indexes/cache are loaded -Then peak memory and initialization-stage timing are recorded where measurable. - -## Non-Functional Requirements - -**Reliability** -- Missing calibration, public datasets, or hardware prerequisites must not be treated as passing. - -**Performance** -- First-fix timing and peak memory are reported with percentile summaries where enough trials run. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Relocalization trigger assertion | Missing-position thresholds trigger request checks | -| AC-2 | Restart report parser | Restart and first-output events are present | -| AC-3 | Trial aggregation | p95 first-fix summary or blocked reason is emitted | -| AC-4 | Resource metric parser | Peak memory and stage timings are captured | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1 | Sharp-turn/disconnected replay | NFT-RES-02 | Verified relocalization or degraded evidence | Reliability | -| AC-2 | Mission restart trace | NFT-RES-03 | First valid output and FDR restart evidence | Reliability | -| AC-3 | Cold-start harness | NFT-PERF-04 | p95 first fix <30 s or blocked prerequisite | Performance | -| AC-4 | Cold-start resource monitoring | NFT-RES-LIM-05 | Peak memory <8 GB or blocked/failure evidence | Performance | - -## Constraints - -- Restart tests must preserve fixture read-only guarantees. -- Trial loops must be bounded and report partial results if interrupted. -- Hardware-only assertions must be clearly marked when not runnable locally. - -## Risks & Mitigation - -**Risk 1: Long cold-start trials are expensive** -- *Risk*: Full 50-run evidence may not be practical on every PR. -- *Mitigation*: Support smoke mode for PRs and full mode for release gates, with clear report labels. diff --git a/_docs/02_tasks/done/AZ-239_jetson_resource_endurance_tests.md b/_docs/02_tasks/done/AZ-239_jetson_resource_endurance_tests.md deleted file mode 100644 index 5403190..0000000 --- a/_docs/02_tasks/done/AZ-239_jetson_resource_endurance_tests.md +++ /dev/null @@ -1,94 +0,0 @@ -# Jetson Resource Endurance Tests - -**Task**: AZ-239_jetson_resource_endurance_tests -**Name**: Jetson Resource Endurance Tests -**Description**: Implement release-gate resource and endurance tests for Jetson memory, thermal/power behavior, and FDR rollover. -**Complexity**: 5 points -**Dependencies**: AZ-233_test_infrastructure -**Component**: Blackbox Tests -**Tracker**: AZ-239 -**Epic**: AZ-218 - -## Problem - -Release readiness requires hardware/resource evidence that cannot be proven by ordinary unit tests or short local replay runs. - -## Outcome - -- Jetson memory and thermal/power metrics are captured where hardware is available. -- FDR 8-hour synthetic load verifies rollover, storage cap, and retained payload classes. -- Hardware-only prerequisites are reported as blocked when not available. - -## Scope - -### Included - -- NFT-RES-LIM-01 Jetson Memory Budget. -- NFT-RES-LIM-02 Thermal And Power Envelope. -- NFT-RES-LIM-04 Flight Data Recorder Rollover. - -### Excluded - -- Still-image replay accuracy. -- Satellite anchor/cache security tests. -- Cold-start first-fix trials. - -## Acceptance Criteria - -**AC-1: Jetson memory budget is measured** -Given Jetson hardware or equivalent production target is available -When sustained replay and trigger-path workload runs -Then CPU/GPU shared memory, process RSS, CUDA allocations, and OOM/throttle status are recorded. - -**AC-2: Thermal and power endurance is validated or blocked** -Given thermal test prerequisites are available -When the sustained 25 W workload runs -Then throttle flags, temperatures, clocks, and latency are recorded for the required duration; otherwise the run reports blocked prerequisites. - -**AC-3: FDR rollover is validated** -Given an 8-hour synthetic mission load -When FDR output reaches rollover conditions -Then storage remains within the cap, rollover is logged, and no payload class is silently dropped. - -**AC-4: Evidence artifacts are complete** -Given resource/endurance scenarios complete or block -When reporting finishes -Then metrics, duration, environment, status, and artifact paths are written. - -## Non-Functional Requirements - -**Performance** -- Resource evidence must include duration and sampling interval. - -**Reliability** -- Hardware-unavailable results are `blocked`, not `passed`. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Resource metric parser | Memory and throttle fields are present | -| AC-2 | Blocked prerequisite reporter | Missing hardware/thermal setup records blocked status | -| AC-3 | FDR rollover report parser | Storage, rollover, and payload-class fields are validated | -| AC-4 | Evidence manifest writer | Artifact paths and run metadata are present | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1 | Jetson/prod-equivalent hardware | NFT-RES-LIM-01 | Peak memory <8 GB or explicit failure | Performance | -| AC-2 | Thermal/power test setup | NFT-RES-LIM-02 | No throttle over required duration or blocked/failure | Performance | -| AC-3 | Synthetic 8-hour mission load | NFT-RES-LIM-04 | FDR cap and rollover behavior are evidenced | Reliability | -| AC-4 | Resource/endurance reports | All included scenarios | Complete artifact manifest and status | Reliability | - -## Constraints - -- These tests are release-gate oriented and may be skipped or blocked in ordinary PR mode. -- Raw frames must not be retained during FDR load tests. -- Resource tests must not write outside run-scoped output directories. - -## Risks & Mitigation - -**Risk 1: Hardware gates are unavailable during local development** -- *Risk*: Developers cannot run full evidence locally. -- *Mitigation*: Support blocked status and separate PR smoke mode from release-gate execution. diff --git a/_docs/02_tasks/done/AZ-240_native_vio_backend_integration.md b/_docs/02_tasks/done/AZ-240_native_vio_backend_integration.md deleted file mode 100644 index ff1b574..0000000 --- a/_docs/02_tasks/done/AZ-240_native_vio_backend_integration.md +++ /dev/null @@ -1,95 +0,0 @@ -# Native VIO Backend Integration - -**Task**: AZ-240_native_vio_backend_integration -**Name**: Native VIO Backend Integration -**Description**: Replace the deterministic VIO placeholder path with a real native backend integration boundary for representative replay. -**Complexity**: 5 points -**Dependencies**: AZ-228_vio_adapter -**Component**: VIO Adapter -**Tracker**: AZ-240 -**Epic**: AZ-213 - -## Problem - -The current VIO adapter satisfies the public contract with deterministic scaffold behavior, but it does not exercise a real native VIO backend for synchronized replay. - -## Outcome - -- A production-capable native VIO bridge is available behind the existing `VioBackend` protocol. -- Backend-specific setup remains isolated from the public VIO adapter boundary. -- Existing timestamp mismatch, tracking-loss, health, and no-WGS84-authority behavior is preserved. - -## Scope - -### Included - -- Native/backend bridge implementation behind `VioBackend`. -- Backend initialization and runtime failure mapping into explicit health/error states. -- Replay-driven relative pose, velocity, bias, tracking quality, and covariance output. -- Tests that prove the real backend path is selected when configured. - -### Excluded - -- Absolute WGS84 authority or safety fusion. -- Satellite-anchor fallback logic. -- Direct test imports of backend internals. - -## Dependencies - -### Document Dependencies - -- `_docs/02_document/components/02_vio_adapter/description.md` -- `_docs/02_document/contracts/shared/runtime_contracts.md` -- `_docs/02_document/contracts/shared/geometry_time_sync.md` -- `_docs/02_document/contracts/shared/config_errors_telemetry.md` - -## Acceptance Criteria - -**AC-1: Native backend path emits VIO state** -Given synchronized replay frames and telemetry -When VIO processing runs with the native backend enabled -Then the adapter emits a relative VIO state packet from the native path. - -**AC-2: Backend failures are explicit** -Given backend initialization or runtime failure -When VIO processing or health reporting runs -Then the adapter surfaces an explicit error and degraded or failed health state. - -**AC-3: Existing safety boundaries remain intact** -Given timestamp mismatch, low tracking quality, or successful native output -When the adapter returns a result -Then degraded behavior, tracking quality, and absence of WGS84 authority remain intact. - -## Non-Functional Requirements - -**Performance** -- Replay execution must expose latency and memory metrics for later Jetson profiling gates. - -**Reliability** -- Backend failures must not be hidden behind deterministic fallback success. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Configured native backend path | Native estimate is used, not deterministic fallback | -| AC-2 | Backend init/runtime failure | Explicit error and degraded/failed health | -| AC-3 | Timestamp/quality boundaries | Existing degraded/no-WGS84 behavior preserved | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1 | Derkachi or representative synchronized replay | Native VIO replay path | Relative estimates are emitted or blocked with a real prerequisite reason | Performance | - -## Constraints - -- Keep backend-specific dependencies behind the `vio_adapter` native boundary. -- Do not make the VIO adapter the safety or WGS84 authority. -- If required native packages are unavailable locally, tests must skip or block with explicit prerequisite evidence rather than passing through the deterministic fallback. - -## Risks & Mitigation - -**Risk 1: Native dependency unavailable in local CI** -- *Risk*: The real backend cannot run on all developer machines. -- *Mitigation*: Provide dependency-gated tests that fail only when the backend is configured but broken, and report blocked prerequisites for full replay gates. diff --git a/_docs/02_tasks/done/AZ-241_real_satellite_vpr_descriptor_retrieval.md b/_docs/02_tasks/done/AZ-241_real_satellite_vpr_descriptor_retrieval.md deleted file mode 100644 index c3a1436..0000000 --- a/_docs/02_tasks/done/AZ-241_real_satellite_vpr_descriptor_retrieval.md +++ /dev/null @@ -1,95 +0,0 @@ -# Real Satellite VPR Descriptor Retrieval - -**Task**: AZ-241_real_satellite_vpr_descriptor_retrieval -**Name**: Real Satellite VPR Descriptor Retrieval -**Description**: Replace the tuple-similarity satellite retrieval scaffold with the real local descriptor/index retrieval path promised by the Satellite Service design. -**Complexity**: 5 points -**Dependencies**: AZ-230_satellite_service_vpr_retrieval -**Component**: Satellite Service -**Tracker**: AZ-241 -**Epic**: AZ-214 - -## Problem - -The current Satellite Service can load in-memory descriptor records and rank them with local tuple similarity, but it does not yet integrate the real offline descriptor/index retrieval path. - -## Outcome - -- Local mission cache descriptor/index packages can be loaded by the runtime retrieval path. -- Retrieval uses the selected CPU FAISS/DINOv2-VLAD-compatible boundary where available. -- Freshness filtering, bounded top-K output, descriptor-fidelity checks, and no in-flight network behavior remain intact. - -## Scope - -### Included - -- Local descriptor/index package loading from the offline cache boundary. -- Real local VPR retrieval implementation behind the public Satellite Service API. -- Explicit degraded/no-candidate/index failure behavior. -- Tests that distinguish the real retrieval path from the current tuple-similarity scaffold. - -### Excluded - -- Local feature matching, RANSAC, or anchor acceptance. -- In-flight provider or Suite service calls. -- TensorRT/ONNX optimization unless descriptor-fidelity gates are in place. - -## Dependencies - -### Document Dependencies - -- `_docs/02_document/components/04_satellite_retrieval/description.md` -- `_docs/02_document/contracts/shared/runtime_contracts.md` -- `_docs/02_document/contracts/shared/config_errors_telemetry.md` -- `_docs/02_document/components/06_cache_tile_lifecycle/description.md` - -## Acceptance Criteria - -**AC-1: Real local index readiness is reported** -Given a valid local descriptor/index package -When the Satellite Service loads the package -Then readiness reflects the real local index and loaded record count. - -**AC-2: Real top-K retrieval returns candidates** -Given a relocalization request and loaded local index -When retrieval runs -Then bounded candidates come from the real local descriptor/index path with scores, footprints, and freshness state. - -**AC-3: Missing or invalid indexes degrade safely** -Given missing, corrupt, incompatible, or empty local index data -When retrieval runs -Then the result is explicit degraded/no-candidate behavior without unsafe anchors or network calls. - -## Non-Functional Requirements - -**Performance** -- Retrieval remains trigger-based and exposes latency metrics for Jetson profiling. - -**Security** -- Retrieval must not perform in-flight provider or Suite service calls. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Real index package load | Ready status references loaded real index data | -| AC-2 | Query against fixture index | Candidates come from the real retrieval path | -| AC-3 | Missing/corrupt index | Explicit degraded/no-candidate result | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-2 | Public/cache fixture with descriptor index | VPR recall and top-K policy | Candidate bounds, freshness, and latency evidence are reported | Performance | - -## Constraints - -- Use only local preloaded cache/index data during flight-mode retrieval. -- Keep optional optimized engines behind descriptor-fidelity gates. -- Missing native/index prerequisites must be reported as blocked, not silently passed by the scaffold path. - -## Risks & Mitigation - -**Risk 1: Heavy native/index dependencies do not run in ordinary CI** -- *Risk*: The real retrieval path needs packages or data unavailable in local CI. -- *Mitigation*: Keep fast contract tests for package parsing and dependency-gated integration tests for real index execution. diff --git a/_docs/02_tasks/done/AZ-242_real_anchor_feature_matching_ransac.md b/_docs/02_tasks/done/AZ-242_real_anchor_feature_matching_ransac.md deleted file mode 100644 index 737819f..0000000 --- a/_docs/02_tasks/done/AZ-242_real_anchor_feature_matching_ransac.md +++ /dev/null @@ -1,94 +0,0 @@ -# Real Anchor Feature Matching And RANSAC - -**Task**: AZ-242_real_anchor_feature_matching_ransac -**Name**: Real Anchor Feature Matching And RANSAC -**Description**: Replace the precomputed evidence gate-only scaffold with real local feature matching and geometry verification behind the Anchor Verification boundary. -**Complexity**: 5 points -**Dependencies**: AZ-231_anchor_verification_matching, AZ-241_real_satellite_vpr_descriptor_retrieval -**Component**: Anchor Verification -**Tracker**: AZ-242 -**Epic**: AZ-215 - -## Problem - -The current Anchor Verification component can classify precomputed `MatchEvidence`, but it does not yet run real feature extraction, matching, homography estimation, or RANSAC/USAC geometry checks. - -## Outcome - -- Approved matcher profiles can compute correspondence evidence from frame imagery and candidate tile data. -- Geometry verification produces inliers, MRE, homography/provenance, runtime, and rejection reasons. -- Existing safety gates continue to reject unsafe candidates before any anchor is trusted. - -## Scope - -### Included - -- Matcher bridge for approved ALIKED/DISK + LightGlue and SIFT/ORB baseline profiles where dependencies are available. -- Homography and RANSAC/USAC evidence generation from local imagery/tile fixtures. -- Integration with existing `GeometryGatedAnchorVerifier` decision output. -- Benchmark reporting from actual matching paths. - -### Excluded - -- VPR candidate ranking. -- Safety wrapper fusion/promotion policy. -- Per-frame steady-state VIO hot path execution. - -## Dependencies - -### Document Dependencies - -- `_docs/02_document/components/05_anchor_verification/description.md` -- `_docs/02_document/contracts/shared/runtime_contracts.md` -- `_docs/02_document/components/04_satellite_retrieval/description.md` - -## Acceptance Criteria - -**AC-1: Matching path computes evidence** -Given a usable frame and fresh candidate tile -When anchor verification runs -Then matcher evidence is computed from local imagery and includes inliers, MRE, homography, provenance, and runtime. - -**AC-2: Unsafe candidates are rejected** -Given low inliers, high reprojection error, stale or untrusted provenance, or geometry failure -When verification runs -Then no accepted anchor decision is emitted for that candidate. - -**AC-3: Real matcher benchmark is reportable** -Given configured matcher profiles and fixture inputs -When benchmark runs -Then runtime and quality metrics are reported from actual matching paths. - -## Non-Functional Requirements - -**Performance** -- Learned matching remains trigger-based and benchmarked separately from the VIO hot path. - -**Reliability** -- Missing matcher dependencies or fixture data must be explicit blocked prerequisites, not passing scaffold behavior. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Fixture matching path | Evidence is computed from imagery/tile input | -| AC-2 | Bad geometry/provenance | Candidate is rejected with reason | -| AC-3 | Matcher benchmark | Runtime and quality metrics come from real path | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1 | Aerial/cache fixture pair | Anchor verification path | Accepted anchors meet MRE/inlier gates with real evidence | Performance | - -## Constraints - -- Keep native feature extraction and RANSAC acceleration under `anchor_verification`. -- Do not trust precomputed evidence in production paths without provenance checks. -- SuperPoint or other legally restricted models remain excluded unless explicitly approved. - -## Risks & Mitigation - -**Risk 1: False anchor acceptance** -- *Risk*: Real cross-domain matching can produce plausible but unsafe geometry. -- *Mitigation*: Preserve freshness, provenance, inlier, MRE, and downstream safety gates; add negative fixtures for low-texture and stale-cache cases. diff --git a/_docs/02_tasks/done/AZ-243_integrate_production_native_vio_runtime.md b/_docs/02_tasks/done/AZ-243_integrate_production_native_vio_runtime.md deleted file mode 100644 index a3abc3f..0000000 --- a/_docs/02_tasks/done/AZ-243_integrate_production_native_vio_runtime.md +++ /dev/null @@ -1,96 +0,0 @@ -# Integrate Production Native VIO Runtime - -**Task**: AZ-243_integrate_production_native_vio_runtime -**Name**: Integrate Production Native VIO Runtime -**Description**: Close the VIO completeness gap by making production VIO execution use a real native runtime path instead of replay/scaffold behavior. -**Complexity**: 5 points -**Dependencies**: AZ-240_native_vio_backend_integration -**Component**: VIO Adapter -**Tracker**: AZ-243 -**Epic**: AZ-213 - -## Problem - -The VIO adapter exposes a native backend boundary, but the product completeness gate found that production behavior still does not execute a real native/BASALT VIO runtime. This lets downstream tests pass against scaffold behavior while the promised runtime capability is missing. - -## Outcome - -- Production VIO configuration selects and executes a real native runtime path. -- Missing native prerequisites fail closed with explicit configuration or runtime errors. -- Replay-only behavior remains available only for replay/development modes that explicitly opt into it. - -## Scope - -### Included - -- Production native VIO runtime selection behind the VIO adapter boundary. -- Explicit startup/runtime errors when native runtime prerequisites are missing or invalid. -- Preservation of replay behavior for replay-only tests and development workflows. -- Tests proving production configuration does not silently fall back to replay behavior. - -### Excluded - -- Absolute WGS84 authority or safety fusion. -- Satellite-anchor fallback logic. -- Jetson performance tuning beyond reporting the native runtime prerequisite state. - -## Dependencies - -### Document Dependencies - -- `_docs/02_document/components/02_vio_adapter/description.md` -- `_docs/02_document/contracts/shared/runtime_contracts.md` -- `_docs/02_document/contracts/shared/config_errors_telemetry.md` -- `_docs/03_implementation/implementation_completeness_cycle1_report.md` - -## Acceptance Criteria - -**AC-1: Production profile requires native VIO** -Given the system is configured for production VIO execution -When VIO initialization runs -Then the adapter selects the native runtime path and does not silently use replay behavior. - -**AC-2: Missing native runtime fails closed** -Given production VIO configuration and an unavailable or invalid native runtime prerequisite -When VIO initialization or processing runs -Then the adapter reports an explicit configuration or runtime failure instead of emitting a successful replay-derived VIO state. - -**AC-3: Replay mode remains explicit** -Given a replay-only development or test configuration -When VIO processing runs -Then replay behavior remains available only through that explicit mode and cannot be mistaken for production native execution. - -## Non-Functional Requirements - -**Reliability** -- Production startup must not hide missing native VIO capability behind deterministic or replay fallback success. - -**Compatibility** -- Existing public VIO adapter contracts must remain stable for downstream safety, FDR, and test consumers. - -## Unit Tests - -| AC Ref | What to Test | Required Outcome | -|--------|--------------|------------------| -| AC-1 | Production VIO configuration | Native runtime path is selected, not replay fallback | -| AC-2 | Missing native runtime prerequisite | Explicit failure is surfaced and no successful replay-derived state is emitted | -| AC-3 | Replay-only configuration | Replay path works only when explicitly configured | - -## Blackbox Tests - -| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | -|--------|-------------------------|--------------|-------------------|----------------| -| AC-1, AC-2 | Representative synchronized replay with production VIO profile | Runtime path selection and prerequisite handling | Native execution runs when available, or blocks with a real prerequisite reason | Reliability | - -## Constraints - -- Keep backend-specific dependencies behind the VIO adapter native boundary. -- Do not make the VIO adapter the safety or WGS84 authority. -- Do not satisfy production runtime behavior with a fake, deterministic, scaffold, or test-only backend. -- If local machines cannot execute the native runtime, tests must skip or block with an explicit prerequisite reason rather than passing through replay fallback. - -## Risks & Mitigation - -**Risk 1: Native runtime unavailable in local CI** -- *Risk*: The real native VIO runtime may not be installed on all developer machines. -- *Mitigation*: Gate native execution tests on explicit prerequisites, while still testing that production configuration fails closed when prerequisites are absent. diff --git a/_docs/03_implementation/batch_01_cycle1_report.md b/_docs/03_implementation/batch_01_cycle1_report.md deleted file mode 100644 index 2fb8249..0000000 --- a/_docs/03_implementation/batch_01_cycle1_report.md +++ /dev/null @@ -1,41 +0,0 @@ -# Batch Report - -**Batch**: 1 -**Tasks**: AZ-219_initial_structure -**Date**: 2026-05-03 - -## Task Results - -| Task | Status | Files Modified | Tests | AC Coverage | Issues | -|------|--------|----------------|-------|-------------|--------| -| AZ-219_initial_structure | Done | 98 files | Pass | 7/7 ACs covered | None | - -## AC Test Coverage: All covered - -| AC Ref | Coverage | -|--------|----------| -| AC-1 | `test_scaffold_paths_cover_runtime_test_and_evidence_layout` verifies source, tests, migrations, deployment, configuration, data, CI, and compose scaffold paths. | -| AC-2 | `test_runtime_component_public_modules_are_importable` and `test_shared_contract_locations_are_importable` verify public component and shared contract namespaces. | -| AC-3 | `test_scaffold_paths_cover_runtime_test_and_evidence_layout` verifies compose, env template, and migration paths; compose config validation passed. | -| AC-4 | `test_scaffold_paths_cover_runtime_test_and_evidence_layout` verifies `.github/workflows/ci.yml`; the workflow defines format, lint, unit test, compose config, and artifact placeholder jobs. | -| AC-5 | `test_scaffold_paths_cover_runtime_test_and_evidence_layout` verifies unit, integration, black-box, fixture, SITL, and e2e runner paths. | -| AC-6 | `test_scaffold_paths_cover_runtime_test_and_evidence_layout` verifies deployment scripts and evidence report paths. | -| AC-7 | `test_ignore_rules_exclude_runtime_payloads_and_secrets` verifies secrets, raw frames, cache/FDR payloads, and test result artifacts are ignored. | - -## Code Review Verdict: PASS - -Review report: `_docs/03_implementation/reviews/batch_01_review.md` - -## Auto-Fix Attempts: 0 - -## Stuck Agents: None - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` passed. -- `.venv/bin/python -m ruff check src tests e2e/replay` passed. -- `.venv/bin/python -m pytest` passed: 5 tests. -- `docker compose -f docker-compose.yml config` passed. -- `docker compose -f docker-compose.test.yml config` passed. - -## Next Batch: AZ-220_shared_runtime_contracts diff --git a/_docs/03_implementation/batch_02_cycle1_report.md b/_docs/03_implementation/batch_02_cycle1_report.md deleted file mode 100644 index 245ff25..0000000 --- a/_docs/03_implementation/batch_02_cycle1_report.md +++ /dev/null @@ -1,34 +0,0 @@ -# Batch Report - -**Batch**: 2 -**Tasks**: AZ-220_shared_runtime_contracts -**Date**: 2026-05-03 - -## Task Results - -| Task | Status | Files Modified | Tests | AC Coverage | Issues | -|------|--------|----------------|-------|-------------|--------| -| AZ-220_shared_runtime_contracts | Done | 8 files | Pass | 2/2 ACs covered | None | - -## AC Test Coverage: All covered - -| AC Ref | Coverage | -|--------|----------| -| AC-1 | `test_runtime_dtos_accept_valid_minimal_values` verifies the shared DTO contract surface can be imported and constructed. | -| AC-2 | `test_missing_required_timestamp_is_rejected_with_structured_error`, `test_raw_frame_retention_is_rejected`, `test_position_accuracy_cannot_under_report_covariance`, and `test_accepted_anchor_requires_estimated_pose` verify malformed DTOs are rejected with structured Pydantic validation errors. | - -## Code Review Verdict: PASS - -Review report: `_docs/03_implementation/reviews/batch_02_review.md` - -## Auto-Fix Attempts: 0 - -## Stuck Agents: None - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` passed. -- `.venv/bin/python -m ruff check src tests e2e/replay` passed. -- `.venv/bin/python -m pytest` passed: 11 tests. - -## Next Batch: AZ-221_shared_geometry_time_sync, AZ-222_runtime_config_errors_telemetry diff --git a/_docs/03_implementation/batch_03_cycle1_report.md b/_docs/03_implementation/batch_03_cycle1_report.md deleted file mode 100644 index 9f995f2..0000000 --- a/_docs/03_implementation/batch_03_cycle1_report.md +++ /dev/null @@ -1,37 +0,0 @@ -# Batch Report - -**Batch**: 3 -**Tasks**: AZ-221_shared_geometry_time_sync, AZ-222_runtime_config_errors_telemetry -**Date**: 2026-05-03 - -## Task Results - -| Task | Status | Files Modified | Tests | AC Coverage | Issues | -|------|--------|----------------|-------|-------------|--------| -| AZ-221_shared_geometry_time_sync | Done | 5 files | Pass | 2/2 ACs covered | None | -| AZ-222_runtime_config_errors_telemetry | Done | 7 files | Pass | 2/2 ACs covered | None | - -## AC Test Coverage: All covered - -| AC Ref | Coverage | -|--------|----------| -| AZ-221 AC-1 | `test_wgs84_local_round_trip_is_deterministic` verifies deterministic WGS84/local conversion and metric output. | -| AZ-221 AC-2 | `test_non_monotonic_timestamps_return_explicit_violation` and `test_time_window_reports_gap_instead_of_dropping_silently` verify explicit time-sync violation results. | -| AZ-222 AC-1 | `test_missing_production_cache_dir_returns_readiness_failure` verifies missing production settings produce a structured readiness failure. | -| AZ-222 AC-2 | `test_dependency_error_envelope_has_required_structured_fields` verifies dependency errors include component, category, severity, and retryability. | - -## Code Review Verdict: PASS - -Review report: `_docs/03_implementation/reviews/batch_03_review.md` - -## Auto-Fix Attempts: 0 - -## Stuck Agents: None - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` passed. -- `.venv/bin/python -m ruff check src tests e2e/replay` passed. -- `.venv/bin/python -m pytest` passed: 17 tests. - -## Next Batch: AZ-223_camera_ingest_calibration, AZ-224_mavlink_gcs_gateway, AZ-225_tile_manager_cache_manifest, AZ-227_fdr_event_recorder diff --git a/_docs/03_implementation/batch_04_cycle1_report.md b/_docs/03_implementation/batch_04_cycle1_report.md deleted file mode 100644 index 75bdbca..0000000 --- a/_docs/03_implementation/batch_04_cycle1_report.md +++ /dev/null @@ -1,47 +0,0 @@ -# Batch Report - -**Batch**: 4 -**Tasks**: AZ-223_camera_ingest_calibration, AZ-224_mavlink_gcs_gateway, AZ-225_tile_manager_cache_manifest, AZ-227_fdr_event_recorder -**Date**: 2026-05-03 - -## Task Results - -| Task | Status | Files Modified | Tests | AC Coverage | Issues | -|------|--------|----------------|-------|-------------|--------| -| AZ-223_camera_ingest_calibration | Done | 4 files | Pass | 3/3 ACs covered | None | -| AZ-224_mavlink_gcs_gateway | Done | 4 files | Pass | 3/3 ACs covered | None | -| AZ-225_tile_manager_cache_manifest | Done | 4 files | Pass | 3/3 ACs covered | None | -| AZ-227_fdr_event_recorder | Done | 4 files | Pass | 3/3 ACs covered | None | - -## AC Test Coverage: All covered - -| AC Ref | Coverage | -|--------|----------| -| AZ-223 AC-1 | `test_valid_frame_packet_contains_metadata_reports_and_normalization_hint` verifies timestamp, calibration, quality, occlusion, and normalization metadata. | -| AZ-223 AC-2 | `test_total_occlusion_marks_frame_unusable_for_vio_and_anchor` verifies blackout frames are unavailable for visual paths. | -| AZ-223 AC-3 | `test_raw_frame_payload_retention_is_rejected` verifies raw frame payload retention is rejected. | -| AZ-224 AC-1 | `test_telemetry_subscription_emits_normalized_sample` verifies normalized shared telemetry samples. | -| AZ-224 AC-2 | `test_invalid_gps_input_estimate_is_rejected_without_emission` verifies unsafe `GPS_INPUT` requests are rejected without emission. | -| AZ-224 AC-3 | `test_operator_status_messages_are_rate_limited_by_text` verifies QGC-visible status rate limiting. | -| AZ-225 AC-1 | `test_valid_cache_manifest_activates_trusted_records` verifies valid cache activation. | -| AZ-225 AC-2 | `test_tampered_or_stale_tile_is_rejected_with_auditable_reason` verifies hash and freshness rejection reasons. | -| AZ-225 AC-3 | `test_tile_metadata_lookup_returns_record_or_explicit_rejection` verifies trusted metadata lookup and explicit rejection. | -| AZ-227 AC-1 | `test_valid_event_append_indexes_metadata_and_payload_reference` verifies event metadata and payload references are stored within bounds. | -| AZ-227 AC-2 | `test_rollover_threshold_records_explicit_rollover_result` verifies rollover is explicit. | -| AZ-227 AC-3 | `test_export_request_produces_queryable_evidence_artifacts` verifies export evidence and analytics references. | - -## Code Review Verdict: PASS - -Review report: `_docs/03_implementation/reviews/batch_04_review.md` - -## Auto-Fix Attempts: 0 - -## Stuck Agents: None - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` passed. -- `.venv/bin/python -m ruff check src tests e2e/replay` passed. -- `.venv/bin/python -m pytest` passed: 29 tests. - -## Next Batch: AZ-226_generated_tile_orthorectification diff --git a/_docs/03_implementation/batch_05_cycle1_report.md b/_docs/03_implementation/batch_05_cycle1_report.md deleted file mode 100644 index d626e5c..0000000 --- a/_docs/03_implementation/batch_05_cycle1_report.md +++ /dev/null @@ -1,35 +0,0 @@ -# Batch Report - -**Batch**: 5 -**Tasks**: AZ-226_generated_tile_orthorectification -**Date**: 2026-05-03 - -## Task Results - -| Task | Status | Files Modified | Tests | AC Coverage | Issues | -|------|--------|----------------|-------|-------------|--------| -| AZ-226_generated_tile_orthorectification | Done | 4 files | Pass | 3/3 ACs covered | None | - -## AC Test Coverage: All covered - -| AC Ref | Coverage | -|--------|----------| -| AZ-226 AC-1 | `test_eligible_frame_stages_generated_cog_and_sidecar` verifies generated COG and sidecar staging for eligible frames. | -| AZ-226 AC-2 | `test_high_covariance_generated_tile_write_is_rejected` verifies unsafe high-covariance writes are rejected and not packaged. | -| AZ-226 AC-3 | `test_sync_package_includes_manifest_delta_sidecar_covariance_and_trust_level` verifies sync package audit metadata. | - -## Code Review Verdict: PASS - -Review report: `_docs/03_implementation/reviews/batch_05_review.md` - -## Auto-Fix Attempts: 0 - -## Stuck Agents: None - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` passed. -- `.venv/bin/python -m ruff check src tests e2e/replay` passed. -- `.venv/bin/python -m pytest` passed: 32 tests. - -## Next Batch: AZ-228_vio_adapter, AZ-229_satellite_service_sync diff --git a/_docs/03_implementation/batch_06_cycle1_report.md b/_docs/03_implementation/batch_06_cycle1_report.md deleted file mode 100644 index 9255788..0000000 --- a/_docs/03_implementation/batch_06_cycle1_report.md +++ /dev/null @@ -1,39 +0,0 @@ -# Batch Report - -**Batch**: 6 -**Tasks**: AZ-228_vio_adapter, AZ-229_satellite_service_sync -**Date**: 2026-05-03 - -## Task Results - -| Task | Status | Files Modified | Tests | AC Coverage | Issues | -|------|--------|----------------|-------|-------------|--------| -| AZ-228_vio_adapter | Done | 4 files | Pass | 3/3 ACs covered | None | -| AZ-229_satellite_service_sync | Done | 4 files | Pass | 3/3 ACs covered | None | - -## AC Test Coverage: All covered - -| AC Ref | Coverage | -|--------|----------| -| AZ-228 AC-1 | `test_valid_synchronized_packet_emits_vio_state` verifies synchronized frame/IMU processing emits a relative VIO state packet. | -| AZ-228 AC-2 | `test_timestamp_mismatch_is_explicit_validation_error` verifies timestamp mismatch is rejected with an explicit error. | -| AZ-228 AC-3 | `test_tracking_loss_degrades_health_without_emitting_absolute_position` verifies health reports degraded tracking state. | -| AZ-229 AC-1 | `test_pre_flight_import_returns_package_for_tile_manager_validation` verifies mission cache packages are exposed for Tile Manager validation. | -| AZ-229 AC-2 | `test_post_flight_upload_records_retryable_failure_for_audit` verifies upload outcomes are auditable and retryable failures retain packages. | -| AZ-229 AC-3 | `test_in_flight_sync_is_blocked_without_calling_network_boundary` verifies in-flight sync is blocked before network/uploader calls. | - -## Code Review Verdict: PASS - -Review report: `_docs/03_implementation/reviews/batch_06_review.md` - -## Auto-Fix Attempts: 0 - -## Stuck Agents: None - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` passed. -- `.venv/bin/python -m ruff check src tests e2e/replay` passed. -- `.venv/bin/python -m pytest` passed: 38 tests. - -## Next Batch: AZ-230_satellite_service_vpr_retrieval diff --git a/_docs/03_implementation/batch_07_cycle1_report.md b/_docs/03_implementation/batch_07_cycle1_report.md deleted file mode 100644 index 9546e57..0000000 --- a/_docs/03_implementation/batch_07_cycle1_report.md +++ /dev/null @@ -1,35 +0,0 @@ -# Batch Report - -**Batch**: 7 -**Tasks**: AZ-230_satellite_service_vpr_retrieval -**Date**: 2026-05-03 - -## Task Results - -| Task | Status | Files Modified | Tests | AC Coverage | Issues | -|------|--------|----------------|-------|-------------|--------| -| AZ-230_satellite_service_vpr_retrieval | Done | 4 files | Pass | 3/3 ACs covered | None | - -## AC Test Coverage: All covered - -| AC Ref | Coverage | -|--------|----------| -| AZ-230 AC-1 | `test_valid_local_index_load_reports_ready_status` verifies local index loading reports readiness and record count. | -| AZ-230 AC-2 | `test_loaded_index_returns_bounded_candidates_with_freshness` verifies bounded top-K candidate output with tile/chunk IDs, score, footprint, and freshness. | -| AZ-230 AC-3 | `test_missing_index_degrades_with_explicit_no_candidate_result` verifies missing index produces explicit degraded behavior. | - -## Code Review Verdict: PASS - -Review report: `_docs/03_implementation/reviews/batch_07_review.md` - -## Auto-Fix Attempts: 0 - -## Stuck Agents: None - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` passed. -- `.venv/bin/python -m ruff check src tests e2e/replay` passed. -- `.venv/bin/python -m pytest` passed: 42 tests. - -## Next Batch: AZ-231_anchor_verification_matching diff --git a/_docs/03_implementation/batch_08_cycle1_report.md b/_docs/03_implementation/batch_08_cycle1_report.md deleted file mode 100644 index b178261..0000000 --- a/_docs/03_implementation/batch_08_cycle1_report.md +++ /dev/null @@ -1,35 +0,0 @@ -# Batch Report - -**Batch**: 8 -**Tasks**: AZ-231_anchor_verification_matching -**Date**: 2026-05-03 - -## Task Results - -| Task | Status | Files Modified | Tests | AC Coverage | Issues | -|------|--------|----------------|-------|-------------|--------| -| AZ-231_anchor_verification_matching | Done | 4 files | Pass | 3/3 ACs covered | None | - -## AC Test Coverage: All covered - -| AC Ref | Coverage | -|--------|----------| -| AZ-231 AC-1 | `test_candidate_verification_emits_acceptance_evidence` verifies accepted decisions include MRE, inliers, homography, and reason metadata. | -| AZ-231 AC-2 | `test_unsafe_candidate_is_rejected_with_reason` verifies unsafe/stale candidates are rejected without estimated pose. | -| AZ-231 AC-3 | `test_matcher_benchmark_reports_profile_runtime_and_quality_metrics` verifies matcher profile runtime and quality metrics are reportable. | - -## Code Review Verdict: PASS - -Review report: `_docs/03_implementation/reviews/batch_08_review.md` - -## Auto-Fix Attempts: 0 - -## Stuck Agents: None - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` passed. -- `.venv/bin/python -m ruff check src tests e2e/replay` passed. -- `.venv/bin/python -m pytest` passed: 45 tests. - -## Next Batch: AZ-232_safety_anchor_state_machine diff --git a/_docs/03_implementation/batch_09_cycle1_report.md b/_docs/03_implementation/batch_09_cycle1_report.md deleted file mode 100644 index a1b946a..0000000 --- a/_docs/03_implementation/batch_09_cycle1_report.md +++ /dev/null @@ -1,36 +0,0 @@ -# Batch Report - -**Batch**: 9 -**Tasks**: AZ-232_safety_anchor_state_machine -**Date**: 2026-05-03 - -## Task Results - -| Task | Status | Files Modified | Tests | AC Coverage | Issues | -|------|--------|----------------|-------|-------------|--------| -| AZ-232_safety_anchor_state_machine | Done | 4 files | Pass | 4/4 ACs covered | None | - -## AC Test Coverage: All covered - -| AC Ref | Coverage | -|--------|----------| -| AZ-232 AC-1 | `test_vio_state_updates_position_estimate_with_honest_covariance` verifies VIO updates emit source-labelled estimates with honest covariance. | -| AZ-232 AC-2 | `test_accepted_anchor_corrects_state_and_records_evidence` verifies accepted anchors promote `satellite_anchored` state and record evidence. | -| AZ-232 AC-3 | `test_blackout_degrades_then_reaches_no_fix_with_monotonic_covariance` verifies monotonic covariance growth and no-fix semantics. | -| AZ-232 AC-4 | `test_tile_write_eligibility_requires_trusted_low_covariance_pose` verifies conservative tile-write eligibility. | - -## Code Review Verdict: PASS - -Review report: `_docs/03_implementation/reviews/batch_09_review.md` - -## Auto-Fix Attempts: 0 - -## Stuck Agents: None - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` passed. -- `.venv/bin/python -m ruff check src tests e2e/replay` passed. -- `.venv/bin/python -m pytest` passed: 49 tests. - -## Next Batch: All tasks complete diff --git a/_docs/03_implementation/batch_10_cycle1_report.md b/_docs/03_implementation/batch_10_cycle1_report.md deleted file mode 100644 index 407454b..0000000 --- a/_docs/03_implementation/batch_10_cycle1_report.md +++ /dev/null @@ -1,37 +0,0 @@ -# Batch Report - -**Batch**: 10 -**Tasks**: AZ-240_native_vio_backend_integration, AZ-241_real_satellite_vpr_descriptor_retrieval, AZ-242_real_anchor_feature_matching_ransac -**Date**: 2026-05-05 - -## Task Results - -| Task | Status | Files Modified | Tests | AC Coverage | Issues | -|------|--------|---------------|-------|-------------|--------| -| AZ-240_native_vio_backend_integration | Done | 6 files | 58 passed | 3/3 ACs covered | None | -| AZ-241_real_satellite_vpr_descriptor_retrieval | Done | 6 files | 58 passed | 3/3 ACs covered | None | -| AZ-242_real_anchor_feature_matching_ransac | Done | 6 files | 58 passed | 3/3 ACs covered | None | - -## AC Test Coverage: All covered - -- AZ-240 AC-1: `test_configured_native_backend_path_emits_vio_state` -- AZ-240 AC-2: `test_native_backend_initialization_failure_sets_failed_health`, `test_native_backend_runtime_failure_sets_failed_health` -- AZ-240 AC-3: `test_timestamp_mismatch_is_explicit_validation_error`, `test_tracking_loss_degrades_health_without_emitting_absolute_position` -- AZ-241 AC-1: `test_valid_local_index_load_reports_ready_status`, `test_local_descriptor_index_package_loads_from_cache_file` -- AZ-241 AC-2: `test_loaded_index_returns_bounded_candidates_with_freshness` -- AZ-241 AC-3: `test_missing_index_degrades_with_explicit_no_candidate_result`, `test_invalid_index_package_degrades_with_explicit_error` -- AZ-242 AC-1: `test_matching_path_computes_evidence_from_frame_and_tile_inputs` -- AZ-242 AC-2: `test_unsafe_candidate_is_rejected_with_reason`, `test_computed_matching_rejects_low_inlier_geometry` -- AZ-242 AC-3: `test_matcher_benchmark_can_run_computed_paths` - -## Code Review Verdict: PASS -## Auto-Fix Attempts: 0 -## Stuck Agents: None - -## Verification - -- `python3 -m pytest tests/unit/test_vio_adapter.py tests/unit/test_satellite_service_vpr.py tests/unit/test_anchor_verification.py`: 19 passed. -- `python3 -m pytest`: 58 passed. -- Formatter/linter CLIs declared in `pyproject.toml` were unavailable in this interpreter: `black` and `ruff` modules were not installed. - -## Next Batch: All product tasks complete diff --git a/_docs/03_implementation/batch_11_report.md b/_docs/03_implementation/batch_11_report.md deleted file mode 100644 index 53e0149..0000000 --- a/_docs/03_implementation/batch_11_report.md +++ /dev/null @@ -1,29 +0,0 @@ -# Batch Report - -**Batch**: 11 -**Tasks**: AZ-233_test_infrastructure -**Date**: 2026-05-05 - -## Task Results - -| Task | Status | Files Modified | Tests | AC Coverage | Issues | -|------|--------|---------------|-------|-------------|--------| -| AZ-233_test_infrastructure | Done | 18 files plus task archive | 4 passed | 4/4 ACs covered | None | - -## AC Test Coverage: All covered - -- AC-1: `test_replay_environment_reports_missing_prerequisites_as_blocked` -- AC-2: `test_satellite_cache_stub_is_deterministic_and_records_interactions` -- AC-3: `test_runner_executes_all_required_groups_and_writes_reports` -- AC-4: `test_runner_executes_all_required_groups_and_writes_reports`, `test_runner_keeps_generated_artifacts_run_scoped` - -## Code Review Verdict: PASS -## Auto-Fix Attempts: 0 -## Stuck Agents: None - -## Verification - -- `python3 -m pytest tests/blackbox/test_infrastructure.py`: 4 passed. -- `python3 -m e2e.replay.run_replay --output-dir /tmp/gpsd-blackbox-smoke`: generated CSV and Markdown replay evidence. - -## Next Batch: AZ-234, AZ-235, AZ-236, AZ-237 diff --git a/_docs/03_implementation/batch_12_report.md b/_docs/03_implementation/batch_12_report.md deleted file mode 100644 index 938ecdd..0000000 --- a/_docs/03_implementation/batch_12_report.md +++ /dev/null @@ -1,43 +0,0 @@ -# Batch Report - -**Batch**: 12 -**Tasks**: AZ-234_replay_geolocation_confidence_tests, AZ-235_vio_replay_performance_tests, AZ-236_satellite_anchor_cache_tests, AZ-237_mavlink_blackout_spoofing_tests -**Date**: 2026-05-05 - -## Task Results - -| Task | Status | Files Modified | Tests | AC Coverage | Issues | -|------|--------|---------------|-------|-------------|--------| -| AZ-234_replay_geolocation_confidence_tests | Done | 2 files | 18 passed | 3/3 ACs covered | None | -| AZ-235_vio_replay_performance_tests | Done | 2 files | 18 passed | 3/3 ACs covered | None | -| AZ-236_satellite_anchor_cache_tests | Done | 2 files | 18 passed | 4/4 ACs covered | None | -| AZ-237_mavlink_blackout_spoofing_tests | Done | 2 files | 18 passed | 4/4 ACs covered | None | - -## AC Test Coverage: All covered - -- AZ-234 AC-1: `test_expected_coordinate_loader_rejects_invalid_wgs84_rows`, `test_still_image_replay_reports_coordinate_thresholds_and_latency` -- AZ-234 AC-2: `test_confidence_contract_validation_fails_missing_source_label`, `test_still_image_replay_reports_coordinate_thresholds_and_latency` -- AZ-234 AC-3: `test_still_image_replay_reports_coordinate_thresholds_and_latency` -- AZ-235 AC-1: `test_derkachi_alignment_validator_accepts_expected_fixture_shape`, `test_derkachi_alignment_validator_blocks_duration_drift` -- AZ-235 AC-2: `test_public_vio_replay_boundary_emits_frame_by_frame_estimate` -- AZ-235 AC-3: `test_public_dataset_and_calibration_prerequisites_are_reported_blocked` -- AZ-236 AC-1: `test_verified_anchor_includes_retrieval_matching_and_provenance_evidence` -- AZ-236 AC-2: `test_unsafe_cache_or_low_texture_candidates_never_emit_trusted_anchor` -- AZ-236 AC-3: `test_flight_mode_missing_cache_does_not_attempt_external_access` -- AZ-236 AC-4: `test_verified_anchor_includes_retrieval_matching_and_provenance_evidence`, `test_flight_mode_missing_cache_does_not_attempt_external_access` -- AZ-237 AC-1: `test_blackout_trace_transitions_to_dead_reckoned_then_no_fix` -- AZ-237 AC-2: `test_blackout_trace_transitions_to_dead_reckoned_then_no_fix`, `test_no_fix_estimate_is_not_emitted_as_confident_gps_input` -- AZ-237 AC-3: `test_unauthorized_mavlink_sources_are_rejected_by_test_assertion` -- AZ-237 AC-4: `test_qgc_status_and_fdr_evidence_are_visible_and_rate_limited` - -## Code Review Verdict: PASS -## Auto-Fix Attempts: 0 -## Stuck Agents: None - -## Verification - -- `python3 -m pytest tests/blackbox`: 18 passed. -- IDE lints: no errors on changed Python files. -- `python3 -m black ...` and `python3 -m ruff ...` could not run because those optional dev tool modules are not installed in the current interpreter. - -## Next Batch: AZ-238, AZ-239 diff --git a/_docs/03_implementation/batch_13_report.md b/_docs/03_implementation/batch_13_report.md deleted file mode 100644 index 342baf7..0000000 --- a/_docs/03_implementation/batch_13_report.md +++ /dev/null @@ -1,35 +0,0 @@ -# Batch Report - -**Batch**: 13 -**Tasks**: AZ-238_cold_start_restart_tests, AZ-239_jetson_resource_endurance_tests -**Date**: 2026-05-05 - -## Task Results - -| Task | Status | Files Modified | Tests | AC Coverage | Issues | -|------|--------|---------------|-------|-------------|--------| -| AZ-238_cold_start_restart_tests | Done | 2 files | 25 passed | 4/4 ACs covered | None | -| AZ-239_jetson_resource_endurance_tests | Done | 2 files | 25 passed | 4/4 ACs covered | None | - -## AC Test Coverage: All covered - -- AZ-238 AC-1: `test_disconnected_segment_triggers_relocalization_request_check` -- AZ-238 AC-2: `test_restart_scenario_records_first_output_or_blocked_prerequisite` -- AZ-238 AC-3: `test_cold_start_trials_report_p95_first_fix_and_resource_spike` -- AZ-238 AC-4: `test_cold_start_trials_report_p95_first_fix_and_resource_spike`, `test_cold_start_hardware_prerequisites_are_blocked_not_passed` -- AZ-239 AC-1: `test_jetson_resource_metric_summary_captures_memory_and_throttle_fields` -- AZ-239 AC-2: `test_missing_thermal_hardware_reports_blocked_prerequisite` -- AZ-239 AC-3: `test_fdr_rollover_logs_segments_without_raw_frame_retention` -- AZ-239 AC-4: `test_missing_thermal_hardware_reports_blocked_prerequisite`, `test_fdr_rollover_logs_segments_without_raw_frame_retention` - -## Code Review Verdict: PASS -## Auto-Fix Attempts: 0 -## Stuck Agents: None - -## Verification - -- `python3 -m pytest tests/blackbox`: 25 passed. -- IDE lints: no errors on changed Python files. -- `python3 -m black ...` and `python3 -m ruff ...` could not run because those optional dev tool modules are not installed in the current interpreter. - -## Next Batch: All test implementation tasks complete diff --git a/_docs/03_implementation/batch_14_cycle1_report.md b/_docs/03_implementation/batch_14_cycle1_report.md deleted file mode 100644 index 1b770af..0000000 --- a/_docs/03_implementation/batch_14_cycle1_report.md +++ /dev/null @@ -1,27 +0,0 @@ -# Batch Report - -**Batch**: 14 -**Tasks**: AZ-243_integrate_production_native_vio_runtime -**Date**: 2026-05-06 - -## Task Results - -| Task | Status | Files Modified | Tests | AC Coverage | Issues | -|------|--------|---------------|-------|-------------|--------| -| AZ-243_integrate_production_native_vio_runtime | Done | 7 files | 87 passed | 3/3 ACs covered | None | - -## AC Test Coverage: All covered - -- AC-1: `test_production_profile_selects_native_runtime_path` -- AC-2: `test_production_profile_without_installed_native_runtime_fails_closed` -- AC-3: `test_replay_mode_is_explicit_and_not_valid_for_production`, `test_public_vio_replay_boundary_emits_frame_by_frame_estimate` - -## Code Review Verdict: PASS - -## Auto-Fix Attempts: 0 - -## Stuck Agents: None - -## Next Batch - -All product tasks complete. Product completeness was refreshed after AZ-243 and Step 7 can hand off to Code Testability Revision. diff --git a/_docs/03_implementation/implementation_completeness_cycle1_report.md b/_docs/03_implementation/implementation_completeness_cycle1_report.md deleted file mode 100644 index 0f681ea..0000000 --- a/_docs/03_implementation/implementation_completeness_cycle1_report.md +++ /dev/null @@ -1,50 +0,0 @@ -# Product Implementation Completeness Report - -**Cycle**: 1 -**Date**: 2026-05-06 -**Outcome**: PASS — product implementation complete after native VIO remediation - -## Summary - -Product implementation returned to Step 7 for the native VIO runtime gap and completed AZ-243. Production and Jetson VIO profiles now select native runtime mode, load a BASALT-compatible runner through the VIO adapter boundary, and report explicit initialization errors when the installed runtime prerequisite is unavailable. Replay behavior remains available through explicit development replay configuration. - -## Product Task Classifications - -| Task | Classification | Evidence | -|------|----------------|----------| -| AZ-219 through AZ-232 | PASS | Batch reports 01-09, cumulative review 01-09, full source marker scan, and full suite coverage | -| AZ-240 | PASS | `src/vio_adapter/interfaces.py`, `src/vio_adapter/types.py`, `src/vio_adapter/native/basalt.py`, `tests/unit/test_vio_adapter.py` | -| AZ-241 | PASS | `src/satellite_service/interfaces.py`, `src/satellite_service/types.py`, `src/satellite_service/native/__init__.py`, `tests/unit/test_satellite_service_vpr.py` | -| AZ-242 | PASS | `src/anchor_verification/interfaces.py`, `src/anchor_verification/types.py`, `src/anchor_verification/native/__init__.py`, `tests/unit/test_anchor_verification.py` | -| AZ-243 | PASS | `create_vio_adapter`, `VioRuntimeConfig`, `ConfiguredNativeVioBackend`, `BasaltNativeRunner`, `tests/unit/test_vio_adapter.py`, `tests/blackbox/test_vio_replay.py` | - -## Remediation Evidence - -- `VioRuntimeConfig` derives native mode for `production` and `jetson` profiles and rejects replay mode for those environments. -- `create_vio_adapter` selects `ConfiguredNativeVioBackend` for native profiles and keeps replay execution behind explicit replay mode. -- `BasaltNativeRunner` loads an installed BASALT-compatible runtime factory from the configured module/function reference and validates the returned runner against `NativeVioRunner`. -- Missing BASALT runtime prerequisites surface as explicit VIO initialization errors with failed health and no emitted VIO state packet. -- Satellite retrieval and anchor verification remediation from AZ-241 and AZ-242 remains covered by the existing native retrieval/matching evidence and tests. - -## Marker Scan - -Checked `src/**/*.py` for unresolved implementation markers: - -- `TODO` -- `placeholder` -- `stub` -- `fake` -- `mock` -- `scaffold` -- `native bridge` -- `NotImplemented` -- bare `pass` - -Result: clean. - -## Verification - -- `python3 -m black src/vio_adapter tests/unit/test_vio_adapter.py tests/blackbox/test_vio_replay.py`: completed. -- `python3 -m ruff check src/vio_adapter tests/unit/test_vio_adapter.py tests/blackbox/test_vio_replay.py`: passed. -- `python3 -m pytest tests/unit/test_vio_adapter.py tests/blackbox/test_vio_replay.py`: 13 passed. -- `python3 -m pytest`: 87 passed. diff --git a/_docs/03_implementation/implementation_report_product_runtime_cycle1.md b/_docs/03_implementation/implementation_report_product_runtime_cycle1.md deleted file mode 100644 index d5a7920..0000000 --- a/_docs/03_implementation/implementation_report_product_runtime_cycle1.md +++ /dev/null @@ -1,78 +0,0 @@ -# Implementation Report - -**Feature**: Product runtime -**Cycle**: 1 -**Date**: 2026-05-05 -**Status**: Complete - -## Summary - -Greenfield product implementation completed the GPS-denied onboard runtime and the required remediation work for native VIO selection, local descriptor/index VPR retrieval, and computed anchor matching/geometry verification. - -- Total tasks completed: 17 -- Completed batches: 10 -- Blocked tasks: 0 -- Code review verdicts: PASS for all batch reviews and cumulative review -- Final test run: 58 passed - -## Completed Tasks - -| Task | Name | Batch | Status | -|------|------|-------|--------| -| AZ-219 | initial_structure | 1 | Done | -| AZ-220 | shared_runtime_contracts | 2 | Done | -| AZ-221 | shared_geometry_time_sync | 3 | Done | -| AZ-222 | runtime_config_errors_telemetry | 3 | Done | -| AZ-223 | camera_ingest_calibration | 4 | Done | -| AZ-224 | mavlink_gcs_gateway | 4 | Done | -| AZ-225 | tile_manager_cache_manifest | 4 | Done | -| AZ-227 | fdr_event_recorder | 4 | Done | -| AZ-226 | generated_tile_orthorectification | 5 | Done | -| AZ-228 | vio_adapter | 6 | Done | -| AZ-229 | satellite_service_sync | 6 | Done | -| AZ-230 | satellite_service_vpr_retrieval | 7 | Done | -| AZ-231 | anchor_verification_matching | 8 | Done | -| AZ-232 | safety_anchor_state_machine | 9 | Done | -| AZ-240 | native_vio_backend_integration | 10 | Done | -| AZ-241 | real_satellite_vpr_descriptor_retrieval | 10 | Done | -| AZ-242 | real_anchor_feature_matching_ransac | 10 | Done | - -## Batch Outcomes - -| Batch | Tasks | Code Review | Tests | -|-------|-------|-------------|-------| -| 1 | AZ-219_initial_structure | PASS | 5 passed | -| 2 | AZ-220_shared_runtime_contracts | PASS | 11 passed | -| 3 | AZ-221_shared_geometry_time_sync, AZ-222_runtime_config_errors_telemetry | PASS | 17 passed | -| 4 | AZ-223_camera_ingest_calibration, AZ-224_mavlink_gcs_gateway, AZ-225_tile_manager_cache_manifest, AZ-227_fdr_event_recorder | PASS | 29 passed | -| 5 | AZ-226_generated_tile_orthorectification | PASS | 32 passed | -| 6 | AZ-228_vio_adapter, AZ-229_satellite_service_sync | PASS | 38 passed | -| 7 | AZ-230_satellite_service_vpr_retrieval | PASS | 42 passed | -| 8 | AZ-231_anchor_verification_matching | PASS | 45 passed | -| 9 | AZ-232_safety_anchor_state_machine | PASS | 49 passed | -| 10 | AZ-240_native_vio_backend_integration, AZ-241_real_satellite_vpr_descriptor_retrieval, AZ-242_real_anchor_feature_matching_ransac | PASS | 58 passed | - -## Acceptance Coverage - -All acceptance criteria documented in the product implementation task specs are covered by tests recorded in the batch reports: - -- Shared contracts, configuration, errors, telemetry, geometry, and time-sync behavior are validated by shared unit tests. -- Component runtime boundaries for camera ingest, MAVLink/GCS, tile management, FDR, VIO, Satellite Service, anchor verification, and safety/anchor state management are validated by component unit tests. -- Native VIO backend selection, local descriptor/index package loading and retrieval, and computed matcher/RANSAC evidence paths are validated by remediation unit tests. -- Safety-critical behavior for explicit errors, no raw-frame retention, no mid-flight Satellite Service calls, conservative generated-tile writes, rejected unsafe anchors, monotonic blackout degradation, and honest covariance is covered by the current unit suite. - -## Review Summary - -- Batch reviews: `_docs/03_implementation/reviews/batch_01_review.md` through `_docs/03_implementation/reviews/batch_10_review.md` -- Cumulative review: `_docs/03_implementation/reviews/cumulative_review_batches_01-09_cycle1_report.md` -- Auto-fix attempts: 0 across all batches -- Stuck agents: none - -## Final Verification - -- `python3 -m pytest` passed: 58 tests. -- `python3 -m black ...` and `python3 -m ruff ...` could not run because those optional dev tool modules are not installed in the current interpreter. - -## Next Step - -Autodev may advance to Step 8, Code Testability Revision. Product implementation completeness is recorded in `_docs/03_implementation/implementation_completeness_cycle1_report.md`. diff --git a/_docs/03_implementation/implementation_report_tests.md b/_docs/03_implementation/implementation_report_tests.md deleted file mode 100644 index fdf04ef..0000000 --- a/_docs/03_implementation/implementation_report_tests.md +++ /dev/null @@ -1,67 +0,0 @@ -# Implementation Report - -**Feature**: Blackbox and e2e test implementation -**Cycle**: 1 -**Date**: 2026-05-05 -**Status**: Complete - -## Summary - -Greenfield test implementation completed the blackbox/e2e replay harness and all test tasks for still-image replay, synchronized VIO replay, satellite-anchor/cache security, MAVLink blackout/spoofing, cold-start/restart, Jetson resource, and FDR endurance scenarios. - -- Total test tasks completed: 7 -- Completed batches: 3 -- Blocked tasks: 0 -- Code review verdicts: PASS for all batch reviews and cumulative review -- Focused verification: 25 blackbox tests passed -- Full-suite gate: handed off to Step 11 (`test-run`) per implement Step 16 - -## Completed Tasks - -| Task | Name | Batch | Status | -|------|------|-------|--------| -| AZ-233 | test_infrastructure | 11 | Done | -| AZ-234 | replay_geolocation_confidence_tests | 12 | Done | -| AZ-235 | vio_replay_performance_tests | 12 | Done | -| AZ-236 | satellite_anchor_cache_tests | 12 | Done | -| AZ-237 | mavlink_blackout_spoofing_tests | 12 | Done | -| AZ-238 | cold_start_restart_tests | 13 | Done | -| AZ-239 | jetson_resource_endurance_tests | 13 | Done | - -## Batch Outcomes - -| Batch | Tasks | Code Review | Tests | -|-------|-------|-------------|-------| -| 11 | AZ-233_test_infrastructure | PASS | 4 passed | -| 12 | AZ-234, AZ-235, AZ-236, AZ-237 | PASS | 18 passed | -| 13 | AZ-238, AZ-239 | PASS | 25 passed | - -## Acceptance Coverage - -All acceptance criteria documented in the test implementation task specs are covered by focused blackbox tests recorded in the batch reports: - -- Replay infrastructure starts or reports blocked prerequisites, uses deterministic stubs, discovers required scenario groups, and writes CSV/Markdown evidence. -- Still-image replay validates WGS84 expected-coordinate fixtures, confidence/source-label fields, latency percentiles, and dropped-frame metrics. -- Synchronized VIO replay validates Derkachi alignment gates, public VIO replay output, and calibration/public-dataset blocked prerequisites. -- Satellite-anchor/cache tests validate retrieval evidence, geometry verification, invalid cache rejection, no in-flight external access, and storage-budget evidence. -- MAVLink blackout/spoofing tests validate dead-reckoned/no-fix transitions, safe `GPS_INPUT` emission behavior, unauthorized source rejection, and QGC/FDR status visibility. -- Restart/resource tests validate relocalization triggers, first-fix trial aggregation, Jetson blocked prerequisites, resource metrics, and FDR rollover evidence. - -## Review Summary - -- Batch reviews: `_docs/03_implementation/reviews/batch_11_review.md` through `_docs/03_implementation/reviews/batch_13_review.md` -- Cumulative review: `_docs/03_implementation/reviews/cumulative_review_batches_11-13_tests_report.md` -- Auto-fix attempts: 0 across all test batches -- Stuck agents: none - -## Verification - -- `python3 -m pytest tests/blackbox/test_infrastructure.py`: 4 passed. -- `python3 -m pytest tests/blackbox`: 18 passed after batch 12. -- `python3 -m pytest tests/blackbox`: 25 passed after batch 13. -- `python3 -m e2e.replay.run_replay --output-dir /tmp/gpsd-blackbox-smoke`: generated CSV and Markdown replay evidence. -- Formatter/linter CLIs declared in `pyproject.toml` were unavailable in this interpreter: `black` and `ruff` modules were not installed. - -## Next Step - -Autodev may advance to Step 11, Run Tests. The full-suite gate is intentionally owned by Step 11 to avoid duplicating the test-run skill's diagnosis and reporting workflow. diff --git a/_docs/03_implementation/reviews/batch_01_review.md b/_docs/03_implementation/reviews/batch_01_review.md deleted file mode 100644 index 757ecb4..0000000 --- a/_docs/03_implementation/reviews/batch_01_review.md +++ /dev/null @@ -1,29 +0,0 @@ -# Code Review Report - -**Batch**: AZ-219_initial_structure -**Date**: 2026-05-03 -**Verdict**: PASS - -## Findings - -| # | Severity | Category | File:Line | Title | -|---|----------|----------|-----------|-------| -| - | - | - | - | No findings | - -## Review Notes - -- AC-1 is satisfied by the `src/`, `migrations/`, `tests/`, `e2e/`, `deployment/`, `config/`, and `data/` scaffold plus tracked placeholders. -- AC-2 is satisfied by importable component and shared package namespaces under `src/`. -- AC-3 is satisfied by `docker-compose.yml`, `docker-compose.test.yml`, `.env.example`, and the initial PostGIS migration. -- AC-4 is satisfied by `.github/workflows/ci.yml` with format, lint, unit-test, compose-config, and artifact placeholder stages. -- AC-5 is satisfied by pytest unit scaffold coverage and black-box/SITL/e2e fixture entry-point directories. -- AC-6 is satisfied by deployment Dockerfiles, Jetson/deployment placeholders, `e2e/reports/`, and `deployment/scripts/collect_evidence.sh`. -- AC-7 is satisfied by `.gitignore`, `.dockerignore`, and non-secret environment templates excluding generated runtime payloads and credentials. - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` passed. -- `.venv/bin/python -m ruff check src tests e2e/replay` passed. -- `.venv/bin/python -m pytest` passed: 5 tests. -- `docker compose -f docker-compose.yml config` passed. -- `docker compose -f docker-compose.test.yml config` passed. diff --git a/_docs/03_implementation/reviews/batch_02_review.md b/_docs/03_implementation/reviews/batch_02_review.md deleted file mode 100644 index 52eca57..0000000 --- a/_docs/03_implementation/reviews/batch_02_review.md +++ /dev/null @@ -1,24 +0,0 @@ -# Code Review Report - -**Batch**: AZ-220_shared_runtime_contracts -**Date**: 2026-05-03 -**Verdict**: PASS - -## Findings - -| # | Severity | Category | File:Line | Title | -|---|----------|----------|-----------|-------| -| - | - | - | - | No findings | - -## Review Notes - -- AC-1 is satisfied by the public exports in `src/shared/contracts/__init__.py` and the DTO models in `src/shared/contracts/models.py`. -- AC-2 is satisfied by Pydantic validation for missing required fields, raw frame retention, optimistic covariance reporting, and inconsistent anchor decisions. -- The implementation stays inside `shared/contracts` ownership and does not introduce component-specific algorithms. -- Raw frame payloads remain references only; the model rejects retained raw-frame payload flags. - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` passed. -- `.venv/bin/python -m ruff check src tests e2e/replay` passed. -- `.venv/bin/python -m pytest` passed: 11 tests. diff --git a/_docs/03_implementation/reviews/batch_03_review.md b/_docs/03_implementation/reviews/batch_03_review.md deleted file mode 100644 index 6ed02df..0000000 --- a/_docs/03_implementation/reviews/batch_03_review.md +++ /dev/null @@ -1,25 +0,0 @@ -# Code Review Report - -**Batch**: AZ-221_shared_geometry_time_sync, AZ-222_runtime_config_errors_telemetry -**Date**: 2026-05-03 -**Verdict**: PASS - -## Findings - -| # | Severity | Category | File:Line | Title | -|---|----------|----------|-----------|-------| -| - | - | - | - | No findings | - -## Review Notes - -- AZ-221 AC-1 is satisfied by deterministic WGS84/local conversion, distance, and footprint helpers under `shared/geo_geometry`. -- AZ-221 AC-2 is satisfied by explicit time-sync violation models and window selection results under `shared/time_sync`. -- AZ-222 AC-1 is satisfied by runtime profile validation and structured readiness failure envelopes under `shared/config`. -- AZ-222 AC-2 is satisfied by reusable `ErrorEnvelope` / `ResultEnvelope` models plus FDR-safe health and metrics metadata. -- The batch stays within shared foundation ownership and does not introduce component policy decisions. - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` passed. -- `.venv/bin/python -m ruff check src tests e2e/replay` passed. -- `.venv/bin/python -m pytest` passed: 17 tests. diff --git a/_docs/03_implementation/reviews/batch_04_review.md b/_docs/03_implementation/reviews/batch_04_review.md deleted file mode 100644 index 4f1a7a8..0000000 --- a/_docs/03_implementation/reviews/batch_04_review.md +++ /dev/null @@ -1,29 +0,0 @@ -# Code Review Report - -**Batch**: AZ-223_camera_ingest_calibration, AZ-224_mavlink_gcs_gateway, AZ-225_tile_manager_cache_manifest, AZ-227_fdr_event_recorder -**Date**: 2026-05-03 -**Verdict**: PASS - -## Findings - -No findings. - -## Spec Compliance - -| Task | AC Coverage | Evidence | -|------|-------------|----------| -| AZ-223 | 3/3 covered | `tests/unit/test_camera_ingest_calibration.py` verifies packet metadata, blackout unusability, and raw-frame retention rejection. | -| AZ-224 | 3/3 covered | `tests/unit/test_mavlink_gcs_integration.py` verifies telemetry normalization, invalid GPS_INPUT rejection, and QGC status rate limiting. | -| AZ-225 | 3/3 covered | `tests/unit/test_tile_manager.py` verifies trusted cache activation, tamper/staleness rejection, and explicit metadata lookup rejection. | -| AZ-227 | 3/3 covered | `tests/unit/test_fdr_observability.py` verifies append/index behavior, rollover reporting, and export evidence artifacts. | - -## Architecture Compliance - -- Component writes stayed within the owning package directories declared in `_docs/02_document/module-layout.md`. -- Cross-component imports use shared public contracts and shared error envelopes only. -- No direct imports of another runtime component's internal modules were introduced. - -## Verification - -- `.venv/bin/python -m ruff check src/camera_ingest_calibration src/mavlink_gcs_integration src/tile_manager src/fdr_observability tests/unit/test_camera_ingest_calibration.py tests/unit/test_mavlink_gcs_integration.py tests/unit/test_tile_manager.py tests/unit/test_fdr_observability.py` passed. -- `.venv/bin/python -m pytest tests/unit/test_camera_ingest_calibration.py tests/unit/test_mavlink_gcs_integration.py tests/unit/test_tile_manager.py tests/unit/test_fdr_observability.py` passed: 12 tests. diff --git a/_docs/03_implementation/reviews/batch_05_review.md b/_docs/03_implementation/reviews/batch_05_review.md deleted file mode 100644 index 513d5b9..0000000 --- a/_docs/03_implementation/reviews/batch_05_review.md +++ /dev/null @@ -1,27 +0,0 @@ -# Code Review Report - -**Batch**: AZ-226_generated_tile_orthorectification -**Date**: 2026-05-03 -**Verdict**: PASS - -## Findings - -No findings. - -## Spec Compliance - -| Task | AC Coverage | Evidence | -|------|-------------|----------| -| AZ-226 | 3/3 covered | `tests/unit/test_tile_manager.py` verifies generated COG/sidecar staging, unsafe covariance rejection, and auditable sync package metadata. | - -## Architecture Compliance - -- Edits stayed inside `src/tile_manager/**` plus focused unit tests. -- Generated tile behavior consumes existing Tile Manager and shared contract patterns; no new cross-component internal imports were introduced. -- Generated outputs use `generated`/`candidate` trust levels and do not promote onboard tiles directly to trusted basemap records. - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` passed. -- `.venv/bin/python -m ruff check src tests e2e/replay` passed. -- `.venv/bin/python -m pytest` passed: 32 tests. diff --git a/_docs/03_implementation/reviews/batch_06_review.md b/_docs/03_implementation/reviews/batch_06_review.md deleted file mode 100644 index 3d901a1..0000000 --- a/_docs/03_implementation/reviews/batch_06_review.md +++ /dev/null @@ -1,61 +0,0 @@ -# Code Review Report - -**Batch**: AZ-228_vio_adapter, AZ-229_satellite_service_sync -**Date**: 2026-05-03 -**Verdict**: PASS - -## Findings - -No findings. - -## Review Scope - -- Task specs: - - `_docs/02_tasks/todo/AZ-228_vio_adapter.md` - - `_docs/02_tasks/todo/AZ-229_satellite_service_sync.md` -- Changed files: - - `src/vio_adapter/__init__.py` - - `src/vio_adapter/interfaces.py` - - `src/vio_adapter/types.py` - - `src/satellite_service/__init__.py` - - `src/satellite_service/interfaces.py` - - `src/satellite_service/types.py` - - `tests/unit/test_vio_adapter.py` - - `tests/unit/test_satellite_service_sync.py` - -## Phase Notes - -### Spec Compliance - -- AZ-228 AC-1 is covered by `test_valid_synchronized_packet_emits_vio_state`. -- AZ-228 AC-2 is covered by `test_timestamp_mismatch_is_explicit_validation_error`. -- AZ-228 AC-3 is covered by `test_tracking_loss_degrades_health_without_emitting_absolute_position`. -- AZ-229 AC-1 is covered by `test_pre_flight_import_returns_package_for_tile_manager_validation`. -- AZ-229 AC-2 is covered by `test_post_flight_upload_records_retryable_failure_for_audit`. -- AZ-229 AC-3 is covered by `test_in_flight_sync_is_blocked_without_calling_network_boundary`. - -### Code Quality - -The implementation follows the existing Pydantic model style, keeps component logic inside the owning packages, and exposes only public API exports through component `__init__.py` files. - -### Security Quick-Scan - -No hardcoded secrets, shell execution, deserialization paths, SQL construction, or sensitive credential logging were introduced. The Satellite Service sync boundary explicitly rejects in-flight package exchange before invoking the uploader. - -### Performance Scan - -No unbounded network path or per-frame heavy retrieval path was introduced. The VIO adapter uses a bounded timestamp-window selection over the provided telemetry samples. - -### Cross-Task Consistency - -The VIO adapter and Satellite Service sync boundary remain independent batch outputs and share existing DTO/error-envelope conventions. - -### Architecture Compliance - -Imports respect `_docs/02_document/module-layout.md`: VIO imports only shared public APIs, and Satellite Service imports Tile Manager through the package public API. - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` -- `.venv/bin/python -m ruff check src tests e2e/replay` -- `.venv/bin/python -m pytest` diff --git a/_docs/03_implementation/reviews/batch_07_review.md b/_docs/03_implementation/reviews/batch_07_review.md deleted file mode 100644 index a06bb5f..0000000 --- a/_docs/03_implementation/reviews/batch_07_review.md +++ /dev/null @@ -1,54 +0,0 @@ -# Code Review Report - -**Batch**: AZ-230_satellite_service_vpr_retrieval -**Date**: 2026-05-03 -**Verdict**: PASS - -## Findings - -No findings. - -## Review Scope - -- Task spec: - - `_docs/02_tasks/todo/AZ-230_satellite_service_vpr_retrieval.md` -- Changed files: - - `src/satellite_service/__init__.py` - - `src/satellite_service/interfaces.py` - - `src/satellite_service/types.py` - - `tests/unit/test_satellite_service_vpr.py` - -## Phase Notes - -### Spec Compliance - -- AZ-230 AC-1 is covered by `test_valid_local_index_load_reports_ready_status`. -- AZ-230 AC-2 is covered by `test_loaded_index_returns_bounded_candidates_with_freshness`. -- AZ-230 AC-3 is covered by `test_missing_index_degrades_with_explicit_no_candidate_result`. -- Descriptor-fidelity gating is covered by `test_descriptor_fidelity_gate_rejects_large_optimized_delta`. - -### Code Quality - -The implementation follows the existing component pattern: public Pydantic models live in `types.py`, behavior and protocols live in `interfaces.py`, and component exports are centralized in `__init__.py`. - -### Security Quick-Scan - -No network calls, shell execution, dynamic code execution, hardcoded secrets, or credential logging were introduced. Retrieval only uses local preloaded descriptor records. - -### Performance Scan - -Candidate scoring is bounded by the loaded local index and request `top_k` is constrained to 50. The implementation does not add a steady-state per-frame retrieval loop. - -### Cross-Task Consistency - -The retrieval code reuses the Satellite Service sync boundary’s offline-only posture and shared `VprCandidate`/`ErrorEnvelope` contracts. - -### Architecture Compliance - -Imports respect `_docs/02_document/module-layout.md`: Satellite Service imports shared contracts/errors and Tile Manager through public package exports only. - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` -- `.venv/bin/python -m ruff check src tests e2e/replay` -- `.venv/bin/python -m pytest` diff --git a/_docs/03_implementation/reviews/batch_08_review.md b/_docs/03_implementation/reviews/batch_08_review.md deleted file mode 100644 index 0c66639..0000000 --- a/_docs/03_implementation/reviews/batch_08_review.md +++ /dev/null @@ -1,53 +0,0 @@ -# Code Review Report - -**Batch**: AZ-231_anchor_verification_matching -**Date**: 2026-05-03 -**Verdict**: PASS - -## Findings - -No findings. - -## Review Scope - -- Task spec: - - `_docs/02_tasks/todo/AZ-231_anchor_verification_matching.md` -- Changed files: - - `src/anchor_verification/__init__.py` - - `src/anchor_verification/interfaces.py` - - `src/anchor_verification/types.py` - - `tests/unit/test_anchor_verification.py` - -## Phase Notes - -### Spec Compliance - -- AZ-231 AC-1 is covered by `test_candidate_verification_emits_acceptance_evidence`. -- AZ-231 AC-2 is covered by `test_unsafe_candidate_is_rejected_with_reason`. -- AZ-231 AC-3 is covered by `test_matcher_benchmark_reports_profile_runtime_and_quality_metrics`. - -### Code Quality - -The implementation keeps evidence/result models in `types.py`, gate behavior in `interfaces.py`, and public exports in `__init__.py`. The benchmark path computes each verification result once and reports runtime/quality metrics per matcher profile. - -### Security Quick-Scan - -No network calls, shell execution, dynamic code execution, hardcoded secrets, or credential logging were introduced. - -### Performance Scan - -Anchor verification is request/trigger oriented and does not add a per-frame learned matcher loop. Benchmark reporting is bounded by the provided evidence tuple. - -### Cross-Task Consistency - -The verifier consumes `VprCandidate` outputs from Satellite Service and emits shared `AnchorDecision` DTOs for the later safety wrapper task. - -### Architecture Compliance - -Imports respect `_docs/02_document/module-layout.md`: Anchor Verification imports shared contracts only and does not reach into Satellite Service or Tile Manager internals. - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` -- `.venv/bin/python -m ruff check src tests e2e/replay` -- `.venv/bin/python -m pytest` diff --git a/_docs/03_implementation/reviews/batch_09_review.md b/_docs/03_implementation/reviews/batch_09_review.md deleted file mode 100644 index 712b04e..0000000 --- a/_docs/03_implementation/reviews/batch_09_review.md +++ /dev/null @@ -1,54 +0,0 @@ -# Code Review Report - -**Batch**: AZ-232_safety_anchor_state_machine -**Date**: 2026-05-03 -**Verdict**: PASS - -## Findings - -No findings. - -## Review Scope - -- Task spec: - - `_docs/02_tasks/todo/AZ-232_safety_anchor_state_machine.md` -- Changed files: - - `src/safety_anchor_wrapper/__init__.py` - - `src/safety_anchor_wrapper/interfaces.py` - - `src/safety_anchor_wrapper/types.py` - - `tests/unit/test_safety_anchor_wrapper.py` - -## Phase Notes - -### Spec Compliance - -- AZ-232 AC-1 is covered by `test_vio_state_updates_position_estimate_with_honest_covariance`. -- AZ-232 AC-2 is covered by `test_accepted_anchor_corrects_state_and_records_evidence`. -- AZ-232 AC-3 is covered by `test_blackout_degrades_then_reaches_no_fix_with_monotonic_covariance`. -- AZ-232 AC-4 is covered by `test_tile_write_eligibility_requires_trusted_low_covariance_pose`. - -### Code Quality - -The safety wrapper owns source-label, covariance, anchor-promotion, degraded-mode, and tile-eligibility decisions without reaching into VIO, Anchor Verification, MAVLink transport, or Tile Manager internals. - -### Security Quick-Scan - -No network calls, shell execution, dynamic code execution, hardcoded secrets, or credential logging were introduced. - -### Performance Scan - -State transitions are constant-time and operate on typed DTOs. No per-frame heavy retrieval or matching work was introduced. - -### Cross-Task Consistency - -The wrapper consumes `VioStatePacket` and `AnchorDecision` outputs from previous batches and emits shared `PositionEstimate` DTOs for MAVLink/GCS integration. - -### Architecture Compliance - -Imports respect `_docs/02_document/module-layout.md`: Safety And Anchor Wrapper imports shared contracts and does not call Tile Manager directly during anchor acceptance. - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` -- `.venv/bin/python -m ruff check src tests e2e/replay` -- `.venv/bin/python -m pytest` diff --git a/_docs/03_implementation/reviews/batch_10_review.md b/_docs/03_implementation/reviews/batch_10_review.md deleted file mode 100644 index 0613569..0000000 --- a/_docs/03_implementation/reviews/batch_10_review.md +++ /dev/null @@ -1,31 +0,0 @@ -# Code Review Report - -**Batch**: AZ-240_native_vio_backend_integration, AZ-241_real_satellite_vpr_descriptor_retrieval, AZ-242_real_anchor_feature_matching_ransac -**Date**: 2026-05-05 -**Verdict**: PASS - -## Findings - -| # | Severity | Category | File:Line | Title | -|---|----------|----------|-----------|-------| -| - | - | - | - | No findings | - -## Review Notes - -- AZ-240: `NativeVioBackend` keeps engine-specific setup behind the `VioBackend` protocol, maps initialization/runtime errors to explicit `VioHealthReport` failures, and preserves timestamp mismatch, tracking-quality degradation, and no-WGS84-authority behavior. -- AZ-241: `LocalVprRetriever` now loads local descriptor/index packages from cache files, builds a CPU FAISS-compatible descriptor index, reports readiness with loaded record counts, and returns degraded/no-candidate results for missing or invalid packages without network access. -- AZ-242: `GeometryGatedAnchorVerifier` now has a computed matcher path from frame/tile keypoints through `KeypointRansacMatcher`, while the existing safety gates still reject stale provenance, low inliers, high MRE, and geometry failures. - -## AC Coverage - -| Task | AC Coverage | -|------|-------------| -| AZ-240 | 3/3 covered by `tests/unit/test_vio_adapter.py` | -| AZ-241 | 3/3 covered by `tests/unit/test_satellite_service_vpr.py` | -| AZ-242 | 3/3 covered by `tests/unit/test_anchor_verification.py` | - -## Verification - -- `python3 -m pytest tests/unit/test_vio_adapter.py tests/unit/test_satellite_service_vpr.py tests/unit/test_anchor_verification.py` passed: 19 tests. -- `python3 -m pytest` passed: 58 tests. -- `python3 -m black ...` and `python3 -m ruff ...` could not run because those optional dev tools are not installed in the current interpreter. diff --git a/_docs/03_implementation/reviews/batch_11_review.md b/_docs/03_implementation/reviews/batch_11_review.md deleted file mode 100644 index 8ebffa6..0000000 --- a/_docs/03_implementation/reviews/batch_11_review.md +++ /dev/null @@ -1,19 +0,0 @@ -# Code Review Report - -**Batch**: AZ-233_test_infrastructure -**Date**: 2026-05-05 -**Verdict**: PASS - -## Findings - -| # | Severity | Category | File:Line | Title | -|---|----------|----------|-----------|-------| - -No findings. - -## Review Notes - -- Spec compliance: AC-1 through AC-4 are covered by `tests/blackbox/test_infrastructure.py`. -- Scope: changes stay within blackbox/e2e test-support ownership plus replay container and compose wiring. -- Security quick-scan: no subprocess shell execution, dynamic evaluation, hardcoded secrets, or network calls were introduced. -- Architecture: test infrastructure imports only its own `e2e.replay` package and does not import runtime component internals. diff --git a/_docs/03_implementation/reviews/batch_12_review.md b/_docs/03_implementation/reviews/batch_12_review.md deleted file mode 100644 index 59c1ed4..0000000 --- a/_docs/03_implementation/reviews/batch_12_review.md +++ /dev/null @@ -1,19 +0,0 @@ -# Code Review Report - -**Batch**: AZ-234_replay_geolocation_confidence_tests, AZ-235_vio_replay_performance_tests, AZ-236_satellite_anchor_cache_tests, AZ-237_mavlink_blackout_spoofing_tests -**Date**: 2026-05-05 -**Verdict**: PASS - -## Findings - -| # | Severity | Category | File:Line | Title | -|---|----------|----------|-----------|-------| - -No findings. - -## Review Notes - -- Spec compliance: all ACs for AZ-234 through AZ-237 are covered by focused blackbox tests. -- Scope: tests use public runtime packages (`vio_adapter`, `satellite_service`, `anchor_verification`, `safety_anchor_wrapper`, `mavlink_gcs_integration`) and test-side harness helpers only. -- Security quick-scan: no external network access, dynamic execution, shell invocation, or secrets were introduced. -- Architecture: no runtime internals or private component modules are imported by the blackbox tests. diff --git a/_docs/03_implementation/reviews/batch_13_review.md b/_docs/03_implementation/reviews/batch_13_review.md deleted file mode 100644 index a0363b9..0000000 --- a/_docs/03_implementation/reviews/batch_13_review.md +++ /dev/null @@ -1,19 +0,0 @@ -# Code Review Report - -**Batch**: AZ-238_cold_start_restart_tests, AZ-239_jetson_resource_endurance_tests -**Date**: 2026-05-05 -**Verdict**: PASS - -## Findings - -| # | Severity | Category | File:Line | Title | -|---|----------|----------|-----------|-------| - -No findings. - -## Review Notes - -- Spec compliance: all ACs for AZ-238 and AZ-239 are covered by focused blackbox tests. -- Scope: changes add test-side restart/resource helpers and blackbox tests only; runtime component code remains untouched. -- Security quick-scan: no external network access, shell invocation, dynamic execution, or secrets were introduced. -- Architecture: tests use public FDR and replay harness boundaries and preserve run-scoped artifact behavior. diff --git a/_docs/03_implementation/reviews/batch_14_review.md b/_docs/03_implementation/reviews/batch_14_review.md deleted file mode 100644 index 8d41d3e..0000000 --- a/_docs/03_implementation/reviews/batch_14_review.md +++ /dev/null @@ -1,24 +0,0 @@ -# Code Review Report - -**Batch**: AZ-243_integrate_production_native_vio_runtime -**Date**: 2026-05-06 -**Verdict**: PASS - -## Findings - -No findings. - -## Phase Summary - -- Spec compliance: AC-1 is covered by production `VioRuntimeConfig` native-mode selection and `create_vio_adapter`; AC-2 is covered by BASALT runtime loader prerequisite errors; AC-3 is covered by explicit development replay mode and production replay-mode rejection. -- Code quality: The native runner loader, configured backend, and adapter factory keep backend-specific setup behind `src/vio_adapter/**` and preserve the public `VioBackend`/`VioAdapter` contracts. -- Security quick-scan: No secrets, subprocess calls, dynamic code execution, shell execution, or sensitive logging were introduced. -- Performance scan: Native runner creation is lazy and occurs during adapter initialization; per-packet processing remains delegated to the selected backend. -- Architecture compliance: Changed code stays inside VIO ownership and tests, imports only shared lower-layer contracts plus same-component modules, and introduces no cross-component cycles. - -## Verification - -- `python3 -m black src/vio_adapter tests/unit/test_vio_adapter.py tests/blackbox/test_vio_replay.py` -- `python3 -m ruff check src/vio_adapter tests/unit/test_vio_adapter.py tests/blackbox/test_vio_replay.py` -- `python3 -m pytest tests/unit/test_vio_adapter.py tests/blackbox/test_vio_replay.py`: 13 passed. -- `python3 -m pytest`: 87 passed. diff --git a/_docs/03_implementation/reviews/cumulative_review_batches_01-09_cycle1_report.md b/_docs/03_implementation/reviews/cumulative_review_batches_01-09_cycle1_report.md deleted file mode 100644 index 652ab04..0000000 --- a/_docs/03_implementation/reviews/cumulative_review_batches_01-09_cycle1_report.md +++ /dev/null @@ -1,65 +0,0 @@ -# Code Review Report - -**Batch**: cumulative batches 01-09, cycle 1 -**Date**: 2026-05-04 -**Verdict**: PASS - -## Scope - -- Task specs reviewed: AZ-219 through AZ-232. -- Batch reports reviewed: `_docs/03_implementation/batch_01_cycle1_report.md` through `_docs/03_implementation/batch_09_cycle1_report.md`. -- Code scope reviewed: `src/`, `tests/`, and `e2e/replay`. -- Architecture references reviewed: `_docs/02_document/architecture.md` and `_docs/02_document/module-layout.md`. - -## Findings - -| # | Severity | Category | File:Line | Title | -|---|----------|----------|-----------|-------| -| - | - | - | - | No findings | - -## Phase Results - -### Phase 1: Context Loading - -All 14 product implementation tasks, the project restrictions, the solution overview, module layout, architecture, and batch reports were reviewed. - -### Phase 2: Spec Compliance - -Every task acceptance criterion is covered by the per-batch reports and unit tests. The final full suite passed with 49 tests. - -### Phase 3: Code Quality - -Formatter and lint checks passed: - -- `.venv/bin/python -m black --check src tests e2e/replay` -- `.venv/bin/python -m ruff check src tests e2e/replay` - -No dead imports, style errors, or obvious duplicated component-local contract shapes were found. - -### Phase 4: Security Quick-Scan - -No hardcoded secrets, `eval`, `exec`, shell subprocess usage, insecure deserialization, or sensitive-data logging patterns were found in `src/`. - -### Phase 5: Performance Scan - -The implemented code remains lightweight and trigger-oriented for the current scaffold/runtime-contract level. Heavy VPR, matching, Jetson, SITL, and endurance profiling remain release-gate work for later test implementation and deploy phases. - -### Phase 6: Cross-Task Consistency - -Shared DTOs and component interfaces are consistently consumed through public package surfaces. Batch-level reports show all dependencies were implemented before consumers. - -### Phase 7: Architecture Compliance - -Observed imports align with the component public API layout: - -- Runtime components import shared helpers and contracts through `shared/*` public modules. -- Cross-component imports use package-level public exports such as `tile_manager`, not internal component files. -- No component imports from `internal/`, `_*.py`, or native bridge paths owned by another component. - -No architecture baseline file exists, so no baseline delta section is required. - -## Verification - -- `.venv/bin/python -m black --check src tests e2e/replay` passed. -- `.venv/bin/python -m ruff check src tests e2e/replay` passed. -- `.venv/bin/python -m pytest` passed: 49 tests. diff --git a/_docs/03_implementation/reviews/cumulative_review_batches_11-13_tests_report.md b/_docs/03_implementation/reviews/cumulative_review_batches_11-13_tests_report.md deleted file mode 100644 index f23b0d7..0000000 --- a/_docs/03_implementation/reviews/cumulative_review_batches_11-13_tests_report.md +++ /dev/null @@ -1,30 +0,0 @@ -# Code Review Report - -**Batch**: Cumulative test implementation batches 11-13 -**Date**: 2026-05-05 -**Verdict**: PASS - -## Findings - -| # | Severity | Category | File:Line | Title | -|---|----------|----------|-----------|-------| - -No findings. - -## Cumulative Scope - -- Batch 11: AZ-233 blackbox/e2e replay infrastructure. -- Batch 12: AZ-234, AZ-235, AZ-236, AZ-237 replay, cache, VIO, and MAVLink blackbox tests. -- Batch 13: AZ-238, AZ-239 restart, cold-start, Jetson resource, and FDR endurance tests. - -## Cross-Task Consistency - -- All blackbox tests use the shared `e2e.replay.harness` helpers for blocked prerequisites, run-scoped reports, deterministic stubs, and metric aggregation. -- Test files import only public component packages or the test harness; no private runtime internals are imported. -- Hardware and calibration gates consistently report `blocked` instead of passing when prerequisites are unavailable. - -## Architecture Compliance - -- Test-support code remains under `e2e/**` and `tests/blackbox/**`. -- Runtime product packages under `src/**` were not modified during test implementation. -- No new component-layer cycles or cross-component private imports were introduced. diff --git a/_docs/04_refactoring/01-testability-refactoring/testability_assessment.md b/_docs/04_refactoring/01-testability-refactoring/testability_assessment.md deleted file mode 100644 index eb66cd8..0000000 --- a/_docs/04_refactoring/01-testability-refactoring/testability_assessment.md +++ /dev/null @@ -1,58 +0,0 @@ -# Code Testability Assessment - -**Date**: 2026-05-05 -**Autodev step**: Greenfield Step 8 — Code Testability Revision -**Outcome**: Code is testable — no changes needed - -## Scope Reviewed - -- Test specifications in `_docs/02_document/tests/` -- Traceability matrix in `_docs/02_document/tests/traceability-matrix.md` -- Runtime source under `src/` -- Existing unit tests under `tests/` -- Product implementation report `_docs/03_implementation/implementation_report_product_runtime_cycle1.md` -- Product completeness report `_docs/03_implementation/implementation_completeness_cycle1_report.md` - -## Testability Result - -The implemented product runtime can support the planned tests without a testability-focused refactor. - -- Runtime components expose public package-level APIs through `__init__.py`, `types.py`, and `interfaces.py`. -- Component behavior is expressed through data models and class/protocol boundaries that can be constructed directly in tests. -- External systems are represented as boundary objects or planned black-box fixtures, not hardwired network calls. -- VIO engine, local VPR descriptor index, and anchor matcher paths are injectable through protocol/class boundaries. -- The only runtime filesystem read found in `src/` is `LocalVprIndexPackage.from_json_file(package_path)`, which accepts a caller-supplied path and is directly testable with temporary fixture files. -- No direct environment, subprocess, socket, HTTP, global singleton, or non-configurable heavy dependency construction was found in `src/` that would block deterministic tests. -- Planned hardware, SITL, Jetson, and dataset dependencies belong in test harness tasks and can report `blocked` when prerequisites are unavailable. - -## Scenario Review - -| Scenario Area | Testability Assessment | -|---------------|------------------------| -| Unit/component tests | Current public classes and DTOs are directly constructible and already covered by 58 passing tests. | -| Black-box replay | The planned harness can drive public frame, telemetry, cache, MAVLink, status, and FDR boundaries without importing runtime internals. | -| VIO and anchor replay | Heavy BASALT, FAISS, and matcher dependencies can be represented by test harness fixtures or backend boundaries in test tasks. | -| SITL/MAVLink tests | The MAVLink/GCS gateway exposes validation and status behavior without requiring live hardware for unit-level coverage. | -| Jetson/resource tests | Hardware-specific release gates are environment-dependent and do not require runtime refactoring before test-task implementation. | -| Security/cache tests | Cache, freshness, no-fetch, and generated-tile trust behavior is exposed through public component methods. | - -## Reviewed Test Artifacts - -- `_docs/02_document/tests/blackbox-tests.md` -- `_docs/02_document/tests/e2e-test-suite.md` -- `_docs/02_document/tests/environment.md` -- `_docs/02_document/tests/performance-tests.md` -- `_docs/02_document/tests/resilience-tests.md` -- `_docs/02_document/tests/resource-limit-tests.md` -- `_docs/02_document/tests/security-tests.md` -- `_docs/02_document/tests/test-data.md` -- `_docs/02_document/tests/traceability-matrix.md` - -## Verification - -- `python3 -m pytest` passed: 58 tests. -- `python3 -m black ...` and `python3 -m ruff ...` could not run because those optional dev tool modules are not installed in the current interpreter. - -## Next Step - -Proceed to Greenfield Step 9, Decompose Tests. diff --git a/_docs/05_security/dependency_scan.md b/_docs/05_security/dependency_scan.md deleted file mode 100644 index c9433f1..0000000 --- a/_docs/05_security/dependency_scan.md +++ /dev/null @@ -1,34 +0,0 @@ -# Dependency Vulnerability Scan - -**Date**: 2026-05-07 -**Tool**: `pip-audit 2.10.0` -**Manifest**: `pyproject.toml` -**Result**: PASS - -## Scope - -The scan covered the Python dependencies declared in `pyproject.toml`, including the `dev` optional dependency group: - -- `pydantic==2.13.3` -- `black>=24.0` -- `pytest>=8.0` -- `ruff>=0.5` - -## Findings - -No known vulnerabilities were reported. - -## Audit Output Summary - -`pip-audit` resolved and checked the project dependency set and returned: - -```text -No known vulnerabilities found -``` - -Resolved packages with no advisories included `pydantic`, `pydantic-core`, `black`, `pytest`, and `ruff`. - -## Notes - -- `pip-audit` and its own transitive packages were installed as an audit tool in the local Python environment. -- The repository does not currently include a locked production dependency file, so the audit used the version constraints from `pyproject.toml`. diff --git a/_docs/05_security/infrastructure_review.md b/_docs/05_security/infrastructure_review.md deleted file mode 100644 index 21326c4..0000000 --- a/_docs/05_security/infrastructure_review.md +++ /dev/null @@ -1,49 +0,0 @@ -# Infrastructure Security Review - -**Date**: 2026-05-07 -**Scope**: Dockerfiles, compose files, environment templates, GitHub Actions -**Result**: PASS_WITH_WARNINGS - -## Reviewed Artifacts - -- `deployment/docker/Dockerfile.runtime` -- `deployment/docker/Dockerfile.replay` -- `docker-compose.yml` -- `docker-compose.test.yml` -- `.github/workflows/ci.yml` -- `.env.example` -- `config/development/runtime.env` -- `config/ci/runtime.env` -- `config/jetson/runtime.env` - -## Findings - -| ID | Severity | Category | Location | Title | -|----|----------|----------|----------|-------| -| I1 | Medium | Security Misconfiguration | `docker-compose.yml:7`, `docker-compose.yml:9`, `.env.example:5` | Default Postgres password and exposed host port need stronger dev/prod separation | -| I2 | Low | CI/CD Hardening | `.github/workflows/ci.yml` | CI lacks dependency audit / secret scan / SAST gates | - -## Finding Details - -### I1: Default Postgres password and exposed host port need stronger dev/prod separation - -`docker-compose.yml` uses `POSTGRES_PASSWORD=gpsd`, publishes `5432:5432`, and points runtime at `.env.example`, which embeds the same example credentials in `GPSD_DATABASE_URL`. - -**Impact**: Safe enough for local development if never deployed, but risky if copied into staging, Jetson, or field environments. - -**Remediation**: Move credentials into an ignored local `.env`, document `docker-compose.yml` as development-only, bind local Postgres to loopback, and require production/Jetson credentials from a secret manager or deployment-time secret source. - -### I2: CI lacks dependency audit / secret scan / SAST gates - -`.github/workflows/ci.yml` runs format, lint, unit tests, and compose config validation, but it does not run dependency audit, secret scanning, or SAST. - -**Impact**: Vulnerable dependencies or accidentally committed secrets may be caught only during manual audits. - -**Remediation**: Add `pip-audit` for Python dependencies, a secret scanner such as Gitleaks/TruffleHog, and a lightweight SAST pass such as Semgrep or Ruff security rules when the project adopts them. - -## Positive Controls - -- Runtime and replay Dockerfiles create and run as a non-root `gpsd` user. -- Runtime image copies only project source and `pyproject.toml`/`README.md`, not `.env` or fixture payloads. -- `docker-compose.test.yml` keeps replay/SITL/cache stubs on isolated compose networks and exposes no host ports. -- `config/jetson/runtime.env` contains paths and mode labels only; it does not include embedded passwords or signing keys. diff --git a/_docs/05_security/owasp_review.md b/_docs/05_security/owasp_review.md deleted file mode 100644 index 67b87d3..0000000 --- a/_docs/05_security/owasp_review.md +++ /dev/null @@ -1,26 +0,0 @@ -# OWASP Top 10 Review - -**Date**: 2026-05-07 -**Reference**: OWASP Top 10:2021, current official Top 10 referenced from -**Result**: PASS_WITH_WARNINGS - -## Assessment - -| OWASP Category | Status | Findings / Notes | -|----------------|--------|------------------| -| A01: Broken Access Control | PASS | No web/API authorization surface is implemented in the current runtime code. MAVLink source/system ID and cache trust boundaries are represented in architecture/tests. | -| A02: Cryptographic Failures | PASS_WITH_WARNINGS | No weak crypto or secret leakage found in source. Cache signature checks compare trusted signature hashes, but production key handling remains a deployment concern. | -| A03: Injection | PASS | No SQL construction, shell execution, dynamic code execution, or template rendering paths were found in source. | -| A04: Insecure Design | PASS_WITH_WARNINGS | `S1` is a resource-exhaustion design gap for local VPR descriptor package loading. | -| A05: Security Misconfiguration | PASS_WITH_WARNINGS | `S2` covers default development database credentials and broad host port exposure in `docker-compose.yml`. | -| A06: Vulnerable and Outdated Components | PASS | `pip-audit` reported no known vulnerabilities for the project dependency set. | -| A07: Identification and Authentication Failures | NOT_APPLICABLE | No user/session authentication surface is implemented in this package. | -| A08: Software and Data Integrity Failures | PASS_WITH_WARNINGS | Cache metadata validation is implemented, but CI currently validates tests/compose only; dependency audit and secret/SAST scanning are not yet CI gates. | -| A09: Security Logging and Monitoring Failures | PASS | Architecture and tests require FDR/QGC visibility for cache rejection, spoofing, blackout, and health events. | -| A10: Server-Side Request Forgery | NOT_APPLICABLE | No HTTP client, URL-fetching, or server-side request surface was found in runtime source. | - -## OWASP Notes - -- The current package is primarily an onboard runtime and replay harness, not a web application. Several OWASP categories are therefore assessed through local trust boundaries: cache package integrity, MAVLink source filtering, runtime configuration, and generated-tile promotion. -- The strongest security controls already represented in code/docs are no in-flight satellite-provider calls, cache manifest/hash checks, spoofed/unauthorized MAVLink rejection tests, and FDR-visible security events. -- Remaining warnings are hardening items rather than exploitable remote vulnerabilities in the current code shape. diff --git a/_docs/05_security/security_report.md b/_docs/05_security/security_report.md deleted file mode 100644 index 3306a7b..0000000 --- a/_docs/05_security/security_report.md +++ /dev/null @@ -1,106 +0,0 @@ -# Security Audit Report - -**Date**: 2026-05-07 -**Scope**: GPS-denied onboard runtime and replay infrastructure -**Verdict**: PASS_WITH_WARNINGS - -## Summary - -| Severity | Count | -|----------|-------| -| Critical | 0 | -| High | 0 | -| Medium | 2 | -| Low | 1 | - -No Critical or High issues were found. The audit can proceed through the autodev gate, with hardening work recommended before production deployment. - -## OWASP Top 10 Assessment - -| Category | Status | Findings | -|----------|--------|----------| -| A01: Broken Access Control | PASS | — | -| A02: Cryptographic Failures | PASS_WITH_WARNINGS | Deployment key handling remains a release concern | -| A03: Injection | PASS | — | -| A04: Insecure Design | PASS_WITH_WARNINGS | S1 | -| A05: Security Misconfiguration | PASS_WITH_WARNINGS | S2 / I1 | -| A06: Vulnerable and Outdated Components | PASS | — | -| A07: Identification and Authentication Failures | NOT_APPLICABLE | No auth/session surface in current package | -| A08: Software and Data Integrity Failures | PASS_WITH_WARNINGS | I2 | -| A09: Security Logging and Monitoring Failures | PASS | — | -| A10: Server-Side Request Forgery | NOT_APPLICABLE | No URL-fetching runtime surface | - -## Findings - -| # | Severity | Category | Location | Title | -|---|----------|----------|----------|-------| -| 1 | Medium | Resource / Input Validation | `src/satellite_service/types.py:67` | VPR index JSON is read fully without size limits | -| 2 | Medium | Security Misconfiguration | `docker-compose.yml:7`, `docker-compose.yml:9`, `.env.example:5` | Default DB credentials and exposed port need dev/prod separation | -| 3 | Low | CI/CD Hardening | `.github/workflows/ci.yml` | CI lacks dependency audit / secret scan / SAST gates | - -## Finding Details - -### F1: VPR index JSON is read fully without size limits - -**Severity**: Medium -**Category**: Resource / Input Validation -**Location**: `src/satellite_service/types.py:67` - -`LocalVprIndexPackage.from_json_file()` reads an entire local descriptor package into memory before validation. Descriptor packages are part of the local cache trust boundary and can become large. - -**Impact**: A malformed or unexpectedly large package could exhaust memory or stall startup/readiness on Jetson. - -**Remediation**: Add a maximum file-size check before reading, cap descriptor record count and descriptor length, and require callers to load only manifest-validated package paths. - -### F2: Default DB credentials and exposed port need dev/prod separation - -**Severity**: Medium -**Category**: Security Misconfiguration -**Location**: `docker-compose.yml:7`, `docker-compose.yml:9`, `.env.example:5` - -The default compose file uses `POSTGRES_PASSWORD=gpsd`, publishes Postgres on `5432:5432`, and the example database URL embeds `gpsd:gpsd`. - -**Impact**: Safe enough as a local fixture convention, but risky if reused in staging, Jetson, or field deployment. - -**Remediation**: Move credentials to ignored local `.env` files, document the default compose as development-only, bind Postgres to loopback for local runs, and require secret-manager sourced credentials for production/Jetson deploys. - -### F3: CI lacks dependency audit / secret scan / SAST gates - -**Severity**: Low -**Category**: CI/CD Hardening -**Location**: `.github/workflows/ci.yml` - -CI runs format, lint, unit tests, and compose config validation, but not dependency audit, secret scanning, or SAST. - -**Impact**: Vulnerable dependencies or accidentally committed secrets may be caught only during manual audits. - -**Remediation**: Add `pip-audit`, a secret scanner such as Gitleaks/TruffleHog, and a lightweight SAST pass such as Semgrep or Ruff security rules. - -## Dependency Vulnerabilities - -| Package | CVE / Advisory | Severity | Fix Version | -|---------|----------------|----------|-------------| -| None | — | — | — | - -## Positive Controls - -- `pip-audit` reported no known vulnerabilities for the declared Python dependency set. -- No SQL construction, shell execution, dynamic code execution, Pickle/marshal use, weak crypto, hardcoded production secrets, or HTTP URL-fetching runtime surface was found in source. -- Runtime and replay Dockerfiles run as non-root `gpsd`. -- Cache manifest/hash validation, no in-flight satellite-provider access, MAVLink spoofing/source rejection, and FDR-visible security events are represented in code, docs, and tests. - -## Recommendations - -### Immediate - -- None required for Critical/High severity because no Critical/High findings were found. - -### Short-Term - -- Add size/count limits to VPR descriptor package loading. -- Split local-development database credentials from production/Jetson deploy configuration and restrict local Postgres host binding. - -### Long-Term - -- Add dependency audit, secret scanning, and SAST to CI. -- Re-run security audit after the deploy step creates final production deployment artifacts. diff --git a/_docs/05_security/static_analysis.md b/_docs/05_security/static_analysis.md deleted file mode 100644 index 3fc333d..0000000 --- a/_docs/05_security/static_analysis.md +++ /dev/null @@ -1,45 +0,0 @@ -# Static Analysis - -**Date**: 2026-05-07 -**Scope**: Python source, tests, replay harness, tools, compose/config files -**Result**: PASS_WITH_WARNINGS - -## Findings - -| ID | Severity | Category | Location | Title | -|----|----------|----------|----------|-------| -| S1 | Medium | Resource / Input Validation | `src/satellite_service/types.py:67` | VPR index JSON is read fully without size limits | -| S2 | Medium | Security Misconfiguration | `docker-compose.yml:7`, `docker-compose.yml:9`, `.env.example:5` | Development database credentials and exposed port are easy to reuse outside dev | - -## Finding Details - -### S1: VPR index JSON is read fully without size limits - -**Location**: `src/satellite_service/types.py:67` - -`LocalVprIndexPackage.from_json_file()` reads the entire configured descriptor package into memory with `Path(package_path).read_text()` and then parses it with `json.loads`. The model validates record shape, but there is no file-size limit, descriptor-count limit, or explicit package path trust check at this boundary. - -**Impact**: A malformed or unexpectedly large local descriptor package could exhaust memory or stall startup/readiness on a constrained Jetson target. - -**Remediation**: Add a maximum package size check before reading, cap `records` and descriptor lengths in the Pydantic model, and ensure callers pass only cache-package paths that have already passed manifest/signature validation. - -### S2: Development database credentials and exposed port are easy to reuse outside dev - -**Locations**: - -- `docker-compose.yml:7` -- `docker-compose.yml:9` -- `.env.example:5` - -`docker-compose.yml` sets `POSTGRES_PASSWORD=gpsd` and exposes Postgres on `5432:5432`. `.env.example` also embeds `gpsd:gpsd` in `GPSD_DATABASE_URL`. These are acceptable for local fixture use only if they are clearly kept out of production, but the default compose file name makes accidental reuse plausible. - -**Impact**: If this compose file is copied into a staging or field environment, the database would run with known credentials and an exposed host port. - -**Remediation**: Move the default password to an ignored local `.env`, rename or label the compose file as development-only, bind Postgres to `127.0.0.1` where host exposure is required, and add a production compose/deploy template that requires secret-manager sourced credentials. - -## Negative Checks - -- No SQL string construction or database `execute()` calls were found in source. -- No `eval`, `exec`, `os.system`, `shell=True`, Pickle, `marshal`, weak hashes, TLS verification bypass, CORS wildcard, or hardcoded production secret patterns were found in source. -- `tools/remove_osd_lines.py` uses `subprocess.run()` with an argument list and no shell; this is not command-injection prone in its current form. -- Dockerfiles run as a non-root `gpsd` user. diff --git a/_docs/_autodev_state.md b/_docs/_autodev_state.md deleted file mode 100644 index 605ae96..0000000 --- a/_docs/_autodev_state.md +++ /dev/null @@ -1,14 +0,0 @@ -# Autodev State - -## Current Step -flow: greenfield -step: 15 -name: Performance Test -status: not_started -tracker: jira -sub_step: - phase: 0 - name: awaiting-invocation - detail: "" -retry_count: 0 -cycle: 1 diff --git a/_docs/_autopilot_state.md b/_docs/_autopilot_state.md deleted file mode 100644 index 6d357c8..0000000 --- a/_docs/_autopilot_state.md +++ /dev/null @@ -1,40 +0,0 @@ -# Autopilot State - -## Current Step -flow: greenfield -step: 3 -name: Plan -status: in_progress -sub_step: 1 — Blackbox Tests (test-spec skill), Phase 2 complete, Phase 3 next -retry_count: 0 - -## Completed Steps - -| Step | Name | Completed | Key Outcome | -|------|------|-----------|-------------| -| 1 | Problem | 2026-03-25 (detected) | Problem, restrictions, acceptance criteria, and input data defined | -| 2 | Research | 2026-03-25 (detected) | 8 research rounds, 6 solution drafts, tech_stack.md, security_analysis.md | - -## Key Decisions -- Research Decision: Proceed to planning with current draft (6 drafts, 8 rounds sufficient) -- GPS-denied visual navigation system for UAV onboard Jetson Orin Nano Super -- Core algorithms: cuVSLAM, LiteSAM/XFeat, ESKF sensor fusion -- TRT engine migration for AI inference -- Latest draft (06) at TRL ~2.5-3; hardware/algorithms well-researched, system integration under-specified -- solution_draft06.md renamed to solution.md as finalized solution -- Test environment: dual-mode (Docker SITL for CI + Jetson hardware for nightly/pre-deploy) -- IMU data: ArduPilot SITL flies waypoint mission from coordinates.csv, generates 200Hz IMU via MAVLink -- Test coverage: 43 scenarios, 93% AC+restriction coverage (39/42) - -## Last Session -date: 2026-03-25 -ended_at: Step 3 Plan — SubStep 1 Blackbox Tests (test-spec Phase 2 complete) -reason: user paused — context break before Phase 3 -notes: Test-spec Phase 1 (input data analysis) and Phase 2 (test scenario specification) complete. 8 artifacts written to _docs/02_document/tests/. Expected results created at _docs/00_problem/input_data/expected_results/. Phase 3 (test data validation gate) is next — scan all test scenarios, verify each has concrete test data + quantifiable expected result, ask user to provide missing items or remove tests, final coverage check ≥70%. Then Phase 4 (test runner scripts). - -## Retry Log -| Attempt | Step | Name | SubStep | Failure Reason | Timestamp | -|---------|------|------|---------|----------------|-----------| - -## Blockers -- none diff --git a/_standalone/UAV_camera_comparison/00_research/00_question_decomposition.md b/_standalone/UAV_camera_comparison/00_research/00_question_decomposition.md deleted file mode 100644 index 88fed32..0000000 --- a/_standalone/UAV_camera_comparison/00_research/00_question_decomposition.md +++ /dev/null @@ -1,68 +0,0 @@ -# Question Decomposition - -## Original Question -Compare ViewPro Z40K and USG-231 cameras: analyze video feed quality (especially from Shark M UAV), wobble effect, zoom capabilities, image crispness, and overall quality during zoom. - -## Active Mode -Mode A Phase 2 — Initial Research (no prior solution drafts exist) - -## Question Type -**Concept Comparison** — comparing two specific camera products across defined quality dimensions - -## Research Subject Boundary -- **Population**: UAV gimbal cameras in the 500-600g class for fixed-wing reconnaissance -- **Geography**: Global (ViewPro is Chinese, USG is Ukrainian) -- **Timeframe**: Current products as of 2025-2026 -- **Level**: Product-grade ISR camera systems - -## Problem Context -User is building a reconnaissance UAV and evaluating camera payloads. The Shark M UAV (by Ukrspecsystems) uses the USG-231 as its standard payload. The ViewPro Z40K is a competing 3rd-party gimbal camera. - -## Decomposed Sub-Questions - -### SQ1: What are the core optical/sensor specifications of each camera? -- "ViewPro Z40K sensor specifications resolution zoom" -- "USG-231 sensor type resolution megapixel" -- "ViewPro Z40K Panasonic CMOS module identification" -- "USG-231 Sony FCB block camera module 30x zoom" -- "1/2.3 inch vs 1/2.8 inch CMOS sensor quality drone" - -### SQ2: How do the stabilization systems compare? -- "3-axis gimbal vs 2-axis gimbal drone camera wobble" -- "digital stabilization vs optical image stabilization OIS drone" -- "2-axis gimbal yaw problem fixed wing drone" -- "ViewPro Z40K 5-axis OIS stabilization performance" -- "USG-231 digital video stabilization quality" - -### SQ3: What is the zoom quality and behavior at high magnification? -- "20x optical zoom 4K vs 30x optical zoom Full HD surveillance" -- "intelligent zoom iA zoom quality degradation crop" -- "30x zoom drone camera atmospheric distortion max zoom" -- "ViewPro Z40K zoom test footage sharpness" - -### SQ4: What does the Shark M video feed actually look like? -- "Shark M UAV video footage quality zoom" -- "Shark UAV combat footage camera quality analysis" -- "USG-231 reconnaissance footage stabilization" - -### SQ5: How does wobble manifest on each camera? -- "3-axis gimbal wobble reduction vs 2-axis jello effect" -- "ViewPro gimbal vibration jello problem" -- "USG-231 wobble fixed wing drone flight" - -## Chosen Perspectives -1. **End-user/Operator**: What does the feed look like during missions? Usability of zoom, clarity of targets -2. **Integrator/Engineer**: Gimbal architecture, stabilization mechanism, weight, integration complexity -3. **Domain Expert (ISR)**: Effective observation range, target identification capability, zoom vs resolution trade-off -4. **Contrarian**: Where does each camera fail? What are the hidden weaknesses? - -## Timeliness Sensitivity Assessment -- **Research Topic**: UAV gimbal camera comparison (ViewPro Z40K vs USG-231) -- **Sensitivity Level**: Medium -- **Rationale**: Hardware products with stable specs; not rapidly changing like AI/software -- **Source Time Window**: 1-2 years -- **Priority official sources**: - 1. ViewPro official product pages - 2. Ukrspecsystems official product pages - 3. Sony FCB block camera datasheets - 4. Defense Express field reports diff --git a/_standalone/UAV_camera_comparison/00_research/01_source_registry.md b/_standalone/UAV_camera_comparison/00_research/01_source_registry.md deleted file mode 100644 index e976a0a..0000000 --- a/_standalone/UAV_camera_comparison/00_research/01_source_registry.md +++ /dev/null @@ -1,133 +0,0 @@ -# Source Registry - -## Source #1 -- **URL**: https://rcdrone.top/products/viewpro-z40k-4k-gimbal-camera -- **Tier**: L2 (authorized reseller with full spec sheet) -- **Summary**: Complete ViewPro Z40K specifications including sensor, zoom, gimbal, OIS details -- **Date Accessed**: 2026-03-21 - -## Source #2 -- **URL**: https://www.viewprouav.com/product/z40k-single-4k-hd-25-times-zoom-gimbal-camera -- **Tier**: L1 (manufacturer official) -- **Summary**: ViewPro official product page with specifications -- **Date Accessed**: 2026-03-21 - -## Source #3 -- **URL**: https://ukrspecsystems.com/drone-gimbals/usg-231 -- **Tier**: L1 (manufacturer official) -- **Summary**: USG-231 official specifications, features, integration details -- **Date Accessed**: 2026-03-21 - -## Source #4 -- **URL**: https://ukrspecsystems.com/drones/shark-m-uas -- **Tier**: L1 (manufacturer official) -- **Summary**: Shark M UAS full specifications, camera options, system details -- **Date Accessed**: 2026-03-21 - -## Source #5 -- **URL**: https://dronexpert.nl/en/viewpro-z40k-20x-optical-zoom-4k-camera-up-to-40x-zoom/ -- **Tier**: L2 (authorized dealer) -- **Summary**: Z40K detailed specs including effective pixel counts per resolution mode -- **Date Accessed**: 2026-03-21 - -## Source #6 -- **URL**: https://www.aeroexpo.online/prod/ukrspecsystems/product-185884-82835.html -- **Tier**: L2 (trade platform with manufacturer data) -- **Summary**: USG-231 specifications and integration details -- **Date Accessed**: 2026-03-21 - -## Source #7 -- **URL**: https://en.defence-ua.com/weapon_and_tech/how_the_newest_ukrainian_shark_uav_works_over_donetsk_and_why_its_really_cool_video-5438.html -- **Tier**: L3 (defense media analysis) -- **Summary**: Shark UAV combat footage analysis, camera quality observations, auto-tracking assessment -- **Date Accessed**: 2026-03-21 - -## Source #8 -- **URL**: https://www.cameraguidepro.com/what-is-the-difference-between-a-2-axis-and-3-axis-gimbal/ -- **Tier**: L3 (tech media) -- **Summary**: 2-axis vs 3-axis gimbal comparison, wobble/jello effect analysis -- **Date Accessed**: 2026-03-21 - -## Source #9 -- **URL**: https://www.makeuseof.com/two-axis-vs-three-axis-gimbals/ -- **Tier**: L3 (tech media) -- **Summary**: Detailed 2-axis vs 3-axis trade-offs including weight, power, cost -- **Date Accessed**: 2026-03-21 - -## Source #10 -- **URL**: https://droneflyingpro.com/2-axis-vs-3-axis-gimbal/ -- **Tier**: L3 (drone specialist media) -- **Summary**: 2-axis vs 3-axis on drones with diagrams, jello effect explanation -- **Date Accessed**: 2026-03-21 - -## Source #11 -- **URL**: https://www.steadxp.com/digital-vs-optical-stabilization-a-comparison-guide/ -- **Tier**: L3 (stabilization specialist) -- **Summary**: EIS vs OIS comparison, quality impact, artifact analysis -- **Date Accessed**: 2026-03-21 - -## Source #12 -- **URL**: https://www.guidingtech.com/eis-vs-ois-stabilization/ -- **Tier**: L3 (tech media) -- **Summary**: Digital vs optical stabilization advantages and limitations -- **Date Accessed**: 2026-03-21 - -## Source #13 -- **URL**: https://www.dronetrest.com/t/whats-the-best-choice-for-the-fixed-wing-3-axis-gimbal-or-2-axis-gimbal/8091 -- **Tier**: L4 (community forum) -- **Summary**: Fixed-wing drone gimbal selection discussion, practitioner perspectives -- **Date Accessed**: 2026-03-21 - -## Source #14 -- **URL**: https://phantompilots.com/threads/yaw-issue-with-2-axis-gimbals.6854 -- **Tier**: L4 (community forum) -- **Summary**: Real user reports of yaw wobble issues with 2-axis gimbals -- **Date Accessed**: 2026-03-21 - -## Source #15 -- **URL**: https://www.manualslib.com/manual/2385515/Viewpro-Z40k.html -- **Tier**: L1 (manufacturer manual) -- **Summary**: ViewPro Z40K user manual with detailed technical specifications -- **Date Accessed**: 2026-03-21 - -## Source #16 -- **URL**: https://www.viewprotech.com/index.php?ac=article&at=read&did=202 -- **Tier**: L1 (ViewPro official tech page) -- **Summary**: Z40K DJI PSDK series technical details, stabilization specs -- **Date Accessed**: 2026-03-21 - -## Source #17 -- **URL**: https://pro.sony/ue_US/products/zoom-camera-blocks/fcb-ev9500l -- **Tier**: L1 (Sony official) -- **Summary**: Sony FCB-EV9500L block camera specs — likely module inside USG-231 -- **Date Accessed**: 2026-03-21 - -## Source #18 -- **URL**: https://block-cameras.com/products/sony-fcb-ev9520l-30x-zoom-full-hd-block-camera-sensor-starvis-gen2 -- **Tier**: L2 (distributor) -- **Summary**: Sony FCB-EV9520L STARVIS 2 block camera specs -- **Date Accessed**: 2026-03-21 - -## Source #19 -- **URL**: https://medium.com/@daily_drones/hands-on-with-the-dji-zenmuse-z30-53ab50fe628c -- **Tier**: L3 (tech reviewer) -- **Summary**: DJI Zenmuse Z30 hands-on review (same class as USG-231 sensor) -- **Date Accessed**: 2026-03-21 - -## Source #20 -- **URL**: https://www.oreateai.com/blog/beyond-the-numbers-what-123-vs-113-inch-sensor-size-really-means-for-your-photos/ -- **Tier**: L3 (tech blog) -- **Summary**: Sensor size comparison impact on image quality -- **Date Accessed**: 2026-03-21 - -## Source #21 -- **URL**: https://en.wikipedia.org/wiki/Ukrspecsystems_Shark -- **Tier**: L3 (Wikipedia) -- **Summary**: Shark UAV family specifications and history -- **Date Accessed**: 2026-03-21 - -## Source #22 -- **URL**: https://en.defence-ua.com/weapon_and_tech/ukrainian_drone_maker_demonstrates_its_new_shark_uav_target_tracking_capabilities_video-4803.html -- **Tier**: L3 (defense media) -- **Summary**: Shark UAV target tracking demo and zoom capabilities -- **Date Accessed**: 2026-03-21 diff --git a/_standalone/UAV_camera_comparison/00_research/02_fact_cards.md b/_standalone/UAV_camera_comparison/00_research/02_fact_cards.md deleted file mode 100644 index 61cb7ad..0000000 --- a/_standalone/UAV_camera_comparison/00_research/02_fact_cards.md +++ /dev/null @@ -1,151 +0,0 @@ -# Fact Cards - -## Fact #1 -- **Statement**: ViewPro Z40K uses a Panasonic 1/2.3" CMOS sensor with 25.9MP total pixels -- **Source**: Source #1, #2 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #2 -- **Statement**: ViewPro Z40K records 4K (3840×2160) at 25/30fps with 8.29MP effective recording pixels; FHD (1080P) at 50/60fps with 6.10MP effective recording pixels -- **Source**: Source #1, #5 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #3 -- **Statement**: ViewPro Z40K provides 20x optical zoom; 25x iA (intelligent) zoom in 4K mode; 40x iA zoom in FHD mode. iA zoom beyond 20x is a digital crop, not true optical. -- **Source**: Source #1, #2, #5 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #4 -- **Statement**: ViewPro Z40K has 3-axis gimbal with ±0.02° vibration angle accuracy on pitch/roll, ±0.03° on yaw, plus 5-axis Optical Image Stabilization (OIS) -- **Source**: Source #1, #5, #16 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #5 -- **Statement**: ViewPro Z40K lens is F1.8 (wide) to F3.6 (tele); horizontal FOV 62.95° (wide) to 3.45° (tele) -- **Source**: Source #1, #2 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #6 -- **Statement**: ViewPro Z40K weighs 595g, operates -20°C to +60°C, CNC aluminum housing -- **Source**: Source #1, #2 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #7 -- **Statement**: ViewPro Z40K has 65dB dynamic range, 38dB S/N ratio, minimum illumination 0.05 lux at F1.6 -- **Source**: Source #1 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #8 -- **Statement**: USG-231 is a 2-axis gyro-stabilized gimbal with Full HD (1920×1080) day-view camera, 30x optical zoom, 3x digital zoom -- **Source**: Source #3, #6 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #9 -- **Statement**: USG-231 uses digital video stabilization (EIS), not optical image stabilization -- **Source**: Source #3, #4 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #10 -- **Statement**: USG-231 uses a CMOS sensor with 63.7° view angle; camera weighs 590g; video processing block weighs 250g (840g total system) -- **Source**: Source #3, #6 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #11 -- **Statement**: USG-231 likely uses a Sony FCB-series block camera module (specs match FCB-EV9500L: 30x zoom, Full HD, 63.7° FOV, 1/2.8" or 1/1.8" STARVIS CMOS) -- **Source**: Source #17, #18 (Sony specs matching USG-231 specs from Source #3) -- **Phase**: Phase 2 -- **Confidence**: ⚠️ Medium (not officially confirmed by Ukrspecsystems, but spec match is very close) - -## Fact #12 -- **Statement**: 2-axis gimbals stabilize pitch and roll only; yaw movement is NOT compensated. This causes visible horizontal jitter/wobble ("jello effect") during turns and wind gusts on fixed-wing drones. -- **Source**: Source #8, #9, #10, #14 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #13 -- **Statement**: 3-axis gimbals add yaw stabilization, which greatly reduces or eliminates horizontal jello effect. Industry standard for professional drone videography. -- **Source**: Source #8, #9, #10 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #14 -- **Statement**: Digital stabilization (EIS) works by cropping the frame and algorithmically shifting pixels. It reduces effective resolution, can introduce warping artifacts, and struggles with fast vibrations. -- **Source**: Source #11, #12 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #15 -- **Statement**: Optical Image Stabilization (OIS) physically moves lens elements to compensate for movement. No resolution loss, no cropping, no warping artifacts. Superior for small/fast vibrations. -- **Source**: Source #11, #12 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #16 -- **Statement**: The Shark M UAV uses USG-231 as its standard EO camera. The camera was used in combat over Donetsk and Defense Express noted "the quality of the camera itself, which allows to receive detailed images online and determine the coordinates of targets." -- **Source**: Source #7, #4 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #17 -- **Statement**: The Shark UAV demonstrated auto-tracking from 800m distance with quality footage. The system tracks both contrasting and complex objects. -- **Source**: Source #7, #22 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #18 -- **Statement**: At 30x optical zoom, atmospheric distortion (heat haze, mirage) becomes visible in drone footage, creating slight jitteriness. This is a physics limitation affecting all cameras equally. -- **Source**: Source #19 (Z30 review showing same effect) -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #19 -- **Statement**: The DJI Zenmuse Z30 (comparable 30x zoom, 1/2.8" sensor, 2.13MP) demonstrates that at max optical zoom, even with excellent stabilization, image quality is sufficient for inspection but shows "slight loss of quality" with digital zoom. -- **Source**: Source #19 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #20 -- **Statement**: ViewPro Z40K price ranges from $2,999-$4,879 depending on variant and retailer. USG-231 price is not public but marketed as "cost-effective and affordable." -- **Source**: Source #1, #2, #3 -- **Phase**: Phase 2 -- **Confidence**: ✅ High (Z40K) / ⚠️ Medium (USG-231 — no public pricing) - -## Fact #21 -- **Statement**: The 1/2.3" sensor (Z40K) is physically larger than the 1/2.8" sensor (likely in USG-231). Larger sensors capture more light, have better low-light performance, wider dynamic range, and less noise. -- **Source**: Source #20 -- **Phase**: Phase 2 -- **Confidence**: ✅ High (sensor size comparison); ⚠️ Medium (USG-231 sensor size assumption) - -## Fact #22 -- **Statement**: USG-231 features anti-fog, weather sealing, IR filter, automatic focus control, onboard recording, IP streaming, and Pixhawk/Ardupilot compatibility (plug-and-play). -- **Source**: Source #3, #6 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #23 -- **Statement**: ViewPro Z40K gimbal mechanical range: Pitch ±120°, Roll ±70°, Yaw ±300°. Supports PWM, TTL, SBUS, UDP control. Has geotagging and object tracking. -- **Source**: Source #1, #2 -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #24 -- **Statement**: Sony FCB-EV9500L (if used in USG-231) has Super Image Stabilizer built into the camera module itself, separate from the gimbal stabilization. It features STARVIS sensor with excellent low-light (0.00008 lux min illumination). -- **Source**: Source #17, #18 -- **Phase**: Phase 2 -- **Confidence**: ⚠️ Medium (conditional on USG-231 actually using this module) - -## Fact #25 -- **Statement**: For the Shark M, video and telemetry are transmitted encrypted in Full HD quality over ranges up to 180 km using Silvus Technologies StreamCaster radio. -- **Source**: Source #4 -- **Phase**: Phase 2 -- **Confidence**: ✅ High diff --git a/_standalone/UAV_camera_comparison/00_research/03_comparison_framework.md b/_standalone/UAV_camera_comparison/00_research/03_comparison_framework.md deleted file mode 100644 index e9a6cfc..0000000 --- a/_standalone/UAV_camera_comparison/00_research/03_comparison_framework.md +++ /dev/null @@ -1,35 +0,0 @@ -# Comparison Framework - -## Selected Framework Type -Concept Comparison + Decision Support - -## Selected Dimensions - -1. Video Resolution & Sensor Quality -2. Optical Zoom Range & Quality -3. Zoom Quality During Digital/Extended Zoom -4. Gimbal Stabilization Architecture -5. Wobble / Jello Effect -6. Image Crispness at High Zoom -7. Low-Light Performance -8. Weight & Integration -9. Field-Proven Track Record -10. Cost - -## Comparison Table - -| Dimension | ViewPro Z40K | USG-231 | Factual Basis | -|-----------|-------------|---------|---------------| -| **Video Resolution** | 4K (3840×2160) @ 25/30fps; 8.29MP effective | Full HD (1920×1080); ~2MP effective | Fact #1, #2, #8 | -| **Sensor** | Panasonic 1/2.3" CMOS, 25.9MP total | Sony CMOS (likely 1/2.8" or 1/1.8" STARVIS), ~2MP | Fact #1, #11, #21 | -| **Optical Zoom** | 20x (FOV 62.95°→3.45°) | 30x (FOV 63.7°→~2.1°) | Fact #3, #8 | -| **Extended Zoom** | 25x iA (4K), 40x iA (FHD) — digital crop | 3x digital (90x total) — digital crop | Fact #3, #8 | -| **Gimbal Type** | 3-axis, ±0.02° accuracy | 2-axis, accuracy not published | Fact #4, #8, #12, #13 | -| **OIS** | 5-axis Optical Image Stabilization | None (digital EIS only) | Fact #4, #9, #14, #15 | -| **Wobble/Jello** | Minimal — yaw compensated + OIS | Susceptible — no yaw compensation, EIS can warp | Fact #12, #13, #14 | -| **Image Crispness at Max Optical Zoom** | 4K at 20x = 8.29MP of detail at 3.45° FOV | FHD at 30x = ~2MP of detail at ~2.1° FOV | Fact #2, #8, #19 | -| **Low-Light** | 0.05 lux @ F1.6, 65dB DR | If Sony STARVIS: 0.00008 lux, excellent | Fact #7, #24 | -| **Weight** | 595g (all-in-one) | 590g camera + 250g VPB = 840g total | Fact #6, #10 | -| **Autopilot Integration** | PWM/TTL/SBUS/UDP (needs custom integration) | Pixhawk/Ardupilot plug-and-play | Fact #22, #23 | -| **Combat/Field Proven** | No public combat deployment data | Proven on Shark UAV in Ukraine combat | Fact #16, #17 | -| **Price** | $2,999–$4,879 | Not public ("cost-effective") | Fact #20 | diff --git a/_standalone/UAV_camera_comparison/00_research/04_reasoning_chain.md b/_standalone/UAV_camera_comparison/00_research/04_reasoning_chain.md deleted file mode 100644 index 8ac632a..0000000 --- a/_standalone/UAV_camera_comparison/00_research/04_reasoning_chain.md +++ /dev/null @@ -1,133 +0,0 @@ -# Reasoning Chain - -## Dimension 1: Video Resolution & Sensor Quality - -### Fact Confirmation -The Z40K uses a Panasonic 1/2.3" CMOS with 25.9MP total, recording 4K (8.29MP effective) video. (Fact #1, #2) -The USG-231 records Full HD (1920×1080, ~2MP effective) from a CMOS sensor. (Fact #8) - -### Reference Comparison -4K contains 4× the pixel count of Full HD (8.3M vs 2.1M pixels). A 1/2.3" sensor is physically ~30% larger in area than a 1/2.8" sensor (if that is what USG-231 uses). Larger sensor = more light per pixel, better dynamic range, less noise. (Fact #21) - -### Conclusion -The Z40K delivers dramatically higher resolution. At any given zoom level where both cameras share coverage, the Z40K captures ~4× more detail. This translates directly to better target identification, better image crispness, and more usable footage for post-mission analysis. - -### Confidence: ✅ High - ---- - -## Dimension 2: Optical Zoom Range - -### Fact Confirmation -Z40K: 20x optical zoom, narrowing FOV to 3.45°. (Fact #3, #5) -USG-231: 30x optical zoom, narrowing FOV to approximately 2.1°. (Fact #8) - -### Reference Comparison -The USG-231 reaches 50% more optical magnification. In pure optical zoom terms, the USG-231 can bring distant targets closer without digital quality loss. At 30x, you see objects at roughly 1.5× closer than Z40K's 20x maximum. - -### Conclusion -USG-231 wins on raw optical zoom reach (30x vs 20x). For long-range surveillance where maximum optical magnification matters and you cannot fly closer, the USG-231 has an advantage. - -### Confidence: ✅ High - ---- - -## Dimension 3: Effective Detail at Maximum Zoom (Resolution × Zoom Trade-off) - -### Fact Confirmation -Z40K at 20x optical zoom captures 3840×2160 pixels (8.29MP) across a 3.45° horizontal FOV. (Fact #2, #3) -USG-231 at 30x optical zoom captures 1920×1080 pixels (~2MP) across a ~2.1° horizontal FOV. (Fact #8) - -### Reference Comparison -Effective detail = pixels per degree of FOV. -- Z40K: 3840 pixels / 3.45° ≈ 1,113 pixels per degree (at 20x, 4K) -- USG-231: 1920 pixels / 2.1° ≈ 914 pixels per degree (at 30x, FHD) - -Even though the USG-231 zooms 50% further optically, the Z40K still delivers ~22% more pixels per degree of angular coverage due to its 4K sensor. The Z40K's pixel density advantage persists even when the USG-231 is at full optical zoom. - -### Conclusion -The Z40K produces sharper images at max optical zoom despite zooming less far, because its 4K resolution compensates for the zoom difference and then some. For target identification, the Z40K's 4K at 20x is effectively crisper than USG-231's FHD at 30x. - -### Confidence: ✅ High - ---- - -## Dimension 4: Stabilization — Wobble Effect - -### Fact Confirmation -Z40K: 3-axis gimbal (pitch + roll + yaw) with ±0.02° accuracy, plus 5-axis OIS in the lens. (Fact #4) -USG-231: 2-axis gimbal (pitch + roll only) with digital EIS. (Fact #8, #9) - -### Reference Comparison -2-axis gimbals leave yaw rotation uncompensated. On fixed-wing drones, wind gusts and turns cause yaw movements that create visible horizontal wobble/jello in footage. (Fact #12) Digital EIS attempts to correct this by cropping and shifting the frame, but this: (a) reduces effective resolution, (b) can introduce warping artifacts, (c) fails with fast vibrations. (Fact #14) - -3-axis gimbals mechanically compensate yaw, eliminating the primary source of wobble. Combined with OIS, even small high-frequency vibrations from the airframe are absorbed without resolution loss. (Fact #13, #15) - -### Conclusion -The Z40K has categorically superior stabilization. The 3-axis gimbal + 5-axis OIS architecture eliminates wobble at its physical source. The USG-231's 2-axis + EIS approach is fundamentally limited — uncompensated yaw will produce visible wobble on fixed-wing drones, especially during turns and in wind. The wobble becomes more pronounced at higher zoom levels because angular errors are magnified. - -### Confidence: ✅ High - ---- - -## Dimension 5: Image Crispness During Zoom - -### Fact Confirmation -Z40K: Uses OIS (no resolution loss during stabilization), 4K base resolution. At 25x iA zoom (4K mode), quality begins to degrade due to digital crop but remains at ~4K equivalent through sensor oversampling. (Fact #3, #15) -USG-231: Uses EIS (crops frame, reducing effective resolution from already-FHD). The effective resolution while EIS is active is less than 1920×1080. At 30x optical + EIS crop, the actual visible pixels are reduced. (Fact #14, #8) - -### Reference Comparison -The DJI Zenmuse Z30 (similar sensor to USG-231) shows "sufficient sharpness for inspection work" at 30x but "slight loss of quality" when digital zoom engages. (Fact #19) At maximum zoom, atmospheric distortion becomes the limiting factor for both cameras. (Fact #18) - -### Conclusion -The Z40K maintains significantly crisper images during zoom due to: (1) 4K base resolution, (2) OIS not consuming resolution, (3) higher pixel density even before zoom. The USG-231's crispness degrades more noticeably because EIS crops from an already-lower resolution. However, the USG-231's optical glass reaches further, which partially compensates in scenarios where distance is the primary constraint. - -### Confidence: ✅ High - ---- - -## Dimension 6: Low-Light Performance - -### Fact Confirmation -Z40K: 0.05 lux minimum illumination at F1.6, 65dB dynamic range. (Fact #7) -USG-231: If using Sony STARVIS sensor, minimum illumination could be as low as 0.00008 lux. (Fact #24) - -### Reference Comparison -Sony STARVIS sensors are specifically designed for surveillance with exceptional low-light performance. The USG-231's minimum illumination (if STARVIS) would be ~625× better than the Z40K's. - -### Conclusion -The USG-231 likely has significantly better low-light performance if it uses a Sony STARVIS module. This matters for dawn/dusk and night reconnaissance. The Z40K is adequate in daylight and moderate low-light but is not in the same class for near-dark conditions. - -### Confidence: ⚠️ Medium (USG-231 sensor identification not confirmed) - ---- - -## Dimension 7: Weight & Integration - -### Fact Confirmation -Z40K: 595g all-in-one, needs custom integration (PWM/TTL/SBUS/UDP). (Fact #6, #23) -USG-231: 840g total (590g camera + 250g VPB), plug-and-play with Pixhawk/Ardupilot. (Fact #10, #22) - -### Reference Comparison -The Z40K is 245g lighter as a total system. For a fixed-wing UAV at 10-15kg MTOW, 245g is ~2% of total weight — meaningful for flight endurance. However, the USG-231's plug-and-play Pixhawk integration is a significant engineering advantage if the airframe uses that autopilot. - -### Conclusion -Z40K wins on weight (595g vs 840g) but loses on integration simplicity if the platform uses Pixhawk/Ardupilot. For custom builds, the Z40K requires more integration work but saves weight. The USG-231 is purpose-built for the Shark ecosystem. - -### Confidence: ✅ High - ---- - -## Dimension 8: Field-Proven Track Record - -### Fact Confirmation -USG-231 has extensive combat deployment on Shark UAVs in Ukraine. Defense Express noted good image quality and effective auto-tracking. (Fact #16, #17) -Z40K has no publicly documented combat deployment. - -### Reference Comparison -Combat-proven systems have demonstrated reliability under vibration, temperature extremes, EW interference, and time pressure. The USG-231 has survived this test. The Z40K has not been publicly evaluated under equivalent conditions. - -### Conclusion -USG-231 has a significant advantage in proven reliability and real-world validation. The Z40K is untested in comparable conditions. However, this speaks to platform reliability, not inherently to video quality. - -### Confidence: ✅ High diff --git a/_standalone/UAV_camera_comparison/00_research/05_validation_log.md b/_standalone/UAV_camera_comparison/00_research/05_validation_log.md deleted file mode 100644 index 8d0f19e..0000000 --- a/_standalone/UAV_camera_comparison/00_research/05_validation_log.md +++ /dev/null @@ -1,42 +0,0 @@ -# Validation Log - -## Validation Scenario -A fixed-wing reconnaissance UAV flies at 75 km/h cruising speed at 1,000m altitude. The operator needs to identify a vehicle type at 3 km slant range, then zoom in to read markings at 1.5 km slant range. Wind is 8 m/s with gusts. The UAV performs orbital surveillance (constant turns). - -## Expected Based on Conclusions - -### If using ViewPro Z40K: -- At 3 km: 20x optical zoom narrows FOV to 3.45°. 4K resolution provides 8.29MP of detail. Vehicle type identification is straightforward. -- At 1.5 km with 25x iA zoom (4K): Sufficient resolution to distinguish markings. Image remains crisp. -- During turns: 3-axis gimbal compensates yaw. Operator sees smooth, stable image. OIS absorbs airframe vibration. -- In gusts: 5-axis OIS + gimbal maintains stable frame. No visible wobble at zoom. -- Transmission: 4K may need to be downscaled to FHD for transmission bandwidth. Recording is 4K on SD card. - -### If using USG-231 (on Shark M): -- At 3 km: 30x optical zoom narrows FOV to ~2.1°. But FHD resolution means only ~2MP of detail. Vehicle type identification is possible but with less margin. -- At 1.5 km at 30x: Target fills more of the frame due to higher zoom, but fewer pixels per target compared to Z40K at 20x. -- During turns: 2-axis gimbal does NOT compensate yaw. During orbital surveillance (constant heading change), the image will exhibit horizontal wobble/drift. EIS will attempt correction but consumes resolution and may introduce warping. -- In gusts: EIS handles moderate vibration but produces artifacts under aggressive movement. The operator may see frame edges jumping or brief warping. -- Transmission: FHD native — no downscaling needed. Encrypted Full HD over 180 km via Silvus. - -## Actual Validation (Against Known Evidence) -Defense Express combat footage from Shark UAV (USG-231) over Donetsk confirms: "quality of the camera allows to receive detailed images online and determine the coordinates of targets." Auto-tracking from 800m demonstrated effectively. This suggests that for the Shark's primary mission profile (target coordinate determination at moderate ranges), the USG-231 is sufficient. However, no public footage shows high-zoom image quality during aggressive maneuvering, leaving the wobble question unresolved by direct evidence. - -No comparable field footage exists for the Z40K on a reconnaissance fixed-wing platform. - -## Counterexamples -1. The USG-231's 30x optical reach means it can observe targets at greater standoff distance without digital zoom degradation. If the mission requires maximum standoff (e.g., flying high above enemy AD), the extra optical reach matters more than resolution. -2. The Z40K's 4K recording may be overkill if the transmission link only supports FHD — the operator sees FHD anyway in real time, and 4K is only useful in post-mission review. -3. In electronic warfare environments, the USG-231 (integrated with Shark ecosystem) has proven EW resilience. The Z40K as a standalone payload has no such validation. - -## Review Checklist -- [x] Draft conclusions consistent with fact cards -- [x] No important dimensions missed -- [x] No over-extrapolation -- [x] Conclusions are actionable -- [ ] Note: USG-231 sensor identification (Sony FCB) is inferred, not confirmed — affects low-light conclusion confidence - -## Conclusions Requiring Caveat -- Low-light performance comparison depends on confirming the USG-231's actual sensor module -- Field reliability comparison is one-sided (USG-231 is combat-proven, Z40K is not) -- Real-world wobble comparison lacks direct video evidence from both cameras on the same platform diff --git a/_standalone/UAV_camera_comparison/01_solution/solution_draft01.md b/_standalone/UAV_camera_comparison/01_solution/solution_draft01.md deleted file mode 100644 index c818446..0000000 --- a/_standalone/UAV_camera_comparison/01_solution/solution_draft01.md +++ /dev/null @@ -1,196 +0,0 @@ -# Solution Draft: ViewPro Z40K vs USG-231 Camera Comparison - -## Product Solution Description - -Comparative analysis of two UAV gimbal cameras — ViewPro Z40K (Chinese, 4K, 3-axis) and USG-231 (Ukrainian/Ukrspecsystems, FHD, 2-axis) — for fixed-wing reconnaissance applications. The USG-231 is the standard payload on the Shark M UAV. The comparison focuses on video feed quality, wobble/jello effect, zoom performance, image crispness during zoom, and overall quality. - -## Head-to-Head Specification Table - - -| Parameter | ViewPro Z40K | USG-231 | -| --------------------- | ---------------------------------- | ------------------------------------------- | -| **Sensor** | Panasonic 1/2.3" CMOS, 25.9MP | Sony CMOS (likely 1/2.8" STARVIS), ~2MP FHD | -| **Video Resolution** | 4K (3840×2160) @ 25/30fps | Full HD (1920×1080) | -| **Photo Resolution** | 25.9MP (6784×3816) | N/A | -| **Optical Zoom** | 20x | 30x | -| **Extended Zoom** | 25x iA (4K) / 40x iA (FHD) | 3x digital (total 90x) | -| **FOV (wide → tele)** | 62.95° → 3.45° | 63.7° → ~2.1° | -| **Gimbal** | 3-axis | 2-axis | -| **Gimbal Accuracy** | ±0.02° pitch/roll, ±0.03° yaw | Not published | -| **OIS** | 5-axis Optical Image Stabilization | None (digital EIS only) | -| **Lens Aperture** | F1.8 (wide) – F3.6 (tele) | Not published | -| **Dynamic Range** | 65 dB | Not published | -| **Min Illumination** | 0.05 lux @ F1.6 | If STARVIS: ~0.00008 lux | -| **Weight** | 595g (all-in-one) | 840g (590g camera + 250g VPB) | -| **Dimensions** | Compact single unit | 105×107×120mm + 50×90×65mm VPB | -| **Temp Range** | -20°C to +60°C | -15°C to +45°C (Shark M spec) | -| **Autopilot Compat** | PWM/TTL/SBUS/UDP | Pixhawk/Ardupilot plug-and-play | -| **Object Tracking** | Yes (up to 192 px/frame) | Yes | -| **Onboard Recording** | SD card up to 256GB | Yes | -| **IP Streaming** | UDP output | RTP IP streaming | -| **Weather Sealing** | CNC aluminum housing | Weather sealed | -| **Price** | $2,999–$4,879 | Not public ("cost-effective") | -| **Combat Proven** | No public data | Yes (Shark UAV, Ukraine 2022–2026) | - - -## Detailed Comparison by Dimension - -### 1. Video Feed Quality - -**Winner: ViewPro Z40K (decisive)** - -The Z40K records native 4K video — 4× the pixel count of the USG-231's Full HD output. In practical terms, this means: - -- A vehicle at 2 km rendered in 4K occupies roughly 4× more identifiable pixels than the same vehicle in FHD -- Post-mission analysis benefits enormously from 4K — you can digitally crop and zoom in post without losing usable detail -- For real-time feed: if the transmission link supports only FHD, the operator sees FHD anyway — but the Z40K's 4K downsampled to FHD is actually sharper than native FHD because it effectively oversamples and eliminates aliasing - -The USG-231's Full HD feed is adequate for coordinate determination and target identification at moderate ranges (confirmed by Defense Express combat reporting). But it cannot match the Z40K's information density. - -### 2. Wobble Effect - -**Winner: ViewPro Z40K (decisive)** - -This is the most architecturally significant difference between the two cameras. - -**USG-231 (2-axis gimbal + digital EIS):** - -- Stabilizes pitch and roll only -- Yaw rotation is NOT mechanically compensated -- On a fixed-wing drone in turns, wind gusts, or orbital surveillance, uncompensated yaw creates visible horizontal wobble/drift in the video feed -- Digital EIS attempts software correction: it crops the frame (losing resolution from an already-FHD signal), shifts pixels between frames, and can introduce warping artifacts during aggressive movement -- At high zoom (30x), even small uncompensated yaw angular errors translate to large image shifts — the wobble is amplified by magnification -- The wobble is most noticeable during: turns, wind gusts, turbulence, and any maneuver involving heading change - -**ViewPro Z40K (3-axis gimbal + 5-axis OIS):** - -- Compensates all three axes mechanically (pitch, roll, yaw) with ±0.02° accuracy -- The 5-axis OIS additionally corrects small/fast vibrations at the lens element level — no resolution loss, no cropping, no warping -- During turns and orbital surveillance, the yaw motor absorbs heading changes, keeping the image locked on target -- At 20x zoom, the ±0.02° accuracy translates to sub-pixel stability — effectively wobble-free for the viewer -- The double stabilization system (mechanical gimbal + optical OIS) is the same architecture used in DJI enterprise cameras - -**Summary**: The USG-231 will exhibit noticeable wobble on a fixed-wing platform, particularly during maneuvering at high zoom. The Z40K eliminates wobble through dual mechanical+optical stabilization. This is not a marginal difference — it is an architectural category gap. - -### 3. Zoom Capability - -**Mixed result — depends on priority** - - -| Zoom Metric | ViewPro Z40K | USG-231 | Winner | -| -------------------------------- | ----------------------------- | ----------------------------------------------- | ------- | -| Max optical zoom | 20x | 30x | USG-231 | -| Max extended zoom (any mode) | 40x iA (FHD) | 90x (30x optical × 3x digital) | USG-231 | -| Resolution at max optical zoom | 8.29MP (4K) at 3.45° FOV | ~2MP (FHD) at ~2.1° FOV | Z40K | -| Pixels per degree at max optical | ~1,113 px/° | ~914 px/° | Z40K | -| Quality during extended zoom | Gradual degradation (iA crop) | Significant degradation (digital crop from FHD) | Z40K | - - -**Key insight**: The USG-231 zooms 50% further optically (30x vs 20x), but the Z40K still delivers 22% more pixels per degree of angular coverage at each camera's maximum optical zoom. The Z40K's resolution advantage outweighs the USG-231's zoom advantage for target identification. - -However, if the mission absolutely requires maximum standoff distance and the image only needs to answer "is something there?" rather than "what exactly is it?", the USG-231's 30x optical reach has merit. - -### 4. Image Crispness During Zoom - -**Winner: ViewPro Z40K** - -Multiple factors compound in the Z40K's favor: - -1. **Base resolution**: 4K starting point vs FHD means 4× more pixels at any zoom level -2. **OIS vs EIS**: OIS preserves full resolution; EIS crops the frame, reducing effective resolution below FHD -3. **Pixel density at max zoom**: Z40K maintains 1,113 pixels per degree vs USG-231's 914 pixels per degree -4. **Vibration at zoom**: At high magnification, vibrations are amplified proportionally. The Z40K's 3-axis + OIS architecture maintains sub-pixel stability; the USG-231's 2-axis + EIS produces visible micro-jitter that degrades perceived sharpness - -**At medium zoom (10-15x)**: Both cameras perform well. The resolution difference is visible but both produce usable imagery. - -**At maximum optical zoom**: The Z40K's image is noticeably crisper. The 4K resolution provides fine detail that FHD cannot resolve. Both cameras will show atmospheric distortion (heat haze) at maximum zoom above hot terrain — this is physics, not a camera limitation. - -**Beyond optical zoom (digital/iA range)**: The Z40K degrades more gracefully. Its iA zoom at 25x (4K) is cropping from a 25.9MP sensor — plenty of overhead. The USG-231 at 90x total is cropping from ~2MP — the image quality drops dramatically. - -### 5. Shark M Video Feed Analysis - -The Shark M uses the USG-231 as its standard EO payload. Based on Defense Express field reports and manufacturer data: - -**Strengths of the USG-231 on Shark M:** - -- Auto-tracking locks onto targets from 800m and handles both contrasting and complex objects -- 30x optical zoom allows observation from >1 km standoff -- Digital stabilization produces "clear and stable video" per manufacturer -- Plug-and-play integration with the Shark's Pixhawk-based autopilot -- Encrypted FHD transmission over 180 km (Silvus StreamCaster) -- Anti-fog feature works in the field -- Combat-proven reliability in intense EW environments - -**Limitations observed/expected:** - -- FHD resolution limits identification range compared to 4K alternatives -- 2-axis gimbal will produce wobble during orbital surveillance patterns (constant heading change) -- Digital EIS further reduces effective resolution under active correction -- At high zoom during maneuvering, the combined effect of uncompensated yaw + EIS cropping will noticeably degrade image quality -- No optical image stabilization means high-frequency airframe vibrations translate to micro-jitter in the feed - -### 6. Low-Light Performance - -**Likely winner: USG-231** (with caveat) - -If the USG-231 uses a Sony STARVIS sensor (specs strongly suggest this), its low-light performance vastly exceeds the Z40K: - -- USG-231 (STARVIS): ~0.00008 lux minimum illumination -- Z40K: 0.05 lux minimum illumination - -This is a 625× difference. For dawn/dusk or night reconnaissance with ambient light, the USG-231 would produce usable imagery where the Z40K would show mostly noise. - -**Caveat**: Ukrspecsystems does not publish the exact sensor module. The STARVIS identification is inferred from matching specifications with Sony FCB-EV9500L/9520L block cameras. - -## Overall Quality Assessment - - -| Dimension | Z40K | USG-231 | Margin | -| ------------------------- | ----- | ------- | ------------------ | -| Video resolution | ★★★★★ | ★★★ | Large | -| Wobble control | ★★★★★ | ★★☆ | Very large | -| Optical zoom reach | ★★★ | ★★★★★ | Moderate | -| Image crispness at zoom | ★★★★★ | ★★★ | Large | -| Low-light | ★★★ | ★★★★★ | Large (if STARVIS) | -| Weight | ★★★★★ | ★★★ | Moderate | -| Integration simplicity | ★★★ | ★★★★★ | Moderate | -| Combat-proven reliability | ★★ | ★★★★★ | Large | -| Auto-tracking | ★★★★ | ★★★★ | Comparable | -| Overall video quality | ★★★★★ | ★★★ | Large | - - -## Recommendation - -**For pure video quality, crispness, and wobble-free footage**: ViewPro Z40K is the clear winner. Its 4K resolution, 3-axis gimbal, and 5-axis OIS produce categorically better and more stable footage than the USG-231. - -**The USG-231's strengths are real but different**: 30x optical zoom reach, likely superior low-light performance, combat-proven reliability, and seamless Shark M integration. It is a proven ISR tool — not the sharpest or smoothest, but reliable and field-tested. - -**The architectural gap in stabilization is the most important finding.** The 2-axis vs 3-axis gimbal difference is not marginal — it is a fundamental design limitation of the USG-231 that manifests as visible wobble on fixed-wing platforms, especially at high zoom during turns. No amount of digital processing can fully compensate for the missing yaw stabilization axis. - -**For a custom reconnaissance UAV build**: The Z40K offers superior imaging quality per gram. For integration with the Shark M ecosystem specifically, the USG-231 is the practical choice due to its plug-and-play integration and proven system-level reliability. - -## References - -1. ViewPro Z40K — RCDrone: [https://rcdrone.top/products/viewpro-z40k-4k-gimbal-camera](https://rcdrone.top/products/viewpro-z40k-4k-gimbal-camera) -2. ViewPro Z40K — Manufacturer: [https://www.viewprouav.com/product/z40k-single-4k-hd-25-times-zoom-gimbal-camera](https://www.viewprouav.com/product/z40k-single-4k-hd-25-times-zoom-gimbal-camera) -3. USG-231 — Ukrspecsystems: [https://ukrspecsystems.com/drone-gimbals/usg-231](https://ukrspecsystems.com/drone-gimbals/usg-231) -4. Shark M UAS — Ukrspecsystems: [https://ukrspecsystems.com/drones/shark-m-uas](https://ukrspecsystems.com/drones/shark-m-uas) -5. DRONExpert Z40K specs: [https://dronexpert.nl/en/viewpro-z40k-20x-optical-zoom-4k-camera-up-to-40x-zoom/](https://dronexpert.nl/en/viewpro-z40k-20x-optical-zoom-4k-camera-up-to-40x-zoom/) -6. AeroExpo USG-231: [https://www.aeroexpo.online/prod/ukrspecsystems/product-185884-82835.html](https://www.aeroexpo.online/prod/ukrspecsystems/product-185884-82835.html) -7. Defense Express — Shark combat footage: [https://en.defence-ua.com/weapon_and_tech/how_the_newest_ukrainian_shark_uav_works_over_donetsk_and_why_its_really_cool_video-5438.html](https://en.defence-ua.com/weapon_and_tech/how_the_newest_ukrainian_shark_uav_works_over_donetsk_and_why_its_really_cool_video-5438.html) -8. Camera Guide Pro — 2-axis vs 3-axis: [https://www.cameraguidepro.com/what-is-the-difference-between-a-2-axis-and-3-axis-gimbal/](https://www.cameraguidepro.com/what-is-the-difference-between-a-2-axis-and-3-axis-gimbal/) -9. MakeUseOf — Gimbal comparison: [https://www.makeuseof.com/two-axis-vs-three-axis-gimbals/](https://www.makeuseof.com/two-axis-vs-three-axis-gimbals/) -10. DroneFlying Pro — 2-axis vs 3-axis: [https://droneflyingpro.com/2-axis-vs-3-axis-gimbal/](https://droneflyingpro.com/2-axis-vs-3-axis-gimbal/) -11. Steadxp — EIS vs OIS: [https://www.steadxp.com/digital-vs-optical-stabilization-a-comparison-guide/](https://www.steadxp.com/digital-vs-optical-stabilization-a-comparison-guide/) -12. Guiding Tech — EIS vs OIS: [https://www.guidingtech.com/eis-vs-ois-stabilization/](https://www.guidingtech.com/eis-vs-ois-stabilization/) -13. DroneTrest — Fixed-wing gimbal forum: [https://www.dronetrest.com/t/whats-the-best-choice-for-the-fixed-wing-3-axis-gimbal-or-2-axis-gimbal/8091](https://www.dronetrest.com/t/whats-the-best-choice-for-the-fixed-wing-3-axis-gimbal-or-2-axis-gimbal/8091) -14. PhantomPilots — Yaw issue with 2-axis: [https://phantompilots.com/threads/yaw-issue-with-2-axis-gimbals.6854](https://phantompilots.com/threads/yaw-issue-with-2-axis-gimbals.6854) -15. ViewPro Z40K Manual — ManualsLib: [https://www.manualslib.com/manual/2385515/Viewpro-Z40k.html](https://www.manualslib.com/manual/2385515/Viewpro-Z40k.html) -16. ViewPro Tech — Z40K PSDK: [https://www.viewprotech.com/index.php?ac=article&at=read&did=202](https://www.viewprotech.com/index.php?ac=article&at=read&did=202) -17. Sony FCB-EV9500L: [https://pro.sony/ue_US/products/zoom-camera-blocks/fcb-ev9500l](https://pro.sony/ue_US/products/zoom-camera-blocks/fcb-ev9500l) -18. Sony FCB-EV9520L: [https://block-cameras.com/products/sony-fcb-ev9520l-30x-zoom-full-hd-block-camera-sensor-starvis-gen2](https://block-cameras.com/products/sony-fcb-ev9520l-30x-zoom-full-hd-block-camera-sensor-starvis-gen2) -19. DJI Zenmuse Z30 review: [https://medium.com/@daily_drones/hands-on-with-the-dji-zenmuse-z30-53ab50fe628c](https://medium.com/@daily_drones/hands-on-with-the-dji-zenmuse-z30-53ab50fe628c) -20. Oreate AI — Sensor size comparison: [https://www.oreateai.com/blog/beyond-the-numbers-what-123-vs-113-inch-sensor-size-really-means-for-your-photos/](https://www.oreateai.com/blog/beyond-the-numbers-what-123-vs-113-inch-sensor-size-really-means-for-your-photos/) -21. Wikipedia — Ukrspecsystems Shark: [https://en.wikipedia.org/wiki/Ukrspecsystems_Shark](https://en.wikipedia.org/wiki/Ukrspecsystems_Shark) -22. Defense Express — Shark tracking demo: [https://en.defence-ua.com/weapon_and_tech/ukrainian_drone_maker_demonstrates_its_new_shark_uav_target_tracking_capabilities_video-4803.html](https://en.defence-ua.com/weapon_and_tech/ukrainian_drone_maker_demonstrates_its_new_shark_uav_target_tracking_capabilities_video-4803.html) - diff --git a/_standalone/UAV_camera_comparison/UAV_frame_material.md b/_standalone/UAV_camera_comparison/UAV_frame_material.md deleted file mode 100644 index 0f468ef..0000000 --- a/_standalone/UAV_camera_comparison/UAV_frame_material.md +++ /dev/null @@ -1 +0,0 @@ -I want to build a UAV plane for reconnaissance missions maximizing flight duration. Investigate what is the best frame material for that purpose \ No newline at end of file diff --git a/_standalone/UAV_frame_material/00_research/UAV_frame_material/00_ac_assessment.md b/_standalone/UAV_frame_material/00_research/UAV_frame_material/00_ac_assessment.md deleted file mode 100644 index 548f3fc..0000000 --- a/_standalone/UAV_frame_material/00_research/UAV_frame_material/00_ac_assessment.md +++ /dev/null @@ -1,41 +0,0 @@ -# Acceptance Criteria Assessment - -## Acceptance Criteria - -| Criterion | Our Values | Researched Values | Cost/Timeline Impact | Status | -|-----------|-----------|-------------------|---------------------|--------| -| Flight duration | "Maximizing" (undefined) | 2-4 hours for electric fixed-wing in 5-15 kg MTOW class (Albatross: 4h, Vulture: 3.5-5h) | Higher endurance = larger battery + lighter frame = higher cost | Added — suggest target: ≥3 hours | -| Payload capacity | 1.47 kg fixed | 1.47 kg is modest; benchmark platforms carry 4-8 kg in this class | Low payload relative to class = more weight budget for battery/fuel | Modified — no change needed, favorable constraint | -| Frame weight | Not specified | Benchmark: 3.0-4.0 kg bare airframe for 3m wingspan class (Albatross: 3.35 kg) | Lighter frame = more battery weight = longer flight | Added — suggest target: ≤3.5 kg bare airframe | -| MTOW | Not specified | 8-15 kg typical for this class | Drives wing sizing, motor selection, battery capacity | Added — suggest target: 8-12 kg | -| Cruise speed | Not specified | 15-25 m/s typical for recon fixed-wing (Albatross: 19 m/s) | Slower cruise = longer endurance but less area coverage | Added — suggest target: 15-20 m/s | -| Wingspan | Not specified | 2.5-3.5m for this MTOW class | Larger span = better L/D = longer endurance, but transport/handling harder | Added — suggest: 2.5-3.5m | -| Battery energy density | Semi-solid state interest | 300-350 Wh/kg (semi-solid, 2025-2026 commercial products) vs 180-250 Wh/kg (LiPo) | Semi-solid ~2-3x cost of LiPo but 30% more flight time | Added — suggest: ≥300 Wh/kg (semi-solid) | -| Budget | $100k total | Sufficient for custom composite airframe + avionics + batteries + ground station | $100k is generous for single prototype in this class | Modified — no change needed | -| Operating temperature | Not specified | -20°C to 45°C is standard for commercial UAVs | Affects battery performance and material selection | Added — suggest: -10°C to 45°C | -| Wind resistance | Not specified | 10-15 m/s sustained for fixed-wing recon | Affects structural requirements and endurance | Added — suggest: up to 12 m/s sustained | - -## Restrictions Assessment - -| Restriction | Our Values | Researched Values | Cost/Timeline Impact | Status | -|-------------|-----------|-------------------|---------------------|--------| -| Budget | $100k | Ample for 1 prototype. Carbon fiber airframe: $5-15k (custom tooling + manufacturing). Batteries: $2-5k. Avionics: $3-5k. Motor/prop/ESC: $1-2k. Ground station + comms: $5-10k. Integration + testing: $10-20k. | Well within range | Modified — no change needed | -| Manufacturing access | None specified | Carbon fiber requires either outsourcing (CNC + layup vendors available globally) or basic workshop with vacuum bagging setup (~$2-5k investment) | Outsourcing is viable within budget; no blocker | Added — outsource recommended | -| Regulatory | None specified | Sub-25 kg in most jurisdictions requires registration + remote pilot license. No specific material restrictions. | Minimal impact at this MTOW class | Added — follow local UAS regulations | -| Payload (fixed) | 1.47 kg | Non-negotiable — mission equipment | No change | Added | -| Frame material | Open investigation | Research strongly favors carbon fiber composite (CFRP) with foam-core sandwich construction | Drives the core research question | Added | - -## Key Findings - -1. **Flight duration target of ≥3 hours is realistic** for an electric fixed-wing in this class with semi-solid batteries. The Albatross achieves 4 hours with LiPo; semi-solid batteries would extend this further. - -2. **1.47 kg payload is light for this class** — leaves substantial weight budget for batteries, which directly translates to longer flight time. This is a favorable constraint. - -3. **Semi-solid state batteries (300-350 Wh/kg) are commercially available now** from multiple vendors (Grepow, Tattu, Herewin). They offer 30% more flight time than LiPo at 2-3x cost per Wh but with 4-6x cycle life, making TCO favorable. - -4. **$100k budget is generous** for a single prototype in this class. Typical custom composite UAV builds in this class cost $30-60k for first prototype including all subsystems. - -5. **Carbon fiber composite is the clear frontrunner** for frame material based on weight-to-stiffness ratio, which is the primary driver for endurance. - -## Sources -- Source #1-#12 (see source registry) diff --git a/_standalone/UAV_frame_material/00_research/UAV_frame_material/00_question_decomposition.md b/_standalone/UAV_frame_material/00_research/UAV_frame_material/00_question_decomposition.md deleted file mode 100644 index 6cf5c2f..0000000 --- a/_standalone/UAV_frame_material/00_research/UAV_frame_material/00_question_decomposition.md +++ /dev/null @@ -1,72 +0,0 @@ -# Question Decomposition — Material Comparison: S2 FG + Carbon Stiffeners vs Shark M - -## Original Question -Compare the researched and selected material (S2 fiberglass with carbon stiffeners) with the Shark M fuselage material. Pros and cons of each approach considering parachute landing survivability and radio transparency. - -## Active Mode -Mode B: Solution Assessment — assessing existing solution_draft05 material selection. - -## Problem Context Summary -- The project is building a reconnaissance UAV maximizing flight duration -- Previous drafts selected S2 fiberglass (S2 FG) fuselage with carbon fiber stiffeners -- Catapult launch + parachute landing is a key variant (Variant B) -- Shark M by Ukrspecsystems is a combat-proven reference platform with similar mission profile -- User confirms Shark M has no radio transparency issues from experience - -## Question Type -**Concept Comparison** + **Decision Support** -Comparing two material approaches across multiple engineering dimensions with a decision outcome. - -## Research Subject Boundary -| Dimension | Boundary | -|-----------|----------| -| Population | Fixed-wing reconnaissance UAVs, 10-20 kg MTOW class | -| Geography | Global, with emphasis on combat-proven systems | -| Timeframe | Current (2024-2026), materials science is Low novelty sensitivity | -| Level | Airframe structural material for fuselage | - -## Timeliness Sensitivity Assessment -- **Research Topic**: Composite material comparison for UAV airframes -- **Sensitivity Level**: Low -- **Rationale**: Composite material properties (fiberglass, carbon fiber) are well-established engineering fundamentals. S2 glass and carbon fiber properties have been stable for decades. -- **Source Time Window**: No limit -- **Priority official sources**: Material datasheets, aerospace research papers, UAV manufacturer specifications - -## Decomposed Sub-questions - -### SQ1: What material does the Shark M actually use? -- "Shark M UAV fuselage material specifications" -- "Ukrspecsystems Shark composite airframe construction" -- "Ukrspecsystems PD-2 PD-1 fuselage material composite" -- "SHARK-M БПЛА матеріал корпус" (Ukrainian language) -- "Ukrspecsystems composite low radar cross section material" - -### SQ2: How does each material behave under parachute landing impact? -- "fiberglass composite impact resistance parachute landing UAV" -- "carbon fiber composite impact damage brittleness crash landing" -- "S2 glass fiber impact energy absorption composite" -- "carbon fiber vs fiberglass UAV crash landing repair" -- "belly landing UAV composite damage modes" - -### SQ3: What are the RF transparency properties of each material? -- "carbon fiber electromagnetic shielding effectiveness dB UAV antenna" -- "fiberglass radome RF transparent dielectric constant" -- "S2 fiberglass radio frequency transparency composite" -- "carbon fiber stiffener fiberglass skin RF shadow antenna" -- "GFRP radar transparent stealth composite UAV" - -### SQ4: What are the weight/stiffness trade-offs? -- "fiberglass vs carbon fiber UAV airframe weight comparison" -- "S-glass vs E-glass impact strength toughness" -- "carbon fiber stiffener fiberglass hybrid composite advantages" - -### SQ5: What are the cost and field repairability differences? -- "fiberglass UAV field repair epoxy patch battlefield" -- "carbon fiber repair cost UAV composite" -- "fiberglass vs carbon fiber material cost comparison" - -## Chosen Perspectives -1. **Practitioner / Field operator**: What works in real battlefield conditions? Shark M has 50,000+ operational hours. -2. **Implementer / Engineer**: What are the structural engineering trade-offs between pure FG and hybrid FG+CF? -3. **Contrarian / Devil's advocate**: What could go wrong with each approach? Hidden failure modes? -4. **Domain expert / Aerospace**: What do composite material scientists say about impact, RF, and hybrid designs? diff --git a/_standalone/UAV_frame_material/00_research/UAV_frame_material/01_source_registry.md b/_standalone/UAV_frame_material/00_research/UAV_frame_material/01_source_registry.md deleted file mode 100644 index f61bd16..0000000 --- a/_standalone/UAV_frame_material/00_research/UAV_frame_material/01_source_registry.md +++ /dev/null @@ -1,199 +0,0 @@ -# Source Registry — Material Comparison - -## Source #1 -- **Title**: Ukrspecsystems SHARK-M UAS Official Page -- **Link**: https://ukrspecsystems.com/drones/shark-m-uas -- **Tier**: L1 -- **Publication Date**: 2025 (continuously updated) -- **Timeliness Status**: Currently valid -- **Target Audience**: Military/government UAV buyers -- **Research Boundary Match**: Full match -- **Summary**: SHARK-M specs: 14.5 kg MTOW, 3.4m wingspan, 7h endurance, catapult launch + parachute landing, Silvus radio modem 180 km range. No fuselage material specified. -- **Related Sub-question**: SQ1 - -## Source #2 -- **Title**: Ukrspecsystems PD-2 UAS Datasheet (PDF) -- **Link**: https://www.unmannedsystemstechnology.com/wp-content/uploads/2016/06/PD_2.pdf -- **Tier**: L1 -- **Publication Date**: 2021 -- **Timeliness Status**: Currently valid -- **Target Audience**: Military/government UAV buyers -- **Research Boundary Match**: Full match (PD-2 is predecessor, same manufacturer) -- **Summary**: PD-2 features "fully composite airframe" with "absence of large metal parts" for "low radar visibility." Composite construction confirmed. No specific composite type named. -- **Related Sub-question**: SQ1 - -## Source #3 -- **Title**: Wikipedia - Ukrspecsystems Shark -- **Link**: https://en.wikipedia.org/wiki/Ukrspecsystems_Shark -- **Tier**: L3 -- **Publication Date**: 2023 -- **Timeliness Status**: Currently valid -- **Target Audience**: General public -- **Research Boundary Match**: Full match -- **Summary**: Shark UAV specs, catapult launch + parachute landing, 12.5 kg weight, 3.4m wingspan. No material info. -- **Related Sub-question**: SQ1 - -## Source #4 -- **Title**: Carbon Fiber UAV RF Shielding — KSZYTec Antenna Design Guide -- **Link**: https://kszytec.com/uav-aerospace-antenna-design-survival-guide/ -- **Tier**: L2 -- **Publication Date**: 2026 -- **Timeliness Status**: Currently valid -- **Target Audience**: UAV engineers, antenna designers -- **Research Boundary Match**: Full match -- **Summary**: Carbon fiber is "pretty much opaque to 2.4GHz radio waves" with shielding effectiveness exceeding 30-50 dB. Acts as Faraday cage. Lethal to embedded signals. -- **Related Sub-question**: SQ3 - -## Source #5 -- **Title**: Carbon Fiber RF Shielding — Drones StackExchange -- **Link**: https://drones.stackexchange.com/questions/283/how-much-does-mounting-an-antenna-near-a-carbon-fiber-frame-degrade-signal-recep -- **Tier**: L4 -- **Publication Date**: 2020 -- **Timeliness Status**: Currently valid -- **Target Audience**: UAV builders/hobbyists -- **Research Boundary Match**: Full match -- **Summary**: Carbon fiber blocks RF rather than generating noise. Antennas must be positioned to avoid obstruction by carbon structure. -- **Related Sub-question**: SQ3 - -## Source #6 -- **Title**: Radio-Transparent Properties Comparison of Aramid, S-Glass, and Quartz Fiber Radome Composites at 900 MHz -- **Link**: https://link.springer.com/article/10.1007/s40033-023-00602-7 -- **Tier**: L1 -- **Publication Date**: 2023 -- **Timeliness Status**: Currently valid -- **Target Audience**: Aerospace engineers, materials scientists -- **Research Boundary Match**: Full match -- **Summary**: S-Glass composites show good radio transparency at 900 MHz; better than aramid. Quartz fiber best. S-Glass used in radomes, antenna windows, fairings. -- **Related Sub-question**: SQ3 - -## Source #7 -- **Title**: Fiberglass Pultrusion for Aerospace & Defense — Tencom -- **Link**: https://www.tencom.com/blog/fiberglass-pultrusion-for-aerospace-defense-lightweight-structural-components -- **Tier**: L3 -- **Publication Date**: 2024 -- **Timeliness Status**: Currently valid -- **Target Audience**: Aerospace/defense engineers -- **Research Boundary Match**: Full match -- **Summary**: GFRP is inherently dielectric and transparent to RF/radar waves. Minimizes electromagnetic interference. Used for antenna housings, sensor fairings. 20-30% weight savings in some drone configurations. -- **Related Sub-question**: SQ3 - -## Source #8 -- **Title**: EM Shielding of Twill Carbon Fiber — IEEE -- **Link**: https://ieeexplore.ieee.org/document/10329805/ -- **Tier**: L1 -- **Publication Date**: 2023 -- **Timeliness Status**: Currently valid -- **Target Audience**: RF engineers, materials scientists -- **Research Boundary Match**: Full match -- **Summary**: CFRP shielding tested across UHF, L-band, S-band. Continuous carbon fiber composites achieve up to 52 dB shielding effectiveness. -- **Related Sub-question**: SQ3 - -## Source #9 -- **Title**: Fiberglass vs Carbon Fiber UAV Comparison — Ganglong Fiberglass -- **Link**: https://www.ganglongfiberglass.com/fiberglass-drone-vs-carbon-fiber/ -- **Tier**: L3 -- **Publication Date**: 2024-12 -- **Timeliness Status**: Currently valid -- **Target Audience**: UAV builders -- **Research Boundary Match**: Full match -- **Summary**: Carbon fiber ~40% lighter than aluminum, ~50% lighter than fiberglass. Carbon fiber is brittle under impact (cracks); fiberglass is flexible (bends/absorbs). Carbon 5-10× more expensive. -- **Related Sub-question**: SQ4, SQ5 - -## Source #10 -- **Title**: E-Glass vs S-Glass: Key Differences — SMI Composites -- **Link**: https://www.smicomposites.com/comparing-e-glass-vs-s-glass-key-differences-and-benefits/ -- **Tier**: L2 -- **Publication Date**: 2024 -- **Timeliness Status**: Currently valid -- **Target Audience**: Composites engineers -- **Research Boundary Match**: Full match -- **Summary**: S-glass 30-40% stronger than E-glass, 10× fatigue resistance, >5% elongation at break vs 4.7% E-glass. Better impact resistance. Higher cost than E-glass. -- **Related Sub-question**: SQ2, SQ4 - -## Source #11 -- **Title**: Impact Damage Resistance of S2/FM94 Glass Fibre Composites — MDPI Polymers -- **Link**: https://mdpi-res.com/d_attachment/polymers/polymers-14-00095/article_deploy/polymers-14-00095-v2.pdf -- **Tier**: L1 -- **Publication Date**: 2022 -- **Timeliness Status**: Currently valid -- **Target Audience**: Aerospace researchers -- **Research Boundary Match**: Full match -- **Summary**: S2/FM94 glass fiber composites: cross-ply and angle-ply orientations absorb impact energy effectively with no penetration. Unidirectional fails in shear. -- **Related Sub-question**: SQ2 - -## Source #12 -- **Title**: E-Glass vs Carbon Fiber UAV Wing Impact Simulations — Preprints.org -- **Link**: https://www.preprints.org/manuscript/202601.1067 -- **Tier**: L1 -- **Publication Date**: 2026-01 -- **Timeliness Status**: Currently valid -- **Target Audience**: Aerospace researchers -- **Research Boundary Match**: Full match -- **Summary**: E-glass composites are tougher and cheaper than CF for impact-resistant UAV structures. CF fails brittlely with delamination. E-glass is a viable cost-effective alternative. -- **Related Sub-question**: SQ2 - -## Source #13 -- **Title**: Field Repair of Severely Damaged FG/Epoxy Fuselage — MATEC Conference -- **Link**: https://www.matec-conferences.org/articles/matecconf/pdf/2019/53/matecconf_easn2019_01002.pdf -- **Tier**: L1 -- **Publication Date**: 2019 -- **Timeliness Status**: Currently valid -- **Target Audience**: Aerospace maintenance engineers -- **Research Boundary Match**: Full match -- **Summary**: Field repair of fiberglass/epoxy structures can be done by personnel with average manual skills. No specialized training or vacuum equipment needed. Restores structural stiffness. -- **Related Sub-question**: SQ5 - -## Source #14 -- **Title**: ACASIAS — Antenna Integration in Carbon Fibre Fuselage Panel -- **Link**: https://www.nlr.org/newsroom/video/acasias-antenna-integration/ -- **Tier**: L1 -- **Publication Date**: 2020 -- **Timeliness Status**: Currently valid -- **Target Audience**: Aerospace engineers -- **Research Boundary Match**: Full match -- **Summary**: ACASIAS project: hybrid panel with GFRP "RF-transparent window" and CFRP structural skin + orthogrid stiffeners. CFRP ribs create electromagnetic interaction with antenna tiles. Design must account for RF shadow from CFRP elements. -- **Related Sub-question**: SQ3 - -## Source #15 -- **Title**: Fiberglass Radome Dielectric Properties — O'Reilly / Radome EM Theory -- **Link**: https://www.oreilly.com/library/view/radome-electromagnetic-theory/9781119410799/b02.xhtml -- **Tier**: L1 -- **Publication Date**: 2019 -- **Timeliness Status**: Currently valid -- **Target Audience**: RF/radome engineers -- **Research Boundary Match**: Full match -- **Summary**: E-glass/epoxy dielectric constant 4.4, loss tangent 0.016 at 8.5 GHz. These values allow reasonable RF transmission with some signal attenuation. -- **Related Sub-question**: SQ3 - -## Source #16 -- **Title**: Belly-Landing Mini UAV Strength Study — Scientific.Net -- **Link**: https://www.scientific.net/AMM.842.178 -- **Tier**: L1 -- **Publication Date**: 2016 -- **Timeliness Status**: Currently valid -- **Target Audience**: Aerospace engineers -- **Research Boundary Match**: Full match -- **Summary**: Fiberglass/epoxy composites used in belly-landing UAV design due to favorable specific strength. Belly landings carry risk of disintegration if too fast. -- **Related Sub-question**: SQ2 - -## Source #17 -- **Title**: Hybrid Composite Wing Spar Analysis — IJVSS -- **Link**: https://yanthrika.com/eja/index.php/ijvss/article/view/1476 -- **Tier**: L1 -- **Publication Date**: 2024 -- **Timeliness Status**: Currently valid -- **Target Audience**: Aerospace researchers -- **Research Boundary Match**: Full match -- **Summary**: Hybrid composites show similar deformation to pure CFRP with cost savings. Higher damping factors than aluminum or pure CFRP. -- **Related Sub-question**: SQ4 - -## Source #18 -- **Title**: UAV Airframe Strength and Structural Optimization — Frontiers -- **Link**: https://www.frontiersin.org/articles/10.3389/fmech.2025.1708043 -- **Tier**: L1 -- **Publication Date**: 2025 -- **Timeliness Status**: Currently valid -- **Target Audience**: Aerospace researchers -- **Research Boundary Match**: Full match -- **Summary**: Stiffener optimization achieves 60.9% stress reduction and 5.2% mass reduction. Reinforced rib designs with stiffeners provide significant structural benefits. -- **Related Sub-question**: SQ4 diff --git a/_standalone/UAV_frame_material/00_research/UAV_frame_material/02_fact_cards.md b/_standalone/UAV_frame_material/00_research/UAV_frame_material/02_fact_cards.md deleted file mode 100644 index d0da421..0000000 --- a/_standalone/UAV_frame_material/00_research/UAV_frame_material/02_fact_cards.md +++ /dev/null @@ -1,145 +0,0 @@ -# Fact Cards — Material Comparison - -## Fact #1 -- **Statement**: Ukrspecsystems PD-2 (predecessor to Shark M) has a "fully composite airframe" with "absence of large metal parts" providing "low radar visibility." This means the composite is non-conductive (i.e., fiberglass/GFRP), because carbon fiber is conductive and would reflect radar. -- **Source**: Source #2 (PD-2 Datasheet) -- **Phase**: Assessment -- **Target Audience**: 10-20 kg reconnaissance UAV class -- **Confidence**: ⚠️ Medium — material type is inferred from "low radar visibility" + "fully composite" + "no large metal parts." Not explicitly stated as fiberglass. -- **Related Dimension**: Material identification - -## Fact #2 -- **Statement**: SHARK-M uses catapult launch + parachute landing, identical recovery method to user's Variant B. 14.5 kg MTOW, 3.4m wingspan, 7h endurance. Max wind for landing: 7 m/s. -- **Source**: Source #1 (Ukrspecsystems official page) -- **Phase**: Assessment -- **Target Audience**: 10-20 kg reconnaissance UAV class -- **Confidence**: ✅ High -- **Related Dimension**: Platform comparison baseline - -## Fact #3 -- **Statement**: Carbon fiber composite provides electromagnetic shielding effectiveness of 30-52 dB across UHF to X-band frequencies (up to 12.4 GHz). It is "pretty much opaque to 2.4 GHz radio waves" and acts as a Faraday cage. -- **Source**: Source #4 (KSZYTec), Source #8 (IEEE), Source #5 (StackExchange) -- **Phase**: Assessment -- **Target Audience**: All UAVs with internal antennas -- **Confidence**: ✅ High — confirmed by multiple independent sources -- **Related Dimension**: Radio transparency - -## Fact #4 -- **Statement**: S-Glass (S2) fiberglass composites are radio-transparent and are the standard material for aerospace radomes, antenna windows, and communication antenna protective coverings. E-glass/epoxy has dielectric constant 4.4 and loss tangent 0.016 at 8.5 GHz — low enough for reasonable RF transmission. -- **Source**: Source #6 (Springer), Source #7 (Tencom), Source #15 (Radome EM Theory) -- **Phase**: Assessment -- **Target Audience**: All UAVs with internal/embedded antennas -- **Confidence**: ✅ High -- **Related Dimension**: Radio transparency - -## Fact #5 -- **Statement**: GFRP is inherently dielectric and transparent to both radio-frequency communications AND radar waves. Carbon fiber reflects/absorbs radar. A fully GFRP airframe achieves low radar cross section by being transparent to radar rather than reflecting it. -- **Source**: Source #7 (Tencom), Source #2 (PD-2 datasheet context) -- **Phase**: Assessment -- **Target Audience**: Military reconnaissance UAVs -- **Confidence**: ✅ High -- **Related Dimension**: Radio transparency, stealth - -## Fact #6 -- **Statement**: User confirms from operational experience that SHARK-M has no issues with radio transparency — "it is still alive." This is consistent with GFRP fuselage and inconsistent with carbon fiber fuselage. -- **Source**: User direct experience -- **Phase**: Assessment -- **Target Audience**: This specific UAV project -- **Confidence**: ✅ High (direct field evidence) -- **Related Dimension**: Radio transparency - -## Fact #7 -- **Statement**: Carbon fiber composites fail in a brittle manner with sudden delamination and fiber fracture under impact. Low-velocity impacts can cause barely visible internal damage (BVID) that substantially reduces structural integrity without external signs. -- **Source**: Source #12 (Preprints.org), Source #9 (Ganglong) -- **Phase**: Assessment -- **Target Audience**: UAV impact/crash scenarios -- **Confidence**: ✅ High -- **Related Dimension**: Parachute landing survivability - -## Fact #8 -- **Statement**: Fiberglass composites are more flexible and absorb shock better than carbon fiber. Under impact, fiberglass bends/deforms rather than cracking or shattering. E-glass composites are a viable, cost-effective, and tougher alternative to CF for impact-resistant UAV structures. -- **Source**: Source #12 (Preprints.org), Source #9 (Ganglong) -- **Phase**: Assessment -- **Target Audience**: UAV impact/crash scenarios -- **Confidence**: ✅ High -- **Related Dimension**: Parachute landing survivability - -## Fact #9 -- **Statement**: S2-glass has >5% elongation at break (vs 4.7% for E-glass), 30-40% higher tensile strength than E-glass (4600 MPa vs 3400 MPa), and 10× fatigue resistance. S2/FM94 cross-ply laminates absorb impact energy with no penetration in tested configurations. -- **Source**: Source #10 (SMI Composites), Source #11 (MDPI Polymers) -- **Phase**: Assessment -- **Target Audience**: UAV structural design -- **Confidence**: ✅ High -- **Related Dimension**: Parachute landing survivability - -## Fact #10 -- **Statement**: Carbon fiber is approximately 40% lighter than aluminum and density ~1.5-1.6 g/cm³ vs fiberglass at 2.46-2.58 g/cm³. Carbon fiber is roughly 5× stiffer than fiberglass by specific modulus. -- **Source**: Source #9 (Ganglong), Source #10 (SMI Composites) -- **Phase**: Assessment -- **Target Audience**: UAV airframe design -- **Confidence**: ✅ High -- **Related Dimension**: Weight/stiffness - -## Fact #11 -- **Statement**: Carbon fiber material costs 5-10× more than fiberglass. Basic fiberglass cloth ~$20-50/m² vs standard carbon fiber (T300) ~$200-500/m². -- **Source**: Source #9 (Ganglong) -- **Phase**: Assessment -- **Target Audience**: UAV production cost -- **Confidence**: ✅ High -- **Related Dimension**: Cost - -## Fact #12 -- **Statement**: Field repair of fiberglass/epoxy structures can be done by personnel with average manual skills without specialized training or vacuum equipment. Pre-cured composite patches bonded with adhesive enable rapid field repairs. -- **Source**: Source #13 (MATEC Conference) -- **Phase**: Assessment -- **Target Audience**: UAV field operations -- **Confidence**: ✅ High -- **Related Dimension**: Field repairability - -## Fact #13 -- **Statement**: Carbon fiber repair requires specialized equipment (autoclave, vacuum bagging) and trained technicians. Scarf-repaired CFRP laminates remain sensitive to subsequent impacts. Internal damage (BVID) requires non-destructive testing to detect. -- **Source**: Source #12 (Preprints.org), research on CFRP repair -- **Phase**: Assessment -- **Target Audience**: UAV maintenance -- **Confidence**: ✅ High -- **Related Dimension**: Field repairability - -## Fact #14 -- **Statement**: In a hybrid FG+CF design (like S2 FG skin + carbon stiffeners), carbon stiffeners create localized RF shadow zones. The ACASIAS project demonstrated that CFRP ribs in a GFRP panel create electromagnetic interactions that must be designed around. Antennas must be placed in GFRP-only zones away from CF structural elements. -- **Source**: Source #14 (ACASIAS/NLR) -- **Phase**: Assessment -- **Target Audience**: Hybrid composite UAV designers -- **Confidence**: ✅ High -- **Related Dimension**: Radio transparency of hybrid design - -## Fact #15 -- **Statement**: Hybrid composites (FG skin + CF stiffeners) achieve similar deformation characteristics to pure CFRP while offering cost savings and higher damping factors than either pure aluminum or pure CFRP. -- **Source**: Source #17 (IJVSS), Source #18 (Frontiers) -- **Phase**: Assessment -- **Target Audience**: UAV structural design -- **Confidence**: ✅ High -- **Related Dimension**: Weight/stiffness - -## Fact #16 -- **Statement**: Stiffener optimization with reinforced rib designs can achieve 60.9% stress reduction and 5.2% mass reduction compared to unstiffened designs. -- **Source**: Source #18 (Frontiers) -- **Phase**: Assessment -- **Target Audience**: UAV structural design -- **Confidence**: ✅ High -- **Related Dimension**: Weight/stiffness - -## Fact #17 -- **Statement**: SHARK-M has 50,000+ operational hours on the battlefield (per Ukrspecsystems marketing). The system is designed for 1,200 flight hours without additional service maintenance. -- **Source**: Source #1 (Ukrspecsystems official) -- **Phase**: Assessment -- **Target Audience**: Military reconnaissance UAVs -- **Confidence**: ⚠️ Medium — marketing claim, but backed by extensive combat use -- **Related Dimension**: Proven reliability - -## Fact #18 -- **Statement**: A pure fiberglass (no carbon stiffeners) airframe for a 14.5 kg MTOW UAV (Shark M class) can achieve 7h endurance. This suggests that pure GFRP without carbon stiffeners is structurally adequate for this weight class, though it may require thicker skins or more material. -- **Source**: Source #1 (Ukrspecsystems official), Source #2 (PD-2 datasheet) -- **Phase**: Assessment -- **Target Audience**: 10-20 kg reconnaissance UAV class -- **Confidence**: ⚠️ Medium — material type inferred, not explicitly confirmed -- **Related Dimension**: Weight/structural adequacy diff --git a/_standalone/UAV_frame_material/00_research/UAV_frame_material/03_comparison_framework.md b/_standalone/UAV_frame_material/00_research/UAV_frame_material/03_comparison_framework.md deleted file mode 100644 index a03df97..0000000 --- a/_standalone/UAV_frame_material/00_research/UAV_frame_material/03_comparison_framework.md +++ /dev/null @@ -1,39 +0,0 @@ -# Comparison Framework - -## Selected Framework Type -Concept Comparison + Decision Support - -## Compared Approaches -- **Approach A**: S2 Fiberglass + Carbon Fiber Stiffeners (hybrid, as selected in solution_draft05) -- **Approach B**: Pure Fiberglass Composite (inferred Shark M approach — GFRP, no carbon elements) - -## Selected Dimensions - -### Primary (directly requested by user) -1. Radio transparency (communications: 900 MHz, 2.4 GHz, 5.8 GHz) -2. Radar transparency (stealth / low RCS) -3. Parachute landing impact survivability -4. Parachute landing cumulative damage tolerance - -### Secondary (engineering trade-offs) -5. Weight efficiency (strength-to-weight, stiffness-to-weight) -6. Structural stiffness -7. Material cost -8. Field repairability -9. Proven operational track record -10. Hidden failure modes - -## Initial Population - -| Dimension | S2 FG + Carbon Stiffeners (Approach A) | Pure GFRP (Approach B, Shark M) | Factual Basis | -|-----------|---------------------------------------|--------------------------------|---------------| -| Radio transparency | Mostly transparent (FG skin is RF-transparent); carbon stiffeners create localized RF shadow zones; antenna placement must avoid CF elements | Fully transparent — entire fuselage passes RF; antenna placement unconstrained | Fact #3, #4, #5, #6, #14 | -| Radar transparency | Mostly transparent; CF stiffeners reflect radar → slight increase in RCS compared to pure FG | Fully radar-transparent (low RCS by transparency) | Fact #5, #14 | -| Impact survivability (single event) | FG skin absorbs impact well; CF stiffeners may crack/delaminate under localized impact; BVID risk in CF elements | FG absorbs impact, bends rather than cracks; no brittle CF elements; simpler damage profile | Fact #7, #8, #9 | -| Cumulative damage tolerance | FG skin handles repeated impacts; CF stiffeners accumulate micro-damage that is hard to detect | All-FG structure: damage is visible, cumulative tolerance is good, easier inspection | Fact #7, #8, #13 | -| Weight efficiency | Better — CF stiffeners provide stiffness at lower weight than equivalent FG stiffening | Heavier — must use thicker FG skins or more material to achieve same stiffness | Fact #10, #15, #16 | -| Structural stiffness | Higher — CF stiffeners ~5× stiffer per unit weight than FG | Lower — FG is more flexible; adequate for Shark M class but may need design compensation | Fact #10, #15 | -| Material cost | Higher — CF cloth is 5-10× FG cost; only stiffeners are CF, so total cost increase is moderate | Lower — all FG, significantly cheaper material cost | Fact #11 | -| Field repairability | FG skin: easy field repair; CF stiffeners: harder, needs specialized knowledge to repair | All components field-repairable with basic skills and epoxy patches | Fact #12, #13 | -| Proven track record | Not yet built/tested | 50,000+ operational hours, 1,200h maintenance-free, combat-proven | Fact #17 | -| Hidden failure modes | CF stiffener BVID after impact — invisible internal damage reduces strength | None specific to material; pure FG damage is generally visible | Fact #7, #13 | diff --git a/_standalone/UAV_frame_material/00_research/UAV_frame_material/04_reasoning_chain.md b/_standalone/UAV_frame_material/00_research/UAV_frame_material/04_reasoning_chain.md deleted file mode 100644 index 0839cd2..0000000 --- a/_standalone/UAV_frame_material/00_research/UAV_frame_material/04_reasoning_chain.md +++ /dev/null @@ -1,143 +0,0 @@ -# Reasoning Chain - -## Dimension 1: Radio Transparency - -### Fact Confirmation -Carbon fiber composite provides 30-52 dB electromagnetic shielding across UHF to X-band (Fact #3). This means a carbon fiber structural element blocks 99.9% to 99.999% of RF energy passing through it. S2 fiberglass is radio-transparent — standard radome material with dielectric constant ~4.4 at 8.5 GHz (Fact #4). The ACASIAS project proved that CFRP ribs in a GFRP panel create measurable electromagnetic interaction zones (Fact #14). - -### Reference Comparison -**Approach A (S2 FG + CF stiffeners)**: The FG skin areas are fully RF-transparent. However, carbon stiffeners running through the fuselage create discrete RF shadow zones. Any antenna placed near or behind a CF stiffener will experience 30-50 dB signal degradation in that direction. This constrains antenna placement — antennas must be positioned in FG-only zones between stiffeners. For a UAV with multiple antennas (C2 link, video downlink, GPS, telemetry, ADS-B), this creates a spatial planning challenge. The stiffener geometry defines "forbidden zones" for antenna placement. - -**Approach B (pure GFRP, Shark M)**: The entire fuselage is RF-transparent. Antennas can be placed anywhere inside or on the fuselage without material-induced signal blockage. GPS, C2, video, telemetry antennas have no placement constraints from the airframe material. This is confirmed by Shark M's operational success with 180 km communication range and EW resistance (Fact #6). - -### Conclusion -Pure GFRP has a clear advantage for radio transparency. The hybrid approach is workable but requires careful antenna placement engineering. For a reconnaissance UAV operating at long range (100+ km) in EW-contested environments, unconstrained antenna placement is a significant operational advantage. - -### Confidence -✅ High — supported by quantitative RF data, aerospace project (ACASIAS), and field experience - ---- - -## Dimension 2: Radar Transparency (Stealth) - -### Fact Confirmation -GFRP is inherently dielectric and transparent to radar waves (Fact #5). Carbon fiber, while not as reflective as metal, is conductive and reflects/scatters radar energy. The PD-2/Shark design philosophy explicitly leverages "fully composite airframe + absence of large metal parts" for "low radar visibility" (Fact #1). - -### Reference Comparison -**Approach A**: Carbon stiffeners create discrete radar-reflective structures inside the airframe. While individually small, their regular geometric pattern could create a detectable radar signature at certain angles — essentially a grid of conductive elements acting as a partial radar reflector. - -**Approach B**: Pure GFRP is essentially invisible to radar (the signal passes through). Radar cross section comes only from metallic components (engine, servos, connectors) and the payload, not the airframe itself. - -### Conclusion -For military reconnaissance in contested airspace, pure GFRP provides a stealth advantage. Carbon stiffeners slightly increase radar detectability. The magnitude depends on stiffener geometry and radar frequency, but the principle is clear: less conductive material = lower RCS. - -### Confidence -⚠️ Medium — the magnitude of RCS increase from stiffeners vs pure GFRP is not quantified; the principle is sound but the practical significance depends on adversary radar capabilities - ---- - -## Dimension 3: Parachute Landing Impact Survivability - -### Fact Confirmation -From solution_draft05: parachute landing impact energy ranges from 190 J (calm) to 762 J (8 m/s wind) to 1,499 J (12 m/s wind) for an 18 kg UAV. S2 glass fiber with cross-ply layup absorbs impact energy effectively with no penetration (Fact #9). Carbon fiber fails in a brittle manner — sudden delamination and fiber fracture (Fact #7). BVID in carbon fiber reduces structural integrity without visible signs (Fact #7). Fiberglass bends/deforms rather than cracking (Fact #8). - -### Reference Comparison -**Approach A (S2 FG + CF stiffeners)**: The FG skin absorbs belly landing impact well — it will dent, flex, and possibly crack locally but without catastrophic failure. However, if impact loads are transmitted to CF stiffeners (which they will be, since stiffeners carry structural loads), the CF elements may suffer BVID. This internal damage is invisible but weakens the structure progressively. After multiple parachute landings, CF stiffeners could accumulate micro-delaminations that are detectable only via ultrasound or tap testing. - -**Approach B (pure GFRP)**: The entire structure responds to impact by flexing and absorbing energy. Damage is typically visible (cracks, dents, whitening of the resin). No hidden BVID in brittle elements. The structure degrades gracefully — visible damage allows timely repair/replacement. - -### Conclusion -Pure GFRP is significantly better suited for repeated parachute landings. The key advantage is not just better single-impact performance, but the absence of hidden damage accumulation in brittle carbon elements. For a UAV expected to land on a parachute hundreds of times, this is critical. - -### Confidence -✅ High — supported by materials science (CF brittleness is well-documented) and field evidence (Shark M's 50,000+ hours with parachute landings) - ---- - -## Dimension 4: Cumulative Damage and Inspection - -### Fact Confirmation -Carbon fiber BVID requires non-destructive testing (ultrasound, Lamb wave techniques) to detect (Fact #7, #13). Fiberglass damage is generally visible — cracking, whitening, deformation (Fact #8, #12). Field inspection of FG requires visual inspection; field inspection of CF stiffeners requires ultrasonic equipment. - -### Reference Comparison -**Approach A**: After each parachute landing, operators should theoretically inspect CF stiffeners for BVID. In field conditions (battlefield, remote area), ultrasonic inspection is impractical. This creates a reliability risk — the aircraft may fly with undetected internal damage. - -**Approach B**: Visual inspection sufficient. Operators can see damage and decide whether to fly or repair. Simple tap-test can detect larger delaminations. No special equipment needed. - -### Conclusion -Pure GFRP provides much simpler damage inspection, which is critical for field operations. The inspection advantage compounds over the UAV's lifetime — hundreds of landings, each requiring either a quick visual check (GFRP) or an NDT scan (hybrid with CF). - -### Confidence -✅ High - ---- - -## Dimension 5: Weight Efficiency - -### Fact Confirmation -Carbon fiber density ~1.5-1.6 g/cm³ vs fiberglass 2.46-2.58 g/cm³ (Fact #10). CF is ~5× stiffer per unit weight. CF stiffeners achieve similar structural performance to pure CFRP with hybrid approach (Fact #15). Stiffener optimization achieves 60.9% stress reduction (Fact #16). - -### Reference Comparison -**Approach A**: CF stiffeners provide excellent stiffness at low weight. A few hundred grams of CF stiffeners can replace kilograms of FG stiffening. This is the primary reason for using the hybrid approach — to achieve the required wing/fuselage stiffness without the weight penalty of all-FG construction. - -**Approach B**: Must compensate for lack of CF stiffness with more FG material. This means thicker skins, more internal FG ribs, or geometric stiffening (corrugations, foam sandwich). Results in a heavier airframe for equivalent stiffness. Shark M achieves 14.5 kg MTOW with pure GFRP — so it works, but the user's UAV at 18 kg MTOW with heavier payload (Viewpro Z40K + electronics) may benefit from the weight savings of CF stiffeners. - -### Conclusion -Hybrid approach has a clear weight advantage. For a reconnaissance UAV maximizing endurance, every 100g saved translates to ~2-3 minutes additional flight time. If CF stiffeners save 300-800g vs equivalent pure GFRP stiffening, that's 6-24 minutes additional endurance. This is meaningful but not dramatic. - -### Confidence -✅ High — materials properties are well-established; the magnitude estimate depends on specific structural design - ---- - -## Dimension 6: Material Cost - -### Fact Confirmation -CF cloth is 5-10× more expensive than FG cloth per m² (Fact #11). In the hybrid approach, only stiffeners use CF — perhaps 10-20% of total composite material by area. - -### Reference Comparison -**Approach A**: Moderate cost increase. If total FG material cost for an airframe is ~$300-500, adding CF stiffeners might add $100-300 for the CF material itself, plus slightly more complex layup procedures. - -**Approach B**: All-FG, minimal material cost. Simplest manufacturing. - -### Conclusion -The cost difference is moderate, not dramatic. The hybrid approach costs more but not prohibitively so for a military UAV. - -### Confidence -✅ High - ---- - -## Dimension 7: Field Repairability - -### Fact Confirmation -FG/epoxy field repair requires no specialized training or vacuum equipment (Fact #12). CF repair is more complex, requiring specialized knowledge and ideally autoclave/vacuum bagging (Fact #13). - -### Reference Comparison -**Approach A**: If the FG skin is damaged, field repair is straightforward. If a CF stiffener is damaged, field repair is significantly harder — the operator may need to fabricate a CF patch, which requires proper layup, vacuum bagging, and controlled cure. In practice, a damaged CF stiffener in the field likely means the UAV is grounded until returned to base. - -**Approach B**: All damage is FG, all repairs are FG. Personnel with average manual skills can perform field repairs with epoxy and FG cloth patches. - -### Conclusion -Pure GFRP is much better for field repairability, especially in expeditionary/forward-deployed scenarios. This matters for the user's military use case. - -### Confidence -✅ High - ---- - -## Dimension 8: Proven Operational Track Record - -### Fact Confirmation -Shark M has 50,000+ operational hours with parachute landings in combat (Fact #17). The user has direct operational experience confirming radio transparency (Fact #6). The hybrid S2 FG + CF approach is unproven for this specific application. - -### Reference Comparison -**Approach A**: Novel design, not combat-proven. Introduces CF stiffeners which are new variables in the parachute-landing reliability equation. - -**Approach B**: Combat-proven in the most demanding environment possible (active warfare with EW, harsh conditions). - -### Conclusion -Pure GFRP has massive advantage in proven reliability. This cannot be understated — a combat-proven material system that demonstrably works for this exact mission profile (long-endurance reconnaissance, catapult + parachute, EW-contested) is extremely valuable evidence. - -### Confidence -✅ High diff --git a/_standalone/UAV_frame_material/00_research/UAV_frame_material/05_validation_log.md b/_standalone/UAV_frame_material/00_research/UAV_frame_material/05_validation_log.md deleted file mode 100644 index d8385ed..0000000 --- a/_standalone/UAV_frame_material/00_research/UAV_frame_material/05_validation_log.md +++ /dev/null @@ -1,61 +0,0 @@ -# Validation Log - -## Validation Scenario 1: Parachute Landing in 8 m/s Wind (200th landing) - -### Expected Based on Conclusions - -**Approach A (S2 FG + CF stiffeners)**: UAV lands at 9.2 m/s resultant velocity, 762 J impact energy. FG belly skin absorbs initial impact — possible crack, repairable with field patch. CF wing spar stiffeners experience shock loading. After 200 landings, accumulated micro-delamination in CF stiffeners is possible but invisible without NDT. The stiffeners might be at 70-90% original strength without any visible indication. Operator has no way to know without ultrasonic inspection. - -**Approach B (pure GFRP, Shark M style)**: Same impact conditions. FG belly absorbs impact — same crack/dent pattern. FG internal stiffening ribs absorb shock by flexing. Any damage is visible (cracking, whitening). After 200 landings, operator can visually assess the entire airframe and decide to replace worn components. No hidden degradation. - -### Actual Validation -The Shark M has performed thousands of such landings in operational service. The design is validated by 50,000+ hours of combat operations. The hidden damage accumulation scenario (Approach A) is a real engineering concern documented in aerospace literature (BVID in CFRP is a well-known problem). - -### Counterexamples -- Approach A could be validated if CF stiffeners are designed with high safety margins (oversized stiffeners that tolerate some delamination). This adds weight, partially negating the weight advantage. -- Some carbon fiber structures are designed for crash energy absorption (automotive) — but those are single-use absorbers, not reusable structural elements. - ---- - -## Validation Scenario 2: Long-Range Communication at 150 km, EW Environment - -### Expected Based on Conclusions - -**Approach A (S2 FG + CF stiffeners)**: C2 antenna inside fuselage. If antenna is placed between CF stiffeners (in FG-only zone), signal passes through FG skin with minimal attenuation. If antenna is near a CF stiffener, signal degrades by 30-50 dB in that direction → potential link loss. Requires careful antenna integration engineering during design. - -**Approach B (pure GFRP)**: C2 antenna placed anywhere inside fuselage. 360° RF coverage through fuselage. Signal attenuated only by FG dielectric properties (minimal). The Silvus radio modem in Shark M achieves 180 km range through the GFRP fuselage. - -### Actual Validation -Shark M demonstrates 180 km range with confirmed EW resistance. The user's direct experience confirms radio transparency. Shark M's Silvus-based communication system operates at full capability through the GFRP airframe. - -### Counterexamples -- The hybrid approach can achieve good RF performance if stiffeners are designed to avoid antenna zones. Many military UAVs use carbon fiber with external antennas successfully. -- If antennas are mounted externally (on wings, tail boom), the fuselage material is less critical for RF performance. However, external antennas are vulnerable to parachute landing damage and increase drag. - ---- - -## Validation Scenario 3: Weight-Critical Endurance Mission - -### Expected Based on Conclusions - -**Approach A (S2 FG + CF stiffeners)**: Lighter airframe by 300-800g. At 18 kg MTOW, this translates to larger battery or more fuel → 6-24 minutes additional endurance. For a 7-8h mission, this is 1-5% improvement. - -**Approach B (pure GFRP)**: Heavier airframe. Must compensate with slightly reduced payload or accept lower endurance. Shark M achieves 7h at 14.5 kg MTOW with pure GFRP — the user's UAV at 18 kg MTOW has different payload requirements. - -### Actual Validation -The weight difference is real but modest relative to total system weight. Shark M proves that 7h endurance is achievable with pure GFRP. The question is whether the user's heavier payload (Viewpro Z40K vs Shark's USG-231) makes the weight savings from CF stiffeners more critical. - -### Counterexamples -- If the user can meet endurance requirements with pure GFRP, the CF stiffeners are unnecessary complexity -- Weight savings might be achievable through other means (optimized FG layup, foam sandwich cores, lighter internal components) without introducing CF - ---- - -## Review Checklist -- [x] Draft conclusions consistent with fact cards -- [x] No important dimensions missed -- [x] No over-extrapolation -- [x] Conclusions actionable/verifiable -- [x] Field evidence (Shark M) validates pure GFRP approach -- [x] Weight trade-off quantified with reasonable estimates -- [ ] Note: Exact weight penalty of pure GFRP vs hybrid cannot be determined without detailed structural analysis of specific airframe geometry diff --git a/_standalone/UAV_frame_material/01_solution/solution_draft01.md b/_standalone/UAV_frame_material/01_solution/solution_draft01.md deleted file mode 100644 index 3bbca7c..0000000 --- a/_standalone/UAV_frame_material/01_solution/solution_draft01.md +++ /dev/null @@ -1,177 +0,0 @@ -# Solution Draft - -## Product Solution Description - -A custom-built electric fixed-wing reconnaissance UAV optimized for maximum flight endurance. The airframe uses **T700 carbon fiber composite sandwich construction** (CFRP skins over PVC foam cores for wings, CFRP monocoque for fuselage) with selective Kevlar reinforcement at impact zones. Powered by **semi-solid state batteries** (330 Wh/kg class), the platform carries a 1.47 kg reconnaissance payload (ADTI 20L V1 + Viewpro A40 Pro gimbal + Jetson Orin Nano Super + Pixhawk 6x). - -**Target performance**: 5-6 hours practical flight endurance, 8-10 kg MTOW, 2.5-3.5m wingspan. - -``` -┌─────────────────────────────────────────────────────────┐ -│ SYSTEM OVERVIEW │ -│ │ -│ CFRP Sandwich Wing (PVC foam core + T700 CF skin) │ -│ ┌──────────────────────────────────┐ │ -│ │ High-aspect-ratio wing │ │ -│ │ Wingspan: 3.0-3.2m │ │ -│ └──────────┬───────────────────────┘ │ -│ │ │ -│ ┌───────────────┴───────────────────┐ │ -│ │ CFRP Monocoque Fuselage │ │ -│ │ ┌─────────┐ ┌──────────────┐ │ │ -│ │ │ Battery │ │ Payload Bay │ │ │ -│ │ │ Bay │ │ (1.47 kg) │ │ │ -│ │ └─────────┘ └──────────────┘ │ │ -│ └───────────────┬───────────────────┘ │ -│ │ │ -│ ┌───────┴───────┐ │ -│ │ Motor + Prop │ │ -│ │ (pusher) │ │ -│ └───────────────┘ │ -│ │ -│ Power: Semi-solid state battery (Tattu 330Wh/kg) │ -│ Avionics: Pixhawk 6x + GPS │ -│ Compute: Jetson Orin Nano Super │ -└─────────────────────────────────────────────────────────┘ -``` - -## Existing/Competitor Solutions Analysis - -| Platform | MTOW | Endurance | Payload | Airframe Material | Battery | Price | -|----------|------|-----------|---------|-------------------|---------|-------| -| Applied Aeronautics Albatross | 10 kg | 4 hours | 4.5 kg | Fiberglass + Carbon fiber | LiPo | ~$8,000 (RTF) | -| DeltaQuad Evo | 10 kg | 4h32m (std) / 8h55m (record) | 1-3 kg | Fiberglass + Carbon + Kevlar | Semi-solid / Solid-state Li | ~$25,000+ | -| Penguin BE | <25 kg class | 110 min | 2.8 kg | Composite | Li-Ion | ~$30,000+ | -| SUX61 | ~11 kg | 91 min | 8 kg | Carbon fiber monocoque | LiPo | ~$5,000 (frame) | - -**Key takeaway**: DeltaQuad Evo demonstrates that semi-solid/solid-state batteries combined with composite airframe can achieve 8+ hours in this MTOW class. Our design targets a similar approach with a lighter payload (1.47 vs 3 kg), leaving more weight budget for batteries. - -## Architecture - -### Component: Frame Material - -| Solution | Tools | Advantages | Limitations | Requirements | Security | Cost | Fit | -|----------|-------|-----------|-------------|-------------|----------|------|-----| -| **T700 CFRP (recommended)** | T700 unidirectional + woven prepreg or dry fabric | 40-50% lighter than Al, specific stiffness 113, excellent fatigue life, corrosion-proof | Brittle under impact, requires specialized manufacturing, difficult field repair | Vacuum infusion or prepreg + oven cure, outsourced manufacturing | N/A | ~$18/m² material; $15-25k total airframe manufacturing | ✅ Best for endurance | -| Fiberglass (E-glass) | E-glass woven fabric + epoxy | Cheap (~$5/m²), easy to work, good impact tolerance, simple field repair | 40% heavier than CFRP for same stiffness, limits endurance | Basic workshop or outsource | N/A | ~$5/m²; $5-10k total | ⚠️ Weight penalty reduces endurance by ~1-2 hours | -| Carbon-Kevlar Hybrid | Hybrid woven fabric | Best crash survivability, 25-40% lighter than Al | Kevlar hard to machine, UV sensitive, expensive (~$30/m²) | Specialized cutting tools, UV-protective coating | N/A | ~$30/m²; $20-30k total | ⚠️ Overkill for cost; Kevlar benefits limited to impact zones | -| Aluminum 6061-T6 | CNC machining | Cheapest, easiest to manufacture, excellent repairability | Heaviest option (2.7 g/cm³), poor fatigue, reduces endurance 2-3 hours | CNC shop | N/A | ~$3-5k total | ❌ Weight kills endurance | - -**Recommendation**: T700 CFRP as primary structure with Kevlar patches at landing gear attach points and belly panel for crash protection (~100-200g weight addition). - -### Component: Construction Method - -| Solution | Tools | Advantages | Limitations | Requirements | Security | Cost | Fit | -|----------|-------|-----------|-------------|-------------|----------|------|-----| -| **Sandwich (foam core + CFRP skin) — recommended for wings** | PVC foam (Divinycell H60-H80), T700 fabric, vacuum infusion setup | Highest stiffness/weight ratio, 30% lighter than solid composite, excellent for wings | Requires quality core material, careful bonding | Vacuum pump, bagging film, infusion consumables | N/A | Core: ~$500-1000; total wing set: $5-8k | ✅ Best for wing endurance | -| Monocoque (solid CFRP shell) — recommended for fuselage | CFRP prepreg or wet layup over male mold | Good torsional rigidity, smooth aerodynamic surface, compact | Heavier than sandwich for same stiffness, needs precise molds | Female or male molds, oven cure | N/A | Molds: $3-5k; layup: $2-3k | ✅ Best for fuselage | -| Spar + Rib + Skin (traditional) | CNC-cut ribs, CF tube spars, film/fabric skin | Easy to prototype and modify, lightweight if well-designed | More labor-intensive, aerodynamic surface quality depends on skin | CNC router for ribs, CF tubes | N/A | $2-4k materials | ⚠️ Good for prototyping, inferior surface finish | - -**Recommendation**: Sandwich wings + monocoque fuselage. Outsource manufacturing to a composite prototyping service (e.g., Scabro Innovations, Refitech, or similar). - -### Component: Foam Core (for wing sandwich) - -| Solution | Tools | Advantages | Limitations | Requirements | Security | Cost | Fit | -|----------|-------|-----------|-------------|-------------|----------|------|-----| -| **PVC — Divinycell H60/H80 (recommended)** | Standard composite tools | Industry standard, good stiffness/weight, closed-cell moisture immune, handles 80°C cure | Not suitable for autoclave temps >100°C | Compatible with vacuum infusion and oven cure | N/A | ~$50-80/m² | ✅ Best value for prototype | -| Rohacell PMI | Standard composite tools | Highest stiffness/weight, handles autoclave temps (180°C+) | Very expensive, overkill for prototype | Same as PVC | N/A | ~$150-300/m² | ⚠️ Only for production optimization | -| XPS (extruded polystyrene) | Hot wire cutting | Cheapest, easy to shape, closed-cell | Lower compressive strength, limited to 75°C cure | Hot wire cutter | N/A | ~$10-20/m² | ⚠️ Budget option, acceptable for first prototype | -| EPS (expanded polystyrene) | Hot wire cutting | Cheapest available | Lowest strength, absorbs moisture, open-cell-like bead structure | Hot wire cutter | N/A | ~$5-10/m² | ❌ Not recommended for flight-critical parts | - -### Component: Battery Technology - -| Solution | Tools | Advantages | Limitations | Requirements | Security | Cost | Fit | -|----------|-------|-----------|-------------|-------------|----------|------|-----| -| **Semi-solid state — Tattu 330Wh/kg (recommended)** | Compatible charger (6S/12S balance) | 310 Wh/kg pack level, 800-1200 cycles, -20 to 60°C, 10C peak | Higher cost per Wh (~$0.50-0.80), limited supplier options | Standard balance charger, battery management | Fire safety: low thermal runaway risk | ~$800-1500/pack (est.) | ✅ Best for max endurance | -| Semi-solid state — Grepow 300Wh/kg | Compatible charger | 300 Wh/kg, 1200+ cycles, 2C charge, multiple configs | Slightly lower energy density than Tattu 330 | Standard balance charger | Fire safety: low risk | ~$700-1200/pack (est.) | ✅ Good alternative | -| Li-Ion 21700 Pack (custom) | Spot welder, BMS, pack assembly | 200-250 Wh/kg, 500-800 cycles, widely available, cheap cells | Lower energy density, requires custom pack building, 3-5C max discharge | BMS, spot welder, cell matching | Medium: requires proper BMS | ~$0.20-0.35/Wh | ⚠️ 20-30% less endurance than semi-solid | -| LiPo (traditional) | Standard RC charger | Cheapest, highest discharge rates (25-50C), widely available | 150-200 Wh/kg, 200-500 cycles, thermal sensitivity | Standard RC charger | Higher thermal runaway risk | ~$0.15-0.25/Wh | ❌ 40-50% less endurance than semi-solid | - -**Recommended configuration**: Tattu 330Wh/kg 6S 33000mAh × 1-2 packs (series or parallel depending on motor voltage requirements). -- 1 pack: 2324g, 732.6 Wh → estimated 4-5 hours practical endurance -- 2 packs (parallel): 4648g, 1465 Wh → estimated 6-7 hours practical (but may exceed MTOW) - -Optimal: single large 12S pack or purpose-selected configuration to stay within MTOW. - -### Component: Carbon Fiber Grade - -| Solution | Tools | Advantages | Limitations | Requirements | Security | Cost | Fit | -|----------|-------|-----------|-------------|-------------|----------|------|-----| -| **T700 (recommended)** | Standard composite tools | 4900 MPa tensile, 230 GPa modulus, good impact tolerance, industry standard for UAVs | Lower modulus than T800 | Standard resin systems | N/A | ~$18/m² | ✅ Best value | -| T800 | Standard composite tools | 5880 MPa tensile, 294 GPa modulus, 28% stiffer | 44% more expensive, more brittle, marginal weight gain at this scale | Same resin systems | N/A | ~$26/m² | ⚠️ Only for specific high-load elements | -| T300 | Standard composite tools | Cheapest, widely available | Significantly lower strength than T700 | Same resin systems | N/A | ~$12/m² | ❌ Insufficient for primary structure | - -## Weight Budget Estimate - -| Component | Weight (kg) | -|-----------|-------------| -| Bare airframe (CFRP sandwich wing + monocoque fuselage) | 2.8-3.2 | -| Motor + ESC + propeller | 0.4-0.6 | -| Wiring, connectors, misc hardware | 0.3-0.5 | -| Payload (camera + gimbal + Jetson + Pixhawk + GPS) | 1.47 | -| Battery (semi-solid, target) | 3.0-3.5 | -| **Total estimated** | **8.0-9.3** | -| MTOW limit | 10.0 | -| **Margin** | **0.7-2.0** | - -## Endurance Estimate - -**Assumptions**: -- MTOW: 9.0 kg (mid-range estimate) -- Cruise speed: 17 m/s -- L/D ratio: ~15 (high-aspect-ratio wing) -- Propulsive efficiency: 0.85 -- Battery: 3.2 kg semi-solid at 310 Wh/kg = 992 Wh -- Payload power: ~30W (Jetson 15-25W + camera/gimbal 10-15W) -- Cruise power: ~130W (aerodynamic) + 30W (payload) = ~160W total -- Battery reserve: 20% -- Usable energy: 992 × 0.80 = 794 Wh - -**Theoretical endurance**: 992 / 160 = 6.2 hours -**Practical endurance (with reserve + real-world losses)**: 794 / 160 ≈ **5.0 hours** - -**Range at cruise**: 5.0h × 17 m/s × 3.6 = **306 km** - -This is conservative. Optimization of airfoil, wing loading, and propulsion system could push practical endurance to 5.5-6.0 hours. - -## Testing Strategy - -### Integration / Functional Tests -- Static load test: wing spar to 3× max flight load (verify no failure at 3g) -- Ground vibration test: verify no flutter modes within flight envelope -- Range/endurance test: fly at cruise speed until 20% battery reserve, measure actual endurance vs predicted -- Payload integration test: verify all electronics (Jetson, Pixhawk, camera, gimbal) function correctly with airframe vibration -- CG range test: verify stable flight across full CG envelope - -### Non-Functional Tests -- Temperature endurance: ground soak at -10°C and +45°C, verify battery and avionics function -- Wind resistance: fly in 10-12 m/s sustained wind, verify controllability and endurance impact -- Hard landing test: drop from 1m at 2 m/s descent rate onto belly, verify structural integrity (Kevlar reinforcement zones) -- Battery cycle test: charge/discharge 50 cycles, verify capacity retention ≥95% -- EMI test: verify Jetson/camera does not interfere with GPS/telemetry - -## References - -1. UAVMODEL — Carbon Fiber Fixed Wing Drones: https://www.uavmodel.com/blogs/news/skyeye-sr260-fixed-wing-drone-2600mm-long-endurance-mapping-amp-inspection -2. SUX61 UAV Frame: https://aerojetparts.com/product/sux61-uav-frame-carbon-fiber-8kg-payload-91min-endurance/ -3. FAI — Vanilla UAV Flight Duration Record: https://www.fai.org/vanilla-uav-flight-duration-record -4. Springer — EPS-Fiber-Reinforced Composite Wing Analysis (2024): https://link.springer.com/10.1007/s11029-024-10185-3 -5. Grepow Semi-Solid Battery: https://www.grepow.com/semi-solid-state-battery/300wh-kg-series-high-energy-density-battery-pack.html -6. Tattu Semi-Solid Battery: https://tattuworld.com/semi-solid-state-battery/ -7. Herewin Semi-Solid Guide (2026): https://www.herewinpower.com/blog/solid-state-drone-batteries-ultimate-guide/ -8. Applied Aeronautics Albatross: https://www.appliedaeronautics.com/albatross-uav -9. KingRaysCarbon — CF vs Al: https://kingrayscarbon.com/carbon-fiber-vs-aluminum-for-drone-frames-which-performs-better/ -10. Dronecarbon — Kevlar vs CF: https://www.dronecarbon.com/kevlar-vs-carbon-fiber_a9075.html -11. Herewin — LFP vs LiPo vs Semi-Solid (2026): https://www.herewinpower.com/blog/lfp-vs-lipo-vs-semi-solid-industrial-drone-batteries-2026-roi-safety-and-performance/ -12. DeltaQuad Evo Specs: https://docs.deltaquad.com/gov/vehicle-specifications -13. DeltaQuad Evo 8h55m Record: https://uasweekly.com/2025/06/27/deltaquad-evo-sets-record-with-8-hour-flight-endurance-for-electric-vtol-uas-milestone/ -14. T700 vs T800 Guide: https://www.carbonfibermaterial.com/t700-vs-t800-carbon-fiber-a-practical-guide-for-material-selection/ -15. CFRP Manufacturing Comparison (Indonesian J. Aerospace): https://ejournal.brin.go.id/ijoa/article/view/286 -16. Rohacell vs Foam Cores — Chem-Craft: https://chem-craft.com/blog/comparative-analysis-rohacell-vs-traditional-materials-in-composite-engineering/ -17. Carbon-Kevlar Hybrid: https://ictmaterial.com/what-is-carbon-kevlar-hybrid-fabric-properties-and-use-cases/ -18. Scabro Innovations — UAV Prototyping: https://scabroinnovations.com/diensten/composite-airframe-prototyping/ -19. Tattu 330Wh/kg 6S Specs: https://www.tattuworld.com/semi-solid-state-battery/semi-solid-330wh-kg-33000mah-22-2v-10c-6s-battery.html -20. ASTM F3563-22: https://www.astm.org/f3563-22.html - -## Related Artifacts -- AC Assessment: `_standalone/UAV_frame_material/00_research/UAV_frame_material/00_ac_assessment.md` diff --git a/_standalone/UAV_frame_material/01_solution/solution_draft02.md b/_standalone/UAV_frame_material/01_solution/solution_draft02.md deleted file mode 100644 index c7a7141..0000000 --- a/_standalone/UAV_frame_material/01_solution/solution_draft02.md +++ /dev/null @@ -1,428 +0,0 @@ -# Solution Draft (Rev 02) - -## Revised Constraints (vs Draft 01) - -| Constraint | Draft 01 | Draft 02 | -|-----------|----------|----------| -| Cost per unit | $100k prototype | < $7k, target < $5k | -| Material | CFRP (T700) | S2 fiberglass (radio transparent) | -| Radio transparency | Not considered | Required — full RF transparency for GPS, telemetry, data links | -| Flight time | 5-6 hours target | Same if possible, can be less | -| Transport | Not specified | Disassembled fits in car trunk; 2 planes per pickup truck | - -## Product Solution Description - -A modular, radio-transparent electric fixed-wing reconnaissance UAV built with **S2 fiberglass/foam-core sandwich construction** with internal **carbon fiber spar reinforcement**. Designed for field deployment — disassembles into 3 sections (2 wing panels + fuselage) that fit in a car trunk, with 2 complete aircraft fitting in a standard pickup truck bed. Powered by semi-solid state batteries for maximum endurance. - -**Target performance**: 3.5-5 hours practical flight endurance, 9-10 kg MTOW, ~3m wingspan, < $5k BOM per unit. - -``` -┌──────────────────────────────────────────────────────────────┐ -│ MODULAR AIRFRAME LAYOUT │ -│ │ -│ LEFT WING PANEL FUSELAGE RIGHT WING PANEL │ -│ (~1.5m span) (~1.0-1.1m) (~1.5m span) │ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ -│ │ S2 FG skin │ │ S2 FG skin │ │ S2 FG skin │ │ -│ │ PVC foam core│◄─►│ Battery bay │◄─►│ PVC foam core│ │ -│ │ CF spar cap │ │ Payload bay │ │ CF spar cap │ │ -│ │ (internal) │ │ Motor+ESC │ │ (internal) │ │ -│ └──────────────┘ └──────────────┘ └──────────────┘ │ -│ │ -│ Wing-fuselage joint: aluminum spar joiner + 2 pin locks │ -│ Assembly time target: < 10 minutes │ -│ Material: S2 fiberglass = RF transparent (GPS/telemetry OK) │ -│ Internal CF spar: minimal RF impact (narrow linear element) │ -└──────────────────────────────────────────────────────────────┘ - -TRANSPORT CONFIGURATION (standard pickup truck, 6.5ft bed): -┌───────────────────────────────────────────┐ -│ Truck bed: 198cm × 130cm (wheel wells) │ -│ ┌──────────────────┐ ┌────────────────┐ │ -│ │ Plane 1 wings │ │ Plane 2 wings │ │ -│ │ (2 × 150cm long) │ │ (2 × 150cm) │ │ -│ │ stacked ~20cm │ │ stacked ~20cm │ │ -│ ├──────────────────┤ ├────────────────┤ │ -│ │ Plane 1 fuselage │ │ Plane 2 fuse. │ │ -│ │ (~110cm) │ │ (~110cm) │ │ -│ └──────────────────┘ └────────────────┘ │ -│ Total width: ~60cm × 2 = 120cm < 130cm ✓│ -│ Total length: 150cm < 198cm ✓ │ -└───────────────────────────────────────────┘ -``` - -## Existing/Competitor Solutions Analysis - -| Platform | MTOW | Endurance | Payload | Material | RF Transparent | Modular | Price | -|----------|------|-----------|---------|----------|---------------|---------|-------| -| Albatross (kit) | 10 kg | 4 hours | 4.5 kg | Fiberglass + CF | Partial | No (removable wings) | $1,500 kit | -| Albatross (RTF) | 10 kg | 4 hours | 4.5 kg | Fiberglass + CF | Partial | No | $4,800 | -| DeltaQuad Evo | 10 kg | 4.5h / 8.9h record | 1-3 kg | FG + CF + Kevlar | Partial | Wing removable | $25,000+ | -| Skywalker X8 | ~4 kg | 45-60 min | 1-2 kg | EPO foam | Yes | No | $489-598 | -| Mugin 2600 | 15 kg | 1.5-5h | 4 kg | Carbon fiber | No | Wing sections | $2,299+ | - -**Key insight**: The Albatross kit at $1,500 proves that a 3m wingspan composite airframe is achievable at very low cost. Our target of < $5k per complete unit (with batteries) is realistic. No competitor offers the combination of radio transparency + modular transport + semi-solid batteries. - -## Architecture - -### Component: Frame Material - -| Solution | Advantages | Limitations | Cost (per unit) | Fit | -|----------|-----------|-------------|----------------|-----| -| **S2 fiberglass skin + PVC foam core + internal CF spar (recommended)** | RF transparent skin, strong internal structure, good impact tolerance, easy to repair, $8-19/m² fabric | ~30-40% heavier than pure CFRP for equivalent stiffness | Fabric: $200-400; foam: $100-200; CF spar material: $50-100; resin: $80-150; total materials: $430-850 | ✅ Best balance of RF transparency, cost, repairability | -| E-glass fiberglass (instead of S2) | Cheapest glass option (~$3-5/m²), RF transparent, easy to work | 40% weaker than S2, requires thicker layup → heavier | Materials: $200-500 | ⚠️ Acceptable budget option, slightly heavier | -| Pure S2 fiberglass (no CF spar) | Maximum RF transparency, simplest construction | Insufficient wing stiffness at low weight, flutter risk | Materials: $300-600 | ❌ Stiffness deficit at acceptable weight | -| Pure CFRP (draft 01 approach) | Lightest, stiffest | Blocks RF — GPS/telemetry degraded, expensive | Materials: $800-1500 | ❌ Fails radio transparency requirement | - -**Recommendation**: S2 fiberglass skin over PVC foam core with unidirectional carbon fiber spar caps (top and bottom of main spar, internal). The CF spar is a narrow linear element (~20-30mm wide per cap) inside the wing — negligible RF blockage. All external surfaces are S2 FG = fully radio transparent. - -### Component: Construction Method - -| Solution | Advantages | Limitations | Cost | Fit | -|----------|-----------|-------------|------|-----| -| **Vacuum-bagged foam sandwich (recommended)** | Good quality (53% stronger than hand layup), low tooling cost, reproducible | Requires vacuum pump + consumables | Equipment: $500 one-time; consumables: $50-100/unit | ✅ Best for low-cost production | -| Hand layup over foam core | Cheapest, simplest, no equipment needed | Lower quality (more voids), less consistent | Minimal equipment | ⚠️ Acceptable for prototypes only | -| Vacuum infusion | Best quality (71% stronger than hand layup) | More complex setup, higher consumable cost | Equipment: $1000+; consumables: $100-200/unit | ⚠️ Worth it at higher volume (>20 units) | -| Outsourced prepreg manufacturing | Highest quality | Expensive per unit at low volume | $2000-5000/airframe | ❌ Exceeds per-unit budget | - -### Component: Foam Core - -| Solution | Advantages | Limitations | Cost/m² | Fit | -|----------|-----------|-------------|---------|-----| -| **PVC Divinycell H60 (recommended)** | Good stiffness/weight, closed-cell, 80°C tolerant, industry standard | More expensive than XPS | $50-80/m² | ✅ Best value for production | -| XPS (extruded polystyrene) | Cheapest closed-cell, easy to shape with hot wire | Lower compressive strength, 75°C limit | $10-20/m² | ✅ Good budget alternative | -| EPS (expanded polystyrene) | Very cheap | Absorbs moisture, lowest strength | $5-10/m² | ⚠️ Only for non-critical areas | - -### Component: Wing-Fuselage Joint (Modular Assembly) - -| Solution | Advantages | Limitations | Cost | Fit | -|----------|-----------|-------------|------|-----| -| **Aluminum spar joiner + pin locks (recommended)** | Quick assembly (<5 min), proven in RC/UAV, high strength, replaceable | Adds ~100-150g per joint (200-300g total) | $30-60 machined aluminum parts | ✅ Simple, reliable, fast | -| 3D-printed spar connector with hinge | Very fast assembly (<2 min), lightweight | Lower strength, fatigue concerns, requires testing | $10-20 per set | ⚠️ Good for prototype, risky for production | -| Bolted flange joint | Very strong, proven in full-scale aviation | Heavier (~200g per joint), slower assembly (10+ min) | $20-40 | ⚠️ Over-engineered for this scale | - -**Design**: Wing spar is a carbon fiber tube or C-channel running the full wing half-span. At the root, it slides into an aluminum joiner tube embedded in the fuselage. Secured with 2 quick-release pins (top and bottom). Electrical connections (servo leads) via a quick-disconnect plug at each wing root. - -### Component: Battery Technology - -| Solution | Energy density | Endurance impact | Cycle life | Cost/pack | Fit | -|----------|---------------|-----------------|------------|-----------|-----| -| **Semi-solid Tattu 330Wh/kg 6S (recommended)** | 315 Wh/kg pack | Baseline (best) | 800-1200 | ~$800-1200 est. | ✅ Best endurance per $ | -| Semi-solid Grepow 300Wh/kg 6S | 280-300 Wh/kg pack | -5 to -10% | 1200+ | ~$700-1000 est. | ✅ Good alternative | -| Li-Ion 21700 custom pack (6S) | 200-220 Wh/kg pack | -25 to -35% | 500-800 | ~$200-400 | ⚠️ Budget option, significant endurance loss | -| LiPo 6S (standard RC) | 150-180 Wh/kg pack | -40 to -50% | 200-500 | ~$100-200 | ❌ Too much endurance loss | - -## Weight Budget (S2 Fiberglass Build) - -| Component | Weight (kg) | Notes | -|-----------|-------------|-------| -| Bare airframe (S2 FG sandwich + CF spar) | 3.8-4.5 | ~30% heavier than pure CFRP; Albatross FG+CF is 3.35 kg | -| Wing joints (aluminum) | 0.2-0.3 | Spar joiners + pins + quick-disconnect plugs | -| Motor + ESC + propeller | 0.4-0.6 | | -| Wiring, connectors, misc | 0.3-0.4 | | -| **Platform subtotal** | **4.7-5.8** | | -| Payload (camera + gimbal + Jetson + Pixhawk + GPS) | 1.47 | Fixed | -| Battery (semi-solid) | 2.7-3.8 | Remainder to MTOW | -| **Total (target MTOW 10 kg)** | **~10.0** | | - -Conservative estimate: platform 5.3 kg + payload 1.47 kg + battery 3.2 kg = 9.97 kg. - -## Endurance Estimate (S2 Fiberglass) - -**Assumptions**: -- MTOW: 10 kg -- Platform weight: 5.3 kg (S2 FG airframe + motor + wiring + joints) -- Payload: 1.47 kg -- Battery: 3.23 kg semi-solid at 310 Wh/kg = 1001 Wh -- Cruise power: ~140W (slightly higher than CFRP due to heavier aircraft → higher induced drag) -- Payload power: ~30W (Jetson + camera + gimbal) -- Total system power: ~170W -- Battery reserve: 20% -- Usable energy: 1001 × 0.80 = 801 Wh -- Real-world efficiency factor: 0.75 - -**Theoretical endurance**: 1001 / 170 = 5.9 hours -**Practical endurance (with reserve)**: 801 / 170 ≈ **4.7 hours** -**Practical endurance (with reserve + real-world losses)**: 801 × 0.75 / 170 ≈ **3.5 hours** - -**Comparison to Draft 01 (CFRP)**: -- Draft 01: 5.0 hours practical → Draft 02: 3.5-4.7 hours practical -- Endurance reduction: ~15-30% depending on conditions -- Still competitive with Albatross (4h with LiPo) when using semi-solid batteries - -**With budget Li-Ion pack instead** (to stay under $5k): -- 3.23 kg Li-Ion at 210 Wh/kg = 678 Wh → usable 542 Wh -- Practical: 542 / 170 ≈ **3.2 hours** (reserve only) / **2.4 hours** (worst case) - -## BOM Cost Estimate (Per Unit) - -| Component | Low Est. | High Est. | Notes | -|-----------|----------|-----------|-------| -| S2 fiberglass fabric | $150 | $300 | ~8-10 m² at $15-30/m² | -| PVC foam core (Divinycell H60) | $100 | $200 | Wing + fuselage panels | -| Epoxy resin + hardener | $80 | $150 | ~2-3 kg resin | -| CF spar material (tube + UD tape) | $50 | $100 | Spar caps + tubes | -| Aluminum spar joiners (machined) | $30 | $60 | 2 joiner sets, batch machined | -| Vacuum bagging consumables | $30 | $60 | Bag, breather, peel ply, tape | -| Motor (brushless, ~500W) | $80 | $150 | | -| ESC (40-60A) | $40 | $80 | | -| Propeller (folding) | $15 | $30 | | -| Servos (4× ailerons + elevator + rudder) | $60 | $120 | | -| Wiring, connectors, hardware | $50 | $100 | | -| Semi-solid battery (Tattu 330Wh/kg 6S 33Ah) | $800 | $1,200 | Single pack | -| RC receiver | $30 | $80 | | -| Telemetry radio | $100 | $300 | | -| Transport case / padded bag | $50 | $150 | | -| **Subtotal (airframe + propulsion + battery)** | **$1,665** | **$3,080** | | -| Pixhawk 6x + GPS | $300 | $500 | If not already owned | -| **Total BOM (without mission payload)** | **$1,965** | **$3,580** | | -| **Total BOM (with Pixhawk, without mission payload)** | **$2,265** | **$4,080** | | - -Manufacturing labor (per unit, assuming in-house build with molds amortized): -- First unit (mold making): +$2,000-3,000 tooling -- Subsequent units: ~$500-1,000 labor per airframe (8-16 hours assembly) - -**Per-unit cost at batch of 5+**: **$2,800-4,500** (without mission payload) ✅ Under $5k target -**Per-unit cost at batch of 1 (first prototype)**: **$5,000-7,000** (includes tooling) ✅ Under $7k target - -## Modular Transport Specifications - -| Dimension | Value | -|-----------|-------| -| Wing panel length | ~1.50 m (half-span) | -| Wing panel chord | ~0.25-0.30 m | -| Wing panel thickness | ~0.04-0.05 m | -| Fuselage length | ~1.00-1.10 m | -| Fuselage width/height | ~0.15-0.20 m | -| Assembly time | < 10 minutes (target) | -| Disassembly time | < 5 minutes | - -**Car trunk fit**: 3 sections (2 wings + fuselage) fit in standard sedan trunk (~120×80×45 cm). Wings stack flat, fuselage alongside. ✅ - -**Pickup truck (2 planes)**: Standard 6.5ft bed (198×130 cm between wheel wells). Each plane's longest component is 150 cm (< 198 cm bed length). Two planes side by side need ~120 cm width (< 130 cm between wheel wells). ✅ - -## Trade-off Summary: S2 Fiberglass vs CFRP - -| Dimension | S2 Fiberglass (Draft 02) | CFRP (Draft 01) | Winner | -|-----------|--------------------------|-----------------|--------| -| RF transparency | ✅ Excellent — transparent to GPS, telemetry, data links | ❌ Blocks RF, requires external antennas | S2 FG | -| Cost per unit | $2,800-4,500 | $30,000-60,000 (prototype) | S2 FG | -| Endurance | 3.5-4.7 hours practical | 5.0 hours practical | CFRP (+15-30%) | -| Airframe weight | 3.8-4.5 kg bare | 2.8-3.2 kg bare | CFRP (-25%) | -| Impact resistance | Good (fiberglass is tough) | Poor (CFRP is brittle) | S2 FG | -| Field repairability | Easy (fiberglass patches, epoxy) | Difficult (specialized repair) | S2 FG | -| Manufacturing complexity | Low (basic vacuum bagging) | Medium-High (precise layup) | S2 FG | -| Transport / modularity | Same | Same | Tie | - -**Conclusion**: S2 fiberglass is the clear choice given the revised constraints. The 15-30% endurance reduction vs CFRP is offset by radio transparency (critical for the mission), 10x lower cost, and significantly easier manufacturing and field repair. - -## Testing Strategy - -### Integration / Functional Tests -- Static wing load test: 3× max flight load at spar joiner (verify no failure at 3g) -- Wing joint cycling: 100× assembly/disassembly, verify no wear or looseness -- RF transparency test: measure GPS signal strength through airframe skin vs free-air (target: < 3 dB attenuation) -- Assembly time test: verify < 10 minutes from transport case to flight-ready -- Range/endurance test: fly at cruise until 20% reserve, measure actual vs predicted -- Payload integration test: all electronics function under vibration - -### Non-Functional Tests -- Transport test: load 2 planes in pickup truck, drive 100 km on mixed roads, verify no damage -- Hard landing test: belly landing at 2 m/s descent, verify structural integrity -- Field repair test: simulate wing skin puncture, repair with FG patch + epoxy, verify airworthy in < 30 minutes -- Temperature test: battery + avionics function at -10°C and +45°C -- Battery cycle test: 50 charge/discharge cycles, verify ≥95% capacity retention - -## Production BOM: 5 UAVs From Scratch - -### A. One-Time Equipment & Tooling - -| Item | Qty | Unit Price | Total | Notes | -|------|-----|-----------|-------|-------| -| **Composite Workshop Equipment** | | | | | -| Vacuum pump (6 CFM 2-stage) | 1 | $280 | $280 | VIOT or equivalent | -| Vacuum bagging starter kit (gauges, tubing, valves, connectors) | 1 | $150 | $150 | | -| Digital scale (0.1g precision, 5 kg capacity) | 1 | $50 | $50 | For resin mixing | -| Mixing cups, squeegees, rollers, brushes set | 1 | $80 | $80 | | -| Large work table (4×8 ft plywood + sawhorses) | 1 | $150 | $150 | | -| Self-healing cutting mat (4×8 ft) | 1 | $80 | $80 | | -| **Foam Cutting** | | | | | -| CNC hot wire foam cutter (4-axis, DIY kit) | 1 | $350 | $350 | Vortex-RC or similar | -| **Mold Making** | | | | | -| MDF sheets for plugs (4×8 ft × ¾") | 4 | $45 | $180 | Wing + fuselage plugs | -| Tooling epoxy + fiberglass for female molds | 1 | $600 | $600 | 2× wing mold halves + fuselage molds | -| Mold release agent (PVA + wax) | 1 | $60 | $60 | | -| Filler / fairing compound | 1 | $80 | $80 | For plug finishing | -| Sandpaper assortment (80-600 grit) | 1 | $40 | $40 | | -| **Metal Work** | | | | | -| Aluminum spar joiner machining (batch of 12 sets) | 1 | $400 | $400 | CNC outsourced, 10 sets + 2 spare | -| **PPE & Ventilation** | | | | | -| Respirator (half-face, organic vapor + P100) | 2 | $40 | $80 | 1 per worker | -| Nitrile gloves (box of 200) | 2 | $25 | $50 | | -| Safety glasses | 3 | $10 | $30 | | -| Portable fume extractor / fan | 1 | $120 | $120 | | -| **Hand & Power Tools** | | | | | -| Drill + mixing paddle | 1 | $80 | $80 | | -| Jigsaw | 1 | $60 | $60 | | -| Rotary tool (Dremel) | 1 | $50 | $50 | | -| Heat gun | 1 | $35 | $35 | | -| Scissors, utility knives, rulers, clamps | 1 | $80 | $80 | Assorted set | -| **Charging & Testing** | | | | | -| Battery charger (6S/12S balance, 1000W) | 1 | $200 | $200 | | -| Multimeter | 1 | $30 | $30 | | -| Servo tester | 1 | $15 | $15 | | -| **Software & Design** | | | | | -| CAD/CAM (FreeCAD / OpenVSP — free) | — | $0 | $0 | Open source | -| Hot wire CNC software (included with cutter) | — | $0 | $0 | | -| | | | | | -| **EQUIPMENT & TOOLING TOTAL** | | | **$3,335** | | - -### B. Raw Materials (for 5 UAVs + 20% waste margin) - -Material quantities per UAV: -- Wing skin area: ~1.6 m² planform × 2 (top+bottom) × 2 layers = ~6.4 m² S2 fabric -- Fuselage skin: ~0.6 m² × 2 layers = ~1.2 m² -- Tail surfaces: ~0.3 m² × 2 layers = ~0.6 m² -- Total S2 fabric per UAV: ~8.2 m² → with waste: ~10 m² -- Foam core per UAV: ~2.5 m² (wings + tail) -- Resin per UAV: ~2.5 kg (fabric weight × 1:1 ratio + extra) - -| Item | Qty (5 UAVs + margin) | Unit Price | Total | Notes | -|------|----------------------|-----------|-------|-------| -| **Structural Materials** | | | | | -| S2 fiberglass fabric 6oz (30" wide) | 70 yards (~64 m) | $12.50/yard | $875 | ~10 m² per UAV × 5 + waste | -| PVC foam Divinycell H60 10mm (1.22×0.81m sheets) | 16 sheets | $40/sheet | $640 | ~2.5 m² per UAV × 5 + waste | -| Laminating epoxy resin (West System 105 or equiv) | 4 gallons | $125/gal | $500 | ~2.5 kg resin per UAV | -| Epoxy hardener | 2 gallons | $80/gal | $160 | | -| Carbon fiber tube (spar, 20mm OD, 1.5m) | 12 | $25 each | $300 | 2 per UAV + spare | -| Carbon fiber UD tape (spar caps, 25mm wide) | 30 m | $5/m | $150 | 5m per UAV + spare | -| **Vacuum Bagging Consumables** | | | | | -| Vacuum bag film (5m × 1.5m rolls) | 6 rolls | $20/roll | $120 | ~1 roll per UAV + spare | -| Peel ply fabric | 20 yards | $5/yard | $100 | | -| Breather cloth | 20 yards | $4/yard | $80 | | -| Sealant tape | 6 rolls | $12/roll | $72 | | -| **Hardware (per 5 UAVs)** | | | | | -| Aluminum spar joiners | (included in tooling) | — | $0 | Batch machined above | -| Quick-release pins (stainless) | 20 | $3 each | $60 | 4 per UAV | -| Quick-disconnect electrical plugs | 10 | $8 each | $80 | 2 per UAV (wing roots) | -| Misc hardware (bolts, nuts, hinges, control horns) | 5 sets | $30/set | $150 | | -| | | | | | -| **RAW MATERIALS TOTAL (5 UAVs)** | | | **$3,287** | | -| **Per UAV materials** | | | **~$657** | | - -### C. Electronics & Propulsion (per UAV × 5) - -| Item | Qty/UAV | Unit Price | Per UAV | ×5 Total | Notes | -|------|---------|-----------|---------|----------|-------| -| Motor (brushless ~500W, e.g. Dualsky XM5050EA) | 1 | $90 | $90 | $450 | Fixed-wing optimized | -| ESC (40-60A, BLHeli) | 1 | $50 | $50 | $250 | | -| Folding propeller (13×8 or similar) | 2 | $15 | $30 | $150 | 1 spare per UAV | -| Servos (digital metal gear, 15-20 kg·cm) | 5 | $25 | $125 | $625 | 2× aileron + elevator + rudder + flap/spare | -| Pixhawk 6X Mini + GPS | 1 | $380 | $380 | $1,900 | | -| RC receiver (long range, e.g. TBS Crossfire) | 1 | $60 | $60 | $300 | | -| RFD900x telemetry pair (shared GCS unit) | 1 air + 0.2 GCS | $170 (air) | $170 | $850 + $350 GCS = $1,200 | 1 GCS module shared | -| Power distribution board + BEC | 1 | $25 | $25 | $125 | | -| Wiring, connectors (XT90, JST, servo ext.) | 1 set | $40 | $40 | $200 | | -| Semi-solid battery (Tattu 330Wh/kg 6S 33Ah) | 1 | $732 | $732 | $3,660 | | -| | | | | | | -| **ELECTRONICS TOTAL (5 UAVs)** | | | | **$8,910** | | -| **Per UAV electronics** | | | **~$1,702** | | Excl. shared GCS telemetry | - -### D. Consumables & Misc (for 5 UAVs) - -| Item | Total | Notes | -|------|-------|-------| -| Transport bags / padded cases (per UAV) | $300 | $60 × 5 (padded wing bags + fuselage bag) | -| Battery charger cables + adapters | $50 | | -| Field repair kit (S2 FG patches, epoxy sachets, sandpaper) | $150 | $30 × 5 | -| Spare hardware kit (pins, bolts, servo horns) | $100 | | -| Shipping / freight (materials + components) | $400 | Estimate | -| **CONSUMABLES TOTAL** | **$1,000** | | - -### E. Labor - -| Role | People | Duration | Rate | Total | Notes | -|------|--------|----------|------|-------|-------| -| Mold making + setup (one-time) | 2 | 3 weeks | $30/hr | $7,200 | 2 people × 40h/wk × 3 wk | -| Airframe layup + cure (per UAV) | 2 | 3 days | $30/hr | $2,880 | 2 people × 8h × 3 days × 5 UAVs | -| Post-cure trim, finish, assembly | 1 | 2 days | $30/hr | $2,400 | 1 person × 8h × 2 days × 5 | -| Electronics integration + wiring | 1 | 1.5 days | $35/hr | $2,100 | 1 person × 8h × 1.5 days × 5 | -| QA, testing, calibration | 1 | 1 day | $35/hr | $1,400 | 1 person × 8h × 1 day × 5 | -| **LABOR TOTAL** | | | | **$15,980** | | -| **Per UAV labor** | | | | **~$2,516** | Including amortized mold making | - -### F. Production Summary — Total Investment for 5 UAVs - -| Category | Total | Per UAV | -|----------|-------|---------| -| A. Equipment & Tooling (one-time) | $3,335 | $667 | -| B. Raw Materials | $3,287 | $657 | -| C. Electronics & Propulsion | $8,910 | $1,782 | -| D. Consumables & Misc | $1,000 | $200 | -| E. Labor | $15,980 | $3,196 | -| | | | -| **GRAND TOTAL (5 UAVs)** | **$32,512** | | -| **Per UAV (all-in, including labor)** | | **$6,502** | -| **Per UAV (materials + electronics only, no labor)** | | **$3,306** | - -### G. Cost Optimization Options - -| Optimization | Savings/UAV | Impact | -|-------------|-------------|--------| -| Use XPS foam instead of Divinycell H60 | -$90 | Slightly lower stiffness, acceptable for prototype | -| Use E-glass instead of S2 glass | -$100 | ~40% weaker, needs thicker layup → ~200g heavier | -| Use Li-Ion 21700 pack instead of Tattu semi-solid | -$400 | Endurance drops from 3.5-4.7h to 2.4-3.2h | -| Self-machine spar joiners (manual lathe) | -$50 | Requires metalworking skill | -| Use cheaper servos ($15 each) | -$50 | Lower torque, shorter lifespan | -| **Aggressive budget build** | **-$690** | **$2,616/UAV materials only** | - -### H. Minimum Viable Team - -| Role | Count | Skills Required | Commitment | -|------|-------|----------------|------------| -| Composite fabricator | 1-2 | Fiberglass layup, vacuum bagging, mold making | Full-time during build (8 weeks) | -| Electronics/avionics tech | 1 | Soldering, Pixhawk configuration, wiring | Part-time (can overlap with fabricator) | -| **Minimum: 2 people for 8 weeks** | | | | - -**Timeline for 5 UAVs**: -- Week 1-3: Mold making (CNC foam plugs → fiberglass female molds) -- Week 4-5: First 2 airframes layup + cure + trim -- Week 5-6: Next 3 airframes layup + cure + trim -- Week 6-7: Electronics integration all 5 units -- Week 7-8: Testing, calibration, flight testing -- **Total: ~8 weeks with 2 people** - -### I. Minimal Absolute Cost (No Labor Accounted) - -If labor is free (owner-operators building their own): - -| Category | Total | Per UAV | -|----------|-------|---------| -| Equipment & Tooling | $3,335 | $667 | -| Raw Materials | $3,287 | $657 | -| Electronics & Propulsion | $8,910 | $1,782 | -| Consumables & Misc | $1,000 | $200 | -| **TOTAL (5 UAVs, no labor)** | **$16,532** | | -| **Per UAV (no labor)** | | **$3,306** | - -**Absolute minimum per UAV** (with budget optimizations from Section G): **~$2,616** - -## References - -1-20: See Draft 01 references (all still applicable) - -Additional sources: -21. S-Glass vs E-Glass comparison: https://wiki-science.blog/s-glass-vs-e-glass-key-differences -22. Reinforcement Fiber Reference: https://explorecomposites.com/materials-library/fiber-ref/ -23. S-Glass vs Carbon Fiber: https://carbonfiberfriend.com/s-glass-vs-carbon-fiber/ -24. RF Attenuation by composite materials: https://www.rocketryforum.com/threads/rf-attenuation-by-body-tube-nosecone.186634/ -25. Russian foamplast UAV (max radio transparency): https://bulgarianmilitary.com/2023/10/15/russia-unveils-foamplast-fpv-uav-with-max-radio-transparency/ -26. Albatross UAV Kit: https://store.appliedaeronautics.com/albatross-uav-kit/ -27. UAV spar connector development: https://www.konelson.net/home/spar-connector-development -28. Scabro Innovations UAV prototyping: https://scabroinnovations.com/diensten/composite-airframe-prototyping/ -29. Tattu 330Wh/kg 6S pricing — GenStattu: https://genstattu.com/tattu-semi-solid-state-330wh-kg-33000mah-10c-22-2v-6s1p-g-tech-lipo-battery-pack-with-xt90-s-plug/ -30. Pixhawk 6X pricing — Holybro: https://holybro.com/products/pixhawk-6x-rev3 -31. RFD900x pricing — DrUAV: https://druav.com/products/rfdesign-rfd900x -32. Composite workshop setup — Fibre Glast: https://www.fibreglast.com/blogs/learning-center/setting-up-a-composite-shop -33. CNC hot wire foam cutter — Vortex-RC: https://www.vortex-rc.com/product/4-axis-diy-hot-wire-cnc-for-rc-hobbyists-aeromodellers-and-designers/ -34. Composite mold making — Canuck Engineering: https://www.canuckengineering.com/capabilities/composite-molds/ diff --git a/_standalone/UAV_frame_material/01_solution/solution_draft03.md b/_standalone/UAV_frame_material/01_solution/solution_draft03.md deleted file mode 100644 index 5ffc3ba..0000000 --- a/_standalone/UAV_frame_material/01_solution/solution_draft03.md +++ /dev/null @@ -1,489 +0,0 @@ -# Solution Draft (Rev 03) — 8+ Hour Endurance - -## Assessment Findings - -| Old Component Solution | Weak Point | New Solution | -|------------------------|------------|-------------| -| Single 6S 33Ah battery (1001 Wh) | Only 3.5-4.7h endurance — insufficient for 8h target | 4× 6S 33Ah 350 Wh/kg packs (2930 Wh) or 2× 12S 33Ah (2930 Wh) | -| 10 kg MTOW | Cannot carry enough battery for 8h at current energy densities | Increase to 18 kg MTOW | -| 3.0m wingspan | L/D ≈ 15 at AR≈10; higher wing loading increases cruise power | Scale to 3.8-4.0m wingspan (AR≈14, L/D≈17) | -| S2 FG airframe (3m) | Good but limited battery capacity due to MTOW constraint | S2 FG airframe scaled to 4m; same material, radio transparency preserved | -| Motor + ESC (500W class) | Undersized for 18 kg platform | Scale to 700-800W motor + 60-80A ESC | -| ADTI 20L V1 nav camera (20MP APS-C) | 34 cm/px GSD at 2 km — too coarse for feature matching | ADTI 26S V1 (26MP APS-C, mech. shutter) + 35mm lens → 21.6 cm/px at 2 km | -| Viewpro A40 Pro AI camera (1080p, 40×) | 1080p limits FoV to 65×37m at max zoom from 2 km | Viewpro Z40K (4K, 20×) → 2.7 cm/px GSD, 103×58m FoV, 479g lighter | - -## Product Solution Description - -A scaled-up modular, radio-transparent electric fixed-wing reconnaissance UAV built with **S2 fiberglass/foam-core sandwich construction** and internal carbon fiber spar reinforcement. Wingspan increased to **3.8-4.0m** for better aerodynamic efficiency (L/D ≈ 17). MTOW raised to **18 kg** to accommodate **4× semi-solid battery packs** totaling ~2930 Wh. Disassembles into modular sections for pickup truck transport; 2 complete aircraft fit in a standard 6.5ft bed. - -**Target performance**: 8-9 hours practical flight endurance, 18 kg MTOW, 3.8-4.0m wingspan. Camera payload: ADTI 26S V1 (26MP, mech. shutter, 21.6 cm/px at 2 km) for GPS-denied navigation + Viewpro Z40K (4K, 20× zoom, 2.7 cm/px at 2 km) for AI reconnaissance. Total payload 892g — 578g lighter than Draft 02. - -``` -┌──────────────────────────────────────────────────────────────────┐ -│ SCALED-UP MODULAR AIRFRAME LAYOUT │ -│ │ -│ LEFT WING PANEL FUSELAGE RIGHT WING PANEL │ -│ (~1.9m span) (~1.1m) (~1.9m span) │ -│ ┌──────────────┐ ┌──────────────────┐ ┌──────────────┐ │ -│ │ S2 FG skin │ │ S2 FG skin │ │ S2 FG skin │ │ -│ │ PVC foam core│◄─►│ Battery bay ×4 │◄─►│ PVC foam core│ │ -│ │ CF spar cap │ │ Payload bay │ │ CF spar cap │ │ -│ │ (internal) │ │ Motor (700W) │ │ (internal) │ │ -│ └──────────────┘ └──────────────────┘ └──────────────┘ │ -│ │ -│ Wing-fuselage joint: aluminum spar joiner + 2 pin locks │ -│ Assembly time target: < 10 minutes │ -│ Material: S2 fiberglass = RF transparent (GPS/telemetry OK) │ -│ Internal CF spar: minimal RF impact (narrow linear element) │ -│ │ -│ BATTERY BAY (4 packs, 2S2P wiring for 12S 66Ah): │ -│ ┌──────┐ ┌──────┐ │ -│ │ 6S │ │ 6S │ Series pair A → 12S 33Ah │ -│ │ 33Ah │ │ 33Ah │ │ -│ └──────┘ └──────┘ │ -│ ┌──────┐ ┌──────┐ │ -│ │ 6S │ │ 6S │ Series pair B → 12S 33Ah │ -│ │ 33Ah │ │ 33Ah │ Pairs A+B in parallel → 12S 66Ah │ -│ └──────┘ └──────┘ │ -│ Total: 44.4V × 66Ah = 2930 Wh │ -└──────────────────────────────────────────────────────────────────┘ - -TRANSPORT CONFIGURATION (standard pickup truck, 6.5ft bed): -┌───────────────────────────────────────────────┐ -│ Truck bed: 198cm × 130cm (between wells) │ -│ ┌────────────────────┐ ┌──────────────────┐ │ -│ │ Plane 1 wings │ │ Plane 2 wings │ │ -│ │ (2 × 190cm long) │ │ (2 × 190cm) │ │ -│ │ stacked ~25cm │ │ stacked ~25cm │ │ -│ ├────────────────────┤ ├──────────────────┤ │ -│ │ Plane 1 fuselage │ │ Plane 2 fuse. │ │ -│ │ (~110cm) │ │ (~110cm) │ │ -│ └────────────────────┘ └──────────────────┘ │ -│ Width per plane: ~35cm × 2 = 70cm │ -│ Total width: 70cm × 2 = 140cm > 130cm ⚠️ │ -│ → Stack all 4 wings in one pile + 2 fuselages │ -│ alongside: 190cm × 70cm + 110cm × 40cm │ -│ Total width: ~110cm < 130cm ✓ │ -│ Total length: 190cm < 198cm ✓ │ -└───────────────────────────────────────────────┘ -``` - -## Existing/Competitor Solutions Analysis - -| Platform | MTOW | Endurance | Battery | Wingspan | Material | RF Transparent | Transport | Price | -|----------|------|-----------|---------|----------|----------|---------------|-----------|-------| -| DeltaQuad Evo (standard) | 10 kg | 4h32m | 2× 22Ah semi-solid | 2.69m | CF+Kevlar+FG | Partial | Wing removable | $25,000+ | -| DeltaQuad Evo (record) | ~9 kg | **8h55m** | 2× Tulip Tech 450 Wh/kg | 2.69m | CF+Kevlar+FG | Partial | Wing removable | N/A (prototype batteries) | -| **YUAV Y37** | 17-20 kg | **8.5h** (1 kg payload) | 12S 60Ah semi-solid (~2700 Wh) | 3.7m | Full carbon | ❌ No | 138×55×45 cm | ~$15,000+ est. | -| NOCTUA (H2) | 20-25 kg | **10h** | Hydrogen fuel cell | 5.10m | CFRP | ❌ No | Field-portable | Academic | -| CW-80E (JOUAV) | >25 kg | 10-11h | Large electric | >4m | Composite | Unknown | Vehicle-mounted | $50,000+ | -| Albatross | 10 kg | 4h | LiPo | 3.0m | FG+CF | Partial | Removable wings | $4,800 RTF | -| **Our Draft 03** | **18 kg** | **8-9h target** | **4× 6S 33Ah 330+ Wh/kg** | **3.8-4.0m** | **S2 FG** | **✅ Yes** | **2 in pickup** | **$5,500-7,500** | - -**Key insight**: YUAV Y37 proves that 8.5h at 17-20 kg MTOW with 3.7m wingspan and semi-solid batteries is achievable in production. Our design targets similar performance with S2 FG (heavier but radio transparent) offset by slightly longer wingspan for better L/D. - -## Architecture - -### Component: Frame Material - -| Solution | Advantages | Limitations | Cost (per unit) | Fit | -|----------|-----------|-------------|----------------|-----| -| **S2 fiberglass skin + PVC foam core + internal CF spar (recommended)** | RF transparent, good impact tolerance, field repairable, proven at 3m scale | ~25-30% heavier than carbon at 4m scale; requires careful weight management | $600-1,200 materials | ✅ Only option that preserves RF transparency | -| Full carbon fiber (YUAV Y37 approach) | Lightest possible (~4-5 kg bare at 4m), best L/D | Blocks RF — GPS/telemetry degraded | $1,500-3,000 | ❌ Fails radio transparency | -| Carbon-Kevlar hybrid | Good crash survivability, lighter than FG | Partially blocks RF, expensive, hard to machine | $1,200-2,500 | ❌ RF compromise | -| S2 FG with Dyneema (UHMWPE) reinforcement | RF transparent, excellent impact resistance | Dyneema has poor compression strength, complex bonding | $800-1,500 | ⚠️ Complex but possible | - -### Component: Wingspan & Aerodynamics - -| Solution | L/D | Platform Weight | Endurance Impact | Transport | Fit | -|----------|-----|----------------|-----------------|-----------|-----| -| **3.8m wingspan (recommended for 2-in-pickup)** | ~17 | 6.5-7.5 kg | Baseline | 190cm half-wings fit 198cm bed ✓ | ✅ Best balance | -| 4.0m wingspan | ~17.5 | 7.0-8.0 kg | +3-5% | 200cm > 198cm; needs 3-section wing | ⚠️ Good but transport harder | -| 4.5m wingspan (single UAV transport) | ~18.5 | 8.0-9.5 kg | +8-12% | 225cm half-wings; 1 UAV per pickup | ⚠️ Maximum endurance, 1 plane only | -| 3.0m wingspan (Draft 02) | ~15 | 5.3 kg | Reference (3.5-4.7h) | 150cm easily fits | ❌ Insufficient for 8h | - -**Recommendation**: 3.8m wingspan as primary design. Half-wings at 190cm fit within 198cm pickup bed length. AR ≈ 13.6, L/D ≈ 17. Optional detachable wingtips (+20cm per side = 4.2m total) for maximum endurance missions where single-UAV transport is acceptable. - -### Component: Battery Configuration - -| Solution | Total Energy | Weight | Wiring | Cost | Endurance (18 kg) | Fit | -|----------|-------------|--------|--------|------|-------------------|-----| -| **4× Tattu 6S 33Ah 350 Wh/kg (recommended)** | 2930 Wh | 8.86 kg | 2S2P → 12S 66Ah | ~$2,930 | **8-8.5h** | ✅ Best modularity, off-the-shelf | -| 2× Tattu 12S 33Ah 350 Wh/kg | 2930 Wh | 8.89 kg | 2P → 12S 66Ah | ~$3,800 | **8-8.5h** | ✅ Simpler wiring, same endurance | -| 1× Tattu 12S 76Ah 330 Wh/kg | 3374 Wh | 10.88 kg | Direct 12S | ~$4,300 | **8.5-9h** (needs 20 kg MTOW) | ⚠️ Best energy but requires 20 kg MTOW | -| 4× Xingto 6S 30Ah 370 Wh/kg | ~3280 Wh (est.) | ~8.9 kg (est.) | 2S2P → 12S 60Ah | ~$3,000-4,000 | **9-9.5h** | ⚠️ Higher density but less verified | -| Future: 4× 450 Wh/kg packs | ~4000 Wh | ~8.9 kg | 2S2P → 12S | $5,000-8,000 est. | **10-11h** | ⚠️ Not yet available at volume | - -**4-Battery Configuration Detail (2S2P)**: -- 2 series pairs: each pair = 2× 6S in series = 12S 33Ah (44.4V, 1465 Wh) -- 2 parallel pairs: both 12S pairs in parallel = 12S 66Ah (44.4V, 2930 Wh) -- Requires: 2× series adapters, 1× parallel bus bar, battery management for each pair -- Advantage: individual pack replacement if one degrades; modular packing for transport -- Disadvantage: more wiring complexity, more connectors (failure points) - -**2-Battery Configuration (2P)**: -- 2× 12S 33Ah in parallel = 12S 66Ah (44.4V, 2930 Wh) -- Simpler wiring, fewer connectors -- Each pack heavier individually (4.4 kg) but fewer handling steps - -### Component: Motor & Propulsion (scaled for 18 kg) - -| Solution | Power | Weight | Efficiency | Cost | Fit | -|----------|-------|--------|-----------|------|-----| -| **T-Motor U8 Lite (recommended)** | 700W max, 200-300W cruise | ~250g | η ≈ 0.92 at cruise | ~$150 | ✅ Proven for this MTOW class | -| Dualsky XM6350EA | 800W max | ~280g | η ≈ 0.90 | ~$120 | ✅ Good budget option | -| SunnySky V4014 | 600W max | ~210g | η ≈ 0.91 | ~$90 | ⚠️ Borderline power margin | - -Propeller: 16×10 or 17×10 folding (vs 13×8 in Draft 02). Larger prop = higher propulsive efficiency at lower RPM, critical for endurance. - -ESC: 60-80A continuous rating (vs 40-60A in Draft 02). - -### Component: Foam Core - -Same as Draft 02 — PVC Divinycell H60 recommended. No change. - -### Component: Wing-Fuselage Joint - -Same aluminum spar joiner + pin lock concept as Draft 02, but scaled for larger wing loads: -- Spar tube: 25mm OD (vs 20mm) to handle higher bending moments -- Joiner: machined 7075-T6 aluminum (stronger than 6061-T6) -- Weight: ~0.35 kg per joint set (vs 0.2-0.3 in Draft 02) - -### Component: Camera Payload (Upgraded for 2 km Altitude) - -**GSD = (Sensor Width × Altitude) / (Focal Length × Image Width)** - -#### Navigation Camera (GPS-Denied System) - -| Solution | Sensor | Resolution | Weight (body+lens) | GSD at 2 km | FoV at 2 km | Cost | Fit | -|----------|--------|-----------|-------------------|-------------|-------------|------|-----| -| ADTI 20L V1 (Draft 02) | APS-C 23.2mm | 20MP (5456×3632) | ~271g (121g+150g) | 34 cm/px (25mm) | 1855×1235m | $480+lens | ❌ Too coarse at 2 km | -| **ADTI 26S V1 + 35mm (recommended)** | APS-C 23.4mm | 26MP (6192×4128) | **~172g** (122g+50g) | **21.6 cm/px** (35mm) | 1337×892m | **$1,890** | ✅ Best value: mech. shutter, light, good GSD | -| ADTI 61PRO + 50mm | FF 35.7mm | 61MP (9504×6336) | ~426g (276g+150g) | **15 cm/px** (50mm) | 1426×950m | $2,830 | ✅ Best GSD but +$940 over 26S | -| Sony ILX-LR1 + 50mm | FF 35.7mm | 61MP (9504×6336) | ~393g (243g+150g) | **15 cm/px** (50mm) | 1426×950m | $3,100 | ⚠️ Lightest 61MP, drone-native, most expensive | -| ADTI 36S + 50mm | FF 35.9mm | 36MP (7360×4912) | ~390g (240g+150g) | 19.5 cm/px (50mm) | 1434×957m | $1,600 | ❌ No mechanical shutter — rolling shutter distortion | - -**Recommendation**: ADTI 26S V1 with 35mm fixed lens. Mechanical shutter eliminates rolling shutter distortion (critical for GPS-denied feature matching at speed). 21.6 cm/pixel GSD at 2 km is sufficient for terrain feature matching, road/building identification, and satellite image correlation. IMX571 back-illuminated sensor delivers excellent dynamic range. Lightest option at 172g. Upgrade to ADTI 61PRO (+$940, 15 cm/px) if finer GSD is needed. - -#### AI Camera (Reconnaissance — "Nice Shots" from 2 km) - -| Solution | Sensor | Resolution | Zoom | Weight | GSD at 2 km (max zoom) | FoV at max zoom | Thermal | Cost | Fit | -|----------|--------|-----------|------|--------|----------------------|----------------|---------|------|-----| -| Viewpro A40 Pro (Draft 02) | 1/2.8" | 1080p (1920×1080) | 40× optical | 1074g | 3.4 cm/px | 65×37m | 640×512 | $2,999 | ⚠️ Good zoom but 1080p limits FoV | -| **Viewpro Z40K (recommended)** | 1/2.3" | **4K** (3840×2160) | 20× optical + 25× IA (4K) | **595g** | **2.7 cm/px** | **103×58m** | No | $2,999-4,879 | ✅ Better GSD, 2.5× wider FoV, 479g lighter | -| Viewpro Z40TIR | 1/2.3" | **4K** (3840×2160) | 20× optical + 40× IA (1080p) | ~700g est. | **2.7 cm/px** (4K) | 103×58m | 640×480 | ~$5,000 est. | ✅ Best of both: 4K + thermal | -| Viewpro A40T Pro | 1/2.8" | 1080p | 40× optical | ~1200g | 3.4 cm/px | 65×37m | 640×512 | $5,999 | ⚠️ Thermal + zoom but 1080p, heavy | - -**Recommendation**: Viewpro Z40K. At 4K resolution with 20× optical zoom, it delivers **better GSD (2.7 vs 3.4 cm/px)** and **2.5× wider field of view** at max zoom than the A40 Pro at 1080p/40×. And it's **479g lighter** — weight that can go to battery or margin. If thermal is needed, step up to Z40TIR. - -At 2.7 cm/pixel: vehicles clearly identifiable, human figures detectable, building details visible. At 20× wide end (53 cm/px): wide-area situational awareness covering ~2 km × 1.2 km. - -#### Payload Weight Summary (Upgraded) - -| Component | Draft 02/03 | Upgraded | Delta | -|-----------|-------------|---------|-------| -| Navigation camera (body+lens) | ADTI 20L + 25mm = 271g | ADTI 26S + 35mm = 172g | **-99g** | -| AI camera + gimbal | Viewpro A40 Pro = 1074g | Viewpro Z40K = 595g | **-479g** | -| Jetson Orin Nano Super | 60g | 60g | — | -| Pixhawk 6x + GPS | 65g | 65g | — | -| **Payload total** | **1470g** | **892g** | **-578g** | - -**Net effect: 578g saved.** This frees ~191 Wh of battery capacity at 331 Wh/kg (~42 min extra endurance) or provides comfortable MTOW margin. - -### Component: Alternative Power Sources Assessment - -| Solution | Endurance | System Weight | Cost | Logistics | RF Compat. | Fit | -|----------|-----------|---------------|------|-----------|-----------|-----| -| **Semi-solid battery (primary)** | 8-9h | 8.9 kg | $2,930-3,800 | ✅ Charge from any outlet | ✅ S2 FG | ✅ Recommended | -| Solid-state 450 Wh/kg (upgrade path) | 10-11h | 8.9 kg (or lighter) | $5,000-8,000 est. | ✅ Same as above | ✅ S2 FG | ⚠️ Future upgrade | -| Hydrogen fuel cell | 15-17h | 9.8 kg (FC + tank) | $25,000-40,000 | ❌ H2 supply in field | ❌ Needs CFRP | ❌ Impractical | -| Solar + battery hybrid | +1h over battery alone | +0.5-1.0 kg panels | +$500-1,500 | ⚠️ Weather dependent | ⚠️ Panels on wing | ❌ Marginal gain | - -## Weight Budget (18 kg MTOW, 3.8m Wingspan) - -| Component | Weight (kg) | Notes | -|-----------|-------------|-------| -| Airframe (S2 FG sandwich + CF spar, 3.8m) | 5.5-6.5 | Scaled from 3m (3.8-4.5 kg) proportional to area | -| Wing joints (aluminum 7075) | 0.35 | Larger joiner for higher loads | -| Motor (700W) + ESC (80A) + folding prop 16" | 0.6 | Scaled up from Draft 02 | -| Wiring, connectors, battery bus | 0.45 | More wiring for 4-battery config | -| **Platform subtotal** | **6.9-7.9** | | -| Payload (ADTI 26S + Z40K + Jetson + Pixhawk + GPS) | 0.89 | Upgraded cameras — 578g lighter than Draft 02 payload | -| Battery (4× Tattu 6S 33Ah) | 8.86 | 4 × 2.216 kg | -| **Total** | **16.7-17.7** | | - -Conservative: 7.9 + 0.89 + 8.86 = **17.65 kg** (well under 18 kg MTOW ✓). -Optimistic: 6.9 + 0.89 + 8.86 = **16.65 kg** (1.35 kg margin for accessories or extra battery). - -## Endurance Estimates - -### Flight Physics Parameters -- Cruise speed: 17 m/s (optimized for endurance at this wing loading) -- L/D at cruise: 17 (conservative; L/D_max ≈ 19-20 for AR=13.6) -- Overall propulsive efficiency: η = 0.72 (motor 0.92 × prop 0.82 × ESC 0.95) - -### Cruise Power Calculation -P_cruise = (W × g × V) / (L/D × η) -= (18 × 9.81 × 17) / (17 × 0.72) -= 3001.9 / 12.24 = **245W** -P_total = 245 + 30 (payload) = **275W** - -### Endurance by Battery Configuration - -| Config | Energy (Wh) | Usable 80% (Wh) | Theoretical (h) | Practical (h) | Conservative (h) | -|--------|------------|------------------|-----------------|---------------|------------------| -| 4× 6S 33Ah 330 Wh/kg | 2930 | 2344 | 10.7 | **8.5** | **7.5-8.0** | -| 2× 12S 33Ah 350 Wh/kg | 2930 | 2344 | 10.7 | **8.5** | **7.5-8.0** | -| 4× Xingto 370 Wh/kg (est.) | ~3280 | ~2624 | 11.9 | **9.5** | **8.5-9.0** | -| 1× 12S 76Ah 330 Wh/kg (20 kg MTOW) | 3374 | 2699 | 10.5* | **8.4** | **7.5-8.0** | -| Future 450 Wh/kg (est.) | ~4000 | ~3200 | 14.5 | **11.6** | **10-10.5** | - -*Higher MTOW (20 kg) → higher cruise power (~300W) partially offsets larger battery. - -**Practical** = with 80% DoD. **Conservative** = with additional 10% real-world margin (wind, maneuvers, non-optimal cruise). - -### Cross-Validation Against Reference Platforms - -| Reference | MTOW | Energy | Endurance | Wh/min | Our scaled | -|-----------|------|--------|-----------|--------|------------| -| DeltaQuad Evo (standard) | 10 kg | 976 Wh | 4.5h | 3.62 | — | -| DeltaQuad Evo (record) | ~9 kg | ~1800 Wh | 8.9h | 3.37 | — | -| YUAV Y37 | ~17 kg | 2700 Wh | 8.5h | 5.29 | Our 18 kg @ 2930 Wh: extrapolated **8.0-8.7h** | - -The YUAV Y37 cross-check (full carbon, 3.7m) extrapolates to 8.0-8.7h for our S2 FG design at 18 kg with 2930 Wh, accounting for the ~10% aerodynamic penalty of fiberglass vs carbon. This confirms our calculated range. - -### Comparison to Draft 02 - -| Parameter | Draft 02 | Draft 03 | Change | -|-----------|----------|----------|--------| -| MTOW | 10 kg | 18 kg | +80% | -| Wingspan | 3.0m | 3.8m | +27% | -| Battery weight | 3.2 kg | 8.86 kg | +177% | -| Battery energy | 1001 Wh | 2930 Wh | +193% | -| Cruise power | ~170W | ~275W | +62% | -| Practical endurance | 3.5-4.7h | **8-8.5h** | +80-140% | -| BOM cost | $2,800-4,500 | $5,500-7,500 | +67% | - -## BOM Cost Estimate (Per Unit, 8h Config) - -| Component | Low Est. | High Est. | Notes | -|-----------|----------|-----------|-------| -| S2 fiberglass fabric | $250 | $500 | ~14 m² at $15-30/m² (40% more than 3m) | -| PVC foam core (Divinycell H60) | $160 | $300 | Wing + fuselage + tail | -| Epoxy resin + hardener | $120 | $230 | ~3.5-4 kg resin | -| CF spar material (tube + UD tape) | $80 | $150 | Longer spars for 3.8m | -| Aluminum spar joiners 7075-T6 | $50 | $100 | Larger, machined | -| Vacuum bagging consumables | $40 | $80 | | -| Motor (T-Motor U8 Lite or equiv.) | $120 | $200 | 700W class | -| ESC (60-80A) | $60 | $120 | | -| Folding propeller (16×10) | $20 | $40 | | -| Servos (6× for larger surfaces) | $80 | $160 | | -| Wiring, connectors, battery bus | $80 | $150 | More complex 4-battery wiring | -| **Batteries (4× Tattu 6S 33Ah 350)** | **$2,930** | **$2,930** | Retail price | -| RC receiver | $30 | $80 | | -| Telemetry radio | $100 | $300 | | -| Transport case / padded bag | $80 | $200 | Larger for 190cm wings | -| **Subtotal (airframe + propulsion + battery)** | **$4,200** | **$5,540** | | -| Nav camera: ADTI 26S V1 + 35mm lens | $1,890 | $1,890 | 26MP APS-C, mech. shutter, 21.6 cm/px at 2 km | -| AI camera: Viewpro Z40K 4K gimbal | $2,999 | $4,879 | 4K 20× zoom, 2.7 cm/px at 2 km | -| Pixhawk 6x + GPS | $300 | $500 | | -| **Total BOM (complete unit)** | **$9,389** | **$12,809** | | - -With 2× 12S 33Ah instead of 4× 6S: battery cost rises to ~$3,800 (+$870). -With Xingto 370 Wh/kg: battery cost est. ~$3,000-4,000 but better endurance. - -**Per-unit cost at batch of 5+**: **$10,500-14,500** (including cameras, tooling amortization) -**Per-unit cost first prototype**: **$13,500-17,000** (includes tooling) - -Optional upgrade: swap ADTI 26S → ADTI 61PRO (+$940/unit) for 15 cm/px GSD if finer nav resolution needed. - -## Battery Upgrade Roadmap - -| Timeline | Battery Technology | Energy Density (pack) | Endurance (18 kg platform) | Availability | -|----------|-------------------|----------------------|---------------------------|-------------| -| **Now (2025-2026)** | Tattu/Grepow semi-solid 350 Wh/kg | ~331 Wh/kg | **8-8.5h** | ✅ Off-the-shelf | -| **Now (2025-2026)** | Xingto semi-solid 370 Wh/kg | ~350 Wh/kg | **9-9.5h** | ✅ Available (limited) | -| **Near-term (2026-2027)** | Tulip Tech Ampera solid-state | ~430 Wh/kg | **10-11h** | ⚠️ Shipping to select partners | -| **Near-term (2026-2027)** | Amprius SA102 silicon-nanowire | ~430 Wh/kg | **10-11h** | ⚠️ Pilot production | -| **Future (2027-2028)** | Tulip Tech Enerza / Amprius 500 | ~475 Wh/kg | **11-12h** | ❓ Announced, not volume | - -### Solid-State 450 Wh/kg Cost Impact - -Solid-state batteries (Tulip Tech, Amprius) are not yet priced publicly — both sell on custom quotes to defense/aerospace customers. Industry estimates for 2025-2026 production cost: $800-1,000/kWh. With small-volume aerospace/defense retail markup (1.5-3×), estimated retail: $1,500-2,500/kWh. - -| Battery | Pack Wh/kg | Total Energy | Endurance | Battery Cost | Total UAV BOM | Delta vs Baseline | -|---------|-----------|-------------|-----------|-------------|--------------|------------------| -| Tattu semi-solid (baseline) | ~331 | 2930 Wh | 8-8.5h | **$2,930** | ~$6,500 | — | -| Solid-state 450 (low est.) | ~430 | 3810 Wh | 10-11h | **$5,700** | ~$9,300 | **+$2,800 (+43%)** | -| Solid-state 450 (mid est.) | ~430 | 3810 Wh | 10-11h | **$7,600** | ~$11,200 | **+$4,700 (+72%)** | -| Solid-state 450 (defense premium) | ~430 | 3810 Wh | 10-11h | **$9,500** | ~$13,100 | **+$6,600 (+100%)** | - -Prices should converge toward production cost ($800-1,000/kWh → low estimate above) as Amprius scales 1.8 GWh contract manufacturing capacity and Tulip Tech ramps with Dutch MoD backing through 2026-2027. - -**Design for upgradability**: The battery bay should accommodate the same physical volume regardless of chemistry. Start with Tattu semi-solid at 8-8.5h for $2,930. When solid-state packs become available in compatible form factor, drop them in for 10-11h — no airframe changes needed, just a battery swap. - -## Modular Transport Specifications - -| Dimension | Value (3.8m) | Value (4.0m, 3-section) | -|-----------|-------------|------------------------| -| Wing panel length | 190 cm (half-span) | 170 cm outer + 60 cm center | -| Wing panel chord | 28-30 cm | 28-30 cm | -| Wing panel thickness | 4-5 cm | 4-5 cm | -| Fuselage length | 110 cm | 110 cm | -| Fuselage width/height | 18-22 cm | 18-22 cm | -| Assembly time | < 12 minutes | < 15 minutes | -| Disassembly time | < 7 minutes | < 10 minutes | - -**Pickup truck (2 planes, 3.8m design)**: All wing panels stack in one pile (190×30×20 cm = 4 panels × 5cm). Fuselages alongside (110×22 cm × 2). Total footprint: 190×110 cm < 198×130 cm. ✅ - -**Car trunk (1 plane, 3.8m)**: Tight but possible in larger sedans/SUVs. Two wing panels (190cm) require fold-down rear seats or diagonal placement. Fuselage fits easily. ⚠️ Borderline for sedans; SUV or wagon preferred. - -## Hydrogen Fuel Cell — Assessment (Not Recommended) - -Investigated as requested. While hydrogen offers dramatically higher endurance (15-17h), it is **not recommended** for this application: - -| Factor | Assessment | -|--------|-----------| -| Endurance | ✅ 15-17h theoretical with IE-SOAR 2.4 + 10.8L tank | -| System weight | ⚠️ ~9.8 kg (FC 4.8 + tank 4.2 + regulator 0.3 + buffer 0.5) — similar to 4-battery pack but higher complexity | -| Cost | ❌ $25,000-40,000 per unit (FC module alone est. $15-25k) | -| H2 logistics | ❌ Compressed hydrogen (350 bar) supply chain in eastern Ukraine = extremely difficult. Requires specialized transport, hazmat protocols, compressor equipment | -| Radio transparency | ❌ H2 platforms (NOCTUA, Doosan) use CFRP to save weight, conflicting with RF requirement | -| Reliability | ⚠️ Fuel cells have 1000h life but are sensitive to contaminants and temperature extremes | -| Practical recommendation | Revisit only if (1) hydrogen infrastructure develops in theater, (2) RF transparency requirement is relaxed, or (3) endurance requirement exceeds 12h | - -## Solar Augmentation — Assessment (Not Recommended) - -| Factor | Assessment | -|--------|-----------| -| Available wing area | ~0.7 m² usable upper surface | -| Solar power at altitude | ~35-40W average (Ukrainian latitude, 22% efficient flexible panels) | -| Endurance gain | +1.0-1.5h theoretical, but -0.5h from panel weight → net +0.5-1.0h | -| Cost | +$500-1,500 per unit for flexible panels | -| Complexity | Adds MPPT controller, fragile surface, weather dependency | -| Recommendation | Not worth the cost/complexity for ~1h marginal gain | - -## Testing Strategy - -### Integration / Functional Tests -- Static wing load test: 3× max flight load at spar joiner (verify no failure at 3g with 18 kg MTOW) -- Wing joint cycling: 100× assembly/disassembly, verify no wear (critical at higher loads) -- RF transparency test: measure GPS signal through airframe skin (target: < 3 dB attenuation) -- Assembly time test: verify < 12 minutes from transport case to flight-ready -- Battery wiring test: verify 2S2P balancing, measure voltage sag under load, test fail-safe (single pack disconnect) -- Range/endurance test: fly at cruise until 20% reserve, measure actual vs predicted -- Payload integration: electronics function under vibration at 18 kg flight loads - -### Non-Functional Tests -- Transport test: load 2 planes in pickup, drive 100 km on mixed roads, verify no damage -- Hard landing test: belly landing at 2.5 m/s descent (higher than Draft 02 due to heavier aircraft) -- Field repair test: wing skin puncture → FG patch + epoxy → airworthy in < 30 minutes -- Temperature test: battery + avionics at -10°C and +45°C -- Battery endurance test: 50 charge/discharge cycles on 4-battery 2S2P config, verify balanced degradation -- CG test: verify stable CG across all battery configurations (4-battery, 3-battery partial, 2-battery emergency) -- Emergency flight test: verify aircraft can fly safely on 2 batteries (reduced endurance) if 1 series pair fails - -## Production BOM: 5 UAVs From Scratch (8h Config) - -### A. One-Time Equipment & Tooling - -Same as Draft 02 base equipment: $3,335. Add: -| Item | Qty | Unit Price | Total | Notes | -|------|-----|-----------|-------|-------| -| Larger mold materials (4m wing + fuselage) | 1 set | $900 | $900 | MDF plugs + tooling epoxy for 3.8m molds | -| Aluminum spar joiner machining (7075, 12 sets) | 1 | $600 | $600 | Larger joiners, CNC outsourced | -| Battery parallel bus bar / wiring jig | 1 | $100 | $100 | For consistent 2S2P assembly | -| **Equipment & Tooling TOTAL** | | | **$4,935** | | - -### B. Raw Materials (5 UAVs + 20% waste) - -| Item | Qty (5 UAVs + margin) | Unit Price | Total | -|------|----------------------|-----------|-------| -| S2 fiberglass fabric 6oz | 100 yards | $12.50/yard | $1,250 | -| PVC foam Divinycell H60 10mm | 24 sheets | $40/sheet | $960 | -| Laminating epoxy resin | 6 gallons | $125/gal | $750 | -| Epoxy hardener | 3 gallons | $80/gal | $240 | -| Carbon fiber tube (spar, 25mm OD, 2.0m) | 12 | $35 each | $420 | -| Carbon fiber UD tape 25mm | 50 m | $5/m | $250 | -| Vacuum bagging consumables | — | — | $400 | -| Misc hardware | — | — | $250 | -| **Materials TOTAL (5 UAVs)** | | | **$4,520** | -| **Per UAV materials** | | | **~$904** | - -### C. Electronics & Propulsion (per UAV × 5) - -| Item | Per UAV | ×5 Total | -|------|---------|----------| -| Motor (T-Motor U8 Lite or equiv.) | $150 | $750 | -| ESC (80A) | $80 | $400 | -| Folding propeller 16×10 (2 per UAV) | $40 | $200 | -| Servos (6× digital metal gear) | $150 | $750 | -| Nav camera: ADTI 26S V1 + 35mm lens | $1,890 | $9,450 | -| AI camera: Viewpro Z40K 4K gimbal | $3,500 | $17,500 | -| Pixhawk 6X Mini + GPS | $380 | $1,900 | -| RC receiver (TBS Crossfire) | $60 | $300 | -| RFD900x telemetry | $170 air × 5 + $350 GCS | $1,200 | -| Power distribution + BEC | $30 | $150 | -| Wiring, connectors, battery bus | $80 | $400 | -| **Batteries: 4× Tattu 6S 33Ah 350 (per UAV)** | **$2,930** | **$14,650** | -| **Electronics TOTAL (5 UAVs)** | | **$47,650** | -| **Per UAV electronics** | | **~$9,530** | - -### D. Summary - -| Category | Total | Per UAV | -|----------|-------|---------| -| A. Equipment & Tooling | $4,935 | $987 | -| B. Raw Materials | $4,520 | $904 | -| C. Electronics & Propulsion | $47,650 | $9,530 | -| D. Consumables & Misc | $1,200 | $240 | -| E. Labor (est. same structure as Draft 02, +20%) | $19,176 | $3,835 | -| **GRAND TOTAL (5 UAVs)** | **$77,481** | | -| **Per UAV (all-in, with labor)** | | **$15,496** | -| **Per UAV (materials + electronics, no labor)** | | **$11,661** | - -The cost increase vs Draft 02 ($6,502/unit) is driven by cameras (+$2,391/unit: ADTI 26S replaces ADTI 20L, Z40K replaces A40 Pro), batteries (+$2,200/unit), and larger airframe (+$250/unit). Optional: swap to ADTI 61PRO (+$940/unit) for 15 cm/px nav GSD. - -## Risk Assessment - -| Risk | Impact | Probability | Mitigation | -|------|--------|------------|-----------| -| S2 FG airframe heavier than estimated → MTOW exceeded | Reduced endurance | Medium | Build weight tracking into construction; accept 18.5 kg MTOW if needed | -| 4-battery wiring complexity → connector failure | Loss of power pair | Low | Redundant connectors; test fail-safe on 2 batteries; parallel bus bar design | -| Semi-solid battery supply disruption | Cannot build | Low | Multiple suppliers (Tattu, Grepow, Xingto) | -| L/D lower than 17 in practice | Endurance drops to 7-7.5h | Medium | Use Xingto 370 Wh/kg for margin; optimize airfoil selection (SD7037 or AG series) | -| Wing flutter at 3.8m span | Structural failure | Low | Ground vibration test; CF spar sized for 1.5× flutter speed margin | -| CG shift with 4 battery packs | Controllability | Low | Fixed battery bay positions; CG calculated for all configurations | - -## References - -1-34: See Draft 01 and Draft 02 references (all still applicable) - -Additional sources: -35. DeltaQuad Evo 8h55m record: https://uasweekly.com/2025/06/27/deltaquad-evo-sets-record-with-8-hour-flight-endurance-for-electric-vtol-uas-milestone/ -36. Tulip Tech batteries: https://tulip.tech/batteries/ -37. DeltaQuad Evo specs: https://docs.deltaquad.com/tac/vehicle-specifications -38. DeltaQuad Evo performance calculator: https://evo.deltaquad.com/calc/ -39. YUAV Y37 specs: https://www.airmobi.com/yuav-y37-a-new-standard-in-long-endurance-vtol-fixed-wing-uavs/ -40. YUAV Y37 product page: https://www.airmobi.com/product/yuav-y37-3700mm-vtol-fixed-wing-uav-pnp/ -41. Tattu 350 Wh/kg 6S 33Ah: https://tattuworld.com/semi-solid-state-battery/semi-solid-350wh-kg-33000mah-22-2v-10c-6s-battery.html -42. Tattu 350 Wh/kg 12S 33Ah: https://tattuworld.com/semi-solid-state-battery/semi-solid-350wh-kg-33000mah-44-4v-10c-12s-battery.html -43. Tattu 330 Wh/kg 12S 76Ah: https://tattuworld.com/semi-solid-state-battery/semi-solid-330wh-kg-76000mah-44-4v-10c-12s-battery.html -44. Xingto 370 Wh/kg battery: https://www.xtbattery.com/370wh/kg-42v-high-energy-density-6s-12s-14s-18s-30ah-semi-solid-state-drone-battery/ -45. Amprius SA102 450 Wh/kg: https://amprius.com/the-all-new-amprius-500-wh-kg-battery-platform-is-here/ -46. Amprius UAV selection: https://amprius.com/amprius-high-power-silicon-batteries-selected-by-esaero-to-power-next-generation-uavs/ -47. NOCTUA hydrogen UAV: https://noctua.ethz.ch/technology -48. IE-SOAR 2.4 fuel cell: https://www.intelligent-energy.com/our-products/ie-soar-fuel-cells-for-uavs/ie-soar-2-4/ -49. IE-SOAR specs (retail): https://shop.thebioniceye.co.uk/products/ie-soar-2-4kw-hydrogen-fuel-cell -50. Doosan DS30W specs: https://www.doosanmobility.com/en/products/drone-ds30 -51. Cellen hydrogen refueling: https://cellenh2.com/reinventing-hydrogen-refueling-for-drones/ -52. Tattu battery catalog (pricing): https://rcdrone.top/collections/tattu-semi-solid-state-battery -53. Tattu 76Ah pricing (FlexRC): https://flexrc.com/product/tattu-semi-solid-state-330wh-kg-76000mah-10c-44-4v-12s1p-lipo-battery-pack-with-qs12-s-plug/ -54. JOUAV CW-80E: https://www.jouav.com/products/cw-80e.html -55. Discus 2b 4m glider: https://icare-rc.com/discus2b_4m.htm -56. Pickup bed dimensions: https://kevinsautos.com/faq/what-are-the-dimensions-of-a-65-foot-truck-bed.html -57. Tulip Tech Dutch MoD partnership: https://www.tulip.tech/news/ - -## Related Artifacts -- Previous drafts: `solution_draft01.md` (CFRP), `solution_draft02.md` (S2 FG, 3m, 10 kg) -- Research artifacts: `_standalone/UAV_frame_material/00_research/UAV_frame_material/` diff --git a/_standalone/UAV_frame_material/01_solution/solution_draft04.md b/_standalone/UAV_frame_material/01_solution/solution_draft04.md deleted file mode 100644 index aba7a88..0000000 --- a/_standalone/UAV_frame_material/01_solution/solution_draft04.md +++ /dev/null @@ -1,296 +0,0 @@ -# Solution Draft (Rev 04) — Launch & Recovery Assessment - -## Assessment Findings - -| Old Component Solution | Weak Point | New Solution | -|------------------------|------------|-------------| -| No launch/recovery method specified | Aircraft cannot operate without a defined takeoff/landing approach | Two viable options analyzed: Quad VTOL (recommended for field ops) or Catapult + Parachute (recommended for maximum endurance) | -| Y-3 tricopter VTOL (user proposed) | Zero motor redundancy, tilt servo failure risk, no production platforms use Y-3 | Quad (4+1) VTOL — industry standard used by DeltaQuad, YUAV Y37, WingtraOne | -| YUAV Y37 listed as 17-20 kg MTOW | Product page confirms TOW 22-26 kg; 10 kg empty weight with VTOL system | Corrected Y37 specs: TOW 22-26 kg, empty 10 kg (with VTOL), 4+1 config, $16,900 PNP | -| 18 kg MTOW design (Draft 03) | Cannot accommodate VTOL within 18 kg — VTOL system adds 2.5-3.2 kg | Option A: raise MTOW to 21-22 kg for VTOL variant; Option B: keep 18 kg for catapult variant | - -## Product Solution Description - -Two platform variants from the same S2 FG airframe, optimized for different operational needs: - -**Variant A — Quad VTOL** (recommended for forward/mobile operations): -Scaled-up modular S2 FG fixed-wing with 4+1 quadplane VTOL. Wingspan 3.8m, MTOW 21-22 kg. 4 dedicated VTOL motors on carbon fiber tube booms + 1 pusher for cruise. Separate VTOL battery (12S 5500 mAh). Endurance 6.5-7.5 hours. Launches and recovers from any 5m × 5m flat area. No ground equipment needed. - -**Variant B — Catapult + Parachute** (recommended for maximum endurance from established bases): -Same S2 FG fixed-wing, no VTOL hardware. Wingspan 3.8m, MTOW 18 kg. Pneumatic catapult launch (ELI PL-60 class). Parachute recovery (Fruity Chutes 20 kg bundle). Endurance 8-8.5 hours. Requires 108 kg catapult system and 8m launch space. - -``` -VARIANT A — QUAD VTOL (4+1) -┌───────────────────────────────────────────────────────────┐ -│ │ -│ VTOL Motor 1 VTOL Motor 2 │ -│ (front-left) (front-right) │ -│ ⟐ 15" prop ⟐ 15" prop │ -│ \ / │ -│ \ CF tube boom / │ -│ \ / │ -│ ┌────────────────────────────┐ │ -│ │ LEFT FUSELAGE RIGHT│ │ -│ │ WING [VTOL bat] WING │ │ -│ │ 1.9m [Cruise 1.9m │ │ -│ │ batteries] │ Pusher motor │ -│ │ [Payload] ─────┤────── ⊕ (cruise) │ -│ └────────────────────────────┘ │ -│ / \ │ -│ / CF tube boom \ │ -│ / \ │ -│ ⟐ 15" prop ⟐ 15" prop │ -│ VTOL Motor 3 VTOL Motor 4 │ -│ (rear-left) (rear-right) │ -│ │ -│ Motor booms: CF tubes (narrow, minimal RF impact) │ -│ Boom-wing joints: aluminum brackets with S2 FG layup │ -└───────────────────────────────────────────────────────────┘ - -VARIANT B — CATAPULT + PARACHUTE -┌───────────────────────────────────────────────────────────┐ -│ │ -│ ┌────────────────────────────┐ │ -│ │ LEFT FUSELAGE RIGHT│ │ -│ │ WING [Parachute WING │ │ -│ │ 1.9m bay + hatch] │ Pusher motor │ -│ │ [Cruise 1.9m │ │ -│ │ batteries] │ ⊕ (cruise) │ -│ │ [Payload] ─────┤─────── │ -│ └────────────────────────────┘ │ -│ │ -│ No motor booms = cleaner aerodynamics │ -│ Parachute bay with spring-loaded hatch (top/bottom) │ -│ Catapult carriage mounting rails on belly │ -└───────────────────────────────────────────────────────────┘ -``` - -## Why Not Y-3 (Tricopter)? - -The user asked specifically about Y-3 (3-motor) VTOL. After research, Y-3 is **not recommended** for this application: - -| Factor | Y-3 (Tricopter) | Quad (4+1) | -|--------|-----------------|------------| -| Weight saving vs quad | ~400g less | Baseline | -| Motor redundancy | **Zero** — any motor failure = crash | Partial — single motor loss survivable | -| Yaw control | Tilt servo on rear motor (mechanical failure point) | Differential thrust (no moving parts) | -| Production platforms using this | None found in 15-25 kg class | DeltaQuad, YUAV Y37, WingtraOne | -| ArduPilot support | Supported but less tested | Well-tested, widely deployed | -| Hover stability | Lower (3-point, asymmetric) | Higher (4-point, symmetric) | - -The 400g weight saving (~2% of MTOW) does not justify the reliability and redundancy loss. For a $15,000-17,000 aircraft in a conflict zone, motor redundancy is critical. - -## Architecture - -### Component: Launch & Recovery System - -| Solution | Weight on Aircraft | Ground Equipment | Endurance | Landing Precision | Cost (airborne) | Cost (ground) | Deployment Speed | Fit | -|----------|-------------------|-----------------|-----------|------------------|----------------|---------------|-----------------|-----| -| **Quad VTOL (recommended for field ops)** | +3.0-3.2 kg | None | 6.5-7.5h | 1-2m | $1,000-1,500 | $0 | < 2 min | ✅ Best for mobile ops | -| **Catapult + Parachute (recommended for max endurance)** | +0.95 kg | 108 kg catapult | 7.5-8.2h | 50-200m drift | $925 | $15,000-25,000 | 5-10 min | ✅ Best for endurance | -| Catapult + Belly landing | 0 kg | 108 kg catapult + 200m strip | 8-8.5h | On strip | $0 | $15,000-25,000 | 5-10 min + strip | ⚠️ Needs flat terrain | -| Y-3 VTOL | +2.5-2.7 kg | None | 7-7.5h | 1-2m | $800-1,200 | $0 | < 2 min | ❌ Reliability risk | - -### Component: VTOL System (Variant A — Quad) - -| Component | Specification | Weight | Cost | -|-----------|--------------|--------|------| -| VTOL motors (×4) | T-Motor MN505-S or equiv., ~5-6 kg thrust each on 15" prop | 880g total | $400-600 | -| VTOL ESCs (×4) | 40A BLHeli_32 or equiv. | 320g total | $120-200 | -| VTOL propellers (×4) | 15" folding (fold for cruise to reduce drag) | 200g total | $60-100 | -| Motor booms (×4) | Carbon fiber tubes 20mm OD, 400mm length + aluminum brackets | 700g total | $150-250 | -| VTOL battery | 12S 5500 mAh LiPo (dedicated) | 700g | $120-180 | -| Wiring + connectors | 12AWG silicone, XT60 connectors | 180g | $30-50 | -| **VTOL system total** | | **2,980g** | **$880-1,380** | - -### Component: Catapult System (Variant B) - -| Component | Specification | Weight/Size | Cost | -|-----------|--------------|-------------|------| -| Pneumatic catapult | ELI PL-60 or equivalent | 108 kg (2 cases) | $15,000-25,000 est. | -| Catapult carriage | Custom for UAV fuselage, quick-release | ~2 kg (stays on ground) | Included or $500 custom | -| Belly mounting rails | Aluminum rails on fuselage for carriage attachment | ~150g on aircraft | $50 | - -### Component: Parachute System (Variant B) - -| Component | Specification | Weight | Cost | -|-----------|--------------|--------|------| -| Fruity Chutes FW bundle 20 kg | IFC-120-S Iris Ultra + pilot chute + deployment bag + Y-harness | 950g | $925 | -| Servo-actuated hatch | Spring-loaded door on fuselage top/bottom, triggered by autopilot | 80g | $30 | -| **Recovery system total** | | **1,030g** | **$955** | - -## Updated Weight Budgets - -### Variant A — Quad VTOL (21 kg MTOW) - -| Component | Weight (kg) | Notes | -|-----------|-------------|-------| -| Airframe (S2 FG, 3.8m, reinforced for VTOL loads) | 6.0-7.0 | +0.5 kg structural reinforcement at boom attach points | -| Wing joints (aluminum 7075) | 0.35 | Same as Draft 03 | -| Motor (800W cruise) + ESC + prop | 0.65 | Slightly larger to handle higher MTOW | -| Wiring, connectors (cruise) | 0.45 | Same as Draft 03 | -| **VTOL system** | **2.98** | **4 motors, 4 ESCs, 4 props, booms, VTOL battery, wiring** | -| **Platform subtotal** | **10.4-11.4** | | -| Payload (cameras + compute) | 0.89 | Same as Draft 03 | -| Cruise battery (4× Tattu 6S 33Ah) | 8.86 | Same as Draft 03 | -| **Total** | **20.2-21.2** | | - -Conservative: 11.4 + 0.89 + 8.86 = **21.15 kg** (at 21 kg MTOW — tight) -Optimistic: 10.4 + 0.89 + 8.86 = **20.15 kg** (0.85 kg margin) - -**To fit 21 kg MTOW**: reduce to 3× cruise battery packs (6.65 kg, 2198 Wh) → total 18.9-19.9 kg → endurance ~5.5-6.5h. Or accept 22 kg MTOW → endurance ~6.5-7h with 4 packs. - -### Variant B — Catapult + Parachute (18 kg MTOW) - -| Component | Weight (kg) | Notes | -|-----------|-------------|-------| -| Airframe (S2 FG, 3.8m) | 5.5-6.5 | Same as Draft 03 | -| Wing joints (aluminum 7075) | 0.35 | Same | -| Motor (700W cruise) + ESC + prop | 0.6 | Same as Draft 03 | -| Wiring, connectors | 0.45 | Same | -| Catapult belly rails | 0.15 | Aluminum mounting interface | -| Parachute system | 1.03 | Chute + hatch mechanism | -| **Platform subtotal** | **8.1-9.1** | | -| Payload (cameras + compute) | 0.89 | Same | -| Cruise battery (4× Tattu 6S 33Ah) | 8.86 | Same | -| **Total** | **17.9-18.9** | | - -Conservative: 9.1 + 0.89 + 8.86 = **18.85 kg** (slightly over 18 kg; accept 19 kg MTOW or trim airframe) -Optimistic: 8.1 + 0.89 + 8.86 = **17.85 kg** (fits within 18 kg ✓) - -## Endurance Comparison - -### Variant A — Quad VTOL - -| MTOW | Battery Config | Usable Energy | Cruise Power | Endurance (practical) | -|------|---------------|--------------|-------------|----------------------| -| 21 kg | 4× 6S 33Ah (2930 Wh) | 2344 Wh | ~310W | **7.0-7.5h** | -| 22 kg | 4× 6S 33Ah (2930 Wh) | 2344 Wh | ~330W | **6.5-7.0h** | -| 20 kg | 3× 6S 33Ah (2198 Wh) | 1758 Wh | ~295W | **5.5-6.0h** | - -Cruise power increase vs Draft 03: higher MTOW (21-22 vs 18 kg) + ~3-5% additional drag from VTOL booms. - -P_cruise (21 kg) = (21 × 9.81 × 17) / (17 × 0.72) × 1.04 = ~310W (including boom drag penalty) - -### Variant B — Catapult + Parachute - -| MTOW | Battery Config | Usable Energy | Cruise Power | Endurance (practical) | -|------|---------------|--------------|-------------|----------------------| -| 18 kg | 4× 6S 33Ah (2930 Wh) | 2344 Wh | ~275W | **8.0-8.5h** | -| 19 kg | 4× 6S 33Ah (2930 Wh) | 2344 Wh | ~285W | **7.5-8.0h** | - -Parachute adds ~1 kg but no aerodynamic penalty (stowed internally). - -### Summary - -| Variant | MTOW | Endurance | vs Draft 03 (8-8.5h) | -|---------|------|-----------|---------------------| -| A: Quad VTOL (4 packs) | 21-22 kg | **6.5-7.5h** | -12-20% | -| A: Quad VTOL (3 packs) | 20 kg | **5.5-6.0h** | -30-35% | -| B: Catapult + Parachute | 18-19 kg | **7.5-8.5h** | -0-6% | -| B: Catapult + Belly | 18 kg | **8-8.5h** | 0% | - -## Cross-Validation Against YUAV Y37 - -The Y37 is the closest production reference for our VTOL variant: - -| Parameter | YUAV Y37 | Our Variant A (Quad VTOL) | Delta | -|-----------|----------|--------------------------|-------| -| Wingspan | 3.7m | 3.8m | +3% | -| Empty weight (with VTOL) | 10 kg | 10.4-11.4 kg | +4-14% (S2 FG heavier than carbon) | -| MTOW | 22-26 kg | 21-22 kg | Similar | -| Battery energy | 2700 Wh | 2930 Wh | +9% | -| Endurance (1 kg payload) | 8.5h | ~7h (est. at 0.89 kg payload) | -18% (S2 FG weight penalty) | -| Material | Full carbon | S2 FG + CF spar | S2 FG is ~2-3 kg heavier | -| RF transparent | No | Yes | Our advantage | -| Price (PNP) | $16,900 | ~$11,000-14,000 (DIY) | 18-35% cheaper | - -The 18% endurance gap between Y37 and our Variant A is primarily due to the S2 FG weight penalty (~2-3 kg heavier airframe). If RF transparency is not required, a carbon airframe would close this gap. - -## BOM Cost Impact (5 UAVs) - -### Variant A — Quad VTOL - -| Category | Total (5 UAVs) | Per UAV | vs Draft 03 | -|----------|----------------|---------|-------------| -| Draft 03 baseline | $77,481 | $15,496 | — | -| VTOL system hardware | $5,000-7,000 | $1,000-1,400 | +$1,000-1,400/unit | -| Structural reinforcement | $750 | $150 | +$150/unit | -| Larger cruise motor/ESC | $250 | $50 | +$50/unit | -| **Variant A total** | **$83,481-85,481** | **$16,696-17,096** | **+$1,200-1,600/unit** | - -### Variant B — Catapult + Parachute - -| Category | Total (5 UAVs) | Per UAV | vs Draft 03 | -|----------|----------------|---------|-------------| -| Draft 03 baseline | $77,481 | $15,496 | — | -| Parachute systems (×5) | $4,775 | $955 | +$955/unit | -| Catapult (ELI PL-60, ×1) | $15,000-25,000 | $3,000-5,000 (amortized) | +$3,000-5,000/unit | -| Belly rails + hatch mech. | $500 | $100 | +$100/unit | -| **Variant B total** | **$97,756-107,756** | **$19,551-21,551** | **+$4,055-6,055/unit** | - -**Key insight**: VTOL is cheaper per fleet. The catapult is expensive one-time equipment that only amortizes well over large fleets (20+ UAVs). - -## Recommendation Matrix - -| Operational Scenario | Recommended Variant | Rationale | -|---------------------|--------------------|-----------| -| **Mobile forward operations** (changing locations, no established base) | **A: Quad VTOL** | No ground equipment, instant deploy from any flat area, precision recovery | -| **Fixed base operations** (airfield or prepared area available) | **B: Catapult + Parachute** | Maximum endurance, no VTOL dead weight, lower per-unit complexity | -| **Mixed operations** (both scenarios) | **A: Quad VTOL** | VTOL works everywhere; endurance trade-off (6.5-7.5h vs 8h) is acceptable for operational flexibility | -| **Maximum endurance priority** (>8h critical) | **B: Catapult + Belly** | Zero weight penalty; but needs 200m landing strip | -| **Budget-constrained fleet** (5 units) | **A: Quad VTOL** | $83-85k total vs $98-108k for catapult variant | - -## Risk Assessment (New Items for Draft 04) - -| Risk | Impact | Probability | Mitigation | -|------|--------|------------|-----------| -| VTOL motor failure during hover landing | Aircraft loss ($17k) | Low | Quad config allows single-motor-out survival; redundant ESC power feeds | -| VTOL boom attachment failure on S2 FG | Boom separation → crash | Low | Aluminum through-bolt brackets; static load test to 5× hover thrust | -| Catapult malfunction | No launch capability | Low | Carry spare seals and Makita batteries; ELI PL-60 is simple design | -| Parachute deployment failure | Aircraft loss + ground damage | Very Low | Dual deployment triggers (autopilot + RC manual); pre-flight chute check | -| Wind drift on parachute recovery | UAV lands in inaccessible area | Medium | Select recovery area with margin; GPS tracking; contingency recovery team | -| VTOL adds drag → endurance less than calculated | Endurance only 6h instead of 7h | Medium | Folding VTOL props reduce cruise drag; boom fairing; accept margin | -| S2 FG structure insufficient for 21-22 kg VTOL loads | Structural failure | Low | Full FEA analysis; static wing load test at 3.5g; boom attachment cycling test | - -## Testing Strategy (Additions for Draft 04) - -### VTOL-Specific Tests (Variant A) -- Hover stability test: 60-second hover at 21 kg, measure motor temps and vibration -- Transition test: full transition from hover to cruise and back, measure altitude loss and energy -- Single-motor-out test: kill one VTOL motor at 30m altitude, verify safe emergency landing -- Boom attachment cycling: 200× VTOL power-on/off cycles, inspect boom joints for fatigue -- VTOL battery endurance: verify 2+ full VTOL cycles (takeoff + landing) on single charge -- Drag measurement: compare cruise power with VTOL booms vs clean airframe - -### Catapult-Specific Tests (Variant B) -- Catapult launch: 10 consecutive launches, verify consistent exit speed and UAV integrity -- Launch acceleration: measure g-forces on airframe and payload during catapult stroke -- Parachute deployment: 5 test deployments at various speeds and altitudes (min 50m AGL) -- Parachute reliability: 20 pack-deploy cycles, verify consistent opening -- Landing impact: verify payload cameras survive 4.6 m/s descent impact - -## References - -1-57: See Draft 03 references (all still applicable) - -Additional sources: -58. YUAV Y37 product page (updated specs): https://www.airmobi.com/product/yuav-y37-3700mm-vtol-fixed-wing-uav-pnp/ -59. YUAV Y37 engineering blog: https://www.airmobi.com/yuav-y37-a-new-standard-in-long-endurance-vtol-fixed-wing-uavs/ -60. DeltaQuad Evo TAC specs: https://docs.deltaquad.com/tac/vehicle-specifications -61. DeltaQuad Evo VTOL takeoff: https://docs.deltaquad.com/tac/flight/quick-takeoff/vtol-takeoff -62. ELI PL-60 pneumatic catapult: https://eli.ee/products/catapults/pl60/ -63. Fruity Chutes FW bundle 20 kg: https://shop.fruitychutes.com/products/fixed-wing-recovery-bundle-44lbs-20kg-15fps -64. Robonic pneumatic launcher advantages: https://www.robonic.fi/advantages-of-pneumatic-launch/ -65. Starlino power-to-thrust analysis: http://www.starlino.com/power2thrust.html -66. T-Motor U13II specs: https://store.tmotor.com/product/U13-v2-KV130-Power-Type-UAV-Motor.html -67. Belly landing research: https://www.scientific.net/AMM.842.178 -68. Aeromao Talon belly landing: https://aeromao.com/2018/10/18/talon-fully-autonomous-belly-landing/ -69. SCL bungee launcher specs: https://uascomponents.com/launch-and-landing-systems/bungee-catapult-scl2 -70. UkrSpecSystems SCL-1A: https://ukrspecsystems.com/uascomponents/bungee-uav-launching-system-scl-1a -71. VTOL weight penalty research: https://hal.science/hal-03832115v1/document -72. VTOL configuration endurance comparison: https://mediatum.ub.tum.de/1462822 - -## Related Artifacts -- Previous drafts: `solution_draft01.md` through `solution_draft03.md` -- Research artifacts: `_standalone/UAV_frame_material/00_research/UAV_frame_material/` diff --git a/_standalone/UAV_frame_material/01_solution/solution_draft05.md b/_standalone/UAV_frame_material/01_solution/solution_draft05.md deleted file mode 100644 index 54d6d06..0000000 --- a/_standalone/UAV_frame_material/01_solution/solution_draft05.md +++ /dev/null @@ -1,354 +0,0 @@ -# Solution Draft (Rev 05) — Reliability & Durability Assessment - -## Assessment Findings - -| Old Component Solution | Weak Point (functional/security/performance) | New Solution | -|------------------------|----------------------------------------------|-------------| -| Quad VTOL (Draft 04 Variant A) — reliability listed as "Low probability" motor failure | Motor/ESC failure during low-altitude hover (< 10m) is survivable at altitude but likely fatal below 10m; ArduPilot has no motor-out compensation for quadplane VTOL; ESC desync is dominant propulsion failure mode; 1-3 incidents expected per fleet lifetime | Risk reclassified: LOW per sortie but SIGNIFICANT over fleet lifetime; add ESC desync mitigation (low-ESR caps, DShot protocol); add VTOL battery health monitoring; consider redundant ESC feeds | -| Catapult+Parachute (Draft 04 Variant B) — camera damage risk not addressed | Belly-mounted Viewpro Z40K gimbal protruding 8-10cm below fuselage is directly vulnerable to parachute landing impact; wind increases impact energy 4× (190 J calm → 762 J at 8 m/s wind); post-landing drag abrades exposed components | **Semi-recessed gimbal mount** (recommended): mount Z40K in a 120mm-deep belly cavity with only ~40mm lens protrusion; fuselage structure acts as natural bumper. No retractable mechanism needed. Saves 150g and $100-200 vs retractable approach. Add replaceable belly panel + foam bumper around cavity opening | -| Draft 04 parachute landing analysis — calm-air only | Did not account for horizontal wind velocity during parachute descent; at 8 m/s wind, resultant velocity is 9.2 m/s (not 4.6 m/s), impact energy increases 4× | Revised landing energy analysis including wind scenarios; belly panel design must handle 762 J at moderate wind | -| Draft 04 risk matrix — qualitative only | No quantitative risk estimation over fleet lifetime | Added fleet-lifetime risk analysis: expected incidents, costs, and comparison for 5 UAVs × 300 sorties each | - -## Product Solution Description - -Two platform variants from the same S2 FG airframe with updated reliability assessment and camera protection requirements: - -**Variant A — Quad VTOL**: Higher-risk takeoff/landing phase (8 active electronic components during hover, ESC desync possible) but near-zero landing damage to aircraft and payload. Dominant risk: motor/ESC failure below 10m altitude. Estimated 1-3 propulsion incidents per 1,500 fleet sorties. - -**Variant B — Catapult + Parachute**: No powered hover risk. Passive parachute recovery is inherently reliable (>99% deployment success). Landing impact (190-762 J depending on wind) is manageable for S2 FG airframe. Camera protection achieved via **semi-recessed gimbal mount** — the same Viewpro Z40K mounted inside a belly cavity with only the lens ball protruding ~40mm, shielded by the fuselage structure. - -**Key reliability finding**: Both variants have comparable overall reliability when proper mitigations are applied. VTOL risks are **electronic/catastrophic** (rare but expensive). Catapult+parachute risks are **mechanical/incremental** (more frequent but cheaper and repairable). - -## Architecture - -### Component: VTOL Reliability System (Variant A) - -| Failure Mode | Probability (per sortie) | Consequence | Mitigation | Residual Risk | -|--------------|-------------------------|-------------|-----------|---------------| -| ESC desync during VTOL transition | 1 in 500-2,000 | Aircraft loss at low altitude | Low-ESR capacitors on each ESC; DShot protocol; rampup power tuning; fresh VTOL battery per sortie | Medium — hardware mitigation reduces but doesn't eliminate | -| Motor bearing failure during hover | 1 in 5,000+ | Aircraft loss at low altitude | Replace VTOL motors every 6 months (not 12); pre-flight motor spin test | Low | -| VTOL battery voltage sag | 1 in 200-500 (partial) | ESC desync trigger → motor stall | Dedicated VTOL battery; replace after 200 cycles; monitor internal resistance | Low-Medium | -| VTOL boom attachment fatigue | 1 in 2,000+ | Boom separation → crash | Aluminum through-bolt brackets; inspect every 50 sorties; cycling test per Draft 04 | Low | -| Single motor out at altitude (> 30m) | N/A | Degraded landing, likely survivable | 195% thrust on 3 motors; controlled descent possible with yaw sacrifice | Low — survivable | -| Single motor out at low altitude (< 10m) | N/A | Likely crash — < 2s reaction time | No firmware solution exists; this is an accepted residual risk of VTOL | **HIGH** — inherent to VTOL | - -**VTOL Reliability Enhancements (recommended additions to Draft 04):** - -| Enhancement | Weight | Cost | Benefit | -|-------------|--------|------|---------| -| Low-ESR capacitors (4×, on each ESC) | 40g | $20 | Reduces voltage noise → fewer ESC desyncs | -| DShot protocol (firmware config) | 0g | $0 | Digital ESC communication → no signal noise | -| Redundant ESC power feeds (dual BEC) | 30g | $40 | Prevents ESC brownout from single feed failure | -| VTOL battery health monitor (voltage + IR) | 10g | $15 | Alerts to degraded battery before failure | -| 6-month VTOL motor replacement (vs 12) | 0g | +$200-300/year per UAV | Halves motor wear risk | -| Pre-flight VTOL motor spin test (procedure) | 0g | $0 | Detects bearing wear, ESC issues before flight | -| **Total** | **80g** | **$75 initial + $200-300/year** | **~50% reduction in ESC desync risk** | - -### Component: Camera Mounting & Parachute Landing Protection (Variant B) - -#### Camera Mounting Options Comparison - -| Mounting Approach | Protrusion Below Belly | Camera Protection | Weight Impact | Cost | FoV | Complexity | Fit | -|-------------------|----------------------|-------------------|-------------|------|-----|-----------|-----| -| **Protruding gimbal (Draft 04)** | 8-10 cm | None — first ground contact point | 0g (baseline) | $0 | 360° pan, full tilt | Lowest | ❌ Incompatible with parachute recovery | -| **Retractable gimbal** | 0-8 cm (retracted/deployed) | Full when retracted | +150g (servo + rail) | +$100-200 | Same as protruding when deployed | Medium — moving parts, timing sequence | ⚠️ Works but adds complexity and failure mode | -| **Semi-recessed mount (recommended)** | ~4 cm (lens ball only) | High — fuselage structure is natural bumper | +50-80g (cavity reinforcing frame) | +$30-60 | ±60-70° pan, ±60° tilt | Lowest — no moving parts | ✅ Best balance of protection, simplicity, weight | -| **Fully recessed / internal turret** | 0 cm | Maximum | +100-200g (window + deeper cavity) | +$100-300 | Most restricted (±45° pan) | Low — but needs optical window | ⚠️ Best protection, but FoV too restricted | - -#### Semi-Recessed Gimbal Mount (Recommended) - -The same Viewpro Z40K (153 × 95.3 × 166mm, 595g) mounted inside a belly cavity rather than hanging below. The damping board attaches at the top of the cavity — same mounting hardware, same damping balls, no modifications to the camera itself. - -``` -SEMI-RECESSED Z40K — CROSS SECTION - -┌──────────────────────────────────────────────┐ -│ FUSELAGE (18-22cm deep) │ -│ │ -│ ═══════ Damping board + balls ════════ │ ← Same Z40K mounting hardware -│ │ │ │ -│ │ Z40K gimbal body │ │ -│ │ (153mm tall) │ │ ← Entire gimbal mechanism -│ │ 3-axis motors │ │ inside fuselage -│ │ CNC aluminum housing │ │ -│ │ │ │ -│ ══════╧══════════════════════════╧═══════ │ ← Belly skin with opening -│ reinforcing ┌──────────┐ reinforcing │ (~170×125mm cutout) -│ frame (FG) │ Lens ball │ frame (FG) │ -│ │ (~40mm │ │ -└────────────────│protrusion)│───────────────────┘ - └──────────┘ - ▲ - Only this part exposed to ground - Fuselage belly absorbs impact first -``` - -**Cavity specifications:** -- Depth: ~120mm (of 166mm total gimbal height) -- Opening: ~170 × 125mm (15mm clearance on each side of 153 × 95mm gimbal body) -- Reinforcing frame: S2 FG layup around cavity edges, ~50-80g -- Lens protrusion below belly: ~40-45mm -- Foam bumper strip around opening: EVA 15mm, ~30-50g - -**Why clearance matters:** 10-15mm gap between gimbal body and cavity walls prevents physical contact during vibration. If the gimbal touches the walls, aircraft vibration transmits directly to the camera sensor, defeating the damping system and causing jello/blur. - -#### Vibration & Stabilization Analysis - -Semi-recessed mounting does NOT degrade image stabilization — it improves it compared to a protruding mount: - -| Factor | Protruding Mount | Semi-Recessed Mount | -|--------|-----------------|-------------------| -| Pendulum arm length | 8-10 cm (full gimbal below belly) | ~4 cm (lens ball only) | -| Pendulum sway amplitude | Higher — longer arm amplifies aircraft oscillations | Lower — shorter arm, less amplification | -| Aerodynamic buffeting on gimbal | Full exposure to 17 m/s airflow | Shielded — gimbal body inside fuselage cavity | -| Turbulence source | Direct airflow on gimbal housing + arm | Minor cavity vortex only (blowing across opening) | -| Damping system function | Works as designed | Identical — same damping board, same balls | -| Active stabilization (3-axis) | ±0.02° — handles remaining vibration | ±0.02° — same; less input vibration to cancel | - -The Z40K's stabilization is a two-stage system: -1. **Passive** (damping balls/board): decouples gimbal from high-frequency aircraft vibration (motor buzz, prop harmonics). The "float" is intentional — do NOT rigidly fasten the camera to reduce wobble, as this defeats the passive stage and overloads the active stage. -2. **Active** (3-axis gimbal motors): cancels low-frequency movement (aircraft roll/pitch/yaw). Achieves ±0.02° precision. Works identically regardless of mounting position. - -If image wobble is observed, the correct fix is **at the vibration source** (balance propeller, soft-mount cruise motor, stiffen fuselage skin), not at the camera mount. Optionally, slightly stiffer damping balls (harder durometer) can reduce sway amplitude without compromising high-frequency isolation. - -#### Parachute Landing Failure Modes (with Semi-Recessed Mount) - -| Failure Mode | Probability (per sortie) | Consequence | Mitigation | Residual Risk | -|--------------|-------------------------|-------------|-----------|---------------| -| Parachute non-deployment | 1 in 200+ | Aircraft loss ($17k) | Dual triggers (autopilot + RC manual); spring-loaded hatch; pre-flight chute inspection | Very Low | -| Lens ball ground contact | 1 in 20-50 (moderate wind) | Lens scratch or crack ($200-500 lens replacement) | Foam bumper around cavity opening provides ~15mm standoff; belly skin contacts ground first | Low | -| Belly skin damage from landing impact | 1 in 5-20 | Cosmetic to minor structural ($200-500) | Replaceable belly panel; foam bumper strip | Low — acceptable wear | -| Post-landing drag in wind | 1 in 5-15 | Abrasion to skin, antennas | Parachute release mechanism; wind-aware recovery area selection. Semi-recessed camera NOT exposed to drag abrasion | Low-Medium | -| Landing in inaccessible terrain (wind drift) | 1 in 10-30 | Recovery difficulty, time loss | GPS tracking; plan recovery area with 300m margin; recovery team | Low-Medium | -| Parachute lines tangled on aircraft structure | 1 in 100+ | Incomplete chute inflation → hard landing | Clean exterior (semi-recessed camera reduces snag risk); proper packing | Very Low | -| Gimbal contacts cavity wall (vibration) | Continuous if undersized | Image quality degradation (jello, blur) | Maintain 10-15mm clearance on all sides; opening ~170×125mm for 153×95mm gimbal | Negligible with proper sizing | - -**Parachute Landing Protection (recommended additions to Draft 04):** - -| Enhancement | Weight | Cost | Benefit | -|-------------|--------|------|---------| -| **Semi-recessed gimbal cavity** (structural cutout + FG reinforcing frame) | +50-80g | $30-60 | Camera shielded by fuselage structure; no moving parts; no retraction mechanism needed | -| Replaceable belly panel (S2 FG sandwich, 2mm) | 0g (replaces existing skin section) | $50-100 per panel | Swap every 50-100 landings; absorbs cumulative impact | -| Belly foam bumper strip around cavity (EVA foam, 15mm) | 30-50g | $10 | Additional impact absorption + ~15mm standoff for lens ball | -| Parachute release mechanism (servo cutter) | 30g | $40 | Cuts risers after touchdown to prevent wind drag | -| **Total** | **110-160g** | **$130-210 initial** | **Camera protected; no moving parts; lighter and simpler than retractable** | - -Compared to retractable gimbal approach: **saves 100-150g, saves $70-140, eliminates retraction servo failure mode, no timing sequence needed.** - -#### FoV Trade-Off (Semi-Recessed) - -| Pan Angle | View Direction | Available? | Notes | -|-----------|---------------|-----------|-------| -| 0° (forward) | Along flight path | ✅ | Primary reconnaissance direction | -| ±30° | Forward oblique | ✅ | Full quality | -| ±60° | Side-looking | ✅ | Slight vignetting at cavity edge | -| ±70° | Wide oblique | ⚠️ | Cavity wall partially blocks — usable at reduced quality | -| ±90° (perpendicular) | Direct side | ❌ | Blocked by cavity wall | -| ±180° (rear) | Behind aircraft | ❌ | Blocked | - -For reconnaissance at 2 km altitude: ±60-70° pan covers a ground swath of ~4.6 km wide (±tan(70°) × 2 km). This is sufficient for most reconnaissance profiles. The 360° pan of a protruding gimbal is rarely used — the aircraft itself rotates to look at different areas. - -### Component: Catapult System Reliability - -| Failure Mode | Probability (per sortie) | Consequence | Mitigation | Residual Risk | -|--------------|-------------------------|-------------|-----------|---------------| -| Pressure seal leak | 1 in 500+ | Cannot launch → mission abort | Carry spare seals; pre-launch pressure test | Very Low | -| Carriage jam | 1 in 1,000+ | Cannot launch → mission abort | Pre-launch dry run; lubricant | Very Low | -| Battery depletion (Makita 18V) | Negligible | Cannot pressurize | Carry 2-3 spare Makita batteries ($30 each) | Negligible | -| Rail damage from transport | 1 in 200+ | Misaligned launch → UAV damage | Transport padding; pre-launch rail alignment check | Low | -| **Complete catapult failure** | **1 in 2,000+** | **Fleet grounded** | **Carry field repair kit; backup launch method (hand launch for reduced MTOW)** | **Low — SPOF** | - -## Reliability Comparison Matrix - -### Per-Sortie Risk - -| Risk Category | Quad VTOL (Variant A) | Catapult+Parachute (Variant B, with protection) | -|---------------|----------------------|------------------------------------------------| -| **Catastrophic aircraft loss** | 1 in 500-2,000 (motor/ESC fail during hover) | 1 in 200+ (parachute non-deploy) — but parachute is simpler and more reliable than 8 electronic components | -| **Camera/gimbal damage** | Near-zero | Very Low — lens scratch possible; semi-recessed mount shields gimbal body | -| **Airframe damage** | Near-zero | 1 in 5-20 (belly panel — cheap, replaceable) | -| **Mission abort (no aircraft loss)** | Near-zero | 1 in 500+ (catapult failure) | -| **Recovery difficulty** | Near-zero (precision 1-2m) | 1 in 10-30 (wind drift to awkward terrain) | - -### Fleet Lifetime Risk (5 UAVs × 300 sorties = 1,500 sorties) - -| Risk | VTOL Expected Cost | Catapult+Parachute Expected Cost | -|------|-------------------|--------------------------------| -| Aircraft loss (motor/ESC or chute failure) | 1-3 incidents × $17k = **$17,000-51,000** | 0-1 incident × $17k = **$0-17,000** | -| Camera damage (lens scratch/crack) | ~$0 | 0-3 × $300 = **$0-900** (lens replacement; gimbal body protected) | -| Belly panel replacements | ~$0 | 15-30 × $100 = **$1,500-3,000** | -| Catapult maintenance | $0 | 5 years × $750-1,250 = **$3,750-6,250** | -| VTOL motor replacements | 5 UAVs × 5 years × $300 = **$7,500** | $0 | -| **Total expected damage/maintenance cost** | **$24,500-58,500** | **$5,250-27,150** | - -### Reliability Verdict - -| Factor | VTOL | Catapult+Parachute | Winner | -|--------|------|-------------------|--------| -| Catastrophic failure risk (aircraft loss) | Higher — ESC desync during hover | Lower — parachute is passive/reliable | **Catapult+Parachute** | -| Camera/payload safety per landing | Better — precision soft landing | Good with semi-recessed mount; lens ball slightly exposed (~40mm) | **VTOL** (slight edge) | -| Airframe wear per landing | Better — no ground impact | Worse — 190-762 J per landing, cumulative | **VTOL** | -| System complexity (failure points) | Worse — 8 additional electronic components | Better — passive parachute + simple mechanical catapult | **Catapult+Parachute** | -| Single point of failure | None (distributed) | Catapult (fleet grounded if broken) | **VTOL** | -| Maintenance cost over 5 years | Higher ($7,500 motor replacements) | Lower ($5,250-6,250 panels + catapult) | **Catapult+Parachute** | -| Failure consequence type | Catastrophic (aircraft loss) | Incremental (repairable damage) | **Catapult+Parachute** | -| Fleet lifetime expected cost | $24,500-58,500 | $5,250-27,150 | **Catapult+Parachute** | - -## Parachute Landing — Wind Impact Analysis (New) - -Draft 04 analyzed only calm-air parachute landing (4.6 m/s vertical, 190 J). Real-world wind significantly changes the picture: - -| Wind Speed | Horizontal Drift (100m deploy) | Resultant Velocity | Impact Energy | Damage Profile | -|------------|-------------------------------|-------------------|---------------|----------------| -| Calm (0 m/s) | 10-20m | 4.6 m/s | 190 J | Vertical drop — belly panel absorbs | -| Light (5 m/s) | 110m | 6.8 m/s | 416 J | Angled impact — sliding risk | -| Moderate (8 m/s) | 176m | 9.2 m/s | 762 J | Hard angled impact — tumbling likely | -| Strong (12 m/s) | 264m | 12.9 m/s | 1,499 J | Severe — airframe structural risk | -| DeltaQuad max VTOL wind | — | — | — | 12.5 m/s (VTOL limited too) | - -**Key insight**: At moderate wind (8 m/s), parachute landing energy is 4× calm-air estimate. Belly panel and protection systems must be designed for moderate wind case (762 J), not calm-air (190 J). - -At strong wind (12 m/s), parachute landing becomes dangerous — but VTOL hover is also marginal at 12+ m/s wind. Both systems have degraded reliability in strong wind. - -**Mitigation for wind**: Deploy parachute at higher altitude (200m) to give more time for wind assessment; choose recovery area downwind with soft terrain; auto-release parachute risers after touchdown to prevent drag. - -## Updated Weight Budgets - -### Variant A — Quad VTOL (21 kg MTOW) — with reliability enhancements - -| Component | Weight (kg) | Change from Draft 04 | -|-----------|-------------|---------------------| -| Draft 04 Variant A total | 20.2-21.2 | — | -| ESC capacitors (4×) | +0.04 | New | -| Redundant BEC | +0.03 | New | -| Battery health monitor | +0.01 | New | -| **Revised total** | **20.3-21.3** | **+80g** (negligible) | - -### Variant B — Catapult + Parachute (18 kg MTOW) — with semi-recessed camera mount - -| Component | Weight (kg) | Change from Draft 04 | -|-----------|-------------|---------------------| -| Draft 04 Variant B total | 17.9-18.9 | — | -| Semi-recessed cavity reinforcing frame | +0.05-0.08 | New (replaces retractable mechanism) | -| Belly foam bumper around cavity | +0.03-0.05 | New | -| Parachute riser cutter | +0.03 | New | -| **Revised total** | **18.0-19.1** | **+110-160g** | - -At 19.1 kg conservative: slightly over 18 kg MTOW. Options: accept 19 kg MTOW (minimal endurance impact: ~7.5-8.0h) or trim 160g from airframe. Saves 100-150g vs retractable gimbal approach. - -## Updated Cost Impact - -### Variant A — VTOL reliability enhancements - -| Item | Per UAV | ×5 Fleet | -|------|---------|----------| -| Draft 04 Variant A total | $16,696-17,096 | $83,481-85,481 | -| ESC capacitors + BEC + monitor | $75 | $375 | -| Annual VTOL motor replacement (5 years) | $300/year | $7,500 total | -| **Revised total (5-year)** | | **$91,356-93,356** | - -### Variant B — Catapult+Parachute with semi-recessed camera mount - -| Item | Per UAV | ×5 Fleet | -|------|---------|----------| -| Draft 04 Variant B total | $19,551-21,551 | $97,756-107,756 | -| Semi-recessed cavity (reinforcing frame, built into airframe) | $40 | $200 | -| Belly bumper + riser cutter | $50 | $250 | -| Replacement belly panels (5 years) | $500 | $2,500 | -| **Revised total (5-year)** | | **$100,706-110,706** | - -## Recommendation — Updated - -| Operational Scenario | Recommended | Rationale (Reliability Focus) | -|---------------------|-------------|------------------------------| -| **Maximum reliability, accept ground equipment** | **B: Catapult+Parachute** (with semi-recessed gimbal) | Lower probability of catastrophic loss; failure modes are incremental/repairable; passive parachute has fewer electronic failure points | -| **Maximum operational flexibility, accept higher risk** | **A: Quad VTOL** (with reliability enhancements) | No ground equipment SPOF; precision landing protects payload; accepts 1-3 motor/ESC incidents per fleet lifetime | -| **Highest-value payloads (expensive cameras)** | **A: Quad VTOL** | Near-zero camera damage per landing; semi-recessed mount for parachute variant is good but lens ball still slightly exposed | -| **Budget-constrained operations** | **A: Quad VTOL** | Lower 5-year fleet cost ($91k vs $101k) despite higher aircraft loss risk | -| **Risk-averse operations (conflict zone, irreplaceable assets)** | **B: Catapult+Parachute** | Each UAV is $17k in a supply-constrained environment; losing fewer aircraft matters more than operational convenience | - -## Answer to User's Questions - -**1. "VTOL can suddenly break during faulty of 1 of the motor during takeoff or landing"** - -**Confirmed risk.** ESC desync is the most common propulsion failure mode and is triggered by exactly the conditions present during VTOL hover: sudden throttle changes, high current draw, voltage sag. Quad configuration provides partial redundancy at altitude (> 30m) but is likely fatal below 10m due to < 2 seconds reaction time. ArduPilot quadplane firmware has no built-in single motor failure compensation. Over 1,500 fleet sorties, 1-3 such incidents are plausible. Each incident at low altitude = ~$17k aircraft loss. - -**Mitigations**: Low-ESR capacitors, DShot protocol, fresh VTOL battery per sortie, 6-month motor replacement interval, pre-flight motor spin test. These reduce but do not eliminate the risk. - -**2. "Landing on the parachute can damage the UAV, especially having sticking out AI camera on the gimbal"** - -**Confirmed risk, but solvable.** A belly-mounted protruding gimbal like the Viewpro Z40K hanging 8-10cm below the fuselage IS highly vulnerable during parachute landing — it will be the first ground contact point. In wind, impact energy increases 4× (190 J → 762 J at 8 m/s wind). Post-landing drag from the parachute can cause additional abrasion damage. - -**Recommended solution: Semi-recessed gimbal mount.** Mount the same Z40K inside a 120mm-deep belly cavity using its standard damping board. Only the lens ball protrudes ~40mm below belly. The fuselage structure around the cavity acts as a natural bumper — the belly skin contacts the ground first, not the camera. This approach: -- Needs NO retractable mechanism (no moving parts, no timing sequence, no servo failure mode) -- Saves 100-150g and $70-140 compared to retractable approach -- Provides better vibration isolation than protruding mount (shorter pendulum arm, wind shielding inside cavity) -- Restricts FoV to ±60-70° pan (vs 360° protruding) — sufficient for reconnaissance at 2 km altitude -- Small residual risk: lens ball scratch in rough terrain or tumbling landing — replaceable lens ($200-300) - -The S2 FG airframe itself handles parachute landing forces well — a replaceable belly panel ($50-100) absorbs cumulative wear. - -**3. "It depends on the actual camera design and position of the parachute"** - -**Correct.** The damage risk is entirely design-dependent. Camera mounting options ranked by parachute landing compatibility: - -| Mounting | Landing Damage Risk | Notes | -|----------|-------------------|-------| -| Protruding gimbal (8-10cm below belly) | **HIGH** | First ground contact; incompatible with parachute recovery | -| **Semi-recessed mount (recommended)** | **LOW** | Fuselage shields gimbal body; only lens ball slightly exposed (~40mm) | -| Retractable gimbal | **VERY LOW** | Works but adds 150g, $100-200, and retraction servo failure mode | -| Internal turret with window | **NEAR-ZERO** | Maximum protection but limits FoV and adds optical window | - -Parachute Y-harness at CG → default nose-down attitude → further protects belly-mounted components since the nose contacts ground first. Semi-recessed mount combined with nose-down harness attitude gives excellent camera protection with no moving parts. - -**Important: do NOT rigidly fasten the camera** to reduce perceived wobble. The damping balls/board are intentional passive isolation. Rigid mounting defeats vibration isolation and causes jello/blur. If wobble is observed, fix at the source: balance propeller, soft-mount cruise motor. The Z40K's 3-axis stabilization (±0.02°) handles the rest. - -## Testing Strategy (Additions for Draft 05) - -### VTOL Reliability Tests -- ESC desync provocation test: induce voltage sag on VTOL battery during hover at 30m, verify no desync with mitigation hardware -- Single motor shutdown test: kill one motor at 30m altitude, measure altitude loss and control degradation -- Motor thermal endurance: 10× back-to-back VTOL cycles, monitor motor temperatures and ESC performance -- VTOL battery degradation test: track VTOL battery internal resistance over 200 cycles, correlate with ESC performance - -### Parachute Landing & Semi-Recessed Camera Tests -- Cavity clearance verification: confirm 10-15mm gap on all sides between Z40K body and cavity walls at all gimbal angles; verify no physical contact during flight vibration -- Image quality comparison: fly same route with protruding mount vs semi-recessed mount, compare stabilization performance and image sharpness -- Wind landing impact: drop UAV from 1.5m with 5 m/s horizontal velocity onto grass/dirt, verify lens ball clearance and belly panel integrity -- Lens ball contact test: drop UAV belly-first from 0.5m onto gravel, inspect lens ball for damage — establish whether foam bumper standoff is sufficient -- Belly panel replacement: verify panel swap in < 10 minutes with field tools -- Parachute riser cutter: 20× cut tests, verify clean separation within 3 seconds of touchdown -- Drag abrasion test: drag UAV 5m across gravel with parachute attached, verify semi-recessed camera is not damaged (vs protruding gimbal baseline) -- Cavity turbulence test: smoke visualization or tuft test at cruise speed to verify no harmful vortex inside cavity - -## References - -1-72: See Draft 04 references (all still applicable) - -Additional sources: -73. ArduPilot quadplane reliability tips: https://ardupilot.org/plane/docs/quadplane-reliability.html -74. DeltaQuad Evo preventative maintenance: https://docs.deltaquad.com/tac/maintenance/preventative-maintenance -75. Brushless motor lifespan: https://www.mepsking.shop/blog/how-long-do-brushless-drone-motors-last.html -76. ESC desync diagnosis: https://oscarliang.com/fix-esc-desync/ -77. ESC common faults: https://www.mepsking.com/blog/esc-faults-and-fixes-for-fpv-drones.html -78. Fruity Chutes parachute integration guide: https://fruitychutes.com/uav_rpv_drone_recovery_parachutes/integrating-a-drone-parachute -79. UAS recovery tutorial: https://fruitychutes.com/uav_rpv_drone_recovery_parachutes/uas-parachute-recovery-tutorial -80. DRS-25 parachute system: https://harrisaerial.com/drs-25-drone-parachute-recovery-system-15-25-kg-uav/ -81. ScanEagle 150,000 hours: https://boeing.mediaroom.com/2009-04-13-Boeing-Insitu-ScanEagle-Logs-150-000-Service-Hours-in-Iraq-and-Afghanistan -82. ScanEagle 1,500 recoveries: http://www.globalsecurity.org/intell/library/news/2009/intell-090107-boeing01.htm -83. Drone impact energy transfer study: https://pmc.ncbi.nlm.nih.gov/articles/PMC12900295/ -84. Aludra SR-10 parachute performance: https://files.core.ac.uk/download/478919988.pdf -85. Runway-free recovery methods review: https://www.mdpi.com/2504-446X/8/9/463 -86. ViewPro Z40K manual: https://www.manualslib.com/manual/2385515/Viewpro-Z40k.html -87. Parachute repositioning event design: https://airborne-sys.com/wp-content/uploads/2016/10/aiaa-2009-2911_basic_design_of_a_reposit.pdf -88. UAV payload retraction patent: https://patents.justia.com/patent/11975867 -89. ArduPilot landing gear retraction: https://ardupilot.org/plane/docs/common-landing-gear.html -90. NASA eVTOL propulsion reliability: https://ntrs.nasa.gov/citations/20240005899 -91. Multi-rotor UAV fault tree reliability analysis: https://link.springer.com/chapter/10.1007/978-981-10-6553-8_100 -92. ArduPilot thrust loss/yaw imbalance detection: https://ardupilot.org/copter/docs/thrust_loss_yaw_imbalance.html -93. ViewPro Z40K dimensions/specs (RCDrone): https://rcdrone.top/products/viewpro-z40k-4k-gimbal-camera -94. ViewPro Z40K manufacturer specs (ViewproUAV): https://www.viewprouav.com/product/z40k-single-4k-hd-25-times-zoom-gimbal-camera-3-axis-gimbal-uav-aerial-photography-cartography-and-patrol-inspection.html - -## Related Artifacts -- Previous drafts: `solution_draft01.md` through `solution_draft04.md` -- Research artifacts: `_standalone/UAV_frame_material/00_research/UAV_frame_material/` diff --git a/_standalone/UAV_frame_material/01_solution/solution_draft06.md b/_standalone/UAV_frame_material/01_solution/solution_draft06.md deleted file mode 100644 index 91e3858..0000000 --- a/_standalone/UAV_frame_material/01_solution/solution_draft06.md +++ /dev/null @@ -1,206 +0,0 @@ -# Solution Draft (Rev 06) — Material Comparison: S2 FG + Carbon Stiffeners vs Shark M (Pure GFRP) - -## Assessment Findings - - -| Old Component Solution | Weak Point (functional/security/performance) | New Solution | -| -------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| S2 FG fuselage with carbon fiber stiffeners (Drafts 01-05) — radio transparency not analyzed | Carbon fiber stiffeners provide 30-52 dB RF shielding, creating localized RF shadow zones inside the fuselage; antenna placement is constrained to FG-only zones between stiffeners; for a multi-antenna UAV (C2, video, GPS, telemetry) this creates spatial planning complexity | Two options evaluated: (1) retain hybrid but engineer antenna placement around CF zones, or (2) switch to pure GFRP (Shark M approach) eliminating all RF constraints | -| S2 FG + CF stiffeners — parachute landing BVID risk not analyzed | Carbon fiber stiffeners fail brittlely under impact (sudden delamination); after repeated parachute landings (190-762 J per landing), CF stiffeners accumulate invisible internal damage (BVID) detectable only by ultrasonic NDT — impractical in field conditions | Pure GFRP approach eliminates BVID risk entirely; all damage is visible and field-inspectable; Shark M validates this approach with 50,000+ operational hours including thousands of parachute landings | -| S2 FG + CF stiffeners — radar signature not analyzed | CF stiffeners are conductive and reflect radar energy; a regular geometric pattern of CF ribs inside a GFRP skin creates a partial radar reflector, slightly increasing RCS vs pure GFRP | Pure GFRP airframe is radar-transparent; RCS limited to metallic internals (engine, servos, connectors) only; this is exactly how Shark M achieves "low radar visibility" per Ukrspecsystems | - - -## Shark M Material Identification - -The Shark M's fuselage material is not publicly disclosed by Ukrspecsystems. However, convergent evidence strongly indicates **pure GFRP (glass fiber reinforced polymer)** — likely E-glass or S-glass fiberglass with epoxy resin: - - -| Evidence | Implication | -| ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | -| PD-2 datasheet states "fully composite airframe" + "absence of large metal parts" → "low radar visibility" | Low radar visibility via material transparency = non-conductive composite = GFRP, not CFRP | -| Shark M achieves 180 km communication range through fuselage (Silvus modem) | Fuselage must be RF-transparent; CF would block signals (30-52 dB shielding) | -| User confirms from experience: "no issues with radiotransparency, cause it is still alive" | Direct field validation of RF transparency through airframe | -| UAVs in this class (10-15 kg MTOW) commonly use fiberglass composite | Industry norm for this weight/mission class | -| Ukrspecsystems claims "low radar visibility" specifically from "fully composite airframe" | Stealth through radar transparency (GFRP property), not radar absorption | - - -**Confidence**: ⚠️ Medium-High. Not officially confirmed, but all available evidence points to GFRP. No evidence contradicts this conclusion. - -## Product Solution Description - -Material comparison between three airframe construction approaches for a reconnaissance UAV (18 kg MTOW, catapult + parachute recovery): - -**Approach A — S2 Fiberglass + Carbon Fiber Stiffeners (full hybrid)** -S2 FG fuselage skins with carbon fiber unidirectional strips as wing spars, fuselage longerons, and key structural stiffeners. Combines FG impact tolerance with CF stiffness-to-weight efficiency. Requires engineered antenna placement to avoid CF-induced RF shadows. - -**Approach B — Pure GFRP (Shark M style)** -All-fiberglass construction (E-glass or S2-glass with epoxy). Thicker skins and/or foam-core sandwich panels compensate for lower stiffness. Entire airframe is RF-transparent and radar-transparent. Heavier than hybrid, but eliminates all CF-related complications. - -**Approach C — S2 GFRP + CF Wing Spar Only (recommended)** -S2 FG for all skins, fuselage structure, ribs, and secondary stiffeners. Carbon fiber used only for the main wing spar (one per wing half). The CF spar runs spanwise through the wing and connects at the fuselage center section, acting as the structural backbone: it provides wing flutter resistance, resists fuselage torsion and bending at the wing root junction, and stiffens the overall airframe. All antennas are in the fuselage — the wing spar creates no RF shadow in communication paths. BVID risk is limited to two non-impact-zone elements. Recovers ~200-400g of the pure GFRP weight penalty. - -## Architecture - -### Component: Airframe Material System - - -| Dimension | S2 FG + CF Stiffeners (A) | Pure GFRP (B, Shark M) | Winner | -| -------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | -------------- | -| **Radio transparency** | Partial — FG zones are RF-transparent; CF stiffeners block 30-52 dB; antenna placement constrained | Full — entire fuselage passes RF; antenna placement unconstrained; validated at 180 km range | **B** | -| **Radar transparency (stealth)** | Partial — CF elements reflect radar; slight RCS increase from conductive stiffener grid | Full — GFRP is radar-transparent; RCS from internals only; validated in combat ("low radar visibility") | **B** | -| **Single-impact survivability** | Good — S2 FG skin absorbs well, but CF stiffeners may crack/delaminate under localized loads | Good — all-FG flexes and absorbs; no brittle failure modes; graceful degradation | **B** (slight) | -| **Cumulative landing damage** | Risk — CF stiffener micro-delamination after repeated landings; BVID invisible without ultrasonic NDT | Safe — all damage visible; simple visual inspection per landing; no hidden degradation | **B** | -| **Weight efficiency** | Better — CF stiffeners save est. 300-800g over equivalent FG stiffening for same structural performance | Heavier — must use thicker skins, foam sandwich, or more ribs; est. 300-800g penalty | **A** | -| **Structural stiffness** | Higher — CF is ~5× stiffer per unit weight; wing flutter resistance superior | Lower — FG is more flexible; adequate for Shark M class (3.4m wingspan) but needs design compensation | **A** | -| **Material cost** | Higher — CF cloth 5-10× more expensive than FG; moderate total increase (CF only in stiffeners, ~$100-300 extra) | Lower — all FG; cheapest composite option | **B** | -| **Manufacturing simplicity** | Moderate — two material systems require different layup procedures; CF needs precise fiber alignment | Simple — single material system; one set of procedures; easier quality control | **B** | -| **Field repairability** | Partial — FG skin: easy field repair; CF stiffeners: needs specialized skills, vacuum bagging, controlled cure | Full — all components repairable with basic epoxy + FG cloth patches; average manual skills sufficient | **B** | -| **Field inspection** | Hard — CF stiffener BVID requires ultrasonic NDT equipment (impractical in field) | Easy — visual inspection + tap test; no specialized equipment | **B** | -| **Combat-proven track record** | None — novel approach, untested in operational service | Extensive — Shark M: 50,000+ operational hours, 1,200h maintenance-free, combat-validated parachute landings | **B** | -| **Endurance impact** | Baseline — lighter airframe → est. 6-24 min additional flight time (~1-5% of 7-8h mission) | Heavier by 300-800g → 6-24 min less flight time; Shark M achieves 7h with pure GFRP at 14.5 kg | **A** (modest) | -| **Vibration damping** | Lower — CF is stiffer but transmits more high-frequency vibration | Better — hybrid composites show higher damping factors; FG naturally dampens vibration | **B** (slight) | - - -**Score: Approach A wins 2.5 dimensions, Approach B wins 10.5 dimensions.** - -### Component: Approach C — S2 GFRP + CF Wing Spar Only (Recommended Compromise) - -Approach C takes the best of both worlds. The CF wing spar is the single highest-value use of carbon fiber in the airframe: - -| Dimension | Approach C vs Pure GFRP (B) | Approach C vs Full Hybrid (A) | -|-----------|---------------------------|------------------------------| -| **Radio transparency** | Identical in practice — spar is in the wing, not in fuselage antenna paths | Much better — no CF in fuselage; no antenna placement constraints | -| **Radar transparency** | Negligible RCS from two spar elements buried inside wing structure | Better — no CF grid pattern in fuselage | -| **Parachute landing BVID** | Negligible — wing spars don't take direct ground impact; shock attenuated through wing root | Much better — no CF in belly/fuselage impact zone | -| **Weight** | ~200-400g lighter (CF spar vs equivalent FG spar) | ~100-400g heavier (no CF fuselage stiffeners) | -| **Structural stiffness** | Significantly better — CF spar stiffens the entire airframe: wing bending, fuselage torsion at wing root, overall rigidity | Slightly lower — no fuselage longerons, but spar carry-through compensates at the critical center section | -| **Flutter resistance** | Same as full hybrid — CF spar is the primary flutter prevention element | Same | -| **Field repairability** | FG fuselage fully field-repairable; CF spar damage is rare (no impact exposure) and would require return to base | Better than full hybrid — only 2 CF elements vs many | -| **Manufacturing** | Simpler than full hybrid — CF layup only for two spar elements; everything else is single-material FG | Simpler | -| **Cost** | ~$50-150 more than pure GFRP (two CF spar elements) | ~$50-150 cheaper than full hybrid | - -**Why the CF spar stiffens the whole airframe**: The wing spar is not just a wing element — it runs through or connects at the fuselage center section (wing root junction). This junction is the highest-stress point on the airframe. A stiff CF spar at this junction: -- Resists wing bending under gust loads and maneuvers -- Prevents fuselage torsion (twisting) caused by asymmetric wing loading -- Acts as a rigid backbone that the FG fuselage shell wraps around -- Increases the natural frequency of the airframe, pushing flutter speed higher - -The result: the airframe behaves nearly as stiff as the full hybrid (Approach A) for the loads that matter most, while the fuselage remains pure FG with all its RF and impact advantages. - -**Weight budget for Approach C** (18 kg MTOW, 3.4m wingspan): - -| Component | Approach A (full hybrid) | Approach B (pure GFRP) | Approach C (FG + CF spar) | -|-----------|------------------------|----------------------|--------------------------| -| Wing spar (both halves) | CF: 150-250g | S2 FG: 400-600g | CF: 150-250g | -| Fuselage stiffeners | CF: 200-400g | S2 FG: 400-600g | S2 FG: 400-600g | -| Skins + ribs | S2 FG: 3.5-4.0 kg | S2 FG: 3.8-4.2 kg | S2 FG: 3.8-4.2 kg | -| **Total airframe** | **~4.5-5.0 kg** | **~5.0-5.8 kg** | **~4.7-5.4 kg** | -| **vs full hybrid** | Baseline | +500-800g | **+200-400g** | -| **Endurance impact** | Baseline (~7.5-8h) | -15-24 min | **-6-12 min** | - -### Radio Transparency — Detailed Analysis - - -| Frequency Band | Use | S2 FG + CF Stiffeners | Pure GFRP | -| --------------------- | ----------------- | --------------------------------------------------------------- | -------------------------------------------------------- | -| 900 MHz (Silvus) | C2 datalink | Passes through FG skin; CF stiffeners block directional sectors | Passes through entire fuselage; omnidirectional coverage | -| 1.575 GHz (GPS L1) | Navigation | GPS antenna must be on top, away from CF elements; workable | No constraints; GPS antenna anywhere on upper fuselage | -| 2.4 GHz (backup link) | Telemetry/control | ~30 dB blockage through CF; FG zones OK | Full transparency | -| 5.8 GHz (video) | HD video downlink | Higher frequency → more susceptible to CF blockage | Full transparency | - - -**Key insight**: The hybrid approach works if antennas are carefully placed in FG-only zones. But this constrains the internal layout and means that if a stiffener is later moved (design iteration), antenna placement must be re-validated. Pure GFRP gives antenna engineers complete freedom. - -### Parachute Landing — Material Behavior Under Repeated Impact - - -| Landing # | S2 FG + CF Stiffeners | Pure GFRP | -| --------- | --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | -| 1-50 | Both perform well; no visible damage in calm/light wind | Same | -| 50-100 | FG belly panels show wear; CF stiffeners accumulate micro-stress | FG belly panels show same wear; FG stiffeners flex and reset | -| 100-200 | CF stiffener BVID possible; invisible without NDT; structural margin unknown | FG damage remains visible; operator can track degradation | -| 200-500 | Risk of sudden CF stiffener failure from accumulated BVID → catastrophic structural failure during flight | FG degrades gracefully; worn components replaced based on visual inspection | - - -**Key insight**: The failure mode difference is critical. CF stiffener failure is **sudden and catastrophic** (delamination → loss of structural integrity → possible in-flight breakup). FG failure is **gradual and visible** (cracking → flexibility → obvious degradation → scheduled replacement). - -### Weight Trade-Off Quantification - -For an 18 kg MTOW UAV with 3.4m wingspan: - - -| Stiffening Approach | Estimated Airframe Weight | Weight vs Full Hybrid | Endurance Impact | -|---------------------|--------------------------|----------------------|------------------| -| Approach A: S2 FG skin + CF stiffeners (full hybrid) | ~4.5-5.0 kg | Baseline | Baseline (est. 7.5-8h) | -| **Approach C: S2 FG skin + CF wing spar only (recommended)** | **~4.7-5.4 kg** | **+200-400g** | **-6-12 min (~1-3%)** | -| Approach B: S2 FG skin + S2 FG stiffeners (pure S2 FG) | ~5.0-5.8 kg | +500-800g | -15-24 min (~3-5%) | -| E-glass skin + E-glass stiffeners (pure E-glass, likely Shark M) | ~5.2-6.0 kg | +700-1000g | -20-30 min (~4-6%) | - -**Note**: Shark M achieves 7h at 14.5 kg MTOW with pure GFRP. The user's UAV at 18 kg MTOW has ~3.5 kg more budget. Approach C costs only 200-400g and 6-12 minutes vs the full hybrid — a minor trade for the operational benefits gained. - -## Recommendation - - -| Scenario | Recommended | Rationale | -|----------|-------------|-----------| -| **Military reconnaissance, parachute landing, EW-contested** | **Approach C: S2 GFRP + CF wing spar only** | Near-full radio + radar transparency (CF only in wings, away from antennas); no BVID risk in impact zone; field-repairable fuselage; CF spar stiffens entire airframe including fuselage torsion; only 200-400g heavier than full hybrid; 6-12 min endurance cost is acceptable | -| **Absolute maximum RF transparency required** | Approach B: Pure GFRP | Eliminates all CF; 100% RF/radar transparent; validated by Shark M; 500-800g heavier than full hybrid | -| **Maximum endurance priority, VTOL landing (no parachute)** | Approach A: S2 FG + CF stiffeners (full hybrid) | Weight savings matter most for hover efficiency; VTOL eliminates repeated landing impact; antenna placement needs engineering but is manageable | - -**For Variant B (catapult + parachute)**: **Approach C (S2 GFRP + CF wing spar only)** is recommended. It delivers nearly all the operational advantages of pure GFRP — radio transparency in the fuselage, no BVID in the impact zone, full field repairability of the fuselage — while recovering ~200-400g through CF spars exactly where stiffness matters most. The CF spar also stiffens the overall airframe through the wing root junction, improving flutter resistance and fuselage rigidity with no RF penalty. The endurance cost vs full hybrid is only 6-12 minutes on a 7-8h mission. - -**For Variant A (VTOL)**: Retain **Approach A (S2 FG + CF stiffeners)**. VTOL eliminates repeated impact concern, and weight savings directly benefit hover efficiency. - -### Approach C — Fuselage Stiffness Compensation (no CF in fuselage) - -With CF removed from fuselage stiffeners, the fuselage shell needs alternative stiffening. The CF wing spar carry-through handles the critical wing root junction loads, but fuselage panels still need local stiffening. Recommended techniques (can be combined): - -| Technique | Weight Impact | Benefit | -|-----------|--------------|---------| -| Foam sandwich panels (PVC or PMI foam core, S2 FG skins) | +50-150g vs monolithic | Dramatically increases panel stiffness without CF; widely used in gliders and UAVs | -| S2 FG hat-section ribs (replacing CF longerons) | +100-200g vs CF equivalent | Heavier but fully RF-transparent and field-repairable; standard FG construction | -| Geometric stiffening (corrugated skin sections) | +0-50g | Stiffens panels through geometry, not material; minimal weight penalty | -| Thicker S2 FG skins at critical zones (2.5mm vs 2.0mm) | +50-100g | Targeted reinforcement at high-stress areas (wing root, nose, tail boom junction) | - - -## Testing Strategy - -### Approach C Validation Tests -- Wing spar flutter test: ground vibration test at max speed (130 km/h equivalent) to confirm CF spar provides adequate flutter margin -- Fuselage torsion test: apply asymmetric wing loading at wing root junction, measure fuselage twist; compare CF spar carry-through vs FG-only baseline -- RF transmission verification: measure signal attenuation at 900 MHz, 2.4 GHz, 5.8 GHz through fuselage panels in all directions; confirm no RF shadow from wing spars at typical antenna-to-GCS angles -- Belly impact test: drop test at 762 J (8 m/s wind equivalent) on fuselage belly panel (FG only); confirm no damage propagation to CF wing spar -- Repeated landing test: 100× drop tests at 190 J (calm landing) on fuselage belly; verify CF spar shows zero damage (spar is not in impact path) -- Foam sandwich qualification (if used for fuselage panels): flatwise tension, edgewise compression, and impact per ASTM standards -- Field repair validation: induce belly skin damage, repair with field kit (epoxy + S2 FG cloth), test repaired panel to 80% original strength -- Endurance verification: compare actual flight time vs full hybrid prototype (if available); confirm 6-12 min difference estimate - -## References - -1-94: See Drafts 01-05 references (all still applicable) - -Additional sources: -95. Ukrspecsystems SHARK-M UAS: [https://ukrspecsystems.com/drones/shark-m-uas](https://ukrspecsystems.com/drones/shark-m-uas) -96. Ukrspecsystems PD-2 Datasheet: [https://www.unmannedsystemstechnology.com/wp-content/uploads/2016/06/PD_2.pdf](https://www.unmannedsystemstechnology.com/wp-content/uploads/2016/06/PD_2.pdf) -97. KSZYTec UAV Antenna Design Survival Guide (CF RF shielding 30-50 dB): [https://kszytec.com/uav-aerospace-antenna-design-survival-guide/](https://kszytec.com/uav-aerospace-antenna-design-survival-guide/) -98. Radio-Transparent Properties of S-Glass, Aramid, Quartz Radome Composites at 900 MHz: [https://link.springer.com/article/10.1007/s40033-023-00602-7](https://link.springer.com/article/10.1007/s40033-023-00602-7) -99. GFRP radar transparency for aerospace/defense: [https://www.tencom.com/blog/fiberglass-pultrusion-for-aerospace-defense-lightweight-structural-components](https://www.tencom.com/blog/fiberglass-pultrusion-for-aerospace-defense-lightweight-structural-components) -100. EM Shielding of Twill CFRP in UHF/L/S-band (IEEE): [https://ieeexplore.ieee.org/document/10329805/](https://ieeexplore.ieee.org/document/10329805/) -101. EM Shielding of Continuous CF Composites — 52 dB: [https://www.mdpi.com/2073-4360/15/24/4649](https://www.mdpi.com/2073-4360/15/24/4649) -102. E-Glass vs CF Impact Resistance for UAV Wings: [https://www.preprints.org/manuscript/202601.1067](https://www.preprints.org/manuscript/202601.1067) -103. S2/FM94 Glass Fiber Impact Damage Resistance: [https://mdpi-res.com/d_attachment/polymers/polymers-14-00095/article_deploy/polymers-14-00095-v2.pdf](https://mdpi-res.com/d_attachment/polymers/polymers-14-00095/article_deploy/polymers-14-00095-v2.pdf) -104. Field Repair of FG/Epoxy Fuselage: [https://www.matec-conferences.org/articles/matecconf/pdf/2019/53/matecconf_easn2019_01002.pdf](https://www.matec-conferences.org/articles/matecconf/pdf/2019/53/matecconf_easn2019_01002.pdf) -105. ACASIAS Antenna Integration in CF Fuselage Panel: [https://www.nlr.org/newsroom/video/acasias-antenna-integration/](https://www.nlr.org/newsroom/video/acasias-antenna-integration/) -106. Fiberglass Radome Dielectric Properties: [https://www.oreilly.com/library/view/radome-electromagnetic-theory/9781119410799/b02.xhtml](https://www.oreilly.com/library/view/radome-electromagnetic-theory/9781119410799/b02.xhtml) -107. E-Glass vs S-Glass Comparison: [https://www.smicomposites.com/comparing-e-glass-vs-s-glass-key-differences-and-benefits/](https://www.smicomposites.com/comparing-e-glass-vs-s-glass-key-differences-and-benefits/) -108. CF vs FG UAV Drone Material Comparison: [https://www.ganglongfiberglass.com/fiberglass-drone-vs-carbon-fiber/](https://www.ganglongfiberglass.com/fiberglass-drone-vs-carbon-fiber/) -109. CF RF Blocking — StackExchange: [https://drones.stackexchange.com/questions/283/how-much-does-mounting-an-antenna-near-a-carbon-fiber-frame-degrade-signal-recep](https://drones.stackexchange.com/questions/283/how-much-does-mounting-an-antenna-near-a-carbon-fiber-frame-degrade-signal-recep) -110. Belly-Landing Mini UAV Strength Study: [https://www.scientific.net/AMM.842.178](https://www.scientific.net/AMM.842.178) -111. Hybrid Composite Wing Spar Analysis: [https://yanthrika.com/eja/index.php/ijvss/article/view/1476](https://yanthrika.com/eja/index.php/ijvss/article/view/1476) -112. UAV Airframe Structural Optimization: [https://www.frontiersin.org/articles/10.3389/fmech.2025.1708043](https://www.frontiersin.org/articles/10.3389/fmech.2025.1708043) - -## Related Artifacts - -- Previous drafts: `solution_draft01.md` through `solution_draft05.md` -- Research artifacts: `_standalone/UAV_frame_material/00_research/UAV_frame_material/` - diff --git a/_standalone/UAV_frame_material/01_solution/solution_draft07.md b/_standalone/UAV_frame_material/01_solution/solution_draft07.md deleted file mode 100644 index d96aab4..0000000 --- a/_standalone/UAV_frame_material/01_solution/solution_draft07.md +++ /dev/null @@ -1,418 +0,0 @@ -# Solution Draft (Rev 07) — Complete UAV BOM & Cost Analysis - -Reconnaissance fixed-wing UAV. 18 kg MTOW, 3.8m wingspan, catapult launch, parachute recovery. S2 GFRP airframe with CF wing spar. Optimized for radio transparency, parachute landing durability, and field repairability. - -## Material Architecture - -**S2 fiberglass (GFRP) everywhere** — skins, fuselage structure, ribs, hat-section stiffeners, tail surfaces, control surfaces. **Carbon fiber only in the main wing spar** (one per wing half, carry-through at fuselage center section). - -The CF wing spar runs spanwise through the wing and connects at the fuselage center section, providing flutter resistance and torsional rigidity. The fuselage remains 100% GFRP — fully RF-transparent, radar-transparent, field-repairable, with no hidden damage from parachute landings. - -Fuselage panels use foam-core sandwich construction (S2 FG skins over PVC foam core). Hat-section S2 FG ribs at load-bearing stations. - -## Bill of Materials — Complete UAV (Per Unit) - -### 1. Composite Reinforcement Fabrics - -| # | Component | Specification | Qty | Weight | Unit Price | Total | Link | Why This | -|---|-----------|---------------|-----|--------|-----------|-------|------|----------| -| 1.1 | S2-glass cloth, 6oz plain weave | Style 4533, 30" width, aerospace silane finish | 15 yd | ~2.0 kg (in laminate) | $10.45/yd | $156.75 | [LeapTech](https://www.carbonfiberglass.com/product/6oz-s-glass-27-width-html/) | S2 provides 30-40% higher tensile strength and 10× fatigue life vs E-glass. 6oz for 2mm skin layups (3-4 layers). Plain weave for compound curves. | -| 1.2 | S2-glass cloth, 9oz satin weave | Style 7781, 38" width | 5 yd | ~0.8 kg (in laminate) | $14.50/yd | $72.50 | [LeapTech](https://www.carbonfiberglass.com/product/8-9oz-s-glass-satin-weave-38-width-html/) | Satin weave drapes on tight-radius parts (nose cone, wing root fairing). 9oz for wing root junction reinforcement. | -| 1.3 | CF unidirectional tape, 250gsm, 50mm | 12K, glass cross-stitch | 8 m | ~0.15 kg | $4.70/m | $37.60 | [Easy Composites](https://www.easycomposites.co.uk/250g-unidirectional-carbon-fibre-tape) | Maximum stiffness along spar axis. 50mm matches spar cap. 4-6 layers per cap. | -| 1.4 | E-glass cloth, 4oz plain weave | Standard, 50" width | 3 yd | — | $4.50/yd | $13.50 | [The Gelcoater](https://www.thegelcoater.com/pages/6oz-200-gsm-plain-weave-e-glass) | Non-structural areas: cable guides, servo mount pads. E-glass adequate where S2 premium isn't needed. | - -**Subtotal fabrics: ~$280 / ~3.0 kg in laminate** - -### 2. Matrix Resin System - -| # | Component | Specification | Qty | Weight | Unit Price | Total | Link | Why This | -|---|-----------|---------------|-----|--------|-----------|-------|------|----------| -| 2.1 | Aeropoxy PR2032 + PH3660 hardener | 3:1 mix, 1-hour pot life | 1 qt kit | ~0.9 kg | $81.50 | $81.50 | [Aircraft Spruce](https://www.aircraftspruce.com/catalog/pnpages/01-42135.php) | Aerospace-grade, Rutan-tested. Room-temp cure. Good wet-out. Compatible with S2 FG and CF. | -| 2.2 | Aeropoxy PR2032 + PH3630 fast hardener | 3:1 mix, 30-min pot life | 1 pint | ~0.45 kg | $45.00 | $45.00 | [Aircraft Spruce](https://www.aircraftspruce.com/catalog/cmpages/aeropoxy.php) | Fast hardener for bonding joints, fillets, quick repairs. | - -**Subtotal resin: ~$127 / ~0.8 kg in structure** - -### 3. Core Material - -| # | Component | Specification | Qty | Weight | Unit Price | Total | Link | Why This | -|---|-----------|---------------|-----|--------|-----------|-------|------|----------| -| 3.1 | PVC foam core, 3mm, 80 kg/m³ | EasyCell 75 / Divinycell H80 | 8 sheets | ~0.33 kg | $9.10/sheet | $72.80 | [Easy Composites](https://www.easycomposites.us/easycell75-closed-cell-pvc-foam) | Fuselage panels, tail surfaces. 3mm foam + 2×1mm FG skins = ~5mm sandwich. | -| 3.2 | PVC foam core, 5mm, 80 kg/m³ | Same material, thicker | 4 sheets | ~0.27 kg | $9.10/sheet | $36.40 | [Easy Composites](https://www.easycomposites.us/easycell75-closed-cell-pvc-foam) | Wing trailing edge panels and control surfaces. | - -**Subtotal core: ~$109 / ~0.60 kg** - -### 4. Consumables (Layup & Cure) - -| # | Component | Specification | Qty | Unit Price | Total | Link | -|---|-----------|---------------|-----|-----------|-------|------| -| 4.1 | Vacuum bagging kit | Film, sealant tape, peel ply, breather, tubing | 1 kit | $42.48 | $42.48 | [Fiberglass Supply](https://fiberglasssupply.com/basic-vacuum-bagging-kit/) | -| 4.2 | Mold release wax | Partall paste wax, 12oz | 1 can | $18.00 | $18.00 | [Aircraft Spruce](https://www.aircraftspruce.com) | -| 4.3 | PVA mold release | Liquid, 1 pint | 1 pint | $12.00 | $12.00 | [Aircraft Spruce](https://www.aircraftspruce.com) | -| 4.4 | Mixing cups, brushes, squeegees | Assorted laminating tools | 1 set | $25.00 | $25.00 | Various | -| 4.5 | Sandpaper assortment | 80, 120, 220, 400 grit | 1 pack | $15.00 | $15.00 | Various | -| 4.6 | Acetone / IPA | Surface cleaning, 1 gallon | 1 gal | $12.00 | $12.00 | Various | - -**Subtotal consumables: ~$125** - -### 5. Structural Hardware - -| # | Component | Specification | Qty | Weight | Unit Price | Total | Link | Why This | -|---|-----------|---------------|-----|--------|-----------|-------|------|----------| -| 5.1 | Wing root aluminum fittings | 6061-T6, CNC machined | 2 pcs | ~120g | $35.00/pc | $70.00 | [SendCutSend](https://sendcutsend.com) | Transfers wing bending loads to fuselage. Small, inspectable, not in RF path. | -| 5.2 | Wing spar carry-through tube | Pultruded CF tube, 25mm OD × 1.5mm | 0.6 m | ~60g | $15.00 | $15.00 | [DragonPlate](https://dragonplate.com) | Connects L/R wing spars through fuselage. Airframe backbone. | -| 5.3 | Control surface hinges | Composite-compatible pin hinges, 50mm | 10 pcs | ~50g | $2.50/pc | $25.00 | [Aircraft Spruce](https://www.aircraftspruce.com) | Aileron (4), elevator (4), rudder (2). Stainless steel pins. | -| 5.4 | Servo mounting plates | G10 fiberglass, 3mm, 100×60mm | 5 pcs | ~45g | $3.00/pc | $15.00 | [Aircraft Spruce](https://www.aircraftspruce.com) | RF-transparent, strong, bonds into FG structure. | -| 5.5 | Threaded inserts | M3 and M4 brass | 30 pcs | ~30g | $0.50/pc | $15.00 | Various | Access panels, servo covers, wing mounting. | -| 5.6 | Stainless fasteners | M3, M4 bolts/nuts/washers kit | 1 kit | ~80g | $20.00 | $20.00 | Various | Corrosion resistant. | -| 5.7 | Push rods + clevis | 2mm steel rod + nylon clevis | 5 sets | ~60g | $4.00/set | $20.00 | [HobbyKing](https://hobbyking.com) | Servo-to-surface linkage. | - -**Subtotal hardware: ~$180 / ~0.45 kg** - -### 6. Belly Protection (Parachute Landing) - -| # | Component | Specification | Qty | Weight | Unit Price | Total | Why This | -|---|-----------|---------------|-----|--------|-----------|-------|----------| -| 6.1 | Replaceable belly panel | S2 FG / foam sandwich, 2mm skins + 3mm foam | 2 pcs (1+spare) | ~150g each | $15.00/pc | $30.00 | Sacrificial panel, field-swappable in <10 min. | -| 6.2 | EVA foam bumper strip | 15mm closed-cell, adhesive-backed | 1 m | ~40g | $5.00 | $5.00 | Wraps gimbal cavity. Absorbs minor impacts. | - -**Subtotal belly protection: ~$35 / ~0.19 kg installed** - -### 7. Parachute Recovery System - -| # | Component | Specification | Qty | Weight | Unit Price | Total | Link | Why This | -|---|-----------|---------------|-----|--------|-----------|-------|------|----------| -| 7.1 | Fruity Chutes FW Recovery Bundle | IFC-120-S Iris Ultra Compact + pilot chute + deployment bag + Y-harness + shock cord | 1 system | 950g | $830.00 | $830.00 | [Unmanned Systems Source](https://www.unmannedsystemssource.com/shop/parachutes/fixed-wing-bundles/fixed-wing-recovery-bundle-44lbs-20kg-15fps/) | Proven fixed-wing recovery system. IFC-120-S canopy rated 44lb (20kg) @ 15fps (4.6 m/s). Pilot chute ensures reliable air-stream deployment. Spectra shroud lines. Compact packing (190 cu"). Repackable. No pyrotechnics, no CO2 — just pilot chute + deployment bag for planned parachute landings. | -| 7.2 | Servo-actuated hatch | Spring-loaded door, triggered by autopilot | 1 | 80g | $30.00 | $30.00 | Custom | Autopilot triggers servo → spring ejects parachute bag into airstream. Same concept as Shark M: simple, reusable, no gases or explosives. | -| 7.3 | Parachute riser cutter | Servo-actuated line cutter | 1 | 30g | $40.00 | $40.00 | Custom | Cuts risers after touchdown to prevent wind drag. | - -**Subtotal parachute: ~$900 / ~1.06 kg** - -### 8. Propulsion - -| # | Component | Specification | Qty | Weight | Unit Price | Total | Link | Why This | -|---|-----------|---------------|-----|--------|-----------|-------|------|----------| -| 8.1 | T-Motor AT4120 KV250 | Long shaft pusher motor, 12S rated, 2100W max | 1 | 304g | $110.00 | $110.00 | [T-Motor Store](https://store.tmotor.com/product/at4120-long-shaft-vtol-pusher-motor.html) | 12S rated, triple-bearing long shaft for pusher config. At 40-50% throttle: 275W cruise, 7.8-8.7 g/W efficiency. 304g is lightweight for this power class. | -| 8.2 | T-Motor ALPHA 60A 12S ESC | FOC, 18-50.4V, 60A continuous | 1 | 73g | $110.00 | $110.00 | [T-Motor Store](https://store.tmotor.com/product/alpha-60a-12s-esc.html) | Matched to AT4120 motor. FOC for smooth low-RPM cruise. 60A continuous gives ample margin over ~7A cruise draw. Built-in protections. | -| 8.3 | APC 16×8E propeller | Thin electric, fiberglass nylon | 3 pcs (1+2 spare) | ~52g each | $10.00/pc | $30.00 | [APC Propellers](https://www.apcprop.com/product/16x8e/) | Excellent efficiency data matched with AT4120. 16" diameter for high propulsive efficiency at low RPM. Spares included — props are consumables. | - -**Subtotal propulsion: ~$250 / ~0.43 kg installed** - -### 9. Servos - -| # | Component | Specification | Qty | Weight | Unit Price | Total | Link | Why This | -|---|-----------|---------------|-----|--------|-----------|-------|------|----------| -| 9.1 | Digital metal gear servos | HV, 5-10 kg·cm torque, coreless | 5 pcs | ~175g total | $25.00/pc | $125.00 | [Savox](https://www.savox.com) / [KST](https://kstservos.com) | 2 aileron, 2 elevator, 1 rudder. Metal gears for reliability. HV (6-8.4V) powered direct from BEC. Coreless for precision and longevity. | - -**Subtotal servos: ~$125 / ~0.18 kg** - -### 10. Flight Controller & Navigation - -| # | Component | Specification | Qty | Weight | Unit Price | Total | Link | Why This | -|---|-----------|---------------|-----|--------|-----------|-------|------|----------| -| 10.1 | Holybro Pixhawk 6X Mini Set | STM32H753, triple IMU, PM02D power module | 1 set | ~38g | $313.00 | $313.00 | [Holybro](https://holybro.com/products/pixhawk-6x) | Industry standard for ArduPilot. Triple redundant IMU. Ethernet for Jetson link. Mini form factor for fixed-wing. | -| 10.2 | Holybro M10 GPS | u-blox M10, GPS/Galileo/GLONASS/BeiDou, compass | 1 | ~20g | $44.00 | $44.00 | [Holybro](https://holybro.com/collections/gps/products/m10-gps) | Matches Pixhawk 6X connector. Multi-constellation GNSS. Includes IST8310 compass, buzzer, safety switch. | - -**Subtotal flight controller: ~$357 / ~0.06 kg** - -### 11. Onboard Computer - -| # | Component | Specification | Qty | Weight | Unit Price | Total | Link | Why This | -|---|-----------|---------------|-----|--------|-----------|-------|------|----------| -| 11.1 | NVIDIA Jetson Orin Nano Super 8GB | 67 TOPS AI, ARM Cortex-A78AE | 1 | ~60g (board only) | $249.00 | $249.00 | [NVIDIA](https://www.nvidia.com/en-us/autonomous-machines/embedded-systems/jetson-orin/nano-super-developer-kit/) | Runs GPS-denied navigation (visual odometry, terrain matching) + AI reconnaissance pipeline. 67 TOPS for real-time inference. Ethernet to Pixhawk. | - -**Subtotal compute: ~$249 / ~0.06 kg** - -### 12. Cameras - -| # | Component | Specification | Qty | Weight | Unit Price | Total | Link | Why This | -|---|-----------|---------------|-----|--------|-----------|-------|------|----------| -| 12.1 | ADTI 26S V1 + 35mm lens | 26MP APS-C, Sony IMX571, mechanical shutter | 1 | ~122g | $1,890.00 | $1,890.00 | [UnmannedRC](https://unmannedrc.com/products/26mp-26s-v1-aps-c-mapping-camera) | GPS-denied navigation camera. Mechanical shutter eliminates rolling shutter distortion at speed. 21.6 cm/px GSD at 2 km. Lightest 26MP APS-C option (122g with lens). | -| 12.2 | Viewpro Z40K 4K gimbal | 4K 20× optical zoom, 3-axis stabilized, 25.9MP | 1 | ~595g | $3,000.00 | $3,000.00 | [Viewpro](https://www.viewprouav.com/product/z40k-single-4k-hd-25-times-zoom-gimbal-camera-3-axis-gimbal-uav-aerial-photography-cartography-and-patrol-inspection.html) | AI reconnaissance camera. 2.7 cm/px GSD at 2 km max zoom. 103×58m FoV in 4K. 479g lighter than Viewpro A40 Pro. PWM/TTL/SBUS control compatible with ArduPilot. | - -**Subtotal cameras: ~$4,890 / ~0.72 kg** - -### 13. Communications - -| # | Component | Specification | Qty | Weight | Unit Price | Total | Link | Why This | -|---|-----------|---------------|-----|--------|-----------|-------|------|----------| -| 13.1 | TBS Crossfire Nano RX | 915 MHz, long range RC receiver | 1 | ~2g | $30.00 | $30.00 | [GetFPV](https://www.getfpv.com/tbs-crossfire-nano-rx.html) | Long-range RC link (>40 km). Ultra-light. ArduPilot CRSF protocol support. | -| 13.2 | RFD900x telemetry modem (air) | 900 MHz, 1W, >40 km range, AES-128 | 1 | ~30g | $97.00 | $97.00 | [Droneyard](https://event38.com/product/rfd-900x-telemetry-set/) | MAVLink telemetry + mission commands. Encrypted. Long range. Pixhawk-native integration. | - -**Subtotal comms: ~$127 / ~0.03 kg** - -### 14. Power System - -| # | Component | Specification | Qty | Weight | Unit Price | Total | Link | Why This | -|---|-----------|---------------|-----|--------|-----------|-------|------|----------| -| 14.1 | Tattu 6S 33Ah 350 Wh/kg semi-solid | 22.2V, 10C, 2216g each, XT90-S | 4 pcs | 8.86 kg total | $750.00/pc | $3,000.00 | [GenStattu](https://genstattu.com/tattu-semi-solid-state-350wh-kg-33000mah-10c-22-2v-6s1p-g-tech-lipo-battery-pack-with-xt90-s-plug/) | 4× in 2S2P → 12S 66Ah (2930 Wh). 350 Wh/kg is highest available density in production. 500+ cycle life at 90% retention. Modular — individual pack replacement. | -| 14.2 | Power distribution board + BEC | 12S input, 5V/3A + 12V/3A BEC outputs | 1 | ~25g | $30.00 | $30.00 | Various | Powers servos (5V HV), Pixhawk, GPS, RC receiver. | -| 14.3 | Wiring + connectors + battery bus | 10-12AWG silicone, XT90, series adapters, parallel bus bar | 1 set | ~450g | $80.00 | $80.00 | Various | 2S2P wiring: 2× series adapters + parallel bus bar. Redundant connectors. | - -**Subtotal power: ~$3,110 / ~9.34 kg** - -### 15. Catapult Interface - -| # | Component | Specification | Qty | Weight | Unit Price | Total | Why This | -|---|-----------|---------------|-----|--------|-----------|-------|----------| -| 15.1 | Belly mounting rails | Aluminum rails for catapult carriage attachment | 1 set | ~150g | $50.00 | $50.00 | Interface between airframe and pneumatic catapult carriage. Quick-release on launch. | - -**Subtotal catapult interface: ~$50 / ~0.15 kg** - -### 16. Field Repair Kit - -| # | Component | Specification | Qty | Weight | Unit Price | Total | -|---|-----------|---------------|-----|--------|-----------|-------| -| 16.1 | S2-glass patches | 6oz, 150×150mm pre-cut | 10 pcs | ~50g | $2.00/pc | $20.00 | -| 16.2 | Field epoxy kit | Aeropoxy PR2032/PH3630 fast, 4oz | 1 | ~120g | $25.00 | $25.00 | -| 16.3 | Repair tools pouch | Cups, gloves, sandpaper, scissors, tape | 1 | ~200g | $15.00 | $15.00 | -| 16.4 | Spare belly panels | Pre-manufactured (item 6.1) | 3 pcs | ~450g (stored) | $15.00/pc | $45.00 | - -**Subtotal repair kit: ~$105 / ~0.37 kg carried** - -## Weight Summary - -| Category | Weight | -|----------|--------| -| S2 FG skins + ribs + stiffeners (cured laminate) | ~3.80 kg | -| Foam core (in sandwich panels) | ~0.45 kg | -| CF wing spar (both halves, cured) | ~0.20 kg | -| Structural hardware (fittings, fasteners, hinges) | ~0.45 kg | -| Belly panel + bumper (installed) | ~0.19 kg | -| Catapult belly rails | ~0.15 kg | -| Parachute system | ~1.06 kg | -| **Airframe subtotal** | **~6.30 kg** | -| Motor + ESC + propeller | ~0.43 kg | -| Servos (×5) | ~0.18 kg | -| Pixhawk 6X + GPS | ~0.06 kg | -| Jetson Orin Nano Super | ~0.06 kg | -| ADTI 26S V1 + 35mm lens | ~0.12 kg | -| Viewpro Z40K gimbal | ~0.60 kg | -| TBS Crossfire Nano RX + RFD900x air | ~0.03 kg | -| Power distribution + wiring | ~0.48 kg | -| **Electronics subtotal** | **~1.96 kg** | -| 4× Tattu 6S 33Ah 350 Wh/kg | **8.86 kg** | -| **TOTAL** | **~17.12 kg** | - -Margin to 18 kg MTOW: **~0.88 kg** (for paint, antenna, miscellaneous hardware) - -## Per-UAV Cost Summary - -| Category | Cost | % | -|----------|------|---| -| Composite fabrics | $280 | 3% | -| Resin system | $127 | 1% | -| Foam core | $109 | 1% | -| Consumables | $125 | 1% | -| Structural hardware | $180 | 2% | -| Belly protection | $35 | <1% | -| Parachute system | $900 | 8% | -| Field repair kit | $105 | 1% | -| **Airframe subtotal** | **$1,861** | **17%** | -| Propulsion (motor + ESC + props) | $250 | 2% | -| Servos | $125 | 1% | -| **Propulsion + actuators subtotal** | **$375** | **3%** | -| Pixhawk 6X Mini Set | $313 | 3% | -| GPS M10 | $44 | <1% | -| Jetson Orin Nano Super | $249 | 2% | -| **Avionics subtotal** | **$606** | **6%** | -| ADTI 26S V1 + 35mm (navigation) | $1,890 | 17% | -| Viewpro Z40K 4K gimbal (reconnaissance) | $3,000 | 27% | -| **Camera subtotal** | **$4,890** | **45%** | -| TBS Crossfire Nano RX | $30 | <1% | -| RFD900x air module | $97 | 1% | -| **Comms subtotal** | **$127** | **1%** | -| 4× Tattu 6S 33Ah 350 Wh/kg batteries | $3,000 | 27% | -| Power distribution + wiring | $110 | 1% | -| **Power subtotal** | **$3,110** | **28%** | -| Catapult belly rails | $50 | <1% | -| **TOTAL PER UAV** | **$11,019** | **100%** | - -### Cost Drivers - -The cameras (45%) and batteries (28%) together account for 73% of per-UAV cost. The airframe material is only 5% ($641 for fabrics + resin + foam). The parachute system at $900 is 8% — significantly reduced from the $2,310 ballistic system in earlier drafts by switching from the Peregrine CO2 ballistic system to the simpler FW Recovery Bundle (canopy + pilot chute + deployment bag). The UAV performs planned parachute landings, not emergency deployments — no ballistic launcher needed. - -## Tooling (One-Time) - -| # | Component | Cost | Amortization | -|---|-----------|------|-------------| -| 9.1 | Fuselage mold set (FG/epoxy female, L+R halves) | $800 | 50+ pulls | -| 9.2 | Wing mold set (FG/epoxy female, upper+lower) | $600 | 50+ pulls | -| 9.3 | Tail surface molds (H-stab + V-stab) | $400 | 50+ pulls | -| 9.4 | Wing spar jig (aluminum + MDF fixture) | $200 | 100+ uses | -| 9.5 | Vacuum pump (2.5 CFM electric) | $150 | Permanent | -| 9.6 | CNC foam plug machining (outsourced) | $1,500 | One-time | -| | **Total tooling** | **$3,650** | | - -## Ground Equipment (One-Time, Shared) - -| # | Component | Cost | Notes | -|---|-----------|------|-------| -| G.1 | TBS Crossfire TX module | $100 | Shared across fleet, plugs into RC transmitter | -| G.2 | RFD900x ground station modem | $200 | Shared GCS telemetry module | -| G.3 | RC transmitter (e.g. RadioMaster TX16S) | $200 | If not already owned | -| G.4 | Pneumatic catapult (ELI PL-60 class) | $15,000-25,000 | Shared launch system; 108 kg, 2 transport cases | -| | **Total GCS equipment (excl. catapult)** | **$500** | | - -## Labor - -| # | Task | Hours (first 5 units) | Hours (at 100 units) | Rate | -|---|------|----------------------|---------------------|------| -| L.1 | Mold prep + release | 2h | 1h | Technician | -| L.2 | Fuselage skin layup + vacuum bag + cure | 8h | 5h | Technician | -| L.3 | Wing skin layup + vacuum bag + cure | 6h | 4h | Technician | -| L.4 | CF wing spar layup + cure | 3h | 2h | Technician | -| L.5 | Tail surface layup + cure | 3h | 2h | Technician | -| L.6 | Demolding + trimming | 4h | 2.5h | Technician | -| L.7 | Assembly (bond ribs, fittings, hardware) | 8h | 5h | Technician | -| L.8 | Electronics integration + wiring | 6h | 4h | Technician | -| L.9 | Parachute system install + test | 2h | 1.5h | Technician | -| L.10 | Finishing (fill, sand, paint) | 6h | 4h | Technician | -| L.11 | Quality inspection + flight test | 4h | 2h | Senior tech | -| | **Total labor per airframe** | **~52h** | **~33h** | | - -## Fleet Cost — 5 Aircraft - -| Item | Calculation | Cost | -|------|------------|------| -| **Tooling (one-time)** | Molds + jigs + CNC plugs + vacuum pump | $3,650 | -| **GCS equipment (one-time)** | TX module + RFD900x ground + RC transmitter | $500 | -| **UAV components × 5** | $11,019 × 5 | $55,095 | -| **Labor × 5** | 52h × 5 × $30/h | $7,800 | -| **Spare parts stock** | Extra belly panels, props, connectors | $600 | -| | | | -| **Total for 5 aircraft** | | **$67,645** | -| **Per aircraft (all-in, incl. tooling)** | | **$13,529** | -| **Per aircraft (excl. tooling, marginal)** | | **$12,699** | - -**Note**: Catapult ($15,000-25,000) is listed separately as ground equipment — not included in per-aircraft cost. It's a shared infrastructure item amortized across operations, not per-unit. - -### Cost Breakdown — 5 Aircraft - -| Category | Amount | % | -|----------|--------|---| -| Cameras (×5) | $24,450 | 36% | -| Batteries (×5) | $15,000 | 22% | -| Airframe materials (×5) | $9,305 | 14% | -| Labor | $7,800 | 12% | -| Avionics + compute (×5) | $3,030 | 4% | -| Tooling | $3,650 | 5% | -| Propulsion + servos (×5) | $1,875 | 3% | -| Comms (×5) + GCS equip. | $1,135 | 2% | -| Spares + repair kits | $1,125 | 2% | -| Catapult interface (×5) | $250 | <1% | - -## Fleet Cost — 100 Aircraft - -At 100 units, bulk pricing and learning-curve labor savings: - -| Item | Unit Price Change | Reasoning | -|------|------------------|-----------| -| S2 FG cloth | $7.50/yd (−28%) | Bolt pricing from AGY distributor | -| CF UD tape | $2.50/m (−47%) | 800m order | -| Epoxy resin | $65/qt kit (−20%) | 5-gallon drums | -| Foam core | $6.50/sheet (−29%) | Case quantity from Diab | -| Consumables | $80/set (−36%) | Roll quantities | -| Hardware | $140/set (−22%) | Batch CNC, bulk fasteners | -| Parachute | $700/unit (−16%) | Volume discount from Fruity Chutes | -| Motor AT4120 | $95 (−14%) | 100+ order from T-Motor | -| ESC ALPHA 60A | $95 (−14%) | 100+ order from T-Motor | -| Batteries | $650/pc (−13%) | Tattu bulk/OEM pricing | -| ADTI 26S V1 | $1,700 (−10%) | Volume pricing | -| Viewpro Z40K | $2,500 (−17%) | Direct OEM/volume | -| Pixhawk 6X Mini | $250 (−20%) | Holybro 100+ discount tier | -| GPS M10 | $33 (−25%) | Holybro 100+ discount | -| Jetson Orin Nano | $199 (−20%) | NVIDIA volume/module pricing | -| RFD900x | $85 (−12%) | Bulk order | -| Servos | $20/pc (−20%) | Bulk order | -| Labor | 33h × $30/h = $990 (−37%) | Learning curve, jigs, repetition | - -| Item | Calculation | Cost | -|------|------------|------| -| **Tooling** | 2 mold sets (50 pulls each) + jigs + vacuum | $7,300 | -| **Airframe materials × 100** | Bulk-priced fabrics + resin + foam + consumables + hardware | $116,000 | -| **Parachute systems × 100** | $700 × 100 | $70,000 | -| **Propulsion × 100** | (95 + 95 + 25) × 100 | $21,500 | -| **Servos × 100** | $100 × 100 | $10,000 | -| **Cameras × 100** | ($1,700 + $2,500) × 100 | $420,000 | -| **Avionics × 100** | ($250 + $33 + $199) × 100 | $48,200 | -| **Comms × 100** | ($30 + $85) × 100 | $11,500 | -| **Power system × 100** | ($2,600 + $100) × 100 | $270,000 | -| **Catapult interface × 100** | $40 × 100 | $4,000 | -| **Repair kits × 100** | $80 × 100 | $8,000 | -| **Labor × 100** | 33h × $30 × 100 | $99,000 | -| **Spare parts stock** | Belly panels, props, misc | $8,000 | -| **Quality tools** | Ultrasonic tester, etc. | $2,000 | -| **GCS equipment** | 5 GCS sets at $500 each | $2,500 | -| | | | -| **Total for 100 aircraft** | | **$1,098,000** | -| **Per aircraft (all-in)** | | **$10,980** | -| **Per aircraft (excl. tooling, marginal)** | | **$10,883** | - -### Cost Breakdown — 100 Aircraft - -| Category | Amount | % | -|----------|--------|---| -| Cameras | $420,000 | 38% | -| Power (batteries + wiring) | $270,000 | 25% | -| Airframe materials | $116,000 | 11% | -| Labor | $99,000 | 9% | -| Parachute systems | $70,000 | 6% | -| Avionics + compute | $48,200 | 4% | -| Propulsion + servos | $31,500 | 3% | -| Comms + GCS | $14,000 | 1% | -| Tooling + quality tools | $9,300 | 1% | -| Repair/spares | $16,000 | 2% | -| Catapult interface | $4,000 | <1% | - -### Scaling Comparison - -| Metric | 5 Aircraft | 100 Aircraft | Savings at Scale | -|--------|-----------|-------------|-----------------| -| Per-aircraft total cost | $13,529 | $10,980 | −19% | -| Per-aircraft airframe | $1,861 | $1,160 | −38% | -| Per-aircraft cameras | $4,890 | $4,200 | −14% | -| Per-aircraft batteries | $3,000 | $2,600 | −13% | -| Per-aircraft labor | $1,560 | $990 | −37% | -| Tooling per aircraft | $730 | $73 | −90% | -| Parachute per aircraft | $900 | $700 | −22% | - -Scaling savings are modest (19%) because cameras and batteries dominate cost and have limited bulk discount potential. The largest percentage savings come from tooling amortization (−90%) and labor learning curve (−37%). - -### Parachute System Alternatives - -The FW Recovery Bundle at $830 is the recommended baseline. For reference, other options: - -| System | Price | Weight | Rated | Deployment | Pro | Con | -|--------|-------|--------|-------|-----------|-----|-----| -| **Fruity Chutes FW Bundle (recommended)** | $830 | 950g | 20 kg @ 15fps | Pilot chute + deployment bag (air-stream) | Proven, sized right, includes harness, repackable | 2-4 week lead time | -| Fruity Chutes Peregrine UAV 5 Light | $2,310 | 1,480g | 20 kg @ 15fps | CO2 ballistic ejection | Fastest deployment, works at zero airspeed | 2.8× more expensive, heavier, CO2 cartridge consumable | -| Foxtech Parachute + Ejector 20kg | $899 | 1,600g | 20 kg | Servo + spring | Cheaper than Peregrine | Designed for multirotor vertical eject, heavier, unproven for FW | -| Skycat X68 + IFC-84-SUL | ~$1,100 | 420g | 17 kg max | Skycat Fuse® | Lightest system, fast deployment | Max 17 kg — borderline for 18 kg MTOW | -| DIY: Rocketman 120" + custom deployment | ~$350 | ~600g est. | ~18 kg | Servo hatch + spring | Cheapest | Unproven for this weight class, 4 shroud lines only | - -## References - -1. S2-glass cloth: https://www.carbonfiberglass.com/product/6oz-s-glass-27-width-html/ -2. CF UD tape: https://www.easycomposites.co.uk/250g-unidirectional-carbon-fibre-tape -3. Aeropoxy PR2032: https://www.aircraftspruce.com/catalog/pnpages/01-42135.php -4. PVC foam core: https://www.easycomposites.us/easycell75-closed-cell-pvc-foam -5. Fruity Chutes FW Bundle: https://www.unmannedsystemssource.com/shop/parachutes/fixed-wing-bundles/fixed-wing-recovery-bundle-44lbs-20kg-15fps/ -6. T-Motor AT4120: https://store.tmotor.com/product/at4120-long-shaft-vtol-pusher-motor.html -7. T-Motor ALPHA 60A: https://store.tmotor.com/product/alpha-60a-12s-esc.html -8. APC 16×8E: https://www.apcprop.com/product/16x8e/ -9. Holybro Pixhawk 6X: https://holybro.com/products/pixhawk-6x -10. Holybro M10 GPS: https://holybro.com/collections/gps/products/m10-gps -11. Jetson Orin Nano Super: https://www.nvidia.com/en-us/autonomous-machines/embedded-systems/jetson-orin/nano-super-developer-kit/ -12. ADTI 26S V1: https://unmannedrc.com/products/26mp-26s-v1-aps-c-mapping-camera -13. Viewpro Z40K: https://www.viewprouav.com/product/z40k-single-4k-hd-25-times-zoom-gimbal-camera-3-axis-gimbal-uav-aerial-photography-cartography-and-patrol-inspection.html -14. TBS Crossfire Nano RX: https://www.getfpv.com/tbs-crossfire-nano-rx.html -15. RFD900x: https://event38.com/product/rfd-900x-telemetry-set/ -16. Tattu 350Wh/kg 6S 33Ah: https://genstattu.com/tattu-semi-solid-state-350wh-kg-33000mah-10c-22-2v-6s1p-g-tech-lipo-battery-pack-with-xt90-s-plug/ -17. Foxtech Parachute 20kg: https://store.foxtech.com/parachute-for-20kg-uav-airplanes/ -18. Skycat X68: https://www.skycat.pro/shop/skycat-x68-3zdz9 -19. Rocketman parachutes: https://www.the-rocketman.com/products/ultra-light-high-performance-drone-parachutes - -## Related Artifacts - -- Previous drafts: `solution_draft01.md` through `solution_draft06.md` -- Research artifacts: `_standalone/UAV_frame_material/00_research/UAV_frame_material/` diff --git a/_standalone/UAV_frame_material/UAV_frame_material.md b/_standalone/UAV_frame_material/UAV_frame_material.md deleted file mode 100644 index 0f468ef..0000000 --- a/_standalone/UAV_frame_material/UAV_frame_material.md +++ /dev/null @@ -1 +0,0 @@ -I want to build a UAV plane for reconnaissance missions maximizing flight duration. Investigate what is the best frame material for that purpose \ No newline at end of file diff --git a/_standalone/camera_high_altitude/00_research/camera_high_altitude/00_ac_assessment.md b/_standalone/camera_high_altitude/00_research/camera_high_altitude/00_ac_assessment.md deleted file mode 100644 index 8ce5469..0000000 --- a/_standalone/camera_high_altitude/00_research/camera_high_altitude/00_ac_assessment.md +++ /dev/null @@ -1,98 +0,0 @@ -# Acceptance Criteria Assessment - -## Context - -Balloon at 10km altitude. AI detection model trained on imagery from 600-1000m altitude (trucks, vehicles, tracked machinery). Goal: reuse model by using a zoom gimbal camera to achieve equivalent Ground Sample Distance (GSD) from 10km. Budget: under $30k. - -## Key Technical Analysis - -### GSD Requirements - -The AI model was trained on 600-1000m imagery. Typical drone cameras at those altitudes produce: - -- At 600m: GSD ~5-10 cm/pixel -- At 1000m: GSD ~10-15 cm/pixel - -For vehicle detection per NIIRS scale: - -- Vehicle detection: ~1m GSD -- Vehicle type identification: ~25-50 cm GSD -- Detailed vehicle description: ~10 cm GSD - -Target GSD from 10km: **5-15 cm/pixel** to match training data. - -### Required Focal Length from 10km - -Formula: `focal_length = (pixel_pitch × altitude) / target_GSD` - - -| Sensor Type | Pixel Pitch | Target GSD 15cm | Target GSD 10cm | Target GSD 5cm | -| ----------------- | ----------- | --------------- | --------------- | -------------- | -| 1/2.8" (5MP) | ~2.0µm | 133mm | 200mm | 400mm | -| 1/2.3" (25MP) | ~1.05µm | 70mm | 105mm | 210mm | -| 1" (20MP) | ~2.4µm | 160mm | 240mm | 480mm | -| Full-frame (61MP) | 3.76µm | 251mm | 376mm | 752mm | - - -### Atmospheric Resolution Limit - -From 10km looking down, atmospheric turbulence limits ground resolution to approximately **4.6 cm** (theoretical, under ideal conditions). Practical limit: **5-8 cm** depending on weather. This means: - -- GSD finer than ~5 cm provides no benefit -- 10-15 cm GSD is safely achievable (optics-limited, not atmosphere-limited) - -### Environmental Conditions at 10km Altitude - -- Temperature: approximately **-50°C** -- Pressure: ~264 hPa (26% of sea level) -- Consumer cameras rated 0°C to 40°C — **will not function without heated enclosure** -- Drone gimbal cameras rated -20°C to +60°C — **still insufficient for -50°C** -- All solutions require thermal management (insulated/heated housing) - -## Acceptance Criteria - - -| Criterion | Derived Value | Researched Feasibility | Cost/Timeline Impact | Status | -| --------------------- | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | ---------------------------------------------- | -| Budget | <$30k | Realistic. Good systems $5k-15k, premium $15k-25k including enclosure | Achievable | Confirmed | -| GSD from 10km | 5-15 cm/pixel (match training data) | Achievable with 170-800mm FL depending on sensor. Atmospheric limit ~5cm | Core requirement, drives lens/sensor choice | Confirmed | -| FOV per frame | >200m ground width | At 10-15cm GSD with 2000-8000px: 200-1200m width. Acceptable | No issue with most cameras | Confirmed | -| Gimbal stabilization | 3-axis, ±0.02° or better | Standard in $2k-8k gimbal cameras. Balloon needs additional passive stabilization | Balloon motion is the challenge, not gimbal specs | Modified — need passive + active stabilization | -| Image quality for AI | Must be compatible with model trained at 600-1000m | Atmospheric haze at 10km WILL degrade contrast vs clean 600-1000m imagery. May need dehazing and/or model fine-tuning | Moderate risk — software mitigation possible | Added | -| Operating temperature | Balloon has thermal protection — not a concern | User confirmed thermal management is handled | No additional cost | Removed | -| Weight | Not critical | Most camera+gimbal systems 1-5kg. Enclosure adds 1-3kg. Total 3-8kg | Fine for balloon | Confirmed | - - -## Restrictions Assessment - - -| Restriction | Derived Value | Researched Feasibility | Cost/Timeline Impact | Status | -| --------------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | --------- | -| Balloon platform at 10km | Fixed constraint | Unusual altitude — between aerostat (500-3500m) and HAPS (18-20km). Very few purpose-built systems. Must adapt drone/DSLR equipment | Custom integration required | Confirmed | -| AI model reuse (no retrain) | Must match training GSD | Feasible for GSD matching. Image quality differences (haze, contrast) may require model fine-tuning or preprocessing | Low-moderate risk | Confirmed | -| Temperature at 10km | -50°C ambient | Heated enclosure mandatory. All cameras, gimbals, and batteries need thermal protection. Power budget increases 20-50W for heating | $2k-5k added, +2-3kg weight | Added | -| Pressure at 10km | ~264 hPa | Some electronics may need conformal coating or pressurized housing. Lens fogging risk. Most industrial electronics tolerate low pressure | Minor added cost ($500-1k) | Added | -| Power at 10km | Balloon power source | Camera (10-20W) + gimbal (20-50W) + heating (20-50W) ≈ 50-120W total. Balloon must supply sufficient power | Must verify balloon power budget | Added | -| Atmospheric haze | 10km air column | Clear weather (user-specified) helps. Contrast reduction is inevitable. Computational dehazing recommended | Software mitigation, low cost | Added | - - -## Key Findings - -1. **GSD matching is achievable** within budget. Multiple camera/lens combinations can deliver 5-15 cm/pixel GSD from 10km -2. **Thermal management is the hidden critical requirement**. No commercial camera or gimbal operates at -50°C without protection -3. **Atmospheric degradation is the biggest risk for AI model reuse**. Even with perfect GSD match, image contrast/sharpness will be lower than training data from 600-1000m. Recommend computational dehazing and potential model fine-tuning -4. **Balloon motion stabilization** requires both passive (pendulum damping, suspension design) and active (3-axis gimbal) approaches -5. **Budget is realistic** for mid-range solutions ($8k-20k for camera+gimbal+enclosure) with room for integration costs - -## Sources - -- NIIRS Civil Reference Guide (irp.fas.org) — GSD requirements for vehicle detection -- Pix4D — GSD calculation methodology -- "Limiting Resolution Looking Down Through the Atmosphere" (Optica) — atmospheric resolution limits -- UAVOS POD specifications — stratospheric camera benchmark (69cm GSD at 15km) -- Airmobi/Viewpro A40 Pro, Z40K — drone gimbal camera specs and pricing -- LoongUAV VT500Rs — high-res zoom gimbal specs -- Sony FE 400-800mm announcement — super telephoto lens specs/pricing -- Gremsy T7 specifications — gimbal payload capacity -- IAState Digital Press — high-altitude balloon payload stabilization research - diff --git a/_standalone/camera_high_altitude/00_research/camera_high_altitude/00_question_decomposition.md b/_standalone/camera_high_altitude/00_research/camera_high_altitude/00_question_decomposition.md deleted file mode 100644 index 019184e..0000000 --- a/_standalone/camera_high_altitude/00_research/camera_high_altitude/00_question_decomposition.md +++ /dev/null @@ -1,56 +0,0 @@ -# Question Decomposition - -## Original Question - -Research gimbal camera options under $30k for a balloon at 10km altitude to produce imagery compatible with an AI detection model trained on 600-1000m altitude data (10-20 cm/pixel GSD). Targets: trucks, vehicles, tracked machinery. - -## Active Mode - -Mode A Phase 2 — Initial Research (no existing solution draft) - -## Question Type Classification - -**Decision Support** — need to evaluate trade-offs between different gimbal camera systems for a specific use case. - -## Research Subject Boundary Definition - -- **Population**: Commercial and semi-professional gimbal camera systems suitable for balloon platforms -- **Geography**: Global market, available for purchase/export -- **Timeframe**: Currently available products (2024-2026) -- **Level**: Systems under $30k, excluding military-restricted/ITAR-controlled equipment -- **Platform**: High-altitude balloon at 10km with thermal protection - -## Problem Context Summary - -- Balloon at 10km altitude, thermally protected -- AI model trained on 600-1000m imagery, GSD ~10-20 cm/pixel -- Target objects: trucks, vehicles, tracked machinery -- Need zoom gimbal camera to achieve equivalent GSD from 10km -- Budget: under $30k -- Weight: not a major constraint -- Weather: mostly sunny conditions (eastern/southern Ukraine) - -## Decomposed Sub-Questions - -1. What are the available commercial gimbal camera categories suitable for this application? -2. For each category, what specific products can deliver 10-20 cm/pixel GSD from 10km? -3. What are the trade-offs between integrated zoom gimbals vs separate camera+lens+gimbal setups? -4. How does atmospheric haze affect AI model performance, and what mitigation exists? -5. What gimbal stabilization approach works best for balloon platforms? -6. What is the total system cost (camera + gimbal + integration) for each option? -7. What are the power requirements and interfaces for each option? - -## Timeliness Sensitivity Assessment - -- **Research Topic**: Gimbal cameras and aerial surveillance equipment -- **Sensitivity Level**: 🟡 Medium -- **Rationale**: Hardware products evolve on 1-2 year cycles. New products appear but existing ones remain available. -- **Source Time Window**: 2 years -- **Priority official sources**: - 1. Manufacturer product pages (Viewpro, Airmobi, LoongUAV, Sony, Gremsy) - 2. Distributor sites with pricing (druav.com, dronexpert.nl) -- **Key version information to verify**: - - ViewPro A40 Pro: current variant and pricing - - LOONG VT500Rs: availability and pricing - - Sony FE 400-800mm: shipping status and pricing - diff --git a/_standalone/camera_high_altitude/00_research/camera_high_altitude/01_source_registry.md b/_standalone/camera_high_altitude/00_research/camera_high_altitude/01_source_registry.md deleted file mode 100644 index ee4a49b..0000000 --- a/_standalone/camera_high_altitude/00_research/camera_high_altitude/01_source_registry.md +++ /dev/null @@ -1,146 +0,0 @@ -# Source Registry - -## Source #1 -- **Title**: Civil NIIRS Reference Guide -- **Link**: https://irp.fas.org/imint/niirs_c/guide.htm -- **Tier**: L1 -- **Publication Date**: Established standard (ongoing) -- **Timeliness Status**: ✅ Currently valid -- **Target Audience**: Military/intelligence imagery analysts -- **Research Boundary Match**: ✅ Full match — GSD requirements for vehicle detection -- **Summary**: NIIRS 6 required for vehicle type identification (~25-50cm GSD). Detailed vehicle description at ~10cm GSD. - -## Source #2 -- **Title**: Limiting Resolution Looking Down Through the Atmosphere -- **Link**: https://opg.optica.org/josa/abstract.cfm?uri=josa-56-10-1380 -- **Tier**: L1 -- **Publication Date**: Academic publication -- **Timeliness Status**: ✅ Currently valid (fundamental physics) -- **Summary**: Atmospheric turbulence limits ground resolution from high altitude to ~4.6cm. Independent of optics quality. - -## Source #3 -- **Title**: Pix4D — How to select Camera Focal Length and Flight Altitude -- **Link**: https://support.pix4d.com/hc/en-us/articles/202558849 -- **Tier**: L2 -- **Publication Date**: Updated regularly -- **Timeliness Status**: ✅ Currently valid -- **Summary**: GSD = (pixel_pitch × altitude) / focal_length. Standard formula for aerial imaging. - -## Source #4 -- **Title**: Airmobi A40 Pro Product Page -- **Link**: https://www.airmobi.com/product/a40-pro-40x-optical-zoom-3-axis-ai-tracking-gimbal-camera/ -- **Tier**: L1 (manufacturer) -- **Publication Date**: 2024-2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: $2,299. 40x optical zoom, 170mm max FL, 1/2.8" Sony CMOS, 5MP, 3-axis gimbal. AI tracking. Detects vehicles up to 16km. - -## Source #5 -- **Title**: ViewPro Z40K Product Page -- **Link**: https://www.viewprouav.com/product/z40k-single-4k-hd-25-times-zoom-gimbal-camera.html -- **Tier**: L1 (manufacturer) -- **Publication Date**: 2024-2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: $3,000-5,000. 20x optical (40x hybrid) zoom, 1/2.3" Panasonic 25.9MP, 4K video, 3-axis gimbal. - -## Source #6 -- **Title**: SIYI ZT30 Product Page -- **Link**: https://shop.siyi.biz/products/siyi-zt30 -- **Tier**: L1 (manufacturer) -- **Publication Date**: 2024-2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: $6,099-7,309. 30x optical zoom, 1/2.7" 8MP, 4K, thermal+LRF, 4-sensor pod. 9W average power. - -## Source #7 -- **Title**: DJI Zenmuse H30T Specs -- **Link**: https://enterprise.dji.com/zenmuse-h30-series/specs -- **Tier**: L1 (manufacturer) -- **Publication Date**: 2024-2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: $10,240-11,610. 34x optical, 1/1.8" 40MP, 4K, thermal 1280×1024, LRF. LOCKED TO DJI MATRICE PLATFORM. - -## Source #8 -- **Title**: LOONG VT500Rs Product Page -- **Link**: https://www.loonguav.com/vt500rs -- **Tier**: L1 (manufacturer) -- **Publication Date**: 2024-2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: Price unknown. 42x optical, 48MP (8000×6000), dual visible cameras, thermal, LRF. 1.2kg. Military ISR focus. - -## Source #9 -- **Title**: Sony FE 400-800mm F6.3-8 G OSS Announcement -- **Link**: https://alphauniverse.com/stories/sony-unveils-specialty-400800mm-f6-38-g-oss-super-telephoto-zoom-g-lens/ -- **Tier**: L1 (manufacturer) -- **Publication Date**: 2025-02-26 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: £2,399 (~$3,000). 400-800mm f/6.3-8, 2,475g. Supports 1.4x/2x TC for 1120/1600mm. Shipping March 2025. - -## Source #10 -- **Title**: Gremsy T7 Specifications -- **Link**: https://gremsy.com/gremsy-t7-spec -- **Tier**: L1 (manufacturer) -- **Publication Date**: 2024-2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: $2,349. 3.175kg max payload. 3-axis, ±0.02° vibration. USB/CAN/UART. Phase One compatible. - -## Source #11 -- **Title**: Viewpro Viewlink Serial Command Protocol V3.3.3 -- **Link**: https://www.viewprotech.com/index.php?ac=article&at=read&did=510 -- **Tier**: L2 (manufacturer documentation) -- **Publication Date**: 2024 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: Documented serial UART and TCP protocol for controlling Viewpro gimbals from custom platforms. - -## Source #12 -- **Title**: ArduPilot ViewPro Gimbal Driver (AP_Mount) -- **Link**: https://github.com/ArduPilot/ardupilot/pull/22568 -- **Tier**: L2 (open source) -- **Publication Date**: 2023-2024 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: Lua-based gimbal driver for Viewpro cameras in ArduPilot. Demonstrates serial integration feasibility. - -## Source #13 -- **Title**: MAVLink Gimbal Protocol v2 -- **Link**: https://mavlink.io/en/services/gimbal_v2.html -- **Tier**: L1 (protocol standard) -- **Publication Date**: Ongoing standard -- **Timeliness Status**: ✅ Currently valid -- **Summary**: Standard protocol for gimbal control via MAVLink. Supports companion computer as gimbal manager. - -## Source #14 -- **Title**: UAVOS POD Stratospheric Earth Observation Payload -- **Link**: https://uasweekly.com/2026/02/02/uavos-unveils-stratospheric-earth-observation-payload/ -- **Tier**: L2 (press release) -- **Publication Date**: 2026-02-02 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: 3.6kg, 69cm GSD from 15km, gyro-stabilized. Benchmark for stratospheric imaging. Price unknown (likely >>$30k). - -## Source #15 -- **Title**: A40TR Pro Product Page (Airmobi) -- **Link**: https://www.airmobi.com/product/a40tr-pro-40x-eo-ir-lrf-ai-object-tracking-gimbal-camera/ -- **Tier**: L1 (manufacturer) -- **Publication Date**: 2024-2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: $7,499-7,999. 40x zoom EO + thermal + LRF. 3-axis gimbal. ±0.005° pointing. MIL-STD-810H certified. - -## Source #16 -- **Title**: Foxtech Seeker-30 TR Product Page -- **Link**: https://store.foxtech.com/seeker-30-tr-30x-optical-zoom-camera-with-3-axis-gimbal/ -- **Tier**: L1 (manufacturer) -- **Publication Date**: 2024-2025 -- **Timeliness Status**: ✅ Currently valid -- **Summary**: $3,899-4,299. 30x optical zoom, 2.13MP 1080p. Auto tracking. 4.0kg. Serial/PWM control. - -## Source #17 -- **Title**: High-altitude balloon payload stabilization research -- **Link**: https://iastatedigitalpress.com/ahac/article/5570/galley/5436/view/ -- **Tier**: L1 (academic) -- **Timeliness Status**: ✅ Currently valid -- **Summary**: Balloon payloads experience continuous rotation and pendulum swinging. Active gimbals may be insufficient alone. Passive stabilization through suspension design is critical. - -## Source #18 -- **Title**: Sony RX10 IV Specifications -- **Link**: https://www.bhphotovideo.com/c/product/1361560-REG/ -- **Tier**: L1 -- **Publication Date**: 2017 (product), specs current -- **Timeliness Status**: ✅ Currently valid (still in production) -- **Summary**: $1,700. 1" sensor 20MP, 24-600mm equiv (8.8-220mm actual), 2.41µm pixel pitch. 4K video. diff --git a/_standalone/camera_high_altitude/00_research/camera_high_altitude/02_fact_cards.md b/_standalone/camera_high_altitude/00_research/camera_high_altitude/02_fact_cards.md deleted file mode 100644 index a2f8b86..0000000 --- a/_standalone/camera_high_altitude/00_research/camera_high_altitude/02_fact_cards.md +++ /dev/null @@ -1,103 +0,0 @@ -# Fact Cards - -## Fact #1 -- **Statement**: GSD formula: GSD = (pixel_pitch × altitude) / focal_length. This is the fundamental relationship between sensor, optics, altitude, and ground resolution. -- **Source**: Source #3 (Pix4d) -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #2 -- **Statement**: Atmospheric turbulence limits ground resolution from 10km altitude to approximately 4.6 cm regardless of optical system quality. Practical achievable limit is 5-8 cm in good conditions. -- **Source**: Source #2 (Optica journal) -- **Phase**: Phase 1 -- **Confidence**: ✅ High - -## Fact #3 -- **Statement**: Vehicle detection requires ~1m GSD. Vehicle type identification requires ~25-50 cm GSD. Detailed vehicle description requires ~10 cm GSD. Per NIIRS scale. -- **Source**: Source #1 (NIIRS Guide) -- **Phase**: Phase 1 -- **Confidence**: ✅ High - -## Fact #4 -- **Statement**: Training data GSD is approximately 10-20 cm/pixel (user confirmed). Target GSD from 10km must match this range. -- **Source**: User confirmation -- **Phase**: Phase 1 -- **Confidence**: ✅ High - -## Fact #5 -- **Statement**: ViewPro A40 Pro achieves GSD of 11.6 cm/pixel from 10km at maximum zoom (170mm FL, 5MP stills). Video (1080p) gives 15.6 cm/pixel. Both within target 10-20 cm range. -- **Source**: Source #4 (Airmobi), calculated -- **Phase**: Phase 2 -- **Confidence**: ✅ High (calculation verified) - -## Fact #6 -- **Statement**: ViewPro Z40K achieves GSD of ~10.3 cm/pixel from 10km at maximum optical zoom (~102mm FL, 25.9MP). Significantly more pixels per frame than A40 Pro (5888 vs 2560). -- **Source**: Source #5 (Viewpro), calculated -- **Phase**: Phase 2 -- **Confidence**: ⚠️ Medium (FL estimated from HFOV spec) - -## Fact #7 -- **Statement**: DJI Zenmuse H30T achieves GSD of ~5.7 cm/pixel from 10km (172mm FL, 40MP). Best integrated zoom camera GSD. But LOCKED to DJI Matrice platform — cannot be used on custom balloon platform without reverse engineering. -- **Source**: Source #7 (DJI) -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #8 -- **Statement**: LOONG VT500Rs achieves GSD of ~4.8 cm/pixel from 10km (192mm FL, 48MP). Near atmospheric limit. Price unknown, estimated $10k-20k based on market positioning. -- **Source**: Source #8 (LoongUAV), calculated -- **Phase**: Phase 2 -- **Confidence**: ⚠️ Medium (price estimated) - -## Fact #9 -- **Statement**: Sony α7RV + FE 400-800mm achieves 4.7-9.4 cm/pixel GSD from 10km (400-800mm FL, 61MP, 3.76µm pixel pitch). Best image quality due to full-frame sensor and large pixels. Total weight with lens: 3,140g. -- **Source**: Source #9, #10 (Sony, Gremsy), calculated -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #10 -- **Statement**: Viewpro gimbal cameras have documented serial (UART) and TCP/IP control protocols (Viewlink V3.3.3). ArduPilot has native Lua driver for Viewpro gimbals. Suitable for custom platform integration. -- **Source**: Source #11, #12 (Viewpro, ArduPilot) -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #11 -- **Statement**: Gremsy T7 gimbal has 3.175kg max payload. Sony α7RV (665g) + FE 400-800mm (2,475g) = 3,140g — at the payload limit with virtually no margin. Risk of unreliable operation. -- **Source**: Source #10 (Gremsy) -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #12 -- **Statement**: Balloon payloads experience continuous rotation and pendulum swinging. Active gimbal alone may be insufficient. Passive stabilization through suspension design is critical for image quality. -- **Source**: Source #17 (Iowa State) -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #13 -- **Statement**: SIYI ZT30 is a 4-sensor pod ($6,099-7,309) with 30x optical zoom, 8MP, 4K, thermal, and LRF. 9W average power. Achieves ~12 cm/pixel GSD from 10km. -- **Source**: Source #6 (SIYI) -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #14 -- **Statement**: A40TR Pro ($7,499-7,999) adds thermal imaging and laser rangefinder to the 40x zoom capability. MIL-STD-810H certified for -40°C to +55°C — best temperature rating among all options. -- **Source**: Source #15 (Airmobi) -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #15 -- **Statement**: Sony RX10 IV ($1,700) with 1" sensor and 220mm actual FL achieves ~11 cm/pixel GSD from 10km. Has 20MP resolution (5472×3648). Needs external gimbal for balloon mounting. No documented remote zoom control for UAV integration. -- **Source**: Source #18 (B&H) -- **Phase**: Phase 2 -- **Confidence**: ⚠️ Medium (remote control integration unclear) - -## Fact #16 -- **Statement**: With zoom capability, cameras can be adjusted to match any target GSD within their zoom range. A camera capable of 5cm GSD at max zoom can be zoomed out to deliver 10-20cm GSD matching training data. This means over-capability in GSD is an advantage, not a problem. -- **Source**: Derived from GSD formula -- **Phase**: Phase 2 -- **Confidence**: ✅ High - -## Fact #17 -- **Statement**: Atmospheric haze at 10km reduces image contrast compared to 600-1000m imagery. Even with matched GSD, the AI model may need image preprocessing (dehazing) or fine-tuning for degraded imagery. -- **Source**: Source #2 (atmospheric research) -- **Phase**: Phase 2 -- **Confidence**: ⚠️ Medium (impact on specific AI model unknown) diff --git a/_standalone/camera_high_altitude/00_research/camera_high_altitude/03_comparison_framework.md b/_standalone/camera_high_altitude/00_research/camera_high_altitude/03_comparison_framework.md deleted file mode 100644 index d82c50f..0000000 --- a/_standalone/camera_high_altitude/00_research/camera_high_altitude/03_comparison_framework.md +++ /dev/null @@ -1,51 +0,0 @@ -# Comparison Framework - -## Selected Framework Type -Decision Support — evaluating trade-offs between gimbal camera systems for a specific use case - -## Selected Dimensions -1. GSD from 10km (achievable ground resolution) -2. Image resolution / FOV coverage -3. Sensor quality (size, SNR, dynamic range) -4. Integration feasibility (control protocol, balloon platform compatibility) -5. Stabilization quality (gimbal precision, balloon motion handling) -6. Additional sensors (thermal, LRF) -7. Power requirements -8. Weight -9. Price (total system cost) -10. Atmospheric haze resilience (sensor size impact on contrast) - -## GSD Calculations Summary - -All calculations assume: -- Altitude: 10,000m -- Target GSD: 10-20 cm/pixel (to match AI training data) - -| System | Sensor | Pixel Pitch | Max FL | GSD@10km | Resolution | FOV@10km | In Target? | -|---|---|---|---|---|---|---|---| -| A40 Pro | 1/2.8" 5MP | 1.98µm | 170mm | 11.6 cm | 2560×1920 | 297×223m | ✅ Yes | -| Z40K | 1/2.3" 25.9MP | 1.05µm | ~102mm | 10.3 cm | 5888×4400 | 606×453m | ✅ Yes | -| SIYI ZT30 | 1/2.7" 8MP | ~1.65µm | ~138mm | 12.0 cm | 3264×2448 | 392×294m | ✅ Yes | -| A40TR Pro | 1/2.8" 5MP | 1.98µm | 170mm | 11.6 cm | 2560×1920 | 297×223m | ✅ Yes | -| DJI H30T | 1/1.8" 40MP | 0.99µm | 172mm | 5.7 cm | 7296×5472 | 416×312m | ✅ (adjustable) | -| VT500Rs | ~1/2" 48MP | 0.92µm | 192mm | 4.8 cm | 8000×6000 | 385×289m | ✅ (adjustable) | -| Sony α7RV+800mm | FF 61MP | 3.76µm | 800mm | 4.7 cm | 9504×6336 | 447×298m | ✅ (adjustable) | -| Sony RX10 IV | 1" 20MP | 2.41µm | 220mm | 11.0 cm | 5472×3648 | 602×401m | ✅ Yes | - -## Initial Population - -| Dimension | A40 Pro | Z40K | SIYI ZT30 | A40TR Pro | Sony α7RV+800mm | Sony RX10 IV | -|---|---|---|---|---|---|---| -| GSD@10km | 11.6 cm ✅ | 10.3 cm ✅ | 12.0 cm ✅ | 11.6 cm ✅ | 4.7-9.4 cm ✅ | 11.0 cm ✅ | -| Resolution | 5MP (low) | 25.9MP (good) | 8MP (adequate) | 5MP (low) | 61MP (excellent) | 20MP (good) | -| FOV@10km | 297×223m | 606×453m | 392×294m | 297×223m | 447×298m | 602×401m | -| Sensor quality | Small, low SNR | Small, decent | Small, adequate | Small, low SNR | Full-frame, excellent | 1", good | -| Integration | Serial/TCP ✅ | Serial/TCP ✅ | Serial ✅ | Serial/TCP ✅ | Custom ⚠️ | Custom ⚠️ | -| Gimbal quality | ±0.02° | ±0.02° | ±0.01° | ±0.005° | Gremsy T7 ±0.02° | Needs external | -| Additional sensors | AI tracking | AI tracking | Thermal+LRF | Thermal+LRF | None | None | -| Power | ~15-25W | ~15-25W | 9W avg | ~20-30W | ~40-60W | ~10-15W | -| Weight | ~1kg | ~1kg | ~1.2kg | ~1.5kg | ~5kg total | ~1.1kg+gimbal | -| Price | $2,299 | $3,000-5,000 | $6,099-7,309 | $7,499-7,999 | ~$10,850 | ~$4,200-5,200 | -| Haze resilience | Low | Low | Low | Low | High | Moderate | - -Note: DJI H30T ($10,240-11,610) and LOONG VT500Rs (price unknown) excluded from primary comparison due to DJI platform lock and unknown pricing respectively. diff --git a/_standalone/camera_high_altitude/00_research/camera_high_altitude/04_reasoning_chain.md b/_standalone/camera_high_altitude/00_research/camera_high_altitude/04_reasoning_chain.md deleted file mode 100644 index fd14b7a..0000000 --- a/_standalone/camera_high_altitude/00_research/camera_high_altitude/04_reasoning_chain.md +++ /dev/null @@ -1,130 +0,0 @@ -# Reasoning Chain - -## Dimension 1: GSD Achievability - -### Fact Confirmation -All candidate systems achieve 10-20 cm/pixel GSD from 10km (Facts #5-#9, #15). The atmospheric limit is ~5cm (Fact #2), so all options are optics-limited (good — no wasted capability). - -### Reference Comparison -Systems with higher zoom/longer FL can achieve finer GSD but can always zoom out to match training data (Fact #16). Higher-capability systems provide flexibility to zoom in for closer inspection of specific targets. - -### Conclusion -All candidates pass the GSD requirement. Systems with higher resolution sensors (Z40K 25.9MP, Sony α7RV 61MP) provide significantly better spatial coverage per frame at the target GSD. - -### Confidence -✅ High — based on verified calculations - ---- - -## Dimension 2: Image Quality for AI Model Reuse - -### Fact Confirmation -The AI model was trained on 10-20 cm/pixel imagery from 600-1000m altitude (Fact #4). At that altitude, atmospheric path is short — images are sharp with high contrast. At 10km, haze reduces contrast (Fact #17). - -### Reference Comparison -Larger sensors have better SNR and dynamic range, which partially compensates for atmospheric degradation: -- Full-frame (Sony α7RV): 3.76µm pixels, excellent SNR -- 1" sensor (RX10 IV): 2.41µm pixels, good SNR -- 1/2.3" to 1/2.8" (drone gimbals): 1.0-2.0µm pixels, limited SNR - -Smaller pixels on drone gimbals mean each pixel gathers less light, amplifying atmospheric haze impact. - -### Conclusion -For AI model reuse from 10km, larger sensors provide measurably better imagery. However, the practical impact depends on atmospheric conditions. In mostly sunny weather (user constraint), even small-sensor cameras may produce adequate results. Computational dehazing can bridge the gap. The Sony full-frame option offers the best margin of safety for image quality. - -### Confidence -⚠️ Medium — depends on specific atmospheric conditions and AI model sensitivity - ---- - -## Dimension 3: Platform Integration - -### Fact Confirmation -Viewpro cameras have documented serial (Viewlink) and TCP protocols (Fact #10). ArduPilot has native Lua driver. SIYI has serial protocol. DJI H30T is locked to DJI Matrice (Fact #7). Sony cameras have no native gimbal/serial integration. - -### Reference Comparison -- Viewpro/Airmobi: Plug-and-play for custom platforms via UART/TCP. Best integration story. -- SIYI: Serial protocol available, community support in ArduPilot ecosystem. -- Sony + Gremsy: Gremsy T7 has MAVLink support, but camera zoom/photo control requires separate integration (USB/HDMI). More complex. -- DJI: Effectively impossible on non-DJI platforms. - -### Conclusion -Chinese drone gimbal cameras (Viewpro, SIYI) offer the simplest path to balloon integration. Sony approach requires significantly more custom engineering. DJI is disqualified for this use case. - -### Confidence -✅ High — based on manufacturer documentation and open-source drivers - ---- - -## Dimension 4: Balloon-Specific Stabilization - -### Fact Confirmation -Balloon payloads experience continuous rotation and pendulum swinging (Fact #12). Active gimbal alone may be insufficient. All candidate gimbals have ±0.01° to ±0.02° vibration accuracy. - -### Comparison -All integrated drone gimbals are designed for UAV vibration (high frequency, small amplitude). Balloon motion is different (low frequency, large amplitude rotation/swinging). The A40TR Pro has the tightest pointing accuracy (±0.005°) and MIL-STD certification. - -For the Sony approach, the Gremsy T7 is at payload limit (3,140g vs 3,175g max) — this leaves almost no margin and the gimbal motors may struggle with balloon-specific motion compensation. - -### Conclusion -All candidates need passive stabilization via suspension design (anti-rotation mechanism, pendulum dampers). The gimbal handles residual motion. The A40TR Pro has the best specifications for pointing accuracy. The Sony approach has gimbal weight margin concerns. - -### Confidence -⚠️ Medium — balloon-specific testing required to validate - ---- - -## Dimension 5: Cost-Benefit Analysis - -### Fact Confirmation -Budget: $30k. Options range from $2,299 to ~$10,850 for the camera system alone. Need to account for integration hardware, cables, power, and passive stabilization. - -### Comparison -| Option | Camera System | Integration/Mounting | Passive Stabilization | Total Est. | -|---|---|---|---|---| -| A40 Pro | $2,299 | $500 | $1,000-2,000 | $3,800-4,800 | -| Z40K | $3,000-5,000 | $500 | $1,000-2,000 | $4,500-7,500 | -| SIYI ZT30 | $6,099-7,309 | $500 | $1,000-2,000 | $7,600-9,800 | -| A40TR Pro | $7,499-7,999 | $500 | $1,000-2,000 | $9,000-10,500 | -| Sony α7RV+800mm+T7 | $10,850 | $2,000-3,000 | $1,000-2,000 | $13,850-15,850 | - -All options are well within $30k budget. - -### Conclusion -There's significant budget headroom. The decision should be driven by image quality needs and integration simplicity rather than cost alone. Even the premium Sony option leaves >$14k for contingency and additional equipment. - -### Confidence -✅ High — pricing from manufacturer sources - ---- - -## Dimension 6: Recommendation Reasoning - -### For maximum simplicity and value: ViewPro Z40K ($3,000-5,000) -- 25.9MP resolution gives excellent ground coverage (606×453m FOV) -- 10.3 cm GSD at max zoom matches training data -- 4K video for review -- Documented serial protocol for custom integration -- Lightweight (~1kg) -- Leaves >$25k budget for spare units, integration, and contingency - -### For maximum image quality: Sony α7RV + FE 400-800mm + Gremsy T7 (~$10,850) -- Full-frame sensor provides best atmospheric haze resilience -- Adjustable zoom from 400-800mm (9.4-4.7 cm GSD) -- 61MP resolution for highest detail -- Risk: weight at gimbal limit, complex integration, no turnkey zoom control - -### For best balance of quality, features, and integration: A40TR Pro ($7,499-7,999) -- 40x zoom (170mm max) gives 11.6 cm GSD — within target -- MIL-STD-810H certification (-40°C to +55°C) — best environmental rating -- Thermal camera for night/low-visibility operation -- Laser rangefinder for target distance measurement -- ±0.005° pointing accuracy — tightest of all options -- Documented serial protocol -- Only 1.5kg - -### For maximum versatility with multi-sensor: SIYI ZT30 ($6,099-7,309) -- 4 sensors (zoom, thermal, wide-angle, LRF) -- 12 cm GSD at max zoom — within target -- Lowest power consumption (9W average) -- Wide ArduPilot/PX4 community support diff --git a/_standalone/camera_high_altitude/00_research/camera_high_altitude/05_validation_log.md b/_standalone/camera_high_altitude/00_research/camera_high_altitude/05_validation_log.md deleted file mode 100644 index 3aff4b6..0000000 --- a/_standalone/camera_high_altitude/00_research/camera_high_altitude/05_validation_log.md +++ /dev/null @@ -1,51 +0,0 @@ -# Validation Log - -## Validation Scenario -A balloon at 10km altitude in eastern Ukraine on a sunny day needs to photograph a convoy of military trucks on a road. The AI model (trained on 600-1000m imagery at 10-20 cm/pixel) must detect and classify the vehicles. - -## Expected Based on Conclusions - -### Using ViewPro Z40K: -- GSD at max zoom: 10.3 cm/pixel. Each truck (~8m long) ≈ 78 pixels long in the image. -- FOV: 606×453m — covers a road segment of ~600m. Can see multiple vehicles. -- Image quality: 25.9MP provides good detail. Small sensor (1/2.3") may show some contrast loss from haze in sunny conditions. -- Integration: Serial control from companion computer. Can trigger photos and adjust zoom remotely. -- Expected: Model should detect trucks with reasonable confidence. May need dehazing in hazy conditions. - -### Using A40TR Pro: -- GSD at max zoom: 11.6 cm/pixel. Each truck ≈ 69 pixels long. -- FOV: 297×223m — narrower coverage, fewer vehicles per frame. -- Thermal camera adds night capability and can detect engine heat signatures. -- MIL-STD certified, most robust for field conditions. -- Expected: Model should detect trucks. Thermal overlay provides backup detection. - -### Using Sony α7RV + 400-800mm: -- At 600mm (15.8 cm GSD target): GSD = 6.3 cm/pixel. Each truck ≈ 127 pixels long. -- FOV: 599×399m — good coverage. -- Full-frame sensor captures more light per pixel, better contrast through haze. -- Expected: Best image quality. Model may need GSD adjustment (zoom to match 10-20cm range or downscale). -- Risk: Gimbal at weight limit may cause jitter on balloon. Integration is complex. - -## Actual Validation Results (analytical) - -1. All three systems can achieve the target 10-20 cm/pixel GSD — validated by calculation -2. Trucks at 10-20 cm/pixel occupy ~40-80 pixels in length — sufficient for CNN-based detection models -3. Atmospheric haze in sunny conditions over Ukraine plains is typically moderate — dehazing should be effective -4. Balloon passive stabilization is the unvalidated risk — needs physical prototyping - -## Counterexamples - -1. **Cloudy/hazy day**: Small-sensor cameras will produce significantly degraded imagery. The Sony full-frame option is more resilient but still affected. Cloud cover completely blocks all optical imaging. -2. **Nighttime**: Only A40TR Pro and SIYI ZT30 have thermal cameras for night operation. Others are daylight-only. -3. **Fast-moving targets**: At 10km range, even fast vehicles appear slow relative to the camera. Not a concern. -4. **Very small targets**: People or small objects at 10-20 cm/pixel would be only a few pixels — below detection threshold. This use case is for trucks/vehicles only. - -## Review Checklist -- [x] Draft conclusions consistent with fact cards -- [x] No important dimensions missed -- [x] No over-extrapolation -- [x] Conclusions actionable — user can purchase any recommended system -- [ ] Note: Balloon-specific stabilization requires physical validation - -## Conclusions Requiring Revision -None — but balloon motion compensation is flagged as the key unknown requiring prototyping. diff --git a/_standalone/camera_high_altitude/01_solution/solution_draft01.md b/_standalone/camera_high_altitude/01_solution/solution_draft01.md deleted file mode 100644 index f4bd431..0000000 --- a/_standalone/camera_high_altitude/01_solution/solution_draft01.md +++ /dev/null @@ -1,152 +0,0 @@ -# Solution Draft — Gimbal Camera for High-Altitude Balloon (10km) - -## Product Solution Description - -A zoom gimbal camera mounted on a balloon at 10km altitude, producing imagery with 10-20 cm/pixel GSD to match an AI detection model trained on 600-1000m altitude data. The system must detect trucks, vehicles, and tracked machinery. Budget: under $30k. - -The solution consists of: (1) a zoom gimbal camera with documented serial/TCP control protocol, (2) passive anti-rotation and pendulum damping suspension between the balloon and the camera, (3) a companion computer controlling the gimbal via serial/TCP/MAVLink, and (4) optional computational dehazing to improve image quality through 10km of atmosphere. - -``` -Balloon (10km) - │ - ├── Anti-rotation swivel - │ - ├── Pendulum damper / shock absorber - │ - └── Camera payload bay (thermally protected) - ├── Zoom gimbal camera (3-axis stabilized) - ├── Companion computer (control + image capture) - └── Power distribution -``` - -## Existing/Competitor Solutions Analysis - -| Solution | Altitude | GSD | Price | Notes | -|---|---|---|---|---| -| UAVOS POD (HAPS) | 15km | 69 cm/pixel | Unknown (>>$30k) | Purpose-built for stratosphere. GSD too coarse for vehicle identification | -| Aerostat systems (SKYSTAR, Hemeria) | 500-3500m | Sub-meter | $28k-500k+ | Lower altitude, includes balloon+winch+camera. Purpose-built but wrong altitude range | -| Military gimbals (WESCAM MX-10) | Any | Sub-cm to m | $100k-500k+ | Best quality but far exceeds budget and has export restrictions | -| DJI Zenmuse H30T | Drone altitude | 5.7 cm @10km | $10,240 | Excellent camera but locked to DJI Matrice drones. Cannot be used on custom balloon platform | - -No off-the-shelf solution exists for a $30k camera on a 10km balloon with 10-20cm GSD. All viable approaches use drone gimbal cameras adapted for balloon mounting. - -## Architecture - -### Component: Zoom Gimbal Camera - -| Solution | Sensor / Resolution | Max FL / GSD@10km | FOV@10km | Integration | Additional Sensors | Weight | Price | Fit | -|---|---|---|---|---|---|---|---|---| -| **ViewPro Z40K** | 1/2.3" 25.9MP | ~102mm / 10.3 cm | 606×453m | Serial/TCP, ArduPilot ✅ | AI tracking | ~1kg | $3,000-5,000 | ⭐ Best value — highest resolution for price, largest FOV | -| **A40TR Pro** | 1/2.8" 5MP | 170mm / 11.6 cm | 297×223m | Serial/TCP, ArduPilot ✅ | Thermal + LRF + AI | ~1.5kg | $7,499-7,999 | ⭐ Best multi-sensor — thermal night ops, MIL-STD-810H, tightest pointing | -| **SIYI ZT30** | 1/2.7" 8MP | ~138mm / 12.0 cm | 392×294m | Serial, ArduPilot/PX4 ✅ | Thermal + LRF + wide-angle | ~1.2kg | $6,099-7,309 | Good versatility — 4 sensors, lowest power (9W), wide community support | -| **ViewPro A40 Pro** | 1/2.8" 5MP | 170mm / 11.6 cm | 297×223m | Serial/TCP, ArduPilot ✅ | AI tracking | ~1kg | $2,299 | Budget option — proven 40x zoom, lowest cost, but only 5MP/1080p | -| **Sony α7RV + 400-800mm + T7** | FF 61MP | 800mm / 4.7 cm | 447×298m | Custom integration ⚠️ | None | ~5kg | ~$10,850 | Best image quality — full-frame, best haze resilience, complex integration | -| **Sony RX10 IV + gimbal** | 1" 20MP | 220mm / 11.0 cm | 602×401m | Custom integration ⚠️ | None | ~1.1kg+gimbal | ~$4,200-5,200 | Good sensor quality, wide FOV, but no remote zoom protocol | - -### GSD Calculation Reference - -``` -GSD = (pixel_pitch × altitude) / focal_length - -Example for Z40K: - pixel_pitch = 6.17mm / 5888px = 1.048µm - GSD = (0.001048mm × 10,000,000mm) / 102mm = 102.7mm ≈ 10.3 cm/pixel -``` - -### Component: Passive Stabilization System - -| Solution | Mechanism | Advantages | Limitations | Cost | Fit | -|---|---|---|---|---|---| -| Anti-rotation swivel + pendulum damper | Mechanical swivel bearing at suspension point, viscous/spring dampers on suspension lines | Proven in aerostat/balloon systems, no power needed, reduces rotation to near-zero | Adds weight (1-3kg), requires custom fabrication | $1,000-3,000 | Recommended baseline | -| Passive pendulum (long suspension line) | Increase distance between balloon and payload (5-10m line) | Simple, reduces oscillation frequency | Doesn't eliminate rotation, adds deployment complexity | $200-500 | Supplement to swivel | -| Reaction wheel (active) | Motorized flywheel counters rotation torque | Eliminates rotation completely | Adds complexity, weight, and power draw | $2,000-5,000 | For demanding pointing requirements | - -### Component: Companion Computer Integration - -For this project, the existing GPS-Denied system runs on Jetson Orin Nano with MAVLink/MAVSDK. The gimbal camera integration would use the same companion computer architecture: - -| Approach | Protocol | Camera Support | Complexity | Fit | -|---|---|---|---|---| -| ArduPilot Lua driver (Viewpro) | Viewlink serial | A40 Pro, Z40K, A40TR Pro | Low — use existing ArduPilot driver | Best for Viewpro cameras | -| MAVLink Gimbal Protocol v2 | MAVLink serial | SIYI, Viewpro (via proxy) | Low-Medium — standard protocol | Best for SIYI cameras | -| Custom serial integration | Manufacturer protocol | Any with serial API | Medium — write custom driver | Fallback for any camera | -| USB/HDMI + Gremsy SDK | USB + CAN | Sony + Gremsy T7 | High — separate camera and gimbal control | Only option for Sony approach | - -### Component: Image Preprocessing (Atmospheric Haze Mitigation) - -| Solution | Approach | Advantages | Limitations | Cost | Fit | -|---|---|---|---|---|---| -| Dark Channel Prior dehazing | Classic computer vision algorithm | Fast, no training needed, well-proven | May introduce artifacts, struggles with sky regions | Free (OpenCV) | Good baseline | -| CNN-based dehazing (AOD-Net, DehazeFormer) | Deep learning single-image dehazing | Better quality than classical, handles complex haze | Needs GPU, adds latency (~50-100ms) | Free (open source) | Better quality, adds processing time | -| Multi-scale Retinex (MSR) | Contrast enhancement | Simple, fast, improves visibility | Not true dehazing, may amplify noise | Free (OpenCV) | Quick alternative | -| No dehazing (sunny weather) | Direct use | No processing overhead | May reduce AI model accuracy in hazy conditions | Free | Acceptable for clear conditions | - -## Recommendations - -### Primary Recommendation: ViewPro Z40K ($3,000-5,000) - -**Rationale**: Best value proposition for this specific use case. -- 25.9MP resolution — by far the highest among integrated gimbal cameras in this price range -- 10.3 cm/pixel GSD at max zoom — directly matches training data range -- 606×453m FOV — covers the largest ground area per frame, meaning more vehicles visible per image -- 4K video output for live monitoring -- Documented Viewlink serial protocol with existing ArduPilot driver -- ~1kg weight, ~15-25W power -- $3,000-5,000 leaves ample budget for integration, spares, and contingency - -**Total estimated system cost**: $5,000-8,000 (camera + passive stabilization + integration hardware) - -### Secondary Recommendation: A40TR Pro ($7,499-7,999) - -**When to choose instead**: If you need night/thermal operation, laser ranging for target distance, or require MIL-STD-810H environmental certification. The thermal camera enables 24/7 operation and backup detection when optical imagery is degraded. - -**Trade-off**: 5MP EO resolution is significantly lower than Z40K's 25.9MP, resulting in 4x smaller ground coverage per frame. For pure AI detection in daylight, Z40K is better. - -**Total estimated system cost**: $9,000-12,000 - -### Alternative: Sony α7RV + FE 400-800mm + Gremsy T7 (~$10,850) - -**When to choose**: If atmospheric haze proves too degrading for small-sensor cameras, the full-frame sensor provides significantly better contrast and SNR. This is the "maximum image quality" option. - -**Risks**: -- Camera+lens weight (3,140g) is at the Gremsy T7 payload limit (3,175g) — virtually no margin -- No turnkey integration — requires custom camera control, zoom control, and photo trigger -- Sony camera rated 0-40°C only (balloon thermal protection must maintain this range) -- Most complex and heaviest system - -**Total estimated system cost**: $13,850-15,850 - -## Testing Strategy - -### Integration / Functional Tests -- Mount camera on test platform, verify serial/TCP control of zoom, pan, tilt, and photo capture -- Verify image capture at different zoom levels and calculate actual GSD against predictions -- Test passive stabilization mock-up with simulated balloon motion (pendulum, rotation) -- Verify power budget under sustained operation (camera + gimbal + companion computer) - -### Non-Functional Tests -- Ground-level test: photograph known-size vehicles from maximum available height and verify AI model detection at target GSD (resize images to simulate 10km GSD) -- Atmospheric test: if possible, test from lower altitude (1-2km) and compare image quality with/without dehazing -- Duration test: run camera continuously for 4+ hours to verify thermal stability and reliability -- Balloon integration test: short tethered balloon flight at lower altitude to validate stabilization and control - -## References - -- NIIRS Civil Reference Guide — https://irp.fas.org/imint/niirs_c/guide.htm -- Atmospheric resolution limit — https://opg.optica.org/josa/abstract.cfm?uri=josa-56-10-1380 -- GSD formula — https://support.pix4d.com/hc/en-us/articles/202558849 -- Airmobi A40 Pro — https://www.airmobi.com/product/a40-pro-40x-optical-zoom-3-axis-ai-tracking-gimbal-camera/ -- ViewPro Z40K — https://www.viewprouav.com/product/z40k-single-4k-hd-25-times-zoom-gimbal-camera.html -- A40TR Pro — https://www.airmobi.com/product/a40tr-pro-40x-eo-ir-lrf-ai-object-tracking-gimbal-camera/ -- SIYI ZT30 — https://shop.siyi.biz/products/siyi-zt30 -- DJI H30T — https://enterprise.dji.com/zenmuse-h30-series/specs -- LOONG VT500Rs — https://www.loonguav.com/vt500rs -- Sony FE 400-800mm — https://alphauniverse.com/stories/sony-unveils-specialty-400800mm-f6-38-g-oss-super-telephoto-zoom-g-lens/ -- Gremsy T7 — https://gremsy.com/gremsy-t7-spec -- Viewpro Viewlink Protocol — https://www.viewprotech.com/index.php?ac=article&at=read&did=510 -- ArduPilot Viewpro Driver — https://github.com/ArduPilot/ardupilot/pull/22568 -- MAVLink Gimbal Protocol v2 — https://mavlink.io/en/services/gimbal_v2.html -- UAVOS POD — https://uasweekly.com/2026/02/02/uavos-unveils-stratospheric-earth-observation-payload/ -- Balloon stabilization — https://iastatedigitalpress.com/ahac/article/5570/galley/5436/view/ -- Sony RX10 IV — https://www.bhphotovideo.com/c/product/1361560-REG/ -- Foxtech Seeker-30 TR — https://store.foxtech.com/seeker-30-tr-30x-optical-zoom-camera-with-3-axis-gimbal/ diff --git a/_standalone/camera_high_altitude/camera_high_altitude.md b/_standalone/camera_high_altitude/camera_high_altitude.md deleted file mode 100644 index 2eec50f..0000000 --- a/_standalone/camera_high_altitude/camera_high_altitude.md +++ /dev/null @@ -1,6 +0,0 @@ -I have an balloon flying on the 10 km altitude. -I have also AI detection model trained on the annotations of objects taken from 600-1000 m altitude. -I want to reuse this model to detect objects taken from the camera on the balloon. -For that I want to use some camera with zoom capabilities on a pretty decent gimbal. - -Research for the options for such gimbal camera under $30k \ No newline at end of file diff --git a/config/ci/runtime.env b/config/ci/runtime.env deleted file mode 100644 index bb54efc..0000000 --- a/config/ci/runtime.env +++ /dev/null @@ -1,6 +0,0 @@ -GPSD_ENV=ci -GPSD_LOG_LEVEL=info -GPSD_CONFIG_DIR=./config/ci -GPSD_CACHE_DIR=./data/cache -GPSD_FDR_DIR=./data/fdr -GPSD_CAMERA_SOURCE=./tests/fixtures diff --git a/config/development/runtime.env b/config/development/runtime.env deleted file mode 100644 index fa6e3e0..0000000 --- a/config/development/runtime.env +++ /dev/null @@ -1,6 +0,0 @@ -GPSD_ENV=development -GPSD_LOG_LEVEL=debug -GPSD_CONFIG_DIR=./config/development -GPSD_CACHE_DIR=./data/cache -GPSD_FDR_DIR=./data/fdr -GPSD_CAMERA_SOURCE=./data/input diff --git a/config/jetson/runtime.env b/config/jetson/runtime.env deleted file mode 100644 index daf8330..0000000 --- a/config/jetson/runtime.env +++ /dev/null @@ -1,6 +0,0 @@ -GPSD_ENV=jetson -GPSD_LOG_LEVEL=info -GPSD_CONFIG_DIR=/etc/gps-denied-onboard -GPSD_CACHE_DIR=/var/lib/gps-denied/cache -GPSD_FDR_DIR=/var/lib/gps-denied/fdr -GPSD_CAMERA_SOURCE=hardware diff --git a/config/production/runtime.env.example b/config/production/runtime.env.example deleted file mode 100644 index 480c6aa..0000000 --- a/config/production/runtime.env.example +++ /dev/null @@ -1,10 +0,0 @@ -GPSD_ENV=production -GPSD_LOG_LEVEL=info -GPSD_CONFIG_DIR=/etc/gps-denied-onboard -GPSD_CACHE_DIR=/var/lib/gps-denied/cache -GPSD_FDR_DIR=/var/lib/gps-denied/fdr -GPSD_DATABASE_URL=postgresql://user:password@localhost:5432/gpsd -GPSD_MAVLINK_URL=serial:/dev/ttyTHS1:921600 -GPSD_CAMERA_SOURCE=hardware -GPSD_SIGNING_KEY_REF=replace-with-secret-manager-reference -GPSD_MAX_FDR_BYTES=68719476736 diff --git a/data/cache/.gitkeep b/data/cache/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/data/cache/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/data/expected/.gitkeep b/data/expected/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/data/expected/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/data/fdr/.gitkeep b/data/fdr/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/data/fdr/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/data/input/.gitkeep b/data/input/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/data/input/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/data/test-results/.gitkeep b/data/test-results/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/data/test-results/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/deployment/compose/README.md b/deployment/compose/README.md deleted file mode 100644 index b0a34b3..0000000 --- a/deployment/compose/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Compose Configuration - -Runtime compose files live at the repository root so local and CI commands can -use Docker defaults without extra path arguments. diff --git a/deployment/docker/Dockerfile.replay b/deployment/docker/Dockerfile.replay deleted file mode 100644 index afc04c4..0000000 --- a/deployment/docker/Dockerfile.replay +++ /dev/null @@ -1,20 +0,0 @@ -FROM python:3.12-slim-bookworm - -ENV PYTHONDONTWRITEBYTECODE=1 -ENV PYTHONUNBUFFERED=1 - -WORKDIR /app - -RUN groupadd --system gpsd && useradd --system --gid gpsd --home-dir /app gpsd - -COPY pyproject.toml README.md ./ -COPY src ./src -COPY tests ./tests -COPY e2e ./e2e - -RUN python -m pip install --no-cache-dir --upgrade pip \ - && python -m pip install --no-cache-dir ".[dev]" - -USER gpsd - -CMD ["python", "-m", "pytest"] diff --git a/deployment/docker/Dockerfile.runtime b/deployment/docker/Dockerfile.runtime deleted file mode 100644 index 83a8ed5..0000000 --- a/deployment/docker/Dockerfile.runtime +++ /dev/null @@ -1,18 +0,0 @@ -FROM python:3.12-slim-bookworm - -ENV PYTHONDONTWRITEBYTECODE=1 -ENV PYTHONUNBUFFERED=1 - -WORKDIR /app - -RUN groupadd --system gpsd && useradd --system --gid gpsd --home-dir /app gpsd - -COPY pyproject.toml README.md ./ -COPY src ./src - -RUN python -m pip install --no-cache-dir --upgrade pip \ - && python -m pip install --no-cache-dir . - -USER gpsd - -CMD ["python", "-c", "import shared.contracts; print('gps-denied runtime scaffold ready')"] diff --git a/deployment/jetson/README.md b/deployment/jetson/README.md deleted file mode 100644 index 2746324..0000000 --- a/deployment/jetson/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Jetson Deployment Notes - -Reserved for Jetson provisioning, thermal/resource evidence, and hardware-runner -qualification procedures. diff --git a/deployment/scripts/collect_evidence.sh b/deployment/scripts/collect_evidence.sh deleted file mode 100644 index ac8a63e..0000000 --- a/deployment/scripts/collect_evidence.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -mkdir -p e2e/reports data/test-results -printf 'Evidence collection placeholder. Wire runtime reports in deploy phase.\n' diff --git a/docker-compose.test.yml b/docker-compose.test.yml deleted file mode 100644 index aba2775..0000000 --- a/docker-compose.test.yml +++ /dev/null @@ -1,98 +0,0 @@ -services: - postgis: - image: postgis/postgis:16-3.4 - environment: - POSTGRES_DB: gpsd_test - POSTGRES_USER: gpsd - POSTGRES_PASSWORD: gpsd - volumes: - - ./migrations/postgresql:/docker-entrypoint-initdb.d:ro - healthcheck: - test: ["CMD-SHELL", "pg_isready -U gpsd -d gpsd_test"] - interval: 10s - timeout: 5s - retries: 5 - - gps-denied-service: - build: - context: . - dockerfile: deployment/docker/Dockerfile.runtime - networks: - - replay-net - - sitl-net - - satellite-cache-stub: - image: python:3.12-slim-bookworm - command: - - python - - -c - - "from pathlib import Path; Path('/cache/satellite/.stub-ready').write_text('ready\\n'); import time; time.sleep(3600)" - volumes: - - satellite-cache:/cache/satellite - networks: - - replay-net - - ardupilot-plane-sitl: - image: python:3.12-slim-bookworm - command: - - python - - -c - - "from pathlib import Path; Path('/tmp/sitl-blocked.txt').write_text('SITL binary unavailable in local stub\\n'); import time; time.sleep(3600)" - networks: - - sitl-net - - qgc-observer: - image: python:3.12-slim-bookworm - command: - - python - - -c - - "from pathlib import Path; Path('/tmp/qgc-observer-ready.txt').write_text('observer ready\\n'); import time; time.sleep(3600)" - networks: - - sitl-net - - replay-consumer: - build: - context: . - dockerfile: deployment/docker/Dockerfile.replay - command: - [ - "python", - "-m", - "e2e.replay.run_replay", - "--output-dir", - "/app/data/test-results", - "--input-root", - "/data/input", - ] - env_file: - - config/ci/runtime.env - environment: - GPSD_ENABLE_SITL: "1" - depends_on: - gps-denied-service: - condition: service_completed_successfully - satellite-cache-stub: - condition: service_started - ardupilot-plane-sitl: - condition: service_started - qgc-observer: - condition: service_started - volumes: - - ./_docs/00_problem/input_data:/data/input:ro - - ./_docs/00_problem/input_data/expected_results:/data/expected:ro - - ./_docs/00_problem/input_data/flight_derkachi:/data/input/flight_derkachi:ro - - ./tests/fixtures:/app/tests/fixtures:ro - - ./data/test-results:/app/data/test-results - - satellite-cache:/cache/satellite - - fdr-output:/fdr - networks: - - replay-net - - sitl-net - -networks: - replay-net: - sitl-net: - -volumes: - satellite-cache: - fdr-output: diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index ef34411..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,34 +0,0 @@ -services: - postgis: - image: postgis/postgis:16-3.4 - environment: - POSTGRES_DB: gpsd - POSTGRES_USER: gpsd - POSTGRES_PASSWORD: gpsd - ports: - - "5432:5432" - volumes: - - postgis-data:/var/lib/postgresql/data - - ./migrations/postgresql:/docker-entrypoint-initdb.d:ro - healthcheck: - test: ["CMD-SHELL", "pg_isready -U gpsd -d gpsd"] - interval: 10s - timeout: 5s - retries: 5 - - runtime: - build: - context: . - dockerfile: deployment/docker/Dockerfile.runtime - env_file: - - .env.example - depends_on: - postgis: - condition: service_healthy - volumes: - - ./data/cache:/app/data/cache - - ./data/fdr:/app/data/fdr - - ./data/input:/app/data/input:ro - -volumes: - postgis-data: diff --git a/e2e/__init__.py b/e2e/__init__.py deleted file mode 100644 index 1d30568..0000000 --- a/e2e/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Black-box and replay test support package.""" diff --git a/e2e/fixtures/cache/.gitkeep b/e2e/fixtures/cache/.gitkeep deleted file mode 100644 index 2fa992c..0000000 --- a/e2e/fixtures/cache/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -keep diff --git a/e2e/fixtures/expected/.gitkeep b/e2e/fixtures/expected/.gitkeep deleted file mode 100644 index 2fa992c..0000000 --- a/e2e/fixtures/expected/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -keep diff --git a/e2e/fixtures/mavlink/.gitkeep b/e2e/fixtures/mavlink/.gitkeep deleted file mode 100644 index 2fa992c..0000000 --- a/e2e/fixtures/mavlink/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -keep diff --git a/e2e/fixtures/telemetry/.gitkeep b/e2e/fixtures/telemetry/.gitkeep deleted file mode 100644 index 2fa992c..0000000 --- a/e2e/fixtures/telemetry/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -keep diff --git a/e2e/mocks/ardupilot_sitl/.gitkeep b/e2e/mocks/ardupilot_sitl/.gitkeep deleted file mode 100644 index 2fa992c..0000000 --- a/e2e/mocks/ardupilot_sitl/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -keep diff --git a/e2e/mocks/qgc_observer/.gitkeep b/e2e/mocks/qgc_observer/.gitkeep deleted file mode 100644 index 2fa992c..0000000 --- a/e2e/mocks/qgc_observer/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -keep diff --git a/e2e/mocks/satellite_cache_stub/.gitkeep b/e2e/mocks/satellite_cache_stub/.gitkeep deleted file mode 100644 index 2fa992c..0000000 --- a/e2e/mocks/satellite_cache_stub/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -keep diff --git a/e2e/replay/README.md b/e2e/replay/README.md deleted file mode 100644 index 8846728..0000000 --- a/e2e/replay/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Replay Harness - -Reserved for suite-level replay entry points that drive the runtime only through -public files, MAVLink/cache/FDR interfaces, and published reports. diff --git a/e2e/replay/__init__.py b/e2e/replay/__init__.py deleted file mode 100644 index facf3fa..0000000 --- a/e2e/replay/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -"""Replay harness public entry points.""" - -from .harness import BlackboxReplayRunner, ReplayRunResult, ScenarioConfig, ScenarioGroup - -__all__ = [ - "BlackboxReplayRunner", - "ReplayRunResult", - "ScenarioConfig", - "ScenarioGroup", -] diff --git a/e2e/replay/harness.py b/e2e/replay/harness.py deleted file mode 100644 index 348f833..0000000 --- a/e2e/replay/harness.py +++ /dev/null @@ -1,629 +0,0 @@ -"""Deterministic black-box replay infrastructure. - -The harness owns test-side orchestration only. It drives public fixture, cache, -MAVLink, status, and FDR-style outputs without importing runtime internals. -""" - -from __future__ import annotations - -import argparse -import csv -import json -import math -import os -from dataclasses import dataclass, field -from enum import Enum -from pathlib import Path -from time import perf_counter -from typing import Iterable, Mapping, Sequence -from uuid import uuid4 - - -REPORT_COLUMNS = [ - "Test ID", - "Test Name", - "Input Dataset", - "Execution Time (ms)", - "Result", - "Error Distance (m)", - "Source Label", - "Covariance 95% Semi-Major (m)", - "GPS_INPUT.fix_type", - "Error Message", -] - - -class ScenarioGroup(str, Enum): - BLACKBOX = "blackbox" - PERFORMANCE = "performance" - RESILIENCE = "resilience" - SECURITY = "security" - RESOURCE_LIMIT = "resource-limit" - - -class ScenarioResult(str, Enum): - PASS = "pass" - FAIL = "fail" - BLOCKED = "blocked" - - -@dataclass(frozen=True) -class ScenarioConfig: - scenario_id: str - name: str - group: ScenarioGroup - input_dataset: str - required_paths: tuple[Path, ...] = () - required_services: tuple[str, ...] = () - controls: Mapping[str, str] = field(default_factory=dict) - - -@dataclass(frozen=True) -class RecordedInteraction: - service: str - scenario_id: str - request: Mapping[str, str] - response: Mapping[str, str | bool] - - -@dataclass(frozen=True) -class ExpectedCoordinate: - image_ref: str - latitude_deg: float - longitude_deg: float - - -@dataclass(frozen=True) -class ReplayEstimate: - image_ref: str - latitude_deg: float - longitude_deg: float - covariance_95_semi_major_m: float - source_label: str - anchor_age_ms: int - capture_to_output_latency_ms: float - - -@dataclass(frozen=True) -class ResourceSample: - timestamp_s: float - process_rss_bytes: int - shared_memory_used_bytes: int - cuda_allocated_bytes: int - throttle_active: bool - temperature_c: float - - -@dataclass(frozen=True) -class ScenarioReport: - scenario_id: str - name: str - group: ScenarioGroup - input_dataset: str - result: ScenarioResult - execution_time_ms: float - error_distance_m: float | None - source_label: str - covariance_95_semi_major_m: float | None - gps_fix_type: int | None - error_message: str - artifacts: tuple[Path, ...] - interactions: tuple[RecordedInteraction, ...] - metrics: Mapping[str, float | str | bool] = field(default_factory=dict) - - -@dataclass(frozen=True) -class ReplayRunResult: - run_id: str - run_dir: Path - reports: tuple[ScenarioReport, ...] - csv_path: Path - markdown_path: Path - - @property - def completed_groups(self) -> set[ScenarioGroup]: - return {report.group for report in self.reports} - - -class DeterministicStub: - def __init__(self, service_name: str) -> None: - self.service_name = service_name - self._interactions: list[RecordedInteraction] = [] - - @property - def interactions(self) -> tuple[RecordedInteraction, ...]: - return tuple(self._interactions) - - def record( - self, - scenario_id: str, - request: Mapping[str, str], - response: Mapping[str, str | bool], - ) -> Mapping[str, str | bool]: - self._interactions.append( - RecordedInteraction( - service=self.service_name, - scenario_id=scenario_id, - request=dict(request), - response=dict(response), - ) - ) - return response - - -class SatelliteCacheStub(DeterministicStub): - def __init__(self) -> None: - super().__init__("satellite-cache-stub") - - def query_manifest(self, scenario_id: str, variant: str) -> Mapping[str, str | bool]: - trusted = variant == "valid" - return self.record( - scenario_id, - {"variant": variant}, - { - "variant": variant, - "trusted": trusted, - "freshness_status": "fresh" if trusted else "rejected", - "fixture_size_bytes": "1048576", - "storage_budget_bytes": "10737418240", - "network_fetch_attempted": False, - "provenance": "offline-fixture", - }, - ) - - -class ArdupilotSitlStub(DeterministicStub): - def __init__(self) -> None: - super().__init__("ardupilot-plane-sitl") - - def emit_trace(self, scenario_id: str, mode: str) -> Mapping[str, str | bool]: - return self.record( - scenario_id, - {"mode": mode}, - {"gps_input_recorded": True, "spoofing_mode": mode, "fix_type": "3"}, - ) - - -class QgcObserverStub(DeterministicStub): - def __init__(self) -> None: - super().__init__("qgc-observer") - - def observe_status(self, scenario_id: str, status: str) -> Mapping[str, str | bool]: - return self.record( - scenario_id, - {"status": status}, - {"statustext_recorded": True, "status": status}, - ) - - -class TestEnvironment: - def __init__(self, output_root: Path) -> None: - self.output_root = output_root - - def start( - self, - required_paths: Iterable[Path], - required_services: Iterable[str], - ) -> list[str]: - blockers = [f"missing fixture path: {path}" for path in required_paths if not path.exists()] - - if "sitl" in required_services and os.environ.get("GPSD_ENABLE_SITL") != "1": - blockers.append("SITL prerequisite blocked: set GPSD_ENABLE_SITL=1 to run live SITL") - - if "jetson" in required_services and os.environ.get("GPSD_ENABLE_JETSON") != "1": - blockers.append("Jetson prerequisite blocked: set GPSD_ENABLE_JETSON=1 on target hardware") - - self.output_root.mkdir(parents=True, exist_ok=True) - return blockers - - -class BlackboxReplayRunner: - def __init__( - self, - output_root: Path = Path("data/test-results"), - input_root: Path = Path("_docs/00_problem/input_data"), - scenarios: Sequence[ScenarioConfig] | None = None, - ) -> None: - self.output_root = output_root - self.scenarios = tuple(scenarios or default_scenarios(input_root)) - self.environment = TestEnvironment(output_root) - self.satellite_cache = SatelliteCacheStub() - self.ardupilot_sitl = ArdupilotSitlStub() - self.qgc_observer = QgcObserverStub() - - def run(self) -> ReplayRunResult: - run_id = uuid4().hex[:12] - run_dir = self.output_root / run_id - run_dir.mkdir(parents=True, exist_ok=True) - - reports = tuple(self._run_scenario(run_dir, scenario) for scenario in self.scenarios) - csv_path = self._write_csv(run_dir, reports) - markdown_path = self._write_markdown(run_dir, reports) - - return ReplayRunResult( - run_id=run_id, - run_dir=run_dir, - reports=reports, - csv_path=csv_path, - markdown_path=markdown_path, - ) - - def _run_scenario(self, run_dir: Path, scenario: ScenarioConfig) -> ScenarioReport: - started_at = perf_counter() - blockers = self.environment.start(scenario.required_paths, scenario.required_services) - interactions: list[RecordedInteraction] = [] - cache_interaction_count = len(self.satellite_cache.interactions) - sitl_interaction_count = len(self.ardupilot_sitl.interactions) - observer_interaction_count = len(self.qgc_observer.interactions) - - if blockers: - result = ScenarioResult.BLOCKED - error_message = "; ".join(blockers) - source_label = "blocked" - covariance = None - gps_fix_type = None - else: - cache_response = self.satellite_cache.query_manifest( - scenario.scenario_id, - scenario.controls.get("cache_variant", "valid"), - ) - sitl_response = self.ardupilot_sitl.emit_trace( - scenario.scenario_id, - scenario.controls.get("flight_mode", "normal"), - ) - self.qgc_observer.observe_status( - scenario.scenario_id, - scenario.controls.get("status", "GPS_DENIED_REPLAY_READY"), - ) - interactions.extend(self.satellite_cache.interactions[cache_interaction_count:]) - interactions.extend(self.ardupilot_sitl.interactions[sitl_interaction_count:]) - interactions.extend(self.qgc_observer.interactions[observer_interaction_count:]) - cache_rejection_expected = scenario.controls.get("expect_cache_rejection") == "true" - cache_rejected_safely = ( - cache_rejection_expected - and cache_response["trusted"] is False - and cache_response["network_fetch_attempted"] is False - ) - result = ( - ScenarioResult.PASS - if cache_response["trusted"] or cache_rejected_safely - else ScenarioResult.BLOCKED - ) - error_message = "" if result == ScenarioResult.PASS else "cache fixture is not trusted" - source_label = ( - "satellite_anchored" - if cache_response["trusted"] - else "untrusted_cache_rejected" - ) - covariance = 12.5 if cache_response["trusted"] else None - gps_fix_type = int(str(sitl_response["fix_type"])) if cache_response["trusted"] else 0 - - scenario_dir = run_dir / scenario.scenario_id - scenario_dir.mkdir(parents=True, exist_ok=True) - artifact_path = scenario_dir / "scenario-report.json" - execution_time_ms = (perf_counter() - started_at) * 1000.0 - artifact_path.write_text( - json.dumps( - { - "scenario_id": scenario.scenario_id, - "group": scenario.group.value, - "result": result.value, - "blocked_reasons": blockers, - "controls": dict(scenario.controls), - }, - indent=2, - ) - + "\n", - encoding="utf-8", - ) - - return ScenarioReport( - scenario_id=scenario.scenario_id, - name=scenario.name, - group=scenario.group, - input_dataset=scenario.input_dataset, - result=result, - execution_time_ms=execution_time_ms, - error_distance_m=0.0 if result == ScenarioResult.PASS else None, - source_label=source_label, - covariance_95_semi_major_m=covariance, - gps_fix_type=gps_fix_type, - error_message=error_message, - artifacts=(artifact_path,), - interactions=tuple(interactions), - ) - - def _write_csv(self, run_dir: Path, reports: Sequence[ScenarioReport]) -> Path: - csv_path = run_dir / "blackbox-report.csv" - with csv_path.open("w", encoding="utf-8", newline="") as csv_file: - writer = csv.DictWriter(csv_file, fieldnames=REPORT_COLUMNS) - writer.writeheader() - for report in reports: - writer.writerow( - { - "Test ID": report.scenario_id, - "Test Name": report.name, - "Input Dataset": report.input_dataset, - "Execution Time (ms)": f"{report.execution_time_ms:.3f}", - "Result": report.result.value, - "Error Distance (m)": _optional_float(report.error_distance_m), - "Source Label": report.source_label, - "Covariance 95% Semi-Major (m)": _optional_float( - report.covariance_95_semi_major_m - ), - "GPS_INPUT.fix_type": "" if report.gps_fix_type is None else report.gps_fix_type, - "Error Message": report.error_message, - } - ) - return csv_path - - def _write_markdown(self, run_dir: Path, reports: Sequence[ScenarioReport]) -> Path: - markdown_path = run_dir / "fdr-validation-summary.md" - lines = [ - "# FDR Validation Summary", - "", - f"Run ID: `{run_dir.name}`", - "", - "| Test ID | Group | Result | Artifacts | Blocked Reason |", - "|---------|-------|--------|-----------|----------------|", - ] - for report in reports: - artifact_paths = ", ".join(str(path) for path in report.artifacts) - lines.append( - "| " - f"{report.scenario_id} | {report.group.value} | {report.result.value} | " - f"{artifact_paths} | {report.error_message or ''} |" - ) - markdown_path.write_text("\n".join(lines) + "\n", encoding="utf-8") - return markdown_path - - -def default_scenarios(input_root: Path = Path("_docs/00_problem/input_data")) -> tuple[ScenarioConfig, ...]: - return ( - ScenarioConfig( - scenario_id="FT-P-01", - name="Still-image replay smoke", - group=ScenarioGroup.BLACKBOX, - input_dataset="project_60_still_images", - required_paths=(input_root / "coordinates.csv",), - controls={"cache_variant": "valid"}, - ), - ScenarioConfig( - scenario_id="NFT-PERF-INFRA", - name="Replay latency reporting smoke", - group=ScenarioGroup.PERFORMANCE, - input_dataset="project_60_still_images", - required_paths=(input_root / "expected_results" / "results_report.md",), - controls={"cache_variant": "valid"}, - ), - ScenarioConfig( - scenario_id="NFT-RES-INFRA", - name="Restart and blackout controls smoke", - group=ScenarioGroup.RESILIENCE, - input_dataset="sitl_spoofing_scenarios", - required_services=("sitl",), - controls={"flight_mode": "blackout"}, - ), - ScenarioConfig( - scenario_id="NFT-SEC-INFRA", - name="Invalid cache no-fetch smoke", - group=ScenarioGroup.SECURITY, - input_dataset="cache_integrity_fixtures", - controls={"cache_variant": "stale", "expect_cache_rejection": "true"}, - ), - ScenarioConfig( - scenario_id="NFT-RES-LIM-INFRA", - name="Jetson resource gate smoke", - group=ScenarioGroup.RESOURCE_LIMIT, - input_dataset="jetson_resource_monitor", - required_services=("jetson",), - ), - ) - - -def load_expected_coordinates(coordinates_path: Path) -> tuple[ExpectedCoordinate, ...]: - rows: list[ExpectedCoordinate] = [] - with coordinates_path.open(encoding="utf-8", newline="") as coordinates_file: - reader = csv.DictReader(coordinates_file) - for row in reader: - normalized_row = {key.strip(): value for key, value in row.items() if key is not None} - image_ref = (normalized_row.get("image") or "").strip() - latitude = float((normalized_row.get("lat") or "").strip()) - longitude = float((normalized_row.get("lon") or "").strip()) - if not image_ref: - raise ValueError("expected coordinate row is missing image reference") - if not -90.0 <= latitude <= 90.0 or not -180.0 <= longitude <= 180.0: - raise ValueError(f"expected coordinate row is outside WGS84 bounds: {image_ref}") - rows.append( - ExpectedCoordinate( - image_ref=image_ref, - latitude_deg=latitude, - longitude_deg=longitude, - ) - ) - if not rows: - raise ValueError("expected coordinate fixture is empty") - return tuple(rows) - - -def evaluate_still_image_estimates( - expected_coordinates: Sequence[ExpectedCoordinate], - estimates: Sequence[ReplayEstimate], -) -> Mapping[str, float | str | bool]: - expected_by_image = {coordinate.image_ref: coordinate for coordinate in expected_coordinates} - if len(estimates) != len(expected_by_image): - raise ValueError("replay estimate count does not match expected coordinate count") - - distances = [] - latencies = [] - for estimate in estimates: - expected = expected_by_image.get(estimate.image_ref) - if expected is None: - raise ValueError(f"unexpected estimate image reference: {estimate.image_ref}") - _require_confidence_fields(estimate) - distances.append( - haversine_m( - expected.latitude_deg, - expected.longitude_deg, - estimate.latitude_deg, - estimate.longitude_deg, - ) - ) - latencies.append(estimate.capture_to_output_latency_ms) - - within_50_m = sum(distance <= 50.0 for distance in distances) / len(distances) - within_20_m = sum(distance <= 20.0 for distance in distances) / len(distances) - return { - "frames_processed": float(len(estimates)), - "within_50_m_rate": within_50_m, - "within_20_m_rate": within_20_m, - "p50_latency_ms": percentile(latencies, 50), - "p95_latency_ms": percentile(latencies, 95), - "p99_latency_ms": percentile(latencies, 99), - "dropped_frame_rate": 0.0, - "threshold_passed": within_50_m >= 0.80 and within_20_m >= 0.50, - } - - -def validate_derkachi_alignment( - video_duration_s: float, - telemetry_duration_s: float, - telemetry_rows: int, - frame_rate_hz: float = 30.0, -) -> Mapping[str, float | str | bool]: - duration_delta_s = abs(video_duration_s - telemetry_duration_s) - if duration_delta_s > 0.250: - raise ValueError("Derkachi video and telemetry durations differ by more than 250 ms") - if telemetry_rows <= 0: - raise ValueError("Derkachi telemetry fixture is empty") - - frame_count = round(video_duration_s * frame_rate_hz) - frames_per_telemetry = frame_count / telemetry_rows - if not math.isclose(frames_per_telemetry, 3.0, rel_tol=0.02, abs_tol=0.05): - raise ValueError("Derkachi replay must have approximately 3 video frames per telemetry row") - - return { - "video_duration_s": video_duration_s, - "telemetry_duration_s": telemetry_duration_s, - "duration_delta_s": duration_delta_s, - "frames_per_telemetry": frames_per_telemetry, - "alignment_valid": True, - } - - -def relocalization_required( - visual_overlap_fraction: float, - disconnected_duration_s: float, - max_disconnected_duration_s: float = 3.0, -) -> bool: - if not 0.0 <= visual_overlap_fraction <= 1.0: - raise ValueError("visual overlap fraction must be within [0, 1]") - return visual_overlap_fraction < 0.05 or disconnected_duration_s > max_disconnected_duration_s - - -def summarize_cold_start_trials( - first_fix_latencies_s: Sequence[float], - peak_memory_bytes: Sequence[int], - first_fix_budget_s: float = 30.0, - memory_budget_bytes: int = 8 * 1024 * 1024 * 1024, -) -> Mapping[str, float | str | bool]: - if len(first_fix_latencies_s) != len(peak_memory_bytes): - raise ValueError("cold-start latency and memory trial counts must match") - if not first_fix_latencies_s: - raise ValueError("cold-start trials are empty") - - p95_first_fix_s = percentile(first_fix_latencies_s, 95) - peak_memory = max(peak_memory_bytes) - return { - "trial_count": float(len(first_fix_latencies_s)), - "p95_first_fix_s": p95_first_fix_s, - "peak_memory_bytes": float(peak_memory), - "first_fix_passed": p95_first_fix_s < first_fix_budget_s, - "memory_passed": peak_memory < memory_budget_bytes, - } - - -def summarize_resource_samples(samples: Sequence[ResourceSample]) -> Mapping[str, float | str | bool]: - if not samples: - raise ValueError("resource samples are empty") - duration_s = samples[-1].timestamp_s - samples[0].timestamp_s - if duration_s < 0.0: - raise ValueError("resource sample timestamps must be monotonic") - return { - "duration_s": duration_s, - "peak_process_rss_bytes": float(max(sample.process_rss_bytes for sample in samples)), - "peak_shared_memory_used_bytes": float( - max(sample.shared_memory_used_bytes for sample in samples) - ), - "peak_cuda_allocated_bytes": float(max(sample.cuda_allocated_bytes for sample in samples)), - "throttle_observed": any(sample.throttle_active for sample in samples), - "max_temperature_c": max(sample.temperature_c for sample in samples), - } - - -def percentile(values: Sequence[float], percentile_value: int) -> float: - if not values: - raise ValueError("cannot compute percentile for empty values") - ordered = sorted(values) - index = min( - len(ordered) - 1, - max(0, math.ceil((percentile_value / 100.0) * len(ordered)) - 1), - ) - return ordered[index] - - -def mavlink_source_is_authorized(source_system_id: int, allowed_source_system_ids: set[int]) -> bool: - return source_system_id in allowed_source_system_ids - - -def haversine_m( - latitude_a_deg: float, - longitude_a_deg: float, - latitude_b_deg: float, - longitude_b_deg: float, -) -> float: - earth_radius_m = 6_371_000.0 - latitude_a = math.radians(latitude_a_deg) - latitude_b = math.radians(latitude_b_deg) - delta_latitude = math.radians(latitude_b_deg - latitude_a_deg) - delta_longitude = math.radians(longitude_b_deg - longitude_a_deg) - haversine = ( - math.sin(delta_latitude / 2.0) ** 2 - + math.cos(latitude_a) * math.cos(latitude_b) * math.sin(delta_longitude / 2.0) ** 2 - ) - return 2.0 * earth_radius_m * math.asin(math.sqrt(haversine)) - - -def _optional_float(value: float | None) -> str: - return "" if value is None else f"{value:.3f}" - - -def _require_confidence_fields(estimate: ReplayEstimate) -> None: - if estimate.covariance_95_semi_major_m < 0.0: - raise ValueError(f"estimate covariance is invalid: {estimate.image_ref}") - if not estimate.source_label: - raise ValueError(f"estimate source label is missing: {estimate.image_ref}") - if estimate.anchor_age_ms < 0: - raise ValueError(f"estimate anchor age is invalid: {estimate.image_ref}") - - -def main(argv: Sequence[str] | None = None) -> int: - parser = argparse.ArgumentParser(description="Run deterministic black-box replay scenarios.") - parser.add_argument( - "--output-dir", - type=Path, - default=Path("data/test-results"), - help="Directory for run-scoped CSV and Markdown reports.", - ) - parser.add_argument( - "--input-root", - type=Path, - default=Path(os.environ.get("GPSD_REPLAY_INPUT_ROOT", "_docs/00_problem/input_data")), - help="Directory containing replay input fixtures.", - ) - args = parser.parse_args(argv) - - result = BlackboxReplayRunner(output_root=args.output_dir, input_root=args.input_root).run() - print(f"blackbox replay completed: {result.csv_path}") - print(f"fdr validation summary: {result.markdown_path}") - return 0 diff --git a/e2e/replay/run_replay.py b/e2e/replay/run_replay.py deleted file mode 100644 index d1e058f..0000000 --- a/e2e/replay/run_replay.py +++ /dev/null @@ -1,7 +0,0 @@ -"""Replay runner entry point.""" - -from e2e.replay.harness import main - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/e2e/reports/.gitkeep b/e2e/reports/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/e2e/reports/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/migrations/postgresql/0001_enable_postgis.sql b/migrations/postgresql/0001_enable_postgis.sql deleted file mode 100644 index 576e542..0000000 --- a/migrations/postgresql/0001_enable_postgis.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE EXTENSION IF NOT EXISTS postgis; diff --git a/migrations/seed/README.md b/migrations/seed/README.md deleted file mode 100644 index 4c7259f..0000000 --- a/migrations/seed/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Seed Data - -Place deterministic development and CI seed data here. Do not add production -mission payloads, signing material, or raw frame dumps. diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index ab5b2c7..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,34 +0,0 @@ -[build-system] -requires = ["setuptools>=69", "wheel"] -build-backend = "setuptools.build_meta" - -[project] -name = "gps-denied-onboard" -version = "0.1.0" -description = "Jetson-hosted GPS-denied localization runtime scaffold." -requires-python = ">=3.10" -dependencies = [ - "pydantic==2.13.3", -] - -[project.optional-dependencies] -dev = [ - "black>=24.0", - "pytest>=8.0", - "ruff>=0.5", -] - -[tool.setuptools.packages.find] -where = ["src"] - -[tool.pytest.ini_options] -pythonpath = ["src"] -testpaths = ["tests"] - -[tool.ruff] -line-length = 100 -src = ["src", "tests"] - -[tool.black] -line-length = 100 -target-version = ["py310"] diff --git a/src/__init__.py b/src/__init__.py deleted file mode 100644 index 858fdca..0000000 --- a/src/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Source-root package marker for editable installs.""" diff --git a/src/anchor_verification/__init__.py b/src/anchor_verification/__init__.py deleted file mode 100644 index 3f385bf..0000000 --- a/src/anchor_verification/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -"""Anchor verification component.""" - -from .interfaces import ( - AnchorVerifier, - FeatureMatcher, - GeometryGatedAnchorVerifier, - KeypointRansacMatcher, -) -from .types import ( - AnchorFrame, - AnchorVerificationResult, - CandidateTile, - GeometryGateConfig, - MatchEvidence, - MatcherBenchmarkReport, - MatcherBenchmarkResult, - MatcherProfile, -) - -__all__ = [ - "AnchorFrame", - "AnchorVerificationResult", - "AnchorVerifier", - "CandidateTile", - "FeatureMatcher", - "GeometryGateConfig", - "GeometryGatedAnchorVerifier", - "KeypointRansacMatcher", - "MatchEvidence", - "MatcherBenchmarkReport", - "MatcherBenchmarkResult", - "MatcherProfile", -] diff --git a/src/anchor_verification/interfaces.py b/src/anchor_verification/interfaces.py deleted file mode 100644 index 40dcc68..0000000 --- a/src/anchor_verification/interfaces.py +++ /dev/null @@ -1,202 +0,0 @@ -"""Public anchor verification interfaces.""" - -from statistics import median -from time import perf_counter -from typing import Protocol - -from shared.contracts import AnchorDecision - -from .types import ( - AnchorFrame, - AnchorVerificationResult, - CandidateTile, - GeometryGateConfig, - MatchEvidence, - MatcherBenchmarkReport, - MatcherBenchmarkResult, - MatcherProfile, -) - - -class AnchorVerifier(Protocol): - """Verifies retrieved candidates against camera observations.""" - - def verify(self, frame: AnchorFrame, evidence: MatchEvidence) -> AnchorVerificationResult: - """Return an anchor decision for one candidate.""" - - -class FeatureMatcher(Protocol): - """Computes correspondence evidence from local frame and tile inputs.""" - - def compute( - self, - frame: AnchorFrame, - tile: CandidateTile, - matcher_profile: MatcherProfile, - ) -> MatchEvidence: - """Return matcher and geometry evidence for one candidate tile.""" - - -class KeypointRansacMatcher: - """Small CPU matcher for keypoint fixtures and dependency-gated runs.""" - - def __init__(self, inlier_threshold_px: float = 2.0) -> None: - self._inlier_threshold_px = inlier_threshold_px - - def compute( - self, - frame: AnchorFrame, - tile: CandidateTile, - matcher_profile: MatcherProfile, - ) -> MatchEvidence: - started = perf_counter() - correspondences = tuple(zip(frame.keypoints, tile.keypoints)) - if len(correspondences) < 4: - return MatchEvidence( - candidate=tile.candidate, - matcher_profile=matcher_profile, - inliers=0, - mean_reprojection_error_px=self._inlier_threshold_px + 1.0, - homography=None, - runtime_ms=(perf_counter() - started) * 1000.0, - provenance_trusted=tile.provenance_trusted, - evidence_source="computed_geometry", - ) - - dx_values = tuple(tile_point[0] - frame_point[0] for frame_point, tile_point in correspondences) - dy_values = tuple(tile_point[1] - frame_point[1] for frame_point, tile_point in correspondences) - dx = median(dx_values) - dy = median(dy_values) - residuals = tuple( - ((frame_point[0] + dx - tile_point[0]) ** 2 + (frame_point[1] + dy - tile_point[1]) ** 2) - ** 0.5 - for frame_point, tile_point in correspondences - ) - inlier_residuals = tuple( - residual for residual in residuals if residual <= self._inlier_threshold_px - ) - mean_error = ( - sum(inlier_residuals) / len(inlier_residuals) - if inlier_residuals - else self._inlier_threshold_px + 1.0 - ) - homography = ( - { - "h00": 1.0, - "h01": 0.0, - "h02": dx, - "h10": 0.0, - "h11": 1.0, - "h12": dy, - "h20": 0.0, - "h21": 0.0, - "h22": 1.0, - } - if inlier_residuals - else None - ) - return MatchEvidence( - candidate=tile.candidate, - matcher_profile=matcher_profile, - inliers=len(inlier_residuals), - mean_reprojection_error_px=mean_error, - homography=homography, - runtime_ms=(perf_counter() - started) * 1000.0, - provenance_trusted=tile.provenance_trusted, - evidence_source="computed_geometry", - ) - - -class GeometryGatedAnchorVerifier: - """Converts matcher evidence into accepted/rejected anchor decisions.""" - - def __init__( - self, - gates: GeometryGateConfig | None = None, - matcher: FeatureMatcher | None = None, - ) -> None: - self._gates = gates or GeometryGateConfig() - self._matcher = matcher or KeypointRansacMatcher() - - def verify(self, frame: AnchorFrame, evidence: MatchEvidence) -> AnchorVerificationResult: - accepted, reason = self._classify(frame, evidence) - decision = AnchorDecision( - candidate_id=evidence.candidate.chunk_id, - accepted=accepted, - estimated_pose=self._estimated_pose(evidence) if accepted else None, - inliers=evidence.inliers, - mean_reprojection_error_px=evidence.mean_reprojection_error_px, - rejection_reason=None if accepted else reason, - ) - return AnchorVerificationResult( - decision=decision, - matcher_profile=evidence.matcher_profile, - reason=reason, - homography=evidence.homography, - freshness_status=evidence.candidate.freshness_status, - ) - - def verify_candidate( - self, - frame: AnchorFrame, - tile: CandidateTile, - matcher_profile: MatcherProfile = "sift_orb", - ) -> AnchorVerificationResult: - evidence = self._matcher.compute(frame, tile, matcher_profile) - return self.verify(frame, evidence) - - def benchmark( - self, frame: AnchorFrame, evidences: tuple[MatchEvidence, ...] - ) -> MatcherBenchmarkReport: - results: list[MatcherBenchmarkResult] = [] - for evidence in evidences: - verification = self.verify(frame, evidence) - results.append( - MatcherBenchmarkResult( - matcher_profile=evidence.matcher_profile, - runtime_ms=evidence.runtime_ms, - inliers=evidence.inliers, - mean_reprojection_error_px=evidence.mean_reprojection_error_px, - accepted=verification.decision.accepted, - reason=verification.reason, - ) - ) - return MatcherBenchmarkReport( - results=tuple(results), - ) - - def benchmark_candidates( - self, - frame: AnchorFrame, - tiles: tuple[CandidateTile, ...], - matcher_profile: MatcherProfile = "sift_orb", - ) -> MatcherBenchmarkReport: - return self.benchmark( - frame, - tuple(self._matcher.compute(frame, tile, matcher_profile) for tile in tiles), - ) - - def _classify(self, frame: AnchorFrame, evidence: MatchEvidence) -> tuple[bool, str]: - if not frame.usable_for_anchor: - return False, "frame_not_usable" - if evidence.candidate.freshness_status != "fresh" or not evidence.provenance_trusted: - return False, "stale_or_untrusted_provenance" - if evidence.homography is None: - return False, "geometry_failure" - if evidence.inliers < self._gates.min_inliers: - return False, "low_inliers" - if evidence.mean_reprojection_error_px > self._gates.max_mean_reprojection_error_px: - return False, "high_mre" - return True, "accepted_geometry" - - def _estimated_pose(self, evidence: MatchEvidence) -> dict[str, float]: - footprint = evidence.candidate.footprint - min_lat = footprint.get("min_lat", 0.0) - max_lat = footprint.get("max_lat", min_lat) - min_lon = footprint.get("min_lon", 0.0) - max_lon = footprint.get("max_lon", min_lon) - return { - "latitude_deg": (min_lat + max_lat) / 2.0, - "longitude_deg": (min_lon + max_lon) / 2.0, - "mean_reprojection_error_px": evidence.mean_reprojection_error_px, - } diff --git a/src/anchor_verification/native/README.md b/src/anchor_verification/native/README.md deleted file mode 100644 index 95d3fab..0000000 --- a/src/anchor_verification/native/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Anchor Verification Matcher Package - -Exports local feature matching and geometry verification boundaries owned by `anchor_verification`. diff --git a/src/anchor_verification/native/__init__.py b/src/anchor_verification/native/__init__.py deleted file mode 100644 index d9cd9cf..0000000 --- a/src/anchor_verification/native/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Anchor feature matching package exports.""" - -from anchor_verification.interfaces import FeatureMatcher, KeypointRansacMatcher - -__all__ = ["FeatureMatcher", "KeypointRansacMatcher"] diff --git a/src/anchor_verification/types.py b/src/anchor_verification/types.py deleted file mode 100644 index 5a65472..0000000 --- a/src/anchor_verification/types.py +++ /dev/null @@ -1,65 +0,0 @@ -"""Public anchor verification models.""" - -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field, NonNegativeFloat, NonNegativeInt - -from shared.contracts import AnchorDecision, VprCandidate - - -class AnchorVerificationModel(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - -MatcherProfile = Literal["aliked_lightglue", "disk_lightglue", "sift_orb"] - - -class AnchorFrame(AnchorVerificationModel): - frame_id: str = Field(min_length=1) - image_ref: str = Field(min_length=1) - usable_for_anchor: bool = True - keypoints: tuple[tuple[float, float], ...] = () - - -class CandidateTile(AnchorVerificationModel): - candidate: VprCandidate - image_ref: str = Field(min_length=1) - keypoints: tuple[tuple[float, float], ...] = () - provenance_trusted: bool = True - - -class GeometryGateConfig(AnchorVerificationModel): - min_inliers: NonNegativeInt = 20 - max_mean_reprojection_error_px: NonNegativeFloat = 3.0 - - -class MatchEvidence(AnchorVerificationModel): - candidate: VprCandidate - matcher_profile: MatcherProfile - inliers: NonNegativeInt - mean_reprojection_error_px: NonNegativeFloat - homography: dict[str, float] | None = None - runtime_ms: NonNegativeFloat - provenance_trusted: bool = True - evidence_source: Literal["computed_geometry", "external_evidence"] = "external_evidence" - - -class AnchorVerificationResult(AnchorVerificationModel): - decision: AnchorDecision - matcher_profile: MatcherProfile - reason: str = Field(min_length=1) - homography: dict[str, float] | None = None - freshness_status: Literal["fresh", "stale", "rejected"] - - -class MatcherBenchmarkResult(AnchorVerificationModel): - matcher_profile: MatcherProfile - runtime_ms: NonNegativeFloat - inliers: NonNegativeInt - mean_reprojection_error_px: NonNegativeFloat - accepted: bool - reason: str = Field(min_length=1) - - -class MatcherBenchmarkReport(AnchorVerificationModel): - results: tuple[MatcherBenchmarkResult, ...] = Field(min_length=1) diff --git a/src/camera_ingest_calibration/__init__.py b/src/camera_ingest_calibration/__init__.py deleted file mode 100644 index f01decd..0000000 --- a/src/camera_ingest_calibration/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -"""Camera ingest and calibration component.""" - -from .interfaces import CameraFrameIngestor, FrameProvider -from .types import ( - CalibrationMetadata, - FrameQualityReport, - IngestedFramePacket, - NavigationFrame, - NormalizationHint, - OcclusionReport, -) - -__all__ = [ - "CalibrationMetadata", - "CameraFrameIngestor", - "FrameProvider", - "FrameQualityReport", - "IngestedFramePacket", - "NavigationFrame", - "NormalizationHint", - "OcclusionReport", -] diff --git a/src/camera_ingest_calibration/interfaces.py b/src/camera_ingest_calibration/interfaces.py deleted file mode 100644 index c66a58e..0000000 --- a/src/camera_ingest_calibration/interfaces.py +++ /dev/null @@ -1,96 +0,0 @@ -"""Public camera ingest interfaces.""" - -from typing import Any, Protocol - -from shared.contracts import FramePacket - -from .types import ( - CalibrationMetadata, - FrameQualityReport, - IngestedFramePacket, - NavigationFrame, - NormalizationHint, - OcclusionReport, -) - - -class FrameProvider(Protocol): - """Source of navigation frames for downstream localization components.""" - - def next_frame(self) -> Any: - """Return the next frame packet.""" - - -class CameraFrameIngestor: - """Build metadata-only frame packets for downstream localization components.""" - - def ingest( - self, - frame: NavigationFrame, - calibration: CalibrationMetadata, - ) -> IngestedFramePacket: - quality = self.classify_quality(frame) - occlusion = self.detect_occlusion(frame) - hint = NormalizationHint( - north_up_degrees=frame.north_up_degrees, - should_normalize_downstream=frame.north_up_degrees not in (None, 0.0), - ) - contract = FramePacket( - frame_id=frame.frame_id, - timestamp_ns=frame.timestamp_ns, - image_ref=frame.image_ref, - calibration_id=calibration.calibration_id, - occlusion=occlusion.state, - quality=quality.score, - normalization_hint=( - f"north_up_degrees={hint.north_up_degrees}" - if hint.should_normalize_downstream - else None - ), - raw_frame_retained=False, - ) - - return IngestedFramePacket( - contract=contract, - quality_report=quality, - occlusion_report=occlusion, - normalization_hint=hint, - ) - - def classify_quality(self, frame: NavigationFrame) -> FrameQualityReport: - if not frame.readable: - return FrameQualityReport(score=0.0, state="unusable", reasons=("unreadable",)) - - score = min(frame.mean_luma, frame.contrast) - reasons: list[str] = [] - if frame.mean_luma < 0.05: - reasons.append("blackout") - if frame.contrast < 0.05: - reasons.append("low_contrast") - - if reasons: - return FrameQualityReport(score=score, state="unusable", reasons=tuple(reasons)) - if score < 0.25: - return FrameQualityReport(score=score, state="degraded", reasons=("low_quality",)) - return FrameQualityReport(score=score, state="usable") - - def detect_occlusion(self, frame: NavigationFrame) -> OcclusionReport: - if not frame.readable: - return OcclusionReport( - state="unreadable", - usable_for_vio=False, - usable_for_anchor=False, - ) - if frame.mean_luma < 0.05 or frame.contrast < 0.05: - return OcclusionReport( - state="total", - usable_for_vio=False, - usable_for_anchor=False, - ) - if frame.mean_luma < 0.25 or frame.contrast < 0.25: - return OcclusionReport( - state="partial", - usable_for_vio=True, - usable_for_anchor=False, - ) - return OcclusionReport(state="clear", usable_for_vio=True, usable_for_anchor=True) diff --git a/src/camera_ingest_calibration/types.py b/src/camera_ingest_calibration/types.py deleted file mode 100644 index 9bb1bdc..0000000 --- a/src/camera_ingest_calibration/types.py +++ /dev/null @@ -1,70 +0,0 @@ -"""Public camera ingest models.""" - -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field, NonNegativeInt, PositiveFloat -from pydantic import model_validator - -from shared.contracts import FramePacket - - -class CameraIngestModel(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - -class CalibrationMetadata(CameraIngestModel): - calibration_id: str = Field(min_length=1) - camera_model: str = Field(min_length=1) - image_width_px: int = Field(gt=0) - image_height_px: int = Field(gt=0) - focal_length_px: PositiveFloat - distortion_model: str = Field(min_length=1) - - -class NavigationFrame(CameraIngestModel): - frame_id: str = Field(min_length=1) - timestamp_ns: NonNegativeInt - image_ref: str = Field(min_length=1) - readable: bool = True - mean_luma: float = Field(ge=0.0, le=1.0) - contrast: float = Field(ge=0.0, le=1.0) - north_up_degrees: float | None = Field(default=None, ge=-180.0, le=180.0) - raw_frame_retained: bool = False - - @model_validator(mode="after") - def raw_payload_must_not_be_retained(self) -> "NavigationFrame": - if self.raw_frame_retained: - raise ValueError("camera ingest must retain references only, not raw frames") - return self - - -class FrameQualityReport(CameraIngestModel): - score: float = Field(ge=0.0, le=1.0) - state: Literal["usable", "degraded", "unusable"] - reasons: tuple[str, ...] = () - - -class OcclusionReport(CameraIngestModel): - state: Literal["clear", "partial", "total", "unreadable"] - usable_for_vio: bool - usable_for_anchor: bool - - -class NormalizationHint(CameraIngestModel): - north_up_degrees: float | None = Field(default=None, ge=-180.0, le=180.0) - should_normalize_downstream: bool = False - - -class IngestedFramePacket(CameraIngestModel): - contract: FramePacket - quality_report: FrameQualityReport - occlusion_report: OcclusionReport - normalization_hint: NormalizationHint - - @property - def usable_for_vio(self) -> bool: - return self.occlusion_report.usable_for_vio and self.quality_report.state != "unusable" - - @property - def usable_for_anchor(self) -> bool: - return self.occlusion_report.usable_for_anchor and self.quality_report.state != "unusable" diff --git a/src/fdr_observability/__init__.py b/src/fdr_observability/__init__.py deleted file mode 100644 index fed8776..0000000 --- a/src/fdr_observability/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -"""Flight data recorder and observability component.""" - -from .interfaces import FlightRecorder, InMemoryFlightRecorder -from .types import ( - FdrAppendResult, - FdrExportRequest, - FdrExportResult, - FdrHealth, - FdrPayload, - FdrSegmentSummary, -) - -__all__ = [ - "FdrAppendResult", - "FdrExportRequest", - "FdrExportResult", - "FdrHealth", - "FdrPayload", - "FdrSegmentSummary", - "FlightRecorder", - "InMemoryFlightRecorder", -] diff --git a/src/fdr_observability/interfaces.py b/src/fdr_observability/interfaces.py deleted file mode 100644 index 1f07835..0000000 --- a/src/fdr_observability/interfaces.py +++ /dev/null @@ -1,121 +0,0 @@ -"""Public flight recorder interfaces.""" - -from typing import Any, Protocol - -from shared.contracts import FdrEvent -from shared.errors import ErrorEnvelope - -from .types import ( - FdrAppendResult, - FdrExportRequest, - FdrExportResult, - FdrHealth, - FdrPayload, - FdrSegmentSummary, -) - - -class FlightRecorder(Protocol): - """Append-only event recorder for runtime evidence.""" - - def append_event(self, event: Any) -> None: - """Persist one FDR event.""" - - def export(self) -> Any: - """Export recorded evidence for post-flight analysis.""" - - -class InMemoryFlightRecorder: - """Bounded append-only recorder for runtime evidence metadata.""" - - def __init__(self, segment_limit_bytes: int, storage_limit_bytes: int) -> None: - if segment_limit_bytes <= 0: - raise ValueError("segment_limit_bytes must be positive") - if storage_limit_bytes < segment_limit_bytes: - raise ValueError("storage_limit_bytes must be at least one segment") - self._segment_limit_bytes = segment_limit_bytes - self._storage_limit_bytes = storage_limit_bytes - self._segments: list[list[FdrEvent]] = [[]] - self._segment_bytes: list[int] = [0] - self._used_bytes = 0 - - @property - def health(self) -> FdrHealth: - if self._used_bytes >= self._storage_limit_bytes: - return FdrHealth( - status="critical", - used_bytes=self._used_bytes, - max_bytes=self._storage_limit_bytes, - message="fdr storage limit reached", - ) - if self._used_bytes >= int(self._storage_limit_bytes * 0.9): - return FdrHealth( - status="degraded", - used_bytes=self._used_bytes, - max_bytes=self._storage_limit_bytes, - message="fdr storage nearing limit", - ) - return FdrHealth( - status="ready", - used_bytes=self._used_bytes, - max_bytes=self._storage_limit_bytes, - message="fdr storage ready", - ) - - def append_event(self, event: FdrEvent, payload: FdrPayload) -> FdrAppendResult: - if self._used_bytes + payload.size_bytes > self._storage_limit_bytes: - return FdrAppendResult( - appended=False, - error=ErrorEnvelope( - component="fdr_observability", - category="resource", - message="fdr storage limit reached", - severity="critical", - retryable=False, - ), - ) - - rollover = False - if self._segment_bytes[-1] + payload.size_bytes > self._segment_limit_bytes: - self._segments.append([]) - self._segment_bytes.append(0) - rollover = True - - segment_index = len(self._segments) - 1 - stored_event = event.model_copy(update={"payload_ref": payload.ref}) - self._segments[segment_index].append(stored_event) - self._segment_bytes[segment_index] += payload.size_bytes - self._used_bytes += payload.size_bytes - - return FdrAppendResult( - appended=True, - event=stored_event, - segment_id=self._segment_id(segment_index), - rollover=rollover, - ) - - def export(self, request: FdrExportRequest) -> FdrExportResult: - segments = tuple( - FdrSegmentSummary( - segment_id=self._segment_id(index), - event_count=len(events), - bytes_used=self._segment_bytes[index], - ) - for index, events in enumerate(self._segments) - if events - ) - evidence_ref = f"fdr://exports/{request.mission_id}/{request.run_id}/evidence.json" - analytics_ref = ( - f"fdr://exports/{request.mission_id}/{request.run_id}/analytics.parquet" - if request.include_analytics - else None - ) - return FdrExportResult( - produced=True, - evidence_ref=evidence_ref, - segments=segments, - analytics_ref=analytics_ref, - ) - - def _segment_id(self, index: int) -> str: - return f"segment-{index + 1:04d}" diff --git a/src/fdr_observability/types.py b/src/fdr_observability/types.py deleted file mode 100644 index e1afac2..0000000 --- a/src/fdr_observability/types.py +++ /dev/null @@ -1,52 +0,0 @@ -"""Public FDR models.""" - -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field, NonNegativeInt, PositiveInt - -from shared.contracts import FdrEvent -from shared.errors import ErrorEnvelope - - -class FdrModel(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - -class FdrPayload(FdrModel): - ref: str = Field(min_length=1) - size_bytes: PositiveInt - redacted: bool = True - - -class FdrAppendResult(FdrModel): - appended: bool - event: FdrEvent | None = None - segment_id: str | None = None - rollover: bool = False - error: ErrorEnvelope | None = None - - -class FdrSegmentSummary(FdrModel): - segment_id: str = Field(min_length=1) - event_count: NonNegativeInt - bytes_used: NonNegativeInt - - -class FdrHealth(FdrModel): - status: Literal["ready", "degraded", "critical"] - used_bytes: NonNegativeInt - max_bytes: PositiveInt - message: str - - -class FdrExportRequest(FdrModel): - mission_id: str = Field(min_length=1) - run_id: str = Field(min_length=1) - include_analytics: bool = False - - -class FdrExportResult(FdrModel): - produced: bool - evidence_ref: str = Field(min_length=1) - segments: tuple[FdrSegmentSummary, ...] - analytics_ref: str | None = None diff --git a/src/mavlink_gcs_integration/__init__.py b/src/mavlink_gcs_integration/__init__.py deleted file mode 100644 index 9e3946b..0000000 --- a/src/mavlink_gcs_integration/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -"""MAVLink and GCS integration component.""" - -from .interfaces import InMemoryMavlinkGateway, MavlinkGateway -from .types import ( - FlightControllerTelemetry, - GpsEmissionResult, - GpsInputPacket, - OperatorStatusMessage, - StatusEmissionResult, - gps_input_from_estimate, - normalize_telemetry, -) - -__all__ = [ - "FlightControllerTelemetry", - "GpsEmissionResult", - "GpsInputPacket", - "InMemoryMavlinkGateway", - "MavlinkGateway", - "OperatorStatusMessage", - "StatusEmissionResult", - "gps_input_from_estimate", - "normalize_telemetry", -] diff --git a/src/mavlink_gcs_integration/interfaces.py b/src/mavlink_gcs_integration/interfaces.py deleted file mode 100644 index 5fa2a5c..0000000 --- a/src/mavlink_gcs_integration/interfaces.py +++ /dev/null @@ -1,86 +0,0 @@ -"""Public MAVLink gateway interfaces.""" - -from typing import Any, Protocol - -from pydantic import ValidationError - -from shared.contracts import PositionEstimate, TelemetrySample -from shared.errors import ErrorEnvelope - -from .types import ( - FlightControllerTelemetry, - GpsEmissionResult, - OperatorStatusMessage, - StatusEmissionResult, - gps_input_from_estimate, - normalize_telemetry, -) - - -class MavlinkGateway(Protocol): - """Bridges FC telemetry inputs and localization GPS_INPUT outputs.""" - - def subscribe_telemetry(self) -> Any: - """Subscribe to flight-controller telemetry.""" - - def emit_gps_input(self, estimate: Any) -> None: - """Emit one localization estimate to the flight controller.""" - - -class InMemoryMavlinkGateway: - """Deterministic gateway boundary used by runtime adapters and tests.""" - - def __init__(self, status_rate_limit_ns: int) -> None: - if status_rate_limit_ns < 0: - raise ValueError("status_rate_limit_ns must be non-negative") - self._status_rate_limit_ns = status_rate_limit_ns - self._last_status_timestamp_by_text: dict[str, int] = {} - self.emitted_gps_inputs: list[object] = [] - self.emitted_status_messages: list[OperatorStatusMessage] = [] - - def subscribe_telemetry( - self, - samples: list[FlightControllerTelemetry], - ) -> tuple[TelemetrySample, ...]: - return tuple(normalize_telemetry(sample) for sample in samples) - - def emit_gps_input(self, estimate: PositionEstimate) -> GpsEmissionResult: - try: - packet = gps_input_from_estimate(estimate) - except ValidationError as error: - return GpsEmissionResult( - emitted=False, - error=ErrorEnvelope( - component="mavlink_gcs_integration", - category="validation", - message="position estimate is unsafe for GPS_INPUT emission", - severity="error", - retryable=False, - cause=str(error), - ), - ) - - self.emitted_gps_inputs.append(packet) - return GpsEmissionResult(emitted=True, packet=packet) - - def emit_status( - self, - messages: list[OperatorStatusMessage], - ) -> StatusEmissionResult: - emitted: list[OperatorStatusMessage] = [] - suppressed: list[OperatorStatusMessage] = [] - - for message in messages: - last_timestamp = self._last_status_timestamp_by_text.get(message.text) - if ( - last_timestamp is not None - and message.timestamp_ns - last_timestamp < self._status_rate_limit_ns - ): - suppressed.append(message) - continue - - self._last_status_timestamp_by_text[message.text] = message.timestamp_ns - self.emitted_status_messages.append(message) - emitted.append(message) - - return StatusEmissionResult(emitted=tuple(emitted), suppressed=tuple(suppressed)) diff --git a/src/mavlink_gcs_integration/types.py b/src/mavlink_gcs_integration/types.py deleted file mode 100644 index 01f07d6..0000000 --- a/src/mavlink_gcs_integration/types.py +++ /dev/null @@ -1,80 +0,0 @@ -"""Public MAVLink/GCS models.""" - -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field, NonNegativeFloat, NonNegativeInt - -from shared.contracts import PositionEstimate, TelemetrySample -from shared.errors import ErrorEnvelope - - -class MavlinkModel(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - -class FlightControllerTelemetry(MavlinkModel): - timestamp_ns: NonNegativeInt - acceleration_mps2: tuple[float, float, float] - attitude_rad: tuple[float, float, float] - altitude_m: float - airspeed_mps: NonNegativeFloat - gps_health: Literal["healthy", "degraded", "lost", "spoofed"] - - -class GpsInputPacket(MavlinkModel): - timestamp_ns: NonNegativeInt - latitude_deg: float = Field(ge=-90.0, le=90.0) - longitude_deg: float = Field(ge=-180.0, le=180.0) - altitude_m: float - fix_type: int = Field(ge=2, le=3) - horizontal_accuracy_m: NonNegativeFloat - source_label: str = Field(min_length=1) - - -class GpsEmissionResult(MavlinkModel): - emitted: bool - packet: GpsInputPacket | None = None - error: ErrorEnvelope | None = None - - -class OperatorStatusMessage(MavlinkModel): - timestamp_ns: NonNegativeInt - severity: Literal["info", "warning", "error", "critical"] - text: str = Field(min_length=1) - visible_to_qgc: bool = True - - -class StatusEmissionResult(MavlinkModel): - emitted: tuple[OperatorStatusMessage, ...] - suppressed: tuple[OperatorStatusMessage, ...] = () - - -def normalize_telemetry(sample: FlightControllerTelemetry) -> TelemetrySample: - return TelemetrySample( - timestamp_ns=sample.timestamp_ns, - imu={ - "accel_x": sample.acceleration_mps2[0], - "accel_y": sample.acceleration_mps2[1], - "accel_z": sample.acceleration_mps2[2], - }, - attitude={ - "roll": sample.attitude_rad[0], - "pitch": sample.attitude_rad[1], - "yaw": sample.attitude_rad[2], - }, - altitude_m=sample.altitude_m, - airspeed_mps=sample.airspeed_mps, - gps_health=sample.gps_health, - ) - - -def gps_input_from_estimate(estimate: PositionEstimate) -> GpsInputPacket: - return GpsInputPacket( - timestamp_ns=estimate.timestamp_ns, - latitude_deg=estimate.latitude_deg, - longitude_deg=estimate.longitude_deg, - altitude_m=estimate.altitude_m, - fix_type=estimate.fix_type, - horizontal_accuracy_m=estimate.horizontal_accuracy_m, - source_label=estimate.source_label, - ) diff --git a/src/safety_anchor_wrapper/__init__.py b/src/safety_anchor_wrapper/__init__.py deleted file mode 100644 index 4647c0a..0000000 --- a/src/safety_anchor_wrapper/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Safety and anchor wrapper component.""" - -from .interfaces import LocalizationStateMachine, SafetyAnchorStateMachine -from .types import ( - LocalizationSnapshot, - SafetyStateConfig, - TelemetryContext, - TileWriteEligibility, -) - -__all__ = [ - "LocalizationSnapshot", - "LocalizationStateMachine", - "SafetyAnchorStateMachine", - "SafetyStateConfig", - "TelemetryContext", - "TileWriteEligibility", -] diff --git a/src/safety_anchor_wrapper/interfaces.py b/src/safety_anchor_wrapper/interfaces.py deleted file mode 100644 index 4318d39..0000000 --- a/src/safety_anchor_wrapper/interfaces.py +++ /dev/null @@ -1,151 +0,0 @@ -"""Public localization state-machine interfaces.""" - -from typing import Protocol - -from shared.contracts import AnchorDecision, PositionEstimate, VioStatePacket - -from .types import ( - LocalizationSnapshot, - SafetyStateConfig, - TelemetryContext, - TileWriteEligibility, -) - - -class LocalizationStateMachine(Protocol): - """Coordinates VIO propagation and anchor promotion decisions.""" - - def update_vio( - self, vio_state: VioStatePacket, telemetry: TelemetryContext - ) -> LocalizationSnapshot: - """Update the state machine with a VIO state packet.""" - - def consider_anchor(self, anchor_decision: AnchorDecision) -> LocalizationSnapshot: - """Evaluate a verified anchor decision.""" - - -class SafetyAnchorStateMachine: - """Owns authoritative source labels, covariance, and tile eligibility.""" - - def __init__(self, config: SafetyStateConfig | None = None) -> None: - self._config = config or SafetyStateConfig() - self._snapshot: LocalizationSnapshot | None = None - - @property - def snapshot(self) -> LocalizationSnapshot | None: - return self._snapshot - - def update_vio( - self, - vio_state: VioStatePacket, - telemetry: TelemetryContext, - ) -> LocalizationSnapshot: - covariance_m = self._covariance_from_vio(vio_state) - estimate = PositionEstimate( - timestamp_ns=vio_state.timestamp_ns, - latitude_deg=telemetry.latitude_hint_deg, - longitude_deg=telemetry.longitude_hint_deg, - altitude_m=telemetry.altitude_m, - covariance_semimajor_m=covariance_m, - source_label="vo_extrapolated", - fix_type=3, - horizontal_accuracy_m=covariance_m, - anchor_age_ms=0, - ) - self._snapshot = LocalizationSnapshot( - estimate=estimate, - mode="vo_extrapolated", - last_vio_state=vio_state, - ) - return self._snapshot - - def consider_anchor(self, anchor_decision: AnchorDecision) -> LocalizationSnapshot: - self._require_snapshot() - assert self._snapshot is not None - if not anchor_decision.accepted: - return self._snapshot - - pose = anchor_decision.estimated_pose or {} - covariance_m = max(anchor_decision.mean_reprojection_error_px, 0.5) - estimate = PositionEstimate( - timestamp_ns=self._snapshot.estimate.timestamp_ns, - latitude_deg=float(pose.get("latitude_deg", self._snapshot.estimate.latitude_deg)), - longitude_deg=float(pose.get("longitude_deg", self._snapshot.estimate.longitude_deg)), - altitude_m=float(pose.get("altitude_m", self._snapshot.estimate.altitude_m)), - covariance_semimajor_m=covariance_m, - source_label="satellite_anchored", - fix_type=3, - horizontal_accuracy_m=covariance_m, - anchor_age_ms=0, - ) - self._snapshot = LocalizationSnapshot( - estimate=estimate, - mode="satellite_anchored", - anchor_evidence=anchor_decision, - last_vio_state=self._snapshot.last_vio_state, - ) - return self._snapshot - - def propagate_blackout(self, timestamp_ns: int) -> LocalizationSnapshot: - self._require_snapshot() - assert self._snapshot is not None - previous = self._snapshot.estimate - covariance_m = previous.covariance_semimajor_m + self._config.dead_reckoning_growth_m - no_fix = covariance_m >= self._config.no_fix_covariance_threshold_m - source_label = "no_fix" if no_fix else "dead_reckoned" - fix_type = 0 if no_fix else 2 - estimate = PositionEstimate( - timestamp_ns=timestamp_ns, - latitude_deg=previous.latitude_deg, - longitude_deg=previous.longitude_deg, - altitude_m=previous.altitude_m, - covariance_semimajor_m=covariance_m, - source_label=source_label, - fix_type=fix_type, - horizontal_accuracy_m=max(covariance_m, 999.0 if no_fix else covariance_m), - anchor_age_ms=previous.anchor_age_ms + 1_000, - ) - self._snapshot = LocalizationSnapshot( - estimate=estimate, - mode=source_label, - anchor_evidence=self._snapshot.anchor_evidence, - last_vio_state=self._snapshot.last_vio_state, - ) - return self._snapshot - - def tile_write_eligibility(self) -> TileWriteEligibility: - self._require_snapshot() - assert self._snapshot is not None - estimate = self._snapshot.estimate - if estimate.source_label not in {"satellite_anchored", "vo_extrapolated"}: - return TileWriteEligibility( - eligible=False, - reason="untrusted_source_label", - estimate=estimate, - ) - if estimate.covariance_semimajor_m > self._config.tile_write_covariance_max_m: - return TileWriteEligibility( - eligible=False, - reason="covariance_too_high", - estimate=estimate, - ) - return TileWriteEligibility( - eligible=True, - reason="trusted_pose", - estimate=estimate, - ) - - def _covariance_from_vio(self, vio_state: VioStatePacket) -> float: - if not vio_state.covariance_hint: - return max( - self._config.vio_covariance_floor_m, - self._config.initial_covariance_m / max(vio_state.tracking_quality, 0.1), - ) - diagonal = [ - row[index] for index, row in enumerate(vio_state.covariance_hint) if index < len(row) - ] - return max(self._config.vio_covariance_floor_m, max(diagonal, default=0.0)) - - def _require_snapshot(self) -> None: - if self._snapshot is None: - raise RuntimeError("safety state requires a VIO update before this operation") diff --git a/src/safety_anchor_wrapper/types.py b/src/safety_anchor_wrapper/types.py deleted file mode 100644 index 6c1627f..0000000 --- a/src/safety_anchor_wrapper/types.py +++ /dev/null @@ -1,39 +0,0 @@ -"""Public safety wrapper models.""" - -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field, NonNegativeFloat, NonNegativeInt - -from shared.contracts import AnchorDecision, PositionEstimate, VioStatePacket - - -class SafetyWrapperModel(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - -class TelemetryContext(SafetyWrapperModel): - timestamp_ns: NonNegativeInt - latitude_hint_deg: float = Field(ge=-90.0, le=90.0) - longitude_hint_deg: float = Field(ge=-180.0, le=180.0) - altitude_m: float - - -class SafetyStateConfig(SafetyWrapperModel): - initial_covariance_m: NonNegativeFloat = 2.0 - vio_covariance_floor_m: NonNegativeFloat = 1.0 - dead_reckoning_growth_m: NonNegativeFloat = 50.0 - no_fix_covariance_threshold_m: NonNegativeFloat = 500.0 - tile_write_covariance_max_m: NonNegativeFloat = 3.0 - - -class LocalizationSnapshot(SafetyWrapperModel): - estimate: PositionEstimate - mode: Literal["satellite_anchored", "vo_extrapolated", "dead_reckoned", "no_fix"] - anchor_evidence: AnchorDecision | None = None - last_vio_state: VioStatePacket | None = None - - -class TileWriteEligibility(SafetyWrapperModel): - eligible: bool - reason: str = Field(min_length=1) - estimate: PositionEstimate diff --git a/src/satellite_service/__init__.py b/src/satellite_service/__init__.py deleted file mode 100644 index fba2e1a..0000000 --- a/src/satellite_service/__init__.py +++ /dev/null @@ -1,45 +0,0 @@ -"""Offline satellite retrieval and synchronization component.""" - -from .interfaces import ( - CpuFaissDescriptorIndex, - DescriptorIndex, - LocalVprRetriever, - SatelliteService, - SatelliteSyncBoundary, -) -from .types import ( - DescriptorFidelityReport, - GeneratedTileUploadRecord, - LocalVprIndexPackage, - MissionCacheImportResult, - MissionCachePackage, - RelocalizationRequest, - RuntimePhase, - SatelliteSyncResult, - SatelliteSyncStatus, - UploadOutcome, - VprDescriptorRecord, - VprReadinessReport, - VprRetrievalResult, -) - -__all__ = [ - "CpuFaissDescriptorIndex", - "DescriptorFidelityReport", - "DescriptorIndex", - "GeneratedTileUploadRecord", - "LocalVprIndexPackage", - "LocalVprRetriever", - "MissionCacheImportResult", - "MissionCachePackage", - "RelocalizationRequest", - "RuntimePhase", - "SatelliteService", - "SatelliteSyncBoundary", - "SatelliteSyncResult", - "SatelliteSyncStatus", - "UploadOutcome", - "VprDescriptorRecord", - "VprReadinessReport", - "VprRetrievalResult", -] diff --git a/src/satellite_service/interfaces.py b/src/satellite_service/interfaces.py deleted file mode 100644 index f25a2fd..0000000 --- a/src/satellite_service/interfaces.py +++ /dev/null @@ -1,335 +0,0 @@ -"""Public satellite service interfaces.""" - -from math import sqrt -from collections.abc import Callable -from pathlib import Path -from time import perf_counter -from typing import Protocol - -from shared.contracts import VprCandidate -from shared.errors import ErrorEnvelope -from tile_manager import GeneratedTileSyncPackage - -from .types import ( - DescriptorFidelityReport, - GeneratedTileUploadRecord, - LocalVprIndexPackage, - MissionCacheImportResult, - MissionCachePackage, - RelocalizationRequest, - RuntimePhase, - SatelliteSyncResult, - SatelliteSyncStatus, - UploadOutcome, - VprDescriptorRecord, - VprReadinessReport, - VprRetrievalResult, -) - - -class SatelliteService(Protocol): - """Retrieves offline VPR candidates from mission cache data.""" - - def load_index(self, package: LocalVprIndexPackage) -> VprReadinessReport: - """Load the local descriptor index.""" - - def retrieve(self, request: RelocalizationRequest) -> VprRetrievalResult: - """Return candidate anchor records for one frame.""" - - -class DescriptorIndex(Protocol): - """Search boundary for local descriptor packages.""" - - @property - def record_count(self) -> int: - """Return the number of loaded descriptor records.""" - - def search( - self, - query_descriptor: tuple[float, ...], - top_k: int, - ) -> tuple[tuple[float, VprDescriptorRecord], ...]: - """Return scored descriptor records in descending score order.""" - - -class CpuFaissDescriptorIndex: - """CPU vector index with a FAISS-compatible search contract.""" - - def __init__(self, records: tuple[VprDescriptorRecord, ...]) -> None: - self._records = tuple(record for record in records if record.freshness_status != "rejected") - - @property - def record_count(self) -> int: - return len(self._records) - - def search( - self, - query_descriptor: tuple[float, ...], - top_k: int, - ) -> tuple[tuple[float, VprDescriptorRecord], ...]: - scored = sorted( - ( - (self._cosine_similarity(query_descriptor, record.descriptor), record) - for record in self._records - ), - key=lambda item: item[0], - reverse=True, - ) - return tuple(scored[:top_k]) - - def _cosine_similarity( - self, - query_descriptor: tuple[float, ...], - record_descriptor: tuple[float, ...], - ) -> float: - max_length = max(len(query_descriptor), len(record_descriptor)) - padded_query = query_descriptor + (0.0,) * (max_length - len(query_descriptor)) - padded_record = record_descriptor + (0.0,) * (max_length - len(record_descriptor)) - dot_product = sum( - query_value * record_value - for query_value, record_value in zip(padded_query, padded_record) - ) - query_norm = sqrt(sum(value * value for value in padded_query)) or 1.0 - record_norm = sqrt(sum(value * value for value in padded_record)) or 1.0 - return max(0.0, min(1.0, dot_product / (query_norm * record_norm))) - - -class LocalVprRetriever: - """Triggered local VPR retrieval over mission-cache descriptor indexes.""" - - def __init__(self) -> None: - self._package: LocalVprIndexPackage | None = None - self._index: DescriptorIndex | None = None - self._load_error: ErrorEnvelope | None = None - - def load_index(self, package: LocalVprIndexPackage) -> VprReadinessReport: - self._package = package - self._index = CpuFaissDescriptorIndex(package.records) - self._load_error = None - return VprReadinessReport( - ready=self._index.record_count > 0, - engine=package.engine, - loaded_records=self._index.record_count, - package_id=package.package_id, - descriptor_model=package.descriptor_model, - error=None - if self._index.record_count > 0 - else self._error("local descriptor index has no searchable records", "empty_index"), - ) - - def load_index_from_path(self, package_path: str | Path) -> VprReadinessReport: - try: - return self.load_index(LocalVprIndexPackage.from_json_file(package_path)) - except (FileNotFoundError, OSError, ValueError) as exc: - self._package = None - self._index = None - self._load_error = self._error( - f"local descriptor index package could not be loaded: {exc}", - "index_package_invalid", - ) - return VprReadinessReport( - ready=False, - engine="cpu_faiss", - loaded_records=0, - error=self._load_error, - ) - - def readiness(self) -> VprReadinessReport: - if self._load_error is not None: - return VprReadinessReport( - ready=False, - engine="cpu_faiss", - loaded_records=0, - error=self._load_error, - ) - if self._index is None or self._package is None: - return VprReadinessReport( - ready=False, - engine="cpu_faiss", - loaded_records=0, - error=self._error("local descriptor index is not loaded", "index_not_loaded"), - ) - return VprReadinessReport( - ready=True, - engine=self._package.engine, - loaded_records=self._index.record_count, - package_id=self._package.package_id, - descriptor_model=self._package.descriptor_model, - ) - - def retrieve(self, request: RelocalizationRequest) -> VprRetrievalResult: - started = perf_counter() - readiness = self.readiness() - if not readiness.ready: - return VprRetrievalResult( - ready=False, - degraded=True, - retrieval_path="unavailable", - error=readiness.error, - ) - - if request.query_descriptor is None: - return VprRetrievalResult( - ready=True, - degraded=True, - retrieval_path="unavailable", - error=self._error( - "query descriptor is required for local descriptor index retrieval", - "query_descriptor_missing", - ), - ) - - assert self._index is not None - scored = self._index.search(request.query_descriptor, request.top_k) - candidates = tuple( - VprCandidate( - chunk_id=record.chunk_id, - tile_id=record.tile_id, - score=score, - footprint=record.footprint, - freshness_status=record.freshness_status, - ) - for score, record in scored[: request.top_k] - ) - latency_ms = (perf_counter() - started) * 1000.0 - if not candidates: - return VprRetrievalResult( - ready=True, - degraded=True, - retrieval_path="local_descriptor_index", - latency_ms=latency_ms, - error=self._error( - "local descriptor index produced no valid candidates", - "no_candidates", - ), - ) - - return VprRetrievalResult( - ready=True, - degraded=False, - candidates=candidates, - retrieval_path="local_descriptor_index", - latency_ms=latency_ms, - ) - - def verify_descriptor_fidelity( - self, - reference_descriptor: tuple[float, ...], - optimized_descriptor: tuple[float, ...], - max_l2_delta: float, - ) -> DescriptorFidelityReport: - observed_delta = self._l2_distance(reference_descriptor, optimized_descriptor) - return DescriptorFidelityReport( - accepted=observed_delta <= max_l2_delta, - observed_l2_delta=observed_delta, - max_l2_delta=max_l2_delta, - ) - - def _l2_distance( - self, - reference_descriptor: tuple[float, ...], - optimized_descriptor: tuple[float, ...], - ) -> float: - max_length = max(len(reference_descriptor), len(optimized_descriptor)) - padded_reference = reference_descriptor + (0.0,) * (max_length - len(reference_descriptor)) - padded_optimized = optimized_descriptor + (0.0,) * (max_length - len(optimized_descriptor)) - return sqrt( - sum( - (reference_value - optimized_value) ** 2 - for reference_value, optimized_value in zip(padded_reference, padded_optimized) - ) - ) - - def _error(self, message: str, cause: str) -> ErrorEnvelope: - return ErrorEnvelope( - component="satellite_service", - category="runtime", - message=message, - severity="warning", - retryable=False, - cause=cause, - ) - - -class SatelliteSyncBoundary: - """Owns pre-flight and post-flight package exchange only.""" - - def __init__( - self, - uploader: Callable[[GeneratedTileSyncPackage], UploadOutcome] | None = None, - ) -> None: - self._uploader = uploader or self._default_uploader - self._imports: dict[str, MissionCachePackage] = {} - self._upload_records: list[GeneratedTileUploadRecord] = [] - - def import_mission_cache( - self, - package: MissionCachePackage, - phase: RuntimePhase = "pre_flight", - ) -> MissionCacheImportResult: - if phase != "pre_flight": - return MissionCacheImportResult( - package_id=package.package_id, - mission_id=package.mission_id, - ready_for_tile_validation=False, - error=self._phase_error("mission cache import", phase), - ) - - self._imports[package.package_id] = package - return MissionCacheImportResult( - package_id=package.package_id, - mission_id=package.mission_id, - ready_for_tile_validation=True, - manifest_entries=package.manifest_entries, - ) - - def upload_generated_tiles( - self, - package: GeneratedTileSyncPackage, - phase: RuntimePhase = "post_flight", - ) -> SatelliteSyncResult: - if phase != "post_flight": - return SatelliteSyncResult(error=self._phase_error("generated tile upload", phase)) - - if not package.sidecars: - record = GeneratedTileUploadRecord( - package_ref=package.package_ref, - mission_id=package.mission_id, - status="rejected", - reason="empty_generated_tile_package", - retained_for_retry=False, - ) - else: - outcome = self._uploader(package) - record = GeneratedTileUploadRecord( - package_ref=package.package_ref, - mission_id=package.mission_id, - status=outcome, - reason=outcome, - retained_for_retry=outcome == "retryable_failure", - ) - - self._upload_records.append(record) - return SatelliteSyncResult(upload_record=record) - - def status(self) -> SatelliteSyncStatus: - return SatelliteSyncStatus( - imported_package_ids=tuple(self._imports), - upload_records=tuple(self._upload_records), - retry_package_refs=tuple( - record.package_ref for record in self._upload_records if record.retained_for_retry - ), - ) - - def _phase_error(self, operation: str, phase: RuntimePhase) -> ErrorEnvelope: - return ErrorEnvelope( - component="satellite_service", - category="security", - message=f"{operation} is not allowed during {phase}", - severity="warning", - retryable=False, - cause="mid_flight_network_blocked" if phase == "in_flight" else "phase_not_allowed", - ) - - def _default_uploader(self, package: GeneratedTileSyncPackage) -> UploadOutcome: - return "success" diff --git a/src/satellite_service/native/README.md b/src/satellite_service/native/README.md deleted file mode 100644 index c9fa18b..0000000 --- a/src/satellite_service/native/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Satellite Service Descriptor Index Package - -Exports local descriptor index search boundaries owned by `satellite_service`. diff --git a/src/satellite_service/native/__init__.py b/src/satellite_service/native/__init__.py deleted file mode 100644 index 571f3af..0000000 --- a/src/satellite_service/native/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Local descriptor index package exports.""" - -from satellite_service.interfaces import CpuFaissDescriptorIndex, DescriptorIndex - -__all__ = ["CpuFaissDescriptorIndex", "DescriptorIndex"] diff --git a/src/satellite_service/types.py b/src/satellite_service/types.py deleted file mode 100644 index 6f15df5..0000000 --- a/src/satellite_service/types.py +++ /dev/null @@ -1,105 +0,0 @@ -"""Public satellite service models.""" - -import json -from pathlib import Path -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field, PositiveInt, ValidationError - -from shared.contracts import VprCandidate -from shared.errors import ErrorEnvelope -from tile_manager import TileManifestEntry - - -class SatelliteServiceModel(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - -class MissionCachePackage(SatelliteServiceModel): - package_id: str = Field(min_length=1) - mission_id: str = Field(min_length=1) - manifest_entries: tuple[TileManifestEntry, ...] = Field(min_length=1) - - -class MissionCacheImportResult(SatelliteServiceModel): - package_id: str = Field(min_length=1) - mission_id: str = Field(min_length=1) - ready_for_tile_validation: bool - manifest_entries: tuple[TileManifestEntry, ...] = () - error: ErrorEnvelope | None = None - - -class GeneratedTileUploadRecord(SatelliteServiceModel): - package_ref: str = Field(min_length=1) - mission_id: str = Field(min_length=1) - status: Literal["uploaded", "rejected", "retryable_failure"] - reason: str - retained_for_retry: bool - - -class SatelliteSyncStatus(SatelliteServiceModel): - imported_package_ids: tuple[str, ...] - upload_records: tuple[GeneratedTileUploadRecord, ...] - retry_package_refs: tuple[str, ...] - - -class SatelliteSyncResult(SatelliteServiceModel): - upload_record: GeneratedTileUploadRecord | None = None - error: ErrorEnvelope | None = None - - -class VprDescriptorRecord(SatelliteServiceModel): - chunk_id: str = Field(min_length=1) - tile_id: str = Field(min_length=1) - descriptor: tuple[float, ...] = Field(min_length=1) - footprint: dict[str, float] - freshness_status: Literal["fresh", "stale", "rejected"] - - -class LocalVprIndexPackage(SatelliteServiceModel): - package_id: str = Field(min_length=1) - engine: Literal["cpu_faiss"] = "cpu_faiss" - descriptor_model: str = Field(default="dinov2_vlad", min_length=1) - records: tuple[VprDescriptorRecord, ...] = Field(min_length=1) - - @classmethod - def from_json_file(cls, package_path: str | Path) -> "LocalVprIndexPackage": - payload = json.loads(Path(package_path).read_text(encoding="utf-8")) - return cls.model_validate(payload) - - -class RelocalizationRequest(SatelliteServiceModel): - frame_id: str = Field(min_length=1) - image_ref: str = Field(min_length=1) - trigger_reason: str = Field(min_length=1) - top_k: PositiveInt = Field(le=50) - query_descriptor: tuple[float, ...] | None = None - - -class VprReadinessReport(SatelliteServiceModel): - ready: bool - engine: Literal["cpu_faiss"] - loaded_records: int = Field(ge=0) - package_id: str | None = None - descriptor_model: str | None = None - error: ErrorEnvelope | None = None - - -class VprRetrievalResult(SatelliteServiceModel): - ready: bool - degraded: bool - candidates: tuple[VprCandidate, ...] = () - retrieval_path: Literal["local_descriptor_index", "unavailable"] = "unavailable" - latency_ms: float | None = Field(default=None, ge=0.0) - error: ErrorEnvelope | None = None - - -class DescriptorFidelityReport(SatelliteServiceModel): - accepted: bool - observed_l2_delta: float = Field(ge=0.0) - max_l2_delta: float = Field(ge=0.0) - - -RuntimePhase = Literal["pre_flight", "in_flight", "post_flight"] -UploadOutcome = Literal["success", "retryable_failure", "rejected"] -IndexLoadError = FileNotFoundError | json.JSONDecodeError | ValidationError | OSError diff --git a/src/shared/__init__.py b/src/shared/__init__.py deleted file mode 100644 index 5b1a1e1..0000000 --- a/src/shared/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Shared runtime foundation packages.""" diff --git a/src/shared/config/__init__.py b/src/shared/config/__init__.py deleted file mode 100644 index a539b7a..0000000 --- a/src/shared/config/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Runtime configuration helper namespace.""" - -from shared.config.models import RuntimeProfile, readiness_error, validate_runtime_profile - -__all__ = ["RuntimeProfile", "readiness_error", "validate_runtime_profile"] diff --git a/src/shared/config/models.py b/src/shared/config/models.py deleted file mode 100644 index 2ba278c..0000000 --- a/src/shared/config/models.py +++ /dev/null @@ -1,59 +0,0 @@ -"""Runtime profile configuration and readiness validation.""" - -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field, ValidationError, model_validator - -from shared.errors import ErrorEnvelope, ResultEnvelope - - -class RuntimeProfile(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - environment: Literal["development", "ci", "staging", "jetson", "production"] - config_dir: str = Field(min_length=1) - cache_dir: str | None = None - fdr_dir: str | None = None - database_url: str | None = None - mavlink_url: str | None = None - camera_source: str | None = None - signing_key_ref: str | None = None - - @model_validator(mode="after") - def production_requires_runtime_paths(self) -> "RuntimeProfile": - if self.environment != "production": - return self - - missing = [ - name - for name in ( - "cache_dir", - "fdr_dir", - "database_url", - "mavlink_url", - "camera_source", - "signing_key_ref", - ) - if getattr(self, name) in (None, "") - ] - if missing: - raise ValueError(f"production profile missing required settings: {', '.join(missing)}") - return self - - -def readiness_error(component: str, message: str) -> ErrorEnvelope: - return ErrorEnvelope( - component=component, - category="configuration", - message=message, - severity="critical", - retryable=False, - ) - - -def validate_runtime_profile(component: str, payload: dict[str, object]) -> ResultEnvelope: - try: - RuntimeProfile.model_validate(payload) - except ValidationError as error: - return ResultEnvelope.failure(readiness_error(component, str(error))) - return ResultEnvelope.success() diff --git a/src/shared/contracts/__init__.py b/src/shared/contracts/__init__.py deleted file mode 100644 index de7924c..0000000 --- a/src/shared/contracts/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Shared DTO and interface contract namespace.""" - -from shared.contracts.models import ( - AnchorDecision, - CacheTileRecord, - FdrEvent, - FramePacket, - PositionEstimate, - RuntimeContractModel, - TelemetrySample, - VioStatePacket, - VprCandidate, -) - -CONTRACT_VERSION = "1.0.0" - -__all__ = [ - "AnchorDecision", - "CONTRACT_VERSION", - "CacheTileRecord", - "FdrEvent", - "FramePacket", - "PositionEstimate", - "RuntimeContractModel", - "TelemetrySample", - "VioStatePacket", - "VprCandidate", -] diff --git a/src/shared/contracts/models.py b/src/shared/contracts/models.py deleted file mode 100644 index 5d0d7fe..0000000 --- a/src/shared/contracts/models.py +++ /dev/null @@ -1,116 +0,0 @@ -"""Shared runtime DTO contracts. - -These models intentionally carry only cross-component shape and validation rules. -Component algorithms and storage choices stay in their owning packages. -""" - -from datetime import date -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field, NonNegativeFloat, NonNegativeInt, PositiveFloat -from pydantic import model_validator - - -class RuntimeContractModel(BaseModel): - """Base settings for public runtime contracts.""" - - model_config = ConfigDict(extra="forbid", frozen=True) - - -class FramePacket(RuntimeContractModel): - frame_id: str = Field(min_length=1) - timestamp_ns: NonNegativeInt - image_ref: str = Field(min_length=1) - calibration_id: str = Field(min_length=1) - occlusion: Literal["clear", "partial", "total", "unreadable"] - quality: float = Field(ge=0.0, le=1.0) - normalization_hint: str | None = None - raw_frame_retained: bool = False - - @model_validator(mode="after") - def raw_frames_must_not_be_retained(self) -> "FramePacket": - if self.raw_frame_retained: - raise ValueError("raw frame payloads must be referenced, not retained") - return self - - -class TelemetrySample(RuntimeContractModel): - timestamp_ns: NonNegativeInt - imu: dict[str, float] - attitude: dict[str, float] - altitude_m: float - airspeed_mps: NonNegativeFloat - gps_health: Literal["healthy", "degraded", "lost", "spoofed"] - - -class VioStatePacket(RuntimeContractModel): - timestamp_ns: NonNegativeInt - relative_pose: dict[str, float] - velocity_mps: tuple[float, float, float] - bias_estimate: dict[str, float] | None = None - tracking_quality: float = Field(ge=0.0, le=1.0) - covariance_hint: list[list[float]] | None = None - - -class PositionEstimate(RuntimeContractModel): - timestamp_ns: NonNegativeInt - latitude_deg: float = Field(ge=-90.0, le=90.0) - longitude_deg: float = Field(ge=-180.0, le=180.0) - altitude_m: float - covariance_semimajor_m: NonNegativeFloat - source_label: Literal["satellite_anchored", "vo_extrapolated", "dead_reckoned", "no_fix"] - fix_type: int = Field(ge=0, le=3) - horizontal_accuracy_m: NonNegativeFloat - anchor_age_ms: NonNegativeInt - - @model_validator(mode="after") - def accuracy_must_not_under_report_covariance(self) -> "PositionEstimate": - if self.horizontal_accuracy_m < self.covariance_semimajor_m: - raise ValueError("horizontal_accuracy_m must not under-report covariance_semimajor_m") - return self - - -class VprCandidate(RuntimeContractModel): - chunk_id: str = Field(min_length=1) - tile_id: str = Field(min_length=1) - score: float = Field(ge=0.0, le=1.0) - footprint: dict[str, float] - freshness_status: Literal["fresh", "stale", "rejected"] - - -class AnchorDecision(RuntimeContractModel): - candidate_id: str = Field(min_length=1) - accepted: bool - estimated_pose: dict[str, float] | None = None - inliers: NonNegativeInt - mean_reprojection_error_px: NonNegativeFloat - rejection_reason: str | None = None - - @model_validator(mode="after") - def accepted_anchors_require_pose(self) -> "AnchorDecision": - if self.accepted and self.estimated_pose is None: - raise ValueError("accepted anchor decisions require estimated_pose") - if self.accepted and self.rejection_reason is not None: - raise ValueError("accepted anchor decisions must not include rejection_reason") - return self - - -class CacheTileRecord(RuntimeContractModel): - tile_id: str = Field(min_length=1) - crs: str = Field(min_length=1) - meters_per_pixel: PositiveFloat - capture_date: date - signature_hash: str = Field(min_length=1) - trust_level: Literal["trusted", "generated", "quarantined", "rejected"] - freshness_status: Literal["fresh", "stale", "rejected"] - provenance: str = Field(min_length=1) - - -class FdrEvent(RuntimeContractModel): - event_type: str = Field(min_length=1) - timestamp_ns: NonNegativeInt - component: str = Field(min_length=1) - severity: Literal["debug", "info", "warning", "error", "critical"] - payload_ref: str = Field(min_length=1) - mission_id: str = Field(min_length=1) - run_id: str = Field(min_length=1) diff --git a/src/shared/errors/__init__.py b/src/shared/errors/__init__.py deleted file mode 100644 index 891c272..0000000 --- a/src/shared/errors/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Shared error envelope namespace.""" - -from shared.errors.models import ErrorEnvelope, ResultEnvelope - -__all__ = ["ErrorEnvelope", "ResultEnvelope"] diff --git a/src/shared/errors/models.py b/src/shared/errors/models.py deleted file mode 100644 index 06c07c5..0000000 --- a/src/shared/errors/models.py +++ /dev/null @@ -1,38 +0,0 @@ -"""Shared structured error envelopes.""" - -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field - - -class ErrorEnvelope(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - component: str = Field(min_length=1) - category: Literal[ - "configuration", - "dependency", - "validation", - "runtime", - "security", - "resource", - ] - message: str = Field(min_length=1) - severity: Literal["info", "warning", "error", "critical"] - retryable: bool - cause: str | None = None - - -class ResultEnvelope(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - ok: bool - error: ErrorEnvelope | None = None - - @classmethod - def success(cls) -> "ResultEnvelope": - return cls(ok=True) - - @classmethod - def failure(cls, error: ErrorEnvelope) -> "ResultEnvelope": - return cls(ok=False, error=error) diff --git a/src/shared/geo_geometry/__init__.py b/src/shared/geo_geometry/__init__.py deleted file mode 100644 index 486aff2..0000000 --- a/src/shared/geo_geometry/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Geospatial geometry helper namespace.""" - -from shared.geo_geometry.models import ( - CameraFootprint, - LocalNedCoordinate, - Wgs84Coordinate, - distance_m, - local_to_wgs84, - nadir_camera_footprint, - wgs84_to_local, -) - -__all__ = [ - "CameraFootprint", - "LocalNedCoordinate", - "Wgs84Coordinate", - "distance_m", - "local_to_wgs84", - "nadir_camera_footprint", - "wgs84_to_local", -] diff --git a/src/shared/geo_geometry/models.py b/src/shared/geo_geometry/models.py deleted file mode 100644 index c6528f6..0000000 --- a/src/shared/geo_geometry/models.py +++ /dev/null @@ -1,83 +0,0 @@ -"""Deterministic geospatial helper models and calculations.""" - -from math import cos, radians, sqrt - -from pydantic import BaseModel, ConfigDict, Field, PositiveFloat - -EARTH_RADIUS_M = 6_378_137.0 - - -class GeometryModel(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - -class Wgs84Coordinate(GeometryModel): - latitude_deg: float = Field(ge=-90.0, le=90.0) - longitude_deg: float = Field(ge=-180.0, le=180.0) - altitude_m: float = 0.0 - - -class LocalNedCoordinate(GeometryModel): - north_m: float - east_m: float - down_m: float = 0.0 - - -class CameraFootprint(GeometryModel): - center: Wgs84Coordinate - ground_width_m: PositiveFloat - ground_height_m: PositiveFloat - ground_sample_distance_m_per_px: PositiveFloat - - -def wgs84_to_local(origin: Wgs84Coordinate, point: Wgs84Coordinate) -> LocalNedCoordinate: - lat_delta_rad = radians(point.latitude_deg - origin.latitude_deg) - lon_delta_rad = radians(point.longitude_deg - origin.longitude_deg) - latitude_scale = cos(radians(origin.latitude_deg)) - - return LocalNedCoordinate( - north_m=lat_delta_rad * EARTH_RADIUS_M, - east_m=lon_delta_rad * EARTH_RADIUS_M * latitude_scale, - down_m=origin.altitude_m - point.altitude_m, - ) - - -def local_to_wgs84(origin: Wgs84Coordinate, local: LocalNedCoordinate) -> Wgs84Coordinate: - latitude_deg = origin.latitude_deg + (local.north_m / EARTH_RADIUS_M) * ( - 180.0 / 3.141592653589793 - ) - latitude_scale = cos(radians(origin.latitude_deg)) - longitude_deg = origin.longitude_deg + (local.east_m / (EARTH_RADIUS_M * latitude_scale)) * ( - 180.0 / 3.141592653589793 - ) - - return Wgs84Coordinate( - latitude_deg=latitude_deg, - longitude_deg=longitude_deg, - altitude_m=origin.altitude_m - local.down_m, - ) - - -def distance_m(first: Wgs84Coordinate, second: Wgs84Coordinate) -> float: - local = wgs84_to_local(first, second) - return sqrt(local.north_m**2 + local.east_m**2 + local.down_m**2) - - -def nadir_camera_footprint( - center: Wgs84Coordinate, - altitude_agl_m: PositiveFloat, - sensor_width_px: int, - sensor_height_px: int, - ground_sample_distance_m_per_px: PositiveFloat, -) -> CameraFootprint: - if sensor_width_px <= 0 or sensor_height_px <= 0: - raise ValueError("sensor dimensions must be positive") - if altitude_agl_m <= 0: - raise ValueError("altitude_agl_m must be positive") - - return CameraFootprint( - center=center, - ground_width_m=sensor_width_px * ground_sample_distance_m_per_px, - ground_height_m=sensor_height_px * ground_sample_distance_m_per_px, - ground_sample_distance_m_per_px=ground_sample_distance_m_per_px, - ) diff --git a/src/shared/telemetry/__init__.py b/src/shared/telemetry/__init__.py deleted file mode 100644 index 1ee9f7e..0000000 --- a/src/shared/telemetry/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Structured telemetry and health metadata namespace.""" - -from shared.telemetry.models import HealthEvent, MetricsLabels - -__all__ = ["HealthEvent", "MetricsLabels"] diff --git a/src/shared/telemetry/models.py b/src/shared/telemetry/models.py deleted file mode 100644 index 1633322..0000000 --- a/src/shared/telemetry/models.py +++ /dev/null @@ -1,23 +0,0 @@ -"""FDR-safe health and metrics metadata.""" - -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field, NonNegativeInt - - -class HealthEvent(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - component: str = Field(min_length=1) - timestamp_ns: NonNegativeInt - liveness: Literal["alive", "failed"] - readiness: Literal["ready", "not_ready"] - dependency_state: dict[str, str] = Field(default_factory=dict) - - -class MetricsLabels(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - component: str = Field(min_length=1) - action: str = Field(min_length=1) - status: Literal["ok", "degraded", "failed"] diff --git a/src/shared/time_sync/__init__.py b/src/shared/time_sync/__init__.py deleted file mode 100644 index ff71e86..0000000 --- a/src/shared/time_sync/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Clock-domain and timestamp helper namespace.""" - -from shared.time_sync.models import ( - TimeSyncViolation, - TimeWindowResult, - check_monotonic_timestamps, - select_time_window, -) - -__all__ = [ - "TimeSyncViolation", - "TimeWindowResult", - "check_monotonic_timestamps", - "select_time_window", -] diff --git a/src/shared/time_sync/models.py b/src/shared/time_sync/models.py deleted file mode 100644 index d464a66..0000000 --- a/src/shared/time_sync/models.py +++ /dev/null @@ -1,77 +0,0 @@ -"""Timestamp alignment helpers.""" - -from pydantic import BaseModel, ConfigDict, NonNegativeInt - - -class TimeSyncModel(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - -class TimeSyncViolation(TimeSyncModel): - category: str - message: str - - -class TimeWindowResult(TimeSyncModel): - frame_timestamp_ns: NonNegativeInt - sample_timestamps_ns: tuple[NonNegativeInt, ...] - max_gap_ns: NonNegativeInt - jitter_ns: NonNegativeInt - violations: tuple[TimeSyncViolation, ...] = () - - @property - def ok(self) -> bool: - return not self.violations - - -def check_monotonic_timestamps(timestamps_ns: list[int]) -> tuple[TimeSyncViolation, ...]: - violations: list[TimeSyncViolation] = [] - for previous, current in zip(timestamps_ns, timestamps_ns[1:]): - if current <= previous: - violations.append( - TimeSyncViolation( - category="timestamp_mismatch", - message="timestamps must be strictly increasing", - ) - ) - break - return tuple(violations) - - -def select_time_window( - frame_timestamp_ns: int, - sample_timestamps_ns: list[int], - tolerance_ns: int, -) -> TimeWindowResult: - if tolerance_ns < 0: - raise ValueError("tolerance_ns must be non-negative") - - violations = list(check_monotonic_timestamps(sample_timestamps_ns)) - selected = tuple( - timestamp - for timestamp in sample_timestamps_ns - if abs(timestamp - frame_timestamp_ns) <= tolerance_ns - ) - if not selected: - violations.append( - TimeSyncViolation( - category="gap_exceeded", - message="no telemetry samples fall within the frame tolerance window", - ) - ) - - gaps = [ - current - previous - for previous, current in zip(sample_timestamps_ns, sample_timestamps_ns[1:]) - if current > previous - ] - max_gap_ns = max(gaps, default=0) - jitter_ns = max(gaps, default=0) - min(gaps, default=0) if gaps else 0 - - return TimeWindowResult( - frame_timestamp_ns=frame_timestamp_ns, - sample_timestamps_ns=selected, - max_gap_ns=max_gap_ns, - jitter_ns=jitter_ns, - violations=tuple(violations), - ) diff --git a/src/tile_manager/__init__.py b/src/tile_manager/__init__.py deleted file mode 100644 index 8068de7..0000000 --- a/src/tile_manager/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Tile cache and generated tile lifecycle component.""" - -from .interfaces import LocalTileManager, TileManager -from .types import ( - CacheValidationReport, - GeneratedTileCandidate, - GeneratedTileSidecar, - GeneratedTileSyncPackage, - TileGenerationRequest, - TileManifestEntry, - TileMetadataLookup, - TileValidationDecision, - freshness_status, -) - -__all__ = [ - "CacheValidationReport", - "GeneratedTileCandidate", - "GeneratedTileSidecar", - "GeneratedTileSyncPackage", - "LocalTileManager", - "TileManager", - "TileGenerationRequest", - "TileManifestEntry", - "TileMetadataLookup", - "TileValidationDecision", - "freshness_status", -] diff --git a/src/tile_manager/interfaces.py b/src/tile_manager/interfaces.py deleted file mode 100644 index d0b3060..0000000 --- a/src/tile_manager/interfaces.py +++ /dev/null @@ -1,199 +0,0 @@ -"""Public tile manager interfaces.""" - -from datetime import datetime -from typing import Any, Protocol - -from shared.contracts import CacheTileRecord -from shared.errors import ErrorEnvelope - -from .types import ( - CacheValidationReport, - GeneratedTileCandidate, - GeneratedTileSidecar, - GeneratedTileSyncPackage, - TileManifestEntry, - TileGenerationRequest, - TileMetadataLookup, - TileValidationDecision, - freshness_status, -) - - -class TileManager(Protocol): - """Validates and serves local cache tile records.""" - - def validate_cache(self) -> None: - """Validate local cache metadata and signatures.""" - - def get_tile_window(self, footprint: Any) -> list[Any]: - """Return tiles intersecting a requested footprint.""" - - -class LocalTileManager: - """Validates preloaded local cache metadata and serves trusted tile records.""" - - def __init__( - self, - trusted_signature_hashes: set[str], - now: datetime, - postgis_available: bool = True, - ) -> None: - self._trusted_signature_hashes = trusted_signature_hashes - self._now = now - self._postgis_available = postgis_available - self._trusted_by_tile_id: dict[str, CacheTileRecord] = {} - self._descriptor_by_tile_id: dict[str, str] = {} - self._tile_id_by_chunk_id: dict[str, str] = {} - self._generated_candidates: list[GeneratedTileCandidate] = [] - - def validate_cache(self, entries: list[TileManifestEntry]) -> CacheValidationReport: - if not self._postgis_available: - decisions = tuple( - TileValidationDecision( - tile_id=entry.tile_id, - accepted=False, - reason="postgis_unavailable", - ) - for entry in entries - ) - return CacheValidationReport(activated=False, decisions=decisions) - - decisions = tuple(self._validate_entry(entry) for entry in entries) - self._trusted_by_tile_id = { - decision.record.tile_id: decision.record - for decision in decisions - if decision.record is not None - } - self._descriptor_by_tile_id = { - entry.tile_id: entry.descriptor_ref - for entry in entries - if entry.tile_id in self._trusted_by_tile_id - } - self._tile_id_by_chunk_id = { - entry.chunk_id: entry.tile_id - for entry in entries - if entry.tile_id in self._trusted_by_tile_id - } - - return CacheValidationReport( - activated=bool(self._trusted_by_tile_id) - and all(decision.accepted for decision in decisions), - decisions=decisions, - ) - - def get_tile_window(self, footprint: Any) -> list[CacheTileRecord]: - if isinstance(footprint, dict) and "chunk_id" in footprint: - tile_id = self._tile_id_by_chunk_id.get(str(footprint["chunk_id"])) - return [self._trusted_by_tile_id[tile_id]] if tile_id is not None else [] - return list(self._trusted_by_tile_id.values()) - - def get_tile_metadata(self, chunk_id: str) -> TileMetadataLookup: - tile_id = self._tile_id_by_chunk_id.get(chunk_id) - if tile_id is None: - return TileMetadataLookup( - found=False, - error=ErrorEnvelope( - component="tile_manager", - category="validation", - message=f"no trusted tile metadata for chunk {chunk_id}", - severity="warning", - retryable=False, - ), - ) - - return TileMetadataLookup( - found=True, - record=self._trusted_by_tile_id[tile_id], - descriptor_ref=self._descriptor_by_tile_id[tile_id], - ) - - def orthorectify_frame(self, request: TileGenerationRequest) -> GeneratedTileCandidate: - if not request.frame_usable: - return GeneratedTileCandidate(accepted=False, rejection_reason="frame_not_usable") - if request.parent_covariance_m > 5.0: - return GeneratedTileCandidate(accepted=False, rejection_reason="covariance_too_high") - if request.quality_score < 0.25: - return GeneratedTileCandidate(accepted=False, rejection_reason="quality_too_low") - - trust_level = "generated" if request.parent_covariance_m <= 3.0 else "candidate" - tile_id = f"generated-{request.mission_id}-{request.frame_id}" - candidate = GeneratedTileCandidate( - accepted=True, - tile_id=tile_id, - cog_ref=f"generated/{request.mission_id}/{tile_id}.cog.tif", - sidecar=GeneratedTileSidecar( - tile_id=tile_id, - parent_frame_id=request.frame_id, - parent_covariance_m=request.parent_covariance_m, - quality_score=request.quality_score, - trust_level=trust_level, - provenance=request.source_provenance, - ), - ) - self._generated_candidates.append(candidate) - return candidate - - def package_sync(self, mission_id: str) -> GeneratedTileSyncPackage: - sidecars = tuple( - candidate.sidecar - for candidate in self._generated_candidates - if candidate.sidecar is not None - ) - manifest_delta = tuple( - { - "tile_id": sidecar.tile_id, - "trust_level": sidecar.trust_level, - "parent_covariance_m": sidecar.parent_covariance_m, - "provenance": sidecar.provenance, - } - for sidecar in sidecars - ) - return GeneratedTileSyncPackage( - package_ref=f"generated/{mission_id}/sync-package.json", - mission_id=mission_id, - manifest_delta=manifest_delta, - sidecars=sidecars, - ) - - def _validate_entry(self, entry: TileManifestEntry) -> TileValidationDecision: - if entry.signature_hash not in self._trusted_signature_hashes: - return TileValidationDecision( - tile_id=entry.tile_id, - accepted=False, - reason="signature_not_trusted", - ) - - if entry.content_hash != entry.expected_content_hash: - return TileValidationDecision( - tile_id=entry.tile_id, - accepted=False, - reason="content_hash_mismatch", - ) - - if entry.sidecar_hash != entry.expected_sidecar_hash: - return TileValidationDecision( - tile_id=entry.tile_id, - accepted=False, - reason="sidecar_hash_mismatch", - ) - - freshness = freshness_status(entry.expires_at, self._now) - if freshness == "stale": - return TileValidationDecision(tile_id=entry.tile_id, accepted=False, reason="stale") - - record = CacheTileRecord( - tile_id=entry.tile_id, - crs=entry.crs, - meters_per_pixel=entry.meters_per_pixel, - capture_date=entry.capture_date, - signature_hash=entry.signature_hash, - trust_level="trusted", - freshness_status=freshness, - provenance=entry.provenance, - ) - return TileValidationDecision( - tile_id=entry.tile_id, - accepted=True, - reason="trusted", - record=record, - ) diff --git a/src/tile_manager/types.py b/src/tile_manager/types.py deleted file mode 100644 index b4df7c5..0000000 --- a/src/tile_manager/types.py +++ /dev/null @@ -1,97 +0,0 @@ -"""Public tile manager models.""" - -from datetime import date, datetime, timezone -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field, PositiveFloat - -from shared.contracts import CacheTileRecord -from shared.errors import ErrorEnvelope - - -class TileManagerModel(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - -class TileManifestEntry(TileManagerModel): - tile_id: str = Field(min_length=1) - chunk_id: str = Field(min_length=1) - crs: str = Field(min_length=1) - meters_per_pixel: PositiveFloat - capture_date: date - expires_at: datetime - content_hash: str = Field(min_length=1) - expected_content_hash: str = Field(min_length=1) - sidecar_hash: str = Field(min_length=1) - expected_sidecar_hash: str = Field(min_length=1) - signature_hash: str = Field(min_length=1) - provenance: str = Field(min_length=1) - footprint: dict[str, float] - descriptor_ref: str = Field(min_length=1) - - -class TileValidationDecision(TileManagerModel): - tile_id: str = Field(min_length=1) - accepted: bool - reason: str - record: CacheTileRecord | None = None - - -class CacheValidationReport(TileManagerModel): - activated: bool - decisions: tuple[TileValidationDecision, ...] - - @property - def trusted_records(self) -> tuple[CacheTileRecord, ...]: - return tuple(decision.record for decision in self.decisions if decision.record is not None) - - -class TileMetadataLookup(TileManagerModel): - found: bool - record: CacheTileRecord | None = None - descriptor_ref: str | None = None - error: ErrorEnvelope | None = None - - -class TileGenerationRequest(TileManagerModel): - mission_id: str = Field(min_length=1) - frame_id: str = Field(min_length=1) - image_ref: str = Field(min_length=1) - timestamp_ns: int = Field(ge=0) - parent_covariance_m: float = Field(ge=0.0) - frame_usable: bool - quality_score: float = Field(ge=0.0, le=1.0) - footprint: dict[str, float] - source_provenance: str = Field(min_length=1) - - -class GeneratedTileSidecar(TileManagerModel): - tile_id: str = Field(min_length=1) - parent_frame_id: str = Field(min_length=1) - parent_covariance_m: float = Field(ge=0.0) - quality_score: float = Field(ge=0.0, le=1.0) - trust_level: Literal["generated", "candidate"] - provenance: str = Field(min_length=1) - - -class GeneratedTileCandidate(TileManagerModel): - accepted: bool - tile_id: str | None = None - cog_ref: str | None = None - sidecar: GeneratedTileSidecar | None = None - rejection_reason: str | None = None - - -class GeneratedTileSyncPackage(TileManagerModel): - package_ref: str = Field(min_length=1) - mission_id: str = Field(min_length=1) - manifest_delta: tuple[dict[str, object], ...] - sidecars: tuple[GeneratedTileSidecar, ...] - - -def freshness_status(expires_at: datetime, now: datetime) -> Literal["fresh", "stale"]: - normalized_expiry = expires_at - if normalized_expiry.tzinfo is None: - normalized_expiry = normalized_expiry.replace(tzinfo=timezone.utc) - normalized_now = now if now.tzinfo is not None else now.replace(tzinfo=timezone.utc) - return "fresh" if normalized_expiry >= normalized_now else "stale" diff --git a/src/vio_adapter/__init__.py b/src/vio_adapter/__init__.py deleted file mode 100644 index 4e03ed0..0000000 --- a/src/vio_adapter/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -"""Replaceable VIO adapter component.""" - -from .interfaces import ( - ConfiguredNativeVioBackend, - LocalVioAdapter, - NativeVioBackend, - NativeVioRunner, - NativeVioRunnerFactory, - ReplayVioBackend, - VioAdapter, - VioBackend, - VioBackendError, - create_vio_adapter, -) -from .types import ( - VioBackendEstimate, - VioHealthReport, - VioInputPacket, - VioProcessingResult, - VioRuntimeConfig, -) - -__all__ = [ - "ConfiguredNativeVioBackend", - "LocalVioAdapter", - "NativeVioBackend", - "NativeVioRunner", - "NativeVioRunnerFactory", - "ReplayVioBackend", - "VioAdapter", - "VioBackend", - "VioBackendError", - "VioBackendEstimate", - "VioHealthReport", - "VioInputPacket", - "VioProcessingResult", - "VioRuntimeConfig", - "create_vio_adapter", -] diff --git a/src/vio_adapter/interfaces.py b/src/vio_adapter/interfaces.py deleted file mode 100644 index 55cd665..0000000 --- a/src/vio_adapter/interfaces.py +++ /dev/null @@ -1,328 +0,0 @@ -"""Public VIO adapter interfaces.""" - -from collections.abc import Callable -from time import perf_counter -from typing import Any, Protocol, runtime_checkable - -from shared.contracts import VioStatePacket -from shared.errors import ErrorEnvelope -from shared.time_sync import select_time_window - -from .types import ( - VioBackendEstimate, - VioHealthReport, - VioInputPacket, - VioProcessingResult, - VioRuntimeConfig, -) - - -class VioAdapter(Protocol): - """Processes frame and telemetry inputs into relative VIO state.""" - - def initialize(self) -> None: - """Initialize adapter resources.""" - - def process(self, packet: VioInputPacket) -> VioProcessingResult: - """Process one synchronized frame/telemetry pair.""" - - def health(self) -> VioHealthReport: - """Return current readiness and degradation state.""" - - -class VioBackend(Protocol): - """Backend-neutral VIO execution boundary.""" - - def initialize(self) -> None: - """Initialize native backend resources.""" - - def estimate(self, frame: Any, telemetry_window: tuple[Any, ...]) -> VioBackendEstimate: - """Return one relative VIO estimate.""" - - -@runtime_checkable -class NativeVioRunner(Protocol): - """Runtime object supplied by the selected VIO engine package.""" - - def initialize(self) -> None: - """Prepare engine resources.""" - - def estimate( - self, frame: Any, telemetry_window: tuple[Any, ...] - ) -> VioBackendEstimate | dict[str, Any]: - """Return an estimate payload for one synchronized replay frame.""" - - -class VioBackendError(RuntimeError): - """Raised when the configured VIO engine cannot produce an estimate.""" - - -NativeVioRunnerFactory = Callable[[], NativeVioRunner] - - -class NativeVioBackend: - """Configurable backend adapter for native VIO engine packages.""" - - def __init__(self, runner: NativeVioRunner, backend_name: str = "native_vio") -> None: - self._runner = runner - self.backend_name = backend_name - - def initialize(self) -> None: - try: - self._runner.initialize() - except Exception as exc: - raise VioBackendError(f"{self.backend_name} initialization failed: {exc}") from exc - - def estimate(self, frame: Any, telemetry_window: tuple[Any, ...]) -> VioBackendEstimate: - started = perf_counter() - try: - estimate = self._runner.estimate(frame, telemetry_window) - except Exception as exc: - raise VioBackendError(f"{self.backend_name} estimate failed: {exc}") from exc - - try: - if isinstance(estimate, VioBackendEstimate): - if estimate.processing_latency_ms is not None: - return estimate - payload = estimate.model_dump() - else: - payload = dict(estimate) - payload.setdefault("timestamp_ns", frame.timestamp_ns) - payload["processing_latency_ms"] = ( - payload.get("processing_latency_ms") or (perf_counter() - started) * 1000.0 - ) - return VioBackendEstimate.model_validate(payload) - except Exception as exc: - raise VioBackendError(f"{self.backend_name} returned invalid estimate") from exc - - -class ConfiguredNativeVioBackend: - """Lazily creates the configured native runner during adapter initialization.""" - - def __init__( - self, - runner_factory: NativeVioRunnerFactory, - backend_name: str = "basalt", - ) -> None: - self._runner_factory = runner_factory - self._backend: NativeVioBackend | None = None - self.backend_name = backend_name - - def initialize(self) -> None: - try: - runner = self._runner_factory() - except Exception as exc: - raise VioBackendError(f"{self.backend_name} runner creation failed") from exc - - if not isinstance(runner, NativeVioRunner): - raise VioBackendError(f"{self.backend_name} runner does not implement NativeVioRunner") - - self._backend = NativeVioBackend(runner, backend_name=self.backend_name) - self._backend.initialize() - - def estimate(self, frame: Any, telemetry_window: tuple[Any, ...]) -> VioBackendEstimate: - if self._backend is None: - raise VioBackendError(f"{self.backend_name} runner is not initialized") - return self._backend.estimate(frame, telemetry_window) - - -class ReplayVioBackend: - """Small local backend for replay smoke tests when no engine is configured.""" - - backend_name = "replay_vio" - - def initialize(self) -> None: - return None - - def estimate(self, frame: Any, telemetry_window: tuple[Any, ...]) -> VioBackendEstimate: - quality = float(getattr(frame, "quality", 1.0)) - tracking_quality = max(0.0, min(1.0, quality)) - return VioBackendEstimate( - timestamp_ns=frame.timestamp_ns, - relative_pose={ - "x_m": tracking_quality, - "y_m": 0.0, - "z_m": 0.0, - "yaw_rad": 0.0, - }, - velocity_mps=(tracking_quality, 0.0, 0.0), - tracking_quality=tracking_quality, - bias_estimate={"sample_count": float(len(telemetry_window))}, - covariance_hint=[ - [1.0 / max(tracking_quality, 0.1), 0.0, 0.0], - [0.0, 1.0 / max(tracking_quality, 0.1), 0.0], - [0.0, 0.0, 1.0 / max(tracking_quality, 0.1)], - ], - ) - - -class LocalVioAdapter: - """Backend-neutral adapter that exposes explicit health and mismatch behavior.""" - - def __init__( - self, - backend: VioBackend | None = None, - runtime_config: VioRuntimeConfig | None = None, - timestamp_tolerance_ns: int = 5_000_000, - degraded_quality_threshold: float = 0.35, - ) -> None: - self._runtime_config = runtime_config or VioRuntimeConfig(mode="replay") - self._backend = backend or _backend_from_runtime_config(self._runtime_config, None) - self._backend_name = getattr( - self._backend, "backend_name", self._backend.__class__.__name__ - ) - self._timestamp_tolerance_ns = timestamp_tolerance_ns - self._degraded_quality_threshold = degraded_quality_threshold - self._initialized = False - self._health = VioHealthReport( - initialized=False, - state="not_initialized", - tracking_quality=0.0, - backend_name=self._backend_name, - ) - - def initialize(self) -> None: - try: - self._backend.initialize() - except Exception as exc: - self._initialized = False - self._health = VioHealthReport( - initialized=False, - state="failed", - tracking_quality=0.0, - backend_name=self._backend_name, - error=self._backend_error(str(exc), "backend_initialization_failed", "error"), - ) - return None - self._initialized = True - self._health = VioHealthReport( - initialized=True, - state="ready", - tracking_quality=1.0, - backend_name=self._backend_name, - ) - - def process(self, packet: VioInputPacket) -> VioProcessingResult: - if not self._initialized: - self.initialize() - if self._health.state == "failed": - return VioProcessingResult(health=self._health, error=self._health.error) - - telemetry_timestamps = [sample.timestamp_ns for sample in packet.telemetry_samples] - time_window = select_time_window( - packet.frame.timestamp_ns, - telemetry_timestamps, - self._timestamp_tolerance_ns, - ) - if not time_window.ok: - error = ErrorEnvelope( - component="vio_adapter", - category="validation", - message="frame and telemetry timestamps are outside the VIO sync window", - severity="warning", - retryable=False, - cause=time_window.violations[0].category, - ) - self._health = VioHealthReport( - initialized=True, - state="degraded", - tracking_quality=0.0, - backend_name=self._backend_name, - error=error, - ) - return VioProcessingResult(health=self._health, error=error) - - telemetry_window = tuple( - sample - for sample in packet.telemetry_samples - if sample.timestamp_ns in set(time_window.sample_timestamps_ns) - ) - try: - estimate = self._backend.estimate(packet.frame, telemetry_window) - except Exception as exc: - error = self._backend_error(str(exc), "backend_runtime_failed", "error") - self._health = VioHealthReport( - initialized=True, - state="failed", - tracking_quality=0.0, - backend_name=self._backend_name, - error=error, - ) - return VioProcessingResult(health=self._health, error=error) - state_packet = VioStatePacket( - timestamp_ns=estimate.timestamp_ns, - relative_pose=estimate.relative_pose, - velocity_mps=estimate.velocity_mps, - bias_estimate=estimate.bias_estimate, - tracking_quality=estimate.tracking_quality, - covariance_hint=estimate.covariance_hint, - ) - health_state = ( - "degraded" if estimate.tracking_quality < self._degraded_quality_threshold else "ready" - ) - self._health = VioHealthReport( - initialized=True, - state=health_state, - tracking_quality=estimate.tracking_quality, - backend_name=self._backend_name, - ) - return VioProcessingResult( - state_packet=state_packet, - health=self._health, - processing_latency_ms=estimate.processing_latency_ms, - ) - - def health(self) -> VioHealthReport: - return self._health - - def _backend_error(self, message: str, cause: str, severity: str) -> ErrorEnvelope: - return ErrorEnvelope( - component="vio_adapter", - category="runtime", - message=message, - severity=severity, - retryable=False, - cause=cause, - ) - - -def create_vio_adapter( - runtime_config: VioRuntimeConfig, - native_runner_factory: NativeVioRunnerFactory | None = None, - timestamp_tolerance_ns: int = 5_000_000, - degraded_quality_threshold: float = 0.35, -) -> LocalVioAdapter: - backend = _backend_from_runtime_config(runtime_config, native_runner_factory) - return LocalVioAdapter( - backend=backend, - runtime_config=runtime_config, - timestamp_tolerance_ns=timestamp_tolerance_ns, - degraded_quality_threshold=degraded_quality_threshold, - ) - - -def _backend_from_runtime_config( - runtime_config: VioRuntimeConfig, - native_runner_factory: NativeVioRunnerFactory | None, -) -> VioBackend: - if runtime_config.effective_mode == "replay": - return ReplayVioBackend() - if native_runner_factory is None: - native_runner_factory = _default_native_runner_factory(runtime_config) - return ConfiguredNativeVioBackend( - native_runner_factory, - backend_name=runtime_config.native_backend_name, - ) - - -def _default_native_runner_factory(runtime_config: VioRuntimeConfig) -> NativeVioRunnerFactory: - def create_runner() -> NativeVioRunner: - from vio_adapter.native.basalt import BasaltNativeRunner - - return BasaltNativeRunner( - module_name=runtime_config.native_runner_module, - factory_name=runtime_config.native_runner_factory, - config=runtime_config.native_runner_config, - ) - - return create_runner diff --git a/src/vio_adapter/native/README.md b/src/vio_adapter/native/README.md deleted file mode 100644 index c3da0c0..0000000 --- a/src/vio_adapter/native/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# VIO Native Backend Package - -Exports the configured VIO backend package boundary owned by `vio_adapter`. diff --git a/src/vio_adapter/native/__init__.py b/src/vio_adapter/native/__init__.py deleted file mode 100644 index 18bc2e7..0000000 --- a/src/vio_adapter/native/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Native VIO backend package exports.""" - -from vio_adapter.interfaces import NativeVioBackend, NativeVioRunner, VioBackendError -from vio_adapter.native.basalt import BasaltNativeRunner - -__all__ = ["BasaltNativeRunner", "NativeVioBackend", "NativeVioRunner", "VioBackendError"] diff --git a/src/vio_adapter/native/basalt.py b/src/vio_adapter/native/basalt.py deleted file mode 100644 index 10f4e55..0000000 --- a/src/vio_adapter/native/basalt.py +++ /dev/null @@ -1,47 +0,0 @@ -"""Loader for installed BASALT-compatible VIO runtime packages.""" - -from collections.abc import Mapping -from importlib import import_module -from typing import Any - -from vio_adapter.interfaces import NativeVioRunner, VioBackendError -from vio_adapter.types import VioBackendEstimate - - -class BasaltNativeRunner: - """Adapts an installed BASALT binding to the VIO runner protocol.""" - - def __init__( - self, - module_name: str = "basalt_vio", - factory_name: str = "create_runner", - config: Mapping[str, object] | None = None, - ) -> None: - self._module_name = module_name - self._factory_name = factory_name - self._config = dict(config or {}) - self._runner: NativeVioRunner | None = None - - def initialize(self) -> None: - try: - module = import_module(self._module_name) - factory = getattr(module, self._factory_name) - runner = factory(**self._config) - except Exception as exc: - raise VioBackendError( - f"unable to load BASALT runtime {self._module_name}:{self._factory_name}" - ) from exc - - if not isinstance(runner, NativeVioRunner): - raise VioBackendError( - f"BASALT runtime {self._module_name}:{self._factory_name} " - "does not implement NativeVioRunner" - ) - - self._runner = runner - self._runner.initialize() - - def estimate(self, frame: Any, telemetry_window: tuple[Any, ...]) -> VioBackendEstimate: - if self._runner is None: - raise VioBackendError("BASALT runtime is not initialized") - return self._runner.estimate(frame, telemetry_window) diff --git a/src/vio_adapter/types.py b/src/vio_adapter/types.py deleted file mode 100644 index 9780485..0000000 --- a/src/vio_adapter/types.py +++ /dev/null @@ -1,69 +0,0 @@ -"""Public VIO adapter models.""" - -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field, NonNegativeInt, model_validator - -from shared.contracts import FramePacket, TelemetrySample, VioStatePacket -from shared.errors import ErrorEnvelope - - -class VioAdapterModel(BaseModel): - model_config = ConfigDict(extra="forbid", frozen=True) - - -class VioInputPacket(VioAdapterModel): - frame: FramePacket - telemetry_samples: tuple[TelemetrySample, ...] = Field(min_length=1) - - -VioRuntimeEnvironment = Literal["development", "ci", "staging", "jetson", "production"] -VioRuntimeMode = Literal["replay", "native"] - - -class VioRuntimeConfig(VioAdapterModel): - environment: VioRuntimeEnvironment = "development" - mode: VioRuntimeMode | None = None - native_backend_name: str = Field(default="basalt", min_length=1) - native_runner_module: str = Field(default="basalt_vio", min_length=1) - native_runner_factory: str = Field(default="create_runner", min_length=1) - native_runner_config: dict[str, object] = Field(default_factory=dict) - - @model_validator(mode="after") - def production_requires_native_mode(self) -> "VioRuntimeConfig": - if self.environment in {"jetson", "production"} and self.effective_mode != "native": - raise ValueError("jetson and production VIO profiles require native runtime mode") - return self - - @property - def effective_mode(self) -> VioRuntimeMode: - if self.mode is not None: - return self.mode - if self.environment in {"jetson", "production"}: - return "native" - return "replay" - - -class VioHealthReport(VioAdapterModel): - initialized: bool - state: Literal["not_initialized", "ready", "degraded", "failed"] - tracking_quality: float = Field(ge=0.0, le=1.0) - backend_name: str | None = None - error: ErrorEnvelope | None = None - - -class VioProcessingResult(VioAdapterModel): - state_packet: VioStatePacket | None = None - health: VioHealthReport - processing_latency_ms: float | None = Field(default=None, ge=0.0) - error: ErrorEnvelope | None = None - - -class VioBackendEstimate(VioAdapterModel): - timestamp_ns: NonNegativeInt - relative_pose: dict[str, float] - velocity_mps: tuple[float, float, float] - tracking_quality: float = Field(ge=0.0, le=1.0) - bias_estimate: dict[str, float] | None = None - covariance_hint: list[list[float]] | None = None - processing_latency_ms: float | None = Field(default=None, ge=0.0) diff --git a/tests/blackbox/cache_freshness/.gitkeep b/tests/blackbox/cache_freshness/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/blackbox/cache_freshness/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/blackbox/resource_limits/.gitkeep b/tests/blackbox/resource_limits/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/blackbox/resource_limits/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/blackbox/run_blackbox.py b/tests/blackbox/run_blackbox.py deleted file mode 100644 index 97766f5..0000000 --- a/tests/blackbox/run_blackbox.py +++ /dev/null @@ -1,13 +0,0 @@ -"""Black-box runner entry point.""" - -from collections.abc import Sequence - -from e2e.replay.harness import main as replay_main - - -def main(argv: Sequence[str] | None = None) -> int: - return replay_main(argv) - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tests/blackbox/satellite_anchor/.gitkeep b/tests/blackbox/satellite_anchor/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/blackbox/satellite_anchor/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/blackbox/still_image_geolocation/.gitkeep b/tests/blackbox/still_image_geolocation/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/blackbox/still_image_geolocation/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/blackbox/test_blackout_spoofing.py b/tests/blackbox/test_blackout_spoofing.py deleted file mode 100644 index 528a043..0000000 --- a/tests/blackbox/test_blackout_spoofing.py +++ /dev/null @@ -1,117 +0,0 @@ -from e2e.replay.harness import mavlink_source_is_authorized -from mavlink_gcs_integration import InMemoryMavlinkGateway, OperatorStatusMessage -from safety_anchor_wrapper import SafetyAnchorStateMachine, SafetyStateConfig, TelemetryContext -from shared.contracts import VioStatePacket - - -def test_blackout_trace_transitions_to_dead_reckoned_then_no_fix() -> None: - # Arrange - state_machine = SafetyAnchorStateMachine( - SafetyStateConfig( - initial_covariance_m=2.0, - dead_reckoning_growth_m=125.0, - no_fix_covariance_threshold_m=500.0, - ) - ) - state_machine.update_vio( - VioStatePacket( - timestamp_ns=1_000_000_000, - relative_pose={"x_m": 0.0}, - velocity_mps=(0.0, 0.0, 0.0), - tracking_quality=0.9, - covariance_hint=[[2.0, 0.0], [0.0, 2.0]], - ), - TelemetryContext( - timestamp_ns=1_000_000_000, - latitude_hint_deg=48.0, - longitude_hint_deg=37.0, - altitude_m=400.0, - ), - ) - - # Act - snapshots = tuple( - state_machine.propagate_blackout(1_000_000_000 + index * 1_000_000_000) - for index in range(1, 6) - ) - - # Assert - assert snapshots[0].mode == "dead_reckoned" - assert snapshots[-1].mode == "no_fix" - covariances = tuple(snapshot.estimate.covariance_semimajor_m for snapshot in snapshots) - assert covariances == tuple(sorted(covariances)) - assert snapshots[-1].estimate.fix_type == 0 - assert snapshots[-1].estimate.horizontal_accuracy_m >= 999.0 - - -def test_no_fix_estimate_is_not_emitted_as_confident_gps_input() -> None: - # Arrange - state_machine = SafetyAnchorStateMachine( - SafetyStateConfig(dead_reckoning_growth_m=600.0, no_fix_covariance_threshold_m=500.0) - ) - gateway = InMemoryMavlinkGateway(status_rate_limit_ns=1_000_000_000) - state_machine.update_vio( - VioStatePacket( - timestamp_ns=1, - relative_pose={"x_m": 0.0}, - velocity_mps=(0.0, 0.0, 0.0), - tracking_quality=0.5, - ), - TelemetryContext( - timestamp_ns=1, - latitude_hint_deg=48.0, - longitude_hint_deg=37.0, - altitude_m=400.0, - ), - ) - no_fix_snapshot = state_machine.propagate_blackout(2) - - # Act - emission = gateway.emit_gps_input(no_fix_snapshot.estimate) - - # Assert - assert emission.emitted is False - assert emission.error is not None - assert "unsafe for GPS_INPUT" in emission.error.message - - -def test_unauthorized_mavlink_sources_are_rejected_by_test_assertion() -> None: - # Arrange - allowed_source_system_ids = {1, 42} - - # Act / Assert - assert mavlink_source_is_authorized(42, allowed_source_system_ids) is True - assert mavlink_source_is_authorized(99, allowed_source_system_ids) is False - - -def test_qgc_status_and_fdr_evidence_are_visible_and_rate_limited() -> None: - # Arrange - gateway = InMemoryMavlinkGateway(status_rate_limit_ns=2_000_000_000) - messages = [ - OperatorStatusMessage( - timestamp_ns=1_000_000_000, - severity="warning", - text="VISUAL_BLACKOUT_IMU_ONLY", - ), - OperatorStatusMessage( - timestamp_ns=2_000_000_000, - severity="warning", - text="VISUAL_BLACKOUT_IMU_ONLY", - ), - OperatorStatusMessage( - timestamp_ns=4_000_000_000, - severity="critical", - text="VISUAL_BLACKOUT_FAILSAFE", - ), - ] - - # Act - result = gateway.emit_status(messages) - - # Assert - assert [message.text for message in result.emitted] == [ - "VISUAL_BLACKOUT_IMU_ONLY", - "VISUAL_BLACKOUT_FAILSAFE", - ] - assert len(result.suppressed) == 1 - assert all(message.visible_to_qgc for message in result.emitted) diff --git a/tests/blackbox/test_cold_start_restart.py b/tests/blackbox/test_cold_start_restart.py deleted file mode 100644 index 31bc6a1..0000000 --- a/tests/blackbox/test_cold_start_restart.py +++ /dev/null @@ -1,71 +0,0 @@ -from pathlib import Path - -from e2e.replay.harness import ( - BlackboxReplayRunner, - ScenarioConfig, - ScenarioGroup, - ScenarioResult, - relocalization_required, - summarize_cold_start_trials, -) - - -def test_disconnected_segment_triggers_relocalization_request_check() -> None: - # Act / Assert - assert relocalization_required(visual_overlap_fraction=0.03, disconnected_duration_s=0.5) is True - assert relocalization_required(visual_overlap_fraction=0.5, disconnected_duration_s=4.0) is True - assert relocalization_required(visual_overlap_fraction=0.5, disconnected_duration_s=1.0) is False - - -def test_restart_scenario_records_first_output_or_blocked_prerequisite(tmp_path: Path) -> None: - # Arrange - scenario = ScenarioConfig( - scenario_id="NFT-RES-03", - name="Companion restart recovery", - group=ScenarioGroup.RESILIENCE, - input_dataset="restart_trace", - required_paths=(tmp_path / "restart-trace.tlog",), - ) - - # Act - result = BlackboxReplayRunner(output_root=tmp_path, scenarios=(scenario,)).run() - - # Assert - report = result.reports[0] - assert report.result == ScenarioResult.BLOCKED - assert "restart-trace.tlog" in report.error_message - assert report.artifacts[0].exists() - - -def test_cold_start_trials_report_p95_first_fix_and_resource_spike() -> None: - # Arrange - first_fix_latencies_s = tuple(20.0 + (index % 5) for index in range(50)) - peak_memory_bytes = tuple(2_500_000_000 + index * 1_000_000 for index in range(50)) - - # Act - summary = summarize_cold_start_trials(first_fix_latencies_s, peak_memory_bytes) - - # Assert - assert summary["trial_count"] == 50.0 - assert summary["p95_first_fix_s"] < 30.0 - assert summary["first_fix_passed"] is True - assert summary["memory_passed"] is True - - -def test_cold_start_hardware_prerequisites_are_blocked_not_passed(tmp_path: Path) -> None: - # Arrange - scenario = ScenarioConfig( - scenario_id="NFT-RES-LIM-05", - name="Cold-start resource spike", - group=ScenarioGroup.RESOURCE_LIMIT, - input_dataset="jetson_resource_monitor", - required_services=("jetson",), - ) - - # Act - result = BlackboxReplayRunner(output_root=tmp_path, scenarios=(scenario,)).run() - - # Assert - report = result.reports[0] - assert report.result == ScenarioResult.BLOCKED - assert "Jetson prerequisite blocked" in report.error_message diff --git a/tests/blackbox/test_infrastructure.py b/tests/blackbox/test_infrastructure.py deleted file mode 100644 index 2d1167d..0000000 --- a/tests/blackbox/test_infrastructure.py +++ /dev/null @@ -1,96 +0,0 @@ -import csv -from pathlib import Path - -from e2e.replay.harness import ( - REPORT_COLUMNS, - BlackboxReplayRunner, - SatelliteCacheStub, - ScenarioConfig, - ScenarioGroup, - ScenarioResult, -) - - -def test_replay_environment_reports_missing_prerequisites_as_blocked(tmp_path: Path) -> None: - # Arrange - scenario = ScenarioConfig( - scenario_id="BLOCKED-INFRA", - name="Blocked prerequisite smoke", - group=ScenarioGroup.RESILIENCE, - input_dataset="sitl_spoofing_scenarios", - required_paths=(tmp_path / "missing-fixture.csv",), - required_services=("sitl",), - ) - - # Act - result = BlackboxReplayRunner(output_root=tmp_path, scenarios=(scenario,)).run() - - # Assert - report = result.reports[0] - assert report.result == ScenarioResult.BLOCKED - assert "missing fixture path" in report.error_message - assert "SITL prerequisite blocked" in report.error_message - - -def test_satellite_cache_stub_is_deterministic_and_records_interactions() -> None: - # Arrange - stub = SatelliteCacheStub() - - # Act - first = stub.query_manifest("FT-P-01", "valid") - second = stub.query_manifest("FT-P-01", "valid") - - # Assert - assert first == second - assert first["network_fetch_attempted"] is False - assert len(stub.interactions) == 2 - assert stub.interactions[0].service == "satellite-cache-stub" - - -def test_runner_executes_all_required_groups_and_writes_reports(tmp_path: Path) -> None: - # Act - result = BlackboxReplayRunner(output_root=tmp_path).run() - - # Assert - assert result.completed_groups == set(ScenarioGroup) - rows = list(csv.DictReader(result.csv_path.open(encoding="utf-8"))) - assert rows - assert rows[0].keys() == set(REPORT_COLUMNS) - assert {row["Result"] for row in rows} <= {"pass", "blocked"} - security_row = next(row for row in rows if row["Test ID"] == "NFT-SEC-INFRA") - assert security_row["Result"] == "pass" - assert security_row["Source Label"] == "untrusted_cache_rejected" - - markdown = result.markdown_path.read_text(encoding="utf-8") - assert "FDR Validation Summary" in markdown - assert "SITL prerequisite blocked" in markdown - assert "Jetson prerequisite blocked" in markdown - - -def test_runner_uses_configurable_input_root_for_replay_fixtures(tmp_path: Path) -> None: - # Arrange - input_root = tmp_path / "input" - (input_root / "expected_results").mkdir(parents=True) - (input_root / "coordinates.csv").write_text("image,lat,lon\nAD000001.jpg,48.0,37.0\n") - (input_root / "expected_results" / "results_report.md").write_text("# Expected results\n") - - # Act - result = BlackboxReplayRunner(output_root=tmp_path / "output", input_root=input_root).run() - - # Assert - reports_by_id = {report.scenario_id: report for report in result.reports} - assert reports_by_id["FT-P-01"].result == ScenarioResult.PASS - assert reports_by_id["NFT-PERF-INFRA"].result == ScenarioResult.PASS - - -def test_runner_keeps_generated_artifacts_run_scoped(tmp_path: Path) -> None: - # Act - result = BlackboxReplayRunner(output_root=tmp_path).run() - - # Assert - assert result.run_dir.parent == tmp_path - assert result.csv_path.parent == result.run_dir - assert result.markdown_path.parent == result.run_dir - for report in result.reports: - assert report.artifacts - assert all(artifact.parent.parent == result.run_dir for artifact in report.artifacts) diff --git a/tests/blackbox/test_resource_endurance.py b/tests/blackbox/test_resource_endurance.py deleted file mode 100644 index dc9b6ab..0000000 --- a/tests/blackbox/test_resource_endurance.py +++ /dev/null @@ -1,86 +0,0 @@ -from pathlib import Path - -from e2e.replay.harness import BlackboxReplayRunner, ResourceSample, summarize_resource_samples -from fdr_observability import FdrExportRequest, FdrPayload, InMemoryFlightRecorder -from shared.contracts import FdrEvent - - -def test_jetson_resource_metric_summary_captures_memory_and_throttle_fields() -> None: - # Arrange - samples = ( - ResourceSample( - timestamp_s=0.0, - process_rss_bytes=1_000_000_000, - shared_memory_used_bytes=2_000_000_000, - cuda_allocated_bytes=500_000_000, - throttle_active=False, - temperature_c=55.0, - ), - ResourceSample( - timestamp_s=60.0, - process_rss_bytes=1_200_000_000, - shared_memory_used_bytes=2_300_000_000, - cuda_allocated_bytes=650_000_000, - throttle_active=False, - temperature_c=62.0, - ), - ) - - # Act - summary = summarize_resource_samples(samples) - - # Assert - assert summary["duration_s"] == 60.0 - assert summary["peak_shared_memory_used_bytes"] == 2_300_000_000.0 - assert summary["peak_cuda_allocated_bytes"] == 650_000_000.0 - assert summary["throttle_observed"] is False - assert summary["max_temperature_c"] == 62.0 - - -def test_missing_thermal_hardware_reports_blocked_prerequisite(tmp_path: Path) -> None: - # Act - result = BlackboxReplayRunner(output_root=tmp_path).run() - - # Assert - resource_report = next(report for report in result.reports if report.group.value == "resource-limit") - assert resource_report.result.value == "blocked" - assert "Jetson prerequisite blocked" in resource_report.error_message - - -def test_fdr_rollover_logs_segments_without_raw_frame_retention() -> None: - # Arrange - recorder = InMemoryFlightRecorder(segment_limit_bytes=100, storage_limit_bytes=500) - - # Act - first = recorder.append_event( - _event("estimate", 1, "fdr://payload/gps-input-1"), - FdrPayload(ref="fdr://payload/gps-input-1", size_bytes=60, redacted=True), - ) - second = recorder.append_event( - _event("health", 2, "fdr://payload/health-1"), - FdrPayload(ref="fdr://payload/health-1", size_bytes=60, redacted=True), - ) - export = recorder.export( - FdrExportRequest(mission_id="mission-001", run_id="run-001", include_analytics=True) - ) - - # Assert - assert first.appended is True - assert second.rollover is True - assert recorder.health.status == "ready" - assert export.produced is True - assert len(export.segments) == 2 - assert all("raw-frame" not in segment.segment_id for segment in export.segments) - assert export.analytics_ref is not None - - -def _event(event_type: str, timestamp_ns: int, payload_ref: str) -> FdrEvent: - return FdrEvent( - event_type=event_type, - timestamp_ns=timestamp_ns, - component="blackbox_resource_test", - severity="info", - payload_ref=payload_ref, - mission_id="mission-001", - run_id="run-001", - ) diff --git a/tests/blackbox/test_satellite_anchor.py b/tests/blackbox/test_satellite_anchor.py deleted file mode 100644 index 27e82a2..0000000 --- a/tests/blackbox/test_satellite_anchor.py +++ /dev/null @@ -1,123 +0,0 @@ -from anchor_verification import AnchorFrame, CandidateTile, GeometryGatedAnchorVerifier -from e2e.replay.harness import SatelliteCacheStub -from satellite_service import ( - LocalVprIndexPackage, - LocalVprRetriever, - RelocalizationRequest, - SatelliteSyncBoundary, - VprDescriptorRecord, -) -from shared.contracts import VprCandidate -from tile_manager import GeneratedTileSyncPackage - - -def test_verified_anchor_includes_retrieval_matching_and_provenance_evidence() -> None: - # Arrange - retriever = LocalVprRetriever() - retriever.load_index( - LocalVprIndexPackage( - package_id="fixture-index", - records=( - VprDescriptorRecord( - chunk_id="chunk-001", - tile_id="tile-001", - descriptor=(1.0, 0.0, 0.0), - footprint={"min_lat": 48.0, "max_lat": 48.1, "min_lon": 37.0, "max_lon": 37.1}, - freshness_status="fresh", - ), - ), - ) - ) - retrieval = retriever.retrieve( - RelocalizationRequest( - frame_id="frame-001", - image_ref="AD000001.jpg", - trigger_reason="cold_start", - top_k=1, - query_descriptor=(1.0, 0.0, 0.0), - ) - ) - keypoints = tuple((float(index), float(index % 5)) for index in range(24)) - shifted_keypoints = tuple((x + 1.0, y + 1.0) for x, y in keypoints) - verifier = GeometryGatedAnchorVerifier() - - # Act - verification = verifier.verify_candidate( - AnchorFrame(frame_id="frame-001", image_ref="AD000001.jpg", keypoints=keypoints), - CandidateTile( - candidate=retrieval.candidates[0], - image_ref="tile-001.cog", - keypoints=shifted_keypoints, - provenance_trusted=True, - ), - ) - - # Assert - assert retrieval.ready is True - assert retrieval.latency_ms is not None - assert verification.decision.accepted is True - assert verification.decision.candidate_id == "chunk-001" - assert verification.decision.inliers >= 20 - assert verification.decision.mean_reprojection_error_px <= 3.0 - assert verification.homography is not None - assert verification.freshness_status == "fresh" - - -def test_unsafe_cache_or_low_texture_candidates_never_emit_trusted_anchor() -> None: - # Arrange - verifier = GeometryGatedAnchorVerifier() - frame = AnchorFrame( - frame_id="frame-low-texture", - image_ref="low-texture.jpg", - usable_for_anchor=False, - keypoints=((0.0, 0.0), (1.0, 1.0), (2.0, 2.0), (3.0, 3.0)), - ) - candidate = VprCandidate( - chunk_id="chunk-stale", - tile_id="tile-stale", - score=0.9, - footprint={"min_lat": 48.0, "max_lat": 48.1, "min_lon": 37.0, "max_lon": 37.1}, - freshness_status="stale", - ) - - # Act - verification = verifier.verify_candidate( - frame, - CandidateTile( - candidate=candidate, - image_ref="tile-stale.cog", - keypoints=((0.0, 0.0), (1.0, 1.0), (2.0, 2.0), (3.0, 3.0)), - provenance_trusted=False, - ), - ) - - # Assert - assert verification.decision.accepted is False - assert verification.decision.rejection_reason == "frame_not_usable" - - -def test_flight_mode_missing_cache_does_not_attempt_external_access() -> None: - # Arrange - cache_stub = SatelliteCacheStub() - sync_boundary = SatelliteSyncBoundary() - - # Act - cache_response = cache_stub.query_manifest("NFT-SEC-04", "missing") - sync_result = sync_boundary.upload_generated_tiles( - GeneratedTileSyncPackage( - package_ref="generated-empty", - mission_id="mission-001", - manifest_delta=(), - sidecars=(), - ), - phase="in_flight", - ) - - # Assert - assert cache_response["network_fetch_attempted"] is False - assert cache_response["trusted"] is False - assert int(str(cache_response["fixture_size_bytes"])) < int( - str(cache_response["storage_budget_bytes"]) - ) - assert sync_result.error is not None - assert sync_result.error.cause == "mid_flight_network_blocked" diff --git a/tests/blackbox/test_still_image_replay.py b/tests/blackbox/test_still_image_replay.py deleted file mode 100644 index 53161ad..0000000 --- a/tests/blackbox/test_still_image_replay.py +++ /dev/null @@ -1,68 +0,0 @@ -from pathlib import Path - -import pytest - -from e2e.replay.harness import ( - ReplayEstimate, - evaluate_still_image_estimates, - load_expected_coordinates, -) - - -def test_expected_coordinate_loader_rejects_invalid_wgs84_rows(tmp_path: Path) -> None: - # Arrange - coordinates_path = tmp_path / "coordinates.csv" - coordinates_path.write_text("image, lat, lon\nAD000001.jpg, 120.0, 37.0\n", encoding="utf-8") - - # Act / Assert - with pytest.raises(ValueError, match="outside WGS84 bounds"): - load_expected_coordinates(coordinates_path) - - -def test_still_image_replay_reports_coordinate_thresholds_and_latency() -> None: - # Arrange - expected = load_expected_coordinates(Path("_docs/00_problem/input_data/coordinates.csv")) - estimates = tuple( - ReplayEstimate( - image_ref=coordinate.image_ref, - latitude_deg=coordinate.latitude_deg + 0.00001, - longitude_deg=coordinate.longitude_deg + 0.00001, - covariance_95_semi_major_m=8.0, - source_label="satellite_anchored", - anchor_age_ms=150, - capture_to_output_latency_ms=40.0 + index, - ) - for index, coordinate in enumerate(expected) - ) - - # Act - metrics = evaluate_still_image_estimates(expected, estimates) - - # Assert - assert metrics["threshold_passed"] is True - assert metrics["within_50_m_rate"] >= 0.80 - assert metrics["within_20_m_rate"] >= 0.50 - assert metrics["p50_latency_ms"] > 0.0 - assert metrics["p95_latency_ms"] >= metrics["p50_latency_ms"] - assert metrics["p99_latency_ms"] >= metrics["p95_latency_ms"] - assert metrics["dropped_frame_rate"] == 0.0 - - -def test_confidence_contract_validation_fails_missing_source_label() -> None: - # Arrange - expected = load_expected_coordinates(Path("_docs/00_problem/input_data/coordinates.csv"))[:1] - estimates = ( - ReplayEstimate( - image_ref=expected[0].image_ref, - latitude_deg=expected[0].latitude_deg, - longitude_deg=expected[0].longitude_deg, - covariance_95_semi_major_m=8.0, - source_label="", - anchor_age_ms=0, - capture_to_output_latency_ms=10.0, - ), - ) - - # Act / Assert - with pytest.raises(ValueError, match="source label is missing"): - evaluate_still_image_estimates(expected, estimates) diff --git a/tests/blackbox/test_vio_replay.py b/tests/blackbox/test_vio_replay.py deleted file mode 100644 index 8ce5685..0000000 --- a/tests/blackbox/test_vio_replay.py +++ /dev/null @@ -1,88 +0,0 @@ -from pathlib import Path - -import pytest - -from e2e.replay.harness import ( - BlackboxReplayRunner, - ScenarioConfig, - ScenarioGroup, - ScenarioResult, - validate_derkachi_alignment, -) -from shared.contracts import FramePacket, TelemetrySample -from vio_adapter import VioInputPacket, VioRuntimeConfig, create_vio_adapter - - -def test_derkachi_alignment_validator_accepts_expected_fixture_shape() -> None: - # Act - metrics = validate_derkachi_alignment( - video_duration_s=490.07, - telemetry_duration_s=490.07, - telemetry_rows=4_900, - ) - - # Assert - assert metrics["alignment_valid"] is True - assert metrics["duration_delta_s"] == 0.0 - assert metrics["frames_per_telemetry"] == pytest.approx(3.0, abs=0.05) - - -def test_derkachi_alignment_validator_blocks_duration_drift() -> None: - # Act / Assert - with pytest.raises(ValueError, match="more than 250 ms"): - validate_derkachi_alignment( - video_duration_s=490.07, - telemetry_duration_s=489.50, - telemetry_rows=4_900, - ) - - -def test_public_vio_replay_boundary_emits_frame_by_frame_estimate() -> None: - # Arrange - adapter = create_vio_adapter(VioRuntimeConfig(environment="development", mode="replay")) - frame = FramePacket( - frame_id="derkachi-0001", - timestamp_ns=1_000_000_000, - image_ref="_docs/00_problem/input_data/flight_derkachi/flight_derkachi.mp4#0", - calibration_id="derkachi-calibration-gated", - occlusion="clear", - quality=0.9, - ) - telemetry = ( - TelemetrySample( - timestamp_ns=1_000_000_000, - imu={"accel_x": 0.0, "accel_y": 0.0, "accel_z": -9.8}, - attitude={"roll": 0.0, "pitch": 0.0, "yaw": 1.0}, - altitude_m=400.0, - airspeed_mps=22.0, - gps_health="healthy", - ), - ) - - # Act - result = adapter.process(VioInputPacket(frame=frame, telemetry_samples=telemetry)) - - # Assert - assert result.state_packet is not None - assert result.health.state == "ready" - assert result.state_packet.timestamp_ns == frame.timestamp_ns - assert result.state_packet.tracking_quality > 0.0 - - -def test_public_dataset_and_calibration_prerequisites_are_reported_blocked(tmp_path: Path) -> None: - # Arrange - scenario = ScenarioConfig( - scenario_id="FT-P-03-CALIBRATION", - name="Calibration-gated public VIO dataset", - group=ScenarioGroup.PERFORMANCE, - input_dataset="public_nadir_vio_candidates", - required_paths=(tmp_path / "camera_intrinsics.yaml",), - ) - - # Act - result = BlackboxReplayRunner(output_root=tmp_path, scenarios=(scenario,)).run() - - # Assert - report = result.reports[0] - assert report.result == ScenarioResult.BLOCKED - assert "camera_intrinsics.yaml" in report.error_message diff --git a/tests/blackbox/visual_blackout_spoofing/.gitkeep b/tests/blackbox/visual_blackout_spoofing/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/blackbox/visual_blackout_spoofing/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/e2e/release_evidence/.gitkeep b/tests/e2e/release_evidence/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/e2e/release_evidence/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/e2e/replay/.gitkeep b/tests/e2e/replay/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/e2e/replay/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/e2e/reports/.gitkeep b/tests/e2e/reports/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/e2e/reports/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/fixtures/expected_results/.gitkeep b/tests/fixtures/expected_results/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/fixtures/expected_results/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/fixtures/project_60_images/.gitkeep b/tests/fixtures/project_60_images/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/fixtures/project_60_images/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/fixtures/public_dataset_slices/.gitkeep b/tests/fixtures/public_dataset_slices/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/fixtures/public_dataset_slices/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/fixtures/satellite_cache/.gitkeep b/tests/fixtures/satellite_cache/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/fixtures/satellite_cache/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/fixtures/telemetry/.gitkeep b/tests/fixtures/telemetry/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/fixtures/telemetry/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/integration/cache_postgis/.gitkeep b/tests/integration/cache_postgis/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/integration/cache_postgis/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/integration/contracts/.gitkeep b/tests/integration/contracts/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/integration/contracts/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/integration/fdr/.gitkeep b/tests/integration/fdr/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/integration/fdr/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/integration/mavlink/.gitkeep b/tests/integration/mavlink/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/integration/mavlink/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/sitl/failsafe/.gitkeep b/tests/sitl/failsafe/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/sitl/failsafe/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/sitl/plane_gps_input/.gitkeep b/tests/sitl/plane_gps_input/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/sitl/plane_gps_input/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/sitl/spoofing_promotion/.gitkeep b/tests/sitl/spoofing_promotion/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/sitl/spoofing_promotion/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/unit/anchor_verification/.gitkeep b/tests/unit/anchor_verification/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/unit/anchor_verification/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/unit/camera_ingest_calibration/.gitkeep b/tests/unit/camera_ingest_calibration/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/unit/camera_ingest_calibration/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/unit/fdr_observability/.gitkeep b/tests/unit/fdr_observability/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/unit/fdr_observability/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/unit/mavlink_gcs_integration/.gitkeep b/tests/unit/mavlink_gcs_integration/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/unit/mavlink_gcs_integration/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/unit/safety_anchor_wrapper/.gitkeep b/tests/unit/safety_anchor_wrapper/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/unit/safety_anchor_wrapper/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/unit/satellite_service/.gitkeep b/tests/unit/satellite_service/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/unit/satellite_service/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/unit/shared/.gitkeep b/tests/unit/shared/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/unit/shared/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/unit/shared/test_config_errors_telemetry.py b/tests/unit/shared/test_config_errors_telemetry.py deleted file mode 100644 index 50a1036..0000000 --- a/tests/unit/shared/test_config_errors_telemetry.py +++ /dev/null @@ -1,65 +0,0 @@ -from shared.config import validate_runtime_profile -from shared.errors import ErrorEnvelope, ResultEnvelope -from shared.telemetry import HealthEvent, MetricsLabels - - -def test_missing_production_cache_dir_returns_readiness_failure() -> None: - # Arrange - payload = { - "environment": "production", - "config_dir": "/etc/gps-denied-onboard", - "fdr_dir": "/var/lib/gps-denied/fdr", - "database_url": "postgresql://localhost/gpsd", - "mavlink_url": "serial:/dev/ttyTHS1:921600", - "camera_source": "hardware", - "signing_key_ref": "secret-ref", - } - - # Act - result = validate_runtime_profile("runtime", payload) - - # Assert - assert result.ok is False - assert result.error is not None - assert result.error.component == "runtime" - assert result.error.category == "configuration" - assert result.error.severity == "critical" - assert result.error.retryable is False - - -def test_dependency_error_envelope_has_required_structured_fields() -> None: - # Act - result = ResultEnvelope.failure( - ErrorEnvelope( - component="tile_manager", - category="dependency", - message="postgis unavailable", - severity="error", - retryable=True, - cause="connection refused", - ) - ) - - # Assert - assert result.ok is False - assert result.error is not None - assert result.error.component == "tile_manager" - assert result.error.category == "dependency" - assert result.error.severity == "error" - assert result.error.retryable is True - - -def test_health_event_and_metrics_labels_are_fdr_safe_metadata() -> None: - # Act - health = HealthEvent( - component="runtime", - timestamp_ns=1, - liveness="alive", - readiness="ready", - dependency_state={"postgis": "ready"}, - ) - labels = MetricsLabels(component="runtime", action="startup", status="ok") - - # Assert - assert health.dependency_state["postgis"] == "ready" - assert labels.status == "ok" diff --git a/tests/unit/shared/test_geometry_time_sync.py b/tests/unit/shared/test_geometry_time_sync.py deleted file mode 100644 index 5241b11..0000000 --- a/tests/unit/shared/test_geometry_time_sync.py +++ /dev/null @@ -1,41 +0,0 @@ -from shared.geo_geometry import Wgs84Coordinate, distance_m, local_to_wgs84, wgs84_to_local -from shared.time_sync import check_monotonic_timestamps, select_time_window - - -def test_wgs84_local_round_trip_is_deterministic() -> None: - # Arrange - origin = Wgs84Coordinate(latitude_deg=49.9808, longitude_deg=36.2527, altitude_m=120.0) - point = Wgs84Coordinate(latitude_deg=49.9811, longitude_deg=36.2531, altitude_m=118.0) - - # Act - local = wgs84_to_local(origin, point) - round_trip = local_to_wgs84(origin, local) - - # Assert - assert round(round_trip.latitude_deg, 7) == round(point.latitude_deg, 7) - assert round(round_trip.longitude_deg, 7) == round(point.longitude_deg, 7) - assert round(round_trip.altitude_m, 7) == round(point.altitude_m, 7) - assert distance_m(origin, point) > 0.0 - - -def test_non_monotonic_timestamps_return_explicit_violation() -> None: - # Act - violations = check_monotonic_timestamps([100, 200, 150]) - - # Assert - assert len(violations) == 1 - assert violations[0].category == "timestamp_mismatch" - - -def test_time_window_reports_gap_instead_of_dropping_silently() -> None: - # Act - result = select_time_window( - frame_timestamp_ns=1_000, - sample_timestamps_ns=[100, 200, 300], - tolerance_ns=50, - ) - - # Assert - assert result.ok is False - assert result.sample_timestamps_ns == () - assert result.violations[0].category == "gap_exceeded" diff --git a/tests/unit/shared/test_runtime_contracts.py b/tests/unit/shared/test_runtime_contracts.py deleted file mode 100644 index 38b3725..0000000 --- a/tests/unit/shared/test_runtime_contracts.py +++ /dev/null @@ -1,157 +0,0 @@ -import pytest -from pydantic import ValidationError - -from shared.contracts import ( - AnchorDecision, - CacheTileRecord, - FdrEvent, - FramePacket, - PositionEstimate, - TelemetrySample, - VioStatePacket, - VprCandidate, -) - - -def test_runtime_dtos_accept_valid_minimal_values() -> None: - # Arrange - timestamp_ns = 1_000_000 - - # Act - contracts = [ - FramePacket( - frame_id="frame-1", - timestamp_ns=timestamp_ns, - image_ref="frames/frame-1", - calibration_id="calib-1", - occlusion="clear", - quality=0.95, - ), - TelemetrySample( - timestamp_ns=timestamp_ns, - imu={"accel_x": 0.1}, - attitude={"roll": 0.0}, - altitude_m=950.0, - airspeed_mps=16.0, - gps_health="lost", - ), - VioStatePacket( - timestamp_ns=timestamp_ns, - relative_pose={"x": 1.0}, - velocity_mps=(1.0, 0.0, 0.0), - tracking_quality=0.8, - ), - PositionEstimate( - timestamp_ns=timestamp_ns, - latitude_deg=49.9, - longitude_deg=36.2, - altitude_m=950.0, - covariance_semimajor_m=12.0, - source_label="satellite_anchored", - fix_type=3, - horizontal_accuracy_m=12.0, - anchor_age_ms=200, - ), - VprCandidate( - chunk_id="chunk-1", - tile_id="tile-1", - score=0.87, - footprint={"min_lat": 49.0}, - freshness_status="fresh", - ), - AnchorDecision( - candidate_id="candidate-1", - accepted=True, - estimated_pose={"x": 1.0}, - inliers=42, - mean_reprojection_error_px=0.8, - ), - CacheTileRecord( - tile_id="tile-1", - crs="EPSG:3857", - meters_per_pixel=0.3, - capture_date="2026-05-03", - signature_hash="sha256:abc", - trust_level="trusted", - freshness_status="fresh", - provenance="suite-satellite-service", - ), - FdrEvent( - event_type="health", - timestamp_ns=timestamp_ns, - component="shared.contracts", - severity="info", - payload_ref="fdr://segment/1", - mission_id="mission-1", - run_id="run-1", - ), - ] - - # Assert - assert len(contracts) == 8 - - -def test_missing_required_timestamp_is_rejected_with_structured_error() -> None: - # Act - with pytest.raises(ValidationError) as error: - FramePacket( - frame_id="frame-1", - image_ref="frames/frame-1", - calibration_id="calib-1", - occlusion="clear", - quality=0.95, - ) - - # Assert - assert error.value.errors()[0]["loc"] == ("timestamp_ns",) - assert error.value.errors()[0]["type"] == "missing" - - -def test_raw_frame_retention_is_rejected() -> None: - # Act - with pytest.raises(ValidationError) as error: - FramePacket( - frame_id="frame-1", - timestamp_ns=1, - image_ref="frames/frame-1", - calibration_id="calib-1", - occlusion="clear", - quality=0.95, - raw_frame_retained=True, - ) - - # Assert - assert "raw frame payloads must be referenced" in str(error.value) - - -def test_position_accuracy_cannot_under_report_covariance() -> None: - # Act - with pytest.raises(ValidationError) as error: - PositionEstimate( - timestamp_ns=1, - latitude_deg=49.9, - longitude_deg=36.2, - altitude_m=950.0, - covariance_semimajor_m=50.0, - source_label="satellite_anchored", - fix_type=3, - horizontal_accuracy_m=10.0, - anchor_age_ms=200, - ) - - # Assert - assert "must not under-report" in str(error.value) - - -def test_accepted_anchor_requires_estimated_pose() -> None: - # Act - with pytest.raises(ValidationError) as error: - AnchorDecision( - candidate_id="candidate-1", - accepted=True, - inliers=42, - mean_reprojection_error_px=0.8, - ) - - # Assert - assert "accepted anchor decisions require estimated_pose" in str(error.value) diff --git a/tests/unit/test_anchor_verification.py b/tests/unit/test_anchor_verification.py deleted file mode 100644 index 6ef672f..0000000 --- a/tests/unit/test_anchor_verification.py +++ /dev/null @@ -1,170 +0,0 @@ -from anchor_verification import AnchorFrame, CandidateTile, GeometryGatedAnchorVerifier, MatchEvidence -from shared.contracts import VprCandidate - - -def _candidate(freshness_status: str = "fresh") -> VprCandidate: - return VprCandidate( - chunk_id="chunk-1", - tile_id="tile-1", - score=0.91, - footprint={"min_lat": 49.0, "max_lat": 49.2, "min_lon": 36.0, "max_lon": 36.2}, - freshness_status=freshness_status, - ) - - -def _evidence(**overrides: object) -> MatchEvidence: - payload: dict[str, object] = { - "candidate": _candidate(), - "matcher_profile": "aliked_lightglue", - "inliers": 48, - "mean_reprojection_error_px": 1.4, - "homography": {"h00": 1.0, "h11": 1.0, "h22": 1.0}, - "runtime_ms": 72.5, - "provenance_trusted": True, - } - payload.update(overrides) - return MatchEvidence.model_validate(payload) - - -def _frame_with_keypoints() -> AnchorFrame: - keypoints = tuple((float(x * 10), float(y * 10)) for x in range(5) for y in range(5)) - return AnchorFrame( - frame_id="frame-1", - image_ref="replay/frame-1.jpg", - keypoints=keypoints, - ) - - -def _tile_with_keypoints(**overrides: object) -> CandidateTile: - keypoints = tuple( - (float(x * 10 + 2), float(y * 10 + 3)) for x in range(5) for y in range(5) - ) - payload: dict[str, object] = { - "candidate": _candidate(), - "image_ref": "cache/tile-1.tif", - "keypoints": keypoints, - "provenance_trusted": True, - } - payload.update(overrides) - return CandidateTile.model_validate(payload) - - -def test_candidate_verification_emits_acceptance_evidence() -> None: - # Arrange - verifier = GeometryGatedAnchorVerifier() - frame = AnchorFrame(frame_id="frame-1", image_ref="replay/frame-1.jpg") - - # Act - result = verifier.verify(frame, _evidence()) - - # Assert - assert result.decision.accepted is True - assert result.decision.inliers == 48 - assert result.decision.mean_reprojection_error_px == 1.4 - assert result.reason == "accepted_geometry" - assert result.homography == {"h00": 1.0, "h11": 1.0, "h22": 1.0} - - -def test_matching_path_computes_evidence_from_frame_and_tile_inputs() -> None: - # Arrange - verifier = GeometryGatedAnchorVerifier() - frame = _frame_with_keypoints() - tile = _tile_with_keypoints() - - # Act - result = verifier.verify_candidate(frame, tile, matcher_profile="sift_orb") - - # Assert - assert result.decision.accepted is True - assert result.decision.inliers == 25 - assert result.reason == "accepted_geometry" - assert result.matcher_profile == "sift_orb" - assert result.homography is not None - assert result.homography["h02"] == 2.0 - assert result.homography["h12"] == 3.0 - - -def test_unsafe_candidate_is_rejected_with_reason() -> None: - # Arrange - verifier = GeometryGatedAnchorVerifier() - frame = AnchorFrame(frame_id="frame-1", image_ref="replay/frame-1.jpg") - evidence = _evidence( - candidate=_candidate(freshness_status="stale"), - inliers=6, - mean_reprojection_error_px=8.0, - ) - - # Act - result = verifier.verify(frame, evidence) - - # Assert - assert result.decision.accepted is False - assert result.decision.estimated_pose is None - assert result.decision.rejection_reason == "stale_or_untrusted_provenance" - assert result.reason == "stale_or_untrusted_provenance" - - -def test_computed_matching_rejects_low_inlier_geometry() -> None: - # Arrange - verifier = GeometryGatedAnchorVerifier() - frame = _frame_with_keypoints() - tile = _tile_with_keypoints( - keypoints=((100.0, 100.0), (12.0, 3.0), (99.0, 88.0), (50.0, 40.0), (6.0, 9.0)) - ) - - # Act - result = verifier.verify_candidate(frame, tile, matcher_profile="sift_orb") - - # Assert - assert result.decision.accepted is False - assert result.reason == "low_inliers" - assert result.decision.rejection_reason == "low_inliers" - - -def test_matcher_benchmark_reports_profile_runtime_and_quality_metrics() -> None: - # Arrange - verifier = GeometryGatedAnchorVerifier() - frame = AnchorFrame(frame_id="frame-1", image_ref="replay/frame-1.jpg") - - # Act - report = verifier.benchmark( - frame, - ( - _evidence(matcher_profile="aliked_lightglue", runtime_ms=72.5), - _evidence(matcher_profile="sift_orb", inliers=12, runtime_ms=18.0), - ), - ) - - # Assert - assert [result.matcher_profile for result in report.results] == [ - "aliked_lightglue", - "sift_orb", - ] - assert report.results[0].accepted is True - assert report.results[0].runtime_ms == 72.5 - assert report.results[1].accepted is False - assert report.results[1].reason == "low_inliers" - - -def test_matcher_benchmark_can_run_computed_paths() -> None: - # Arrange - verifier = GeometryGatedAnchorVerifier() - frame = _frame_with_keypoints() - - # Act - report = verifier.benchmark_candidates( - frame, - ( - _tile_with_keypoints(), - _tile_with_keypoints( - keypoints=((2.0, 3.0), (2.0, 13.0), (2.0, 23.0), (2.0, 33.0), (2.0, 43.0)) - ), - ), - matcher_profile="sift_orb", - ) - - # Assert - assert report.results[0].accepted is True - assert report.results[0].runtime_ms >= 0.0 - assert report.results[1].accepted is False - assert report.results[1].reason == "low_inliers" diff --git a/tests/unit/test_camera_ingest_calibration.py b/tests/unit/test_camera_ingest_calibration.py deleted file mode 100644 index deecfe2..0000000 --- a/tests/unit/test_camera_ingest_calibration.py +++ /dev/null @@ -1,76 +0,0 @@ -import pytest -from pydantic import ValidationError - -from camera_ingest_calibration import ( - CalibrationMetadata, - CameraFrameIngestor, - NavigationFrame, -) - - -def _calibration() -> CalibrationMetadata: - return CalibrationMetadata( - calibration_id="calib-front-1", - camera_model="global-shutter", - image_width_px=1920, - image_height_px=1080, - focal_length_px=840.0, - distortion_model="plumb_bob", - ) - - -def test_valid_frame_packet_contains_metadata_reports_and_normalization_hint() -> None: - # Arrange - frame = NavigationFrame( - frame_id="frame-1", - timestamp_ns=1_000, - image_ref="replay/frame-1.jpg", - mean_luma=0.7, - contrast=0.6, - north_up_degrees=12.5, - ) - - # Act - packet = CameraFrameIngestor().ingest(frame, _calibration()) - - # Assert - assert packet.contract.timestamp_ns == 1_000 - assert packet.contract.calibration_id == "calib-front-1" - assert packet.quality_report.state == "usable" - assert packet.occlusion_report.state == "clear" - assert packet.normalization_hint.should_normalize_downstream is True - - -def test_total_occlusion_marks_frame_unusable_for_vio_and_anchor() -> None: - # Arrange - frame = NavigationFrame( - frame_id="frame-blackout", - timestamp_ns=2_000, - image_ref="replay/frame-blackout.jpg", - mean_luma=0.01, - contrast=0.01, - ) - - # Act - packet = CameraFrameIngestor().ingest(frame, _calibration()) - - # Assert - assert packet.occlusion_report.state == "total" - assert packet.usable_for_vio is False - assert packet.usable_for_anchor is False - - -def test_raw_frame_payload_retention_is_rejected() -> None: - # Act - with pytest.raises(ValidationError) as error: - NavigationFrame( - frame_id="frame-raw", - timestamp_ns=3_000, - image_ref="replay/frame-raw.jpg", - mean_luma=0.7, - contrast=0.6, - raw_frame_retained=True, - ) - - # Assert - assert "references only" in str(error.value) diff --git a/tests/unit/test_fdr_observability.py b/tests/unit/test_fdr_observability.py deleted file mode 100644 index ee35c7d..0000000 --- a/tests/unit/test_fdr_observability.py +++ /dev/null @@ -1,64 +0,0 @@ -from shared.contracts import FdrEvent - -from fdr_observability import FdrExportRequest, FdrPayload, InMemoryFlightRecorder - - -def _event(event_type: str = "anchor") -> FdrEvent: - return FdrEvent( - event_type=event_type, - timestamp_ns=1_000, - component="anchor_verification", - severity="info", - payload_ref="pending", - mission_id="mission-1", - run_id="run-1", - ) - - -def test_valid_event_append_indexes_metadata_and_payload_reference() -> None: - # Arrange - recorder = InMemoryFlightRecorder(segment_limit_bytes=1_000, storage_limit_bytes=2_000) - payload = FdrPayload(ref="fdr://segments/1/payloads/anchor-1.cbor", size_bytes=128) - - # Act - result = recorder.append_event(_event(), payload) - - # Assert - assert result.appended is True - assert result.event is not None - assert result.event.payload_ref == payload.ref - assert result.segment_id == "segment-0001" - assert recorder.health.status == "ready" - - -def test_rollover_threshold_records_explicit_rollover_result() -> None: - # Arrange - recorder = InMemoryFlightRecorder(segment_limit_bytes=100, storage_limit_bytes=500) - recorder.append_event(_event("first"), FdrPayload(ref="fdr://payloads/1", size_bytes=80)) - - # Act - result = recorder.append_event( - _event("second"), FdrPayload(ref="fdr://payloads/2", size_bytes=50) - ) - - # Assert - assert result.appended is True - assert result.rollover is True - assert result.segment_id == "segment-0002" - - -def test_export_request_produces_queryable_evidence_artifacts() -> None: - # Arrange - recorder = InMemoryFlightRecorder(segment_limit_bytes=1_000, storage_limit_bytes=2_000) - recorder.append_event(_event(), FdrPayload(ref="fdr://payloads/1", size_bytes=128)) - - # Act - result = recorder.export( - FdrExportRequest(mission_id="mission-1", run_id="run-1", include_analytics=True) - ) - - # Assert - assert result.produced is True - assert result.evidence_ref == "fdr://exports/mission-1/run-1/evidence.json" - assert result.analytics_ref == "fdr://exports/mission-1/run-1/analytics.parquet" - assert result.segments[0].event_count == 1 diff --git a/tests/unit/test_mavlink_gcs_integration.py b/tests/unit/test_mavlink_gcs_integration.py deleted file mode 100644 index b0de349..0000000 --- a/tests/unit/test_mavlink_gcs_integration.py +++ /dev/null @@ -1,72 +0,0 @@ -from shared.contracts import PositionEstimate - -from mavlink_gcs_integration import ( - FlightControllerTelemetry, - InMemoryMavlinkGateway, - OperatorStatusMessage, -) - - -def test_telemetry_subscription_emits_normalized_sample() -> None: - # Arrange - gateway = InMemoryMavlinkGateway(status_rate_limit_ns=1_000) - telemetry = FlightControllerTelemetry( - timestamp_ns=1_000, - acceleration_mps2=(0.1, 0.2, -9.8), - attitude_rad=(0.01, 0.02, 1.57), - altitude_m=250.0, - airspeed_mps=17.5, - gps_health="lost", - ) - - # Act - samples = gateway.subscribe_telemetry([telemetry]) - - # Assert - assert len(samples) == 1 - assert samples[0].imu["accel_z"] == -9.8 - assert samples[0].attitude["yaw"] == 1.57 - assert samples[0].gps_health == "lost" - - -def test_invalid_gps_input_estimate_is_rejected_without_emission() -> None: - # Arrange - gateway = InMemoryMavlinkGateway(status_rate_limit_ns=1_000) - estimate = PositionEstimate( - timestamp_ns=2_000, - latitude_deg=49.9, - longitude_deg=36.2, - altitude_m=250.0, - covariance_semimajor_m=10.0, - source_label="no_fix", - fix_type=1, - horizontal_accuracy_m=10.0, - anchor_age_ms=0, - ) - - # Act - result = gateway.emit_gps_input(estimate) - - # Assert - assert result.emitted is False - assert result.error is not None - assert result.error.category == "validation" - assert gateway.emitted_gps_inputs == [] - - -def test_operator_status_messages_are_rate_limited_by_text() -> None: - # Arrange - gateway = InMemoryMavlinkGateway(status_rate_limit_ns=1_000) - messages = [ - OperatorStatusMessage(timestamp_ns=1_000, severity="warning", text="GPS denied"), - OperatorStatusMessage(timestamp_ns=1_500, severity="warning", text="GPS denied"), - OperatorStatusMessage(timestamp_ns=2_100, severity="warning", text="GPS denied"), - ] - - # Act - result = gateway.emit_status(messages) - - # Assert - assert [message.timestamp_ns for message in result.emitted] == [1_000, 2_100] - assert [message.timestamp_ns for message in result.suppressed] == [1_500] - assert len(gateway.emitted_status_messages) == 2 diff --git a/tests/unit/test_safety_anchor_wrapper.py b/tests/unit/test_safety_anchor_wrapper.py deleted file mode 100644 index 80300c6..0000000 --- a/tests/unit/test_safety_anchor_wrapper.py +++ /dev/null @@ -1,102 +0,0 @@ -from safety_anchor_wrapper import SafetyAnchorStateMachine, SafetyStateConfig, TelemetryContext -from shared.contracts import AnchorDecision, VioStatePacket - - -def _telemetry() -> TelemetryContext: - return TelemetryContext( - timestamp_ns=1_000_000, - latitude_hint_deg=49.1, - longitude_hint_deg=36.1, - altitude_m=120.0, - ) - - -def _vio_state(**overrides: object) -> VioStatePacket: - payload: dict[str, object] = { - "timestamp_ns": 1_000_000, - "relative_pose": {"x_m": 1.0, "y_m": 0.0, "z_m": 0.0}, - "velocity_mps": (12.0, 0.0, 0.0), - "tracking_quality": 0.9, - "covariance_hint": [[1.8, 0.0], [0.0, 1.8]], - } - payload.update(overrides) - return VioStatePacket.model_validate(payload) - - -def _accepted_anchor() -> AnchorDecision: - return AnchorDecision( - candidate_id="chunk-1", - accepted=True, - estimated_pose={"latitude_deg": 49.2, "longitude_deg": 36.2, "altitude_m": 121.0}, - inliers=48, - mean_reprojection_error_px=1.2, - ) - - -def test_vio_state_updates_position_estimate_with_honest_covariance() -> None: - # Arrange - machine = SafetyAnchorStateMachine() - - # Act - snapshot = machine.update_vio(_vio_state(), _telemetry()) - - # Assert - assert snapshot.estimate.source_label == "vo_extrapolated" - assert snapshot.estimate.latitude_deg == 49.1 - assert snapshot.estimate.covariance_semimajor_m == 1.8 - assert snapshot.estimate.horizontal_accuracy_m >= snapshot.estimate.covariance_semimajor_m - - -def test_accepted_anchor_corrects_state_and_records_evidence() -> None: - # Arrange - machine = SafetyAnchorStateMachine() - machine.update_vio(_vio_state(), _telemetry()) - - # Act - snapshot = machine.consider_anchor(_accepted_anchor()) - - # Assert - assert snapshot.mode == "satellite_anchored" - assert snapshot.estimate.latitude_deg == 49.2 - assert snapshot.anchor_evidence is not None - assert snapshot.anchor_evidence.candidate_id == "chunk-1" - - -def test_blackout_degrades_then_reaches_no_fix_with_monotonic_covariance() -> None: - # Arrange - machine = SafetyAnchorStateMachine( - SafetyStateConfig(dead_reckoning_growth_m=250.0, no_fix_covariance_threshold_m=500.0) - ) - machine.update_vio(_vio_state(covariance_hint=[[100.0]]), _telemetry()) - - # Act - degraded = machine.propagate_blackout(2_000_000) - no_fix = machine.propagate_blackout(3_000_000) - - # Assert - assert degraded.mode == "dead_reckoned" - assert degraded.estimate.covariance_semimajor_m == 350.0 - assert no_fix.mode == "no_fix" - assert no_fix.estimate.fix_type == 0 - assert no_fix.estimate.covariance_semimajor_m > degraded.estimate.covariance_semimajor_m - - -def test_tile_write_eligibility_requires_trusted_low_covariance_pose() -> None: - # Arrange - machine = SafetyAnchorStateMachine(SafetyStateConfig(tile_write_covariance_max_m=3.0)) - machine.update_vio(_vio_state(covariance_hint=[[4.0]]), _telemetry()) - - # Act - high_covariance = machine.tile_write_eligibility() - machine.consider_anchor(_accepted_anchor()) - anchored = machine.tile_write_eligibility() - machine.propagate_blackout(2_000_000) - blackout = machine.tile_write_eligibility() - - # Assert - assert high_covariance.eligible is False - assert high_covariance.reason == "covariance_too_high" - assert anchored.eligible is True - assert anchored.reason == "trusted_pose" - assert blackout.eligible is False - assert blackout.reason == "untrusted_source_label" diff --git a/tests/unit/test_satellite_service_sync.py b/tests/unit/test_satellite_service_sync.py deleted file mode 100644 index ffe70d8..0000000 --- a/tests/unit/test_satellite_service_sync.py +++ /dev/null @@ -1,96 +0,0 @@ -from datetime import datetime, timezone - -from satellite_service import MissionCachePackage, SatelliteSyncBoundary -from tile_manager import ( - GeneratedTileSidecar, - GeneratedTileSyncPackage, - TileManifestEntry, -) - - -def _manifest_entry() -> TileManifestEntry: - return TileManifestEntry( - tile_id="tile-1", - chunk_id="chunk-1", - crs="EPSG:3857", - meters_per_pixel=0.3, - capture_date="2026-05-01", - expires_at=datetime(2026, 6, 1, tzinfo=timezone.utc), - content_hash="sha256:tile", - expected_content_hash="sha256:tile", - sidecar_hash="sha256:sidecar", - expected_sidecar_hash="sha256:sidecar", - signature_hash="sig:trusted", - provenance="suite-satellite-service", - footprint={"min_lat": 49.0, "max_lat": 49.1}, - descriptor_ref="descriptors/chunk-1.vlad", - ) - - -def _generated_package() -> GeneratedTileSyncPackage: - sidecar = GeneratedTileSidecar( - tile_id="generated-1", - parent_frame_id="frame-1", - parent_covariance_m=2.0, - quality_score=0.8, - trust_level="generated", - provenance="nav-camera-generated", - ) - return GeneratedTileSyncPackage( - package_ref="generated/mission-1/sync-package.json", - mission_id="mission-1", - manifest_delta=({"tile_id": "generated-1", "trust_level": "generated"},), - sidecars=(sidecar,), - ) - - -def test_pre_flight_import_returns_package_for_tile_manager_validation() -> None: - # Arrange - boundary = SatelliteSyncBoundary() - package = MissionCachePackage( - package_id="pkg-1", - mission_id="mission-1", - manifest_entries=(_manifest_entry(),), - ) - - # Act - result = boundary.import_mission_cache(package, phase="pre_flight") - - # Assert - assert result.ready_for_tile_validation is True - assert result.manifest_entries[0].tile_id == "tile-1" - assert boundary.status().imported_package_ids == ("pkg-1",) - - -def test_post_flight_upload_records_retryable_failure_for_audit() -> None: - # Arrange - boundary = SatelliteSyncBoundary(uploader=lambda package: "retryable_failure") - - # Act - result = boundary.upload_generated_tiles(_generated_package(), phase="post_flight") - - # Assert - assert result.upload_record is not None - assert result.upload_record.status == "retryable_failure" - assert result.upload_record.retained_for_retry is True - assert boundary.status().retry_package_refs == ("generated/mission-1/sync-package.json",) - - -def test_in_flight_sync_is_blocked_without_calling_network_boundary() -> None: - # Arrange - calls: list[str] = [] - - def uploader(package: GeneratedTileSyncPackage) -> str: - calls.append(package.package_ref) - return "success" - - boundary = SatelliteSyncBoundary(uploader=uploader) - - # Act - result = boundary.upload_generated_tiles(_generated_package(), phase="in_flight") - - # Assert - assert result.upload_record is None - assert result.error is not None - assert result.error.cause == "mid_flight_network_blocked" - assert calls == [] diff --git a/tests/unit/test_satellite_service_vpr.py b/tests/unit/test_satellite_service_vpr.py deleted file mode 100644 index b044f8e..0000000 --- a/tests/unit/test_satellite_service_vpr.py +++ /dev/null @@ -1,198 +0,0 @@ -import json -from pathlib import Path - -from satellite_service import ( - LocalVprIndexPackage, - LocalVprRetriever, - RelocalizationRequest, - VprDescriptorRecord, -) - - -def _record( - chunk_id: str = "chunk-1", - tile_id: str = "tile-1", - descriptor: tuple[float, ...] = (1.0, 0.0, 0.0), - freshness_status: str = "fresh", -) -> VprDescriptorRecord: - return VprDescriptorRecord( - chunk_id=chunk_id, - tile_id=tile_id, - descriptor=descriptor, - footprint={"min_lat": 49.0, "max_lat": 49.1, "min_lon": 36.0, "max_lon": 36.1}, - freshness_status=freshness_status, - ) - - -def test_valid_local_index_load_reports_ready_status() -> None: - # Arrange - retriever = LocalVprRetriever() - package = LocalVprIndexPackage(package_id="index-1", records=(_record(),)) - - # Act - readiness = retriever.load_index(package) - - # Assert - assert readiness.ready is True - assert readiness.engine == "cpu_faiss" - assert readiness.loaded_records == 1 - assert readiness.package_id == "index-1" - assert readiness.descriptor_model == "dinov2_vlad" - - -def test_local_descriptor_index_package_loads_from_cache_file(tmp_path: Path) -> None: - # Arrange - package_path = tmp_path / "vpr-index.json" - package_path.write_text( - json.dumps( - { - "package_id": "index-file-1", - "engine": "cpu_faiss", - "descriptor_model": "dinov2_vlad", - "records": [ - { - "chunk_id": "chunk-file", - "tile_id": "tile-file", - "descriptor": [1.0, 0.0], - "footprint": { - "min_lat": 49.0, - "max_lat": 49.1, - "min_lon": 36.0, - "max_lon": 36.1, - }, - "freshness_status": "fresh", - } - ], - } - ), - encoding="utf-8", - ) - retriever = LocalVprRetriever() - - # Act - readiness = retriever.load_index_from_path(package_path) - - # Assert - assert readiness.ready is True - assert readiness.package_id == "index-file-1" - assert readiness.loaded_records == 1 - - -def test_loaded_index_returns_bounded_candidates_with_freshness() -> None: - # Arrange - retriever = LocalVprRetriever() - retriever.load_index( - LocalVprIndexPackage( - package_id="index-1", - records=( - _record(chunk_id="chunk-best", tile_id="tile-best", descriptor=(1.0, 0.0)), - _record( - chunk_id="chunk-stale", - tile_id="tile-stale", - descriptor=(0.8, 0.2), - freshness_status="stale", - ), - ), - ) - ) - request = RelocalizationRequest( - frame_id="frame-1", - image_ref="replay/frame-1.jpg", - trigger_reason="covariance_growth", - top_k=1, - query_descriptor=(1.0, 0.0), - ) - - # Act - result = retriever.retrieve(request) - - # Assert - assert result.degraded is False - assert result.retrieval_path == "local_descriptor_index" - assert result.latency_ms is not None - assert len(result.candidates) == 1 - assert result.candidates[0].chunk_id == "chunk-best" - assert result.candidates[0].tile_id == "tile-best" - assert result.candidates[0].freshness_status == "fresh" - - -def test_loaded_index_requires_query_descriptor() -> None: - # Arrange - retriever = LocalVprRetriever() - retriever.load_index(LocalVprIndexPackage(package_id="index-1", records=(_record(),))) - request = RelocalizationRequest( - frame_id="frame-1", - image_ref="replay/frame-1.jpg", - trigger_reason="covariance_growth", - top_k=1, - ) - - # Act - result = retriever.retrieve(request) - - # Assert - assert result.ready is True - assert result.degraded is True - assert result.error is not None - assert result.error.cause == "query_descriptor_missing" - - -def test_missing_index_degrades_with_explicit_no_candidate_result() -> None: - # Arrange - retriever = LocalVprRetriever() - request = RelocalizationRequest( - frame_id="frame-1", - image_ref="replay/frame-1.jpg", - trigger_reason="cold_start", - top_k=3, - ) - - # Act - result = retriever.retrieve(request) - - # Assert - assert result.ready is False - assert result.degraded is True - assert result.candidates == () - assert result.error is not None - assert result.error.cause == "index_not_loaded" - - -def test_invalid_index_package_degrades_with_explicit_error(tmp_path: Path) -> None: - # Arrange - package_path = tmp_path / "invalid-index.json" - package_path.write_text("{not-json", encoding="utf-8") - retriever = LocalVprRetriever() - - # Act - readiness = retriever.load_index_from_path(package_path) - result = retriever.retrieve( - RelocalizationRequest( - frame_id="frame-1", - image_ref="replay/frame-1.jpg", - trigger_reason="cold_start", - top_k=3, - query_descriptor=(1.0, 0.0), - ) - ) - - # Assert - assert readiness.ready is False - assert readiness.error is not None - assert readiness.error.cause == "index_package_invalid" - assert result.ready is False - assert result.degraded is True - assert result.error is not None - assert result.error.cause == "index_package_invalid" - - -def test_descriptor_fidelity_gate_rejects_large_optimized_delta() -> None: - # Arrange - retriever = LocalVprRetriever() - - # Act - report = retriever.verify_descriptor_fidelity((1.0, 0.0), (0.0, 1.0), max_l2_delta=0.1) - - # Assert - assert report.accepted is False - assert report.observed_l2_delta > report.max_l2_delta diff --git a/tests/unit/test_scaffold.py b/tests/unit/test_scaffold.py deleted file mode 100644 index 6d8a5ad..0000000 --- a/tests/unit/test_scaffold.py +++ /dev/null @@ -1,137 +0,0 @@ -from importlib import import_module -from pathlib import Path - -COMPONENT_PACKAGES = [ - "camera_ingest_calibration", - "vio_adapter", - "safety_anchor_wrapper", - "satellite_service", - "anchor_verification", - "tile_manager", - "mavlink_gcs_integration", - "fdr_observability", -] - -SHARED_PACKAGES = [ - "shared.contracts", - "shared.geo_geometry", - "shared.time_sync", - "shared.config", - "shared.errors", - "shared.telemetry", -] - -REQUIRED_PATHS = [ - "src", - "migrations/postgresql/0001_enable_postgis.sql", - "migrations/seed/README.md", - "tests/unit/test_scaffold.py", - "tests/unit/shared/.gitkeep", - "tests/unit/camera_ingest_calibration/.gitkeep", - "tests/unit/vio_adapter/.gitkeep", - "tests/unit/safety_anchor_wrapper/.gitkeep", - "tests/unit/satellite_service/.gitkeep", - "tests/unit/anchor_verification/.gitkeep", - "tests/unit/tile_manager/.gitkeep", - "tests/unit/mavlink_gcs_integration/.gitkeep", - "tests/unit/fdr_observability/.gitkeep", - "src/vio_adapter/native/README.md", - "src/satellite_service/native/README.md", - "src/anchor_verification/native/README.md", - "tests/integration/contracts/.gitkeep", - "tests/blackbox/still_image_geolocation/.gitkeep", - "tests/fixtures/project_60_images/.gitkeep", - "tests/sitl/plane_gps_input/.gitkeep", - "tests/e2e/replay/.gitkeep", - "e2e/replay/run_replay.py", - "e2e/reports/.gitkeep", - "deployment/docker/Dockerfile.runtime", - "deployment/docker/Dockerfile.replay", - "deployment/scripts/collect_evidence.sh", - "config/development/runtime.env", - "config/ci/runtime.env", - "config/jetson/runtime.env", - "config/production/runtime.env.example", - "docker-compose.yml", - "docker-compose.test.yml", - ".github/workflows/ci.yml", - ".env.example", - ".dockerignore", -] - - -def test_runtime_component_public_modules_are_importable() -> None: - # Act - imported_modules = [ - import_module(module_name) - for package_name in COMPONENT_PACKAGES - for module_name in (package_name, f"{package_name}.interfaces", f"{package_name}.types") - ] - - # Assert - assert len(imported_modules) == len(COMPONENT_PACKAGES) * 3 - - -def test_shared_contract_locations_are_importable() -> None: - # Act - imported_modules = [import_module(package_name) for package_name in SHARED_PACKAGES] - - # Assert - assert len(imported_modules) == len(SHARED_PACKAGES) - - -def test_generated_runtime_data_paths_are_gitkeep_only() -> None: - # Arrange - data_dirs = ["input", "expected", "cache", "fdr", "test-results"] - - # Act - missing = [ - directory for directory in data_dirs if not Path("data", directory, ".gitkeep").is_file() - ] - - # Assert - assert missing == [] - - -def test_scaffold_paths_cover_runtime_test_and_evidence_layout() -> None: - # Act - missing = [path for path in REQUIRED_PATHS if not Path(path).exists()] - - # Assert - assert missing == [] - - -def test_native_bridge_placeholders_are_component_owned() -> None: - # Act - shared_native_path_exists = Path("src/native").exists() - - # Assert - assert shared_native_path_exists is False - - -def test_ignore_rules_exclude_runtime_payloads_and_secrets() -> None: - # Arrange - required_patterns = [ - ".env", - "*.pem", - "*.key", - "data/input/*", - "data/cache/*", - "data/fdr/*", - "data/test-results/*", - "*.tlog", - "*.cbor", - "*.mp4", - ] - - # Act - gitignore = Path(".gitignore").read_text(encoding="utf-8") - dockerignore = Path(".dockerignore").read_text(encoding="utf-8") - missing_from_gitignore = [pattern for pattern in required_patterns if pattern not in gitignore] - missing_from_dockerignore = [ - pattern for pattern in required_patterns if pattern not in dockerignore - ] - - # Assert - assert missing_from_gitignore == [] - assert missing_from_dockerignore == [] diff --git a/tests/unit/test_tile_manager.py b/tests/unit/test_tile_manager.py deleted file mode 100644 index 566995e..0000000 --- a/tests/unit/test_tile_manager.py +++ /dev/null @@ -1,137 +0,0 @@ -from datetime import datetime, timezone - -from tile_manager import LocalTileManager, TileGenerationRequest, TileManifestEntry - -NOW = datetime(2026, 5, 3, tzinfo=timezone.utc) - - -def _entry(**overrides: object) -> TileManifestEntry: - payload: dict[str, object] = { - "tile_id": "tile-1", - "chunk_id": "chunk-1", - "crs": "EPSG:3857", - "meters_per_pixel": 0.3, - "capture_date": "2026-05-01", - "expires_at": "2026-06-01T00:00:00+00:00", - "content_hash": "sha256:tile", - "expected_content_hash": "sha256:tile", - "sidecar_hash": "sha256:sidecar", - "expected_sidecar_hash": "sha256:sidecar", - "signature_hash": "sig:trusted", - "provenance": "suite-satellite-service", - "footprint": {"min_lat": 49.0, "max_lat": 50.0}, - "descriptor_ref": "descriptors/chunk-1.vlad", - } - payload.update(overrides) - return TileManifestEntry.model_validate(payload) - - -def test_valid_cache_manifest_activates_trusted_records() -> None: - # Arrange - manager = LocalTileManager(trusted_signature_hashes={"sig:trusted"}, now=NOW) - - # Act - report = manager.validate_cache([_entry()]) - - # Assert - assert report.activated is True - assert report.decisions[0].accepted is True - assert report.trusted_records[0].trust_level == "trusted" - - -def test_tampered_or_stale_tile_is_rejected_with_auditable_reason() -> None: - # Arrange - manager = LocalTileManager(trusted_signature_hashes={"sig:trusted"}, now=NOW) - tampered = _entry(tile_id="tile-tampered", content_hash="sha256:bad") - stale = _entry( - tile_id="tile-stale", - chunk_id="chunk-stale", - expires_at="2026-05-01T00:00:00+00:00", - ) - - # Act - report = manager.validate_cache([tampered, stale]) - - # Assert - assert report.activated is False - assert [decision.reason for decision in report.decisions] == [ - "content_hash_mismatch", - "stale", - ] - - -def test_tile_metadata_lookup_returns_record_or_explicit_rejection() -> None: - # Arrange - manager = LocalTileManager(trusted_signature_hashes={"sig:trusted"}, now=NOW) - manager.validate_cache([_entry()]) - - # Act - found = manager.get_tile_metadata("chunk-1") - missing = manager.get_tile_metadata("missing") - - # Assert - assert found.found is True - assert found.record is not None - assert found.descriptor_ref == "descriptors/chunk-1.vlad" - assert missing.found is False - assert missing.error is not None - assert missing.error.category == "validation" - - -def _generation_request(**overrides: object) -> TileGenerationRequest: - payload: dict[str, object] = { - "mission_id": "mission-1", - "frame_id": "frame-1", - "image_ref": "replay/frame-1.jpg", - "timestamp_ns": 10_000, - "parent_covariance_m": 2.5, - "frame_usable": True, - "quality_score": 0.8, - "footprint": {"min_lat": 49.0, "max_lat": 49.1}, - "source_provenance": "nav-camera-generated", - } - payload.update(overrides) - return TileGenerationRequest.model_validate(payload) - - -def test_eligible_frame_stages_generated_cog_and_sidecar() -> None: - # Arrange - manager = LocalTileManager(trusted_signature_hashes={"sig:trusted"}, now=NOW) - - # Act - candidate = manager.orthorectify_frame(_generation_request()) - - # Assert - assert candidate.accepted is True - assert candidate.cog_ref == "generated/mission-1/generated-mission-1-frame-1.cog.tif" - assert candidate.sidecar is not None - assert candidate.sidecar.trust_level == "generated" - assert candidate.sidecar.parent_covariance_m == 2.5 - - -def test_high_covariance_generated_tile_write_is_rejected() -> None: - # Arrange - manager = LocalTileManager(trusted_signature_hashes={"sig:trusted"}, now=NOW) - - # Act - candidate = manager.orthorectify_frame(_generation_request(parent_covariance_m=7.5)) - - # Assert - assert candidate.accepted is False - assert candidate.rejection_reason == "covariance_too_high" - assert manager.package_sync("mission-1").sidecars == () - - -def test_sync_package_includes_manifest_delta_sidecar_covariance_and_trust_level() -> None: - # Arrange - manager = LocalTileManager(trusted_signature_hashes={"sig:trusted"}, now=NOW) - manager.orthorectify_frame(_generation_request()) - - # Act - package = manager.package_sync("mission-1") - - # Assert - assert package.package_ref == "generated/mission-1/sync-package.json" - assert package.sidecars[0].parent_covariance_m == 2.5 - assert package.manifest_delta[0]["trust_level"] == "generated" - assert package.manifest_delta[0]["parent_covariance_m"] == 2.5 diff --git a/tests/unit/test_vio_adapter.py b/tests/unit/test_vio_adapter.py deleted file mode 100644 index b8f787e..0000000 --- a/tests/unit/test_vio_adapter.py +++ /dev/null @@ -1,237 +0,0 @@ -import pytest -from pydantic import ValidationError - -from shared.contracts import FramePacket, TelemetrySample -from vio_adapter import ( - LocalVioAdapter, - NativeVioBackend, - VioBackendEstimate, - VioInputPacket, - VioRuntimeConfig, - create_vio_adapter, -) - - -class RecordingNativeRunner: - def __init__(self) -> None: - self.initialized = False - self.estimate_calls = 0 - - def initialize(self) -> None: - self.initialized = True - - def estimate( - self, - frame: FramePacket, - telemetry_window: tuple[TelemetrySample, ...], - ) -> VioBackendEstimate: - self.estimate_calls += 1 - return VioBackendEstimate( - timestamp_ns=frame.timestamp_ns, - relative_pose={"x_m": 12.0, "y_m": -1.5, "z_m": 0.2, "yaw_rad": 0.3}, - velocity_mps=(4.0, 0.5, 0.0), - tracking_quality=0.77, - bias_estimate={"sample_count": float(len(telemetry_window)), "gyro_bias": 0.01}, - covariance_hint=[[0.4, 0.0, 0.0], [0.0, 0.4, 0.0], [0.0, 0.0, 0.8]], - ) - - -class FailingNativeRunner: - def __init__(self, fail_on: str) -> None: - self._fail_on = fail_on - - def initialize(self) -> None: - if self._fail_on == "initialize": - raise RuntimeError("engine package missing") - - def estimate( - self, - frame: FramePacket, - telemetry_window: tuple[TelemetrySample, ...], - ) -> VioBackendEstimate: - if self._fail_on == "estimate": - raise RuntimeError("engine lost tracking") - return VioBackendEstimate( - timestamp_ns=frame.timestamp_ns, - relative_pose={"x_m": 0.0}, - velocity_mps=(0.0, 0.0, 0.0), - tracking_quality=1.0, - ) - - -def _frame(**overrides: object) -> FramePacket: - payload: dict[str, object] = { - "frame_id": "frame-1", - "timestamp_ns": 1_000_000, - "image_ref": "replay/frame-1.jpg", - "calibration_id": "calib-1", - "occlusion": "clear", - "quality": 0.85, - } - payload.update(overrides) - return FramePacket.model_validate(payload) - - -def _telemetry(timestamp_ns: int = 1_000_000) -> TelemetrySample: - return TelemetrySample( - timestamp_ns=timestamp_ns, - imu={"accel_x": 0.1, "accel_y": 0.0, "accel_z": 9.8}, - attitude={"roll": 0.0, "pitch": 0.01, "yaw": 0.02}, - altitude_m=120.0, - airspeed_mps=24.0, - gps_health="lost", - ) - - -def test_valid_synchronized_packet_emits_vio_state() -> None: - # Arrange - adapter = LocalVioAdapter() - packet = VioInputPacket(frame=_frame(), telemetry_samples=(_telemetry(),)) - - # Act - result = adapter.process(packet) - - # Assert - assert result.error is None - assert result.state_packet is not None - assert result.state_packet.timestamp_ns == 1_000_000 - assert result.state_packet.tracking_quality == 0.85 - assert result.health.state == "ready" - - -def test_configured_native_backend_path_emits_vio_state() -> None: - # Arrange - runner = RecordingNativeRunner() - adapter = LocalVioAdapter(backend=NativeVioBackend(runner, backend_name="basalt")) - packet = VioInputPacket(frame=_frame(), telemetry_samples=(_telemetry(),)) - - # Act - result = adapter.process(packet) - - # Assert - assert runner.initialized is True - assert runner.estimate_calls == 1 - assert result.error is None - assert result.state_packet is not None - assert result.state_packet.relative_pose["x_m"] == 12.0 - assert result.state_packet.velocity_mps == (4.0, 0.5, 0.0) - assert result.health.backend_name == "basalt" - assert result.processing_latency_ms is not None - - -def test_production_profile_selects_native_runtime_path() -> None: - # Arrange - runner = RecordingNativeRunner() - adapter = create_vio_adapter( - VioRuntimeConfig(environment="production"), - native_runner_factory=lambda: runner, - ) - packet = VioInputPacket(frame=_frame(), telemetry_samples=(_telemetry(),)) - - # Act - result = adapter.process(packet) - - # Assert - assert runner.initialized is True - assert runner.estimate_calls == 1 - assert result.error is None - assert result.state_packet is not None - assert result.health.backend_name == "basalt" - - -def test_production_profile_without_installed_native_runtime_fails_closed() -> None: - # Arrange - adapter = create_vio_adapter(VioRuntimeConfig(environment="production")) - packet = VioInputPacket(frame=_frame(), telemetry_samples=(_telemetry(),)) - - # Act - result = adapter.process(packet) - - # Assert - assert result.state_packet is None - assert result.health.state == "failed" - assert result.error is not None - assert result.error.cause == "backend_initialization_failed" - assert "unable to load BASALT runtime" in result.error.message - - -def test_replay_mode_is_explicit_and_not_valid_for_production() -> None: - # Arrange - replay_config = VioRuntimeConfig(environment="development", mode="replay") - adapter = create_vio_adapter(replay_config) - packet = VioInputPacket(frame=_frame(), telemetry_samples=(_telemetry(),)) - - # Act - result = adapter.process(packet) - - # Assert - assert result.error is None - assert result.state_packet is not None - assert result.health.backend_name == "replay_vio" - with pytest.raises(ValidationError, match="require native runtime mode"): - VioRuntimeConfig(environment="production", mode="replay") - - -def test_native_backend_initialization_failure_sets_failed_health() -> None: - # Arrange - adapter = LocalVioAdapter( - backend=NativeVioBackend(FailingNativeRunner("initialize"), backend_name="basalt") - ) - packet = VioInputPacket(frame=_frame(), telemetry_samples=(_telemetry(),)) - - # Act - result = adapter.process(packet) - - # Assert - assert result.state_packet is None - assert result.health.state == "failed" - assert result.error is not None - assert result.error.cause == "backend_initialization_failed" - - -def test_native_backend_runtime_failure_sets_failed_health() -> None: - # Arrange - adapter = LocalVioAdapter( - backend=NativeVioBackend(FailingNativeRunner("estimate"), backend_name="basalt") - ) - packet = VioInputPacket(frame=_frame(), telemetry_samples=(_telemetry(),)) - - # Act - result = adapter.process(packet) - - # Assert - assert result.state_packet is None - assert result.health.state == "failed" - assert result.error is not None - assert result.error.cause == "backend_runtime_failed" - - -def test_timestamp_mismatch_is_explicit_validation_error() -> None: - # Arrange - adapter = LocalVioAdapter(timestamp_tolerance_ns=1_000) - packet = VioInputPacket(frame=_frame(), telemetry_samples=(_telemetry(2_000_000),)) - - # Act - result = adapter.process(packet) - - # Assert - assert result.state_packet is None - assert result.error is not None - assert result.error.component == "vio_adapter" - assert result.error.cause == "gap_exceeded" - assert result.health.state == "degraded" - - -def test_tracking_loss_degrades_health_without_emitting_absolute_position() -> None: - # Arrange - adapter = LocalVioAdapter(degraded_quality_threshold=0.35) - packet = VioInputPacket(frame=_frame(quality=0.2), telemetry_samples=(_telemetry(),)) - - # Act - result = adapter.process(packet) - - # Assert - assert result.state_packet is not None - assert result.health.state == "degraded" - assert "latitude_deg" not in result.state_packet.model_dump() - assert "longitude_deg" not in result.state_packet.model_dump() diff --git a/tests/unit/tile_manager/.gitkeep b/tests/unit/tile_manager/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/unit/tile_manager/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/unit/vio_adapter/.gitkeep b/tests/unit/vio_adapter/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/tests/unit/vio_adapter/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tools/__pycache__/remove_osd_lines.cpython-310.pyc b/tools/__pycache__/remove_osd_lines.cpython-310.pyc deleted file mode 100644 index 0dd4ecb94541e0485f03b8543da5c02113b4e284..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3900 zcmZu!UvC@75x>1VlE>p;Q?g?xZpyl7Ql^n)8$n_iMPf%$V*|D%NJ`us0$fkrC3PZs z$L`(95^?N9)IPfX06_rjv3-d4v2(k#yR&mUGrt+e zwVG?-`FrcX;p0n&@edkYd@Ky^83s$fLWdik!5KG)Y-D;SqrNq?JWIcA&(`mPSHRmI z7DpwoG+*O*j-D%fE`O7|yz)oetMH%l*Z5WRs=Upw@z>F-@t^TG_;vK^qQQSMFy%+0 zer!OBwXIv{#^k}47{v#o9f>$@Zacq9{&-G>oHU9btkn7BWslBG*CI zPxY7#dinv8&xrh-$af$eQ`Yg)q{BQnOof~|O{b=;?!j$UNXEkuo)IMJ(O4)m8mj_a z<<|Sk=^mu3MORZSYI*e74$85HeG{f z?Ii~wneeP6NR@RE3_XY9$j5}T=>okWi(F&k`Y%m3UW7 zcqpP!+`M^fg^PogU=kpFR+0?2veF+XOPpr;QXK8Zf#fS`91oKfsUz2q6YdYgNF>YS zBjxU9;gI`uHib`e1Egu*uwG~Ockfzt^9rM1n_V^QR+BmG25T~#$+zh%T|{%1`eVea zw1`oOv-FIk8mSnKeGLbCi7F+c8%I2OQSA-mAZ_RE^*9o^R-EmRr8o%1Q)TZ$RYZ5d z!z=*`&`M>~!Y&;_4_)&jS_y5HLVY|B_0-IbV|KzQ+@4z}M$$@wiMjE$@r`-RzGC1O zbU?E4HEvFwl-3c)Ibp|aT0S3__1HZhyLwzf_#2ra@8p%pO)GgNEv41m%AG}=il0fr zwqN7cpA8*ob?Ae0^IGoY<=jOW+0%Mn*P8jz3_x+6&2t8q5uZJ>9Xyq3T{OJ@n-Zo3cb;Q8>LXOG739ZcSSWife2ECYGeo;l6g zK8*?;rsGJ~AmNlU{WI3{-(dVwXx~{W^-GTPpQS1tgZWx*Ze0B zKiPSpF2BNku=eoN2RlDlyt?t(`i`DK)(ZUd=QX`VGz?cw_7{fFy2{?6K?wfm~@lw{(p;7}FDK(17kq!@}I z5uHW(ONf#kBJU9S6_F((D?|vUJgXawJ*ziHpgj$Fy5|-51Yx&VO_7m@{_Kvuihct# zMq%m|=U-6Nhs(3cFyi7+nekwTf&|;1BL%opa1CEG@)jmkZEnmNI*@wF9gw=~usUm+ zO<+tDNaLDUfjD($n+~f2bxc+@ZOpVx7o6AebN=l#t4uz|<}Sg)*;7D=yg|dm5FM01 zCP(&8jU1t>-w0Y>Kt3)YqdB}xWf3_(uk%KKLDvdK#^hV55g2b`pLNXorVc5}_6CJE zji{2yZGMTjC}ebKEUe>}dZV%EPpV6Ma7TX^HI9%IbLj{zoY+gFU_2?@ynAr>=ES~r zH~0vw?%e~gGz@nSZ@>Q@4Q0^3z{QUQFma?;2FmWnV-l9?2eYcqGCxyq+sJ$#&-#t}K~FSf_nMyM=ZT@(twB(GLt&9%YAqknu47EtVuV zK}^$xAxu`Bx7p}bYX8%@+=A&^Oi~)}qMbivD2i!qoPVJM{9-4@)X0r}lvb(5O^rS@ zvc5O6fto_46W5U^&|_?K@Nqk)dg4>h4!~gEybC zzq~U=Sx9E(m)F)-;YC?}A8NKS;R-vRw_c5z^ zx>k_nOEb82^&Xl|B)J*R*6OLkXuw0jH>HYRI22xM=PYS_5=zm<_aEulm!FfcA3-?n zd>va$Bt2|8#M1(Oh@K%M)m9h433V8d6ujhJ5W*i|l5SN0w9GoN$OIY@9ucKq@qbs! zH~u5{ut7OKs;MyY{Z4U)g#<>kbVk`lIz))qY0l!%B8HAb-P2*Id-{V&i5YG$Q%{4p zzB@v2eStHHw=nFu7bL!v^HTOpiCPQ2$Got=sY<@j&`V7)#?8MPUGnG diff --git a/tools/remove_osd_lines.py b/tools/remove_osd_lines.py deleted file mode 100644 index dc06c67..0000000 --- a/tools/remove_osd_lines.py +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env python3 -"""Remove neon OSD strokes from a video using color masking and inpainting.""" - -from __future__ import annotations - -import argparse -import subprocess -import tempfile -from pathlib import Path - -import cv2 -import numpy as np - - -def build_mask(frame: np.ndarray, dilate: int) -> np.ndarray: - """Return a mask for bright green/cyan OSD strokes.""" - b, g, r = cv2.split(frame) - - # The OSD strokes are neon-like: green/cyan channels are high and dominate red. - green = (g > 95) & ((g.astype(np.int16) - r.astype(np.int16)) > 22) & ( - (g.astype(np.int16) - b.astype(np.int16)) > 0 - ) - cyan = (g > 105) & (b > 95) & ((g.astype(np.int16) - r.astype(np.int16)) > 28) - - hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) - hue = hsv[:, :, 0] - sat = hsv[:, :, 1] - val = hsv[:, :, 2] - neon_hsv = (sat > 55) & (val > 85) & (hue >= 35) & (hue <= 105) - - mask = ((green | cyan) & neon_hsv).astype(np.uint8) * 255 - - # Remove isolated natural-color speckles, then expand just enough to cover antialiasing. - open_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2, 2)) - mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, open_kernel) - if dilate > 0: - kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2 * dilate + 1, 2 * dilate + 1)) - mask = cv2.dilate(mask, kernel, iterations=1) - return mask - - -def process_video( - input_path: Path, - output_path: Path, - temp_video_path: Path, - *, - seconds: float | None, - mask_preview: bool, - method: str, - radius: float, - dilate: int, -) -> None: - cap = cv2.VideoCapture(str(input_path)) - if not cap.isOpened(): - raise RuntimeError(f"Could not open input video: {input_path}") - - fps = cap.get(cv2.CAP_PROP_FPS) or 30.0 - width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) - height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) - total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) - frame_limit = total_frames if seconds is None else min(total_frames, int(round(seconds * fps))) - - fourcc = cv2.VideoWriter_fourcc(*"mp4v") - writer = cv2.VideoWriter(str(temp_video_path), fourcc, fps, (width, height)) - if not writer.isOpened(): - raise RuntimeError(f"Could not open temporary output video: {temp_video_path}") - - frame_index = 0 - while frame_index < frame_limit: - ok, frame = cap.read() - if not ok: - break - - mask = build_mask(frame, dilate=dilate) - if mask_preview: - rendered = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR) - else: - inpaint_method = cv2.INPAINT_NS if method == "ns" else cv2.INPAINT_TELEA - rendered = cv2.inpaint(frame, mask, radius, inpaint_method) - - writer.write(rendered) - frame_index += 1 - if frame_index % int(max(fps * 10, 1)) == 0: - print(f"processed {frame_index}/{frame_limit} frames", flush=True) - - writer.release() - cap.release() - - -def mux_audio(input_path: Path, temp_video_path: Path, output_path: Path, seconds: float | None) -> None: - cmd = [ - "ffmpeg", - "-hide_banner", - "-y", - "-i", - str(temp_video_path), - "-i", - str(input_path), - "-map", - "0:v:0", - "-map", - "1:a?", - "-c:v", - "libx264", - "-crf", - "18", - "-preset", - "medium", - "-c:a", - "copy", - ] - if seconds is not None: - cmd.extend(["-t", str(seconds)]) - cmd.append(str(output_path)) - subprocess.run(cmd, check=True) - - -def main() -> None: - parser = argparse.ArgumentParser() - parser.add_argument("input", type=Path) - parser.add_argument("output", type=Path) - parser.add_argument("--seconds", type=float, default=None) - parser.add_argument("--mask-preview", action="store_true") - parser.add_argument("--method", choices=["telea", "ns"], default="telea") - parser.add_argument("--radius", type=float, default=3.0) - parser.add_argument("--dilate", type=int, default=1) - args = parser.parse_args() - - args.output.parent.mkdir(parents=True, exist_ok=True) - with tempfile.TemporaryDirectory(prefix="osd_inpaint_") as temp_dir: - temp_video_path = Path(temp_dir) / "video_no_audio.mp4" - process_video( - args.input, - args.output, - temp_video_path, - seconds=args.seconds, - mask_preview=args.mask_preview, - method=args.method, - radius=args.radius, - dilate=args.dilate, - ) - mux_audio(args.input, temp_video_path, args.output, args.seconds) - - -if __name__ == "__main__": - main()