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
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
| File | Purpose | Validation |
|---|---|---|
urdf/*.urdf.xacro | Robot geometry, kinematics | Exactly one file, valid XML |
urdf/*.ros2_control.xacro | Hardware interface definition | Included in URDF, prefix parameter |
config/joint_limits.yaml | Position/velocity/acceleration limits | Valid YAML, matches URDF joints |
PLEM_COMPAT_VERSION | PLEM library compatibility version (e.g., 1.0.0) | File exists, SemVer format |
Optional Files (Auto-Generated or MoveIt Disabled)
| File | Purpose | Auto-Generation Behavior |
|---|---|---|
srdf/*.srdf | MoveIt semantic description | Not auto-generated. MoveIt will not start if missing. |
config/kinematics.yaml | IK solver configuration | Generated with KDL solver, default parameters (requires SRDF) |
config/controllers.yaml | Joint trajectory controller configuration | Generated 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.xacroextension - 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
xacro files from external packages must be independently executable without arguments.
xacro my_robot.urdf.xacro # Works without arguments
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"/>
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.yamlcontrollers.yamlkinematics.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/HardwareInterfaceplugin - All actuated joints must be declared
prefixparameter support (for multi-robot scenarios)
2. Joint Types
Supported: revolute, prismatic, continuous (actuated joints)
Ignored: fixed joints are excluded from DOF count
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)
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>
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
| Argument | Default | Purpose |
|---|---|---|
description_package | wim_description | ROS2 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_type | indy7_v2 | Legacy: 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
| Validation | Checks |
|---|---|
| URDF ↔ joint_limits.yaml | All URDF joints have limit entries, no extra entries |
| URDF ↔ SRDF | All SRDF groups reference valid URDF links/joints |
| URDF ↔ controllers.yaml | All controller joints exist in URDF |
| URDF ↔ kinematics.yaml | All kinematic groups match SRDF groups |
Validation Timing
| Stage | Validation |
|---|---|
| After Build | Pre-validate with validate_description tool (recommended) |
| Launch Time | File existence, YAML syntax, URDF XML syntax |
| Node Startup | ros2_control tags, joint count, joint types |
| Runtime | IPC 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)
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:
- Run once to generate files
- Copy from
/tmp/wim_launch_<timestamp>/to packageconfig/ - Commit to version control
- 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.
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.
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
- Robot Integration: Robot Integration Guide
- Quick Start: Quickstart