Modeling the Humanoid with URDF
Learning Objectives
By the end of this chapter, you will be able to:
- Explain the purpose of URDF in humanoid robotics
- Define links, joints, and kinematic chains for humanoid robots
- Distinguish between visual and collision models
- Validate and visualize URDF models using ROS tools
Purpose of URDF in Humanoid Robotics
Unified Robot Description Format (URDF) is an XML-based format used to describe robots in ROS. It's essential for humanoid robotics because it provides a standardized way to represent:
- Physical structure of the robot
- Kinematic relationships between parts
- Visual appearance for simulation
- Collision properties for physics simulation
- Inertial properties for dynamics
Why URDF is Critical for Humanoid Robots
Humanoid robots have complex structures with many degrees of freedom, making URDF particularly valuable:
- Complex Kinematics: Humanoid robots have multiple limbs with complex joint relationships
- Simulation Requirements: Accurate models are needed for physics simulation
- Visualization: 3D models needed for RViz and other visualization tools
- Collision Detection: Proper collision models for safe operation
- Dynamics: Inertial properties for realistic simulation
Defining Links, Joints, and Kinematic Chains
Understanding Links
A link in URDF represents a rigid part of the robot. Each link has:
- A unique name
- Visual properties (shape, color, material)
- Collision properties (shape for collision detection)
- Inertial properties (mass, center of mass, moment of inertia)
Here's the basic structure of a link:
<link name="link_name">
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<box size="0.1 0.1 0.1"/>
</geometry>
<material name="blue">
<color rgba="0 0 1 1"/>
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<box size="0.1 0.1 0.1"/>
</geometry>
</collision>
<inertial>
<mass value="1.0"/>
<inertia ixx="0.0833" ixy="0.0" ixz="0.0" iyy="0.0833" iyz="0.0" izz="0.0833"/>
</inertial>
</link>
Understanding Joints
A joint connects two links and defines their relative motion. Joints have:
- A unique name
- A type (revolute, continuous, prismatic, fixed, etc.)
- Parent and child links
- Joint limits (for revolute and prismatic joints)
- Origin (position and orientation relative to parent)
Here's the basic structure of a joint:
<joint name="joint_name" type="joint_type">
<parent link="parent_link_name"/>
<child link="child_link_name"/>
<origin xyz="0 0 0" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-1.57" upper="1.57" effort="100" velocity="1"/>
</joint>
Joint Types
- Fixed: No relative motion (like a rigid connection)
- Revolute: Single-axis rotation with limits
- Continuous: Single-axis rotation without limits
- Prismatic: Single-axis translation with limits
- Planar: Motion in a plane
- Floating: 6-DOF motion
Creating Kinematic Chains
Kinematic chains connect multiple links through joints to form the robot's structure. Here's an example of a simple humanoid arm:
<?xml version="1.0"?>
<robot name="simple_arm">
<!-- Base link -->
<link name="base_link">
<visual>
<geometry>
<cylinder radius="0.05" length="0.1"/>
</geometry>
<material name="grey">
<color rgba="0.5 0.5 0.5 1"/>
</material>
</visual>
<collision>
<geometry>
<cylinder radius="0.05" length="0.1"/>
</geometry>
</collision>
<inertial>
<mass value="0.5"/>
<inertia ixx="0.001" ixy="0" ixz="0" iyy="0.001" iyz="0" izz="0.002"/>
</inertial>
</link>
<!-- Shoulder joint -->
<joint name="shoulder_joint" type="revolute">
<parent link="base_link"/>
<child link="upper_arm"/>
<origin xyz="0 0 0.05" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
<limit lower="-1.57" upper="1.57" effort="100" velocity="1"/>
</joint>
<!-- Upper arm link -->
<link name="upper_arm">
<visual>
<geometry>
<cylinder radius="0.03" length="0.2"/>
</geometry>
<material name="blue">
<color rgba="0 0 1 1"/>
</material>
</visual>
<collision>
<geometry>
<cylinder radius="0.03" length="0.2"/>
</geometry>
</collision>
<inertial>
<mass value="0.3"/>
<inertia ixx="0.001" ixy="0" ixz="0" iyy="0.001" iyz="0" izz="0.002"/>
</inertial>
</link>
<!-- Elbow joint -->
<joint name="elbow_joint" type="revolute">
<parent link="upper_arm"/>
<child link="lower_arm"/>
<origin xyz="0 0 -0.2" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
<limit lower="-1.57" upper="1.57" effort="100" velocity="1"/>
</joint>
<!-- Lower arm link -->
<link name="lower_arm">
<visual>
<geometry>
<cylinder radius="0.02" length="0.15"/>
</geometry>
<material name="red">
<color rgba="1 0 0 1"/>
</material>
</visual>
<collision>
<geometry>
<cylinder radius="0.02" length="0.15"/>
</geometry>
</collision>
<inertial>
<mass value="0.2"/>
<inertia ixx="0.0005" ixy="0" ixz="0" iyy="0.0005" iyz="0" izz="0.001"/>
</inertial>
</link>
</robot>
Visual vs Collision Models
Visual Models
Visual models define how the robot appears in simulation and visualization tools. They focus on:
- Appearance (shape, color, texture)
- Rendering performance
- Visual clarity for debugging
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<mesh filename="package://my_robot/meshes/link1.dae" scale="1 1 1"/>
</geometry>
<material name="green">
<color rgba="0 1 0 1"/>
</material>
</visual>
Collision Models
Collision models define how the robot interacts with the environment in physics simulation. They focus on:
- Accurate collision detection
- Computational efficiency
- Physical interaction properties
<collision>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<mesh filename="package://my_robot/meshes/link1_collision.stl"/>
</geometry>
</collision>
Key Differences
- Visual models can use complex meshes and textures but may impact rendering performance
- Collision models should use simpler shapes for better physics performance
- Visual and collision models can be different shapes for the same link
- Collision models should fully encompass the physical robot for safety
Creating a Complete Humanoid URDF Model
Here's an example of a basic humanoid torso model:
<?xml version="1.0"?>
<robot name="humanoid_torso">
<!-- Base link (pelvis) -->
<link name="base_link">
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<box size="0.2 0.15 0.15"/>
</geometry>
<material name="light_grey">
<color rgba="0.7 0.7 0.7 1"/>
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<box size="0.2 0.15 0.15"/>
</geometry>
</collision>
<inertial>
<mass value="10.0"/>
<inertia ixx="0.2" ixy="0" ixz="0" iyy="0.2" iyz="0" izz="0.2"/>
</inertial>
</link>
<!-- Spine joint -->
<joint name="spine_joint" type="revolute">
<parent link="base_link"/>
<child link="torso"/>
<origin xyz="0 0 0.075" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
<limit lower="-0.5" upper="0.5" effort="200" velocity="1"/>
</joint>
<!-- Torso link -->
<link name="torso">
<visual>
<origin xyz="0 0 0.15" rpy="0 0 0"/>
<geometry>
<box size="0.15 0.15 0.3"/>
</geometry>
<material name="light_grey">
<color rgba="0.7 0.7 0.7 1"/>
</material>
</visual>
<collision>
<origin xyz="0 0 0.15" rpy="0 0 0"/>
<geometry>
<box size="0.15 0.15 0.3"/>
</geometry>
</collision>
<inertial>
<mass value="8.0"/>
<inertia ixx="0.3" ixy="0" ixz="0" iyy="0.3" iyz="0" izz="0.1"/>
</inertial>
</link>
<!-- Head joint -->
<joint name="head_joint" type="revolute">
<parent link="torso"/>
<child link="head"/>
<origin xyz="0 0 0.3" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
<limit lower="-0.5" upper="0.5" effort="50" velocity="2"/>
</joint>
<!-- Head link -->
<link name="head">
<visual>
<origin xyz="0 0 0.05" rpy="0 0 0"/>
<geometry>
<sphere radius="0.08"/>
</geometry>
<material name="skin">
<color rgba="0.9 0.8 0.7 1"/>
</material>
</visual>
<collision>
<origin xyz="0 0 0.05" rpy="0 0 0"/>
<geometry>
<sphere radius="0.08"/>
</geometry>
</collision>
<inertial>
<mass value="2.0"/>
<inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.01"/>
</inertial>
</link>
<!-- Left shoulder joint -->
<joint name="left_shoulder_joint" type="revolute">
<parent link="torso"/>
<child link="left_upper_arm"/>
<origin xyz="0.075 0 0.2" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-1.57" upper="1.57" effort="100" velocity="1"/>
</joint>
<!-- Left upper arm link -->
<link name="left_upper_arm">
<visual>
<origin xyz="0 0 -0.1" rpy="0 0 0"/>
<geometry>
<cylinder radius="0.03" length="0.2"/>
</geometry>
<material name="light_grey">
<color rgba="0.7 0.7 0.7 1"/>
</material>
</visual>
<collision>
<origin xyz="0 0 -0.1" rpy="0 0 0"/>
<geometry>
<cylinder radius="0.03" length="0.2"/>
</geometry>
</collision>
<inertial>
<mass value="1.5"/>
<inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.001"/>
</inertial>
</link>
<!-- Left elbow joint -->
<joint name="left_elbow_joint" type="revolute">
<parent link="left_upper_arm"/>
<child link="left_lower_arm"/>
<origin xyz="0 0 -0.2" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-1.57" upper="1.57" effort="100" velocity="1"/>
</joint>
<!-- Left lower arm link -->
<link name="left_lower_arm">
<visual>
<origin xyz="0 0 -0.075" rpy="0 0 0"/>
<geometry>
<cylinder radius="0.025" length="0.15"/>
</geometry>
<material name="light_grey">
<color rgba="0.7 0.7 0.7 1"/>
</material>
</visual>
<collision>
<origin xyz="0 0 -0.075" rpy="0 0 0"/>
<geometry>
<cylinder radius="0.025" length="0.15"/>
</geometry>
</collision>
<inertial>
<mass value="1.0"/>
<inertia ixx="0.005" ixy="0" ixz="0" iyy="0.005" iyz="0" izz="0.001"/>
</inertial>
</link>
</robot>
Validating and Visualizing URDF Models
URDF Validation
Before using a URDF model, it's important to validate it for syntax and logical errors:
# Check URDF syntax
check_urdf /path/to/robot.urdf
# Parse and display robot information
urdf_to_graphiz /path/to/robot.urdf
Visualization Tools
ROS provides several tools for visualizing URDF models:
- RViz: Real-time visualization of robot models
- Robot State Publisher: Publishes joint states for visualization
- Joint State Publisher GUI: Interactive joint control for visualization
Launching Visualization
Here's a simple launch file to visualize a URDF model:
<launch>
<!-- Load robot description parameter -->
<param name="robot_description" command="xacro $(find my_robot)/urdf/robot.urdf.xacro" />
<!-- Publish robot state -->
<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" />
<!-- Joint state publisher for interactive control -->
<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher">
<param name="use_gui" value="true" />
</node>
<!-- Launch RViz -->
<node name="rviz" pkg="rviz" type="rviz" args="-d $(find my_robot)/config/robot.rviz" />
</launch>
Using Xacro for Complex Models
Xacro (XML Macros) allows you to create more maintainable URDF models:
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="humanoid_with_xacro">
<!-- Define properties -->
<xacro:property name="M_PI" value="3.1415926535897931" />
<xacro:property name="torso_mass" value="8.0" />
<!-- Macro for creating limbs -->
<xacro:macro name="limb" params="name parent side">
<joint name="${side}_${name}_joint" type="revolute">
<parent link="${parent}"/>
<child link="${side}_${name}"/>
<origin xyz="0.075 0 0" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-1.57" upper="1.57" effort="100" velocity="1"/>
</joint>
<link name="${side}_${name}">
<visual>
<origin xyz="0 0 -0.1" rpy="0 0 0"/>
<geometry>
<cylinder radius="0.03" length="0.2"/>
</geometry>
<material name="grey">
<color rgba="0.7 0.7 0.7 1"/>
</material>
</visual>
<collision>
<origin xyz="0 0 -0.1" rpy="0 0 0"/>
<geometry>
<cylinder radius="0.03" length="0.2"/>
</geometry>
</collision>
<inertial>
<mass value="1.5"/>
<inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.001"/>
</inertial>
</link>
</xacro:macro>
<!-- Define base link -->
<link name="base_link">
<visual>
<geometry>
<box size="0.2 0.15 0.15"/>
</geometry>
<material name="light_grey">
<color rgba="0.7 0.7 0.7 1"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.2 0.15 0.15"/>
</geometry>
</collision>
<inertial>
<mass value="10.0"/>
<inertia ixx="0.2" ixy="0" ixz="0" iyy="0.2" iyz="0" izz="0.2"/>
</inertial>
</link>
<!-- Use the macro to create limbs -->
<xacro:limb name="upper_arm" parent="base_link" side="left"/>
<xacro:limb name="upper_arm" parent="base_link" side="right"/>
</robot>
Best Practices for URDF Modeling
Naming Conventions
- Use descriptive names for links and joints
- Follow consistent naming patterns (e.g., left_arm_joint, right_arm_link)
- Use underscores to separate words
- Keep names concise but meaningful
Model Organization
- Group related links and joints together
- Use meaningful comments to explain complex sections
- Organize the file logically (base to end effectors)
Performance Considerations
- Use simple shapes for collision models
- Optimize mesh complexity for visual models
- Balance detail with performance requirements
Safety Considerations
- Ensure collision models fully encompass the physical robot
- Include all safety-relevant parts in the model
- Validate that joint limits prevent dangerous configurations
Troubleshooting Common URDF Issues
Common Syntax Errors
- Missing closing tags
- Incorrect attribute names
- Invalid numerical values
- Missing required attributes
Common Logic Errors
- Non-existent parent/child links
- Inconsistent joint types
- Invalid joint limits
- Missing inertial properties
Validation Commands
# Check for basic syntax errors
xmllint --noout robot.urdf
# Validate URDF specifically
check_urdf robot.urdf
# Generate graph of robot structure
urdf_to_graphiz robot.urdf
Summary
This chapter has covered the essential aspects of modeling humanoid robots with URDF. You've learned about the purpose of URDF in robotics, how to define links and joints to create kinematic chains, the difference between visual and collision models, and how to validate and visualize URDF models using ROS tools.
With this knowledge, you can now create accurate representations of humanoid robots for simulation, control, and visualization. The combination of understanding ROS 2 fundamentals, node integration, and URDF modeling provides a strong foundation for working with humanoid robots in the ROS ecosystem.
Exercises
- Create a simple URDF model of a 2-link manipulator arm
- Validate your URDF model using the
check_urdfcommand - Visualize your model in RViz
- Add a gripper to your robot model with appropriate joints
- Create a Xacro macro to simplify repeated elements in your model