Instructions to use nocrab/microduck-swing with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Microduck
How to use nocrab/microduck-swing with Microduck:
# Replace SLOT with the slot specified in the model card (walk, stand, sitstand, ground_pick, kick_left, kick_right, roulade). sudo robotctl policy load SLOT nocrab/microduck-swing
- Notebooks
- Google Colab
- Kaggle
Microduck on a swing
A fully 3D-printable standing swing for Microduck, plus three policies that chain into a full ride: hop on → pump → slow stop → walk off → stand. SIMULATION ONLY.
The video shows one ride in real time (about 28 s), then 4× slow-motion replays of the hop-on and the hop-off.
⚠️ Simulation only
Nothing here has been printed or run on a real duck. The mount and pump policies also need an input the robot software doesn't provide yet: the pose of the deck (see Observations). Treat this as a sim result and a starting point, not a trick to install.
The swing
The duck's legs are about 10 cm long and an XL330 hop clears about 4–5 cm, so it stands on a
low deck (top 40 mm above the floor) instead of sitting. The deck is 220 mm wide between the side
rails and open at the front and back. It hangs from two bowed arms on 608 bearings. Every part fits
a 256 mm bed. The STLs are in stl/ (_xN = how many to print).
| Printed (PETG) | Qty | ~g each |
|---|---|---|
deck_x1 (print as-is, ribs down) |
1 | 209 |
arm_x2 (print on its side) |
2 | 44 |
tower_upper_x2 (print flat) |
2 | 82 |
tower_lower_x4 (print flat) |
4 | 58 |
base_splice_x2 (print standing) |
2 | 6 |
crossbar_half_x2 (lap-jointed in the middle) |
2 | 42 |
Hardware: 2× 608 bearing, 2× M8×45 bolt + nyloc nut + 4 washers, about 18× M4×20–25 bolt + nut. Screw or clamp the base down for big swings. The simulation assumes 3 walls, 4 top/bottom layers and 25 % gyroid infill (55 % of solid PETG mass). Its empty-swing period is 1.078 s, so time ten swings of your print to check it matches. Fits (bearing press fit, nut pockets) are untested on a real printer.
The policies
All three use the standard 61-D Microduck contract (obs[1,61] → actions[1,14] at 50 Hz, observation
normalizer baked in), exported with scripts/export.py.
| File | Skill | Command (twist slots) | Head / body slots |
|---|---|---|---|
policies/mount.onnx |
walk up to the swing and step onto the deck, then stand | [0, 0, 0] |
body = deck pose |
policies/pump.onnx |
pump the swing / ride calmly and brake it | twist[0] = 1 pump, 0 calm |
body = deck pose |
policies/dismount.onnx |
walk off the open front or back of the deck and stand | walking command (vx, vy, wz) toward the nearer open end | zeros (walking contract) |
Observations. For mount and pump, the 6 body-command slots carry the deck pose in the duck's
yaw frame: [3·x, 3·y, 3·z, sin(yaw), cos(yaw) − 1, hinge angle], where (x, y, z) is the deck-top
centre relative to the trunk and yaw is the deck's heading relative to the duck. On a real duck this
would come from a fiducial marker on the frame plus a hinge angle sensor (not built). The dismount
policy needs no deck input. It is a walking policy you steer off the deck with a stick-like command
of about 0.15 m/s toward the exit, turning toward it.
Results (simulation, MuJoCo Warp, domain randomized)
Pivot friction, deck friction, swing mass, robot mass, CoM, joint friction, encoder bias and IMU mounting are randomized as in training.
Full ride (30 rides): mount, pump 10 s, twist[0] = 0 until the swing is below 2.5°, dismount, stand.
| Rides | |
|---|---|
| completed every phase without a fall | 28 / 30 |
| …and nothing but the feet ever touched the swing | 25 / 30 |
| failures by phase | mount 4 (beak or shin brushing the frame), calming 1 fall, dismount 0 |
Mount (40 mm deck): 84 % clean (no non-sole contact), 75 % at 60 mm.
Pump: from 1° the swing reaches 20° in about 1.5 s and holds 23–28°. The duck pumps mostly by
throwing its head and trunk along the swing in a deep crouch, not by crouch-and-rise.
Calm (twist[0] = 0): it brakes actively and quietly, 25° → about 6° in 4 s and about 2° in
16 s, where friction alone would leave 14–19°. Pump for 10 s then stop: 88 % ride the full 20 s.
Dismount, at the real hand-off from calm mode: 95–97 % clean (on the floor, clear of the deck, no shin or beak touch), 2–3 % falls. The push-off kicks the empty swing back up to about 13–17°.
How it was trained
mjlab + PPO, with tasks built on
pollen-robotics/microduck_rl (commit 4757d6ae)
and the swing modelled from the same numbers as the STLs:
- Mount: a deck-height curriculum from 10 to 80 mm. Any touch of the swing by something other than a sole voids the episode. The arms are bowed outward at head height after the beak kept brushing straight arms.
- Pump: starts from recorded mount-policy stances, sideways on the deck. Facing along the swing turns the deck into a rocking board. The reward is swing amplitude, capped at 30°, with a potential-based growth term paid only while riding cleanly; in calm mode the growth term flips sign.
- Dismount: three attempts that started from the mount policy never stepped off the deck. The
actor is instead Pollen's released walking policy (
alpha_walking.onnx, policy release seed-v8), fine-tuned with a deck-height curriculum and then on recorded real hand-off states, which took clean dismounts at the hand-off from 54 % to 95–97 %.
Credits
Microduck, its training stack and the walking policy the dismount is fine-tuned from are by Pollen Robotics (Apache-2.0). Swing design and swing policies by nocrab, made with Claude Code.