A two-part guidance / navigation / control study built around a real drone flight log.
- Tracking — reconstructs world-frame target line-of-sight from asynchronous on-board sensor data (camera, gimbal, attitude). Estimates azimuth / elevation rates with five different methods including a causal Kalman constant-velocity filter, then picks the best one with a noise-and-latency-weighted selector.
- Intercept — simulates a 3D speed/acceleration-constrained interceptor closing on four target maneuver modes (
straight,weave,bounded_turn,reactive) under three guidance laws (pure pursuit,predictive lead,proportional navigation). Produces a 12-scenario comparison matrix.
- Asynchronous sensor fusion done right. The flight log is an interleaved event stream — different sensors post-date each other. The pipeline treats the camera stream as the master timeline, SLERP-interpolates attitude, and runs a frame-convention selector against the data instead of guessing quaternion direction.
- Five rate estimators compared on the same axis —
gradient,savgol,local_polynomial,spline, and a causalkalman_cvfilter with[θ, θ̇]state. Selection is driven by a weighted score dominated by lag and noise, with reconstruction / edge / holdout RMSE acting as guardrails against smooth-but-distorted candidates. - Three guidance laws in one simulator. Pure pursuit and predictive lead are baselines; the proportional-navigation mode adds an LOS-rate-driven lateral correction on top of predictive. All three respect the same speed and per-axis acceleration limits.
- Four target maneuver modes including a reactive mode that responds to the interceptor's geometry — useful for showing how each guidance law degrades against evasion.
- Production-grade rigor on a research-y problem: 53 tests, deterministic artifact contracts, all assumptions documented, rejected alternatives kept on the record (see
docs/design-notes.md).
python3 -m venv .venv
source .venv/bin/activate # or .\.venv\Scripts\Activate.ps1 on Windows
pip install -r requirements.txt
python3 tracking.py # runs the tracking pipeline
python3 intercept.py # runs the intercept simulation (12 scenarios)
python3 -m pytest -q # runs the test suite (53 tests)Both pipelines accept --skip-animation to skip GIF rendering for fast iteration:
python3 tracking.py --skip-animation
python3 intercept.py --skip-animationPre-rendered artifacts ship in outputs/ so you can browse without running anything.
| Artifact | Shows |
|---|---|
tracking_sync_diagnostics.png |
Camera / gimbal / attitude stream alignment |
tracking_frame_diagnostics.png |
Frame-convention selector evidence |
tracking_kalman_tracking.png |
Raw vs Kalman-filtered world angles + rate estimates |
tracking_rate_estimates.png |
All five rate estimators on the same axis |
tracking_geometry_3d.png / tracking_geometry_animation.gif |
3D world-frame geometry |
| Artifact | Shows |
|---|---|
intercept_overview_matrix.png |
12-bundle comparison (4 target modes × 3 guidance laws) |
intercept_guidance_3d_comparison.png |
Side-by-side 3D trajectories for the three guidance laws |
intercept_constraint_traces.png |
Speed and per-axis acceleration vs limits |
outputs/intercept/<target_mode>/<guidance_mode>/ |
12 per-scenario bundles (trajectory, engagement, constraints, animation) |
tracking.py # CLI entry — world-frame LOS reconstruction + rate selection
intercept.py # CLI entry — 3D constrained intercept simulation matrix
helpers/
paths.py # Output dir resolution + flight-log path
utils.py # Small shared utilities
plotting.py # Common plot config
tracking_pipeline.py # Stream split, SLERP, frame conventions, rate estimation, Kalman
tracking_visualization.py # All tracking plots and the 3D animation
intercept_simulation.py # Numerical simulation, scenario grid, output bundling
intercept_guidance.py # Pure pursuit, predictive lead, proportional navigation
intercept_targets.py # Target maneuver behaviors
intercept_visualization.py # All intercept plots, overview matrix, animations
tests/ # 53 tests covering pipelines, hardening, plot annotations
outputs/ # Pre-rendered artifacts (tracking/, intercept/)
docs/design-notes.md # Engineering rationale, bug fixes, rejected alternatives
flight_log.csv # Source flight log
For the why-not-the-what — frame-convention selection, the rate-method scoring policy, the guidance-law math, the rejected alternatives, and the bugs caught during iteration — see docs/design-notes.md.
python3 -m pytest -q53 tests covering:
- Stream synchronization and frame-convention selection
- Rate estimator correctness (including the Kalman candidate)
- Intercept-pipeline contract and constraint enforcement
- Guidance-law math (lead-time analytic, PN command construction)
- Plot annotation invariants
- Hardening / regression coverage
From a recent end-to-end run:
- Selected rate method:
savgol— won the lag/noise-weighted selector by a clean margin while the Kalman candidate sat second - Selected frame convention: quaternion is
world-to-body, camera azimuth +right / elevation +down, gimbal +pitch down - Baseline intercept (predictive law, straight target): intercept =
True, time =129.5 s, min distance =1.97 m