Skip to main content

Description Package Protocol

Convention-based specification for external robot description packages.

Overview

The Description Package Protocol enables external robot descriptions to integrate with PLEM without configuration. Users provide a ROS2 package containing URDF and joint limits, and the system automatically discovers files and generates missing MoveIt configurations.

Package Structure Convention

my_robot_description/
├── urdf/
│ ├── my_robot.urdf.xacro # Required: exactly one URDF
│ └── my_robot.ros2_control.xacro # Required: hardware interface definition
├── srdf/
│ └── my_robot.srdf.xacro # Optional: for MoveIt (generated with --with-moveit)
├── config/
│ ├── joint_limits.yaml # Required: safety limits
│ ├── controllers.yaml # Optional: auto-generated if missing
│ └── kinematics.yaml # Optional: auto-generated if missing
├── launch/ # Optional: custom launch files (generated by default)
│ └── bringup.launch.py # (scaffold tool generates by default)
├── meshes/ # Optional: visual/collision meshes
├── PLEM_COMPAT_VERSION # Required: PLEM compatibility version
├── CMakeLists.txt
└── package.xml
Scaffold Tool

The entire structure can be auto-generated with ros2 run plem_bringup create_description --name <name> --dof <n> [--with-moveit]. Omitting --name/--dof automatically launches interactive mode. Launch files are generated by default and can be disabled with --no-launch. Re-running on existing packages skips identical files, or use --force to overwrite.

Required Files

FilePurposeValidation
urdf/*.urdf.xacroRobot geometry, kinematicsExactly one file, valid XML
urdf/*.ros2_control.xacroHardware interface definitionIncluded in URDF, prefix parameter
config/joint_limits.yamlPosition/velocity/acceleration limitsValid YAML, matches URDF joints
PLEM_COMPAT_VERSIONPLEM library compatibility version (e.g., 1.0.0)File exists, SemVer format

Optional Files (Auto-Generated or MoveIt Disabled)

FilePurposeAuto-Generation Behavior
srdf/*.srdfMoveIt semantic descriptionNot auto-generated. MoveIt will not start if missing.
config/kinematics.yamlIK solver configurationGenerated with KDL solver, default parameters (requires SRDF)
config/controllers.yamlJoint trajectory controller configurationGenerated from joint_limits.yaml

Auto-Discovery Rules

URDF Discovery

Rule: The system searches for .urdf.xacro files in the urdf/ directory.

Constraints:

  • Exactly one URDF file must exist
  • File must have .urdf.xacro extension
  • File name is arbitrary (doesn't need to match package name)
  • xacro file must be independently executable without arguments (see section below)

Override: Use the urdf_file:=/absolute/path/to/file.urdf.xacro launch argument.

URDF/SRDF Independent Execution Requirement

Important

xacro files from external packages must be independently executable without arguments.

Correct Example
xacro my_robot.urdf.xacro  # Works without arguments
Example to Avoid
xacro my_robot.urdf.xacro name:=... type:=...  # Requires arguments → Not supported

If arguments are required, specify defaults in a wrapper xacro:

<!-- my_robot.urdf.xacro -->
<xacro:include filename="base_robot.urdf.xacro"/>
<xacro:base_robot name="my_robot" prefix="" eye="false"/>
Rationale

This maintains consistency with industry standards (UR, Franka, MoveIt2) and simplifies user experience.

SRDF Discovery

Rule: The system searches for .srdf files in the srdf/ directory.

Constraints:

  • At most one SRDF file
  • File name is arbitrary

Override: Use the srdf_file:=/absolute/path/to/file.srdf launch argument.

Config Discovery

Rule: The system searches for exact file names in the config/ directory.

Expected File Names:

  • joint_limits.yaml
  • controllers.yaml
  • kinematics.yaml

URDF Requirements

1. ros2_control Hardware Interface Tag

Recommended Pattern: Define the hardware interface in a separate {name}.ros2_control.xacro file and include it in the URDF. The scaffold tool auto-generates this pattern.

ros2_control.xacro:

<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:macro name="my_robot_ros2_control" params="prefix:=''">
<ros2_control name="${prefix}my_robot_hardware" type="system">
<hardware>
<plugin>hardware/HardwareInterface</plugin>
</hardware>
<joint name="${prefix}joint1">
<command_interface name="position"/>
<command_interface name="velocity"/>
<command_interface name="acceleration"/>
<command_interface name="effort"/>
<state_interface name="position"/>
<state_interface name="velocity"/>
<state_interface name="effort"/>
</joint>
<!-- Repeat for all actuated joints -->
</ros2_control>
</xacro:macro>
</robot>

Include in URDF:

<xacro:include filename="$(find my_robot_description)/urdf/my_robot.ros2_control.xacro"/>
<xacro:my_robot_ros2_control prefix="$(arg prefix)"/>

Validation:

  • <ros2_control> tag must exist
  • Must reference hardware/HardwareInterface plugin
  • All actuated joints must be declared
  • prefix parameter support (for multi-robot scenarios)

2. Joint Types

Supported: revolute, prismatic, continuous (actuated joints)

Ignored: fixed joints are excluded from DOF count

Note

The current RT driver is optimized for revolute joints. Prismatic and continuous joints are extracted but may require additional testing.

3. Joint Count

Supported DOF: 6 or 7

Detection: Calculated from URDF joint declarations at runtime

Constraint: Must match RT driver compile-time DOF (see IPC Compatibility section)

Current Support

DOF=6, 7. Robots with 8+ DOF require a custom build of the RT driver.

Config File Format

joint_limits.yaml (Required)

joint_limits:
joint1:
has_position_limits: true
min_position: -3.14159 # radians
max_position: 3.14159
max_velocity: 3.0 # rad/s
max_acceleration: 5.0 # rad/s^2
max_jerk: 50.0 # rad/s^3
joint2:
# ... repeat for all joints

Validation:

  • All URDF joints must have entries
  • All limits must be positive (except position min/max)
  • min_position < max_position

controllers.yaml (Optional)

controller_manager:
ros__parameters:
update_rate: 1000

arm_controller:
ros__parameters:
type: joint_trajectory_controller/JointTrajectoryController
joints:
- joint1
- joint2
# ...
command_interfaces:
- position
state_interfaces:
- position
- velocity
constraints:
stopped_velocity_tolerance: 0.01
goal_time: 0.0

Auto-Generation: Generated from joint_limits.yaml with default tolerances.

kinematics.yaml (Optional)

arm:
kinematics_solver: kdl_kinematics_plugin/KDLKinematicsPlugin
kinematics_solver_search_resolution: 0.005
kinematics_solver_timeout: 0.05
kinematics_solver_attempts: 3

Auto-Generation: Uses KDL solver with conservative default values.

SRDF (Optional)

<robot name="my_robot">
<group name="arm">
<chain base_link="base_link" tip_link="link6"/>
</group>
<group_state name="home" group="arm">
<joint name="joint1" value="0"/>
<!-- ... all joints -->
</group_state>
</robot>
Important

SRDF is not auto-generated. You must create it manually. If SRDF is not provided, MoveIt will not start, and only ros2_control will be enabled.

Launch Argument Reference

ArgumentDefaultPurpose
description_packagewim_descriptionROS2 package name for robot description
robot_name(from description_package)Robot identifier for topic namespace
urdf_file(auto-discovered)URDF path override
srdf_file(auto-discovered)SRDF path override
robot_typeindy7_v2Legacy: built-in robots (indy7_v2, indy12_v2, indyrp2, indyrp2_v2)

Usage Patterns

Quick Test: Integrated Launcher

Launch all PLEM components at once:

# Convention-based (recommended)
ros2 launch plem_bringup plem_launch.py description_package:=my_robot_description

# URDF path override
ros2 launch plem_bringup plem_launch.py \
description_package:=my_robot_description \
urdf_file:=/path/to/custom.urdf.xacro

# Legacy built-in robot
ros2 launch plem_bringup plem_launch.py robot_type:=indy7_v2

Use Case: Prototyping, feature verification, full stack testing

Features: Starts RT driver, ROS2 Control, MoveIt, Bridge, AI Server

Production: Scaffold Launcher

Custom launcher with selectable components:

# 1. Create description package (launch files included by default)
ros2 run plem_bringup create_description --name my_robot --dof 6

# 2. Edit generated bringup.launch.py to select components
# my_robot_description/launch/bringup.launch.py
# Example: Disable MoveIt and AI Server, run only RT driver and ROS2 Control

# 3. Run custom launcher
ros2 launch my_robot_description bringup.launch.py

Use Case: Production deployment, embedded systems, resource optimization

Features:

  • Per-component enable/disable control
  • Add robot-specific initialization logic
  • Version control configuration with code

Validation Rules

Automated Validation Tool

ros2 run plem_bringup validate_description <package_name>

Automatically validates:

  • URDF structure and ros2_control tags
  • Joint limit consistency
  • Joint name matches across files
  • DOF count verification
  • SRDF-URDF consistency (if SRDF provided)

Cross-File Consistency

ValidationChecks
URDF ↔ joint_limits.yamlAll URDF joints have limit entries, no extra entries
URDF ↔ SRDFAll SRDF groups reference valid URDF links/joints
URDF ↔ controllers.yamlAll controller joints exist in URDF
URDF ↔ kinematics.yamlAll kinematic groups match SRDF groups

Validation Timing

StageValidation
After BuildPre-validate with validate_description tool (recommended)
Launch TimeFile existence, YAML syntax, URDF XML syntax
Node Startupros2_control tags, joint count, joint types
RuntimeIPC DOF match, joint limit enforcement

Error Message Format

All errors follow a WHAT/WHY/HOW structure:

ERROR: No URDF file found in package 'my_robot_description'
WHAT: Auto-discovery expected exactly one .urdf.xacro file in urdf/ directory
WHY: Found 0 matching files
HOW: Create urdf/my_robot.urdf.xacro or use urdf_file:=/path launch argument

Common Error Categories:

  • File discovery failures (missing, multiple, wrong extension)
  • Validation failures (schema, cross-file inconsistencies)
  • Runtime failures (DOF mismatch, joint name mismatch)

Auto-Generation Behavior

Trigger Conditions

Missing config files trigger auto-generation during launch.

Log Output:

[plem_launch.py] INFO: SRDF not found - MoveIt will not be started
[plem_launch.py] INFO: Auto-generating kinematics.yaml (KDL solver)
Important

SRDF is not auto-generated. Without SRDF, MoveIt is disabled and only ros2_control is enabled.

Generated File Location

Auto-generated files are temporary (not written to package directory).

Location: /tmp/wim_launch_<timestamp>/

Rationale: Prevents user package modification, enables version control

Permanent Preservation

To permanently preserve auto-generated files:

  1. Run once to generate files
  2. Copy from /tmp/wim_launch_<timestamp>/ to package config/
  3. Commit to version control
  4. Customize as needed

Extension Points

Custom Hardware Interface

Replace hardware/HardwareInterface with a custom plugin:

<hardware>
<plugin>my_package/MyHardwareInterface</plugin>
</hardware>

Requirement: Custom plugin must implement hardware_interface::SystemInterface.

Custom Kinematics Solver

Override in kinematics.yaml:

arm:
kinematics_solver: trac_ik_kinematics_plugin/TRAC_IKKinematicsPlugin
# ...

Requirement: Solver plugin must be installed and loadable.

Backward Compatibility

Legacy robot_type Argument

ros2 launch plem_bringup plem_launch.py robot_type:=indy7_v2

Behavior: Resolves to built-in description package (indy7_v2_description).

Built-in Robots: indy7_v2, indy12_v2, indyrp2, indyrp2_v2

Migration Path: Create external description package, use description_package:= argument

Implementation Notes

DOF Detection

DOF is detected at runtime from URDF joint count.

Current Support

DOF=6, 7. Using 6-DOF or 7-DOF URDF ensures IPC compatibility.

IPC Compatibility

The RT driver uses compile-time DOF for IPC memory layout.

Current Constraint: IPC DOF must match URDF DOF.

Current Support

DOF=6, 7. Robots with 8+ DOF require a custom build of the RT driver.

Future: Dynamic IPC sizing based on URDF DOF planned

References