MicroDuck

MuJoCo · Robot control · A small experiment series

MicroDuck grows up

A wobble board, a paintbrush, two backward crawls, a playground swing, a narrow beam, a human bridge, a rope, and a trampoline. Eight small experiments with one little robot in MuJoCo.

01One little duck, eight experiments

I put MicroDuck on a wobble board. Then I gave it a paintbrush, implemented two backward crawls, and put it on a playground swing. These started as separate short posts. Here they are together, with the videos and a closer look at the code behind them.

Later I added four more: a beam narrower than the duck's feet, a human bridge, a rope, and a trampoline.

The clips are playful, but each scene asks a different control question. How do you balance when the ground moves? How do you turn a brush path into joint motion? What makes a crawling motion actually travel? How do you pump a swing without a motor at its pivot? And how do you hand control from one policy to another in mid-air?

All eight are MuJoCo simulation experiments. The implementation lives in my microduck_lab package, built on top of the upstream mjlab-microduck code. The demos use different methods: feedback control, inverse kinematics, optimized motion cycles, and reinforcement learning.

The common thread: give the robot joint targets, let the simulator resolve the motion and contact, and check what the robot actually does.

02A wobble board, and one final move too far

The first challenge looks simple: stand on a plank resting on a loose roller. But the support can move underneath the duck. A correction in the legs changes the board, and the moving board changes the duck's balance. I first shared it in a LinkedIn post.

Slow and wide, quick and small, a long lean, a build-up, and a flutter. The final move deliberately asks for more than the controller can hold.

Balance with the whole body

The stabilizer uses a linear quadratic regulator, or LQR. It starts from a settled configuration and estimates how small changes in state and motor targets affect the next simulation step. That local model provides a feedback gain: when the robot, plank, or roller moves away from the reference, the controller adjusts the joint targets.

The useful detail is that the controller coordinates all 14 actuators. Earlier approaches restricted the duck to one or two joint combinations. The LQR uses the coupled motion of the whole robot and its support.

Rocking adds a moving reference and a feedforward command on top of that stabilizer. The feedback then corrects the difference between the desired motion and the measured state. The routine changes amplitude, frequency, and how long the duck leans to each side, blending between moves so the target does not jump.

The fall is part of the routine

The ending is deliberate. The code appends a final move with an 18° commanded swing amplitude, beyond the measured operating range used for the earlier moves. That is a requested motion, not a claim that the board tracks it exactly. The duck eventually loses the board.

This is a controller with access to the exact simulated state of the duck, plank, and roller. Using it on hardware would also require a way to estimate that moving support.

Implementation: whole-body LQR and the rocking routine and deliberate finale.

03Meet MicroDuck Picasso

Next, a quieter task: sit in a chair, dip a brush into paint, and draw a flower. I first shared it in a LinkedIn post.

There is no arm here. The brush is held at the mouth, and the neck, head pitch, and head yaw move its tip across the canvas.

A blank canvas becomes a green stem and leaves, eight pink petals, and a yellow center. The inset shows the same canvas as the brush draws on it.

From a flower path to motor targets

The flower is described as a sequence of brush paths. Inverse kinematics works backward from each desired tip position to the joint angles needed to reach it. That calculation runs on a separate copy of the simulator state. It supplies targets to the motors; it does not reposition the live robot.

The actual tip does not follow every target perfectly. Its measured position determines the painted line, which gives the flower its uneven, hand-drawn appearance.

Where does the paint come from?

The canvas starts blank. The brush loads a color only when its measured tip reaches the corresponding palette well. A mark is added when the tip is within 3.5 mm of the canvas plane and inside its bounds. Lifting the brush breaks the stroke.

This is a texture-based paint model. It does not simulate liquid paint or bristle forces against the canvas. The brush also starts rigidly attached to the mouth, representing a clamped grip; picking it up is outside this demo.

The distinction matters: the flower path is prescribed, while the visible drawing is produced from the motor-driven tip's measured motion.

Implementation: painting notes, brush paths and canvas updates, and the inverse-kinematics controller.

04Learning to crawl backward

MicroDuck also needed a baby milestone: crawling. Backward, naturally. I first shared it in a LinkedIn post.

There are two versions. The little crawl folds and extends both legs together. The faster crawl alternates them, with the legs half a cycle apart.

Little crawl above; fast crawl below. Both are shown at real time, with distance stripes 25 cm apart. Open the original GIF.

Moving the legs is not enough

The starting point for the little crawl was the tuck-and-drive motion used after the duck lands at the end of the swing video below. It looked like crawling, but much of its movement went out and back. A convincing pose cycle does not necessarily produce useful displacement.

The synchronized crawl searches over the two poses and their dwell times. It uses the cross-entropy method: sample candidates, simulate them, keep the better ones, and update the sampling distribution. The documented search uses eight rounds of 40 candidates, followed by longer evaluations of the best individual candidates.

The fast version uses sinusoidal joint targets, with offsets, amplitudes, phases, and a shared frequency. The two legs alternate. Both versions execute motion cycles through the motor model; they are not newly trained neural-network policies.

Reported measurements from the documented 20-second rollouts
GaitLeg motionNet distanceMean speed
Little crawlTuck and drive together0.537 m26.8 mm/s
Fast crawlAlternate, half a cycle apart3.371 m168.6 mm/s

These are measurements reported in the implementation notes for those runs. Distance means net horizontal displacement of the trunk, so repeated back-and-forth motion does not inflate the result. The stripes in the video make that difference easy to see.

Implementation: the two-crawl comparison and search procedure and the alternating gait.

05Nobody pushes the swing

Then I put the little duck on a playground swing. I first shared it in a LinkedIn post.

Nobody pushes it. The swing has no motor at its pivot. The duck has to pump using its own head and legs, timing their motion to the swing.

The two-minute edit reaches roughly 50°; the implementation notes report a peak of about 53°. The opening and ending play at real time, and 0:15–1:45 plays at 2× speed. Wait for the end.

Timing the motion to the swing

The controller observes the swing angle and angular velocity, estimates where it is in the oscillation, and synchronizes the joint targets to that phase. An amplitude regulator reduces pumping near the target and can reverse the energy input if the swing becomes too large.

That makes this a feedback controller. The duck's motion responds to the swing rather than following a fixed animation clock.

The head and neck matter as well as the legs. In this model, moving them shifts the center of mass. The hips contribute too, while bending the knees changes the moment of inertia. Their timing determines whether the motor work builds the oscillation or works against it.

The seat and contact geometry were part of the problem. The duck is a free body supported by the bucket seat, not welded to it. The swing itself uses rigid hangers and one passive hinge, so it does not model flexible ropes or lateral sway.

And then the seat opens

The final drop is also deliberate. A latch releases the hinged seat floor near the front of the arc, and gravity lets the duck fall onto the grass. After landing, it cycles through tuck-and-drive poses. It does not stand back up.

That ending connects directly to the crawling experiment: a motion that looked promising after a fall became a separate task, with net travel as the criterion.

Implementation: swing construction, pumping, and the long-video sequence and the phase-feedback controller.

06A beam narrower than its feet

Next, a balance beam. It is 2 m long and 40 mm high. In the video it is 115 mm wide.

Standing, the duck's feet measure 125 mm from outer edge to outer edge. So on this beam, each foot hangs about 5 mm over the edge.

The duck walks the whole 115 mm beam to the finish line without stepping off.

The walker cannot step sideways

The walking itself is the pretrained walking policy from the upstream project, trained with reinforcement learning. I did not change it. I only added a small steering loop on top.

The policy cannot step sideways: a sideways command gives no sideways motion. So the loop corrects drift by turning. The farther the duck is from the centre line, the more it aims back at it.

How narrow can it go?

Runs on a 2 m beam. The simulation is deterministic: the same width and start give the same run.
Beam widthCentred start5 starts, 10 mm left to 10 mm right
120 mmReaches the end5 of 5
115 mmReaches the end3 of 5
110 mmSteps off after 0.23 m0 of 5

At 110 mm and below, it never reached the end. The limit comes from where the policy puts its feet, plus the sway of the trunk in each step. Together they need about 60 mm on each side of the centre line.

Implementation: beam notes and results and the steering loop.

07A bridge for his sister

You may have seen this video: a boy lies down across a gap in the street, and his little sister climbs over his back. I wanted two MicroDucks to do the same. I first shared it in a LinkedIn post.

Top: the original clip. Bottom: the MicroDucks in simulation. Open the original GIF.

The blue brother lies down across the gap and holds himself straight. The pink sister walks sideways over his back. Her walking was trained with reinforcement learning (PPO in MuJoCo), first on narrow beams.

The rules are strict. She must stay upright, only her feet may touch him, and she must take real steps. Falling or crawling across does not count.

It does not work from every start. In my tests, she crossed from about 65% of 23 start positions. She cannot see the edges, and most failures are a foot clipping the corner of a ledge.

The full story, with the funny failures, has its own page: Can a MicroDuck be a bridge for its sister?

Implementation: human bridge notes and the narrow-beam walking task.

08Hanging from a rope by its legs

Here the duck hangs upside down from a rope, held only by its two legs. Then it moves along the rope, a little at a time.

Post to post: 45 cm of rope in 79 s and 16 gait cycles, shown at 4× speed. Left: the whole rope. Right: a close view of the legs.

Legs as hooks

Each leg folds into a hook over the rope. The thigh is on one side, the shin lies across the top, and the foot is on the other side. Folding the knee further squeezes the hook around the rope, so the hold needs no friction.

My first version held the rope with the mouth and the feet. It fell to the floor in all 60 trials.

An inchworm gait

One gait cycle has three moves. Both legs stay on the rope the whole time.

  1. The back leg clamps. The front leg opens a little and slides out along the rope.
  2. The front leg clamps. The back leg opens and slides in.
  3. Both hooks relax, and the hips turn back together. This carries the body forward.

This is not a learned policy. It is a fixed sequence of joint targets. A cross-entropy search made it about 3 times faster: 5.2 mm/s, against 1.7 mm/s for my hand-tuned gait.

The rules

Only the legs may touch the rope. Nothing may touch the floor or the posts, and the legs must carry at least half the weight at every moment. Two shorter runs pass these rules over 15 cm.

The post-to-post run in the video has one 20 ms moment with only 47% leg support. So by the strict rules it does not pass. Under 16 changes, for example friction, mass, battery, and rope sag and thickness, both gaits kept moving and never fell.

Implementation: rope notes and results and the gait.

09Bouncing and flipping on a trampoline

Last, a trampoline. The duck starts standing on the bed, bounces higher and higher, and then does a front flip in the air. I first shared it in a LinkedIn post.

Two runs. Top: real time. Bottom: 4× slow motion. Each time, the duck lands on its feet and keeps bouncing. Open the original GIF.

Two policies and a hand-over in the air

Both parts were trained with reinforcement learning (PPO in MuJoCo Warp). The bed is a plate on a spring, with a damper.

  1. The bounce policy starts standing. It is paid for the height of each bounce, but only if it is close to its standing pose at the top of the flight.
  2. When a bounce is high enough, the legs move to the standing pose. At the top of that flight, the flip policy takes over.
  3. The flip policy lands, uses the rebound, turns a full front flip in one flight, and lands on its feet.

What did not work

First, I trained one policy to bounce a few times and then flip. It learned to stand still. Standing was safe, and a failed flip cost a fall. Splitting the task into two policies fixed this.

My first flip policy only flipped from a perfect standing pose. But the bounce policy flew with its head bent back 103°. So I trained the bounce policy to fly closer to its standing pose, and the flip policy to start from many different poses.

How robust is it?

I tested the full chain with 16 changes to the bed and the battery. It works in 4 of them, including the normal bed. Most failures complete the flip, then a shin touches the bed in a deep landing squat.

Implementation: the trampoline, the hand-over, and the films and the RL tasks.

10A small love-story detour

The series also had a less technical chapter: MicroDuck becomes MatureDuck, then MarriedDuck, and they give birth to NanoDuck!

That was the caption for the original love-story post, on X and LinkedIn. It sits alongside these experiments as a bit of robot storytelling.

The repository now documents several versions of that scene. The corrected physical version uses mechanical egg release and hinged shells. Its documentation explicitly distinguishes it from the earlier film, which used staged state changes for some props. Those later details should not be read as a description of every version of the original clip.

11Eight scenes, eight ways to build a behavior

The robot is the same, but the control problem changes with the scene.

SceneHow it worksWhat to check
BoardWhole-body LQR plus a rocking referenceBalance and contact on a moving support
PaintingPrescribed paths, inverse kinematics, motor trackingThe measured brush tip and resulting strokes
CrawlingOptimized periodic joint targetsNet travel while remaining in a crawl posture
SwingPhase-feedback pumpingOscillation growth through the robot's own motion
BeamPretrained RL walking policy plus a steering loopStaying on a beam narrower than the stance
BridgeRL sideways walker, trained on narrow beamsUpright, real steps, and only the feet touch
RopeSearched inchworm gait of joint targetsThe legs carry the weight, with no other contact
TrampolineTwo RL policies with a hand-over in the airA full turn inside one flight, landing on the feet

A recurring lesson across the implementations is to measure the outcome that matters. A moving leg is not necessarily a traveling crawl. A desired brush path is not the actual painted stroke. A duck sitting on a moving swing does not, by itself, show that its motion is driving the swing. And a flip counts only if the full turn happens inside one flight: one trampoline policy once collected small tilts over many bounces instead.

These examples make those questions visible. They are specific simulated behaviors, each with its own controller, setup, and checks. Hardware transfer remains a separate step.

12Explore the implementation

The scenes, controllers, task notes, and tests are in microduck_lab on the microduck-lab branch.

The package keeps one folder per behavior in tasks/, with sim/ for shared simulation setup, models/ for robot and scene variants, and docs/tasks/ for the implementation notes. The rl/ directory holds the reinforcement learning tasks, and film/ the film-building utilities.

A good place to start is the package README, then the task corresponding to the video you want to explore.

The videos bring the duck to life. The code shows how each small behavior is built.

13LinkedIn posts