Skip to main content

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.