# How the 14 Dynamixel Servos of the Microduck Robot Map to Joint Indices

> Discover how the 14 Dynamixel servos in the Microduck robot map to joint indices 0-13. Understand the servo layout for left leg, neck, head, and right leg control.

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

---

**The 14 Dynamixel XL330 servos in the Microduck robot are indexed contiguously from 0 to 13, with indices 0–4 controlling the left leg, 5–8 controlling the neck and head, and 9–13 controlling the right leg.**

The Microduck robot in the `pollen-robotics/microduck_rl` repository utilizes a fixed 14-servo actuation layout that remains consistent across all Isaac Lab environment variants. Understanding this standardized indexing scheme is essential for configuring reward functions, action rate penalties, and joint-specific control policies in reinforcement learning workflows.

## Joint Index Layout Overview

The robot's articulation model assigns contiguous indices to each Dynamixel servo. The layout organizes the 14 degrees of freedom into three functional groups: the left leg, the neck and head assembly, and the right leg.

| Index | Joint Name | Functional Group |
|-------|------------|------------------|
| 0 | `left_hip_yaw` | Left Leg (0–4) |
| 1 | `left_hip_roll` | Left Leg (0–4) |
| 2 | `left_hip_pitch` | Left Leg (0–4) |
| 3 | `left_knee` | Left Leg (0–4) |
| 4 | `left_ankle` | Left Leg (0–4) |
| 5 | `neck_pitch` | Neck/Head (5–8) |
| 6 | `head_pitch` | Neck/Head (5–8) |
| 7 | `head_yaw` | Neck/Head (5–8) |
| 8 | `head_roll` | Neck/Head (5–8) |
| 9 | `right_hip_yaw` | Right Leg (9–13) |
| 10 | `right_hip_roll` | Right Leg (9–13) |
| 11 | `right_hip_pitch` | Right Leg (9–13) |
| 12 | `right_knee` | Right Leg (9–13) |
| 13 | `right_ankle` | Right Leg (9–13) |

## Joint Index Conventions in the Codebase

The `pollen-robotics/microduck_rl` source code enforces these index conventions through explicit helper functions and constants. In [`src/mjlab_microduck/tasks/mdp.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/tasks/mdp.py), the codebase defines separate index lists for leg and neck joints to facilitate reward computations and action monitoring.

**Leg joint indices** are constructed by concatenating the left and right leg ranges:

```python
leg_joint_indices = list(range(0, 5)) + list(range(9, 14))

```

This creates the list `[0, 1, 2, 3, 4, 9, 10, 11, 12, 13]`, encompassing all hip, knee, and ankle servos while excluding the neck and head joints at indices 5–8.

**Neck joint indices** use a single contiguous range:

```python
neck_joint_indices = list(range(5, 9))

```

This captures indices 5 through 8, corresponding to the neck pitch, head pitch, head yaw, and head roll servos.

According to the source code at line 1449 of [`mdp.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/mdp.py), these conventions are documented with the explicit comment: "left hip-ankle: 0-4, right hip-ankle: 9-13". The leg index list appears at line 54, while the neck index list is defined at line 62.

## Home Pose Configuration

The same indexing scheme governs the robot's initial configuration. In [`src/mjlab_microduck/robot/microduck_constants.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/robot/microduck_constants.py) (lines 81–94), the home pose array assigns default angles using this 0–13 index ordering. This ensures that initialization values align precisely with the servo layout used throughout the training environment.

## Practical Code Examples

To retrieve the complete servo-only joint view in an environment, use the `_servo_joint_ids` helper function:

```python

# Retrieve servo joint indices for the robot

servo_ids = _servo_joint_ids(env, env.scene["robot"])

# Returns: tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13])

```

When computing action-rate penalties specifically for leg movements, filter actions using the predefined leg indices:

```python

# Isolate leg actions using the established index convention

leg_joint_indices = list(range(0, 5)) + list(range(9, 14))
leg_actions = env.action_manager.action[:, leg_joint_indices]

# Calculate action rate against previous step

action_rate = leg_actions - env._prev_leg_actions
penalty = torch.sum(torch.square(action_rate), dim=1)

```

## Summary

- The Microduck robot uses **14 Dynamixel XL330 servos** indexed contiguously from 0 to 13.
- **Indices 0–4** control the left leg joints: `hip_yaw`, `hip_roll`, `hip_pitch`, `knee`, and `ankle`.
- **Indices 5–8** control the neck and head: `neck_pitch`, `head_pitch`, `head_yaw`, and `head_roll`.
- **Indices 9–13** control the right leg, mirroring the left leg joint configuration.
- The `leg_joint_indices` and `neck_joint_indices` lists in [`src/mjlab_microduck/tasks/mdp.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/tasks/mdp.py) enforce these groupings for reward calculations.
- The home pose in [`src/mjlab_microduck/robot/microduck_constants.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/robot/microduck_constants.py) confirms this ordering through initialization arrays.

## Frequently Asked Questions

### What type of Dynamixel servos does the Microduck robot use?

The Microduck robot uses **Dynamixel XL330** servos for all 14 actuated joints. These compact, high-torque servos provide precise position control for the leg mechanisms and the active neck/head assembly.

### How are the joint indices grouped in the Microduck robot?

Indices are grouped by anatomical function: **0–4** for the left leg, **5–8** for the neck and head, and **9–13** for the right leg. This grouping allows the reinforcement learning framework to apply specific reward modifiers—such as action rate penalties—selectively to the leg servos while excluding the neck joints.

### Where is the joint index mapping defined in the source code?

The index mapping is defined in [`src/mjlab_microduck/tasks/mdp.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/tasks/mdp.py) at lines 54 and 62, where `leg_joint_indices` and `neck_joint_indices` are explicitly constructed. The home pose configuration in [`src/mjlab_microduck/robot/microduck_constants.py`](https://github.com/pollen-robotics/microduck_rl/blob/main/src/mjlab_microduck/robot/microduck_constants.py) (lines 81–94) further confirms this layout by indexing initial joint angles according to the same 0–13 scheme.

### How do I access only the leg joints in the Microduck environment?

Filter the action tensor using the leg index list: `list(range(0, 5)) + list(range(9, 14))`. This excludes neck joints (indices 5–8) and returns a tensor containing only the 10 leg servo values (5 left + 5 right), which is the standard approach for computing leg-specific rewards in the MDP module.