15 #ifndef RCLCPP__PUBLISHER_HPP_
16 #define RCLCPP__PUBLISHER_HPP_
23 #include <type_traits>
26 #include "rcl/error_handling.h"
28 #include "rmw/error_handling.h"
30 #include "rosidl_runtime_cpp/traits.hpp"
32 #include "rclcpp/allocator/allocator_common.hpp"
33 #include "rclcpp/allocator/allocator_deleter.hpp"
34 #include "rclcpp/detail/resolve_use_intra_process.hpp"
35 #include "rclcpp/detail/resolve_intra_process_buffer_type.hpp"
36 #include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
37 #include "rclcpp/experimental/create_intra_process_buffer.hpp"
38 #include "rclcpp/experimental/intra_process_manager.hpp"
39 #include "rclcpp/get_message_type_support_handle.hpp"
40 #include "rclcpp/is_ros_compatible_type.hpp"
41 #include "rclcpp/loaned_message.hpp"
42 #include "rclcpp/macros.hpp"
43 #include "rclcpp/node_interfaces/node_base_interface.hpp"
44 #include "rclcpp/publisher_base.hpp"
45 #include "rclcpp/publisher_options.hpp"
46 #include "rclcpp/type_adapter.hpp"
47 #include "rclcpp/type_support_decl.hpp"
48 #include "rclcpp/visibility_control.hpp"
50 #include "tracetools/tracetools.h"
55 template<
typename MessageT,
typename AllocatorT>
79 template<
typename MessageT,
typename AllocatorT = std::allocator<
void>>
85 "given message type is not compatible with ROS and cannot be used with a Publisher");
88 using PublishedType =
typename rclcpp::TypeAdapter<MessageT>::custom_type;
89 using ROSMessageType =
typename rclcpp::TypeAdapter<MessageT>::ros_message_type;
91 using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, AllocatorT>;
92 using PublishedTypeAllocator =
typename PublishedTypeAllocatorTraits::allocator_type;
93 using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
95 using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, AllocatorT>;
96 using ROSMessageTypeAllocator =
typename ROSMessageTypeAllocatorTraits::allocator_type;
97 using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
101 ROSMessageTypeAllocator,
102 ROSMessageTypeDeleter
119 rclcpp::node_interfaces::NodeBaseInterface * node_base,
120 const std::
string & topic,
126 rclcpp::get_message_type_support_handle<MessageT>(),
127 options.template to_rcl_publisher_options<MessageT>(qos),
129 options.event_callbacks,
130 options.use_default_callbacks),
132 published_type_allocator_(*options.get_allocator()),
133 ros_message_type_allocator_(*options.get_allocator())
135 allocator::set_allocator_for_deleter(&published_type_deleter_, &published_type_allocator_);
136 allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
145 const std::string & topic,
150 if (rclcpp::detail::resolve_use_intra_process(
options_, *node_base)) {
156 if (qos_profile.history() != rclcpp::HistoryPolicy::KeepLast) {
157 throw std::invalid_argument(
158 "intraprocess communication on topic '" + topic +
159 "' allowed only with keep last history qos policy");
161 if (qos_profile.depth() == 0) {
162 throw std::invalid_argument(
163 "intraprocess communication on topic '" + topic +
164 "' is not allowed with a zero qos history depth value");
166 if (qos_profile.durability() == rclcpp::DurabilityPolicy::TransientLocal) {
167 buffer_ = rclcpp::experimental::create_intra_process_buffer<
168 ROSMessageType, ROSMessageTypeAllocator, ROSMessageTypeDeleter>(
169 rclcpp::detail::resolve_intra_process_buffer_type(
options_.intra_process_buffer_type),
171 std::make_shared<ROSMessageTypeAllocator>(ros_message_type_allocator_));
174 uint64_t intra_process_publisher_id = ipm->add_publisher(this->shared_from_this(), buffer_);
176 intra_process_publisher_id,
204 this->get_ros_message_type_allocator());
219 typename std::enable_if_t<
220 rosidl_generator_traits::is_message<T>::value &&
221 std::is_same<T, ROSMessageType>::value
223 publish(std::unique_ptr<T, ROSMessageTypeDeleter> msg)
225 if (!intra_process_is_enabled_) {
226 this->do_inter_process_publish(*msg);
239 bool inter_process_publish_needed =
242 if (inter_process_publish_needed) {
244 this->do_intra_process_ros_message_publish_and_return_shared(std::move(msg));
246 buffer_->add_shared(shared_msg);
248 this->do_inter_process_publish(*shared_msg);
252 this->do_intra_process_ros_message_publish_and_return_shared(std::move(msg));
253 buffer_->add_shared(shared_msg);
255 this->do_intra_process_ros_message_publish(std::move(msg));
273 typename std::enable_if_t<
274 rosidl_generator_traits::is_message<T>::value &&
275 std::is_same<T, ROSMessageType>::value
280 if (!intra_process_is_enabled_) {
281 this->do_inter_process_publish(msg);
288 this->
publish(std::move(unique_msg));
303 typename std::enable_if_t<
305 std::is_same<T, PublishedType>::value
307 publish(std::unique_ptr<T, PublishedTypeDeleter> msg)
309 if (!intra_process_is_enabled_) {
311 auto ros_msg_ptr = std::make_unique<ROSMessageType>();
313 this->do_inter_process_publish(*ros_msg_ptr);
320 bool inter_process_publish_needed =
323 if (inter_process_publish_needed) {
324 auto ros_msg_ptr = std::make_shared<ROSMessageType>();
326 this->do_intra_process_publish(std::move(msg));
327 this->do_inter_process_publish(*ros_msg_ptr);
329 buffer_->add_shared(ros_msg_ptr);
333 auto ros_msg_ptr = std::make_shared<ROSMessageType>();
335 buffer_->add_shared(ros_msg_ptr);
337 this->do_intra_process_publish(std::move(msg));
353 typename std::enable_if_t<
355 std::is_same<T, PublishedType>::value
359 if (!intra_process_is_enabled_) {
361 auto ros_msg_ptr = std::make_unique<ROSMessageType>();
363 this->do_inter_process_publish(*ros_msg_ptr);
371 this->
publish(std::move(unique_msg));
377 return this->do_serialized_publish(&serialized_msg);
381 publish(
const SerializedMessage & serialized_msg)
383 return this->do_serialized_publish(&serialized_msg.get_rcl_serialized_message());
397 if (!loaned_msg.is_valid()) {
398 throw std::runtime_error(
"loaned message is not valid");
409 this->do_loaned_message_publish(loaned_msg.release());
413 this->
publish(loaned_msg.get());
417 PublishedTypeAllocator
418 get_published_type_allocator()
const
420 return published_type_allocator_;
423 ROSMessageTypeAllocator
424 get_ros_message_type_allocator()
const
426 return ros_message_type_allocator_;
431 do_inter_process_publish(
const ROSMessageType & msg)
433 TRACETOOLS_TRACEPOINT(rclcpp_publish,
nullptr,
static_cast<const void *
>(&msg));
434 auto status =
rcl_publish(publisher_handle_.get(), &msg,
nullptr);
447 rclcpp::exceptions::throw_from_rcl_error(status,
"failed to publish message");
454 if (intra_process_is_enabled_) {
456 throw std::runtime_error(
"storing serialized messages in intra process is not supported yet");
460 rclcpp::exceptions::throw_from_rcl_error(status,
"failed to publish serialized message");
465 do_loaned_message_publish(
466 std::unique_ptr<ROSMessageType, std::function<
void(ROSMessageType *)>> msg)
468 TRACETOOLS_TRACEPOINT(rclcpp_publish,
nullptr,
static_cast<const void *
>(msg.get()));
482 rclcpp::exceptions::throw_from_rcl_error(status,
"failed to publish message");
487 do_intra_process_publish(std::unique_ptr<PublishedType, PublishedTypeDeleter> msg)
489 auto ipm = weak_ipm_.lock();
491 throw std::runtime_error(
492 "intra process publish called after destruction of intra process manager");
495 throw std::runtime_error(
"cannot publish msg which is a null pointer");
497 TRACETOOLS_TRACEPOINT(
498 rclcpp_intra_publish,
499 static_cast<const void *
>(publisher_handle_.get()),
502 ipm->template do_intra_process_publish<PublishedType, ROSMessageType, AllocatorT>(
503 intra_process_publisher_id_,
505 published_type_allocator_);
509 do_intra_process_ros_message_publish(std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> msg)
511 auto ipm = weak_ipm_.lock();
513 throw std::runtime_error(
514 "intra process publish called after destruction of intra process manager");
517 throw std::runtime_error(
"cannot publish msg which is a null pointer");
519 TRACETOOLS_TRACEPOINT(
520 rclcpp_intra_publish,
521 static_cast<const void *
>(publisher_handle_.get()),
524 ipm->template do_intra_process_publish<ROSMessageType, ROSMessageType, AllocatorT>(
525 intra_process_publisher_id_,
527 ros_message_type_allocator_);
530 std::shared_ptr<const ROSMessageType>
531 do_intra_process_ros_message_publish_and_return_shared(
532 std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> msg)
534 auto ipm = weak_ipm_.lock();
536 throw std::runtime_error(
537 "intra process publish called after destruction of intra process manager");
540 throw std::runtime_error(
"cannot publish msg which is a null pointer");
542 TRACETOOLS_TRACEPOINT(
543 rclcpp_intra_publish,
544 static_cast<const void *
>(publisher_handle_.get()),
547 return ipm->template do_intra_process_publish_and_return_shared<ROSMessageType, ROSMessageType,
549 intra_process_publisher_id_,
551 ros_message_type_allocator_);
556 std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
559 auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_type_allocator_, 1);
560 ROSMessageTypeAllocatorTraits::construct(ros_message_type_allocator_, ptr);
561 return std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, ros_message_type_deleter_);
565 std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
568 auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_type_allocator_, 1);
569 ROSMessageTypeAllocatorTraits::construct(ros_message_type_allocator_, ptr, msg);
570 return std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, ros_message_type_deleter_);
574 std::unique_ptr<PublishedType, PublishedTypeDeleter>
577 auto ptr = PublishedTypeAllocatorTraits::allocate(published_type_allocator_, 1);
578 PublishedTypeAllocatorTraits::construct(published_type_allocator_, ptr, msg);
579 return std::unique_ptr<PublishedType, PublishedTypeDeleter>(ptr, published_type_deleter_);
589 PublishedTypeAllocator published_type_allocator_;
590 PublishedTypeDeleter published_type_deleter_;
591 ROSMessageTypeAllocator ros_message_type_allocator_;
592 ROSMessageTypeDeleter ros_message_type_deleter_;
594 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, 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.