architecture.md §5 states the requirement; this owns the mechanism. Local
signalling only: everything in it runs on the robot and works on a LAN with no
backend, because the remote case is defined in terms of the local one rather
than beside it.
The load-bearing choice is `webrtcsink` over `webrtcbin`. It brings a signalling
protocol, a session model and per-consumer encoder management, so what is left
to design is the control surface rather than the media plumbing — and that
protocol is what a remote bridge proxies, which is why the bridge is a relay and
not a translator. `run-signalling-server` (verified present in gst-plugins-rs
0.15.3, with host and port properties) means mediad runs the server in its own
process, so the separate gst-webrtc-signalling-server binary never has to be
built or shipped.
Four things it decides rather than defers:
- Authorisation reuses `system.authenticate`. The signalling port is open on
the LAN by necessity — loopback-only would force every session through a
bridge — so the control channel serves that one method and refuses the rest
until it passes, exactly as a BLE session does. Two schemes for two
transports is how the newer one ends up weaker.
- The control channel is a pipe to the JSON-RPC that already exists. btd is
the precedent and three of its four files are transport-independent; the
routing table should be lifted so the exhaustive match over proto::Call
holds *per transport*, or WebRTC becomes the hole in it. Replies stay
uncorrelated, so the pipe needs no per-method work.
- Teleop carries sequence numbers. intents.rs takes last-writer-wins, which is
correct over a unix socket and wrong over SCTP with maxRetransmits=0 — a
twist from 80 ms ago can land after a fresher one and win. Transport
property, so it belongs in mediad.
- update.* mutations are refused, and the refusal says why: preflight already
declines an update during a remote session, and restarting mediad drops the
session the client is watching progress on.
And the thing this feature breaks. intents.rs says its slots are "single-writer
in practice"; a pad and a remote peer both driving at 50 Hz makes that false,
and the result is not a contest but two writers interleaving into one slot.
architecture.md §6 already calls for priority and handoff and the roadmap defers
it to M6 — WebRTC is what makes it due. That is the one part touching a file
robotd owns, and the part most worth arguing about before it is written.
Assisted-by: Claude:claude-opus-5[1m]
3.6 KiB
Docs
Start at the README if you have a robot and want to use it.
robot/ — you have a robot
cheatsheet.md |
Every robotctl command. |
pair-a-gamepad.md |
Once per pad: pairing mode, pad pair, and what to do when it will not bond. |
cheatsheet-dev.md |
The commands that need a dev board: branch builds, candidates, dev pushes. |
dev-push.md |
Build on your machine and install on the board over ssh, with no CI run. |
duck-btctl.md |
Every duck-btctl command — the robot over Bluetooth, from a laptop. |
install-dev.md |
Setting up a board for development, from nothing. |
install-by-hand.md |
The same install as separate commands, for testing one step at a time. |
design/ — you are changing the daemon
How it works and why. These change rarely; when behaviour and a design doc disagree, the doc is the bug.
One page owns a mechanism, and the others link to it. The table below is that assignment: if a
fact belongs to a page listed here, every other page says one sentence and points, rather than
explaining it again. A fact written down in six places drifts in six directions, each of them locally
reasonable — which is how six documents came to promise that updaterd and btd kept their old
binaries until the next reboot, two releases after they stopped doing so, including the two pages
someone reads while diagnosing exactly that. So when two documents disagree, the one that does not
own the mechanism is the bug.
architecture.md |
The service split, the IPC contract, state ownership, safety and authority. |
robotd-design.md |
The control loop: the Dynamixel bus and who owns the port, the model, sensing, observations, policy, safety. |
updater-design.md |
The update engine: verification, atomic swap, health gate, rollback, release format. |
restart-order.md |
Which unit restarts, at which step, on every path that moves current — and at boot. |
app-path-design.md |
btd and configd — how a phone configures a robot over BLE. |
remote-webrtc.md |
WebRTC sessions, signalling, and the control channel — how a peer drives and observes the robot. |
boot-recovery-net.md |
Falling back to golden when the release that booted cannot start its daemons. |
project/ — you are running the project
Dated records rather than reference. They describe a moment, and go stale on purpose.
roadmap.md |
Milestones, and what works today versus what is designed. |
ci-setup.md |
One-time setup for the release pipeline: keys, secrets, rotation. |
install-path-gap.md |
Why four install-path bugs reached a board, and what closed it. Closed. |
slice-2-bringup.md |
What a real Radxa Zero 3W did with slice 2. |
update-over-ble.md |
Driving the update path from a phone: what it turned up, and what rollback over a radio was decided on. |
Elsewhere
../CONTRIBUTING.md |
Building, testing, repo layout, conventions, releasing. |
../deploy/README.md |
What a robot image is configured with, and what provisioning actually does. |