Microduck Arabesque β a 740 g desktop robot that holds a ballet pose
Microduck Arabesque is a reinforcement-learning policy that lets Microduck, a ~740 g desktop-scale biped robot with 14 hobby servos, perform a stable arabesque: standing on one leg while raising the other leg ~5.5 cm behind the body β and holding it for the full 8-second episode without falling.
Everything about this is tiny: the robot (0.74 kg, 14 Γ Dynamixel XL330-class servos), the policy (**200k parameters, a 0.76 MB ONNX file**), and the training budget (36.9 M environment steps in ~81 minutes on a single RTX 3090). The policy transfers zero-shot from simulation to hardware thanks to a voltage-level actuator model and aggressive domain randomization.
| Hold duration (sim) | 397.7 / 400 steps β 7.95 s of the 8 s episode cap |
| Fall rate (final 100 iters, sim) | β 0 (ballet_fallen termination ~0) |
| Raised-foot height (sim) | 5.5 Β± 0.8 cm at target |
| Action std at convergence | 0.12 (precise, "held" posture) |
| Hardware validation | β validated on the physical robot |
https://huggingface.co///blob/main/demo.mp4
Model Details
Model Description
Microduck Arabesque is a sim-to-real reinforcement-learning locomotion policy, not a neural network trained on a dataset. It was learned entirely through trial and error in GPU-accelerated physics simulation (mjlab / MuJoCo-Warp), then exported to ONNX for on-robot inference.
The skill it encodes is deliberately narrow and deep: from the robot's HOME stance, shift weight over the left foot, swing the right leg up and back to ~5.5 cm foot height, counterbalance with a slight forward trunk lean, and hold the pose indefinitely while rejecting disturbances. Behavior emerges from a single fixed reward objective plus a fall penalty β no demonstrations, no motion capture, no scripted keyframes.
- Developed by: Microduck Project β [your name / team]
- Funded by: independent project
- Shared by: [your HF username]
- Model type: PPO actor-critic policy (MLP 512β256β128, ELU, Gaussian action head) exported to ONNX; observation normalization baked into the graph
- Language(s) (NLP): N/A β this is a motor-control policy, not a language model
- License: apache-2.0
- Finetuned from model: No β trained from scratch
Model Sources
- Repository: [your code repo URL]
- Paper: none β software stack credits in Citation
- Demo: [Viser web viewer / video link]
Uses
Direct Use
Run the ONNX policy on (or next to) the robot: at 50 Hz, assemble the 61-D observation vector, feed it to the network, and apply the 14 joint-position targets through the on-board firmware PD loop. The observation layout is a fixed 61-dim contract shared by all Microduck skills (see How to Get Started).
Because all command slots are pinned near zero for this skill, the policy is effectively command-free: it holds the pose regardless of the command channels, which makes deployment simple and predictable.
Downstream Use
- The 61-D observation contract is shared across the Microduck task family (walking, stand-up, sit-stand, spinβ¦), so this checkpoint can be used as a warm start for further ballet skills (arabesque variants, turns, choreography sequences) by fine-tuning with the same code base.
- The reward design (one dominant task objective +
left-support & right-airbornecontact shaping + an explicit fall penalty) is a reusable recipe for other static-pose skills on small robots.
Out-of-Scope Use
- Dynamic choreography (turns, jumps, transitions between poses) β this checkpoint holds a single static pose only.
- Other hardware β the actuator model is fitted to XL330 servos with the specific BAM M6 parameters and 6.5β8.2 V battery sag of this robot; on modified mechanics or electronics the policy will transfer poorly.
- Payloads beyond the training randomization (Β±3 mm trunk/head CoM offsets) β heavy add-ons (extra sensors, decorations) shift the CoM outside the trained envelope.
- Any use near people, pets, or on uneven/slippery surfaces without a safety perimeter.
Bias, Risks, and Limitations
- Static pose only. The policy was trained on flat ground with a fixed target; it does not walk, turn, or recover from large disturbances.
- Fixed handedness. Trained exclusively as a left-support / right-lift arabesque; the mirrored pose would require retraining (the project's bilateral-symmetry tooling can provide it).
- Sim-to-real gap remains. Domain randomization covers CoM offset, friction, armature, encoder bias, actuator delay and battery sag, but contact-rich single-leg balance is inherently sensitive; expect occasional falls on dusty/slippery surfaces.
- Upright carriage. The learned trunk counter-lean is partial (~a few degrees vs. the ~11.5Β° a classical arabesque line would have): the robot raises the leg with a more upright torso.
- 50 Hz control loop required. The policy assumes 50 Hz observation/action exchange with the 200 Hz on-board firmware PD loop; running it on a slower link degrades balance.
Recommendations
Operate the robot on a flat, non-slip desk surface, with the battery in the trained 6.5β8.2 V range, and keep a hand ready to catch it during the first seconds. Stop immediately if any servo overheats β holding a single-leg pose loads the support ankle continuously.
How to Get Started with the Model
The exported ONNX embeds the observation normalizer (actor(normalizer(obs))), so raw observations go in and joint targets come out:
import numpy as np
import onnxruntime as ort
sess = ort.InferenceSession("microduck-arabesque.onnx")
# 61-D observation contract (Microduck skill family):
# [0:3] base_ang_vel (body-frame IMU, rad/s)
# [3:6] projected_gravity (body-frame)
# [6:20] joint_pos - HOME (14 joints)
# [20:34] joint_vel (14 joints)
# [34:48] last_action (14 joints)
# [48:51] twist command (lin_vx, lin_vy, ang_vz) β pinned ~0 for this skill
# [51:55] head command (neck_pitch, head_pitch, head_yaw, head_roll) β pinned ~0
# [55:61] body command (x, y, z, roll, pitch, yaw) β pinned ~0
#
# Joint order in each 14-dim block:
# 0:left_hip_yaw 1:left_hip_roll 2:left_hip_pitch 3:left_knee 4:left_ankle
# 5:neck_pitch 6:head_pitch 7:head_yaw 8:head_roll
# 9:right_hip_yaw 10:right_hip_roll 11:right_hip_pitch 12:right_knee 13:right_ankle
obs = np.zeros(61, dtype=np.float32) # fill from IMU / encoders each cycle
action = sess.run(None, {"obs": obs[None]})[0][0] # 14 joint-position offsets
# Send `action` as position targets at 50 Hz; the on-board 200 Hz firmware
# PD loop (modeled as a BAM M6 actuator in training) tracks them.
The matching robot-side runtime (observation assembly, serial protocol, safety watchdog) ships with the training repository.
Training Details
Training Data
None β model-free reinforcement learning with self-generated experience. Every training sample was produced by 512 parallel MuJoCo-Warp simulations exploring from the HOME stance. No demonstrations, teleoperation, or motion-capture data were used.
Training Procedure
The behavior is shaped by a fixed reward: a Gaussian pose objective, a left-support β§ right-airborne contact reward that pays from the first centimeter off the ground, a bounded foot-height target (5.5 cm), a trunk-lean objective, upright/height anchors, and a β5 fall penalty on the fallen state. The fall penalty is the only curriculum: it makes "lunge and topple" unprofitable, so the policy first discovers standing (~90% of its reward early in training) and only then extends into the one-leg hold β a stand-then-lift curriculum that emerges rather than being staged by hand.
Domain randomization (sim-to-real): per-env battery voltage 6.5β8.2 V with load-dependent sag, actuator command latency (3β6 physics steps), trunk/head CoM offsets, joint friction and armature, encoder bias, foot friction, link mass/inertia.
Training Hyperparameters
- Algorithm: PPO (rsl_rl), symmetric-free, fp32
- Rollout: 512 parallel envs Γ 24 steps; minibatches 4; learning epochs 5
- Learning rate: 1e-3, adaptive (KL target 0.01); Ξ³ 0.99, Ξ»(GAE) 0.95, clip 0.2
- Entropy coefficient: 0.005 (halved from the walking recipe β a static precision pose needs the action std to anneal, ending at 0.12)
- Training regime: fp32 (no mixed precision)
- Episode length: 8 s (policy at 50 Hz, physics at 200 Hz)
Speeds, Sizes, Times
- Throughput: ~7.5β8k environment steps/s on one RTX 3090
- Total experience: 36.9 M env steps (3,000 iterations), ~81 minutes wall-clock
- Checkpoint β deployment: ~200k-parameter actor, 0.76 MB ONNX β small enough to push over serial to the robot's companion compute each boot
Evaluation
Testing Data, Factors & Metrics
Testing Data
Held-out evaluation is the simulation itself (the policy never overfits a dataset) plus qualitative validation on the physical robot.
Factors
Flat-terrain operation across the domain-randomization envelope (CoM offsets, friction, battery voltage, actuator latency).
Metrics
- Hold duration / fall rate: episode length and
fallenterminations β the skill's success criterion is not falling for the whole 8 s episode. - Pose accuracy: raised-foot height against the 5.5 cm target (Gaussian reward β 2.83 / 3.0 β 5.5 Β± 0.8 cm).
- Deployment readiness: action std (0.12 β a "held", low-tremor posture).
Results
| Metric | Value (final iteration, sim) |
|---|---|
| Episode length | 397.7 / 400 steps (7.95 s) |
| Fall terminations | β 0 per episode |
| Foot-height reward | 2.83 / 3.0 (β 5.5 Β± 0.8 cm) |
| Fall-penalty collected | β 0 (falls no longer profitable) |
| Mean return | 134 (vs. 59 for the previous standing-only policy) |
On hardware, the robot performs the arabesque as intended; the sim-to-real transfer required no retraining.
Summary
A 740 g, 14-servo desktop robot reliably holds a one-leg ballet pose for the full episode, with a 0.76 MB policy trained in ~81 minutes of simulation on a single consumer GPU.
Environmental Impact
Carbon emissions can be estimated using the Machine Learning Impact calculator presented in Lacoste et al. (2019).
- Hardware Type: 1 Γ NVIDIA GeForce RTX 3090 (24 GB)
- Hours used: β 1.4 h (final run; earlier exploration runs of the same project add a few GPU-hours total)
- Cloud Provider: on-premises workstation
- Compute Region: private (estimated at ~0.5 kWh β well under 0.5 kg COβeq)
Technical Specifications
Model Architecture and Objective
Actor MLP 61 β 512 β 256 β 128 β 14 (ELU, Gaussian head with state-independent log-std; observation normalization baked in at export). Trained by PPO with a fixed reward: arabesque pose Gaussian (Ο = 0.35 rad, swing-leg joints at hip β0.15 / knee β0.10 / ankle +0.10), support-contact reward requiring left foot grounded β§ right foot airborne β§ trunk upright, bounded right-foot height target 5.5 cm, trunk-lean objective, upright/height anchors, smoothness taxes, and a β5 fall penalty aligned with the fall termination.
Compute Infrastructure
Hardware
- Training: 1 Γ NVIDIA RTX 3090 (24 GB), on-premises
- Deployment: the robot's companion compute running onnxruntime; servos: 14 Γ Dynamixel XL330-class
Software
- mjlab 1.3.0 (Isaac-Lab-style manager API on MuJoCo-Warp GPU physics), warp-lang 1.12
- rsl_rl 5.x PPO
- bam (better-actuator-models),
mjlab_frictionlossbranch β voltage-level XL330 actuator model with battery sag and firmware-loop latency - onnxruntime for on-robot inference; wandb (offline) for experiment tracking
Citation
No paper yet β if this work helps you, please cite the model card / repository:
BibTeX:
@misc{microduck_arabesque_2026,
title = {Microduck Arabesque: Sim-to-Real One-Leg Ballet Pose for a 740 g Desktop Biped},
author = {Microduck Project Team},
year = {2026},
url = {https://huggingface.co/<username>/microduck-arabesque}
}
APA:
Microduck Project Team (2026). Microduck Arabesque: Sim-to-Real One-Leg Ballet Pose for a 740 g Desktop Biped. Hugging Face model card.
Glossary
- Arabesque β a ballet pose: standing on one leg with the other leg extended behind the body.
- BAM actuator model β a data-driven voltage-level model of the XL330 servo (firmware PD loop, friction, battery sag, latency) used to close the sim-to-real gap.
- Domain randomization (DR) β randomizing physics parameters per episode during training so the real robot is just "another randomized env".
- mjlab β Isaac-Lab-style manager-based RL framework running on MuJoCo-Warp GPU physics.
Model Card Authors
Microduck Project Team β [your name / team]
Model Card Contact
[your contact: GitHub issues on the code repo, or email]