rclcpp  master
C++ ROS Client Library API
publisher.hpp
Go to the documentation of this file.
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 <rmw/error_handling.h>
19 #include <rmw/rmw.h>
20 
21 #include <functional>
22 #include <iostream>
23 #include <memory>
24 #include <sstream>
25 #include <string>
26 
27 #include "rcl/error_handling.h"
28 #include "rcl/publisher.h"
29 
30 #include "rcl_interfaces/msg/intra_process_message.hpp"
31 
34 #include "rclcpp/macros.hpp"
38 
39 namespace rclcpp
40 {
41 
42 // Forward declaration is used for friend statement.
43 namespace node_interfaces
44 {
45 class NodeTopicsInterface;
46 }
47 
48 namespace publisher
49 {
50 
52 {
54 
55 public:
57 
58 
59 
70  const std::string & topic,
71  const rosidl_message_type_support_t & type_support,
72  const rcl_publisher_options_t & publisher_options);
73 
75  virtual ~PublisherBase();
76 
78 
80  const char *
81  get_topic_name() const;
82 
84 
86  size_t
87  get_queue_size() const;
88 
90 
92  const rmw_gid_t &
93  get_gid() const;
94 
96 
98  const rmw_gid_t &
99  get_intra_process_gid() const;
100 
102 
108  bool
109  operator==(const rmw_gid_t & gid) const;
110 
112 
118  bool
119  operator==(const rmw_gid_t * gid) const;
120 
121  using StoreMessageCallbackT = std::function<uint64_t(uint64_t, void *, const std::type_info &)>;
122 
125  void
126  setup_intra_process(
127  uint64_t intra_process_publisher_id,
128  StoreMessageCallbackT callback,
129  const rcl_publisher_options_t & intra_process_options);
130 
131 protected:
132  std::shared_ptr<rcl_node_t> rcl_node_handle_;
133 
135  rcl_publisher_t intra_process_publisher_handle_ = rcl_get_zero_initialized_publisher();
136 
139 
142 };
143 
145 template<typename MessageT, typename Alloc = std::allocator<void>>
146 class Publisher : public PublisherBase
147 {
148 public:
150  using MessageAlloc = typename MessageAllocTraits::allocator_type;
152  using MessageUniquePtr = std::unique_ptr<MessageT, MessageDeleter>;
153 
155 
157  rclcpp::node_interfaces::NodeBaseInterface * node_base,
158  const std::string & topic,
159  const rcl_publisher_options_t & publisher_options,
160  const std::shared_ptr<MessageAlloc> & allocator)
161  : PublisherBase(
162  node_base,
163  topic,
164  *rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
165  publisher_options),
166  message_allocator_(allocator)
167  {
168  allocator::set_allocator_for_deleter(&message_deleter_, message_allocator_.get());
169  }
170 
171  virtual ~Publisher()
172  {}
173 
175 
179  virtual void
180  publish(std::unique_ptr<MessageT, MessageDeleter> & msg)
181  {
182  this->do_inter_process_publish(msg.get());
183  if (store_intra_process_message_) {
184  // Take the pointer from the unique_msg, release it and pass as a void *
185  // to the ipm. The ipm should then capture it again as a unique_ptr of
186  // the correct type.
187  // TODO(wjwwood):
188  // investigate how to transfer the custom deleter (if there is one)
189  // from the incoming unique_ptr through to the ipm's unique_ptr.
190  // See: http://stackoverflow.com/questions/11002641/dynamic-casting-for-unique-ptr
191  MessageT * msg_ptr = msg.get();
192  msg.release();
193  uint64_t message_seq =
194  store_intra_process_message_(intra_process_publisher_id_, msg_ptr, typeid(MessageT));
195  rcl_interfaces::msg::IntraProcessMessage ipm;
196  ipm.publisher_id = intra_process_publisher_id_;
197  ipm.message_sequence = message_seq;
198  auto status = rcl_publish(&intra_process_publisher_handle_, &ipm);
199  if (status != RCL_RET_OK) {
200  // *INDENT-OFF* (prevent uncrustify from making unnecessary indents here)
201  throw std::runtime_error(
202  std::string("failed to publish intra process message: ") + rcl_get_error_string_safe());
203  // *INDENT-ON*
204  }
205  } else {
206  // Always destroy the message, even if we don't consume it, for consistency.
207  msg.reset();
208  }
209  }
210 
211  virtual void
212  publish(const std::shared_ptr<MessageT> & msg)
213  {
214  // Avoid allocating when not using intra process.
215  if (!store_intra_process_message_) {
216  // In this case we're not using intra process.
217  return this->do_inter_process_publish(msg.get());
218  }
219  // Otherwise we have to allocate memory in a unique_ptr and pass it along.
220  // TODO(wjwwood):
221  // The intra process manager should probably also be able to store
222  // shared_ptr's and do the "smart" thing based on other intra process
223  // subscriptions. For now call the other publish().
224  auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
225  MessageAllocTraits::construct(*message_allocator_.get(), ptr, *msg.get());
226  MessageUniquePtr unique_msg(ptr, message_deleter_);
227  return this->publish(unique_msg);
228  }
229 
230  virtual void
231  publish(std::shared_ptr<const MessageT> msg)
232  {
233  // Avoid allocating when not using intra process.
234  if (!store_intra_process_message_) {
235  // In this case we're not using intra process.
236  return this->do_inter_process_publish(msg.get());
237  }
238  // Otherwise we have to allocate memory in a unique_ptr and pass it along.
239  // TODO(wjwwood):
240  // The intra process manager should probably also be able to store
241  // shared_ptr's and do the "smart" thing based on other intra process
242  // subscriptions. For now call the other publish().
243  auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
244  MessageAllocTraits::construct(*message_allocator_.get(), ptr, *msg.get());
245  MessageUniquePtr unique_msg(ptr, message_deleter_);
246  return this->publish(unique_msg);
247  }
248 
249  virtual void
250  publish(const MessageT & msg)
251  {
252  // Avoid allocating when not using intra process.
253  if (!store_intra_process_message_) {
254  // In this case we're not using intra process.
255  return this->do_inter_process_publish(&msg);
256  }
257  // Otherwise we have to allocate memory in a unique_ptr and pass it along.
258  auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
259  MessageAllocTraits::construct(*message_allocator_.get(), ptr, msg);
260  MessageUniquePtr unique_msg(ptr, message_deleter_);
261  return this->publish(unique_msg);
262  }
263 
264  virtual void
265  publish(const MessageT * msg)
266  {
267  if (!msg) {
268  throw std::runtime_error("msg argument is nullptr");
269  }
270  return this->publish(*msg);
271  }
272 
273  std::shared_ptr<MessageAlloc> get_allocator() const
274  {
275  return message_allocator_;
276  }
277 
278 protected:
279  void
280  do_inter_process_publish(const MessageT * msg)
281  {
282  auto status = rcl_publish(&publisher_handle_, msg);
283  if (status != RCL_RET_OK) {
284  // *INDENT-OFF* (prevent uncrustify from making unnecessary indents here)
285  throw std::runtime_error(
286  std::string("failed to publish message: ") + rcl_get_error_string_safe());
287  // *INDENT-ON*
288  }
289  }
290 
291  std::shared_ptr<MessageAlloc> message_allocator_;
292 
294 };
295 
296 } // namespace publisher
297 
298 } // namespace rclcpp
299 
300 #endif // RCLCPP__PUBLISHER_HPP_
uint64_t intra_process_publisher_id_
Definition: publisher.hpp:137
MessageDeleter message_deleter_
Definition: publisher.hpp:293
Definition: allocator_common.hpp:24
Definition: parameter.hpp:235
virtual void publish(std::unique_ptr< MessageT, MessageDeleter > &msg)
Send a message to the topic for this publisher.
Definition: publisher.hpp:180
std::function< uint64_t(uint64_t, void *, const std::type_info &)> StoreMessageCallbackT
Definition: publisher.hpp:121
Definition: publisher.hpp:51
virtual ~Publisher()
Definition: publisher.hpp:171
std::shared_ptr< MessageAlloc > message_allocator_
Definition: publisher.hpp:291
std::unique_ptr< rcl_interfaces::msg::ParameterEvent, MessageDeleter > MessageUniquePtr
Definition: publisher.hpp:152
#define RCL_RET_OK
std::shared_ptr< rcl_node_t > rcl_node_handle_
Definition: publisher.hpp:132
void set_allocator_for_deleter(D *deleter, Alloc *alloc)
Definition: allocator_deleter.hpp:72
allocator::Deleter< MessageAlloc, rcl_interfaces::msg::ParameterEvent > MessageDeleter
Definition: publisher.hpp:151
typename MessageAllocTraits::allocator_type MessageAlloc
Definition: publisher.hpp:150
typename std::allocator_traits< Alloc >::template rebind_traits< T > AllocRebind
Definition: allocator_common.hpp:30
rcl_publisher_t rcl_get_zero_initialized_publisher(void)
#define RCLCPP_SMART_PTR_DEFINITIONS(...)
Definition: macros.hpp:36
std::shared_ptr< MessageAlloc > get_allocator() const
Definition: publisher.hpp:273
StoreMessageCallbackT store_intra_process_message_
Definition: publisher.hpp:138
Pure virtual interface class for the NodeBase part of the Node API.
Definition: node_base_interface.hpp:36
#define rcl_get_error_string_safe
rmw_gid_t rmw_gid_
Definition: publisher.hpp:140
virtual void publish(std::shared_ptr< const MessageT > msg)
Definition: publisher.hpp:231
#define RCLCPP_PUBLIC
Definition: visibility_control.hpp:50
Pure virtual interface class for the NodeTopics part of the Node API.
Definition: node_topics_interface.hpp:38
rmw_gid_t intra_process_rmw_gid_
Definition: publisher.hpp:141
virtual void publish(const MessageT &msg)
Definition: publisher.hpp:250
typename std::conditional< std::is_same< typename std::allocator_traits< Alloc >::template rebind_alloc< T >, typename std::allocator< void >::template rebind< T >::other >::value, std::default_delete< T >, AllocatorDeleter< Alloc > >::type Deleter
Definition: allocator_deleter.hpp:101
void do_inter_process_publish(const MessageT *msg)
Definition: publisher.hpp:280
allocator::AllocRebind< rcl_interfaces::msg::ParameterEvent, std::allocator< void > > MessageAllocTraits
Definition: publisher.hpp:149
rcl_ret_t rcl_publish(const rcl_publisher_t *publisher, const void *ros_message)
virtual void publish(const MessageT *msg)
Definition: publisher.hpp:265
A publisher publishes messages of any type to a topic.
Definition: publisher.hpp:146
virtual void publish(const std::shared_ptr< MessageT > &msg)
Definition: publisher.hpp:212