# Reasoning Chain

## Dimension 1: Output Architecture

### Fact Confirmation
Per Fact #3, GPS_INPUT (MAVLink msg ID 232) accepts lat/lon in WGS84 (degrees×1E7), altitude, fix_type, accuracy fields, and NED velocities. Per Fact #4, ArduPilot uses GPS1_TYPE=14 to accept MAVLink GPS input. The flight controller's EKF fuses this as if it were a real GPS module.

### Reference Comparison
Draft02 uses FastAPI + SSE to stream position data to a REST client. The new AC requires the system to output GPS coordinates directly to the flight controller via MAVLink GPS_INPUT, replacing the real GPS module. The flight controller then uses these coordinates for navigation/autopilot functions. The ground station receives position data indirectly via the flight controller's telemetry forwarding.

### Conclusion
The entire output architecture must change from REST API + SSE → pymavlink GPS_INPUT sender. FastAPI is no longer the primary output mechanism. It may be retained only for local IPC with other onboard AI systems (object localization requests). The SSE streaming to external clients is replaced by MAVLink telemetry forwarding through the flight controller.

### Confidence
✅ High — clear requirement change backed by MAVLink specification

---

## Dimension 2: Ground Station Communication

### Fact Confirmation
Per Fact #7, typical telemetry bandwidth is ~12kbit/s (SiK). Per Fact #8, NAMED_VALUE_FLOAT can stream custom values from companion to GCS. Per Fact #12, COMMAND_LONG can deliver commands from GCS to companion.

### Reference Comparison
Draft02 has no ground station integration. The new AC requires:
1. Stream position + confidence to ground station (passive, via telemetry forwarding of GPS_INPUT data + custom NAMED_VALUE_FLOAT for confidence/drift)
2. Receive re-localization commands from operator (active, via COMMAND_LONG or custom MAVLink message)

### Conclusion
Ground station communication uses MAVLink messages forwarded through the flight controller's telemetry radio. Position data flows automatically (flight controller forwards GPS data to GCS). Custom telemetry (confidence, drift, status) uses NAMED_VALUE_FLOAT. Re-localization hints from operator use a custom COMMAND_LONG with lat/lon payload. Bandwidth is tight (~12kbit/s) so minimize custom message frequency (1-2Hz max for NAMED_VALUE_FLOAT).

### Confidence
✅ High — standard MAVLink patterns

---

## Dimension 3: MAVLink Library Choice

### Fact Confirmation
Per Fact #1, MAVSDK-Python v3.15.3 does NOT support GPS_INPUT. Per Fact #2, pymavlink provides full GPS_INPUT support via `mav.gps_input_send()`. Per Fact #13, the restrictions say "using MAVSDK library" but MAVSDK literally cannot do the core function.

### Reference Comparison
MAVSDK is a higher-level abstraction over MAVLink. pymavlink is the lower-level direct MAVLink implementation. For GPS_INPUT (our core output), only pymavlink works.

### Conclusion
Use **pymavlink** as the MAVLink library. The restriction mentioning MAVSDK must be noted as a conflict — pymavlink is the only viable option for GPS_INPUT in Python. pymavlink is lightweight, pure Python, works on aarch64, and provides full access to all MAVLink messages. MAVSDK v4 may add custom message support in the future but is not available now.

### Confidence
✅ High — confirmed limitation, clear alternative

---

## Dimension 4: GPS Update Rate

### Fact Confirmation
Per Fact #5, ArduPilot GPS_RATE_MS has a minimum of 200ms (5Hz). Our camera shoots at ~3fps (333ms). We produce a full VO+ESKF position estimate per frame at ~3Hz.

### Reference Comparison
3Hz < 5Hz minimum. ArduPilot's EKF expects at least 5Hz GPS updates for stable fusion.

### Conclusion
Between camera frames, use IMU prediction from the ESKF to interpolate position at 5Hz (or higher, e.g., 10Hz). The ESKF already runs IMU prediction at 100+Hz internally. Simply emit the ESKF predicted state as GPS_INPUT at 5-10Hz. Camera frame updates (3Hz) provide the measurement corrections. This is standard in sensor fusion: prediction runs fast, measurements arrive slower. The `fix_type` field can differentiate: camera-corrected frames → fix_type=3 (3D), IMU-predicted → fix_type=2 (2D) or adjust horiz_accuracy to reflect lower confidence.

### Confidence
✅ High — standard sensor fusion approach

---

## Dimension 5: Startup & Failsafe

### Fact Confirmation
Per new AC: system initializes from last known GPS before GPS denial. On reboot: re-initialize from flight controller's IMU-extrapolated position. On total failure for N seconds: flight controller falls back to IMU-only.

### Reference Comparison
Draft02 has no startup or failsafe procedures. The system was assumed to already know its position at session start.

### Conclusion
Startup sequence:
1. On boot, connect to flight controller via pymavlink
2. Read current GPS position from flight controller (GLOBAL_POSITION_INT or GPS_RAW_INT message)
3. Initialize ESKF state with this position
4. Begin cuVSLAM initialization with first camera frames
5. Start sending GPS_INPUT once ESKF has a valid position estimate

Failsafe:
1. If no position estimate for N seconds → stop sending GPS_INPUT (flight controller auto-detects GPS loss and falls back to IMU)
2. Log failure event
3. Continue attempting VO/satellite matching

Reboot recovery:
1. On companion computer reboot, reconnect to flight controller
2. Read current GPS_RAW_INT (which is now IMU-extrapolated by flight controller)
3. Re-initialize ESKF with this position (lower confidence)
4. Resume normal operation

### Confidence
✅ High — standard autopilot integration patterns

---

## Dimension 6: Object Localization

### Fact Confirmation
Per Fact #11, for oblique camera: ground_distance = altitude × tan(θ) where θ is angle from vertical. Combined with camera azimuth (yaw + camera pan angle) gives direction. With zoom, effective FOV narrows → higher pixel-to-meter resolution.

### Reference Comparison
Draft02 has basic nadir-only projection: pixel offset × GSD → meters → rotate by heading → lat/lon. The AI camera has configurable angle and zoom, so this needs extension.

### Conclusion
Object localization for AI camera:
1. Get current UAV position from GPS-Denied system
2. Get AI camera params: pan angle (azimuth relative to heading), tilt angle (from vertical), zoom level (→ effective focal length)
3. Get pixel coordinates of detected object in AI camera frame
4. Compute: a) bearing = UAV heading + camera pan angle + pixel horizontal offset angle, b) ground_distance = altitude / cos(tilt) × (tilt + pixel vertical offset angle) → simplified for flat terrain, c) convert bearing + distance to lat/lon offset from UAV position
5. Accuracy inherits GPS-Denied position error + projection error from altitude/angle uncertainty

Expose as lightweight local API (Unix socket or shared memory for speed, or simple HTTP on localhost).

### Confidence
✅ High — well-established trigonometry, flat terrain simplifies

---

## Dimension 7: Thermal Management

### Fact Confirmation
Per Fact #9, Jetson Orin Nano Super throttles at 80°C junction temperature, dropping GPU from ~1GHz to ~300MHz (3x slowdown). Active cooling required. Power modes: 15W, 25W, MAXN SUPER.

### Reference Comparison
Draft02 ignores thermal constraints. Our pipeline (cuVSLAM ~9ms + satellite matcher ~50-200ms) runs on GPU continuously at 3fps. This is moderate but sustained load.

### Conclusion
Mitigation:
1. Use 25W power mode (not MAXN SUPER) for stable sustained performance
2. Require active cooling (5V fan, should be standard on any UAV companion computer mount)
3. Monitor temperature via tegrastats/jtop at runtime
4. If temp >75°C: reduce satellite matching frequency (every 5-10 frames instead of 3)
5. If temp >80°C: skip satellite matching entirely, rely on VO+IMU only (cuVSLAM at 9ms is low power)
6. Our total GPU time per 333ms frame: ~9ms cuVSLAM + ~50-200ms satellite match (async) = <60% GPU utilization → thermal throttling unlikely with proper cooling

### Confidence
⚠️ Medium — actual thermal behavior depends on airflow in UAV enclosure, ambient temperature in-flight

---

## Dimension 8: VO Drift Budget Monitoring

### Fact Confirmation
New AC: max cumulative VO drift between satellite correction anchors < 100m. The ESKF maintains a position covariance matrix that grows during VO-only periods and shrinks on satellite corrections.

### Reference Comparison
Draft02 uses ESKF covariance for keyframe selection (trigger satellite match when covariance exceeds threshold) but doesn't explicitly track drift as a budget.

### Conclusion
Use ESKF position covariance diagonal (σ_x² + σ_y²) as the drift estimate. When √(σ_x² + σ_y²) approaches 100m:
1. Force satellite matching on every frame (not just keyframes)
2. Report LOW confidence via GPS_INPUT horiz_accuracy
3. If drift exceeds 100m without satellite correction → flag as critical, increase matching frequency, send alert to ground station
This is essentially what draft02 already does with covariance-based keyframe triggering, but now with an explicit 100m threshold.

### Confidence
✅ High — standard ESKF covariance interpretation

---

## Dimension 9: Satellite Imagery Specs

### Fact Confirmation
New AC: ≥0.5 m/pixel resolution, <2 years old. Google Maps at zoom 18 = ~0.6 m/pixel, zoom 19 = ~0.3 m/pixel.

### Reference Comparison
Draft02 uses Google Maps zoom 18-19. Zoom 19 (0.3 m/pixel) exceeds the requirement. Zoom 18 (0.6 m/pixel) meets the minimum. Age depends on Google's imagery updates for eastern Ukraine — conflict zone may have stale imagery.

### Conclusion
Validate during offline preprocessing:
1. Download at zoom 19 first (0.3 m/pixel)
2. If zoom 19 unavailable for some tiles, fall back to zoom 18 (0.6 m/pixel — exceeds 0.5 minimum)
3. Check imagery date metadata if available from Google Maps API
4. Flag tiles where imagery appears stale (seasonal mismatch, destroyed buildings, etc.)
5. No architectural change needed — add validation step to preprocessing pipeline

### Confidence
⚠️ Medium — Google Maps imagery age is not reliably queryable

---

## Dimension 10: Internal IPC for Object Localization

### Fact Confirmation
Other onboard AI systems need to request GPS coordinates of detected objects. These systems run on the same Jetson.

### Reference Comparison
Draft02 has FastAPI for external API. For local IPC between processes on the same device, FastAPI is overkill but works.

### Conclusion
Retain a minimal FastAPI server on localhost:8000 for inter-process communication:
- POST /localize: accepts pixel coordinates + AI camera params → returns GPS coordinates
- GET /status: returns system health/state for monitoring
This is local-only (bind to 127.0.0.1), not exposed externally. The primary output channel is MAVLink GPS_INPUT. This is a lightweight addition, not the core architecture.

### Confidence
✅ High — simple local IPC pattern
