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).
SDF - Used for simulation models in Gazebo
URDF - Used to describe elements of a robot, mainly for use in localization
XACRO - File type which allows you to combine a series of URDF files together into one file. Mainly used for breaking down / organizing large URDF files.
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.
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.
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.
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.
https://docs.ros.org/en/foxy/Tutorials/URDF/Using-URDF-with-Robot-State-Publisher.html
https://github.com/benbongalon/ros2-urdf-tutorial/tree/master/urdf_tutorial
https://github.com/cra-ros-pkg/robot_localization/tree/foxy-devel