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

> Learn how backlash is simulated in Microduck RL environments. Discover the three-layer system for modeling mechanical play, actuator behavior, and task configurations for accurate reinforcement learning.

- Repository: [Pollen Robotics/microduck_rl](https://github.com/pollen-robotics/microduck_rl)
- Tags: deep-dive
- Published: 2026-09-08

---

**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`](https://github.com/pollen-robotics/microduck_rl/blob/main/add_backlash.py)

The foundation of backlash simulation lies in physical joint injection. The [`add_backlash.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/add_backlash.py) script, located at [`src/mjlab_microduck/robot/microduck/add_backlash.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/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.

```bash
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`](https://github.com/pollen-robotics/microduck_rl/blob/main/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`](https://github.com/pollen-robotics/microduck_rl/blob/main/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:

```python
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`](https://github.com/pollen-robotics/microduck_rl/blob/main/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.

```python
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`](https://github.com/pollen-robotics/microduck_rl/blob/main/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`](https://github.com/pollen-robotics/microduck_rl/blob/main/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`](https://github.com/pollen-robotics/microduck_rl/blob/main/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`](https://github.com/pollen-robotics/microduck_rl/blob/main/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`](https://github.com/pollen-robotics/microduck_rl/blob/main/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`](https://github.com/pollen-robotics/microduck_rl/blob/main/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.