Understanding the ROS computation graph level
The computation in ROS is done using a network of process called ROS nodes. This computation network can be called the computation graph. The main concepts in the computation graph are ROS Nodes, Master, Parameter server, Messages, Topics, Services, and Bags. Each concept in the graph is contributed to this graph in different ways.
The ROS communication related packages including core client libraries such as roscpp
and rospython
and the implementation of concepts such as topics, nodes, parameters, and services are included in a stack called ros_comm
(http://wiki.ros.org/ros_comm).
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.
Figure 6 : Structure of the ROS Graph layer
The following are abstracts of each graph's concepts:
- Nodes: Nodes are the process that perform computation. Each ROS node is written using ROS client libraries such as
roscpp
androspy
. 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
- Messages: Nodes communicate with each other using messages. Messages are simply a data structure containing the typed field, which can hold a set of data and that can be sent to another node. There are standard primitive types (integer, floating point, Boolean, and so on) and these are supported by ROS messages. We can also build our own message types using these standard types.
- Topics: Each message in ROS is transported using named buses called topics. When a node sends a message through a topic, then we can say the node is publishing a topic. When a node receives a message through a topic, then we can say that the node is subscribing to a topic. The publishing node and subscribing node are not aware of each other's existence. We can even subscribe a topic that might not have any publisher. In short, the production of information and consumption of it are decoupled. Each topic has a unique name, and any node can access this topic and send data through it as long as they have the right message type.
- Services: In some robot applications, a publish/subscribe model will not be enough if it needs a request/response interaction. The publish/subscribe model is a kind of one-way transport system and when we work with a distributed system, we might need a request/response kind of interaction. ROS Services are used in these case. We can define a service definition that contains two parts; one is for requests and the other is for responses. Using ROS Services, we can write a server node and client node. The server node provides the service under a name, and when the client node sends a request message to this server, it will respond and send the result to the client. The client might need to wait until the server responds. The ROS service interaction is like a remote procedure call.
- 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).
Figure 7 : Graph of communication between nodes using topics
Understanding ROS nodes
ROS nodes are a process that perform computation using ROS client libraries such as roscpp
and rospy
. One node can communicate with other nodes using ROS Topics, Services, and Parameters.
A robot might contain many nodes, for example, one node processes camera images, one node handles serial data from the robot, one node can be used to compute odometry, and so on.
Using nodes can make the system fault tolerant. Even if a node crashes, an entire robot system can still work. Nodes also reduce the complexity and increase debug-ability compared to monolithic codes because each node is handling only a single function.
All running nodes should have a name assigned to identify them from the rest of the system. For example, /camera_node
could be a name of a node that is broadcasting camera images.
There is a rosbash
tool to introspect ROS nodes. The rosnode
command can be used to get information about a ROS node. Here are the usages of rosnode
:
$ rosnode info [node_name]
: This will print the information about the node$ rosnode kill [node_name]
: This will kill a running node$ rosnode list
: This will list the running nodes$ rosnode machine [machine_name]
: This will list the nodes running on a particular machine or a list of machines$ rosnode ping
: This will check the connectivity of a node$ rosnode cleanup
: This will purge the registration of unreachable nodes
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
:
$ rosmsg show [message]
: This shows the message description$ rosmsg list
: This lists all messages$ rosmsg md5 [message]
: This displaysmd5sum
of a message$ rosmsg package [package_name]
: This lists messages in a package$ rosmsg packages [package_1] [package_2]
: This lists packages that contain messages
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.
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 bw /topic
: This command will display the bandwidth used by the given topic$ rostopic echo /topic
: This command will print the content of the given topic$ rostopic find /message_type
: This command will find topics using the given message type$ rostopic hz /topic
: This command will display the publishing rate of the given topic$ rostopic info /topic
: This command will print information about an active topic$ rostopic list
: This command will list all active topics in the ROS system$ rostopic pub /topic message_type args
: This command can be used to publish a value to a topic with a message type$ 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
.
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 find service_type
: This command will find services in the given service type$ rosservice info /services
: This will print information about the given service$ rosservice list
: This command will list the active services running on 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 record [topic_1] [topic_2] -o [bag_name]
: This command will record the given topics into a bag file that is given in the command. We can also record all topics using the-a
argument.$ rosbag play [bag_name]
: This will playback the existing bag file.
Here are more details about this command:
http://wiki.ros.org/rosbag/Commandline
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
:
Understanding ROS Master
ROS Master is much like a DNS server. When any node starts in the ROS system, it will start looking for ROS Master and register the name of the node in it. So ROS Master has the details of all nodes currently running on the ROS system. When any details of the nodes change, it will generate a call-back and update with the latest details. These node details are useful for connecting with each node.
When a node starts publishing a topic, the node will give the details of the topic such as name and data type to ROS Master. ROS Master will check whether any other nodes are subscribed to the same topic. If any nodes are subscribed to the same topic, ROS Master will share the node details of the publisher to the subscriber node. After getting the node details, these two nodes will interconnect using the TCPROS protocol, which is based on TCP/IP sockets. After connecting to the two nodes, ROS Master has no role in controlling them. We might be able to stop either the publisher node or the subscriber node according to our wish. If we stop any nodes, it will check with ROS Master once again. This same method is for the ROS services.
The nodes are written using the ROS client libraries such as roscpp
and rospy
. These clients interact with ROS Master using XMLRPC (XML Remote Procedure Call) based APIs, which act as the backend of the ROS system APIs.
The ROS_MASTER_URI
environment variable contains the IP and port of ROS Master. Using this variable, ROS nodes can locate ROS Master. If this variable is wrong, the communication between nodes will not take place. When we use ROS in a single system, we can use the IP of localhost or the name localhost
itself. But in a distributed network, in which computation is on different physical computers, we should define ROS_MASTER_URI
properly, only then, the remote node could find each other and communicate with each other. We need only one Master, in a distributed system, and it should run on a computer in which all other computers can ping it properly to ensure that remote ROS nodes can access the Master.
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.
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.
Using the ROS parameter
While programming a robot, we might have to define robot parameters such as robot controller gain such as P, I, and D. When the number of parameters increases, we might need to store it as files. In some situation, these parameters have to share between two or more programs too. In this case, ROS provides a parameter server, which is a shared server in which all ROS nodes can access parameters from this server. A node can read, write, modify and delete parameter values from the parameter server.
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
- base64-encoded binary data
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' #string type /camera/fps : 30 #integer /camera/exposure : 1.2 #float /camera/active : true #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 set [parameter_name] [value]
: This command will set a value in the given parameter$ rosparam get [parameter_name]
: This command will retrieve a value from the given parameter$ 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 parameters to a YAML file$ rosparam delete [parameter_name]
: This command will delete the given parameter$ rosparam list
: This command will list existing parameter names
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).