YouDuck.ai

duckctl: reach the robot with no network and no ssh

Last updated

duckctl runs on your laptop and talks to the robot over Bluetooth LE. It stands in for the phone app, and it is the only way to reach a robot that has never seen a wifi network.

That solves a chicken-and-egg problem: a new robot needs wifi, and configuring wifi usually needs to reach it first. duckctl wifi connect goes over the radio and needs no network of its own.

Never on a robot. Nothing in a release depends on it — robotctl is the tool that ships.

The name deliberately does not say Bluetooth: mediad gives a robot a second transport reaching a different set of methods, so the tool is named for what it talks to rather than the radio it currently uses.

Getting it

cargo run -q -p duckctl -- --name <robot-name> info
# or install once, at the cost of a snapshot that no longer follows the branch
cargo install --path duckctl

This tool used to install itself as btctl. If which btctl still finds one, it is a build from whenever you installed it and will never change again: cargo uninstall btd --bin btctl.

Finding a robot

duckctl scan
1 robot(s) advertising the duck service:
  aa:bb:cc:dd:ee:ff duck-c51b — 192.168.1.42, 1 service(s)  ← DUCK_ROBOT

Robots only, with everything else in range counted rather than listed. Each robot broadcasts its IPv4 address, so this is also where the address to ssh to comes from — no connection is made and no PIN is needed.

no address means the robot is not on a network. A line with no address at all is a release from before robots broadcast one.

The address on its own

ssh radxa@$(duckctl ip)

ip prints the address and nothing else. It reads the advertisement, so it connects to nothing, needs no PIN, and takes about a second — and the answer is not stale: btd re-reads the address every five seconds.

A robot bonded to this machine often stops advertising the service to it, and then ip connects and asks net.status instead: slower, needs the PIN, always answers. --verbose says which happened.

Names

A robot that has never been renamed calls itself duck- plus four characters from its serial. macOS shows a robot under two names at once — radxa-zero3 [duck-c51b] — and either half works as --name.

Two robots answering to one name happens on a board whose bootloader leaves its serial blank: it is then named after its hostname, and every board flashed from one image has the same one. Rename one with robotctl system set-name ducky.

Always the same robot

export DUCK_ROBOT=duck-c51b
export DUCK_PIN=418299
duckctl info

--name still wins for one command. DUCK_ROBOT= duckctl scan ignores the default for one command.

A rename does not follow DUCK_ROBOT. The tool says so; the variable has to be changed by hand, or every later command looks for a name that no longer answers.

The console

duckctl open

Finds the robot, then opens http://<address>:8080/. Nothing to install and nothing to servemediad embeds the page, so a robot running that daemon is a robot with a console.

On it: the camera with the link’s bitrate, frame rate, loss and round trip; two pads plus W/A/S/D and Q/E to drive; a drag on the picture to look at a point; enable, init, relax, stop and shutdown; the skills and voice bank as menus; and the state stream at 2 Hz beside robot.health.

stop zeroes the intents the page is sending. It is not an emergency stop — nothing in this system cuts servo power from a browser — and the button is a plain one for that reason.

Two ports are involved and only one is typed. The page reaches the signalling server on 8443 itself. If the page loads and then says its signalling port did not answer, the robot is up and something between you and 8443 is not — a firewall, most often.

The camera and drive controls are WebRTC only, so a robot with no network address has no console. Join it to one over the radio first.

Wifi, with no network of your own

duckctl --name <robot> wifi status
duckctl --name <robot> wifi scan
duckctl --name <robot> wifi connect <ssid> --psk <passphrase>
duckctl --name <robot> wifi forget <ssid>

wifi scan sweeps the radio rather than returning a previous scan, so it takes a few seconds.

wifi connect has two behaviours worth expecting: joining disconnects the robot from the network it is on, so an ssh session over wifi drops — that is the command working — and it can take up to 45 seconds to answer.

net.connect is refused over WebRTC by design, which is why configuring the network has to be possible over the radio.

Status, version, updates

duckctl --name <robot> info      # name, serial, uptime
duckctl --name <robot> health    # is the control loop healthy
duckctl --name <robot> version   # API version, release, git revision
duckctl --name <robot> update apply

A revision of null means the release was built on somebody’s laptop rather than by CI. Useful when chasing something strange.

Update wording matches robotctl update, so a command learned on the robot works here. Installing prints progress as it goes, and the connection drops when it finishes — the robot restarts its daemons, and btd about five seconds after the reply. That is the update working.

Related