ROS Topics

Creating and managing ROS topics

Content Outline

    Before to start


    Create an ament_cmake built-type package called demo_interfaces

    test.cpp
    ros2 pkg create --build-type ament_cmake demo_interfaces

    Topics


    Topics are:

    • Anonymous
    • Strongly-typed
    • Allow:
      • intra-process
      • inter-process

    Simple Topic-based interface.

    For details about topics names: check Names in ROS 2 .

    Publishers/Subscribers

    Topics use a asynchronous communication paradigms refer as publication/subscription:

    • publishers don’t know if anyone’s listening
    • subscribers are event-triggered (by incoming messages)
    • messages may be dropped (depending on the QoS, but more on that later.)

    Anonymous

    Topics are anonymous: “This means that when a subscriber gets a piece of data, it doesn’t generally know or care which publisher originally sent it (though it can find out if it wants). ” from Official ROS docs .

    Strongly-typed

    The communication using topics relies in the concept of Strongly-typed definitions called messages.

    Messages


    Messages are a way for a ROS 2 node to send data on the network to other ROS nodes, with no response expected. Messages are described and defined in .msg files in the msg/ directory of a ROS package.

    Message Definition Structure

    Simple message definition.

    Structure:

    • Field type.
    • Field name
    • Field with constant value. Fields with constant values have to be UPPERCASE.
    • Field with default value

    Creating a Simple Message


    With in the demo_interfaces package, let’s create a folder called msg.

    Create a 'msg' folder
    mkdir msg

    Inside msg directory create a file called Counter.msg with the following content:

    int64 count
    

    Add the rosidl_default_generators and “friends” to the package.xml of the demo_interfaces package.

    <buildtool_depend>rosidl_default_generators</buildtool_depend>
    <exec_depend>rosidl_default_runtime</exec_depend>
    <member_of_group>rosidl_interface_packages</member_of_group>

    Add the following code to the CMakeLists.txt:

    find_package(rosidl_default_generators REQUIRED)
    
    rosidl_generate_interfaces(${PROJECT_NAME}
      "msg/Counter.msg"
    )

    Build the message definition:

    Build the workspace
    cd ~/ros2_ws/ && colcon build --symlink-install

    Creating a Mininal Publisher


    Let’s create a minimal publisher that publishes our custom message definition called Counter.msg.

    import rclpy
    from rclpy.node import Node
    from demo_interfaces.msg import Counter
    
    class MinimalPublisher(Node):
    
        def __init__(self):
            super().__init__("publisher_node")
    
            self.__count = 0
    
            self.__pub = self.create_publisher(Counter, "/count", 10)
    
            timer = self.create_timer(0.5, self.callback)
    
        def callback(self):
            msg = Counter()
            msg.count = self.__count
            self.__pub.publish(msg)
            self.get_logger().info(f"Publishing count: {self.__count}")
            self.__count += 1
    
    def main(args=None) -> None:
    
        rclpy.init(args=args)
    
        minimal_publisher = MinimalPublisher()
    
        rclpy.spin(minimal_publisher)
    
        minimal_publisher.destroy_node()
    
        rclpy.shutdown()
    
    if __name__ == "__main__":
        main()
    

    Creating a Mininal Subscriber


    Let’s create a minimal subscriber that subscribes our custom message definition called Counter.msg.

    import rclpy
    from rclpy.node import Node
    from demo_interfaces.msg import Counter
    
    class MinimalSubscriber(Node):
    
        def __init__(self):
            super().__init__("subscriber_node")
    
            self.__sub = self.create_subscription(Counter, "/count", self.callback, 10)
    
        def callback(self, msg) -> None:
            self.get_logger().info(f"Got count: {msg.count}")
    
    
    def main(args=None) -> None:
    
        rclpy.init(args=args)
    
        minimal_subscriber = MinimalSubscriber()
    
        rclpy.spin(minimal_subscriber)
    
        minimal_subscriber.destroy_node()
    
        rclpy.shutdown()
    
    if __name__ == "__main__":
        main()
    

    Quality of Service (QoS)


    “ROS 2 offers a rich variety of Quality of Service (QoS) policies that allow you to tune communication between nodes” from Quality of Service settings .

    “A set of QoS policies combine to form a QoS profile. Given the complexity of choosing the correct QoS policies for a given scenario, ROS 2 provides a set of predefined QoS profiles for common use cases (e.g. sensor data). At the same time, developers are given the flexibility to control specific policies of the QoS profiles.”

    Check Quality of Service settings for more details.