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

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, 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, 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 where the _BAM_ACTUATOR_KWARGS dictionary encapsulates all BAM M6 parameters:

_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:

actuators = FrictionDRBamActuatorCfg(**_BAM_ACTUATOR_KWARGS)

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

backlash_actuators = BacklashEncoderBamActuatorCfg(**_BAM_ACTUATOR_KWARGS)

Both classes import from 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 extends the base BAM M6 model with per-episode friction randomization. The randomization hooks in 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. This script loads the M6 parameter file (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:

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:

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:

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 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, 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, setting model="m6" loads the physics kernel defined in 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 through the FrictionDRBamActuatorCfg class, with randomization hooks located in 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.

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 →