Working With ROS nodelets in ROS Noetic

2020-01-07-151031

In this section, we’ll learn how to work with ROS nodelets.

What is a ROS nodelet?

A node in ROS is a program that runs a specific process. These nodes communicate back and forth with each other on the ROS network via special ROS constructs, known as topics. The disadvantage of this framework is that message passing can get pretty slow if there is a large volume of data that needs to be passed (e.g. data from 3D sensor). 

Fortunately, ROS has something called a nodelet. A nodelet is a special type of ROS node that enables you to run multiple nodes in a single process on a single computer. These nodes are actually separate threads that can communicate with each other directly without going through the traditional ROS communication network middleman. 

The cool thing about nodelets is that they can load as plugins (see the last section of this tutorial), which means that you can add them to your application or remove them from your application without having to make major modifications to your main source code.

The disadvantage of a nodelet is that if a nodelet goes down, all the running processes within it go down as well. Also, the nodelet concept is only implemented in C++, so you can’t use Python.

Bottom Line: If you need a quick and efficient way to pass large amounts of data from one node to another, consider using a nodelet. Otherwise, always use nodes because they are more flexible.

With that background, let’s take a look now at how to create a ROS nodelet. I will loosely follow the official tutorial on the ROS website.

How to Create a ROS Nodelet

The nodelet that we will create will subscribe to a topic (/ros_in). It will then receive a message via that topic and then republish that message to another topic (/ros_out).

Open a new terminal window.

Type the following command:

cd ~/catkin_ws/src

Create a new package called nodelet_basics

catkin_create_pkg nodelet_basics nodelet roscpp std_msgs

The nodelet package we included in the command above provides the tools to build a nodelet.

Move to the src folder of the package you just created.

cd nodelet_basics/src

Create a new file. This file will have the code for the nodelet.

gedit hello_world.cpp

Type the following lines of code:

/*
Author: Addison Sears-Collins

This ROS nodelet will subscribe to a topic (/ros_in). 
It will then receive a message via that topic and then 
republish that message to another topic (/ros_out). 

Date: 6/19/2020

ROS Version: ROS Noetic Ninjemys
*/

// Add the necessary includes
#include <ros/ros.h>
#include <std_msgs/String.h>
#include <nodelet/nodelet.h>
#include <pluginlib/class_list_macros.h>
#include <stdio.h>


namespace nodelet_basics
{
	/*********
	* Nodelet
	**********/

	// This code here means the class needs to inherit from 
	// nodelet::Nodelet
	class Hello_World : public nodelet::Nodelet
	{
	
		public:
			Hello_World()
			{
			}

		private:
			// The onInit method is called by nodelet manager. 
			// It is responsible for initializing the nodelet.
			virtual void onInit()
			{
				// Create a NodeHandle object
				ros::NodeHandle& private_nh = getPrivateNodeHandle();
				NODELET_DEBUG("Initializing nodelet...");
			
				// Create a publisher topic
				pub = private_nh.advertise<std_msgs::String>("ros_out",10); 
			
				// Create a subscriber topic
				sub = private_nh.subscribe("ros_in",10, &Hello_World::callback, this);	
			}

			ros::Publisher pub;
			ros::Subscriber sub;
	
			// Display messages from /ros_in topic to the terminal window.
			// Publish to /ros_out topic
			void callback(const std_msgs::String::ConstPtr& input)
			{

				std_msgs::String output;
				output.data = input->data;
				NODELET_DEBUG("msg data = %s",output.data.c_str());
				ROS_INFO("msg data = %s",output.data.c_str());
				pub.publish(output);		
			}
	};
	// Export the Hello_World class as a plugin using the
	// PLUGINLIB_EXPORT_CLASS macro.
	PLUGINLIB_EXPORT_CLASS(nodelet_basics::Hello_World, nodelet::Nodelet);
}

Save and close the editor.

Now, let’s create an xml file that describes the plugin.

roscd nodelet_basics
gedit nodelet_plugins.xml

Add these lines. 

<library path="lib/libnodelet_basics">
  <class name="nodelet_basics/Hello_World" 
         type="nodelet_basics::Hello_World" 
		 base_class_type="nodelet::Nodelet">
	<description>
		This nodelet receives a message and publishes it.
	</description>
  </class>
</library>

This nodelet receives a message and publishes it.

Save and close the editor.

Open the package.xml file.

gedit package.xml

Make sure you add this line between the <export></export> tags.

<nodelet plugin="${prefix}/nodelet_plugins.xml" />

Save and close the file.

Now let’s edit CMakeLists.txt.

gedit CMakeLists.txt

Add these lines to the bottom of the CMakeLists.txt file.

## Declare C++ library
add_library(nodelet_basics src/hello_world.cpp)

## Link libraries
target_link_libraries(nodelet_basics ${catkin_LIBRARIES}) 

Click Save and close the editor.

Build the package.

cd ~/catkin_ws/
catkin_make

If the build is successful, you’ll see a shared object named libnodelet_basics.co. This file is the plugin.

26-thats-our-pluginJPG

Now let’s create a launch file.

roscd nodelet_basics
mkdir launch
cd launch
gedit hello_world_launch.launch
<launch>
  <node pkg="nodelet" 
        type="nodelet" 
        name="standalone_nodelet"  
        args="manager" 
        output="screen"
  />

  <node pkg="nodelet" 
        type="nodelet" 
        name="Hello_World" 
        args="load nodelet_basics/Hello_World standalone_nodelet" 
        output="screen"
  />
</launch>

Save and close the editor.

Now, launch the nodelet. Remember when you use the roslaunch command, you don’t have to launch the ROS master using roscore.

roslaunch nodelet_basics hello_world_launch.launch

Here is the output.

27-ran-launch-fileJPG

In another terminal, check out the list of active nodes.

rosnode list
28-rosnode-listJPG

In another terminal, check out the list of topics.

rostopic list
29-rostopic-listJPG

Let’s publish a string message to the /ros_in topic. In a new terminal, type the following

rostopic echo /Hello_World/ros_out

This code above is now ready for you to publish your string. It will republish the string it receives. Let’s type the string now.

rostopic pub /Hello_World/ros_in std_msgs/String "Hi Automatic Addison"

Here is what you should see on the /Hello_World/ros_in topic terminal window.

30-publish-messageJPG

Here is what you should see on the /Hello_World/ros_out terminal window.

31-rosout-republish-messageJPG

Let’s check out the node graph.

rqt_graph
32-node-graphJPG

That’s it! You now know how to create a nodelet.