15 #ifndef RCLCPP__PUBLISHER_HPP_
16 #define RCLCPP__PUBLISHER_HPP_
21 #include <type_traits>
24 #include "rcl/error_handling.h"
26 #include "rmw/error_handling.h"
28 #include "rosidl_runtime_cpp/traits.hpp"
30 #include "rclcpp/allocator/allocator_common.hpp"
31 #include "rclcpp/allocator/allocator_deleter.hpp"
32 #include "rclcpp/detail/resolve_use_intra_process.hpp"
33 #include "rclcpp/detail/resolve_intra_process_buffer_type.hpp"
34 #include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
35 #include "rclcpp/experimental/create_intra_process_buffer.hpp"
36 #include "rclcpp/experimental/intra_process_manager.hpp"
37 #include "rclcpp/get_message_type_support_handle.hpp"
38 #include "rclcpp/is_ros_compatible_type.hpp"
39 #include "rclcpp/loaned_message.hpp"
40 #include "rclcpp/macros.hpp"
41 #include "rclcpp/node_interfaces/node_base_interface.hpp"
42 #include "rclcpp/publisher_base.hpp"
43 #include "rclcpp/publisher_options.hpp"
44 #include "rclcpp/type_adapter.hpp"
45 #include "rclcpp/type_support_decl.hpp"
46 #include "rclcpp/visibility_control.hpp"
48 #include "tracetools/tracetools.h"
53 template<
typename MessageT,
typename AllocatorT>
77 template<
typename MessageT,
typename AllocatorT = std::allocator<
void>>
83 "given message type is not compatible with ROS and cannot be used with a Publisher");
86 using PublishedType =
typename rclcpp::TypeAdapter<MessageT>::custom_type;
87 using ROSMessageType =
typename rclcpp::TypeAdapter<MessageT>::ros_message_type;
89 using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, AllocatorT>;
90 using PublishedTypeAllocator =
typename PublishedTypeAllocatorTraits::allocator_type;
91 using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
93 using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, AllocatorT>;
94 using ROSMessageTypeAllocator =
typename ROSMessageTypeAllocatorTraits::allocator_type;
95 using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
99 ROSMessageTypeAllocator,
100 ROSMessageTypeDeleter
117 rclcpp::node_interfaces::NodeBaseInterface * node_base,
118 const std::
string & topic,
124 rclcpp::get_message_type_support_handle<MessageT>(),
125 options.template to_rcl_publisher_options<MessageT>(qos),
127 options.event_callbacks,
128 options.use_default_callbacks),
130 published_type_allocator_(*options.get_allocator()),
131 ros_message_type_allocator_(*options.get_allocator())
133 allocator::set_allocator_for_deleter(&published_type_deleter_, &published_type_allocator_);
134 allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
143 const std::string & topic,
148 if (rclcpp::detail::resolve_use_intra_process(
options_, *node_base)) {
154 if (qos_profile.history() != rclcpp::HistoryPolicy::KeepLast) {
155 throw std::invalid_argument(
156 "intraprocess communication on topic '" + topic +
157 "' allowed only with keep last history qos policy");
159 if (qos_profile.depth() == 0) {
160 throw std::invalid_argument(
161 "intraprocess communication on topic '" + topic +
162 "' is not allowed with a zero qos history depth value");
164 if (qos_profile.durability() == rclcpp::DurabilityPolicy::TransientLocal) {
165 buffer_ = rclcpp::experimental::create_intra_process_buffer<
166 ROSMessageType, ROSMessageTypeAllocator, ROSMessageTypeDeleter>(
167 rclcpp::detail::resolve_intra_process_buffer_type(
options_.intra_process_buffer_type),
169 std::make_shared<ROSMessageTypeAllocator>(ros_message_type_allocator_));
172 uint64_t intra_process_publisher_id = ipm->add_publisher(this->shared_from_this(), buffer_);
174 intra_process_publisher_id,
202 this->get_ros_message_type_allocator());
217 typename std::enable_if_t<
218 rosidl_generator_traits::is_message<T>::value &&
219 std::is_same<T, ROSMessageType>::value
221 publish(std::unique_ptr<T, ROSMessageTypeDeleter> msg)
223 if (!intra_process_is_enabled_) {
224 this->do_inter_process_publish(*msg);
237 bool inter_process_publish_needed =
240 if (inter_process_publish_needed) {
242 this->do_intra_process_ros_message_publish_and_return_shared(std::move(msg));
244 buffer_->add_shared(shared_msg);
246 this->do_inter_process_publish(*shared_msg);
250 this->do_intra_process_ros_message_publish_and_return_shared(std::move(msg));
251 buffer_->add_shared(shared_msg);
253 this->do_intra_process_ros_message_publish(std::move(msg));
271 typename std::enable_if_t<
272 rosidl_generator_traits::is_message<T>::value &&
273 std::is_same<T, ROSMessageType>::value
278 if (!intra_process_is_enabled_) {
279 this->do_inter_process_publish(msg);
286 this->
publish(std::move(unique_msg));
301 typename std::enable_if_t<
303 std::is_same<T, PublishedType>::value
305 publish(std::unique_ptr<T, PublishedTypeDeleter> msg)
307 if (!intra_process_is_enabled_) {
309 auto ros_msg_ptr = std::make_unique<ROSMessageType>();
311 this->do_inter_process_publish(*ros_msg_ptr);
318 bool inter_process_publish_needed =
321 if (inter_process_publish_needed) {
322 auto ros_msg_ptr = std::make_shared<ROSMessageType>();
324 this->do_intra_process_publish(std::move(msg));
325 this->do_inter_process_publish(*ros_msg_ptr);
327 buffer_->add_shared(ros_msg_ptr);
331 auto ros_msg_ptr = std::make_shared<ROSMessageType>();
333 buffer_->add_shared(ros_msg_ptr);
335 this->do_intra_process_publish(std::move(msg));
351 typename std::enable_if_t<
353 std::is_same<T, PublishedType>::value
357 if (!intra_process_is_enabled_) {
359 auto ros_msg_ptr = std::make_unique<ROSMessageType>();
361 this->do_inter_process_publish(*ros_msg_ptr);
369 this->
publish(std::move(unique_msg));
375 return this->do_serialized_publish(&serialized_msg);
379 publish(
const SerializedMessage & serialized_msg)
381 return this->do_serialized_publish(&serialized_msg.get_rcl_serialized_message());
395 if (!loaned_msg.is_valid()) {
396 throw std::runtime_error(
"loaned message is not valid");
407 this->do_loaned_message_publish(loaned_msg.release());
411 this->
publish(loaned_msg.get());
415 PublishedTypeAllocator
416 get_published_type_allocator()
const
418 return published_type_allocator_;
421 ROSMessageTypeAllocator
422 get_ros_message_type_allocator()
const
424 return ros_message_type_allocator_;
429 do_inter_process_publish(
const ROSMessageType & msg)
431 TRACETOOLS_TRACEPOINT(rclcpp_publish,
nullptr,
static_cast<const void *
>(&msg));
432 auto status =
rcl_publish(publisher_handle_.get(), &msg,
nullptr);
445 rclcpp::exceptions::throw_from_rcl_error(status,
"failed to publish message");
452 if (intra_process_is_enabled_) {
454 throw std::runtime_error(
"storing serialized messages in intra process is not supported yet");
458 rclcpp::exceptions::throw_from_rcl_error(status,
"failed to publish serialized message");
463 do_loaned_message_publish(
464 std::unique_ptr<ROSMessageType, std::function<
void(ROSMessageType *)>> msg)
466 TRACETOOLS_TRACEPOINT(rclcpp_publish,
nullptr,
static_cast<const void *
>(msg.get()));
480 rclcpp::exceptions::throw_from_rcl_error(status,
"failed to publish message");
485 do_intra_process_publish(std::unique_ptr<PublishedType, PublishedTypeDeleter> msg)
487 auto ipm = weak_ipm_.lock();
489 throw std::runtime_error(
490 "intra process publish called after destruction of intra process manager");
493 throw std::runtime_error(
"cannot publish msg which is a null pointer");
495 TRACETOOLS_TRACEPOINT(
496 rclcpp_intra_publish,
497 static_cast<const void *
>(publisher_handle_.get()),
500 ipm->template do_intra_process_publish<PublishedType, ROSMessageType, AllocatorT>(
501 intra_process_publisher_id_,
503 published_type_allocator_);
507 do_intra_process_ros_message_publish(std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> msg)
509 auto ipm = weak_ipm_.lock();
511 throw std::runtime_error(
512 "intra process publish called after destruction of intra process manager");
515 throw std::runtime_error(
"cannot publish msg which is a null pointer");
517 TRACETOOLS_TRACEPOINT(
518 rclcpp_intra_publish,
519 static_cast<const void *
>(publisher_handle_.get()),
522 ipm->template do_intra_process_publish<ROSMessageType, ROSMessageType, AllocatorT>(
523 intra_process_publisher_id_,
525 ros_message_type_allocator_);
528 std::shared_ptr<const ROSMessageType>
529 do_intra_process_ros_message_publish_and_return_shared(
530 std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> msg)
532 auto ipm = weak_ipm_.lock();
534 throw std::runtime_error(
535 "intra process publish called after destruction of intra process manager");
538 throw std::runtime_error(
"cannot publish msg which is a null pointer");
540 TRACETOOLS_TRACEPOINT(
541 rclcpp_intra_publish,
542 static_cast<const void *
>(publisher_handle_.get()),
545 return ipm->template do_intra_process_publish_and_return_shared<ROSMessageType, ROSMessageType,
547 intra_process_publisher_id_,
549 ros_message_type_allocator_);
554 std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
557 auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_type_allocator_, 1);
558 ROSMessageTypeAllocatorTraits::construct(ros_message_type_allocator_, ptr);
559 return std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, ros_message_type_deleter_);
563 std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
566 auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_type_allocator_, 1);
567 ROSMessageTypeAllocatorTraits::construct(ros_message_type_allocator_, ptr, msg);
568 return std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, ros_message_type_deleter_);
572 std::unique_ptr<PublishedType, PublishedTypeDeleter>
577 static_assert(!detail::has_overloaded_operator_new_v<PublishedType>,
578 "When publishing by value (i.e. when calling publish(const T& msg)), the published "
579 "message type must not have an overloaded operator new. In this case, please use the "
580 "publish(std::unique_ptr<T> msg) method instead.");
582 auto ptr = PublishedTypeAllocatorTraits::allocate(published_type_allocator_, 1);
583 PublishedTypeAllocatorTraits::construct(published_type_allocator_, ptr, msg);
584 return std::unique_ptr<PublishedType, PublishedTypeDeleter>(ptr, published_type_deleter_);
594 PublishedTypeAllocator published_type_allocator_;
595 PublishedTypeDeleter published_type_deleter_;
596 ROSMessageTypeAllocator ros_message_type_allocator_;
597 ROSMessageTypeDeleter ros_message_type_deleter_;
599 BufferSharedPtr buffer_{
nullptr};
RCLCPP_PUBLIC size_t get_intra_process_subscription_count() const
Get intraprocess subscription count.
RCLCPP_PUBLIC rclcpp::QoS get_actual_qos() const
Get the actual QoS settings, after the defaults have been determined.
RCLCPP_PUBLIC void setup_intra_process(uint64_t intra_process_publisher_id, const IntraProcessManagerSharedPtr &ipm)
Implementation utility function used to setup intra process publishing after creation.
RCLCPP_PUBLIC bool can_loan_messages() const
Check if publisher instance can loan messages.
RCLCPP_PUBLIC size_t get_subscription_count() const
Get subscription count.
A publisher publishes messages of any type to a topic.
typename rclcpp::TypeAdapter< MessageT >::custom_type PublishedType
MessageT::custom_type if MessageT is a TypeAdapter, otherwise just MessageT.
std::enable_if_t< rclcpp::TypeAdapter< MessageT >::is_specialized::value &&std::is_same< T, PublishedType >::value > publish(std::unique_ptr< T, PublishedTypeDeleter > msg)
Publish a message on the topic.
const rclcpp::PublisherOptionsWithAllocator< AllocatorT > options_
Copy of original options passed during construction.
rclcpp::LoanedMessage< ROSMessageType, AllocatorT > borrow_loaned_message()
Borrow a loaned ROS message from the middleware.
std::unique_ptr< ROSMessageType, ROSMessageTypeDeleter > duplicate_ros_message_as_unique_ptr(const ROSMessageType &msg)
Duplicate a given ros message as a unique_ptr.
virtual void post_init_setup(rclcpp::node_interfaces::NodeBaseInterface *node_base, const std::string &topic, [[maybe_unused]] const rclcpp::QoS &qos, [[maybe_unused]] const rclcpp::PublisherOptionsWithAllocator< AllocatorT > &options)
Called post construction, so that construction may continue after shared_from_this() works.
std::enable_if_t< rosidl_generator_traits::is_message< T >::value &&std::is_same< T, ROSMessageType >::value > publish(std::unique_ptr< T, ROSMessageTypeDeleter > msg)
Publish a message on the topic.
std::enable_if_t< rclcpp::TypeAdapter< MessageT >::is_specialized::value &&std::is_same< T, PublishedType >::value > publish(const T &msg)
Publish a message on the topic.
std::unique_ptr< PublishedType, PublishedTypeDeleter > duplicate_type_adapt_message_as_unique_ptr(const PublishedType &msg)
Duplicate a given type adapted message as a unique_ptr.
std::unique_ptr< ROSMessageType, ROSMessageTypeDeleter > create_ros_message_unique_ptr()
Return a new unique_ptr using the ROSMessageType of the publisher.
std::enable_if_t< rosidl_generator_traits::is_message< T >::value &&std::is_same< T, ROSMessageType >::value > publish(const T &msg)
Publish a message on the topic.
void publish(rclcpp::LoanedMessage< ROSMessageType, AllocatorT > &&loaned_msg)
Publish an instance of a LoanedMessage.
Encapsulation of Quality of Service settings.
This class performs intra process communication between nodes.
Pure virtual interface class for the NodeBase part of the Node API.
virtual RCLCPP_PUBLIC rclcpp::Context::SharedPtr get_context()=0
Return the context of the node.
RCL_PUBLIC RCL_WARN_UNUSED bool rcl_context_is_valid(const rcl_context_t *context)
Return true if the given context is currently valid, otherwise false.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_publish_loaned_message(const rcl_publisher_t *publisher, void *ros_message, rmw_publisher_allocation_t *allocation)
Publish a loaned message on a topic using a publisher.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_publish_serialized_message(const rcl_publisher_t *publisher, const rcl_serialized_message_t *serialized_message, rmw_publisher_allocation_t *allocation)
Publish a serialized message on a topic using a publisher.
RCL_PUBLIC RCL_WARN_UNUSED rcl_context_t * rcl_publisher_get_context(const rcl_publisher_t *publisher)
Return the context associated with this publisher.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_publish(const rcl_publisher_t *publisher, const void *ros_message, rmw_publisher_allocation_t *allocation)
Publish a ROS message on a topic using a publisher.
RCL_PUBLIC bool rcl_publisher_is_valid_except_context(const rcl_publisher_t *publisher)
Return true if the publisher is valid except the context, otherwise false.
Encapsulates the non-global state of an init/shutdown cycle.
Structure containing optional configuration for Publishers.
Template structure used to adapt custom, user-defined types to ROS types.
#define RCL_RET_OK
Success return code.
rmw_serialized_message_t rcl_serialized_message_t
typedef for rmw_serialized_message_t;
#define RCL_RET_PUBLISHER_INVALID
Invalid rcl_publisher_t given return code.