mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-04-23 03:46:37 +00:00
+5
-3
@@ -44,6 +44,8 @@
|
|||||||
- Generate draw.io components diagram shows relations between components.
|
- Generate draw.io components diagram shows relations between components.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
Components should be semantically coherents. Do not spread similar functionality across multiple components
|
- Strongly follow Single Responsibility Principle during creation of components.
|
||||||
Do not put any code yet, only names, input and output.
|
- Follow dumb code - smart data principle. Do not overcomplicate
|
||||||
Ask as many questions as possible to clarify all uncertainties.
|
- Components should be semantically coherents. Do not spread similar functionality across multiple components
|
||||||
|
- Do not put any code yet, only names, input and output.
|
||||||
|
- Ask as many questions as possible to clarify all uncertainties.
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# component assesment
|
||||||
|
|
||||||
|
## Problem statement
|
||||||
|
- @00_problem
|
||||||
|
|
||||||
|
## Solution and decomposition
|
||||||
|
- @docs/01_solution/solution.md
|
||||||
|
- @02_components
|
||||||
|
|
||||||
|
## Role
|
||||||
|
You are a professional software architect
|
||||||
|
|
||||||
|
## Task
|
||||||
|
- Read carefully all the documents above
|
||||||
|
- check all the components @02_components how coherent they are
|
||||||
|
- Follow interaction logic and flows, try to find some potential problems there
|
||||||
|
- Try to find some missing interaction or circular dependencies
|
||||||
|
- Check all the components follows Single Responsibility Principle
|
||||||
|
- Check all the follows dumb code - smart data principle. So that resulting code shouldn't be overcomplicated
|
||||||
|
|
||||||
|
## Output
|
||||||
|
Form a list of problems with fixes in the next format:
|
||||||
|
- Component
|
||||||
|
- Problem, reason
|
||||||
|
- Fix or potential fixes
|
||||||
@@ -148,9 +148,10 @@ flight_id: str # UUID
|
|||||||
3. Validate rough_waypoints via validate_waypoint()
|
3. Validate rough_waypoints via validate_waypoint()
|
||||||
4. Get flight configuration from F17 Configuration Manager
|
4. Get flight configuration from F17 Configuration Manager
|
||||||
5. Initialize flight state
|
5. Initialize flight state
|
||||||
6. Trigger F04 Satellite Data Manager → prefetch_route_corridor()
|
6. **Set ENU origin**: Call F13 Coordinate Transformer → set_enu_origin(flight_id, start_gps)
|
||||||
7. Save flight to F03 Flight Database
|
7. Trigger F04 Satellite Data Manager → prefetch_route_corridor()
|
||||||
8. Return flight_id
|
8. Save flight to F03 Flight Database
|
||||||
|
9. Return flight_id
|
||||||
|
|
||||||
**Error Conditions**:
|
**Error Conditions**:
|
||||||
- `ValidationError`: Invalid waypoints or geofences
|
- `ValidationError`: Invalid waypoints or geofences
|
||||||
@@ -586,8 +587,7 @@ FrameResult:
|
|||||||
5. Else:
|
5. Else:
|
||||||
- Pre-rotate image to current heading
|
- Pre-rotate image to current heading
|
||||||
6. Compute relative pose via F07 Sequential VO (chunk-aware)
|
6. Compute relative pose via F07 Sequential VO (chunk-aware)
|
||||||
7. Add relative factor to chunk via F10.add_relative_factor_to_chunk()
|
7. Add frame to chunk via F12 Route Chunk Manager.add_frame_to_chunk() (F12 handles F10 internally)
|
||||||
8. Add frame to chunk via F12 Route Chunk Manager.add_frame_to_chunk()
|
|
||||||
9. Get satellite tile from F04 Satellite Data Manager
|
9. Get satellite tile from F04 Satellite Data Manager
|
||||||
10. Align to satellite via F09 Metric Refinement (with tile_bounds)
|
10. Align to satellite via F09 Metric Refinement (with tile_bounds)
|
||||||
11. If alignment successful:
|
11. If alignment successful:
|
||||||
@@ -953,7 +953,7 @@ bool: True if initialization successful
|
|||||||
- **F10 Factor Graph Optimizer**: Trajectory optimization and chunk management
|
- **F10 Factor Graph Optimizer**: Trajectory optimization and chunk management
|
||||||
- **F11 Failure Recovery Coordinator**: Tracking loss handling and chunk matching
|
- **F11 Failure Recovery Coordinator**: Tracking loss handling and chunk matching
|
||||||
- **F12 Route Chunk Manager**: Chunk lifecycle management
|
- **F12 Route Chunk Manager**: Chunk lifecycle management
|
||||||
- **F13 Coordinate Transformer**: Pixel to GPS conversion
|
- **F13 Coordinate Transformer**: Pixel to GPS conversion and ENU coordinate management
|
||||||
- **F14 Result Manager**: Result publishing
|
- **F14 Result Manager**: Result publishing
|
||||||
- **F15 SSE Event Streamer**: Real-time streaming
|
- **F15 SSE Event Streamer**: Real-time streaming
|
||||||
- **F16 Model Manager**: ML model loading
|
- **F16 Model Manager**: ML model loading
|
||||||
|
|||||||
@@ -93,6 +93,19 @@ class IFlightDatabase(ABC):
|
|||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_image_metadata(self, flight_id: str, frame_id: int) -> Optional[Dict]:
|
def get_image_metadata(self, flight_id: str, frame_id: int) -> Optional[Dict]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Chunk State Operations
|
||||||
|
@abstractmethod
|
||||||
|
def save_chunk_state(self, flight_id: str, chunk: ChunkHandle) -> bool:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def load_chunk_states(self, flight_id: str) -> List[ChunkHandle]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def delete_chunk_state(self, flight_id: str, chunk_id: str) -> bool:
|
||||||
|
pass
|
||||||
```
|
```
|
||||||
|
|
||||||
## Component Description
|
## Component Description
|
||||||
@@ -342,7 +355,7 @@ waypoint_id: str
|
|||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- F02 Flight Processor
|
- F02 Flight Processor
|
||||||
- F13 Result Manager
|
- F14 Result Manager
|
||||||
|
|
||||||
**Input**:
|
**Input**:
|
||||||
```python
|
```python
|
||||||
@@ -475,7 +488,7 @@ Optional[FlightState]
|
|||||||
**Description**: Saves frame processing result.
|
**Description**: Saves frame processing result.
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- F13 Result Manager
|
- F14 Result Manager
|
||||||
|
|
||||||
**Input**:
|
**Input**:
|
||||||
```python
|
```python
|
||||||
@@ -505,7 +518,7 @@ bool: True if saved
|
|||||||
**Description**: Gets all frame results for flight.
|
**Description**: Gets all frame results for flight.
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- F13 Result Manager
|
- F14 Result Manager
|
||||||
|
|
||||||
**Test Cases**:
|
**Test Cases**:
|
||||||
1. Get results → returns all frames
|
1. Get results → returns all frames
|
||||||
@@ -646,6 +659,100 @@ Optional[Dict]: Metadata dictionary or None
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Chunk State Operations
|
||||||
|
|
||||||
|
### `save_chunk_state(flight_id: str, chunk: ChunkHandle) -> bool`
|
||||||
|
|
||||||
|
**Description**: Saves chunk state to database for crash recovery.
|
||||||
|
|
||||||
|
**Called By**:
|
||||||
|
- F12 Route Chunk Manager (after chunk state changes)
|
||||||
|
|
||||||
|
**Input**:
|
||||||
|
```python
|
||||||
|
flight_id: str
|
||||||
|
chunk: ChunkHandle:
|
||||||
|
chunk_id: str
|
||||||
|
start_frame_id: int
|
||||||
|
end_frame_id: Optional[int]
|
||||||
|
frames: List[int]
|
||||||
|
is_active: bool
|
||||||
|
has_anchor: bool
|
||||||
|
anchor_frame_id: Optional[int]
|
||||||
|
anchor_gps: Optional[GPSPoint]
|
||||||
|
matching_status: str
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output**:
|
||||||
|
```python
|
||||||
|
bool: True if saved successfully
|
||||||
|
```
|
||||||
|
|
||||||
|
**Database Operations**:
|
||||||
|
```sql
|
||||||
|
INSERT INTO chunks (chunk_id, flight_id, start_frame_id, end_frame_id, frames,
|
||||||
|
is_active, has_anchor, anchor_frame_id, anchor_lat, anchor_lon,
|
||||||
|
matching_status, updated_at)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())
|
||||||
|
ON CONFLICT (chunk_id) UPDATE SET ...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Test Cases**:
|
||||||
|
1. **Save new chunk**: Persisted successfully
|
||||||
|
2. **Update existing chunk**: State updated
|
||||||
|
3. **Multiple chunks**: All persisted correctly
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `load_chunk_states(flight_id: str) -> List[ChunkHandle]`
|
||||||
|
|
||||||
|
**Description**: Loads all chunk states for a flight (for crash recovery).
|
||||||
|
|
||||||
|
**Called By**:
|
||||||
|
- F12 Route Chunk Manager (on flight resume)
|
||||||
|
- System startup (recovery)
|
||||||
|
|
||||||
|
**Input**:
|
||||||
|
```python
|
||||||
|
flight_id: str
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output**:
|
||||||
|
```python
|
||||||
|
List[ChunkHandle]: All chunks for the flight
|
||||||
|
```
|
||||||
|
|
||||||
|
**Test Cases**:
|
||||||
|
1. **Load chunks**: Returns all chunks
|
||||||
|
2. **No chunks**: Returns empty list
|
||||||
|
3. **Crash recovery**: Chunks restored correctly
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `delete_chunk_state(flight_id: str, chunk_id: str) -> bool`
|
||||||
|
|
||||||
|
**Description**: Deletes chunk state from database.
|
||||||
|
|
||||||
|
**Called By**:
|
||||||
|
- F12 Route Chunk Manager (after chunk merged/deleted)
|
||||||
|
|
||||||
|
**Input**:
|
||||||
|
```python
|
||||||
|
flight_id: str
|
||||||
|
chunk_id: str
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output**:
|
||||||
|
```python
|
||||||
|
bool: True if deleted
|
||||||
|
```
|
||||||
|
|
||||||
|
**Test Cases**:
|
||||||
|
1. **Delete chunk**: Removed from database
|
||||||
|
2. **Non-existent chunk**: Returns False
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Integration Tests
|
## Integration Tests
|
||||||
|
|
||||||
### Test 1: Complete Flight Lifecycle
|
### Test 1: Complete Flight Lifecycle
|
||||||
@@ -809,6 +916,27 @@ CREATE TABLE flight_images (
|
|||||||
FOREIGN KEY (flight_id) REFERENCES flights(id) ON DELETE CASCADE,
|
FOREIGN KEY (flight_id) REFERENCES flights(id) ON DELETE CASCADE,
|
||||||
INDEX idx_images_flight (flight_id, frame_id)
|
INDEX idx_images_flight (flight_id, frame_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- Chunks table
|
||||||
|
CREATE TABLE chunks (
|
||||||
|
chunk_id VARCHAR(36) PRIMARY KEY,
|
||||||
|
flight_id VARCHAR(36) NOT NULL,
|
||||||
|
start_frame_id INT NOT NULL,
|
||||||
|
end_frame_id INT,
|
||||||
|
frames JSONB NOT NULL,
|
||||||
|
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
|
has_anchor BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
anchor_frame_id INT,
|
||||||
|
anchor_lat DECIMAL(10, 7),
|
||||||
|
anchor_lon DECIMAL(11, 7),
|
||||||
|
matching_status VARCHAR(50) NOT NULL DEFAULT 'unanchored',
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (flight_id) REFERENCES flights(id) ON DELETE CASCADE,
|
||||||
|
INDEX idx_chunks_flight (flight_id),
|
||||||
|
INDEX idx_chunks_active (flight_id, is_active),
|
||||||
|
INDEX idx_chunks_matching (flight_id, matching_status)
|
||||||
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -245,15 +245,16 @@ for tiles in progressive_fetch(lat, lon, [1, 4, 9, 16, 25], 19):
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `cache_tile(tile_coords: TileCoords, tile_data: np.ndarray) -> bool`
|
### `cache_tile(flight_id: str, tile_coords: TileCoords, tile_data: np.ndarray) -> bool`
|
||||||
|
|
||||||
**Description**: Caches a satellite tile to disk.
|
**Description**: Caches a satellite tile to disk with flight_id association.
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- Internal (after fetching tiles)
|
- Internal (after fetching tiles)
|
||||||
|
|
||||||
**Input**:
|
**Input**:
|
||||||
```python
|
```python
|
||||||
|
flight_id: str # Flight this tile belongs to
|
||||||
tile_coords: TileCoords:
|
tile_coords: TileCoords:
|
||||||
x: int
|
x: int
|
||||||
y: int
|
y: int
|
||||||
@@ -267,10 +268,11 @@ bool: True if cached successfully
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Processing Flow**:
|
**Processing Flow**:
|
||||||
1. Generate cache key from tile_coords
|
1. Generate cache path: `/satellite_cache/{flight_id}/{zoom}/{tile_x}_{tile_y}.png`
|
||||||
2. Serialize tile_data (PNG format)
|
2. Create flight cache directory if not exists
|
||||||
3. Write to disk cache directory
|
3. Serialize tile_data (PNG format)
|
||||||
4. Update cache index
|
4. Write to disk cache directory
|
||||||
|
5. Update cache index with flight_id association
|
||||||
|
|
||||||
**Error Conditions**:
|
**Error Conditions**:
|
||||||
- Returns `False`: Disk write error, space full
|
- Returns `False`: Disk write error, space full
|
||||||
@@ -282,9 +284,9 @@ bool: True if cached successfully
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `get_cached_tile(tile_coords: TileCoords) -> Optional[np.ndarray]`
|
### `get_cached_tile(flight_id: str, tile_coords: TileCoords) -> Optional[np.ndarray]`
|
||||||
|
|
||||||
**Description**: Retrieves a cached tile from disk.
|
**Description**: Retrieves a cached tile from disk, checking flight-specific cache first.
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- Internal (before fetching from API)
|
- Internal (before fetching from API)
|
||||||
@@ -292,6 +294,7 @@ bool: True if cached successfully
|
|||||||
|
|
||||||
**Input**:
|
**Input**:
|
||||||
```python
|
```python
|
||||||
|
flight_id: str # Flight to check cache for
|
||||||
tile_coords: TileCoords
|
tile_coords: TileCoords
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -301,10 +304,11 @@ Optional[np.ndarray]: Tile image or None if not cached
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Processing Flow**:
|
**Processing Flow**:
|
||||||
1. Generate cache key
|
1. Generate cache path: `/satellite_cache/{flight_id}/{zoom}/{tile_x}_{tile_y}.png`
|
||||||
2. Check if file exists
|
2. Check flight-specific cache first
|
||||||
3. Load and deserialize
|
3. If not found, check global cache (shared tiles)
|
||||||
4. Return tile_data
|
4. If file exists, load and deserialize
|
||||||
|
5. Return tile_data or None
|
||||||
|
|
||||||
**Error Conditions**:
|
**Error Conditions**:
|
||||||
- Returns `None`: Not cached, corrupted file
|
- Returns `None`: Not cached, corrupted file
|
||||||
|
|||||||
@@ -330,8 +330,8 @@ ImageMetadata:
|
|||||||
**Description**: Gets current processing status for a flight.
|
**Description**: Gets current processing status for a flight.
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- F01 GPS-Denied REST API (status endpoint)
|
- F01 Flight API (status endpoint)
|
||||||
- F02 Flight Manager
|
- F02 Flight Processor
|
||||||
|
|
||||||
**Input**:
|
**Input**:
|
||||||
```python
|
```python
|
||||||
@@ -349,6 +349,11 @@ ProcessingStatus:
|
|||||||
processing_rate: float # images/second
|
processing_rate: float # images/second
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Processing Flow**:
|
||||||
|
1. Get flight state via F02 Flight Processor.get_flight_state(flight_id)
|
||||||
|
2. Combine with internal queue status
|
||||||
|
3. Return ProcessingStatus
|
||||||
|
|
||||||
**Test Cases**:
|
**Test Cases**:
|
||||||
1. **Get status**: Returns accurate counts
|
1. **Get status**: Returns accurate counts
|
||||||
2. **During processing**: Updates in real-time
|
2. **During processing**: Updates in real-time
|
||||||
@@ -397,7 +402,8 @@ ProcessingStatus:
|
|||||||
|
|
||||||
### Internal Components
|
### Internal Components
|
||||||
- **H08 Batch Validator**: For validation logic
|
- **H08 Batch Validator**: For validation logic
|
||||||
- **F17 Database Layer**: For metadata persistence
|
- **F03 Flight Database**: For metadata persistence
|
||||||
|
- **F02 Flight Processor**: For flight state information
|
||||||
|
|
||||||
### External Dependencies
|
### External Dependencies
|
||||||
- **opencv-python**: Image I/O
|
- **opencv-python**: Image I/O
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class IImageRotationManager(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def try_rotation_steps(self, flight_id: str, image: np.ndarray, satellite_tile: np.ndarray) -> Optional[RotationResult]:
|
def try_rotation_steps(self, flight_id: str, frame_id: int, image: np.ndarray, satellite_tile: np.ndarray, tile_bounds: TileBounds, timestamp: datetime) -> Optional[RotationResult]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@@ -25,7 +25,7 @@ class IImageRotationManager(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def update_heading(self, flight_id: str, heading: float) -> bool:
|
def update_heading(self, flight_id: str, frame_id: int, heading: float, timestamp: datetime) -> bool:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@@ -41,29 +41,29 @@ class IImageRotationManager(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def try_chunk_rotation_steps(self, chunk_images: List[np.ndarray], satellite_tile: np.ndarray) -> Optional[RotationResult]:
|
def try_chunk_rotation_steps(self, chunk_images: List[np.ndarray], satellite_tile: np.ndarray, tile_bounds: TileBounds) -> Optional[RotationResult]:
|
||||||
pass
|
pass
|
||||||
```
|
```
|
||||||
|
|
||||||
## Component Description
|
## Component Description
|
||||||
|
|
||||||
### Responsibilities
|
### Responsibilities
|
||||||
- Handle UAV image rotation preprocessing for LiteSAM
|
- Handle UAV image rotation preprocessing
|
||||||
- **Critical**: LiteSAM fails if images rotated >45°, requires preprocessing
|
- **Critical**: LiteSAM (F09 Metric Refinement) fails if images rotated >45°, requires preprocessing
|
||||||
- Perform 30° step rotation sweeps (12 rotations: 0°, 30°, 60°, ..., 330°)
|
- Perform 30° step rotation sweeps (12 rotations: 0°, 30°, 60°, ..., 330°)
|
||||||
- Track UAV heading angle across flight
|
- Track UAV heading angle across flight
|
||||||
- Calculate precise rotation angle from homography point correspondences
|
- Calculate precise rotation angle from homography point correspondences
|
||||||
- Detect sharp turns requiring rotation sweep
|
- Detect sharp turns requiring rotation sweep
|
||||||
- Pre-rotate images to known heading for subsequent frames
|
- Pre-rotate images to known heading for subsequent frames
|
||||||
- **Chunk rotation operations (rotate all images in chunk)**
|
- **Chunk rotation operations (rotate all images in chunk)**
|
||||||
- **Chunk rotation sweeps for LiteSAM matching**
|
- **Chunk rotation sweeps (delegates matching to F09 Metric Refinement)**
|
||||||
|
|
||||||
### Scope
|
### Scope
|
||||||
- Image rotation operations
|
- Image rotation operations (pure rotation, no matching)
|
||||||
- UAV heading tracking and history
|
- UAV heading tracking and history
|
||||||
- Sharp turn detection
|
- Sharp turn detection
|
||||||
- Rotation sweep coordination with LiteSAM matching
|
- Rotation sweep coordination (rotates images, delegates matching to F09 Metric Refinement)
|
||||||
- Precise angle calculation from homography
|
- Precise angle calculation from homography (extracted from F09 results)
|
||||||
- **Chunk-level rotation (all images rotated by same angle)**
|
- **Chunk-level rotation (all images rotated by same angle)**
|
||||||
|
|
||||||
## API Methods
|
## API Methods
|
||||||
@@ -103,9 +103,9 @@ np.ndarray # Rotated image (same dimensions)
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `try_rotation_steps(flight_id: str, image: np.ndarray, satellite_tile: np.ndarray) -> Optional[RotationResult]`
|
### `try_rotation_steps(flight_id: str, frame_id: int, image: np.ndarray, satellite_tile: np.ndarray, tile_bounds: TileBounds, timestamp: datetime) -> Optional[RotationResult]`
|
||||||
|
|
||||||
**Description**: Performs 30° rotation sweep, trying LiteSAM match for each rotation.
|
**Description**: Performs 30° rotation sweep, rotating image at each step and delegating matching to F09 Metric Refinement.
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- Internal (when requires_rotation_sweep() returns True)
|
- Internal (when requires_rotation_sweep() returns True)
|
||||||
@@ -114,8 +114,11 @@ np.ndarray # Rotated image (same dimensions)
|
|||||||
**Input**:
|
**Input**:
|
||||||
```python
|
```python
|
||||||
flight_id: str
|
flight_id: str
|
||||||
|
frame_id: int # Frame identifier for heading persistence
|
||||||
image: np.ndarray # UAV image
|
image: np.ndarray # UAV image
|
||||||
satellite_tile: np.ndarray # Satellite reference tile
|
satellite_tile: np.ndarray # Satellite reference tile
|
||||||
|
tile_bounds: TileBounds # GPS bounds and GSD of satellite tile (for F09)
|
||||||
|
timestamp: datetime # Timestamp for heading persistence
|
||||||
```
|
```
|
||||||
|
|
||||||
**Output**:
|
**Output**:
|
||||||
@@ -132,23 +135,23 @@ RotationResult:
|
|||||||
```
|
```
|
||||||
For angle in [0°, 30°, 60°, 90°, 120°, 150°, 180°, 210°, 240°, 270°, 300°, 330°]:
|
For angle in [0°, 30°, 60°, 90°, 120°, 150°, 180°, 210°, 240°, 270°, 300°, 330°]:
|
||||||
rotated_image = rotate_image_360(image, angle)
|
rotated_image = rotate_image_360(image, angle)
|
||||||
result = LiteSAM.align_to_satellite(rotated_image, satellite_tile)
|
result = F09.align_to_satellite(rotated_image, satellite_tile, tile_bounds)
|
||||||
if result.matched and result.confidence > threshold:
|
if result.matched and result.confidence > threshold:
|
||||||
precise_angle = calculate_precise_angle(result.homography, angle)
|
precise_angle = calculate_precise_angle(result.homography, angle)
|
||||||
update_heading(flight_id, precise_angle)
|
update_heading(flight_id, frame_id, precise_angle, timestamp)
|
||||||
return RotationResult(matched=True, initial_angle=angle, precise_angle=precise_angle, ...)
|
return RotationResult(matched=True, initial_angle=angle, precise_angle=precise_angle, ...)
|
||||||
return None # No match found
|
return None # No match found
|
||||||
```
|
```
|
||||||
|
|
||||||
**Processing Flow**:
|
**Processing Flow**:
|
||||||
1. For each 30° step:
|
1. For each 30° step:
|
||||||
- Rotate image
|
- Rotate image via rotate_image_360()
|
||||||
- Call F09 Metric Refinement (LiteSAM)
|
- Call F09 Metric Refinement.align_to_satellite(rotated_image, satellite_tile, tile_bounds)
|
||||||
- Check if match found
|
- Check if match found
|
||||||
2. If match found:
|
2. If match found:
|
||||||
- Calculate precise angle from homography
|
- Calculate precise angle from homography via calculate_precise_angle()
|
||||||
- Update UAV heading
|
- Update UAV heading via update_heading()
|
||||||
- Return result
|
- Return RotationResult
|
||||||
3. If no match:
|
3. If no match:
|
||||||
- Return None (triggers progressive search expansion)
|
- Return None (triggers progressive search expansion)
|
||||||
|
|
||||||
@@ -228,7 +231,7 @@ Optional[float]: Heading angle in degrees (0-360), or None if not initialized
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `update_heading(flight_id: str, heading: float) -> bool`
|
### `update_heading(flight_id: str, frame_id: int, heading: float, timestamp: datetime) -> bool`
|
||||||
|
|
||||||
**Description**: Updates UAV heading angle after successful match.
|
**Description**: Updates UAV heading angle after successful match.
|
||||||
|
|
||||||
@@ -239,7 +242,9 @@ Optional[float]: Heading angle in degrees (0-360), or None if not initialized
|
|||||||
**Input**:
|
**Input**:
|
||||||
```python
|
```python
|
||||||
flight_id: str
|
flight_id: str
|
||||||
|
frame_id: int # Frame identifier for database persistence
|
||||||
heading: float # New heading angle (0-360)
|
heading: float # New heading angle (0-360)
|
||||||
|
timestamp: datetime # Timestamp for database persistence
|
||||||
```
|
```
|
||||||
|
|
||||||
**Output**:
|
**Output**:
|
||||||
@@ -251,7 +256,7 @@ bool: True if updated successfully
|
|||||||
1. Normalize angle to 0-360 range
|
1. Normalize angle to 0-360 range
|
||||||
2. Add to heading history (last 10 headings)
|
2. Add to heading history (last 10 headings)
|
||||||
3. Update current_heading for flight
|
3. Update current_heading for flight
|
||||||
4. Persist to database (optional)
|
4. **Persist to database**: Call F03 Flight Database.save_heading(flight_id, frame_id, heading, timestamp)
|
||||||
|
|
||||||
**Test Cases**:
|
**Test Cases**:
|
||||||
1. **Update heading**: Sets new heading
|
1. **Update heading**: Sets new heading
|
||||||
@@ -365,17 +370,18 @@ List[np.ndarray] # Rotated images (same dimensions)
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `try_chunk_rotation_steps(chunk_images: List[np.ndarray], satellite_tile: np.ndarray) -> Optional[RotationResult]`
|
### `try_chunk_rotation_steps(chunk_images: List[np.ndarray], satellite_tile: np.ndarray, tile_bounds: TileBounds) -> Optional[RotationResult]`
|
||||||
|
|
||||||
**Description**: Performs 30° rotation sweep on entire chunk, trying LiteSAM match for each rotation.
|
**Description**: Performs 30° rotation sweep on entire chunk, rotating all images at each step and delegating matching to F09 Metric Refinement.
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- F11 Failure Recovery Coordinator (chunk LiteSAM matching with rotation)
|
- F11 Failure Recovery Coordinator (chunk matching with rotation)
|
||||||
|
|
||||||
**Input**:
|
**Input**:
|
||||||
```python
|
```python
|
||||||
chunk_images: List[np.ndarray] # Chunk images
|
chunk_images: List[np.ndarray] # Chunk images
|
||||||
satellite_tile: np.ndarray # Reference satellite tile
|
satellite_tile: np.ndarray # Reference satellite tile
|
||||||
|
tile_bounds: TileBounds # GPS bounds and GSD of satellite tile (for F09)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Output**:
|
**Output**:
|
||||||
@@ -392,7 +398,7 @@ RotationResult:
|
|||||||
```
|
```
|
||||||
For angle in [0°, 30°, 60°, 90°, 120°, 150°, 180°, 210°, 240°, 270°, 300°, 330°]:
|
For angle in [0°, 30°, 60°, 90°, 120°, 150°, 180°, 210°, 240°, 270°, 300°, 330°]:
|
||||||
rotated_chunk = rotate_chunk_360(chunk_images, angle)
|
rotated_chunk = rotate_chunk_360(chunk_images, angle)
|
||||||
result = LiteSAM.align_chunk_to_satellite(rotated_chunk, satellite_tile)
|
result = F09.align_chunk_to_satellite(rotated_chunk, satellite_tile, tile_bounds)
|
||||||
if result.matched and result.confidence > threshold:
|
if result.matched and result.confidence > threshold:
|
||||||
precise_angle = calculate_precise_angle(result.homography, angle)
|
precise_angle = calculate_precise_angle(result.homography, angle)
|
||||||
return RotationResult(matched=True, initial_angle=angle, precise_angle=precise_angle, ...)
|
return RotationResult(matched=True, initial_angle=angle, precise_angle=precise_angle, ...)
|
||||||
@@ -401,17 +407,17 @@ return None # No match found
|
|||||||
|
|
||||||
**Processing Flow**:
|
**Processing Flow**:
|
||||||
1. For each 30° step:
|
1. For each 30° step:
|
||||||
- Rotate all chunk images
|
- Rotate all chunk images via rotate_chunk_360()
|
||||||
- Call F09 Metric Refinement.align_chunk_to_satellite()
|
- Call F09 Metric Refinement.align_chunk_to_satellite(rotated_chunk, satellite_tile, tile_bounds)
|
||||||
- Check if match found
|
- Check if match found
|
||||||
2. If match found:
|
2. If match found:
|
||||||
- Calculate precise angle from homography
|
- Calculate precise angle from homography via calculate_precise_angle()
|
||||||
- Return RotationResult
|
- Return RotationResult
|
||||||
3. If no match:
|
3. If no match:
|
||||||
- Return None
|
- Return None
|
||||||
|
|
||||||
**Performance**:
|
**Performance**:
|
||||||
- 12 rotations × chunk LiteSAM (~60ms) = ~720ms
|
- 12 rotations × chunk matching via F09 (~60ms) = ~720ms
|
||||||
- Acceptable for chunk matching (async operation)
|
- Acceptable for chunk matching (async operation)
|
||||||
|
|
||||||
**Test Cases**:
|
**Test Cases**:
|
||||||
@@ -425,18 +431,19 @@ return None # No match found
|
|||||||
### Test 1: First Frame Rotation Sweep
|
### Test 1: First Frame Rotation Sweep
|
||||||
1. First frame arrives (no heading set)
|
1. First frame arrives (no heading set)
|
||||||
2. requires_rotation_sweep() → True
|
2. requires_rotation_sweep() → True
|
||||||
3. try_rotation_steps() → rotates 12 times
|
3. try_rotation_steps(flight_id, frame_id=1, image, satellite_tile, tile_bounds, timestamp=now()) → rotates 12 times
|
||||||
4. Match found at 60° step
|
4. F09 Metric Refinement called for each rotation
|
||||||
5. calculate_precise_angle() → 62.3°
|
5. Match found at 60° step
|
||||||
6. update_heading(62.3°)
|
6. calculate_precise_angle() → 62.3°
|
||||||
7. Subsequent frames use 62.3° heading
|
7. update_heading(flight_id, frame_id=1, heading=62.3°, timestamp=now())
|
||||||
|
8. Subsequent frames use 62.3° heading
|
||||||
|
|
||||||
### Test 2: Normal Frame Processing
|
### Test 2: Normal Frame Processing
|
||||||
1. Heading known (90°)
|
1. Heading known (90°)
|
||||||
2. requires_rotation_sweep() → False
|
2. requires_rotation_sweep() → False
|
||||||
3. Pre-rotate image to 90°
|
3. Pre-rotate image to 90°
|
||||||
4. LiteSAM match succeeds with small delta (+2.5°)
|
4. LiteSAM match succeeds with small delta (+2.5°)
|
||||||
5. update_heading(92.5°)
|
5. update_heading(flight_id, frame_id=237, heading=92.5°, timestamp=now())
|
||||||
|
|
||||||
### Test 3: Sharp Turn Detection
|
### Test 3: Sharp Turn Detection
|
||||||
1. UAV heading 45°
|
1. UAV heading 45°
|
||||||
@@ -446,17 +453,19 @@ return None # No match found
|
|||||||
5. Perform rotation sweep → find match at 120° step
|
5. Perform rotation sweep → find match at 120° step
|
||||||
|
|
||||||
### Test 4: Tracking Loss Recovery
|
### Test 4: Tracking Loss Recovery
|
||||||
1. LiteSAM fails to match (no overlap after turn)
|
1. F09 Metric Refinement fails to match (no overlap after turn)
|
||||||
2. requires_rotation_sweep() → True
|
2. requires_rotation_sweep() → True
|
||||||
3. try_rotation_steps() with all 12 rotations
|
3. try_rotation_steps(flight_id, frame_id, image, satellite_tile, tile_bounds, timestamp) with all 12 rotations
|
||||||
4. Match found → heading updated
|
4. F09 called for each rotation step
|
||||||
|
5. Match found → heading updated
|
||||||
|
|
||||||
### Test 5: Chunk Rotation Sweeps
|
### Test 5: Chunk Rotation Sweeps
|
||||||
1. Build chunk with 10 images (unknown orientation)
|
1. Build chunk with 10 images (unknown orientation)
|
||||||
2. try_chunk_rotation_steps() with satellite tile
|
2. try_chunk_rotation_steps(chunk_images, satellite_tile, tile_bounds) with all 12 rotations
|
||||||
3. Match found at 120° step
|
3. F09 Metric Refinement called for each rotation
|
||||||
4. Precise angle calculated (122.5°)
|
4. Match found at 120° step
|
||||||
5. Verify all images rotated consistently
|
5. Precise angle calculated (122.5°)
|
||||||
|
6. Verify all images rotated consistently
|
||||||
|
|
||||||
## Non-Functional Requirements
|
## Non-Functional Requirements
|
||||||
|
|
||||||
@@ -479,9 +488,12 @@ return None # No match found
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
### Internal Components
|
### Internal Components
|
||||||
- **F09 Metric Refinement**: For LiteSAM matching during rotation sweep and chunk matching
|
- **F09 Metric Refinement**: For matching during rotation sweep (align_to_satellite, align_chunk_to_satellite). F06 rotates images, F09 performs the actual matching.
|
||||||
- **H07 Image Rotation Utils**: For image rotation and angle calculations
|
- **H07 Image Rotation Utils**: For image rotation and angle calculations
|
||||||
- **F12 Route Chunk Manager**: For chunk image retrieval
|
- **F12 Route Chunk Manager**: For chunk image retrieval
|
||||||
|
- **F03 Flight Database**: For heading persistence
|
||||||
|
|
||||||
|
**Note**: `TileBounds` data model is imported from F09 Metric Refinement.
|
||||||
|
|
||||||
### External Dependencies
|
### External Dependencies
|
||||||
- **opencv-python**: Image rotation (`cv2.warpAffine`)
|
- **opencv-python**: Image rotation (`cv2.warpAffine`)
|
||||||
|
|||||||
@@ -205,18 +205,19 @@ List[TileCandidate] # Re-ranked list
|
|||||||
|
|
||||||
### `initialize_database(satellite_tiles: List[SatelliteTile]) -> bool`
|
### `initialize_database(satellite_tiles: List[SatelliteTile]) -> bool`
|
||||||
|
|
||||||
**Description**: Initializes satellite descriptor database during system startup.
|
**Description**: Loads pre-built satellite descriptor database. **Note**: Semantic index building (DINOv2 descriptors) is performed by the satellite provider service, not during system startup.
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- F02 Flight Manager (during system initialization)
|
- F02 Flight Processor (during system initialization)
|
||||||
|
|
||||||
**Input**:
|
**Input**:
|
||||||
```python
|
```python
|
||||||
List[SatelliteTile]:
|
List[SatelliteTile]:
|
||||||
tile_id: str
|
tile_id: str
|
||||||
image: np.ndarray
|
image: np.ndarray # Optional - only if building index locally
|
||||||
gps_center: GPSPoint
|
gps_center: GPSPoint
|
||||||
bounds: TileBounds
|
bounds: TileBounds
|
||||||
|
descriptor: Optional[np.ndarray] # Pre-computed descriptor from provider
|
||||||
```
|
```
|
||||||
|
|
||||||
**Output**:
|
**Output**:
|
||||||
@@ -225,19 +226,31 @@ bool: True if database initialized successfully
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Processing Flow**:
|
**Processing Flow**:
|
||||||
1. For each satellite tile:
|
1. **Load pre-built index**: Satellite provider provides pre-computed DINOv2 descriptors
|
||||||
- compute_location_descriptor(tile.image) → descriptor
|
2. If descriptors provided:
|
||||||
- Store descriptor with tile metadata
|
- Load descriptors directly
|
||||||
2. Build Faiss index using H04 Faiss Index Manager
|
- Build Faiss index using H04 Faiss Index Manager
|
||||||
3. Persist index to disk for fast startup
|
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
|
||||||
|
|
||||||
|
**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
|
||||||
|
|
||||||
**Performance**:
|
**Performance**:
|
||||||
- Initialization time: ~10-30 minutes for 10,000 tiles (one-time cost)
|
- **Load pre-built index**: <10 seconds (fast startup)
|
||||||
- Can be done offline and loaded at startup
|
- **Build index locally**: ~10-30 minutes for 10,000 tiles (fallback only)
|
||||||
|
|
||||||
**Test Cases**:
|
**Test Cases**:
|
||||||
1. **Initialize with 1000 tiles**: Completes successfully
|
1. **Load pre-built index**: Completes successfully, fast startup
|
||||||
2. **Load pre-built index**: Fast startup (<10s)
|
2. **Fallback local building**: Builds index if provider doesn't supply it
|
||||||
|
3. **Index query**: Works correctly after loading
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -114,12 +114,21 @@ covariance: np.ndarray # (6, 6) - uncertainty
|
|||||||
**Scale Resolution**:
|
**Scale Resolution**:
|
||||||
F07 returns unit translation vectors due to monocular scale ambiguity. F10 resolves scale by:
|
F07 returns unit translation vectors due to monocular scale ambiguity. F10 resolves scale by:
|
||||||
1. Using altitude prior to constrain Z-axis
|
1. Using altitude prior to constrain Z-axis
|
||||||
2. Computing expected displacement from H02 GSD Calculator:
|
2. **Computing expected displacement**: Call H02 GSD Calculator.compute_gsd() to get GSD
|
||||||
- GSD = (sensor_width × altitude) / (focal_length × resolution_width)
|
- GSD = (sensor_width × altitude) / (focal_length × resolution_width)
|
||||||
- expected_displacement ≈ frame_spacing × GSD (typically ~100m)
|
- expected_displacement ≈ frame_spacing × GSD (typically ~100m)
|
||||||
3. Scaling: scaled_translation = unit_translation × expected_displacement
|
3. Scaling: scaled_translation = unit_translation × expected_displacement
|
||||||
4. Global refinement using absolute GPS factors from F09 LiteSAM
|
4. Global refinement using absolute GPS factors from F09 LiteSAM
|
||||||
|
|
||||||
|
**Explicit Flow**:
|
||||||
|
```python
|
||||||
|
# In add_relative_factor():
|
||||||
|
gsd = H02.compute_gsd(altitude, focal_length, sensor_width, image_width)
|
||||||
|
expected_displacement = frame_spacing * gsd # ~100m
|
||||||
|
scaled_translation = relative_pose.translation * expected_displacement
|
||||||
|
# Add scaled_translation to factor graph
|
||||||
|
```
|
||||||
|
|
||||||
**Output**:
|
**Output**:
|
||||||
```python
|
```python
|
||||||
bool: True if factor added successfully
|
bool: True if factor added successfully
|
||||||
@@ -689,7 +698,7 @@ OptimizationResult:
|
|||||||
|
|
||||||
### Internal Components
|
### Internal Components
|
||||||
- **H03 Robust Kernels**: For Huber/Cauchy loss functions
|
- **H03 Robust Kernels**: For Huber/Cauchy loss functions
|
||||||
- **H02 GSD Calculator**: For coordinate conversions
|
- **H02 GSD Calculator**: For GSD computation and scale resolution
|
||||||
|
|
||||||
### External Dependencies
|
### External Dependencies
|
||||||
- **GTSAM**: Graph optimization library
|
- **GTSAM**: Graph optimization library
|
||||||
|
|||||||
+25
-15
@@ -222,7 +222,8 @@ tiles: Dict[str, np.ndarray] # From G04
|
|||||||
**Processing Flow**:
|
**Processing Flow**:
|
||||||
1. Get UAV image for frame_id
|
1. Get UAV image for frame_id
|
||||||
2. For each tile in grid:
|
2. For each tile in grid:
|
||||||
- Call G09.align_to_satellite(uav_image, tile)
|
- Get tile_bounds via F04.compute_tile_bounds(tile_coords)
|
||||||
|
- Call F09.align_to_satellite(uav_image, tile, tile_bounds)
|
||||||
- If match found with confidence > threshold:
|
- If match found with confidence > threshold:
|
||||||
- mark_found(session, result)
|
- mark_found(session, result)
|
||||||
- Return result
|
- Return result
|
||||||
@@ -457,15 +458,17 @@ Optional[ChunkAlignmentResult]: Match result or None
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `merge_chunk_to_trajectory(chunk_id: str, alignment_result: ChunkAlignmentResult) -> bool`
|
### `merge_chunk_to_trajectory(flight_id: str, chunk_id: str, alignment_result: ChunkAlignmentResult) -> bool`
|
||||||
|
|
||||||
**Description**: Merges chunk into main trajectory after successful matching.
|
**Description**: Merges chunk into main trajectory after successful matching.
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- Internal (after chunk LiteSAM matching succeeds)
|
- Internal (after chunk LiteSAM matching succeeds)
|
||||||
|
- process_unanchored_chunks() (which has flight_id from chunk handle)
|
||||||
|
|
||||||
**Input**:
|
**Input**:
|
||||||
```python
|
```python
|
||||||
|
flight_id: str # Flight identifier (available from chunk handle)
|
||||||
chunk_id: str
|
chunk_id: str
|
||||||
alignment_result: ChunkAlignmentResult:
|
alignment_result: ChunkAlignmentResult:
|
||||||
chunk_center_gps: GPSPoint
|
chunk_center_gps: GPSPoint
|
||||||
@@ -479,13 +482,16 @@ bool: True if merge successful
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Processing Flow**:
|
**Processing Flow**:
|
||||||
1. Get chunk anchor frame (middle frame or best frame)
|
1. Get chunk frames via F12.get_chunk_frames(chunk_id) → merged_frames (all frames in chunk that will be updated)
|
||||||
2. Call F12.mark_chunk_anchored() with GPS (F12 coordinates with F10)
|
2. Get chunk anchor frame (middle frame or best frame)
|
||||||
3. Find target chunk (previous chunk or main trajectory)
|
3. Call F12.mark_chunk_anchored() with GPS (F12 coordinates with F10)
|
||||||
4. Call F12.merge_chunks(chunk_id, target_chunk_id, transform) (F12 coordinates with F10)
|
4. Find target chunk (previous chunk or main trajectory)
|
||||||
5. F12 handles chunk state updates (deactivation, status updates)
|
5. Call F12.merge_chunks(chunk_id, target_chunk_id, transform) (F12 coordinates with F10)
|
||||||
6. F10 optimizes merged graph globally (via F12.merge_chunks())
|
6. F12 handles chunk state updates (deactivation, status updates)
|
||||||
7. Return True
|
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
|
||||||
|
9. Return True
|
||||||
|
|
||||||
**Sim(3) Transform**:
|
**Sim(3) Transform**:
|
||||||
- Translation: GPS offset
|
- Translation: GPS offset
|
||||||
@@ -493,9 +499,10 @@ bool: True if merge successful
|
|||||||
- Scale: Resolved from altitude and GSD
|
- Scale: Resolved from altitude and GSD
|
||||||
|
|
||||||
**Test Cases**:
|
**Test Cases**:
|
||||||
1. **Merge chunk**: Chunk merged successfully
|
1. **Merge chunk**: Chunk merged successfully, results updated via F14
|
||||||
2. **Global consistency**: Merged trajectory globally consistent
|
2. **Global consistency**: Merged trajectory globally consistent
|
||||||
3. **Multiple chunks**: Can merge multiple chunks sequentially
|
3. **Multiple chunks**: Can merge multiple chunks sequentially
|
||||||
|
4. **Result updates**: All merged frames have updated GPS coordinates published
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -525,15 +532,17 @@ while flight_active:
|
|||||||
if candidates:
|
if candidates:
|
||||||
alignment = try_chunk_litesam_matching(chunk.chunk_id, candidates)
|
alignment = try_chunk_litesam_matching(chunk.chunk_id, candidates)
|
||||||
if alignment:
|
if alignment:
|
||||||
merge_chunk_to_trajectory(chunk.chunk_id, alignment)
|
merge_chunk_to_trajectory(chunk.flight_id, chunk.chunk_id, alignment)
|
||||||
sleep(5 seconds)
|
sleep(5 seconds)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Background Processing**:
|
**Background Processing**:
|
||||||
|
- **Trigger**: Started by F02 Flight Processor after flight creation
|
||||||
- Runs asynchronously, doesn't block frame processing
|
- Runs asynchronously, doesn't block frame processing
|
||||||
- Periodically checks for ready chunks
|
- Periodically checks for ready chunks (every 5 seconds)
|
||||||
- Attempts matching and merging
|
- Attempts matching and merging
|
||||||
- Reduces user input requests
|
- Reduces user input requests
|
||||||
|
- **Lifecycle**: Starts when flight becomes active, stops when flight completed
|
||||||
|
|
||||||
**Test Cases**:
|
**Test Cases**:
|
||||||
1. **Background matching**: Unanchored chunks matched asynchronously
|
1. **Background matching**: Unanchored chunks matched asynchronously
|
||||||
@@ -606,14 +615,15 @@ while flight_active:
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
### Internal Components
|
### Internal Components
|
||||||
- F04 Satellite Data Manager (tile grids)
|
- F04 Satellite Data Manager (tile grids and tile_bounds computation)
|
||||||
- F06 Image Rotation Manager (rotation sweep and chunk rotation)
|
- F06 Image Rotation Manager (rotation sweep and chunk rotation)
|
||||||
- F08 Global Place Recognition (candidates and chunk semantic matching)
|
- F08 Global Place Recognition (candidates and chunk semantic matching)
|
||||||
- F09 Metric Refinement (LiteSAM and chunk LiteSAM matching)
|
- F09 Metric Refinement (LiteSAM and chunk LiteSAM matching)
|
||||||
- F10 Factor Graph Optimizer (anchor application and chunk merging)
|
- F10 Factor Graph Optimizer (anchor application and chunk merging)
|
||||||
- F02 Flight Manager (status updates)
|
|
||||||
- F14 SSE Event Streamer (user input events)
|
|
||||||
- F12 Route Chunk Manager (chunk lifecycle)
|
- 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)
|
||||||
|
|
||||||
### External Dependencies
|
### External Dependencies
|
||||||
- None
|
- None
|
||||||
|
|||||||
@@ -462,13 +462,15 @@ bool: True if merge successful
|
|||||||
1. Verify both chunks exist
|
1. Verify both chunks exist
|
||||||
2. Verify chunk_id_1 is anchored (has_anchor=True)
|
2. Verify chunk_id_1 is anchored (has_anchor=True)
|
||||||
3. Validate chunks can be merged (not already merged, not same chunk)
|
3. Validate chunks can be merged (not already merged, not same chunk)
|
||||||
4. Call F10.merge_chunks(chunk_id_1, chunk_id_2, transform)
|
4. **Merge direction**: chunk_id_1 (newer, source) merges INTO chunk_id_2 (older, target)
|
||||||
5. Update chunk_id_1 state:
|
5. Call F10.merge_chunks(chunk_id_1, chunk_id_2, transform)
|
||||||
|
6. Update chunk_id_1 state:
|
||||||
- Set is_active=False
|
- Set is_active=False
|
||||||
- Set matching_status="merged"
|
- Set matching_status="merged"
|
||||||
- Call deactivate_chunk(chunk_id_1)
|
- Call deactivate_chunk(chunk_id_1)
|
||||||
6. Update chunk_id_2 state (if needed)
|
7. Update chunk_id_2 state (if needed)
|
||||||
7. Return True
|
8. Persist chunk state via F03 Flight Database.save_chunk_state()
|
||||||
|
9. Return True
|
||||||
|
|
||||||
**Validation**:
|
**Validation**:
|
||||||
- Both chunks must exist
|
- Both chunks must exist
|
||||||
@@ -476,6 +478,11 @@ bool: True if merge successful
|
|||||||
- chunk_id_1 must not already be merged
|
- chunk_id_1 must not already be merged
|
||||||
- chunk_id_1 and chunk_id_2 must be different
|
- chunk_id_1 and chunk_id_2 must be different
|
||||||
|
|
||||||
|
**Merge Direction**:
|
||||||
|
- **chunk_id_1**: Source chunk (newer, recently anchored)
|
||||||
|
- **chunk_id_2**: Target chunk (older, main trajectory or previous chunk)
|
||||||
|
- Newer chunks merge INTO older chunks to maintain chronological consistency
|
||||||
|
|
||||||
**Test Cases**:
|
**Test Cases**:
|
||||||
1. **Merge anchored chunks**: Chunks merged successfully, chunk_id_1 deactivated
|
1. **Merge anchored chunks**: Chunks merged successfully, chunk_id_1 deactivated
|
||||||
2. **Merge unanchored chunk**: Returns False (validation fails)
|
2. **Merge unanchored chunk**: Returns False (validation fails)
|
||||||
@@ -570,6 +577,7 @@ bool: True if marked successfully
|
|||||||
- **F05 Image Input Pipeline**: Image retrieval
|
- **F05 Image Input Pipeline**: Image retrieval
|
||||||
- **F08 Global Place Recognition**: Descriptor computation
|
- **F08 Global Place Recognition**: Descriptor computation
|
||||||
- **F07 Sequential VO**: VO results for chunk building
|
- **F07 Sequential VO**: VO results for chunk building
|
||||||
|
- **F03 Flight Database**: Chunk state persistence
|
||||||
|
|
||||||
### External Dependencies
|
### External Dependencies
|
||||||
- **numpy**: Array operations
|
- **numpy**: Array operations
|
||||||
|
|||||||
@@ -68,26 +68,32 @@ class ICoordinateTransformer(ABC):
|
|||||||
|
|
||||||
### ENU Origin Management
|
### ENU Origin Management
|
||||||
|
|
||||||
#### `set_enu_origin(origin_gps: GPSPoint) -> None`
|
#### `set_enu_origin(flight_id: str, origin_gps: GPSPoint) -> None`
|
||||||
|
|
||||||
**Description**: Sets the ENU (East-North-Up) coordinate system origin. Called once during flight creation using the flight's start_gps.
|
**Description**: Sets the ENU (East-North-Up) coordinate system origin for a specific flight. Called once during flight creation using the flight's start_gps.
|
||||||
|
|
||||||
|
**Why ENU Origin?**: Factor graph optimization works in Cartesian coordinates (meters) for better numerical stability. ENU converts GPS (degrees) to local meters relative to an origin. See `helpers/enu_origin_explanation.md` for details.
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- F02 Flight Processor (during create_flight)
|
- F02 Flight Processor (during create_flight)
|
||||||
|
|
||||||
**Input**:
|
**Input**:
|
||||||
```python
|
```python
|
||||||
|
flight_id: str # Flight identifier
|
||||||
origin_gps: GPSPoint
|
origin_gps: GPSPoint
|
||||||
lat: float # Origin latitude in WGS84
|
lat: float # Origin latitude in WGS84 (flight start_gps)
|
||||||
lon: float # Origin longitude in WGS84
|
lon: float # Origin longitude in WGS84 (flight start_gps)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Processing Flow**:
|
**Processing Flow**:
|
||||||
1. Store origin_gps as ENU origin
|
1. Store origin_gps as ENU origin for flight_id
|
||||||
2. Precompute conversion factors for lat/lon to meters
|
2. Precompute conversion factors for lat/lon to meters at origin latitude
|
||||||
3. All subsequent ENU operations use this origin
|
3. All subsequent ENU operations for this flight use this origin
|
||||||
|
|
||||||
**Important**: The ENU origin is set to the flight's start_gps during flight creation and remains constant for the entire flight duration.
|
**Important**:
|
||||||
|
- Each flight has its own ENU origin (the flight's start_gps)
|
||||||
|
- Origin remains constant for the entire flight duration
|
||||||
|
- All frames in the flight use the same origin for ENU conversions
|
||||||
|
|
||||||
**Test Cases**:
|
**Test Cases**:
|
||||||
1. **Set origin**: Store origin GPS
|
1. **Set origin**: Store origin GPS
|
||||||
@@ -96,13 +102,18 @@ origin_gps: GPSPoint
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### `get_enu_origin() -> GPSPoint`
|
#### `get_enu_origin(flight_id: str) -> GPSPoint`
|
||||||
|
|
||||||
**Description**: Returns the currently set ENU origin.
|
**Description**: Returns the ENU origin for a specific flight.
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- F10 Factor Graph Optimizer (for coordinate checks)
|
- F10 Factor Graph Optimizer (for coordinate checks)
|
||||||
- F13 Result Manager (for reference)
|
- F14 Result Manager (for reference)
|
||||||
|
|
||||||
|
**Input**:
|
||||||
|
```python
|
||||||
|
flight_id: str
|
||||||
|
```
|
||||||
|
|
||||||
**Output**:
|
**Output**:
|
||||||
```python
|
```python
|
||||||
@@ -110,7 +121,7 @@ GPSPoint: The ENU origin (flight start_gps)
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Error Conditions**:
|
**Error Conditions**:
|
||||||
- Raises `OriginNotSetError` if called before set_enu_origin()
|
- Raises `OriginNotSetError` if called before set_enu_origin() for this flight_id
|
||||||
|
|
||||||
**Test Cases**:
|
**Test Cases**:
|
||||||
1. **After set_enu_origin**: Returns stored origin
|
1. **After set_enu_origin**: Returns stored origin
|
||||||
@@ -118,9 +129,9 @@ GPSPoint: The ENU origin (flight start_gps)
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### `gps_to_enu(gps: GPSPoint) -> Tuple[float, float, float]`
|
#### `gps_to_enu(flight_id: str, gps: GPSPoint) -> Tuple[float, float, float]`
|
||||||
|
|
||||||
**Description**: Converts GPS coordinates to ENU (East, North, Up) relative to the set origin.
|
**Description**: Converts GPS coordinates to ENU (East, North, Up) relative to the flight's ENU origin.
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- F10 Factor Graph Optimizer (for absolute factors)
|
- F10 Factor Graph Optimizer (for absolute factors)
|
||||||
@@ -128,6 +139,7 @@ GPSPoint: The ENU origin (flight start_gps)
|
|||||||
|
|
||||||
**Input**:
|
**Input**:
|
||||||
```python
|
```python
|
||||||
|
flight_id: str # Flight identifier
|
||||||
gps: GPSPoint
|
gps: GPSPoint
|
||||||
lat: float
|
lat: float
|
||||||
lon: float
|
lon: float
|
||||||
@@ -135,7 +147,7 @@ gps: GPSPoint
|
|||||||
|
|
||||||
**Output**:
|
**Output**:
|
||||||
```python
|
```python
|
||||||
Tuple[float, float, float]: (east, north, up) in meters relative to origin
|
Tuple[float, float, float]: (east, north, up) in meters relative to flight's origin
|
||||||
```
|
```
|
||||||
|
|
||||||
**Algorithm**:
|
**Algorithm**:
|
||||||
@@ -153,17 +165,18 @@ Tuple[float, float, float]: (east, north, up) in meters relative to origin
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### `enu_to_gps(enu: Tuple[float, float, float]) -> GPSPoint`
|
#### `enu_to_gps(flight_id: str, enu: Tuple[float, float, float]) -> GPSPoint`
|
||||||
|
|
||||||
**Description**: Converts ENU coordinates back to GPS.
|
**Description**: Converts ENU coordinates back to GPS using the flight's ENU origin.
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- F10 Factor Graph Optimizer (for get_trajectory)
|
- F10 Factor Graph Optimizer (for get_trajectory)
|
||||||
- F13 Result Manager (for publishing GPS results)
|
- F14 Result Manager (for publishing GPS results)
|
||||||
|
|
||||||
**Input**:
|
**Input**:
|
||||||
```python
|
```python
|
||||||
enu: Tuple[float, float, float] # (east, north, up) in meters
|
flight_id: str # Flight identifier
|
||||||
|
enu: Tuple[float, float, float] # (east, north, up) in meters relative to flight's origin
|
||||||
```
|
```
|
||||||
|
|
||||||
**Output**:
|
**Output**:
|
||||||
@@ -420,7 +433,6 @@ List[Tuple[float, float]]: Transformed points
|
|||||||
|
|
||||||
### Internal Components
|
### Internal Components
|
||||||
- **F10 Factor Graph Optimizer**: For frame poses
|
- **F10 Factor Graph Optimizer**: For frame poses
|
||||||
- **F12 Route Chunk Manager**: For chunk context (chunk-aware coordinate transforms)
|
|
||||||
- **F17 Configuration Manager**: For camera parameters
|
- **F17 Configuration Manager**: For camera parameters
|
||||||
- **H01 Camera Model**: For projection operations
|
- **H01 Camera Model**: For projection operations
|
||||||
- **H02 GSD Calculator**: For GSD calculations
|
- **H02 GSD Calculator**: For GSD calculations
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class IResultManager(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def publish_to_route_api(self, flight_id: str, frame_id: int) -> bool:
|
def publish_waypoint_update(self, flight_id: str, frame_id: int) -> bool:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@@ -34,14 +34,14 @@ class IResultManager(ABC):
|
|||||||
### Responsibilities
|
### Responsibilities
|
||||||
- Manage trajectory results per flight
|
- Manage trajectory results per flight
|
||||||
- Track frame refinements and changes
|
- Track frame refinements and changes
|
||||||
- Trigger per-frame Route API updates via G03
|
- Store waypoint updates via F03 Flight Database
|
||||||
- Send incremental updates via F14 SSE
|
- Send incremental updates via F15 SSE Event Streamer
|
||||||
- Maintain result versioning for audit trail
|
- Maintain result versioning for audit trail
|
||||||
- Convert optimized poses to GPS coordinates
|
- Convert optimized poses to GPS coordinates
|
||||||
|
|
||||||
### Scope
|
### Scope
|
||||||
- Result state management
|
- Result state management
|
||||||
- Route API integration
|
- Flight Database integration (waypoint storage)
|
||||||
- SSE event triggering
|
- SSE event triggering
|
||||||
- Incremental update detection
|
- Incremental update detection
|
||||||
- Result persistence
|
- Result persistence
|
||||||
@@ -73,9 +73,9 @@ result: FrameResult:
|
|||||||
**Output**: `bool` - True if updated
|
**Output**: `bool` - True if updated
|
||||||
|
|
||||||
**Processing Flow**:
|
**Processing Flow**:
|
||||||
1. Store result in memory/database
|
1. Store result via F03 Flight Database.save_frame_result()
|
||||||
2. Call publish_to_route_api()
|
2. Call publish_waypoint_update()
|
||||||
3. Call G14.send_frame_result()
|
3. Call F15 SSE Event Streamer.send_frame_result()
|
||||||
4. Update flight statistics
|
4. Update flight statistics
|
||||||
|
|
||||||
**Test Cases**:
|
**Test Cases**:
|
||||||
@@ -84,9 +84,9 @@ result: FrameResult:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `publish_to_route_api(flight_id: str, frame_id: int) -> bool`
|
### `publish_waypoint_update(flight_id: str, frame_id: int) -> bool`
|
||||||
|
|
||||||
**Description**: Sends frame GPS to Route API via G03 client.
|
**Description**: Updates waypoint in Flight Database via F03.
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- Internal (after update_frame_result)
|
- Internal (after update_frame_result)
|
||||||
@@ -97,17 +97,17 @@ flight_id: str
|
|||||||
frame_id: int
|
frame_id: int
|
||||||
```
|
```
|
||||||
|
|
||||||
**Output**: `bool` - True if published successfully
|
**Output**: `bool` - True if updated successfully
|
||||||
|
|
||||||
**Processing Flow**:
|
**Processing Flow**:
|
||||||
1. Get result for frame_id
|
1. Get result for frame_id
|
||||||
2. Convert to Waypoint format
|
2. Convert to Waypoint format
|
||||||
3. Call G03.update_route_waypoint()
|
3. Call F03 Flight Database.update_waypoint()
|
||||||
4. Handle errors (retry if transient)
|
4. Handle errors (retry if transient)
|
||||||
|
|
||||||
**Test Cases**:
|
**Test Cases**:
|
||||||
1. Successful publish → Route API updated
|
1. Successful update → Waypoint stored in database
|
||||||
2. Route API unavailable → logs error, continues
|
2. Database unavailable → logs error, continues
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -151,11 +151,11 @@ frame_ids: List[int] # Frames with updated poses
|
|||||||
|
|
||||||
**Processing Flow**:
|
**Processing Flow**:
|
||||||
1. For each frame_id:
|
1. For each frame_id:
|
||||||
- Get refined pose from F10
|
- Get refined pose from F10 Factor Graph Optimizer → ENU pose
|
||||||
- Convert to GPS via G12
|
- Convert ENU pose to GPS via F13 Coordinate Transformer.enu_to_gps(flight_id, enu_pose)
|
||||||
- Update result with refined=True
|
- Update result with refined=True via F03 Flight Database.save_frame_result()
|
||||||
- publish_to_route_api()
|
- Update waypoint via F03 Flight Database.update_waypoint()
|
||||||
- Call G14.send_refinement()
|
- Call F15 SSE Event Streamer.send_refinement()
|
||||||
|
|
||||||
**Test Cases**:
|
**Test Cases**:
|
||||||
1. Batch refinement → all frames updated and published
|
1. Batch refinement → all frames updated and published
|
||||||
@@ -167,7 +167,7 @@ frame_ids: List[int] # Frames with updated poses
|
|||||||
**Description**: Gets frames changed since timestamp (for incremental updates).
|
**Description**: Gets frames changed since timestamp (for incremental updates).
|
||||||
|
|
||||||
**Called By**:
|
**Called By**:
|
||||||
- F14 SSE Event Streamer (for reconnection replay)
|
- F15 SSE Event Streamer (for reconnection replay)
|
||||||
|
|
||||||
**Input**:
|
**Input**:
|
||||||
```python
|
```python
|
||||||
@@ -181,19 +181,49 @@ since: datetime
|
|||||||
1. Get changes → returns only modified frames
|
1. Get changes → returns only modified frames
|
||||||
2. No changes → returns empty list
|
2. No changes → returns empty list
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `update_results_after_chunk_merge(flight_id: str, merged_frames: List[int]) -> bool`
|
||||||
|
|
||||||
|
**Description**: Updates frame results after chunk merging changes frame poses.
|
||||||
|
|
||||||
|
**Called By**:
|
||||||
|
- F11 Failure Recovery Coordinator (after chunk merging)
|
||||||
|
|
||||||
|
**Input**:
|
||||||
|
```python
|
||||||
|
flight_id: str
|
||||||
|
merged_frames: List[int] # Frames whose poses changed due to chunk merge
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output**: `bool` - True if updated successfully
|
||||||
|
|
||||||
|
**Processing Flow**:
|
||||||
|
1. For each frame_id in merged_frames:
|
||||||
|
- Get updated pose from F10 Factor Graph Optimizer.get_trajectory() → ENU pose
|
||||||
|
- Convert ENU pose to GPS via F13 Coordinate Transformer.enu_to_gps(flight_id, enu_pose)
|
||||||
|
- Update frame result via F03 Flight Database.save_frame_result()
|
||||||
|
- Update waypoint via F03 Flight Database.update_waypoint()
|
||||||
|
- Send refinement event via F15 SSE Event Streamer.send_refinement()
|
||||||
|
2. Return True
|
||||||
|
|
||||||
|
**Test Cases**:
|
||||||
|
1. **Chunk merge updates**: All merged frames updated and published
|
||||||
|
2. **GPS accuracy**: Updated GPS matches optimized poses
|
||||||
|
|
||||||
## Integration Tests
|
## Integration Tests
|
||||||
|
|
||||||
### Test 1: Per-Frame Processing
|
### Test 1: Per-Frame Processing
|
||||||
1. Process frame 237
|
1. Process frame 237
|
||||||
2. update_frame_result() → stores result
|
2. update_frame_result() → stores result
|
||||||
3. Verify publish_to_route_api() called
|
3. Verify publish_waypoint_update() called (F03.update_waypoint())
|
||||||
4. Verify F14 SSE event sent
|
4. Verify F15 SSE event sent
|
||||||
|
|
||||||
### Test 2: Batch Refinement
|
### Test 2: Batch Refinement
|
||||||
1. Process 100 frames
|
1. Process 100 frames
|
||||||
2. Factor graph refines frames 10-50
|
2. Factor graph refines frames 10-50
|
||||||
3. mark_refined([10-50]) → updates all
|
3. mark_refined([10-50]) → updates all
|
||||||
4. Verify Route API updated
|
4. Verify Flight Database updated (F03.batch_update_waypoints())
|
||||||
5. Verify SSE refinement events sent
|
5. Verify SSE refinement events sent
|
||||||
|
|
||||||
### Test 3: Incremental Updates
|
### Test 3: Incremental Updates
|
||||||
@@ -207,22 +237,22 @@ since: datetime
|
|||||||
|
|
||||||
### Performance
|
### Performance
|
||||||
- **update_frame_result**: < 50ms
|
- **update_frame_result**: < 50ms
|
||||||
- **publish_to_route_api**: < 100ms (non-blocking)
|
- **publish_waypoint_update**: < 100ms (non-blocking)
|
||||||
- **get_flight_results**: < 200ms for 2000 frames
|
- **get_flight_results**: < 200ms for 2000 frames
|
||||||
|
|
||||||
### Reliability
|
### Reliability
|
||||||
- Result persistence survives crashes
|
- Result persistence survives crashes
|
||||||
- Guaranteed at-least-once delivery to Route API
|
- Guaranteed at-least-once delivery to Flight Database
|
||||||
- Idempotent updates
|
- Idempotent updates
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
### Internal Components
|
### Internal Components
|
||||||
- G03 Route API Client
|
- **F03 Flight Database**: For waypoint and frame result persistence
|
||||||
- F10 Factor Graph Optimizer
|
- **F10 Factor Graph Optimizer**: For refined pose retrieval
|
||||||
- F12 Coordinate Transformer
|
- **F13 Coordinate Transformer**: For ENU to GPS conversion
|
||||||
- F14 SSE Event Streamer
|
- **F15 SSE Event Streamer**: For real-time result streaming
|
||||||
- F17 Database Layer
|
- **F11 Failure Recovery Coordinator**: Triggers chunk merge result updates
|
||||||
|
|
||||||
### External Dependencies
|
### External Dependencies
|
||||||
- None
|
- None
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
<root>
|
<root>
|
||||||
<mxCell id="0"/>
|
<mxCell id="0"/>
|
||||||
<mxCell id="1" parent="0"/>
|
<mxCell id="1" parent="0"/>
|
||||||
<mxCell id="title" value="ASTRAL-Next System Architecture GPS-Denied Localization for UAVs 29 Components: Route API (4) + GPS-Denied 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">
|
<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="1000" height="80" as="geometry"/>
|
<mxGeometry x="200" y="20" width="1200" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</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">
|
<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"/>
|
<mxGeometry x="200" y="110" width="600" height="350" as="geometry"/>
|
||||||
@@ -37,84 +37,84 @@
|
|||||||
<mxCell id="r04-db" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="route-api-lane" source="r04" target="route-db" edge="1">
|
<mxCell id="r04-db" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="route-api-lane" source="r04" target="route-db" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="gps-denied-lane" value="GPS-Denied API (Main Processing System)" style="swimlane;horizontal=1;whiteSpace=wrap;html=1;fontSize=14;fontStyle=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="1" vertex="1">
|
<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="1200" height="2200" as="geometry"/>
|
<mxGeometry x="130" y="500" width="1400" height="2400" as="geometry"/>
|
||||||
</mxCell>
|
</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">
|
<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"/>
|
<mxGeometry x="20" y="40" width="560" height="140" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g01" value="G01 GPS-Denied REST API" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="core-layer" vertex="1">
|
<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"/>
|
<mxGeometry x="20" y="40" width="150" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g02" value="G02 Flight Manager" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="core-layer" vertex="1">
|
<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="60" as="geometry"/>
|
<mxGeometry x="200" y="40" width="150" height="70" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g03" value="G03 Route API Client" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="core-layer" vertex="1">
|
<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"/>
|
<mxGeometry x="380" y="40" width="150" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g01-g02" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="core-layer" source="g01" target="g02" edge="1">
|
<mxCell id="f01-f02" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="core-layer" source="f01" target="f02" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</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">
|
<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"/>
|
<mxGeometry x="600" y="40" width="560" height="140" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g04" value="G04 Satellite Data Manager (fetch, cache, grid)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="data-layer" vertex="1">
|
<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"/>
|
<mxGeometry x="20" y="40" width="160" height="70" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g05" value="G05 Image Input Pipeline (queue, validate, store)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="data-layer" vertex="1">
|
<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"/>
|
<mxGeometry x="200" y="40" width="160" height="70" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g06" value="G06 Image Rotation Mgr (30° sweep, heading)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="data-layer" vertex="1">
|
<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"/>
|
<mxGeometry x="380" y="40" width="160" height="70" as="geometry"/>
|
||||||
</mxCell>
|
</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">
|
<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"/>
|
<mxGeometry x="20" y="200" width="560" height="140" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g07" value="G07 Sequential VO (SuperPoint+LightGlue)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="visual-layer" vertex="1">
|
<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="70" as="geometry"/>
|
<mxGeometry x="20" y="40" width="160" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g08" value="G08 Global Place Recognition (AnyLoc DINOv2)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="visual-layer" vertex="1">
|
<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="70" as="geometry"/>
|
<mxGeometry x="200" y="40" width="160" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g09" value="G09 Metric Refinement (LiteSAM)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="visual-layer" vertex="1">
|
<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="70" as="geometry"/>
|
<mxGeometry x="380" y="40" width="160" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="state-layer" value="State Estimation & Coordination" style="swimlane;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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="560" height="140" as="geometry"/>
|
<mxGeometry x="600" y="200" width="760" height="200" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g10" value="G10 Factor Graph Optimizer (GTSAM iSAM2)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="state-layer" vertex="1">
|
<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="70" as="geometry"/>
|
<mxGeometry x="20" y="40" width="160" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g11" value="G11 Failure Recovery (Progressive 1→25)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="state-layer" vertex="1">
|
<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="70" as="geometry"/>
|
<mxGeometry x="200" y="40" width="160" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g12" value="G12 Coordinate Transform (Pixel↔GPS)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="state-layer" vertex="1">
|
<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="70" as="geometry"/>
|
<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>
|
||||||
<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">
|
<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"/>
|
<mxGeometry x="20" y="360" width="380" height="140" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g13" value="G13 Result Manager" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="results-layer" vertex="1">
|
<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"/>
|
<mxGeometry x="20" y="40" width="150" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g14" value="G14 SSE Event Streamer" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="results-layer" vertex="1">
|
<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"/>
|
<mxGeometry x="200" y="40" width="150" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g13-g14" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="results-layer" source="g13" target="g14" edge="1">
|
<mxCell id="f14-f15" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="results-layer" source="f14" target="f15" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</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">
|
<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"/>
|
<mxGeometry x="420" y="360" width="740" height="140" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g15" value="G15 Model Manager (TensorRT/ONNX)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#424242;strokeColor=#BDBDBD;fontColor=#ffffff;" parent="infra-layer" vertex="1">
|
<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"/>
|
<mxGeometry x="20" y="40" width="160" height="70" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g16" value="G16 Configuration Mgr" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#424242;strokeColor=#BDBDBD;fontColor=#ffffff;" parent="infra-layer" vertex="1">
|
<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"/>
|
<mxGeometry x="200" y="40" width="160" height="70" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g17" value="G17 GPS-Denied DB Layer" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#424242;strokeColor=#BDBDBD;fontColor=#ffffff;" parent="infra-layer" vertex="1">
|
|
||||||
<mxGeometry x="380" 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">
|
<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"/>
|
<mxGeometry x="570" y="30" width="140" height="90" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
@@ -149,37 +149,40 @@
|
|||||||
<mxGeometry x="20" y="700" width="200" height="30" as="geometry"/>
|
<mxGeometry x="20" y="700" width="200" height="30" as="geometry"/>
|
||||||
</mxCell>
|
</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">
|
<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="1140" height="600" as="geometry"/>
|
<mxGeometry x="20" y="740" width="1340" height="800" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="flow-1" value="1. Client uploads batch G01 → G05" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1565C0;strokeColor=#64B5F6;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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"/>
|
<mxGeometry x="40" y="760" width="160" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="flow-2" value="2. Get next image G05 → G06" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1565C0;strokeColor=#64B5F6;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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"/>
|
<mxGeometry x="230" y="760" width="160" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="flow-3" value="3. Rotation preprocessing G06 (30° sweep if needed)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#B8860B;strokeColor=#FFD54F;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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"/>
|
<mxGeometry x="420" y="760" width="180" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="flow-4" value="4. Sequential VO G07 (SuperPoint+LightGlue)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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="180" height="60" as="geometry"/>
|
<mxGeometry x="630" y="760" width="200" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="flow-5" value="5. Check confidence G11 Failure Recovery" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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="840" y="760" width="180" height="60" as="geometry"/>
|
<mxGeometry x="860" y="760" width="180" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="flow-6a" value="6a. IF GOOD: LiteSAM (1 tile) G09 drift correction" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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="860" width="200" height="60" as="geometry"/>
|
<mxGeometry x="40" y="880" width="200" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="flow-6b" value="6b. IF LOST: Progressive search G11 → G04 (1→4→9→16→25) G08 Global PR + G09 LiteSAM" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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="860" width="220" height="80" as="geometry"/>
|
<mxGeometry x="270" y="880" width="240" height="100" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="flow-7" value="7. Factor Graph optimize G10 (fuse VO + GPS)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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="520" y="860" width="180" height="60" as="geometry"/>
|
<mxGeometry x="540" y="880" width="220" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="flow-8" value="8. Coordinate transform G12 (Pixel → GPS)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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="730" y="860" width="180" height="60" as="geometry"/>
|
<mxGeometry x="790" y="880" width="200" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="flow-9" value="9. Publish results G13 → G03 (Route API) G13 → G14 (SSE to client)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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="940" y="860" width="180" height="80" as="geometry"/>
|
<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>
|
||||||
<mxCell id="arrow-1-2" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-1" target="flow-2" edge="1">
|
<mxCell id="arrow-1-2" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-1" target="flow-2" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
@@ -199,29 +202,65 @@
|
|||||||
<mxCell id="arrow-5-6b" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-5" target="flow-6b" edge="1">
|
<mxCell id="arrow-5-6b" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-5" target="flow-6b" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
|
<mxCell id="arrow-5-6c" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-5" target="flow-6c" edge="1">
|
||||||
|
<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="arrow-6a-7" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-6a" target="flow-7" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</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="arrow-6b-7" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-6b" target="flow-7" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</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">
|
<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"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="arrow-8-9" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="flow-8" target="flow-9" edge="1">
|
<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"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</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">
|
<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="980" width="400" height="30" as="geometry"/>
|
<mxGeometry x="40" y="1160" width="400" height="30" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="user-1" value="G11 exhausted (grid=25) → G14 send user_input_needed" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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="1020" width="240" height="70" as="geometry"/>
|
<mxGeometry x="40" y="1200" width="240" height="70" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="user-2" value="Client responds G01 → G11 apply_user_anchor" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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="1020" width="240" height="70" as="geometry"/>
|
<mxGeometry x="310" y="1200" width="240" height="70" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="user-3" value="G11 → G10 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">
|
<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="1020" width="240" height="70" as="geometry"/>
|
<mxGeometry x="580" y="1200" width="240" height="70" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="arrow-user-1-2" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="user-1" target="user-2" edge="1">
|
<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"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
@@ -230,16 +269,16 @@
|
|||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</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">
|
<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="1130" width="350" height="30" as="geometry"/>
|
<mxGeometry x="40" y="1310" width="350" height="30" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="async-1" value="G10 back-propagates new absolute factors" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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="1170" width="220" height="60" as="geometry"/>
|
<mxGeometry x="40" y="1350" width="220" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="async-2" value="G13 detect changed frames → G03 batch_update_waypoints" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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="1170" width="240" height="60" as="geometry"/>
|
<mxGeometry x="290" y="1350" width="240" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="async-3" value="G13 → G14 send frame_refined events" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="gps-denied-lane" vertex="1">
|
<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="1170" width="220" height="60" as="geometry"/>
|
<mxGeometry x="560" y="1350" width="220" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="arrow-async-1-2" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="gps-denied-lane" source="async-1" target="async-2" edge="1">
|
<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"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
@@ -256,21 +295,30 @@
|
|||||||
<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">
|
<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"/>
|
<mxGeometry x="1340" y="800" width="160" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="client-g01" value="HTTP REST" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="client" target="g01" edge="1">
|
<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"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g03-route" value="Per-frame waypoint updates" style="edgeStyle=orthogonalEdgeStyle;curved=1;dashed=1;strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="g03" target="r01" edge="1">
|
<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"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g04-sat" value="Fetch tiles" style="strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="g04" target="satellite-provider" edge="1">
|
<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">
|
<mxGeometry x="0.3759" y="-10" relative="1" as="geometry">
|
||||||
<mxPoint as="offset"/>
|
<mxPoint as="offset"/>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="g14-client" value="SSE Events" style="dashed=1;strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="g14" target="client" edge="1">
|
<mxCell id="f15-client" value="SSE Events" style="dashed=1;strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="f15" target="client" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="detector-g12" value="Object pixels → GPS" style="dashed=1;strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="external-detector" target="g12" edge="1">
|
<mxCell id="detector-f13" value="Object pixels → GPS" style="dashed=1;strokeColor=#FFFFFF;fontColor=#ffffff;" parent="1" source="external-detector" target="f13" edge="1">
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
<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"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</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">
|
<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">
|
||||||
@@ -282,9 +330,12 @@
|
|||||||
<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">
|
<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"/>
|
<mxGeometry x="120" y="2790" width="140" height="40" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="legend-2" value="GPS-Denied Core/API" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="1" vertex="1">
|
<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"/>
|
<mxGeometry x="280" y="2790" width="140" height="40" as="geometry"/>
|
||||||
</mxCell>
|
</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">
|
<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"/>
|
<mxGeometry x="440" y="2790" width="140" height="40" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
|
|||||||
@@ -1,440 +0,0 @@
|
|||||||
# Chunking System Assessment: F12 Route Chunk Manager and Integration
|
|
||||||
|
|
||||||
## Executive Summary
|
|
||||||
|
|
||||||
The chunking system implements the Atlas multi-map architecture from the solution document, with **F12 Route Chunk Manager** serving as the high-level coordinator. The system demonstrates **strong coherence** with clear separation of concerns between F12 (lifecycle), F10 (factor graph), and F11 (matching coordination). However, there are some **integration inconsistencies** and **missing lifecycle transitions** that should be addressed.
|
|
||||||
|
|
||||||
**Overall Assessment: 8/10** - Well-designed with minor gaps
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Architecture Coherence
|
|
||||||
|
|
||||||
### 1.1 Separation of Concerns ✅
|
|
||||||
|
|
||||||
The chunking system properly separates responsibilities:
|
|
||||||
|
|
||||||
| Component | Responsibility | Level |
|
|
||||||
|-----------|---------------|-------|
|
|
||||||
| **F12 Route Chunk Manager** | Chunk lifecycle, state tracking, matching coordination | High-level (flight context) |
|
|
||||||
| **F10 Factor Graph Optimizer** | Chunk subgraphs, factor management, optimization | Low-level (factor graph) |
|
|
||||||
| **F11 Failure Recovery Coordinator** | Chunk creation triggers, matching orchestration | Coordination layer |
|
|
||||||
| **F02 Flight Processor** | Chunk-aware frame processing | Application layer |
|
|
||||||
|
|
||||||
**Assessment:** ✅ **Excellent separation** - Clear boundaries, no overlap
|
|
||||||
|
|
||||||
### 1.2 Chunk Lifecycle Completeness
|
|
||||||
|
|
||||||
**Lifecycle States:**
|
|
||||||
- `unanchored` → `matching` → `anchored` → `merged`
|
|
||||||
|
|
||||||
**Lifecycle Methods:**
|
|
||||||
|
|
||||||
| State Transition | F12 Method | F10 Method | Status |
|
|
||||||
|------------------|------------|------------|--------|
|
|
||||||
| **Creation** | `create_chunk()` | `create_new_chunk()` | ✅ Complete |
|
|
||||||
| **Building** | `add_frame_to_chunk()` | `add_relative_factor_to_chunk()` | ✅ Complete |
|
|
||||||
| **Matching** | `is_chunk_ready_for_matching()` | N/A | ✅ Complete |
|
|
||||||
| **Anchoring** | `mark_chunk_anchored()` | `add_chunk_anchor()` | ✅ Complete |
|
|
||||||
| **Merging** | `deactivate_chunk()` | `merge_chunks()` | ⚠️ **Gap** |
|
|
||||||
| **Deactivation** | `deactivate_chunk()` | N/A | ✅ Complete |
|
|
||||||
|
|
||||||
**Status:** ✅ **Fixed** - Added `F12.merge_chunks()` method for chunk merging coordination
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Integration Analysis
|
|
||||||
|
|
||||||
### 2.1 F12 ↔ F10 Integration
|
|
||||||
|
|
||||||
**F12 calls F10:**
|
|
||||||
- ✅ `create_chunk()` → `F10.create_new_chunk()` - Correct
|
|
||||||
- ✅ `add_frame_to_chunk()` → `F10.add_relative_factor_to_chunk()` - Correct
|
|
||||||
- ✅ `mark_chunk_anchored()` → `F10.add_chunk_anchor()` - Correct
|
|
||||||
- ✅ `get_chunk_bounds()` → `F10.get_chunk_trajectory()` - Correct
|
|
||||||
|
|
||||||
**F10 exposes chunk operations:**
|
|
||||||
- ✅ `create_new_chunk()` - Low-level factor graph operation
|
|
||||||
- ✅ `add_relative_factor_to_chunk()` - Factor management
|
|
||||||
- ✅ `add_chunk_anchor()` - Anchor management
|
|
||||||
- ✅ `merge_chunks()` - Sim(3) transformation
|
|
||||||
- ✅ `optimize_chunk()` - Chunk-level optimization
|
|
||||||
- ✅ `get_chunk_trajectory()` - Trajectory retrieval
|
|
||||||
|
|
||||||
**Assessment:** ✅ **Well-integrated** - F12 properly wraps F10 operations
|
|
||||||
|
|
||||||
**Status:** ✅ **Fixed** - F10's method renamed to `get_chunk_for_frame(frame_id)` for clarity, F12's `get_active_chunk(flight_id)` remains for high-level queries.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2.2 F12 ↔ F11 Integration
|
|
||||||
|
|
||||||
**F11 calls F12:**
|
|
||||||
- ✅ `create_chunk_on_tracking_loss()` → `F12.create_chunk()` - Correct (proactive)
|
|
||||||
- ✅ `try_chunk_semantic_matching()` → Uses F12 methods indirectly - Correct
|
|
||||||
- ✅ `try_chunk_litesam_matching()` → Uses F12 methods indirectly - Correct
|
|
||||||
- ✅ `merge_chunk_to_trajectory()` → Calls `F10.merge_chunks()` directly - ⚠️ **Bypasses F12**
|
|
||||||
|
|
||||||
**F12 provides for F11:**
|
|
||||||
- ✅ `get_chunks_for_matching()` - Returns unanchored chunks
|
|
||||||
- ✅ `get_chunk_images()` - Image retrieval
|
|
||||||
- ✅ `get_chunk_composite_descriptor()` - Descriptor computation
|
|
||||||
- ✅ `get_chunk_bounds()` - Bounds for tile search
|
|
||||||
|
|
||||||
**Assessment:** ⚠️ **Minor inconsistency** - F11 bypasses F12 for merging
|
|
||||||
|
|
||||||
**Status:** ✅ **Fixed** - F11 now calls `F12.merge_chunks()` which coordinates with F10 and updates chunk states.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2.3 F12 ↔ F02 Integration
|
|
||||||
|
|
||||||
**F02 calls F12:**
|
|
||||||
- ✅ `get_active_chunk(flight_id)` - Before processing frame
|
|
||||||
- ✅ `create_new_chunk(flight_id, frame_id)` - On tracking loss
|
|
||||||
- ✅ `add_frame_to_chunk()` - During frame processing
|
|
||||||
|
|
||||||
**F02 chunk-aware processing:**
|
|
||||||
- ✅ Gets active chunk before processing frame
|
|
||||||
- ✅ Creates new chunk on tracking loss
|
|
||||||
- ✅ Adds frames to chunk with VO results
|
|
||||||
|
|
||||||
**Assessment:** ✅ **Well-integrated** - F02 properly uses F12 for chunk management
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2.4 F12 ↔ F08/F09 Integration
|
|
||||||
|
|
||||||
**F08 Global Place Recognition:**
|
|
||||||
- ✅ `get_chunk_images()` - Retrieves chunk images
|
|
||||||
- ✅ `get_chunk_composite_descriptor()` - Gets aggregate descriptor
|
|
||||||
- ⚠️ **Issue:** F12's `get_chunk_composite_descriptor()` calls `F08.compute_location_descriptor()` for each image, but F08 also has `compute_chunk_descriptor()` method. This creates duplication.
|
|
||||||
|
|
||||||
**F09 Metric Refinement:**
|
|
||||||
- ✅ `get_chunk_images()` - Retrieves chunk images
|
|
||||||
- ✅ `align_chunk_to_satellite()` - Chunk-to-satellite matching
|
|
||||||
|
|
||||||
**Assessment:** ⚠️ **Descriptor duplication** - F12 and F08 both compute chunk descriptors
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Chunk Lifecycle Flow Analysis
|
|
||||||
|
|
||||||
### 3.1 Normal Chunk Lifecycle
|
|
||||||
|
|
||||||
```
|
|
||||||
1. Tracking Lost (F02/F11 detects)
|
|
||||||
↓
|
|
||||||
2. create_chunk() (F12) → create_new_chunk() (F10)
|
|
||||||
↓
|
|
||||||
3. add_frame_to_chunk() × N (F12) → add_relative_factor_to_chunk() (F10)
|
|
||||||
↓
|
|
||||||
4. is_chunk_ready_for_matching() (F12) → True (>=5 frames)
|
|
||||||
↓
|
|
||||||
5. get_chunks_for_matching() (F12) → Returns chunk
|
|
||||||
↓
|
|
||||||
6. try_chunk_semantic_matching() (F11) → Uses F12.get_chunk_composite_descriptor()
|
|
||||||
↓
|
|
||||||
7. try_chunk_litesam_matching() (F11) → Uses F12.get_chunk_images()
|
|
||||||
↓
|
|
||||||
8. mark_chunk_anchored() (F12) → add_chunk_anchor() (F10)
|
|
||||||
↓
|
|
||||||
9. merge_chunks() (F10) → Called directly by F11 (bypasses F12)
|
|
||||||
↓
|
|
||||||
10. deactivate_chunk() (F12) → Chunk marked as merged
|
|
||||||
```
|
|
||||||
|
|
||||||
**Status:** ✅ **Fixed** - Step 9 now goes through F12.merge_chunks() maintaining abstraction
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3.2 Proactive Chunk Creation
|
|
||||||
|
|
||||||
**Solution Requirement:** Chunks created proactively on tracking loss, not reactively after matching failures.
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
- ✅ F11's `create_chunk_on_tracking_loss()` creates chunk immediately
|
|
||||||
- ✅ F02's `handle_tracking_loss()` creates chunk proactively
|
|
||||||
- ✅ Processing continues in new chunk while matching happens asynchronously
|
|
||||||
|
|
||||||
**Assessment:** ✅ **Correctly implements proactive creation**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3.3 Chunk Matching Strategy
|
|
||||||
|
|
||||||
**Solution Requirement:** Chunk semantic matching (aggregate DINOv2) → Chunk LiteSAM matching (rotation sweeps) → Chunk merging (Sim3)
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
- ✅ F12 provides `get_chunk_composite_descriptor()` for semantic matching
|
|
||||||
- ✅ F11 coordinates semantic matching via F08
|
|
||||||
- ✅ F11 coordinates LiteSAM matching via F09 with rotation sweeps
|
|
||||||
- ✅ F10 provides `merge_chunks()` with Sim(3) transform
|
|
||||||
|
|
||||||
**Assessment:** ✅ **Correctly implements matching strategy**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. State Management Coherence
|
|
||||||
|
|
||||||
### 4.1 ChunkHandle State Fields
|
|
||||||
|
|
||||||
**F12 ChunkHandle:**
|
|
||||||
```python
|
|
||||||
chunk_id: str
|
|
||||||
flight_id: str
|
|
||||||
start_frame_id: int
|
|
||||||
end_frame_id: Optional[int]
|
|
||||||
frames: List[int]
|
|
||||||
is_active: bool
|
|
||||||
has_anchor: bool
|
|
||||||
anchor_frame_id: Optional[int]
|
|
||||||
anchor_gps: Optional[GPSPoint]
|
|
||||||
matching_status: str # "unanchored", "matching", "anchored", "merged"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Assessment:** ✅ **Complete state representation** - All necessary fields present
|
|
||||||
|
|
||||||
**Issue:** `matching_status` and `has_anchor` are redundant (if `matching_status == "anchored"`, then `has_anchor == True`). Consider consolidating.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 4.2 State Transitions
|
|
||||||
|
|
||||||
**Valid Transitions:**
|
|
||||||
- `unanchored` → `matching` (when matching starts)
|
|
||||||
- `matching` → `anchored` (when anchor found)
|
|
||||||
- `anchored` → `merged` (when merged to global trajectory)
|
|
||||||
- `unanchored` → `anchored` (direct anchor, e.g., user input)
|
|
||||||
|
|
||||||
**Assessment:** ✅ **State transitions are well-defined**
|
|
||||||
|
|
||||||
**Status:** ✅ **Fixed** - Added `F12.mark_chunk_matching(chunk_id)` method for explicit state transitions.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Missing Functionality
|
|
||||||
|
|
||||||
### 5.1 Chunk Merging Coordination
|
|
||||||
|
|
||||||
**Gap:** F12 doesn't have a method to coordinate chunk merging.
|
|
||||||
|
|
||||||
**Current:** F11 calls `F10.merge_chunks()` directly, bypassing F12.
|
|
||||||
|
|
||||||
**Recommendation:** Add `F12.merge_chunks(chunk_id_1, chunk_id_2, transform)` that:
|
|
||||||
1. Validates chunks can be merged
|
|
||||||
2. Calls `F10.merge_chunks()`
|
|
||||||
3. Updates chunk states (deactivates chunk_id_1, updates chunk_id_2)
|
|
||||||
4. Updates `matching_status` to "merged"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 5.2 Chunk State Persistence
|
|
||||||
|
|
||||||
**Gap:** No explicit persistence of chunk state.
|
|
||||||
|
|
||||||
**Current:** Chunk state is in-memory only (via F12 and F10).
|
|
||||||
|
|
||||||
**Recommendation:** F12 should persist chunk state to F03 Flight Database for:
|
|
||||||
- Recovery after system restart
|
|
||||||
- Chunk state queries
|
|
||||||
- Debugging and analysis
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 5.3 Chunk Matching Status Updates
|
|
||||||
|
|
||||||
**Gap:** No explicit method to update `matching_status` to "matching".
|
|
||||||
|
|
||||||
**Current:** Status transitions happen implicitly in F11.
|
|
||||||
|
|
||||||
**Recommendation:** Add `F12.mark_chunk_matching(chunk_id)` to explicitly track matching state.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. Inconsistencies
|
|
||||||
|
|
||||||
### 6.1 Descriptor Computation Duplication
|
|
||||||
|
|
||||||
**Issue:** Both F08 and F12 compute chunk descriptors.
|
|
||||||
|
|
||||||
- **F08:** `compute_chunk_descriptor(chunk_images)` - Computes aggregate DINOv2 descriptor
|
|
||||||
- **F12:** `get_chunk_composite_descriptor(chunk_id)` - Also computes aggregate descriptor
|
|
||||||
|
|
||||||
**Current Implementation (F12):**
|
|
||||||
```python
|
|
||||||
1. Get chunk images via get_chunk_images()
|
|
||||||
2. For each image:
|
|
||||||
- Call F08.compute_location_descriptor(image) → descriptor
|
|
||||||
3. Aggregate descriptors (mean, max, or VLAD)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Status:** ✅ **Fixed** - F12 now calls `F08.compute_chunk_descriptor()` directly, eliminating duplication.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 6.2 Active Chunk Query Inconsistency
|
|
||||||
|
|
||||||
**Issue:** F10 and F12 have different signatures for `get_active_chunk()`.
|
|
||||||
|
|
||||||
- **F10:** `get_active_chunk(frame_id: int)` - Query by frame ID
|
|
||||||
- **F12:** `get_active_chunk(flight_id: str)` - Query by flight ID
|
|
||||||
|
|
||||||
**Status:** ✅ **Fixed** - F10's method renamed to `get_chunk_for_frame(frame_id)` for clarity, clearly distinguishing from F12's `get_active_chunk(flight_id)`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 6.3 Chunk Merging Bypass
|
|
||||||
|
|
||||||
**Issue:** F11 bypasses F12 when merging chunks.
|
|
||||||
|
|
||||||
**Current:** `F11.merge_chunk_to_trajectory()` → `F10.merge_chunks()` directly
|
|
||||||
|
|
||||||
**Status:** ✅ **Fixed** - F11 now calls `F12.merge_chunks()` which properly coordinates merging and updates chunk states.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. Strengths
|
|
||||||
|
|
||||||
### 7.1 Clear Abstraction Layers ✅
|
|
||||||
|
|
||||||
- **F12** provides high-level chunk lifecycle management
|
|
||||||
- **F10** provides low-level factor graph operations
|
|
||||||
- Clear separation of concerns
|
|
||||||
|
|
||||||
### 7.2 Proactive Chunk Creation ✅
|
|
||||||
|
|
||||||
- Chunks created immediately on tracking loss
|
|
||||||
- Processing continues while matching happens asynchronously
|
|
||||||
- Matches solution requirement perfectly
|
|
||||||
|
|
||||||
### 7.3 Complete Chunk State Tracking ✅
|
|
||||||
|
|
||||||
- ChunkHandle captures all necessary state
|
|
||||||
- State transitions are well-defined
|
|
||||||
- Matching status tracks chunk progress
|
|
||||||
|
|
||||||
### 7.4 Chunk Matching Integration ✅
|
|
||||||
|
|
||||||
- F12 provides chunk representations (images, descriptors, bounds)
|
|
||||||
- F11 coordinates matching strategies
|
|
||||||
- F08/F09 perform actual matching
|
|
||||||
|
|
||||||
### 7.5 Chunk Isolation ✅
|
|
||||||
|
|
||||||
- Each chunk has independent subgraph in F10
|
|
||||||
- Factors isolated to chunks
|
|
||||||
- Local optimization before global merging
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. Weaknesses
|
|
||||||
|
|
||||||
### 8.1 Missing Merging Coordination ✅ **FIXED**
|
|
||||||
|
|
||||||
- ✅ F12.merge_chunks() method added
|
|
||||||
- ✅ F11 now calls F12, maintaining abstraction
|
|
||||||
- ✅ State updates handled by F12
|
|
||||||
|
|
||||||
### 8.2 Descriptor Computation Duplication ✅ **FIXED**
|
|
||||||
|
|
||||||
- ✅ F12 now delegates to F08.compute_chunk_descriptor() directly
|
|
||||||
- ✅ Single source of truth for chunk descriptor computation
|
|
||||||
|
|
||||||
### 8.3 No State Persistence ⚠️
|
|
||||||
|
|
||||||
- Chunk state is in-memory only
|
|
||||||
- No recovery after restart
|
|
||||||
- No debugging/analysis capabilities
|
|
||||||
- **Note:** This is a Priority 2 enhancement, not critical
|
|
||||||
|
|
||||||
### 8.4 Implicit State Transitions ✅ **FIXED**
|
|
||||||
|
|
||||||
- ✅ F12.mark_chunk_matching() method added
|
|
||||||
- ✅ Explicit state transitions for matching status
|
|
||||||
- ✅ Easier to track chunk state changes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. Recommendations
|
|
||||||
|
|
||||||
### Priority 1: Critical Fixes ✅ **COMPLETED**
|
|
||||||
|
|
||||||
1. ✅ **Add F12.merge_chunks() method** - **FIXED**
|
|
||||||
- F12.merge_chunks() method added
|
|
||||||
- Coordinates chunk merging and updates states
|
|
||||||
- F11 now calls F12, maintaining abstraction
|
|
||||||
|
|
||||||
2. ✅ **Fix descriptor computation duplication** - **FIXED**
|
|
||||||
- F12.get_chunk_composite_descriptor() now calls F08.compute_chunk_descriptor() directly
|
|
||||||
- Removed duplicate aggregation logic from F12
|
|
||||||
|
|
||||||
3. ✅ **Add explicit matching status updates** - **FIXED**
|
|
||||||
- F12.mark_chunk_matching(chunk_id) method added
|
|
||||||
- Explicitly tracks when matching starts
|
|
||||||
|
|
||||||
### Priority 2: Important Enhancements
|
|
||||||
|
|
||||||
4. **Add chunk state persistence**
|
|
||||||
- Persist ChunkHandle to F03 Flight Database
|
|
||||||
- Enable recovery after restart
|
|
||||||
- Support debugging and analysis
|
|
||||||
|
|
||||||
5. ✅ **Clarify method naming** - **FIXED**
|
|
||||||
- F10.get_active_chunk() renamed to get_chunk_for_frame() for clarity
|
|
||||||
- Documented different use cases (low-level vs high-level)
|
|
||||||
|
|
||||||
6. **Add chunk validation**
|
|
||||||
- Validate chunk state before operations
|
|
||||||
- Prevent invalid state transitions
|
|
||||||
- Better error messages
|
|
||||||
|
|
||||||
### Priority 3: Nice-to-Have
|
|
||||||
|
|
||||||
7. **Add chunk metrics**
|
|
||||||
- Track chunk creation time
|
|
||||||
- Track matching success rate
|
|
||||||
- Track merging statistics
|
|
||||||
|
|
||||||
8. **Add chunk query methods**
|
|
||||||
- Query chunks by status
|
|
||||||
- Query chunks by frame range
|
|
||||||
- Query chunks by matching status
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 10. Overall Assessment
|
|
||||||
|
|
||||||
### Coherence Score: 9/10 (Updated after fixes)
|
|
||||||
|
|
||||||
**Strengths:**
|
|
||||||
- ✅ Clear separation of concerns
|
|
||||||
- ✅ Proactive chunk creation
|
|
||||||
- ✅ Complete lifecycle coverage
|
|
||||||
- ✅ Well-integrated with F10, F11, F02
|
|
||||||
- ✅ Proper chunk isolation
|
|
||||||
- ✅ **FIXED:** Merging coordination through F12
|
|
||||||
- ✅ **FIXED:** Descriptor computation delegation
|
|
||||||
- ✅ **FIXED:** Explicit state transitions
|
|
||||||
|
|
||||||
**Remaining Enhancement:**
|
|
||||||
- ⚠️ No state persistence (Priority 2, not critical)
|
|
||||||
|
|
||||||
**Conclusion:** The chunking system is **excellent and coherent** with clear architectural boundaries. All Priority 1 issues have been **fixed**. The system now properly maintains abstraction layers with F12 coordinating all chunk lifecycle operations. Remaining enhancement (state persistence) is a nice-to-have feature for recovery and debugging.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 11. Solution Alignment
|
|
||||||
|
|
||||||
### Atlas Multi-Map Architecture ✅
|
|
||||||
|
|
||||||
The chunking system correctly implements the Atlas architecture from the solution:
|
|
||||||
|
|
||||||
- ✅ **Chunks are first-class entities** - F12 manages chunks as primary units
|
|
||||||
- ✅ **Proactive chunk creation** - Chunks created immediately on tracking loss
|
|
||||||
- ✅ **Independent chunk processing** - Each chunk has its own subgraph in F10
|
|
||||||
- ✅ **Chunk matching and merging** - Semantic matching → LiteSAM → Sim(3) merging
|
|
||||||
- ✅ **Multiple chunks simultaneously** - System supports multiple unanchored chunks
|
|
||||||
|
|
||||||
**Assessment:** ✅ **Fully aligned with solution architecture**
|
|
||||||
|
|
||||||
@@ -1,526 +0,0 @@
|
|||||||
# Component Coverage Analysis: Solution, Problem, Acceptance Criteria, and Restrictions
|
|
||||||
|
|
||||||
## Executive Summary
|
|
||||||
|
|
||||||
This document analyzes how the ASTRAL-Next component architecture covers the solution design, addresses the original problem, meets acceptance criteria, and operates within restrictions.
|
|
||||||
|
|
||||||
**Key Findings:**
|
|
||||||
- ✅ Components comprehensively implement the tri-layer localization strategy (Sequential VO, Global PR, Metric Refinement)
|
|
||||||
- ✅ Atlas multi-map chunk architecture properly handles sharp turns and disconnected routes
|
|
||||||
- ✅ All 10 acceptance criteria are addressed by specific component capabilities
|
|
||||||
- ✅ Restrictions are respected through component design choices
|
|
||||||
- ⚠️ Some architectural concerns identified (see architecture_assessment.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Solution Coverage Analysis
|
|
||||||
|
|
||||||
### 1.1 Tri-Layer Localization Strategy
|
|
||||||
|
|
||||||
The solution document specifies three layers operating concurrently:
|
|
||||||
|
|
||||||
| Solution Layer | Component(s) | Implementation Status |
|
|
||||||
|----------------|--------------|----------------------|
|
|
||||||
| **L1: Sequential Tracking** | F07 Sequential Visual Odometry | ✅ Fully covered |
|
|
||||||
| **L2: Global Re-Localization** | F08 Global Place Recognition | ✅ Fully covered |
|
|
||||||
| **L3: Metric Refinement** | F09 Metric Refinement | ✅ Fully covered |
|
|
||||||
| **State Estimation** | F10 Factor Graph Optimizer | ✅ Fully covered |
|
|
||||||
|
|
||||||
**Coverage Details:**
|
|
||||||
|
|
||||||
**L1 - Sequential VO (F07):**
|
|
||||||
- Uses SuperPoint + LightGlue as specified
|
|
||||||
- Handles <5% overlap scenarios
|
|
||||||
- Provides relative pose factors to F10
|
|
||||||
- Chunk-aware operations (factors added to chunk subgraphs)
|
|
||||||
|
|
||||||
**L2 - Global PR (F08):**
|
|
||||||
- Implements AnyLoc (DINOv2 + VLAD) as specified
|
|
||||||
- Faiss indexing for efficient retrieval
|
|
||||||
- Chunk semantic matching (aggregate descriptors)
|
|
||||||
- Handles "kidnapped robot" scenarios
|
|
||||||
|
|
||||||
**L3 - Metric Refinement (F09):**
|
|
||||||
- Implements LiteSAM for cross-view matching
|
|
||||||
- Requires pre-rotation (handled by F06)
|
|
||||||
- Extracts GPS from homography
|
|
||||||
- Chunk-to-satellite matching support
|
|
||||||
|
|
||||||
**State Estimation (F10):**
|
|
||||||
- GTSAM-based factor graph optimization
|
|
||||||
- Robust kernels (Huber/Cauchy) for outlier handling
|
|
||||||
- Multi-chunk support (Atlas architecture)
|
|
||||||
- Sim(3) transformation for chunk merging
|
|
||||||
|
|
||||||
### 1.2 Atlas Multi-Map Architecture
|
|
||||||
|
|
||||||
**Solution Requirement:** Chunks are first-class entities, created proactively on tracking loss.
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- ✅ **F12 Route Chunk Manager**: Manages chunk lifecycle (creation, activation, matching, merging)
|
|
||||||
- ✅ **F10 Factor Graph Optimizer**: Provides multi-chunk factor graph with independent subgraphs
|
|
||||||
- ✅ **F11 Failure Recovery Coordinator**: Proactively creates chunks on tracking loss
|
|
||||||
- ✅ **F02 Flight Processor**: Chunk-aware frame processing
|
|
||||||
|
|
||||||
**Chunk Lifecycle Flow:**
|
|
||||||
1. **Tracking Loss Detected** → F11 creates chunk proactively (not reactive)
|
|
||||||
2. **Chunk Building** → F07 adds VO factors to chunk subgraph via F10
|
|
||||||
3. **Chunk Matching** → F08 (semantic) + F09 (LiteSAM) match chunks
|
|
||||||
4. **Chunk Anchoring** → F10 anchors chunk with GPS
|
|
||||||
5. **Chunk Merging** → F10 merges chunks using Sim(3) transform
|
|
||||||
|
|
||||||
**Coverage Verification:**
|
|
||||||
- ✅ Chunks created proactively (not after matching failures)
|
|
||||||
- ✅ Chunks processed independently
|
|
||||||
- ✅ Chunk semantic matching (aggregate DINOv2)
|
|
||||||
- ✅ Chunk LiteSAM matching with rotation sweeps
|
|
||||||
- ✅ Chunk merging via Sim(3) transformation
|
|
||||||
|
|
||||||
### 1.3 REST API + SSE Architecture
|
|
||||||
|
|
||||||
**Solution Requirement:** Background service with REST API and SSE streaming.
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- ✅ **F01 Flight API**: REST endpoints (FastAPI)
|
|
||||||
- ✅ **F15 SSE Event Streamer**: Real-time result streaming
|
|
||||||
- ✅ **F02 Flight Processor**: Background processing orchestration
|
|
||||||
- ✅ **F14 Result Manager**: Result publishing coordination
|
|
||||||
|
|
||||||
**API Coverage:**
|
|
||||||
- ✅ `POST /flights` - Flight creation
|
|
||||||
- ✅ `GET /flights/{id}` - Flight retrieval
|
|
||||||
- ✅ `POST /flights/{id}/images/batch` - Batch image upload
|
|
||||||
- ✅ `POST /flights/{id}/user-fix` - User anchor input
|
|
||||||
- ✅ `GET /flights/{id}/stream` - SSE streaming
|
|
||||||
|
|
||||||
**SSE Events:**
|
|
||||||
- ✅ `frame_processed` - Per-frame results
|
|
||||||
- ✅ `frame_refined` - Refinement updates
|
|
||||||
- ✅ `user_input_needed` - User intervention required
|
|
||||||
- ✅ `search_expanded` - Progressive search updates
|
|
||||||
|
|
||||||
### 1.4 Human-in-the-Loop Strategy
|
|
||||||
|
|
||||||
**Solution Requirement:** User input for 20% of route where automation fails.
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- ✅ **F11 Failure Recovery Coordinator**: Monitors confidence, triggers user input
|
|
||||||
- ✅ **F01 Flight API**: Accepts user fixes via REST endpoint
|
|
||||||
- ✅ **F15 SSE Event Streamer**: Sends user input requests
|
|
||||||
- ✅ **F10 Factor Graph Optimizer**: Applies user anchors as hard constraints
|
|
||||||
|
|
||||||
**Recovery Stages:**
|
|
||||||
1. ✅ Stage 1: Progressive tile search (single-image)
|
|
||||||
2. ✅ Stage 2: Chunk building and semantic matching
|
|
||||||
3. ✅ Stage 3: Chunk LiteSAM matching with rotation sweeps
|
|
||||||
4. ✅ Stage 4: User input (last resort)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Original Problem Coverage
|
|
||||||
|
|
||||||
### 2.1 Problem Statement
|
|
||||||
|
|
||||||
**Original Problem:** Determine GPS coordinates of image centers from UAV flight, given only starting GPS coordinates.
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- ✅ **F13 Coordinate Transformer**: Converts pixel coordinates to GPS
|
|
||||||
- ✅ **F09 Metric Refinement**: Extracts GPS from satellite alignment
|
|
||||||
- ✅ **F10 Factor Graph Optimizer**: Optimizes trajectory to GPS coordinates
|
|
||||||
- ✅ **F14 Result Manager**: Publishes GPS results per frame
|
|
||||||
|
|
||||||
**Coverage Verification:**
|
|
||||||
- ✅ Starting GPS used to initialize ENU coordinate system (F13)
|
|
||||||
- ✅ Per-frame GPS computed from trajectory (F10 → F13)
|
|
||||||
- ✅ Object coordinates computed via pixel-to-GPS transformation (F13)
|
|
||||||
|
|
||||||
### 2.2 Image Processing Requirements
|
|
||||||
|
|
||||||
**Requirement:** Process images taken consecutively within 100m spacing.
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- ✅ **F05 Image Input Pipeline**: Handles sequential image batches
|
|
||||||
- ✅ **F07 Sequential VO**: Processes consecutive frames
|
|
||||||
- ✅ **F02 Flight Processor**: Validates sequence continuity
|
|
||||||
|
|
||||||
**Coverage Verification:**
|
|
||||||
- ✅ Batch validation ensures sequential ordering
|
|
||||||
- ✅ VO handles 100m spacing via relative pose estimation
|
|
||||||
- ✅ Factor graph maintains trajectory continuity
|
|
||||||
|
|
||||||
### 2.3 Satellite Data Usage
|
|
||||||
|
|
||||||
**Requirement:** Use external satellite provider for ground checks.
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- ✅ **F04 Satellite Data Manager**: Fetches Google Maps tiles
|
|
||||||
- ✅ **F08 Global Place Recognition**: Matches UAV images to satellite tiles
|
|
||||||
- ✅ **F09 Metric Refinement**: Aligns UAV images to satellite tiles
|
|
||||||
|
|
||||||
**Coverage Verification:**
|
|
||||||
- ✅ Google Maps Static API integration (F04)
|
|
||||||
- ✅ Tile caching and prefetching (F04)
|
|
||||||
- ✅ Progressive tile search (1→4→9→16→25) (F04 + F11)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Acceptance Criteria Coverage
|
|
||||||
|
|
||||||
### AC-1: 80% of photos < 50m error
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F09 Metric Refinement**: LiteSAM achieves ~17.86m RMSE (within 50m requirement)
|
|
||||||
- **F10 Factor Graph Optimizer**: Fuses measurements for accuracy
|
|
||||||
- **F13 Coordinate Transformer**: Accurate GPS conversion
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
- LiteSAM provides pixel-level alignment
|
|
||||||
- Factor graph optimization reduces drift
|
|
||||||
- Altitude priors resolve scale ambiguity
|
|
||||||
|
|
||||||
**Status:** ✅ Covered
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### AC-2: 60% of photos < 20m error
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F09 Metric Refinement**: LiteSAM RMSE ~17.86m (close to 20m requirement)
|
|
||||||
- **F10 Factor Graph Optimizer**: Global optimization improves precision
|
|
||||||
- **F04 Satellite Data Manager**: High-resolution tiles (Zoom Level 19, ~0.30m/pixel)
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
- Multi-scale LiteSAM processing
|
|
||||||
- Per-keyframe scale model in factor graph
|
|
||||||
- High-resolution satellite tiles
|
|
||||||
|
|
||||||
**Status:** ✅ Covered (may require Tier-2 commercial data per solution doc)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### AC-3: Robust to 350m outlier
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F10 Factor Graph Optimizer**: Robust kernels (Huber/Cauchy) downweight outliers
|
|
||||||
- **F11 Failure Recovery Coordinator**: Detects outliers and triggers recovery
|
|
||||||
- **F07 Sequential VO**: Reports low confidence for outlier frames
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
- Huber loss function in factor graph
|
|
||||||
- M-estimation automatically rejects high-residual constraints
|
|
||||||
- Stage 2 failure logic discards outlier frames
|
|
||||||
|
|
||||||
**Status:** ✅ Covered
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### AC-4: Robust to sharp turns (<5% overlap)
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F12 Route Chunk Manager**: Creates new chunks on tracking loss
|
|
||||||
- **F08 Global Place Recognition**: Re-localizes after sharp turns
|
|
||||||
- **F06 Image Rotation Manager**: Handles unknown orientation
|
|
||||||
- **F11 Failure Recovery Coordinator**: Coordinates recovery
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
- Proactive chunk creation on tracking loss
|
|
||||||
- Rotation sweeps (0°, 30°, ..., 330°) for unknown orientation
|
|
||||||
- Chunk semantic matching handles featureless terrain
|
|
||||||
- Chunk LiteSAM matching aggregates correspondences
|
|
||||||
|
|
||||||
**Status:** ✅ Covered
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### AC-5: < 10% outlier anchors
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F10 Factor Graph Optimizer**: Robust M-estimation (Huber loss)
|
|
||||||
- **F09 Metric Refinement**: Match confidence filtering
|
|
||||||
- **F11 Failure Recovery Coordinator**: Validates matches before anchoring
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
- Huber loss automatically downweights bad anchors
|
|
||||||
- Match confidence threshold (0.7) filters outliers
|
|
||||||
- Inlier count validation before anchoring
|
|
||||||
|
|
||||||
**Status:** ✅ Covered
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### AC-6: Connect route chunks; User input
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F12 Route Chunk Manager**: Manages chunk lifecycle
|
|
||||||
- **F10 Factor Graph Optimizer**: Merges chunks via Sim(3) transform
|
|
||||||
- **F11 Failure Recovery Coordinator**: Coordinates chunk matching
|
|
||||||
- **F01 Flight API**: User input endpoint
|
|
||||||
- **F15 SSE Event Streamer**: User input requests
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
- Chunk semantic matching connects chunks
|
|
||||||
- Chunk LiteSAM matching provides Sim(3) transform
|
|
||||||
- Chunk merging maintains global consistency
|
|
||||||
- User input as last resort (Stage 4)
|
|
||||||
|
|
||||||
**Status:** ✅ Covered
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### AC-7: < 5 seconds processing/image
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F16 Model Manager**: TensorRT optimization (2-4x speedup)
|
|
||||||
- **F07 Sequential VO**: ~50ms (SuperPoint + LightGlue)
|
|
||||||
- **F08 Global Place Recognition**: ~150ms (DINOv2 + VLAD, keyframes only)
|
|
||||||
- **F09 Metric Refinement**: ~60ms (LiteSAM)
|
|
||||||
- **F10 Factor Graph Optimizer**: ~100ms (iSAM2 incremental)
|
|
||||||
|
|
||||||
**Performance Breakdown:**
|
|
||||||
- Sequential VO: ~50ms
|
|
||||||
- Global PR (keyframes): ~150ms
|
|
||||||
- Metric Refinement: ~60ms
|
|
||||||
- Factor Graph: ~100ms
|
|
||||||
- **Total (worst case): ~360ms << 5s**
|
|
||||||
|
|
||||||
**Status:** ✅ Covered (with TensorRT optimization)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### AC-8: Real-time stream + async refinement
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F15 SSE Event Streamer**: Real-time frame results
|
|
||||||
- **F14 Result Manager**: Per-frame and refinement publishing
|
|
||||||
- **F10 Factor Graph Optimizer**: Asynchronous batch refinement
|
|
||||||
- **F02 Flight Processor**: Decoupled processing pipeline
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
- Immediate per-frame results via SSE
|
|
||||||
- Background refinement thread
|
|
||||||
- Batch waypoint updates for refinements
|
|
||||||
- Incremental SSE events for refinements
|
|
||||||
|
|
||||||
**Status:** ✅ Covered
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### AC-9: Image Registration Rate > 95%
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F07 Sequential VO**: Handles <5% overlap
|
|
||||||
- **F12 Route Chunk Manager**: Chunk creation prevents "lost" frames
|
|
||||||
- **F08 Global Place Recognition**: Re-localizes after tracking loss
|
|
||||||
- **F09 Metric Refinement**: Aligns frames to satellite
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
- "Lost track" creates new chunk (not registration failure)
|
|
||||||
- Chunk matching recovers disconnected segments
|
|
||||||
- System never "fails" - fragments and continues
|
|
||||||
|
|
||||||
**Status:** ✅ Covered (Atlas architecture ensures >95%)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### AC-10: Mean Reprojection Error (MRE) < 1.0px
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F10 Factor Graph Optimizer**: Local and global bundle adjustment
|
|
||||||
- **F07 Sequential VO**: High-quality feature matching (SuperPoint + LightGlue)
|
|
||||||
- **F09 Metric Refinement**: Precise homography estimation
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
- Local BA in sequential VO
|
|
||||||
- Global BA in factor graph optimizer
|
|
||||||
- Per-keyframe scale model minimizes graph tension
|
|
||||||
- Robust kernels prevent outlier contamination
|
|
||||||
|
|
||||||
**Status:** ✅ Covered
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Restrictions Compliance
|
|
||||||
|
|
||||||
### R-1: Photos from airplane-type UAVs only
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F17 Configuration Manager**: Validates flight type
|
|
||||||
- **F02 Flight Processor**: Validates flight parameters
|
|
||||||
|
|
||||||
**Compliance:** ✅ Validated at flight creation
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### R-2: Camera pointing downwards, fixed, not autostabilized
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F06 Image Rotation Manager**: Handles rotation variations
|
|
||||||
- **F09 Metric Refinement**: Requires pre-rotation (handled by F06)
|
|
||||||
- **F07 Sequential VO**: Handles perspective variations
|
|
||||||
|
|
||||||
**Compliance:** ✅ Rotation sweeps handle fixed camera orientation
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### R-3: Flying range restricted to Eastern/Southern Ukraine
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F02 Flight Processor**: Validates waypoints within operational area
|
|
||||||
- **F04 Satellite Data Manager**: Prefetches tiles for operational area
|
|
||||||
- **F13 Coordinate Transformer**: ENU origin set to operational area
|
|
||||||
|
|
||||||
**Compliance:** ✅ Geofence validation, operational area constraints
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### R-4: Image resolution FullHD to 6252×4168
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F16 Model Manager**: TensorRT handles variable resolutions
|
|
||||||
- **F07 Sequential VO**: SuperPoint processes variable resolutions
|
|
||||||
- **F05 Image Input Pipeline**: Validates image dimensions
|
|
||||||
|
|
||||||
**Compliance:** ✅ Components handle variable resolutions
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### R-5: Altitude predefined, no more than 1km
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F10 Factor Graph Optimizer**: Altitude priors resolve scale
|
|
||||||
- **F13 Coordinate Transformer**: GSD calculations use altitude
|
|
||||||
- **F02 Flight Processor**: Validates altitude <= 1000m
|
|
||||||
|
|
||||||
**Compliance:** ✅ Altitude used as soft constraint in factor graph
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### R-6: NO data from IMU
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F10 Factor Graph Optimizer**: Monocular VO only (no IMU factors)
|
|
||||||
- **F07 Sequential VO**: Pure visual odometry
|
|
||||||
- **F13 Coordinate Transformer**: Scale resolved via altitude + satellite matching
|
|
||||||
|
|
||||||
**Compliance:** ✅ No IMU components, scale resolved via altitude priors
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### R-7: Flights mostly in sunny weather
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F08 Global Place Recognition**: DINOv2 handles appearance changes
|
|
||||||
- **F09 Metric Refinement**: LiteSAM robust to lighting variations
|
|
||||||
- **F07 Sequential VO**: SuperPoint handles texture variations
|
|
||||||
|
|
||||||
**Compliance:** ✅ Algorithms robust to lighting conditions
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### R-8: Google Maps (may be outdated)
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F04 Satellite Data Manager**: Google Maps Static API integration
|
|
||||||
- **F08 Global Place Recognition**: DINOv2 semantic features (invariant to temporal changes)
|
|
||||||
- **F09 Metric Refinement**: LiteSAM focuses on structural features
|
|
||||||
|
|
||||||
**Compliance:** ✅ Semantic matching handles outdated satellite data
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### R-9: 500-1500 photos typically, up to 3000
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F05 Image Input Pipeline**: Batch processing (10-50 images)
|
|
||||||
- **F10 Factor Graph Optimizer**: Efficient optimization (iSAM2)
|
|
||||||
- **F03 Flight Database**: Handles large flight datasets
|
|
||||||
|
|
||||||
**Compliance:** ✅ Components scale to 3000 images
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### R-10: Sharp turns possible (exception, not rule)
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F12 Route Chunk Manager**: Chunk architecture handles sharp turns
|
|
||||||
- **F11 Failure Recovery Coordinator**: Recovery strategies for sharp turns
|
|
||||||
- **F06 Image Rotation Manager**: Rotation sweeps for unknown orientation
|
|
||||||
|
|
||||||
**Compliance:** ✅ Chunk architecture handles exceptions gracefully
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### R-11: Processing on RTX 2060/3070 (TensorRT required)
|
|
||||||
|
|
||||||
**Component Coverage:**
|
|
||||||
- **F16 Model Manager**: TensorRT optimization (FP16 quantization)
|
|
||||||
- **F07 Sequential VO**: TensorRT-optimized SuperPoint + LightGlue
|
|
||||||
- **F08 Global Place Recognition**: TensorRT-optimized DINOv2
|
|
||||||
- **F09 Metric Refinement**: TensorRT-optimized LiteSAM
|
|
||||||
|
|
||||||
**Compliance:** ✅ All models optimized for TensorRT, FP16 quantization
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Coverage Gaps and Concerns
|
|
||||||
|
|
||||||
### 5.1 Architectural Concerns
|
|
||||||
|
|
||||||
See `architecture_assessment.md` for detailed concerns:
|
|
||||||
- Component numbering inconsistencies
|
|
||||||
- Circular dependencies (F14 → F01)
|
|
||||||
- Duplicate functionality (chunk descriptors)
|
|
||||||
- Missing component connections
|
|
||||||
|
|
||||||
### 5.2 Potential Gaps
|
|
||||||
|
|
||||||
1. **Performance Monitoring**: H05 Performance Monitor exists but integration unclear
|
|
||||||
2. **Error Recovery**: Comprehensive error handling not fully specified
|
|
||||||
3. **Concurrent Flights**: Multi-flight processing not fully validated
|
|
||||||
4. **Satellite Data Freshness**: Handling of outdated Google Maps data relies on semantic features (may need validation)
|
|
||||||
|
|
||||||
### 5.3 Recommendations
|
|
||||||
|
|
||||||
1. **Fix Architectural Issues**: Address concerns in architecture_assessment.md
|
|
||||||
2. **Performance Validation**: Validate <5s processing on RTX 2060
|
|
||||||
3. **Accuracy Validation**: Test against ground truth data (coordinates.csv)
|
|
||||||
4. **Chunk Matching Validation**: Validate chunk matching reduces user input by 50-70%
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. Summary Matrix
|
|
||||||
|
|
||||||
| Requirement Category | Coverage | Status |
|
|
||||||
|---------------------|----------|--------|
|
|
||||||
| **Solution Architecture** | Tri-layer + Atlas + REST/SSE | ✅ Complete |
|
|
||||||
| **Problem Statement** | GPS localization from images | ✅ Complete |
|
|
||||||
| **AC-1** (80% < 50m) | LiteSAM + Factor Graph | ✅ Covered |
|
|
||||||
| **AC-2** (60% < 20m) | LiteSAM + High-res tiles | ✅ Covered |
|
|
||||||
| **AC-3** (350m outlier) | Robust kernels | ✅ Covered |
|
|
||||||
| **AC-4** (Sharp turns) | Chunk architecture | ✅ Covered |
|
|
||||||
| **AC-5** (<10% outliers) | Robust M-estimation | ✅ Covered |
|
|
||||||
| **AC-6** (Chunk connection) | Chunk matching + User input | ✅ Covered |
|
|
||||||
| **AC-7** (<5s processing) | TensorRT optimization | ✅ Covered |
|
|
||||||
| **AC-8** (Real-time stream) | SSE + Async refinement | ✅ Covered |
|
|
||||||
| **AC-9** (>95% registration) | Atlas architecture | ✅ Covered |
|
|
||||||
| **AC-10** (MRE < 1.0px) | Bundle adjustment | ✅ Covered |
|
|
||||||
| **Restrictions** | All 11 restrictions | ✅ Compliant |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. Conclusion
|
|
||||||
|
|
||||||
The component architecture comprehensively covers the solution design, addresses the original problem, meets all acceptance criteria, and operates within restrictions. The Atlas multi-map chunk architecture is properly implemented across F10, F11, and F12 components. The tri-layer localization strategy is fully covered by F07, F08, and F09.
|
|
||||||
|
|
||||||
**Key Strengths:**
|
|
||||||
- Complete solution coverage
|
|
||||||
- All acceptance criteria addressed
|
|
||||||
- Restrictions respected
|
|
||||||
- Chunk architecture properly implemented
|
|
||||||
|
|
||||||
**Areas for Improvement:**
|
|
||||||
- Fix architectural concerns (see architecture_assessment.md)
|
|
||||||
- Validate performance on target hardware
|
|
||||||
- Test accuracy against ground truth data
|
|
||||||
- Validate chunk matching effectiveness
|
|
||||||
|
|
||||||
@@ -85,42 +85,50 @@
|
|||||||
|
|
||||||
# 2. Planning phase
|
# 2. Planning phase
|
||||||
|
|
||||||
## 2.1 **🤖📋AI plan**: Generate components
|
## 2.10 **🤖📋AI plan**: Generate components
|
||||||
|
|
||||||
### Execute `/gen_components`
|
### Execute `/2.10_gen_components`
|
||||||
|
|
||||||
### Revise
|
### Revise
|
||||||
- Revise the plan, answer questions, put detailed descriptions
|
- Revise the plan, answer questions, put detailed descriptions
|
||||||
- Make sure stored components are coherent and make sense
|
- Make sure stored components are coherent and make sense
|
||||||
- Ask AI
|
|
||||||
```
|
|
||||||
analyze carefully interaction between components. All covered? also, state that each component should implement interface, so that they could be interchangeable with different implementations
|
|
||||||
```
|
|
||||||
|
|
||||||
### Store plan
|
### Store plan
|
||||||
save plan to `docs/02_components/00_decomposition_plan.md`
|
save plan to `docs/02_components/00_decomposition_plan.md`
|
||||||
|
|
||||||
|
|
||||||
## 2.2 **🤖📋AI plan**: Generate tests
|
## 2.15 **🤖📋AI plan**: Components assesment
|
||||||
|
|
||||||
### Execute `/gen_tests`
|
### Execute `/2.15_components_assesment`
|
||||||
|
|
||||||
### Revise
|
### Revise
|
||||||
- Revise the tests, answer questions, put detailed descriptions
|
- Revise the plan, answer questions, put detailed descriptions
|
||||||
- Make sure stored tests are coherent and make sense
|
- Make sure stored components are coherent and make sense
|
||||||
|
|
||||||
## 2.3 **🤖📋AI plan**: Generate Jira Epics
|
### plan
|
||||||
|
save plan to `docs/02_components/00_decomposition_plan.md`
|
||||||
|
|
||||||
### Execute `/gen_epics`
|
## 2.20 **🤖📋AI plan**: Generate Jira Epics
|
||||||
|
|
||||||
|
### Execute `/2.20/_gen_epics`
|
||||||
|
|
||||||
### Revise
|
### Revise
|
||||||
- Revise the epics, answer questions, put detailed descriptions
|
- Revise the epics, answer questions, put detailed descriptions
|
||||||
- Make sure epics are coherent and make sense
|
- Make sure epics are coherent and make sense
|
||||||
|
|
||||||
## 2.4 **🤖📋AI plan**: Component Decomposition To Features
|
|
||||||
|
## 2.30 **🤖📋AI plan**: Generate tests
|
||||||
|
|
||||||
|
### Execute `/2.30_gen_tests`
|
||||||
|
|
||||||
|
### Revise
|
||||||
|
- Revise the tests, answer questions, put detailed descriptions
|
||||||
|
- Make sure stored tests are coherent and make sense
|
||||||
|
|
||||||
|
## 2.40 **🤖📋AI plan**: Component Decomposition To Features
|
||||||
### Execute
|
### Execute
|
||||||
For each component in `docs/02_components` run
|
For each component in `docs/02_components` run
|
||||||
`/gen_features --component @docs/02_components/[##]_[component_name]/[component_name]_spec.md`
|
`/2.40_gen_features --component @docs/02_components/[##]_[component_name]/[component_name]_spec.md`
|
||||||
|
|
||||||
### Revise
|
### Revise
|
||||||
- Revise the features, answer questions, put detailed descriptions
|
- Revise the features, answer questions, put detailed descriptions
|
||||||
|
|||||||
Reference in New Issue
Block a user