mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-04-22 22:06:37 +00:00
78dcf7b4e7
Phase A — Runtime bugs: - SSE: add push_event() method to SSEEventStreamer (was missing, masked by mocks) - MAVLink: satellites_visible=10 (was 0, triggers ArduPilot failsafe) - MAVLink: horiz_accuracy=sqrt(P[0,0]+P[1,1]) per spec (was sqrt(avg)) - MAVLink: MEDIUM confidence → fix_type=3 per solution.md (was 2) Phase B — Functional gaps: - handle_user_fix() injects operator GPS into ESKF with noise=500m - app.py uses create_vo_backend() factory (was hardcoded SequentialVO) - ESKF: Mahalanobis gating on satellite updates (rejects outliers >5σ) - ESKF: public accessors (position, quaternion, covariance, last_timestamp) - Processor: no more private ESKF field access Phase C — Documentation: - README: correct API endpoints, CLI command, 40+ env vars documented - Dockerfile: ENV prefixes match pydantic-settings (DB_, SATELLITE_, MAVLINK_) - tech_stack.md marked ARCHIVED (contradicts solution.md) Phase D — Hardening: - JWT auth middleware (AUTH_ENABLED=false default, verify_token on /flights) - TLS config env vars (AUTH_SSL_CERTFILE, AUTH_SSL_KEYFILE) - SHA-256 tile manifest verification in SatelliteDataManager - AuthConfig, ESKFSettings, MAVLinkConfig, SatelliteConfig in config.py Also: conftest.py shared fixtures, download_tiles.py, convert_to_trt.py scripts, config wiring into app.py lifespan, config-driven ESKF, calculate_precise_angle fix. Tests: 196 passed / 8 skipped. Ruff clean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
171 lines
5.4 KiB
Python
171 lines
5.4 KiB
Python
#!/usr/bin/env python3
|
|
"""TensorRT engine conversion script.
|
|
|
|
Converts ONNX models to TensorRT FP16 .engine files for Jetson deployment.
|
|
Wraps trtexec CLI (available on Jetson with JetPack installed).
|
|
|
|
Usage:
|
|
# Convert a single model
|
|
python scripts/convert_to_trt.py --onnx weights/litesam.onnx --output /opt/engines/litesam.engine
|
|
|
|
# Convert all known models from weights/ to engines/
|
|
python scripts/convert_to_trt.py --all --onnx-dir weights/ --engine-dir /opt/engines/
|
|
|
|
# Dry run (check trtexec availability)
|
|
python scripts/convert_to_trt.py --check
|
|
|
|
Requires:
|
|
- NVIDIA TensorRT (trtexec in PATH) — available on Jetson with JetPack
|
|
- NOT available on dev/CI machines — script exits cleanly with a message
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
|
|
# Known models and their expected ONNX filenames
|
|
_MODELS = {
|
|
"superpoint": "superpoint.onnx",
|
|
"lightglue": "lightglue.onnx",
|
|
"xfeat": "xfeat.onnx",
|
|
"dinov2": "dinov2.onnx",
|
|
"litesam": "litesam.onnx",
|
|
}
|
|
|
|
|
|
def find_trtexec() -> str | None:
|
|
"""Find trtexec binary in PATH or common Jetson locations."""
|
|
path = shutil.which("trtexec")
|
|
if path:
|
|
return path
|
|
# Common Jetson paths
|
|
for candidate in [
|
|
"/usr/src/tensorrt/bin/trtexec",
|
|
"/usr/local/cuda/bin/trtexec",
|
|
]:
|
|
if os.path.isfile(candidate) and os.access(candidate, os.X_OK):
|
|
return candidate
|
|
return None
|
|
|
|
|
|
def convert_onnx_to_engine(
|
|
onnx_path: str,
|
|
engine_path: str,
|
|
fp16: bool = True,
|
|
workspace_mb: int = 1024,
|
|
trtexec_path: str | None = None,
|
|
) -> bool:
|
|
"""Run trtexec to convert ONNX → TensorRT engine.
|
|
|
|
Returns True on success, False on failure.
|
|
"""
|
|
trtexec = trtexec_path or find_trtexec()
|
|
if not trtexec:
|
|
print("ERROR: trtexec not found. Install TensorRT or run on Jetson with JetPack.")
|
|
return False
|
|
|
|
if not os.path.isfile(onnx_path):
|
|
print(f"ERROR: ONNX file not found: {onnx_path}")
|
|
return False
|
|
|
|
os.makedirs(os.path.dirname(engine_path) or ".", exist_ok=True)
|
|
|
|
cmd = [
|
|
trtexec,
|
|
f"--onnx={onnx_path}",
|
|
f"--saveEngine={engine_path}",
|
|
f"--workspace={workspace_mb}",
|
|
]
|
|
if fp16:
|
|
cmd.append("--fp16")
|
|
|
|
print(f" Converting: {onnx_path} → {engine_path}")
|
|
print(f" Command: {' '.join(cmd)}")
|
|
|
|
try:
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
|
|
if result.returncode == 0:
|
|
size_mb = os.path.getsize(engine_path) / (1024 * 1024)
|
|
print(f" OK: {engine_path} ({size_mb:.1f} MB)")
|
|
return True
|
|
else:
|
|
print(f" FAIL (exit {result.returncode})")
|
|
if result.stderr:
|
|
print(f" stderr: {result.stderr[:500]}")
|
|
return False
|
|
except subprocess.TimeoutExpired:
|
|
print(" FAIL: trtexec timed out (>600s)")
|
|
return False
|
|
except FileNotFoundError:
|
|
print(f" FAIL: trtexec not found at {trtexec}")
|
|
return False
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description="Convert ONNX models to TensorRT FP16 engines")
|
|
parser.add_argument("--onnx", help="Input ONNX model path")
|
|
parser.add_argument("--output", help="Output .engine path")
|
|
parser.add_argument("--all", action="store_true", help="Convert all known models")
|
|
parser.add_argument("--onnx-dir", default="weights", help="Directory with ONNX files")
|
|
parser.add_argument("--engine-dir", default="/opt/engines", help="Output engine directory")
|
|
parser.add_argument("--no-fp16", action="store_true", help="Disable FP16 (use FP32)")
|
|
parser.add_argument("--workspace", type=int, default=1024, help="TRT workspace (MB)")
|
|
parser.add_argument("--check", action="store_true", help="Check trtexec availability only")
|
|
args = parser.parse_args()
|
|
|
|
# Check mode
|
|
if args.check:
|
|
trtexec = find_trtexec()
|
|
if trtexec:
|
|
print(f"trtexec found: {trtexec}")
|
|
return 0
|
|
else:
|
|
print("trtexec not found. Not on Jetson or TensorRT not installed.")
|
|
return 1
|
|
|
|
fp16 = not args.no_fp16
|
|
|
|
# Single model conversion
|
|
if args.onnx and args.output:
|
|
ok = convert_onnx_to_engine(args.onnx, args.output, fp16=fp16, workspace_mb=args.workspace)
|
|
return 0 if ok else 1
|
|
|
|
# Batch conversion
|
|
if args.all:
|
|
trtexec = find_trtexec()
|
|
if not trtexec:
|
|
print("trtexec not found. Conversion requires Jetson with JetPack installed.")
|
|
return 1
|
|
|
|
print(f"Converting all known models from {args.onnx_dir}/ → {args.engine_dir}/")
|
|
success = 0
|
|
fail = 0
|
|
for model_name, onnx_file in _MODELS.items():
|
|
onnx_path = os.path.join(args.onnx_dir, onnx_file)
|
|
engine_path = os.path.join(args.engine_dir, f"{model_name}.engine")
|
|
if not os.path.isfile(onnx_path):
|
|
print(f" SKIP {model_name}: {onnx_path} not found")
|
|
continue
|
|
ok = convert_onnx_to_engine(
|
|
onnx_path, engine_path,
|
|
fp16=fp16, workspace_mb=args.workspace, trtexec_path=trtexec,
|
|
)
|
|
if ok:
|
|
success += 1
|
|
else:
|
|
fail += 1
|
|
|
|
print(f"\nDone: {success} converted, {fail} failed")
|
|
return 1 if fail > 0 else 0
|
|
|
|
parser.print_help()
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|