← Server Deploy — the other half of this stack, on the host (server2)
Robot deployment 🤖 robot aarch64
One container on the Jetson AGX Thor, all ROS 2 Jazzy. For a from-scratch machine (Ubuntu on JetPack, Docker, udev rules for the sensors), follow THOR-FRESH-INSTALL.html in the production-limit-robot-docker repo — this page assumes a Thor that is already set up and only covers the container itself.
What's in the box
| Node | Role |
|---|---|
zed_pub | publishes the two ZED 2i units — SDK backend (per-eye RGB + onboard IMU) or UVC/V4L2 backend (pre-composited stereo, no IMU) |
os_driver ouster_ros | Ouster OS0-128 (dedicated Ethernet, static IP) point cloud |
sensor_bridge limitx_sensors | the canonical /limitx/* bridge — composites the two ZED units into cam1/cam2, applies the camera rule, multiplexes IMU, forwards lidar + GNSS, publishes source health |
gateway limitx_gateway | packs /limitx/* into compact JSON over UDP, chunks large payloads, and sends to relay_host:relay_port |
The contract
- Publishes (6 topics):
/limitx/cam1(REAR stereo),/limitx/cam2(FRONT stereo),/limitx/imu,/limitx/lidar,/limitx/gnss,/limitx/source_health. - Subscribes: sensor sources only — the ZED pub topics,
/ouster/points, and/gnss/fix(the F9P receiver publishes this directly; no robot node drives it). There is no/limitx/cmd— the stack has no command path. - Camera rule: each composite is 2688×376 (2 × 1344×376 native ZED 2i eyes). Encoded frame > 256 KB (262,144 B) → JPEG quality 90,
codec=1; otherwise sent as raw RGB24,codec=2. The gateway base64-encodes the payload, and payloads larger than 48,000 B are split into ≤ 48,000 B UDP datagrams with a 12-byte header (magic, chunk seq, chunk count, message id, total length) — the relay reassembles, still one UDP port.
Deploy
# on the Jetson (AGX Thor) docker run -d \ --name limit-robot \ --restart unless-stopped \ --net host \ --privileged \ --device /dev/video0 \ --device /dev/video1 \ --device /dev/video2 \ --device /dev/video3 \ production-limit-robot-docker
--net hostis required — the UDP egress wants the machine's own interfaces./dev/video*are the ZED 2i UVC streams:video0/video1= FRONT unit,video2/video3= REAR unit (the odd numbers are V4L2 metadata nodes that never stream — the devices are still passed for the USB stack).- Any extra arguments are forwarded to
zed_pubas ROS 2 parameters — e.g. pin the backend explicitly:docker run … production-limit-robot-docker --ros-args -p backend:=uvc(backends:auto(default),sdk,uvc). - Config is baked into the image — no host volume mount.
/ws/params/gateway.yaml(relay target),/ws/params/ouster_os0.yaml, and the sensor_bridge defaults in/ws/install/limitx_sensors/share/limitx_sensors/config/sensors.yaml(camera rule, topic wiring, enable flags):
relay_host: 192.168.0.83 # server2 (eno1) relay_port: 9000 # limitx_relay UDP ingest lidar_max_pts: 512 # points per frame for the browser
docker exec -it limit-robot vi /ws/params/gateway.yaml then docker restart limit-robot (lost on image rebuild — bake the new file in for anything permanent).Verify
docker logs -f limit-robot ros2 topic hz /limitx/cam2 ros2 topic echo /limitx/source_health --once
Then on the dashboard: tiles T04, T05L/R, T06L/R, T09, T12, T28 light up (plus T08 IMU — work in progress — only with the SDK backend), the DASH LED goes ok, and the other three (ENGINE, DOG LINK, MUSIC) stay off until their sources exist — the whole loop working, no sim involved.
INVALID CALIBRATION FILE), so backend=auto degrades to UVC and /limitx/imu has no source — T08 stays STALE by design, not a fault. Once a valid SDK calibration file lands on the unit, auto picks the SDK and /limitx/imu (and T08) come online./gnss/fix. In an indoor lab it reports "no fix" forever — that's correct behaviour, not a fault. Point the antenna at sky and it locks.Day-to-day
| Task | Command |
|---|---|
| follow the logs | docker logs -f limit-robot (per-node logs land in /tmp/limit-robot/*.log in the container) |
| restart after a config edit | docker restart limit-robot |
| record a session | ros2 bag record /limitx/* on the Jetson |
| stop the robot | docker stop limit-robot — telemetry stops; there is no command channel, so the host can never drive it into a bad state |