The browser reached this node through `dora-websocket-transceiver`: a second node, a second port, and a round trip through the dataflow for every button press, to carry a UI only this node can interpret. The node now serves the page and holds the browsers' sockets itself on one port, so the console is one URL and a consumer wires nothing for it. `dora_teleop/server.py` runs aiohttp on a thread of its own and meets the control loop at two non-blocking points: a bounded queue the tick drains, and a snapshot handed back. Both queues are bounded deliberately — a flood is dropped rather than grown, and a slow browser loses stale snapshots rather than the newest — because nothing a browser does may stall the thread that stops the arm. A port already in use stops the node rather than leaving it announcing a console nobody can open. The web deadman moved but did not change: it was a `clients` message from the bridge and is now the open-socket count read each tick. One hop fewer, same meaning. Contract, so 0.2.0 -> 0.3.0: `ui_command` and `clients` are gone. `ui_state` stays published for `dora topic echo` and the bench, with no browser reading it. New WEB_HOST and WEB_PORT (7000; 0 opens no port). The console itself is laid out like the arm's own pendant — two rings quartered into arc sectors you hold, each with its out-of-plane axis as pills above. Directions and signs match xArm Studio on the controller, `Y+` on the left included: two consoles driving one arm that disagree about which way is +Y is a trap, not a preference. Also sends a velocity only when it changes, repeating an unchanged one on JOG_KEEPALIVE_S (0.2 s) purely to beat the consumer's own expiry. Repeating every tick made `dora-ulite6` re-plan the same motion twenty times a second. That turned out not to be the whole cause of the stepping an operator felt — the rest was fixed in dora-ulite6 v0.3.1, pinned here — but sending 18 messages where 83 went before is worth keeping on its own. `dora-joy` moves to v0.1.1: v0.1 is an annotated tag, and dora 1.0.1 records the tag object's id as the commit hash and then rejects its own checkout for sitting on the peeled commit. Neither dataflow could be built before this.
112 lines
3.9 KiB
YAML
112 lines
3.9 KiB
YAML
# Joystick control of a real arm. Three nodes, no bench and no browser.
|
|
#
|
|
# This is the one that moves a robot. `dataflow.yml` and `dataflow-gamepad.yml`
|
|
# drive a stand-in; this one drives `dora-ulite6`, so everything the pad does
|
|
# here happens in the room. Read `The gamepad` in README.md before picking it up
|
|
# — Back is the E-STOP.
|
|
#
|
|
# Both sibling nodes are pulled by `git:`, so this runs from a fresh clone with
|
|
# no other checkouts. It needs the network on its first build, and an arm.
|
|
#
|
|
# source .venv/bin/activate
|
|
# dora build dataflow-robot.yml
|
|
# dora run dataflow-robot.yml
|
|
#
|
|
# Not `--uv`: dora 1.0.1 installs a `git:` node into a venv inside its own clone and
|
|
# then looks for its entrypoint in this dataflow's venv instead. README.md has the
|
|
# detail. `dataflow.yml` has no `git:` nodes and is fine with --uv.
|
|
#
|
|
# Set ROBOT_IP and TOOL_TYPE below to match the arm in front of you. The
|
|
# defaults are `dora-ulite6`'s own: 192.168.1.192 and a vacuum tool.
|
|
#
|
|
# The web console comes with the node: it serves the page and holds the
|
|
# browsers' sockets itself, so `http://<this machine>:7000` is a second way to
|
|
# drive the same arm, with the same lease deciding who gets it. Set WEB_PORT to
|
|
# 0 below for a pad-only run that opens no port at all.
|
|
|
|
strict_types: true
|
|
|
|
# Lets `dora topic echo` read what is on the wire — the velocities going to the
|
|
# arm, above all. Run under `dora start` rather than `dora run` to use it.
|
|
debug:
|
|
enable_debug_inspection: true
|
|
|
|
nodes:
|
|
- id: joy
|
|
git: https://gitea.liria.cl/liria/dora-joy.git
|
|
tag: v0.1.1
|
|
build: pip install .
|
|
path: dora-joy
|
|
inputs:
|
|
tick: dora/timer/millis/20
|
|
outputs:
|
|
- joy
|
|
|
|
- id: teleop
|
|
path: dora-teleop
|
|
build: pip install .
|
|
inputs:
|
|
tick: dora/timer/millis/50
|
|
# queue_size 1: joy ticks at 20 ms and this node at 50, so without it the
|
|
# loop would work through a backlog of readings that have already been
|
|
# overtaken. An arm should be driven by the newest one or by none.
|
|
joy:
|
|
source: joy/joy
|
|
queue_size: 1
|
|
queue_policy: drop_oldest
|
|
response: ulite6/response
|
|
motion_state: ulite6/motion_state
|
|
robot_state: ulite6/robot_state
|
|
tcp_pose: ulite6/tcp_pose
|
|
joint_pose: ulite6/joint_pose
|
|
outputs:
|
|
- twist
|
|
- command
|
|
- jog
|
|
- request
|
|
- ui_state
|
|
env:
|
|
SPEED_MM_S: "60"
|
|
SPEED_DEG_S: "30"
|
|
# Keep the deadman layers ordered: JOY_TTL_S < JOG_TTL_S < the arm's own
|
|
# VELOCITY_COMMAND_TTL_S, which is 0.5 s below. Each backs up the one
|
|
# inside it, and a backstop that fires first backs up nothing.
|
|
JOY_TTL_S: "0.2"
|
|
JOG_TTL_S: "0.4"
|
|
# The console, on this machine. It is bound to every interface because
|
|
# the operator is rarely sitting at the box wired to the arm.
|
|
WEB_HOST: "0.0.0.0"
|
|
WEB_PORT: "7000"
|
|
|
|
- id: ulite6
|
|
git: https://gitea.liria.cl/liria/dora-ulite6.git
|
|
tag: v0.3.1
|
|
build: pip install .
|
|
path: dora-ulite6
|
|
inputs:
|
|
tick: dora/timer/millis/100
|
|
request: teleop/request
|
|
jog: teleop/jog
|
|
outputs:
|
|
- response
|
|
- motion_state
|
|
- joint_pose
|
|
- tcp_pose
|
|
- robot_state
|
|
# dora type-checks before it fetches a `git:` source, so it cannot read the
|
|
# arm's own manifest from here. These three repeat what `dora-ulite6`
|
|
# v0.3.1 annotates; `response` and `motion_state` stay untyped there and so
|
|
# stay untyped here. Re-check them when moving to a new tag.
|
|
output_types:
|
|
joint_pose: std/core/v1/Float32
|
|
tcp_pose: std/core/v1/Float32
|
|
robot_state: std/core/v1/String
|
|
env:
|
|
ROBOT_IP: "192.168.1.192"
|
|
TOOL_TYPE: "vacuum"
|
|
# The outermost deadman, enforced by the controller whether or not any of
|
|
# this is alive. Every timer above must stay below it.
|
|
VELOCITY_COMMAND_TTL_S: "0.5"
|
|
# The pad does not home. Nothing moves until somebody pushes a stick.
|
|
INIT_MODE: "none"
|