ZERO Notificatons

NO Feedback yet!!

okay

xparo
X.P.A.R.O



project - ROS 2 Package Generator



Publishing and subscribing to topics is the heart of ROS 2. This tutorial builds a talker that publishes messages and a listener that prints them, in Python with rclpy, from an empty workspace to two nodes talking to each other. Every command and file below was run on ROS 2 Jazzy while writing it.

1. Create a workspace and a package

source /opt/ros/jazzy/setup.bash
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
ros2 pkg create --build-type ament_python --license Apache-2.0 \
  --dependencies rclpy std_msgs -- robot_demo

The -- before the package name stops --dependencies from swallowing it as a third dependency, a surprisingly common slip. You can also generate the package in the browser with the ROS 2 Package Generator and unzip it into src/.

2. Write the publisher

Save this as robot_demo/robot_demo/talker.py:

import rclpy
from rclpy.node import Node
from std_msgs.msg import String


class Talker(Node):
    def __init__(self):
        super().__init__('talker')
        self.declare_parameter('rate_hz', 2.0)
        self.publisher = self.create_publisher(String, 'chatter', 10)
        period = 1.0 / self.get_parameter('rate_hz').value
        self.timer = self.create_timer(period, self.publish_message)
        self.count = 0

    def publish_message(self):
        msg = String()
        msg.data = f'hello {self.count}'
        self.publisher.publish(msg)
        self.get_logger().info(f'Publishing: {msg.data}')
        self.count += 1


def main(args=None):
    rclpy.init(args=args)
    node = Talker()
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass
    finally:
        node.destroy_node()
        rclpy.try_shutdown()


if __name__ == '__main__':
    main()

What each part does:

  • Node subclass: every ROS 2 program is one or more nodes. The string passed to super().__init__ is the node's name.
  • declare_parameter: makes the publishing rate configurable at launch time instead of hard-coded. Parameters must be declared before they are read.
  • create_publisher(String, 'chatter', 10): the message type, the topic name, and the queue depth. The plain number is shorthand for the default "reliable, keep last 10" quality of service.
  • create_timer: calls publish_message periodically from the executor, so the node never blocks.
  • rclpy.spin: runs callbacks until you press Ctrl+C. try_shutdown avoids an error if the context was already shut down by the signal handler.

3. Write the subscriber

Save this as robot_demo/robot_demo/listener.py:

import rclpy
from rclpy.node import Node
from std_msgs.msg import String


class Listener(Node):
    def __init__(self):
        super().__init__('listener')
        self.subscription = self.create_subscription(String, 'chatter', self.on_message, 10)

    def on_message(self, msg):
        self.get_logger().info(f'I heard: {msg.data}')


def main(args=None):
    rclpy.init(args=args)
    node = Listener()
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass
    finally:
        node.destroy_node()
        rclpy.try_shutdown()

Keep a reference to the subscription (here self.subscription). The callback runs each time a message arrives, in the executor's thread, so keep it short: do heavy work elsewhere.

4. Register the nodes and build

Add one entry point per node in setup.py:

entry_points={
    'console_scripts': [
        'talker = robot_demo.talker:main',
        'listener = robot_demo.listener:main',
    ],
},

Then build from the workspace root, not from inside src, and source the result:

cd ~/ros2_ws
colcon build --symlink-install --packages-select robot_demo
source install/setup.bash

--symlink-install links your Python files into the install space, so later edits to talker.py take effect without rebuilding. New entry points still need a rebuild.

5. Run it

In one terminal:

ros2 run robot_demo talker

In a second terminal (source both setup files again first):

ros2 run robot_demo listener

On our test machine the two terminals printed:

[INFO] [talker]: Publishing: hello 0
[INFO] [talker]: Publishing: hello 1

[INFO] [listener]: I heard: hello 0
[INFO] [listener]: I heard: hello 1

To publish faster, override the parameter: ros2 run robot_demo talker --ros-args -p rate_hz:=5.0.

6. Look inside with the command line

ros2 node list                 # /talker and /listener
ros2 topic list                # includes /chatter
ros2 topic echo /chatter       # print messages as they arrive
ros2 topic hz /chatter         # measured publishing rate
ros2 topic info /chatter -v    # publishers, subscribers and their QoS
ros2 param get /talker rate_hz

These commands are the first thing to reach for when two nodes do not seem to talk.

Quality of service in one paragraph

Each publisher and subscriber has a QoS profile. Reliability (reliable or best effort), durability (volatile or transient local) and history depth are the settings that matter most. A subscriber asking for reliable delivery will not receive anything from a best effort publisher, which is a classic cause of "the topic exists but my callback never fires" with sensor drivers. ros2 topic info -v shows each side's profile so you can spot the mismatch.

Common mistakes

  • "Package 'robot_demo' not found": the terminal has not sourced install/setup.bash.
  • "No executable found": the entry point is missing or misspelled, or the package was not rebuilt after adding it.
  • Nothing received: different topic names (check for a missing or extra leading slash or namespace), a QoS mismatch, or two machines on different ROS_DOMAIN_IDs.
  • The rate is wrong: timers depend on the executor; a callback that blocks (for example with time.sleep) delays every other callback in the node.

Next, start both nodes with one command, with parameters and namespaces, in our guide to ROS 2 launch files. If the build fails, see common colcon errors.

More guides

Oct. 4, 2026, 10:20 a.m.
Common colcon build Errors in ROS 2 and How to Fix Them
Read more..
Oct. 4, 2026, 10:21 a.m.
ROS 2 Launch Files in Python: Parameters, Remapping and Namespaces
Read more..
Oct. 4, 2026, 10:23 a.m.
Anatomy of a ROS 2 Package: package.xml, setup.py, CMakeLists.txt Explained
Read more..
Oct. 4, 2026, 10:24 a.m.
ament_python vs ament_cmake: Which ROS 2 Build Type Should You Use?
Read more..

If you have any query or problem
feel free to contact us
email: [email protected]