[AZ-654] [AZ-655] [AZ-656] gimbal_controller primitives + monotonic clock fix (batch 11)
ci/woodpecker/push/build-arm Pipeline failed

AZ-654 SweepEngine: pendulum default, Raster/LawnMower variants
reserved and explicitly NotImplemented (no silent fallback per AC-3).
Time injected via next_step(now) for deterministic dwell tests.

AZ-655 PlanExecutor: linear yaw/pitch interpolation between PanGoals
with self-throttle (default 50 ms); stats expose
commands_emitted/dropped_to_throttle counters. PanGoal/PanPlan added
to shared::models::gimbal (spec drift: data_model.md §PanPlan flagged
for next doc sync).

AZ-656 CentreOnTarget: zoom-aware proportional control loop (correction
~ 1/zoom); target_lost debounced — fires once per loss streak, resets
on bbox return. Also fixes the misleadingly-named monotonic_ns() helper
introduced by AZ-653 that used SystemTime::now(): GimbalController now
owns a shared::clock::MonoClock and stamps GimbalState::ts_monotonic_ns
via clock.elapsed_ns(). AZ-656 AC-2 forced the correction; integration
test verifies the fix end-to-end.

58/58 gimbal_controller tests green (47 unit + 7 AZ-653 integration +
4 new batch_11 integration). Workspace test suite green this run.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-19 20:21:00 +03:00
parent 288e7f8c46
commit 4c63829ccd
12 changed files with 1470 additions and 13 deletions
+22 -1
View File
@@ -1,4 +1,4 @@
//! `GimbalState` — per `data_model.md §4 Action / piloting entities`.
//! `GimbalState` + `PanPlan` — per `data_model.md §4 Action / piloting entities`.
use serde::{Deserialize, Serialize};
@@ -10,3 +10,24 @@ pub struct GimbalState {
pub ts_monotonic_ns: u64,
pub command_in_flight: bool,
}
/// One waypoint in a `PanPlan`. `at_ns` is monotonic-nanoseconds since
/// the plan was loaded (i.e. relative to the plan's clock origin, not
/// since boot); the executor interpolates between adjacent goals based
/// on this relative timeline.
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct PanGoal {
pub yaw_deg: f32,
pub pitch_deg: f32,
pub zoom: f32,
pub at_ns: u64,
}
/// Path-tracking plan emitted by `semantic_analyzer` (via
/// `scan_controller`) and consumed by `gimbal_controller`. Goals are
/// ordered strictly increasing in `at_ns`. Empty plans are rejected by
/// the executor's validate step.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PanPlan {
pub goals: Vec<PanGoal>,
}