Previous Lesson
Lesson Purpose:
By the end of this lesson you should be able to:
Lesson Purpose:
By the end of this lesson you should be able to:
- Make a *.xacro file
- Convert *.xacro into *.urdf
- Be able to spawn our *.xacro into Gazebo
Lesson 2: URDF and XACRO
1. How Wheely_Boi is defined
Full urdf tutorial
Gazebo uses *.urdf files to encode features about the robots it simulates, but urdfs can be a pain to write at times - we can be repeating the same part over and over again, and it gets to a point where there must be a better way to do it.
First things first, let's look at Wheely_Boi's xacro file, and get a feel for what a xacro is. Wheely Boi doesn't take advantage of most features of xacro, but he's pretty simple, so he's a nice place to start.
Full urdf tutorial
Gazebo uses *.urdf files to encode features about the robots it simulates, but urdfs can be a pain to write at times - we can be repeating the same part over and over again, and it gets to a point where there must be a better way to do it.
First things first, let's look at Wheely_Boi's xacro file, and get a feel for what a xacro is. Wheely Boi doesn't take advantage of most features of xacro, but he's pretty simple, so he's a nice place to start.
wheely_boi.xacro
That's a lot of XML to parse, so let's take it bit by bit.
The outermost layer of the xacro is what tells gazebo that this is indeed a model. First we let our computer know that this is xml, and anything reading it should read it as an xml (this is purely for the sake of your text editor, so it can load up the right hilighting), then we have this <robot> block.
The <robot> block has two required parts that we need to tell it, first that we are using xacro, so we need to add the property:
xmlns:xacro="http://www.ros.org/wiki/xacro"
And second, the name of the model, so that gazebo knows what to call it:
name="wheely_boi"
The <robot> block has two required parts that we need to tell it, first that we are using xacro, so we need to add the property:
xmlns:xacro="http://www.ros.org/wiki/xacro"
And second, the name of the model, so that gazebo knows what to call it:
name="wheely_boi"
Next we have this weird looking block.
All this is doing is declaring some constants for xacro. In programming in general, we don't want to have to repeat magic numbers in our code, and we want to know what those magic numbers are when we use them, so we give them names. Xacro lets us do this, so now when we refer to "body_height", we will get 0.1 meters.
All this is doing is declaring some constants for xacro. In programming in general, we don't want to have to repeat magic numbers in our code, and we want to know what those magic numbers are when we use them, so we give them names. Xacro lets us do this, so now when we refer to "body_height", we will get 0.1 meters.
Now we have three little components that look like this.
What each one of them is doing, is they are pointing at a specific link ("edumip_body" in this case), and telling gazebo what sort of material and properties it has.
The material is mostly visual, in this case we are just saying to paint the body white.
The mu1 and mu2 are the coulomb friction parameters. I believe that mu1 is the friction in the x direction of the material, and mu2 is the friction in a normal direction, or the y direction.
Remember, in the real world everything has a little bit of friction, so your robot should too. Otherwise it's not going to end up being a very good simulation.
What each one of them is doing, is they are pointing at a specific link ("edumip_body" in this case), and telling gazebo what sort of material and properties it has.
The material is mostly visual, in this case we are just saying to paint the body white.
The mu1 and mu2 are the coulomb friction parameters. I believe that mu1 is the friction in the x direction of the material, and mu2 is the friction in a normal direction, or the y direction.
Remember, in the real world everything has a little bit of friction, so your robot should too. Otherwise it's not going to end up being a very good simulation.
Now we've actually started to define our links. Each link is a piece of the robot, and in order to simulate our robot each link needs three parts: a visual, a collision, and an inertial component.
The visual component tells gazebo how to render the part on screen. In the case of this link we are just telling it to make a box of a certain size.
The collision component tells gazebo how big the "hitbox" of the part should be, or where it should be checking for collisions. Most of the time this should be identical to the visual component, however if the part is some insanely complicated model, it might be better to just draw a box around it - otherwise your simulations might take a whole lot longer than you want them to.
The inertial component tells gazebo how hard this should be to move, and how much mass it should have. In the inertial component you need to specify the mass (in kg) and the moments of inertia. For most common shapes good formulas for the moments of inertia can be found at this wikipedia page.
Take a moment to compare the links of the "edumip_body" "wheelL" and "wheelR". The main difference is just that the body is a box, the wheels are cylinders and the moments of inertia are different.
The visual component tells gazebo how to render the part on screen. In the case of this link we are just telling it to make a box of a certain size.
The collision component tells gazebo how big the "hitbox" of the part should be, or where it should be checking for collisions. Most of the time this should be identical to the visual component, however if the part is some insanely complicated model, it might be better to just draw a box around it - otherwise your simulations might take a whole lot longer than you want them to.
The inertial component tells gazebo how hard this should be to move, and how much mass it should have. In the inertial component you need to specify the mass (in kg) and the moments of inertia. For most common shapes good formulas for the moments of inertia can be found at this wikipedia page.
Take a moment to compare the links of the "edumip_body" "wheelL" and "wheelR". The main difference is just that the body is a box, the wheels are cylinders and the moments of inertia are different.
Above what we've done is defined a lot of blocks and pieces. But in terms of LEGO, we've just grabbed a bunch of parts, we haven't managed to snap any of them together. This is where joints come in. Joints are the connections between links.
Each joint needs a unique name ("jointL") and a type ("continuous"). The type tells gazebo what type of "motor" this joint is, it can be a static link for a weld, a continuous link for a normal motor, or one of several other types of links.
Then we need to specify the parent and the child of the link. The child is the part that is rotated by the link, and the parent is where the motor is mounted.
Then we need to tell it how it rotates, or the axis of the link, in the case of this wheel it rotates around the z axis.
Now we tell it where on the parent we are mounting it, or the origin of the link. You'll notice that xacro lets us use our macros we defined earlier and do some math with them too, making the whole process much easier. The origin is defined using position in x, y, and z (units being in meters), as well as roll, pitch, and yaw (units in radians).
We then need to tell it certain traits about the dynamics of the joint. In the case of our continuous joint, all we need to know is how much friction the joint has.
Each joint needs a unique name ("jointL") and a type ("continuous"). The type tells gazebo what type of "motor" this joint is, it can be a static link for a weld, a continuous link for a normal motor, or one of several other types of links.
Then we need to specify the parent and the child of the link. The child is the part that is rotated by the link, and the parent is where the motor is mounted.
Then we need to tell it how it rotates, or the axis of the link, in the case of this wheel it rotates around the z axis.
Now we tell it where on the parent we are mounting it, or the origin of the link. You'll notice that xacro lets us use our macros we defined earlier and do some math with them too, making the whole process much easier. The origin is defined using position in x, y, and z (units being in meters), as well as roll, pitch, and yaw (units in radians).
We then need to tell it certain traits about the dynamics of the joint. In the case of our continuous joint, all we need to know is how much friction the joint has.
The last thing we do to wheely_boi is we tell it what code we are running on it. To do this we tell gazebo what plugin to load, and the file name of the plugin.
2. Getting Wheely_Boi into Gazebo
That's all well and good that we have him defined as a *.xacro, but Gazebo takes *.urdf's, and we have no idea how to even spawn him right now.
So first we need to turn that xacro into a urdf - which luckily there's a tool for!
First as always, make sure you source your ROS, so you will actually be able to call ROS commands.
Navigate to where wheely_boi.xacro is stored, and all you need to do is call:
$ rosrun xacro xacro wheely_boi.xacro > wheely_boi.urdf
And now we have a nice *.urdf we can bring into Gazebo!
Let's launch an empty world:
$ roslaunch gazebo_ros empty_world.launch
Now open a new terminal (don't forget to source it), and let's spawn in our little wheely_boi:
$ rosrun gazebo_ros spawn_model -file wheely_boi.urdf -urdf -model Fred
All this command is doing is running the spawn_model script, pointing it to our file, telling it that our file is a urdf, and naming the robot we are going to spawn (naming it Fred)
Now we want to take advantage of that code that good ol' Fred is running, so we can start sending him commands. Either launch the tutorial's input program:
$ rosrun robot_tutorial_1 keyin Fred
Or launch the control node that you programmed in lesson 1, tell it to point to Fred, and go wild controlling him!
Homework
1. Create a simple rover
Create a xacro robot of a little 4 wheeled cart. The robot should fit within a 0.4m by 0.2m box, and each of the four joints should be logically named and able to move. In addition, make sure that the robot has inertial values that make sense
Label the main link "body", and the four wheels "wFL", "wFR", "wBL", "wBR", where each wheel has a F if it is a front wheel, a B if it is a back wheel, an L if it is a left wheel, and an R if it is a right wheel.
Make a continuous joint for each wheel, attaching it to the body, and label each joint "jFL", "jFR", "jBL", and "jBR" where each joint is labeled with respect to the wheel it attaches to.
It should look something like this:
2. Getting Wheely_Boi into Gazebo
That's all well and good that we have him defined as a *.xacro, but Gazebo takes *.urdf's, and we have no idea how to even spawn him right now.
So first we need to turn that xacro into a urdf - which luckily there's a tool for!
First as always, make sure you source your ROS, so you will actually be able to call ROS commands.
Navigate to where wheely_boi.xacro is stored, and all you need to do is call:
$ rosrun xacro xacro wheely_boi.xacro > wheely_boi.urdf
And now we have a nice *.urdf we can bring into Gazebo!
Let's launch an empty world:
$ roslaunch gazebo_ros empty_world.launch
Now open a new terminal (don't forget to source it), and let's spawn in our little wheely_boi:
$ rosrun gazebo_ros spawn_model -file wheely_boi.urdf -urdf -model Fred
All this command is doing is running the spawn_model script, pointing it to our file, telling it that our file is a urdf, and naming the robot we are going to spawn (naming it Fred)
Now we want to take advantage of that code that good ol' Fred is running, so we can start sending him commands. Either launch the tutorial's input program:
$ rosrun robot_tutorial_1 keyin Fred
Or launch the control node that you programmed in lesson 1, tell it to point to Fred, and go wild controlling him!
Homework
1. Create a simple rover
Create a xacro robot of a little 4 wheeled cart. The robot should fit within a 0.4m by 0.2m box, and each of the four joints should be logically named and able to move. In addition, make sure that the robot has inertial values that make sense
Label the main link "body", and the four wheels "wFL", "wFR", "wBL", "wBR", where each wheel has a F if it is a front wheel, a B if it is a back wheel, an L if it is a left wheel, and an R if it is a right wheel.
Make a continuous joint for each wheel, attaching it to the body, and label each joint "jFL", "jFR", "jBL", and "jBR" where each joint is labeled with respect to the wheel it attaches to.
It should look something like this:
Reference Tutorial
Reference Answer
2. Spawn it
Make a script to launch an empty world in one terminal, compile your robot into a urdf, and spawn that robot into the empty world.
Reference Answer (Look at play.sh in scripts)
Next Lesson
Reference Answer
2. Spawn it
Make a script to launch an empty world in one terminal, compile your robot into a urdf, and spawn that robot into the empty world.
Reference Answer (Look at play.sh in scripts)
Next Lesson