How to write a simple publisher and subscriber in ROS in C++

ROS (Robot Operating System) is an open-source middleware framework that provides a collection of software libraries and tools to help developers create robot applications. Despite its name, ROS is not an actual operating system; rather, it runs on top of a conventional operating system (typically Linux) and provides services such as hardware abstraction, device drivers, communication between processes, package management, and more.

In this tutorial, we’ll write a simple publisher and subscriber to demonstrate basic communication between different nodes in the ROS system. We’ll explore how to work with catkin workspace, create a ROS package, and run different ROS nodes. To get started, we need to install ROS. We can do that by following the instructions on the ROS Installationhttps://wiki.ros.org/ROS/Installation page. On our platform, we’ve installed ROS Noetic.

ROS publisher-subscriber protocol
ROS publisher-subscriber protocol

Create a new ROS package

A ROS package is a fundamental organizational unit used to structure and manage the robotic software. It is a directory that contains code, data, and configuration files related to a specific functionality, module, or component of a robotic system.

Let’s start by creating a ROS package. We’ll build our code in the widget at the bottom. First, we change our directory to the source space directory of the catkin workspace (we created this directory while setting up ROS):

cd ~/catkin_ws/src

Next, we utilize the catkin_create_pkg script to generate a new package. To use it, we need to provide a package name, and we can optionally specify a list of dependencies that the package relies on. We can use the following command to create a package named edu_pub_sub, specifying its dependencies as std_msgs, and roscpp.

catkin_create_pkg edu_pub_sub std_msgs roscpp

As a result, we’ll find a edu_pub_sub directory containing a CMakeLists.txt that have already been partially populated with the details we provided to catkin_create_pkg.

Build the catkin workspace

Building the catkin workspace is the process of compiling and constructing the software packages contained within a catkin workspace in ROS. A catkin workspace is a directory where ROS packages are organized, built, and maintained.

Let’s first change our directory to catkin workspace:

cd ~/catkin_ws

Before building the package, let’s copy the code to the package directory:

Note: On Educative, all codes in the widget are kept in the /usercode directory.

cp ../../usercode/edu_pub_sub src -r

Now, we’re all set to build our catkin workspace. We execute the following command in the terminal:

catkin_make

After the workspace has been built, we get build and devel folders in our current directory. In the devel folder, we have several setup.*sh files. Sourcing any of these files will overlay this workspace on top of our environment.

Run the nodes

We’re all set to run our ROS nodes to exhibit the publisher and subscriber behavior. Before running the nodes, we need to make sure that the roscore is up and running.

The roscore

It is the core of the ROS ecosystem and serves as the master process that manages various essential services and functionalities required for ROS nodes to communicate and work together.

To start roscore, we can run the following command:

roscore

Publisher

The code for the publisher can be viewed in talker.cpp in the widget at the end of this answer.

  • Line 1: We include the ros/ros.h header, which is a convenient header inclusion that incorporates all the necessary headers for utilizing the widely used public components of the ROS system.

  • Line 11: We initialize ROS.

  • Line 22: We inform the ROS Master that we intend to publish a message of type std_msgs/String on the topic chatter. This communication allows the ROS Master to notify any nodes monitoring chatter that data will be published on that topic.

    • The NodeHandle::advertise() function returns a ros::Publisher object, serving two functions: firstly, it includes a publish() method enabling the publication of messages on the specified topic, and secondly, when it goes out of scope, it is automatically unadvertised.

  • Lines 32–36: We prepare a ROS message by utilizing a class adapted for messages, typically generated from a msg file.

  • Line 43: We broadcast the message to any node that’s connected.

To run the publisher, we open a new terminal using the “+” button. We change the directory to catkin workspace and source the workspace’s setup.*sh file using the following commands:

cd ~/catkin_ws
source ./devel/setup.bash
Source setup file

After that, we run the talker node using the following command:

rosrun edu_pub_sub talker

Subscriber

The code for the subscriber is given in listener.cpp file and is explained below:

  • Lines 7–10: This is the callback function triggered upon the arrival of a new message on the chatter topic.

  • Line 27: We subscribe to the chatter topic with the master. The chatterCallback() function will be invoked by ROS whenever a new message is received. The second argument represents the queue size, providing a buffer in case messages cannot be processed quickly. If the queue accumulates 1000 messages, older ones will be discarded to make room for new arrivals.

    • The NodeHandle::subscribe() function yields a ros::Subscriber object, which should be retained until we decide to unsubscribe. Upon the destruction of the Subscriber object, it will automatically unsubscribe from the chatter topic.

We run the subscriber node in a similar fashion: open a new terminal, change the directory, and source the setup file:

cd ~/catkin_ws
source ./devel/setup.bash
Source setup file

The last setup is to run the listener node using the following command:

rosrun edu_pub_sub listener

Playground

As mentioned earlier, we’ll practice in the following widget:

cmake_minimum_required(VERSION 2.8.3)
project(edu_pub_sub)

## Find catkin and any catkin packages
find_package(catkin REQUIRED COMPONENTS roscpp std_msgs genmsg)

## Generate added messages and services
generate_messages(DEPENDENCIES std_msgs)

## Declare a catkin package
catkin_package()

## Build talker and listener
include_directories(include ${catkin_INCLUDE_DIRS})

add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker edu_pub_sub_generate_messages_cpp)

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener edu_pub_sub_generate_messages_cpp)
Writing a simple publisher and subscriber in C++

Conclusion

Creating a new ROS package and building different nodes under that package facilitates the development of a robust robotic system in which each node executes distinct tasks, enhancing the overall system throughput and efficiency.

Free Resources

Copyright ©2024 Educative, Inc. All rights reserved