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.
In these tutorials, we’re going to rely on some tools and launch files from the urdf_tools package. Most notably, joint_state_publisher needs to be downloaded from the Washington University repository, linked to on the joint_state_publisher wiki page. All of the robot models mentioned in this tutorial can be found in the urdf_tutorial package.
<span class="anchor" id="line-1-2"></span>$ rosdep install joint_state_publisher <span class="anchor" id="line-2-2"></span>$ rosdep install urdf_tutorial <span class="anchor" id="line-3-2"></span>$ roscd urdf_tutorial
There is currently a known bug in the urdf_tutorial launch files. See urdf_tutorial/issues/6 for the issue, and no robot visible in rviz for urdf tutorial on ROS Answers for a temporary work-around.
Starting with urdf_tutorial version 0.2.3 this workaround is no longer needed. The commands in this (and the following) tutorial(s) have been updated to work with the new version of the 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
<span class="line"><span class="LineAnchor" id="CA-360a598e8173ffe3fdd7978b189831b146e02d97_1"></span><span class="anchor" id="line-1-6"></span><span class="Preprc"><?xml version="1.0"?></span></span> <span class="line"><span class="ID"><robot</span> <span class="ID">name=</span><span class="String">"myfirst"</span><span class="ID">></span></span> <span class="line"><span class="ID"><link</span> <span class="ID">name=</span><span class="String">"base_link"</span><span class="ID">></span></span> <span class="line"><span class="ID"><visual</span><span class="ID">></span></span> <span class="line"><span class="ID"><geometry</span><span class="ID">></span></span> <span class="line"><span class="ID"><cylinder</span> <span class="ID">length=</span><span class="String">"0.6"</span> <span class="ID">radius=</span><span class="String">"0.2"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></geometry></span></span> <span class="line"><span class="ID"></visual></span></span> <span class="line"><span class="ID"></link></span></span> <span class="line"><span class="LineAnchor" id="CA-360a598e8173ffe3fdd7978b189831b146e02d97_10"></span><span class="anchor" id="line-10-2"></span><span class="ID"></robot></span></span>
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 .6 meters long with a .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, type roslaunch urdf_tutorial display.launch model:=urdf/01-myfirst.urdf This does three things. It
- Loads the specified model into the parameter server
-
Runs nodes to publish the JointState and transforms (more on these later)
- Starts Rviz with a configuration file
This launch file assumes that 01-myfirst.urdf is in the urdf subdirectory of the directory that you type the command in. Otherwise, you should say model:='$(find pkg-name)/urdf/01-myfirst.urdf' where pkg-name is the name of the package that the file is in (single quotes required). All of the example files are in the urdf_tutorial package, so if you are in that directory you can run the commands without modification.
The model we made should look like this
Things to note:
- The fixed frame is transform frame where the center of the grid is located. Here, it’s a frame defined by our one link, base_link.
- The visual element (the cylinder) has its origin at the center of its geometry as a default. Hence, half the cylinder is below the grid.
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
<span class="line"><span class="LineAnchor" id="CA-5536eaca6fd62b558920aa76c7af49a511c91a0e_1"></span><span class="anchor" id="line-1-8"></span><span class="Preprc"><?xml version="1.0"?></span></span> <span class="line"><span class="ID"><robot</span> <span class="ID">name=</span><span class="String">"multipleshapes"</span><span class="ID">></span></span> <span class="line"><span class="ID"><link</span> <span class="ID">name=</span><span class="String">"base_link"</span><span class="ID">></span></span> <span class="line"><span class="ID"><visual</span><span class="ID">></span></span> <span class="line"><span class="ID"><geometry</span><span class="ID">></span></span> <span class="line"><span class="ID"><cylinder</span> <span class="ID">length=</span><span class="String">"0.6"</span> <span class="ID">radius=</span><span class="String">"0.2"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></geometry></span></span> <span class="line"><span class="ID"></visual></span></span> <span class="line"><span class="ID"></link></span></span> <span class="line"><span class="ID"><link</span> <span class="ID">name=</span><span class="String">"right_leg"</span><span class="ID">></span></span> <span class="line"><span class="ID"><visual</span><span class="ID">></span></span> <span class="line"><span class="ID"><geometry</span><span class="ID">></span></span> <span class="line"><span class="ID"><box</span> <span class="ID">size=</span><span class="String">"0.6 .2 .1"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></geometry></span></span> <span class="line"> <span class="ID"></visual></span></span> <span class="line"><span class="ID"></link></span></span> <span class="line"><span class="ID"><joint</span> <span class="ID">name=</span><span class="String">"base_to_right_leg"</span> <span class="ID">type=</span><span class="String">"fixed"</span><span class="ID">></span></span> <span class="line"><span class="ID"><parent</span> <span class="ID">link=</span><span class="String">"base_link"</span><span class="ID">/></span></span> <span class="line"><span class="ID"><child</span> <span class="ID">link=</span><span class="String">"right_leg"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></joint></span></span> <span class="line"><span class="LineAnchor" id="CA-5536eaca6fd62b558920aa76c7af49a511c91a0e_24"></span><span class="anchor" id="line-24-1"></span><span class="ID"></robot></span></span>
- Note how we defined a 0.6m x 0.2m x 0.1m box
- The joint is defined in terms of a parent and a child. URDF is ultimately a tree structure with one root link. This means that the leg’s position is dependent on the base_link’s position.
roslaunch urdf_tutorial display.launch model:=urdf/02-multipleshapes.urdf
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
So 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
<span class="line"><span class="LineAnchor" id="CA-d6ff7c253db5895c6a687a53822c54fc90dceee6_1"></span><span class="anchor" id="line-1-10"></span><span class="Preprc"><?xml version="1.0"?></span></span> <span class="line"><span class="LineAnchor" id="CA-d6ff7c253db5895c6a687a53822c54fc90dceee6_2"></span><span class="anchor" id="line-2-5"></span><span class="ID"><robot</span> <span class="ID">name=</span><span class="String">"origins"</span><span class="ID">></span></span> <span class="line"><span class="ID"><link</span> <span class="ID">name=</span><span class="String">"base_link"</span><span class="ID">></span></span> <span class="line"><span class="ID"><visual</span><span class="ID">></span></span> <span class="line"><span class="ID"><geometry</span><span class="ID">></span></span> <span class="line"><span class="ID"><cylinder</span> <span class="ID">length=</span><span class="String">"0.6"</span> <span class="ID">radius=</span><span class="String">"0.2"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></geometry></span></span> <span class="line"><span class="ID"></visual></span></span> <span class="line"><span class="ID"></link></span></span> <span class="line"><span class="ID"><link</span> <span class="ID">name=</span><span class="String">"right_leg"</span><span class="ID">></span></span> <span class="line"><span class="ID"><visual</span><span class="ID">></span></span> <span class="line"><span class="ID"><geometry</span><span class="ID">></span></span> <span class="line"><span class="ID"><box</span> <span class="ID">size=</span><span class="String">"0.6 .2 .1"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></geometry></span></span> <span class="line"><span class="ID"><origin</span> <span class="ID">rpy=</span><span class="String">"0 1.57075 0"</span> <span class="ID">xyz=</span><span class="String">"0 0 -0.3"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></visual></span></span> <span class="line"><span class="ID"></link></span></span> <span class="line"><span class="ID"><joint</span> <span class="ID">name=</span><span class="String">"base_to_right_leg"</span> <span class="ID">type=</span><span class="String">"fixed"</span><span class="ID">></span></span> <span class="line"><span class="ID"><parent</span> <span class="ID">link=</span><span class="String">"base_link"</span><span class="ID">/></span></span> <span class="line"><span class="ID"><child</span> <span class="ID">link=</span><span class="String">"right_leg"</span><span class="ID">/></span></span> <span class="line"><span class="ID"><origin</span> <span class="ID">xyz=</span><span class="String">"0.22 0 .25"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></joint></span></span> <span class="line"><span class="ID"></robot></span></span>
- Let’s start by examining the joint’s origin. It is defined in terms of the parent’s reference frame. So we are .22 meters in the x direction (left) and .25 meters in the z direction (up). This means that the origin for the child link will be up and to the left, regardless of the child link’s visual origin tag. Since we didn’t specify a rpy (roll pitch yaw) attribute, the child frame will be default have the same orientation as the parent frame.
- Now, looking at the leg’s visual origin, it has both a xyz and rpy offset. This defines where the center of the visual element should be, relative to its origin. Since we want the leg to attach at the top, we offset the origin down by setting the z offset to be -.3 meters. And since we want the long part of the leg to be parallel to the z axis, we rotate the visual part PI/2 around the Y axis.
roslaunch urdf_tutorial display.launch model:=urdf/03-origins.urdf
- The launch file runs packages that will create TF frames for each link in your model based on your URDF. Rviz uses this information to figure out where to display each shape.
- If a TF frame does not exist for a given URDF link, then it will be placed at the origin in white.
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
<span class="line"><span class="LineAnchor" id="CA-e73c9a84933fd2c39c8dd8508bb8a46d3d5390ec_1"></span><span class="anchor" id="line-1-12"></span><span class="Preprc"><?xml version="1.0"?></span></span> <span class="line"><span class="ID"><robot</span> <span class="ID">name=</span><span class="String">"materials"</span><span class="ID">></span></span> <span class="line"> <span class="ID"><link</span> <span class="ID">name=</span><span class="String">"base_link"</span><span class="ID">></span></span> <span class="line"> <span class="ID"><visual</span><span class="ID">></span></span> <span class="line"><span class="ID"><geometry</span><span class="ID">></span></span> <span class="line"><span class="ID"><cylinder</span> <span class="ID">length=</span><span class="String">"0.6"</span> <span class="ID">radius=</span><span class="String">"0.2"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></geometry></span></span> <span class="line"><span class="ID"><material</span> <span class="ID">name=</span><span class="String">"blue"</span><span class="ID">></span></span> <span class="line"><span class="ID"><color</span> <span class="ID">rgba=</span><span class="String">"0 0 .8 1"</span><span class="ID">/></span></span> <span class="line"> <span class="ID"></material></span></span> <span class="line"><span class="ID"></visual></span></span> <span class="line"><span class="ID"></link></span></span> <span class="line"><span class="ID"><link</span> <span class="ID">name=</span><span class="String">"right_leg"</span><span class="ID">></span></span> <span class="line"><span class="ID"><visual</span><span class="ID">></span></span> <span class="line"><span class="ID"><geometry</span><span class="ID">></span></span> <span class="line"><span class="ID"><box</span> <span class="ID">size=</span><span class="String">"0.6 .2 .1"</span><span class="ID">/></span></span> <span class="line"> <span class="ID"></geometry></span></span> <span class="line"> <span class="ID"><origin</span> <span class="ID">rpy=</span><span class="String">"0 1.57075 0"</span> <span class="ID">xyz=</span><span class="String">"0 0 -0.3"</span><span class="ID">/></span></span> <span class="line"> <span class="ID"><material</span> <span class="ID">name=</span><span class="String">"white"</span><span class="ID">></span></span> <span class="line"><span class="ID"><color</span> <span class="ID">rgba=</span><span class="String">"1 1 1 1"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></material></span></span> <span class="line"><span class="ID"></visual></span></span> <span class="line"><span class="ID"></link></span></span> <span class="line"><span class="ID"><joint</span> <span class="ID">name=</span><span class="String">"base_to_right_leg"</span> <span class="ID">type=</span><span class="String">"fixed"</span><span class="ID">></span></span> <span class="line"><span class="ID"><parent</span> <span class="ID">link=</span><span class="String">"base_link"</span><span class="ID">/></span></span> <span class="line"><span class="ID"><child</span> <span class="ID">link=</span><span class="String">"right_leg"</span><span class="ID">/></span></span> <span class="line"><span class="ID"><origin</span> <span class="ID">xyz=</span><span class="String">"0.22 0 .25"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></joint></span></span> <span class="line"> <span class="ID"><link</span> <span class="ID">name=</span><span class="String">"left_leg"</span><span class="ID">></span></span> <span class="line"><span class="ID"><visual</span><span class="ID">></span></span> <span class="line"><span class="ID"><geometry</span><span class="ID">></span></span> <span class="line"><span class="ID"><box</span> <span class="ID">size=</span><span class="String">"0.6 .2 .1"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></geometry></span></span> <span class="line"><span class="ID"><origin</span> <span class="ID">rpy=</span><span class="String">"0 1.57075 0"</span> <span class="ID">xyz=</span><span class="String">"0 0 -0.3"</span><span class="ID">/></span></span> <span class="line"> <span class="ID"><material</span> <span class="ID">name=</span><span class="String">"white"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></visual></span></span> <span class="line"><span class="ID"></link></span></span> <span class="line"><span class="ID"><joint</span> <span class="ID">name=</span><span class="String">"base_to_left_leg"</span> <span class="ID">type=</span><span class="String">"fixed"</span><span class="ID">></span></span> <span class="line"><span class="ID"><parent</span> <span class="ID">link=</span><span class="String">"base_link"</span><span class="ID">/></span></span> <span class="line"><span class="ID"><child</span> <span class="ID">link=</span><span class="String">"left_leg"</span><span class="ID">/></span></span> <span class="line"><span class="ID"><origin</span> <span class="ID">xyz=</span><span class="String">"-0.22 0 .25"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></joint></span></span> <span class="line"><span class="LineAnchor" id="CA-e73c9a84933fd2c39c8dd8508bb8a46d3d5390ec_48"></span><span class="ID"></robot></span></span>
- The body is now blue. By adding the first material tag, we’ve defined a new material called “blue”, with the red, green, blue and alpha channels defined as 0,0,.8 and 1 respectively. All of the values can be in the range [0,1].
- The white material is defined similarly
- For the second leg, we can refer to the material just by name, since it’s been previously defined. No one will complain if you redefine it though.
- You can also use a texture to specify an image file to be used for coloring the object
roslaunch urdf_tutorial display.launch model:=urdf/04-materials.urdf
Finishing the Model
Now we finish the model off with a few more shapes. Most notably, we add a sphere and a some meshes. We’ll also add few other pieces that we’ll use later. Source
roslaunch urdf_tutorial display.launch model:=urdf/05-visual.urdf
How to add the sphere should be fairly self explanatory
<span class="line"><span class="ID"><link</span> <span class="ID">name=</span><span class="String">"head"</span><span class="ID">></span></span> <span class="line"><span class="ID"><visual</span><span class="ID">></span></span> <span class="line"><span class="ID"><geometry</span><span class="ID">></span></span> <span class="line"><span class="ID"><sphere</span> <span class="ID">radius=</span><span class="String">"0.2"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></geometry></span></span> <span class="line"><span class="ID"><material</span> <span class="ID">name=</span><span class="String">"white"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></visual></span></span> <span class="line"><span class="ID"></link></span></span>
The meshes here were borrowed from the PR2, meaning you’ll need the package pr2_description to be able to see them.
<span class="line"><span class="ID"><link</span> <span class="ID">name=</span><span class="String">"left_gripper"</span><span class="ID">></span></span> <span class="line"><span class="ID"><visual</span><span class="ID">></span></span> <span class="line"><span class="ID"><geometry</span><span class="ID">></span></span> <span class="line"><span class="ID"><mesh</span> <span class="ID">filename=</span><span class="String">"package://pr2_description/meshes/gripper_v0/l_finger.dae"</span><span class="ID">/></span></span> <span class="line"><span class="ID"></geometry></span></span> <span class="line"><span class="ID"></visual></span></span> <span class="line"><span class="ID"></link></span></span>
- The meshes can be imported in a number of different formats. STL is fairly common, but the engine also supports DAE, which can have its own color data, meaning you don’t have to specify the color data.
- Meshes can also be sized using relative scaling parameters or a bounding box size.
There you have it. A R2D2-like URDF model. Now you can continue on to the next step, making it move.
Leave a Reply
You must be logged in to post a comment.