dora-teleop

dora-rs teleoperation node: normalises two control sources — a gamepad read from dora-joy, and a web console served by this node itself — into one owner's lease, and emits velocity set-points and robot-agnostic commands. It carries no hardware driver: pad I/O lives in dora-joy, arm I/O in a robot node.

Requirements: dora 1.0+ (verified with dora-cli 1.0.1), Python 3.12+, uv.

System

flowchart LR
    pad([gamepad]) --> joy
    browser([browser]) -- "ws: held directions, verbs" --> web
    web -- "ui_state snapshot" --> browser
    joy["dora-joy — sibling repo"]
    subgraph teleop["dora-teleop"]
        web["web console — built in, HTTP + ws on one port"]
        core["command arbitration"]
    end
    joy -- "joy: axes, buttons, present" --> core
    web -- "held directions, ±1" --> core
    core -- "twist SI · command verbs (standard)" --> arm
    core -- "jog · request (deprecated)" --> arm
    arm -. "state · poses · response" .-> core
    arm["robot node"]

Quick start

uv sync
dora run dataflow.yml --uv        # teleop + bench stand-in: no pad, no arm

Open http://localhost:7000 and drive the robot from the console. The bench answers services and publishes telemetry so the loop closes.

Watching the wire

Every dataflow sets debug: enable_debug_inspection: true, so dora can inspect the wire without any node printing. This needs a coordinator, so it works for the arm-free dataflow:

dora up
dora start dataflow.yml --uv --name teleop-bench
dora topic list -d teleop-bench                              # every edge in the graph
dora topic echo -d teleop-bench teleop/jog                   # every velocity, live
dora topic hz   -d teleop-bench teleop/jog --duration 10     # the re-send cadence
dora stop --name teleop-bench && dora down

Running with hardware

Dataflow Nodes Needs
dataflow.yml teleop + bench stand-in nothing
dataflow-robot.yml joy + teleop + ulite6 a pad and an arm
dataflow-gamepad.yml the same, plus the probe, no console a pad and an arm

Gamepad

Control Does (base frame) Index Units
Left stick X / Y Translate in the horizontal plane: +X stick up, +Y stick right axes 0, 1 mm/s
Left / right trigger Translate along Z: right trigger lifts (+Z), left lowers axes 4, 5 mm/s
Right stick X / Y Rotate: +roll stick right, +pitch stick up axes 2, 3 deg/s
LB / RB Yaw: RB is +yaw buttons 6, 7 deg/s
A Close the tool button 0 —
B Open the tool button 1 —
X Release the E-STOP and clear the arm's error button 3 —
Y Toggle freedrive button 4 —
Back E-STOP — latches until X button 11 —

The sticks move the arm in its horizontal X/Y plane only; the triggers are the one path to Z. Up on the stick sends the arm away from the operator, the same +X convention the console draws.

Inputs and outputs

Direction Name Description
in tick 50 ms — change detection, deadman, telemetry
in joy One pad reading from dora-joy
in response An answer from the arm
in motion_state How a motion ended
in robot_state The arm's own state
in tcp_pose Tool-tip pose, six float32, mm and degrees
in joint_pose Joint angles, six float32, degrees
out twist Standard. {linear, angular, frame}, SI
out command Standard. {action, value}, robot-agnostic verbs
out jog Deprecated. mm/s + deg/s, for dora-ulite6
out request Deprecated. A service call, request_id in metadata
out ui_state The console's telemetry snapshot, as JSON

Environment variables

Variable Default Description
SPEED_MM_S 60.0 Translation speed at full deflection
SPEED_DEG_S 30.0 Rotation speed at full deflection
DEADZONE 0.12 Stick travel near centre to ignore
EXPO 0.4 How much of the curve is cubic; 0 is linear
JOG_TTL_S 0.4 Owner silence before the arm is stopped
JOG_KEEPALIVE_S 0.2 How often an unchanged velocity is repeated
JOY_TTL_S 0.2 joy silence before the pad reads as gone
GAMEPAD_IDLE_RELEASE_S 2.0 Untouched pad before it hands the arm back
STATE_POLL_S 0.5 How often to ask the arm what telemetry does not carry
WEB_HOST 0.0.0.0 Address the console binds to
WEB_PORT 7000 Console port; 0 opens no port at all

Development

uv sync --group dev
uv run pytest      # 149 tests, no gamepad, arm, browser or daemon needed
uv run ruff check .
uv run ruff format --check .
S
Description
Dora node that hands a robot arm to a human, from a gamepad or a browser
Readme
537 KiB
Languages
Python 89.5%
HTML 10.5%