Skip to main content

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

AspectURDFSDF
Primary UseROS robot descriptionsGazebo simulation
Kinematic Structure
Simulation Physics❌ (with plugins)
SensorsBasic definitionDetailed 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

  1. Create a new ROS 2 package called humanoid_description
  2. 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
  3. Create a controller configuration file
  4. Test the model in Gazebo
  5. 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: b
Explanation: 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

  1. "URDF/XML Guide" - Complete URDF specification
  2. "SDF Guide" - Complete SDF specification
  3. "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.