Fortress And Humble Tutorial
Examining an empty world
Introduction and explanation
What software are we using and why
All of these instructions have been tested using the current version of Ubuntu: Jammy Jellyfish.We are going to use two packages: Gazebo for the physics based Simulator and ROS (Robot Operating System) for the control system. There are many releases of each of these, and only some combinations are mutually compatible. Also, since we are focusing on a stable development platform, we will use the Long Term Support (LTS) versions that are current at the time we are posting this. As of 20Mar2024, this means we will use Gazebo Fortress (release 6) which is supported until 2025.
One quirk: the current LTS version of Gazebo only seems to work with the LTS version of Ubuntu
How will the demonstration proceed.We will go through 7 steps: 1) Install Gazebo Fortress and confirm that it is correct. 2) Examine an empty world 3) Build a simple robot and test it using keyboard controls. 4) Build a 'world' for our robot to explore. 5) Install ROS (and its components) and confirm the installation. 6) Add Lidar to the robot 7) Write control software in ROS to make the robot autonomous.
This post covers Step 2
One quirk: the current LTS version of Gazebo only seems to work with the LTS version of Ubuntu
How will the demonstration proceed.We will go through 7 steps: 1) Install Gazebo Fortress and confirm that it is correct. 2) Examine an empty world 3) Build a simple robot and test it using keyboard controls. 4) Build a 'world' for our robot to explore. 5) Install ROS (and its components) and confirm the installation. 6) Add Lidar to the robot 7) Write control software in ROS to make the robot autonomous.
This post covers Step 2
NOTE: if you are already familiar with the basic elements of an empty gazebo world specification, you can jump ahead to Building a Pong-Bot
Examining an Empty World
When talking about simulations there is really no such thing as an empty world.
In Gazebo, there are two main components that need to be defined: the characteristics of the world and descriptions of the things in the world.The world definition contains the description of the underlying structure, things like the physics model to use, the manner in which collisions are calculated, and the gravity (or lack of gravity).The models describe the things in the world, the surface that objects rest on, the models of robots, and obstacles – in short anything that exists in the space. If this sound like a lot of work – you are right. But, there are a lot of helpful parts that are pre-built, so it can be easier than it sounds.Our long term goal is to build a simple simulation, a world with the physics we are used to, and a simple two-wheeled robot to wander around in an enclosed space. Since we don’t want the poor little robot to bump into things, we will give it a simple sensor to detect when it gets close to a wall, and turn away.Let’s start with the world. We will walk through the empty world file chunk by chunk and see what is needed to describe a world.
Housekeeping
If you haven't done so, use a text editor to open the
pong-world-1.sdf
file. If you don't have this file, you can create one by following the steps in the previous part of the tutorial
building an empty world
The world description is encoded as an xml file, so if your favorite editor provides syntax highlighting you can add
<?xml version="1.0" ?>
as the first line
The SDF file begins with a tag set identifying the version of the sdf file<sdf version=’1.9’>…</sdf>This tells the simulator what to expect and which versions are compatible.The next layer of tags tell the simulator that you are opening a world:
<sdf version=’1.9’> <world name=’empty’>… <!-- everything in the world --> </world></sdf>Now that we have taken care of the housekeeping, we can start defining the world.
Describing the physics
The next section of the file describes the simulation physics: how fast does the simulation run, how frequently does it recalculate,etc. These are defined inside the <physics> … </physics> tag set:
<physics name='1ms' type='ignored'> <max_step_size>0.001</max_step_size> <real_time_factor>1</real_time_factor> <real_time_update_rate>1000</real_time_update_rate> </physics>
Now that we have given the setup instructions to the simulator, we need to tell it what to do. This is done by adding specific plugins to the description. A plugin defines a dynamic component of the world, something that defines the behavior of objects in the world. The default world has 4 plugins:<plugin name='gz::sim::systems::Physics' filename='ignition-gazebo-physics-system'/> <plugin name='gz::sim::systems::UserCommands' filename='ignition-gazebo-user-commands-system'/> <plugin name='gz::sim::systems::SceneBroadcaster' filename='ignition-gazebo-scene-broadcaster-system'/> <plugin name='gz::sim::systems::Contact' filename='ignition-gazebo-contact-system'/>
• Physics Plugin: this is the actual physics of the world, • UserCommands Plugin: these allow you it interact with the world, • SceneBroadcaster Plugin: this converts the world into something that van be viewed and streams it, and • Contact Plugin: this plugin calculates collisions.
Next we add some world simulation characteristics like gravity, magnetic fields, and atmosphere. Finally, we put in some lighting characteristics for the entire scene. <gravity>0 0 -9.8</gravity> <magnetic_field>6e-06 2.3e-05 -4.2e-05</magnetic_field> <atmosphere type='adiabatic'/>Note: if you want to you can set the gravity to anything you want (Mars, Jupiter, Deep space?) and you can adjust the atmosphere and magnetic fields the same way.The final section here is the general scene characteristics. These don’t change the behavior, but they provide some light so that you can see what is going on: <scene> <ambient>0.4 0.4 0.4 1</ambient> <background>0.7 0.7 0.7 1</background> <shadows>true</shadows> </scene>
Okay, so here is a quirk. At the bottom of the stock file generated from an empty world is another section on lighting, we will get to that later.
<physics name='1ms' type='ignored'> <max_step_size>0.001</max_step_size> <real_time_factor>1</real_time_factor> <real_time_update_rate>1000</real_time_update_rate> </physics>
Now that we have given the setup instructions to the simulator, we need to tell it what to do. This is done by adding specific plugins to the description. A plugin defines a dynamic component of the world, something that defines the behavior of objects in the world. The default world has 4 plugins:<plugin name='gz::sim::systems::Physics' filename='ignition-gazebo-physics-system'/> <plugin name='gz::sim::systems::UserCommands' filename='ignition-gazebo-user-commands-system'/> <plugin name='gz::sim::systems::SceneBroadcaster' filename='ignition-gazebo-scene-broadcaster-system'/> <plugin name='gz::sim::systems::Contact' filename='ignition-gazebo-contact-system'/>
• Physics Plugin: this is the actual physics of the world, • UserCommands Plugin: these allow you it interact with the world, • SceneBroadcaster Plugin: this converts the world into something that van be viewed and streams it, and • Contact Plugin: this plugin calculates collisions.
Next we add some world simulation characteristics like gravity, magnetic fields, and atmosphere. Finally, we put in some lighting characteristics for the entire scene. <gravity>0 0 -9.8</gravity> <magnetic_field>6e-06 2.3e-05 -4.2e-05</magnetic_field> <atmosphere type='adiabatic'/>Note: if you want to you can set the gravity to anything you want (Mars, Jupiter, Deep space?) and you can adjust the atmosphere and magnetic fields the same way.The final section here is the general scene characteristics. These don’t change the behavior, but they provide some light so that you can see what is going on: <scene> <ambient>0.4 0.4 0.4 1</ambient> <background>0.7 0.7 0.7 1</background> <shadows>true</shadows> </scene>
Okay, so here is a quirk. At the bottom of the stock file generated from an empty world is another section on lighting, we will get to that later.
What's in a model
We are now going to describe the only thing in this empty world using a model:<model name=’ground_plane’> <static>true</static>… <!-- the description of the model> <pose>0 0 0 0 -0 0</pose> <self_collide>false</self_collide></model>
Let’s look at these: • The model has a name, in this case ground_plane. • The described model is static – the simulator doesn’t need to spend cycle recalculating it every millisecond • The model is placed in a specific position in the world using a pose: ◦ The pose is defined as a six-tuple: ◦ The first three numbers are the position: the X, Y, and Z coordinates ◦ The second three numbers are the orientation: R (roll), P (pitch), and Y (yaw) • The model can’t bump into itself: self-collide=false. If this seems puzzling, think about things like a robot arm that can hit itself.
Let’s look at these: • The model has a name, in this case ground_plane. • The described model is static – the simulator doesn’t need to spend cycle recalculating it every millisecond • The model is placed in a specific position in the world using a pose: ◦ The pose is defined as a six-tuple: ◦ The first three numbers are the position: the X, Y, and Z coordinates ◦ The second three numbers are the orientation: R (roll), P (pitch), and Y (yaw) • The model can’t bump into itself: self-collide=false. If this seems puzzling, think about things like a robot arm that can hit itself.
Parts of a model
So we have setup the big picture of a model, but we haven’t really defined what the model is.Our model is pretty simple, since it is just an infinite flat plane, but there is still a lot to define.In general, a model can consist of three basic components: • Links which represent physical component that makes up the model. In this case an infinite plane with a grid of hash lines in the middle. For a mobile robot one link might be the chassis, or a drive wheel. • Joints which describe how the links are connected to each other and how they can move relative to each other.
• Plugins which describe how the model reacts to the world - how it behaves.
Since this model only has one link (the ground plane) no Joints or Pluginsare needed in the empty world, but don't worry in the next part of the tutorial we will cover both.
Describing the ground plane link
A link represents a physical object in the world, but to simulate it we need to define five things: • A name (so that other things in the world can refer to it). • Collision properties to tell the simulator the size and shape of the thing to be used to calculate collisions • Inertial properties to tell the simulator how to calculate what happens when forces are applied to the object • Visual properties to tell the simulator renderer how to show the object. • A pose (usually) to tell the system where it is relative to the models position.Let’s look at each of these:
Name:
<link name='link'>,
well that is pretty simple, you might want to change the name to 'plane' or something.
Collision properties:
There are a number of things to define: • The name • The geometry (the shape and size) • The type of surface, including friction, elasticicy, and contact typeFor our ground-plane these look like: <collision name='collision'> <geometry> <plane> <normal>0 0 1</normal> <size>100 100</size> </plane> </geometry> <surface> <friction> <ode/> </friction> <bounce/> <contact/> </surface> </collision>
Inertial Properties:
These describe how the body acts under forces (what happens when you hit it with something)These describe • Pose: where the center of mass is • Mass: umm, the mass of the body • Inertia: the “cental inertial properties” essentially where the mass is distributed (maybe) <inertial> <pose>0 0 0 0 -0 0</pose> <mass>1</mass> <inertia> <ixx>1</ixx> <ixy>0</ixy> <ixz>0</ixz> <iyy>1</iyy> <iyz>0</iyz> <izz>1</izz> </inertia> </inertial>
Visual Properties:
The visual properties include: • A name • A geometry (should be the same as the collision) • Material (how it reacts to light (color, shininess, etc.) <visual name='visual'> <geometry> <plane> <normal>0 0 1</normal> <size>100 100</size> </plane> </geometry> <material> <ambient>0.8 0.8 0.8 1</ambient> <diffuse>0.8 0.8 0.8 1</diffuse> <specular>0.8 0.8 0.8 1</specular> </material> </visual>
Pose and miscellany
This link needs to exist in some place relative to the model, so we need to specify a pose. Remember this is an offset from the model's pose - not the position in the world.
<pose>0 0 0 0 -0 0</pose>
For some reason, the empty world also takes pains to define a wind setting: <enable_wind>false</enable_wind>
That closes out the <link> tag and we now have a model with one link in it, the ground-plane.
For some reason, the empty world also takes pains to define a wind setting: <enable_wind>false</enable_wind>
That closes out the <link> tag and we now have a model with one link in it, the ground-plane.
Lighting up the world
Of course, the simulator doesn't really care about light, it would work perfectly well in a dark room or a cave. But we'd like to see what is happening, so let's add the sun!
To do this, we need to define: • Where it is, • Does it cast shadows (direct sunlight versus a cloudy day) • How bright is it, • What direction does it point • What color is it when diffused • What color is it direct • How fast does it fade out (how far will it shine) • How tight a beam is it (a tight spot or a general flood light)
The empty world encodes the sun as:
<light name='sun' type='directional'> <pose>0 0 10 0 -0 0</pose> <cast_shadows>true</cast_shadows> <intensity>1</intensity> <direction>-0.5 0.1 -0.9</direction> <diffuse>0.8 0.8 0.8 1</diffuse> <specular>0.2 0.2 0.2 1</specular> <attenuation> <range>1000</range> <linear>0.01</linear> <constant>0.90000000000000002</constant> <quadratic>0.001</quadratic> </attenuation> <spot> <inner_angle>0</inner_angle> <outer_angle>0</outer_angle> <falloff>0</falloff> </spot> </light>
We are done examining the empty world
With this last addition: poof! you have created a world.
We got a lot for free in this 'empty' world.
We have:
1) defined the simulator parameters
2) told the sim to load 4 plugins for running the simulation
3) set up characteristics for gravity, atmosphere, light, and a magnetic field
4) defined a ground plane model, which required: a name, a collision surface, inertial characteristics, visual characteristics.
a) we also learned that to place models we need a pose that defines both the linear (X,Y, and Z) and the orientation (Roll, Pitch, and Yaw)
5) defined a 'Link' - a phyisical body in the model, and specified its own collision, inertial, visual, and pose characteristics
6) finally, we added a light source to the world, so that we could see what was happening.
It seems like a lot of things need to be defined to make a simulation work – this is the downside of a physics based model. See the discussion in Part 0 – To Sim or not to Sim.
Now that we have an idea of what is needed, let's make a simple robot in Part 3
Now that we have an idea of what is needed, let's make a simple robot in Part 3
Previous Step | Current Step | Next Step |
Examine an Empty World |