SIL — 2D Perception
Deploy Halos SIL for Software-in-Loop testing.
Halos SIL requires VSS Warehouse 3.3 as its perception backend. Deploy VSS Warehouse first, as in Deploy AI Perception, with the SIL overrides of Step 2, before proceeding with Halos SIL deployment.
Prerequisites
See Prerequisites for hardware and software requirements.
Deploy with Halos Deployment Skill (recommended)
For an automated bring-up with a coding agent (Claude Code, Codex, Cursor, and similar), use the hoisa-deploy-profile skill — it replaces Steps 1–6 below with a single agent prompt. See Agentic Deployment.
Manual instructions below remain supported and are required if you are not using a coding agent.
Step 1: Download Packages
Clone the Halos Outside-In Safety repository (ships the compose files, profiles, configs, and scripts in-tree), then download the SIL data tarball from NGC:
Output:
halos-outside-in-safety/- Cloned repo (compose files, profiles, configs, scripts)sil-data/- Isaac Sim scenes and configs
Step 2: Deploy VSS Warehouse
Deploy VSS Warehouse 3.3.0, the GitHub release v3.3.0 of the VSS repository, as in Deploy AI Perception, or with the VSS repository’s vss-build-vision-ai skill (warehouse profile). Apply the overrides below before docker compose up — if perception builds its TensorRT engine with the wrong config, it has to build it again.
Before the first up:
-
Log Docker in to
nvcr.iowith your NGC API key. The release images,nvcr.io/nvidia/vss-core/*:3.3.0, do not pull anonymously; without the login a pull stops atunauthorized: authentication required. -
Download the app data,
nvidia/vss-warehouse/vss-warehouse-app-data:3.3.0, one 2.1 GB archive. Without--org nvidia --team vss-warehousethe download stops atMissing org - If Authenticated, org is also required.VSS_DATA_DIRis the extractedvss-warehouse-app-data/directory. It carries no models: perception downloads them into<vss_data>/models/at its first start. -
Prepare the data directories on a fresh extract. The containers run as different users, so their data directories must exist and be writable by all of them; otherwise Redis restarts in a loop on
Can't open the log file: Permission denied. This is the data-directory step of thevss-build-vision-aiskill:
<wh_ops> below is the VSS warehouse-operations directory, <vss_repo>/deploy/docker/industry-profiles/warehouse-operations/. Edit the override files there in place, but do not run docker compose from <wh_ops>/ — its compose.yml is only an app fragment and pulls in no infrastructure (Kafka, Redis, sdr-controller). Deploy from <vss_repo>/deploy/docker/ with containers.env, industry-profiles/warehouse-operations/.env and industry-profiles/warehouse-operations/overrides.env, in that order.
2.1 overrides.env Overrides
Set these in <wh_ops>/overrides.env, which Docker Compose reads last:
MODE=2d, BP_PROFILE=bp_wh_kafka, STREAM_TYPE=kafka, LLM_MODE=none and VLM_MODE=none
already ship; keep them. The Safety Core reads its events from Kafka: with bp_wh, or a
profile list without Kafka, it receives none while every container still looks healthy.
Export NGC_CLI_API_KEY in the shell that runs Docker Compose: perception downloads its
models with it at start. containers.env pins the images to nvcr.io/nvidia/vss-core, tag
3.3.0 (VSS_CONTAINER_TAG); leave it.
2.2 DeepStream Config
File: <wh_ops>/warehouse-2d-app/deepstream/configs/ds-main-config.txt
Disable SEI extraction in [source-list] (the app config ships it enabled):
Set the timing keys in [streammux]:
Isaac Sim 6.1 RTSP does embed SEI, but the Safety Core does not consume sim time — using it as the frame timestamp makes the Safety Core drop every event as STALE. System timestamps keep decisions flowing. Without these changes the perception pipeline also reports low FPS and bounding boxes flicker on VST.
2.3 Perception Model Config
Nothing to change. 2D runs the RT-DETR model that warehouse-2d-app downloads into <vss_data>/models/ at start, and the shipped warehouse-loading-dock-3cams-synthetic calibration is used as-is. (3D downloads its Sparse4D model the same way; see SIL — 3D Perception.)
2.4 VST Config
File: <wh_ops>/warehouse-2d-app/vst/configs/vst_config.json
Several copies of vst_config.json exist in the deploy tree. Edit the one the VST container actually mounts.
rtsp_streaming_over_tcp: true— ingest Isaac’s self-hosted RTSP over TCP. UDP ingest can stall RTP delivery silently (see Isaac Sim Streaming).use_sensor_ntp_time: false— pair withattach-sys-ts-as-ntp=1above so VST and DeepStream agree on wall-clock arrival time.bbox_tolerance_ms: 100— widen the metadata-to-frame match window (default0) to reduce bbox flicker on VST.
This file also carries a halo_safety_* block. Leave halo_safety_udp_port at its shipped -1 for the sil profile — SIL drives the safety indicator through the comm-layer / ROS 2 path, not the VST overlay. Only the base profile sets it to 12345.
2.5 Wait for the TensorRT Engine
Start VSS Warehouse. The first startup downloads the model and builds the TensorRT engine, which takes several minutes. Poll vss-rtvi-cv until all 3 cameras report a non-zero FPS:
Do not use docker logs -f here — it follows the stream and never returns.
Expected output when ready:
All 3 sources must report non-zero FPS. A source stuck at 0.00000 isn’t arriving — Isaac Sim is not streaming yet, the RTSP URL is wrong, or the engine is still building.
Then confirm the Safety Core event seam has data:
Do not proceed to Halos SIL until both signals fire: 3 cameras at FPS > 0, and mdx-events has data.
Step 3: Configure Halos SIL Environment
Required settings:
PSF_IMAGE (the PSF 1.4 Safety Core image,
nvcr.io/nvidia/halos-outside-in/outside-in-safety:nv-psf-halos-1.4-6b92731) and
ISAAC_SIM_IMAGE (nvcr.io/nvidia/isaac-sim:6.1.0) are pre-set — leave them. The 1.4
configurations do not run on the 1.3 image.
PSF_LAUNCH_MODE (Safety AI Monitor) and PSF_PCM_MODE (Perception Monitor) ship skip.
To run one active, also set its key to 1 in
closed-loop-testing/safety-core/configs/nvpss.conf (required_safety_monitor or
required_perception_monitor). Otherwise the Safety Core stops at start with
Error: --saim-mode active conflicts with required_safety_monitor = 0 in /opt/nvidia/psf/bin/nvpss.conf.
See Required monitors.
Two more settings choose the run, and their defaults are the 2D test scenario:
SCENARIO=warehouse_20x20_1flnames the scene, fleet file, cameras config and waypoints together (closed-loop-testing/isaac-sim/sil/configs/scenarios.yaml); Isaac and every controller read it.PSF_APP(unset =atl) picks the decision maker.pxcandboth(proximity) expect the 3D feed; see SIL — 3D Perception and Proximity Monitoring in the Deployment Guide.
Step 4: Deploy Halos SIL
Services started: safety-core, comm-layer, isaac-sim, forklift-controller.
Step 5: Run Test Scenario
SCENARIO from sil.env supplies the IRA config, the fleet file and the cameras config.
-c, --robots-config and --cameras-config still win over it for a one-off run.
For script usage details and additional options, see Execution Script.
What happens:
- Loads warehouse scene (20×20m)
- Spawns the forklift from the fleet file (
robots.yaml) and 3 digital humans - Initializes ROS2 Action Graph for forklift
- Runs forklift playback sequence
- Starts RTSP streaming — Isaac 6.1 self-hosts one RTSP server per camera (
8554/camera,8555/camera_01,8556/camera_02). See RTSP Multi-Camera Graph for the graph that builds them. - Registers 3 cameras with VST (
--enable-vstdeletes existing sensors, then adds the Isaac cameras once the render is warm)
Startup time:
- First run: 10–15 min — Isaac Sim loads its cache and compiles render shaders, then starts the simulation and brings up RTSP streaming.
- Subsequent runs: 5–10 min — cache and shaders are already compiled.
- Simulation: runs until you stop it.
--startstreams continuously rather than for a fixed frame count.
Step 6: Monitor Safety Commands
The log paths below use MDX_DATA_DIR from your sil.env. From the deployments/ directory, load it into your shell first (re-run it in each terminal you monitor from):
Monitor OPC server log:
Expected output:
🟢 MUTE (ALLOW OPERATION): Forklift in trailer, no humans detected (allow loading)
🟡 UNMUTE (PREVENT OPERATION): Human detected or forklift exiting (alarm active)
💓 HEARTBEAT: Periodic keep-alive (every 5s) — confirms PSF→comm-layer link is healthy
Monitor PSF:
Expected output:
EVENT_0 / EVENT_1: Tripwire crossings reported by perception (forklift OUT/IN trailer).
DecisionRequest: PSF decision-maker invoked — produces the corresponding MUTE/UNMUTE command on the OPC log above.
Step 7: View Camera Streams
VST UI — http://<HOST_IP>:30888/vst/
View live camera streams from Isaac Sim.

Cleanup and Restart
Restart the Scenario (Live Stack)
--start runs the scenario until it is stopped. To relaunch the Isaac scenario on an already-running stack, use the wrapper — it pauses VST stream processing for the boot window (so the fresh RTSP mounts don’t hit the cold-start “no caps” race), then resumes it once the streams are live:
Expect the mounts to warm in ~1–2 min (cached shaders), VST to resume, and DeepStream back at 3/3 cameras ~30 s later.
Reset to a Fresh Deployment
When a stack misbehaves in ways a restart doesn’t fix, return it to the clean first-bring-up state without paying the TensorRT/shader rebuild. Stop the scenario and the Halos stack, tear VSS down with down -v (it drops the VST sensor database volume; the models and the TensorRT engine live under VSS_DATA_DIR/models/ and are kept), redeploy VSS, then clear Redis before relaunching:
Keep VSS_DATA_DIR/models/ and the isaac-cache/ shader dirs — rebuilding them costs several minutes each.
Full Cleanup
docker volume prune -f removes every dangling volume on the host, not only this
stack’s. With the VSS stack down that includes the VST sensor database. Skip it unless
you want that reset, or remove the specific volumes instead.
Troubleshooting
Safety Core (PSF) Cannot Connect to Kafka
Warehouse (Kafka) must be running before Halos SIL. Check status:
If Kafka is not running, redeploy VSS Warehouse following Step 2: Deploy VSS Warehouse.
STALE Events in Safety Core (PSF)
First check that DeepStream stamps frames with system time (2.2). nvpss.conf ships timeWindowSize = 6000 (ms) for SIL; raise it only if events still arrive STALE:
Safety Indicator Flickering (Multi-Machine)
If multiple SIL systems run on the same network, each must use a unique ROS_DOMAIN_ID (0-232) in deployments/profiles/sil.env. Without this, ROS2 nodes from different machines publish to the same /safety/is_muted topic, causing cross-machine interference and safety indicator flickering.
Restart Halos SIL after changing. Verify with:
Should show Publisher count: 1.
Known Issues
Upstream Isaac Sim and VST issues affect the stream path; their status on Isaac Sim 6.1 and the workarounds are in Isaac Sim Streaming. They are not specific to 2D.
Next Steps
- SIL Architecture — System architecture and data flow
- Isaac Sim Configuration — Isaac Sim configuration
- Isaac Sim Action Graphs — Forklift control details
- Quick Start Guide — Once SIL is healthy, run the Regression Testing Reporter to score the safety decision