ROS 2 rclcpp + rcl - rolling  rolling-29de98cf
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 <memory>
20 #include <string>
21 #include <type_traits>
22 #include <utility>
23 
24 #include "rcl/error_handling.h"
25 #include "rcl/publisher.h"
26 #include "rmw/error_handling.h"
27 #include "rmw/rmw.h"
28 #include "rosidl_runtime_cpp/traits.hpp"
29 
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"
47 
48 #include "tracetools/tracetools.h"
49 
50 namespace rclcpp
51 {
52 
53 template<typename MessageT, typename AllocatorT>
54 class LoanedMessage;
55 
57 
77 template<typename MessageT, typename AllocatorT = std::allocator<void>>
78 class Publisher : public PublisherBase
79 {
80 public:
81  static_assert(
83  "given message type is not compatible with ROS and cannot be used with a Publisher");
84 
86  using PublishedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
87  using ROSMessageType = typename rclcpp::TypeAdapter<MessageT>::ros_message_type;
88 
89  using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, AllocatorT>;
90  using PublishedTypeAllocator = typename PublishedTypeAllocatorTraits::allocator_type;
91  using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
92 
93  using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, AllocatorT>;
94  using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
95  using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
96 
97  using BufferSharedPtr = typename rclcpp::experimental::buffers::IntraProcessBuffer<
98  ROSMessageType,
99  ROSMessageTypeAllocator,
100  ROSMessageTypeDeleter
101  >::SharedPtr;
102 
103  RCLCPP_SMART_PTR_DEFINITIONS(Publisher<MessageT, AllocatorT>)
104 
105 
117  rclcpp::node_interfaces::NodeBaseInterface * node_base,
118  const std::string & topic,
119  const rclcpp::QoS & qos,
120  const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
121  : PublisherBase(
122  node_base,
123  topic,
124  rclcpp::get_message_type_support_handle<MessageT>(),
125  options.template to_rcl_publisher_options<MessageT>(qos),
126  // NOTE(methylDragon): Passing these args separately is necessary for event binding
127  options.event_callbacks,
128  options.use_default_callbacks),
129  options_(options),
130  published_type_allocator_(*options.get_allocator()),
131  ros_message_type_allocator_(*options.get_allocator())
132  {
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_);
135  // Setup continues in the post construction method, post_init_setup().
136  }
137 
139  virtual
140  void
143  const std::string & topic,
144  [[maybe_unused]] const rclcpp::QoS & qos,
145  [[maybe_unused]] const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
146  {
147  // If needed, setup intra process communication.
148  if (rclcpp::detail::resolve_use_intra_process(options_, *node_base)) {
149  auto context = node_base->get_context();
150  // Get the intra process manager instance for this context.
151  auto ipm = context->get_sub_context<rclcpp::experimental::IntraProcessManager>();
152  // Check if the QoS is compatible with intra-process.
153  auto qos_profile = get_actual_qos();
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");
158  }
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");
163  }
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),
168  qos_profile,
169  std::make_shared<ROSMessageTypeAllocator>(ros_message_type_allocator_));
170  }
171  // Register the publisher with the intra process manager.
172  uint64_t intra_process_publisher_id = ipm->add_publisher(this->shared_from_this(), buffer_);
173  this->setup_intra_process(
174  intra_process_publisher_id,
175  ipm);
176  }
177  }
178 
179  virtual ~Publisher()
180  {}
181 
183 
199  {
201  *this,
202  this->get_ros_message_type_allocator());
203  }
204 
206 
216  template<typename T>
217  typename std::enable_if_t<
218  rosidl_generator_traits::is_message<T>::value &&
219  std::is_same<T, ROSMessageType>::value
220  >
221  publish(std::unique_ptr<T, ROSMessageTypeDeleter> msg)
222  {
223  if (!intra_process_is_enabled_) {
224  this->do_inter_process_publish(*msg);
225  return;
226  }
227  // If an interprocess subscription exist, then the unique_ptr is promoted
228  // to a shared_ptr and published.
229  // This allows doing the intraprocess publish first and then doing the
230  // interprocess publish, resulting in lower publish-to-subscribe latency.
231  // It's not possible to do that with an unique_ptr,
232  // as do_intra_process_publish takes the ownership of the message.
233 
234  // When durability is set to TransientLocal (i.e. there is a buffer),
235  // inter process publish should always take place to ensure
236  // late joiners receive past data.
237  bool inter_process_publish_needed =
239 
240  if (inter_process_publish_needed) {
241  auto shared_msg =
242  this->do_intra_process_ros_message_publish_and_return_shared(std::move(msg));
243  if (buffer_) {
244  buffer_->add_shared(shared_msg);
245  }
246  this->do_inter_process_publish(*shared_msg);
247  } else {
248  if (buffer_) {
249  auto shared_msg =
250  this->do_intra_process_ros_message_publish_and_return_shared(std::move(msg));
251  buffer_->add_shared(shared_msg);
252  } else {
253  this->do_intra_process_ros_message_publish(std::move(msg));
254  }
255  }
256  }
257 
259 
270  template<typename T>
271  typename std::enable_if_t<
272  rosidl_generator_traits::is_message<T>::value &&
273  std::is_same<T, ROSMessageType>::value
274  >
275  publish(const T & msg)
276  {
277  // Avoid allocating when not using intra process.
278  if (!intra_process_is_enabled_) {
279  this->do_inter_process_publish(msg);
280  return;
281  }
282  // Otherwise we have to allocate memory in a unique_ptr and pass it along.
283  // As the message is not const, a copy should be made.
284  // A shared_ptr<const MessageT> could also be constructed here.
285  auto unique_msg = this->duplicate_ros_message_as_unique_ptr(msg);
286  this->publish(std::move(unique_msg));
287  }
288 
290 
300  template<typename T>
301  typename std::enable_if_t<
303  std::is_same<T, PublishedType>::value
304  >
305  publish(std::unique_ptr<T, PublishedTypeDeleter> msg)
306  {
307  if (!intra_process_is_enabled_) {
308  // In this case we're not using intra process.
309  auto ros_msg_ptr = std::make_unique<ROSMessageType>();
311  this->do_inter_process_publish(*ros_msg_ptr);
312  return;
313  }
314 
315  // When durability is set to TransientLocal (i.e. there is a buffer),
316  // inter process publish should always take place to ensure
317  // late joiners receive past data.
318  bool inter_process_publish_needed =
320 
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);
326  if (buffer_) {
327  buffer_->add_shared(ros_msg_ptr);
328  }
329  } else {
330  if (buffer_) {
331  auto ros_msg_ptr = std::make_shared<ROSMessageType>();
333  buffer_->add_shared(ros_msg_ptr);
334  }
335  this->do_intra_process_publish(std::move(msg));
336  }
337  }
338 
340 
350  template<typename T>
351  typename std::enable_if_t<
353  std::is_same<T, PublishedType>::value
354  >
355  publish(const T & msg)
356  {
357  if (!intra_process_is_enabled_) {
358  // Convert to the ROS message equivalent and publish it.
359  auto ros_msg_ptr = std::make_unique<ROSMessageType>();
361  this->do_inter_process_publish(*ros_msg_ptr);
362  return;
363  }
364 
365  // Otherwise we have to allocate memory in a unique_ptr and pass it along.
366  // As the message is not const, a copy should be made.
367  // A shared_ptr<const MessageT> could also be constructed here.
368  auto unique_msg = this->duplicate_type_adapt_message_as_unique_ptr(msg);
369  this->publish(std::move(unique_msg));
370  }
371 
372  void
373  publish(const rcl_serialized_message_t & serialized_msg)
374  {
375  return this->do_serialized_publish(&serialized_msg);
376  }
377 
378  void
379  publish(const SerializedMessage & serialized_msg)
380  {
381  return this->do_serialized_publish(&serialized_msg.get_rcl_serialized_message());
382  }
383 
385 
392  void
394  {
395  if (!loaned_msg.is_valid()) {
396  throw std::runtime_error("loaned message is not valid");
397  }
398 
399  // verify that publisher supports loaned messages
400  // TODO(Karsten1987): This case separation has to be done in rclcpp
401  // otherwise we have to ensure that every middleware implements
402  // `rmw_publish_loaned_message` explicitly the same way as `rmw_publish`
403  // by taking a copy of the ros message.
404  if (this->can_loan_messages()) {
405  // we release the ownership from the rclpp::LoanedMessage instance
406  // and let the middleware clean up the memory.
407  this->do_loaned_message_publish(loaned_msg.release());
408  } else {
409  // we don't release the ownership, let the middleware copy the ros message
410  // and thus the destructor of rclcpp::LoanedMessage cleans up the memory.
411  this->publish(loaned_msg.get());
412  }
413  }
414 
415  PublishedTypeAllocator
416  get_published_type_allocator() const
417  {
418  return published_type_allocator_;
419  }
420 
421  ROSMessageTypeAllocator
422  get_ros_message_type_allocator() const
423  {
424  return ros_message_type_allocator_;
425  }
426 
427 protected:
428  void
429  do_inter_process_publish(const ROSMessageType & msg)
430  {
431  TRACETOOLS_TRACEPOINT(rclcpp_publish, nullptr, static_cast<const void *>(&msg));
432  auto status = rcl_publish(publisher_handle_.get(), &msg, nullptr);
433 
434  if (RCL_RET_PUBLISHER_INVALID == status) {
435  rcl_reset_error(); // next call will reset error message if not context
436  if (rcl_publisher_is_valid_except_context(publisher_handle_.get())) {
437  rcl_context_t * context = rcl_publisher_get_context(publisher_handle_.get());
438  if (nullptr != context && !rcl_context_is_valid(context)) {
439  // publisher is invalid due to context being shutdown
440  return;
441  }
442  }
443  }
444  if (RCL_RET_OK != status) {
445  rclcpp::exceptions::throw_from_rcl_error(status, "failed to publish message");
446  }
447  }
448 
449  void
450  do_serialized_publish(const rcl_serialized_message_t * serialized_msg)
451  {
452  if (intra_process_is_enabled_) {
453  // TODO(Karsten1987): support serialized message passed by intraprocess
454  throw std::runtime_error("storing serialized messages in intra process is not supported yet");
455  }
456  auto status = rcl_publish_serialized_message(publisher_handle_.get(), serialized_msg, nullptr);
457  if (RCL_RET_OK != status) {
458  rclcpp::exceptions::throw_from_rcl_error(status, "failed to publish serialized message");
459  }
460  }
461 
462  void
463  do_loaned_message_publish(
464  std::unique_ptr<ROSMessageType, std::function<void(ROSMessageType *)>> msg)
465  {
466  TRACETOOLS_TRACEPOINT(rclcpp_publish, nullptr, static_cast<const void *>(msg.get()));
467  auto status = rcl_publish_loaned_message(publisher_handle_.get(), msg.get(), nullptr);
468 
469  if (RCL_RET_PUBLISHER_INVALID == status) {
470  rcl_reset_error(); // next call will reset error message if not context
471  if (rcl_publisher_is_valid_except_context(publisher_handle_.get())) {
472  rcl_context_t * context = rcl_publisher_get_context(publisher_handle_.get());
473  if (nullptr != context && !rcl_context_is_valid(context)) {
474  // publisher is invalid due to context being shutdown
475  return;
476  }
477  }
478  }
479  if (RCL_RET_OK != status) {
480  rclcpp::exceptions::throw_from_rcl_error(status, "failed to publish message");
481  }
482  }
483 
484  void
485  do_intra_process_publish(std::unique_ptr<PublishedType, PublishedTypeDeleter> msg)
486  {
487  auto ipm = weak_ipm_.lock();
488  if (!ipm) {
489  throw std::runtime_error(
490  "intra process publish called after destruction of intra process manager");
491  }
492  if (!msg) {
493  throw std::runtime_error("cannot publish msg which is a null pointer");
494  }
495  TRACETOOLS_TRACEPOINT(
496  rclcpp_intra_publish,
497  static_cast<const void *>(publisher_handle_.get()),
498  msg.get());
499 
500  ipm->template do_intra_process_publish<PublishedType, ROSMessageType, AllocatorT>(
501  intra_process_publisher_id_,
502  std::move(msg),
503  published_type_allocator_);
504  }
505 
506  void
507  do_intra_process_ros_message_publish(std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> msg)
508  {
509  auto ipm = weak_ipm_.lock();
510  if (!ipm) {
511  throw std::runtime_error(
512  "intra process publish called after destruction of intra process manager");
513  }
514  if (!msg) {
515  throw std::runtime_error("cannot publish msg which is a null pointer");
516  }
517  TRACETOOLS_TRACEPOINT(
518  rclcpp_intra_publish,
519  static_cast<const void *>(publisher_handle_.get()),
520  msg.get());
521 
522  ipm->template do_intra_process_publish<ROSMessageType, ROSMessageType, AllocatorT>(
523  intra_process_publisher_id_,
524  std::move(msg),
525  ros_message_type_allocator_);
526  }
527 
528  std::shared_ptr<const ROSMessageType>
529  do_intra_process_ros_message_publish_and_return_shared(
530  std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> msg)
531  {
532  auto ipm = weak_ipm_.lock();
533  if (!ipm) {
534  throw std::runtime_error(
535  "intra process publish called after destruction of intra process manager");
536  }
537  if (!msg) {
538  throw std::runtime_error("cannot publish msg which is a null pointer");
539  }
540  TRACETOOLS_TRACEPOINT(
541  rclcpp_intra_publish,
542  static_cast<const void *>(publisher_handle_.get()),
543  msg.get());
544 
545  return ipm->template do_intra_process_publish_and_return_shared<ROSMessageType, ROSMessageType,
546  AllocatorT>(
547  intra_process_publisher_id_,
548  std::move(msg),
549  ros_message_type_allocator_);
550  }
551 
552 
554  std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
556  {
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_);
560  }
561 
563  std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
564  duplicate_ros_message_as_unique_ptr(const ROSMessageType & msg)
565  {
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_);
569  }
570 
572  std::unique_ptr<PublishedType, PublishedTypeDeleter>
574  {
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.");
581 
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_);
585  }
586 
588 
593 
594  PublishedTypeAllocator published_type_allocator_;
595  PublishedTypeDeleter published_type_deleter_;
596  ROSMessageTypeAllocator ros_message_type_allocator_;
597  ROSMessageTypeDeleter ros_message_type_deleter_;
598 
599  BufferSharedPtr buffer_{nullptr};
600 };
601 
602 } // namespace rclcpp
603 
604 #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, 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.
Definition: publisher.hpp:79
typename rclcpp::TypeAdapter< MessageT >::custom_type PublishedType
MessageT::custom_type if MessageT is a TypeAdapter, otherwise just MessageT.
Definition: publisher.hpp:86
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:305
const rclcpp::PublisherOptionsWithAllocator< AllocatorT > options_
Copy of original options passed during construction.
Definition: publisher.hpp:592
rclcpp::LoanedMessage< ROSMessageType, AllocatorT > borrow_loaned_message()
Borrow a loaned ROS message from the middleware.
Definition: publisher.hpp:198
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:564
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:141
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:221
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:355
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:573
std::unique_ptr< ROSMessageType, ROSMessageTypeDeleter > create_ros_message_unique_ptr()
Return a new unique_ptr using the ROSMessageType of the publisher.
Definition: publisher.hpp:555
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:275
void publish(rclcpp::LoanedMessage< ROSMessageType, AllocatorT > &&loaned_msg)
Publish an instance of a LoanedMessage.
Definition: publisher.hpp:393
Encapsulation of Quality of Service settings.
Definition: qos.hpp:114
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:312
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:289
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:406
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:268
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:434
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