Wiki

Note: This tutorial assumes you know how to write well-formatted XML code.
(!) Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags.

Building a Visual Robot Model with URDF from Scratch

Description: Learn how to build a visual model of a robot that you can view in Rviz

Keywords: URDF

Tutorial Level: BEGINNER

Next Tutorial: Making the Model Move

In this tutorial, we’re going to build a visual model of a robot that vaguely looks like R2D2. In later tutorials, you’ll learn how to articulate the model, add in some physical properties, generate neater code with xacro and make it move in Gazebo. But for now, we’re going to focus on getting the visual geometry correct.

Before continuing, make sure you have the joint_state_publisher package installed. If you installed urdf_tutorial using apt-get, this should already be the case. If not, please update your installation to include that package (use rosdep to check).

All of the robot models mentioned in this tutorial (and the source files) can be found in the urdf_tutorial package.

One Shape

First, we’re just going to explore one simple shape. Here’s about as simple as a urdf as you can make. Source

   1 <?xml version="1.0"?>
   2 <robot name="myfirst">
   3   <link name="base_link">
   4     <visual>
   5       <geometry>
   6         <cylinder length="0.6" radius="0.2"/>
   7       </geometry>
   8     </visual>
   9   </link>
  10 </robot>

To translate the XML into English, this is a robot with the name myfirst, that contains only one link (a.k.a. part), whose visual component is just a cylinder 0.6 meters long with a 0.2 meter radius. This may seem like a lot of enclosing tags for a simple “hello world” type example, but it will get more complicated, trust me.

To examine the model, launch the display.launch file:

$ roslaunch urdf_tutorial display.launch model:=urdf/01-myfirst.urdf

This does three things. It

Note that the roslaunch line above assumes that you are executing it from the urdf_tutorial package directory (ie: the urdf directory is a direct child of the current working directory). If that is not the case, the relative path to 01-myfirst.urdf will not be valid, and you'll receive an error as soon as roslaunch tries to load the urdf to the parameter server.

A slightly modified argument allows this to work regardless of the current working directory:

$ roslaunch urdf_tutorial display.launch model:='$(find urdf_tutorial)/urdf/01-myfirst.urdf'

note the single quotes around the argument value.

You'll have to change all example roslaunch lines given in these tutorials if you are not running them from the urdf_tutorial package location.

After launching display.launch, you should end up with RViz showing you the following:

my first image

Things to note:

Multiple Shapes

Now let’s look at how to add multiple shapes/links. If we just add more link elements to the urdf, the parser won’t know where to put them. So, we have to add joints. Joint elements can refer to both flexible and inflexible joints. We’ll start with inflexible, or fixed joints. Source

   1 <?xml version="1.0"?>
   2 <robot name="multipleshapes">
   3   <link name="base_link">
   4     <visual>
   5       <geometry>
   6         <cylinder length="0.6" radius="0.2"/>
   7       </geometry>
   8     </visual>
   9   </link>
  10 
  11   <link name="right_leg">
  12     <visual>
  13       <geometry>
  14         <box size="0.6 0.1 0.2"/>
  15       </geometry>
  16     </visual>
  17   </link>
  18 
  19   <joint name="base_to_right_leg" type="fixed">
  20     <parent link="base_link"/>
  21     <child link="right_leg"/>
  22   </joint>
  23 
  24 </robot>

roslaunch urdf_tutorial display.launch model:=urdf/02-multipleshapes.urdf Multiple Shapes

Both of the shapes overlap with each other, because they share the same origin. If we want them not to overlap we must define more origins.

Origins

R2D2’s leg attaches to the top half of his torso, on the side. So that’s where we specify the origin of the JOINT to be. Also, it doesn’t attach to the middle of the leg, it attaches to the upper part, so we must offset the origin for the leg as well. We also rotate the leg so it is upright. Source

   1 <?xml version="1.0"?>
   2 <robot name="origins">
   3   <link name="base_link">
   4     <visual>
   5       <geometry>
   6         <cylinder length="0.6" radius="0.2"/>
   7       </geometry>
   8     </visual>
   9   </link>
  10 
  11   <link name="right_leg">
  12     <visual>
  13       <geometry>
  14         <box size="0.6 0.1 0.2"/>
  15       </geometry>
  16       <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
  17     </visual>
  18   </link>
  19 
  20   <joint name="base_to_right_leg" type="fixed">
  21     <parent link="base_link"/>
  22     <child link="right_leg"/>
  23     <origin xyz="0 -0.22 0.25"/>
  24   </joint>
  25 
  26 </robot>

roslaunch urdf_tutorial display.launch model:=urdf/03-origins.urdf Origins Screenshot

Material Girl

“Alright,” I hear you say. “That’s very cute, but not everyone owns a B21. My robot and R2D2 are not red!” That’s a good point. Let’s take a look at the material tag. Source

   1 <?xml version="1.0"?>
   2 <robot name="materials">
   3 
   4   <material name="blue">
   5     <color rgba="0 0 0.8 1"/>
   6   </material>
   7 
   8   <material name="white">
   9     <color rgba="1 1 1 1"/>
  10   </material>
  11 
  12 
  13   <link name="base_link">
  14     <visual>
  15       <geometry>
  16         <cylinder length="0.6" radius="0.2"/>
  17       </geometry>
  18       <material name="blue"/>
  19     </visual>
  20   </link>
  21 
  22   <link name="right_leg">
  23     <visual>
  24       <geometry>
  25         <box size="0.6 0.1 0.2"/>
  26       </geometry>
  27       <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
  28       <material name="white"/>
  29     </visual>
  30   </link>
  31 
  32   <joint name="base_to_right_leg" type="fixed">
  33     <parent link="base_link"/>
  34     <child link="right_leg"/>
  35     <origin xyz="0 -0.22 0.25"/>
  36   </joint>
  37 
  38   <link name="left_leg">
  39     <visual>
  40       <geometry>
  41         <box size="0.6 0.1 0.2"/>
  42       </geometry>
  43       <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
  44       <material name="white"/>
  45     </visual>
  46   </link>
  47 
  48   <joint name="base_to_left_leg" type="fixed">
  49     <parent link="base_link"/>
  50     <child link="left_leg"/>
  51     <origin xyz="0 0.22 0.25"/>
  52   </joint>
  53 
  54 </robot>

roslaunch urdf_tutorial display.launch model:=urdf/04-materials.urdf Materials Screenshot

Finishing the Model

Now we finish the model off with a few more shapes: feet, wheels, and head. Most notably, we add a sphere and a some meshes. We’ll also add few other pieces that we’ll use later. Source

   1 <?xml version="1.0"?>
   2 <robot name="visual">
   3 
   4   <material name="blue">
   5     <color rgba="0 0 0.8 1"/>
   6   </material>
   7   <material name="black">
   8     <color rgba="0 0 0 1"/>
   9   </material>
  10   <material name="white">
  11     <color rgba="1 1 1 1"/>
  12   </material>
  13 
  14   <link name="base_link">
  15     <visual>
  16       <geometry>
  17         <cylinder length="0.6" radius="0.2"/>
  18       </geometry>
  19       <material name="blue"/>
  20     </visual>
  21   </link>
  22 
  23   <link name="right_leg">
  24     <visual>
  25       <geometry>
  26         <box size="0.6 0.1 0.2"/>
  27       </geometry>
  28       <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
  29       <material name="white"/>
  30     </visual>
  31   </link>
  32 
  33   <joint name="base_to_right_leg" type="fixed">
  34     <parent link="base_link"/>
  35     <child link="right_leg"/>
  36     <origin xyz="0 -0.22 0.25"/>
  37   </joint>
  38 
  39   <link name="right_base">
  40     <visual>
  41       <geometry>
  42         <box size="0.4 0.1 0.1"/>
  43       </geometry>
  44       <material name="white"/>
  45     </visual>
  46   </link>
  47 
  48   <joint name="right_base_joint" type="fixed">
  49     <parent link="right_leg"/>
  50     <child link="right_base"/>
  51     <origin xyz="0 0 -0.6"/>
  52   </joint>
  53 
  54   <link name="right_front_wheel">
  55     <visual>
  56       <origin rpy="1.57075 0 0" xyz="0 0 0"/>
  57       <geometry>
  58         <cylinder length="0.1" radius="0.035"/>
  59       </geometry>
  60       <material name="black"/>
  61     </visual>
  62   </link>
  63   <joint name="right_front_wheel_joint" type="fixed">
  64     <parent link="right_base"/>
  65     <child link="right_front_wheel"/>
  66     <origin rpy="0 0 0" xyz="0.133333333333 0 -0.085"/>
  67   </joint>
  68 
  69   <link name="right_back_wheel">
  70     <visual>
  71       <origin rpy="1.57075 0 0" xyz="0 0 0"/>
  72       <geometry>
  73         <cylinder length="0.1" radius="0.035"/>
  74       </geometry>
  75       <material name="black"/>
  76     </visual>
  77   </link>
  78   <joint name="right_back_wheel_joint" type="fixed">
  79     <parent link="right_base"/>
  80     <child link="right_back_wheel"/>
  81     <origin rpy="0 0 0" xyz="-0.133333333333 0 -0.085"/>
  82   </joint>
  83 
  84   <link name="left_leg">
  85     <visual>
  86       <geometry>
  87         <box size="0.6 0.1 0.2"/>
  88       </geometry>
  89       <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
  90       <material name="white"/>
  91     </visual>
  92   </link>
  93 
  94   <joint name="base_to_left_leg" type="fixed">
  95     <parent link="base_link"/>
  96     <child link="left_leg"/>
  97     <origin xyz="0 0.22 0.25"/>
  98   </joint>
  99 
 100   <link name="left_base">
 101     <visual>
 102       <geometry>
 103         <box size="0.4 0.1 0.1"/>
 104       </geometry>
 105       <material name="white"/>
 106     </visual>
 107   </link>
 108 
 109   <joint name="left_base_joint" type="fixed">
 110     <parent link="left_leg"/>
 111     <child link="left_base"/>
 112     <origin xyz="0 0 -0.6"/>
 113   </joint>
 114 
 115   <link name="left_front_wheel">
 116     <visual>
 117       <origin rpy="1.57075 0 0" xyz="0 0 0"/>
 118       <geometry>
 119         <cylinder length="0.1" radius="0.035"/>
 120       </geometry>
 121       <material name="black"/>
 122     </visual>
 123   </link>
 124   <joint name="left_front_wheel_joint" type="fixed">
 125     <parent link="left_base"/>
 126     <child link="left_front_wheel"/>
 127     <origin rpy="0 0 0" xyz="0.133333333333 0 -0.085"/>
 128   </joint>
 129 
 130   <link name="left_back_wheel">
 131     <visual>
 132       <origin rpy="1.57075 0 0" xyz="0 0 0"/>
 133       <geometry>
 134         <cylinder length="0.1" radius="0.035"/>
 135       </geometry>
 136       <material name="black"/>
 137     </visual>
 138   </link>
 139   <joint name="left_back_wheel_joint" type="fixed">
 140     <parent link="left_base"/>
 141     <child link="left_back_wheel"/>
 142     <origin rpy="0 0 0" xyz="-0.133333333333 0 -0.085"/>
 143   </joint>
 144 
 145   <joint name="gripper_extension" type="fixed">
 146     <parent link="base_link"/>
 147     <child link="gripper_pole"/>
 148     <origin rpy="0 0 0" xyz="0.19 0 0.2"/>
 149   </joint>
 150 
 151   <link name="gripper_pole">
 152     <visual>
 153       <geometry>
 154         <cylinder length="0.2" radius="0.01"/>
 155       </geometry>
 156       <origin rpy="0 1.57075 0 " xyz="0.1 0 0"/>
 157     </visual>
 158   </link>
 159 
 160   <joint name="left_gripper_joint" type="fixed">
 161     <origin rpy="0 0 0" xyz="0.2 0.01 0"/>
 162     <parent link="gripper_pole"/>
 163     <child link="left_gripper"/>
 164   </joint>
 165 
 166   <link name="left_gripper">
 167     <visual>
 168       <origin rpy="0.0 0 0" xyz="0 0 0"/>
 169       <geometry>
 170         <mesh filename="package://urdf_tutorial/meshes/l_finger.dae"/>
 171       </geometry>
 172     </visual>
 173   </link>
 174 
 175   <joint name="left_tip_joint" type="fixed">
 176     <parent link="left_gripper"/>
 177     <child link="left_tip"/>
 178   </joint>
 179 
 180   <link name="left_tip">
 181     <visual>
 182       <origin rpy="0.0 0 0" xyz="0.09137 0.00495 0"/>
 183       <geometry>
 184         <mesh filename="package://urdf_tutorial/meshes/l_finger_tip.dae"/>
 185       </geometry>
 186     </visual>
 187   </link>
 188   <joint name="right_gripper_joint" type="fixed">
 189     <origin rpy="0 0 0" xyz="0.2 -0.01 0"/>
 190     <parent link="gripper_pole"/>
 191     <child link="right_gripper"/>
 192   </joint>
 193 
 194   <link name="right_gripper">
 195     <visual>
 196       <origin rpy="-3.1415 0 0" xyz="0 0 0"/>
 197       <geometry>
 198         <mesh filename="package://urdf_tutorial/meshes/l_finger.dae"/>
 199       </geometry>
 200     </visual>
 201   </link>
 202 
 203   <joint name="right_tip_joint" type="fixed">
 204     <parent link="right_gripper"/>
 205     <child link="right_tip"/>
 206   </joint>
 207 
 208   <link name="right_tip">
 209     <visual>
 210       <origin rpy="-3.1415 0 0" xyz="0.09137 0.00495 0"/>
 211       <geometry>
 212         <mesh filename="package://urdf_tutorial/meshes/l_finger_tip.dae"/>
 213       </geometry>
 214     </visual>
 215   </link>
 216 
 217   <link name="head">
 218     <visual>
 219       <geometry>
 220         <sphere radius="0.2"/>
 221       </geometry>
 222       <material name="white"/>
 223     </visual>
 224   </link>
 225   <joint name="head_swivel" type="fixed">
 226     <parent link="base_link"/>
 227     <child link="head"/>
 228     <origin xyz="0 0 0.3"/>
 229   </joint>
 230 
 231   <link name="box">
 232     <visual>
 233       <geometry>
 234         <box size="0.08 0.08 0.08"/>
 235       </geometry>
 236       <material name="blue"/>
 237     </visual>
 238   </link>
 239 
 240   <joint name="tobox" type="fixed">
 241     <parent link="head"/>
 242     <child link="box"/>
 243     <origin xyz="0.1814 0 0.1414"/>
 244   </joint>
 245 </robot>

roslaunch urdf_tutorial display.launch model:=urdf/05-visual.urdf Visual Screenshot

How to add the sphere should be fairly self explanatory:

   1   <link name="head">
   2     <visual>
   3       <geometry>
   4         <sphere radius="0.2"/>
   5       </geometry>
   6       <material name="white"/>
   7     </visual>
   8   </link>

The meshes here were borrowed from the PR2. They are separate files which you have to specify the path for. You should use the package://NAME_OF_PACKAGE/path notation. The meshes for this tutorial are located within the urdf_tutorial package, in a folder called meshes.

   1   <link name="left_gripper">
   2     <visual>
   3       <origin rpy="0.0 0 0" xyz="0 0 0"/>
   4       <geometry>
   5         <mesh filename="package://urdf_tutorial/meshes/l_finger.dae"/>
   6       </geometry>
   7     </visual>
   8   </link>

There you have it. A R2D2-like URDF model. Now you can continue on to the next step, making it move.

Video Demonstration

Watch the video below to have more explanation on URDF Creation with step by step guide .

Wiki: urdf/Tutorials/Building a Visual Robot Model with URDF from Scratch (last edited 2022-11-26 10:08:05 by Muhammad Luqman)