Publisher and Subscriber - dhanushshettigar/Getting-Started-With-ROS2 GitHub Wiki

Publisher and Subscriber (Python)

Table of Contents

  1. Background
  2. Create a Package
  3. Publisher Node
  4. Subscriber Node
  5. Customize Package File
  6. Customize Setup File
  7. Build the Package
  8. Test the Package
  9. Conclusion

Background

Create nodes that pass information in the form of string messages to each other over a topic. The example used here is a simple “talker” and “listener” system; one node publishes data and the other subscribes to the topic so it can receive that data.

Writing a simple publisher and subscriber in python

1. Create a Package

Navigate into the ros2_ws directory.

Recall that packages should be created in the src directory, not the root of the workspace. So, navigate into ros2_ws/src .

cd ros2_ws/src

Run the package creation command:

ros2 pkg create --build-type ament_python --license Apache-2.0 py_pubsub

This command will create a package named py_pubsub

2. Write the publisher node

Navigate into ros2_ws/src/py_pubsub/py_pubsub. Recall that this directory is a Python package with the same name as the ROS 2 package it’s nested in.

cd py_pubsub/py_pubsub

Now Create a new file named publisher_member_function.py.

sudo nano publisher_member_function.py

Copy this below python code and save the file.

import rclpy
from rclpy.node import Node

from std_msgs.msg import String


class MinimalPublisher(Node):

    def __init__(self):
        super().__init__('minimal_publisher')
        self.publisher_ = self.create_publisher(String, 'topic', 10)
        timer_period = 0.5  # seconds
        self.timer = self.create_timer(timer_period, self.timer_callback)
        self.i = 0

    def timer_callback(self):
        msg = String()
        msg.data = 'Hello World: %d' % self.i
        self.publisher_.publish(msg)
        self.get_logger().info('Publishing: "%s"' % msg.data)
        self.i += 1


def main(args=None):
    rclpy.init(args=args)

    minimal_publisher = MinimalPublisher()

    rclpy.spin(minimal_publisher)

    # Destroy the node explicitly
    # (optional - otherwise it will be done automatically
    # when the garbage collector destroys the node object)
    minimal_publisher.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

3. Write the subscriber node

Now Create a new file named subscriber_member_function.py.

sudo nano subscriber_member_function.py

Copy this below python code and save the file.

import rclpy
from rclpy.node import Node

from std_msgs.msg import String


class MinimalSubscriber(Node):

    def __init__(self):
        super().__init__('minimal_subscriber')
        self.subscription = self.create_subscription(
            String,
            'topic',
            self.listener_callback,
            10)
        self.subscription  # prevent unused variable warning

    def listener_callback(self, msg):
        self.get_logger().info('I heard: "%s"' % msg.data)


def main(args=None):
    rclpy.init(args=args)

    minimal_subscriber = MinimalSubscriber()

    rclpy.spin(minimal_subscriber)

    # Destroy the node explicitly
    # (optional - otherwise it will be done automatically
    # when the garbage collector destroys the node object)
    minimal_subscriber.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

Now the directory should have these files:

__init__.py publisher_member_function.py subscriber_member_function.py

4. Customize package.xml

You may have noticed in the return message after creating your package that the fields description and license contain TODO notes. That’s because the package description and license declaration are not automatically set, but are required if you ever want to release your package. The maintainer field may also need to be filled in.

From ros2_ws/src/py_pubsub

cd ..

Open package.xml

sudo nano package.xml

Input your name and email on the maintainer line if it hasn’t been automatically populated for you.

<maintainer email="your_email">your_name</maintainer>

Then, edit the description line to summarize the package:

<description>summarize your package</description>

After the lines above, add the following dependencies corresponding to your node’s import statements:

<exec_depend>rclpy</exec_depend>
<exec_depend>std_msgs</exec_depend>

This declares the package needs rclpy and std_msgs when its code is executed.

Examine the file.

<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
    <name>py_pubsub</name>
    <version>0.0.1</version>
    <description>A Simple Publisher and Subscriber</description>
    <maintainer email="[email protected]">dhanush</maintainer>
    <license>Apache-2.0</license>

    <test_depend>ament_copyright</test_depend>
    <test_depend>ament_flake8</test_depend>
    <test_depend>ament_pep257</test_depend>
    <test_depend>python3-pytest</test_depend>

    <exec_depend>rclpy</exec_depend>
    <exec_depend>std_msgs</exec_depend>

    <export>
        <build_type>ament_python</build_type>
    </export>
</package>

Don’t forget to save once you’re done editing.

5. Customize setup.py

Open the setup.py file.

sudo nano setup.py

Again, match the maintainer, maintainer_email, description and license fields to your package.xml:

maintainer='dhanush',
maintainer_email='[email protected]',
description='A Simple Publisher and Subscriber',
license='Apache-2.0',

Add the following line within the console_scripts brackets of the entry_points field:

entry_points={
        'console_scripts': [
                'talker = py_pubsub.publisher_member_function:main',
                'listener = py_pubsub.subscriber_member_function:main',
        ],
},

Examine the file.

from setuptools import find_packages, setup

package_name = 'py_pubsub'

setup(
    name=package_name,
    version='0.0.0',
    packages=find_packages(exclude=['test']),
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='dhanush',
    maintainer_email='[email protected]',
    description='A Simple Publisher and Subscriber',
    license='Apache-2.0',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
                'talker = py_pubsub.publisher_member_function:main',
                'listener = py_pubsub.subscriber_member_function:main',
        ],
    },
)

Don’t forget to save once you’re done editing.

6. Build the package

You likely already have the rclpy and std_msgs packages installed as part of your ROS 2 system. It’s good practice to run rosdep in the root of your workspace (ros2_ws) to check for missing dependencies before building:

rosdep install -i --from-path src --rosdistro jazzy -y

Go to the workspace's root.

cd ../..

Build your new package:

colcon build --packages-select py_pubsub

The output should appear as Summary: 1 package finished

7. Testing the package

Open a new terminal, navigate to ros2_ws, and source the setup files:

source install/setup.bash

Now run the talker node:

ros2 run py_pubsub talker

The terminal should start publishing info messages every 0.5 seconds, like so:

[INFO] [minimal_publisher]: Publishing: "Hello World: 0"
[INFO] [minimal_publisher]: Publishing: "Hello World: 1"
[INFO] [minimal_publisher]: Publishing: "Hello World: 2"
[INFO] [minimal_publisher]: Publishing: "Hello World: 3"
[INFO] [minimal_publisher]: Publishing: "Hello World: 4"
...

Open another terminal, source the setup files from inside ros2_ws again.

source install/setup.bash

Start the listener node:

ros2 run py_pubsub listener

The listener will start printing messages to the console, starting at whatever message count the publisher is on at that time, like so:

[INFO] [minimal_subscriber]: I heard: "Hello World: 10"
[INFO] [minimal_subscriber]: I heard: "Hello World: 11"
[INFO] [minimal_subscriber]: I heard: "Hello World: 12"
[INFO] [minimal_subscriber]: I heard: "Hello World: 13"
[INFO] [minimal_subscriber]: I heard: "Hello World: 14"

Enter Ctrl+C in each terminal to stop the nodes from spinning.

Conclusion

You created two nodes to publish and subscribe to data over a topic. Before running them, you added their dependencies and entry points to the package configuration files.

⚠️ **GitHub.com Fallback** ⚠️