mirror of
https://github.com/azaion/gps-denied-desktop.git
synced 2026-04-22 05:26:36 +00:00
put rest and sse to acceptance criteria. revise components. add system flows diagram
This commit is contained in:
@@ -18,4 +18,4 @@
|
||||
|
||||
- Mean Reprojection Error (MRE) < 1.0 pixels. The distance, in pixels, between the original pixel location of the object and the re-projected pixel location.
|
||||
|
||||
- The whole system should work as a background service. The interaction should be done by zeromq. Sevice should be up and running and awaiting for the initial input message. On the input message processing should started, and immediately after the first results system should provide them to the client
|
||||
- The whole system should work as a background service exposed via REST API with Server-Sent Events (SSE) for real-time streaming. Service should be up and running and awaiting for the initial request. On the request processing should start, and immediately after the first results system should provide them to the client via SSE stream
|
||||
@@ -43,6 +43,10 @@ class IFlightAPI(ABC):
|
||||
@abstractmethod
|
||||
def create_sse_stream(self, flight_id: str) -> SSEStream:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def convert_object_to_gps(self, flight_id: str, frame_id: int, pixel: Tuple[float, float]) -> ObjectGPSResponse:
|
||||
pass
|
||||
```
|
||||
|
||||
## Component Description
|
||||
@@ -367,6 +371,50 @@ UserFixResponse:
|
||||
|
||||
---
|
||||
|
||||
### `convert_object_to_gps(flight_id: str, frame_id: int, pixel: Tuple[float, float]) -> ObjectGPSResponse`
|
||||
|
||||
**REST Endpoint**: `POST /flights/{flightId}/frames/{frameId}/object-to-gps`
|
||||
|
||||
**Description**: Converts object pixel coordinates to GPS. Used by external object detection systems (e.g., Azaion.Inference) to get GPS coordinates for detected objects.
|
||||
|
||||
**Called By**:
|
||||
- External object detection systems (Azaion.Inference)
|
||||
- Any system needing pixel-to-GPS conversion for a specific frame
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
ObjectToGPSRequest:
|
||||
pixel_x: float # X coordinate in image
|
||||
pixel_y: float # Y coordinate in image
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
ObjectGPSResponse:
|
||||
gps: GPSPoint
|
||||
accuracy_meters: float # Estimated accuracy
|
||||
frame_id: int
|
||||
pixel: Tuple[float, float]
|
||||
```
|
||||
|
||||
**Processing Flow**:
|
||||
1. Validate flight_id and frame_id exist
|
||||
2. Validate frame has been processed (has pose in Factor Graph)
|
||||
3. Call F13.image_object_to_gps(pixel, frame_id)
|
||||
4. Return GPS with accuracy estimate
|
||||
|
||||
**Error Conditions**:
|
||||
- `400 Bad Request`: Invalid pixel coordinates
|
||||
- `404 Not Found`: flight_id or frame_id not found
|
||||
- `409 Conflict`: Frame not yet processed (no pose available)
|
||||
|
||||
**Test Cases**:
|
||||
1. **Valid conversion**: Object at (1024, 768) → returns GPS
|
||||
2. **Unprocessed frame**: Frame not in Factor Graph → returns 409
|
||||
3. **Invalid pixel**: Negative coordinates → returns 400
|
||||
|
||||
---
|
||||
|
||||
### `get_flight_status(flight_id: str) -> FlightStatusResponse`
|
||||
|
||||
**REST Endpoint**: `GET /flights/{flightId}/status`
|
||||
|
||||
@@ -113,6 +113,31 @@ class IFlightProcessor(ABC):
|
||||
- System initialization and resource management
|
||||
- Flight state machine management
|
||||
- **Chunk-aware frame processing (Atlas multi-map architecture)**
|
||||
- **Background task management for each flight**
|
||||
- **Event subscription for F11 recovery events**
|
||||
|
||||
### Event-Based Communication
|
||||
|
||||
F02 subscribes to events from F11 Failure Recovery Coordinator instead of F11 directly calling F02's status update methods. This decouples recovery logic from flight state management.
|
||||
|
||||
**Events Subscribed (from F11)**:
|
||||
- `RecoveryStarted`: Update flight status to "recovering"
|
||||
- `RecoverySucceeded`: Update flight status to "processing", resume processing loop
|
||||
- `RecoveryFailed`: Update flight status to "blocked", blocked=True
|
||||
- `UserInputNeeded`: Update flight status to "blocked", blocked=True, await user fix
|
||||
- `UserFixApplied`: Update flight status to "processing", resume processing loop
|
||||
- `ChunkCreated`: Log chunk creation, update internal tracking
|
||||
- `ChunkAnchored`: Log chunk anchor, update statistics
|
||||
- `ChunkMerged`: Trigger result updates via F14
|
||||
|
||||
### Background Task Management
|
||||
|
||||
F02 is responsible for managing background tasks per flight:
|
||||
- **Chunk matching task**: Background task for matching unanchored chunks (delegated to F11)
|
||||
- **Asynchronous refinement task**: Background optimization and result publishing (via F10, F14)
|
||||
- **Task lifecycle**: Tasks created on flight start, cancelled on flight completion/deletion
|
||||
|
||||
Background tasks are coordinated via Python `asyncio` or `ThreadPoolExecutor`, with F02 as the owner. F11 executes chunk matching logic but F02 schedules and monitors the tasks.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -130,6 +130,21 @@ class IFlightDatabase(ABC):
|
||||
- Image metadata storage
|
||||
- Query optimization for large datasets
|
||||
|
||||
### Design Decision: Denormalization
|
||||
|
||||
The schema uses strategic denormalization to optimize for the most common access patterns:
|
||||
|
||||
**Denormalized Fields**:
|
||||
- `frame_results` stores `gps_lat`, `gps_lon` directly (not as foreign key to waypoints)
|
||||
- `flight_state` duplicates `frames_processed` (could be computed from frame_results)
|
||||
- `chunks.frames` stored as JSONB array (not normalized into separate frame_chunk mapping table)
|
||||
|
||||
**Rationale**:
|
||||
- Read-heavy workload: Frame results are read 100x more than written
|
||||
- Avoids JOINs in critical path (per-frame processing)
|
||||
- Simplifies chunk lifecycle (all chunk data in single row)
|
||||
- Acceptable trade-off: Slightly increased storage, significantly faster reads
|
||||
|
||||
---
|
||||
|
||||
## Flight Operations
|
||||
|
||||
@@ -25,11 +25,11 @@ class ISatelliteDataManager(ABC):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def cache_tile(self, tile_coords: TileCoords, tile_data: np.ndarray) -> bool:
|
||||
def cache_tile(self, flight_id: str, tile_coords: TileCoords, tile_data: np.ndarray) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_cached_tile(self, tile_coords: TileCoords) -> Optional[np.ndarray]:
|
||||
def get_cached_tile(self, flight_id: str, tile_coords: TileCoords) -> Optional[np.ndarray]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
|
||||
@@ -350,7 +350,7 @@ ProcessingStatus:
|
||||
```
|
||||
|
||||
**Processing Flow**:
|
||||
1. Get flight state via F02 Flight Processor.get_flight_state(flight_id)
|
||||
1. Get flight state via F03 Flight Database.get_flight(flight_id).status
|
||||
2. Combine with internal queue status
|
||||
3. Return ProcessingStatus
|
||||
|
||||
@@ -402,8 +402,7 @@ ProcessingStatus:
|
||||
|
||||
### Internal Components
|
||||
- **H08 Batch Validator**: For validation logic
|
||||
- **F03 Flight Database**: For metadata persistence
|
||||
- **F02 Flight Processor**: For flight state information
|
||||
- **F03 Flight Database**: For metadata persistence and flight state information
|
||||
|
||||
### External Dependencies
|
||||
- **opencv-python**: Image I/O
|
||||
|
||||
@@ -117,10 +117,17 @@ flight_id: str
|
||||
frame_id: int # Frame identifier for heading persistence
|
||||
image: np.ndarray # UAV image
|
||||
satellite_tile: np.ndarray # Satellite reference tile
|
||||
tile_bounds: TileBounds # GPS bounds and GSD of satellite tile (for F09)
|
||||
tile_bounds: TileBounds # GPS bounds and GSD of satellite tile (passed to F09)
|
||||
timestamp: datetime # Timestamp for heading persistence
|
||||
```
|
||||
|
||||
**About tile_bounds**: `TileBounds` contains the GPS bounding box of the satellite tile:
|
||||
- `nw`, `ne`, `sw`, `se`: GPS coordinates of tile corners
|
||||
- `center`: GPS coordinate of tile center
|
||||
- `gsd`: Ground Sampling Distance (meters/pixel)
|
||||
|
||||
The caller (F02 Flight Processor) obtains tile_bounds by calling `F04.compute_tile_bounds(tile_coords)` before calling this method. F06 passes tile_bounds to F09.align_to_satellite() which uses it to convert pixel coordinates to GPS.
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
RotationResult:
|
||||
|
||||
@@ -25,7 +25,7 @@ class IGlobalPlaceRecognition(ABC):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def initialize_database(self, satellite_tiles: List[SatelliteTile]) -> bool:
|
||||
def load_index(self, flight_id: str, index_path: str) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
@@ -45,7 +45,7 @@ class IGlobalPlaceRecognition(ABC):
|
||||
- Compute image descriptors robust to season/appearance changes
|
||||
- Query Faiss index of satellite tile descriptors
|
||||
- Return top-k candidate tile regions for progressive refinement
|
||||
- Initialize satellite descriptor database during system startup
|
||||
- **Load pre-built satellite descriptor index** (index is built by satellite provider, NOT by F08)
|
||||
- **Chunk semantic matching (aggregate DINOv2 features)**
|
||||
- **Chunk descriptor computation for robust matching**
|
||||
|
||||
@@ -203,54 +203,48 @@ List[TileCandidate] # Re-ranked list
|
||||
|
||||
---
|
||||
|
||||
### `initialize_database(satellite_tiles: List[SatelliteTile]) -> bool`
|
||||
### `load_index(flight_id: str, index_path: str) -> bool`
|
||||
|
||||
**Description**: Loads pre-built satellite descriptor database. **Note**: Semantic index building (DINOv2 descriptors) is performed by the satellite provider service, not during system startup.
|
||||
**Description**: Loads pre-built satellite descriptor database from file. **Note**: The semantic index (DINOv2 descriptors + Faiss index) MUST be provided by the satellite data provider. F08 does NOT build the index - it only loads it.
|
||||
|
||||
**Called By**:
|
||||
- F02 Flight Processor (during system initialization)
|
||||
- F02 Flight Processor (during flight initialization, index_path from F04 Satellite Data Manager)
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
List[SatelliteTile]:
|
||||
tile_id: str
|
||||
image: np.ndarray # Optional - only if building index locally
|
||||
gps_center: GPSPoint
|
||||
bounds: TileBounds
|
||||
descriptor: Optional[np.ndarray] # Pre-computed descriptor from provider
|
||||
index_path: str # Path to pre-built Faiss index file from satellite provider
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
bool: True if database initialized successfully
|
||||
bool: True if database loaded successfully
|
||||
```
|
||||
|
||||
**Processing Flow**:
|
||||
1. **Load pre-built index**: Satellite provider provides pre-computed DINOv2 descriptors
|
||||
2. If descriptors provided:
|
||||
- Load descriptors directly
|
||||
- Build Faiss index using H04 Faiss Index Manager
|
||||
3. If descriptors not provided (fallback):
|
||||
- For each satellite tile:
|
||||
- compute_location_descriptor(tile.image) → descriptor
|
||||
- Store descriptor with tile metadata
|
||||
- Build Faiss index
|
||||
4. Persist index to disk for fast startup
|
||||
1. Load pre-built Faiss index from index_path
|
||||
2. Load tile metadata (tile_id → gps_center, bounds mapping)
|
||||
3. Validate index integrity (check descriptor dimensions, tile count)
|
||||
4. Return True if loaded successfully
|
||||
|
||||
**Satellite Provider Integration**:
|
||||
- **Primary**: Satellite provider builds semantic index offline
|
||||
- Provider exposes index via API or file download
|
||||
- F08 loads pre-built index at startup
|
||||
- **Fallback**: F08 can build index locally if provider doesn't supply it
|
||||
**Satellite Provider Responsibility**:
|
||||
- Satellite provider builds the semantic index offline using DINOv2 + VLAD
|
||||
- Provider delivers index file along with satellite tiles
|
||||
- Index format: Faiss IVF or HNSW index + tile metadata JSON
|
||||
- Provider is responsible for index updates when satellite data changes
|
||||
|
||||
**Error Conditions**:
|
||||
- Raises `IndexNotFoundError`: Index file not found
|
||||
- Raises `IndexCorruptedError`: Index file corrupted or invalid format
|
||||
- Raises `MetadataMismatchError`: Metadata doesn't match index
|
||||
|
||||
**Performance**:
|
||||
- **Load pre-built index**: <10 seconds (fast startup)
|
||||
- **Build index locally**: ~10-30 minutes for 10,000 tiles (fallback only)
|
||||
- **Load time**: <10 seconds for 10,000+ tiles
|
||||
|
||||
**Test Cases**:
|
||||
1. **Load pre-built index**: Completes successfully, fast startup
|
||||
2. **Fallback local building**: Builds index if provider doesn't supply it
|
||||
3. **Index query**: Works correctly after loading
|
||||
1. **Load valid index**: Completes successfully, index operational
|
||||
2. **Index not found**: Raises IndexNotFoundError
|
||||
3. **Corrupted index**: Raises IndexCorruptedError
|
||||
4. **Index query after load**: Works correctly
|
||||
|
||||
---
|
||||
|
||||
@@ -351,10 +345,10 @@ np.ndarray: Aggregated descriptor vector (4096-dim or 8192-dim)
|
||||
2. UAV images from autumn
|
||||
3. retrieve_candidate_tiles() → correct match despite appearance change
|
||||
|
||||
### Test 3: Database Initialization
|
||||
1. Prepare 500 satellite tiles
|
||||
2. initialize_database(tiles)
|
||||
3. Verify Faiss index built
|
||||
### Test 3: Index Loading
|
||||
1. Prepare pre-built index file from satellite provider
|
||||
2. load_index(index_path)
|
||||
3. Verify Faiss index loaded correctly
|
||||
4. Query with test image → returns matches
|
||||
|
||||
### Test 4: Chunk Semantic Matching
|
||||
|
||||
@@ -78,10 +78,28 @@ class IFactorGraphOptimizer(ABC):
|
||||
- Scale resolution through altitude priors and absolute GPS
|
||||
- Trajectory smoothing and global consistency
|
||||
- Back-propagation of refinements to previous frames
|
||||
- **Native multi-chunk/multi-map support (Atlas architecture)**
|
||||
- **Chunk lifecycle management (creation, optimization, merging)**
|
||||
- **Low-level factor graph chunk operations** (subgraph creation, factor addition, optimization)
|
||||
- **Sim(3) transformation for chunk merging**
|
||||
|
||||
### Chunk Responsibility Clarification
|
||||
|
||||
**F10 provides low-level factor graph operations only**:
|
||||
- `create_new_chunk()`: Creates subgraph in factor graph
|
||||
- `add_relative_factor_to_chunk()`: Adds factors to chunk's subgraph
|
||||
- `add_chunk_anchor()`: Adds GPS anchor to chunk
|
||||
- `merge_chunks()`: Applies Sim(3) transform and merges subgraphs
|
||||
- `optimize_chunk()`, `optimize_global()`: Runs optimization
|
||||
|
||||
**F12 is the source of truth for chunk state** (see F12 spec):
|
||||
- Chunk lifecycle management (active, anchored, merged status)
|
||||
- Chunk readiness determination
|
||||
- High-level chunk queries
|
||||
|
||||
**F11 coordinates recovery** (see F11 spec):
|
||||
- Triggers chunk creation via F12
|
||||
- Coordinates matching workflows
|
||||
- Emits chunk-related events
|
||||
|
||||
### Scope
|
||||
- Non-linear least squares optimization
|
||||
- Factor graph representation of SLAM problem
|
||||
@@ -92,6 +110,20 @@ class IFactorGraphOptimizer(ABC):
|
||||
- **Chunk-level optimization and global merging**
|
||||
- **Sim(3) similarity transformation for chunk alignment**
|
||||
|
||||
### Design Pattern: Composition Over Complex Interface
|
||||
|
||||
F10 uses **composition** to keep the interface manageable. Rather than exposing 20+ methods in a monolithic interface, complex operations are composed from simpler primitives:
|
||||
|
||||
**Primitive Operations**:
|
||||
- `add_relative_factor()`, `add_absolute_factor()`, `add_altitude_prior()` - Factor management
|
||||
- `optimize()`, `get_trajectory()`, `get_marginal_covariance()` - Core optimization
|
||||
|
||||
**Chunk Operations** (composed from primitives):
|
||||
- `create_new_chunk()`, `add_relative_factor_to_chunk()`, `add_chunk_anchor()` - Chunk factor management
|
||||
- `merge_chunks()`, `optimize_chunk()`, `optimize_global()` - Chunk optimization
|
||||
|
||||
**Callers compose these primitives** for complex workflows (e.g., F11 composes anchor + merge + optimize_global).
|
||||
|
||||
## API Methods
|
||||
|
||||
### `add_relative_factor(frame_i: int, frame_j: int, relative_pose: RelativePose, covariance: np.ndarray) -> bool`
|
||||
@@ -123,12 +155,17 @@ F07 returns unit translation vectors due to monocular scale ambiguity. F10 resol
|
||||
**Explicit Flow**:
|
||||
```python
|
||||
# In add_relative_factor():
|
||||
# altitude comes from F05 Image Input Pipeline (extracted from EXIF metadata)
|
||||
# focal_length, sensor_width from F17 Configuration Manager
|
||||
gsd = H02.compute_gsd(altitude, focal_length, sensor_width, image_width)
|
||||
expected_displacement = frame_spacing * gsd # ~100m
|
||||
expected_displacement = frame_spacing * gsd # ~100m typical at 300m altitude
|
||||
scaled_translation = relative_pose.translation * expected_displacement
|
||||
# Add scaled_translation to factor graph
|
||||
```
|
||||
|
||||
**Note**: Altitude is passed through the processing chain:
|
||||
- F05 extracts altitude from EXIF → F02 includes in FrameData → F10 receives with add_relative_factor()
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
bool: True if factor added successfully
|
||||
|
||||
+62
-14
@@ -57,7 +57,7 @@ class IFailureRecoveryCoordinator(ABC):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def merge_chunk_to_trajectory(self, chunk_id: str, alignment_result: ChunkAlignmentResult) -> bool:
|
||||
def merge_chunk_to_trajectory(self, flight_id: str, chunk_id: str, alignment_result: ChunkAlignmentResult) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
@@ -72,14 +72,45 @@ class IFailureRecoveryCoordinator(ABC):
|
||||
- Detect tracking loss and trigger recovery
|
||||
- Coordinate progressive tile search (1→4→9→16→25)
|
||||
- Handle human-in-the-loop when all strategies exhausted
|
||||
- Block flight processing when awaiting user input
|
||||
- **Emit recovery events** (RecoveryStarted, RecoveryFailed, RecoverySucceeded, UserInputNeeded)
|
||||
- Apply user-provided anchors to Factor Graph
|
||||
- **Proactive chunk creation on tracking loss**
|
||||
- **Chunk semantic matching coordination**
|
||||
- **Proactive chunk creation on tracking loss** (via F12)
|
||||
- **Chunk LiteSAM matching with rotation sweeps**
|
||||
- **Chunk merging orchestration**
|
||||
- **Background chunk matching processing**
|
||||
|
||||
### Chunk Responsibility Clarification
|
||||
|
||||
**F11 coordinates chunk-based recovery workflow only**:
|
||||
- Detects when to create chunks (on tracking loss)
|
||||
- Calls F12 for ALL chunk operations (F11 NEVER directly calls F10 chunk methods)
|
||||
- Coordinates matching workflows
|
||||
- Emits chunk-related events (ChunkCreated, ChunkAnchored, ChunkMerged)
|
||||
|
||||
**F12 is the source of truth for chunk state** (see F12 spec)
|
||||
|
||||
**F10 provides low-level factor graph operations** (see F10 spec)
|
||||
|
||||
### Event-Based Communication
|
||||
|
||||
F11 emits events instead of directly calling F02's status update methods. This decouples recovery logic from flight state management.
|
||||
|
||||
**Events Emitted**:
|
||||
- `RecoveryStarted`: When tracking loss detected and recovery begins
|
||||
- `RecoverySucceeded`: When recovery finds a match (single-image or chunk)
|
||||
- `RecoveryFailed`: When all recovery strategies exhausted
|
||||
- `UserInputNeeded`: When user input is required
|
||||
- `UserFixApplied`: When user-provided anchor successfully applied
|
||||
- `ChunkCreated`: When new chunk created on tracking loss
|
||||
- `ChunkAnchored`: When chunk successfully matched and anchored
|
||||
- `ChunkMerged`: When chunk merged into main trajectory (includes flight_id, chunk_id, merged_frames)
|
||||
|
||||
**Event Listeners** (F02 Flight Processor subscribes to these):
|
||||
- On `RecoveryStarted`: Update status to "recovering"
|
||||
- On `RecoveryFailed`: Update status to "blocked"
|
||||
- On `RecoverySucceeded`: Update status to "processing"
|
||||
- On `UserInputNeeded`: Update status to "blocked", blocked=True
|
||||
|
||||
### Scope
|
||||
- Confidence monitoring
|
||||
- Progressive search coordination
|
||||
@@ -298,10 +329,10 @@ UserInputRequest:
|
||||
|
||||
**Processing Flow**:
|
||||
1. Get UAV image for frame_id
|
||||
2. Get top-5 candidates from G08
|
||||
2. Get top-5 candidates from F08
|
||||
3. Create request
|
||||
4. Send via F14 SSE → "user_input_needed" event
|
||||
5. Update F02 flight_status("BLOCKED")
|
||||
4. Send via F15 SSE → "user_input_needed" event
|
||||
5. Emit `UserInputNeeded` event (F02 subscribes and updates status to "BLOCKED")
|
||||
|
||||
**Test Cases**:
|
||||
1. All search failed → creates request
|
||||
@@ -330,7 +361,7 @@ anchor: UserAnchor:
|
||||
1. Validate anchor data
|
||||
2. Call F10.add_absolute_factor(frame_id, gps, is_user_anchor=True)
|
||||
3. F10.optimize() → refines trajectory
|
||||
4. Update F02 flight_status("PROCESSING")
|
||||
4. Emit `UserFixApplied` event (F02 subscribes and updates status to "PROCESSING")
|
||||
5. Resume processing from next frame
|
||||
|
||||
**Test Cases**:
|
||||
@@ -482,15 +513,20 @@ bool: True if merge successful
|
||||
```
|
||||
|
||||
**Processing Flow**:
|
||||
1. Get chunk frames via F12.get_chunk_frames(chunk_id) → merged_frames (all frames in chunk that will be updated)
|
||||
1. Get chunk frames via F12.get_chunk_frames(chunk_id) → merged_frames
|
||||
2. Get chunk anchor frame (middle frame or best frame)
|
||||
3. Call F12.mark_chunk_anchored() with GPS (F12 coordinates with F10)
|
||||
4. Find target chunk (previous chunk or main trajectory)
|
||||
4. **Resolve target chunk**:
|
||||
- Query F12.get_merge_target(chunk_id) → returns target_chunk_id
|
||||
- Target selection logic (inside F12):
|
||||
- If chunk has temporal predecessor (previous chunk by frame_id order): merge to predecessor
|
||||
- If no predecessor: merge to main trajectory (chunk_id="main")
|
||||
- F12 maintains chunk ordering based on first frame_id in each chunk
|
||||
5. Call F12.merge_chunks(chunk_id, target_chunk_id, transform) (F12 coordinates with F10)
|
||||
6. F12 handles chunk state updates (deactivation, status updates)
|
||||
7. F10 optimizes merged graph globally (via F12.merge_chunks())
|
||||
8. **Update results**: Call F14 Result Manager.update_results_after_chunk_merge(flight_id, merged_frames)
|
||||
- F14 retrieves updated poses from F10, converts ENU to GPS, updates database, and publishes via SSE
|
||||
8. **Emit ChunkMerged event** with flight_id and merged_frames
|
||||
- F14 subscribes and updates results: retrieves poses from F10, converts ENU to GPS, updates database, publishes via SSE
|
||||
9. Return True
|
||||
|
||||
**Sim(3) Transform**:
|
||||
@@ -499,7 +535,7 @@ bool: True if merge successful
|
||||
- Scale: Resolved from altitude and GSD
|
||||
|
||||
**Test Cases**:
|
||||
1. **Merge chunk**: Chunk merged successfully, results updated via F14
|
||||
1. **Merge successful**: Chunks merged successfully, results updated via F14
|
||||
2. **Global consistency**: Merged trajectory globally consistent
|
||||
3. **Multiple chunks**: Can merge multiple chunks sequentially
|
||||
4. **Result updates**: All merged frames have updated GPS coordinates published
|
||||
@@ -622,9 +658,10 @@ while flight_active:
|
||||
- F10 Factor Graph Optimizer (anchor application and chunk merging)
|
||||
- F12 Route Chunk Manager (chunk lifecycle)
|
||||
- F14 Result Manager (result updates after chunk merging)
|
||||
- F02 Flight Manager (status updates)
|
||||
- F15 SSE Event Streamer (user input events)
|
||||
|
||||
**Note**: F11 does NOT directly call F02. Instead, F11 emits events (RecoveryStarted, RecoveryFailed, etc.) which F02 subscribes to for status updates. This decouples recovery logic from flight state management.
|
||||
|
||||
### External Dependencies
|
||||
- None
|
||||
|
||||
@@ -708,3 +745,14 @@ class Sim3Transform(BaseModel):
|
||||
scale: float
|
||||
```
|
||||
|
||||
### RecoveryEvent
|
||||
```python
|
||||
class RecoveryEvent(BaseModel):
|
||||
event_type: str # "RecoveryStarted", "RecoverySucceeded", "RecoveryFailed", "UserInputNeeded", "ChunkCreated", "ChunkAnchored", "ChunkMerged"
|
||||
flight_id: str
|
||||
frame_id: Optional[int]
|
||||
chunk_id: Optional[str]
|
||||
data: Optional[Dict[str, Any]]
|
||||
timestamp: datetime
|
||||
```
|
||||
|
||||
|
||||
@@ -56,19 +56,51 @@ class IRouteChunkManager(ABC):
|
||||
def merge_chunks(self, chunk_id_1: str, chunk_id_2: str, transform: Sim3Transform) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_merge_target(self, chunk_id: str) -> str:
|
||||
"""Returns target chunk_id for merging. Returns 'main' for main trajectory."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def mark_chunk_matching(self, chunk_id: str) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def save_chunk_state(self, flight_id: str) -> bool:
|
||||
"""Persist all chunk state to F03 for crash recovery."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def load_chunk_state(self, flight_id: str) -> bool:
|
||||
"""Load chunk state from F03 on restart."""
|
||||
pass
|
||||
```
|
||||
|
||||
## Component Description
|
||||
|
||||
### Responsibilities
|
||||
- **Source of truth for chunk state** (active, anchored, merged status)
|
||||
- Manage chunk lifecycle (creation, activation, deactivation, merging)
|
||||
- Track chunk state (frames, anchors, matching status)
|
||||
- Coordinate chunk semantic matching and LiteSAM matching
|
||||
- Provide chunk representations for matching (composite images, descriptors)
|
||||
- Determine chunk readiness for matching (min frames, consistency)
|
||||
- Persist chunk state via F03 Flight Database
|
||||
|
||||
### Chunk Responsibility Clarification
|
||||
|
||||
**F12 is the high-level chunk manager**:
|
||||
- Owns chunk state (ChunkHandle with matching_status, is_active, has_anchor)
|
||||
- Provides high-level queries: `get_active_chunk()`, `get_chunks_for_matching()`
|
||||
- Coordinates with F10 for factor graph operations
|
||||
- Persists chunk state for crash recovery
|
||||
|
||||
**F10 provides low-level factor graph operations** (see F10 spec):
|
||||
- Subgraph creation and factor management
|
||||
- Does NOT own chunk state - only factor graph data
|
||||
|
||||
**F11 coordinates recovery** (see F11 spec):
|
||||
- Calls F12 for chunk operations
|
||||
- F11 NEVER directly calls F10 chunk methods
|
||||
|
||||
### Scope
|
||||
- Chunk lifecycle management
|
||||
|
||||
@@ -10,19 +10,19 @@
|
||||
class ICoordinateTransformer(ABC):
|
||||
# ENU Origin Management
|
||||
@abstractmethod
|
||||
def set_enu_origin(self, origin_gps: GPSPoint) -> None:
|
||||
def set_enu_origin(self, flight_id: str, origin_gps: GPSPoint) -> None:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_enu_origin(self) -> GPSPoint:
|
||||
def get_enu_origin(self, flight_id: str) -> GPSPoint:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def gps_to_enu(self, gps: GPSPoint) -> Tuple[float, float, float]:
|
||||
def gps_to_enu(self, flight_id: str, gps: GPSPoint) -> Tuple[float, float, float]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def enu_to_gps(self, enu: Tuple[float, float, float]) -> GPSPoint:
|
||||
def enu_to_gps(self, flight_id: str, enu: Tuple[float, float, float]) -> GPSPoint:
|
||||
pass
|
||||
|
||||
# Pixel/GPS Conversions
|
||||
@@ -38,10 +38,6 @@ class ICoordinateTransformer(ABC):
|
||||
def image_object_to_gps(self, object_pixel: Tuple[float, float], frame_id: int) -> GPSPoint:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def compute_gsd(self, altitude: float, focal_length: float, sensor_width: float, image_width: int) -> float:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def transform_points(self, points: List[Tuple[float, float]], transformation: np.ndarray) -> List[Tuple[float, float]]:
|
||||
pass
|
||||
@@ -53,10 +49,11 @@ class ICoordinateTransformer(ABC):
|
||||
- Pixel-to-GPS coordinate conversions
|
||||
- GPS-to-pixel inverse projections
|
||||
- **Critical**: Convert object pixel coordinates (from external detection system) to GPS
|
||||
- Ground Sampling Distance (GSD) calculations
|
||||
- Handle multiple coordinate systems: WGS84, Web Mercator, ENU, image pixels, rotated coordinates
|
||||
- Camera model integration for projection operations
|
||||
|
||||
**Note**: GSD calculations are delegated to H02 GSD Calculator helper.
|
||||
|
||||
### Scope
|
||||
- Coordinate system transformations
|
||||
- Camera projection mathematics
|
||||
@@ -278,11 +275,11 @@ Tuple[float, float]: (x, y) pixel coordinates
|
||||
|
||||
### `image_object_to_gps(object_pixel: Tuple[float, float], frame_id: int) -> GPSPoint`
|
||||
|
||||
**Description**: **Critical method** - Converts object pixel coordinates to GPS. Used by external object detection system.
|
||||
**Description**: **Critical method** - Converts object pixel coordinates to GPS. Used for external object detection integration.
|
||||
|
||||
**Called By**:
|
||||
- External object detection system (provides pixel coordinates)
|
||||
- F13 Result Manager (converts objects to GPS for output)
|
||||
- F01 Flight API (via `POST /flights/{flightId}/frames/{frameId}/object-to-gps` endpoint)
|
||||
- F14 Result Manager (converts objects to GPS for output)
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
@@ -316,47 +313,6 @@ GPSPoint: GPS coordinates of object center
|
||||
|
||||
---
|
||||
|
||||
### `compute_gsd(altitude: float, focal_length: float, sensor_width: float, image_width: int) -> float`
|
||||
|
||||
**Description**: Computes Ground Sampling Distance (meters per pixel).
|
||||
|
||||
**Called By**:
|
||||
- Internal (for pixel_to_gps)
|
||||
- F09 Metric Refinement (for scale calculations)
|
||||
- H02 GSD Calculator (may delegate to)
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
altitude: float # meters
|
||||
focal_length: float # mm
|
||||
sensor_width: float # mm
|
||||
image_width: int # pixels
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
float: GSD in meters/pixel
|
||||
```
|
||||
|
||||
**Formula**:
|
||||
```
|
||||
GSD = (altitude * sensor_width) / (focal_length * image_width)
|
||||
```
|
||||
|
||||
**Example**:
|
||||
- altitude = 800m
|
||||
- focal_length = 24mm
|
||||
- sensor_width = 36mm
|
||||
- image_width = 6000px
|
||||
- GSD = (800 * 36) / (24 * 6000) = 0.2 m/pixel
|
||||
|
||||
**Test Cases**:
|
||||
1. **Standard parameters**: Returns reasonable GSD (~0.1-0.3 m/pixel)
|
||||
2. **Higher altitude**: GSD increases
|
||||
3. **Longer focal length**: GSD decreases
|
||||
|
||||
---
|
||||
|
||||
### `transform_points(points: List[Tuple[float, float]], transformation: np.ndarray) -> List[Tuple[float, float]]`
|
||||
|
||||
**Description**: Applies homography or affine transformation to list of points.
|
||||
@@ -406,8 +362,8 @@ List[Tuple[float, float]]: Transformed points
|
||||
3. pixel_to_gps() → GPS
|
||||
4. Verify GPS matches original (within tolerance)
|
||||
|
||||
### Test 4: GSD Calculation
|
||||
1. compute_gsd() with known parameters
|
||||
### Test 4: GSD via H02
|
||||
1. Call H02.compute_gsd() with known parameters
|
||||
2. Verify matches expected value
|
||||
3. Test at different altitudes
|
||||
|
||||
@@ -417,7 +373,6 @@ List[Tuple[float, float]]: Transformed points
|
||||
- **pixel_to_gps**: < 5ms
|
||||
- **gps_to_pixel**: < 5ms
|
||||
- **image_object_to_gps**: < 10ms
|
||||
- **compute_gsd**: < 1ms
|
||||
|
||||
### Accuracy
|
||||
- **GPS accuracy**: Inherits from Factor Graph accuracy (~20m)
|
||||
|
||||
@@ -27,6 +27,10 @@ class IResultManager(ABC):
|
||||
@abstractmethod
|
||||
def get_changed_frames(self, flight_id: str, since: datetime) -> List[int]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_results_after_chunk_merge(self, flight_id: str, merged_frames: List[int]) -> bool:
|
||||
pass
|
||||
```
|
||||
|
||||
## Component Description
|
||||
@@ -187,8 +191,9 @@ since: datetime
|
||||
|
||||
**Description**: Updates frame results after chunk merging changes frame poses.
|
||||
|
||||
**Called By**:
|
||||
- F11 Failure Recovery Coordinator (after chunk merging)
|
||||
**Triggered By**:
|
||||
- `ChunkMerged` event from F11 (F14 subscribes to this event)
|
||||
- Alternative: F02 Flight Processor can coordinate this call after receiving ChunkMerged event
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
|
||||
@@ -1,355 +1,135 @@
|
||||
<mxfile host="65bd71144e">
|
||||
<diagram name="ASTRAL-Next Components" id="astral-next-components">
|
||||
<mxGraphModel dx="1440" dy="1201" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1800" pageHeight="2800" math="0" shadow="0">
|
||||
<mxGraphModel dx="771" dy="632" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="900" pageHeight="500" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="title" value="ASTRAL-Next System Architecture GPS-Denied Localization for UAVs (Atlas Multi-Map Chunk Architecture) 25 Components: Route API (4) + Flight API (17) + Helpers (8)" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=20;fontStyle=1;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="200" y="20" width="1200" height="80" as="geometry"/>
|
||||
<mxCell id="title" value="ASTRAL-Next Component Connections" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontStyle=1;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="280" y="10" width="300" height="25" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="route-api-lane" value="Route API (Separate Project)" style="swimlane;horizontal=1;whiteSpace=wrap;html=1;fontSize=14;fontStyle=1;fillColor=#1565C0;strokeColor=#64B5F6;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="200" y="110" width="600" height="350" as="geometry"/>
|
||||
<mxCell id="client" value="Client" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1565C0;strokeColor=#64B5F6;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="20" y="50" width="60" height="35" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="r01" value="R01 Route REST API" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#B8860B;strokeColor=#FFD54F;fontColor=#ffffff;" parent="route-api-lane" vertex="1">
|
||||
<mxGeometry x="40" y="50" width="120" height="60" as="geometry"/>
|
||||
<mxCell id="f01" value="F01 API" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="100" y="50" width="70" height="35" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="r02" value="R02 Route Data Manager" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#B8860B;strokeColor=#FFD54F;fontColor=#ffffff;" parent="route-api-lane" vertex="1">
|
||||
<mxGeometry x="200" y="50" width="140" height="60" as="geometry"/>
|
||||
<mxCell id="f02" value="F02 Flight Processor" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;fontStyle=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="195" y="70" width="110" height="45" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="r03" value="R03 Waypoint Validator" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#B8860B;strokeColor=#FFD54F;fontColor=#ffffff;" parent="route-api-lane" vertex="1">
|
||||
<mxGeometry x="380" y="50" width="140" height="60" as="geometry"/>
|
||||
<mxCell id="f03" value="F03 DB" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#424242;strokeColor=#BDBDBD;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="340" y="50" width="70" height="35" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="r04" value="R04 Route Database Layer" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#B8860B;strokeColor=#FFD54F;fontColor=#ffffff;" parent="route-api-lane" vertex="1">
|
||||
<mxGeometry x="200" y="150" width="140" height="60" as="geometry"/>
|
||||
<mxCell id="f04" value="F04 Satellite Mgr" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="60" y="367.5" width="80" height="45" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="r01-r02" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="route-api-lane" source="r01" target="r02" edge="1">
|
||||
<mxCell id="f05" value="F05 Image Pipeline" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="550" y="45" width="80" height="45" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="satellite" value="Satellite Provider" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFB300;fontColor=#ffffff;dashed=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="45" width="70" height="45" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f15" value="F15 SSE" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="20" y="120" width="60" height="35" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f11" value="F11 Failure Recovery" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="310" y="120" width="110" height="45" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f06" value="F06 Rotation" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="100" y="195" width="70" height="45" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f07" value="F07 Sequential VO" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="200" y="195" width="90" height="45" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f08" value="F08 Place Recog" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="100" y="120" width="80" height="45" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f09" value="F09 Metric Refine" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="340" y="195" width="80" height="45" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f12" value="F12 Chunk Manager" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#7B1FA2;strokeColor=#BA68C8;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="450" y="120" width="100" height="45" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f10" value="F10 Factor Graph" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;fontStyle=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="330" y="280" width="100" height="45" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f13" value="F13 Coord Transform" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="390" y="355" width="100" height="45" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f14" value="F14 Result Manager" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="190" y="372.5" width="120" height="35" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="c1" value="HTTP" style="strokeColor=#FFFFFF;fontColor=#ffffff;fontSize=8;" edge="1" parent="1" source="client" target="f01">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="r02-r03" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="route-api-lane" source="r02" target="r03" edge="1">
|
||||
<mxCell id="c2" value="SSE" style="strokeColor=#FFFFFF;fontColor=#ffffff;fontSize=8;dashed=1;" edge="1" parent="1" source="f15" target="client">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="r02-r04" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="route-api-lane" source="r02" target="r04" edge="1">
|
||||
<mxCell id="c3" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f01" target="f02">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="route-db" value="Route DB (Separate Schema)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;fillColor=#424242;strokeColor=#BDBDBD;fontColor=#ffffff;" parent="route-api-lane" vertex="1">
|
||||
<mxGeometry x="225" y="240" width="90" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="r04-db" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="route-api-lane" source="r04" target="route-db" edge="1">
|
||||
<mxCell id="c4" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f02" target="f03">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="gps-denied-lane" value="Flight API (Main Processing System - Atlas Multi-Map Architecture)" style="swimlane;horizontal=1;whiteSpace=wrap;html=1;fontSize=14;fontStyle=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="130" y="500" width="1400" height="2400" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="core-layer" value="Core API Layer" style="swimlane;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="20" y="40" width="560" height="140" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f01" value="F01 Flight REST API" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="core-layer" vertex="1">
|
||||
<mxGeometry x="20" y="40" width="150" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f02" value="F02 Flight Processor (chunk-aware)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="core-layer" vertex="1">
|
||||
<mxGeometry x="200" y="40" width="150" height="70" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f03" value="F03 Flight Database" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="core-layer" vertex="1">
|
||||
<mxGeometry x="380" y="40" width="150" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f01-f02" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="core-layer" source="f01" target="f02" edge="1">
|
||||
<mxCell id="c5" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f02" target="f11">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="data-layer" value="Data Management" style="swimlane;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="600" y="40" width="560" height="140" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f04" value="F04 Satellite Data Manager (fetch, cache, grid)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="data-layer" vertex="1">
|
||||
<mxGeometry x="20" y="40" width="160" height="70" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f05" value="F05 Image Input Pipeline (queue, validate, store)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="data-layer" vertex="1">
|
||||
<mxGeometry x="200" y="40" width="160" height="70" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f06" value="F06 Image Rotation Mgr (30° sweep, chunk rotation)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="data-layer" vertex="1">
|
||||
<mxGeometry x="380" y="40" width="160" height="70" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="visual-layer" value="Visual Processing (Tri-Layer Architecture)" style="swimlane;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="20" y="200" width="560" height="140" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f07" value="F07 Sequential VO (SuperPoint+LightGlue chunk-scoped)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="visual-layer" vertex="1">
|
||||
<mxGeometry x="20" y="40" width="160" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f08" value="F08 Global Place Recognition (AnyLoc DINOv2 chunk descriptors)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="visual-layer" vertex="1">
|
||||
<mxGeometry x="200" y="40" width="160" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f09" value="F09 Metric Refinement (LiteSAM chunk matching)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="visual-layer" vertex="1">
|
||||
<mxGeometry x="380" y="40" width="160" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="state-layer" value="State Estimation & Coordination (Atlas Multi-Map)" style="swimlane;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="600" y="200" width="760" height="200" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f10" value="F10 Factor Graph Optimizer (GTSAM iSAM2 multi-chunk, Sim3)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="state-layer" vertex="1">
|
||||
<mxGeometry x="20" y="40" width="160" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f11" value="F11 Failure Recovery (Progressive 1→25 chunk matching)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="state-layer" vertex="1">
|
||||
<mxGeometry x="200" y="40" width="160" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f12" value="F12 Route Chunk Manager (Atlas lifecycle chunk matching)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#7B1FA2;strokeColor=#BA68C8;fontColor=#ffffff;" parent="state-layer" vertex="1">
|
||||
<mxGeometry x="380" y="40" width="160" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f13" value="F13 Coordinate Transform (Pixel↔GPS)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="state-layer" vertex="1">
|
||||
<mxGeometry x="560" y="40" width="160" height="70" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="results-layer" value="Results & Communication" style="swimlane;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="20" y="360" width="380" height="140" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f14" value="F14 Result Manager" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="results-layer" vertex="1">
|
||||
<mxGeometry x="20" y="40" width="150" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f15" value="F15 SSE Event Streamer" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="results-layer" vertex="1">
|
||||
<mxGeometry x="200" y="40" width="150" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f14-f15" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="results-layer" source="f14" target="f15" edge="1">
|
||||
<mxCell id="c6" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f02" target="f07">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="infra-layer" value="Infrastructure" style="swimlane;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="420" y="360" width="740" height="140" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f16" value="F16 Model Manager (TensorRT/ONNX)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#424242;strokeColor=#BDBDBD;fontColor=#ffffff;" parent="infra-layer" vertex="1">
|
||||
<mxGeometry x="20" y="40" width="160" height="70" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f17" value="F17 Configuration Mgr" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#424242;strokeColor=#BDBDBD;fontColor=#ffffff;" parent="infra-layer" vertex="1">
|
||||
<mxGeometry x="200" y="40" width="160" height="70" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="gps-db" value="GPS-Denied DB (Separate Schema) Flights, Frame Results" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;fillColor=#424242;strokeColor=#BDBDBD;fontColor=#ffffff;" parent="infra-layer" vertex="1">
|
||||
<mxGeometry x="570" y="30" width="140" height="90" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="helpers-lane" value="Helper Components (Shared Utilities)" style="swimlane;whiteSpace=wrap;html=1;fillColor=#424242;strokeColor=#BDBDBD;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="20" y="520" width="1140" height="160" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="h01" value="H01 Camera Model" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#689F38;strokeColor=#9CCC65;fontColor=#ffffff;" parent="helpers-lane" vertex="1">
|
||||
<mxGeometry x="20" y="40" width="120" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="h02" value="H02 GSD Calculator" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#689F38;strokeColor=#9CCC65;fontColor=#ffffff;" parent="helpers-lane" vertex="1">
|
||||
<mxGeometry x="160" y="40" width="120" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="h03" value="H03 Robust Kernels" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#689F38;strokeColor=#9CCC65;fontColor=#ffffff;" parent="helpers-lane" vertex="1">
|
||||
<mxGeometry x="300" y="40" width="120" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="h04" value="H04 Faiss Index Mgr" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#689F38;strokeColor=#9CCC65;fontColor=#ffffff;" parent="helpers-lane" vertex="1">
|
||||
<mxGeometry x="440" y="40" width="120" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="h05" value="H05 Performance Monitor" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#689F38;strokeColor=#9CCC65;fontColor=#ffffff;" parent="helpers-lane" vertex="1">
|
||||
<mxGeometry x="580" y="40" width="130" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="h06" value="H06 Web Mercator Utils" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#689F38;strokeColor=#9CCC65;fontColor=#ffffff;" parent="helpers-lane" vertex="1">
|
||||
<mxGeometry x="730" y="40" width="130" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="h07" value="H07 Image Rotation Utils" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#689F38;strokeColor=#9CCC65;fontColor=#ffffff;" parent="helpers-lane" vertex="1">
|
||||
<mxGeometry x="880" y="40" width="120" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="h08" value="H08 Batch Validator" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#689F38;strokeColor=#9CCC65;fontColor=#ffffff;" parent="helpers-lane" vertex="1">
|
||||
<mxGeometry x="1020" y="40" width="100" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="flow-title" value="Main Processing Flow" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontStyle=1;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="20" y="700" width="200" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="flow-box" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#1E1E1E;strokeColor=#FFFFFF;dashed=1;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="20" y="740" width="1340" height="800" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="flow-1" value="1. Client uploads batch F01 → F05" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1565C0;strokeColor=#64B5F6;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="40" y="760" width="160" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="flow-2" value="2. Get next image F05 → F06" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1565C0;strokeColor=#64B5F6;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="230" y="760" width="160" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="flow-3" value="3. Rotation preprocessing F06 (30° sweep if needed)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#B8860B;strokeColor=#FFD54F;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="420" y="760" width="180" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="flow-4" value="4. Sequential VO (chunk-aware) F07 → F12 (get active chunk) F07 → F10 (add to chunk subgraph)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="630" y="760" width="200" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="flow-5" value="5. Check confidence F11 Failure Recovery" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="860" y="760" width="180" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="flow-6a" value="6a. IF GOOD: LiteSAM (1 tile) F09 drift correction" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="40" y="880" width="200" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="flow-6b" value="6b. IF LOST: Create chunk (proactive) F11 → F12 (create_chunk) F12 → F10 (create_new_chunk) Continue processing in chunk" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#7B1FA2;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="270" y="880" width="240" height="100" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="flow-6c" value="6c. Progressive search (single-image) F11 → F04 (1→4→9→16→25) F08 Global PR + F09 LiteSAM" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="540" y="880" width="220" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="flow-7" value="7. Factor Graph optimize F10 (chunk optimization) Fuse VO + GPS in chunk" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="790" y="880" width="200" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="flow-8" value="8. Coordinate transform F13 (Pixel → GPS)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="1020" y="880" width="180" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="flow-9" value="9. Publish results F14 → F03 (Route API) F14 → F15 (SSE to client)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="1230" y="880" width="180" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-1-2" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-1" target="flow-2" edge="1">
|
||||
<mxCell id="c7" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f02" target="f10">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-2-3" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-2" target="flow-3" edge="1">
|
||||
<mxCell id="c10" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f11" target="f08">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-3-4" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-3" target="flow-4" edge="1">
|
||||
<mxCell id="c11" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f11" target="f09">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-4-5" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-4" target="flow-5" edge="1">
|
||||
<mxCell id="c12" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f11" target="f12">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-5-6a" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-5" target="flow-6a" edge="1">
|
||||
<mxCell id="c14" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f07" target="f10">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-5-6b" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-5" target="flow-6b" edge="1">
|
||||
<mxCell id="c15" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f09" target="f10">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-5-6c" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-5" target="flow-6c" edge="1">
|
||||
<mxCell id="c16" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f12" target="f10">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-6a-7" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-6a" target="flow-7" edge="1">
|
||||
<mxCell id="c17" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f10" target="f13">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-6b-7" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-6b" target="flow-7" edge="1">
|
||||
<mxCell id="c18" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f14" target="f13">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-6c-7" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-6c" target="flow-7" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-7-8" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-7" target="flow-8" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-8-9" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-8" target="flow-9" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="chunk-title" value="Chunk Matching (Background - Atlas Multi-Map)" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontStyle=1;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="40" y="1000" width="500" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="chunk-1" value="F11 (background) → F12 get_chunks_for_matching() (unanchored, ready)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#7B1FA2;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="40" y="1040" width="220" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="chunk-2" value="F11 → F08 Chunk semantic matching (aggregate DINOv2)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="290" y="1040" width="220" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="chunk-3" value="F11 → F06 Chunk rotation sweeps (12 angles: 0°-330°)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="540" y="1040" width="220" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="chunk-4" value="F11 → F09 Chunk LiteSAM matching (aggregate correspondences)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="790" y="1040" width="240" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="chunk-5" value="F11 → F10 add_chunk_anchor() merge_chunks(Sim3)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="1060" y="1040" width="200" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-chunk-1-2" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="chunk-1" target="chunk-2" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-chunk-2-3" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="chunk-2" target="chunk-3" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-chunk-3-4" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="chunk-3" target="chunk-4" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-chunk-4-5" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="chunk-4" target="chunk-5" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="user-input-title" value="User Input Recovery (when all search fails)" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontStyle=1;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="40" y="1160" width="400" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="user-1" value="F11 exhausted (grid=25) → F15 send user_input_needed" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="40" y="1200" width="240" height="70" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="user-2" value="Client responds F01 → F11 apply_user_anchor" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="310" y="1200" width="240" height="70" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="user-3" value="F11 → F10 add_absolute_factor (high confidence) Processing resumes" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="580" y="1200" width="240" height="70" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-user-1-2" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="user-1" target="user-2" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-user-2-3" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="user-2" target="user-3" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="async-title" value="Asynchronous Trajectory Refinement" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontStyle=1;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="40" y="1310" width="350" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="async-1" value="F10 back-propagates new absolute factors (chunk + global optimization)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="40" y="1350" width="220" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="async-2" value="F14 detect changed frames → F03 batch_update_waypoints" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="290" y="1350" width="240" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="async-3" value="F14 → F15 send frame_refined events" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
||||
<mxGeometry x="560" y="1350" width="220" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-async-1-2" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="async-1" target="async-2" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="arrow-async-2-3" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="async-2" target="async-3" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="client" value="Client (GPS-Denied UI)" style="shape=actor;whiteSpace=wrap;html=1;fillColor=#1565C0;strokeColor=#64B5F6;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="10" y="560" width="90" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="satellite-provider" value="Satellite Provider API /api/satellite/tiles/..." style="ellipse;shape=cloud;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFB300;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="900" y="290" width="250" height="140" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="external-detector" value="External<br>Object Detector (Azaion.Inference)<br>(provides pixel coords)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#C62828;strokeColor=#EF5350;dashed=1;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="1340" y="800" width="160" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="client-f01" value="HTTP REST" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="client" target="f01" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f14-route" value="Per-frame waypoint updates" style="edgeStyle=orthogonalEdgeStyle;curved=1;dashed=1;strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="f14" target="r01" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f04-sat" value="Fetch tiles" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="f04" target="satellite-provider" edge="1">
|
||||
<mxGeometry x="0.3759" y="-10" relative="1" as="geometry">
|
||||
<mxPoint as="offset"/>
|
||||
<mxCell id="c19" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f14" target="f15">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="80" y="270"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="f15-client" value="SSE Events" style="dashed=1;strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="f15" target="client" edge="1">
|
||||
<mxCell id="c13" style="strokeColor=#66BB6A;dashed=1;" edge="1" parent="1" source="f11" target="f14">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="detector-f13" value="Object pixels → GPS" style="dashed=1;strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="external-detector" target="f13" edge="1">
|
||||
<mxCell id="c21" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f05" target="satellite">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f12-f10" value="Chunk lifecycle" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="f12" target="f10" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
<mxCell id="legend" value="── sync - - event" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=9;fontColor=#888888;" vertex="1" parent="1">
|
||||
<mxGeometry x="600" y="380" width="100" height="20" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f12-f08" value="Chunk descriptors" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="f12" target="f08" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
<mxCell id="3" value="" style="strokeColor=#FFFFFF;endArrow=none;" edge="1" parent="1" source="f11" target="f02">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="507.02127659574467" y="100.00000000000011" as="sourcePoint"/>
|
||||
<mxPoint x="256.3829787234042" y="289.9999999999999" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="f11-f12" value="Chunk matching" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="f11" target="f12" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="legend-title" value="Legend" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontStyle=1;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="100" y="2730" width="100" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="legend-box" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#1E1E1E;strokeColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="100" y="2770" width="700" height="120" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="legend-1" value="Route API Components" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#B8860B;strokeColor=#FFD54F;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="120" y="2790" width="140" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="legend-2" value="Flight API Core" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="280" y="2790" width="140" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="legend-8" value="Chunk Management" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#7B1FA2;strokeColor=#BA68C8;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="600" y="2840" width="140" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="legend-3" value="Visual Processing" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="440" y="2790" width="140" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="legend-4" value="Helper Components" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#689F38;strokeColor=#9CCC65;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="120" y="2840" width="140" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="legend-5" value="State Estimation" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="280" y="2840" width="140" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="legend-6" value="Infrastructure" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#424242;strokeColor=#BDBDBD;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="440" y="2840" width="140" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="legend-7" value="External Systems" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#C62828;strokeColor=#EF5350;fontColor=#ffffff;" vertex="1" parent="1">
|
||||
<mxGeometry x="600" y="2790" width="140" height="40" as="geometry"/>
|
||||
<mxCell id="2" value="" style="strokeColor=#FFFFFF;fontColor=#ffffff;endArrow=none;" edge="1" parent="1" source="f04" target="f14">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="715" y="121.22222222222206" as="sourcePoint"/>
|
||||
<mxPoint x="125" y="212.9999999999999" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
|
||||
@@ -101,7 +101,8 @@
|
||||
|
||||
**F13_coordinate_transformer**
|
||||
**Interface**: `ICoordinateTransformer`
|
||||
**API**: `set_enu_origin()`, `get_enu_origin()`, `gps_to_enu()`, `enu_to_gps()`, `pixel_to_gps()`, `gps_to_pixel()`, `image_object_to_gps()`, `compute_gsd()`, `transform_points()`
|
||||
**API**: `set_enu_origin()`, `get_enu_origin()`, `gps_to_enu()`, `enu_to_gps()`, `pixel_to_gps()`, `gps_to_pixel()`, `image_object_to_gps()`, `transform_points()`
|
||||
**Dependencies**: F10 Factor Graph Optimizer (for frame poses), H02 GSD Calculator (for GSD computation)
|
||||
|
||||
### Results & Communication
|
||||
|
||||
@@ -144,14 +145,14 @@
|
||||
|
||||
| Order | Component | Method | Purpose | Dependencies |
|
||||
|-------|-----------|--------|---------|--------------|
|
||||
| 1 | F16 Configuration Manager | `load_config()` | Load system configuration | None |
|
||||
| 2 | F03 Flight Database | Initialize connections | Establish DB connection pool | F16 |
|
||||
| 3 | F15 Model Manager | `load_model("SuperPoint")` | Load SuperPoint feature extractor | F16 |
|
||||
| 4 | F15 Model Manager | `load_model("LightGlue")` | Load LightGlue matcher | F16 |
|
||||
| 5 | F15 Model Manager | `load_model("DINOv2")` | Load DINOv2 for place recognition | F16 |
|
||||
| 6 | F15 Model Manager | `load_model("LiteSAM")` | Load LiteSAM for cross-view matching | F16 |
|
||||
| 7 | F04 Satellite Data Manager | Initialize cache | Initialize tile cache directory | F16 |
|
||||
| 8 | F08 Global Place Recognition | `build_index()` or `load_index()` | Build/load Faiss index from satellite tiles | F04, F15, H04 |
|
||||
| 1 | F17 Configuration Manager | `load_config()` | Load system configuration | None |
|
||||
| 2 | F03 Flight Database | Initialize connections | Establish DB connection pool | F17 |
|
||||
| 3 | F16 Model Manager | `load_model("SuperPoint")` | Load SuperPoint feature extractor | F17 |
|
||||
| 4 | F16 Model Manager | `load_model("LightGlue")` | Load LightGlue matcher | F17 |
|
||||
| 5 | F16 Model Manager | `load_model("DINOv2")` | Load DINOv2 for place recognition | F17 |
|
||||
| 6 | F16 Model Manager | `load_model("LiteSAM")` | Load LiteSAM for cross-view matching | F17 |
|
||||
| 7 | F04 Satellite Data Manager | Initialize cache | Initialize tile cache directory | F17 |
|
||||
| 8 | F08 Global Place Recognition | `load_index()` | Load pre-built Faiss index from satellite provider | F04, F16, H04 |
|
||||
| 9 | F12 Route Chunk Manager | Initialize | Initialize chunk state tracking | F10 |
|
||||
| 10 | F02 Flight Processor | Ready | Ready to accept flights | All above |
|
||||
| 11 | F01 Flight API | Start server | Start FastAPI/Uvicorn | F02 |
|
||||
@@ -176,7 +177,7 @@
|
||||
| Source | Target | Method | Purpose |
|
||||
|--------|--------|--------|---------|
|
||||
| F02 | F16 | `load_config()` | Load system configuration |
|
||||
| F02 | F15 | `load_model()` × 4 | Load SuperPoint, LightGlue, DINOv2, LiteSAM |
|
||||
| F02 | F16 | `load_model()` × 4 | Load SuperPoint, LightGlue, DINOv2, LiteSAM |
|
||||
| F04 | F08 | Satellite tiles | F08 generates descriptors for Faiss |
|
||||
| F08 | H04 | `build_index()` | Build satellite descriptor index |
|
||||
| F08 | F15 | `get_inference_engine("DINOv2")` | Get model for descriptor generation |
|
||||
@@ -246,6 +247,7 @@
|
||||
| F02 | F11 | `check_confidence()` → FAIL | Low confidence |
|
||||
| F11 | F12 | `create_chunk_on_tracking_loss()` | **Proactive chunk creation** |
|
||||
| F12 | F10 | `create_new_chunk()` | Create chunk in factor graph |
|
||||
| F12 | F03 | `save_chunk_state()` | Persist chunk state for recovery |
|
||||
| F02 | F12 | `get_active_chunk()` | Get new active chunk |
|
||||
| F11 | F06 | `requires_rotation_sweep()` | Trigger rotation sweep (single-image) |
|
||||
| F11 | F08 | `retrieve_candidate_tiles()` | Coarse localization (single-image) |
|
||||
@@ -292,7 +294,7 @@
|
||||
| F01 | F11 | `apply_user_anchor()` | Apply fix |
|
||||
| F11 | F10 | `add_absolute_factor()` (high confidence) | Hard constraint |
|
||||
| F10 | Internal | `optimize()` | Re-optimize |
|
||||
| F11 | F02 | `update_flight_status("PROCESSING")` | Resume |
|
||||
| F11 | Event | Emit `UserFixApplied` | F02 subscribes and resumes |
|
||||
|
||||
### Asynchronous Refinement
|
||||
|
||||
@@ -331,7 +333,7 @@
|
||||
|
||||
## Interaction Coverage Verification
|
||||
|
||||
✅ **Initialization**: F02→F15, F16, F17; F04→F08→H04
|
||||
✅ **Initialization**: F02→F16, F17; F04→F08→H04
|
||||
✅ **Flight creation**: Client→F01→F02→F04,F12,F16,F17,F14
|
||||
✅ **Image upload**: Client→F01→F05→H08,F17
|
||||
✅ **Rotation sweep**: F06→H07,F09 (12 iterations)
|
||||
@@ -392,3 +394,42 @@
|
||||
- [x] F17 Configuration Manager
|
||||
- [x] F03 Flight Database (merged from R04, G17)
|
||||
- [x] Helper components (H01-H08)
|
||||
|
||||
---
|
||||
|
||||
## Architecture Notes
|
||||
|
||||
### F02 Flight Processor Complexity
|
||||
|
||||
F02 Flight Processor handles multiple concerns:
|
||||
- Flight lifecycle management
|
||||
- Processing loop orchestration
|
||||
- Event subscription and state updates
|
||||
- Coordination of F07/F08/F09/F10
|
||||
|
||||
**Current Status**: Acceptable for MVP. The responsibilities are related (all flight processing) and the component acts as a coordinator rather than implementing logic directly.
|
||||
|
||||
**Future Consideration**: If complexity grows, consider splitting into:
|
||||
- F02a Flight State Manager (lifecycle, status)
|
||||
- F02b Processing Loop Coordinator (frame processing orchestration)
|
||||
|
||||
**Decision**: Keep as single component. Clear internal organization with separate methods for state vs processing concerns. Event-based communication with F11 keeps recovery logic separate.
|
||||
|
||||
### Error Recovery Strategy
|
||||
|
||||
**Per-Component Recovery**:
|
||||
- **F02**: Persists flight state via F03 on each significant update. On restart, loads last known state.
|
||||
- **F07**: Stateless - reprocesses frame if VO fails
|
||||
- **F10**: Factor graph state persisted periodically. On restart, rebuilds from F03 checkpoint.
|
||||
- **F11**: Chunk state persisted via F12→F03. Recovery continues from last chunk state.
|
||||
- **F12**: All chunk state persisted to F03. Restores chunk handles on restart.
|
||||
|
||||
**System-Wide Recovery**:
|
||||
1. On crash, F02 loads flight state from F03
|
||||
2. F12 restores chunk state from F03
|
||||
3. Processing resumes from last successfully processed frame
|
||||
4. Incomplete chunks continue building/matching
|
||||
|
||||
**Event Recovery**:
|
||||
- Events are fire-and-forget (no persistence)
|
||||
- Subscribers rebuild state from F03 on restart
|
||||
|
||||
@@ -0,0 +1,883 @@
|
||||
# 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 | Flight Processor | `IFlightProcessor` | Central coordinator, processing loop |
|
||||
| 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 | `ISequentialVO` | 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 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 │ Flight Processor
|
||||
└────┬────┘
|
||||
┌────────────────────────┬─┴─┬────────────────────────┐
|
||||
│ │ │ │
|
||||
▼ │ ▼ ▼
|
||||
┌───────────────┐ │ ┌───────────────┐ ┌───────────────┐
|
||||
│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 Flight Processor │
|
||||
│ │
|
||||
│ ┌─────────────┐ │
|
||||
│ │ 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_in_chunk() │ ││
|
||||
│ │ ├─ 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()│ │ Skip absolute anchor │ ││
|
||||
│ │F06 update_heading() │ │ (VO-only frame) │ ││
|
||||
│ └────────────┬────────────┘ └─────────────────────────┘ ││
|
||||
│ │ ││
|
||||
│ └─────────────────────┬───────────────────────────────────┘│
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ F10 optimize_chunk() │ │
|
||||
│ └──────────────────────────────┬──────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 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 │ │ │
|
||||
│ │ └───────┬───────┘ └───────────────┘ │ │
|
||||
│ │ │ │ │
|
||||
│ │ ▼ │ │
|
||||
│ │ ┌─────────────────────────────────────┐ │ │
|
||||
│ │ │ F03 save_heading() via F06 │ │ │
|
||||
│ │ │ update_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**:
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ F11 Failure Recovery Coordinator │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 1. EMIT RecoveryStarted event │ │
|
||||
│ │ └─ F02 subscribes → Update status to "recovering" │ │
|
||||
│ └──────────────────────────────┬──────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 2. 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]: │ │ │
|
||||
│ │ │ ├─ F04 expand_search_grid() │ │ │
|
||||
│ │ │ ├─ For each tile: │ │ │
|
||||
│ │ │ │ ├─ F04 compute_tile_bounds() │ │ │
|
||||
│ │ │ │ └─ F09 align_to_satellite(img, tile, bounds)│ │ │
|
||||
│ │ │ │ │ │ │
|
||||
│ │ │ └─ If match found: BREAK │ │ │
|
||||
│ │ └───────────────────────────────────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ └──────────────────────────────┬──────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌────────────────────┴────────────────────┐ │
|
||||
│ │ Single-image match found? │ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌─────────────────────┐ ┌─────────────────────────────┐ │
|
||||
│ │ EMIT RecoverySucceeded│ │ 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_new_chunk() ← Factor graph subgraph │ │
|
||||
│ │ ├─ Initialize chunk state (unanchored, active) │ │
|
||||
│ │ └─ F03 save_chunk_state() │ │
|
||||
│ └──────────────────────────────┬──────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌───────────────────────┴───────────────────────────┐ │
|
||||
│ │ For each frame in chunk: │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────────────────────────┐ │ │
|
||||
│ │ │ F07 compute_relative_pose_in_chunk()│ │ │
|
||||
│ │ └───────────────────┬─────────────────┘ │ │
|
||||
│ │ ▼ │ │
|
||||
│ │ ┌─────────────────────────────────────┐ │ │
|
||||
│ │ │ F12 add_frame_to_chunk() │ │ │
|
||||
│ │ │ └─ F10 add_relative_factor_to_chunk│ │ │
|
||||
│ │ └───────────────────┬─────────────────┘ │ │
|
||||
│ │ ▼ │ │
|
||||
│ │ ┌─────────────────────────────────────┐ │ │
|
||||
│ │ │ F10 optimize_chunk() (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**:
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ F11 merge_chunk_to_trajectory() │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 1. Get chunk frames: F12 get_chunk_frames(chunk_id) │ │
|
||||
│ └──────────────────────────────┬──────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 2. Anchor chunk: F12 mark_chunk_anchored(chunk_id, gps) │ │
|
||||
│ │ └─ F10 add_chunk_anchor() │ │
|
||||
│ └──────────────────────────────┬──────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 3. Resolve target: F12 get_merge_target(chunk_id) │ │
|
||||
│ │ └─ Returns target_chunk_id (predecessor or "main") │ │
|
||||
│ └──────────────────────────────┬──────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 4. Merge: F12 merge_chunks(chunk_id, target_chunk_id, Sim3) │ │
|
||||
│ │ ├─ F10 merge_chunks() ← Apply Sim(3) transform │ │
|
||||
│ │ ├─ F12 deactivate_chunk(chunk_id) │ │
|
||||
│ │ └─ F03 save_chunk_state() │ │
|
||||
│ └──────────────────────────────┬──────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 5. Optimize global: F10 optimize_global() │ │
|
||||
│ └──────────────────────────────┬──────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 6. EMIT ChunkMerged event (flight_id, chunk_id, merged_frames)│ │
|
||||
│ │ └─ F14 subscribes → update_results_after_chunk_merge() │ │
|
||||
│ │ ├─ F10 get_trajectory() → ENU poses │ │
|
||||
│ │ ├─ F13 enu_to_gps() for each frame │ │
|
||||
│ │ ├─ F03 save_frame_result() + update_waypoint() │ │
|
||||
│ │ └─ F15 send_refinement() → SSE "frame_refined" × N │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Sim(3) Transform**: Translation + Rotation + Scale alignment between chunks
|
||||
|
||||
---
|
||||
|
||||
## Flow 10: User Input Recovery
|
||||
|
||||
**Purpose**: Request human assistance when all automatic recovery fails.
|
||||
|
||||
**Trigger**: Progressive search exhausted (25 tiles), chunk matching failed
|
||||
|
||||
**Sequence**:
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ F11 create_user_input_request() │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 1. Get UAV image for frame_id │ │
|
||||
│ │ 2. Get top-5 candidates from F08 │ │
|
||||
│ │ 3. Create UserInputRequest │ │
|
||||
│ │ 4. F15 send_user_input_request() → SSE "user_input_needed" │ │
|
||||
│ │ 5. EMIT UserInputNeeded event │ │
|
||||
│ │ └─ F02 subscribes → Update 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 subscribes → Update 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() → 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 Flight Processor │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 1. All frames processed │ │
|
||||
│ │ 2. Wait for pending chunk merges (if any) │ │
|
||||
│ │ 3. F10 optimize_global(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 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 Flight Processor │ │
|
||||
│ │ (Central coordinator, event subscriber, background task manager) │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
├─────────────────────────────────────────────────────────────┐
|
||||
▼ ▼
|
||||
┌─────────────────────────────────────────────┐ ┌────────────────────────────┐
|
||||
│ DATA MANAGEMENT LAYER │ │ RECOVERY LAYER │
|
||||
│ ┌─────────────┐ ┌─────────────┐ │ │ ┌───────────────────────┐ │
|
||||
│ │ F04 │ │ F05 │ │ │ │ F11 │ │
|
||||
│ │ Satellite │ │ Image │ │ │ │ Failure Recovery │ │
|
||||
│ │ Data │ │ Input │ │ │ │ (Event emitter) │ │
|
||||
│ └─────────────┘ └─────────────┘ │ │ └───────────────────────┘ │
|
||||
│ │ │ │ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ │ │ ▼ │
|
||||
│ │ 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 │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 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) ││
|
||||
│ └───────────────┘ └───────────────┘ └───────────────────────────────────┘│
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Event-Based Communication
|
||||
|
||||
F11 Failure Recovery Coordinator emits events instead of directly calling F02:
|
||||
|
||||
| Event | Publisher | Subscribers | Action |
|
||||
|-------|-----------|-------------|--------|
|
||||
| `RecoveryStarted` | F11 | F02 | Update status to "recovering" |
|
||||
| `RecoverySucceeded` | F11 | F02 | Update status to "processing", resume |
|
||||
| `RecoveryFailed` | F11 | F02 | Update status to "blocked" |
|
||||
| `UserInputNeeded` | F11 | F02 | Update status to "blocked", await fix |
|
||||
| `UserFixApplied` | F11 | F02 | Update status to "processing", resume |
|
||||
| `ChunkCreated` | F11 | F02 | Log chunk creation |
|
||||
| `ChunkAnchored` | F11 | F02 | Log chunk anchor |
|
||||
| `ChunkMerged` | F11 | F02, F14 | F14 updates results for merged frames |
|
||||
|
||||
---
|
||||
|
||||
## 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) |
|
||||
|
||||
@@ -0,0 +1,603 @@
|
||||
# ASTRAL-Next System Flow Diagrams
|
||||
|
||||
## Component Architecture Diagram
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph External["External Systems"]
|
||||
Client[Client UI]
|
||||
SatProv[Satellite Provider]
|
||||
ExtDet[External Detector]
|
||||
end
|
||||
|
||||
subgraph API["API Layer"]
|
||||
F01[F01 Flight API]
|
||||
end
|
||||
|
||||
subgraph Orchestration["Orchestration Layer"]
|
||||
F02[F02 Flight Processor]
|
||||
end
|
||||
|
||||
subgraph Data["Data Management"]
|
||||
F03[F03 Flight Database]
|
||||
F04[F04 Satellite Data Manager]
|
||||
F05[F05 Image Input Pipeline]
|
||||
F12[F12 Route Chunk Manager]
|
||||
end
|
||||
|
||||
subgraph Recovery["Recovery Layer"]
|
||||
F11[F11 Failure Recovery Coordinator]
|
||||
end
|
||||
|
||||
subgraph Visual["Visual Processing"]
|
||||
F06[F06 Image Rotation Manager]
|
||||
F07[F07 Sequential Visual Odometry]
|
||||
F08[F08 Global Place Recognition]
|
||||
F09[F09 Metric Refinement]
|
||||
end
|
||||
|
||||
subgraph State["State Estimation"]
|
||||
F10[F10 Factor Graph Optimizer]
|
||||
end
|
||||
|
||||
subgraph Output["Output Layer"]
|
||||
F13[F13 Coordinate Transformer]
|
||||
F14[F14 Result Manager]
|
||||
F15[F15 SSE Event Streamer]
|
||||
end
|
||||
|
||||
subgraph Infra["Infrastructure"]
|
||||
F16[F16 Model Manager]
|
||||
F17[F17 Configuration Manager]
|
||||
end
|
||||
|
||||
Client -->|REST| F01
|
||||
F15 -->|SSE| Client
|
||||
ExtDet -->|REST| F01
|
||||
F04 -->|HTTP| SatProv
|
||||
|
||||
F01 --> F02
|
||||
F02 --> F03
|
||||
F02 --> F05
|
||||
F02 --> F11
|
||||
F02 --> F07
|
||||
F02 --> F10
|
||||
F02 --> F12
|
||||
F02 --> F04
|
||||
|
||||
F11 --> F08
|
||||
F11 --> F09
|
||||
F11 --> F12
|
||||
F11 -.->|events| F02
|
||||
F11 -.->|events| F14
|
||||
|
||||
F06 --> F09
|
||||
F07 --> F10
|
||||
F09 --> F10
|
||||
F12 --> F10
|
||||
F10 --> F13
|
||||
F14 --> F13
|
||||
F14 --> F15
|
||||
F14 --> F03
|
||||
|
||||
F07 --> F16
|
||||
F08 --> F16
|
||||
F09 --> F16
|
||||
F02 --> F17
|
||||
```
|
||||
|
||||
## Flow 1: System Initialization
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Main as System
|
||||
participant F17 as Config Manager
|
||||
participant F03 as Flight Database
|
||||
participant F16 as Model Manager
|
||||
participant F04 as Satellite Manager
|
||||
participant F08 as Place Recognition
|
||||
participant F12 as Chunk Manager
|
||||
participant F02 as Flight Processor
|
||||
participant F01 as Flight API
|
||||
|
||||
Main->>F17: load_config()
|
||||
F17-->>Main: SystemConfig
|
||||
|
||||
Main->>F03: Initialize connections
|
||||
F03-->>Main: Connection pool ready
|
||||
|
||||
Main->>F16: load_model("SuperPoint")
|
||||
Main->>F16: load_model("LightGlue")
|
||||
Main->>F16: load_model("DINOv2")
|
||||
Main->>F16: load_model("LiteSAM")
|
||||
F16-->>Main: Models loaded (~25s)
|
||||
|
||||
Main->>F04: Initialize cache
|
||||
F04-->>Main: Cache ready
|
||||
|
||||
Main->>F08: load_index()
|
||||
F08-->>Main: Faiss index loaded
|
||||
|
||||
Main->>F12: Initialize
|
||||
F12-->>Main: Chunk tracking ready
|
||||
|
||||
Main->>F02: Ready
|
||||
F02-->>Main: Ready to accept flights
|
||||
|
||||
Main->>F01: Start server
|
||||
F01-->>Main: FastAPI running
|
||||
```
|
||||
|
||||
## Flow 2: Flight Creation
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as Client
|
||||
participant F01 as Flight API
|
||||
participant F02 as Flight Processor
|
||||
participant F17 as Config Manager
|
||||
participant F13 as Coord Transformer
|
||||
participant F04 as Satellite Manager
|
||||
participant F03 as Flight Database
|
||||
participant F15 as SSE Streamer
|
||||
|
||||
C->>F01: POST /flights
|
||||
F01->>F02: create_flight()
|
||||
|
||||
F02->>F17: get_flight_config()
|
||||
F17-->>F02: CameraParams, Altitude
|
||||
|
||||
F02->>F13: set_enu_origin(start_gps)
|
||||
|
||||
F02->>F04: prefetch_route_corridor()
|
||||
F04-->>F02: Prefetching async
|
||||
|
||||
F02->>F03: insert_flight()
|
||||
F03-->>F02: flight_id
|
||||
|
||||
F01-->>C: 201 Created {flight_id}
|
||||
|
||||
C->>F01: GET /flights/{id}/stream
|
||||
F01->>F15: create_stream()
|
||||
F15-->>C: SSE Connection
|
||||
```
|
||||
|
||||
## Flow 3: Normal Frame Processing
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant F02 as Flight Processor
|
||||
participant F05 as Image Pipeline
|
||||
participant F12 as Chunk Manager
|
||||
participant F06 as Rotation Manager
|
||||
participant F07 as Sequential VO
|
||||
participant F04 as Satellite Manager
|
||||
participant F09 as Metric Refinement
|
||||
participant F10 as Factor Graph
|
||||
participant F13 as Coord Transformer
|
||||
participant F14 as Result Manager
|
||||
participant F15 as SSE Streamer
|
||||
|
||||
F02->>F05: get_next_image()
|
||||
F05-->>F02: ImageData
|
||||
|
||||
F02->>F12: get_active_chunk()
|
||||
F12-->>F02: ChunkHandle
|
||||
|
||||
F02->>F06: requires_rotation_sweep()
|
||||
F06-->>F02: false (heading known)
|
||||
|
||||
F02->>F07: compute_relative_pose_in_chunk()
|
||||
F07-->>F02: RelativePose
|
||||
|
||||
F02->>F12: add_frame_to_chunk()
|
||||
F12->>F10: add_relative_factor_to_chunk()
|
||||
|
||||
F02->>F04: fetch_tile() + compute_tile_bounds()
|
||||
F04-->>F02: tile, tile_bounds
|
||||
|
||||
F02->>F09: align_to_satellite(img, tile, bounds)
|
||||
F09-->>F02: AlignmentResult (GPS)
|
||||
|
||||
F02->>F10: add_absolute_factor()
|
||||
F02->>F10: optimize_chunk()
|
||||
F10-->>F02: OptimizationResult
|
||||
|
||||
F02->>F13: enu_to_gps()
|
||||
F13-->>F02: GPSPoint
|
||||
|
||||
F02->>F14: update_frame_result()
|
||||
F14->>F15: send_frame_result()
|
||||
F15-->>Client: SSE "frame_processed"
|
||||
```
|
||||
|
||||
## Flow 4: Rotation Sweep (First Frame / Sharp Turn)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant F02 as Flight Processor
|
||||
participant F06 as Rotation Manager
|
||||
participant H07 as Rotation Utils
|
||||
participant F09 as Metric Refinement
|
||||
participant F03 as Flight Database
|
||||
|
||||
F02->>F06: try_rotation_steps(img, tile, bounds)
|
||||
|
||||
loop For angle in [0°, 30°, ... 330°]
|
||||
F06->>H07: rotate_image(img, angle)
|
||||
H07-->>F06: rotated_img
|
||||
|
||||
F06->>F09: align_to_satellite(rotated_img, tile, bounds)
|
||||
F09-->>F06: AlignmentResult
|
||||
|
||||
alt Match Found (confidence > 0.7)
|
||||
F06->>F06: calculate_precise_angle()
|
||||
F06->>F03: save_heading()
|
||||
F06-->>F02: RotationResult
|
||||
end
|
||||
end
|
||||
|
||||
alt No Match Found
|
||||
F06-->>F02: None (trigger recovery)
|
||||
end
|
||||
```
|
||||
|
||||
## Flow 5: Tracking Loss Recovery
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant F02 as Flight Processor
|
||||
participant F11 as Failure Recovery
|
||||
participant F12 as Chunk Manager
|
||||
participant F06 as Rotation Manager
|
||||
participant F08 as Place Recognition
|
||||
participant F04 as Satellite Manager
|
||||
participant F09 as Metric Refinement
|
||||
|
||||
F02->>F11: start_search(frame_id, estimated_gps)
|
||||
F11-->>F02: SearchSession
|
||||
|
||||
Note over F11: Emit RecoveryStarted event
|
||||
|
||||
F11->>F12: create_chunk_on_tracking_loss()
|
||||
F12-->>F11: ChunkHandle (processing continues)
|
||||
|
||||
F11->>F06: requires_rotation_sweep()
|
||||
F11->>F08: retrieve_candidate_tiles()
|
||||
|
||||
loop Progressive Search [1, 4, 9, 16, 25]
|
||||
F11->>F04: expand_search_grid(grid_size)
|
||||
F04-->>F11: tiles
|
||||
|
||||
loop For each tile
|
||||
F11->>F04: compute_tile_bounds()
|
||||
F11->>F09: align_to_satellite(img, tile, bounds)
|
||||
|
||||
alt Match Found
|
||||
Note over F11: Emit RecoverySucceeded
|
||||
F11-->>F02: RecoveryResult(success=true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
alt All Failed
|
||||
Note over F11: Emit UserInputNeeded
|
||||
F11-->>F02: RecoveryResult(success=false)
|
||||
end
|
||||
```
|
||||
|
||||
## Flow 6: Chunk Matching (Background)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant F11 as Failure Recovery
|
||||
participant F12 as Chunk Manager
|
||||
participant F08 as Place Recognition
|
||||
participant F06 as Rotation Manager
|
||||
participant F04 as Satellite Manager
|
||||
participant F09 as Metric Refinement
|
||||
participant F10 as Factor Graph
|
||||
|
||||
loop Every 5 seconds
|
||||
F11->>F12: get_chunks_for_matching()
|
||||
F12-->>F11: List[ChunkHandle]
|
||||
|
||||
loop For each unanchored chunk
|
||||
F11->>F12: is_chunk_ready_for_matching()
|
||||
|
||||
alt Chunk Ready
|
||||
F11->>F12: mark_chunk_matching()
|
||||
|
||||
Note over F11: Step 1: Semantic Matching
|
||||
F11->>F12: get_chunk_images()
|
||||
F11->>F08: retrieve_candidate_tiles_for_chunk()
|
||||
F08-->>F11: List[TileCandidate]
|
||||
|
||||
Note over F11: Step 2: LiteSAM with Rotation
|
||||
loop For each candidate tile
|
||||
F11->>F04: get_tile + compute_tile_bounds()
|
||||
F11->>F06: try_chunk_rotation_steps()
|
||||
F06->>F09: align_chunk_to_satellite()
|
||||
|
||||
alt Match Found
|
||||
F09-->>F11: ChunkAlignmentResult
|
||||
end
|
||||
end
|
||||
|
||||
alt Match Found
|
||||
F11->>F12: mark_chunk_anchored()
|
||||
F12->>F10: add_chunk_anchor()
|
||||
|
||||
F11->>F12: merge_chunks()
|
||||
F12->>F10: merge_chunks(Sim3)
|
||||
|
||||
F11->>F10: optimize_global()
|
||||
|
||||
Note over F11: Emit ChunkMerged event
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Flow 7: User Input Recovery
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant F11 as Failure Recovery
|
||||
participant F08 as Place Recognition
|
||||
participant F15 as SSE Streamer
|
||||
participant C as Client
|
||||
participant F01 as Flight API
|
||||
participant F10 as Factor Graph
|
||||
participant F02 as Flight Processor
|
||||
|
||||
F11->>F08: retrieve_candidate_tiles()
|
||||
F08-->>F11: Top-5 candidates
|
||||
|
||||
F11->>F15: send_user_input_request()
|
||||
F15-->>C: SSE "user_input_needed"
|
||||
|
||||
Note over F11: Emit UserInputNeeded event
|
||||
Note over F02: Status = BLOCKED
|
||||
|
||||
C->>F01: POST /user-fix {pixel, gps}
|
||||
F01->>F11: apply_user_anchor()
|
||||
|
||||
F11->>F10: add_absolute_factor(is_user_anchor=true)
|
||||
F11->>F10: optimize()
|
||||
|
||||
Note over F11: Emit UserFixApplied event
|
||||
Note over F02: Status = PROCESSING
|
||||
|
||||
F11-->>F01: Success
|
||||
F01-->>C: 200 OK
|
||||
```
|
||||
|
||||
## Flow 8: Result Publishing & Refinement
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant F10 as Factor Graph
|
||||
participant F14 as Result Manager
|
||||
participant F13 as Coord Transformer
|
||||
participant F03 as Flight Database
|
||||
participant F15 as SSE Streamer
|
||||
participant C as Client
|
||||
|
||||
Note over F10: New absolute factor added
|
||||
|
||||
F10->>F10: optimize(batch)
|
||||
|
||||
F10->>F14: mark_refined(frame_ids)
|
||||
|
||||
loop For each refined frame
|
||||
F14->>F10: get_trajectory()
|
||||
F10-->>F14: Pose (ENU)
|
||||
|
||||
F14->>F13: enu_to_gps(flight_id, enu)
|
||||
F13-->>F14: GPSPoint
|
||||
|
||||
F14->>F03: save_frame_result(refined=true)
|
||||
F14->>F03: update_waypoint()
|
||||
|
||||
F14->>F15: send_refinement()
|
||||
F15-->>C: SSE "frame_refined"
|
||||
end
|
||||
```
|
||||
|
||||
## Flow 9: Object to GPS Conversion
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Ext as External Detector
|
||||
participant F01 as Flight API
|
||||
participant F13 as Coord Transformer
|
||||
participant F10 as Factor Graph
|
||||
participant F17 as Config Manager
|
||||
participant H01 as Camera Model
|
||||
|
||||
Ext->>F01: POST /object-to-gps {pixel_x, pixel_y}
|
||||
F01->>F13: image_object_to_gps(pixel, frame_id)
|
||||
|
||||
F13->>F10: get_pose(frame_id)
|
||||
F10-->>F13: Pose (ENU)
|
||||
|
||||
F13->>F17: get_camera_params()
|
||||
F17-->>F13: CameraParameters
|
||||
|
||||
F13->>H01: unproject(pixel)
|
||||
F13->>F13: intersect_ground_plane()
|
||||
F13->>F13: enu_to_gps()
|
||||
|
||||
F13-->>F01: GPSPoint
|
||||
F01-->>Ext: {gps, accuracy_meters}
|
||||
```
|
||||
|
||||
## Complete System Flow Overview
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Init["System Initialization"]
|
||||
direction TB
|
||||
I1[Load Config F17]
|
||||
I2[Init DB F03]
|
||||
I3[Load Models F16]
|
||||
I4[Init Cache F04]
|
||||
I5[Load Faiss F08]
|
||||
I6[Start API F01]
|
||||
I1 --> I2 --> I3 --> I4 --> I5 --> I6
|
||||
end
|
||||
|
||||
subgraph Flight["Flight Lifecycle"]
|
||||
direction TB
|
||||
FL1[Create Flight]
|
||||
FL2[Upload Images]
|
||||
FL3[Process Frames]
|
||||
FL4[Complete Flight]
|
||||
FL1 --> FL2 --> FL3 --> FL4
|
||||
end
|
||||
|
||||
subgraph Process["Frame Processing"]
|
||||
direction TB
|
||||
P1{First Frame?}
|
||||
P2[Rotation Sweep]
|
||||
P3[Sequential VO]
|
||||
P4{Tracking OK?}
|
||||
P5[Single Tile Match]
|
||||
P6[Optimize]
|
||||
P7[Publish Result]
|
||||
|
||||
P1 -->|Yes| P2
|
||||
P1 -->|No| P3
|
||||
P2 --> P3
|
||||
P3 --> P4
|
||||
P4 -->|Yes| P5
|
||||
P5 --> P6
|
||||
P6 --> P7
|
||||
end
|
||||
|
||||
subgraph Recovery["Recovery Flow"]
|
||||
direction TB
|
||||
R1[Create Chunk]
|
||||
R2[Progressive Search]
|
||||
R3{Match Found?}
|
||||
R4[Build Chunk]
|
||||
R5[Chunk Matching]
|
||||
R6{Chunk Match?}
|
||||
R7[Merge Chunk]
|
||||
R8[Request User Input]
|
||||
R9[Apply User Anchor]
|
||||
|
||||
P4 -->|No| R1
|
||||
R1 --> R2
|
||||
R2 --> R3
|
||||
R3 -->|Yes| P6
|
||||
R3 -->|No| R4
|
||||
R4 --> R5
|
||||
R5 --> R6
|
||||
R6 -->|Yes| R7
|
||||
R7 --> P6
|
||||
R6 -->|No| R8
|
||||
R8 --> R9
|
||||
R9 --> P6
|
||||
end
|
||||
|
||||
Init --> Flight
|
||||
FL3 --> Process
|
||||
```
|
||||
|
||||
## Event Flow Diagram
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Events["F11 Emits Events"]
|
||||
E1[RecoveryStarted]
|
||||
E2[RecoverySucceeded]
|
||||
E3[RecoveryFailed]
|
||||
E4[UserInputNeeded]
|
||||
E5[UserFixApplied]
|
||||
E6[ChunkCreated]
|
||||
E7[ChunkAnchored]
|
||||
E8[ChunkMerged]
|
||||
end
|
||||
|
||||
subgraph F02Sub["F02 Subscribes"]
|
||||
S1[Update status: recovering]
|
||||
S2[Update status: processing]
|
||||
S3[Update status: blocked]
|
||||
S4[Update status: blocked]
|
||||
S5[Resume processing]
|
||||
S6[Log chunk creation]
|
||||
S7[Log anchor]
|
||||
S8[Trigger result update]
|
||||
end
|
||||
|
||||
subgraph F14Sub["F14 Subscribes"]
|
||||
R1[Update merged frame results]
|
||||
end
|
||||
|
||||
E1 --> S1
|
||||
E2 --> S2
|
||||
E3 --> S3
|
||||
E4 --> S4
|
||||
E5 --> S5
|
||||
E6 --> S6
|
||||
E7 --> S7
|
||||
E8 --> S8
|
||||
E8 --> R1
|
||||
```
|
||||
|
||||
## Data Flow Through Layers
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Input["Input"]
|
||||
IMG[UAV Images]
|
||||
SAT[Satellite Tiles]
|
||||
USR[User Anchors]
|
||||
end
|
||||
|
||||
subgraph Processing["Processing"]
|
||||
SP[SuperPoint Features]
|
||||
LG[LightGlue Matches]
|
||||
DINO[DINOv2 Descriptors]
|
||||
LITE[LiteSAM Homography]
|
||||
end
|
||||
|
||||
subgraph State["State Estimation"]
|
||||
REL[Relative Factors]
|
||||
ABS[Absolute Factors]
|
||||
CHUNK[Chunk Subgraphs]
|
||||
OPT[iSAM2 Optimization]
|
||||
end
|
||||
|
||||
subgraph Output["Output"]
|
||||
ENU[ENU Trajectory]
|
||||
GPS[GPS Coordinates]
|
||||
SSE[SSE Events]
|
||||
DB[Database]
|
||||
end
|
||||
|
||||
IMG --> SP
|
||||
IMG --> DINO
|
||||
IMG --> LITE
|
||||
SAT --> LITE
|
||||
SAT --> DINO
|
||||
USR --> ABS
|
||||
|
||||
SP --> LG
|
||||
LG --> REL
|
||||
DINO --> ABS
|
||||
LITE --> ABS
|
||||
|
||||
REL --> CHUNK
|
||||
ABS --> CHUNK
|
||||
CHUNK --> OPT
|
||||
|
||||
OPT --> ENU
|
||||
ENU --> GPS
|
||||
GPS --> SSE
|
||||
GPS --> DB
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user