How to write a simple publisher and subscriber in ROS in Python

ROS, short for Robot Operating System, is an open-source middleware framework designed to assist developers in building robot applications. ROS operates on top of a conventional operating system, typically Linux, offering services such as hardware abstraction, inter-process communication, package management, and more. This tutorial focuses on creating a basic publisher and subscriber to showcase fundamental communication between different nodes within a ROS system. It delves into working with a catkin workspace, creating a ROS package, and executing various ROS nodes. To begin, the installation of ROS is necessary, and this can be accomplished by following the guidelines provided on the ROS Installation page. For our platform, we’ve opted for ROS Noetic.

ROS publisher-subscriber protocol
ROS publisher-subscriber protocol

Create a ROS Package

A ROS package is a fundamental organizational unit used to structure and manage the robotic software. A ROS package 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. Initially, navigate to the source space directory of the catkin workspace (generated during the ROS setup).

cd ~/catkin_ws/src

Now, 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. Having said that, we use the following command to create a package named edu_pub_sub, specifying its dependencies as std_msgs, and rospy.

catkin_create_pkg edu_pub_sub std_msgs rospy

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 are all set to build our catkin workspace. 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 over 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, make sure that roscore is up and running.

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.py in the widget below:

  • Line 1: At the outset of every Python ROS Node, we find this declaration which ensures that our script is executed as a Python script.

  • Lines 3–4: Importing rospy is essential when crafting a ROS Node. We import std_msgs.msg to enable the reuse of the std_msgs/String message type, which serves as a straightforward string container for publishing.

  • Line 7: The declaration signifies that our node publishes to the chatter topic utilizing the String message type, where String represents the std_msgs.msg.String class. The queue_size parameter restricts the number of queued messages if any subscriber is unable to receive them swiftly.

  • Line 8: We inform the rospy of our node’s name, a crucial step before it can establish communication with the ROS Master. In this instance, our node will be identified as talker. Setting anonymous=True ensures the uniqueness of our node’s name by appending random numbers to the end of the specified name.

  • Line 9: This line initializes a Rate object rate which, through its method, provides a convenient means of iterating at a specified rate.

  • Lines 10–14: The loop follows a standard rospy pattern by checking the rospy.is_shutdown() flag before proceeding with its tasks. This check ensures that the program exits appropriately, such as in response to a Ctrl+C or similar interrupt. In this scenario, the task is calling pub.publish(hello_str), which publishes a string to the chatter topic. The loop then invokes rate.sleep(), causing it to sleep for just enough time to maintain the desired loop rate. Additionally, the loop includes rospy.loginfo(str), serving a triple purpose: printing messages to the screen, writing them to the Node’s log file, and recording them in rosout.

To run the publisher, open a new terminal using the “+” button. 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

After that, run the talker node:

rosrun edu_pub_sub talker.py

Subscriber

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

  • Line 17: This statement signifies that your node subscribes to the chatter topic, which is of the type std_msgs.msg.String. Whenever new messages are received, the callback function is triggered, taking the message as its initial argument.

  • Line 20: It ensures that your node remains active and doesn’t exit until the node has undergone shutdown.

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

The last setup is to run the listener node:

rosrun edu_pub_sub listener.py

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 rospy 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})

catkin_install_python(PROGRAMS scripts/talker.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

catkin_install_python(PROGRAMS scripts/listener.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
Simple Publisher and Subscriber in Python

Conclusion

Creating a ROS package and building different nodes under that package facilitate the development of a robust robotic system, wherein each node executes distinct tasks, thereby enhancing the overall system throughput and efficiency.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved