Simulating ROS Navigation in Gazebo
Simulated environment in which programmers are able to interact and experiment with 3D models at their fingertips. Being able to test algorithms, design robots, monitor systems of networks are essential to a succesful project. With Gazebo, a programmer is able to make use of an incredible physics engine, high-quality graphical interfaces and robust programming to design real tools before they are created.
This blog uses Ubuntu 18.04 with ROS Melodic and Gazebo 9. We assume that you have ROS and Gazebo already installed on your local system.
Installing Nvidia
This project makes use of Nvidia hardware to lower resource consumption and make the simulation run smoothly!
Nvidia Driver
sudo apt-get install nvidia-driver-470
sudo apt-get install nvidia-cuda-toolkit
nvcc --version
Runtime Container
distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
&& curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - \
&& curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update
sudo apt-get install -y nvidia-docker2
sudo systemctl restart docker
nvidia-smi
Launch in Docker
Before we begin this tutorial, you can view the full project in docker!
- Make sure you have docker and docker-compose on your OS.
docker -v
docker-compose --version
- Open a new terminal. Clone the repo below:
cd ~ git clone https://github.com/dlakhiani/ros-navigation-local.git cd ros-navigation-local/src xhost local:docker docker-compose -f docker-compose.nvidia.yml build docker-compose -f docker-compose.nvidia.yml up
Please do be patient when loading Gazebo, as it will take a bit of time due to it being a graphical client.
- To control the robot, open a new terminal and type:
docker exec -it src_ros-develop_1 bash source devel/setup.bash roslaunch turtlebot_teleop keyboard_teleop.launch
Workspace and project
- Feel free to skip this if you already have setup a workspace, if not:
source /opt/ros/$ROS_DISTRO/setup.bash mkdir -p ~/sim_ws/src cd ~/sim_ws/src catkin_init_workspace cd .. catkin_make source ~/sim_ws/devel/setup.bash
- Lets create the project for this tutorial:
cd ~/sim_ws/src catkin_create_pkg navigation_robot gazebo_ros urdf
Gazebo Simulation Box
- Make sure you have gazebo installed on your OS.
-
Launch an empty world of gazebo on your local system.
gazebo
- You now have an empty world in gazebo.
World files
A world in gazebo is just another word for a simulated environment for your experiments. Programmers can evaluate and test their robot in difficult or dangerous scenarios without any harm to the robot themselves.
- An equivalent method of creating an empty world in gazebo is using the
.world
file.cd ~/sim_ws/src/navigation_robot mkdir world cd world touch empty_world.world
-
To make an empty world in gazebo using
.world
, use the following template:<?xml version="1.0" ?> <!-- simulation description format - describes models in xml --> <sdf version="1.5"> <world name="default"> <!-- sky --> <include> <uri>model://sun</uri> </include> <!-- ground --> <include> <uri>model://ground_plane</uri> </include> </world> </sdf>
- Save this under
empty_world.world
- You can now load this file using:
gazebo empty_world.world
Adding objects to the world
- Using the gazebo model database, adding objects are simple through a world file.
-
Lets add a grey wall to our
empty_world.world
file above:<include> <uri>model://grey_wall</uri> <pose>0 0 0 0 0 3.14</pose> <name>wall_1</name> </include>
- the term uri is used to specify the model we want to spawn into the gazebo environment, find more here.
- the term pose (x y z roll pitch yaw) determines the model’s location and orientation in the gazebo environment.
- the term name allows you to spawn several of the same model into the envionment, by just changing the model’s name to a unique one.
- There are several more properties you can add to models in gazebo, see here for more details.
Spawn a Robot in Gazebo
- Robots are like any other model, having multiple links, joints, plugins and, sensors. In this tutorial, we will spawn a TurtleBot !
cd ~ git clone https://github.com/dlakhiani/ros-navigation-local.git cd ros-navigation-local catkin_make source devel/setup.bash roslaunch turtlebot_navigation_gazebo main.launch
Control the Robot
- Now that we have spawned a robot into a world in gazebo, lets try moving it! We can do this by using teleoperation!
roslaunch turtlebot_teleop keyboard_teleop.launch
- Enjoy!
Monitor Robot
Rosnode
- ROS makes use of nodes to control the robot’s publishers, subscribers and, other connections.
- It is used to computer and display debug information to the user, read more here.
rosnode list
displays currently running rosnodesrosnode info /gazebo_gui
provides the connections of the given rosnode
Rostopic
- ROS nodes use topics to publish, subscribe, and send messages to/from the robot from/to the system network.
- With this, we are also able to view the type and content of the messages being sent to the user, read more here.
rostopic list
displays currently running rostopicsrostopic info /cmd_vel
provides the type of message the topic communicates with, along with any publishers/subscribers that are linked to itBy using this topic (cmd_vel), we were able to control the TurtleBot.
rostopic echo /odom
prints the messages that is sent and received by the topic
Rviz
- Rviz is a program interface that allows the user to visually monitor simulated objects and their topics.
- It is incredibly helpful when experimenting with custom models and topics, learn how to use it here!
roslaunch turtlebot_rviz_launchers view_model.launch
RQT
rqt_topic
helps the user view all the currently running rostopic’s messages at a glance.rosrun rqt_topic rqt_topic
rqt_graph
provides the user with a flowchart view of the connections between the currently running rostopics and rosnodes.rosrun rqt_graph rqt_graph
All robot simulations make use of XML, especially the .urdf
extension. The URDF (Universal Robot Description Format) model is a collection of XML files that describe a robot’s physical description. These files are used by ROS (Robot Operating System) to tell the computer what the robot actually looks like in real life.
Launch in Docker
For the customized simulation, you can view it in docker too!
- Make sure you have docker and docker-compose on your OS.
docker -v
docker-compose --version
- Open a new terminal. Clone the repo below:
cd ~ git clone https://github.com/dlakhiani/iris_model.git cd iris_model xhost local:docker docker-compose build docker-compose up ros-develop-gmapping
Please do be patient when loading Gazebo, as it will take a bit of time due to it being a graphical client.
- To control the robot, open a new terminal and type:
docker exec -it iris_model_ros-develop_1 bash source devel/setup.bash rosrun iris_model teleop_twist_key.py
Customize World
Earlier we worked with .world
files to generate an environment for our robot. This time, we are going to customize it:
cd ~/sim_ws/src/navigation_robot
-
Lets add some walls to our
empty_world.world
:<include> <uri>model://grey_wall</uri> <name>wall_1</name> <pose>5.752843 -5.123935 0 0 0 3.14</pose> </include> <include> <uri>model://grey_wall</uri> <name>wall_2</name> <pose>5.752843 -3.123935 0 0 0 3.14</pose> </include> <include> <uri>model://grey_wall</uri> <name>wall_3</name> <pose>5.752843 -1.123935 0 0 0 3.14</pose> </include> <include> <uri>model://grey_wall</uri> <name>wall_4</name> <pose>5.752843 1.123935 0 0 0 3.14</pose> </include> <include> <uri>model://grey_wall</uri> <name>wall_5</name> <pose>5.752843 3.123935 0 0 0 3.14</pose> </include> <include> <uri>model://grey_wall</uri> <name>wall_6</name> <pose>5.752843 5.123935 0 0 0 3.14</pose> </include>
- Save this under
empty_world.world
- As it is a good practice to use a
.launch
file, we will create one now!- LAUNCH files are XML extensions that provide a convenient way to start up multiple nodes and a master, as well as other initialization factors.
cd ~/sim_ws/src/navigation_robot mkdir launch cd launch touch world.launch
- LAUNCH files are XML extensions that provide a convenient way to start up multiple nodes and a master, as well as other initialization factors.
-
Now add the below to the
world.launch
file:<?xml version="1.0" encoding="UTF-8" ?> <launch> <arg name="gui" default="true" /> <arg name="world" default="$(find navigation_robot)/world/empty_world.world" /> <!-- include gazebo_ros launcher --> <include file="$(find gazebo_ros)/launch/empty_world.launch"> <arg name="world_name" value="$(arg world)" /> <arg name="gui" value="$(arg gui)" /> <arg name="use_sim_time" value="true" /> </include> </launch>
The arg tag is an argument parameter that can be altered to initialize different parameter values for the launch file.
- This will execute a default launch file provided by Gazebo, load our world file and display the Gazebo client. You can launch it by doing:
roslaunch navigation_robot world.launch
Build your own model
The more accurate you want your model to be, the more time you would need to spend on the design. The most standard way to go about creating one is placing a SDF file in the ~/.gazebo/models
directory, however, we will be using our newly acquired knowledge on URDF in tandem with Xacro (XML Macro) to make shorter and clearer ROS descriptions.
cd ~/sim_ws/src/navigation_robot
mkdir urdf
cd urdf
Now, lets build a 4-wheel robot!
-
We will begin by building a blueprint for the wheels and chassis of the robot, and for that we will need a
.xacro
file to keep track of the macros!touch macros.xacro
-
Paste the following in
macros.xacro
:<?xml version="1.0"?> <robot name="macros" xmlns:xacro="http://www.ros.org/wiki/xacro"> <!--All units in m-kg-s-radians unit system --> <xacro:property name="M_PI" value="3.1415926535897931" /> <xacro:property name="footprint_vertical_offset" value="-0.05" /> <!-- Chassis --> <xacro:property name="chassis_height" value="0.1" /> <xacro:property name="chassis_width" value="0.5" /> <xacro:property name="chassis_length" value="0.6" /> <xacro:property name="chassis_mass" value="5" /> <!-- in kg--> <!-- Wheels --> <xacro:property name="wheel_horizontal_separation" value="0.15" /> <xacro:property name="wheel_vertical_separation" value="0.23" /> <xacro:property name="wheel_vertical_offset" value="-0.13" /> <xacro:property name="wheel_radius" value="0.098" /> <xacro:property name="wheel_width" value="0.040" /> <xacro:macro name="wheel" params="prefix trans_x trans_y trans_z"> <link name="${prefix}_wheel"> <visual> <origin xyz="0 0 0" rpy="${M_PI/2} 0 0"/> <geometry> <cylinder radius="${wheel_radius}" length="${wheel_width}"/> </geometry> <material name="Red" /> </visual> <collision> <origin xyz="0 0 0" rpy="${M_PI/2} 0 0"/> <geometry> <cylinder radius="${wheel_radius}" length="${wheel_width}"/> </geometry> </collision> <inertial> <origin xyz="0 0 0" rpy="0 0 0"/> <mass value="0.477"/> <inertia ixx="0.0013" ixy="0" ixz="0" iyy="0.0024" iyz="0" izz="0.0013"/> </inertial> </link> <gazebo reference="${prefix}_wheel"> <material>Gazebo/DarkGrey</material> </gazebo> <joint name="${prefix}_joint" type="continuous"> <parent link="chassis_link"/> <child link="${prefix}_wheel" /> <origin xyz="${trans_x} ${trans_y} ${trans_z}" rpy="0 0 0" /> <axis xyz="0 1 0" /> </joint> </xacro:macro> <xacro:macro name="cylinder_inertia" params="mass r l"> <inertia ixx="${mass*(3*r*r+l*l)/12}" ixy = "0" ixz = "0" iyy="${mass*(3*r*r+l*l)/12}" iyz = "0" izz="${mass*(r*r)/2}" /> </xacro:macro> </robot>
- the term xacro:property defines a named value that can serve as a variable for XML documents.
- the term xacro:macro creates a unique named macro (XML tag) for a certain block of code, is similar to creating an object/class in programming (defining parameters and attributes of the object).
- the term link describes an element for ROS to create, often including properties of inertia, visuals and collision.
- the term joint describes the physical relation between links.
- the term gazebo describes how the Gazebo simulator will present the given description.
Great! We now have a blueprint for our components and some. Let’s put it together in another .xacro
file!
touch robot.xacro
-
Paste the following in
robot.xacro
:<?xml version="1.0"?> <robot name="navigation_robot" xmlns:xacro="http://www.ros.org/wiki/xacro"> <xacro:include filename="$(find navigation_robot)/urdf/macros.xacro" /> <!-- base_link is a fictitious link(frame) that is on the ground right below chassis_link origin --> <link name="base_link"> <visual> <origin xyz="0 0 0" rpy="0 0 0" /> <geometry> <box size="0.001 0.001 0.001" /> </geometry> </visual> </link> <joint name="base_link_joint" type="fixed"> <origin xyz="0 0 0" rpy="0 0 0" /> <parent link="base_link"/> <child link="chassis_link" /> </joint> <!-- chassis_link is the centre frame that is essentially the body of the robot, serving as the main connector to all 4 wheels --> <link name="chassis_link"> <visual> <origin xyz="0 0 ${footprint_vertical_offset}" rpy="0 0 0"/> <geometry> <box size="${chassis_length} ${chassis_width} ${chassis_height}"/> </geometry> <material name="Grey" /> </visual> <collision> <origin xyz="0 0 ${footprint_vertical_offset}"/> <geometry> <box size="${chassis_length} ${chassis_width} ${chassis_height}"/> </geometry> </collision> <inertial> <!-- Center of mass --> <origin xyz="0.012 0.002 0.067" rpy="0 0 0"/> <mass value="16.523"/> <!-- Moments of inertia: ( chassis without wheels ) --> <inertia ixx="0.3136" ixy="-0.0008" ixz="0.0164" iyy="0.3922" iyz="-0.0009" izz="0.4485"/> </inertial> </link> <xacro:wheel prefix="front_left" trans_x="${wheel_horizontal_separation}" trans_y="${wheel_vertical_separation+wheel_width/2}" trans_z="${wheel_vertical_offset}"/> <xacro:wheel prefix="front_right" trans_x="${wheel_horizontal_separation}" trans_y="${-wheel_vertical_separation-wheel_width/2}" trans_z="${wheel_vertical_offset}"/> <xacro:wheel prefix="rear_left" trans_x="${-wheel_horizontal_separation}" trans_y="${wheel_vertical_separation+wheel_width/2}" trans_z="${wheel_vertical_offset}"/> <xacro:wheel prefix="rear_right" trans_x="${-wheel_horizontal_separation}" trans_y="${-wheel_vertical_separation-wheel_width/2}" trans_z="${wheel_vertical_offset}"/> </robot>
here we call on our macros from
macros.xacro
using$()
, to help define our wheels and properties of the chassis in a concise manner!
Now we have the description of our robot! All that remains is our .gazebo
file, which will provide Gazebo with the properties we want our robot to have in the simulation!
With the current knowledge of ROS and Gazebo at your disposal, localization is within your grasp! Being able to send goals and automate path building is one of many amazing things we want a robot to be able to do. So, lets try it now!
Launch in Docker
For the localization simulation, its available in docker also!
- Make sure you have docker and docker-compose on your OS.
docker -v
docker-compose --version
- Open a new terminal. Clone the repo below:
cd ~ git clone https://github.com/dlakhiani/iris_model.git cd iris_model xhost local:docker docker-compose build docker-compose up ros-develop-amcl
Please do be patient when loading Gazebo, as it will take a bit of time due to it being a graphical client.
- Now you can send it
Goals
using Rviz, and the robot will configure a path to get to the given destination goal!