mirror of
https://github.com/azaion/autopilot.git
synced 2026-06-21 23:51:09 +00:00
[AZ-649] [AZ-674] [AZ-667] telemetry + vlm schema + mapobjects hydrate batch 6
AZ-649 mission_executor telemetry forwarding: - shared::models::telemetry::UavTelemetry canonical model - TelemetryForwarder with atomic ArcSwap snapshot + 3 lossy tokio::sync::broadcast channels (MissionExecutor, ScanController, MavlinkUplink) + per-consumer drop counters - MavlinkProjection::from_mavlink for HEARTBEAT/GLOBAL_POSITION_INT/ ATTITUDE/SYS_STATUS - spawn_mavlink_pump bridges mavlink_layer into the forwarder at the binary edge AZ-674 vlm_client schema validation + model_version tracking: - AssessmentParser owns schema validation + model-version state - wire::read_response_raw splits raw bytes from parsing so invalid payloads can be logged size-capped - VlmStatus gains an Inconclusive variant; exhaustive-match test guards downstream consumers - VlmPipelineStatus mirrors the new variant in shared::models::poi AZ-667 mapobjects_store hydrate + pending logs + cascade: - SyncState enum aligned with description.md (FreshBoot, Synced, CachedFallback, Degraded, Failed) - Store::hydrate(MapObjectsBundle) replaces in-memory map atomically; freshness=Stale -> CachedFallback - classify() + end_of_pass append MapObjectObservation events to pending_observations (New/Moved/Existing/RemovedCandidate) - apply_decline + LocalAppended ignored items append to pending_ignored - drain_pending() returns and clears both logs - cascade_mission(id) purges by_cell + IgnoredSet + pending logs - Health surface reports sync_state, pending_obs, pending_ign Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -11,5 +11,6 @@ pub mod mission;
|
||||
pub mod movement;
|
||||
pub mod operator;
|
||||
pub mod poi;
|
||||
pub mod telemetry;
|
||||
pub mod tier2;
|
||||
pub mod vlm;
|
||||
|
||||
@@ -13,6 +13,7 @@ pub enum VlmPipelineStatus {
|
||||
NotRequested,
|
||||
Pending,
|
||||
Ok,
|
||||
Inconclusive,
|
||||
Timeout,
|
||||
SchemaInvalid,
|
||||
IpcError,
|
||||
@@ -23,6 +24,7 @@ impl From<VlmStatus> for VlmPipelineStatus {
|
||||
fn from(s: VlmStatus) -> Self {
|
||||
match s {
|
||||
VlmStatus::Ok => Self::Ok,
|
||||
VlmStatus::Inconclusive => Self::Inconclusive,
|
||||
VlmStatus::Timeout => Self::Timeout,
|
||||
VlmStatus::SchemaInvalid => Self::SchemaInvalid,
|
||||
VlmStatus::IpcError => Self::IpcError,
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
//! `UavTelemetry` — projection of decoded MAVLink telemetry into a
|
||||
//! typed snapshot that downstream consumers (`scan_controller`,
|
||||
//! `movement_detector`, `telemetry_stream`, BIT) consume.
|
||||
//!
|
||||
//! Authoritative projection rules:
|
||||
//!
|
||||
//! - `position` from `GLOBAL_POSITION_INT` (id 33). Latitude/longitude
|
||||
//! are kept in their MAVLink-native E7 form so consumers that
|
||||
//! compare against waypoints (also E7) don't re-introduce float
|
||||
//! round-trip drift. Altitude is in metres (MSL + AGL relative).
|
||||
//! Velocities are in m/s, heading in degrees [0, 360).
|
||||
//! - `attitude` from `ATTITUDE` (id 30). Angles in radians per the
|
||||
//! MAVLink convention.
|
||||
//! - `mode` from `HEARTBEAT` (id 0). The `(base_mode, custom_mode)`
|
||||
//! pair is the canonical (vehicle-type-specific) discriminator;
|
||||
//! `system_status` is the MAV_STATE enum (`MAV_STATE_ACTIVE` etc.).
|
||||
//! - `sys_status` from `SYS_STATUS` (id 1). Battery + comms + sensor
|
||||
//! health bitfield — the bits consumers actually read are
|
||||
//! documented in `architecture.md §5.6`.
|
||||
//! - `monotonic_ts_ns` is the host monotonic timestamp captured the
|
||||
//! moment the originating MAVLink message was decoded. Strictly
|
||||
//! non-decreasing across snapshots. Boot-time-relative fields
|
||||
//! (`ts_boot_ms`) are kept on each sub-struct so consumers that
|
||||
//! already correlate against MAVLink time-bases (e.g. EKF logs)
|
||||
//! don't lose them.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub struct UavPosition {
|
||||
pub lat_e7: i32,
|
||||
pub lon_e7: i32,
|
||||
pub alt_m: f32,
|
||||
pub relative_alt_m: f32,
|
||||
pub vx_mps: f32,
|
||||
pub vy_mps: f32,
|
||||
pub vz_mps: f32,
|
||||
pub heading_deg: f32,
|
||||
pub ts_boot_ms: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub struct UavAttitude {
|
||||
pub roll: f32,
|
||||
pub pitch: f32,
|
||||
pub yaw: f32,
|
||||
pub rollspeed: f32,
|
||||
pub pitchspeed: f32,
|
||||
pub yawspeed: f32,
|
||||
pub ts_boot_ms: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct UavMode {
|
||||
pub base_mode: u8,
|
||||
pub custom_mode: u32,
|
||||
pub system_status: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct UavSysStatus {
|
||||
pub voltage_battery_mv: u16,
|
||||
pub current_battery_ca: i16,
|
||||
pub battery_remaining: i8,
|
||||
pub onboard_sensors_health: u32,
|
||||
pub errors_comm: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub struct UavTelemetry {
|
||||
pub position: Option<UavPosition>,
|
||||
pub attitude: Option<UavAttitude>,
|
||||
pub mode: Option<UavMode>,
|
||||
pub sys_status: Option<UavSysStatus>,
|
||||
pub monotonic_ts_ns: u64,
|
||||
}
|
||||
|
||||
impl UavTelemetry {
|
||||
/// Empty snapshot used as the initial value before any telemetry
|
||||
/// has arrived.
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
position: None,
|
||||
attitude: None,
|
||||
mode: None,
|
||||
sys_status: None,
|
||||
monotonic_ts_ns: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for UavTelemetry {
|
||||
fn default() -> Self {
|
||||
Self::empty()
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,24 @@ pub enum VlmLabel {
|
||||
Error,
|
||||
}
|
||||
|
||||
/// Exhaustive status enum per AZ-674 §AC-4. Consumers MUST match every
|
||||
/// variant — no `_ => …` catch-alls in the policy code path.
|
||||
///
|
||||
/// Distinction from [`VlmLabel`]: `status` says "did the VLM call
|
||||
/// itself produce a usable answer"; `label` says "what does that
|
||||
/// answer mean". `(status = Ok, label = Inconclusive)` is a valid
|
||||
/// combination — the call succeeded, the model said it couldn't
|
||||
/// classify. `status = Inconclusive` is reserved for the case where
|
||||
/// the call returned a structured assessment but the verdict envelope
|
||||
/// is itself "inconclusive" at the protocol level (model abstained,
|
||||
/// not the same as label-inconclusive). Keeping both lets the
|
||||
/// scan_controller distinguish "VLM declined to commit" from "VLM
|
||||
/// committed to 'inconclusive'".
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum VlmStatus {
|
||||
Ok,
|
||||
Inconclusive,
|
||||
Timeout,
|
||||
SchemaInvalid,
|
||||
IpcError,
|
||||
|
||||
Reference in New Issue
Block a user