At GTC Berlin this month, a little duck-shaped robot walked across the main stage, sat down on command, and did a forward roll. I wanted one. Pollen's official kit is on pre-order, but it's a 2027 thing, and I'm not waiting till 2027 for a duck. So I'm building my own.
So that's the project. A Microduck: a 25 cm, 800 g two-legged robot from Pollen Robotics' open design, built as the community replica that swaps in Feetech HD-1910 servos. Fifteen servos, a Radxa Zero 3W for a brain, an IMU, a small depth sensor, a camera, and a Sony-style NP-F550 camera battery. A friend with a Bambu printer is doing the plastic.
Big thanks up front, because none of this is my work alone: kissqy for keeping the HD-1910 replica current, the JoyandAI folks for the RL fork I forked, LuwuDynamics for the servo model, and Pollen Robotics for the duck itself.
I made one rule before I started. No parts get ordered until every move works in simulation.
That rule paid for itself twice.
The plan: train first, build second
Robots like this don't get programmed move by move. They get trained. You drop a simulated copy of the robot into a physics engine, give it a reward for doing the thing you want, and let reinforcement learning grind through millions of attempts until a small neural network figures out how. No hand-written joint curves. The duck learns to walk the way you'd learn a sport: try, fall, try again, until falling stops happening.
I used the open training stack the Microduck community already shares: mjlab, which runs MuJoCo physics on the GPU, and a fork tuned for the HD-1910 servo. It runs on one of my two DGX Sparks. The other Spark keeps serving the local model I use all day, so training the duck doesn't take my assistant offline.
Six skills, each its own policy:
- Walk, including turning on the spot
- Stand, and get back up after a fall
- Sit down and stand back up on command
- Peck at the ground, the "pick something up" move
- Kick a ball with the right foot
- A forward roll
Each one exports to a tiny ONNX file. 61 numbers in (joint angles, joint speeds, the IMU, the last action, the command), 14 joint targets out, 50 times a second.

Bug one: I trained the duck on the wrong battery
My first set of policies trained fine. Then I read the electronics docs for the board I'm buying.
The fork I started from assumed the servos run on a clean, regulated 5 volts, with a stiff servo gain of 32. The board in this build doesn't do that. It feeds the servos straight from the battery pack. A two-cell pack is 8.4 volts full and 6.6 volts nearly empty, and the board's servo gain is 5.
That's not a detail. A servo's strength depends on voltage, and its stiffness depends on gain. A policy trained on a stiff 5 volt servo would've met a softer, sagging, differently tuned motor on day one. Everything would've been tuned for the wrong robot.
So I retrained all six skills. I used a servo model from LuwuDynamics (xgoduck_rl, Apache 2.0). Gain is set to 5, and the battery voltage is sampled across the whole discharge curve, 8.4 down to 6.6, with sag under load. I also randomized motor delay and gear backlash, because cheap servos have both.
Then I tried to break them.
The stress test
For each skill I ran 256 simulated ducks at once, through a battery of conditions. Empty battery with sag. Full battery. The longest motor delay from training, then a longer one it never saw. Servo gain 20 percent low and 20 percent high. Pushes 50 percent harder than training.
| Skill | Result across the battery |
|---|---|
| Walk | 0 to 8 percent falls. 17 percent with the extra-hard pushes. |
| Stand and get up | 0 percent falls, every condition |
| Sit and stand | 0 percent falls |
| Peck | under 1 percent falls |
| Kick | 0 to 1 percent falls, ball travels 5 to 6 m |
| Forward roll | lands upright 100 percent of the time |
Everything passed. I was pleased with myself for about an hour.

The Duck Stage
I also built what I call the Duck Stage: the simulated duck running live in a browser, controlled by voice. Say "walk forward," "kick the ball" or "do a somersault," and a small parser turns it into commands for the same policies the real robot will run.
On the stage the roll lands, the peck comes back to a clean stand, and the kick works end to end: the duck walks to the ball, lines up within 2 cm of the sweet spot, and sends it 1.47 m.
Then I said "sit down."
Nothing happened. The duck just stood there.

Bug two: the duck that wouldn't sit
This one took a while, because every check I had said the sit policy was fine. No falls in the stress test. A dedicated sit check showed it sitting to 62 mm, standing back up, and doing it again.
The stage runs physics differently from training. Training uses MuJoCo on the GPU. The stage uses MuJoCo on the CPU with the servo model running in Python. So my first suspect was the simulator. I compared every physics setting the two used. They did differ: a different integrator, a different solver iteration count, a different foot contact priority. I matched all three. The duck still wouldn't sit.
So I went back to the training simulator and asked a sharper question. Not "does it fall?" but "if the duck has been standing still for a few seconds and I say sit, does it sit?"
Here's where it got humbling. I ran that test twice, in the two places the sit policy actually lives.
Without the backlash model, the same one the stage runs, it mostly refused: 3 percent sat within one second, 14 percent within three, 23 percent within six. With backlash on, the exact condition it trained in, it sat on 62 percent within one second, 76 within three, 77 within twelve. So about 1 in 4 never sat at all.
To be fair to myself: it wasn't broken everywhere. It was shaky in its own training setup and mostly failed once I took away the one bit of realism that made it confident.
From a settled stand, told to sit: 3 percent sat within one second without the backlash model. Even with it, 1 in 4 never sat. Every check I had was scoring falls, not sits.
The reason was in the training setup. Episodes were 12 seconds long and the sit/stand command flipped every 3.5 to 6.5 seconds. So the policy almost never practiced the exact situation a real owner creates: the duck standing calmly, then told to sit. The dedicated sit check passed because it started right after a reset, while the duck was still moving. From there it sits easily.
The stage just happened to always start from a calm stand. It was the only test that looked like real use.
The lesson I'm taking away: a fall rate isn't a success rate. Count the thing you actually want to happen.
The fix was to resume from the 15k checkpoint and run another 3,000 iterations with 30 second episodes and commands that hold for up to 14 seconds, so the duck finally practiced the calm-stand-to-sit case. Same test this time. With backlash, 100 percent now sit within one second. Without it, 88 percent within one second, 93 within three, 95 within twelve. The full cycle held too: 128 ducks out of 128 stood up, sat, and stood back up, with only 1 percent tipping past 60 degrees at some point. The stress battery came back at 0 percent falls across all 8 conditions.
Then I said "sit down" on the live stage. And it sat. The duck folded from 115 mm to 61.8 mm in under a second. I said "stand up" and it came right back to 115. Two rounds, both clean.

Where it stands
- Six skills trained for the real power setup. All six verified end to end in the stage, sit included now.
- Walking works but it's cautious. Asked for 0.3 m/s, it does about 0.12. Same in training, so it's the policy, not a bug. A tuning job for later.
- Parts list done, about $515 before one board kit whose price the seller still has to quote. Ordered.
- Every policy matches what the board's firmware expects: same joint order, same home pose, servo gain 5, no extra filtering, and a load slot for each skill.
Where it's going
When the parts arrive, the order is boring on purpose. Print, assemble, calibrate all fifteen joints and the IMU, then the first powered moves: home pose, hold, walk. Each policy loads into its own slot on the robot. Sit and the roll come last.
What'll break? Probably whatever the simulator gets wrong. Two simulators already disagreed about this robot once. Real foam feet, a real IMU mount and a real battery will find something new. The camera is the other big gap. On the stage, the duck knows exactly where the ball is. The real one will have to see it.
When it walks, I'll open-source the 2S training changes. That covers the power fix, the stress battery and the sit retrain. The next person building this replica shouldn't have to find bug one the way I did.
If you're into this kind of thing, the local AI rig posts are where the training hardware comes from: I compared two models across two DGX Sparks and I bought a Spark. Now I want to put local agents to work.
