How Backlash Is Simulated in Microduck RL Environments: A Technical Deep-Dive

Backlash in Microduck RL environments is simulated through a three-layer system: passive hinge joints that model mechanical play, an actuator that reads encoder position through the backlash joint, and task configurations that retarget observations and rewards to preserve the original action space.

Microduck RL, developed by Pollen Robotics, implements realistic gearbox backlash simulation to bridge the gap between simulation and real-world hardware behavior. This article examines exactly how the microduck_rl repository achieves physically accurate backlash modeling without disrupting the learning pipeline's dimensionality.

The Three-Component Backlash Simulation System

The Microduck RL codebase implements backlash through three coordinated components: geometry modification, actuator feedback adjustment, and task configuration adaptation.

Geometry: Passive Backlash Joints via add_backlash.py

The foundation of backlash simulation lies in physical joint injection. The add_backlash.py script, located at src/mjlab_microduck/robot/microduck/add_backlash.py, processes the robot's MuJoCo XML to insert passive hinge joints for every actuated servo.

Each injected joint follows a strict naming convention: passive_<joint>_backlash. These joints receive a constrained rotational range—typically ±0.5° (±1° total play)—that directly models the mechanical gap between servo output shaft and robot link.

The passive_ prefix serves a critical purpose. All regex-based selections throughout the codebase—actuator targets, observation filters, reward computations—automatically exclude these joints. This preserves the original 14-DOF action space while adding physical realism.

python3 src/mjlab_microduck/robot/microduck/add_backlash.py \
    src/mjlab_microduck/robot/microduck/robot_groundcontact.xml \
    --backlash-deg 2.0

The --backlash-deg parameter controls total play magnitude. The script outputs modified XML files such as robot_groundcontact_backlash.xml, referenced in configuration constants.

Actuator: Encoder-Through-Backlash Feedback

The BacklashEncoderBamActuator class in src/mjlab_microduck/actuator/friction_dr_bam.py extends the standard BAM voltage-controlled actuator to handle realistic encoder behavior.

During each control step, the actuator computes encoder position as:

encoder_position = qpos[servo] + qpos[backlash]

This sum replicates real hardware where encoders mount on the output side of gear play. The servo joint angle and passive backlash joint angle combine to represent what the physical encoder actually measures.

Velocity commands (cmd.vel) remain unchanged, still targeting the motor side. This matches physical servo behavior where back-EMF-based velocity feedback operates at the motor rather than the output.

The actuator configuration class, BacklashEncoderBamActuatorCfg, enables clean swapping in environment configurations without modifying learning code.

Task Configuration: Observations and Rewards

The make_backlash_variant function in src/mjlab_microduck/tasks/backlash.py transforms standard Microduck environments into backlash-aware variants through three specific modifications:

  • Observation retargeting: Swaps joint_pos and joint_vel for joint_pos_rel_backlash and joint_vel_rel_backlash. Policies observe the encoder-view (servo + backlash) while maintaining 14-dimensional vectors.
  • Reward boundary adjustment: Modifies dof_pos_limits reward to apply only to servo joints, preventing backlash joints from generating spurious penalties when hitting their ±1° hard limits.
  • Pose reward filtering: Updates joint selection regex to exclude passive_*_backlash joints, ensuring pose-tracking penalties compute on correct servo joints.
from mjlab_microduck.tasks.backlash import make_backlash_variant
from mjlab_microduck.robot.microduck_constants import MICRODUCK_BACKLASH_ROBOT_CFG

# base_cfg is any existing environment config

backlash_cfg = make_backlash_variant(base_cfg, robot_cfg=MICRODUCK_BACKLASH_ROBOT_CFG)

Robot Configuration Constants

The complete integration relies on constants defined in src/mjlab_microduck/robot/microduck_constants.py. Key backlash-enabled configurations include:

  • MICRODUCK_BACKLASH_ROBOT_CFG — Base robot with backlash joints
  • MICRODUCK_WALK_BACKLASH_ROBOT_CFG — Walking-optimized variant

These constants pair the appropriate XML model with the correct actuator configuration, enabling single-line environment customization.

How Backlash Simulation Preserves Learning Compatibility

A critical design requirement in Microduck RL is maintaining consistent state and action dimensions across simulation variants. The backlash simulation achieves this through:

Mechanism Implementation
Action space preservation Passive joints excluded from actuator targets
Observation dimensionality Relative-backlash functions output 14-DOF vectors
Reward stability Joint-specific regex filtering
Configuration inheritance make_backlash_variant wraps existing configs

This architecture allows direct comparison between backlash-aware and ideal-servo policies without architectural changes to learning algorithms.

Summary

  • Backlash simulation in Microduck RL uses passive hinge joints with constrained ranges to model mechanical gear play.
  • The add_backlash.py script injects geometry while preserving naming conventions that existing code ignores.
  • BacklashEncoderBamActuator reads encoder position as the sum of servo and backlash joint angles, matching real hardware behavior.
  • make_backlash_variant retargets observations and rewards without changing vector dimensionality.
  • Robot constants in microduck_constants.py provide pre-configured backlash variants for immediate use.

Frequently Asked Questions

What file adds physical backlash joints to the Microduck robot model?

The src/mjlab_microduck/robot/microduck/add_backlash.py script processes MuJoCo XML files to insert passive hinge joints. It outputs modified XML models with passive_<joint>_backlash joints representing mechanical play.

How does the actuator know to read position through the backlash joint?

The BacklashEncoderBamActuator class in src/mjlab_microduck/actuator/friction_dr_bam.py explicitly sums qpos[servo] + qpos[backlash] when computing encoder feedback. This replicates physical encoders mounted on the output side of gearbox play.

Why don't backlash joints appear in the action space?

All backlash joint names begin with passive_, which regex patterns throughout the codebase automatically exclude. This preserves the original 14-DOF action space while adding physical realism to dynamics.

Can existing environments be converted to backlash variants without code changes?

Yes. The make_backlash_variant function in src/mjlab_microduck/tasks/backlash.py wraps any existing configuration. It handles observation function swapping, reward retargeting, and robot configuration updating through a single function call.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →