|
nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
|
#include <server.hpp>
Public Types | |
| using | FeedbackType = typename A::Feedback |
| using | GoalType = typename A::Goal |
| using | ResultType = typename A::Result |
| using | TypedAcceptedFn = void(*)(const uint8_t uuid[16]) |
| User-facing typed accepted-goal callback signature (issue 0796). | |
| using | TypedAcceptedFnWithCtx = void(*)(const uint8_t uuid[16], void *ctx) |
| User-facing typed accepted-goal callback signature with user context. | |
| using | TypedCancelFn = ::rclcpp_action::CancelResponse(*)(const uint8_t uuid[16]) |
| User-facing typed cancel callback signature. | |
| using | TypedCancelFnWithCtx = ::rclcpp_action::CancelResponse(*)(const uint8_t uuid[16], void *ctx) |
| User-facing typed cancel callback signature with user context (Phase 84.G9). | |
| using | TypedGoalFn = ::rclcpp_action::GoalResponse(*)(const uint8_t uuid[16], const GoalType &goal) |
| User-facing typed goal callback signature. | |
| using | TypedGoalFnWithCtx = ::rclcpp_action::GoalResponse(*)(const uint8_t uuid[16], const GoalType &goal, void *ctx) |
| User-facing typed goal callback signature with user context (Phase 84.G9). | |
| using | TypedVisitorFn = void(*)(const uint8_t uuid[16], ::rclcpp_action::GoalStatus status) |
User-facing visitor signature for for_each_active_goal. | |
Friends | |
| class | ::rclcpp::Node |
Typed action server for a ROS 2 action.
Mirrors upstream's rclcpp_action::Server<A> with a callback-based API. The action type A must provide nested Goal, Result, and Feedback types with TYPE_NAME, TYPE_HASH, SERIALIZED_SIZE_MAX, ffi_serialize(), and ffi_deserialize().
Usage:
Callbacks must be stateless (empty-capture lambdas or plain function pointers). This is a freestanding C++14 library without std::function, so per-instance closure storage is not available.
What upstream's Server<A> has and this one does not (ADOPT-BOUNDED):
Waitable: no execute / is_ready / set_on_ready_callback / clear_on_ready_callback. RFC-0002's executor drives the server directly through the RMW vtable; there is no wait set to join.SharedPtr: there is no rclcpp_action::create_server. The caller owns the object and node.create_action_server(srv, name) initialises it in place (no allocator).ServerGoalHandle: the accepted callback receives the goal id, and feedback and termination are calls on THIS server keyed by that id (publish_feedback, succeed, abort, canceled). Goals live in a static arena the server owns, not in a handle handed to the application. Each missing member is a compile error (no member named ...). User-facing typed accepted-goal callback signature (issue 0796).
| using rclcpp_action::Server< A >::TypedAcceptedFnWithCtx = void (*)(const uint8_t uuid[16], void* ctx) |
User-facing typed accepted-goal callback signature with user context.
| using rclcpp_action::Server< A >::TypedCancelFn = ::rclcpp_action::CancelResponse (*)(const uint8_t uuid[16]) |
User-facing typed cancel callback signature.
| using rclcpp_action::Server< A >::TypedCancelFnWithCtx = ::rclcpp_action::CancelResponse (*)(const uint8_t uuid[16], void* ctx) |
User-facing typed cancel callback signature with user context (Phase 84.G9).
| using rclcpp_action::Server< A >::TypedGoalFn = ::rclcpp_action::GoalResponse (*)(const uint8_t uuid[16], const GoalType& goal) |
User-facing typed goal callback signature.
| using rclcpp_action::Server< A >::TypedGoalFnWithCtx = ::rclcpp_action::GoalResponse (*)(const uint8_t uuid[16], const GoalType& goal, void* ctx) |
User-facing typed goal callback signature with user context (Phase 84.G9).
| using rclcpp_action::Server< A >::TypedVisitorFn = void (*)(const uint8_t uuid[16], ::rclcpp_action::GoalStatus status) |
User-facing visitor signature for for_each_active_goal.
|
inline |
Destructor — RELEASES the arena entry (issue 1496).
The action's five RMW entities (three service servers, the feedback and status publishers), its goal table and its result slab live in an ActionServerRawArenaEntry in the executor arena, and the entry's callback context is storage_. nros_cpp_action_server_detach drops that entry in place — the entities are destroyed, so the action leaves the graph and no late send_goal can dispatch into this storage — frees its callback slot, and returns its arena bytes to the executor's free list for the next registration that fits. A program that creates and destroys servers in a loop therefore does not exhaust NROS_EXECUTOR_MAX_CBS or the arena. (nros_cpp_action_server_destroy after it is a drop_in_place over Copy fields and runs no destructor itself; the release is the detach call's.)
|
inline |
Default constructor — creates an uninitialized action server. Use Node::create_action_server() to initialize.
|
inline |
|
inline |
Terminate goal_id as ABORTED. See succeed.
Upstream's is goal_handle->abort(std::shared_ptr<Result>); this is on the server, keyed by goal id, result by const reference — no goal handle.
|
inline |
|
inline |
Terminate goal_id as CANCELED. See succeed.
Spelled canceled — rclcpp_action's and C's spelling — not cancel. Rust used to disagree here and was renamed to match in the same work item.
Upstream's is goal_handle->canceled(std::shared_ptr<Result>); this is on the server, keyed by goal id, result by const reference — no goal handle.
|
inline |
complete_goal taking a GoalUUID value (phase-417 W4.b).
|
inline |
complete_goal taking a GoalUUID value (phase-417 W4.b).
|
inline |
Terminate a goal with a result and the status it terminated in.
Issue 0796 — status used to be hardcoded Succeeded inside the shim, so a server that aborted a goal reported success to the client. The parameter order matches PollingActionServer::complete_goal and the C API's rclc_polling_action_server_complete_goal_raw, so the three surfaces agree; Succeeded is defaulted because it is the common case and because that keeps existing two-argument calls compiling.
rclcpp_action has no complete_goal: a goal ends through its ServerGoalHandle (succeed / abort / canceled). Here the terminal status is an argument and the goal is named by its id, because there is no goal handle; succeed / abort / canceled below are forwarders onto this.
|
inline |
Terminate a goal as SUCCEEDED. Equivalent to complete_goal(goal_id, GoalStatus::Succeeded, result).
|
inline |
Iterate over every currently live goal and invoke f(uuid, status).
F must be a stateless callable convertible to void (*)(const uint8_t uuid[16], GoalStatus status). The arena never stores the original goal CDR payload, so only identity + status are forwarded — if you need the goal bytes, stash them in a {uuid → state} table from inside set_goal_callback. F must be a stateless callable convertible to void(*)(const uint8_t[16], GoalStatus). phase-456 W3b — the visitor rides the void* ctx this FFI already has, carried by value through rclcpp::detail::fn_to_context, instead of a TypedVisitorFn user_visitor_fn_ member set on entry and cleared on exit. That member was the only piece of per-instance state on this class that was nullptr everywhere except inside one function body, and the move constructor and move assignment each copied it — bookkeeping for a value known to be null at every point a move can observe it.
The lifetime argument is stronger here than the one W3 made for a service handler: this FFI call is SYNCHRONOUS, so the context does not outlive the full-expression that built it. Nothing of the caller's is referenced after the call returns, which is also why the visitor needs no clearing step — there is nowhere for it to be left behind.
Read back the action name this server was created on — phase-417 W4.b.
The callback tier's half of "four surfaces, one accessor" (ledger row c:action_server_get_action_name): PollingActionServer and PollingActionClient have had get_action_name() all along, C now has rcl_action_server_get_action_name, and this tier — the one a ported rclcpp_action program uses — had a char action_name_[256] field populated at construction and read by nothing.
The field is back, and it is now READ. The earlier removal was right about dead state and the note it left ("if an accessor is wanted, it
belongs on an FFI getter over the name the runtime already owns") does not apply: the runtime does NOT own it here. CppActionServer keeps a raw arena handle and nros_cpp_action_server_create takes _action_name and drops it, so there is nothing FFI-side to hand back. Subscription::get_topic_name pays the same 256 bytes for the same reason, and a borrowed const char* was rejected — create_action_server takes a const char* that a hosted caller may well have obtained from a temporary.
Returns "" (never NULL) on an uninitialised server, matching Subscription::get_topic_name and the two polling tiers.
|
inline |
goal_exists taking a GoalUUID value.
|
inline |
Is goal_id a goal this server still knows about? — phase-417 W4.b.
rcl's rcl_action_server_goal_exists, and C's rclc_action_server_goal_exists. TRUE while the goal is ACTIVE and while its completed result is still retained for a later get_result, which is rcl's own window. A predicate rather than a Result, because the ported idiom is a guard.
|
inline |
Check if the action server is initialized and valid.
|
inline |
publish_feedback taking a GoalUUID value (phase-417 W4.b).
|
inline |
Publish feedback for an active goal.
Upstream spells it goal_handle->publish_feedback(std::shared_ptr<Feedback>). There is no goal handle here: the call is on the SERVER, keyed by goal id, and takes the feedback by const reference (no shared_ptr, no allocator).
| goal_id | 16-byte goal UUID from the goal callback. |
| feedback | Feedback to publish. |
|
inline |
Register a callback invoked once per ACCEPTED goal (issue 0796).
Fires after the accept reply has reached the client, for GoalResponse::ACCEPT_AND_EXECUTE and GoalResponse::ACCEPT_AND_DEFER alike. This is where a deferred goal starts executing: the goal callback answers accept/reject and must return promptly, so it is the wrong place to begin work.
Upstream's handle_accepted receives an owning std::shared_ptr<ServerGoalHandle>; this callback receives the 16-byte goal id instead, and the goal is driven through this server (publish_feedback, succeed, ...) because goals live in the server's static arena.
Mirrors C's rclc_accepted_callback_t (passed at rclc_action_server_init_with_callbacks) and Rust's third argument to create_action_server_with_callbacks(goal, cancel, accepted). Without it a C++ user who returned ACCEPT_AND_DEFER was never told the goal had been accepted.
F must be a stateless callable convertible to TypedAcceptedFn.
|
inline |
Register an accepted-goal callback with a user context pointer.
Mirrors set_goal_callback_with_ctx. Mutually exclusive with set_accepted_callback().
|
inline |
Register a cancel callback.
F must be a stateless callable convertible to TypedCancelFn.
|
inline |
Register a cancel callback with a user context pointer.
Mirrors set_goal_callback_with_ctx — the bare function pointer receives a void* alongside each UUID so stateful cancel policies don't need captured lambdas or global state. Mutually exclusive with set_cancel_callback().
|
inline |
Register a typed goal callback.
F must be a stateless callable that decays to TypedGoalFn (empty-capture lambda or plain function pointer). F must be a stateless callable convertible to TypedGoalFn (empty-capture lambda or plain function pointer).
|
inline |
Register a typed goal callback with a user context pointer.
The bare function pointer is stored alongside a void* that is forwarded to every invocation — lets callers reach stateful objects without capturing lambdas or file-scope globals. Overrides and is overridden by set_goal_callback() (the two modes are mutually exclusive).
|
inline |
|
inline |
Terminate goal_id as SUCCEEDED — phase-417 W4.b.
C has rclc_action_succeed / _abort / _canceled, Rust has ActionServerHandle::succeed / abort / canceled, and every rclcpp_action server ends with goal_handle->succeed(result). C++ had only complete_goal, so the terminal line of a ported server was one nobody could keep. These three are FORWARDERS onto complete_goal: the goal state machine stays Rust-side (RFC-0019), and no state is added here.
complete_goal remains the general form for a status computed at runtime.
Upstream's is goal_handle->succeed(std::shared_ptr<Result>). Ours is on the server, keyed by goal id, result by const reference: there is no goal handle and no shared_ptr (goals live in the server's static arena).
|
friend |