ROS2 Python Publisher Example

In this tutorial I will show you a ROS2 Python publisher example. I will break down the code so you can learn how to create your own ROS2 publisher node in Python.

So, here we’ll suppose we have a temperature sensor, and we want to publish the measured temperature every 2 seconds (at 0.5 Hz). We will simulate the temperature measurement so we don’t have to use a real sensor.

>> I’ve also made a video tutorial – using a different example, but the principle is the same. Watch this as an additional resource to this article:

After watching the video, subscribe to the Robotics Back-End Youtube channel so you don’t miss the next tutorials!

ROS2 Python publisher code

Here’s the complete Python code we’ll use for this tutorial.


You want to learn ROS2 efficiently?

Check out ROS2 For Beginners and learn ROS2 step by step, in 1 week.


#!/usr/bin/env python3
import rclpy
from rclpy.node import Node

from example_interfaces.msg import Int64
import random

class TemperatureSensorNode(Node):
    def __init__(self):
        super().__init__("temperature_sensor")
        self.temperature_publisher_ = self.create_publisher(
            Int64, "temperature", 10)
        self.temperature_timer_ = self.create_timer(
            2.0, self.publish_temperature)

    def publish_temperature(self):
        temperature = random.randint(20, 30)
        msg = Int64()
        msg.data = temperature
        self.temperature_publisher_.publish(msg)

def main(args=None):
    rclpy.init(args=args)
    node = TemperatureSensorNode()
    rclpy.spin(node)
    rclpy.shutdown()

if __name__ == "__main__":
    main()

Code explanation

Let’s now break this code down, line by line.

Imports

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node

First we add the Python3 shebang line. Then we import the rclpy library, from which we’ll create the publisher. We also import the Node class from rclpy.

For almost any node you create you’ll have those 3 lines first.

from example_interfaces.msg import Int64
import random

Those are 2 new import lines specific to the functionalities of this program.

To publish a message, well, we need to import a ROS2 message interface. Here we simply use Int64 from the example_interfaces package, which should had been installed when you installed ROS2. Int64 contains one field named “data”, which is an int64 number. You can check that on a terminal by executing ros2 interface show example_interfaces/msg/Int64.

Python publisher – node class

class TemperatureSensorNode(Node):
    def __init__(self):
        super().__init__("temperature_sensor")

As we use OOP in ROS2, we first create a class which inherits from the Node class. The first thing we do is to call super() and pass the name of the node.

Initialize the ROS2 Python publisher

        self.temperature_publisher_ = self.create_publisher(
            Int64, "temperature", 10)

So, here is the ROS2 Python publisher!

Before we can actually use the publisher, we need to initialize it. We’ll do that in the constructor of the class, just after the node has been initialized.

To create a publisher with rclpy you simply have to call the create_publisher() function from rclpy. This function takes at least 3 arguments:

  1. Message (or interface) type. We use the Int64 type we’ve just imported before.
  2. Topic name.
  3. Queue size. This is kind of a buffer for messages in case some of them are late. Unless you send a lot of data at a high frequency, you probably don’t need to worry about that. I often use 10 as a default value.

Add a method to publish a message

    def publish_temperature(self):
        temperature = random.randint(20, 30)
        msg = Int64()
        msg.data = temperature
        self.temperature_publisher_.publish(msg)

OK, we have a publisher, which will be initialized when the node is initialized. Now, we need to be able to use the publisher to actually publish some messages on the topic.

To do that, we’ll first create a method that we can call from anywhere within the class.

In this method we first create a random number for the temperature, since this is a simulation. In a real temperature sensor node, you’d have another function which reads the data from the sensor. So, this first line wouldn’t be here. The 3 following lines represent the core of this method:

  • Instantiate an Int64 message object.
  • Fill the “data” field of the message with an integer – here the temperature data.
  • Use the publish() function from the publisher object to actually publish on the topic.

Add a timer to publish the message at a given rate

        self.temperature_timer_ = self.create_timer(
            2.0, self.publish_temperature)

Even if this line was before the publish_temperature() method, I’ve put it after in the explanation, because that’s usually the order in which you’ll write your code:

  1. Initialize the publisher.
  2. Create a function to publish on the topic.
  3. Call this function from within your code – here as a callback in a timer.

So, the create_timer() function from rclpy, as it name suggests, will create a timer. Don’t forget to store this timer in a class attribute so it stays in scope. You need to give 2 arguments:

  • Period to wait between 2 triggers: here 2 seconds (which corresponds to 0.5 Hz).
  • Callback function.

Program’s main

def main(args=None):
    rclpy.init(args=args)
    node = TemperatureSensorNode()
    rclpy.spin(node)
    rclpy.shutdown()
if __name__ == "__main__":
    main()

Nothing special here: we just init ROS2 communications, initialize the node, make the node spin, and finally shutdown ROS2 communications. For more details about this sequence, check out how to write a minimal Python node with rclpy.

Install and run your ROS2 Python publisher

First, if you don’t really know where to put your code: create a ROS2 Python package, and place the Python file inside the folder that has the same name as the package. You can also make this file executable.

$ cd ~/ros2_ws/src/
$ ros2 pkg create ros2_tutorials_py --build-type ament_python --dependencies rclpy
$ cd ros2_tutorials_py/ros2_tutorials_py/
$ touch temperature_sensor.py
$ chmod +x temperature_sensor.py

Now that you’ve written the file, let’s install the node so we can use it with the ros2 run command line tool.

Install your publisher

Add one line inside the “console_scripts” array of your package’s setup.py file.

...
    entry_points={
        'console_scripts': [
            ...
            "temperature_sensor = ros2_tutorials_py.temperature_sensor:main"
        ],
...

Now, go to your ROS2 workspace and install with colcon.

$ cd ~/ros2_ws/
$ colcon build --packages-select ros2_tutorials_py 
Starting >>> ros2_tutorials_py
Finished <<< ros2_tutorials_py [0.50s]          

Summary: 1 package finished [0.59s]

Run and test the publisher

In another terminal, source your ROS2 workspace, and start the node with ros2 run:

$ ros2 run ros2_tutorials_py temperature_sensor

Nothing will appear on this terminal.

Open yet another terminal, and now you can see what is published on the topic with ros2 topic:

$ ros2 topic echo /temperature 
data: 25
---
data: 20
---
data: 22
---

Great, the ROS2 Python publisher is working, and you can directly subscribe to it from the terminal.

Conclusion

In this tutorial you’ve learned how to create, write, and install a ROS2 Python publisher.

In most cases the code structure will be similar: first you initialize the publisher in your node’s constructor, then you create a method to publish a message (see how to create your custom ROS2 messages), and finally you call this method from within your code, when it’s relevant to do so.

As you saw here, even if we didn’t create a subscriber node, we can still see what’s published to the topic with ROS2 command line tools.

And now, the next logical step is to write a ROS2 Subscriber node to listen to the data published on the topic.

Want to learn how to program with ROS2?

Don't miss this opportunity:

ROS2 For Beginners - Step by Step Course


[NEW] ROS 2 Book


Or, learn with a video course