Creating ROS nodes

In this section, we are going to learn how to create two nodes, where one will publish data and the other will receive this data. This is the most basic way of communicating between two nodes in the ROS system.

We created the ROS package chapter2_tutorials in the earlier section Creating a ROS package and metapackage. Now, we will navigate to the chapter2_tutorials/src/ folder using the following command:

$ roscd chapter2_tutorials/src/

We will create two files with the names example_1a.cpp and example_1b.cpp. The example_1a.cpp file will create a node named example1a, which publishes the data "Hello World!" on the /message topic. Moreover, the example_1b.cpp file will create a node named example1b, which subscribes to the /message topic and receives the data sent by the example1a node, and shows the data in the shell.

We can copy the following code inside the example_1a.cpp file, or download it from the repository (https://github.com/kbipin/Robot-Operating-System-Cookbook/blob/master/chapter2_tutorials/src/example_1a.cpp):

#include "ros/ros.h" 
#include "std_msgs/String.h" 
#include <sstream> 
 
int main(int argc, char **argv) 
{ 
  ros::init(argc, argv, "example1a"); 
  ros::NodeHandle n; 
  ros::Publisher pub = n.advertise<std_msgs::String>("message", 100); 
  ros::Rate loop_rate(10); 
  
  while (ros::ok()) 
  { 
    std_msgs::String msg; 
    std::stringstream ss; 
    ss << "Hello World!"; 
    msg.data = ss.str(); 
    pub.publish(msg); 
     
    ros::spinOnce(); 
    loop_rate.sleep(); 
  } 
  return 0; 
} 

We will discuss the preceding code to understand the ROS development framework in detail. The headers to be included are ros/ros.h, std_msgs/String.h, and sstream. ros/ros.h includes all the files needed for working with ROS, and std_msgs/String.h includes the header that defines the type of message used for publishing to the ROS computational network:

#include "ros/ros.h" 
#include "std_msgs/String.h" 
#include <sstream> 

Here, we will initialize the node and set the name. It should be remembered that the name must be unique:

ros::init(argc, argv, "example1a"); 

This is the handler of the processes associated with the node, which allow it to interact with the environment:

ros::NodeHandle n; 

At this point, we will instantiate a publisher with the name of the topic and the type, which also specifies the size of a buffer in the second parameter (if the topic is publishing data quickly, the buffer will keep at least 100 messages):

ros::Publisher pub = n.advertise<std_msgs::String>("message", 100); 

The next line of code sets the data sending frequency, which, in this case, is 10 Hz:

ros::Rate loop_rate(10); 

The next ros::ok() line stops the node if Ctrl + C is pressed or if ROS stops all the nodes:

while (ros::ok()) 
{

In this part of the code, we will create a variable for the message with the correct type to send the data:

std_msgs::String msg; 
std::stringstream ss; 
ss << "Hello World!"; 
msg.data = ss.str(); 
pub.publish(msg); 

Moreover, we will continue by sending the message, using the previously defined semantics of the publisher:

pub.publish(msg); 

The spinOnce function takes care of handling all of the internal ROS events and actions, such as reading from subscribed topics; however, spinOnce performs one iteration in the main loop of ROS, in order to allow the user to perform actions between iterations, while the spin function runs the main loop without interruption.

Finally, at this point, we sleep for the required time to get a 10 Hz frequency:

loop_rate.sleep();

We have successfully created a publisher node. Likewise, we will now create the subscriber node. Copy the following code inside the example_1b.cpp file, or download it from the repository (https://github.com/kbipin/Robot-Operating-System-Cookbook/blob/master/chapter2_tutorials/src/example_1b.cpp):

#include "ros/ros.h" 
#include "std_msgs/String.h" 
 
void messageCallback(const std_msgs::String::ConstPtr& msg) 
{ 
  ROS_INFO("Thanks: [%s]", msg->data.c_str()); 
} 
 
int main(int argc, char **argv) 
{ 
  ros::init(argc, argv, "example1b"); 
  ros::NodeHandle n; 
  ros::Subscriber sub = n.subscribe("message", 100, messageCallback); 
  ros::spin(); 
  return 0; 
} 

Let's discuss the source code. As discussed previously, ros/ros.h includes all the files necessary for using the node with ROS, and std_msgs/String.h defines the type of message used:

#include "ros/ros.h" 
#include "std_msgs/String.h" 
#include <sstream> 

The following source code shows the type of function callback that is invoked in response to an action, which in this case is the reception of a string message on subscribed topics. This function allows us to process the received message data; in this case, it displays the message data on the Terminal:

void messageCallback(const std_msgs::String::ConstPtr& msg) 
{ 
  ROS_INFO("Thanks: [%s]", msg->data.c_str()); 
}

At this point, we will create a subscriber and start to listen to the topic with the name message where the buffer size will be of 100, and the function to handle the message will be messageCallback:

ros::Subscriber sub = n.subscribe("message", 1000, messageCallback); 

Finally, the line ros::spin() is the main loop where the node begins to read the topics, and, when a message arrives, messageCallback is called. When the user presses Ctrl + C, the node exits the loop and ends:

ros::spin(); 
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.107.90