Files
gps-denied-onboard/e2e/fixtures/sitl_replay_builder/README.md
T
Oleksandr Bezdieniezhnykh 47ad43f913 [AZ-598] Batch 78: sitl_observer.wait_for_outbound + FT-P-01 fixture builder
Phase 1: extend sitl_observer with cursor-based `wait_for_outbound`
returning `OutboundMessage` from `outbound_messages_<fc_kind>_<host>.json`
fixtures. Three outcomes: message, TimeoutError (null entries), or
RuntimeError (missing/malformed). Fix FT-P-01 + FT-P-05 scenarios to
use `fc_kind=` kwarg.

Phase 2: FT-P-01 vertical-slice fixture builder under
`e2e/fixtures/sitl_replay_builder/`. Reuses the production
`gps-denied-replay` CLI + `ReplayInputAdapter`: encode 60 stills as
1 fps MP4 + synthetic stationary tlog (pymavlink); run replay;
project FDR outbound estimates into the schema. Avoids the
13+ cp of SUT-side frame-ingestion that a live-SITL-capture path
would have required. Live execution remains a manual operator step.

+35 unit tests (664 total, up from 637). K=3 cumulative review for
b76-b78 documents the offline-replay arc convergence.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 12:08:02 +03:00

3.1 KiB

SITL Replay Fixture Builder (AZ-598)

Produces the outbound_messages_<fc_kind>_<host>.json + observer_<fc_kind>_<host>.json fixtures consumed by the b75 sitl_observer module in offline FDR-replay mode (b75/b78).

Vertical-slice scope (this batch)

Only the FT-P-01 still-image accuracy scenario is supported. Other scenarios (FT-P-02 Derkachi continuous flight, FT-N-04 blackout-spoof, etc.) need their own capture flows and will land as follow-up tickets.

Strategy

Rather than spinning up a SITL container, this builder reuses the production gps-denied-replay CLI + ReplayInputAdapter:

  1. Encode the 60 AD0000NN.jpg still images into a 1 fps MP4.
  2. Generate a synthetic stationary tlog (zero-motion RAW_IMU + ATTITUDE pairs at 200 Hz) — bypasses the AZ-405 take-off pre-validator without needing real flight data.
  3. Run gps-denied-replay --video stills.mp4 --tlog stationary.tlog --time-offset-ms 0 --fdr-out fdr.jsonl (auto-sync bypassed because the synthetic tlog has no take-off signal).
  4. Read fdr.jsonl, filter to kind == outbound_position_estimate, project each into the outbound_messages_* schema.
  5. Write the two fixture JSON files into --output-dir.

This avoids needing new SUT-side frame-ingestion code (HTTP endpoint, file-watch source, etc.) which would otherwise be required to push individual stills to a running SUT container.

Usage

gps-denied-build-p01-fixtures \
  --input-dir _docs/00_problem/input_data \
  --output-dir e2e/fixtures/sitl_replay/p01 \
  --fc-kind ardupilot \
  --host sitl-host

The output directory will contain:

  • stills.mp4 — the 60 images encoded at 1 fps.
  • stationary.tlog — synthetic 120-s zero-motion tlog at 200 Hz.
  • fdr.jsonl — the FDR JSONL stream from the replay run.
  • outbound_messages_ardupilot_sitl-host.json — the consumed fixture.
  • observer_ardupilot_sitl-host.json — the consumed fixture.

To activate the fixtures in a scenario run:

E2E_SITL_REPLAY_DIR=e2e/fixtures/sitl_replay/p01 \
    pytest e2e/tests/positive/test_ft_p_01_still_image_accuracy.py

Limitations

  • The synthetic tlog encodes zero motion — auto-sync MUST be bypassed via --time-offset-ms 0 (the builder does this automatically).
  • The FDR record kind is assumed to be outbound_position_estimate — the --fdr-kind CLI flag overrides if the actual schema differs.
  • Per-image timeout handling: if the SUT emits fewer outbound estimates than pushed frames, trailing image_ids are written as null entries (encoded as TimeoutError on scenario replay).
  • iNav adapter is NOT supported by this batch — only ArduPilot. iNav will land as a follow-up once the AP path is validated end-to-end.

Testing

Unit tests under e2e/_unit_tests/fixtures/test_sitl_replay_builder.py mock all external dependencies (OpenCV, pymavlink, subprocess) so the test suite runs without a real gps-denied-replay install. The actual end-to-end run requires the SUT to be installed (pip install -e . at repo root) and is documented as a manual step until CI infrastructure catches up.