Skip to content

Commit 974259b

Browse files
committed
fix: preserve altitude evidence in drone state API
1 parent f8594ad commit 974259b

4 files changed

Lines changed: 67 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ and this project uses simple two-part versioning: `X.Y` (Major.Minor).
1010
## [Unreleased]
1111

1212
### Fixed
13+
- The drone-side typed `/api/v1/drone/state` response now preserves the
14+
communicator's altitude-policy and local-NED fields so GCS can receive
15+
relative/local evidence instead of only the MSL position fallback.
1316
- Fleet status now follows the shared altitude policy and labels relative,
1417
local, barometric, and MSL frames explicitly instead of showing an MSL
1518
fallback as an unlabeled relative altitude. Current telemetry now uses

docs/plans/2026-07-27-simurgh-feasibility-checkpoint.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ Fleet status now:
4444

4545
- follows the telemetry altitude policy order (relative/home, local NED, baro,
4646
then absolute MSL);
47+
- receives the communicator's altitude-policy and local-NED fields through the
48+
typed drone-state API instead of losing them during response serialization;
4749
- never presents an MSL fallback as an unlabeled relative altitude;
4850
- labels the displayed frame (`REL`, `LCL`, `BARO`, or `MSL`);
4951
- calls the current bundle `Flight state` instead of `Final state`;

src/drone_api_server.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,22 @@ class DroneStateResponse(BaseModel):
228228
gps_raw_timestamp_ms: int = 0
229229
gps_raw_age_ms: Optional[int] = None
230230
gps_raw_altitude_m: Optional[float] = None
231+
# Keep the shared altitude-policy fields in the typed response model.
232+
# Pydantic otherwise drops the communicator's relative/local evidence,
233+
# leaving GCS with only the MSL ``position_alt`` fallback.
234+
altitude_report: Dict[str, Any] = Field(default_factory=dict)
235+
altitude_display_m: Optional[float] = None
236+
altitude_source: Optional[str] = None
237+
relative_altitude_m: Optional[float] = None
238+
baro_altitude_m: Optional[float] = None
239+
baro_timestamp_ms: int = 0
240+
baro_age_ms: Optional[int] = None
241+
local_position_ok: bool = False
242+
local_position_north: float = 0.0
243+
local_position_east: float = 0.0
244+
local_position_down: float = 0.0
245+
local_position_time_boot_ms: int = 0
246+
local_position_timestamp_ms: int = 0
231247
position_source: str = "unavailable"
232248
position_unavailable_reason: Optional[str] = None
233249
readiness_status: str = "unknown"

tests/test_drone_api_http.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,52 @@ def test_v1_health_survives_ulog_capability_probe_failure(self, test_client, api
8686
assert data["ulog_capability"]["missing_dependency"] == "ulog_capability_probe_failed"
8787

8888

89+
class TestDroneStateTelemetryFields:
90+
def test_state_preserves_altitude_policy_evidence(self, api_server):
91+
payload = api_server._serialize_drone_state_payload(
92+
{
93+
"pos_id": 1,
94+
"detected_pos_id": 1,
95+
"state": 0,
96+
"mission": 0,
97+
"last_mission": 0,
98+
"position_lat": 35.7,
99+
"position_long": 51.2,
100+
"position_alt": 1298.2,
101+
"velocity_north": 0.0,
102+
"velocity_east": 0.0,
103+
"velocity_down": 0.0,
104+
"yaw": 0.0,
105+
"battery_voltage": 16.2,
106+
"flight_mode": 0,
107+
"base_mode": 0,
108+
"system_status": 3,
109+
"is_armed": False,
110+
"is_ready_to_arm": True,
111+
"hdop": 0.7,
112+
"vdop": 1.1,
113+
"gps_fix_type": 3,
114+
"satellites_visible": 10,
115+
"ip": "172.18.0.2",
116+
"update_time": 1732270245,
117+
"altitude_report": {
118+
"display_m": 20.2,
119+
"source": "local_ned",
120+
"label": "LCL",
121+
"local_up_m": 20.2,
122+
},
123+
"altitude_display_m": 20.2,
124+
"altitude_source": "local_ned",
125+
"relative_altitude_m": None,
126+
"local_position_down": -20.2,
127+
}
128+
)
129+
130+
assert payload["altitude_report"]["display_m"] == 20.2
131+
assert payload["altitude_source"] == "local_ned"
132+
assert payload["local_position_down"] == -20.2
133+
134+
89135
class TestNodeEnvironment:
90136
"""Test node-local env inspection and mutation endpoints."""
91137

0 commit comments

Comments
 (0)