15 #include "rclcpp/client.hpp"
30 #include "rmw/impl/cpp/demangle.hpp"
32 #include "rclcpp/detail/cpp_callback_trampoline.hpp"
33 #include "rclcpp/exceptions.hpp"
34 #include "rclcpp/node_interfaces/node_base_interface.hpp"
35 #include "rclcpp/node_interfaces/node_graph_interface.hpp"
36 #include "rclcpp/qos.hpp"
37 #include "rclcpp/utilities.hpp"
38 #include "rclcpp/logging.hpp"
42 using rclcpp::exceptions::throw_from_rcl_error;
44 ClientBase::ClientBase(
46 const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr & node_graph)
47 : node_graph_(node_graph),
48 node_handle_(node_base->get_shared_rcl_node_handle()),
49 context_(node_base->get_context()),
52 std::weak_ptr<rcl_node_t> weak_node_handle(node_handle_);
56 new_rcl_client, [weak_node_handle](
rcl_client_t * client)
58 auto handle = weak_node_handle.lock();
62 rclcpp::get_node_logger(handle.get()).get_child(
"rclcpp"),
63 "Error in destruction of rcl client handle: %s", rcl_get_error_string().str);
69 "Error in destruction of rcl client handle: "
70 "the Node Handle was destructed too early. You will leak memory");
77 ClientBase::take_type_erased_response(
void * response_out, rmw_request_id_t & request_header_out)
86 rclcpp::exceptions::throw_from_rcl_error(ret);
97 std::shared_ptr<rcl_client_t>
100 return client_handle_;
103 std::shared_ptr<const rcl_client_t>
106 return client_handle_;
114 this->get_rcl_node_handle(),
118 const rcl_node_t * node_handle = this->get_rcl_node_handle();
125 throw_from_rcl_error(ret,
"rcl_service_server_is_available failed");
131 ClientBase::wait_for_service_nanoseconds(std::chrono::nanoseconds timeout)
133 auto start = std::chrono::steady_clock::now();
134 auto node_ptr = node_graph_.lock();
142 if (timeout == std::chrono::nanoseconds(0)) {
147 auto event = node_ptr->get_graph_event();
150 std::chrono::nanoseconds time_to_wait =
151 timeout > std::chrono::nanoseconds(0) ?
152 timeout - (std::chrono::steady_clock::now() - start) :
153 std::chrono::nanoseconds::max();
154 if (time_to_wait < std::chrono::nanoseconds(0)) {
157 time_to_wait = std::chrono::nanoseconds(0);
170 node_ptr->wait_for_graph_change(
171 event, std::min(time_to_wait, std::chrono::nanoseconds(
RCL_MS_TO_NS(100))));
174 event->check_and_clear();
179 if (timeout > std::chrono::nanoseconds(0)) {
180 time_to_wait = timeout - (std::chrono::steady_clock::now() - start);
183 }
while (time_to_wait > std::chrono::nanoseconds(0));
188 ClientBase::get_rcl_node_handle()
190 return node_handle_.get();
194 ClientBase::get_rcl_node_handle()
const
196 return node_handle_.get();
202 return in_use_by_wait_set_.exchange(in_use_state);
208 const rmw_qos_profile_t * qos =
212 std::string(
"failed to get client's request publisher qos settings: ") +
213 rcl_get_error_string().str;
215 throw std::runtime_error(msg);
221 return request_publisher_qos;
227 const rmw_qos_profile_t * qos =
231 std::string(
"failed to get client's response subscription qos settings: ") +
232 rcl_get_error_string().str;
234 throw std::runtime_error(msg);
240 return response_subscription_qos;
247 client_handle_.get(),
252 throw_from_rcl_error(ret,
"failed to set the on new response callback for client");
260 throw std::invalid_argument(
261 "The callback passed to set_on_new_response_callback "
266 [callback,
this](
size_t number_of_responses) {
268 callback(number_of_responses);
269 }
catch (
const std::exception & exception) {
272 "rclcpp::ClientBase@" <<
this <<
273 " caught " << rmw::impl::cpp::demangle(exception) <<
274 " exception in user-provided callback for the 'on new response' callback: " <<
279 "rclcpp::ClientBase@" <<
this <<
280 " caught unhandled exception in user-provided callback " <<
281 "for the 'on new response' callback");
285 std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
291 rclcpp::detail::cpp_callback_trampoline<decltype(new_callback),
const void *,
size_t>,
292 static_cast<const void *
>(&new_callback));
295 on_new_response_callback_ = new_callback;
299 rclcpp::detail::cpp_callback_trampoline<
300 decltype(on_new_response_callback_),
const void *,
size_t>,
301 static_cast<const void *
>(&on_new_response_callback_));
307 std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
308 if (on_new_response_callback_) {
310 on_new_response_callback_ =
nullptr;
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.
RCLCPP_PUBLIC rclcpp::QoS get_request_publisher_actual_qos() const
Get the actual request publsher QoS settings, after the defaults have been determined.
RCLCPP_PUBLIC std::shared_ptr< rcl_client_t > get_client_handle()
Return the rcl_client_t client handle in a std::shared_ptr.
RCLCPP_PUBLIC 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.
RCLCPP_PUBLIC void clear_on_new_response_callback()
Unset the callback registered for new responses, if any.
RCLCPP_PUBLIC const char * get_service_name() const
Return the name of the service.
RCLCPP_PUBLIC rclcpp::QoS get_response_subscription_actual_qos() const
Get the actual response subscription QoS settings, after the defaults have been determined.
RCLCPP_PUBLIC bool service_is_ready() const
Return if the service is ready.
Encapsulation of Quality of Service settings.
Thrown when a method is trying to use a node, but it is invalid.
Pure virtual interface class for the NodeBase part of the Node API.
RCL_PUBLIC RCL_WARN_UNUSED const rmw_qos_profile_t * rcl_client_request_publisher_get_actual_qos(const rcl_client_t *client)
Get the actual qos settings of the client's request publisher.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_client_get_service_name(const rcl_client_t *client)
Get the name of the service that this client will request a response from.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_client_fini(rcl_client_t *client, rcl_node_t *node)
Finalize a rcl_client_t.
RCL_PUBLIC RCL_WARN_UNUSED rcl_client_t rcl_get_zero_initialized_client(void)
Return a rcl_client_t struct with members set to NULL.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take_response(const rcl_client_t *client, rmw_request_id_t *request_header, void *ros_response)
backwards compatibility function that takes a rmw_request_id_t only
struct rcl_client_s rcl_client_t
Structure which encapsulates a ROS Client.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_client_set_on_new_response_callback(const rcl_client_t *client, rcl_event_callback_t callback, const void *user_data)
Set the on new response callback function for the client.
RCL_PUBLIC RCL_WARN_UNUSED const rmw_qos_profile_t * rcl_client_response_subscription_get_actual_qos(const rcl_client_t *client)
Get the actual qos settings of the client's response subscription.
RCL_PUBLIC RCL_WARN_UNUSED bool rcl_context_is_valid(const rcl_context_t *context)
Return true if the given context is currently valid, otherwise false.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_service_server_is_available(const rcl_node_t *node, const rcl_client_t *client, bool *is_available)
Check if a service server is available for the given service client.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC bool ok(const rclcpp::Context::SharedPtr &context=rclcpp::contexts::get_global_default_context())
Check rclcpp's status.
RCLCPP_PUBLIC Logger get_node_logger(const rcl_node_t *node)
Return a named logger using an rcl_node_t.
RCLCPP_PUBLIC Logger get_logger(const std::string &name)
Return a named logger.
Structure which encapsulates a ROS Client.
Structure which encapsulates a ROS Node.
rcl_context_t * context
Context associated with this node.
static QoSInitialization from_rmw(const rmw_qos_profile_t &rmw_qos)
Create a QoSInitialization from an existing rmw_qos_profile_t, using its history and depth.
#define RCL_MS_TO_NS
Convenience macro to convert milliseconds to nanoseconds.
#define RCL_RET_CLIENT_TAKE_FAILED
Failed to take a response from the client return code.
#define RCL_RET_OK
Success return code.
#define RCL_RET_NODE_INVALID
Invalid rcl_node_t given return code.
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.