URDF Files: What They Are, And When To Use Them

In the previous lectures we created simulation models which could interact with ROS2 from within the Gazebo simulator. This model was created using a Simulation Description Format (SDF). However there may be times when you are working with ROS packages (generally having to do with robot localization) which you will need to use a Unified Robotic Description Format (URDF).

Utilizing URDF files for localization and/or simulation purposes in ROS2 is an advanced topic which goes far beyond the scope of this course. But I want you to be aware that URDF files exist, so that should you ever need it for your own future ROS projects, you are aware of it. It is also worth noting that availability of public projects/resources which use URDF in ROS2 are still very rare (mainly due to the fact that ROS2 is still relatively new).


ROS Simulation File Type Usage:


Examples Of When To Use URDF

Let’s say you had an outdoor mobile robot that was equipped with GPS and IMU sensors. You may want to map out it’s position relative to its global environment. In which case you may want to create a URDF file which describes the relationship between the position/orientation of the sensors relative to your robot. This would allow you to understand more precisely the position/orientation of the robot when the corresponding sensor data is received.

Some packages that may help you to accomplish this include the robot_state_publisher (publish static transforms or bot/sensors), joint_state_publisher (publish transforms or entities joined together with joints that can move), and the robot_localization ROS packages. Resources links can be found at the bottom of this article.


Using URDF With Gazebo Simulation

I highly discourage utilizing URDF in Gazebo unless you have to. In general it will be much more straightforward to simply use the SDF file format we have used throughout this section.

When utilizing URDF in gazebo, you will most likely want to create an entire ROS package dedicated to organizing your files. Including folders which will hold configurations, launch files, meshes, models, URDF files, and possibly even world files. You will need to use the urdf_spawner ROS package to convert your URDF into an SDF format and place it into Gazebo. You will most likely want to have this configured within a launch file. Resource on this can be found at the bottom of this document.


What Does URDF Format Look Like?

URDF file is somewhat similar to SDF files, mainly in the sense that it is XML based. But let’s look at an example URDF file, followed by an equivalent example SDF file.


URDF File Example:

<?xml version="1.0" encoding="UTF-8"?>
<robot name="camera_bot" >

<link name="base">
   <inertial>
     <mass value="1"/>
     <inertia
       ixx="0.166667" ixy="0" ixz="0"
       iyx="0" iyy="0.166667" iyz="0"
       izx="0" izy="0" izz="0.166667"
      />
   </inertial>

  <visual name='visual'>
    <geometry>
       <box size="0.5 1 0.25" />
    </geometry>
    <material name="blue" >
      <color rgba="0 0 1 1" />
    </material>
  </visual>

  <collision name='collision'>
    <geometry>
      <box size="0.5 1 0.25" />
    </geometry>
  </collision>

 </link>


<link name='wheel_BR'>
 <inertial>
   <mass value="1" />
   <inertia
   ixx="0.145833" ixy="0" ixz="0"
   iyx="0" iyy="0.145833" iyz="0"
   izx="0" izy="0" izz="0.125"
   />
 </inertial>

 <visual name='visual'>
   <geometry>
     <cylinder radius="0.25" length="0.1"/>
   </geometry>
 </visual>

  <collision name='collision'>
    <geometry>
      <cylinder radius="0.25" length="0.1"/>
    </geometry>
  </collision>
 </link>


...

 <joint name='wheel_BR_joint' type="continuous">
   <origin xyz="0.3 -0.5 0" rpy="-3.14159 1.57079 -3.14159" />
   <parent link="base" />
   <child link="wheel_BR" />
   <axis xyz="0 0 -1" />
 </joint>
...
</robot>



SDF File Example:

<?xml version='1.0'?>
<sdf version='1.7'>
 <model name='camera_bot'>
   <link name='base'>
     <inertial>
       <mass>1</mass>
       <inertia>
         <ixx>0.166667</ixx>
         <ixy>0</ixy>
         <ixz>0</ixz>
         <iyy>0.166667</iyy>
         <iyz>0</iyz>
         <izz>0.166667</izz>
      </inertia>
      <pose>0 0 0 0 -0 0</pose>
   </inertial>
   <pose>0 -0.071429 -0.228571 0 -0 0</pose>
   <gravity>1</gravity>
   <self_collide>0</self_collide>
   <kinematic>0</kinematic>
   <enable_wind>0</enable_wind>

   <visual name='visual'>
     <pose>0 0 0 0 -0 0</pose>
     <geometry>
       <box>
        <size>0.5 1 0.25</size>
       </box>
     </geometry>
     <material>
        <lighting>1</lighting>
          <script>
             <uri>file://media/materials/scripts/gazebo.material</uri>
            <name>Gazebo/Grey</name>
          </script>
       <shader type='pixel'>
         <normal_map>__default__</normal_map>
       </shader>
       <ambient>0.3 0.3 0.3 1</ambient>
       <diffuse>0.7 0.7 0.7 1</diffuse>
       <specular>0.01 0.01 0.01 1</specular>
       <emissive>0 0 0 1</emissive>
     </material>
     <transparency>0</transparency>
     <cast_shadows>1</cast_shadows>
   </visual>

   <collision name='collision'>
     <laser_retro>0</laser_retro>
     <max_contacts>10</max_contacts>
     <pose>0 0 0 0 -0 0</pose>
     <geometry>
       <box>
         <size>0.5 1 0.25</size>
       </box>
    </geometry>
    <surface>
       <friction>
       <ode>
         <mu>1</mu>
         <mu2>1</mu2>
         <fdir1>0 0 0</fdir1>
         <slip1>0</slip1>
         <slip2>0</slip2>
       </ode>
       <torsional>
         <coefficient>1</coefficient>
         <patch_radius>0</patch_radius>
        <surface_radius>0</surface_radius>
        <use_patch_radius>1</use_patch_radius>
        <ode>
           <slip>0</slip>
        </ode>
       </torsional>
     </friction>
     <bounce>
       <restitution_coefficient>0</restitution_coefficient>
       <threshold>1e+06</threshold>
     </bounce>
     <contact>
       <collide_without_contact>0</collide_without_contact>
       <collide_without_contact_bitmask>1</collide_without_contact_bitmask>
       <collide_bitmask>1</collide_bitmask>
       <ode>
         <soft_cfm>0</soft_cfm>
         <soft_erp>0.2</soft_erp>
         <kp>1e+13</kp>
         <kd>1</kd>
         <max_vel>0.01</max_vel>
         <min_depth>0</min_depth>
      </ode>
      <bullet>
        <split_impulse>1</split_impulse>
         <split_impulse_penetration_threshold>-0.01</split_impulse_penetration_threshold>
         <soft_cfm>0</soft_cfm>
         <soft_erp>0.2</soft_erp>
         <kp>1e+13</kp>
         <kd>1</kd>
     </bullet>
   </contact>
   </surface>
 </collision>
</link>

 <link name='wheel_BR'>
   <inertial>
     <mass>1</mass>
     <inertia>
       <ixx>0.145833</ixx>
       <ixy>0</ixy>
       <ixz>0</ixz>
       <iyy>0.145833</iyy>
       <iyz>0</iyz>
       <izz>0.125</izz>
     </inertia>
     <pose>0 0 0 0 -0 0</pose>
   </inertial>
   <pose>0.3 -0.571429 -0.228571 0 1.57079 0</pose>
   <gravity>1</gravity>
   <self_collide>0</self_collide>
   <kinematic>0</kinematic>
   <enable_wind>0</enable_wind>

   <visual name='visual'>
     <pose>0 0 0 0 -0 0</pose>
     <geometry>
       <cylinder>
         <radius>0.25</radius>
         <length>0.1</length>
       </cylinder>
     </geometry>
     <material>
       <lighting>1</lighting>
       <script>
         <uri>file://media/materials/scripts/gazebo.material</uri>
         <name>Gazebo/Grey</name>
      </script>
      <shader type='pixel'>
        <normal_map>__default__</normal_map>
      </shader>
      <ambient>0.3 0.3 0.3 1</ambient>
      <diffuse>0.7 0.7 0.7 1</diffuse>
      <specular>0.01 0.01 0.01 1</specular>
      <emissive>0 0 0 1</emissive>
    </material>
    <transparency>0</transparency>
    <cast_shadows>1</cast_shadows>
   </visual>

   <collision name='collision'>
     <laser_retro>0</laser_retro>
     <max_contacts>10</max_contacts>
     <pose>0 0 0 0 -0 0</pose>
     <geometry>
        <cylinder>
          <radius>0.25</radius>
          <length>0.1</length>
       </cylinder>
      </geometry>
      <surface>
         <friction>
          <ode>
            <mu>0.1</mu>
            <mu2>0.1</mu2>
            <fdir1>0 0 0</fdir1>
            <slip1>0</slip1>
            <slip2>0</slip2>
          </ode>
          <torsional>
             <coefficient>1</coefficient>
             <patch_radius>0</patch_radius>
             <surface_radius>0</surface_radius>
             <use_patch_radius>1</use_patch_radius>
             <ode>
               <slip>0</slip>
             </ode>
          </torsional>
        </friction>
        <bounce>
          <restitution_coefficient>0</restitution_coefficient>
          <threshold>1e+06</threshold>
        </bounce>
        <contact>
           <collide_without_contact>0</collide_without_contact>
           <collide_without_contact_bitmask>1</collide_without_contact_bitmask>
           <collide_bitmask>1</collide_bitmask>
           <ode>
             <soft_cfm>0</soft_cfm>
             <soft_erp>0.2</soft_erp>
             <kp>1e+13</kp>
             <kd>1</kd>
             <max_vel>0.01</max_vel>
             <min_depth>0</min_depth>
           </ode>
          <bullet>
             <split_impulse>1</split_impulse>
             <split_impulse_penetration_threshold>-0.01</split_impulse_penetration_threshold>
             <soft_cfm>0</soft_cfm>
             <soft_erp>0.2</soft_erp>
             <kp>1e+13</kp>
             <kd>1</kd>
         </bullet>
      </contact>
    </surface>
   </collision>
 </link>
...
  <joint name='base_JOINT_3' type='revolute'>
    <parent>base</parent>
    <child>wheel_BR</child>
    <pose>0 0 0 0 -0 0</pose>
    <axis>
      <xyz>-0 -0 -1</xyz>
      <limit>
        <lower>-1.79769e+308</lower>
        <upper>1.79769e+308</upper>
        <effort>-1</effort>
        <velocity>-1</velocity>
      </limit>
      <dynamics>
        <spring_reference>0</spring_reference>
        <spring_stiffness>0</spring_stiffness>
        <damping>0</damping>
      </dynamics>
   </axis>
   <physics>
     <ode>
       <limit>
         <cfm>0</cfm>
         <erp>0.2</erp>
       </limit>
       <suspension>
          <cfm>0</cfm>
          <erp>0.2</erp>
      </suspension>
    </ode>
  </physics>
 </joint>


These two examples are snippets of a model which has a rectangular base which shares a joint with a cylinder (wheel) which allows it to spin relative to the base. Based on these two examples, you can see the SDF has much more information, mainly towards physical attributes of each component which are needed for the simulation physics calculations.


Closing:

In most scenarios, most ROS/ROS2 developers will not have to worry about URDF files unless they need it for performing advanced robot localization tasks. In which case the URDF file describes robot component/sensor placement, generally as a way to help compute robot component position/transforms based on sensor data.


Other Resources: