Whose tools these are. The robot, its software and its board are Pollen Robotics'. The runs read here are duckbatch's, an open project by this site's author that fine-tunes, in simulation, Pollen's kick and smaller networks distilled from Pollen's walk. Book 4, How a Policy Became, tells the story behind each run. If a step goes wrong for you, tell us which one.
Read a real run
How do you find out what a run actually did? Every fine-tuning run in Book 4 left its records in a public
Hugging Face dataset, craigm26/duckbatch-records, one folder per job, and b003's, the run in the book's
first lesson, is a good first read. With uv, from the first-duck guides:
uvx --from huggingface_hub hf download craigm26/duckbatch-records \
--repo-type dataset --include "jobs/6ab6d30b6b030d633f69210a/*" \
--local-dir records
uvx tensorboard --logdir records/jobs
Open the address TensorBoard prints, and read the log in this order:
- What it practised. The
Curriculum/charts are the settings that actually ran, andCurriculum/standing_envsreads 0.25 at every iteration, though the run'smenu.yamlasked for 0.05. The menu is a request; the log is what ran. - Each term's pay. The
Episode_Reward/charts, one per reward term, show which term moved: here the pay for tracking the command rises over the run while the duck learns to stand. The steep start is episodes growing to their full length, not learning. - The total, last.
Train/mean_rewardadds every term together, which hides which one moved.
Beside the log are the menu that was asked for, record.json with the final evaluation, the speed
reached at each command in speed/speed_curve.json, the trained network, and a checkpoint every 250
iterations.
Then read the two notes the run was judged by, both in duckbatch's notes folder: the plan, written before it ran, and the verdict after.
Change one thing
A result is something you can learn from only when you wrote down, before it ran, what you expected and the lines it must pass. duckbatch runs a menu, one YAML file, on Hugging Face Jobs, so copy one of its menus, change one setting, and write that note first.
git clone https://github.com/craigm26/duckbatch && cd duckbatch
uv sync
cp menus/b003b-progress.yaml menus/mine.yaml
Edit one line of menus/mine.yaml, give it a new batch_id, and leave it uncommitted. The
job runs duckbatch's own code at the commit your copy is on, and
--inline sends your menu along with it.
The job needs a Hugging Face token that can write, as HF_TOKEN: export it in your shell, or put the
line HF_TOKEN=<your token> in a .env file in the folder, which git ignores. Look
first, because --dry-run says what it would start and starts nothing.
uv run duckbatch hf-job menus/mine.yaml --run finetune --inline \
--dataset <you>/duckbatch-records --dry-run
Then run the same line without --dry-run. That run is billed to your Hugging Face account, which
needs credit on it, and a fine-grained token also needs permission to start Jobs, neither of which the dry run
checks. The job stops at duckbatch's default limit, --timeout 4h.
- Pilot first. Set
iterationsto 100 and keep just one of thefinal_seeds, as b003b's pilot did, for a run that only has to run: it trained for 224.7 s, and a pilot is not judged on the pass lines. - Then the full run. b003's 1,500 iterations trained for 54.6 minutes on one L4, and with setup and measuring, Microduck Studio puts a full run at about an hour and a half, about $1.20 at $0.80 an hour.
- A setting that looks like a lever.
rel_standing_envsundercommandnever took effect, as the log above shows. To change how often the duck practises standing, setstanding_envsunderfinetune, the key b003g added, and checkCurriculum/standing_envsafterwards. - Your records are public unless you make them otherwise: the job creates the dataset you name, if it does not exist yet, as a public one. Create it on Hugging Face as private first if you would rather.
On an iPhone, iPad or Mac, Microduck Studio's Train a network on Hugging Face sends the same kind of request, and b003b itself was launched from the request Studio builds.
Other cards and services
Every fine-tuning run in Book 4 trained on one NVIDIA L4 on Hugging Face Jobs, l4x1, duckbatch's
default; b002, the distillation that made their starting network, ran on a laptop's graphics card. The
Windows and Linux guides train on an NVIDIA card in your own
PC instead.
We have not tried another Hugging Face Jobs card yet. duckbatch's --flavor takes one by its hardware
name, though its menus size the practice for the L4's memory. Nor have we tried a Linux machine with an NVIDIA card
rented from another cloud, which should follow the Linux guide.
If you try either, tell us how it went, and this page will say so. Training in another simulator altogether is lesson 10 of Book 4.
Put a trick on a button
The robot runs two kinds of policy, and Pollen's tools treat them differently. A slot is what it runs by default,
the walk or the stand, and robotctl policy load walk replaces it. A skill is what it runs when asked, a bow
or a kick, and it sits beside the walk instead of replacing it
(Pollen's cheat sheet).
sudo robotctl policy add polite-bow fffiloni/microduck-polite-bow-b1d864
robotctl robot do polite-bow
sudo robotctl pad bind x polite-bow
The first line installs a bow someone published as a skill. The second runs it, once the robot is driving: press
Start on the pad first, or the request is refused. The last puts it on the pad's X button, which ships empty, and
sudo robotctl pad reset puts the buttons back; nothing restarts either way. A skill that holds until told
otherwise, like a one-footed stand, has no length of its own, so policy add takes one with
--hold, and the command it reads with --command.
Ports between your devices
The duck and your computers talk over a few ports, and only ssh asks for anything: the duck account's password, or your key.
- A shell on the duck.
ssh microduck@<address>. Pollen's duckctl finds the address over Bluetooth, from a laptop with uv:uvx duckctl --name <robot-name> ip. - The console. Pollen's camera service serves a page on port 8080 that streams the head camera
and drives the duck, and the page connects back on port 8443 to start the stream.
uvx duckctl --name <robot-name> openfinds the duck and opens it, and the same port answershttp://<address>:8080/framewith one frame as a PNG, the right way up. - A pad over the network. Pollen's UDP pad, on port 4210, drives the duck the way a Bluetooth pad
does. It is off until you switch it on, with
netpad.enabledinsudo robotctl configureand thensudo systemctl restart padd netpadd, and it stays on, across restarts, until you switch it off. While it is on, the Bluetooth pad does not work. - Pages on your own computers. TensorBoard and Pollen's workshop each open a page for the machine
they run on alone. To see one from another computer, run
ssh -L <port>:localhost:<port> you@<that computer>on it, with the port from the page's address, then openhttp://localhost:<port>there. The computer with the page needs an ssh server: Remote Login on a Mac, OpenSSH Server on Windows.
Who can drive. Pollen's own notes say it plainly: anyone on the duck's network can drive it
from the console and see through its camera.
Pollen's
design note calls that fine on a bench and in an office, not in a home, and a thing to revisit before ducks ship
to homes. Anyone who can reach the pad's port, once it is on, can drive it, sit it down and switch it off.
Bluetooth is another way in: anyone in range with duckctl and the pairing PIN, the factory 000000 until you change
it with sudo robotctl system set-pin, can stand the duck up, run a skill or load another walk, though
not steer it.
So keep the duck on a network you would let into the room with it, and never forward these ports to the internet. Pollen's way to reach a duck from outside its network goes through a rendezvous service that checks your account at both ends and keeps the video encrypted. That route stays off until the duck is signed in, and signing in stores a Hugging Face token on the duck that, Pollen's notes say, can push to your repositories, start Jobs and read your billing.
The duck's other channels
The walk reads 61 numbers, but the duck carries more, and Pollen's robotctl, on the duck, shows
it:
robotctl monitor
It shows what was asked for beside what was applied, every joint, and the IMU's view of which way is down. Press c for a frame from the head camera, and t for the 8×8 depth grid, which also tells you whether your duck has the depth sensor at all: Pollen's robot docs say most ducks so far have none fitted, while its mapping post describes the duck with one in its head.
To keep the whole state, 50 times a second, for comparing a real walk with the simulator's:
robotctl monitor --json --hz 50 > run.jsonl
A program can also drive. Pollen's UDP pad page describes the 28-byte datagram and has a complete sender in Python, which stands the duck up, turns the walk on and walks it forward for three seconds.
A sensor that steers the duck sends the same datagrams with different stick values, and with a gamepad plugged
into a laptop, duckctl udp-pad sends them for you.
Pollen's own mapping post shows these
channels working together. Its service, mapd, builds a map of the room from the 8×8 depth sensor, a little
at each stop, and finds the duck again after someone carries it, all on the duck's own processor.
Odometry alone, the post measured, drifts about 2.4 cm for every metre walked. The mapper is not in a release yet:
a version of it is on the maploc-v2 branch of Pollen's microduck repository, and the recordings it was
tested on, with ground truth, are public on Hugging Face as pollen-robotics/SLAM_JJ_Salon_with_GT.
The spare Qwiic port
Can you add a sensor of your own? Pollen has said in its Discord that the duck's board still has an unused Qwiic connector: a small 3.3 V I²C socket, the plug Adafruit calls STEMMA QT.
Pollen's open board, the Robot HAT, has four of them. Its schematic puts J5 on the bus the IMU and the audio codec use, header pins 3 and 5, and the other three on buses that depend on the computer underneath.
Pollen says the final ducks carry an improved version of that board, so look at yours before trusting the open schematic.
- See what answers now. On the duck, list the bus and write down every address that answers.
On the Zero 3W ducks, Pollen's
code expects the audio codec at 0x18, the board's BMI088 IMU at 0x19 and 0x68, connected though unused by
default, and the depth sensor, where fitted, at 0x29, or 0x52 on some early ducks. The open board's latest revision
has an LSM6DSV16X IMU at 0x6A instead, and Pollen's beta board puts the depth sensor on SPI, where i2cdetect cannot
see it:
sudo i2cdetect -y -r 3 - Pick a sensor with an address of its own, one that nothing on the bus already answers to.
- Leave the depth sensor's service off while you experiment, which Pollen's cheatsheet calls
safe:
sudo systemctl stop tofd. - With the duck switched off, plug the sensor in. Switch it on and stop
tofdagain, since it starts at boot, then runi2cdetectagain and look for the new address. If it is not there,i2cdetect -llists every bus, and the socket may be on another. - Read it from a program, and steer with it, through the UDP pad above, which changes no policy.
- Measure the walk again with the sensor on. Anything mounted on the duck changes the body the walk was trained for, so if the walk got worse, that is a case for retraining, with the sensor's weight added to the simulated duck.
Then
Book 4 traces the runs this page reads: why a walk learned to stand, why more practice made it worse, and how a kick learned to go straighter. Lesson 9 is the Qwiic port's, and lesson 10 is about training in another simulator. To race what you train, Race in Pollen's Arena takes the Arena's events one at a time. Found a better way, or a step that failed? Tell us.