Deploy Guide

Limit X — Software Stack Deployment

Two machines, two sections: the server stack on the host, the robot stack on the Jetson. Everything is Docker, offline at runtime, zero network calls after deploy.

drag to orbit · scroll to zoom
LOADING LIMIT
STEP 1 · 🖥️ HOST
Server deployment
limit-docs :3000 · limit-dash :3002
STEP 2 · 🤖 ROBOT
Robot deployment
limit-robot on the Jetson · aarch64

Server deployment 🖥️ host x86-64

The host (Server2, 192.168.0.83) runs two containers — the docs site and the dashboard. Nothing else: no database, no optional extras.

Before you start

  1. Two machines on the same L2 network — the host and the robot (Jetson AGX Thor). No internet needed at runtime.
  2. Docker Engine installed and sudo-free for the deploy user on both machines.
  3. Images on the host: limit-docs:1.0, limit-dash:1.0 (both x86-64); limit-robot:1.0 (aarch64) on the Jetson.
  4. Ports free on the host: 3000 (docs), 3002 (dash), 9000/udp (telemetry in from the robot).
Architecture rule: x86-64 images run only on the host, limit-robot (aarch64) only on the Jetson. docker load of the wrong image on the wrong machine fails immediately — the only thing that crosses the wire is UDP JSON telemetry (robot → host, port 9000).

Air-gapped image transfer

bash · save → transport → load
# 1. on the machine that BUILT the image
docker save limit-dash:1.0 -o limit-dash.tar
# 2. copy limit-dash.tar to the target (USB stick, sftp, whatever)
# 3. on the TARGET machine
docker load -i limit-dash.tar
docker images | grep limit-dash   # confirm tag + arch before you run

Docs site (port 3000)

bash · docs
docker run -d \
  --name limit-docs \
  -p 3000:80 \
  limit-docs:1.0

Limit Dash (port 3002)

bash · dash
docker run -d \
  --name limit-dash \
  -p 3002:80 \
  -p 9000:9000/udp \
  limit-dash:1.0

Verify

  1. curl http://192.168.0.83:3002/ — dashboard HTML.
  2. curl http://192.168.0.83:3002/api/health — relay reports alive.
  3. Open http://192.168.0.83:3002 — panels are grey/stale until the robot starts; flip SIM and they light up with synthetic data, proving the pipeline.

Day-to-day

TaskCommand
follow the logsdocker logs -f limit-dash (or limit-docs)
restart a piecedocker restart limit-dash
change the dash portrerun with a free published port (e.g. -p 8443:80) — the relay's internal 9000/8000 split doesn't change
stop the host stackdocker stop limit-dash limit-docs

Robot deployment 🤖 robot aarch64

One container on the Jetson, all ROS 2 Jazzy. It sees the USB cameras, drives the joints, and streams the /limitx/* telemetry to the host over UDP 9000.

What's in the box

NodeRole
limitx_gatewayingests the ROS topics, packs them into the UDP JSON envelope
limitx_drivertalks to the joint bus, runs the gait state machine
camera_bridgegrabs ZED 2i frames, encodes per the camera rule below
telemetry_publisherstamps, sequences, and publishes the /limitx/* topics

The contract

Deploy

bash · robot
# on the Jetson, as the limit user
docker run -d \
  --name limit-robot \
  --network host \
  --device /dev/video0 \
  --device /dev/video1 \
  -v /home/limit/limit-robot/config:/app/config \
  limit-robot:1.0
yaml · gateway.yaml
relay_host: 192.168.0.83
relay_port: 9000
gateway.yaml changes are read at startup only. Edit the host file, then docker restart limit-robot — editing inside the running container is a no-op.

Verify

bash · verify
docker logs -f limit-robot
ros2 topic hz /limitx/joints
ros2 topic echo /limitx/status

Then on the dashboard: panels T01–T27 light up and the 4 status LEDs reflect the real sensor state — the whole loop working, no sim involved.

IMU: fused from the ZED 2i — if the camera is cold-booted after the IMU, expect ~5 s of no data on /limitx/imu before lock.
GNSS: a F9P in an indoor lab 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
restart after a config editdocker restart limit-robot
record a sessionros2 bag record /limitx/* on the Jetson
stop the robotdocker stop limit-robot — joints drop to the safe idle pose
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.