16 template <
typename ServiceType>
17 requires(rosidl_generator_traits::is_service<ServiceType>::value)
18 class [[nodiscard(
"This service call is only performed when `co_await`ed.")]]
ServiceAwaitable
20 using Client = rclcpp::Client<ServiceType>;
21 using Response = ServiceType::Response;
22 using Request = ServiceType::Request;
35 bool await_suspend(std::coroutine_handle<> continuation)
39 data_.continuation = continuation;
40 std::shared_ptr<Client> client = data_.client.lock();
41 if (client ==
nullptr || !client->service_is_ready())
43 data_.response = std::nullopt;
47 client->async_send_request(data_.request,
48 std::function([data_handle = DataHandle(data_)](std::shared_future<std::shared_ptr<Response>> future)
mutable {
49 auto data = data_handle.leak();
50 data->response = future.get();
51 (*data).response = future.get();
52 auto continuation = std::exchange(data->continuation,
nullptr);
53 internal::resume_coroutine(continuation);
58 std::optional<std::shared_ptr<Response>> await_resume()
60 return data_.response;
64 ServiceAwaitable(std::weak_ptr<Client> client, std::shared_ptr<Request> request)
66 .client = std::move(client),
67 .request = std::move(request),
74 std::weak_ptr<Client> client;
75 std::shared_ptr<Request> request;
76 std::optional<std::shared_ptr<Response>> response = std::nullopt;
77 std::coroutine_handle<> continuation =
nullptr;
79 std::atomic<size_t> ref_count = 0;
85 DataHandle(Data& data) : data_(&data)
87 size_t prev_ref_count = data_->ref_count.fetch_add(1);
90 assert(prev_ref_count == 0);
93 DataHandle(
const DataHandle& other) : data_(other.data_)
98 DataHandle& operator=(
const DataHandle& other)
100 decrement_ref_count_();
105 DataHandle(DataHandle&& other) : data_(other.data_)
110 DataHandle& operator=(DataHandle&& other)
112 decrement_ref_count_();
119 decrement_ref_count_();
122 Data& operator*()
const
128 Data* operator->()
const
137 return std::exchange(data_,
nullptr);
141 void decrement_ref_count_()
143 if (data_ ==
nullptr)
148 size_t prev_ref_count = data_->ref_count.fetch_sub(1);
150 if (prev_ref_count == 1)
154 auto continuation = data_->continuation;
156 if (continuation !=
nullptr)
159 continuation.destroy();
180 template <
class ServiceType>
182 : impl_(std::make_shared<
Impl>(node, address, qos, node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive)))
186 template <
class ServiceType>
191 template <
class ServiceType>
193 const rclcpp::CallbackGroup::SharedPtr& callback_group)
194 : impl_(std::make_shared<
Impl>(node, address, qos, callback_group))
198 template <
class ServiceType>
200 const rclcpp::CallbackGroup::SharedPtr& callback_group)
209 template <
class ServiceType>
210 std::optional<std::shared_ptr<typename ServiceType::Response>>
215 RCLCPP_ERROR(rclcpp::get_logger(
"ServiceClientHandler"),
"Not initialized, cannot use callSync()!");
218 return impl_->callSync(request);
225 template <
class ServiceType>
226 std::optional<std::shared_future<std::shared_ptr<typename ServiceType::Response>>>
231 RCLCPP_ERROR(rclcpp::get_logger(
"ServiceClientHandler"),
"Not initialized, cannot use callAsync()!");
234 return impl_->callAsync(request);
239 template <
class ServiceType>
245 RCLCPP_ERROR(rclcpp::get_logger(
"ServiceClientHandler"),
"Not initialized, cannot use callAwaitable()!");
246 co_return std::nullopt;
249 co_return co_await impl_->callAwaitable(request);
254 template <
class ServiceType>
259 RCLCPP_ERROR(rclcpp::get_logger(
"ServiceClientHandler"),
"Not initialized, cannot use getServiceName()!");
262 return impl_->getServiceName();
269 template <
class ServiceType>
270 template <
typename RepT,
typename RatioT>
275 RCLCPP_ERROR(rclcpp::get_logger(
"ServiceClientHandler"),
"Not initialized, cannot use waitForService()!");
278 return impl_->waitForService(timeout);
284 template <
class ServiceType>
289 RCLCPP_ERROR(rclcpp::get_logger(
"ServiceClientHandler"),
"Not initialized, cannot use isServiceReady()!");
292 return impl_->isServiceReady();
306 template <
class ServiceType>
319 Impl(rclcpp::Node::SharedPtr& node,
const std::string& address,
const rclcpp::QoS& qos,
const rclcpp::CallbackGroup::SharedPtr& callback_group)
320 : callback_group_(callback_group), service_client_(node->create_client<ServiceType>(address, qos, callback_group))
322 RCLCPP_INFO_STREAM(node->get_logger(),
"Created client '" << address <<
"' -> '" << service_client_->get_service_name() <<
"'");
332 std::optional<std::shared_ptr<typename ServiceType::Response>>
callSync(
const std::shared_ptr<typename ServiceType::Request>& request)
335 if (!service_client_->service_is_ready())
339 const auto future_msg = service_client_->async_send_request(request).future.share();
343 if (!future_msg.valid())
347 return future_msg.get();
357 std::optional<std::shared_future<std::shared_ptr<typename ServiceType::Response>>>
callAsync(
const std::shared_ptr<typename ServiceType::Request>& request)
360 if (!service_client_->service_is_ready())
363 const auto future = service_client_->async_send_request(request).future.share();
385 return service_client_->get_service_name();
395 template <
typename RepT =
int64_t,
typename RatioT = std::milli>
398 return service_client_->wait_for_service(timeout);
408 return service_client_->service_is_ready();
412 rclcpp::CallbackGroup::SharedPtr callback_group_;
413 typename rclcpp::Client<ServiceType>::SharedPtr service_client_;
implementation of the service client handler
Definition service_client_handler.hpp:308
std::optional< std::shared_future< std::shared_ptr< typename ServiceType::Response > > > callAsync(const std::shared_ptr< typename ServiceType::Request > &request)
asynchronous service call
Definition service_client_handler.hpp:357
std::optional< std::shared_ptr< typename ServiceType::Response > > callSync(const std::shared_ptr< typename ServiceType::Request > &request)
"classic" synchronous service call
Definition service_client_handler.hpp:332
Impl(rclcpp::Node::SharedPtr &node, const std::string &address, const rclcpp::QoS &qos, const rclcpp::CallbackGroup::SharedPtr &callback_group)
constructor
Definition service_client_handler.hpp:319
std::string getServiceName() const
Returns the name of the service this client connects to.
Definition service_client_handler.hpp:383
bool waitForService(std::chrono::duration< RepT, RatioT > timeout)
Waits for the service to be available.
Definition service_client_handler.hpp:396
bool isServiceReady() const
Checks if the service is available.
Definition service_client_handler.hpp:406
user wrapper of the service client handler implementation
Definition service_client_handler.h:35
ServiceClientHandler()
Default constructor to avoid having to use pointers.
Definition service_client_handler.hpp:187
std::optional< std::shared_ptr< typename ServiceType::Response > > callSync(const std::shared_ptr< typename ServiceType::Request > &request)
Synchronous (blocking) call of the service.
Definition service_client_handler.hpp:211
std::string getServiceName() const
Returns the name of the service this client connects to.
Definition service_client_handler.hpp:255
bool waitForService(std::chrono::duration< RepT, RatioT > timeout=std::chrono::seconds(1))
Waits for the service to be available.
Definition service_client_handler.hpp:271
std::optional< std::shared_future< std::shared_ptr< typename ServiceType::Response > > > callAsync(const std::shared_ptr< typename ServiceType::Request > &request)
Asynchronous (non-blocking) call of the service.
Definition service_client_handler.hpp:227
bool isServiceReady() const
Checks if the service is available.
Definition service_client_handler.hpp:285
Task< std::optional< std::shared_ptr< typename ServiceType::Response > > > callAwaitable(std::shared_ptr< typename ServiceType::Request > request)
Awaitable call of the service.
Definition service_client_handler.hpp:241
Task type for creating coroutines.
Definition task.hpp:313
Definition service_client_handler.hpp:19
All mrs_lib functions, classes, variables and definitions are contained in this namespace.
Definition attitude_converter.h:24
Defines ServiceClientHandler and related convenience classes for upgrading the ROS service client.