15 #ifndef NAV2_ROS_COMMON__SERVICE_CLIENT_HPP_
16 #define NAV2_ROS_COMMON__SERVICE_CLIENT_HPP_
21 #include "rclcpp/rclcpp.hpp"
22 #include "nav2_ros_common/node_utils.hpp"
31 template<
typename ServiceT>
35 using SharedPtr = std::shared_ptr<nav2::ServiceClient<ServiceT>>;
36 using UniquePtr = std::unique_ptr<nav2::ServiceClient<ServiceT>>;
44 template<
typename NodeT>
46 const std::string & service_name,
47 const NodeT & provided_node,
bool use_internal_executor =
false)
48 : service_name_(service_name),
49 clock_(provided_node->get_clock()),
50 logger_(provided_node->get_logger()),
51 node_base_interface_(provided_node->get_node_base_interface()),
52 use_internal_executor_(use_internal_executor)
54 if (use_internal_executor) {
55 callback_group_ = provided_node->create_callback_group(
56 rclcpp::CallbackGroupType::MutuallyExclusive,
58 callback_group_executor_ = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
59 callback_group_executor_->add_callback_group(
61 provided_node->get_node_base_interface());
64 client_ = rclcpp::create_client<ServiceT>(
65 provided_node->get_node_base_interface(),
66 provided_node->get_node_graph_interface(),
67 provided_node->get_node_services_interface(),
69 rclcpp::ServicesQoS(),
72 nav2::setIntrospectionMode(
74 provided_node->get_node_parameters_interface(), clock_);
77 using RequestType =
typename ServiceT::Request;
78 using ResponseType =
typename ServiceT::Response;
86 typename ResponseType::SharedPtr
invoke(
87 typename RequestType::SharedPtr & request,
88 const std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1),
89 const std::chrono::nanoseconds wait_for_service_timeout = std::chrono::seconds(10))
91 auto now = clock_->now();
92 while (!client_->wait_for_service(std::chrono::seconds(1))) {
94 throw std::runtime_error(
95 service_name_ +
" service client: interrupted while waiting for service");
98 logger_,
"%s service client: waiting for service to appear...",
99 service_name_.c_str());
101 if (clock_->now() - now > wait_for_service_timeout) {
102 throw std::runtime_error(
103 service_name_ +
" service client: timed out waiting for service");
108 logger_,
"%s service client: send async request",
109 service_name_.c_str());
110 auto future_result = client_->async_send_request(request);
113 client_->remove_pending_request(future_result);
114 throw std::runtime_error(service_name_ +
" service client: async_send_request failed");
117 return future_result.get();
127 typename RequestType::SharedPtr & request,
128 typename ResponseType::SharedPtr & response,
129 const std::chrono::nanoseconds wait_for_service_timeout = std::chrono::seconds(10))
131 auto now = clock_->now();
132 while (!client_->wait_for_service(std::chrono::seconds(1))) {
134 throw std::runtime_error(
135 service_name_ +
" service client: interrupted while waiting for service");
138 logger_,
"%s service client: waiting for service to appear...",
139 service_name_.c_str());
141 if (clock_->now() - now > wait_for_service_timeout) {
142 throw std::runtime_error(
143 service_name_ +
" service client: timed out waiting for service");
148 logger_,
"%s service client: send async request",
149 service_name_.c_str());
150 auto future_result = client_->async_send_request(request);
153 client_->remove_pending_request(future_result);
157 response = future_result.get();
158 return response.get();
166 std::shared_future<typename ResponseType::SharedPtr>
async_call(
167 typename RequestType::SharedPtr & request)
169 auto future_result = client_->async_send_request(request);
170 return future_result.share();
179 template<
typename CallbackT>
180 void async_call(
typename RequestType::SharedPtr request, CallbackT && callback)
182 client_->async_send_request(request, callback);
190 bool wait_for_service(
const std::chrono::nanoseconds timeout = std::chrono::nanoseconds::max())
192 return client_->wait_for_service(timeout);
202 template<
typename FutureT>
204 const FutureT & future,
205 const std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1))
207 if (use_internal_executor_) {
208 return callback_group_executor_->spin_until_future_complete(future, timeout);
210 return rclcpp::spin_until_future_complete(node_base_interface_, future, timeout);
220 return service_name_;
229 callback_group_executor_->cancel();
234 std::string service_name_;
235 rclcpp::Clock::SharedPtr clock_;
236 rclcpp::Logger logger_{rclcpp::get_logger(
"nav2_ros_common")};
237 rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface_;
238 rclcpp::CallbackGroup::SharedPtr callback_group_{
nullptr};
239 rclcpp::executors::SingleThreadedExecutor::SharedPtr callback_group_executor_;
240 typename rclcpp::Client<ServiceT>::SharedPtr client_;
241 bool use_internal_executor_;
A simple wrapper on ROS2 services client.
std::shared_future< typename ResponseType::SharedPtr > async_call(typename RequestType::SharedPtr &request)
Asynchronously call the service.
void stop()
Stop any running spin operations on the internal executor.
rclcpp::FutureReturnCode spin_until_complete(const FutureT &future, const std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1))
Spins the executor until the provided future is complete or the timeout is reached.
ResponseType::SharedPtr invoke(typename RequestType::SharedPtr &request, const std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1), const std::chrono::nanoseconds wait_for_service_timeout=std::chrono::seconds(10))
Invoke the service and block until completed or timed out.
void async_call(typename RequestType::SharedPtr request, CallbackT &&callback)
Asynchronously call the service with a callback.
bool invoke(typename RequestType::SharedPtr &request, typename ResponseType::SharedPtr &response, const std::chrono::nanoseconds wait_for_service_timeout=std::chrono::seconds(10))
Invoke the service and block until completed.
ServiceClient(const std::string &service_name, const NodeT &provided_node, bool use_internal_executor=false)
A constructor.
bool wait_for_service(const std::chrono::nanoseconds timeout=std::chrono::nanoseconds::max())
Block until a service is available or timeout.
std::string getServiceName()
Gets the service name.