15 #ifndef RCLCPP__SUBSCRIPTION_HPP_
16 #define RCLCPP__SUBSCRIPTION_HPP_
18 #include <rmw/error_handling.h>
29 #include "rcl/error_handling.h"
32 #include "rclcpp/any_subscription_callback.hpp"
33 #include "rclcpp/detail/resolve_use_intra_process.hpp"
34 #include "rclcpp/detail/resolve_intra_process_buffer_type.hpp"
35 #include "rclcpp/exceptions.hpp"
36 #include "rclcpp/expand_topic_or_service_name.hpp"
37 #include "rclcpp/experimental/intra_process_manager.hpp"
38 #include "rclcpp/experimental/subscription_intra_process.hpp"
39 #include "rclcpp/logging.hpp"
40 #include "rclcpp/macros.hpp"
41 #include "rclcpp/message_info.hpp"
42 #include "rclcpp/message_memory_strategy.hpp"
43 #include "rclcpp/node_interfaces/node_base_interface.hpp"
44 #include "rclcpp/subscription_base.hpp"
45 #include "rclcpp/subscription_options.hpp"
46 #include "rclcpp/type_support_decl.hpp"
47 #include "rclcpp/visibility_control.hpp"
48 #include "rclcpp/waitable.hpp"
49 #include "rclcpp/topic_statistics/subscription_topic_statistics.hpp"
50 #include "tracetools/tracetools.h"
55 namespace node_interfaces
57 class NodeTopicsInterface;
63 typename AllocatorT = std::allocator<void>,
66 typename SubscribedT =
typename rclcpp::TypeAdapter<MessageT>::custom_type,
69 typename ROSMessageT =
typename rclcpp::TypeAdapter<MessageT>::ros_message_type,
80 using SubscribedType = SubscribedT;
81 using ROSMessageType = ROSMessageT;
82 using MessageMemoryStrategyType = MessageMemoryStrategyT;
84 using SubscribedTypeAllocatorTraits = allocator::AllocRebind<SubscribedType, AllocatorT>;
85 using SubscribedTypeAllocator =
typename SubscribedTypeAllocatorTraits::allocator_type;
86 using SubscribedTypeDeleter = allocator::Deleter<SubscribedTypeAllocator, SubscribedType>;
88 using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, AllocatorT>;
89 using ROSMessageTypeAllocator =
typename ROSMessageTypeAllocatorTraits::allocator_type;
90 using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
93 using SubscriptionTopicStatisticsSharedPtr =
94 std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics>;
119 rclcpp::node_interfaces::NodeBaseInterface * node_base,
120 const rosidl_message_type_support_t & type_support_handle,
121 const std::
string & topic_name,
125 typename MessageMemoryStrategyT::SharedPtr message_memory_strategy,
126 SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics =
nullptr)
131 options.to_rcl_subscription_options(qos),
133 options.event_callbacks,
134 options.use_default_callbacks,
136 any_callback_(callback),
138 message_memory_strategy_(message_memory_strategy)
142 if (rclcpp::detail::resolve_use_intra_process(options_, *node_base)) {
143 using rclcpp::detail::resolve_intra_process_buffer_type;
147 if (qos_profile.history() != rclcpp::HistoryPolicy::KeepLast) {
148 throw std::invalid_argument(
149 "intraprocess communication on topic '" + topic_name +
150 "' allowed only with keep last history qos policy");
152 if (qos_profile.depth() == 0) {
153 throw std::invalid_argument(
154 "intraprocess communication on topic '" + topic_name +
155 "' is not allowed with 0 depth qos policy");
161 SubscribedTypeAllocator,
162 SubscribedTypeDeleter,
168 typename SubscriptionIntraProcessT::StatsHandlerFn stats_handler =
nullptr;
169 if (subscription_topic_statistics) {
171 [subscription_topic_statistics](
172 const rmw_message_info_t & info,
const rclcpp::Time & time)
174 subscription_topic_statistics->handle_message(info, time);
179 auto context = node_base->get_context();
180 subscription_intra_process_ = std::make_shared<SubscriptionIntraProcessT>(
182 options_.get_allocator(),
184 this->get_topic_name(),
186 resolve_intra_process_buffer_type(options_.intra_process_buffer_type, callback),
187 std::move(stats_handler));
188 TRACETOOLS_TRACEPOINT(
189 rclcpp_subscription_init,
190 static_cast<const void *
>(get_subscription_handle().get()),
191 static_cast<const void *
>(subscription_intra_process_.get()));
195 auto ipm = context->get_sub_context<IntraProcessManager>();
196 uint64_t intra_process_subscription_id = ipm->template add_subscription<
197 ROSMessageType, ROSMessageTypeAllocator>(subscription_intra_process_);
201 if (subscription_topic_statistics !=
nullptr) {
202 this->subscription_topic_statistics_ = std::move(subscription_topic_statistics);
205 TRACETOOLS_TRACEPOINT(
206 rclcpp_subscription_init,
207 static_cast<const void *
>(get_subscription_handle().get()),
208 static_cast<const void *
>(
this));
209 TRACETOOLS_TRACEPOINT(
210 rclcpp_subscription_callback_added,
211 static_cast<const void *
>(
this),
212 static_cast<const void *
>(&any_callback_));
216 #ifndef TRACETOOLS_DISABLED
217 any_callback_.register_callback_for_tracing();
252 return this->
take_type_erased(
static_cast<void *
>(&message_out), message_info_out);
262 template<
typename TakeT>
264 !rosidl_generator_traits::is_message<TakeT>::value &&
265 std::is_same_v<TakeT, SubscribedType>,
270 ROSMessageType local_message;
271 bool taken = this->
take_type_erased(
static_cast<void *
>(&local_message), message_info_out);
278 std::shared_ptr<void>
285 return message_memory_strategy_->borrow_message();
288 std::shared_ptr<rclcpp::SerializedMessage>
291 return message_memory_strategy_->borrow_serialized_message();
307 any_callback_.disable();
308 if (subscription_intra_process_) {
309 subscription_intra_process_->disable_callbacks();
311 for (
const auto & [_, event_ptr] : event_handlers_) {
313 event_ptr->disable();
327 any_callback_.enable();
328 if (subscription_intra_process_) {
329 subscription_intra_process_->enable_callbacks();
331 for (
const auto & [_, event_ptr] : event_handlers_) {
340 std::shared_ptr<void> & message,
348 auto typed_message = std::static_pointer_cast<ROSMessageType>(message);
350 std::chrono::time_point<std::chrono::system_clock> now;
351 if (subscription_topic_statistics_) {
354 now = std::chrono::system_clock::now();
357 any_callback_.dispatch(typed_message, message_info);
359 if (subscription_topic_statistics_) {
360 const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
361 const auto time =
rclcpp::Time(nanos.time_since_epoch().count());
367 handle_serialized_message(
368 const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
371 std::chrono::time_point<std::chrono::system_clock> now;
372 if (subscription_topic_statistics_) {
375 now = std::chrono::system_clock::now();
378 any_callback_.dispatch(serialized_message, message_info);
380 if (subscription_topic_statistics_) {
381 const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
382 const auto time =
rclcpp::Time(nanos.time_since_epoch().count());
388 handle_loaned_message(
389 void * loaned_message,
398 auto typed_message =
static_cast<ROSMessageType *
>(loaned_message);
400 auto sptr = std::shared_ptr<ROSMessageType>(
401 typed_message, [](ROSMessageType * msg) {(void) msg;});
403 std::chrono::time_point<std::chrono::system_clock> now;
404 if (subscription_topic_statistics_) {
407 now = std::chrono::system_clock::now();
410 any_callback_.dispatch(sptr, message_info);
412 if (subscription_topic_statistics_) {
413 const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
414 const auto time =
rclcpp::Time(nanos.time_since_epoch().count());
426 auto typed_message = std::static_pointer_cast<ROSMessageType>(message);
427 message_memory_strategy_->return_message(typed_message);
437 message_memory_strategy_->return_serialized_message(message);
441 use_take_shared_method()
const
443 return any_callback_.use_take_shared_method();
449 rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
450 get_shared_dynamic_message_type()
override
453 "get_shared_dynamic_message_type is not implemented for Subscription");
456 rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
457 get_shared_dynamic_message()
override
460 "get_shared_dynamic_message is not implemented for Subscription");
463 rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
464 get_shared_dynamic_serialization_support()
override
467 "get_shared_dynamic_serialization_support is not implemented for Subscription");
470 rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
474 "create_dynamic_message is not implemented for Subscription");
478 return_dynamic_message(
479 [[maybe_unused]] rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message)
override
482 "return_dynamic_message is not implemented for Subscription");
486 handle_dynamic_message(
487 [[maybe_unused]]
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
491 "handle_dynamic_message is not implemented for Subscription");
497 AnySubscriptionCallback<MessageT, AllocatorT> any_callback_;
504 typename message_memory_strategy::MessageMemoryStrategy<ROSMessageType, AllocatorT>::SharedPtr
505 message_memory_strategy_;
508 SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics_{
nullptr};
Additional meta data about messages taken from subscriptions.
const rmw_message_info_t & get_rmw_message_info() const
Return the message info as the underlying rmw message info type.
Encapsulation of Quality of Service settings.
RCLCPP_PUBLIC rclcpp::QoS get_actual_qos() const
Get the actual QoS settings, after the defaults have been determined.
virtual RCLCPP_PUBLIC void enable_callbacks()
Enable the callbacks to be called.
RCLCPP_PUBLIC void setup_intra_process(uint64_t intra_process_subscription_id, IntraProcessManagerWeakPtr weak_ipm)
Implemenation detail.
virtual RCLCPP_PUBLIC void disable_callbacks()
Disable callbacks from being called.
RCLCPP_PUBLIC bool take_type_erased(void *message_out, rclcpp::MessageInfo &message_info_out)
Take the next inter-process message from the subscription as a type erased pointer.
Subscription implementation, templated on the type of message this subscription receives.
std::enable_if_t< !rosidl_generator_traits::is_message< TakeT >::value &&std::is_same_v< TakeT, SubscribedType >, bool > take(TakeT &message_out, rclcpp::MessageInfo &message_info_out)
Take the next message from the inter-process subscription.
Subscription(rclcpp::node_interfaces::NodeBaseInterface *node_base, const rosidl_message_type_support_t &type_support_handle, const std::string &topic_name, const rclcpp::QoS &qos, AnySubscriptionCallback< MessageT, AllocatorT > callback, const rclcpp::SubscriptionOptionsWithAllocator< AllocatorT > &options, typename MessageMemoryStrategyT::SharedPtr message_memory_strategy, SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics=nullptr)
Default constructor.
void enable_callbacks() override
Enable the callbacks to be called.
void disable_callbacks() override
Disable callbacks from being called.
void return_serialized_message(std::shared_ptr< rclcpp::SerializedMessage > &message) override
Return the borrowed serialized message.
std::shared_ptr< rclcpp::SerializedMessage > create_serialized_message() override
Borrow a new serialized message.
void return_message(std::shared_ptr< void > &message) override
Return the borrowed message.
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr create_dynamic_message() override
Borrow a new serialized message (this clones!)
void post_init_setup([[maybe_unused]] rclcpp::node_interfaces::NodeBaseInterface *node_base, [[maybe_unused]] const rclcpp::QoS &qos, [[maybe_unused]] const rclcpp::SubscriptionOptionsWithAllocator< AllocatorT > &options)
Called after construction to continue setup that requires shared_from_this().
void handle_message(std::shared_ptr< void > &message, const rclcpp::MessageInfo &message_info) override
Check if we need to handle the message, and execute the callback if we do.
std::shared_ptr< void > create_message() override
Borrow a new message.
bool take(ROSMessageType &message_out, rclcpp::MessageInfo &message_info_out)
Take the next message from the inter-process subscription.
This class performs intra process communication between nodes.
Default allocation strategy for messages received by subscriptions.
Pure virtual interface class for the NodeBase part of the Node API.
Pure virtual interface class for the NodeTopics part of the Node API.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
DeliveredMessageKind
The kind of message that the subscription delivers in its callback, used by the executor.
Structure containing optional configuration for Subscriptions.
Template structure used to adapt custom, user-defined types to ROS types.