Files
gps-denied-desktop/_docs/02_components/system_flows.md
T
Oleksandr Bezdieniezhnykh abc26d5c20 initial structure implemented
docs -> _docs
2025-12-01 14:20:56 +02:00

902 lines
75 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ASTRAL-Next System Flows
> **See also**: [System Flow Diagrams (Mermaid)](./system_flows_diagrams.md) for interactive visual diagrams.
## System Overview
ASTRAL-Next is a GPS-denied UAV visual localization system using tri-layer matching (SuperPoint+LightGlue for VO, DINOv2 for place recognition, LiteSAM for cross-view matching) with an Atlas-style multi-map chunk architecture for robust tracking and recovery.
## Components Summary
| ID | Component | Interface | Purpose |
|----|-----------|-----------|---------|
| F01 | Flight API | `IFlightAPI` | REST endpoints, SSE streaming |
| F02.1 | Flight Lifecycle Manager | `IFlightLifecycleManager` | Flight CRUD, init, API delegation |
| F02.2 | Flight Processing Engine | `IFlightProcessingEngine` | Processing loop, recovery orchestration |
| F03 | Flight Database | `IFlightDatabase` | Persistence layer |
| F04 | Satellite Data Manager | `ISatelliteDataManager` | Tile fetching, caching, progressive search |
| F05 | Image Input Pipeline | `IImageInputPipeline` | Image ingestion, validation, storage |
| F06 | Image Rotation Manager | `IImageRotationManager` | Rotation sweeps, heading tracking |
| F07 | Sequential Visual Odometry | `ISequentialVisualOdometry` | Frame-to-frame VO (SuperPoint+LightGlue) |
| F08 | Global Place Recognition | `IGlobalPlaceRecognition` | Coarse localization (DINOv2+VLAD) |
| F09 | Metric Refinement | `IMetricRefinement` | Precise alignment (LiteSAM) |
| F10 | Factor Graph Optimizer | `IFactorGraphOptimizer` | GTSAM-based trajectory optimization |
| F11 | Failure Recovery Coordinator | `IFailureRecoveryCoordinator` | Recovery orchestration, chunk matching |
| F12 | Route Chunk Manager | `IRouteChunkManager` | Chunk lifecycle management |
| F13 | Coordinate Transformer | `ICoordinateTransformer` | Coordinate conversions (GPS↔ENU↔Pixel) |
| F14 | Result Manager | `IResultManager` | Result tracking and publishing |
| F15 | SSE Event Streamer | `ISSEEventStreamer` | Real-time event streaming |
| F16 | Model Manager | `IModelManager` | ML model loading (TensorRT/ONNX) |
| F17 | Configuration Manager | `IConfigurationManager` | System configuration |
### Helper Components
| ID | Helper | Interface | Purpose |
|----|--------|-----------|---------|
| H01 | Camera Model | `ICameraModel` | Projection/unprojection |
| H02 | GSD Calculator | `IGSDCalculator` | Ground sampling distance |
| H03 | Robust Kernels | `IRobustKernels` | Huber/Cauchy loss functions |
| H04 | Faiss Index Manager | `IFaissIndexManager` | Similarity search |
| H05 | Performance Monitor | `IPerformanceMonitor` | Timing measurements |
| H06 | Web Mercator Utils | `IWebMercatorUtils` | Tile coordinate calculations |
| H07 | Image Rotation Utils | `IImageRotationUtils` | Image rotation operations |
| H08 | Batch Validator | `IBatchValidator` | Image batch validation |
---
## Flow 1: System Initialization
**Purpose**: Initialize all system components on startup.
**Sequence**:
```
┌─────────────────┐
│ System Start │
└────────┬────────┘
┌─────────────────┐
│ F17 load_config │ ← Load system configuration
└────────┬────────┘
┌─────────────────┐
│ F03 Initialize │ ← Establish DB connection pool
│ connections │
└────────┬────────┘
┌─────────────────────────────────────────┐
│ F16 load_model() × 4 │
│ ├─ SuperPoint (feature extraction) │
│ ├─ LightGlue (feature matching) │
│ ├─ DINOv2 (place recognition) │
│ └─ LiteSAM (cross-view matching) │
└────────┬────────────────────────────────┘
┌─────────────────┐
│F04 Initialize │ ← Initialize tile cache
│ cache │
└────────┬────────┘
┌─────────────────────────────────────────┐
│ F08 load_index() │
│ ← Load pre-built Faiss index from │
│ satellite provider │
└────────┬────────────────────────────────┘
┌─────────────────┐
│ F12 Initialize │ ← Initialize chunk state tracking
└────────┬────────┘
┌─────────────────┐
│ F02.1 Ready │ ← Ready to accept flights
└────────┬────────┘
┌─────────────────┐
│ F01 Start │ ← Start FastAPI/Uvicorn
│ server │
└─────────────────┘
```
**Duration**: ~30 seconds (dominated by model loading)
---
## Flow 2: Flight Creation
**Purpose**: Create a new flight with initial configuration and prefetch satellite data.
**Trigger**: `POST /flights`
**Sequence**:
```
┌──────────┐ POST /flights ┌─────┐
│ Client │ ───────────────────► │ F01 │
└──────────┘ └──┬──┘
│ create_flight()
┌─────────┐
│ F02.1 │ Flight Lifecycle Manager
└────┬────┘
┌────────────────────────┬─┴─┬────────────────────────┐
│ │ │ │
▼ │ ▼ ▼
┌───────────────┐ │ ┌───────────────┐ ┌───────────────┐
│F17 get_flight │ │ │F13 set_enu │ │F04 prefetch │
│ _config() │ │ │ _origin() │ │ _route │
└───────────────┘ │ └───────────────┘ │ _corridor() │
│ └───────┬───────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────────┐
│F03 insert │ │ Satellite │
│ _flight() │ │ Provider API │
└─────────────┘ │ GET tiles/batch │
└─────────────────┘
┌──────┴──────┐
│ F14 │
│create_stream│
└─────────────┘
┌──────┴──────┐
SSE Connection │ Client │
◄─────────────────────────────│ GET stream │
└─────────────┘
```
**Output**: `flight_id`, SSE stream established
---
## Flow 3: Image Upload
**Purpose**: Upload batch of UAV images for processing.
**Trigger**: `POST /flights/{flightId}/images/batch`
**Sequence**:
```
┌──────────┐ POST images/batch ┌─────┐
│ Client │ ──────────────────► │ F01 │
│ │ (10-50 images) └──┬──┘
└──────────┘ │ queue_batch()
┌─────────────┐
│ F05 │ Image Input Pipeline
└──────┬──────┘
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│H08 validate │ │ Store to │ │F03 save │
│ _batch() │ │ disk │ │ _image │
└─────────────┘ └─────────────┘ │ _metadata()│
└─────────────┘
```
**Validation Rules**:
- Batch size: 10-50 images
- Naming convention: ADxxxxxx.jpg
- Sequential numbering
- Image dimensions: 640×480 to 6252×4168
---
## Flow 4: Normal Frame Processing (Tracking Good)
**Purpose**: Process a single frame when tracking quality is good.
**Sequence**:
```
┌──────────────────────────────────────────────────────────────────────────┐
│ F02.2 Flight Processing Engine │
│ │
│ ┌─────────────┐ │
│ │ get_next │◄───────────────────────────────────────────────────────┐│
│ │ _image() │ ││
│ └──────┬──────┘ ││
│ │ F05 ││
│ ▼ ││
│ ┌─────────────────────────────────────────────────────────────┐ ││
│ │ get_active_chunk() via F12 │ ││
│ └──────────────────────────────┬──────────────────────────────┘ ││
│ ▼ ││
│ ┌─────────────────────────────────────────────────────────────┐ ││
│ │ requires_rotation_sweep()? via F06 │ ││
│ │ ├─ YES → Flow 5 (First Frame/Sharp Turn) │ ││
│ │ └─ NO → Pre-rotate to current heading │ ││
│ └──────────────────────────────┬──────────────────────────────┘ ││
│ ▼ ││
│ ┌─────────────────────────────────────────────────────────────┐ ││
│ │ F07 compute_relative_pose() │ ││
│ │ ├─ SuperPoint extract (prev + curr) via F16 │ ││
│ │ └─ LightGlue match via F16 │ ││
│ └──────────────────────────────┬──────────────────────────────┘ ││
│ │ ││
│ ┌─────────────────┼─────────────────┐ ││
│ │ Tracking Good? │ Tracking Lost? │ ││
│ ▼ ▼ ▼ ││
│ ┌─────────────────┐ ┌─────────────────────────────────┐ ││
│ │F12 add_frame │ │ →Flow 6 (Tracking Loss/Recovery)│ ││
│ │ _to_chunk() │ └─────────────────────────────────┘ ││
│ └────────┬────────┘ ││
│ ▼ ││
│ ┌─────────────────────────────────────────────────────────────┐ ││
│ │ F04 fetch_tile() + compute_tile_bounds() │ ││
│ └──────────────────────────────┬──────────────────────────────┘ ││
│ ▼ ││
│ ┌─────────────────────────────────────────────────────────────┐ ││
│ │ F09 align_to_satellite(image, tile, tile_bounds) │ ││
│ │ └─ LiteSAM matching via F16 │ ││
│ └──────────────────────────────┬──────────────────────────────┘ ││
│ │ ││
│ ┌─────────────────┴─────────────────┐ ││
│ │ Match Found? │ ││
│ ▼ ▼ ││
│ ┌──────────────────────────────────┐ ┌─────────────────────────┐ ││
│ │F10 add_absolute_factor(flight_id,│ │ Skip absolute anchor │ ││
│ │ frame_id, gps, covariance, │ │ (VO-only frame) │ ││
│ │ is_user_anchor=False) │ └─────────────────────────┘ ││
│ │F06 update_heading() │ ││
│ └────────────┬─────────────────────┘ ││
│ │ ││
│ └─────────────────────┬───────────────────────────────────┘│
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ F10 optimize_chunk(flight_id, chunk_id, iterations) │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ F13 enu_to_gps() → Convert ENU pose to GPS │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ F14 update_frame_result() + publish_waypoint_update() │ │
│ │ └─ F15 send_frame_result() → SSE "frame_processed" │ │
│ │ └─ F03 save_frame_result() │ │
│ └─────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
```
**Performance**: < 5 seconds per frame
---
## Flow 5: First Frame / Sharp Turn (Rotation Sweep)
**Purpose**: Establish UAV heading when unknown or after sharp turn.
**Trigger**: `requires_rotation_sweep()` returns True
**Sequence**:
```
┌───────────────────────────────────────────────────────────────────────────┐
│ F06 Image Rotation Manager │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ try_rotation_steps(image, satellite_tile, tile_bounds) │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ │ │
│ ┌───────────────────────┴────────────────────────────┐ │
│ │ For angle in [0°, 30°, 60°, ... 330°]: │ │
│ │ │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ H07 rotate_image(image, angle) │ │ │
│ │ └───────────────────┬─────────────────┘ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ F09 align_to_satellite(rotated, │ │ │
│ │ │ satellite_tile, tile_bounds) │ │ │
│ │ └───────────────────┬─────────────────┘ │ │
│ │ │ │ │
│ │ ┌──────────────┴──────────────┐ │ │
│ │ │ Match Found? │ │ │
│ │ ▼ ▼ │ │
│ │ ┌───────────────┐ ┌───────────────┐ │ │
│ │ │ Calculate │ │ Try next │ │ │
│ │ │ precise angle │ │ rotation │ │ │
│ │ └───────┬───────┘ └───────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ F06 update_heading() → returns │ │ │
│ │ │ F02.2 calls F03 save_heading() │ │ │
│ │ └─────────────────────────────────────┘ │ │
│ │ │ │
│ └────────────────────────────────────────────────────┘ │
│ │ │
│ ┌────────────┴────────────┐ │
│ │ Return RotationResult │ │
│ │ or None │ │
│ └─────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────────┘
```
**Output**: RotationResult with precise heading angle
---
## Flow 6: Tracking Loss / Recovery (Progressive Search)
**Purpose**: Recover localization after tracking loss.
**Trigger**: VO inlier count < 20 or LiteSAM match fails
**Sequence**:
```
┌──────────────────────────────────────────────────────────────────────────┐
│ F02.2 calls F11 methods (direct returns, NO EVENTS) │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 1. F02.2 calls F11.start_search() → returns SearchSession │ │
│ │ F02.2 updates status to "recovering" │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 2. F02.2 calls F11.create_chunk_on_tracking_loss() via F12 │ │
│ │ └─ Proactive chunk creation (processing continues) │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 3. Single-image recovery attempt: │ │
│ │ ├─ F06 requires_rotation_sweep() → trigger sweep │ │
│ │ ├─ F08 retrieve_candidate_tiles() (DINOv2) │ │
│ │ └─ Progressive tile search (1→4→9→16→25): │ │
│ │ │ │
│ │ ┌───────────────────────────────────────────────────┐ │ │
│ │ │ For grid_size in [1, 4, 9, 16, 25]: │ │ │
│ │ │ ├─ F11.expand_search_radius() → tiles │ │ │
│ │ │ ├─ F02.2 fetches tiles via F04 │ │ │
│ │ │ ├─ F11.try_current_grid() → AlignmentResult │ │ │
│ │ │ │ │ │ │
│ │ │ └─ If match found: BREAK │ │ │
│ │ └───────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ │ │
│ ┌────────────────────┴────────────────────┐ │
│ │ Single-image match found? │ │
│ ▼ ▼ │
│ ┌─────────────────────┐ ┌────────────────────────────┐ │
│ │ F11.mark_found() │ │ Continue chunk building │ │
│ │ Resume normal flow │ │ → Flow 7 (Chunk Building) │ │
│ └─────────────────────┘ │ → Flow 8 (Chunk Matching) │ │
│ │ (Background) │ │
│ └────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ If all strategies exhausted: │ │
│ │ → Flow 10 (User Input Recovery) │ │
│ └─────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
```
---
## Flow 7: Chunk Building
**Purpose**: Build route chunks when tracking is lost, continuing VO within chunk.
**Sequence**:
```
┌───────────────────────────────────────────────────────────────────────────┐
│ F12 Route Chunk Manager │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ create_chunk(flight_id, start_frame_id) │ │
│ │ ├─ F10 create_chunk_subgraph(flight_id, chunk_id, │ │
│ │ │ start_frame_id) ← Factor graph subgraph │ │
│ │ ├─ Initialize chunk state (unanchored, active) │ │
│ │ └─ F03 save_chunk_state() │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ │ │
│ ┌───────────────────────┴────────────────────────────┐ │
│ │ For each frame in chunk: │ │
│ │ │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ F07 compute_relative_pose() │ │ │
│ │ └───────────────────┬─────────────────┘ │ │
│ │ ▼ │ │
│ │ ┌──────────────────────────────────────┐ │ │
│ │ │ F12 add_frame_to_chunk() │ │ │
│ │ │ └─ F10 add_relative_factor_to_chunk│ │ │
│ │ │ (flight_id, chunk_id, frame_i, │ │ │
│ │ │ frame_j, relative_pose, cov) │ │ │
│ │ └───────────────────┬──────────────────┘ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ F10 optimize_chunk(flight_id, │ │ │
│ │ │ chunk_id, iterations) (local) │ │ │
│ │ └─────────────────────────────────────┘ │ │
│ │ │ │
│ └────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ is_chunk_ready_for_matching()? │ │
│ │ ├─ Min 5 frames │ │
│ │ ├─ Max 20 frames │ │
│ │ └─ Internal consistency (good VO inlier counts) │ │
│ └─────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────────┘
```
---
## Flow 8: Background Chunk Matching
**Purpose**: Asynchronously match unanchored chunks to satellite data.
**Trigger**: Background task (every 5 seconds)
**Sequence**:
```
┌──────────────────────────────────────────────────────────────────────────┐
│ F11 process_unanchored_chunks() (Background Task) │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ while flight_active: │ │
│ │ ├─ unanchored = F12 get_chunks_for_matching() │ │
│ │ │ │ │
│ │ └─ for chunk in unanchored: │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ if F12 is_chunk_ready_for_matching(chunk_id): │ │ │
│ │ │ ├─ F12 mark_chunk_matching(chunk_id) │ │ │
│ │ │ │ │ │ │
│ │ │ ├─ STEP 1: Chunk Semantic Matching │ │ │
│ │ │ │ ├─ F12 get_chunk_images() │ │ │
│ │ │ │ └─ F08 retrieve_candidate_tiles_for_chunk() │ │ │
│ │ │ │ └─ F08 compute_chunk_descriptor() │ │ │
│ │ │ │ └─ H04 Faiss search() │ │ │
│ │ │ │ │ │ │
│ │ │ ├─ STEP 2: Chunk LiteSAM Matching (with rotation) │ │ │
│ │ │ │ ├─ For each candidate tile: │ │ │
│ │ │ │ │ ├─ F04 get_tile + compute_tile_bounds() │ │ │
│ │ │ │ │ ├─ F06 try_chunk_rotation_steps() │ │ │
│ │ │ │ │ │ └─ F09 align_chunk_to_satellite() │ │ │
│ │ │ │ │ └─ If match: BREAK │ │ │
│ │ │ │ │ │ │
│ │ │ └─ If match found: │ │ │
│ │ │ └─ → Flow 9 (Chunk Merging) │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ sleep(5 seconds) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
```
---
## Flow 9: Chunk Merging
**Purpose**: Merge anchored chunk into main trajectory.
**Trigger**: Successful chunk matching
**Sequence**:
```
┌───────────────────────────────────────────────────────────────────────-──┐
│ F02.2 orchestrates via F11.merge_chunk_to_trajectory() │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 1. Get chunk frames: F12 get_chunk_frames(new_chunk_id) │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 2. Anchor chunk: F12 mark_chunk_anchored(new_chunk_id, gps) │ │
│ │ └─ F10 add_chunk_anchor(flight_id, new_chunk_id, frame_id│ │
│ │ gps, covariance) │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 3. Determine main chunk (predecessor or "main") │ │
│ │ └─ Returns main_chunk_id (predecessor or "main") │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 4. Merge: F12 merge_chunks(main_chunk_id,new_chunk_id,Sim3) │ │
│ │ ├─ F10 merge_chunk_subgraphs(flight_id, new_chunk_id, │ │
│ │ │ main_chunk_id, transform) ← Apply Sim(3) │ │
│ │ ├─ F12 deactivate_chunk(new_chunk_id) │ │
│ │ └─ F03 save_chunk_state() │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 5. Optimize global: F10 optimize_global(flight_id, │ │
│ │ iterations) │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 6. F11 returns True → F02.2 coordinates result updates: │ │
│ │ ├─ F02.2 calls F10 get_trajectory(flight_id) → ENU poses │ │
│ │ ├─ F02.2 calls F13 enu_to_gps() for each frame │ │
│ │ ├─ F02.2 constructs List[RefinedFrameResult] │ │
│ │ └─ F02.2 calls F14.update_results_after_chunk_merge() │ │
│ │ ├─ F03 save_frame_result() + update_waypoint() │ │
│ │ └─ F15 send_refinement() → SSE "frame_refined" × N │ │
│ └─────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
```
**Sim(3) Transform**: Translation + Rotation + Scale alignment between chunks
**Note**: F14 does NOT call F10/F13. F02.2 performs coordinate conversion and passes GPS results.
---
## Flow 10: User Input Recovery
**Purpose**: Request human assistance when all automatic recovery fails.
**Trigger**: Progressive search exhausted (25 tiles), chunk matching failed
**Sequence**:
```
┌──────────────────────────────────────────────────────────────────────────┐
│ F02.2 orchestrates via F11.create_user_input_request() │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 1. F11.create_user_input_request() → returns UserInputRequest│ │
│ │ └─ Gets UAV image, top-5 candidates from F08 │ │
│ │ └─ Returns request object (does NOT call F15) │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 2. F02.2 receives UserInputRequest │ │
│ │ ├─ F02.2 calls F15.send_user_input_request() │ │
│ │ │ → SSE "user_input_needed" │ │
│ │ └─ F02.2 updates status to "BLOCKED" │ │
│ └─────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
▼ Client receives SSE event
┌───────────────────────────────────────────────────────────────────────────┐
│ Client UI │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Display UAV image + candidate satellite tiles │ │
│ │ User clicks corresponding point on satellite tile │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ POST /flights/{flightId}/user-fix │ │
│ │ body: { frame_id, uav_pixel, satellite_gps } │ │
│ └─────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ F11 apply_user_anchor() │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 1. Validate anchor data │ │
│ │ 2. F10 add_absolute_factor(is_user_anchor=True) ← σ=5m │ │
│ │ 3. F10 optimize() │ │
│ │ 4. EMIT UserFixApplied event │ │
│ │ └─ F02.2 updates status to "PROCESSING" │ │
│ │ 5. Resume processing loop │ │
│ └─────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
```
---
## Flow 11: Asynchronous Refinement
**Purpose**: Back-propagate optimization improvements to previous frames.
**Trigger**: New absolute GPS factor added, chunk merged
**Sequence**:
```
┌─────────────────────────────────────────────────────────────-────────────┐
│ F10 Background Optimization │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 1. New absolute factor triggers batch optimization │ │
│ │ 2. F10 optimize(iterations=50-100) │ │
│ │ └─ Levenberg-Marquardt with robust kernels │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 3. Identify refined frames │ │
│ │ 4. F14 mark_refined(frame_ids) │ │
│ │ ├─ For each frame: │ │
│ │ │ ├─ F10 get_trajectory(flight_id) → ENU pose │ │
│ │ │ ├─ F13 enu_to_gps(flight_id, enu_pose) │ │
│ │ │ ├─ F03 save_frame_result(refined=True) │ │
│ │ │ └─ F03 update_waypoint() │ │
│ │ │ │ │
│ │ └─ F15 send_refinement() × N → SSE "frame_refined" × N │ │
│ └─────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
```
---
## Flow 12: Object to GPS Conversion
**Purpose**: Convert detected object pixel coordinates to GPS (external integration).
**Trigger**: `POST /flights/{flightId}/frames/{frameId}/object-to-gps`
**Sequence**:
```
┌──────────────────┐ POST object-to-gps ┌─────┐
│ External System │ ────────────────────►│ F01 │
│ (Azaion.Inference│ {pixel_x, pixel_y} └──┬──┘
└──────────────────┘ │
┌─────────────┐
│ F13 │ Coordinate Transformer
└──────┬──────┘
┌───────────────────┼───────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│F10 get_pose │ │F17 camera │ │ H01 Camera │
│ (frame_id) │ │ _params │ │ Model │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
└───────────────────┼───────────────────┘
┌─────────────┐
│ pixel_to_gps│
│ calculation │
└──────┬──────┘
┌───────────────────────────┐
│ Return ObjectGPSResponse │
│ { gps, accuracy_meters }│
└───────────────────────────┘
```
---
## Flow 13: Flight Completion
**Purpose**: Complete flight processing and clean up resources.
**Trigger**: All images processed successfully
**Sequence**:
```
┌──────────────────────────────────────────────────────────────────────────┐
│ F02.1 Flight Lifecycle Manager │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 1. All frames processed (Signal from F02.2) │ │
│ │ 2. Wait for pending chunk merges (if any) │ │
│ │ 3. F10 optimize_global(flight_id, iterations=100) │ │
│ │ ← Final optimization │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 4. F14 mark_refined(all_frames) │ │
│ │ └─ Final refinement updates │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 5. F03 save_flight_state(status="completed") │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 6. F15 send event → SSE "flight_completed" │ │
│ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 7. Cleanup: │ │
│ │ ├─ Stop background chunk matching task │ │
│ │ ├─ F04 clear_flight_cache(flight_id) (optional) │ │
│ │ └─ Release flight resources │ │
│ └─────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
```
---
## Flow 14: System Shutdown
**Purpose**: Gracefully shutdown all components.
**Sequence**:
```
┌─────────────────┐
│ Shutdown Signal │
└────────┬────────┘
┌─────────────────┐
│ F01 Stop │ ← Stop accepting requests
│ accepting │
└────────┬────────┘
┌─────────────────┐
│ F02.1 Complete/ │ ← Complete or cancel active flights
│ Cancel │
└────────┬────────┘
┌─────────────────┐
│ F11 Stop │ ← Stop background chunk matching
│ background │
└────────┬────────┘
┌─────────────────┐
│ F12 Save chunk │ ← Save chunk state for recovery
│ state │
└────────┬────────┘
┌─────────────────┐
│ F16 Unload │ ← Unload ML models, free GPU memory
│ models │
└────────┬────────┘
┌─────────────────┐
│ F03 Close │ ← Close database connections
│ connections │
└────────┬────────┘
┌─────────────────┐
│ F04 Flush cache │ ← Flush satellite tile cache
└────────┬────────┘
┌─────────────────┐
│ Shutdown │
│ Complete │
└─────────────────┘
```
---
## Component Interaction Summary
### Data Flow Direction
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ EXTERNAL │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Client │ │ Satellite │ │ External │ │
│ │ (UI) │ │ Provider │ │ Detector │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
└─────────┼───────────────────┼───────────────────┼───────────────────────────┘
│ REST/SSE │ HTTP │ REST
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ API LAYER │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ F01 Flight API │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ ORCHESTRATION LAYER │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ F02.1 Flight Lifecycle Manager │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ (Spawns/Manages) │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ F02.2 Flight Processing Engine │ │
│ │ (Processing loop, State machine, Recovery orchestration) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
├─────────────────────────────────────────────────────────────┐
▼ ▼
┌─────────────────────────────────────────────┐ ┌────────────────────────────┐
│ DATA MANAGEMENT LAYER │ │ RECOVERY LAYER │
│ ┌─────────────┐ ┌─────────────┐ │ │ ┌───────────────────────┐ │
│ │ F04 │ │ F05 │ │ │ │ F11 │ │
│ │ Satellite │ │ Image │ │ │ │ Failure Recovery │ │
│ │ Data │ │ Input │ │ │ │ (Logic & Strategies) │ │
│ └─────────────┘ └─────────────┘ │ │ └───────────────────────┘ │
│ │ │ │ │
│ ┌─────────────┐ ┌─────────────┐ │ │ ▼ │
│ │ F12 │ │ F03 │ │ │ ┌───────────────────────┐ │
│ │Route Chunk │ │ Flight │ │ │ │ F12 │ │
│ │ Manager │ │ Database │ │ │ │ (Chunk state source) │ │
│ └─────────────┘ └─────────────┘ │ │ └───────────────────────┘ │
└─────────────────────────────────────────────┘ └────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ VISUAL PROCESSING LAYER │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌──────────────┐ │
│ │ F06 │ │ F07 │ │ F08 │ │ F09 │ │
│ │ Rotation │ │ Sequential VO │ │ Global │ │ Metric │ │
│ │ Manager │ │(SuperPoint+ │ │ Place │ │ Refinement │ │
│ │ (30° sweeps) │ │ LightGlue) │ │ Recognition │ │ (LiteSAM) │ │
│ │ │ │ │ │ (DINOv2) │ │ │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ STATE ESTIMATION LAYER │
│ ┌──────────────────────────────────────────────────────────────────k──┐ │
│ │ F10 Factor Graph Optimizer │ │
│ │ (GTSAM, iSAM2, Robust kernels, Chunk subgraphs, Sim(3) merging) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ OUTPUT LAYER │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ F13 │ │ F14 │ │ F15 │ │
│ │ Coordinate │ │ Result │ │ SSE │ │
│ │ Transformer │ │ Manager │ │ Streamer │ │
│ │ (ENU↔GPS↔Px) │ │ │ │ │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────-┐
│ INFRASTRUCTURE LAYER │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────────────────────────-┐│
│ │ F16 │ │ F17 │ │ HELPERS ││
│ │ Model │ │Configuration │ │ H01-H08 (Camera, GSD, Kernels, ││
│ │ Manager │ │ Manager │ │ Faiss, Monitor, Mercator, etc) ││
│ └───────────────┘ └───────────────┘ └────────────────────────────────────┘│
└──────────────────────────────────────────────────────────────────────────────┘
```
---
## Status-Based Recovery Communication
F11 Failure Recovery Coordinator uses **Direct Call Returns** to communicate with F02.2 Flight Processing Engine. Events have been removed to eliminate circular dependencies and clarify control flow.
| Action | Caller | Called | Return/Outcome |
|--------|--------|--------|----------------|
| `start_search` | F02.2 | F11 | `SearchSession` object |
| `try_current_grid` | F02.2 | F11 | `AlignmentResult` (or None) |
| `create_user_input_request` | F02.2 | F11 | `UserInputRequest` object |
| `apply_user_anchor` | F02.2 | F11 | Success boolean |
F02.2 is responsible for updating the flight status (e.g., "recovering", "blocked", "processing") based on these return values.
---
## SSE Events to Client
| Event | Trigger | Data |
|-------|---------|------|
| `frame_processed` | Frame completed | frame_id, gps, altitude, heading, confidence |
| `frame_refined` | Trajectory refined | frame_id, updated gps, refined=true |
| `search_expanded` | Progressive search | frame_id, grid_size, status |
| `user_input_needed` | Recovery exhausted | request_id, frame_id, candidate_tiles |
| `processing_blocked` | Status change | reason, frame_id |
| `flight_completed` | Flight done | statistics |
---
## Performance Targets
| Flow | Target |
|------|--------|
| System Initialization | < 30 seconds |
| Flight Creation | < 500ms response |
| Image Batch Upload | < 2 seconds (50 images) |
| Per-Frame Processing | < 5 seconds |
| Rotation Sweep (12 rotations) | < 1.2 seconds |
| Progressive Search (25 tiles) | < 1.5 seconds |
| Chunk Matching | < 3 seconds (background) |
| SSE Event Latency | < 500ms |
---
## Accuracy Targets
| Metric | Target |
|--------|--------|
| GPS Accuracy | 60% < 20m, 80% < 50m |
| Mean Reprojection Error | < 1.0 pixels |
| Place Recognition Recall@5 | > 85% |
| LiteSAM Success Rate | > 95% (when rotation correct) |