Hosted Teleop
Operate a DimOS robot remotely from any browser or Quest headset over WebRTC. The robot dials out to a hosted Cloudflare Realtime SFU broker (teleop.dimensionalos.com), so you don’t need to open any inbound ports on the robot’s network — it works behind a home router, on Wi-Fi, or wired LAN.Quick Start
| Module | Role |
|---|---|
HostedTeleopModule | Dials the broker, owns the WebRTC connection, datachannels, video, clock-sync, and live telemetry |
HostedTwistTeleopModule | Mobile-base subclass: scales operator commands into cmd_vel (m/s, rad/s) |
HostedArmTeleopModule | Arm-IK subclass: per-hand pose routing to coordinator tasks |
Go2Module (in the blueprint) | The robot driver receiving cmd_vel |
Get an API key
- Visit teleop.dimensionalos.com and sign up.
- On the dashboard, API Keys → + New Key.
- Copy the key (shown once) and pass it as
TELEOP_API_KEYwhen launching the blueprint.
Available blueprints
| Blueprint | Use case | Subclass |
|---|---|---|
teleop-hosted-go2 | Mobile base (Unitree Go2, wheeled robots) | HostedTwistTeleopModule |
teleop-hosted-xarm7 | Arm IK (UFactory xArm7) | HostedArmTeleopModule |
recording_teleop_<ts>.db plus a report.md next to it on
disconnect. Reports can also be regenerated from an existing .db:
Operator inputs
The browser is modality-agnostic — it just streams whatever the device gives it, and the robot blueprint decides what to do with it.| Device | Input | Maps to |
|---|---|---|
| Desktop browser | WASD keyboard | TwistStamped → cmd_vel |
| Phone | On-screen WASD keys | same path as keyboard |
| Quest 3 (Twist robot) | Left thumbstick Y → forward/back, X → strafe; Right thumbstick X → yaw | Joy → derived twist on the robot |
| Quest 3 (Arm robot) | Controller poses + analog triggers | PoseStamped → coordinator TeleopIKTask |
Live metrics HUD
While connected, the operator sees a metrics overlay (corner pill in the browser, in-headset stats panel in VR). Color-coded green/amber/red based on video and command-plane health:| Metric | Source |
|---|---|
fps, bitrate, loss, jitter buffer, decode time, freezes | Operator’s getStats() on the inbound video track |
RTT | NTP-style min-RTT clock sync over the reliable datachannel |
cmd latency, jitter, rate | Robot-measured from the inbound twist stream — what actually arrived, sent back over state_reliable_back |
.db and summarizes them in
report.md.
Configuration
HostedTeleopConfig (base, applies to both subclasses):
| Field | Default | Notes |
|---|---|---|
broker_url | https://teleop.dimensionalos.com | Override via -o / config to point at a self-hosted broker |
broker_api_key | "" | Required. Env: TELEOP_API_KEY |
robot_id | "" | Required, identifies this robot. Env: TELEOP_ROBOT_ID |
robot_name | "" | Display name shown in the dashboard. Env: TELEOP_ROBOT_NAME |
control_loop_hz | 50.0 | Per-hand publish + button-state cycle |
heartbeat_hz | 1.0 | HTTP heartbeat to the broker (also drives channel-id sync) |
telemetry_hz | 3.0 | Robot → operator HUD command-plane stats |
stun_urls | [stun:stun.cloudflare.com:3478] | STUN servers for ICE |
turn_urls, turn_username, turn_credential | "" | TURN credentials. Fields exist; not yet auto-provisioned. |
HostedTwistTeleopConfig adds:
| Field | Default | Notes |
|---|---|---|
linear_speed | 0.5 | Multiplied into cmd_vel.linear (m/s) |
angular_speed | 0.8 | Multiplied into cmd_vel.angular (rad/s) |
HostedArmTeleopConfig adds:
| Field | Default | Notes |
|---|---|---|
task_names | {} | Maps "left"/"right" → coordinator task name (e.g. "teleop_xarm"), used as frame_id so the coordinator routes to the right IK task |
How it connects
ontrack fires.
For the WebRTC / aiortc / Cloudflare implementation details (MAX_BUNDLE
constraints, candidate propagation, the throwaway SCTP id 0 channel, thread
model), see dimos/teleop/quest_hosted/README.md.
Known Limitations
- Single operator per robot session today. Multi-viewer / single-driver+watchers is roadmapped.
- TURN is not wired yet. ICE relies on STUN only, so direct connectivity must succeed — works on most home/office networks, can fail on symmetric NAT or cellular. TURN field plumbing exists.
- No auto-reconnect. If the link drops mid-session, the operator must click Connect again. The robot side stays up; reconnection is supported, just manual.
- Single camera per robot today. Multi-camera support is roadmapped.
- Operator is in a fixed slot until clean disconnect — a tab-close leaves the slot held until the broker’s grace timeout fires (or the robot restarts).
