07Operating the robot

One server, one wire contract, every client. The same launcher pattern runs the simulator on a laptop and the real robot on the Jetson; iOS, Vision Pro, and the browser connect identically to either — they cannot tell which is live.

Launch — simulator (laptop)

cd server && ./run.sh              # full sim stack + web studio on :8097
./run.sh --test                    # open-field sandbox scene + native viewer
./run.sh --no-tui                  # plain scrolling output instead of the cockpit

In an interactive terminal the launcher becomes a retro cockpit TUI: live joints with deviation tracks, the robot rendered from the actual model, camera and lidar panels, log tails. It is also a teleop client:

KeyAction
drive the base (hold to move; release stops)
a / drotate left / right
w / slift up / down
Enter / rre-anchor the teleop clutch / reset the sim
l / h / qlog panel / help / quit everything

Launch — real robot (Jetson)

./server/real_run.sh               # HAL + SLAM + Nav2 + app server (+ cockpit TUI)
./server/real_run.sh --no-slam     # motors + cameras only
./server/real_run.sh --only-hands  # bench a single subsystem (also --only-base, --only-cameras)
./server/real_run.sh -h            # every flag

Clients

ClientHow
Browser consolehttp://<host>:8080/console — video + keyboard drive, zero install
Control studiosreal: http://<host>:8094 · sim: :8097 — full control GUI, visualizer, monitor
iPhone appauto-discovers the robot on the same Wi-Fi (Bonjour), or add the host IP
Vision Prowhole-body teleop: your hands drive the arms/hands, stereo video in immersive space
Remotea relay tunnel (rathole + Caddy on any VPS) exposes the same contract over the internet; LAN/Tailscale is always the low-latency path
Whole-body teleop flow: put both hands in view until tracking is solid, then anchor the clutch (headset recenter, or Enter in the cockpit). The arms stay limp until you explicitly enable torque from a client — launching never energizes anything.

The safety model

Every safeguard below is real and lives in the code:

LayerBehavior
E-stopany client sends estop → the bridge zeros all commands and latches stopped; a hardware e-stop de-energizes actuators independently of the host
Deadmanno fresh command in 0.3 s → drive zeros; lost Teensy heartbeat → controllers disable in ~150 ms
Tip-overa ZMP model bounds base speed/accel from the measured CoM — the envelope tightens as the lift rises
Self-collisiona CBF-QP keeps the arms out of each other and the body
Arbitrationa single-driver lock: two operators can't fight; discrete commands outrank streams
Tracking losslost hand tracking holds pose — it never extrapolates
One gateevery base twist from every client passes safe_base_step() in controller/; no code path bypasses it
Before any energized session: know where your hardware e-stop is, confirm the software e-stop from the client you are using, and keep the first sessions in an open area at reduced speed caps.