mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-21 21:11:12 +00:00
[AZ-243] Integrate production native VIO runtime
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,20 +1,31 @@
|
||||
"""Replaceable VIO adapter component."""
|
||||
|
||||
from .interfaces import (
|
||||
ConfiguredNativeVioBackend,
|
||||
LocalVioAdapter,
|
||||
NativeVioBackend,
|
||||
NativeVioRunner,
|
||||
NativeVioRunnerFactory,
|
||||
ReplayVioBackend,
|
||||
VioAdapter,
|
||||
VioBackend,
|
||||
VioBackendError,
|
||||
create_vio_adapter,
|
||||
)
|
||||
from .types import (
|
||||
VioBackendEstimate,
|
||||
VioHealthReport,
|
||||
VioInputPacket,
|
||||
VioProcessingResult,
|
||||
VioRuntimeConfig,
|
||||
)
|
||||
from .types import VioBackendEstimate, VioHealthReport, VioInputPacket, VioProcessingResult
|
||||
|
||||
__all__ = [
|
||||
"ConfiguredNativeVioBackend",
|
||||
"LocalVioAdapter",
|
||||
"NativeVioBackend",
|
||||
"NativeVioRunner",
|
||||
"NativeVioRunnerFactory",
|
||||
"ReplayVioBackend",
|
||||
"VioAdapter",
|
||||
"VioBackend",
|
||||
@@ -23,4 +34,6 @@ __all__ = [
|
||||
"VioHealthReport",
|
||||
"VioInputPacket",
|
||||
"VioProcessingResult",
|
||||
"VioRuntimeConfig",
|
||||
"create_vio_adapter",
|
||||
]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""Public VIO adapter interfaces."""
|
||||
|
||||
from collections.abc import Callable
|
||||
from time import perf_counter
|
||||
from typing import Any, Protocol, runtime_checkable
|
||||
|
||||
@@ -12,6 +13,7 @@ from .types import (
|
||||
VioHealthReport,
|
||||
VioInputPacket,
|
||||
VioProcessingResult,
|
||||
VioRuntimeConfig,
|
||||
)
|
||||
|
||||
|
||||
@@ -45,7 +47,9 @@ class NativeVioRunner(Protocol):
|
||||
def initialize(self) -> None:
|
||||
"""Prepare engine resources."""
|
||||
|
||||
def estimate(self, frame: Any, telemetry_window: tuple[Any, ...]) -> VioBackendEstimate | dict[str, Any]:
|
||||
def estimate(
|
||||
self, frame: Any, telemetry_window: tuple[Any, ...]
|
||||
) -> VioBackendEstimate | dict[str, Any]:
|
||||
"""Return an estimate payload for one synchronized replay frame."""
|
||||
|
||||
|
||||
@@ -53,6 +57,9 @@ class VioBackendError(RuntimeError):
|
||||
"""Raised when the configured VIO engine cannot produce an estimate."""
|
||||
|
||||
|
||||
NativeVioRunnerFactory = Callable[[], NativeVioRunner]
|
||||
|
||||
|
||||
class NativeVioBackend:
|
||||
"""Configurable backend adapter for native VIO engine packages."""
|
||||
|
||||
@@ -64,14 +71,14 @@ class NativeVioBackend:
|
||||
try:
|
||||
self._runner.initialize()
|
||||
except Exception as exc:
|
||||
raise VioBackendError(f"{self.backend_name} initialization failed") from exc
|
||||
raise VioBackendError(f"{self.backend_name} initialization failed: {exc}") from exc
|
||||
|
||||
def estimate(self, frame: Any, telemetry_window: tuple[Any, ...]) -> VioBackendEstimate:
|
||||
started = perf_counter()
|
||||
try:
|
||||
estimate = self._runner.estimate(frame, telemetry_window)
|
||||
except Exception as exc:
|
||||
raise VioBackendError(f"{self.backend_name} estimate failed") from exc
|
||||
raise VioBackendError(f"{self.backend_name} estimate failed: {exc}") from exc
|
||||
|
||||
try:
|
||||
if isinstance(estimate, VioBackendEstimate):
|
||||
@@ -81,14 +88,44 @@ class NativeVioBackend:
|
||||
else:
|
||||
payload = dict(estimate)
|
||||
payload.setdefault("timestamp_ns", frame.timestamp_ns)
|
||||
payload["processing_latency_ms"] = payload.get("processing_latency_ms") or (
|
||||
perf_counter() - started
|
||||
) * 1000.0
|
||||
payload["processing_latency_ms"] = (
|
||||
payload.get("processing_latency_ms") or (perf_counter() - started) * 1000.0
|
||||
)
|
||||
return VioBackendEstimate.model_validate(payload)
|
||||
except Exception as exc:
|
||||
raise VioBackendError(f"{self.backend_name} returned invalid estimate") from exc
|
||||
|
||||
|
||||
class ConfiguredNativeVioBackend:
|
||||
"""Lazily creates the configured native runner during adapter initialization."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
runner_factory: NativeVioRunnerFactory,
|
||||
backend_name: str = "basalt",
|
||||
) -> None:
|
||||
self._runner_factory = runner_factory
|
||||
self._backend: NativeVioBackend | None = None
|
||||
self.backend_name = backend_name
|
||||
|
||||
def initialize(self) -> None:
|
||||
try:
|
||||
runner = self._runner_factory()
|
||||
except Exception as exc:
|
||||
raise VioBackendError(f"{self.backend_name} runner creation failed") from exc
|
||||
|
||||
if not isinstance(runner, NativeVioRunner):
|
||||
raise VioBackendError(f"{self.backend_name} runner does not implement NativeVioRunner")
|
||||
|
||||
self._backend = NativeVioBackend(runner, backend_name=self.backend_name)
|
||||
self._backend.initialize()
|
||||
|
||||
def estimate(self, frame: Any, telemetry_window: tuple[Any, ...]) -> VioBackendEstimate:
|
||||
if self._backend is None:
|
||||
raise VioBackendError(f"{self.backend_name} runner is not initialized")
|
||||
return self._backend.estimate(frame, telemetry_window)
|
||||
|
||||
|
||||
class ReplayVioBackend:
|
||||
"""Small local backend for replay smoke tests when no engine is configured."""
|
||||
|
||||
@@ -125,11 +162,15 @@ class LocalVioAdapter:
|
||||
def __init__(
|
||||
self,
|
||||
backend: VioBackend | None = None,
|
||||
runtime_config: VioRuntimeConfig | None = None,
|
||||
timestamp_tolerance_ns: int = 5_000_000,
|
||||
degraded_quality_threshold: float = 0.35,
|
||||
) -> None:
|
||||
self._backend = backend or ReplayVioBackend()
|
||||
self._backend_name = getattr(self._backend, "backend_name", self._backend.__class__.__name__)
|
||||
self._runtime_config = runtime_config or VioRuntimeConfig(mode="replay")
|
||||
self._backend = backend or _backend_from_runtime_config(self._runtime_config, None)
|
||||
self._backend_name = getattr(
|
||||
self._backend, "backend_name", self._backend.__class__.__name__
|
||||
)
|
||||
self._timestamp_tolerance_ns = timestamp_tolerance_ns
|
||||
self._degraded_quality_threshold = degraded_quality_threshold
|
||||
self._initialized = False
|
||||
@@ -243,3 +284,45 @@ class LocalVioAdapter:
|
||||
retryable=False,
|
||||
cause=cause,
|
||||
)
|
||||
|
||||
|
||||
def create_vio_adapter(
|
||||
runtime_config: VioRuntimeConfig,
|
||||
native_runner_factory: NativeVioRunnerFactory | None = None,
|
||||
timestamp_tolerance_ns: int = 5_000_000,
|
||||
degraded_quality_threshold: float = 0.35,
|
||||
) -> LocalVioAdapter:
|
||||
backend = _backend_from_runtime_config(runtime_config, native_runner_factory)
|
||||
return LocalVioAdapter(
|
||||
backend=backend,
|
||||
runtime_config=runtime_config,
|
||||
timestamp_tolerance_ns=timestamp_tolerance_ns,
|
||||
degraded_quality_threshold=degraded_quality_threshold,
|
||||
)
|
||||
|
||||
|
||||
def _backend_from_runtime_config(
|
||||
runtime_config: VioRuntimeConfig,
|
||||
native_runner_factory: NativeVioRunnerFactory | None,
|
||||
) -> VioBackend:
|
||||
if runtime_config.effective_mode == "replay":
|
||||
return ReplayVioBackend()
|
||||
if native_runner_factory is None:
|
||||
native_runner_factory = _default_native_runner_factory(runtime_config)
|
||||
return ConfiguredNativeVioBackend(
|
||||
native_runner_factory,
|
||||
backend_name=runtime_config.native_backend_name,
|
||||
)
|
||||
|
||||
|
||||
def _default_native_runner_factory(runtime_config: VioRuntimeConfig) -> NativeVioRunnerFactory:
|
||||
def create_runner() -> NativeVioRunner:
|
||||
from vio_adapter.native.basalt import BasaltNativeRunner
|
||||
|
||||
return BasaltNativeRunner(
|
||||
module_name=runtime_config.native_runner_module,
|
||||
factory_name=runtime_config.native_runner_factory,
|
||||
config=runtime_config.native_runner_config,
|
||||
)
|
||||
|
||||
return create_runner
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""Native VIO backend package exports."""
|
||||
|
||||
from vio_adapter.interfaces import NativeVioBackend, NativeVioRunner, VioBackendError
|
||||
from vio_adapter.native.basalt import BasaltNativeRunner
|
||||
|
||||
__all__ = ["NativeVioBackend", "NativeVioRunner", "VioBackendError"]
|
||||
__all__ = ["BasaltNativeRunner", "NativeVioBackend", "NativeVioRunner", "VioBackendError"]
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
"""Loader for installed BASALT-compatible VIO runtime packages."""
|
||||
|
||||
from collections.abc import Mapping
|
||||
from importlib import import_module
|
||||
from typing import Any
|
||||
|
||||
from vio_adapter.interfaces import NativeVioRunner, VioBackendError
|
||||
from vio_adapter.types import VioBackendEstimate
|
||||
|
||||
|
||||
class BasaltNativeRunner:
|
||||
"""Adapts an installed BASALT binding to the VIO runner protocol."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
module_name: str = "basalt_vio",
|
||||
factory_name: str = "create_runner",
|
||||
config: Mapping[str, object] | None = None,
|
||||
) -> None:
|
||||
self._module_name = module_name
|
||||
self._factory_name = factory_name
|
||||
self._config = dict(config or {})
|
||||
self._runner: NativeVioRunner | None = None
|
||||
|
||||
def initialize(self) -> None:
|
||||
try:
|
||||
module = import_module(self._module_name)
|
||||
factory = getattr(module, self._factory_name)
|
||||
runner = factory(**self._config)
|
||||
except Exception as exc:
|
||||
raise VioBackendError(
|
||||
f"unable to load BASALT runtime {self._module_name}:{self._factory_name}"
|
||||
) from exc
|
||||
|
||||
if not isinstance(runner, NativeVioRunner):
|
||||
raise VioBackendError(
|
||||
f"BASALT runtime {self._module_name}:{self._factory_name} "
|
||||
"does not implement NativeVioRunner"
|
||||
)
|
||||
|
||||
self._runner = runner
|
||||
self._runner.initialize()
|
||||
|
||||
def estimate(self, frame: Any, telemetry_window: tuple[Any, ...]) -> VioBackendEstimate:
|
||||
if self._runner is None:
|
||||
raise VioBackendError("BASALT runtime is not initialized")
|
||||
return self._runner.estimate(frame, telemetry_window)
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, NonNegativeInt
|
||||
from pydantic import BaseModel, ConfigDict, Field, NonNegativeInt, model_validator
|
||||
|
||||
from shared.contracts import FramePacket, TelemetrySample, VioStatePacket
|
||||
from shared.errors import ErrorEnvelope
|
||||
@@ -17,6 +17,33 @@ class VioInputPacket(VioAdapterModel):
|
||||
telemetry_samples: tuple[TelemetrySample, ...] = Field(min_length=1)
|
||||
|
||||
|
||||
VioRuntimeEnvironment = Literal["development", "ci", "staging", "jetson", "production"]
|
||||
VioRuntimeMode = Literal["replay", "native"]
|
||||
|
||||
|
||||
class VioRuntimeConfig(VioAdapterModel):
|
||||
environment: VioRuntimeEnvironment = "development"
|
||||
mode: VioRuntimeMode | None = None
|
||||
native_backend_name: str = Field(default="basalt", min_length=1)
|
||||
native_runner_module: str = Field(default="basalt_vio", min_length=1)
|
||||
native_runner_factory: str = Field(default="create_runner", min_length=1)
|
||||
native_runner_config: dict[str, object] = Field(default_factory=dict)
|
||||
|
||||
@model_validator(mode="after")
|
||||
def production_requires_native_mode(self) -> "VioRuntimeConfig":
|
||||
if self.environment in {"jetson", "production"} and self.effective_mode != "native":
|
||||
raise ValueError("jetson and production VIO profiles require native runtime mode")
|
||||
return self
|
||||
|
||||
@property
|
||||
def effective_mode(self) -> VioRuntimeMode:
|
||||
if self.mode is not None:
|
||||
return self.mode
|
||||
if self.environment in {"jetson", "production"}:
|
||||
return "native"
|
||||
return "replay"
|
||||
|
||||
|
||||
class VioHealthReport(VioAdapterModel):
|
||||
initialized: bool
|
||||
state: Literal["not_initialized", "ready", "degraded", "failed"]
|
||||
|
||||
Reference in New Issue
Block a user