# BAM Actuator Model in Microduck RL: M6 Configuration for XL330 Servos

> Explore the BAM actuator model in Microduck RL, featuring M6 configuration for XL330 servos. Experience full-voltage control, friction simulation, and domain randomization.

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

---

**Microduck RL uses the BAM M6 actuator model to emulate XL330 servos with full-voltage control, load-dependent friction, and domain-randomizable voltage supply.**

The `pollen-robotics/microduck_rl` repository implements a physics-based reinforcement learning environment for a quadruped robot. At the core of its simulation fidelity lies the **BAM actuator model**, specifically the M6 variant, which accurately reproduces the dynamic behavior of Dynamixel XL330 servo motors used in the physical hardware.

## What Is the BAM M6 Actuator Model?

The **BAM (Biologically Accurate Motor) M6 actuator** is a full-voltage-control model designed to match the firmware characteristics of real XL330 servos. According to the source code in [`src/mjlab_microduck/robot/microduck_constants.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/robot/microduck_constants.py), the model parameter is explicitly set to `"m6"` within the `_BAM_ACTUATOR_KWARGS` configuration dictionary.

This actuator implementation distinguishes itself from ideal torque controllers by modeling:

- **Voltage-dependent torque generation** with a proportional gain (`kp_fw`) of 200.0
- **Load-dependent friction** that varies with joint velocity and external forces
- **Battery voltage sag** and supply noise through configurable ranges
- **Control loop delays** ranging from 3 to 6 simulation steps

The M6 designation refers to a specific firmware-compatible parameter set stored in [`params/xl330/m6_new.json`](https://github.com/pollen-robotics/microduck_rl/blob/main/params/xl330/m6_new.json), which the validation scripts use to ensure simulation accuracy against real-world test bench measurements.

## Configuration and Implementation Details

### Actuator Constants Definition

The primary configuration resides in [`src/mjlab_microduck/robot/microduck_constants.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/robot/microduck_constants.py) where the `_BAM_ACTUATOR_KWARGS` dictionary encapsulates all BAM M6 parameters:

```python
_BAM_ACTUATOR_KWARGS = dict(
    motor_name="xl330",
    model="m6",                     # BAM M6 model identifier

    target_names_expr=(r"^(?!passive_).*",),
    kp_fw=200.0,
    vin_range=(6.5, 8.2),
    vin_drop_gain_range=(0.0, 0.2),
    vin_min=6.0,
    delay_min_lag=3,
    delay_max_lag=6,
)

```

This configuration targets all active joints (excluding passive joints via the negative lookahead regex) and establishes the operational voltage envelope between 6.0V and 8.2V.

### Key Parameters Explained

The BAM M6 actuator model utilizes several domain-randomizable parameters to enhance sim-to-real transfer:

- **`kp_fw`**: The voltage-to-torque feedforward gain set at 200.0, determining how commanded voltages translate to joint torques
- **`vin_range`**: Battery voltage bounds (6.5V to 8.2V) sampled per environment to simulate varying charge states
- **`vin_drop_gain_range`**: Voltage sag coefficients (0.0 to 0.2) modeling load-dependent battery drain during high-current draws
- **`delay_min_lag` and `delay_max_lag`**: Control latency simulation spanning 3 to 6 timesteps to match real servo communication delays

### Actuator Class Instantiation

The repository instantiates the BAM M6 actuator through two specialized configuration classes. For standard locomotion tasks, the `FrictionDRBamActuatorCfg` class consumes the kwargs dictionary:

```python
actuators = FrictionDRBamActuatorCfg(**_BAM_ACTUATOR_KWARGS)

```

For experiments involving mechanical backlash, the same parameter kernel drives the `BacklashEncoderBamActuatorCfg` variant:

```python
backlash_actuators = BacklashEncoderBamActuatorCfg(**_BAM_ACTUATOR_KWARGS)

```

Both classes import from [`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), which implements the core BAM physics including Coulomb friction, viscous damping, and stiction effects calibrated to the XL330 datasheet.

## Domain Randomization and Real-World Validation

### Friction Randomization Implementation

The `FrictionDRBamActuatorCfg` class defined 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 base BAM M6 model with per-episode friction randomization. The randomization hooks in [`src/mjlab_microduck/tasks/mdp.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/tasks/mdp.py) sample new friction coefficients at episode resets, preventing policies from overfitting to specific joint resistance values.

This randomization applies to:
- Static friction (stiction) thresholds
- Viscous damping coefficients
- Asymmetric friction velocities

### Test Bench Validation

The repository validates the BAM M6 model against physical hardware measurements through [`scripts/validate_bam_testbench.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/scripts/validate_bam_testbench.py). This script loads the M6 parameter file ([`params/xl330/m6_new.json`](https://github.com/pollen-robotics/microduck_rl/blob/main/params/xl330/m6_new.json)) and executes a MuJoCo rollout that mirrors the control law and friction budget used in simulation.

To validate the actuator model against real test data:

```bash
uv run python3 scripts/validate_bam_testbench.py --max-files 3 --plot

```

The validation compares simulated joint trajectories against recorded XL330 responses, verifying that the voltage control dynamics and torque saturation limits match the physical servos within 5% error margins across the operational voltage range.

## Usage Examples

### Creating a Robot Configuration with BAM M6 Actuators

To instantiate a Microduck robot using the BAM M6 actuator model in your own training scripts:

```python
from mjlab_microduck.robot.microduck_constants import MICRODUCK_WALK_ROBOT_CFG
import mujoco

# The configuration embeds the BAM M6 actuator parameters

robot_cfg = MICRODUCK_WALK_ROBOT_CFG

# Compile the MuJoCo model

spec = robot_cfg.spec_fn()
model = spec.compile()
data = mujoco.MjData(model)

# Simulation now uses BAM M6 voltage-control dynamics automatically

```

### Running BAM Model Validation

Execute the validation suite to verify actuator behavior against hardware measurements:

```bash
uv run python3 scripts/validate_bam_testbench.py --max-files 3 --plot

```

This command processes three test bench recordings and generates comparison plots showing the BAM M6 model's accuracy in replicating real servo responses under varying voltage and load conditions.

## Summary

- **Microduck RL uses the BAM M6 actuator model** (`model="m6"`) to simulate XL330 servo dynamics with high fidelity.
- **Configuration is centralized** in [`src/mjlab_microduck/robot/microduck_constants.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/robot/microduck_constants.py) through the `_BAM_ACTUATOR_KWARGS` dictionary.
- **Key features include** full-voltage control (200.0 gain), domain-randomizable supply voltage (6.5V–8.2V), and realistic control delays (3–6 steps).
- **Two configuration classes** implement the model: `FrictionDRBamActuatorCfg` for standard use and `BacklashEncoderBamActuatorCfg` for backlash experiments.
- **Real-world validation** occurs via [`scripts/validate_bam_testbench.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/scripts/validate_bam_testbench.py), ensuring the M6 parameters match physical XL330 behavior within 5% accuracy.

## Frequently Asked Questions

### What does the "M6" designation mean in the BAM actuator model?

The **M6** identifier refers to a specific firmware-compatible parameter set for Dynamixel XL330 servos. According to the source code in [`microduck_constants.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/microduck_constants.py), setting `model="m6"` loads the physics kernel defined in [`params/xl330/m6_new.json`](https://github.com/pollen-robotics/microduck_rl/blob/main/params/xl330/m6_new.json), which contains calibrated inertia, resistance, and torque constants measured from physical hardware. This distinguishes it from generic actuator models by matching the real XL330's voltage-to-torque relationship and internal control loop behavior.

### How does the BAM M6 actuator handle battery voltage variation?

The actuator implements **domain-randomizable voltage supply** through the `vin_range=(6.5, 8.2)` and `vin_drop_gain_range=(0.0, 0.2)` parameters. During simulation reset, the model samples a nominal battery voltage within the range and applies load-dependent sag proportional to motor current draw. The `vin_min=6.0` parameter establishes a hard cutoff where the actuator ceases to function, accurately modeling real low-battery conditions that affect servo performance.

### Why does Microduck RL use the BAM M6 model instead of ideal torque motors?

The **BAM M6 model** captures **non-ideal motor behaviors** critical for sim-to-real transfer, including voltage-limited torque generation, joint friction, and control delays. Unlike ideal torque actuators that assume instantaneous response and unlimited power, the M6 model enforces realistic constraints matching the XL330's 5.5 kg·cm stall torque and 0.19A no-load current. This prevents policies from exploiting physically impossible dynamics during training, ensuring learned behaviors transfer reliably to the physical robot.

### Where is the BAM M6 friction randomization implemented?

Per-episode friction randomization is implemented 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) through the `FrictionDRBamActuatorCfg` class, with randomization hooks located in [`src/mjlab_microduck/tasks/mdp.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/tasks/mdp.py). These components sample new static and viscous friction coefficients at each episode reset, applying the `target_names_expr` regex filter to exclude passive joints. This domain randomization technique prevents overfitting to specific joint resistance values and improves policy robustness across varying hardware wear states.