mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-04-22 22:36:37 +00:00
150 lines
8.7 KiB
Markdown
150 lines
8.7 KiB
Markdown
# Test Environment
|
|
|
|
## Overview
|
|
|
|
**System under test**: GPS-Denied Visual Navigation System — a real-time position estimation service running on Jetson Orin Nano Super. Public interfaces: FastAPI REST/SSE endpoints (port 8000), MAVLink GPS_INPUT messages over serial/UDP, MAVLink telemetry messages.
|
|
|
|
**Consumer app purpose**: Standalone Python test runner (pytest) that exercises the GPS-denied system through its public interfaces (HTTP API, MAVLink message inspection, SSE stream consumption) without access to internal modules, ESKF state, or GPU buffers.
|
|
|
|
## Test Modes
|
|
|
|
This is embedded robotics software targeting Jetson Orin Nano Super. A pure Docker environment cannot exercise GPU-dependent paths (TRT inference, cuVSLAM, CUDA streams). The test environment supports two modes:
|
|
|
|
**Mode 1 — Docker SITL (CI/dev)**: Full system in Docker containers with ArduPilot SITL providing MAVLink + IMU at 200Hz. Camera images replayed from input_data/. Satellite tiles served from a mock HTTP server. GPS-denied system runs in CPU-mode with stubbed TRT/cuVSLAM inference (functionally equivalent but slower). Tests all integration paths, API, MAVLink, resilience, and security.
|
|
|
|
**Mode 2 — Jetson Hardware (nightly/pre-deploy)**: GPS-denied system runs natively on Jetson Orin Nano Super with real CUDA/TRT/cuVSLAM. ArduPilot SITL runs on the Jetson or a companion x86 host, connected via UART or UDP. Camera frames injected via USB camera emulator or replay service. Tests real-time performance, GPU memory, thermal, TRT correctness, and CUDA stream isolation.
|
|
|
|
## Docker Environment (Mode 1)
|
|
|
|
### Services
|
|
|
|
| Service | Image / Build | Purpose | Ports |
|
|
|---------|--------------|---------|-------|
|
|
| gps-denied-system | `./Dockerfile` (build context: project root) | GPS-denied navigation system in CPU-mode (TRT stubs, cuVSLAM stub returning synthetic VO poses derived from ground truth trajectory) | 8000 (FastAPI), 14550/udp (MAVLink) |
|
|
| ardupilot-sitl | `ardupilot/sitl:plane-4.5` (fixed-wing) | ArduPilot SITL: flies waypoint mission following coordinates.csv trajectory, generates IMU at 200Hz via MAVLink, GPS_TYPE=14 accepts GPS_INPUT, provides GLOBAL_POSITION_INT at startup | 5760 (MAVLink TCP), 14551/udp |
|
|
| camera-replay | `./tests/docker/camera-replay/Dockerfile` | Replays AD000001-060.jpg from input_data/ at configurable FPS (default 0.7fps) with timestamps synchronized to SITL clock. Supports fault injection: frame skip, corrupted JPEG, pause. | 8001 (frame server) |
|
|
| satellite-tile-server | `./tests/docker/tile-server/Dockerfile` | HTTP server for pre-cached satellite tiles (zoom 18, ~50-100 tiles covering test area). Supports fault injection: 404 for specific tiles, 503 for full outage, slow responses. | 8002 |
|
|
| mavlink-inspector | `./tests/docker/mavlink-inspector/Dockerfile` | Passively captures all MAVLink traffic (GPS_INPUT, NAMED_VALUE_FLOAT, STATUSTEXT, COMMAND_LONG) for post-test assertion. Can inject operator re-localization hints. | 14552/udp |
|
|
| e2e-consumer | `./tests/e2e/Dockerfile` | Black-box test runner (pytest). Communicates only via HTTP API + MAVLink inspector. | — |
|
|
|
|
### Networks
|
|
|
|
| Network | Services | Purpose |
|
|
|---------|----------|---------|
|
|
| e2e-net | all | Isolated test network; MAVLink UDP multicast between gps-denied-system, ardupilot-sitl, mavlink-inspector |
|
|
|
|
### Volumes
|
|
|
|
| Volume | Mounted to | Purpose |
|
|
|--------|-----------|---------|
|
|
| input-data | camera-replay:/data, e2e-consumer:/test-data | Camera frames (AD000001-060.jpg), coordinates.csv, data_parameters.md, gmaps reference images |
|
|
| satellite-tiles | satellite-tile-server:/tiles, gps-denied-system:/tiles | Pre-processed satellite tiles for test area (zoom 18, 48.249-48.276°N, 37.340-37.386°E) |
|
|
| sitl-mission | ardupilot-sitl:/mission | Waypoint mission file derived from coordinates.csv (SITL flies this trajectory, generating physically consistent 200Hz IMU data) |
|
|
| test-results | e2e-consumer:/results | Test result CSV output |
|
|
| mavlink-capture | mavlink-inspector:/capture | Recorded MAVLink messages for post-test assertions |
|
|
|
|
### IMU Data Flow
|
|
|
|
ArduPilot SITL is the primary source of IMU data. It flies a waypoint mission derived from coordinates.csv and internally generates physically consistent accelerometer + gyroscope readings at 200Hz, delivered to the GPS-denied system via MAVLink (RAW_IMU, SCALED_IMU2). This eliminates the need for pre-recorded IMU data files and ensures IMU/trajectory consistency.
|
|
|
|
```
|
|
coordinates.csv → mission_generator script → ArduPilot waypoint file
|
|
↓
|
|
ArduPilot SITL flies trajectory
|
|
↓
|
|
IMU @ 200Hz + heartbeat + GLOBAL_POSITION_INT
|
|
↓ (MAVLink UDP)
|
|
gps-denied-system receives IMU for ESKF
|
|
```
|
|
|
|
### docker-compose structure
|
|
|
|
```yaml
|
|
services:
|
|
ardupilot-sitl:
|
|
# ArduPilot SITL fixed-wing, outputs IMU at 200Hz via MAVLink
|
|
# GPS_TYPE=14 (MAVLink), pre-configured for GPS_INPUT acceptance
|
|
satellite-tile-server:
|
|
# HTTP tile server with tiles for test area (48.249-48.276°N, 37.340-37.386°E)
|
|
camera-replay:
|
|
# Replays AD000001-060.jpg at 0.7fps, serves via HTTP or shared volume
|
|
depends_on:
|
|
- satellite-tile-server
|
|
gps-denied-system:
|
|
# The system under test
|
|
depends_on:
|
|
- ardupilot-sitl
|
|
- satellite-tile-server
|
|
- camera-replay
|
|
mavlink-inspector:
|
|
# Captures GPS_INPUT, NAMED_VALUE_FLOAT, STATUSTEXT messages
|
|
depends_on:
|
|
- ardupilot-sitl
|
|
e2e-consumer:
|
|
# pytest runner — executes after system reaches steady state
|
|
depends_on:
|
|
- gps-denied-system
|
|
- mavlink-inspector
|
|
```
|
|
|
|
## Consumer Application
|
|
|
|
**Tech stack**: Python 3.11, pytest, httpx (HTTP client), pymavlink (MAVLink inspection), sseclient-py (SSE stream)
|
|
**Entry point**: `pytest tests/e2e/ --tb=short --csv=results/report.csv`
|
|
|
|
### Communication with system under test
|
|
|
|
| Interface | Protocol | Endpoint / Topic | Authentication |
|
|
|-----------|----------|-----------------|----------------|
|
|
| Position API | HTTP REST | http://gps-denied-system:8000/sessions | JWT token |
|
|
| Position stream | HTTP SSE | http://gps-denied-system:8000/sessions/{id}/stream | JWT token |
|
|
| Object localization | HTTP REST | http://gps-denied-system:8000/objects/locate | JWT token |
|
|
| Health check | HTTP REST | http://gps-denied-system:8000/health | None |
|
|
| GPS_INPUT inspection | MAVLink UDP | mavlink-inspector:14552 (recorded messages) | None |
|
|
| Telemetry inspection | MAVLink UDP | mavlink-inspector:14552 (NAMED_VALUE_FLOAT, STATUSTEXT) | None |
|
|
|
|
### What the consumer does NOT have access to
|
|
|
|
- No direct access to ESKF internal state, covariance matrices, or error vectors
|
|
- No direct access to cuVSLAM tracking state or feature maps
|
|
- No direct access to GPU memory, CUDA streams, or TRT engine internals
|
|
- No direct access to the system's file system or configuration files
|
|
- No direct database or state store access
|
|
|
|
## Jetson Hardware Environment (Mode 2)
|
|
|
|
Tests tagged `@pytest.mark.jetson` require actual Jetson Orin Nano Super hardware. These run natively (no Docker for the GPS-denied system) to exercise real GPU paths.
|
|
|
|
**Hardware setup**:
|
|
- Jetson Orin Nano Super (JetPack 6.2, CUDA 12.x, TensorRT 10.3)
|
|
- ArduPilot SITL on same Jetson (or x86 companion connected via UART/UDP)
|
|
- Camera frames injected via: USB camera emulator (v4l2loopback feeding frames from input_data/) or HTTP replay service
|
|
- Satellite tiles on local SSD (same path as production deployment)
|
|
- Active cooling attached (required for sustained load tests)
|
|
|
|
**Tests in this mode**:
|
|
- NFT-PERF-01 through NFT-PERF-06 (real GPU latency, throughput)
|
|
- NFT-RES-LIM-01 (GPU+CPU shared memory monitoring via tegrastats)
|
|
- NFT-RES-LIM-02 (thermal monitoring via thermal_zone sysfs)
|
|
- NFT-RES-LIM-05 (CUDA stream isolation with real concurrent GPU work)
|
|
- TRT engine build and inference correctness (expected_results #42-44)
|
|
|
|
**Jetson CI runner**: Self-hosted GitHub Actions runner on a dedicated Jetson Orin Nano Super, triggered for nightly builds and pre-deploy gates.
|
|
|
|
## CI/CD Integration
|
|
|
|
**When to run**: On every PR to `dev`, nightly full suite, before production deploy
|
|
**Pipeline stages**:
|
|
1. Unit tests (no Docker, no hardware) — on every commit
|
|
2. Docker blackbox tests (SITL + CPU mode) — on PR merge to dev
|
|
3. Hardware tests (Jetson runner) — nightly + pre-deploy
|
|
|
|
**Gate behavior**: Docker tests block merge; hardware tests are advisory (nightly) or blocking (pre-deploy)
|
|
**Timeout**: Docker suite: 15 minutes; Hardware suite: 30 minutes
|
|
|
|
## Reporting
|
|
|
|
**Format**: CSV
|
|
**Columns**: Test ID, Test Name, Execution Time (ms), Result (PASS/FAIL/SKIP), Error Message (if FAIL)
|
|
**Output path**: `./tests/e2e-results/report.csv`
|