What Are the 14 Joints Controlled by the Microduck Robot?

The Microduck robot controls 14 servo-driven actuated joints—comprising bilateral leg joints (hip yaw/roll/pitch, knee, ankle), neck pitch, and three head degrees of freedom (pitch, yaw, roll)—that are directly commanded by reinforcement learning policies in the pollen-robotics/microduck_rl repository.

The pollen-robotics/microduck_rl repository implements a physics-based reinforcement learning platform where precise control of Microduck robot joints is essential for locomotion and head orientation tasks. These 14 controllable degrees of freedom, referred to as the "I4" or servo joints, form the complete set of actuators used during training and inference, producing a stable 61-dimensional observation layout across all tasks.

Complete Joint Index Reference

The 14 joints follow a strict ordering from 0 to 13, as defined in the MJCF model files. This index mapping remains consistent across all observation vectors and action commands.

Index Joint Name Description
0 left_hip_yaw Hip yaw on the left leg
1 left_hip_roll Hip roll on the left leg
2 left_hip_pitch Hip pitch on the left leg
3 left_knee Knee joint on the left leg
4 left_ankle Ankle joint on the left leg
5 neck_pitch Pitch of the neck
6 head_pitch Pitch of the head
7 head_yaw Yaw of the head
8 head_roll Roll of the head
9 right_hip_yaw Hip yaw on the right leg
10 right_hip_roll Hip roll on the right leg
11 right_hip_pitch Hip pitch on the right leg
12 right_knee Knee joint on the right leg
13 right_ankle Ankle joint on the right leg

This layout places all left leg joints (0-4) first, followed by the neck and head joints (5-8), then the right leg joints (9-13).

Implementation in the Source Code

MJCF Definition Files

The joint definitions reside in src/mjlab_microduck/robot/microduck/robot_walk.xml, where each of the 14 servo joints is declared with actuator properties. Complementary default actuator parameters, including damping and friction settings, are specified in src/mjlab_microduck/robot/microduck/joints_properties.xml.

Actuator Targeting Logic

In src/mjlab_microduck/robot/microduck/microduck_constants.py, the system distinguishes servo joints from passive elements (such as wheels or backlash hinges) using the regular expression:

target_names_expr = (r"^(?!passive_).*",)

This pattern ensures that only the 14 controllable joints are matched for policy actions, excluding any passive components.

Joint Access Helpers

The file src/mjlab_microduck/tasks/mdp.py exposes the indices through dedicated helper functions:

  • _servo_joint_ids(env, asset) – Returns the list of indices for the 14 servo joints
  • _servo_joint_pos(env, asset) – Returns current joint positions as a (num_envs, 14) tensor
  • _servo_joint_vel(env, asset) – Returns current joint velocities

Practical Code Examples

To retrieve the current positions of all actuated joints:


# Inside a task implementation or reward function

joint_pos = _servo_joint_pos(env, asset)          # shape: (num_envs, 14)

left_ankle_pos = joint_pos[:, 4]                  # index 4 → left_ankle

right_ankle_pos = joint_pos[:, 13]                # index 13 → right_ankle

To programmatically list all servo joint names:

servo_ids = _servo_joint_ids(env, asset)
servo_names = [asset.joint_name[i] for i in servo_ids]
print(servo_names)

# → ['left_hip_yaw', 'left_hip_roll', ..., 'right_ankle']

When sending commands, the 13-dimensional command block uses the structure [twist(3), head_pose(4), body_pose(6)]. The body_pose segment contains targets for the leg joints. For example, to command the left knee (servo index 3):

command = np.zeros(13)
command[6] = 0.2   # target for left_knee (offset 6 in command vector)

env.set_action(command)

Observation and Control Integration

The 14 joints generate a stable 61-dimensional observation layout across all tasks in the repository. This consistent indexing allows reinforcement learning policies to maintain state continuity between environment resets and episode rollouts. All joint observations use the ordering defined in the MJCF files, ensuring that the physical simulation remains synchronized with the policy's action outputs.

Summary

  • The Microduck robot controls 14 servo-driven joints organized as left leg (5), head/neck (4), and right leg (5).
  • Joint indices 0-13 are defined in robot_walk.xml and accessible via _servo_joint_ids() in mdp.py.
  • The regex r"^(?!passive_).*" in microduck_constants.py filters for actuated joints only.
  • Joint states feed into a 61-dimensional observation vector used by RL policies.
  • Commands use a 13-dimensional vector where leg targets occupy the body_pose(6) segment.

Frequently Asked Questions

What is the difference between servo joints and passive joints in Microduck?

Servo joints are the 14 actuated degrees of freedom directly controlled by reinforcement learning policies, while passive joints include components like wheels or backlash hinges that are not actively commanded. The codebase uses the regular expression r"^(?!passive_).*" in microduck_constants.py to exclude passive elements from actuator targeting.

How are the 14 joints ordered in the observation vector?

The observation vector follows the index order: left leg joints (indices 0-4), neck and head joints (5-8), and right leg joints (9-13). This ordering is hardcoded in the MJCF definition and exposed through the _servo_joint_ids() helper function in mdp.py.

Where can I find the physical limits for each joint?

Physical limits, damping coefficients, and friction parameters for the 14 joints are defined in src/mjlab_microduck/robot/microduck/joints_properties.xml. The complete kinematic structure and joint names are declared in src/mjlab_microduck/robot/microduck/robot_walk.xml.

Which joints are included in the 13-dimensional command block?

The command block structure [twist(3), head_pose(4), body_pose(6)] maps to specific servo joints. The body_pose segment controls the leg joints (hips, knees, ankles), while head_pose commands the neck pitch and head orientation joints. The exact mapping offsets depend on the specific joint index within the servo list.

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 →