mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 20:01:12 +00:00
47ad43f913
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>
78 lines
3.1 KiB
Markdown
78 lines
3.1 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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.
|