ROS 2 rclcpp + rcl - lyrical  lyrical
ROS 2 C++ Client Library with ROS Client Library
client.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__CLIENT_HPP_
16 #define RCLCPP__CLIENT_HPP_
17 
18 #include <atomic>
19 #include <functional>
20 #include <future>
21 #include <memory>
22 #include <mutex>
23 #include <optional>
24 #include <sstream>
25 #include <string>
26 #include <tuple>
27 #include <unordered_map>
28 #include <utility>
29 #include <variant>
30 #include <vector>
31 
32 #include "rcl/client.h"
33 #include "rcl/error_handling.h"
34 #include "rcl/event_callback.h"
35 #include "rcl/service_introspection.h"
36 #include "rcl/wait.h"
37 
38 #include "rclcpp/clock.hpp"
39 #include "rclcpp/detail/cpp_callback_trampoline.hpp"
40 #include "rclcpp/exceptions.hpp"
41 #include "rclcpp/expand_topic_or_service_name.hpp"
42 #include "rclcpp/function_traits.hpp"
43 #include "rclcpp/logging.hpp"
44 #include "rclcpp/macros.hpp"
45 #include "rclcpp/node_interfaces/node_graph_interface.hpp"
46 #include "rclcpp/qos.hpp"
47 #include "rclcpp/type_support_decl.hpp"
48 #include "rclcpp/utilities.hpp"
49 #include "rclcpp/visibility_control.hpp"
50 
51 #include "rmw/error_handling.h"
52 #include "rmw/impl/cpp/demangle.hpp"
53 #include "rmw/rmw.h"
54 
55 namespace rclcpp
56 {
57 
58 namespace detail
59 {
60 template<typename FutureT>
62 {
63  FutureT future;
64  int64_t request_id;
65 
66  FutureAndRequestId(FutureT impl, int64_t req_id)
67  : future(std::move(impl)), request_id(req_id)
68  {}
69 
71  operator FutureT &() {return this->future;}
72 
73  // delegate future like methods in the std::future impl_
74 
76  auto get() {return this->future.get();}
78  bool valid() const noexcept {return this->future.valid();}
80  void wait() const {return this->future.wait();}
82  template<class Rep, class Period>
83  std::future_status wait_for(
84  const std::chrono::duration<Rep, Period> & timeout_duration) const
85  {
86  return this->future.wait_for(timeout_duration);
87  }
89  template<class Clock, class Duration>
90  std::future_status wait_until(
91  const std::chrono::time_point<Clock, Duration> & timeout_time) const
92  {
93  return this->future.wait_until(timeout_time);
94  }
95 
96  // Rule of five, we could use the rule of zero here, but better be explicit as some of the
97  // methods are deleted.
98 
100  FutureAndRequestId(FutureAndRequestId && other) noexcept = default;
102  FutureAndRequestId(const FutureAndRequestId & other) = delete;
104  FutureAndRequestId & operator=(FutureAndRequestId && other) noexcept = default;
108  ~FutureAndRequestId() = default;
109 };
110 
111 template<typename PendingRequestsT, typename AllocatorT = std::allocator<int64_t>>
112 size_t
113 prune_requests_older_than_impl(
114  PendingRequestsT & pending_requests,
115  std::mutex & pending_requests_mutex,
116  std::chrono::time_point<std::chrono::system_clock> time_point,
117  std::vector<int64_t, AllocatorT> * pruned_requests = nullptr)
118 {
119  std::lock_guard guard(pending_requests_mutex);
120  auto old_size = pending_requests.size();
121  for (auto it = pending_requests.begin(), last = pending_requests.end(); it != last; ) {
122  if (it->second.first < time_point) {
123  if (pruned_requests) {
124  pruned_requests->push_back(it->first);
125  }
126  it = pending_requests.erase(it);
127  } else {
128  ++it;
129  }
130  }
131  return old_size - pending_requests.size();
132 }
133 } // namespace detail
134 
135 namespace node_interfaces
136 {
137 class NodeBaseInterface;
138 } // namespace node_interfaces
139 
141 {
142 public:
143  RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(ClientBase)
144 
145  RCLCPP_PUBLIC
146  ClientBase(
148  const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr & node_graph);
149 
150  RCLCPP_PUBLIC
151  virtual ~ClientBase() = default;
152 
154 
170  RCLCPP_PUBLIC
171  bool
172  take_type_erased_response(void * response_out, rmw_request_id_t & request_header_out);
173 
175 
176  RCLCPP_PUBLIC
177  const char *
178  get_service_name() const;
179 
181 
185  RCLCPP_PUBLIC
186  std::shared_ptr<rcl_client_t>
188 
190 
194  RCLCPP_PUBLIC
195  std::shared_ptr<const rcl_client_t>
196  get_client_handle() const;
197 
199 
202  RCLCPP_PUBLIC
203  bool
204  service_is_ready() const;
205 
207 
211  template<typename RepT = int64_t, typename RatioT = std::milli>
212  bool
214  std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
215  {
216  return wait_for_service_nanoseconds(
217  std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
218  );
219  }
220 
221  virtual std::shared_ptr<void> create_response() = 0;
222  virtual std::shared_ptr<rmw_request_id_t> create_request_header() = 0;
223  virtual void handle_response(
224  const std::shared_ptr<rmw_request_id_t> & request_header,
225  const std::shared_ptr<void> & response) = 0;
226 
228 
237  RCLCPP_PUBLIC
238  bool
239  exchange_in_use_by_wait_set_state(bool in_use_state);
240 
242 
253  RCLCPP_PUBLIC
256 
258 
269  RCLCPP_PUBLIC
272 
274 
299  void
300  set_on_new_response_callback(const std::function<void(size_t)> & callback)
301  {
302  if (!callback) {
303  throw std::invalid_argument(
304  "The callback passed to set_on_new_response_callback "
305  "is not callable.");
306  }
307 
308  auto new_callback =
309  [callback, this](size_t number_of_responses) {
310  try {
311  callback(number_of_responses);
312  } catch (const std::exception & exception) {
313  RCLCPP_ERROR_STREAM(
314  node_logger_,
315  "rclcpp::ClientBase@" << this <<
316  " caught " << rmw::impl::cpp::demangle(exception) <<
317  " exception in user-provided callback for the 'on new response' callback: " <<
318  exception.what());
319  } catch (...) {
320  RCLCPP_ERROR_STREAM(
321  node_logger_,
322  "rclcpp::ClientBase@" << this <<
323  " caught unhandled exception in user-provided callback " <<
324  "for the 'on new response' callback");
325  }
326  };
327 
328  std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
329 
330  // Set it temporarily to the new callback, while we replace the old one.
331  // This two-step setting, prevents a gap where the old std::function has
332  // been replaced but the middleware hasn't been told about the new one yet.
334  rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
335  static_cast<const void *>(&new_callback));
336 
337  // Store the std::function to keep it in scope, also overwrites the existing one.
338  on_new_response_callback_ = new_callback;
339 
340  // Set it again, now using the permanent storage.
342  rclcpp::detail::cpp_callback_trampoline<
343  decltype(on_new_response_callback_), const void *, size_t>,
344  static_cast<const void *>(&on_new_response_callback_));
345  }
346 
348  void
350  {
351  std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
352  if (on_new_response_callback_) {
353  set_on_new_response_callback(nullptr, nullptr);
354  on_new_response_callback_ = nullptr;
355  }
356  }
357 
358 protected:
359  RCLCPP_DISABLE_COPY(ClientBase)
360 
361  RCLCPP_PUBLIC
362  bool
363  wait_for_service_nanoseconds(std::chrono::nanoseconds timeout);
364 
365  RCLCPP_PUBLIC
366  rcl_node_t *
367  get_rcl_node_handle();
368 
369  RCLCPP_PUBLIC
370  const rcl_node_t *
371  get_rcl_node_handle() const;
372 
373  RCLCPP_PUBLIC
374  void
375  set_on_new_response_callback(rcl_event_callback_t callback, const void * user_data);
376 
377  rclcpp::node_interfaces::NodeGraphInterface::WeakPtr node_graph_;
378  std::shared_ptr<rcl_node_t> node_handle_;
379  std::shared_ptr<rclcpp::Context> context_;
380  rclcpp::Logger node_logger_;
381 
382  std::recursive_mutex callback_mutex_;
383  // It is important to declare on_new_response_callback_ before
384  // client_handle_, so on destruction the client is
385  // destroyed first. Otherwise, the rmw client callback
386  // would point briefly to a destroyed function.
387  std::function<void(size_t)> on_new_response_callback_{nullptr};
388  // Declare client_handle_ after callback
389  std::shared_ptr<rcl_client_t> client_handle_;
390 
391  std::atomic<bool> in_use_by_wait_set_{false};
392 };
393 
394 template<typename ServiceT>
395 class Client : public ClientBase
396 {
397 public:
398  using Request = typename ServiceT::Request;
399  using Response = typename ServiceT::Response;
400 
401  using SharedRequest = typename ServiceT::Request::SharedPtr;
402  using SharedResponse = typename ServiceT::Response::SharedPtr;
403 
404  using Promise = std::promise<SharedResponse>;
405  using PromiseWithRequest = std::promise<std::pair<SharedRequest, SharedResponse>>;
406 
407  using SharedPromise = std::shared_ptr<Promise>;
408  using SharedPromiseWithRequest = std::shared_ptr<PromiseWithRequest>;
409 
410  using Future = std::future<SharedResponse>;
411  using SharedFuture = std::shared_future<SharedResponse>;
412  using SharedFutureWithRequest = std::shared_future<std::pair<SharedRequest, SharedResponse>>;
413 
414  using CallbackType = std::function<void (SharedFuture)>;
415  using CallbackWithRequestType = std::function<void (SharedFutureWithRequest)>;
416 
417  RCLCPP_SMART_PTR_DEFINITIONS(Client)
418 
419 
428  : detail::FutureAndRequestId<std::future<SharedResponse>>
429  {
431 
432  // delegate future like methods in the std::future impl_
433 
435  SharedFuture share() noexcept {return this->future.share();}
436  };
437 
439 
447  : detail::FutureAndRequestId<std::shared_future<SharedResponse>>
448  {
450  };
451 
453 
461  : detail::FutureAndRequestId<std::shared_future<std::pair<SharedRequest, SharedResponse>>>
462  {
464  std::shared_future<std::pair<SharedRequest, SharedResponse>>
466  };
467 
469 
481  const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr & node_graph,
482  const std::string & service_name,
483  rcl_client_options_t & client_options)
484  : ClientBase(node_base, node_graph),
485  srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
486  {
488  this->get_client_handle().get(),
489  this->get_rcl_node_handle(),
490  srv_type_support_handle_,
491  service_name.c_str(),
492  &client_options);
493  if (ret != RCL_RET_OK) {
494  if (ret == RCL_RET_SERVICE_NAME_INVALID) {
495  auto rcl_node_handle = this->get_rcl_node_handle();
496  // this will throw on any validation problem
497  rcl_reset_error();
499  service_name,
500  rcl_node_get_name(rcl_node_handle),
501  rcl_node_get_namespace(rcl_node_handle),
502  true);
503  }
504  rclcpp::exceptions::throw_from_rcl_error(ret, "could not create client");
505  }
506  }
507 
508  virtual ~Client()
509  {
510  }
511 
513 
525  bool
526  take_response(typename ServiceT::Response & response_out, rmw_request_id_t & request_header_out)
527  {
528  return this->take_type_erased_response(&response_out, request_header_out);
529  }
530 
532 
535  std::shared_ptr<void>
536  create_response() override
537  {
538  return std::shared_ptr<void>(new typename ServiceT::Response());
539  }
540 
542 
545  std::shared_ptr<rmw_request_id_t>
547  {
548  // TODO(wjwwood): This should probably use rmw_request_id's allocator.
549  // (since it is a C type)
550  return std::shared_ptr<rmw_request_id_t>(new rmw_request_id_t);
551  }
552 
554 
558  void
560  const std::shared_ptr<rmw_request_id_t> & request_header,
561  const std::shared_ptr<void> & response) override
562  {
563  std::optional<CallbackInfoVariant>
564  optional_pending_request = this->get_and_erase_pending_request(request_header->sequence_number);
565  if (!optional_pending_request) {
566  return;
567  }
568  auto & value = *optional_pending_request;
569  auto typed_response = std::static_pointer_cast<typename ServiceT::Response>(
570  response);
571  if (std::holds_alternative<Promise>(value)) {
572  auto & promise = std::get<Promise>(value);
573  promise.set_value(std::move(typed_response));
574  } else if (std::holds_alternative<CallbackTypeValueVariant>(value)) {
575  auto & inner = std::get<CallbackTypeValueVariant>(value);
576  const auto & callback = std::get<CallbackType>(inner);
577  auto & promise = std::get<Promise>(inner);
578  auto & future = std::get<SharedFuture>(inner);
579  promise.set_value(std::move(typed_response));
580  callback(std::move(future));
581  } else if (std::holds_alternative<CallbackWithRequestTypeValueVariant>(value)) {
582  auto & inner = std::get<CallbackWithRequestTypeValueVariant>(value);
583  const auto & callback = std::get<CallbackWithRequestType>(inner);
584  auto & promise = std::get<PromiseWithRequest>(inner);
585  auto & future = std::get<SharedFutureWithRequest>(inner);
586  auto & request = std::get<SharedRequest>(inner);
587  promise.set_value(std::make_pair(std::move(request), std::move(typed_response)));
588  callback(std::move(future));
589  }
590  }
591 
593 
620  FutureAndRequestId
621  async_send_request(const SharedRequest & request)
622  {
623  Promise promise;
624  auto future = promise.get_future();
625  auto req_id = async_send_request_impl(
626  *request,
627  std::move(promise));
628  return FutureAndRequestId(std::move(future), req_id);
629  }
630 
632 
646  template<
647  typename CallbackT,
648  typename std::enable_if<
650  CallbackT,
651  CallbackType
652  >::value
653  >::type * = nullptr
654  >
655  SharedFutureAndRequestId
656  async_send_request(const SharedRequest & request, CallbackT && cb)
657  {
658  Promise promise;
659  auto shared_future = promise.get_future().share();
660  auto req_id = async_send_request_impl(
661  *request,
662  std::make_tuple(
663  CallbackType{std::forward<CallbackT>(cb)},
664  shared_future,
665  std::move(promise)));
666  return SharedFutureAndRequestId{std::move(shared_future), req_id};
667  }
668 
670 
677  template<
678  typename CallbackT,
679  typename std::enable_if<
681  CallbackT,
682  CallbackWithRequestType
683  >::value
684  >::type * = nullptr
685  >
686  SharedFutureWithRequestAndRequestId
687  async_send_request(const SharedRequest & request, CallbackT && cb)
688  {
689  PromiseWithRequest promise;
690  auto shared_future = promise.get_future().share();
691  auto req_id = async_send_request_impl(
692  *request,
693  std::make_tuple(
694  CallbackWithRequestType{std::forward<CallbackT>(cb)},
695  request,
696  shared_future,
697  std::move(promise)));
698  return SharedFutureWithRequestAndRequestId{std::move(shared_future), req_id};
699  }
700 
702 
712  bool
713  remove_pending_request(int64_t request_id)
714  {
715  std::lock_guard guard(pending_requests_mutex_);
716  return pending_requests_.erase(request_id) != 0u;
717  }
718 
720 
725  bool
727  {
728  return this->remove_pending_request(future.request_id);
729  }
730 
732 
737  bool
739  {
740  return this->remove_pending_request(future.request_id);
741  }
742 
744 
749  bool
751  {
752  return this->remove_pending_request(future.request_id);
753  }
754 
756 
759  size_t
761  {
762  std::lock_guard guard(pending_requests_mutex_);
763  auto ret = pending_requests_.size();
764  pending_requests_.clear();
765  return ret;
766  }
767 
769 
775  template<typename AllocatorT = std::allocator<int64_t>>
776  size_t
778  std::chrono::time_point<std::chrono::system_clock> time_point,
779  std::vector<int64_t, AllocatorT> * pruned_requests = nullptr)
780  {
781  return detail::prune_requests_older_than_impl(
782  pending_requests_,
783  pending_requests_mutex_,
784  time_point,
785  pruned_requests);
786  }
787 
789 
797  void
799  const Clock::SharedPtr & clock, const QoS & qos_service_event_pub,
800  rcl_service_introspection_state_t introspection_state)
801  {
803  pub_opts.qos = qos_service_event_pub.get_rmw_qos_profile();
804 
806  client_handle_.get(),
807  node_handle_.get(),
808  clock->get_clock_handle(),
809  srv_type_support_handle_,
810  pub_opts,
811  introspection_state);
812 
813  if (RCL_RET_OK != ret) {
814  rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure client introspection");
815  }
816  }
817 
818 protected:
819  using CallbackTypeValueVariant = std::tuple<CallbackType, SharedFuture, Promise>;
820  using CallbackWithRequestTypeValueVariant = std::tuple<
821  CallbackWithRequestType, SharedRequest, SharedFutureWithRequest, PromiseWithRequest>;
822 
823  using CallbackInfoVariant = std::variant<
824  std::promise<SharedResponse>,
825  CallbackTypeValueVariant,
826  CallbackWithRequestTypeValueVariant>;
827 
828  int64_t
829  async_send_request_impl(const Request & request, CallbackInfoVariant value)
830  {
831  int64_t sequence_number;
832  std::lock_guard<std::mutex> lock(pending_requests_mutex_);
833  rcl_ret_t ret = rcl_send_request(get_client_handle().get(), &request, &sequence_number);
834  if (RCL_RET_OK != ret) {
835  rclcpp::exceptions::throw_from_rcl_error(ret, "failed to send request");
836  }
837  pending_requests_.try_emplace(
838  sequence_number,
839  std::make_pair(std::chrono::system_clock::now(), std::move(value)));
840  return sequence_number;
841  }
842 
843  std::optional<CallbackInfoVariant>
844  get_and_erase_pending_request(int64_t request_number)
845  {
846  std::unique_lock<std::mutex> lock(pending_requests_mutex_);
847  auto it = this->pending_requests_.find(request_number);
848  if (it == this->pending_requests_.end()) {
849  RCUTILS_LOG_DEBUG_NAMED(
850  "rclcpp",
851  "Received invalid sequence number. Ignoring...");
852  return std::nullopt;
853  }
854  std::optional<CallbackInfoVariant> value = std::move(it->second.second);
855  this->pending_requests_.erase(request_number);
856  return value;
857  }
858 
859  RCLCPP_DISABLE_COPY(Client)
860 
861  std::unordered_map<
862  int64_t,
863  std::pair<
864  std::chrono::time_point<std::chrono::system_clock>,
865  CallbackInfoVariant>>
866  pending_requests_;
867  std::mutex pending_requests_mutex_;
868 
869 private:
870  const rosidl_service_type_support_t * srv_type_support_handle_;
871 };
872 
873 } // namespace rclcpp
874 
875 #endif // RCLCPP__CLIENT_HPP_
RCLCPP_PUBLIC bool exchange_in_use_by_wait_set_state(bool in_use_state)
Exchange the "in use by wait set" state for this client.
Definition: client.cpp:194
RCLCPP_PUBLIC rclcpp::QoS get_request_publisher_actual_qos() const
Get the actual request publsher QoS settings, after the defaults have been determined.
Definition: client.cpp:200
RCLCPP_PUBLIC std::shared_ptr< rcl_client_t > get_client_handle()
Return the rcl_client_t client handle in a std::shared_ptr.
Definition: client.cpp:92
RCLCPP_PUBLIC bool take_type_erased_response(void *response_out, rmw_request_id_t &request_header_out)
Take the next response for this client as a type erased pointer.
Definition: client.cpp:71
void set_on_new_response_callback(const std::function< void(size_t)> &callback)
Set a callback to be called when each new response is received.
Definition: client.hpp:300
bool wait_for_service(std::chrono::duration< RepT, RatioT > timeout=std::chrono::duration< RepT, RatioT >(-1))
Wait for a service to be ready.
Definition: client.hpp:213
RCLCPP_PUBLIC const char * get_service_name() const
Return the name of the service.
Definition: client.cpp:86
void clear_on_new_response_callback()
Unset the callback registered for new responses, if any.
Definition: client.hpp:349
RCLCPP_PUBLIC rclcpp::QoS get_response_subscription_actual_qos() const
Get the actual response subscription QoS settings, after the defaults have been determined.
Definition: client.cpp:219
RCLCPP_PUBLIC bool service_is_ready() const
Return if the service is ready.
Definition: client.cpp:104
bool take_response(typename ServiceT::Response &response_out, rmw_request_id_t &request_header_out)
Take the next response for this client.
Definition: client.hpp:526
std::shared_ptr< rmw_request_id_t > create_request_header() override
Create a shared pointer with a rmw_request_id_t.
Definition: client.hpp:546
bool remove_pending_request(int64_t request_id)
Cleanup a pending request.
Definition: client.hpp:713
std::shared_ptr< void > create_response() override
Create a shared pointer with the response type.
Definition: client.hpp:536
size_t prune_requests_older_than(std::chrono::time_point< std::chrono::system_clock > time_point, std::vector< int64_t, AllocatorT > *pruned_requests=nullptr)
Clean all pending requests older than a time_point.
Definition: client.hpp:777
void configure_introspection(const Clock::SharedPtr &clock, const QoS &qos_service_event_pub, rcl_service_introspection_state_t introspection_state)
Configure client introspection.
Definition: client.hpp:798
FutureAndRequestId async_send_request(const SharedRequest &request)
Send a request to the service server.
Definition: client.hpp:621
Client(rclcpp::node_interfaces::NodeBaseInterface *node_base, const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr &node_graph, const std::string &service_name, rcl_client_options_t &client_options)
Default constructor.
Definition: client.hpp:479
size_t prune_pending_requests()
Clean all pending requests.
Definition: client.hpp:760
bool remove_pending_request(const SharedFutureAndRequestId &future)
Cleanup a pending request.
Definition: client.hpp:738
SharedFutureWithRequestAndRequestId async_send_request(const SharedRequest &request, CallbackT &&cb)
Send a request to the service server and schedule a callback in the executor.
Definition: client.hpp:687
bool remove_pending_request(const SharedFutureWithRequestAndRequestId &future)
Cleanup a pending request.
Definition: client.hpp:750
void handle_response(const std::shared_ptr< rmw_request_id_t > &request_header, const std::shared_ptr< void > &response) override
Handle a server response.
Definition: client.hpp:559
SharedFutureAndRequestId async_send_request(const SharedRequest &request, CallbackT &&cb)
Send a request to the service server and schedule a callback in the executor.
Definition: client.hpp:656
bool remove_pending_request(const FutureAndRequestId &future)
Cleanup a pending request.
Definition: client.hpp:726
Encapsulation of Quality of Service settings.
Definition: qos.hpp:116
rmw_qos_profile_t & get_rmw_qos_profile()
Return the rmw qos profile.
Definition: qos.cpp:108
Pure virtual interface class for the NodeBase part of the Node API.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_client_configure_service_introspection(rcl_client_t *client, rcl_node_t *node, rcl_clock_t *clock, const rosidl_service_type_support_t *type_support, const rcl_publisher_options_t publisher_options, rcl_service_introspection_state_t introspection_state)
Configures service introspection features for the client.
Definition: client.c:456
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_client_init(rcl_client_t *client, const rcl_node_t *node, const rosidl_service_type_support_t *type_support, const char *service_name, const rcl_client_options_t *options)
Initialize a rcl client.
Definition: client.c:76
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_send_request(const rcl_client_t *client, const void *ros_request, int64_t *sequence_number)
Send a ROS request using a client.
Definition: client.c:308
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC std::string expand_topic_or_service_name(const std::string &name, const std::string &node_name, const std::string &namespace_, bool is_service=false)
Expand a topic or service name and throw if it is not valid.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_name(const rcl_node_t *node)
Return the name of the node.
Definition: node.c:416
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_namespace(const rcl_node_t *node)
Return the namespace of the node.
Definition: node.c:425
RCL_PUBLIC RCL_WARN_UNUSED rcl_publisher_options_t rcl_publisher_get_default_options(void)
Return the default publisher options in a rcl_publisher_options_t.
Definition: publisher.c:220
Options available for a rcl_client_t.
Definition: client.h:50
Structure which encapsulates a ROS Node.
Definition: node.h:45
Options available for a rcl publisher.
Definition: publisher.h:44
rmw_qos_profile_t qos
Middleware quality of service settings for the publisher.
Definition: publisher.h:46
A convenient Client::Future and request id pair.
Definition: client.hpp:429
SharedFuture share() noexcept
See std::future::share().
Definition: client.hpp:435
A convenient Client::SharedFuture and request id pair.
Definition: client.hpp:448
A convenient Client::SharedFutureWithRequest and request id pair.
Definition: client.hpp:462
std::future_status wait_for(const std::chrono::duration< Rep, Period > &timeout_duration) const
See std::future::wait_for().
Definition: client.hpp:83
std::future_status wait_until(const std::chrono::time_point< Clock, Duration > &timeout_time) const
See std::future::wait_until().
Definition: client.hpp:90
FutureAndRequestId & operator=(FutureAndRequestId &&other) noexcept=default
Move assignment.
FutureAndRequestId & operator=(const FutureAndRequestId &other)=delete
Deleted copy assignment, each instance is a unique owner of the future.
FutureAndRequestId(const FutureAndRequestId &other)=delete
Deleted copy constructor, each instance is a unique owner of the future.
void wait() const
See std::future::wait().
Definition: client.hpp:80
FutureAndRequestId(FutureAndRequestId &&other) noexcept=default
Move constructor.
~FutureAndRequestId()=default
Destructor.
auto get()
See std::future::get().
Definition: client.hpp:76
bool valid() const noexcept
See std::future::valid().
Definition: client.hpp:78
#define RCL_RET_SERVICE_NAME_INVALID
Service name (same as topic name) does not pass validation.
Definition: types.h:49
#define RCL_RET_OK
Success return code.
Definition: types.h:27
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24