docs: simplify the README and record the pad layout
The README carried a lot of rationale that AGENTS.md already holds; what is left is the tables a consumer wires against. It gains the swept axis and button indices, and says plainly that the axes check themselves at runtime and the buttons cannot. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -46,16 +46,19 @@ uv sync --group dev # plus pytest and ruff
|
||||
|
||||
```bash
|
||||
dora run dataflow.yml --uv # this node plus a bench stand-in, no pad
|
||||
dora run dataflow-gamepad.yml --uv # the same, with dora-joy pulled in by git:
|
||||
dora run dataflow-robot.yml # the pad and a real arm, both pulled in by git:
|
||||
dora run dataflow-gamepad.yml # the same, with the probe declared and no console
|
||||
```
|
||||
|
||||
`dataflow.yml` is self-contained on purpose — it resolves from this checkout alone, which
|
||||
is what lets CI validate it. Keep it that way; the pad belongs in `dataflow-gamepad.yml`.
|
||||
is what lets CI validate it. Keep it that way; the pad belongs in the other two. Neither
|
||||
of those takes `--uv`: dora 1.0.1 installs a `git:` node into a venv inside its own clone
|
||||
and then looks for its entrypoint in the dataflow's venv. README.md has the detail.
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
uv run pytest # 112 tests, no gamepad, arm, browser or daemon needed
|
||||
uv run pytest # 149 tests, no gamepad, arm, browser or daemon needed
|
||||
uv run ruff check .
|
||||
uv run ruff format --check .
|
||||
```
|
||||
@@ -74,6 +77,14 @@ a source goes away**.
|
||||
- **`dora_teleop/joy.py`** — The pad as it arrives from `dora-joy`. `Sample.present` is
|
||||
the load-bearing field: an unplugged pad reads as *absent*, not as centred, so "the
|
||||
operator let go" and "the pad fell off the desk" stay distinguishable.
|
||||
**`Calibration` is the other half of that seam.** It measures a pad the first time it is
|
||||
seen at rest and hands the rest of the node a reading as the layout's ideal pad would
|
||||
have sent it, so a worn stick's tilt is subtracted rather than deadzoned and a trigger
|
||||
that rests at 0 stops being a special case. A pad whose resting axes do not fit `Layout`
|
||||
reads as *absent* and is never corrected: one reading cannot tell a trigger at -1.0 from
|
||||
a stick held hard over, and guessing wrong drives a real arm. It is not re-measured
|
||||
while the pad is in use — doing that under a held stick would record the deflection as
|
||||
centre, and the arm would move when the operator let go.
|
||||
**`JoyInput.read` is the other safety-critical function in this repo.** Moving the pad
|
||||
into another process added a way for it to go away that did not exist before — that
|
||||
process dying — and from here that looks like silence rather than like an unplugged pad.
|
||||
@@ -90,7 +101,12 @@ a source goes away**.
|
||||
units: mm/s and deg/s, base frame. `is_active` lives here rather than on `Sample`
|
||||
because it needs the layout: **a trigger rests at -1.0**, so the pad-is-in-use test has
|
||||
to normalise triggers exactly as `velocity` does, or every connected pad reads as in use
|
||||
for ever and `GAMEPAD_IDLE_RELEASE_S` never fires.
|
||||
for ever and `GAMEPAD_IDLE_RELEASE_S` never fires. `rest_zeros` and `canonical` are the
|
||||
same concern one layer out: they check a resting pad against `Layout` and map it onto
|
||||
the ideal one. They are the only defence against a wrong index, which is not a
|
||||
theoretical failure — an Xbox One S pad reporting its triggers on 4 and 5 against a
|
||||
layout expecting them on 2 and 5 read as a full-speed pitch command from an untouched
|
||||
pad, held the lease for ever, and moved a real arm into a controller error.
|
||||
- **`dora_teleop/arbiter.py`** — The lease. One place that answers "why did it not move",
|
||||
rather than one answer per input path. Ported from the monolithic repo's `RobotService`
|
||||
lease because the console is already built on it — it gates its controls on
|
||||
@@ -170,6 +186,13 @@ belongs here, and a port nothing wires reads as supported while having never run
|
||||
pair; nothing can enforce the second from here.
|
||||
- **An unplugged pad, a dead `dora-joy` or a departed browser stops the arm immediately**,
|
||||
without waiting out any timer beyond the one that detects it.
|
||||
- **A pad is driven from only after it has been seen at rest**, and a pad whose rest does
|
||||
not fit `Layout` is not driven from at all. This covers the axes and **cannot cover the
|
||||
buttons**: an unpressed button reads the same on every pad, so a wrong button index is
|
||||
silent until somebody presses it and gets another verb. Sweeping a new pad with the
|
||||
probe is the only check, and it is worth doing before the arm is powered. The cost is that a pad held when it appears
|
||||
is ignored until it is let go; the alternative is guessing a numbering from one reading,
|
||||
against a real arm.
|
||||
- **Both control sources go through `mapping`.** The web path used to bypass it and pass
|
||||
a velocity straight through, which is why the console had to speak mm/s. One conversion
|
||||
point or none.
|
||||
|
||||
Reference in New Issue
Block a user