ROS 2 rclcpp + rcl - rolling  rolling-a919a6e5
ROS 2 C++ Client Library with ROS Client Library
publisher.hpp
1 // Copyright 2014 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef RCLCPP__PUBLISHER_HPP_
16 #define RCLCPP__PUBLISHER_HPP_
17 
18 #include <functional>
19 #include <iostream>
20 #include <memory>
21 #include <sstream>
22 #include <string>
23 #include <type_traits>
24 #include <utility>
25 
26 #include "rcl/error_handling.h"
27 #include "rcl/publisher.h"
28 #include "rmw/error_handling.h"
29 #include "rmw/rmw.h"
30 #include "rosidl_runtime_cpp/traits.hpp"
31 
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"
49 
50 #include "tracetools/tracetools.h"
51 
52 namespace rclcpp
53 {
54 
55 template<typename MessageT, typename AllocatorT>
56 class LoanedMessage;
57 
59 
79 template<typename MessageT, typename AllocatorT = std::allocator<void>>
80 class Publisher : public PublisherBase
81 {
82 public:
83  static_assert(
85  "given message type is not compatible with ROS and cannot be used with a Publisher");
86 
88  using PublishedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
89  using ROSMessageType = typename rclcpp::TypeAdapter<MessageT>::ros_message_type;
90 
91  using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, AllocatorT>;
92  using PublishedTypeAllocator = typename PublishedTypeAllocatorTraits::allocator_type;
93  using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
94 
95  using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, AllocatorT>;
96  using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
97  using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
98 
99  using BufferSharedPtr = typename rclcpp::experimental::buffers::IntraProcessBuffer<
100  ROSMessageType,
101  ROSMessageTypeAllocator,
102  ROSMessageTypeDeleter
103  >::SharedPtr;
104 
105  RCLCPP_SMART_PTR_DEFINITIONS(Publisher<MessageT, AllocatorT>)
106 
107 
119  rclcpp::node_interfaces::NodeBaseInterface * node_base,
120  const std::string & topic,
121  const rclcpp::QoS & qos,
122  const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
123  : PublisherBase(
124  node_base,
125  topic,
126  rclcpp::get_message_type_support_handle<MessageT>(),
127  options.template to_rcl_publisher_options<MessageT>(qos),
128  // NOTE(methylDragon): Passing these args separately is necessary for event binding
129  options.event_callbacks,
130  options.use_default_callbacks),
131  options_(options),
132  published_type_allocator_(*options.get_allocator()),
133  ros_message_type_allocator_(*options.get_allocator())
134  {
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_);
137  // Setup continues in the post construction method, post_init_setup().
138  }
139 
141  virtual
142  void
145  const std::string & topic,
146  [[maybe_unused]] const rclcpp::QoS & qos,
147  [[maybe_unused]] const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
148  {
149  // If needed, setup intra process communication.
150  if (rclcpp::detail::resolve_use_intra_process(options_, *node_base)) {
151  auto context = node_base->get_context();
152  // Get the intra process manager instance for this context.
153  auto ipm = context->get_sub_context<rclcpp::experimental::IntraProcessManager>();
154  // Check if the QoS is compatible with intra-process.
155  auto qos_profile = get_actual_qos();
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");
160  }
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");
165  }
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),
170  qos_profile,
171  std::make_shared<ROSMessageTypeAllocator>(ros_message_type_allocator_));
172  }
173  // Register the publisher with the intra process manager.
174  uint64_t intra_process_publisher_id = ipm->add_publisher(this->shared_from_this(), buffer_);
175  this->setup_intra_process(
176  intra_process_publisher_id,
177  ipm);
178  }
179  }
180 
181  virtual ~Publisher()
182  {}
183 
185 
201  {
203  *this,
204  this->get_ros_message_type_allocator());
205  }
206 
208 
218  template<typename T>
219  typename std::enable_if_t<
220  rosidl_generator_traits::is_message<T>::value &&
221  std::is_same<T, ROSMessageType>::value
222  >
223  publish(std::unique_ptr<T, ROSMessageTypeDeleter> msg)
224  {
225  if (!intra_process_is_enabled_) {
226  this->do_inter_process_publish(*msg);
227  return;
228  }
229  // If an interprocess subscription exist, then the unique_ptr is promoted
230  // to a shared_ptr and published.
231  // This allows doing the intraprocess publish first and then doing the
232  // interprocess publish, resulting in lower publish-to-subscribe latency.
233  // It's not possible to do that with an unique_ptr,
234  // as do_intra_process_publish takes the ownership of the message.
235 
236  // When durability is set to TransientLocal (i.e. there is a buffer),
237  // inter process publish should always take place to ensure
238  // late joiners receive past data.
239  bool inter_process_publish_needed =
241 
242  if (inter_process_publish_needed) {
243  auto shared_msg =
244  this->do_intra_process_ros_message_publish_and_return_shared(std::move(msg));
245  if (buffer_) {
246  buffer_->add_shared(shared_msg);
247  }
248  this->do_inter_process_publish(*shared_msg);
249  } else {
250  if (buffer_) {
251  auto shared_msg =
252  this->do_intra_process_ros_message_publish_and_return_shared(std::move(msg));
253  buffer_->add_shared(shared_msg);
254  } else {
255  this->do_intra_process_ros_message_publish(std::move(msg));
256  }
257  }
258  }
259 
261 
272  template<typename T>
273  typename std::enable_if_t<
274  rosidl_generator_traits::is_message<T>::value &&
275  std::is_same<T, ROSMessageType>::value
276  >
277  publish(const T & msg)
278  {
279  // Avoid allocating when not using intra process.
280  if (!intra_process_is_enabled_) {
281  this->do_inter_process_publish(msg);
282  return;
283  }
284  // Otherwise we have to allocate memory in a unique_ptr and pass it along.
285  // As the message is not const, a copy should be made.
286  // A shared_ptr<const MessageT> could also be constructed here.
287  auto unique_msg = this->duplicate_ros_message_as_unique_ptr(msg);
288  this->publish(std::move(unique_msg));
289  }
290 
292 
302  template<typename T>
303  typename std::enable_if_t<
305  std::is_same<T, PublishedType>::value
306  >
307  publish(std::unique_ptr<T, PublishedTypeDeleter> msg)
308  {
309  if (!intra_process_is_enabled_) {
310  // In this case we're not using intra process.
311  auto ros_msg_ptr = std::make_unique<ROSMessageType>();
313  this->do_inter_process_publish(*ros_msg_ptr);
314  return;
315  }
316 
317  // When durability is set to TransientLocal (i.e. there is a buffer),
318  // inter process publish should always take place to ensure
319  // late joiners receive past data.
320  bool inter_process_publish_needed =
322 
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);
328  if (buffer_) {
329  buffer_->add_shared(ros_msg_ptr);
330  }
331  } else {
332  if (buffer_) {
333  auto ros_msg_ptr = std::make_shared<ROSMessageType>();
335  buffer_->add_shared(ros_msg_ptr);
336  }
337  this->do_intra_process_publish(std::move(msg));
338  }
339  }
340 
342 
352  template<typename T>
353  typename std::enable_if_t<
355  std::is_same<T, PublishedType>::value
356  >
357  publish(const T & msg)
358  {
359  if (!intra_process_is_enabled_) {
360  // Convert to the ROS message equivalent and publish it.
361  auto ros_msg_ptr = std::make_unique<ROSMessageType>();
363  this->do_inter_process_publish(*ros_msg_ptr);
364  return;
365  }
366 
367  // Otherwise we have to allocate memory in a unique_ptr and pass it along.
368  // As the message is not const, a copy should be made.
369  // A shared_ptr<const MessageT> could also be constructed here.
370  auto unique_msg = this->duplicate_type_adapt_message_as_unique_ptr(msg);
371  this->publish(std::move(unique_msg));
372  }
373 
374  void
375  publish(const rcl_serialized_message_t & serialized_msg)
376  {
377  return this->do_serialized_publish(&serialized_msg);
378  }
379 
380  void
381  publish(const SerializedMessage & serialized_msg)
382  {
383  return this->do_serialized_publish(&serialized_msg.get_rcl_serialized_message());
384  }
385 
387 
394  void
396  {
397  if (!loaned_msg.is_valid()) {
398  throw std::runtime_error("loaned message is not valid");
399  }
400 
401  // verify that publisher supports loaned messages
402  // TODO(Karsten1987): This case separation has to be done in rclcpp
403  // otherwise we have to ensure that every middleware implements
404  // `rmw_publish_loaned_message` explicitly the same way as `rmw_publish`
405  // by taking a copy of the ros message.
406  if (this->can_loan_messages()) {
407  // we release the ownership from the rclpp::LoanedMessage instance
408  // and let the middleware clean up the memory.
409  this->do_loaned_message_publish(loaned_msg.release());
410  } else {
411  // we don't release the ownership, let the middleware copy the ros message
412  // and thus the destructor of rclcpp::LoanedMessage cleans up the memory.
413  this->publish(loaned_msg.get());
414  }
415  }
416 
417  PublishedTypeAllocator
418  get_published_type_allocator() const
419  {
420  return published_type_allocator_;
421  }
422 
423  ROSMessageTypeAllocator
424  get_ros_message_type_allocator() const
425  {
426  return ros_message_type_allocator_;
427  }
428 
429 protected:
430  void
431  do_inter_process_publish(const ROSMessageType & msg)
432  {
433  TRACETOOLS_TRACEPOINT(rclcpp_publish, nullptr, static_cast<const void *>(&msg));
434  auto status = rcl_publish(publisher_handle_.get(), &msg, nullptr);
435 
436  if (RCL_RET_PUBLISHER_INVALID == status) {
437  rcl_reset_error(); // next call will reset error message if not context
438  if (rcl_publisher_is_valid_except_context(publisher_handle_.get())) {
439  rcl_context_t * context = rcl_publisher_get_context(publisher_handle_.get());
440  if (nullptr != context && !rcl_context_is_valid(context)) {
441  // publisher is invalid due to context being shutdown
442  return;
443  }
444  }
445  }
446  if (RCL_RET_OK != status) {
447  rclcpp::exceptions::throw_from_rcl_error(status, "failed to publish message");
448  }
449  }
450 
451  void
452  do_serialized_publish(const rcl_serialized_message_t * serialized_msg)
453  {
454  if (intra_process_is_enabled_) {
455  // TODO(Karsten1987): support serialized message passed by intraprocess
456  throw std::runtime_error("storing serialized messages in intra process is not supported yet");
457  }
458  auto status = rcl_publish_serialized_message(publisher_handle_.get(), serialized_msg, nullptr);
459  if (RCL_RET_OK != status) {
460  rclcpp::exceptions::throw_from_rcl_error(status, "failed to publish serialized message");
461  }
462  }
463 
464  void
465  do_loaned_message_publish(
466  std::unique_ptr<ROSMessageType, std::function<void(ROSMessageType *)>> msg)
467  {
468  TRACETOOLS_TRACEPOINT(rclcpp_publish, nullptr, static_cast<const void *>(msg.get()));
469  auto status = rcl_publish_loaned_message(publisher_handle_.get(), msg.get(), nullptr);
470 
471  if (RCL_RET_PUBLISHER_INVALID == status) {
472  rcl_reset_error(); // next call will reset error message if not context
473  if (rcl_publisher_is_valid_except_context(publisher_handle_.get())) {
474  rcl_context_t * context = rcl_publisher_get_context(publisher_handle_.get());
475  if (nullptr != context && !rcl_context_is_valid(context)) {
476  // publisher is invalid due to context being shutdown
477  return;
478  }
479  }
480  }
481  if (RCL_RET_OK != status) {
482  rclcpp::exceptions::throw_from_rcl_error(status, "failed to publish message");
483  }
484  }
485 
486  void
487  do_intra_process_publish(std::unique_ptr<PublishedType, PublishedTypeDeleter> msg)
488  {
489  auto ipm = weak_ipm_.lock();
490  if (!ipm) {
491  throw std::runtime_error(
492  "intra process publish called after destruction of intra process manager");
493  }
494  if (!msg) {
495  throw std::runtime_error("cannot publish msg which is a null pointer");
496  }
497  TRACETOOLS_TRACEPOINT(
498  rclcpp_intra_publish,
499  static_cast<const void *>(publisher_handle_.get()),
500  msg.get());
501 
502  ipm->template do_intra_process_publish<PublishedType, ROSMessageType, AllocatorT>(
503  intra_process_publisher_id_,
504  std::move(msg),
505  published_type_allocator_);
506  }
507 
508  void
509  do_intra_process_ros_message_publish(std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> msg)
510  {
511  auto ipm = weak_ipm_.lock();
512  if (!ipm) {
513  throw std::runtime_error(
514  "intra process publish called after destruction of intra process manager");
515  }
516  if (!msg) {
517  throw std::runtime_error("cannot publish msg which is a null pointer");
518  }
519  TRACETOOLS_TRACEPOINT(
520  rclcpp_intra_publish,
521  static_cast<const void *>(publisher_handle_.get()),
522  msg.get());
523 
524  ipm->template do_intra_process_publish<ROSMessageType, ROSMessageType, AllocatorT>(
525  intra_process_publisher_id_,
526  std::move(msg),
527  ros_message_type_allocator_);
528  }
529 
530  std::shared_ptr<const ROSMessageType>
531  do_intra_process_ros_message_publish_and_return_shared(
532  std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> msg)
533  {
534  auto ipm = weak_ipm_.lock();
535  if (!ipm) {
536  throw std::runtime_error(
537  "intra process publish called after destruction of intra process manager");
538  }
539  if (!msg) {
540  throw std::runtime_error("cannot publish msg which is a null pointer");
541  }
542  TRACETOOLS_TRACEPOINT(
543  rclcpp_intra_publish,
544  static_cast<const void *>(publisher_handle_.get()),
545  msg.get());
546 
547  return ipm->template do_intra_process_publish_and_return_shared<ROSMessageType, ROSMessageType,
548  AllocatorT>(
549  intra_process_publisher_id_,
550  std::move(msg),
551  ros_message_type_allocator_);
552  }
553 
554 
556  std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
558  {
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_);
562  }
563 
565  std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
566  duplicate_ros_message_as_unique_ptr(const ROSMessageType & msg)
567  {
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_);
571  }
572 
574  std::unique_ptr<PublishedType, PublishedTypeDeleter>
576  {
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_);
580  }
581 
583 
588 
589  PublishedTypeAllocator published_type_allocator_;
590  PublishedTypeDeleter published_type_deleter_;
591  ROSMessageTypeAllocator ros_message_type_allocator_;
592  ROSMessageTypeDeleter ros_message_type_deleter_;
593 
594  BufferSharedPtr buffer_{nullptr};
595 };
596 
597 } // namespace rclcpp
598 
599 #endif // RCLCPP__PUBLISHER_HPP_
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.
Definition: publisher.hpp:81
typename rclcpp::TypeAdapter< MessageT >::custom_type PublishedType
MessageT::custom_type if MessageT is a TypeAdapter, otherwise just MessageT.
Definition: publisher.hpp:88
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.
Definition: publisher.hpp:307
const rclcpp::PublisherOptionsWithAllocator< AllocatorT > options_
Copy of original options passed during construction.
Definition: publisher.hpp:587
rclcpp::LoanedMessage< ROSMessageType, AllocatorT > borrow_loaned_message()
Borrow a loaned ROS message from the middleware.
Definition: publisher.hpp:200
std::unique_ptr< ROSMessageType, ROSMessageTypeDeleter > duplicate_ros_message_as_unique_ptr(const ROSMessageType &msg)
Duplicate a given ros message as a unique_ptr.
Definition: publisher.hpp:566
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.
Definition: publisher.hpp:143
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.
Definition: publisher.hpp:223
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.
Definition: publisher.hpp:357
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.
Definition: publisher.hpp:575
std::unique_ptr< ROSMessageType, ROSMessageTypeDeleter > create_ros_message_unique_ptr()
Return a new unique_ptr using the ROSMessageType of the publisher.
Definition: publisher.hpp:557
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.
Definition: publisher.hpp:277
void publish(rclcpp::LoanedMessage< ROSMessageType, AllocatorT > &&loaned_msg)
Publish an instance of a LoanedMessage.
Definition: publisher.hpp:395
Encapsulation of Quality of Service settings.
Definition: qos.hpp:116
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.
Definition: context.c:94
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.
Definition: publisher.c:315
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.
Definition: publisher.c:292
RCL_PUBLIC RCL_WARN_UNUSED rcl_context_t * rcl_publisher_get_context(const rcl_publisher_t *publisher)
Return the context associated with this publisher.
Definition: publisher.c:409
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.
Definition: publisher.c:271
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.
Definition: publisher.c:437
Encapsulates the non-global state of an init/shutdown cycle.
Definition: context.h:114
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.
Definition: types.h:27
rmw_serialized_message_t rcl_serialized_message_t
typedef for rmw_serialized_message_t;
Definition: types.h:152
#define RCL_RET_PUBLISHER_INVALID
Invalid rcl_publisher_t given return code.
Definition: types.h:69