"Reading data from subscription without executing callback" is considered to be one of the common use cases of ROS 2. However, I wonder why there is less description about this use case in any documents about ROS 2.

Many users would like to read data directly from a subscription without executing a callback function. Executing the callback function, including waking-up and sleeping the thread, consumes CPU time. If the software is small, the consumption is negligible; otherwise, it is not negligible. To reduce unnecessary callback execution in a large software as much as possible, I want to execute callback functions at the time I intend rather than whenever a topic message arrives.

I found how to read data with no callback execution, and I would like to give a sample code to demonstrate it. The following source code is based on demo_nodes_cpp's listener node.

#include <chrono>
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_components/register_node_macro.hpp"

#include "std_msgs/msg/string.hpp"

using namespace std::chrono_literals;

#include "demo_nodes_cpp/visibility_control.h"

namespace demo_nodes_cpp
// Create a TimerListener class that subclasses the generic rclcpp::Node base class.
// The main function below will instantiate the class as a ROS node.
class TimerListener : public rclcpp::Node
  explicit TimerListener(const rclcpp::NodeOptions & options)
  : Node("Timerlistener", options)
    // Create a callback function for when messages are received.
    // Variations of this function also exist using, for example UniquePtr for zero-copy transport.
    setvbuf(stdout, NULL, _IONBF, BUFSIZ);
    auto not_executed_callback =
      [this](std_msgs::msg::String::ConstSharedPtr msg) -> void
        RCLCPP_INFO(this->get_logger(), "I never heard message");
    auto timer_callback =
        [this]() -> void
      RCLCPP_INFO(this->get_logger(), "Timer triggered.");
      std_msgs::msg::String msg;
      rclcpp::MessageInfo msg_info;
      if (sub_->take(msg, msg_info)) {
        RCLCPP_INFO(this->get_logger(), "Catch message");
        RCLCPP_INFO(this->get_logger(), "I heard: [%s]", msg.data.c_str());
      } else {
        RCLCPP_INFO(this->get_logger(), "Not catch message");
    // Create a subscription to the topic which can be matched with one or more compatible ROS
    // publishers.
    // Note that not all publishers on the same topic with the same type will be compatible:
    // they must have compatible Quality of Service policies.

    rclcpp::CallbackGroup::SharedPtr cb_group_noexec = this->create_callback_group(
        rclcpp::CallbackGroupType::MutuallyExclusive, false);
    auto subscription_options = rclcpp::SubscriptionOptions();
    subscription_options.callback_group = cb_group_noexec;

    sub_ = create_subscription<std_msgs::msg::String>("chatter", 10, not_executed_callback, subscription_options);
    timer_ = this->create_wall_timer(500ms, timer_callback);

  rclcpp::Subscription<std_msgs::msg::String>::SharedPtr sub_;
  rclcpp::TimerBase::SharedPtr timer_;


}  // namespace demo_nodes_cpp


In the sample program, the sub_->take() method is called in timer_callback to read data directly from a subscription. The not_executed_callback belongs to the callback group whose automatically_add_to_executor_with_node is false not to execute callback registered with create_subscription.

Based on my understanding, I would like to ask two questions.

  1. Why is "reading data from subscription without executing callback" hardly mentioned? Is it not recommended?
  2. Is there any other best practice of "Reading data from subscription without executing callback" instead of the one I gave?

Thank you for kind cooperation beforehand and best regards,

Please find the similar questions for your reference.



Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.