Chapter 2.2: URDF and SDF Robot Description
Learning Objectives
By the end of this chapter, students will be able to:
- Understand the differences between URDF and SDF formats
- Convert between URDF and SDF representations
- Enhance URDF models with Gazebo-specific tags
- Create complete robot descriptions for simulation
- Integrate control plugins for simulated robots
Introduction
In the previous chapter, we explored the Gazebo simulation environment and learned how to create basic simulation worlds. Now we'll dive deeper into how robots are described in simulation, focusing on the two primary formats: URDF (Unified Robot Description Format) and SDF (Simulation Description Format).
URDF is the standard format for describing robots in ROS, while SDF is the native format for Gazebo simulation. Understanding both formats and how they interact is crucial for creating effective digital twins of humanoid robots. This chapter will cover how to create comprehensive robot descriptions that work well in simulation while maintaining compatibility with ROS 2 systems.
URDF vs SDF: Key Differences
URDF (Unified Robot Description Format)
URDF is the standard format for robot description in ROS. It's primarily focused on:
- Kinematic structure (links and joints)
- Visual and collision properties
- Inertial properties
- Basic sensor information
URDF is XML-based and integrates well with ROS tools and ecosystem.
SDF (Simulation Description Format)
SDF is the native format for Gazebo simulation. It extends beyond URDF to include:
- Simulation-specific properties
- Physics engine configuration
- Sensor simulation details
- Plugin specifications
- World elements
SDF is more comprehensive for simulation purposes but less integrated with ROS tools.
When to Use Each Format
| Aspect | URDF | SDF |
|---|---|---|
| Primary Use | ROS robot descriptions | Gazebo simulation |
| Kinematic Structure | ✅ | ✅ |
| Simulation Physics | ❌ (with plugins) | ✅ |
| Sensors | Basic definition | Detailed simulation |
| Controllers | ❌ (with plugins) | ✅ |
| World Elements | ❌ | ✅ |
Converting URDF to SDF
Automatic Conversion
Gazebo can automatically convert URDF to SDF when spawning models:
# Convert URDF to SDF using gz sdf tool
gz sdf -p robot.urdf > robot.sdf
# Or when spawning in Gazebo
ros2 run gazebo_ros spawn_entity.py -file robot.urdf -entity my_robot
Manual Conversion Example
Here's a simple URDF:
<?xml version="1.0"?>
<robot name="simple_robot">
<link name="base_link">
<visual>
<geometry>
<box size="0.5 0.5 0.2"/>
</geometry>
<material name="blue">
<color rgba="0 0 1 1"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.5 0.5 0.2"/>
</geometry>
</collision>
<inertial>
<mass value="1.0"/>
<inertia ixx="0.1" ixy="0" ixz="0" iyy="0.1" iyz="0" izz="0.1"/>
</inertial>
</link>
</robot>
And its SDF equivalent:
<?xml version="1.0" ?>
<sdf version="1.7">
<model name="simple_robot">
<link name="base_link">
<pose>0 0 0 0 0 0</pose>
<visual name="visual">
<geometry>
<box>
<size>0.5 0.5 0.2</size>
</box>
</geometry>
<material>
<ambient>0 0 1 1</ambient>
<diffuse>0 0 1 1</diffuse>
</material>
</visual>
<collision name="collision">
<geometry>
<box>
<size>0.5 0.5 0.2</size>
</box>
</geometry>
</collision>
<inertial>
<mass>1.0</mass>
<inertia>
<ixx>0.1</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>0.1</iyy>
<iyz>0</iyz>
<izz>0.1</izz>
</inertia>
</inertial>
</link>
</model>
</sdf>
Enhancing URDF with Gazebo Tags
To use URDF effectively in Gazebo, we add Gazebo-specific tags:
Basic Gazebo Integration
<?xml version="1.0"?>
<robot name="enhanced_robot" xmlns:xacro="http://www.ros.org/wiki/xacro">
<!-- Links and joints as in standard URDF -->
<link name="base_link">
<visual>
<geometry>
<box size="0.5 0.5 0.2"/>
</geometry>
<material name="blue">
<color rgba="0 0 1 1"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.5 0.5 0.2"/>
</geometry>
</collision>
<inertial>
<mass value="1.0"/>
<inertia ixx="0.1" ixy="0" ixz="0" iyy="0.1" iyz="0" izz="0.1"/>
</inertial>
</link>
<!-- Gazebo-specific enhancements -->
<gazebo reference="base_link">
<material>Gazebo/Blue</material>
<mu1>0.2</mu1>
<mu2>0.2</mu2>
</gazebo>
<!-- Gazebo plugin for ROS control -->
<gazebo>
<plugin name="gazebo_ros_control" filename="libgazebo_ros_control.so">
<robotNamespace>/simple_robot</robotNamespace>
<robotSimType>gazebo_ros_control/DefaultRobotHWSim</robotSimType>
</plugin>
</gazebo>
</robot>
Adding Sensors to URDF
<!-- Add a camera sensor to the robot -->
<gazebo reference="camera_link">
<sensor name="camera" type="camera">
<pose>0.1 0 0 0 0 0</pose>
<camera name="head_camera">
<horizontal_fov>1.047</horizontal_fov>
<image>
<width>640</width>
<height>480</height>
<format>R8G8B8</format>
</image>
<clip>
<near>0.1</near>
<far>100</far>
</clip>
</camera>
<always_on>true</always_on>
<update_rate>30</update_rate>
<visualize>true</visualize>
</sensor>
</gazebo>
<!-- Add a LIDAR sensor -->
<gazebo reference="lidar_link">
<sensor name="lidar" type="ray">
<pose>0.1 0 0.1 0 0 0</pose>
<ray>
<scan>
<horizontal>
<samples>360</samples>
<resolution>1.0</resolution>
<min_angle>-3.14159</min_angle>
<max_angle>3.14159</max_angle>
</horizontal>
</scan>
<range>
<min>0.1</min>
<max>10.0</max>
<resolution>0.01</resolution>
</range>
</ray>
<always_on>true</always_on>
<update_rate>10</update_rate>
<visualize>true</visualize>
</sensor>
</gazebo>
<!-- Add an IMU sensor -->
<gazebo reference="imu_link">
<sensor name="imu_sensor" type="imu">
<always_on>true</always_on>
<update_rate>100</update_rate>
<imu>
<angular_velocity>
<x>
<noise type="gaussian">
<mean>0.0</mean>
<stddev>2e-3</stddev>
</noise>
</x>
<y>
<noise type="gaussian">
<mean>0.0</mean>
<stddev>2e-3</stddev>
</noise>
</y>
<z>
<noise type="gaussian">
<mean>0.0</mean>
<stddev>2e-3</stddev>
</noise>
</z>
</angular_velocity>
<linear_acceleration>
<x>
<noise type="gaussian">
<mean>0.0</mean>
<stddev>1.7e-2</stddev>
</noise>
</x>
<y>
<noise type="gaussian">
<mean>0.0</mean>
<stddev>1.7e-2</stddev>
</noise>
</y>
<z>
<noise type="gaussian">
<mean>0.0</mean>
<stddev>1.7e-2</stddev>
</noise>
</z>
</linear_acceleration>
</imu>
</sensor>
</gazebo>
Complete Humanoid Robot Description
Let's create a complete humanoid robot model with Gazebo enhancements:
<?xml version="1.0"?>
<robot name="humanoid_robot" xmlns:xacro="http://www.ros.org/wiki/xacro">
<!-- Include gazebo plugins -->
<gazebo>
<plugin name="gazebo_ros_control" filename="libgazebo_ros_control.so">
<robotNamespace>/humanoid_robot</robotNamespace>
</plugin>
</gazebo>
<!-- Materials -->
<material name="black">
<color rgba="0.0 0.0 0.0 1.0"/>
</material>
<material name="blue">
<color rgba="0.0 0.0 0.8 1.0"/>
</material>
<material name="green">
<color rgba="0.0 0.8 0.0 1.0"/>
</material>
<material name="grey">
<color rgba="0.5 0.5 0.5 1.0"/>
</material>
<material name="orange">
<color rgba="1.0 0.423529411765 0.0392156862745 1.0"/>
</material>
<material name="brown">
<color rgba="0.870588235294 0.811764705882 0.764705882353 1.0"/>
</material>
<material name="red">
<color rgba="0.8 0.0 0.0 1.0"/>
</material>
<material name="white">
<color rgba="1.0 1.0 1.0 1.0"/>
</material>
<!-- Base Link -->
<link name="base_link">
<inertial>
<mass value="1.0"/>
<inertia ixx="0.1" ixy="0.0" ixz="0.0" iyy="0.1" iyz="0.0" izz="0.1"/>
</inertial>
</link>
<!-- Torso -->
<joint name="torso_joint" type="fixed">
<parent link="base_link"/>
<child link="torso"/>
<origin xyz="0 0 0.3" rpy="0 0 0"/>
</joint>
<link name="torso">
<visual>
<geometry>
<box size="0.3 0.3 0.6"/>
</geometry>
<material name="white"/>
</visual>
<collision>
<geometry>
<box size="0.3 0.3 0.6"/>
</geometry>
</collision>
<inertial>
<mass value="10.0"/>
<inertia ixx="0.2" ixy="0.0" ixz="0.0" iyy="0.2" iyz="0.0" izz="0.2"/>
</inertial>
</link>
<!-- Head -->
<joint name="neck_joint" type="revolute">
<parent link="torso"/>
<child link="head"/>
<origin xyz="0 0 0.35" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
<limit lower="-1.0" upper="1.0" effort="10" velocity="2"/>
</joint>
<link name="head">
<visual>
<geometry>
<sphere radius="0.1"/>
</geometry>
<material name="skin"/>
</visual>
<collision>
<geometry>
<sphere radius="0.1"/>
</geometry>
</collision>
<inertial>
<mass value="2.0"/>
<inertia ixx="0.02" ixy="0.0" ixz="0.0" iyy="0.02" iyz="0.0" izz="0.02"/>
</inertial>
</link>
<!-- Camera in the head -->
<joint name="head_camera_joint" type="fixed">
<parent link="head"/>
<child link="head_camera_frame"/>
<origin xyz="0.05 0 0" rpy="0 0 0"/>
</joint>
<link name="head_camera_frame">
<inertial>
<mass value="0.01"/>
<inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0001"/>
</inertial>
</link>
<!-- Left Arm -->
<joint name="left_shoulder_pitch" type="revolute">
<parent link="torso"/>
<child link="left_upper_arm"/>
<origin xyz="0.15 0.1 0.1" rpy="0 0 0"/>
<axis xyz="1 0 0"/>
<limit lower="-1.57" upper="1.57" effort="50" velocity="2"/>
</joint>
<link name="left_upper_arm">
<visual>
<geometry>
<cylinder length="0.3" radius="0.05"/>
</geometry>
<origin xyz="0 0 0.15" rpy="1.57 0 0"/>
</visual>
<collision>
<geometry>
<cylinder length="0.3" radius="0.05"/>
</geometry>
<origin xyz="0 0 0.15" rpy="1.57 0 0"/>
</collision>
<inertial>
<mass value="2.0"/>
<inertia ixx="0.02" ixy="0.0" ixz="0.0" iyy="0.02" iyz="0.0" izz="0.001"/>
</inertial>
</link>
<joint name="left_elbow_joint" type="revolute">
<parent link="left_upper_arm"/>
<child link="left_lower_arm"/>
<origin xyz="0 0 0.3" rpy="0 0 0"/>
<axis xyz="1 0 0"/>
<limit lower="-1.57" upper="1.57" effort="30" velocity="2"/>
</joint>
<link name="left_lower_arm">
<visual>
<geometry>
<cylinder length="0.3" radius="0.04"/>
</geometry>
<origin xyz="0 0 0.15" rpy="1.57 0 0"/>
</visual>
<collision>
<geometry>
<cylinder length="0.3" radius="0.04"/>
</geometry>
<origin xyz="0 0 0.15" rpy="1.57 0 0"/>
</collision>
<inertial>
<mass value="1.5"/>
<inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.01" iyz="0.0" izz="0.001"/>
</inertial>
</link>
<!-- Right Arm (symmetric to left) -->
<joint name="right_shoulder_pitch" type="revolute">
<parent link="torso"/>
<child link="right_upper_arm"/>
<origin xyz="0.15 -0.1 0.1" rpy="0 0 0"/>
<axis xyz="1 0 0"/>
<limit lower="-1.57" upper="1.57" effort="50" velocity="2"/>
</joint>
<link name="right_upper_arm">
<visual>
<geometry>
<cylinder length="0.3" radius="0.05"/>
</geometry>
<origin xyz="0 0 0.15" rpy="1.57 0 0"/>
</visual>
<collision>
<geometry>
<cylinder length="0.3" radius="0.05"/>
</geometry>
<origin xyz="0 0 0.15" rpy="1.57 0 0"/>
</collision>
<inertial>
<mass value="2.0"/>
<inertia ixx="0.02" ixy="0.0" ixz="0.0" iyy="0.02" iyz="0.0" izz="0.001"/>
</inertial>
</link>
<joint name="right_elbow_joint" type="revolute">
<parent link="right_upper_arm"/>
<child link="right_lower_arm"/>
<origin xyz="0 0 0.3" rpy="0 0 0"/>
<axis xyz="1 0 0"/>
<limit lower="-1.57" upper="1.57" effort="30" velocity="2"/>
</joint>
<link name="right_lower_arm">
<visual>
<geometry>
<cylinder length="0.3" radius="0.04"/>
</geometry>
<origin xyz="0 0 0.15" rpy="1.57 0 0"/>
</visual>
<collision>
<geometry>
<cylinder length="0.3" radius="0.04"/>
</geometry>
<origin xyz="0 0 0.15" rpy="1.57 0 0"/>
</collision>
<inertial>
<mass value="1.5"/>
<inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.01" iyz="0.0" izz="0.001"/>
</inertial>
</link>
<!-- Left Leg -->
<joint name="left_hip_joint" type="revolute">
<parent link="torso"/>
<child link="left_upper_leg"/>
<origin xyz="-0.05 0.08 -0.25" rpy="0 0 0"/>
<axis xyz="1 0 0"/>
<limit lower="-1.57" upper="1.57" effort="100" velocity="2"/>
</joint>
<link name="left_upper_leg">
<visual>
<geometry>
<cylinder length="0.4" radius="0.06"/>
</geometry>
<origin xyz="0 0 -0.2" rpy="1.57 0 0"/>
</visual>
<collision>
<geometry>
<cylinder length="0.4" radius="0.06"/>
</geometry>
<origin xyz="0 0 -0.2" rpy="1.57 0 0"/>
</collision>
<inertial>
<mass value="3.0"/>
<inertia ixx="0.05" ixy="0.0" ixz="0.0" iyy="0.05" iyz="0.0" izz="0.002"/>
</inertial>
</link>
<joint name="left_knee_joint" type="revolute">
<parent link="left_upper_leg"/>
<child link="left_lower_leg"/>
<origin xyz="0 0 -0.4" rpy="0 0 0"/>
<axis xyz="1 0 0"/>
<limit lower="0" upper="1.57" effort="80" velocity="2"/>
</joint>
<link name="left_lower_leg">
<visual>
<geometry>
<cylinder length="0.4" radius="0.05"/>
</geometry>
<origin xyz="0 0 -0.2" rpy="1.57 0 0"/>
</visual>
<collision>
<geometry>
<cylinder length="0.4" radius="0.05"/>
</geometry>
<origin xyz="0 0 -0.2" rpy="1.57 0 0"/>
</collision>
<inertial>
<mass value="2.5"/>
<inertia ixx="0.03" ixy="0.0" ixz="0.0" iyy="0.03" iyz="0.0" izz="0.001"/>
</inertial>
</link>
<joint name="left_ankle_joint" type="revolute">
<parent link="left_lower_leg"/>
<child link="left_foot"/>
<origin xyz="0 0 -0.4" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
<limit lower="-0.5" upper="0.5" effort="50" velocity="2"/>
</joint>
<link name="left_foot">
<visual>
<geometry>
<box size="0.2 0.1 0.05"/>
</geometry>
</visual>
<collision>
<geometry>
<box size="0.2 0.1 0.05"/>
</geometry>
</collision>
<inertial>
<mass value="1.0"/>
<inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.01" iyz="0.0" izz="0.01"/>
</inertial>
</link>
<!-- Right Leg (symmetric to left) -->
<joint name="right_hip_joint" type="revolute">
<parent link="torso"/>
<child link="right_upper_leg"/>
<origin xyz="-0.05 -0.08 -0.25" rpy="0 0 0"/>
<axis xyz="1 0 0"/>
<limit lower="-1.57" upper="1.57" effort="100" velocity="2"/>
</joint>
<link name="right_upper_leg">
<visual>
<geometry>
<cylinder length="0.4" radius="0.06"/>
</geometry>
<origin xyz="0 0 -0.2" rpy="1.57 0 0"/>
</visual>
<collision>
<geometry>
<cylinder length="0.4" radius="0.06"/>
</geometry>
<origin xyz="0 0 -0.2" rpy="1.57 0 0"/>
</collision>
<inertial>
<mass value="3.0"/>
<inertia ixx="0.05" ixy="0.0" ixz="0.0" iyy="0.05" iyz="0.0" izz="0.002"/>
</inertial>
</link>
<joint name="right_knee_joint" type="revolute">
<parent link="right_upper_leg"/>
<child link="right_lower_leg"/>
<origin xyz="0 0 -0.4" rpy="0 0 0"/>
<axis xyz="1 0 0"/>
<limit lower="0" upper="1.57" effort="80" velocity="2"/>
</joint>
<link name="right_lower_leg">
<visual>
<geometry>
<cylinder length="0.4" radius="0.05"/>
</geometry>
<origin xyz="0 0 -0.2" rpy="1.57 0 0"/>
</visual>
<collision>
<geometry>
<cylinder length="0.4" radius="0.05"/>
</geometry>
<origin xyz="0 0 -0.2" rpy="1.57 0 0"/>
</collision>
<inertial>
<mass value="2.5"/>
<inertia ixx="0.03" ixy="0.0" ixz="0.0" iyy="0.03" iyz="0.0" izz="0.001"/>
</inertial>
</link>
<joint name="right_ankle_joint" type="revolute">
<parent link="right_lower_leg"/>
<child link="right_foot"/>
<origin xyz="0 0 -0.4" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
<limit lower="-0.5" upper="0.5" effort="50" velocity="2"/>
</joint>
<link name="right_foot">
<visual>
<geometry>
<box size="0.2 0.1 0.05"/>
</geometry>
</visual>
<collision>
<geometry>
<box size="0.2 0.1 0.05"/>
</geometry>
</collision>
<inertial>
<mass value="1.0"/>
<inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.01" iyz="0.0" izz="0.01"/>
</inertial>
</link>
<!-- Gazebo-specific enhancements -->
<gazebo reference="base_link">
<material>Gazebo/Grey</material>
</gazebo>
<gazebo reference="torso">
<material>Gazebo/White</material>
</gazebo>
<gazebo reference="head">
<material>Gazebo/Yellow</material>
</gazebo>
<gazebo reference="left_upper_arm">
<material>Gazebo/Blue</material>
</gazebo>
<gazebo reference="right_upper_arm">
<material>Gazebo/Blue</material>
</gazebo>
<gazebo reference="left_lower_arm">
<material>Gazebo/Blue</material>
</gazebo>
<gazebo reference="right_lower_arm">
<material>Gazebo/Blue</material>
</gazebo>
<gazebo reference="left_upper_leg">
<material>Gazebo/Red</material>
</gazebo>
<gazebo reference="right_upper_leg">
<material>Gazebo/Red</material>
</gazebo>
<gazebo reference="left_lower_leg">
<material>Gazebo/Red</material>
</gazebo>
<gazebo reference="right_lower_leg">
<material>Gazebo/Red</material>
</gazebo>
<gazebo reference="left_foot">
<material>Gazebo/Black</material>
</gazebo>
<gazebo reference="right_foot">
<material>Gazebo/Black</material>
</gazebo>
<!-- Camera sensor in the head -->
<gazebo reference="head_camera_frame">
<sensor name="head_camera" type="camera">
<pose>0 0 0 0 0 0</pose>
<camera name="head_camera">
<horizontal_fov>1.047</horizontal_fov>
<image>
<width>640</width>
<height>480</height>
<format>R8G8B8</format>
</image>
<clip>
<near>0.1</near>
<far>100</far>
</clip>
</camera>
<always_on>true</always_on>
<update_rate>30</update_rate>
<visualize>true</visualize>
</sensor>
</gazebo>
<!-- IMU in the torso -->
<gazebo reference="torso">
<sensor name="imu_sensor" type="imu">
<always_on>true</always_on>
<update_rate>100</update_rate>
</sensor>
</gazebo>
<!-- Gazebo ROS Control plugin -->
<gazebo>
<plugin name="gazebo_ros_control" filename="libgazebo_ros_control.so">
<robotNamespace>/humanoid_robot</robotNamespace>
<controlPeriod>0.001</controlPeriod>
<!-- Use the default robot hardware interface -->
</plugin>
</gazebo>
</robot>
Control Plugins for Simulation
ROS Control Integration
To control the robot in simulation, we need to add ROS Control plugins:
<!-- Transmission elements for ROS Control -->
<transmission name="left_shoulder_pitch_trans">
<type>transmission_interface/SimpleTransmission</type>
<joint name="left_shoulder_pitch">
<hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
</joint>
<actuator name="left_shoulder_pitch_motor">
<hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
<mechanicalReduction>1</mechanicalReduction>
</actuator>
</transmission>
<transmission name="left_elbow_joint_trans">
<type>transmission_interface/SimpleTransmission</type>
<joint name="left_elbow_joint">
<hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
</joint>
<actuator name="left_elbow_joint_motor">
<hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
<mechanicalReduction>1</mechanicalReduction>
</actuator>
</transmission>
<!-- Add transmissions for all joints... -->
Controller Configuration
Create a controller configuration file:
# config/humanoid_controllers.yaml
controller_manager:
ros__parameters:
update_rate: 1000 # Hz
joint_state_controller:
type: joint_state_controller/JointStateController
left_arm_controller:
type: position_controllers/JointTrajectoryController
right_arm_controller:
type: position_controllers/JointTrajectoryController
leg_controller:
type: position_controllers/JointTrajectoryController
left_arm_controller:
ros__parameters:
joints:
- left_shoulder_pitch
- left_elbow_joint
command_interfaces:
- position
state_interfaces:
- position
- velocity
right_arm_controller:
ros__parameters:
joints:
- right_shoulder_pitch
- right_elbow_joint
command_interfaces:
- position
state_interfaces:
- position
- velocity
leg_controller:
ros__parameters:
joints:
- left_hip_joint
- left_knee_joint
- left_ankle_joint
- right_hip_joint
- right_knee_joint
- right_ankle_joint
command_interfaces:
- position
state_interfaces:
- position
- velocity
Best Practices for URDF/SDF Integration
1. Consistent Naming Conventions
Use consistent naming across URDF, SDF, and ROS components:
<!-- Good: Consistent naming -->
<joint name="left_shoulder_pitch" type="revolute">
<parent link="torso"/>
<child link="left_upper_arm"/>
<!-- ... -->
</joint>
<gazebo reference="left_upper_arm">
<!-- Reference the same link name -->
<material>Gazebo/Blue</material>
</gazebo>
2. Proper Inertial Calculations
Calculate realistic inertial properties for each link:
<link name="upper_arm">
<visual>
<geometry>
<cylinder length="0.3" radius="0.05"/>
</geometry>
</visual>
<collision>
<geometry>
<cylinder length="0.3" radius="0.05"/>
</geometry>
</collision>
<!-- Proper inertial calculation for cylinder -->
<inertial>
<mass value="2.0"/>
<!-- For a cylinder: Ixx = Iyy = m*(3*r² + h²)/12, Izz = m*r²/2 -->
<inertia ixx="0.0154" ixy="0" ixz="0"
iyy="0.0154" iyz="0" izz="0.0025"/>
</inertial>
</link>
3. Sensor Noise Modeling
Add realistic noise models to sensors:
<gazebo reference="imu_link">
<sensor name="imu_sensor" type="imu">
<always_on>true</always_on>
<update_rate>100</update_rate>
<imu>
<angular_velocity>
<x>
<noise type="gaussian">
<mean>0.0</mean>
<stddev>2e-3</stddev>
<bias_mean>0.001</bias_mean>
<bias_stddev>0.0001</bias_stddev>
</noise>
</x>
<!-- Similar for y and z axes -->
</angular_velocity>
</imu>
</sensor>
</gazebo>
Hands-On Exercise: Complete Robot Description
Objective
Create a complete humanoid robot description with proper URDF/SDF integration.
Prerequisites
- ROS 2 Humble installed
- Gazebo Fortress installed
- Understanding of URDF basics
Steps
- Create a new ROS 2 package called
humanoid_description - Create a complete URDF for a humanoid robot with:
- Proper kinematic structure
- Visual and collision properties
- Inertial properties
- Gazebo-specific tags
- Sensors (camera, IMU, LIDAR)
- Transmission elements for ROS Control
- Create a controller configuration file
- Test the model in Gazebo
- Verify that sensors are publishing data
Expected Result
Students will have a complete humanoid robot model that can be simulated in Gazebo with realistic physics and sensor simulation.
Assessment Questions
Multiple Choice
Q1: What is the primary difference between URDF and SDF formats?
- a) URDF is for simulation, SDF is for ROS
- b) URDF is for ROS robot descriptions, SDF is for Gazebo simulation
- c) There is no difference, they are the same format
- d) URDF is for sensors, SDF is for actuators
Details
Click to reveal answer
Answer: bExplanation: URDF is the standard format for robot descriptions in ROS, while SDF is the native format for Gazebo simulation. SDF is more comprehensive for simulation-specific features.
Short Answer
Q2: Explain why it's important to add Gazebo-specific tags to a URDF file when using it in simulation.
Practical Exercise
Q3: Create a URDF file for a simple robot with at least 5 joints, add Gazebo-specific tags for physics properties and a camera sensor, and verify that it loads correctly in Gazebo with check_urdf and by launching it in simulation.
Further Reading
- "URDF/XML Guide" - Complete URDF specification
- "SDF Guide" - Complete SDF specification
- "Gazebo Model Tutorial" - Creating models for Gazebo
Summary
In this chapter, we've explored the relationship between URDF and SDF formats, learning how to enhance URDF models with Gazebo-specific tags and create complete robot descriptions for simulation. We've covered the conversion between formats, best practices for integration, and how to add sensors and control plugins to robot models.
Understanding both formats is crucial for creating effective digital twins of humanoid robots, as it allows for proper simulation while maintaining compatibility with ROS 2 systems. The combination of accurate kinematic structure, realistic physics properties, and properly configured sensors enables effective testing and development of humanoid robotics systems in simulation.
In the next chapter, we'll explore physics simulation in detail, learning how to configure and optimize physics parameters for realistic humanoid robot simulation.