Robot Deploy Guide

Limit X — Robot Deployment

One container on the Jetson AGX Thor (aarch64), all ROS 2 Jazzy. It reads two ZED 2i stereo units, an Ouster OS0-128 lidar over dedicated Ethernet, and an external F9P GNSS receiver, then streams the /limitx/* telemetry to the host over UDP :9000. Observe-only — nothing on the host can command it.

drag to orbit · scroll to zoom
LOADING LIMIT
STEP 1 · 🖥️ HOST
Server deployment
limit-docs :3010 · limit-dash :80 (UI) + :9000/udp (ingest)
STEP 2 · 🤖 ROBOT
Robot deployment — this page
limit-robot on the Jetson AGX Thor · aarch64

← 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

NodeRole
zed_pubpublishes the two ZED 2i units — SDK backend (per-eye RGB + onboard IMU) or UVC/V4L2 backend (pre-composited stereo, no IMU)
os_driver ouster_rosOuster OS0-128 (dedicated Ethernet, static IP) point cloud
sensor_bridge limitx_sensorsthe 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_gatewaypacks /limitx/* into compact JSON over UDP, chunks large payloads, and sends to relay_host:relay_port

The contract

Deploy

bash · robot
# 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
yaml · /ws/params/gateway.yaml
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
gateway.yaml is read at startup only. Quick change: 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

bash · 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.

IMU — work in progress: comes from the ZED 2i onboard sensors and only exists on the SDK backend. On the current units the ZED SDK rejects the calibration file (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: the F9P is an external USB receiver publishing /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

TaskCommand
follow the logsdocker logs -f limit-robot (per-node logs land in /tmp/limit-robot/*.log in the container)
restart after a config editdocker restart limit-robot
record a sessionros2 bag record /limitx/* on the Jetson
stop the robotdocker stop limit-robot — telemetry stops; there is no command channel, so the host can never drive it into a bad state
Stop order: robot first, then the host stack. The robot is the producer and holds the physical state; the dashboard can drop off any time. See the Server Deploy page for the host side.