# Domain Randomization Techniques in Microduck RL: A Complete Technical Guide

> Explore domain randomization techniques in Microduck RL. Learn how physics, sensor noise, and disturbances enhance sim-to-real transfer for bipedal robots.

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

---

**Microduck RL implements 10+ domain randomization techniques across physics parameters, sensor noise, and external disturbances to enable robust sim-to-real transfer for bipedal locomotion.**

Domain randomization (DR) is the core strategy that allows policies trained in simulation to deploy successfully on Pollen Robotics' physical Microduck robot. According to the `pollen-robotics/microduck_rl` source code, these techniques are organized as **event terms** in environment configuration files, with granular toggles for each randomization type. This guide breaks down every major DR technique, its implementation, and how to configure it.

---

## Physics-Based Domain Randomization Techniques

### Center-of-Mass (CoM) Randomization

The most critical DR technique for balance control involves perturbing the robot's mass distribution. Microduck RL applies **two levels of CoM randomization**:

- **Trunk CoM randomization**: Adds random offsets to the main body center of mass
  - Configuration: `cfg.events["randomize_com"]` in [`microduck_velocity_env_cfg.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/microduck_velocity_env_cfg.py)
  - Range: ±0.003 m initially, ramped to ±0.015 m during curriculum
  - Toggle: `ENABLE_COM_RANDOMIZATION`

- **Head-assembly CoM randomization**: Applies separate offsets to each head body (`neck`, `head_pitch`, etc.)
  - Configuration: `cfg.events["randomize_head_com"]`
  - Range: ±0.003 m ramped to ±0.01 m
  - Toggle: `ENABLE_HEAD_COM_RANDOMIZATION`

This captures manufacturing variations in the torso and head assemblies that significantly affect balance dynamics.

### Mass and Inertia Randomization

The `dr.pseudo_inertia` helper scales **both mass and inertia tensors** simultaneously for selected bodies:

```python

# From microduck_velocity_env_cfg.py

cfg.events["randomize_mass_inertia"] = EventTermCfg(
    func=dr.pseudo_inertia,
    mode="reset",
    params={
        "asset_cfg": SceneEntityCfg("robot", body_names=("trunk",)),
        "operation": "scale",
        "ranges": (0.95, 1.05),  # ±5%

    },
)

```

This preserves realistic mass-inertia relationships while introducing ±5% variation in trunk dynamics.

### Joint Dynamics Randomization

Three complementary techniques randomize the actuator and transmission models:

| Technique | Implementation | Target Parameter | Range |
|-----------|---------------|------------------|-------|
| **Joint friction randomization** | `microduck_mdp.randomize_bam_friction` | BAM actuator friction budget | 0.9–1.1 |
| **Joint damping randomization** | `microduck_mdp.randomize_dof_field_scaled` | `dof_damping` per joint | 0.9–1.1 |
| **Armature randomization** | `dr.joint_armature` | Reflected rotor inertia | 0.9–1.1 |

The **BAM friction randomizer** ([`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)) specifically handles the tendon-driven actuator model used in Microduck's legs, scaling the friction budget that accounts for cable routing losses.

---

## Sensor and Observation Domain Randomization

### IMU Orientation Randomization

Unlike typical approaches that add noise to IMU readings, Microduck RL applies **constant random rotations** to simulate IMU mounting errors:

- Implementation: Actor-side observation functions `base_ang_vel_imu_misaligned` and `projected_gravity_imu_misaligned`
- Toggle: `ENABLE_IMU_ORIENTATION_RANDOMIZATION` in [`microduck_velocity_env_cfg.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/microduck_velocity_env_cfg.py)
- Range: Up to 6° misalignment in any direction

This is more realistic than additive noise because physical IMU mounting errors are fixed per-robot, not time-varying.

### Encoder Bias Randomization

Each joint's position encoder receives a **permanent offset** for the entire episode:

```python

# Event configuration

cfg.events["encoder_bias"] = EventTermCfg(
    func=mdp.randomize_encoder_bias,
    mode="reset",
    params={
        "asset_cfg": SceneEntityCfg("robot"),
        "bias_range": ENCODER_BIAS_RANGE,  # default ±0.015 rad

    },
)

```

This forces policies to be robust to calibration errors without explicit state estimation.

---

## Episode Initialization and External Disturbances

### Base Orientation Randomization

Every episode starts with randomized initial tilt to improve recovery robustness:

- Configuration: `cfg.events["randomize_base_orientation"]`
- Range: ±10° pitch, ±5° roll
- Effect: Forces the policy to learn rapid stabilization from non-upright poses

### Velocity Push Randomization

To simulate external disturbances and train recovery behaviors:

```python
if ENABLE_VELOCITY_PUSHES:
    cfg.events["push_robot"] = EventTermCfg(
        func=mdp.push_by_setting_velocity,
        mode="interval",                           # Triggers between pushes

        interval_range_s=(3.0, 6.0),              # Random 3-6 second intervals

        params={
            "velocity_range": {"x": (-0.3, 0.3), "y": (-0.3, 0.3)},
            "asset_cfg": SceneEntityCfg("robot"),
        },
    )

```

The **interval mode** is crucial—unlike reset-time randomization, this injects disturbances mid-episode, forcing continuous disturbance rejection rather than just initial pose recovery.

### Wheel Friction Randomization

For roller-equipped variants of Microduck, passive wheel friction is randomized:

- Configuration: `cfg.events["randomize_wheel_friction"]` in [`microduck_velocity_rollers_env_cfg.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/microduck_velocity_rollers_env_cfg.py)
- Target: Backlash and roller contact friction in wheeled locomotion variants
- See also: Used in [`microduck_spin_env_cfg.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/microduck_spin_env_cfg.py) for spinning maneuvers

---

## Configuring Domain Randomization in Your Environment

### Enabling and Disabling Techniques

Each DR component has a boolean toggle defined at the top of environment configuration files:

```python

# In any microduck_*_env_cfg.py

ENABLE_COM_RANDOMIZATION = True                # Trunk CoM drift

ENABLE_HEAD_COM_RANDOMIZATION = True           # Head assembly mass distribution

ENABLE_MASS_INERTIA_RANDOMIZATION = True       # Mass/inertia scaling

ENABLE_JOINT_FRICTION_RANDOMIZATION = True     # BAM friction budget

ENABLE_JOINT_DAMPING_RANDOMIZATION = True      # Joint viscous damping

ENABLE_ARMATURE_RANDOMIZATION = True           # Rotor inertia reflection

ENABLE_IMU_ORIENTATION_RANDOMIZATION = True    # IMU mounting error (~6°)

ENABLE_ENCODER_BIAS_RANDOMIZATION = True       # Encoder zero-point offset

ENABLE_BASE_ORIENTATION_RANDOMIZATION = True   # Initial tilt at reset

ENABLE_VELOCITY_PUSHES = True                  # External disturbance injection

ENABLE_WHEEL_FRICTION_RANDOMIZATION = False    # Only for roller variants

```

### Adding Custom Randomization Events

The `mjlab.envs.mdp.dr` module provides reusable randomizers. Example for body position offset:

```python
from mjlab.envs.mdp import dr
from mjlab.envs.manager_based_rl import EventTermCfg, SceneEntityCfg

cfg.events["randomize_custom"] = EventTermCfg(
    func=dr.body_ipos,                # Position offset randomizer

    mode="reset",                     # Apply at episode start

    params={
        "asset_cfg": SceneEntityCfg("robot", body_names=("custom_body",)),
        "operation": "add",           # Additive offset (vs. "scale")

        "ranges": (-0.005, 0.005),   # ±5 mm

    },
)

```

Available `dr.*` helpers include: `body_ipos`, `body_mass`, `body_inertia`, `joint_armature`, `joint_stiffness`, `joint_damping`, `joint_limits`, `joint_default_pos`, and `pseudo_inertia`.

---

## Key Implementation Files

| File | Purpose |
|------|---------|
| [`src/mjlab_microduck/tasks/microduck_velocity_env_cfg.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/tasks/microduck_velocity_env_cfg.py) | Primary velocity control environment; defines all DR toggles and default event configurations |
| [`src/mjlab_microduck/tasks/microduck_velocity_rollers_env_cfg.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/tasks/microduck_velocity_rollers_env_cfg.py) | Roller variant with wheel friction randomization |
| [`src/mjlab_microduck/tasks/microduck_standup_env_cfg.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/tasks/microduck_standup_env_cfg.py) | Stand-up task reusing core DR components |
| [`src/mjlab_microduck/tasks/microduck_spin_env_cfg.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/tasks/microduck_spin_env_cfg.py) | Spin task with wheel-specific DR |
| [`src/mjlab_microduck/tasks/mdp.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/tasks/mdp.py) | Custom randomization functions: `randomize_bam_friction`, `randomize_dof_field_scaled`, `randomize_delayed_actuator_gains` |
| [`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) | BAM actuator friction model implementation |

---

## Summary

- **Center-of-mass randomization** (trunk and head) handles manufacturing variations in mass distribution
- **Joint dynamics randomization** covers friction, damping, and reflected inertia across the transmission
- **Sensor randomization** uses constant offsets for IMU mounting and encoder bias rather than additive noise
- **External disturbances** via velocity pushes train active recovery behaviors at random intervals
- **Modular toggles** in environment configs allow precise control of which DR techniques are active
- **Extensible design** via `dr.*` helpers and `EventTermCfg` enables rapid experimentation with new randomization strategies

---

## Frequently Asked Questions

### How does Microduck RL's domain randomization differ from Isaac Sim's built-in DR?

Microduck RL extends Isaac Sim's foundation with **BAM-specific actuation models** and **sensor-level randomization** that targets real hardware failure modes. The BAM friction randomizer in [`friction_dr_bam.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/friction_dr_bam.py) models tendon cable losses, while IMU orientation and encoder bias randomization simulate calibration errors rather than measurement noise—both critical for the physical Microduck robot.

### Can I use different domain randomization ranges for training vs. evaluation?

Yes. The `mode` parameter in `EventTermCfg` controls when randomization applies: `"reset"` for episode starts, `"interval"` for mid-episode disturbances, or fixed curriculum ranges that expand during training. For evaluation, set `ENABLE_*_RANDOMIZATION` toggles to `False` or override ranges via `params["ranges"]` to test specific conditions.

### What is the most important domain randomization technique for sim-to-real transfer?

According to the configuration defaults in [`microduck_velocity_env_cfg.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/microduck_velocity_env_cfg.py), **center-of-mass randomization** has the largest magnitude range (±15 mm trunk, ±10 mm head) and is enabled in all locomotion variants. Mass distribution errors most severely affect balance, making CoM randomization the highest-impact technique for bipedal walking transfer.

### How do velocity pushes improve policy robustness compared to other disturbance methods?

Velocity pushes use `mode="interval"` rather than `mode="reset"`, meaning they occur **during running episodes** rather than only at initialization. This forces continuous disturbance rejection rather than pose recovery, and the random 3–6 second interval prevents adaptation to predictable disturbance timing.