Runtime safety · Jetson AGX Thor · Vision-language models

A safety layer that measures itself before it judges a robot.

Structured safety events, a policy engine for PPE, zones and proximity, and an operator review API. Measured on Jetson AGX Thor for what it costs to run, then pushed through a real vision-language model to find out what it gets wrong.

Hardware Jetson AGX Thor Developer Kit, tegra264, L4T R38.4.0, 120W; Cosmos-Reason2-2B and 8B served by vLLM 0.14 on device
Dates 2026-09-09 measurements, ten run artifacts
Scope Runtime overhead and inference cost on simulation footage. Detection quality is not measured: no ground truth exists yet.
// PIPELINE

Frames in, reviewable events out.

An edge worker samples frames from a source, asks a model adapter for detections, evaluates them against the safety policy, and posts structured safety events to a FastAPI backend with an operator review queue. Every event carries the rule, severity, confidence, a human-review flag and its evidence.

The adapter boundary is the point of the design. A deterministic mock adapter measures the pipeline alone. An OpenAI-compatible adapter puts a real vision-language model behind the same interface, so the same run artifact records both the runtime cost and what the model returned.

Every run writes one JSON artifact with device provenance, per-frame timings, token usage, event and detection counts, peak memory and a 1 Hz tegrastats summary. Nothing on this page is typed by hand.

// BUILT

What was built.

  • Safety event schema and policy engine: PPE missing, zone intrusion, human-robot proximity, with severity, confidence gating and human-review flags.
  • Edge worker with mock, OpenAI-compatible and Cosmos-Reason2 adapters; batched event posting; run reports with provenance.
  • FastAPI backend with SQLite store, single and batch event endpoints, operator review, and Alembic migrations.
  • Run recorder and tegrastats sampler that turn each run into a committed artifact; an evidence page generated from those artifacts.
// THOR EVIDENCE

The pipeline keeps camera rate; the backend does not.

With the mock adapter at 30 fps pacing, the worker sustained 28.588 frames/s over 1800 frames with rule evaluation at 0.9877 ms p95 and board power at the idle level, 24,604 mW p50 (`reports/thor/mock_30fps_no_post.json`). Posting each event to the backend synchronously dropped throughput to 4.357 frames/s at 160.9 ms per frame; batching a frame's events into one request lifted it to 7.075 frames/s at 68.2 ms (`mock_30fps_backend.json`, `mock_30fps_backend_batched.json`).

Cosmos-Reason2-2B served by vLLM on the same device cost 4.35 s p50 and 12.85 s p95 per frame with its reasoning block, at 66.6 W board power (`cosmos2b_video_60.json`). Reasoning length drove the tail: the slowest frames produced near 1000 completion tokens at about 61 tokens/s.

28.588 frames/s Worker at 30 fps pacing, mock model, 1800 frames
0.9877 ms Rule evaluation p95 per frame
4.357 to 7.075 frames/s Backend posting, per event versus one batch per frame
4.35 s p50 Cosmos-Reason2-2B per frame, think block on, 66.6 W
Worker throughput per mock run on Thor, log scale
Worker throughput per run, from the mock-adapter artifacts under `reports/thor/`. Served from the repository's evidence page.
Cosmos-Reason2 inference latency p50 and p95 per run on Thor
Per-frame inference latency, p50 and p95, for the six Cosmos-Reason2 runs.
// CONSTRAINED OUTPUT

The grammar fixed the vocabulary and exposed the real problem.

Four runs on the same 60 frames. Disabling the think block halved the p95 to 6.58 s. Adding a JSON-schema grammar to the decoder removed every out-of-vocabulary label, 59 before, 0 after, and brought the p50 to 2.69 s and p95 to 3.36 s (`cosmos2b_video_60_schema.json`). It also made the 2B report six persons on footage that has none, and five of those tripped PPE and proximity rules: seven false safety events.

Cosmos-Reason2-8B under the same grammar and prompt reported zero persons and zero events on the same frames at 3.20 s p50 (`cosmos8b_video_60_schema.json`), decoding at roughly 13 tokens/s against 60 for the 2B. Sixty frames of one video is a signal, not a rate. A server detail is recorded too: with vLLM's `--reasoning-parser qwen3` enabled, `response_format` JSON schema was accepted but not enforced, so the constrained runs used a second container without the parser.

59 to 0 Out-of-vocabulary labels before and after the grammar, 2B
2.69 s p50 2B under the grammar, from 4.35 s
6 persons, 7 events 2B on people-free footage, all false
0 persons, 0 events 8B under the same grammar, 3.20 s p50
Out-of-vocabulary labels, phantom persons and false events per Cosmos-Reason2 run
Vocabulary compliance and phantom persons per run, counts over 60 frames.
Board input power p50 per run on Thor
Board input power at p50 per run; about 24 W is the device's idle level, the model runs sit near 60 to 70 W.
// CORRECTIONS

What went wrong and what was corrected.

The first real-model run failed at frame 26 on a 60 s adapter timeout; the log is kept (`cosmos2b_video_60_attempt1_timeout.log`), the timeout became a command-line option, and a failed run now writes a partial artifact with its error. With the grammar and the original prompt, which still asked for an `<answer>` wrapper the grammar forbids, the model emitted an empty list on every frame; that run is kept as `cosmos2b_video_60_schema_v1prompt.json` and the prompt was rewritten for JSON-only output.

The unconstrained 2B echoed the schema string itself as a label on 12 detections. That is in the artifact, not edited out.

// LIMITS AND NEXT

What is not established.

  • No precision or recall for any rule. There is no labelled ground truth, so the false events above are counted, not rated.
  • No real camera input; the footage is an Isaac Sim recording with no people in it.
  • Runs are 60 to 390 seconds, not sustained operation.
  • No operator dashboard; review is through the API.
  • Zone geometry is configured, not derived from calibration.

Next work is authored simulation scenes with known PPE and zone states so both model sizes get a precision and recall, asynchronous event posting, and a live camera source.

// OPEN THE EVIDENCE

Evidence page and raw records.

The evidence page is generated from the committed run artifacts by the repository's own script and served by GitHub Pages; every row links to its JSON.