ROS 2 rclcpp + rcl - kilted  kilted
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  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  std::shared_ptr<rmw_request_id_t> request_header, std::shared_ptr<void> response) = 0;
225 
227 
236  RCLCPP_PUBLIC
237  bool
238  exchange_in_use_by_wait_set_state(bool in_use_state);
239 
241 
252  RCLCPP_PUBLIC
255 
257 
268  RCLCPP_PUBLIC
271 
273 
298  void
299  set_on_new_response_callback(std::function<void(size_t)> callback)
300  {
301  if (!callback) {
302  throw std::invalid_argument(
303  "The callback passed to set_on_new_response_callback "
304  "is not callable.");
305  }
306 
307  auto new_callback =
308  [callback, this](size_t number_of_responses) {
309  try {
310  callback(number_of_responses);
311  } catch (const std::exception & exception) {
312  RCLCPP_ERROR_STREAM(
313  node_logger_,
314  "rclcpp::ClientBase@" << this <<
315  " caught " << rmw::impl::cpp::demangle(exception) <<
316  " exception in user-provided callback for the 'on new response' callback: " <<
317  exception.what());
318  } catch (...) {
319  RCLCPP_ERROR_STREAM(
320  node_logger_,
321  "rclcpp::ClientBase@" << this <<
322  " caught unhandled exception in user-provided callback " <<
323  "for the 'on new response' callback");
324  }
325  };
326 
327  std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
328 
329  // Set it temporarily to the new callback, while we replace the old one.
330  // This two-step setting, prevents a gap where the old std::function has
331  // been replaced but the middleware hasn't been told about the new one yet.
333  rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
334  static_cast<const void *>(&new_callback));
335 
336  // Store the std::function to keep it in scope, also overwrites the existing one.
337  on_new_response_callback_ = new_callback;
338 
339  // Set it again, now using the permanent storage.
341  rclcpp::detail::cpp_callback_trampoline<
342  decltype(on_new_response_callback_), const void *, size_t>,
343  static_cast<const void *>(&on_new_response_callback_));
344  }
345 
347  void
349  {
350  std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
351  if (on_new_response_callback_) {
352  set_on_new_response_callback(nullptr, nullptr);
353  on_new_response_callback_ = nullptr;
354  }
355  }
356 
357 protected:
358  RCLCPP_DISABLE_COPY(ClientBase)
359 
360  RCLCPP_PUBLIC
361  bool
362  wait_for_service_nanoseconds(std::chrono::nanoseconds timeout);
363 
364  RCLCPP_PUBLIC
365  rcl_node_t *
366  get_rcl_node_handle();
367 
368  RCLCPP_PUBLIC
369  const rcl_node_t *
370  get_rcl_node_handle() const;
371 
372  RCLCPP_PUBLIC
373  void
374  set_on_new_response_callback(rcl_event_callback_t callback, const void * user_data);
375 
376  rclcpp::node_interfaces::NodeGraphInterface::WeakPtr node_graph_;
377  std::shared_ptr<rcl_node_t> node_handle_;
378  std::shared_ptr<rclcpp::Context> context_;
379  rclcpp::Logger node_logger_;
380 
381  std::recursive_mutex callback_mutex_;
382  // It is important to declare on_new_response_callback_ before
383  // client_handle_, so on destruction the client is
384  // destroyed first. Otherwise, the rmw client callback
385  // would point briefly to a destroyed function.
386  std::function<void(size_t)> on_new_response_callback_{nullptr};
387  // Declare client_handle_ after callback
388  std::shared_ptr<rcl_client_t> client_handle_;
389 
390  std::atomic<bool> in_use_by_wait_set_{false};
391 };
392 
393 template<typename ServiceT>
394 class Client : public ClientBase
395 {
396 public:
397  using Request = typename ServiceT::Request;
398  using Response = typename ServiceT::Response;
399 
400  using SharedRequest = typename ServiceT::Request::SharedPtr;
401  using SharedResponse = typename ServiceT::Response::SharedPtr;
402 
403  using Promise = std::promise<SharedResponse>;
404  using PromiseWithRequest = std::promise<std::pair<SharedRequest, SharedResponse>>;
405 
406  using SharedPromise = std::shared_ptr<Promise>;
407  using SharedPromiseWithRequest = std::shared_ptr<PromiseWithRequest>;
408 
409  using Future = std::future<SharedResponse>;
410  using SharedFuture = std::shared_future<SharedResponse>;
411  using SharedFutureWithRequest = std::shared_future<std::pair<SharedRequest, SharedResponse>>;
412 
413  using CallbackType = std::function<void (SharedFuture)>;
414  using CallbackWithRequestType = std::function<void (SharedFutureWithRequest)>;
415 
416  RCLCPP_SMART_PTR_DEFINITIONS(Client)
417 
418 
427  : detail::FutureAndRequestId<std::future<SharedResponse>>
428  {
430 
431  // delegate future like methods in the std::future impl_
432 
434  SharedFuture share() noexcept {return this->future.share();}
435  };
436 
438 
446  : detail::FutureAndRequestId<std::shared_future<SharedResponse>>
447  {
449  };
450 
452 
460  : detail::FutureAndRequestId<std::shared_future<std::pair<SharedRequest, SharedResponse>>>
461  {
463  std::shared_future<std::pair<SharedRequest, SharedResponse>>
465  };
466 
468 
480  rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
481  const std::string & service_name,
482  rcl_client_options_t & client_options)
483  : ClientBase(node_base, node_graph),
484  srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
485  {
487  this->get_client_handle().get(),
488  this->get_rcl_node_handle(),
489  srv_type_support_handle_,
490  service_name.c_str(),
491  &client_options);
492  if (ret != RCL_RET_OK) {
493  if (ret == RCL_RET_SERVICE_NAME_INVALID) {
494  auto rcl_node_handle = this->get_rcl_node_handle();
495  // this will throw on any validation problem
496  rcl_reset_error();
498  service_name,
499  rcl_node_get_name(rcl_node_handle),
500  rcl_node_get_namespace(rcl_node_handle),
501  true);
502  }
503  rclcpp::exceptions::throw_from_rcl_error(ret, "could not create client");
504  }
505  }
506 
507  virtual ~Client()
508  {
509  }
510 
512 
524  bool
525  take_response(typename ServiceT::Response & response_out, rmw_request_id_t & request_header_out)
526  {
527  return this->take_type_erased_response(&response_out, request_header_out);
528  }
529 
531 
534  std::shared_ptr<void>
535  create_response() override
536  {
537  return std::shared_ptr<void>(new typename ServiceT::Response());
538  }
539 
541 
544  std::shared_ptr<rmw_request_id_t>
546  {
547  // TODO(wjwwood): This should probably use rmw_request_id's allocator.
548  // (since it is a C type)
549  return std::shared_ptr<rmw_request_id_t>(new rmw_request_id_t);
550  }
551 
553 
557  void
559  std::shared_ptr<rmw_request_id_t> request_header,
560  std::shared_ptr<void> response) override
561  {
562  std::optional<CallbackInfoVariant>
563  optional_pending_request = this->get_and_erase_pending_request(request_header->sequence_number);
564  if (!optional_pending_request) {
565  return;
566  }
567  auto & value = *optional_pending_request;
568  auto typed_response = std::static_pointer_cast<typename ServiceT::Response>(
569  std::move(response));
570  if (std::holds_alternative<Promise>(value)) {
571  auto & promise = std::get<Promise>(value);
572  promise.set_value(std::move(typed_response));
573  } else if (std::holds_alternative<CallbackTypeValueVariant>(value)) {
574  auto & inner = std::get<CallbackTypeValueVariant>(value);
575  const auto & callback = std::get<CallbackType>(inner);
576  auto & promise = std::get<Promise>(inner);
577  auto & future = std::get<SharedFuture>(inner);
578  promise.set_value(std::move(typed_response));
579  callback(std::move(future));
580  } else if (std::holds_alternative<CallbackWithRequestTypeValueVariant>(value)) {
581  auto & inner = std::get<CallbackWithRequestTypeValueVariant>(value);
582  const auto & callback = std::get<CallbackWithRequestType>(inner);
583  auto & promise = std::get<PromiseWithRequest>(inner);
584  auto & future = std::get<SharedFutureWithRequest>(inner);
585  auto & request = std::get<SharedRequest>(inner);
586  promise.set_value(std::make_pair(std::move(request), std::move(typed_response)));
587  callback(std::move(future));
588  }
589  }
590 
592 
619  FutureAndRequestId
620  async_send_request(SharedRequest request)
621  {
622  Promise promise;
623  auto future = promise.get_future();
624  auto req_id = async_send_request_impl(
625  *request,
626  std::move(promise));
627  return FutureAndRequestId(std::move(future), req_id);
628  }
629 
631 
645  template<
646  typename CallbackT,
647  typename std::enable_if<
649  CallbackT,
650  CallbackType
651  >::value
652  >::type * = nullptr
653  >
654  SharedFutureAndRequestId
655  async_send_request(SharedRequest request, CallbackT && cb)
656  {
657  Promise promise;
658  auto shared_future = promise.get_future().share();
659  auto req_id = async_send_request_impl(
660  *request,
661  std::make_tuple(
662  CallbackType{std::forward<CallbackT>(cb)},
663  shared_future,
664  std::move(promise)));
665  return SharedFutureAndRequestId{std::move(shared_future), req_id};
666  }
667 
669 
676  template<
677  typename CallbackT,
678  typename std::enable_if<
680  CallbackT,
681  CallbackWithRequestType
682  >::value
683  >::type * = nullptr
684  >
685  SharedFutureWithRequestAndRequestId
686  async_send_request(SharedRequest request, CallbackT && cb)
687  {
688  PromiseWithRequest promise;
689  auto shared_future = promise.get_future().share();
690  auto req_id = async_send_request_impl(
691  *request,
692  std::make_tuple(
693  CallbackWithRequestType{std::forward<CallbackT>(cb)},
694  request,
695  shared_future,
696  std::move(promise)));
697  return SharedFutureWithRequestAndRequestId{std::move(shared_future), req_id};
698  }
699 
701 
711  bool
712  remove_pending_request(int64_t request_id)
713  {
714  std::lock_guard guard(pending_requests_mutex_);
715  return pending_requests_.erase(request_id) != 0u;
716  }
717 
719 
724  bool
726  {
727  return this->remove_pending_request(future.request_id);
728  }
729 
731 
736  bool
738  {
739  return this->remove_pending_request(future.request_id);
740  }
741 
743 
748  bool
750  {
751  return this->remove_pending_request(future.request_id);
752  }
753 
755 
758  size_t
760  {
761  std::lock_guard guard(pending_requests_mutex_);
762  auto ret = pending_requests_.size();
763  pending_requests_.clear();
764  return ret;
765  }
766 
768 
774  template<typename AllocatorT = std::allocator<int64_t>>
775  size_t
777  std::chrono::time_point<std::chrono::system_clock> time_point,
778  std::vector<int64_t, AllocatorT> * pruned_requests = nullptr)
779  {
780  return detail::prune_requests_older_than_impl(
781  pending_requests_,
782  pending_requests_mutex_,
783  time_point,
784  pruned_requests);
785  }
786 
788 
796  void
798  Clock::SharedPtr clock, const QoS & qos_service_event_pub,
799  rcl_service_introspection_state_t introspection_state)
800  {
802  pub_opts.qos = qos_service_event_pub.get_rmw_qos_profile();
803 
805  client_handle_.get(),
806  node_handle_.get(),
807  clock->get_clock_handle(),
808  srv_type_support_handle_,
809  pub_opts,
810  introspection_state);
811 
812  if (RCL_RET_OK != ret) {
813  rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure client introspection");
814  }
815  }
816 
817 protected:
818  using CallbackTypeValueVariant = std::tuple<CallbackType, SharedFuture, Promise>;
819  using CallbackWithRequestTypeValueVariant = std::tuple<
820  CallbackWithRequestType, SharedRequest, SharedFutureWithRequest, PromiseWithRequest>;
821 
822  using CallbackInfoVariant = std::variant<
823  std::promise<SharedResponse>,
824  CallbackTypeValueVariant,
825  CallbackWithRequestTypeValueVariant>;
826 
827  int64_t
828  async_send_request_impl(const Request & request, CallbackInfoVariant value)
829  {
830  int64_t sequence_number;
831  std::lock_guard<std::mutex> lock(pending_requests_mutex_);
832  rcl_ret_t ret = rcl_send_request(get_client_handle().get(), &request, &sequence_number);
833  if (RCL_RET_OK != ret) {
834  rclcpp::exceptions::throw_from_rcl_error(ret, "failed to send request");
835  }
836  pending_requests_.try_emplace(
837  sequence_number,
838  std::make_pair(std::chrono::system_clock::now(), std::move(value)));
839  return sequence_number;
840  }
841 
842  std::optional<CallbackInfoVariant>
843  get_and_erase_pending_request(int64_t request_number)
844  {
845  std::unique_lock<std::mutex> lock(pending_requests_mutex_);
846  auto it = this->pending_requests_.find(request_number);
847  if (it == this->pending_requests_.end()) {
848  RCUTILS_LOG_DEBUG_NAMED(
849  "rclcpp",
850  "Received invalid sequence number. Ignoring...");
851  return std::nullopt;
852  }
853  std::optional<CallbackInfoVariant> value = std::move(it->second.second);
854  this->pending_requests_.erase(request_number);
855  return value;
856  }
857 
858  RCLCPP_DISABLE_COPY(Client)
859 
860  std::unordered_map<
861  int64_t,
862  std::pair<
863  std::chrono::time_point<std::chrono::system_clock>,
864  CallbackInfoVariant>>
865  pending_requests_;
866  std::mutex pending_requests_mutex_;
867 
868 private:
869  const rosidl_service_type_support_t * srv_type_support_handle_;
870 };
871 
872 } // namespace rclcpp
873 
874 #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
void set_on_new_response_callback(std::function< void(size_t)> callback)
Set a callback to be called when each new response is received.
Definition: client.hpp:299
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
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:348
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:525
std::shared_ptr< rmw_request_id_t > create_request_header() override
Create a shared pointer with a rmw_request_id_t.
Definition: client.hpp:545
bool remove_pending_request(int64_t request_id)
Cleanup a pending request.
Definition: client.hpp:712
void configure_introspection(Clock::SharedPtr clock, const QoS &qos_service_event_pub, rcl_service_introspection_state_t introspection_state)
Configure client introspection.
Definition: client.hpp:797
std::shared_ptr< void > create_response() override
Create a shared pointer with the response type.
Definition: client.hpp:535
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:776
SharedFutureWithRequestAndRequestId async_send_request(SharedRequest request, CallbackT &&cb)
Send a request to the service server and schedule a callback in the executor.
Definition: client.hpp:686
SharedFutureAndRequestId async_send_request(SharedRequest request, CallbackT &&cb)
Send a request to the service server and schedule a callback in the executor.
Definition: client.hpp:655
void handle_response(std::shared_ptr< rmw_request_id_t > request_header, std::shared_ptr< void > response) override
Handle a server response.
Definition: client.hpp:558
FutureAndRequestId async_send_request(SharedRequest request)
Send a request to the service server.
Definition: client.hpp:620
size_t prune_pending_requests()
Clean all pending requests.
Definition: client.hpp:759
bool remove_pending_request(const SharedFutureAndRequestId &future)
Cleanup a pending request.
Definition: client.hpp:737
bool remove_pending_request(const SharedFutureWithRequestAndRequestId &future)
Cleanup a pending request.
Definition: client.hpp:749
Client(rclcpp::node_interfaces::NodeBaseInterface *node_base, rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph, const std::string &service_name, rcl_client_options_t &client_options)
Default constructor.
Definition: client.hpp:478
bool remove_pending_request(const FutureAndRequestId &future)
Cleanup a pending request.
Definition: client.hpp:725
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:102
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:466
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:87
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:318
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:408
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:417
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:428
SharedFuture share() noexcept
See std::future::share().
Definition: client.hpp:434
A convenient Client::SharedFuture and request id pair.
Definition: client.hpp:447
A convenient Client::SharedFutureWithRequest and request id pair.
Definition: client.hpp:461
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