[Proposal] Adding single message getting API to rclcpp
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 805
- Forks
- 564
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 27
Description
Problem statement:
We're missing a way to get a single message from a topic. This question has come up a number of times in conversations with my colleagues, ROS Answers question askers, and myself even noticing the absense of this API. ROS 1 had this as waitForMessage().
An example use-case is how I used it in ROS 1 in SLAM Toolbox: when a service requests deserialization of a previous SLAM session, I want to get a single message from the current laser scanner to match it to the serialized one to ensure compatibility (else throw exception). Another example mentioned to me by a colleague was getting a single message from the camera info topic from a fixed-focus camera since it never changes to store and have the input to a machine learning system.
There are plenty of examples of a need for a way to get a message from a topic in a polling / blocking manner. I don't think that it is wise for architectural reasons to lean on this kind of method for regular polling of topics and should be advised in documentation that it is used as only when the odd situation requires it. As such, we don't need to be excessively concerned with performance but it shouldn't be outrageously bad (impl proposal below is naive but fine from that perspective).
For better performance or for use of regular polling, it is certainly possible to create subscriptionPolls, or a wrapper on subscriptions that handle message gathering and contain a method getLastMessage() to grab the last message if the programming style for regular polling is desirable in an efficient way. I think that is out of scope of this particular feature request but also could be useful for long-running subscriber/regular polling needs (though easy and common for users to bake into their nodes).
Proposed solution:
I propose adding a top-level rclcpp API called getSingleMessage or getLatestMessage (or similar) which will create a subscription within the function and block until a message is recieved or a timeout expires. An example can be seen below:
template <typename MsgT, NodeT = rclcpp::Node>
MsgT::SharedPtr rclcpp::getSingleMessage<MsgT, NodeT>(
NodeT node,
const std::string & topic,
const rclcpp::Duration & timeout_dur = rclcpp::Duration(0),
const rmw_qos_profile_t qos_profile = rmw_qos_profile_default,
const rclcpp::callback_group::CallbackGroup::SharedPtr callback_group = nullptr)
{
rclcpp::Time start = node->now();
MsgT::SharedPtr my_msg;
auto sub = node->create_subscription<MsgT>(topic, [&](const MsgT::SharedPtr msg){my_msg = msg;}, QoS, callback_group);
while (node->now() - start < timeout_dur) {
rclcpp::spin_some(node);
if (my_msg) {
sub.reset();
return my_msg;
}
}
sub.reset();
throw std::runtime_error("Some error msg");
}
Elements I think are most important:
- Ability to have a timeout for maximum time to block
- Setting QoS / callback group to use for subscription (optionally)
- Templated based on node type so it can support both
rclcpp::Nodeandrclcpp_lifecycle::LifecycleNode(and others in the future) - Handled in the client library so users can easily access rather than baking the above logic in-line in application code that can be easily generalized
Documentation and other considerations:
- Should be for isolated or single use, not polling for a topic. This method is inefficient for regular use and not meant for that.
- Should we add in executor internally so doesn't disrupt program flow? I don't care either way, but seems like it might be excessive but happy to do it if we feel that's the right direction to replace callback groups.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No repository file or test is named. Start by examining the rclcpp top-level API concepts described here, especially create_subscription, spin_some, callback groups, and support for Node and LifecycleNode; completion should define a single-message operation with timeout and optional QoS or callback-group handling, plus guidance that it is not for regular polling.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- api
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100