15 #ifndef NAV2_ROS_COMMON__SERVICE_CLIENT_HPP_
16 #define NAV2_ROS_COMMON__SERVICE_CLIENT_HPP_
21 #include "rclcpp/callback_group.hpp"
22 #include "rclcpp/client.hpp"
23 #include "rclcpp/clock.hpp"
24 #include "rclcpp/create_client.hpp"
25 #include "rclcpp/executors.hpp"
26 #include "rclcpp/executors/single_threaded_executor.hpp"
27 #include "rclcpp/future_return_code.hpp"
28 #include "rclcpp/logger.hpp"
29 #include "rclcpp/logging.hpp"
30 #include "rclcpp/node_interfaces/node_base_interface.hpp"
31 #include "rclcpp/qos.hpp"
32 #include "rclcpp/utilities.hpp"
33 #include "nav2_ros_common/node_utils.hpp"
42 template<
typename ServiceT>
46 using SharedPtr = std::shared_ptr<nav2::ServiceClient<ServiceT>>;
47 using UniquePtr = std::unique_ptr<nav2::ServiceClient<ServiceT>>;
55 template<
typename NodeT>
57 const std::string & service_name,
58 const NodeT & provided_node,
bool use_internal_executor =
false)
59 : service_name_(service_name),
60 clock_(provided_node->get_clock()),
61 logger_(provided_node->get_logger()),
62 node_base_interface_(provided_node->get_node_base_interface()),
63 use_internal_executor_(use_internal_executor)
65 if (use_internal_executor) {
66 callback_group_ = provided_node->create_callback_group(
67 rclcpp::CallbackGroupType::MutuallyExclusive,
69 callback_group_executor_ = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
70 callback_group_executor_->add_callback_group(
72 provided_node->get_node_base_interface());
75 client_ = rclcpp::create_client<ServiceT>(
76 provided_node->get_node_base_interface(),
77 provided_node->get_node_graph_interface(),
78 provided_node->get_node_services_interface(),
80 rclcpp::ServicesQoS(),
83 nav2::setIntrospectionMode(
85 provided_node->get_node_parameters_interface(), clock_);
88 using RequestType =
typename ServiceT::Request;
89 using ResponseType =
typename ServiceT::Response;
97 typename ResponseType::SharedPtr
invoke(
98 typename RequestType::SharedPtr & request,
99 const std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1),
100 const std::chrono::nanoseconds wait_for_service_timeout = std::chrono::seconds(10))
102 auto now = clock_->now();
103 while (!client_->wait_for_service(std::chrono::seconds(1))) {
105 throw std::runtime_error(
106 service_name_ +
" service client: interrupted while waiting for service");
109 logger_,
"%s service client: waiting for service to appear...",
110 service_name_.c_str());
112 if (clock_->now() - now > wait_for_service_timeout) {
113 throw std::runtime_error(
114 service_name_ +
" service client: timed out waiting for service");
119 logger_,
"%s service client: send async request",
120 service_name_.c_str());
121 auto future_result = client_->async_send_request(request);
124 client_->remove_pending_request(future_result);
125 throw std::runtime_error(service_name_ +
" service client: async_send_request failed");
128 return future_result.get();
138 typename RequestType::SharedPtr & request,
139 typename ResponseType::SharedPtr & response,
140 const std::chrono::nanoseconds wait_for_service_timeout = std::chrono::seconds(10))
142 auto now = clock_->now();
143 while (!client_->wait_for_service(std::chrono::seconds(1))) {
145 throw std::runtime_error(
146 service_name_ +
" service client: interrupted while waiting for service");
149 logger_,
"%s service client: waiting for service to appear...",
150 service_name_.c_str());
152 if (clock_->now() - now > wait_for_service_timeout) {
153 throw std::runtime_error(
154 service_name_ +
" service client: timed out waiting for service");
159 logger_,
"%s service client: send async request",
160 service_name_.c_str());
161 auto future_result = client_->async_send_request(request);
164 client_->remove_pending_request(future_result);
168 response = future_result.get();
169 return response.get();
177 std::shared_future<typename ResponseType::SharedPtr>
async_call(
178 typename RequestType::SharedPtr & request)
180 auto future_result = client_->async_send_request(request);
181 return future_result.share();
190 template<
typename CallbackT>
191 void async_call(
typename RequestType::SharedPtr request, CallbackT && callback)
193 client_->async_send_request(request, callback);
201 bool wait_for_service(
const std::chrono::nanoseconds timeout = std::chrono::nanoseconds::max())
203 return client_->wait_for_service(timeout);
213 template<
typename FutureT>
215 const FutureT & future,
216 const std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1))
218 if (use_internal_executor_) {
219 return callback_group_executor_->spin_until_future_complete(future, timeout);
221 return rclcpp::spin_until_future_complete(node_base_interface_, future, timeout);
231 return service_name_;
240 callback_group_executor_->cancel();
245 std::string service_name_;
246 rclcpp::Clock::SharedPtr clock_;
247 rclcpp::Logger logger_{rclcpp::get_logger(
"nav2_ros_common")};
248 rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface_;
249 rclcpp::CallbackGroup::SharedPtr callback_group_{
nullptr};
250 rclcpp::executors::SingleThreadedExecutor::SharedPtr callback_group_executor_;
251 typename rclcpp::Client<ServiceT>::SharedPtr client_;
252 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.