|
nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
|
#include <client.hpp>
Public Types | |
| using | ConstSharedPtr = ::rclcpp::ClientHandle<S> |
| using | RequestType = typename S::Request |
| using | ResponseType = typename S::Response |
| using | SharedPtr = ::rclcpp::ClientHandle<S> |
| using | TypedResponseFn = void (*)(const ResponseType& response) |
| using | UniquePtr = ::rclcpp::ClientHandle<S> |
| rclcpp::Client<S>::UniquePtr — see SharedPtr. | |
Public Member Functions | |
| Result | async_send_request (const RequestType &req) |
| Client () | |
| Client (Client &&other) | |
| ::rclcpp::QoS | get_request_publisher_actual_qos () const |
| ::rclcpp::QoS | get_response_subscription_actual_qos () const |
| const char * | get_service_name () const |
| size_t | handle_id () const |
| Executor arena slot for the registration; SIZE_MAX until registered. | |
| bool | is_valid () const |
| Check if the client was registered. | |
| Client & | operator= (Client &&other) |
| ::rclcpp::ResultOf< bool > | service_is_ready () const |
| template<typename T = void> | |
| Result | wait_for_service () |
| Result | wait_for_service (uint32_t timeout_ms) |
| ~Client () | |
Friends | |
| class | ::rclcpp::Node |
| using Client< S >::ConstSharedPtr = ::rclcpp::ClientHandle<S> |
rclcpp::Client<S>::ConstSharedPtr — see SharedPtr. The same handle: async_send_request is const on it (the handle is two words the caller owns; the mutation is the arena's), so there is no mutable/const distinction to draw.
| using Client< S >::RequestType = typename S::Request |
| using Client< S >::ResponseType = typename S::Response |
| using Client< S >::SharedPtr = ::rclcpp::ClientHandle<S> |
rclcpp::Client<S>::SharedPtr — phase-456 W9.
rclcpp::Client<S>::SharedPtr member_; is how ported source declares a client member, so this alias must exist on every target — which std::shared_ptr does not.
IT IS NOT A POINTER TO A Client<S>. A registered client is the arena's; what this names is rclcpp::ClientHandle<S> — two words, copyable, carrying exactly the one verb the census says a dispatch client is asked for. See client_handle.hpp.
| using Client< S >::TypedResponseFn = void (*)(const ResponseType& response) |
Phase 189.M3.3.f — typed response-handler signature for the callback-style client (rclcpp async dispatch). The handler runs during spin_once when a reply arrives for a request sent via async_send_request.
phase-456 W3 deleted the TypedResponseFnWithCtx sibling, for the reason stated on Service<S>::TypedServiceFn: the SFINAE guard on Node::create_client admits only a void(*)(const Response&), so no overload could set it and the branch reading it was unreachable.
| using Client< S >::UniquePtr = ::rclcpp::ClientHandle<S> |
rclcpp::Client<S>::UniquePtr — see SharedPtr.
Destructor — there is nothing to release.
The executor arena owns the client, the reply buffer and the handler. This destructor deliberately does not release them: it clears this object's own bookkeeping, and the registration lives until its node is destroyed or a ClientHandle releases it (cli_.reset(), issue 1667). Until phase-456 W9 the same destructor also freed a FUTURE-style client, behind an if (initialized_ && !callback_mode_); that half moved to rclcpp::PollClient<S>, where the condition is unconditional.
|
inline |
Default constructor – creates an unregistered service client. Use Node::create_client() to register one.
|
inline |
Phase 189.M3.3.f — THE ONE VERB. Send a request; the reply is delivered to the registered response handler during spin_once (no Future). Returns immediately after sending.
UPSTREAM PARITY: upstream's async_send_request(req) returns a std::shared_future<Response::SharedPtr> and its two-argument form takes a callback per REQUEST. Ours returns a Result and the handler is bound once, at registration — ledgered at cpp:Client::async_send_request, divergence / adopt. What changed in phase-456 W9 is only that the callback_mode_ check is gone with the flag: every rclcpp::Client<S> is a dispatch client now, and the future-style road is rclcpp::PollClient<S>.
|
inline |
The QoS the backend GRANTED this client's REQUEST endpoint — the publisher that sends calls. Issue 1437.
rclcpp::Client::get_request_publisher_actual_qos. ONE create_client builds TWO endpoints that negotiate against DIFFERENT peers, so this and get_response_subscription_actual_qos are two answers and neither stands for the other.
A policy the backend cannot report is an ABSENCE (ReliabilityPolicy::Unknown and friends), never the request echoed back — see Publisher::get_actual_qos.
phase-456 W9 — BOTH HALVES ANSWER, and this accessor is the WORKED EXAMPLE the two later closures copied. Issue 1437 gave a dispatch client executor_ beside handle_id_, and nros_cpp_service_client_get_actual_qos serves both roads by construction — storage for the owner, (executor, handle_id) for the arena — so the upstream no-argument spelling was reachable here with no weakening and no ledger row was ever owed.
W9 had to leave get_actual_qos off the dispatch Subscription<M> for want of exactly that: the type held only sched_handle_id_. Both ends of that gap are closed now, each by taking this shape rather than by changing a signature — the subscription carries its executor since phase-467 (2026-09-25, its ledger row deleted), and this class's own service_is_ready / wait_for_service since 2026-09-28.
|
inline |
The QoS the backend GRANTED this client's RESPONSE endpoint — the subscription that receives replies. Issue 1437; see get_request_publisher_actual_qos.
|
inline |
Read back the service name this client was created on — phase-444.
rclcpp's ClientBase::get_service_name, and the client half of "four entity families, one accessor" (ledger rows cpp:Client::get_service_name and cpp:Service::get_service_name): Publisher and Subscription have had get_topic_name() all along, both action tiers gained get_action_name() in phase-417 W4.b, and the service pair was the one family with no accessor in any C++ tier.
The name lives C++-side in service_name_, for the reason ActionServer::get_action_name states: the runtime does NOT own it. nros_cpp_service_client_register takes service_name and drops it, so there is nothing FFI-side to hand back, and a borrowed const char* was rejected because create_client takes a pointer a hosted caller may well have obtained from a temporary.
Returns "" (never NULL) on an unregistered client, matching Publisher::get_topic_name and both action tiers.
phase-456 W9 split this class in two and the method answers on BOTH halves, unchanged — the same shape Service::get_service_name took under W5. Each half keeps its own service_name_, because the copy is made at create from the argument the caller passed and neither owner can recover it afterwards.
|
inline |
Executor arena slot for the registration; SIZE_MAX until registered.
|
inline |
Check if the client was registered.
|
inline |
Is a matching service server visible? — rclcpp::ClientBase:: service_is_ready, no arguments, as upstream's is.
Never spins the executor, so it is safe inside a callback. The tri-state is the divergence from upstream's bare bool and is ledgered at cpp:Client::service_is_ready: RFC-0018 forbids exceptions, so a failed probe and a successful "no" must be distinguishable by return value.
This is the gap phase-456 W9 RECORDED, closed 2026-09-28. The split left this verb on the future-style half alone, because nros_cpp_service_client_server_available read the RmwServiceClient in CALLER storage and a dispatch client has none — so a porter holding a Client<S>::SharedPtr could not ask at all. The fix is the FFI's, not the signature's: that entry point now takes (storage, executor, handle_id), the shape nros_cpp_service_client_get_actual_qos has had since issue 1437, and this class already holds {executor_, handle_id_}. Inventing an Executor& parameter here was refused — a method that exists to adopt the upstream spelling cannot close a gap by leaving it.
REFUSED — wait_for_service() with no budget. phase-417 stage 3.
A member template rather than = delete for the C++14 reason given on Executor::spin_once(): a deleted function carries no message.
|
inline |
Block until a matching service server is discoverable — rclcpp::ClientBase::wait_for_service.
Spins the executor cooperatively while probing, so do NOT call it from inside a callback; use service_is_ready there. Returns ok when the server is visible, Timeout when the budget elapses, Unsupported at once when the backend cannot know (XRCE — issue 1686; a caller that may send blind proceeds).
The budget is REQUIRED — phase-417 stage 3, and the reason is RFC-0021 rather than convenience: this call drives a single-threaded executor, so a wait that never returns starves every other entity, and uint32_t has no value to port upstream's -1 to. The no-argument form is a compile error carrying NROS_RCLCPP_REFUSE_UNBOUNDED_WAIT, exactly as it is on rclcpp::PollClient<S> and rclcpp_action::Client<A> — one concept, now three sites, each with its own expected-failure TU.
Closed 2026-09-28 with service_is_ready; that method's note carries why the remedy was the FFI's argument list and not this one.
|
friend |