URDF Tools & Visualization
Introduction
Working with URDF models requires specialized tools for creation, validation, visualization, and debugging. This lesson explores the essential tools and techniques for developing, testing, and visualizing URDF robot models, with particular focus on tools relevant to complex humanoid robots.
URDF Validation Tools
Before visualizing or simulating a robot, it's important to validate the URDF for structural correctness.
1. check_urdf Command
The check_urdf command validates the basic structure of your URDF:
# Check the URDF structure
ros2 run urdf check_urdf /path/to/robot.urdf
# Or if using xacro
ros2 run xacro xacro /path/to/robot.xacro | ros2 run urdf check_urdf /dev/stdin
Example output:
robot name is: my_robot
---------- Successfully Parsed XML ---------------
root Link: base_link has 1 child(ren)
child(1): right_front_leg
child(1): right_front_foot
child(2): right_back_leg
child(1): right_back_foot
child(3): left_front_leg
child(1): left_front_foot
child(4): left_back_leg
child(1): left_back_foot
2. URDF to Graphviz
Generate a visual representation of the kinematic tree:
# Generate a graphviz visualization
ros2 run urdf urdf_to_graphiz /path/to/robot.urdf
# Creates robot.pdf showing the kinematic structure
This creates a PDF showing the parent-child relationships and joint types, which is particularly useful for complex humanoid models.
3. Xacro Processing
For Xacro files, validate the expansion:
# Check that xacro expands without errors
xacro --inorder /path/to/robot.xacro > /tmp/expanded.urdf
# Then validate the expanded URDF
check_urdf /tmp/expanded.urdf
Visualization Tools
1. RViz
RViz is the primary visualization tool for ROS robots:
<!-- Launch file to visualize a robot -->
<launch>
<node pkg="robot_state_publisher" executable="robot_state_publisher" name="robot_state_publisher">
<param name="robot_description" value="$(find my_robot_description)/urdf/robot.urdf"/>
</node>
<node pkg="joint_state_publisher_gui" executable="joint_state_publisher_gui" name="joint_state_publisher_gui"/>
</launch>
Key RViz configurations for URDF:
- RobotModel display: Shows the robot mesh/visuals
- TF display: Shows transforms between links
- InteractiveMarkers for direct joint control
2. Gazebo/IGNITION Visualization
For physics-based visualization:
<!-- Example Gazebo URDF enhancement -->
<link name="link_name">
<visual>
<geometry>
<mesh filename="package://my_robot_description/meshes/link_name.dae"/>
</geometry>
</visual>
<collision>
<geometry>
<mesh filename="package://my_robot_description/meshes/link_name_collision.stl"/>
</geometry>
</collision>
<!-- Gazebo-specific properties -->
<gazebo reference="link_name">
<material>Gazebo/Blue</material>
</gazebo>
</link>
3. MeshLab and Blender for Model Creation
For creating and editing robot meshes:
- MeshLab: For mesh processing and optimization
- Blender: For detailed modeling and export to supported formats
4. URDF Editor Tools
Several GUI tools exist for visual URDF editing:
- SW.URDF: Web-based URDF editor
- RoboAnalyzer: Commercial tool with URDF import/export
- XML Editors: With URDF schema validation
Debugging URDF Models
1. Common URDF Issues
Invalid kinematic tree - Check for:
- Multiple base links
- Disconnected links
- Invalid joint connections
Joint limits and types - Verify:
- Proper joint ranges
- Correct joint axes
- Appropriate effort/velocity limits
Inertial issues - Ensure:
- Positive masses
- Valid inertia matrices
- Realistic values
2. TF Tree Analysis
Visualize the transformation tree with:
# View the TF tree in terminal
ros2 run tf2_tools view_frames
# View TF in RViz
ros2 run rqt_tf_tree rqt_tf_tree
3. Joint State Monitoring
Monitor joint states to ensure proper kinematic behavior:
# Echo joint states
ros2 topic echo /joint_states sensor_msgs/msg/JointState
# Use rqt_plot for visualization
rqt_plot /joint_states/position
Programming URDF Tools
1. Parsing URDF in Code
Using the URDF C++ parser:
#include <urdf/model.h>
bool parseURDF(const std::string& urdf_file) {
urdf::Model model;
if (!model.initFile(urdf_file)) {
std::cerr << "Failed to parse URDF file" << std::endl;
return false;
}
std::cout << "Robot name: " << model.getName() << std::endl;
// Access links and joints
for (const auto& link_pair : model.links_) {
std::cout << "Link: " << link_pair.first << std::endl;
}
return true;
}
For Python with urdf_parser_py:
import urdf_parser_py.urdf as urdf
# Parse URDF
robot = urdf.Robot.from_xml_file('/path/to/robot.urdf')
# Access robot properties
print(f"Robot name: {robot.name}")
print(f"Links: {[link.name for link in robot.links]}")
print(f"Joints: {[joint.name for joint in robot.joints]}")
# Access specific link properties
for link in robot.links:
if link.inertial:
print(f"Link {link.name} mass: {link.inertial.mass}")
2. Generating URDF Programmatically
import xml.etree.ElementTree as ET
from xml.dom import minidom
def create_urdf_skeleton(robot_name):
# Create root robot element
robot = ET.Element('robot', name=robot_name)
# Add default material
material = ET.SubElement(robot, 'material', name='default')
color = ET.SubElement(material, 'color', rgba='0.7 0.7 0.7 1.0')
return robot
def add_link(robot_element, link_name, mass, ixx, ixy, ixz, iyy, iyz, izz):
link = ET.SubElement(robot_element, 'link', name=link_name)
# Add visual
visual = ET.SubElement(link, 'visual')
geometry = ET.SubElement(visual, 'geometry')
box = ET.SubElement(geometry, 'box', size='0.1 0.1 0.1')
# Add collision
collision = ET.SubElement(link, 'collision')
col_geom = ET.SubElement(collision, 'geometry')
col_box = ET.SubElement(col_geom, 'box', size='0.1 0.1 0.1')
# Add inertial
inertial = ET.SubElement(link, 'inertial')
ET.SubElement(inertial, 'mass', value=str(mass))
ET.SubElement(inertial, 'inertia',
ixx=str(ixx), ixy=str(ixy), ixz=str(ixz),
iyy=str(iyy), iyz=str(iyz), izz=str(izz))
def save_urdf(robot_element, filename):
rough_string = ET.tostring(robot_element, 'unicode')
reparsed = minidom.parseString(rough_string)
pretty_xml = reparsed.toprettyxml(indent=" ")
# Remove extra blank lines
lines = [line for line in pretty_xml.split('\n') if line.strip()]
pretty_xml = '\n'.join(lines)
with open(filename, 'w') as f:
f.write(pretty_xml)
Simulation-Specific Enhancements
1. Gazebo-Specific Tags
Enhance URDF for Gazebo simulation:
<!-- Add Gazebo plugins -->
<gazebo>
<plugin name="gazebo_ros_control" filename="libgazebo_ros_control.so">
<robotNamespace>/my_robot</robotNamespace>
</plugin>
</gazebo>
<!-- Link-specific Gazebo properties -->
<gazebo reference="my_link">
<mu1>0.2</mu1>
<mu2>0.2</mu2>
<material>Gazebo/Orange</material>
<turnGravityOff>false</turnGravityOff>
</gazebo>
<!-- Transmission for joint control -->
<transmission name="tran1">
<type>transmission_interface/SimpleTransmission</type>
<joint name="joint1">
<hardwareInterface>hardware_interface/PositionJointInterface</hardwareInterface>
</joint>
<actuator name="motor1">
<hardwareInterface>hardware_interface/PositionJointInterface</hardwareInterface>
<mechanicalReduction>1</mechanicalReduction>
</actuator>
</transmission>
2. Contact Sensors
Add contact sensors for humanoid robots:
<gazebo reference="left_foot">
<sensor name="left_foot_contact" type="contact">
<always_on>true</always_on>
<update_rate>100</update_rate>
<contact>
<collision>left_foot_collision</collision>
</contact>
<plugin name="left_foot_contact_plugin" filename="libgazebo_ros_bumper.so">
<alwaysOn>true</alwaysOn>
<updateRate>100.0</updateRate>
<bumperTopicName>left_foot_bumper</bumperTopicName>
<frameName>left_foot</frameName>
</plugin>
</sensor>
</gazebo>
Visualization Best Practices
1. Mesh Optimization
For humanoid robots with complex meshes:
- Use simplified collision meshes
- Optimize visual meshes for real-time rendering
- Use appropriate texture resolution
2. URDF Organization
For complex humanoid robots:
my_robot_description/
├── urdf/
│ ├── robot.xacro # Main robot definition
│ ├── materials.xacro # Material definitions
│ ├── common.xacro # Common macros
│ ├── head.xacro # Head components
│ ├── arms.xacro # Arm components
│ ├── legs.xacro # Leg components
│ └── torso.xacro # Torso components
├── meshes/
│ ├── head/
│ ├── arms/
│ ├── legs/
│ └── torso/
└── launch/
└── view_robot.launch.py
3. Joint State Visualization
Create launch files for easy visualization:
# view_robot.launch.py
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
urdf_file = LaunchConfiguration('urdf_file')
return LaunchDescription([
DeclareLaunchArgument(
'urdf_file',
default_value='robot.xacro',
description='URDF file name'
),
Node(
package='robot_state_publisher',
executable='robot_state_publisher',
name='robot_state_publisher',
parameters=[{
'robot_description': Command(['xacro ', FindFile('my_robot_description/urdf/', urdf_file)])
}]
),
Node(
package='joint_state_publisher_gui',
executable='joint_state_publisher_gui',
name='joint_state_publisher_gui'
)
])
Performance Considerations
1. For Complex Humanoid Models
- Use efficient collision geometries
- Simplify visual meshes where possible
- Optimize joint limit calculations
- Consider level-of-detail approaches
2. Visualization Tips
- Disable unnecessary displays in RViz
- Use appropriate update rates
- Consider using static TF for fixed transforms
Summary
URDF tools and visualization techniques are essential for developing and debugging robot models. From validation with check_urdf to detailed visualization in RViz, these tools provide the means to ensure your robot model is correctly specified and functions as expected. For complex humanoid robots, proper tool usage becomes even more critical due to the complexity of the kinematic structures. The next chapter will explore advanced ROS 2 concepts for complex robotic systems.