Mastering ROS For Robotics Programming - Sample Chapter
Mastering ROS For Robotics Programming - Sample Chapter
$ 54.99 US
34.99 UK
P U B L I S H I N G
Lentin Joseph
ee
pl
C o m m u n i t y
E x p e r i e n c e
D i s t i l l e d
Sa
m
Lentin Joseph
machine vision expert, embedded programmer, and the founder and CEO of Qbotics
Labs (http://www.qboticslabs.com) from India. He completed his bachelor's degree
in electronics and communication engineering at the Federal Institute of Science
and Technology (FISAT), Kerala. For his final year engineering project, he made a
social robot that can interact with people. The project was a huge success and was
mentioned in many forms of visual and print media. The main features of this robot
were that it can communicate with people and reply intelligently and has some image
processing capabilities such as face, motion, and color detection. The entire project was
implemented using the Python programming language. His interest in robotics, image
processing, and Python started with that project.
After his graduation, for 3 years he worked in a start-up company focusing on robotics
and image processing. In the meantime, he learned famous robotic software platforms
such as Robot Operating System (ROS), V-REP, Actin (a robotic simulation tool), and
image processing libraries such as OpenCV, OpenNI, and PCL. He also knows robot
3D designing and embedded programming on Arduino and Tiva Launchpad.
After 3 years of work experience, he started a new company called Qbotics
Labs, which mainly focuses on research to build up some great products in
domains such as robotics and machine vision. He maintains a personal website
(http://www.lentinjoseph.com) and a technology blog called technolabsz
(http://www.technolabsz.com). He publishes his works on his tech blog.
He was also a speaker at PyCon2013, India, on the topic Learning Robotics
using Python.
Lentin is the author of the book Learning Robotics Using Python (refer to http://
learn-robotics.com to know more) by Packt Publishing. The book was about
building an autonomous mobile robot using ROS and OpenCV. The book was
launched in ICRA 2015 and was featured in the ROS blog, Robohub, OpenCV,
the Python website, and various other such forums.
Lentin was a finalist in the ICRA 2015 challenge, HRATC
(http://www2.isr.uc.pt/~embedded/events/HRATC2015/Welcome.html).
Preface
Mastering ROS for Robotics Programming is an advanced guide of ROS that is very
suitable for readers who already have a basic knowledge in ROS. ROS is widely used
in robotics companies, universities, and robotics research institutes for designing,
building, and simulating a robot model and interfacing it into real hardware. ROS is
now an essential requirement for Robotic engineers; this guide can help you acquire
knowledge of ROS and can also help you polish your skills in ROS using interactive
examples. Even though it is an advanced guide, you can see the basics of ROS in the
first chapter to refresh the concepts. It also helps ROS beginners. The book mainly
focuses on the advanced concepts of ROS, such as ROS Navigation stack, ROS
MoveIt!, ROS plugins, nodelets, controllers, ROS Industrial, and so on.
You can work with the examples in the book without any special hardware;
however, in some sections you can see the interfacing of I/O boards, vision
sensors, and actuators to ROS. To work with this hardware, you will need
to buy it.
The book starts with an introduction to ROS and then discusses how to build a robot
model in ROS for simulating and visualizing. After the simulation of robots using
Gazebo, we can see how to connect the robot to Navigation stack and MoveIt!. In
addition to this, we can see ROS plugins, controllers, nodelets, and interfacing of
I/O boards and vision sensors. Finally, we can see more about ROS Industrial and
troubleshooting and best practices in ROS.
Preface
Chapter 3, Simulating Robots Using ROS and Gazebo, discusses the simulation of
seven-DOF arms, differential wheeled robots, and ROS controllers that help control
robot joints in Gazebo.
Chapter 4, Using the ROS MoveIt! and Navigation Stack, interfaces out-of-the-box
functionalities such as robot manipulation and autonomous navigation using ROS
MoveIt! and Navigation stack.
Chapter 5, Working with Pluginlib, Nodelets, and Gazebo Plugins, shows some of the
advanced concepts in ROS, such as ROS pluginlib, nodelets, and Gazebo plugins.
We will discuss the functionalities and application of each concept and can practice
one example to demonstrate its working.
Chapter 6, Writing ROS Controllers and Visualization Plugins, shows how to write a
basic ROS controller for PR2 robots and robots similar to PR2. After creating the
controller, we will run the controller using the PR2 simulation in Gazebo. We can
also see how to create plugin for RViz.
Chapter 7, Interfacing I/O Boards, Sensors, and Actuators to ROS, discusses interfacing
some hardware components, such as sensors and actuators, with ROS. We will see
the interfacing of sensors using I/O boards, such as Arduino, Raspberry Pi, and
Odroid-C1, with ROS.
Chapter 8, Programming Vision Sensors using ROS, Open-CV, and PCL, discusses how
to interface various vision sensors with ROS and program it using libraries such as
Open Source Computer Vision (Open-CV) and Point Cloud Library (PCL).
Chapter 9, Building and Interfacing Differential Drive Mobile Robot Hardware in ROS,
helps you to build autonomous mobile robot hardware with differential drive
configuration and interface it with ROS. This chapter aims at giving you an idea
of building a custom mobile robot and interfacing it with ROS.
Chapter 10, Exploring the Advanced Capabilities of ROS-MoveIt!, discusses the
capabilities of MoveIt! such as collision avoidance, perception using 3D sensors,
grasping, picking, and placing. After that, we can see the interfacing of a robotic
manipulator hardware with MoveIt!
Chapter 11, ROS for Industrial Robots, helps you understand and install ROS-Industrial
packages in ROS. We can see how to develop an MoveIt! IKFast plugin for an
industrial robot.
Chapter 12, Troubleshooting and Best Practices in ROS, discusses how to set the ROS
development environment in Eclipse IDE, best practices in ROS, and troubleshooting
tips in ROS.
[2]
Chapter 1
Tons of tools: ROS is packed with tons of tools for debugging, visualizing,
and performing simulation. The tools such as rqt_gui, RViz and Gazebo
are some of the strong open source tools for debugging, visualization, and
simulation. The software framework that has these many tools is very rare.
Modularity: One of the issues that can occur in most of the standalone
robotic applications are, if any of the threads of main code crash, the entire
robot application can stop. In ROS, the situation is different, we are writing
different nodes for each process and if one node crashes, the system can still
work. Also, ROS provides robust methods to resume operation even if any
sensors or motors are dead.
There are many reasons to choose ROS other than the preceding points.
Next, we can check the various reasons why people don't use ROS. Here are some
of the existing reasons.
Difficulty in learning: It will be difficult to learn ROS from their default wiki
pages. Most users depend on books to start with ROS. Even this book covers
only the basics; learning ROS is going to be bit difficult.
[4]
Chapter 1
We now know where we have to use ROS and where we do not. If ROS is really
required for your robot, let's start discussing ROS in more detail. First, we can see the
underlying core concepts of ROS. There are mainly three levels in ROS: file system
level, computation graph level, and community level. We can have a look at each
level in short.
Meta Packages
Packages
Package
Manifest
Messages
Services
Codes
[5]
Misc
Packages: The ROS packages are the most basic unit of the ROS software.
It contains the ROS runtime process (nodes), libraries, configuration files,
and so on, which are organized together as a single unit. Packages are the
atomic build item and release item in the ROS software.
Package manifest: The package manifest file is inside a package that contains
information about the package, author, license, dependencies, compilation
flags, and so on. The package.xml file inside the ROS package is the manifest
file of that package.
Meta packages: The term meta package is used for a group of packages
for a special purpose. In an older version of ROS such as Electric and
Fuerte, it was called stacks, but later it was removed, as simplicity and
meta packages came to existence. One of the examples of a meta package
is the ROS navigation stack.
Messages (.msg): The ROS messages are a type of information that is sent
from one ROS process to the other. We can define a custom message inside
the msg folder inside a package (my_package/msg/ MyMessageType.msg).
The extension of the message file is .msg.
[6]
Chapter 1
The following screenshot gives you an idea of files and folders of a package that we
are going to make in the upcoming sections:
ROS packages
A typical structure of a ROS package is shown here:
CMakeLists.txt
package.xml
talker.py
listener.py
talker.cpp
listener.cpp
config
include
scripts
src
launch
msg
srv
action
[7]
config: All configuration files that are used in this ROS package are kept
in this folder. This folder is created by the user and is a common practice to
name the folder config to keep the configuration files in it.
scripts: This folder keeps executable Python scripts. In the block diagram,
src: This folder stores the C++ source codes. We can see two examples of
launch: This folder keeps the launch files that are used to launch one or more
ROS nodes.
action: This folder contains the action definition. We will see more about
actionlib in the upcoming sections.
We need to know some commands to create, modify, and work with the ROS
packages. Here are some of the commands used to work with ROS packages:
roscd: This command is used to change the package folder. If we give the
argument a package name, it will switch to that package folder.
Chapter 1
The package.xml file consists of the package name, version of the package, the
package description, author details, package build dependencies, and runtime
dependencies. The <build_depend></build_depend> tag includes the packages
that are necessary to build the source code of the package. The packages inside
the <run_depend></run_depend> tag are necessary during runtime of the
package node.
[9]
The ROS navigation stack is a good example of meta packages. If ROS is installed, we
can try the following command, by switching to the navigation meta package folder:
$ roscd navigation
ROS messages
The ROS nodes can publish data having a particular type. The types of data are
described using a simplified message description language, also called ROS messages.
These datatype descriptions can be used to generate source code for the appropriate
message type in different target languages.
The data type description of ROS messages are stored in .msg files in the msg
subdirectory of a ROS package.
The message definition can consist of two types: fields and constants. The field is
split into field types and field name. Field types is the data type of the transmitting
message and field name is the name of it. The constants define a constant value in the
message file.
Here is an example of message definitions:
int32 number
string name
float32 speed
[ 10 ]
Chapter 1
Here, the first part is the field type and second is the field name. The field type is
the data type and the field name can be used to access the value from the message.
For example, we can use msg.number for accessing the value of the number from
the message.
Here is a table to show some of the built-in field types that we can use in
our message:
Primitive type
Serialization
C++
Python
bool(1)
uint8_t(2)
bool
int8
int8_t
int
uint8
uint8_t
int (3)
int16
int16_t
int
uint16
uint16_t
int
int32
int32_t
int
uint32
uint32_t
int
int64
int64_t
long
uint64
uint64_t
long
float32
float
float
float64
double
float
string
ascii string(4)
std::string
string
time
secs/nsecs unsigned
32-bit ints
ros::Time
rospy.Time
duration
secs/nsecs signed
32-bit ints
ros::Duration
rospy.Duration
A special type of ROS message is called message headers. Headers can carry
information such as time, frame of reference or frame_id, and sequence number.
Using headers, we will get numbered messages and more clarity in who is sending
the current message. The header information is mainly used to send data such as
robot joint transforms (TF). Here is an example of the message header:
uint32 seq
time stamp
string frame_id
The rosmsg command tool can be used to inspect the message header and the
field types. The following command helps to view the message header of a
particular message:
$ rosmsg show std_msgs/Header
[ 11 ]
This will give you an output like the preceding example message header. We can see
more about the rosmsg command and how to work with custom message definitions
in the upcoming sections.
The first section is the message type of request that is separated by --- and in the
next section is the message type of response. In these examples, both Request and
Response are strings.
In the upcoming sections, we can see how to work with ROS services.
[ 12 ]
Chapter 1
This stack also consists of tools such as rostopic, rosparam, rosservice, and
rosnode to introspect the preceding concepts.
The ros_comm stack contains the ROS communication middleware packages and
these packages are collectively called ROS Graph layer.
Nodes
Parameter
Server
Master
Messages
Topics
Services
Bags
Nodes: Nodes are the process that perform computation. Each ROS node is
written using ROS client libraries such as roscpp and rospy. Using client
library APIs, we can implement different types of communication methods in
ROS nodes. In a robot, there will be many nodes to perform different kinds of
tasks. Using the ROS communication methods, it can communicate with each
other and exchange data. One of the aims of ROS nodes is to build simple
processes rather than a large process with all functionality. Being a simple
structure, ROS nodes are easy to debug too.
Master: The ROS Master provides name registration and lookup to the rest
of the nodes. Nodes will not be able to find each other, exchange messages,
or invoke services without a ROS Master. In a distributed system, we should
run the master on one computer, and other remote nodes can find each other
by communicating with this master.
Parameter Server: The parameter server allows you to keep the data to be
stored in a central location. All nodes can access and modify these values.
Parameter server is a part of ROS Master
[ 13 ]
Bags: Bags are a format for saving and playing back ROS message data.
Bags are an important mechanism for storing data, such as sensor data,
which can be difficult to collect but is necessary for developing and testing
robot algorithms. Bags are very useful features when we work with complex
robot mechanisms.
The following graph shows how the nodes communicate with each other using topics.
The topics are mentioned in a rectangle and nodes are represented in ellipses. The
messages and parameters are not included in this graph. These kinds of graphs can be
generated using a tool called rqt_graph (http://wiki.ros.org/rqt_graph).
[ 14 ]
Chapter 1
/mobile_base_nodelet_manager
/cmd_vel_mux
/camera/depth/camera_info
/mobile_base_nodelet_manager/bond
/bumper2pointcloud
/camera/depth/image_raw
/mobile_base/commands/velocity
/gazebo
/joint_states
/laserscan_nodelet_manager
/laserscan_nodelet_manager/bond
/depthimage_to_laserscan
/scan
/slam_gmapping
/robot_state_publisher
/tf
the node
[ 15 ]
We will see example nodes using the roscpp client and will discuss the working of
ROS nodes that use functionalities such ROS Topics, Service, Messages, and actionlib.
ROS messages
ROS nodes communicate with each other by publishing messages to a topic. As we
discussed earlier, messages are a simple data structure containing field types. The
ROS message supports standard primitive datatypes and arrays of primitive types.
Nodes can also exchange information using service calls. Services are also messages,
the service message definitions are defined inside the srv file.
We can access the message definition using the following method. For example,
to access std_msgs/msg/String.msg, we can use std_msgs/String. If we are
using the roscpp client, we have to include std_msgs/String.h for the string
message definition.
In addition to message data type, ROS uses an MD5 checksum comparison
to confirm whether the publisher and subscriber exchange the same message
data types.
ROS has inbuilt tools called rosmsg to get information about ROS messages.
Here are some parameters used along with rosmsg:
ROS topics
ROS topics are named buses in which ROS nodes exchange messages. Topics can
anonymously publish and subscribe, which means that the production of messages is
decoupled from the consumption. The ROS nodes are not interested to know which
node is publishing the topic or subscribing topics, it only looks for the topic name
and whether the message types of publisher and subscriber are matching.
The communication using topics are unidirectional, if we want to implement
request/response such as communication, we have to switch to ROS services.
[ 16 ]
Chapter 1
The ROS nodes communicate with topics using TCP/IP-based transport known as
TCPROS. This method is the default transport method used in ROS. Another type
of communication is UDPROS, which has low-latency, loose transport, and is only
suited for teleoperation.
The ROS topic tool can be used to get information about ROS topics. Here is the
syntax of this command:
$ rostopic echo /topic: This command will print the content of the
given topic
$ rostopic find /message_type: This command will find topics using the
active topic
$ rostopic list: This command will list all active topics in the ROS system
$ rostopic type /topic: This will display the message type of the
given topic
ROS services
When we need a request/response kind of communication in ROS, we have to
use the ROS services. ROS topics can't do this kind of communication because it is
unidirectional. ROS services are mainly used in a distributed system.
The ROS services is defined using a pair of messages. We have to define a request
datatype and a response datatype in a srv file. The srv files are kept in a srv folder
inside a package.
In ROS services, one node acts as a ROS server in which the service client can request
the service from the server. If the server completes the service routine, it will send
the results to the service client.
The ROS service definition can be accessed by the following method, for example,
if my_package/srv/Image.srv can be accessed by my_package/Image.
[ 17 ]
In ROS services also, there is an MD5 checksum that checks in the nodes. If the sum
is equal, then only the server responds to the client.
There are two ROS tools to get information about the ROS service. The first tool is
rossrv, which is similar to rosmsg, and is used to get information about service
types. The next command is rosservice, which is used to list and query about the
running ROS services.
The following explain how to use the rosservice tool to get information about the
running services:
$ rosservice call /service args: This tool will call the service using the
given arguments
$ rosservice list: This command will list the active services running on
given service
the system
$ rosservice type /service: This command will print the service type of
a given service
$ rosservice uri /service: This tool will print the service ROSRPC URI
ROS bags
A bag file in ROS is for storing ROS message data from topics and services. The .bag
extension is used to represent a bag file.
Bag files are created using the rosbag command, which will subscribe one or more
topics and store the message's data in a file as it's received. This file can play the
same topics as they are recorded from or it can remap the existing topics too.
The main application of rosbag is data logging. The robot data can be logged and
can visualize and process offline.
The rosbag command is used to work with rosbag files. Here are the commands to
record and playback a bag file:
$ rosbag play [bag_name]: This will playback the existing bag file.
[ 18 ]
Chapter 1
There is a GUI tool to handle record and playback of bag files called rqt_bag.
Go to the following link to know more about rqt_bag:
http://wiki.ros.org/rqt_bag
[ 19 ]
The following diagram shows an illustration of how ROS Master interacts with a
publishing and subscribing node, the publisher node publishing a string type topic
with a "Hello World" message and the subscriber node subscribes to this topic.
Publish
Subscribe
Master
Hello World
Publisher
Master
Hello World
Subscriber
Hello World
Publisher
(a)
Hello World
Subscriber
(b)
Master
Hello World
Publisher
"Hello World"
Hello World
Subscriber
(c)
Figure 8: Communication between ROS Master and Hello World publisher and subscriber
When the publisher node starts publishing the "Hello World" message in a
particular topic, ROS Master gets the details of the topic and details of the node.
It will search whether any node is subscribing the same topic. If there are no nodes
subscribing the same topic at that time, both nodes remain unconnected. If the
publisher and subscriber nodes run at the same time, ROS Master exchanges the
details of the publisher to the subscriber and they will connect and can exchange
data through ROS messages.
[ 20 ]
Chapter 1
We can store these parameters in a file and load them into the server. The server can
store a wide variety of data types and can even store dictionaries. The programmer
can also set the scope of the parameter, that is, whether it can be accessed by only
this node or all the nodes.
The parameter server supports the following XMLRPC datatypes, which include:
32-bit integers
Booleans
strings
doubles
iso8601 dates
lists
We can also store dictionaries on the parameter server. If the number of parameters
is high, we can use a YAML file to save it. Here is an example of the YAML file
parameter definitions:
/camera/name : 'nikon'
/camera/fps : 30
/camera/exposure : 1.2
/camera/active : true
#string type
#integer
#float
#boolean
The rosparam tool used to get and set the ROS parameter from the command line.
The following are the commands to work with ROS parameters:
$ rosparam load
[YAML file]: The ROS parameters can be saved into
a YAML file and it can load to the parameter server using this command
$ rosparam dump [YAML file]: This command will dump the existing ROS
The parameters can be changed dynamically during the execution of the node that
uses these parameters, using the dyamic_reconfigure package (http://wiki.ros.
org/dynamic_reconfigure).
[ 21 ]
The ROS Wiki: The ROS community Wiki is the main forum for documenting
information about ROS. Anyone can sign up for an account and contribute
their own documentation, provide corrections or updates, write tutorials,
and more.
Bug ticket system: If we find a bug in the existing software or need to add
a new feature, we can use this resource.
Blog: The ROS blog updates with news, photos, and videos related to the
ROS community (http://www.ros.org/news).
Ubuntu 14.04.2 LTS / Ubuntu 15.04: We have to use Ubuntu as the operating
system for installing ROS. We prefer to stick on to the L.T.S version of
Ubuntu, that is, Ubuntu 14.04/14.04.3, or if you want to explore new ROS
distribution you can use Ubuntu 15.04.
Chapter 1
ROS Master
The rosout node will collect log messages from other ROS nodes and store them
in a log file, and will also rebroadcast the collected log message to another topic.
The topic /rosout is published by ROS nodes working using ROS client libraries
such as roscpp and rospy and this topic is subscribed by the rosout node which
rebroadcasts the message in another topic called /rosout_agg. This topic has an
aggregate stream of log messages. The command roscore is a prerequisite before
running any ROS node. The following screenshot shows the messages printing when
we run the roscore command in a terminal.
The following is a command to run roscore on a Linux terminal:
$ roscore
[ 23 ]
In the first section, we can see a log file is creating inside the ~/.ros/log
folder for collecting logs from ROS nodes. This file can be used for debugging
purposes.
In the second section, the command starts a ROS launch file called roscore.
xml. When a launch file starts, it automatically starts the rosmaster and ROS
parameter server. The roslaunch command is a Python script, which can
start rosmaster and the ROS parameter server whenever it tries to execute
a launch file. This section shows the address of the ROS parameter server
within the port.
In the third section, we can see the parameters such as rosdistro and
rosversion displayed on the terminal. These parameters are displayed
when it executes roscore.xml. We can see more on roscore.xml and its
In the fourth section, we can see the rosmaster node is started using
ROS_MASTER_URI, which we defined earlier as an environment variable.
In the fifth section, we can see the rosout node is started, which will start
subscribing the /rosout topic and rebroadcasting into /rosout_agg.
When the roscore command is executed, initially, the command checks the command
line argument for a new port number for the rosmaster. If it gets the port number, it
will start listening to the new port number, otherwise it will use the default port. This
port number and the roscore.xml launch file will pass to the roslaunch system. The
roslaunch system is implemented in a Python module, it will parse the port number
and launch the roscore.xml file.
In the roscore.xml file, we can see the ROS parameters and nodes are encapsulated
in a group XML tag with a "/" namespace. The group XML tag indicates that all the
nodes inside this tag have the same settings.
[ 24 ]
Chapter 1
The two parameters called rosversion and rosdistro store the output of the
rosversion roslaunch and rosversion -d commands using the command tag,
which is a part of the ROS param tag. The command tag will execute the command
mentioned on it and store the output of the command in these two parameters.
The rosmaster and parameter server are executed inside roslaunch modules by
using the ROS_MASTER_URI address. This is happening inside the roslaunch Python
module. The ROS_MASTER_URI is a combination of the IP address and port in which
rosmaster is going to listen. The port number can be changed according to the given
port number in the roscore command.
The list of topics are as follows, as per our discussion on the rosout node subscribe
/rosout topic, which have all log messages from the ROS nodes and /rosout_agg
rebroadcast the log messages:
/rosout
/rosout_agg
The following command lists out the parameters available when running roscore.
The following is the command to list the active ROS parameter:
$ rosparam list
The parameters are mentioned here; they have the ROS distribution name, version,
address of roslaunch server and run_id, where run_id is a unique ID associated
with a particular run of roscore:
/rosdistro
/roslaunch/uris/host_robot_virtualbox__51189
/rosversion
/run_id
The list of the ROS service generated during the running roscore can be checked
using the following command:
$ rosservice list
[ 25 ]
These ROS services are generated for each ROS node for setting the logging levels.
After understanding the basics of ROS Master, Parameter server, and roscore
we can go to the procedure to build a ROS package. Along with working with the
ROS package, we can refresh the concepts of ROS nodes, topics, messages, services,
and actionlib.
Switch to the source folder. The packages are created inside this package:
$cd ~/catkin_ws/src
We can build the workspace even if there are no packages. We can use the following
command to switch to the workspace folder:
$ cd ~/catkin_ws
[ 26 ]
Chapter 1
After building the empty workspace, we should set the environment of the current
workspace to be visible by the ROS system. This process is called overlaying a
workspace. We should add the package environment using the following command:
$ echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc
$ source ~/.bashrc
This command will source a bash script called setup.bash inside the devel
workspace folder. To set the environment in all bash sessions, we need to add a
source command in the .bashrc file, which will source this script whenever a bash
session starts.
This is the link of the procedure http://wiki.ros.org/catkin/Tutorials/
create_a_workspace.
1. After setting the catkin workspace, we can create our own package that has
sample nodes to demonstrate the working of ROS topics, messages, services,
and actionlib.
2. The catkin_create_pkg command is used to create a ROS package.
This command is used to create our package in which we are going to
create demos of various ROS concepts.
3. Switch to the catkin workspace src folder and create the package using
the following command:
Syntax of catkin_create_pkg : catkin_create_pkg [package_name]
[dependency1] [dependency2]
std_msgs: This package contains basic ROS primitive data types such
as integer, float, string, array, and so on. We can directly use these
data types in our nodes without defining a new ROS message.
[ 27 ]
5. After creating this package, build the package without adding any nodes
using the catkin_make command. This command must be executed from the
catkin workspace path. The following command shows you how to build
our empty ROS package:
~/catkin_ws$ catkin_make
6. After a successful build, we can start adding nodes to the src folder
of this package.
The build folder in the CMake build files mainly contains executables of the nodes
that are placed inside the catkin workspace src folder. The devel folder contains
bash script, header files, and executables in different folders generated during the
build process. We can see how to make ROS nodes and build using catkin_make.
Chapter 1
The ros/ros.h is the main header of ROS. If we want to use the roscpp client APIs
in our code, we should include this header. The std_msgs/Int32.h is the standard
message definition of integer datatype.
Here, we are sending an integer value through a topic. So we should need a message
type for handling the integer data. std_msgs contains standard message definition of
primitive datatypes. std_msgs/Int32.h contains integer message definition:
ros::init(argc, argv,"demo_topic_publisher");
This code will initialize a ROS node with a name. It should be noted that the ROS
node should be unique. This line is mandatory for all ROS C++ nodes:
ros::NodeHandle node_obj;
[ 29 ]
This will create a Nodehandle object, which is used to communicate with the
ROS system:
ros::Publisher number_publisher =
node_obj.advertise<std_msgs::Int32>("/numbers",10);
This will create a topic publisher and name the topic /numbers with a message type
std_msgs::Int32. The second argument is the buffer size. It indicates that how
many messages need to be put in a buffer before sending. It should be set to high if
the data sending rate is high:
ros::Rate loop_rate(10);
This is an infinite while loop, and it quits when we press Ctrl+C. The ros::ok()
function returns zero when there is an interrupt; this can terminate this while loop:
std_msgs::Int32 msg;
msg.data = number_count;
The first line creates an integer ROS message and the second line assigns an integer
value to the message. Here, data is the field name of the msg object:
ROS_INFO("%d",msg.data);
This will print the message data. This line is used to log the ROS information:
number_publisher.publish(msg);
This command will read and update all ROS topics. The node will not publish
without a spin() or spinOnce() function:
loop_rate.sleep();
This line will provide the necessary delay to achieve a frequency of 10Hz.
After discussing the publisher node, we can discuss the subscriber node, which is
demo_topic_subscriber.cpp. Copy the code to a new file or use the existing file.
[ 30 ]
Chapter 1
This is a callback function that will execute whenever a data comes to the /numbers
topic. Whenever a data reaches this topic, the function will call and extract the value
and print it on the console:
ros::Subscriber number_subscriber =
node_obj.subscribe("/numbers",10,number_callback);
This is the subscriber and here, we are giving the topic name needed to subscribe,
buffer size, and the callback function. We are subscribing /numbers topic and we
have already seen the callback function in the preceding section:
ros::spin();
[ 31 ]
This is an infinite loop in which the node will wait in this step. This code will fasten
the callbacks whenever a data reaches the topic. The node will quit only when we
press the Ctrl+C key.
We can add the preceding snippet to create a new a CMakeLists.txt file for
compiling the two codes.
The catkin_make command is used to build the package.
We can first switch to workspace:
$ cd ~/catkin_ws
We can either use the preceding command to build a specific package or just
caktin_make to build the entire workspace.
[ 32 ]
Chapter 1
The following diagram shows how the nodes communicate with each other. We can
see the demo_topic_publisher node publish the /numbers topic and subscribe by
then demo_topic_subscriber node.
/demo_topic_publisher
/numbers
/demo_topic_subscriber
[ 33 ]
We can use the rosnode and rostopic tools to debug and understand the working
of two nodes:
publisher node
$ rostopic echo /numbers: This will display the value sending through
$ rostopic type /numbers: This will print the message type of the
/numbers topic
Until now, we have worked only with standard message definitions. Now, we have
created our own definitions and can see how to use them in our code.
The first step is to edit the package.xml file of the current package and uncomment
the lines <build_depend>message_generation</build_depend> and <run_
depend>message_runtime</run_depend>.
Edit the current CMakeLists.txt and add the message_generation line as follows:
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
actionlib
[ 34 ]
Chapter 1
actionlib_msgs
message_generation
)
Uncomment the following line and add the custom message file:
add_message_files(
FILES
demo_msg.msg
)
## Generate added messages and services with any dependencies listed
here
generate_messages(
DEPENDENCIES
std_msgs
actionlib_msgs
)
To check whether the message is built properly, we can use the rosmsg command:
$ rosmsg show mastering_ros_demo_pkg/demo_msg
If the content shown by the command and the definition are the same, the procedure
is correct.
If we want to test the custom message, we can build a publisher and subscriber
using the custom message type named demo_msg_publisher.cpp and demo_msg_
subscriber.cpp. Navigate to the chapter_1_codes/mastering_ros_demo_pkg/
src folder for these codes.
We can test the message by adding the following lines of code in CMakeLists.txt:
add_executable(demo_msg_publisher src/demo_msg_publisher.cpp)
add_executable(demo_msg_subscriber src/demo_msg_subscriber.cpp)
add_dependencies(demo_msg_publisher mastering_ros_demo_pkg_generate_
messages_cpp)
add_dependencies(demo_msg_subscriber mastering_ros_demo_pkg_generate_
messages_cpp)
target_link_libraries(demo_msg_publisher ${catkin_LIBRARIES})
target_link_libraries(demo_msg_subscriber ${catkin_LIBRARIES})
[ 35 ]
Build the package using catkin_make and test the node using the following
commands.
Run roscore:
$ roscore
The publisher node publishes a string along with an integer, and the subscriber
node subscribes the topic and prints the values. The output and graph are shown
as follows:
/demo_msg_subscriber
Next, we can add srv files to the package. Create a new folder called srv in the
current package folder and add a srv file called demo_srv.srv. The definition
of this file is as follows:
string in
--string out
[ 36 ]
Chapter 1
We need to follow the same procedure in generating services as we did for the
ROS message. Apart from that, we need additional sections to be uncommented
as shown here:
## Generate services in the 'srv' folder
add_service_files(
FILES
demo_srv.srv
)
After making these changes, we can build the package using catkin_make and using
the following command we can verify the procedure:
$ rossrv show mastering_ros_demo_pkg/demo_srv
If we see the same content as we defined in the file, we can confirm it's working.
"ros/ros.h"
"mastering_ros_demo_pkg/demo_srv.h"
<iostream>
<sstream>
Here, we included ros/ros.h, which is a mandatory header for a ROS CPP node.
The mastering_ros_demo_pkg/demo_srv.h header is a generated header, which
contains our service definition and can use this in our code. The sstream.h is for
getting string streaming classes:
bool demo_service_callback(mastering_ros_demo_pkg::demo_srv::Request
&req,
mastering_ros_demo_pkg::demo_srv::Response &res)
{
[ 38 ]
Chapter 1
This is the server callback function executed when a request is received on the server.
The server can receive the request from clients having a message type of mastering_
ros_demo_pkg::demo_srv::Request and sends the response in the mastering_
ros_demo_pkg::demo_srv::Response type:
std::stringstream ss;
ss << "Received Here";
res.out = ss.str();
In this code, the string data "Received Here" is passing to the service Response
instance. Here, out is the field name of the response that we have given in the
demo_srv.srv. This response will go to the service client node:
ros::ServiceServer service = n.advertiseService("demo_service",
demo_service_callback);
This line creates a service client that has message type mastering_ros_demo_
pkg::demo_srv and communicates to a ROS service named demo_service:
mastering_ros_demo_pkg::demo_srv srv;
Fill the request instance with a string called "Sending from Here":
if (client.call(srv))
{
This will send the service call to the server. If it is sent successfully, it will print the
response and request, if it failed, it do nothing:
ROS_INFO("From Client [%s], Server says [%s]",srv.request.in.c_
str(),srv.response.out.c_str());
If the response is received, then it will print the request and the response.
[ 40 ]
Chapter 1
After discussing the two nodes, we can discuss how to build these two nodes. The
following code is added to CMakeLists.txt to compile and build the two nodes:
add_executable(demo_service_server src/demo_service_server.cpp)
add_executable(demo_service_client src/demo_service_client.cpp)
add_dependencies(demo_service_server mastering_ros_demo_pkg_generate_
messages_cpp)
add_dependencies(demo_service_client mastering_ros_demo_pkg_generate_
messages_cpp)
target_link_libraries(demo_service_server ${catkin_LIBRARIES})
target_link_libraries(demo_service_client ${catkin_LIBRARIES})
To start nodes, first execute roscore and use the following commands:
$ rosrun mastering_ros_demo_pkg demo_service_server
$ rosrun mastering_ros_demo_pkg demo_service_client
[ 41 ]
of /demo_service
of /demo_service
Goal: The action client can send a goal that has to be executed by the action
server. This is similar to the request in the ROS service. For example, if a
robot arm joint wants to move from 45 degrees to 90 degrees, the goal here is
90 degrees.
Feedback: When an action client sends a goal to the action server, it will start
executing a call-back function. Feedback is simply giving the progress of the
current operation inside the callback function. Using the feedback definition,
we can get the current progress. In the preceding case, the robot arm joint
has to move to 90 degrees; in this case, the feedback can be the intermediate
value between 45 and 90 degrees in which the arm is moving.
Result: After completing the goal, the action server will send a final result of
completion, it can be the computational result or an acknowledgement. In the
preceding example, if the joint reaches 90 degrees it achieves the goal and the
result can be anything indicating it finished the goal.
[ 42 ]
Chapter 1
We can discuss a demo action server and action client here. The demo action client
will send a number as the goal. When an action server receives the goal, it will count
from 0 to the goal number with a step size of 1 and with a one second delay. If it
completes before the given time, it will send the result, otherwise, the task will be
preempted by the client. The feedback here is the progress of counting. The action
file of this task is as follows. The action file is named Demo_action.action:
#goal definition
int32 count
--#result definition
int32 final_count
--#feedback
int32 current_number
Here, the count value is the goal in which the server has to count from zero to this
number. final_count is the result, in which the final value after completion of a task
and current_number is the feedback value. It will specify how much the progress is.
Navigate to chapter_1_codes/mastering_ros_demo_pkg/src and you can
find the action server node as demo_action_server.cpp and action client node
as demo_action_client.cpp.
The first header is the standard action library to implement an action server node.
The second header is generated from the stored action files. It should include for
accessing our action definition:
class Demo_actionAction
{
[ 43 ]
Create a simple action server instance with our custom action message type:
mastering_ros_demo_pkg::Demo_actionFeedback feedback;
This line registers a callback when the action is preempted. The preemtCB is the
callback name executed when there is a preempt request from the action client:
void executeCB(const mastering_ros_demo_pkg::Demo_actionGoalConstPtr
&goal)
{
if(!as.isActive() || as.isPreemptRequested()) return;
This is the callback definition which is executed when the action server receives a
goal value. It will execute callback functions only after checking whether the action
server is currently active or it is preempted already:
for(progress = 0 ; progress < goal->count; progress++){
//Check for ros
if(!ros::ok()){
This loop will execute until the goal value is reached. It will continuously send the
current progress as feedback:
if(!as.isActive() || as.isPreemptRequested()){
return;
}
[ 44 ]
Chapter 1
Inside this loop, it will check whether the action server is active or it is preempted. If
it occurs, the function will return:
if(goal->count == progress){
result.final_count = progress;
as.setSucceeded(result);
}
If the current value reaches the goal value, then it publishes the final result:
Demo_actionAction demo_action_obj(ros::this_node::getName());
number which is the goal. The client is getting the goal value from the command line
arguments. The first command line argument of the client is the goal value and the
second is the time of completion for this task.
The goal value will be sent to the server and the client will wait until the given time,
in seconds. After waiting, the client will check whether it completed or not; if it is not
complete, the client will preempt the action.
The client code is a bit lengthy, so we will discuss the important sections of the code:
#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>
#include "mastering_ros_demo_pkg/Demo_actionAction.h"
This line will wait for an infinite time if there is no action server running on the
system. It will exit only when there is an action server running on the system:
mastering_ros_demo_pkg::Demo_actionGoal goal;
goal.count = atoi(argv[1]);
ac.sendGoal(goal);
[ 45 ]
Create an instance of a goal and send the goal value from the first command
line argument:
bool finished_before_timeout =
ac.waitForResult(ros::Duration(atoi(argv[2])));
This line will wait for the result from the server until the given seconds:
ac.cancelGoal();
[ 46 ]
Chapter 1
After catkin_make, we can run these nodes using the following commands:
Run roscore:
$ roscore
[ 47 ]
[ 48 ]
Chapter 1
The roslaunch command will automatically start ROS Master and the parameter
server. So in essence, there is no need to start the roscore command and individual
node; if we launch the file, all operations will be done in a single command.
Let's start creating launch files. Switch to the package folder and create a new launch
file called demo_topic.launch to launch two ROS nodes that are publishing and
subscribing an integer value. We keep the launch files in a launch folder, which is
inside the package:
$ roscd mastering_ros_demo_pkg
$ mkdir launch
$ cd launch
$ gedit demo_topic.launch
Let's discuss what is in the code. The <launch></launch> tags are the root element
in a launch file. All definitions will be inside these tags.
The <node> tag specifies the desired node to launch:
<node name="publisher_node" pkg="mastering_ros_demo_pkg"
type="demo_topic_publisher" output="screen"/>
The name tag inside <node> indicates the name of the node, pkg is the name of the
package, and type is the name of executable we are going to launch.
After creating the launch file demo_topic.launch, we can launch it using the
following command:
$ roslaunch mastering_ros_demo_pkg demo_topic.launch
[ 49 ]
We can also view the log messages and debug the nodes using a GUI tool called
rqt_console:
$ rqt_console
We can see the logs generated by two nodes in this tool as shown here:
[ 50 ]
Chapter 1
Create a Git repository for the current package. The repository that has the
package is called the upstream repository. Here, we already created a repository
at https://github.com/qboticslabs/mastering_ros_demo_pkg.
Create an empty repository in Git for the release package. This repository is called
the release repository. We have created a package called demo_pkg-release.
This package is at https://github.com/qboticslabs/demo_pkg-release.
After meeting these prerequisites, we can start to create the release of the package.
Navigate to the mastering_ros_demo_pkg local repository where we push our
package code to Git. Open a terminal inside this local repository and execute the
following command:
$ catkin_generate_changelog
The purpose of this command is, it will create a CHANGELOG.rst file inside the local
repository. After executing this command it will show this option:
Continue without -all option [y/N]. Give y here
The command will set a version tag if there is no current version and commit the
changes in the upstream repository.
[ 52 ]
Chapter 1
package in ROS contains an index file, which contains a list of all the packages in
ROS. Currently, there is no index for our package because this is our first release, but
we can add our package details to this index file called distributions.yaml.
The following message will be displayed when there is no reference of the package in
rosdistro:
[ 53 ]
We should give the release repository in the terminal that is marked in red in
the preceding screenshot. In this case, the URL was https://github.com/
qboticslabs/demo_pkg-release.
In the upcoming steps, the wizard will ask for the repository name, upstream, URL,
and so on. We can give these options and finally, a pull request to rosdistro will be
submitted, which is shown in the following screenshot:
[ 54 ]
Chapter 1
distribution.yaml:
After this step, we can confirm that the package is released and officially added to
the ROS index.
[ 55 ]
The first step is to register in wiki using your mail address. Go to wiki.ros.org,
and click on the login button as shown in the screenshot:
After clicking on Login, you can register or directly login with your details if you are
already registered. After login, press the user name link on the right side of the wiki
page as shown in the screenshot:
[ 56 ]
Chapter 1
After clicking on this link, you will get a chance to create a home page for your
package; you will get a text editor with GUI to enter data into. The following
screenshot shows you the page we created for this demo package:
Questions
[ 57 ]
Summary
ROS is now a trending software framework among roboticists. Gaining knowledge in
ROS is essential in the upcoming years if you are planning to build your career as a
robotics engineer. In this chapter, we have gone through the basics of ROS mainly to
refresh the concepts if you have already learned ROS. We discussed the necessity of
learning ROS and how it excels among the current robotics software platforms. We
went through the basic concepts such as ROS Master, Parameter server, and roscore
and saw the explanation of the working of roscore. After discussing the internal
working of roscore, we discussed each ROS concept, such as ROS topics, services,
messages, and actionlib by illustrating examples. After demonstrating the working
of each concept, we uploaded the package to GitHub and created a wiki page for the
package. In the next chapter, we will discuss ROS robot modeling using URDF and
xacro and will design some robot models.
[ 58 ]
www.PacktPub.com
Stay Connected: