Writing URDF
URDF is the description of your robot. It describes how your robot looks like (the number of links, properties of the links, types of joints, where the joints located, properties of the joints, etc) and how the links of the robot move relative to each other. The kinematics of your robot is based on the URDF. Not only kinematics, the rigid body dynamics of the robot is also based on the inertial properties of the robot links provided in the URDF. Some kinematics and dynamics solvers work based on URDF. RViz, the visualization tool in ROS, also works based on URDF. For these reasons, URDF is one of the most important components of your robot.
Some robot manufacturers provide the URDF of their robots so that the robot users can directly develop other components/capabilities of the robot by using the already-provided URDF, i.e. the robot users do not need to write the URDF on their own. They probably just need to append/modify the URDF if they attach additional parts (such as camera and other sensors) to the robots.
A good practice is to write the URDF of your robot in a separate package called my_robot_description. It typically consists of at least two folders: urdf (in which you put your urdf file) and meshes (in which you store the CAD files of the robot links), as well as two files: package.xml and CMakeLists.txt.
URDF is written in XML. Hence, the description of the robot is provided by using some tags. The complete documentation of the XML tags of URDF can be found here: http://wiki.ros.org/urdf/XML. This can be considered the most important reference to write URDF.
So far, URDF can only describe a robot having serial or tree-like topology. URDF cannot describe a robot having a closed-chain topology.
Important concept: Mechanically, a robot only consists of two kinds of parts: 1) links and 2) joints. Two links are joined together by a joint. The type of joint defines how the two joined links move with respect to each other.
The main steps to create a URDF are the following:
- Define all the links and the joints.
- Define the geometry of each link.
- Define the reference frames of each link.
- Define the relative pose between two adjacent reference frames.
The more detailed steps are described below. Let’s call our robot “my_robot”. For simplicity, here it just has two links joined by a “continuous” joint. We will write the URDF in a file called “my_robot.urdf”.
Step 1: Define all the links and the joints.
1 2 3 4 5 6 7 8 9 10 11 12 |
<?xml version="1.0"?> <robot name="my_robot"> <link name="link1" /> <link name="link2" /> <joint name="joint1" type="continuous"> <parent link="link1"/> <child link="link2"/> </joint> </robot> |
Here we can see that the robot namely “my_robot” has two links called “link1” and “link2”. The “link1” link serves as the parent link whereas the “link2” link serves as the child link. The two links are connected by a “continuous” joint called “joint1”. A continuous joint is a revolute joint which can rotate continuously (without lower and upper limits) about its axis.
Step 2: Define the properties of the links. The most important properties are the <geometry> and <origin> tags inside the <visual> tag. Edit the <link> tags to the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<link name="link1"> <visual> <geometry> <box size="0.1 0.2 1.0"/> </geometry> <origin rpy="0 0 0" xyz="0 0 0.4"/> </visual> </link> <link name="link2"> <visual> <geometry> <box size="0.1 0.2 1.0"/> </geometry> <origin rpy="0 0 0" xyz="0 0 -0.4"/> </visual> </link> |
Inside the tag <visual>, we define the geometry of each link by using the tag <geometry> and we define the pose of the reference frame of each link by using the tag <origin>.
- The geometry can be defined by using some primitive geometrical shapes (such as box and cylinder) or by providing a CAD file (in DAE or STL formats).
- The pose of the link reference frame is measured with respect to the default link reference frame (located at the center of the link geometry). Hence, the tag <origin> inside the tag <visual> basically offsetting the link reference frame from the default reference frame.
In the example above, we offset the origin of the reference frame of link1 by 0.4 m in the Z axis without changing the frame orientation. We offset the origin of the reference frame of link2 by -0.4 m in the Z axis without changing the frame orientation. By offsetting the link’s reference frame like this, we can make the child link’s reference frame aligned with the joint. If we don’t do this offset, the link reference frame will stay at the center of each link’s geometry.
If you use CAD mesh files (either DAE or STL), you can modify the link tags to something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<link name="link1"> <visual> <geometry> <mesh filename="package://<package_name>/meshes/link1.dae"/> </geometry> <origin rpy="0 0 0" xyz="0 0 0.4"/> </visual> </link> <link name="link2"> <visual> <geometry> <mesh filename="package://<package_name>/meshes/link2.dae"/> </geometry> <origin rpy="0 0 0" xyz="0 0 -0.4"/> </visual> </link> |
Make sure that you provide the mentioned CAD files in the “meshes” folder inside the package folder.
Furthermore, we can add some other properties of the link inside the tag <geometry>. For example, we can add <color> tag nested inside <material> tag. First, it is convenient to define the color as its RGBA values early in the <material> tag inside the <robot> tag, and subsequently we can define the <material> tag in the <visual> tag inside the <link> tag.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<?xml version="1.0"?> <robot name="my_robot"> <material name="blue"> <color rgba="0 0 0.8 1"/> </material> <material name="white"> <color rgba="1 1 1 1"/> </material> <link name="link1"> <visual> <geometry> <box size="0.1 0.2 1.0"/> </geometry> <material name="blue"/> <origin rpy="0 0 0" xyz="0 0 0.4"/> </visual> </link> <link name="link2"> <visual> <geometry> <box size="0.1 0.2 1.0"/> </geometry> <material name="white"/> <origin rpy="0 0 0" xyz="0 0 -0.4"/> </visual> </link> |
Step 3: Define the relative pose of the child link with respect to the parent link. Edit the <joint> tag to the following:
1 2 3 4 5 6 |
<joint name="joint1" type="continuous"> <parent link="link1"/> <child link="link2"/> <origin xyz="0 0 0" rpy="0 0 0"/> <axis xyz="0 1 0"/> </joint> |
Here, the tag <origin> defines the relative position of the child link’s reference frame origin with respect to the parent link’s reference frame origin, whereas the tag <axis> defines the orientation of the joint. For example, in a continuous or revolute joint, the tag <axis> defines the rotation axis of the joint. In a prismatic joint, the tag <axis> defined the sliding axis of the joint.
In the example above, we define the relative pose between link1’s reference frame and link2’s reference frame as zero translation (in x, y, and z) and zero orientation change. The translation of the frames’ origin is zero since we already make an offset of the reference frame’s origin of each link.
Step 4: Add collision avoidance.
So far, we already define how the links look like by using <visual> tags. To avoid collision between links, you should add <collision> tag inside the <link> tag.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<?xml version="1.0"?> <robot name="my_robot"> <material name="blue"> <color rgba="0 0 0.8 1"/> </material> <material name="white"> <color rgba="1 1 1 1"/> </material> <link name="link1"> <visual> <geometry> <box size="0.1 0.2 1.0"/> </geometry> <material name="blue"/> <origin rpy="0 0 0" xyz="0 0 0.4"/> </visual> <collision> <geometry> <box size="0.1 0.2 1.0"/> </geometry> </collision> </link> <link name="link2"> <visual> <geometry> <box size="0.1 0.2 1.0"/> </geometry> <material name="white"/> <origin rpy="0 0 0" xyz="0 0 -0.4"/> </visual> <collision> <geometry> <box size="0.1 0.2 1.0"/> </geometry> </collision> </link> <joint name="joint1" type="continuous"> <parent link="link1"/> <child link="link2"/> <origin xyz="0 0 0" rpy="0 0 0"/> <axis xyz="0 1 0"/> </joint> </robot> |
Step 5: Add the inertial information of the links.
There are three inertial parameters we should provide for each link: 1) origin of the link’s inertial reference frame, 2) mass of the link, and 3) (second) mass moment of inertia of the link. The three parameters are defined by using <origin>, <mass>, and <inertia> tags in the <inertial> tag inside the <link> tag.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
<?xml version="1.0"?> <robot name="my_robot"> <material name="blue"> <color rgba="0 0 0.8 1"/> </material> <material name="white"> <color rgba="1 1 1 1"/> </material> <link name="link1"> <visual> <geometry> <box size="0.1 0.2 1.0"/> </geometry> <material name="blue"/> <origin rpy="0 0 0" xyz="0 0 0.4"/> </visual> <collision> <geometry> <box size="0.1 0.2 1.0"/> </geometry> </collision> <inertial> <origin="0 0 -0.4"/> <mass value="10"/> <inertia ixx="0.4" ixy="0.0" ixz="0.0" iyy="0.4" iyz="0.0" izz="0.2"/> </inertial> </link> <link name="link2"> <visual> <geometry> <box size="0.1 0.2 1.0"/> </geometry> <material name="white"/> <origin rpy="0 0 0" xyz="0 0 -0.4"/> </visual> <collision> <geometry> <box size="0.1 0.2 1.0"/> </geometry> </collision> <inertial> <origin="0 0 0.4"/> <mass value="10"/> <inertia ixx="0.4" ixy="0.0" ixz="0.0" iyy="0.4" iyz="0.0" izz="0.2"/> </inertial> </link> <joint name="joint1" type="continuous"> <parent link="link1"/> <child link="link2"/> <origin xyz="0 0 0" rpy="0 0 0"/> <axis xyz="0 1 0"/> </joint> </robot> |
The origin of the link’s inertial frame represents the center of the link’s mass. It is defined with respect to the link reference frame. The (second) mass moment of inertia of the link is defined with respect to the origin of the link’s inertial frame (denoted by the <origin> tag inside the <inertial> tag. The mass moment of inertia is actually a 3×3 matrix having six elements as follows:
1 2 3 |
ixx ixy ixz ixy iyy iyz ixz iyz izz |
Since the matrix is symmetric, only six elements are required to define the matrix.
Notice:
- You see that we have three different <origin> tags. The first is in the “visual” tag inside the “link” tag, the second is in the “joint” tag, and the third is inside the <inertial> tag. The first is to offset the position of the origin of the link reference frames with respect to the center of the link’s geometry, the second is the define the relative position of the origin of the child link reference frame with respect to the parent link reference frame, and the third is to define the origin of the link’s inertial frame with respect to the link reference frame.
- The default values of the <origin> tags are xyz = “0 0 0” and rpy = “0 0 0”. If not specified, these values will be taken.
- The units used in URDF is MKS (meter, kilogram, second) SI units. In this case, the angle is defined by using radian, not degree.
To check your URDF, use the following command:
1 |
check_urdf my_robot.urdf |
To check your URDF graphically, use the following command:
1 |
urdf_to_graphiz my_robot.urdf |