OPEN-SOURCE ENGINEERING PRACTICE · EMBODIED INTELLIGENCE · SIM2REAL REINFORCEMENT LEARNING

MicroDuck: A Bipedal Robot with Feetech Servos
(First Edition)

An Engineering Methodology for Sim2Real Transfer in Bipedal Robots

Building on the open-source MicroDuck released by Pollen Robotics, this book presents a reproducible, low-cost bipedal-robot engineering pipeline for China's domestic supply chain: from MJCF reverse engineering and automated Onshape → MJCF dynamic modeling, through bench identification of the HD1910 serial-bus servo using a Bandwidth-Aware Motor (BAM) model, to PPO policy training with extended domain randomization and curriculum learning, and finally to 50 Hz on-device inference on the RK3566 and closed-loop iteration on the physical robot. Together, these cover the full-stack engineering loop of CAD → dynamics → actuation → simulation → hardware.

WWNT Robotics · open-source ecosystem on GitHub UnitClaw

Preface

Reading Entry Points

Every chapter in this book is bound to a specific commit hash in the companion engineering repository, so readers can check out the corresponding version and fully reproduce each experiment. Each chapter has two entry points in its upper-right corner: the 📝 "edit" icon, which jumps to that chapter's source file, and the Octocat icon, which jumps to the repository home.

Chapter ↔ Repository Resource Mapping

Each chapter maps to concrete engineering resources in the repository; click to jump to the source code, drawings, bills of materials, and logs:

Book ChapterCorresponding Repository Resource
Parts StorePARTS.md · Official Store
Minimal Simulation Demosoftware/training/
CAD Model Analysiscad/ · CAD repo
Onshape → MJCFscripts/
3D Printing & Assemblyprint/ · BOM.md
Hardware Circuits & Bushardware/
RK3566 Image & Firmwaresoftware/image/ · software/studio/
Servo / IMU Calibrationtools/
Simulation & Trainingsoftware/training/
ONNX Deploymentsoftware/studio/
Real-Robot Gaitsoftware/
Engineering & Open SourceNOTICE.md · LICENSE
BOMBOM.md
Troubleshooting踩坑记录.md

Reverse entry points on the repository side: the repository README.md carries the online-book link and the parts-store entry at the top; documents such as PARTS.md and BOM.md also reference their corresponding book chapters.

Core Engineering Highlights (Key Innovations of This Book)

Building on the community microduck-replica project, this book completes six engineering loops that constitute the key innovations relative to both the original Pollen robot and the community replica:

Highlight 1 — Automated Onshape → MJCF Pipeline (on par with Pollen's original)

A complete reproduction of Pollen's original Onshape → MJCF automated workflow: starting from the full-assembly STEP import, the pipeline automatically computes each link's mass, center of mass, and inertia tensor, and uses validate_mjcf.py to automatically validate the inertia tensor, joint limits, and total mass — eliminating the Sim2Real bias introduced by the replica's manual inertia estimation.

See Automated Onshape→MJCF Modeling · Deliverables: scripts/cad2mjcf/export_mjcf.py + validate_mjcf.py

Highlight 2 — Bench Identification of the HD1910 Servo Using a BAM Model

Performs bench-based identification of the Feetech HD1910 to fit the full BAM (Bandwidth-Aware Motor) parameter set — bandwidth, viscous friction, Coulomb friction, rotor inertia, and backlash — resolving the Sim2Real bias caused by the original replica's use of empirically guessed parameters.

See Servo and IMU Calibration and BAM Actuator Modeling and Identification · Deliverable: scripts/calibration/hd1910_bench_data_process.py

Highlight 3 — Extended Domain Randomization + Curriculum Learning

Extends the baseline domain randomization with an eight-dimensional parameter set (mass, friction, torque, bandwidth, backlash, IMU noise, ground friction, gravity) combined with curriculum learning that progresses from standing to walking, turning, and climbing; ablation studies compare the real-robot transfer success of different randomization strategies.

See Domain Randomization and PPO Multi-Task Training · Deliverables: the domain_rand extended parameter set + curriculum scheduling logic

Highlight 4 — Automatic Validation Between Simulated Observation Space and On-Device Firmware

Provides an automatic validation script that cross-checks the simulation observation space against the on-device Rust firmware, comparing the dimension, scaling, and ordering of observations/actions in one step, thereby eliminating the most common hidden Sim2Real bugs caused by dimension or scaling mismatches.

See RK3566 Image and Firmware and Policy Deployment and On-Device Inference · Deliverable: scripts/validation/check_obs_act_space.py

Highlight 5 — A Complete Experiment-Management System (Reproducible)

Establishes a standardized experiment-management system: every training run saves config.yaml, an MJCF snapshot, BAM parameters, training logs, and TensorBoard curves, so any experiment can be reproduced and traced one-to-one.

See Engineering Practices and Open-Source Compliance · Deliverable: the experiments/ directory convention (config / mjcf / bam_params / logs / readme)

Highlight 6 — Docker-Locked Dependency Versions

Uses Docker to pin CUDA, Python, MuJoCo-Warp, mjlab, and other dependency versions, eliminating the "works locally, fails elsewhere" environment problem and enabling one-command reproduction of the training environment.

See Minimal Simulation Example and Engineering Practices and Open-Source Compliance · Deliverables: Dockerfile + requirements-lock.txt


Why This Book

In 2025, Pollen Robotics — a robotics team under Hugging Face — open-sourced MicroDuck, a bipedal robot duck trained with Sim2Real reinforcement learning. Its core paradigm is to train the robot's policy in a GPU simulation and deploy it directly to real hardware, with no traditional gait planning required.

The original MicroDuck uses Dynamixel servos and is sold internationally on pre-order; it cannot be shipped directly to mainland China, and at 399 USD plus forwarding and customs fees, it is difficult for hobbyists and domestic university labs to obtain. The community responded with the microduck-replica project, which ports MicroDuck's mechanical structure to the domestic Feetech HD1910 bus servo.

The original replica, however, has clear shortcomings:

  • The MJCF dynamics model relies on manually estimated link inertias and centers of mass, producing a large gap between simulation and hardware that makes Sim2Real transfer difficult;
  • The HD1910 BAM parameters are empirically guessed, with no bench-based calibration procedure;
  • There is no standardized experiment management, so training configs, models, and logs are scattered and hard to reproduce;
  • There is no one-command containerized environment, and CUDA, Warp, and mjlab version dependencies collide easily;
  • There is no complete engineering troubleshooting log, so readers have no systematic way to handle falling in simulation, hardware jitter, servo packet loss, and similar problems.

The goal of this book is to complete this engineering loop: to fully reproduce Pollen's Onshape→MJCF automated workflow and to land bench-based HD1910 BAM identification, domain randomization, curriculum learning, and RK3566 on-device deployment, forming a reproducible, low-cost, domestic-servo MicroDuck full-stack engineering practice.

This book is neither a purely theoretical reinforcement-learning textbook nor a simple parts-assembly manual. It is an engineering practice log: it contains successful experiments, failed attempts, parameter ablation comparisons, and diagnoses of the gap between simulation and hardware.

Intended Audience

  • Graduate and undergraduate students in robotics, embodied intelligence, and reinforcement learning;
  • Robotics-lab engineers at universities and open-source-hardware enthusiasts;
  • Developers who want to get started with Sim2Real, MuJoCo-Warp, and low-cost bipedal RL robots.

Recommended reading path:

  1. First run [Minimal Simulation Demo], launching the simulation with one Docker command to see the robot duck's simulated gait;
  2. After understanding the overall Sim2Real chain, read the mechanical CAD, 3D printing, and hardware assembly chapters;
  3. Advanced readers should go deep into the BAM model, system identification, and domain-randomization ablation experiments.

The Full Technical Chain

STEP assembly → Onshape cloud CAD (assign part densities, override servo masses) → onshape-to-robot MJCF export → MuJoCo-Warp GPU simulation → BAM servo model (bench-identified HD1910 parameters) → domain randomization + curriculum-learning PPO multi-task training → ONNX policy export → RK3566 Rust firmware 50 Hz real-time inference → real-robot IMU/joint data collection → system identification to correct the dynamics model → iterative retraining

Join the Community

WeChat community group QR code
MicroDuck Parts (Mainboard, Servo Group 2)
Scan to join · valid until 2026-10-31

Join our WeChat community to share replication experience, report corrections, and help build the domestic open-source ecosystem for low-cost bipedal robots.

⚠️ The WeChat group QR code expires automatically after 7 days (this image is valid until 2026-10-31). After expiry, visit https://www.wwntai.com/parts.html for the latest QR code, or open a GitHub issue to update it.

Open-Source Licensing Boundaries (Please Read)

  1. The prose of this book: CC-BY 4.0 — free to read and share, with attribution required when quoting;
  2. Upstream software code: Apache 2.0;
  3. Mechanical CAD models: CC BY-NC-SA — non-commercial study and research only.

If a commercial product is required, the mechanical structure must be independently designed from scratch, independent of this CAD model set.

The companion engineering repository hosts all code, scripts, experiment records, Docker configuration, and book source on GitHub; every chapter is bound to a repository commit hash, so you can check out the corresponding version and ensure the code matches the book exactly.

The copyright in this book (including its text, figures, code snippets, and companion documents) belongs to Guangdong WWNT Robotics Co., Ltd. (WWNT Robotics; open-source ecosystem on GitHub: UnitClaw).

Copyright © WWNT Robotics (Guangdong WWNT Robotics Co., Ltd.) All rights reserved.

Unless otherwise noted, the book's prose is licensed under CC-BY 4.0 (free to read and quote, with attribution); upstream code is under Apache-2.0, and the mechanical CAD models are under CC BY-NC-SA (non-commercial study and research only).

Limitation of Liability (Please Read)

This book is an open-source engineering-practice record. Some technical material (simulation parameters, BAM identification results, firmware configuration, assembly tolerances, etc.) derives from specific hardware batches and experimental environments and has not all been fully validated on physical hardware. Hardware assembly, circuit wiring, and power-on debugging inherently carry risks of short circuits, damage, and mechanical injury; an intrinsic gap always exists between the simulation model and the real robot, and directly copying the settings may not produce stable walking; servo, mainboard, and sensor parameters vary with batch, firmware version, power supply, and load conditions.

Accordingly, WWNT Robotics assumes no responsibility for any experimental failure, property loss, or personal injury arising from a reader's direct replication of this book's contents. Please validate progressively in a safe environment — simulation first, then bench, then the physical robot — and ensure power isolation and protection. By using this book, you acknowledge and accept the risks and limitations of liability described above.

Intellectual Property and Infringement

  1. This project is an independent third-party replication study of Pollen Robotics' open-source MicroDuck; it is not affiliated with, authorized by, endorsed by, or sponsored by Pollen Robotics. The "MicroDuck" name and related trademarks and brands belong to their respective owners.
  2. This book and its companion repository are provided solely for educational, research, and non-commercial open-source study and do not constitute an authorized use of any upstream commercial product, trademark, or patent.
  3. If a reader pursues commercial activity based on this book, they must independently design the mechanical structure from scratch (independent of this CAD model set) and perform their own compliance review and obtain any necessary authorization regarding the intellectual property, trademarks, and patents of the relevant rights holders.
  4. WWNT Robotics assumes no responsibility for any dispute or loss arising from unauthorized commercialization, infringing use, or failure to obtain necessary authorization.

Acknowledgments

Thanks to Pollen Robotics for open-sourcing MicroDuck, mjlab, and microduck_rl; to fanhao375 for open-sourcing microduck-replica and microduck-replica-cad; to Feetech for the HD1910 servo hardware and technical documentation; and to all open-source community developers.

For the full company introduction and acknowledgments (Pollen, Feetech, fanhao375, 机械行者Robo, kissqy, LuwuDynamics, Rhoban, and others), see the [Acknowledgments] chapter at the end of the book.

This book is under continuous iteration, and the engineering experiments are updated as they evolve; corrections and suggestions are welcome via GitHub Issues.

Introduction: Pollen MicroDuck and Open-Source Embodied Intelligence

Learning objectives: understand what MicroDuck is, how the Sim2Real paradigm operates, why the original is difficult to obtain in China, and the rationale behind the community replica's servo selection.

1.1 An Open-Source Robot Duck That Can Walk

In 2025, Pollen Robotics — a robotics team under Hugging Face — open-sourced a bipedal robot duck named MicroDuck. It is compact (≈0.7 kg) and affordable, but its core value lies not in the hardware itself but in how it moves: a gait trained via reinforcement learning.

Traditional quadrupedal/bipedal robots (such as Spot and Atlas) rely on complex kinematic planning: first build a precise dynamics model, then solve joint torques frame by frame. MicroDuck takes a completely different route:

  1. In a GPU simulation environment (MuJoCo-Warp), a "digital duck" falls and walks randomly;
  2. A PPO reinforcement-learning algorithm, guided by a reward function, teaches it to stand, walk, and self-recover from falls;
  3. The trained policy is exported as an ONNX model and deployed directly onto the physical duck's "brain" (an RK3566 board);
  4. The physical duck reads IMU and joint angles at 50 Hz, runs ONNX inference to obtain target servo positions, and closes the control loop.

This is the complete Sim2Real (simulation-to-reality) loop. It does not require engineers to hand-design gaits; it only requires a well-designed reward function and simulation environment.

1.2 Why "Simulate First, Deploy Later" Is a Paradigm Shift

DimensionTraditional gait planningSim2Real reinforcement learning
Modeling costRequires a precise dynamics model; error-sensitiveUses domain randomization to tolerate model error
Source of gaitHand-designed by engineersDiscovered automatically by the algorithm
Disturbance robustnessDepends on precise feedback; fragileHas seen various disturbances in training; robust
Complex terrainHard to plan by handGuided by the reward function

The essence of Sim2Real is not "simulation" itself but how to close the gap between simulation and reality — the central problem this book revisits from Automated Onshape→MJCF Modeling through The Sim2Real Closed-Loop Iteration.

1.3 Why the Original Is Hard to Buy in China

The original MicroDuck uses Dynamixel XL330 servos with an official pre-order price of 399 USD. The more critical constraint is the supply chain:

  • Official direct-shipping regions: US, Canada, EU, UK, Norway, Switzerland, Japan, South Korea;
  • Mainland China is not on the direct-shipping list, requiring freight forwarding or proxy ordering;
  • 399 USD plus international shipping, tariffs, and customs clearance makes the actual landed cost significantly higher than the list price;
  • New orders have an estimated 4–6 month wait.

These real-world constraints make it hard for domestic hobbyists and university labs to obtain an original robot duck at low cost. A domestic replica therefore becomes an engineering proposition of genuine value.

1.4 Servo Selection for the Domestic Replica: Why the Feetech HD1910

The original's core actuator is the Dynamixel XL330, a serial-bus servo. Domestic alternatives fall into two main categories:

ServoTypeTorque @ 4.8 VWeightCommunicationPrice range
Dynamixel XL330Magnetic-encoder bus servo~6.5 kg·cm~16 gTTLHigh
Feetech HD1910Magnetic-encoder TTL bus servo9 kg·cm21±2 gTTLLow

Key specifications of the Feetech HD1910:

  • Model: HD-1910-C001, dual-shaft magnetic-encoder TTL bus servo, coreless motor, metal gears;
  • Operating voltage: 4.8–8.4 V;
  • Stall torque: 9 kg·cm @ 4.8 V;
  • No-load speed: 0.137 sec/60° (≈73 RPM) @ 4.8 V;
  • Weight: 21±2 g;
  • Communication: TTL bus, baud rate up to 1 Mbps, 360° magnetic encoder, multi-turn position readout.

⚠️ Selection warning: the torque, friction, bandwidth, and backlash parameters of domestic servos differ dramatically from the original. The original's pre-trained gait model cannot be directly transplanted; the servo model must be re-calibrated and the policy retrained (see BAM Actuator Modeling and Identification).

1.5 The Community Replica Landscape

RepositoryNatureServoCompanion assets
pollen-robotics/microduck_rlOriginal RL coreXL330Training code only
UnitClaw/microduck-wwduckWWNTRobotics-optimized editionHD1910Training + CAD + firmware + image + engineering optimizations
fanhao375/microduck-replicaComplete replica projectXL330 + HD1910Training + CAD + firmware + image
fanhao375/microduck-replica-cadMechanical drawingsXL330 + HD1910SolidWorks/STL
LuwuDynamics/xgoduck_hardwareFeetech-partner robot duckHD1910Standalone robot

Boundary note: 晨芯时代科技 is a domestic hardware solution provider that adapted the original for domestic hardware, but it has no standalone MicroDuck GitHub repository, delivering only RK-platform images and BSP. Feetech has likewise not published an identically named MicroDuck repository.

1.6 Goals of This Book

This book completes something the community has not yet done in full: building, from scratch, a reproducible MicroDuck full-stack engineering loop using domestic Feetech HD1910 servos, while specifically addressing five shortcomings of the original replica project:

  1. Dynamics modeling: replace manually estimated inertia parameters with the Onshape→MJCF automated pipeline (Automated Onshape→MJCF Modeling);
  2. Servo modeling: identify the HD1910's BAM actuator parameters via bench measurement (BAM Actuator Modeling and Identification);
  3. Training robustness: extended domain randomization + curriculum learning to shrink the Sim2Real gap (Domain Randomization);
  4. Engineering: Docker environment, automated validation, experiment management (The MuJoCo-Warp Simulation Environment);
  5. Hardware closed loop: real-robot gait iteration and system identification (The Sim2Real Closed-Loop Iteration).

Chapter summary: You now understand the value of MicroDuck and the necessity of a domestic replica. In the next chapter, we run the simulation end-to-end with one Docker command, building first-hand intuition for the entire pipeline.

Minimal Simulation Example

Learning objectives: with no 3D printing, no hardware, and no soldering, run the Feetech HD1910 MicroDuck simulation environment on a GPU machine with one command, and grasp the full Sim2Real pipeline. Prerequisites: Docker + NVIDIA GPU driver (CUDA support); the repository switched to the book-dev branch.

2.1 Why the Demo Comes First

Traditional robotics tutorials start from mechanical drawings and hardware assembly, so readers spend substantial time printing parts only to discover that the simulation cannot run at all.

This book adopts a problem-driven, virtual-to-physical learning path:

  1. First validate the robot dynamics, servo model, and RL policy in simulation;
  2. After confirming the simulated behavior matches expectations, move on to mechanical design, 3D printing, and hardware assembly;
  3. Fix dynamics defects discovered in simulation (inertia, center of mass, servo parameters) early, avoiding physical rework.

This chapter's minimal demo does only three things:

  • Load the Feetech HD1910 MJCF robot model;
  • Validate the model (inertia, joint limits);
  • Load a pre-trained standing policy, launch MuJoCo-Warp simulation, and visualize the robot duck standing.

This chapter trains no new policy; it only reproduces an already-converged standing policy to quickly verify that the entire software stack works.

2.2 Environment Setup (One-Command Docker Container)

The repository ships a Dockerfile that pins CUDA, Python, MuJoCo-Warp, and mjlab versions, eliminating dependency conflicts.

# Clone the code and switch to the book development branch
git clone https://github.com/your-username/microduck-replica.git
cd microduck-replica
git checkout book-dev

# Build and launch the GPU simulation container
cd docker
docker-compose up --build

The container auto-mounts the local repository directory, so code changes take effect on the host directly, with no image rebuild required.

In a new terminal, enter the container:

docker exec -it microduck-replica-sim bash

2.3 Model Validation (Mandatory)

In Sim2Real engineering, MJCF model errors are the most frequent failure. The repository ships an automated validation script that checks the inertia tensor, total mass, and joint limits.

python scripts/validation/validate_mjcf.py \
--mjcf software/training/assets/robots/microduck_feetech.xml

✅ Normal output example:

✅ MJCF loaded successfully, link count: 16
✅ Total mass: 0.726 kg
✅ Basic MJCF validation passed

❌ Failure scenarios: a non-positive-definite inertia tensor, or joint limits exceeding the servo's physical range — return to the CAD/Onshape step to correct them.

2.4 Running the Minimal Demo: Loading a Pre-trained Standing Policy

python software/training/train_ppo.py \
config=experiments/exp01_standup/config.yaml \
resume=experiments/exp01_standup/checkpoints/latest.onnx

After execution, MuJoCo-Warp launches GPU-parallel simulation, opens a visualization window, and the robot duck holds its standing pose.

2.4.1 Experiment Configuration (exp01_standup/config.yaml)

robot_xml: "software/training/assets/robots/microduck_feetech.xml"
bam_params: "experiments/exp01_standup/bam_params.json"
num_envs: 256
control_freq: 50
policy_type: "ppo"
task: "stand"
domain_randomization: false
  • control_freq: 50: strictly aligned with the RK3566 board's 50 Hz control frequency — the key to Sim2Real transfer;
  • domain_randomization: false: the minimal demo disables domain randomization for stable behavior; later chapters enable it for ablation studies.

2.5 Observations and Basic Diagnostics

Observe the simulated behavior:

  1. The robot duck stands stably, without slow tipping;
  2. Joint angles stay within the HD1910 physical limits;
  3. No large number of numerical-explosion warnings.

Common troubleshooting (pitfall log for this chapter)

  1. Falls immediately on startup: most likely incorrect MJCF center of mass / inertia; re-check the CAD→MJCF pipeline in Automated Onshape→MJCF Modeling;
  2. Violent joint jitter: mismatched BAM servo parameters; bench calibration is required (Servo and IMU Calibration);
  3. CUDA out of memory: reduce num_envs.

2.6 Chapter Summary

You have validated the entire simulation software stack: the MJCF model, the BAM servo model, MuJoCo-Warp, and PPO policy loading.

Simulation is only a digital world; whether the simulated dynamics parameters match the real robot determines the success of subsequent hardware transfer. The next chapter enters mechanical CAD. Automated Onshape→MJCF Modeling automates Onshape MJCF export, computing link inertias and centers of mass from the source — no more manual estimation.

Experiment log: this run is archived under experiments/exp01_standup/; view observation and reward curves in TensorBoard.

HD1910 CAD Model Analysis

Learning objectives: understand the mechanical structure of the microduck-replica-cad repository, grasp the part differences between the two servo versions, and learn to export the full-assembly STEP, preparing for the automated Onshape MJCF export in Automated Onshape→MJCF Modeling.

3.1 Repository Structure Overview

The mechanical CAD drawings live separately in fanhao375/microduck-replica-cad:

microduck-replica-cad/
├── feetech/          # Feetech HD1910 assembly + all parts
│   ├── microduck_feetech.SLDASM    # full-machine assembly
│   └── ... *.sldprt                 # individual parts
├── xl330/            # original Dynamixel XL330 version
│   ├── microduck_xl330.SLDASM
│   └── ... *.sldprt
└── stl/              # ready-to-print STL files

Key distinction: parts are not interchangeable between the two servo versions. The Feetech HD1910 and the original Dynamixel differ in outline, mounting-boss orientation, and output-shaft position. When printing, you must select parts from the matching version to avoid discovering a mismatch during assembly.

3.2 The Robot Duck's Mechanical Topology

MicroDuck is a bipedal robot. Each leg roughly contains:

JointDescriptionCount (per leg)
Hipallows forward/backward swing and lateral opening (pitch/roll/yaw combination)3
Kneeallows shank flexion/extension (pitch)1
Ankleallows foot pitch and roll2

The whole machine has 14–15 servos (some replicas add degrees of freedom at the tail or head); the exact count and limits follow your CAD assembly tree.

3.3 Mapping the Kinematic Tree (Preparing for MJCF)

When exporting MJCF in Automated Onshape→MJCF Modeling, you must tell Onshape/onshape-to-robot which parts are links and which joints are actuated. This must be clarified in advance. The recommended kinematic tree (for 14 DOF):

base(torso/base)
 ├── thigh_right  (hip pitch) ── knee_right(knee) ── ankle_right(ankle)
 └── thigh_left   (hip pitch) ── knee_left (knee) ── ankle_left (ankle)

The hip roll/yaw usually sit between the torso and the thigh; if your assembly places roll/yaw after hip pitch, the joint hierarchy in the exported MJCF must match reality one-to-one, or the simulation will error out immediately.

3.4 Exporting the Full-Assembly STEP

The microduck-replica-cad repository uploads SolidWorks source files (.sldasm/.sldprt) by default and does not provide a pre-packaged STEP; you must export it manually:

  1. Open feetech/microduck_feetech.SLDASM in SolidWorks;
  2. Choose "File → Save As";
  3. Select file type STEP AP214 (recommended, best compatibility);
  4. Save as microduck_feetech.step.

No SolidWorks? The free, open-source FreeCAD can open .sldasm and export STEP, but FreeCAD's compatibility with SolidWorks assembly constraints is limited; some constraints may be lost, so verify assembly integrity before exporting.

3.5 Three Checks Before Exporting STEP

  1. Assembly hierarchy must not collapse: confirm parts are not all flattened to the root node, or the exported MJCF joint hierarchy will be scrambled;
  2. No over- or under-constrained mates: assembly constraints must be complete, or joint positions will drift after importing the STEP into Onshape;
  3. Servo mounting orientation is correct: the HD1910's mounting-boss orientation must match the thigh/shank parts — this is the most error-prone point between the two versions.

3.6 Engineering Pitfall Log

  1. Ankle joint seizure: a classic replica problem. After 3D printing, the servo horn interferes with adjacent structure, restricting rotation or seizing it. Check the horn-to-shell clearance in CAD, and if necessary correct the assembly interference in the STEP source and widen the clearance.
  2. Part walls too thin: some structural parts have insufficient wall thickness and fracture under load after printing. Thicken load-bearing regions or raise the infill ratio.
  3. Printing the wrong part: downloading both the feetech and xl330 STL sets and selecting the wrong version during printing leads to assembly failure. Print by directory and version labeling.

3.7 Chapter Summary

You should now be able to:

  • Locate the correct Feetech-version parts in microduck-replica-cad;
  • Understand MicroDuck's kinematic tree (preparing for MJCF joint definitions);
  • Export the full-assembly STEP AP214 from SolidWorks.

In the next chapter, import this STEP into Onshape and use onshape-to-robot to auto-generate an MJCF model with accurate inertia parameters — no more manual estimation.

Automated Onshape→MJCF Modeling

This chapter is the book's core innovation: replacing the original replica's manual inertia-entry approach with a full reproduction of Pollen's CAD→MJCF automated pipeline, which computes each link's mass, center of mass, and inertia tensor automatically. Companion scripts: scripts/cad2mjcf/export_mjcf.py + onshape_config.json.

4.1 The Pain Point: Why Manual Inertia Estimation Fails

The original microduck-replica MJCF model estimates link mass, inertia, and center of mass by hand. The simulated gait looks perfect, but deploying to hardware causes immediate tipping — the root cause is exactly that the dynamics model does not match the real robot (the Sim2Real gap).

Pollen's original MicroDuck solution: SolidWorks assembly → import into Onshape, assign part densities → onshape-to-robot automatically exports MJCF, computing inertia tensors from geometry. This book reproduces that pipeline in full, adapted for the domestic HD1910 servo.

4.1.1 The Full Workflow Chain

STEP assembly → Onshape import → assign part densities → servo-mass override config → onshape-to-robot export of STL meshes + MJCF → automatic MJCF validation → replace the simulation robot XML

4.2 Onshape Prerequisites

  1. Import the full-assembly STEP into an Onshape document;
  2. Assign each 3D-printed part a PLA-equivalent density: 1240 kg/m³;
  3. For HD1910 servo parts, do not compute mass from geometry; force-override the mass to 21 g in the config;

    A servo's internal coreless motor, magnetic encoder, and gear train are structurally complex, so geometry-derived mass is inaccurate; the manufacturer's nominal weight must override it.

  4. In the Onshape assembly, define the joints (revolute), and record the joint IDs, rotation directions, and physical limits.

4.2.1 PLA Equivalent-Density Reference

Infill ratioEquivalent density (g/cm³)
20%0.35–0.45
40%0.6–0.7
Solid PLA~1.24

4.2.2 Preparing Onshape API Keys

Apply for Onshape API keys so the script can remotely read the assembly geometry:

  • Onshape personal account → developer console → create an API key;
  • Export two environment variables:
export ONSHAPE_ACCESS_KEY="your_access_key"
export ONSHAPE_SECRET_KEY="your_secret_key"

Do not commit the keys to Git; add them to .gitignore.

4.3 Configuration File Walkthrough: onshape_config.json

Path: scripts/cad2mjcf/onshape_config.json

{
  "url": "https://cad.onshape.com/documents/[document-id]/w/[workspace-id]/e/[assembly-id]",
  "output_format": "mjcf",
  "output_dir": "./output",
  "mesh_type": "stl",
  "units": "meters",
  "joints": {
    "thigh_right": {"type":"revolute","limits":[-1.57,1.57]},
    "thigh_left": {"type":"revolute","limits":[-1.57,1.57]},
    "knee_right": {"type":"revolute","limits":[-1.57,1.57]},
    "knee_left": {"type":"revolute","limits":[-1.57,1.57]},
    "hip_pitch_right": {"type":"revolute","limits":[-1.57,1.57]},
    "hip_pitch_left": {"type":"revolute","limits":[-1.57,1.57]},
    "hip_roll_right": {"type":"revolute","limits":[-1.0,1.0]},
    "hip_roll_left": {"type":"revolute","limits":[-1.0,1.0]},
    "hip_yaw_right": {"type":"revolute","limits":[-1.0,1.0]},
    "hip_yaw_left": {"type":"revolute","limits":[-1.0,1.0]},
    "ankle_pitch_right": {"type":"revolute","limits":[-1.57,1.57]},
    "ankle_pitch_left": {"type":"revolute","limits":[-1.57,1.57]},
    "ankle_roll_right": {"type":"revolute","limits":[-0.8,0.8]},
    "ankle_roll_left": {"type":"revolute","limits":[-0.8,0.8]}
  },
  "override_mass": {
    "hd1910_servo": 0.021
  }
}
  • units: meters: MuJoCo enforces SI units (meters, kilograms, seconds);
  • limits are in radians and must match the HD1910 mechanical hard stops exactly, preventing joint overtravel in simulation;
  • override_mass: force-overrides the servo mass, taking precedence over geometry-derived values.

4.4 One-Command MJCF Export: export_mjcf.py

Path: scripts/cad2mjcf/export_mjcf.py

Script logic:

  1. Read the JSON config;
  2. Call the onshape-to-robot library to access Onshape remotely and export STL meshes and MJCF;
  3. Auto-invoke the MJCF validation script after export;
  4. On validation success, prompt to copy robot.xml to the simulation assets directory.

4.4.1 Execution Command

python scripts/cad2mjcf/export_mjcf.py --config scripts/cad2mjcf/onshape_config.json

Normal output:

=== Starting onshape-to-robot MJCF export ===
✅ Export complete, validating MJCF model
✅ MJCF loaded successfully, link count: 16
✅ Total mass: 0.726 kg
✅ Basic MJCF validation passed

✅ All done! MJCF path: scripts/cad2mjcf/output/robot.xml
Tip: copy this robot.xml to software/training/assets/robots/microduck_feetech.xml

4.5 What the Validation Script Does (validate_mjcf.py)

  1. Load the MJCF model and read the link count;
  2. Compute the total machine mass;
  3. Iterate over every link and check that the inertia tensor is positive-definite (ixx, iyy, izz must all be > 0);

A non-positive-definite inertia tensor causes numerical instability and simulation explosion in MuJoCo.

4.6 The Closed-Loop Iteration (new in this book; absent from the original replica)

Exporting MJCF from CAD is only the first step. The complete loop:

  1. Export the initial MJCF from Onshape;
  2. Run the standing demo in simulation and observe center-of-mass stability;
  3. 3D-print the parts, weigh them individually, and record in data/cad_weigh_records/;
  4. Compare the CAD-computed mass against the real weight;
  5. Fine-tune part densities in Onshape and re-export MJCF;
  6. Iterate until the CAD-computed vs. measured mass error is < 5%.

4.7 Engineering Pitfall Log

  1. Unit error: Onshape uses millimeters; exporting without converting to meters scales the model by 1000× and crashes the simulation immediately;
  2. Joint limits entered in reverse, driving the simulated joint in a physically forbidden direction;
  3. Servo without override_mass: geometry-derived mass is too small, shifting the simulated center of mass upward;
  4. Broken STL mesh faces, causing MuJoCo collision-detection errors.

4.8 Chapter Summary

This chapter automates dynamics modeling, no longer relying on empirically estimated inertia.

But robot simulation needs more than rigid-body dynamics — it also needs the servo model. The next chapter introduces the BAM servo model and fits its parameters using HD1910 bench measurements.

3D Printing, Assembly, and Tolerances

Learning objectives: turn the CAD drawings into a robot duck that can move. Includes the full BOM, print parameters, assembly order, tolerance control, and the post-assembly weighing procedure (used for MJCF calibration in Automated Onshape→MJCF Modeling).

5.1 Complete BOM

CategoryPartSpec / quantityNotes
ActuatorFeetech HD191014–15 unitsdual-shaft magnetic-encoder TTL bus servo
MainboardRK3566 board1runs ONNX inference + Rust firmware
SensorIMU (MPU6050/ICM20948)1attitude estimation
Powerlithium battery12S or 3S, requires BMS
Power managementBMS protection board1low-voltage and over-current protection
Structure3D-printed parts1 setPLA, see 6.2
FastenersM2/M3 screwsseveralservo horn and structure fastening
Wiringservo TTL bus cableseveraldaisy-chains 15 servos
Misc.washers, bearingsseveralfriction reduction, positioning

Procurement advice: servos, board, and IMU are critical parts — prefer authorized channels; fasteners and wiring can be sourced locally. The BOM Procurement List lists recommended channels and alternative substitutes.

5.2 3D Printing Parameters

ParameterRecommendedNotes
MaterialPLAeasy to print, low cost
Layer height0.2 mmbalances speed and precision
Infill20%–40%40% for load-bearing parts, 20% for light parts
Supportsas neededoverhangs require supports
Print orientationvertical for axially loaded partsimproves strength

⚠️ The print infill ratio directly changes the machine's dynamics! 20% and 40% infill have different equivalent densities and will introduce error during MJCF calibration in Automated Onshape→MJCF Modeling. Be sure to record the infill ratio of every printed batch, and use the matching equivalent density during MJCF calibration.

5.3 Step-by-Step Assembly Order

  1. Test one leg first: print and assemble a single leg (hip, knee, ankle) to validate servo fit, range of motion, and horn fastening;
  2. Torso assembly: mount the IMU and mainboard in the torso and route wiring;
  3. Join both legs: assemble both legs to the torso base and confirm left-right symmetry;
  4. Daisy-chain the bus: connect the TTL bus in servo-ID order to avoid ID conflicts;
  5. Whole-machine power-on test: before loading any gait, verify each servo can rotate independently and read back position.

Strong recommendation: do not print the full part set at once. Print a single leg to validate the design first, then the whole machine, to avoid scrapping an entire batch due to a design defect.

5.4 Tolerance Control Essentials

RegionTolerance requirementHandling
Servo horn and output shaftinterference fitleave assembly allowance when printing
Bearing-seat holesfit precisionream or shim as needed
Servo mounting holesalignmentcheck hole-position differences between the two servo versions

3D printing itself has ±0.1–0.3 mm shrinkage error; complex assemblies should reserve clearance, or compensate with shims/bearings.

5.5 Post-Assembly Weighing (for Simulation Calibration)

A key to Sim2Real success: the simulated mass must match the real machine. After assembly:

  1. Weigh the whole machine: record the total mass;
  2. Weigh by part: disassemble each thigh, shank, and torso and weigh them individually on a 0.01 g scale;
  3. Record to data/cad_weigh_records/:
part,target_cad_mass_kg,measured_mass_kg,fill_ratio
thigh_right,0.042,0.038,20%
knee_right,0.020,0.019,40%
...
  1. Compare against the Onshape-computed CAD mass from Automated Onshape→MJCF Modeling; if the error exceeds 5%, return to Onshape to fine-tune part densities and re-export MJCF.

5.6 Common Assembly Problems and Troubleshooting

SymptomLikely causeHandling
Servo horn slippinginsufficient interference fituse a tighter horn or adhesive
Wiring interferencewiring not routed along structurere-route and tie with cable ties
Center-of-mass shiftasymmetric assemblycheck left-right part consistency
Joint seizureprint interference / insufficient clearancecorrect CAD per 4.6

5.7 Chapter Summary

Completing this chapter, you should have a robot duck that is mechanically correctly assembled, with the bus daisy-chained and every servo independently rotatable, along with measured mass data for the whole machine and each link.

The next chapter enters the hardware circuits and TTL bus system, resolving the low-level issues of servo communication and power.

Hardware Circuits and the TTL Bus

Learning objectives: build MicroDuck's electrical system — power, servo bus communication, and IMU integration — and master the most common troubleshooting (servo packet loss, communication timeouts, over-current protection).

6.1 System Electrical Architecture

lithium battery → BMS → power distribution
                  ├─ RK3566 mainboard (5V/3.3V logic)
                  ├─ IMU (I2C/SPI)
                  └─ servo bus (TTL, 15 HD1910 daisy-chained)

Key point: servo power and mainboard logic power must be separated. When 15 servos move simultaneously the current is large; if they share a power supply with the mainboard (even with a common ground), the mainboard voltage drops and it resets.

6.2 Power Scheme and BMS

  • Battery: 2S (7.4 V) or 3S (11.1 V) lithium; servos are rated 4.8–8.4 V, so 2S is safer;
  • BMS: must include low-voltage protection and over-current protection. At low voltage, servo torque drops sharply and position readback drifts, destabilizing the policy; over-current burns the servo drivers;
  • Consider adding power soft-start (inrush limiting) to avoid the inrush of charging capacitors at power-on disturbing the bus.

6.3 The Feetech HD1910 TTL Bus Topology

Fifteen servos are daisy-chained on the TTL bus, each with a unique ID:

mainboard UART(TTL) ── HD1910 ID=1 ── ID=2 ── ... ── ID=15
  • Baud rate: up to 1 Mbps; start debugging at a lower rate (e.g., 500 kbps);
  • Half-duplex TTL: transmit and receive share a line, requiring direction control on the mainboard side;
  • Each servo must be configured with its ID and baud rate first; ID conflicts scramble the entire bus.

6.4 IMU Integration and Mounting

  • Models: MPU6050 / ICM20948;
  • Interface: I2C or SPI; I2C bandwidth is limited, so prefer SPI for higher sample rates;
  • Mounting position: as close to the machine's center of mass as possible, on a rigid part of the torso;
  • Mounting tilt: the IMU's mounting attitude enters the attitude-estimation initial value. If it is mounted with a tilt, it must be compensated in firmware; otherwise the attitude angle drifts directly and Sim2Real fails.

6.5 Bus Troubleshooting

SymptomLikely causeHandling
A servo does not respondID conflict / wrong addressreconfigure the ID
Random packet losslong bus, signal interferencelower the baud rate, add bus isolation
Bus freezes after power-oninsufficient power / a shorted servopower up one servo at a time
Position readback driftsupply voltage sagcheck BMS and wire gauge

⚠️ Long-line interference: with 15 daisy-chained servos and long cables, TTL signals are easily affected by EMI. Use shielded cable or add bus-isolation chips. This is the most easily overlooked pitfall from simulation to hardware.

6.6 Wiring Convention for Power/Signal Separation

  1. Servo power wires (thick) come directly from the BMS, not through the mainboard;
  2. The mainboard and servos share only a signal ground; logic levels are driven by the mainboard;
  3. Place a current-limiting resistor/fuse in series at the servo-bus end to protect the mainboard UART.

6.7 Engineering Pitfall Log

  • Shared power causing mainboard reset: current spikes during multi-servo emergency stops pull down the mainboard voltage and reboot the system. Fixed by separating the power supplies.
  • ID conflict paralyzing the whole bus: two servos configured with the same ID scramble every command. Recovered by powering each servo individually and reconfiguring its ID.

6.8 Chapter Summary

You should be able to build an electrical system with separated power, a correct bus, and the IMU integrated, and to troubleshoot servo packet loss and power faults.

The next chapter brings the system up: flash the RK3566 image, deploy the Rust firmware, and understand the 50 Hz control loop.

RK3566 Image and Firmware

Learning objectives: flash the prebuilt RK3566 system image onto the board, understand the on-device Rust firmware's process architecture, and master the implementation and verification of the 50 Hz real-time control loop.

7.1 Flashing the System Image

The repository's software/image/ provides the prebuilt RK3566 image. Flashing procedure:

  1. Prepare: RK3566 board, SD card (≥ 8 GB), card reader, and the image file;
  2. Flash: write to the SD card with balenaEtcher or dd:
# Linux (assuming the SD card is /dev/sdX; verify the device name)
sudo dd if=software/image/microduck_rk3566.img of=/dev/sdX bs=4M status=progress
sync
  1. Configure: after first boot, configure Wi-Fi, SSH, and timezone;
  2. Verify: confirm the system boots and the robotd service runs.

7.2 On-Device Software Architecture

The RK3566 runs a multi-daemon system written in Rust, with this typical structure:

├── robotd           # main control daemon (50 Hz control loop)
├── configd          # configuration service (servo IDs, baud rate, IMU calibration)
├── busd             # servo bus management (TTL communication)
└── webui            # debug WebUI (visualizes IMU / joints / policy output)

Processes communicate via Unix socket + JSON-RPC, with separated responsibilities for independent debugging and fault isolation.

7.3 The 50 Hz Real-Time Control Loop (Core)

The control loop is the key to landing Sim2Real on hardware. Pseudocode:

#![allow(unused)]
fn main() {
loop {
    let t0 = Instant::now();
    // 1. read IMU attitude
    let imu = imu_read();          // quaternion / Euler angles
    // 2. read current servo positions (magnetic-encoder readback)
    let q = servo_read_positions();
    // 3. pack the observation vector (must match the simulation observation space exactly)
    let obs = build_observation(imu, q);
    // 4. ONNX inference to obtain target joint positions
    let action = onnx_infer(&obs); // outputs a 14-dim action
    // 5. write servo target positions
    servo_write_targets(action);
    // 6. hold the 50 Hz (20 ms) period
    let dt = t0.elapsed();
    if dt < Duration::from_millis(20) {
        sleep(20ms - dt);
    }
}
}

⚠️ Observation-space consistency is the single most frequent Sim2Real bug. In simulation the observation vector is 61-dimensional (including IMU, joint positions, velocities, etc.); the observation packed by the on-device firmware must have the same dimension and the same scaling. This book provides the check_obs_act_space.py validation script (see 8.5).

7.4 ONNX Inference Optimization

The RK3566 has limited compute (1 GB RAM), so running ONNX gait inference requires care:

  • Use RKNN/ONNX Runtime for on-device inference;
  • Keep a single inference to a few milliseconds, leaving headroom in the control loop;
  • If high-resolution vision and the RL policy cannot run simultaneously, downgrade or time-share the vision task.

7.5 Observation/Action-Space Validation Script

scripts/validation/check_obs_act_space.py: reads the simulation config and the on-device firmware's observation definition, and automatically compares dimensions and scaling factors.

python scripts/validation/check_obs_act_space.py \
  --sim-cfg experiments/exp02_walk_flat/config.yaml \
  --firmware-src software/firmware/src/obs.rs

Output: any dimension or scaling mismatch raises an error immediately, eliminating the hidden bug of "walks in simulation, walks chaotically on hardware."

7.6 WebUI Debugging

The on-device WebUI provides real-time visualization:

  • IMU attitude curves;
  • per-joint angle readback;
  • policy output (action values);
  • control-loop latency statistics.

During hardware debugging, use the WebUI to observe whether the control loop times out, joints jitter, or attitude drifts.

7.7 Engineering Pitfall Log

  • Control-loop timeout: inference + bus communication exceeding 20 ms causes dropped control frames and gait jitter. Optimize by reducing inference latency and using DMA for batched servo commands.
  • Bus packet loss: servo communication times out, position readback is missing, and the observation vector is filled with garbage data. Add timeout-retransmission and data-validity flags in busd.

7.8 Chapter Summary

You should be able to bring up the RK3566, understand every stage of the 50 Hz control loop, and troubleshoot observation-space consistency and bus timeouts.

The next chapter performs hardware calibration: servo zero positions, IMU six-face calibration, and bench collection of HD1910 dynamics data.

Servo and IMU Calibration

Learning objectives: perform three calibration tasks on the hardware side — servo zero-position calibration, IMU six-face calibration, and HD1910 bench data collection (providing measured data for the BAM parameter fitting in BAM Actuator Modeling and Identification).

8.1 Servo Zero-Position Calibration

The servo's factory center may not match the mechanical zero position. Zero-position calibration procedure:

  1. Send a position-0 command to the servo;
  2. Manually check whether the horn points to the mechanical design zero;
  3. If misaligned, record the offset and write it into configd's offset table;
  4. Calibrate each joint independently and save the offsets to the on-device configuration.
# Example: calibrate a single servo via the configuration service
configd set-servo-offset --id 1 --offset +12

An inaccurate zero position causes policy actions to land in the wrong place, appearing as a "duck standing crooked." This is a hardware prerequisite that must be resolved before Sim2Real.

8.2 Joint-Limit Calibration

Each joint's physical range of motion must be written into both the simulation (MJCF limits) and the board (servo target limits):

  1. Manually drive each joint slowly and record the mechanical hard-stop angles;
  2. Compare against the MJCF limits from Automated Onshape→MJCF Modeling;
  3. If the simulated range exceeds the hardware, the trained policy may command "impossible angles" on the real robot, causing mechanical seizure or servo stall.

8.3 IMU Six-Face Calibration

IMU bias drift is another major source of gait instability. Six-face calibration method:

  1. Place the IMU stationary in six orientations in turn: up, down, forward, backward, left, right;
  2. Collect accelerometer/gyroscope readings for each face and solve for the bias;
  3. Write the IMU calibration parameters to eliminate static drift.
# Example: enter calibration mode and place each of the six faces in turn
robotd imu-calibrate --faces 6

8.4 HD1910 Bench Data Collection (Core; for BAM Fitting)

BAM Actuator Modeling and Identification fits the BAM model using measured data, which requires bench experiments first. Mount the HD1910 on a bench and run four types of tests:

8.4.1 Step-Response Test (to fit bandwidth)

Send a step position command to the servo and record target position, actual magnetic-encoder position, and the time series.

t,target_pos,actual_pos,torque,voltage
0.000,0.0,0.001,0.00,7.4
0.002,0.5,0.003,0.01,7.4
0.004,0.5,0.012,0.02,7.4
...

8.4.2 Torque-Speed Test

Under different loads/voltages, record the maximum sustained torque and no-load speed, used to fit the maximum-torque parameter.

8.4.3 Friction and Backlash Test

  • Rotate slowly in both directions to measure viscous and Coulomb friction;
  • Sweep back and forth to measure the dead-zone/hysteresis (backlash).

8.4.4 Rotor Inertia

Combine the step response with a known load to inversely identify the rotor inertia.

8.5 Bench Data → BAM Parameter Fitting Script

The repository provides scripts/calibration/hd1910_bench_data_process.py:

python scripts/calibration/hd1910_bench_data_process.py \
  --csv data/hd1910_bench/hd1910_step_response.csv \
  --out experiments/exp01_standup/bam_params.json

Output bam_params.json:

{
  "bandwidth_hz": 22.0,
  "b_viscous": 0.0018,
  "tau_coulomb": 0.009,
  "J_rotor": 1.2e-6,
  "servo_model": "HD1910",
  "voltage": 7.4,
  "unit": "SI(kg,m,s,rad)"
}

Fitting algorithm: least-squares fitting of a simplified first-order bandwidth model (scipy.optimize.minimize); see BAM Actuator Modeling and Identification for the code walkthrough.

8.6 Ablation Study Design (recorded in the book)

To quantify the value of calibration, design a comparison:

  • Plan A: train with empirically estimated BAM parameters;
  • Plan B: train with bench-fitted BAM parameters;
  • Compare the transfer success rate on hardware (standing-stability duration, walking success rate).

8.7 Engineering Pitfall Log

  • IMU not six-face calibrated: attitude drifts slowly and the duck stands increasingly crooked. Recovered after calibration.
  • Insufficient bench sampling rate: the step response is too fast for the sampling rate, distorting the bandwidth fit. Re-sample at a higher rate (> 500 Hz).

8.8 Chapter Summary

Completing this chapter, you now have:

  • Calibrated servo zero positions and joint limits;
  • A calibrated IMU;
  • Measured HD1910 bench data suitable for BAM fitting.

The next chapter enters the simulation world: setting up MuJoCo-Warp + mjlab in preparation for training.

The MuJoCo-Warp Simulation Environment

Learning objectives: understand GPU-parallel simulation, resolve the most frustrating environment-deployment issues, and master the definition of the observation and action spaces.

9.1 What MuJoCo-Warp and mjlab Are

  • MuJoCo-Warp (NVIDIA): a GPU-parallel version of the MuJoCo physics engine that can run hundreds of simulation instances simultaneously, greatly accelerating reinforcement learning;
  • mjlab (Pollen's own): a robotics simulation library built on top of MuJoCo-Warp, providing the environment API, actuator models (BAM), and domain-randomization support.

Together they form MicroDuck's training foundation.

9.2 Environment-Deployment Pain Points and the Docker Solution

The original environment has a complex dependency chain, with mjlab, mujoco-warp, and the BAM library tightly version-bound. Common problems:

  • CUDA version mismatch;
  • Python package version conflicts;
  • No native Windows support — only WSL2 / Linux + NVIDIA CUDA GPU;
  • Cannot train on CPU.

The repository's Docker one-command solution resolves these:

cd docker
docker-compose up --build

The companion requirements-lock.txt pins every dependency version, ensuring it "runs even on a different machine."

9.3 Environment Self-Check Script

After every code change, run the simulation-environment self-check first to avoid carrying errors into training:

python scripts/validation/test_env.py
import torch
from mjlab import env

def test_sim_env():
    env = env.MicroDuckEnv(robot="feetech")
    obs, info = env.reset()
    for i in range(200):
        action = torch.zeros((1,14))
        obs, reward, done, trunc, info = env.step(action)
    print("✅ Simulation environment test passed")

if __name__ == "__main__":
    test_sim_env()

9.4 Observation Space and Action Space

MicroDuck's standard interface:

  • Action space: 14-dimensional joint actions (servo target positions), typically normalized to [-1, 1];
  • Observation space: 61-dimensional, including IMU attitude (quaternion/Euler angles), joint positions, joint velocities, and the previous action, etc.

Key convention: actions in simulation are "position commands," not torques. Because the hardware uses position-control servos, simulation must also model position actuators — which leads directly to the BAM model in BAM Actuator Modeling and Identification.

9.5 Parallel Environment Count and Training Speed

# key training configuration parameters
num_envs: 256      # number of parallel simulation instances
control_freq: 50   # control frequency (Hz), must match the board
  • Larger num_envs samples faster but consumes more VRAM; reduce it when VRAM is insufficient;
  • control_freq=50 is a hard constraint, strictly aligned with the RK3566 control loop to guarantee Sim2Real timing consistency.

9.6 Engineering Pitfall Log

  • CUDA version mismatch: the container's CUDA is incompatible with the host driver, and simulation crashes on startup. Resolved by pinning the CUDA version in Docker.
  • Version drift: the environment fails to converge after a dependency upgrade; recovered by reinstalling the version-lock file.

9.7 Chapter Summary

You can now run the simulation environment in the container and understand the observation/action spaces and the 50 Hz timing convention.

The next chapter dives into the BAM servo model — the core of MicroDuck's Sim2Real success and one of the book's most important technical chapters.

BAM Actuator Modeling and Identification

This is one of the book's most important technical chapters. Learning objectives: understand why the BAM (Bandwidth-Aware Motor) model is central to Sim2Real success, learn to fit the HD1910's BAM parameters from bench data, and correctly implement the backlash model.

10.1 Why the Servo Needs a Model

The hardware uses position-control servos, not ideal torque sources. A servo has torque limits, friction, bandwidth, backlash, and response latency. If simulation treats the servo as an ideal "point-and-shoot" actuator, the trained policy will, on hardware:

  • lag behind commands (insufficient bandwidth);
  • jitter (friction/backlash);
  • fall (insufficient torque).

The BAM model is the actuator model that simulates these characteristics accurately — the core of Pollen's original Sim2Real success.

10.2 The Physical Components of the BAM Model

The BAM model contains five key parameters:

ParameterPhysical meaningEffect
Max torque torque_maxthe servo's maximum output torquewhether actions feel "weak"
Rotor inertia J_rotormoment of inertia of motor + gear trainresponse speed
Viscous friction b_viscousproportional to velocitydamping, smoothness
Coulomb friction tau_coulombconstant friction independent of velocityjitter, dead zone
Closed-loop bandwidth bandwidththe servo's upper limit on tracking commandsfailing to keep up

In addition, there is backlash — hysteresis caused by gear clearance.

10.3 Differences Between the Original XL330 and the Feetech HD1910

The original microduck_rl ships Dynamixel XL330-specific parameters (back-EMF, voltage-torque curve, friction, backlash, and response latency, all bench-calibrated). The Feetech HD1910, by contrast, has:

  • different torque constant and rotor inertia;
  • different friction, bandwidth, and backlash characteristics;
  • different voltage characteristics.

Running the original pre-trained model directly on Feetech servos will necessarily fail. The BAM parameters must be re-calibrated and the policy retrained.

10.4 HD1910 Parameter Fitting (Measured vs. Estimated)

Servo and IMU Calibration collected the bench data. Here we fit it with scripts/calibration/hd1910_bench_data_process.py.

10.4.1 Fitting Script Walkthrough

#!/usr/bin/env python3
"""
scripts/calibration/hd1910_bench_data_process.py
Fit BAM model parameters (bandwidth, viscous friction, Coulomb friction, rotor inertia) from bench CSV.
"""
import argparse, json
import pandas as pd, numpy as np
from scipy.optimize import minimize

def bam_model_step(t, params, target):
    """Simplified first-order bandwidth model"""
    w, b, tau_c, J = params
    return target * (1 - np.exp(-w * t))   # first-order response approximation

def loss_fn(params, t, target, measured):
    pred = bam_model_step(t, params, target[0])
    return np.mean((pred - measured)**2)

def fit_bam(csv_path, out_json):
    df = pd.read_csv(csv_path)
    t = df["t"].values
    target = df["target_pos"].values
    actual = df["actual_pos"].values
    x0 = [22.0, 0.003, 0.012, 1.2e-6]     # empirical initial values
    bounds = [(1,60), (1e-6,0.1), (1e-6,0.1), (1e-8,1e-4)]
    res = minimize(loss_fn, x0, args=(t, target, actual),
                   bounds=bounds, method="L-BFGS-B")
    bam_result = {
        "bandwidth_hz": float(res.x[0]),
        "b_viscous": float(res.x[1]),
        "tau_coulomb": float(res.x[2]),
        "J_rotor": float(res.x[3]),
        "servo_model": "HD1910", "voltage": 7.4,
        "unit": "SI(kg,m,s,rad)"
    }
    print(json.dumps(bam_result, indent=2))
    with open(out_json, "w", encoding="utf-8") as f:
        json.dump(bam_result, f, indent=2, ensure_ascii=False)

if __name__ == "__main__":
    p = argparse.ArgumentParser()
    p.add_argument("--csv", required=True)
    p.add_argument("--out", required=True)
    a = p.parse_args()
    fit_bam(a.csv, a.out)

10.4.2 Reference Parameters (replace with measured values)

hd1910_params = {
    "torque_max": 12.0,      # N·cm, HD1910 nominal stall torque @ 12V
    "rotor_inertia": 1.2e-6, # kg·m²
    "damping": 0.0018,       # viscous friction
    "coulomb_friction": 0.009, # Coulomb friction
    "bandwidth": 22,         # Hz, roughly 20–25 Hz
    "backlash": 0.0025,      # backlash (rad)
    "voltage": 12.0
}

10.4.3 Modifying bam_actuator.py

Add to the Feetech branch of software/training/mjlab/actuators/bam_actuator.py:

class FeetechHD1910BAMActuator(FrictionDRBamActuator):
    def __init__(self, **kwargs):
        super().__init__(
            torque_max=12.0, rotor_inertia=1.2e-6,
            damping=0.0018, coulomb_friction=0.009,
            bandwidth=22, backlash=0.0025, voltage=12.0,
            **kwargs
        )

10.5 The Backlash Model: The Easiest Place to Go Wrong

Key design decision: Pollen's original places the backlash at the servo output (the encoder sits after the backlash). This means:

  • the encoder reads the output-shaft position, not the motor-shaft position;
  • the position error caused by backlash enters the observation (feedback) and affects the policy.

The original implements BacklashEncoderBamActuator — the single most important design for Sim2Real success. The replica must implement it in full; otherwise back-and-forth oscillation, jitter, and tracking error will all be mismatched.

⚠️ Backlash is one of the largest contributors to Sim2Real error. Back-and-forth oscillation on hardware is essentially always caused by inaccurate backlash. After fitting, it is recommended to add perturbation to it in domain randomization (see Domain Randomization).

10.6 Ablation Study: Estimated vs. Measured

To demonstrate the value of measured fitting, design a comparison (recorded in the appendix data):

  • Plan A: train with empirically estimated BAM parameters;
  • Plan B: train with bench-fitted BAM parameters;
  • Metrics: hardware standing-stability duration, walking success rate, fall-recovery success rate.

Expected conclusion: measured parameters significantly improve hardware transfer success, especially in walking and rough-terrain scenarios.

10.7 Engineering Pitfall Log

  • Backlash in the wrong place: placing backlash on the motor shaft instead of the output makes the simulated observation inconsistent with the hardware encoder reading, causing back-and-forth oscillation.
  • Distorted bandwidth fit: insufficient bench sampling rate with a fast step response yields an underestimated bandwidth, so the simulated servo "can't keep up." Re-sample at a higher rate (> 500 Hz) and refit.

10.8 Chapter Summary

You can now:

  • understand the BAM model's five core parameters;
  • fit the HD1910's BAM parameters from bench data;
  • correctly implement the backlash model (encoder on the output side).

Next, add domain randomization to training so the policy is robust to parameter error, further shrinking the Sim2Real gap.

Domain Randomization

Learning objectives: understand the principle of domain randomization, learn to extend the randomization parameter set, and combine it with curriculum learning to progress from standing to walking and climbing.

11.1 Why Domain Randomization Is Needed

A simulation model can never reproduce hardware with 100% accuracy. Print infill, servo-parameter error, and ground-material differences all cause "walks in simulation, falls on hardware." Domain randomization addresses this by randomly perturbing simulation parameters during training, so the policy "sees" a wide range of possible conditions and becomes robust to model error.

Pollen's original achieves product-grade Sim2Real through domain randomization (distinguishing flat and rough terrain). The replica project's baseline randomization is too small and must be extended.

11.2 The Extended Domain-Randomization Parameter Set

Extend the domain_rand section of software/training/train_ppo.py:

domain_rand = {
    "mass_scale": [0.85, 1.15],          # link mass ±15% (covers print-infill differences)
    "friction_scale": [0.7, 1.3],         # friction coefficient ±30%
    "actuator_torque_scale": [0.8, 1.2],  # servo max torque ±20%
    "bandwidth_noise": [18, 26],          # servo bandwidth randomized 18–26 Hz
    "backlash_noise": [0.001, 0.004],     # backlash random perturbation
    "imu_noise_std": [0.002, 0.008],      # IMU noise randomization
    "ground_friction": [0.4, 1.2],        # ground friction (carpet / wood floor)
    "gravity_noise": [0.98, 1.02]         # small gravity perturbation
}

Mass randomization mass_scale is especially important: it covers whole-machine mass variation caused by 3D-print infill changes (see Automated Onshape→MJCF Modeling and 3D Printing, Assembly, and Tolerances).

11.3 Wiring Domain Randomization into the Code

On each environment reset(), sample the random parameters once from their distributions and apply them to every step of that episode:

def reset(self):
    # sample this episode's randomization parameters
    self.rand = {
        k: np.random.uniform(*v) for k, v in domain_rand.items()
    }
    # apply to the model: scale mass, friction, etc.
    self.model = self.apply_domain_rand(self.model, self.rand)
    return self.get_obs()

def apply_domain_rand(self, model, r):
    # actually modify the MuJoCo model parameters
    model.body_mass *= r["mass_scale"]
    # friction, torque, etc. handled similarly
    return model

11.4 Curriculum Learning

Full-parameter randomization alone can leave the policy "learning nothing." Curriculum learning progresses from easy to hard, improving convergence stability and final performance:

StageTaskRandomization intensity
1stand in placelow
2squat in placelow
3low-speed walkingmedium
4walking on rough groundmedium
5turningmedium
6climbinghigh

The curriculum advances automatically: once the policy reaches a success-rate threshold on the current stage, the difficulty is raised.

11.5 Reward Smoothing Terms

Beyond domain randomization, the reward function must also suppress jitter. Add an action-smoothing penalty to discourage violent output jumps:

action_smooth_penalty = -0.05 * torch.sum(torch.square(next_action - prev_action), dim=-1)
reward = reward + action_smooth_penalty

11.6 Ablation Study Design (recorded in the book)

To quantify the value of domain randomization, design an ablation:

  • Plan A: no domain randomization;
  • Plan B: mass-only randomization;
  • Plan C: full-parameter domain randomization.

Compare the three on hardware transfer success, and record the results in the appendix experiment data. Expected: C > B > A, with a significant gap especially in walking scenarios.

11.7 Engineering Pitfall Log

  • Over-strong randomization prevents convergence: starting with large full-parameter randomization, the policy cannot learn to stand. Start with low intensity and increase gradually (paired with curriculum learning).
  • Mass randomization not taking effect: the randomization code is not wired to the MuJoCo model — the parameter changed but the simulation didn't. Use a validation script to confirm body_mass is actually modified.

11.8 Chapter Summary

You have mastered: extending the domain-randomization parameter set, wiring it into the reset logic, curriculum progression, and reward smoothing.

The next chapter assembles all of this into PPO multi-task training: from standing to walking, turning, and climbing, all supported by a single policy.

PPO Multi-Task Training

Learning objectives: understand PPO's role in robot locomotion, learn to design multi-task reward functions, implement a single-policy scheme where "one ONNX supports multiple gaits," and master training hyperparameters and export.

12.1 PPO Fundamentals

PPO (Proximal Policy Optimization) is a common algorithm for robot reinforcement learning:

  • it clips between the old and new policies to prevent overly aggressive updates that crash training;
  • it suits continuous action spaces (joint target positions);
  • it has a mature implementation and relatively simple hyperparameters.

MicroDuck's PPO uses MuJoCo-Warp to sample hundreds of environments in parallel, paired with the mjlab training loop.

12.2 Multi-Task, Single-Policy Scheme

The original uses continuous velocity commands. To support multiple gaits, this book adopts a multi-task, single-policy scheme:

append a one-hot task encoding to the observation vector:

EncodingTask
[1,0,0,0,0,0]stand in place
[0,1,0,0,0,0]walk forward
[0,0,1,0,0,0]turn left
[0,0,0,1,0,0]turn right
[0,0,0,0,1,0]self-recover from a fall
[0,0,0,0,0,1]low-speed climbing

The on-device firmware only needs to pass a task id to switch gaits, without loading multiple ONNX models.

12.3 Multi-Task Reward Design

Rewards branch by task. For walking, for example:

forward_reward = torch.clip(obs[:, 0] * 1.2, 0, 1.5)   # forward speed along x
height_reward  = -torch.square(obs[:, 2] - 0.22)        # maintain body height
tilt_penalty   = -(torch.square(obs[:, 3]) + torch.square(obs[:, 4])) # suppress tilt
action_penalty = -0.01 * torch.sum(action**2, dim=-1)   # action penalty
smooth_penalty = -0.05 * torch.sum((action - prev_action)**2, dim=-1)
reward = forward_reward + height_reward + tilt_penalty \
       + action_penalty + smooth_penalty

Reward essentials per task:

TaskKey reward terms
Standingmaintain height, suppress tilt, suppress jitter
Walkingforward speed +, maintain height +, suppress roll
Turningyaw angular velocity +, lateral displacement −
Fall recoverybody elevation +, joint reset, standing reward
Climbingmaintain stability + advance along the slope (see 17.2)

12.4 Training Configuration and Tuning

# key training configuration
num_envs: 256
learning_rate: 3e-4
batch_size: 8192
update_epochs: 10
clip_range: 0.2
task: "multitask"    # multi-task mode
domain_randomization: true
control_freq: 50

Quick tuning reference:

ProblemAdjustment
Not converginglower learning rate, raise reward scale
Action divergenceadd action/smoothing penalties
Training crashreduce clip_range, lower randomization intensity
Overfitting to simulationstrengthen domain randomization

12.5 Exporting the ONNX Policy

After training, export a deployable ONNX:

# export_onnx.py
import torch
from policy import PPOPolicy

policy = PPOPolicy.load("outputs/best_model.pt")
policy.eval()
dummy_input = torch.randn(1, policy.obs_dim)
torch.onnx.export(
    policy, dummy_input,
    "microduck_feetech_multitask.onnx",
    opset_version=17, input_names=["obs"], output_names=["action"]
)

Place the artifact microduck_feetech_multitask.onnx in software/training/pretrained/.

Large-file management: ONNX models are large; use Git LFS rather than committing directly to the main repo (see Engineering Practices and Open-Source Compliance).

12.6 Ready-to-Use Pre-Trained Weights

The repository's pretrained/ should provide pre-trained ONNX models so readers can verify the whole chain out of the box without training from scratch. Each weight must carry:

  • the matching MJCF version;
  • the BAM parameter file;
  • the training configuration;
  • the experiment-log link.

12.7 Engineering Pitfall Log

  • Observation/action scaling mismatch: simulation normalizes to [-1, 1] but the board does not, so hardware actions overflow. Validate with check_obs_act_space.py.
  • Unbalanced multi-task reward weights: the walking reward is too large, so the standing task is ignored. Sample by task per episode to balance training.

12.8 Chapter Summary

You can now: design multi-task rewards, tune PPO, and export and manage ONNX pre-trained weights.

The next chapter handles simulation debugging: methods for locating non-convergence, jitter, and action divergence.

Simulation Debugging and Diagnostics

Learning objectives: learn to observe training with TensorBoard, master methods for locating training failures (non-convergence, jitter, action divergence), and judge whether the problem lies in the reward function, the dynamics, or the observation space.

13.1 Observing Training with TensorBoard

The training process records reward curves, losses, action distributions, and observation statistics:

tensorboard --logdir experiments/exp02_walk_flat/tensorboard

Key metrics:

  • reward: whether it rises overall and whether there are plateaus;
  • action std: whether actions converge (don't diverge);
  • value loss / policy loss: whether they oscillate.

13.2 Locating Common Training Failures

Symptom 1: Non-convergence / reward plateau

Troubleshooting order:

  1. Reward function: is the reward too sparse? Is the signal too small?
  2. Observation: do key states (height, velocity) enter the observation?
  3. Learning rate: too large (oscillation) or too small (too slow)?

Symptom 2: Action jitter / divergence

Troubleshooting order:

  1. Missing action penalty: add action_penalty and smooth_penalty (see 13.3);
  2. High-frequency reward fluctuation: suppress violent actions;
  3. Actuator bandwidth too low: the simulated servo can't keep up (see BAM Actuator Modeling and Identification).

Symptom 3: Always falling

Troubleshooting order:

  1. Dynamics error: wrong MJCF center of mass / inertia (re-check Automated Onshape→MJCF Modeling);
  2. Over-strong domain randomization: too hard to train; lower intensity or pair with curriculum learning;
  3. Reward doesn't encourage standing: add standing and height rewards.

13.3 A Framework for Locating Simulation-vs-Hardware Differences

When "simulation is perfect but the robot walks chaotically," check in priority order:

PriorityCheck itemTool / chapter
1Observation-space consistencycheck_obs_act_space.py (RK3566 Image and Firmware)
2Joint-limit alignmentMJCF limits vs. hardware (HD1910 CAD Model Analysis / Servo and IMU Calibration)
3IMU bias / mountingsix-face calibration (Servo and IMU Calibration)
4BAM parameter accuracybench fitting (BAM Actuator Modeling and Identification)
5Whole-machine mass / center of massweighing vs. CAD (3D Printing, Assembly, and Tolerances)

This framework is the core message the book reiterates: the Sim2Real gap is not a single cause but an entire chain from observation, dynamics, actuation, to sensing, and it must be investigated layer by layer.

13.4 Simulation Self-Check Scripts

After every code change, run the environment self-checks first to keep errors out of training:

python scripts/validation/test_env.py
python scripts/validation/validate_mjcf.py --mjcf software/training/assets/robots/microduck_feetech.xml

13.5 Engineering Pitfall Log

  • MJCF unit error: Onshape exported in millimeters without converting to meters, scaling the model by 1000× and crashing simulation (see Automated Onshape→MJCF Modeling).
  • Reward drowned in noise: the reward signal magnitude is far smaller than action_penalty, so the policy "gives up" and outputs only tiny actions. Adjust the reward weights.

13.6 Chapter Summary

You have mastered the framework for locating training failures, and the layer-by-layer method for "good in simulation, poor on hardware."

The next chapter enters deployment: sending the ONNX policy to the RK3566 board and running the hardware control loop.

Policy Deployment and On-Device Inference

Learning objectives: upload the trained ONNX policy to the board, verify the inference chain, and focus on solving observation/action scaling alignment — the most frequently hit Sim2Real pitfall.

14.1 Deployment Procedure

  1. Upload the ONNX: upload microduck_feetech_multitask.onnx to the RK3566 board:
scp software/training/pretrained/microduck_feetech_multitask.onnx user@rk3566:~/microduck/
  1. Configure the load path: make robotd load that policy file;
  2. Verify loading: confirm the board loads the ONNX and outputs 14 dimensions.

14.2 The On-Device Inference Chain

IMU + joint readback → pack observation (61-dim) → ONNX inference → action (14-dim) → servo target positions

Key: observation space and action scaling must match simulation exactly (see RK3566 Image and Firmware). Actions normalized to [-1, 1] in simulation must be de-normalized on the board to the actual servo position range (radians/degrees) before being sent.

14.3 Observation/Action Scaling Alignment (the Most Common Pitfall)

Three typical bugs:

  1. Dimension mismatch: simulation observation is 61-dimensional but the board packs only 60, causing an inference error or silent misalignment;
  2. Scaling mismatch: simulation uses radians but the board sends degrees, so servos turn the wrong way;
  3. Ordering mismatch: the joint order in the observation differs from the board's readback order, so the policy "can't understand" the data.

Use check_obs_act_space.py for automatic validation to eliminate these hidden bugs (see Section 7.5).

14.4 Verifying the 50 Hz Control-Loop Timing

The control loop must run stably on a 20 ms period:

  • use the WebUI to view each iteration's latency;
  • if inference + bus communication times out, the gait will jitter;
  • optimization: accelerate inference with RKNN and batch servo commands with DMA.
# check control-loop latency statistics on the board
robotd status
# expected output: control_loop_avg_ms < 20

14.5 First Power-On Deployment Steps (Safe)

  1. Stand first: load the standing task and observe whether the duck stands stably;
  2. Then squat/reset: confirm actions stay within physical limits;
  3. Finally walk: test walking only after stability is confirmed.

At each stage observe: jitter, drift, and any exceeding of joint limits.

14.6 Engineering Pitfall Log

  • Action not de-normalized: the [-1, 1] simulation action was sent directly as a position, driving the servo out of its physical limits and seizing the mechanism. Add de-normalization + clamping.
  • Observation ordering misaligned: the board's joint readback order differs from the simulation training order, so policy behavior is abnormal. Use automatic validation + single-joint excitation tests to align them.

14.7 Chapter Summary

You have deployed the ONNX policy to the board, run the 50 Hz control loop, and specifically resolved observation/action scaling alignment.

But "it runs" does not mean "it walks well." The next chapter performs real-robot gait iteration to tune Sim2Real in closed loop.

The Sim2Real Closed-Loop Iteration

Learning objectives: master the hardware testing procedure, methods for diagnosing jitter/drift/falling, and implement the closed-loop iteration of "simulation training → hardware testing → data collection → model correction → retraining." This is the ultimate engineering capability of Sim2Real.

15.1 Hardware Testing Tiers

StageTaskPass criterion
1Standingstands stably for 30 s with no sustained drift
2Squat / resetaction within limits, no seizure
3Turn in placerotates about the vertical axis without tipping
4Walk on flat groundstraight-line progress, no jitter
5Fall recoverystands up on its own after falling

15.2 Diagnosing Jitter, Drift, and Falling on Hardware

Symptom A: Sustained jitter

Troubleshooting order:

  1. BAM parameters: inaccurate bandwidth/backlash → re-calibrate (BAM Actuator Modeling and Identification);
  2. Action smoothing: reward function missing the smoothing penalty → retrain;
  3. Control-loop timeout: inference too slow, unstable control period (see Policy Deployment and On-Device Inference).

Symptom B: Attitude drift (slowly tilting)

Troubleshooting order:

  1. IMU bias: not six-face calibrated → Servo and IMU Calibration;
  2. IMU mounting tilt: not compensated → add compensation in firmware;
  3. Center-of-mass offset: asymmetric assembly → re-weigh per 3D Printing, Assembly, and Tolerances.

Symptom C: Frequent falling

Troubleshooting order:

  1. Observation/action scaling: dimension or scaling misaligned → check_obs_act_space.py;
  2. MJCF inertia error: wrong center of mass → Automated Onshape→MJCF Modeling;
  3. Whole-machine mass differs from simulation: different infill → cover via domain randomization or re-calibrate.

15.3 Hardware Data Collection (the Key to the Closed Loop)

Record IMU, joint angles, policy output, and timestamps on hardware, saving to data/real_robot_logs/:

t,imu_qw,imu_qx,imu_qy,imu_qz,q0,...,q13,a0,...,a13

This data is the basis for system identification and parameter correction, and the source of the book's appendix experiment data.

15.4 Reverse System Identification (Advanced Closed Loop)

Use hardware excitation data to inversely identify the whole-machine inertia and correct the bias in the CAD-exported model:

  1. Apply excitation to the robot (small oscillation, step);
  2. Record the IMU + joint response;
  3. Inversely fit the true mass/center of mass/inertia via least squares;
  4. Write the identification result back to MJCF and retrain.
# script: scripts/calibration/system_id_fit.py
# input: hardware excitation CSV + current MJCF
# output: recommended corrected inertia parameters

This is an advanced academic Sim2Real technique that corrects residual errors (printing, assembly) left by Onshape geometric computation.

15.5 The Closed-Loop Iteration Process

simulation training → ONNX export → hardware test
                        ↓ (collect data)
                diagnose → correct BAM/MJCF/domain randomization
                        ↓
                  retrain → re-test (iterate)

Record each iteration cycle in experiments/, forming a reproducible iteration history.

15.6 Gait Performance Metrics

To quantify progress, define metrics:

  • walking speed (m/s);
  • standing-stability duration;
  • disturbance robustness (can it recover from a push);
  • fall-recovery success rate;
  • turning-angle accuracy.

These metrics are compared against the original Pollen MicroDuck, forming the book's performance-evaluation material (extended in Task Extension).

15.7 Engineering Pitfall Log

  • Changing everything in one iteration: BAM, MJCF, and reward were all changed at once, so the problem still couldn't be located. Change only one variable at a time and record each result.
  • Hardware data without timestamps: IMU and joint timelines can't be aligned. Synchronize clocks before collection.

15.8 Chapter Summary

You have mastered hardware gait diagnosis and the closed-loop iteration, and can continuously bring the simulation model closer to the real robot.

The next chapter extends tasks, turning MicroDuck from "able to walk" into "able to walk in many ways."

Task Extension

Learning objectives: on top of basic walking, implement three advanced tasks — turning, climbing, and obstacle avoidance — turning a "straight-line walker" into a duck that "walks in many ways."

16.1 Turning Gait

On the basic walking task, change the reward from "forward along x" to "drive about the yaw angular velocity":

yaw_rate = obs[:, yaw_vel_idx]        # angular velocity about the vertical axis
turn_reward = clip(target_yaw_speed * yaw_rate, 0, 1.0)
# suppress lateral slip
lateral_penalty = -torch.abs(obs[:, yaw_vel_idx_side])
reward = turn_reward + lateral_penalty + stance_rewards

Hardware verification: the duck turns in place to a specified angle without tipping or slipping.

16.2 Climbing Slopes

16.2.1 Building the Slope Environment

In MuJoCo, turn the ground into a slope, or add a sloped geom in the MJCF:

<geom type="box" size="..." pos="..." quat="..."/>
<!-- or tilt the ground -->

16.2.2 Climbing Reward

The difficulty of climbing is advancing along the slope's projection + maintaining stability:

slope_forward = obs[:, proj_along_slope_idx]
reward = clip(slope_forward * 1.0, 0, 1.0) + stability_terms

Pair with curriculum learning: flat ground first, then a small incline (5°), gradually up to 15° (see Domain Randomization).

16.2.3 Hardware Verification

Test climbing on a wooden block or incline pad, observing slipping and backward tipping. Ground-friction domain randomization is especially critical in this scenario.

16.3 Obstacle Avoidance (Advanced)

16.3.1 Visual Perception Integration

The RK3566 has limited compute (1 GB) and cannot run high-resolution vision + RL policy simultaneously. Recommended degraded schemes:

  • use a lightweight YOLO (e.g., YOLOv5-nano / YOLO11-nano) for obstacle detection;
  • output only low-dimensional information ("obstacle ahead or not, distance") into the observation vector;
  • or time-share: low-frequency vision (e.g., 5 Hz) with high-frequency RL control (50 Hz).

16.3.2 Avoidance Reward

if obstacle_detected:
    reward += turn_away_reward   # encourage turning away
else:
    reward += forward_reward     # advance when clear

16.3.3 Limitations

  • The visual closed loop is an advanced extension of this book, involving camera selection, calibration, and vLA/perception-policy integration, and is a substantial workload;
  • The book's main chain completes "body balancing + walking/turning/climbing," with visual avoidance as an optional extension.

16.4 Combined Multi-Task Training

Merge turning and climbing into the PPO Multi-Task Training multi-task one-hot encoding, so one ONNX supports all behaviors:

EncodingTask
[0,1,0,0,0,0]walk forward
[0,0,1,0,0,0]turn left
[0,0,0,1,0,0]turn right
[0,0,0,0,1,0]self-recover from a fall
[0,0,0,0,0,1]climbing

16.5 Engineering Pitfall Log

  • Backward tipping while climbing: the reward only rewards forward progress, not center-of-mass stability, so the duck tips backward on slopes. Add a center-of-mass-projection reward.
  • Slip while turning: ground friction is too low, causing lateral slip during turns. Strengthen ground-friction domain randomization to train more robust turning.

16.6 Chapter Summary

You have implemented three extended tasks — turning, climbing, and obstacle avoidance (advanced) — advancing MicroDuck from "able to walk" to "able to walk in many ways."

The next part enters engineering and open-source compliance: how to make your entire project a standardized, compliant, reproducible open-source repository.

Engineering Practices and Open-Source Compliance

Learning objectives: turn the entire project into a standardized, reproducible, open-source-compliant repository. Covers branch management, documentation engineering, automated testing, and open-source licensing.

17.1 Fork Workflow and Branch Management

A correct branch strategy avoids "upstream-sync conflicts":

main            # upstream tracking branch, only syncs fanhao375/microduck-replica updates
book-dev        # the book's main development branch (manuscript, scripts, Docker, experiments)
feature/cad2mjcf     # feature branches, merged into book-dev on completion
feature/bam-id
feature/docker

Why separate them:

  • main stays close to upstream, making upstream updates easy to pull;
  • all of your customizations (removing contact info, adding English docs, changing RL code) go into book-dev;
  • on upstream updates, sync main, then merge into book-dev with minimal conflicts.

Upstream Sync Procedure

git fetch upstream
git checkout main
git merge upstream/main
git checkout book-dev
git merge main   # resolve any conflicts that arise

17.2 Documentation Engineering

Repository documentation layers:

  • README.md: Chinese quick start;
  • README_EN.md: English version;
  • book/: this book's mdbook manuscript;
  • docs/tutorials/: standalone step-by-step tutorials (not embedded in the manuscript);
  • docs/engineering_log/: engineering pitfall logs (manuscript material).

Consider adding a bilingual README_EN.md — an improvement missing from the original replica and part of your plan.

17.3 Automated Testing and CI

.github/workflows/test-sim.yml: on every commit, load the MJCF and validate the model, keeping errors out before merging.

name: Sim Validate
on: [push, pull_request]
jobs:
  test-mjcf:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: "3.10" }
      - run: pip install mujoco
      - run: python scripts/validation/validate_mjcf.py --mjcf software/training/assets/robots/microduck_feetech.xml

build-book.yml: mdbook auto-compilation, deploying the GitHub Pages web book.

17.4 Experiment-Management Convention

All training experiments go into experiments/; each experiment folder must contain:

  1. config.yaml: training config, domain randomization, BAM parameters;
  2. mjcf/: MJCF snapshot;
  3. bam_params.json: servo parameters;
  4. logs/ + tensorboard/;
  5. readme.md: goal, ablation variables, results, failure analysis.

Guaranteeing that every experiment is reproducible and traceable is the core of engineering and of the book's case studies.

17.5 Managing Large Files with Git LFS

ONNX, STL, STEP, CSV, and TensorBoard logs are large; use Git LFS:

# .gitattributes
*.onnx filter=lfs diff=lfs merge=lfs -text
*.stl   filter=lfs diff=lfs merge=lfs -text
*.step  filter=lfs diff=lfs merge=lfs -text
*.csv   filter=lfs diff=lfs merge=lfs -text

17.6 Open-Source Licensing Details (Must Comply)

ContentLicenseCommercial restriction
Software code (training/firmware)Apache 2.0✅ commercial use allowed
Mechanical CAD models (replica-cad)CC BY-NC-SA❌ commercial use prohibited
Book manuscriptCC-BY 4.0free to share, attribution required

Fork Compliance Essentials

  1. Do not remove LICENSE files or the original authors' attribution statements;
  2. May remove private contact info (WeChat, email) from the README;
  3. Keep source attribution: derived from pollen-robotics/microduck_rl and fanhao375/microduck-replica;
  4. Do not erase the source or claim complete originality;
  5. For a commercial product, you must independently design the mechanical structure from scratch, independent of the CC BY-NC-SA models.

Image Compliance

Prefer images produced by your own experiments; cite original Pollen images cautiously to avoid image-copyright issues.

17.7 Engineering Pitfall Log

  • Editing main directly: a pile of conflicts after upstream updates. Switching to book-dev + feature branches greatly reduced conflicts.
  • Unpinned versions: the environment broke after dependency upgrades. Pin with requirements-lock.txt.

17.8 Chapter Summary

You have mastered branch management, documentation engineering, CI, experiment management, Git LFS, and open-source licensing compliance.

The final chapter looks ahead: hardware upgrades, algorithm advances, and commercialization boundaries.

Outlook and Future Directions

Learning objectives: point readers to the advanced paths beyond MicroDuck — hardware upgrades, algorithm advances, and commercialization boundaries. This chapter is an open outlook, not a full implementation.

18.1 Hardware Upgrade Directions

DirectionDescription
Higher-compute boardsRK3588 / edge GPUs, supporting high-resolution vision + RL in parallel
Depth camerasintegrate RGB-D for dense perception and obstacle avoidance
Hand end-effectorsadd degrees of freedom and explore grasping/manipulation
Higher-performance servosswitch to higher torque/bandwidth bus servos to extend load capacity

Upgrade note: changing servos changes the whole-machine dynamics; MJCF inertia and BAM parameters must be re-calibrated (return to Automated Onshape→MJCF Modeling and BAM Actuator Modeling and Identification).

18.2 Algorithm-Advance Directions

18.2.1 Online Adaptation

Fine-tune the policy on hardware using real-time data to further shrink the Sim2Real gap:

  • residual policy: simulation learns the baseline, hardware learns the correction;
  • online domain adaptation: update dynamics assumptions in real time.

18.2.2 Multi-Modal Perception Policies

  • fuse vision + proprioception, moving toward vLA (vision-language-action);
  • use spatial VLMs to guide arm/body motion and achieve semantic-level tasks.

This is the "embodied intelligence" direction; its workload and research depth far exceed the book's main chain, and it is offered as an advanced topic.

18.3 Performance Evaluation and Benchmarking

Establish a quantitative metric system and compare against the original Pollen MicroDuck:

  • walking speed;
  • disturbance robustness;
  • fall-recovery success rate;
  • energy consumption.

The comparison data can serve as material for an upgraded edition or a paper, validating the competitiveness of the domestic Feetech solution.

18.4 Commercialization Boundaries (Important Compliance Reminder)

  1. Software is commercializable: the Apache 2.0 training/firmware code may be used commercially;
  2. CAD is not commercializable: the CC BY-NC-SA mechanical models prohibit commercial use — a clean independent design is required;
  3. Brands and trademarks: do not misuse the Pollen/MicroDuck trademarks;
  4. For a commercial product, independent design + self-developed software are required, independent of the open-source CAD models.

This is consistent with the licensing boundaries in Engineering Practices and Open-Source Compliance. Commercialization is a direction, but it must be built on compliant reconstruction.

18.5 Community Collaboration and Continuous Iteration

  • maintain docs/engineering_log/, recording every pitfall;
  • keep Issues / PRs open and iterate with the community;
  • keep the manuscript and repository in sync so readers can reproduce every version.

18.6 Chapter Summary

The book's main chain (mechanics → simulation → training → hardware closed loop) is now complete. This chapter points to advanced directions: hardware upgrades, algorithm adaptation, performance benchmarking, and compliant commercialization.


This concludes the nineteen chapters across six parts. Appendices A–E provide the code inventory, BOM, troubleshooting handbook, glossary, and references.

Code Inventory

All code, scripts, and configuration accompanying this book, indexed by repository path. All code follows the repository's book-dev branch.

A.1 Simulation and Training Code (software/training/)

FilePurposeChapter
mjlab/actuators/bam_actuator.pyBAM servo model (HD1910 parameters)BAM Actuator Modeling and Identification
assets/robots/microduck_feetech.xmlFeetech-edition MJCF modelAutomated Onshape→MJCF Modeling, 9
train_ppo.pyPPO training main script (with domain randomization)Domain Randomization, 12
export_onnx.pyexport the ONNX policyPPO Multi-Task Training
test_env.pysimulation-environment self-checkThe MuJoCo-Warp Simulation Environment
requirements.txt / requirements-lock.txtdependency listThe MuJoCo-Warp Simulation Environment

A.2 Calibration and System Identification (scripts/calibration/)

FilePurposeChapter
hd1910_bench_data_process.pybench CSV → BAM parameter fittingServo and IMU Calibration, 10
system_id_fit.pyhardware data → inertia-parameter identificationThe Sim2Real Closed-Loop Iteration

A.3 CAD Export (scripts/cad2mjcf/)

FilePurposeChapter
onshape_config.jsonOnshape assembly configurationAutomated Onshape→MJCF Modeling
export_mjcf.pyone-command onshape-to-robot exportAutomated Onshape→MJCF Modeling
validate_mjcf.pyMJCF inertia/limit validationAutomated Onshape→MJCF Modeling

A.4 Validation Scripts (scripts/validation/)

FilePurposeChapter
check_bam_params.pyBAM parameter physical-sanity checkBAM Actuator Modeling and Identification
check_obs_act_space.pysimulation ↔ board observation-space comparisonRK3566 Image and Firmware, 14
mass_inertia_check.pywhole-machine mass/inertia validation3D Printing, Assembly, and Tolerances

A.5 Container and Configuration (docker/)

FilePurposeChapter
DockerfileGPU training environment imageThe MuJoCo-Warp Simulation Environment
docker-compose.ymlone-command startupThe MuJoCo-Warp Simulation Environment

A.6 Example Experiment Configurations (experiments/)

DirectoryPurposeChapter
exp01_standup/config.yamlstanding training configMinimal Simulation Example
exp02_walk_flat/config.yamlflat-ground walking configPPO Multi-Task Training
exp03_domain_rand/config.yamldomain-randomization ablationDomain Randomization
exp04_curriculum/config.yamlcurriculum-learning configDomain Randomization

A.7 On-Device Firmware (software/firmware/)

Rust multi-daemon system: robotd (main control loop), configd (configuration), busd (bus), webui (debug interface). See RK3566 Image and Firmware.

Parts Store and Procurement Guide

This chapter is synchronized with the official parts store: https://www.wwntai.com/parts.html Prices and stock are subject to the official site in real time; the product images below are all from the official store.

Source your parts before replicating MicroDuck: this chapter brings the store's components and accessories (servos, mainboards, batteries, cameras, etc.) into the book with images and descriptions, so readers can one-stop procure against the BOM.

19.1 In-Stock Parts (IN STOCK · ships within 7 days)

Radxa ZERO 3W Mainboard

Radxa ZERO 3W mainboard

2 GB / no eMMC / with pin headers. An ultra-compact RK3566 single-board computer with WiFi 6 + USB 3.0 + MIPI CSI, suited to IoT and edge computing.

ItemSpecification
ProcessorRK3566 quad-core Cortex-A55 @ 1.6 GHz
GPUMali-G52-2EE (Vulkan 1.1 / OpenCL 2.0)
Memory2 GB LPDDR4
StorageMicroSD card (no onboard eMMC)
WirelessWiFi 6 + Bluetooth 5.4
InterfacesUSB 3.0 + USB 2.0 OTG (Type-C)
DisplayMicro HDMI 1080p60
CameraMIPI CSI (22-pin)
Dimensions65 × 30 mm · Debian/Ubuntu

¥385 · Buy now

Radxa Camera 8M 219

Radxa Camera 8M 219

Sony IMX219 · 8 megapixels. A high-resolution camera module whose stock FPC cable matches the ZERO 3W/3E, plug-and-play.

ItemSpecification
SensorSony IMX219, 8 MP
Resolution3280 × 2464
Frame rateup to 30 fps (full pixel)
Lensfocal length 2.95 mm · aperture F2.5
Field of viewD74° H62° V49° · distortion < 0.3%
Cable150 mm (22-pin, 0.5 mm)
Applicationsface recognition · license-plate recognition · lane-line recognition

¥180 · Buy now

Radxa ZERO 3E PoE HAT

Radxa ZERO 3E PoE HAT

IEEE 802.3af/at. A Power-over-Ethernet expansion board that delivers power and networking over a single cable, simplifying wiring.

ItemSpecification
StandardIEEE 802.3af/at
FunctionPower + data over a single Ethernet cable
Connection40-pin GPIO stacking
Dimensions65 × 30 mm
Accessoriesstandoffs ×4 + screws ×8
Noterequires a PoE switch/router

¥118 · Buy now

HD-1910-C001 Serial-Bus Servo, 15-Pack

HD-1910-C001 serial-bus servo

FEETECH coreless serial-bus servo, dedicated for open-source AI, suited to the joints of MicroDuck and other biomimetic robots. 12 kg·cm stall torque at 6 V, 12-bit magnetic-encoder 360° position feedback, TTL bus daisy-chaining (see Introduction: Pollen MicroDuck and Open-Source Embodied Intelligence, Servo and IMU Calibration, and BAM Actuator Modeling and Identification for details).

¥1380 · Buy now

FE-URT2-C001 Debug Board + Cables

FE-URT2-C001 debug board

Feetech USB-to-TTL/485 bus debug board (Type-C · 2.54 mm header), with an AMP2.0 dual-ended adapter cable, for servo ID configuration and bus debugging.

¥49.5 · Buy now

VL53L8CX ToF Module

VL53L8CX ToF module

ST 8×8 multi-zone Time-of-Flight ranging sensor: 64-zone simultaneous detection, 65° field of view, range up to 400 cm, enabling obstacle avoidance, gesture recognition, and depth sensing.

¥54.9 · Buy now

Viltrox NP-F550 Battery Pack

Viltrox NP-F550 battery pack

VILTROX NP-F550 lithium battery: 2200 mAh / 7.4 V, USB-C direct charging in ~2 hours, 4-segment LED charge indicator, dimensions 70.7×38.5×25 mm, ~110 g, hot-swappable.

¥49 · Buy now

Speaker Module

Speaker module

A speaker module that lets the robot duck "speak," supporting voice feedback and alert tones.

¥5.9 · Buy now

EZVIZ 64 GB High-Speed TF Card for Surveillance

EZVIZ 64 GB TF card

EZVIZ 64 GB memory card, a high-speed card dedicated to surveillance and video recording, with 90 MB/s read speed.

¥60 · Buy now

Standard Hardware Kit (bearings · screws · threadlocker · anti-slip pads)

ContentsQuantity
Bearing 10×15×3×3
Bearing 16×22×4×11
Bearing 6×12×3 (roller-skate)×4
Self-tapping screw, flat-end M2×5×1 pack
Self-tapping screw, flat-end M2×6×1 pack
Self-tapping screw, flat-end M2×8×1 pack
Self-tapping screw, flat-end M2.5×6×1 pack
Self-tapping screw, flat-end M2.5×8×1 pack
Loctite threadlocker 243×1
Sole anti-slip pads×1

¥99 · Buy now

Full-Assembly Service

A one-stop service for kit assembly + first-run debugging. Professional engineers assemble, flash, and verify the first run, so the robot works out of the box — ideal for users who want peace of mind.

¥699 · Buy now

19.2 MicroDuck Domestic-Edition Parts (Coming Soon)

Components and expansion accessories for the open-source bipedal robot duck, friendly to individual developers.

Complete Kit

Complete kit

All MicroDuck parts in one package: 3D-printed structural parts, electronics, 15 HD-1910-C001 servos, RK3566 mainboard, and NP-F550 battery pack. Includes a bilingual (Chinese/English) assembly tutorial — from parts to a walking robot duck, assemble out of the box.

¥2580 · Coming soon

3D-Printed Structural Parts Kit

3D-printed structural parts kit

Full shell + skeleton structural parts, with FDM / resin (SLA) options available; all drawings fully open-sourced. A public list of tolerance and interference issues means print-and-assemble with a high success rate.

¥128 · Coming soon

Roller-Skate Kit

Roller-skate kit

A roller-skate kit that upgrades the robot duck from "walking" to "rolling," unlocking roller behaviors for faster, smoother motion.

¥49 · Coming soon

Game Controller

A Bluetooth controller, playable with zero code. Connect and remotely drive the robot duck to walk and kick a ball — instantly a remote-control toy.

¥79 · Coming soon

Electronics

  • imu_to_dxl board: an IMU-to-Dynamixel protocol bridge board, converting attitude data for the microduck-replica open-source solution. Price TBD.
  • Banana PCB + banana-plug PCB (gold-plated copper): 2.5 mm banana-plug PCB (gold-plated copper) ×2 + banana PCB (JLC) ×1. Price TBD.

19.3 Coming Soon

ProductStatus
Radxa ZERO 3W 1 GBComing soon
Radxa ZERO 3W 4 GBComing soon
Radxa ZERO 3W 8 GBComing soon
Radxa ZERO 3E (gigabit Ethernet version)Coming soon

19.4 How to Order

  1. Click to buy: on the store card, click "Buy now," which auto-fills the selected part;
  2. Pay via Alipay QR: verify the amount, scan to pay, and record the transfer number;
  3. Submit the order form: fill in the transfer number and send the order details to customer service; after confirmation, shipping is arranged.

Join the Parts Community Group (ordering / Q&A)

MicroDuck Parts (Mainboard, Servo Group 2) WeChat group QR code

MicroDuck Parts (Mainboard, Servo Group 2) · Order at: https://wwntai.com

Scan with WeChat or WeCom to join.

⚠️ The WeChat group QR code expires automatically after 7 days (this image is valid until 2026-10-31). After expiry, visit https://www.wwntai.com/parts.html for the latest QR code, or open a GitHub issue to update it.

19.5 A Note from the Founder

The MicroDuck Parts Store · For anyone who has hit the same pitfalls

In open-source robotics, the most grinding part is often not the code, but the parts.

A part suddenly goes out of stock, and after two weeks you find it cannot ship; the camera cable you bought doesn't match the mainboard; the servo specs look right, but after installing it you discover the protocol is incompatible; to assemble a full set of fasteners you visit three shops and pay three shipping fees, only to find one screw still missing. We have been through all of this ourselves.

The MicroDuck Parts Store was never a platform we planned from the start; it is more like a shelf gradually forced into existence by those pitfalls. Our capabilities are limited — we can't do everything — so we focus on doing one thing as well as we can: helping individual developers who are reproducing open-source robots avoid one more selection headache and one more wasted trip.

A few things we are working hard to do

  • Being upfront about stock status. In-stock parts are marked "ships within 7 days"; coming-soon items are announced in advance, so nobody places an order and then discovers an indefinite wait. Unstable supply is the reality, and we choose to state that reality up front.
  • Spelling out compatibility. Which board a camera cable fits, which joint a servo suits, what prerequisites a PoE HAT requires, exactly how many screws of what size are in the hardware kit — we don't hide these details, because developers know better than anyone what one wrong choice costs.
  • Showing where quality comes from. Sensor models, servo brands, battery specs, TF-card uses — we publish the key parameters as openly as we can. We don't claim every item is the optimal choice, but at least you know what you are buying.
  • Consolidating scattered purchases into one order. The complete kit, structural parts, electronics, standard hardware, and optional accessories are listed together with clear prices and one-click ordering. The full-assembly service is an extra option for those who want peace of mind, not a requirement.

What the store has now

In-stock and orderable today: the Radxa ZERO 3W mainboard, the 8M 219 camera, the PoE HAT, the 15-pack of HD-1910-C001 servos, the debug board, the VL53L8CX ToF module, the NP-F550 battery pack, the speaker module, the 64 GB high-speed TF card, the standard hardware kit, and the full-assembly service.

Coming soon: the MicroDuck domestic-edition complete kit, the 3D-printed structural-parts kit, the roller-skate kit, the game controller, the imu_to_dxl board, the banana-plug PCB, and the ZERO 3W 1 GB/4 GB/8 GB and ZERO 3E gigabit-Ethernet versions. The structural-part drawings are fully open-sourced, and the tolerance-and-interference issue list is public too — a slightly higher reproduction success rate is the sincerity we can offer.

The purchase path is kept simple: click to buy → pay via Alipay QR code → fill in shipping details and the transfer number → copy the order to customer service.

A few honest words

We know this store is still far from perfect. The selection isn't large enough, some parts are still on the way, and customer service may not always be on call. But it has been built up piece by piece around real reproduction scenarios, and every parameter, every image, and every "coming soon" came from a concrete problem we hit while building our own machines.

If, during purchasing or assembly, you find something written wrong, something missing, or something that could be clearer, please tell us directly. Individual developers already have a hard enough time doing hardware; if this little shelf can save you a bit of time, that is the meaning of what we do.

—— Chi Ching Ip (Henry Ip), CEO of WWNT Robotics

The MicroDuck Parts Store — we are still learning, and we'll try our best not to let those who come later step into the same pit again.

BOM Procurement List

Complete bill of materials, with recommended procurement channels and alternative substitutes. Prices are reference only and fluctuate with the market.

B.1 Core Electronics

PartSpecQtyReference unit priceProcurement advice
ServoFeetech HD1910 (dual-shaft magnetic-encoder TTL)14–15low–midFeetech official / authorized distributor
MainboardRK3566 board1midauthorized channel
IMUMPU6050 / ICM209481lowgeneric module
Battery2S/3S lithium1lowpair with BMS
BMSlithium protection board1lowwith low-voltage / over-current protection

B.2 Structure and Fasteners

PartSpecQtyNotes
3D-printed partsPLA1 set20%–40% infill
M2 screwsseveralservo-horn fastening
M3 screwsseveralstructural fastening
Washers / bearingsseveralfriction reduction, positioning

B.3 Wiring and Miscellaneous

PartNotes
Servo TTL bus cabledaisy-chains 15 servos; use shielded cable to reduce interference
Thick power wireservo power, from BMS
Cable ties / heat-shrinkwiring fixation

B.4 Tiered Procurement Advice

Three tiers by budget:

PackageContentsPurpose
Minimal simulation packageGPU computer onlyrun simulation, no hardware needed
Hardware-in-the-loop packageRK3566 + IMU + a few servosvalidate bus / calibration
Full machine packagefull BOMcomplete assembly and deployment

It is recommended to first procure the hardware-in-the-loop package to validate bus communication and calibration, then move to the full machine, reducing one-time investment risk.

B.5 Cost Comparison (Reference)

PlanMain cost
Original MicroDuck399 USD + forwarding/customs
Domestic Feetech full machineservo + board + printing + misc., significantly lower

The domestic solution's core value is low cost + domestic supply + controllability; concrete numbers fluctuate with procurement channels, and the book's main text defers to actual purchases.

Troubleshooting Handbook

A quick reference to troubleshooting across the book, indexed by symptom. Each entry gives the most likely cause and the corresponding chapter.

C.1 Simulation-Side Faults

SymptomLikely causeHandlingChapter
Simulation crash / numerical explosionMJCF unit error / non-positive-definite inertiacheck units, validate_mjcf.pyAutomated Onshape→MJCF Modeling
Falls immediately on startupwrong center of mass / inertiare-check CAD→MJCFAutomated Onshape→MJCF Modeling
Violent joint jittermismatched BAM parametersre-calibrate on the benchBAM Actuator Modeling and Identification
CUDA out of memorynum_envs too largereduce num_envsThe MuJoCo-Warp Simulation Environment
Training not convergingsparse reward / poor learning ratetune reward, lower LRPPO Multi-Task Training
Action divergencemissing action/smoothing penaltyadd penaltiesPPO Multi-Task Training

C.2 Hardware-Side Faults

SymptomLikely causeHandlingChapter
A servo doesn't respondID conflictreconfigure the IDHardware Circuits and the TTL Bus
Random bus packet losssignal interferencelower baud rate, add isolationHardware Circuits and the TTL Bus
Freezes on power-oninsufficient power / shortseparate power, test one by oneHardware Circuits and the TTL Bus
Position driftsupply voltage sagcheck BMS, wire gaugeHardware Circuits and the TTL Bus
Gait jitterinaccurate BAM / control-loop timeoutre-calibrate / optimize inferenceBAM Actuator Modeling and Identification, 14
Attitude slowly tiltingIMU bias / mounting tiltsix-face calibration / compensate tiltServo and IMU Calibration
Frequent fallingobservation scaling misalignedcheck_obs_act_space.pyRK3566 Image and Firmware, 14

C.3 Sim2Real Difference Troubleshooting (Priority Order)

PriorityCheck itemTool
1Observation-space consistencycheck_obs_act_space.py
2Joint-limit alignmentMJCF vs. hardware
3IMU bias / mountingsix-face calibration
4BAM parameter accuracybench fitting
5Whole-machine mass / center of massweighing vs. CAD

Principle: change only one variable at a time and record each result, avoiding the inability to locate the cause from changing multiple factors at once.

C.4 Mechanical-Side Faults

SymptomLikely causeHandlingChapter
Servo horn slippinginsufficient interferencereplace horn / add adhesive3D Printing, Assembly, and Tolerances
Joint seizureprint interferencecorrect CAD clearanceHD1910 CAD Model Analysis
Center-of-mass offsetasymmetric assemblycheck left-right consistency3D Printing, Assembly, and Tolerances
Printed part fractureinsufficient wall thickness/infillthicken, raise infill3D Printing, Assembly, and Tolerances

Glossary

TermFull name / explanationChapter
Sim2RealSimulation-to-Real transfer, the core paradigmthroughout
BAMBandwidth-Aware Motor, a bandwidth-aware servo actuator modelBAM Actuator Modeling and Identification
MJCFMuJoCo robot-modeling file formatAutomated Onshape→MJCF Modeling
PPOProximal Policy Optimization algorithmPPO Multi-Task Training
Domain Randomizationrandomly perturbing simulation parameters during trainingDomain Randomization
Curriculum Learningprogressing training from easy to hardDomain Randomization
ONNXOpen Neural Network Exchange, a model-interchange formatPPO Multi-Task Training, 14
MuJoCo-WarpNVIDIA GPU-parallel physics simulationThe MuJoCo-Warp Simulation Environment
mjlabPollen's in-house robotics simulation libraryThe MuJoCo-Warp Simulation Environment
TTL bushalf-duplex serial communication bus (used by servos)Hardware Circuits and the TTL Bus
Backlashhysteresis caused by gear clearanceBAM Actuator Modeling and Identification
Randomization intensitythe range of the randomly perturbed parametersDomain Randomization
Sim2Real gapthe dynamics gap between simulation and realitySimulation Debugging and Diagnostics, 15
System identificationinversely identifying true parametersThe Sim2Real Closed-Loop Iteration
RKNNRK-platform neural-network inference toolkitRK3566 Image and Firmware, 14
BMSBattery Management SystemHardware Circuits and the TTL Bus
onshape-to-robotCAD→MJCF automatic export toolAutomated Onshape→MJCF Modeling
Observation spacethe sensor-data vector fed to the policyThe MuJoCo-Warp Simulation Environment, 12
Action spacethe control-command vector output by the policyThe MuJoCo-Warp Simulation Environment, 12

References and Project Index

E.1 Open-Source Projects

ProjectURL
Pollen microduck_rlhttps://github.com/pollen-robotics/microduck_rl
Pollen microduck (firmware)https://github.com/pollen-robotics/microduck
Pollen mjlabhttps://github.com/pollen-robotics/mjlab
fanhao375 microduck-replicahttps://github.com/fanhao375/microduck-replica
fanhao375 microduck-replica-cadhttps://github.com/fanhao375/microduck-replica-cad
UnitClaw microduck-wwduck (WWNTRobotics-optimized edition)https://github.com/UnitClaw/microduck-wwduck
LuwuDynamics xgoduck_hardwarehttps://github.com/LuwuDynamics/xgoduck_hardware
onshape-to-robothttps://github.com/onshape-to-robot/onshape-to-robot
NVIDIA Warphttps://github.com/NVIDIA/warp

E.2 Official Pages and Documentation

ContentURL
MicroDuck product pagehttps://pollen-robotics.com/microduck/
MicroDuck pre-order storehttps://store.pollen-robotics.com/products/microduck
HF online simulationhttps://huggingface.co/spaces/pollen-robotics/microduck-simulator
onshape-to-robot docshttps://onshape-to-robot.readthedocs.io/
Onshapehttps://cad.onshape.com/
Warp docshttps://nvidia.github.io/warp/
MJCF docshttps://mujoco.readthedocs.io/en/latest/modeling.html
FreeCADhttps://www.freecadweb.org/
Feetech HD1910 product pagehttps://www.feetech.cn/500263.html
HD1910 XGO-Duck kithttps://www.feetech.cn/en/509038.html

E.3 Foundational Literature (for citation)

The following are classical methodological references; verify the exact entries before citing during writing.

  • PPO: Schulman et al., Proximal Policy Optimization Algorithms.
  • Domain Randomization: related work by NVIDIA's Tobin et al.
  • BAM servo model: Pollen MicroDuck technical papers / blog posts.
  • Low-cost bipedal Sim-to-Real: Pollen MicroDuck technical paper.

Writing convention: on formal publication, verify DOI / volume / page numbers for all references; cite sources when quoting in the main text, and do not erase original authorship.

E.4 Reference-Material Archive

All original material for this book is archived in the repository's book/materials/, organized into subdirectories:

  • pollen_original/: original RL, firmware, blog, papers;
  • replica_source/: microduck-replica source snapshot;
  • cad/: CAD drawings, STEP, Onshape config;
  • feetech_hd1910/: servo specs, protocol, calibration docs;
  • hardware/: RK3566, IMU, power;
  • framework_docs/: MuJoCo-Warp, mjlab, PPO;
  • scripts/: companion scripts;
  • references/: literature and terminology.

Note: some external resources cannot be downloaded and packaged directly; the archive provides access link + acquisition method + key notes instead. The complete HD1910 PDF datasheet and serial-protocol documents must be requested from Feetech customer service.

Acknowledgments

This book is the product of community collaboration. It stands on the shoulders of many open-source authors and manufacturers; without their generous sharing, this full-stack engineering practice for low-cost domestic bipedal robots would not exist. We extend our sincere thanks to each of them here.

About WWNT Robotics

This book is written and maintained by WWNT Robotics (full name: "Guangdong WWNT Robotics Co., Ltd.").

WWNT Robotics is a company focused on embodied intelligence and AI-robotics education. Adhering to the principle of "open-source-driven, full-stack empowerment," it operates along two tracks:

  • Domestically: industry–education integration for university AI/robotics programs, offering one-stop solutions spanning hardware, open-source curricula, training laboratories, campus large language models, and "factory-in-school";
  • Internationally: expanding into the North American market, exporting robot platforms and joint modules.

The company was co-founded by founder Chi Ching Ip (Henry Ip) and co-founder Yan Chaolei. Its open-source ecosystem is hosted under the GitHub UnitClaw organization, and its official websites are wwntai.com (domestic) and wwnt.ai (international).

This book is one of the embodiments of that philosophy: it organizes the process of replicating an overseas commercial product into a reproducible, low-cost engineering book, made freely available to university faculty and students, laboratory engineers, and open-source-hardware enthusiasts.

Acknowledgments

Pollen Robotics

Thanks to Pollen Robotics for open-sourcing MicroDuck, mjlab, and microduck_rl, and for making the complete technical route of a Sim2Real reinforcement-learning bipedal robot available to the community. The mechanical structure, simulation models, and training paradigm of this book all derive from their open-source work.

Note: this project is a third-party replication study of MicroDuck. It has no affiliation with Pollen Robotics and has not received its endorsement.

Hugging Face

Thanks to Hugging Face for its open platform and robotics ecosystem — MicroDuck is an open-source project of Pollen Robotics, its in-house robotics team, and the online simulator (HF Spaces) and related training toolchain also run on the Hugging Face open community. It is this openness that makes "watching the robot duck walk in the cloud" and "reproducing the training locally" possible.

Feetech

Thanks to Feetech for providing the HD-1910 serial-bus servo hardware and its official technical documentation. It is this high-value domestic servo that gives MicroDuck a "half the price, 2.5× the torque" domestic alternative, and that gives this book's BAM bench identification a real calibration target.

fanhao375

Thanks to @fanhao375 — the original author of this project. The reverse-engineering research, assembly drawings, exploded views, hardware analysis, and documentation were initially completed by him (original repository: fanhao375/microduck-replica). This book and its companion repository build on his foundation.

机械行者Robo

Thanks to 机械行者Robo — who organized the SolidWorks drawings, the assembly BOM, and the assembly videos. He made the journey "from parts to a walking robot" genuinely approachable and reproducible.

kissqy

Thanks to kissqy — a key contributor to the Feetech HD-1910 adaptation (training controller, IMU gyroscope fusion, etc.). His controller is subject to personal non-commercial terms; this book and its repository respect that agreement and do not include his controller modifications.

LuwuDynamics and Rhoban

Thanks to LuwuDynamics for sharing the 1910 M6 BAM parameters and companion configuration, which serve as the baseline for this book's simulation training; and thanks to Rhoban for open-sourcing the BAM actuator model and identification library, which provides the theoretical tools for servo modeling.

All Open-Source Community Developers

Thanks to every developer who provided feedback, corrections, and suggestions in GitHub Issues, Pull Requests, and community discussions. The meaning of open source lies precisely in this "many hands" collaboration.

Build It Together

This book and its companion repository are still young and inevitably contain errors and omissions. With humility, we invite you to make them better:

  • If you find errors or unclear wording, please open an Issue;
  • If you have improvements or additions, please submit a Pull Request;
  • If you have reproduced the result successfully or hit pitfalls, please share your experience back with the community.

Please respect the licensing boundaries of each part (code under Apache-2.0, mechanical CAD and documents under CC BY-NC-SA; see NOTICE). The domestic open-source ecosystem for low-cost bipedal robots needs everyone's participation. Together, let us make "bringing the robot dream to life" more inclusive and more open.

—— WWNT Robotics


Copyright and Disclaimer: The copyright in this book belongs to Guangdong WWNT Robotics Co., Ltd. (Copyright © WWNT Robotics). This book is an open-source engineering-practice record, and some technical material has not been fully validated on physical hardware; WWNT Robotics assumes no responsibility for replication failures, property loss, personal injury, or any infringement dispute arising from unauthorized commercialization. For the complete statement, see the "Copyright and Disclaimer" section of the Preface.