|
nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
|
#include <node.hpp>

Public Types | |
| using | ConstSharedPtr = ::rclcpp::Handle< const Node > |
rclcpp::Node::ConstSharedPtr. | |
| using | SharedPtr = ::rclcpp::Handle< Node > |
Static Public Member Functions | |
| static Result | create (Node &out, const char *name, const char *ns=nullptr) |
Friends | |
| class | ::rclcpp::Executor |
| class | ::rclcpp::NodeBuilder |
| Result() | rclcpp::create_node (Node &out, const char *name, const char *ns) |
| Result() | rclcpp::create_node_on (Node &out, void *executor_handle, const char *name, const char *ns) |
| void *() | rclcpp::global_handle () |
| Result() | rclcpp::init_in (const char *locator, uint8_t domain_id) |
| Result() | rclcpp::init_in (const char *locator, uint8_t domain_id, const char *session_name) |
| Result() | rclcpp::init_in (const char *locator, uint8_t domain_id, const char *session_name, const char *node_namespace) |
| Result() | rclcpp::init_with_rmw (const char *rmw, const char *locator, uint8_t domain_id, const char *session_name) |
| bool() | rclcpp::ok () |
| Result() | rclcpp::shutdown_in () |
| Result() | rclcpp::spin_in () |
| Result() | rclcpp::spin_in (uint32_t duration_ms, int32_t poll_ms) |
| Result() | rclcpp::spin_once (int32_t timeout_ms) |
The node — rclcpp::Node, ONE TYPE (phase-427). The primary interface for creating ROS entities: publishers, subscriptions, services, timers are all created through it, and it holds a reference to the parent executor session.
Usage:
Three shapes collapsed here: the freestanding out-ref node, the hosted shared_ptr node that used to be a separate rclcpp::Node in nros.hpp, and (from RFC-0044) the derivable component base, so there is exactly one set of entities, one arena registration path and one parameter facade.
THE CLASS IS DEFINED HERE, in rclcpp:: — RFC-0089 §"Settled: `rclcpp::` is
the HOME, not an alias onto `nros::`", and the tenth and last type of the phase-428 flip (nros::Node remained an alias until phase-483 W1). It was held back for two reasons, both now gone: two landed reviews (PRs #797, #806) were stacked on this header, and scripts/api-parity.py rooted our NATIVE C++ surface at {"nros"} alone, so a class defined here re-bucketed ~60 members to theirs-only with no ledger row. The tool was the thing that had to change and did: OUR_CPP_ROOTS now names both halves of the vocabulary we ship.
LAYOUT IS PROBE-INDEPENDENT (phase-427 W1, gate check-cpp-capability-layout). Every member below is unconditional, and since phase-476 W3 there is no hosted-only state at all. A capability probe may gate a METHOD — and many below are gated — but it may never change sizeof. Two TUs of one image disagreeing about <memory> is a SUPPORTED state here (px4 sets -DNROS_CPP_STD on one module; the Zephyr cyclone module adds a cxx-compat include dir for some targets only), and the shim's std::vector<std::shared_ptr<detail::WallTimer>> timers_ already shipped that bug once.
rclcpp::Node::SharedPtr — phase-482 W2, RFC-0096 D5 item 4.
A copyable, non-owning rclcpp::Handle<Node> on EVERY target, the model of the entity handles (phases 456/476). It was std::shared_ptr<Node> behind NROS_CPP_HAS_SHARED_PTR, so a freestanding port could not spell the type its class body stores and passes. A node is constructed by a generated entry or by main and outlives everything it is handed to, which is the lifetime a handle states.
Hosted interop is in rclcpp::Handle: an lvalue std::shared_ptr<MyNode> converts, a TEMPORARY one is a compile error (it would dangle), and the spin verbs take const std::shared_ptr<N>& so rclcpp::spin(std::make_shared<MyNode>()) is unchanged.
|
inline |
Default constructor — creates an uninitialized node. Pair with [init].
rclcpp::Node("talker") — upstream's shape, no allocator, every target.
Opens on the GLOBAL executor rclcpp::init() created (issue 0465 — one session per image). ADOPT-BOUNDED: upstream throws where this leaves ok() false, which is weaker, so it has to be LOUD by other means — the generated entry checks ok() and halts naming the node (RFC-0044 Q2), and a hand-written main must check it. The book says so; the compiler cannot.
|
inlineexplicit |
Construct against an EXPLICIT executor-bound handle — what a generated entry writes, and what nros::ComponentNode(NodeHandle, name) was before phase-427 W4 merged it here.
This is the SECOND of the type's two constructors. On a null handle or a creation failure it latches the error rather than aborting: the entry checks ok() post-construct and halts naming this node (RFC-0044 Q2).
Precedence (issue 1456), per HALF of the identity and stated rather than emergent:
launch-declared (on the handle) > this constructor's argument > the type's own default (name is required; ns defaults to UNSET, which since issue 1473 means the EXECUTOR's namespace, not the root)
So a component whose class hardcodes a DIFFERENT name than the launch file declares is named by the LAUNCH FILE, which is the only answer that lets one component class be instantiated twice in one launch file: two Comp(h) : Node(h, "talker") objects would otherwise both be /talker. It is upstream's order too — -r __node:=alpha outranks the literal an rclcpp::Node subclass passes its base.
The halves are independent: a launch file declaring only a namespace leaves the class's name standing (/island/talker), and one declaring neither changes nothing at all. The class's literal is a DEFAULT, never dead — which is what keeps a hand-written main constructing the same component (no entry, no handle identity) working unchanged.
|
inline |
Upstream's (name, options) constructor, freestanding. NodeOptions carries no state (options.hpp), so there is nothing to keep.
|
inline |
Upstream's (name, namespace, options) constructor, freestanding. No default for options here: Node(name, ns) is the two-argument constructor above, and a default would make that call ambiguous.
|
inline |
Destructor — releases node resources.
BYTE-IDENTICAL IN EVERY CONFIGURATION (phase-427 W1). It never names the hosted type: the block carries its own destroy function pointer, so a freestanding TU and a hosted TU of the same image emit the same inline destructor. A #if-gated delete here would be the ODR half of exactly the defect the layout rule exists to prevent.
|
inline |
|
inline |
rclcpp::Node::add_on_set_parameters_callback(callback).
The hook runs on every write that reaches the store — a remote ros2 param set, a local set_parameter, another language's setter — and AFTER the store's own read-only / type / range rules, so it never sees a write those already refused. false from the callback REFUSES the write.
Upstream returns an owning handle whose destruction unregisters; with no allocator there is nothing to own, so out_handle receives a token and unregistering is explicit. Result::FULL when every slot is taken — a refusal, never a silent eviction of somebody else's hook.
|
inline |
phase-403 step 2 — the BOOT-TIME half of the declared-depth check.
The compile-time half (NROS_SUBSCRIBE's static_assert) is the primary path and covers every call site whose topic is a string literal, which is all of them in this tree. It cannot cover two shapes: a topic built at runtime or forwarded through a variable (the lookup key is not a constant expression), and a caller that reaches the member directly rather than through the macro. Both get the same comparison here, against the same table, through the same rclcpp::declared_depth.
A disagreement is a named boot failure: it goes through set_error, which makes the entry's post-construct ok() check halt boot. It does NOT create the subscription — an entity built at a depth its own image did not declare is exactly the arena mis-sizing this step prevents.
Returns true when the subscription may be created.
phase-446 W6 – the boot-time check that this node declares a parameter the way its contract does.
The parameter store is sized from the contract's params: (phase-446 W4), so a name the contract does not declare has no slot counted for it, and a type that differs is a value the contract's reader (and play_launch's check of the launch file) would reject. Either one is a named boot failure through set_error, in the idiom check_declared_depth set: the node, the parameter and the contract are printed first, and the entry's post-construct ok() check halts boot. The parameter is NOT declared.
A node whose contract has no params: is not checked, and neither are the names every node carries (rclcpp::declared_param_exempt). Runtime rather than static_assert: the key is the node's fully-qualified name, which is a constructor argument, not a constant expression.
Returns true when the parameter may be declared.
|
inline |
issue 1256 – the BOOT-TIME check of EVERY declared column: the depth (check_declared_depth), then the reliability and the durability.
What create_subscription_in and create_subscription_in_group call. A reliability or durability disagreement is not a sizing fault, it is an INTEROP one – an incompatible-QoS match never delivers – and before this it was not checked at all. Same refusal shape as the depth: the node, the topic and both values are printed, set_error halts boot, and the subscription is NOT created. An undeclared column checks nothing.
Returns true when the subscription may be created.
How many publishers are visible on topic_name — rclcpp's Node::count_publishers().
topic_name is a ROS name ("/chatter"), used as given: it is not remapped and not expanded against this node's namespace, which is what rclcpp documents for this call too. The count reflects what has been DISCOVERED, so it can be low right after startup and a zero is never a proof of absence.
How many subscribers are visible on topic_name — rclcpp's Node::count_subscribers(). See [count_publishers] for the caveats.
|
inlinestatic |
Create a new node.
Issue 1473 — ns == nullptr (or "") is UNSET, not the root. The node INHERITS the executor's namespace, which is how a namespace given to rclcpp::init_in(locator, domain, session, node_namespace) (issue 1434) reaches anything the image creates afterwards. To place a node at the ROOT of a namespaced executor, pass "/" — one character, and the spelling every generated C entry already emits. The two are different requests and this API keeps them apart; nros_cpp_node_create and nros_cpp_node_create_ex answer them identically.
On an executor at the root the two are the same value, so an image that never names a session namespace is unaffected.
| out | Receives the initialized node. |
| name | Node name (null-terminated). |
| ns | Node namespace (null-terminated); nullptr or "" = unset (inherit the executor's), "/" = the root. |
| Result rclcpp::Node::create_action_client | ( | ::rclcpp_action::Client< A > & | out, |
| const char * | action_name, | ||
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::services() |
||
| ) |
Create an action client.
| A | Action type (must define nested Goal, Result, Feedback with TYPE_NAME/TYPE_HASH). |
| out | Receives the initialized action client. |
| action_name | Action name (null-terminated). |
| qos | QoS profile (default: services preset). |
| Result rclcpp::Node::create_action_server | ( | ::rclcpp_action::Server< A > & | out, |
| const char * | action_name, | ||
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::services(), |
||
| const ::rclcpp::ActionServerOptions & | options = {} |
||
| ) |
Create an action server.
Goals are auto-accepted during spin_once(). Use try_recv_goal() to poll.
| A | Action type (must define nested Goal, Result, Feedback with TYPE_NAME/TYPE_HASH). |
| out | Receives the initialized action server. |
| action_name | Action name (null-terminated). |
| qos | QoS profile (default: services preset). |
| options | Named options; options.sched_context (M3.3.c) binds the goal-service dispatch onto a scheduling context. |
|
inline |
Create a named callback-group token.
The returned CallbackGroup may be passed to create_timer_in_group, create_subscription_in_group, or create_publisher_in_group to associate entities with the group's SchedContext (resolved via group_sched_table).
| name | Group name — must be a string literal or static-lifetime string; the pointer is stored directly (no copy). |
phase-459 W6 – inside a component's construction, a name its registration's CALLBACK_GROUPS did not declare is a named boot failure (DECLARED_CALLBACK_GROUP_MISMATCH): the tier derivation ranked the declared list, so an undeclared group would run on a tier nobody ranked. The token is still returned, so the constructor's remaining calls are well-formed; the latch halts boot after it.
| Result rclcpp::Node::create_client | ( | ::rclcpp::Client< S > & | out, |
| const char * | service_name, | ||
| F | callback, | ||
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::services(), |
||
| const ::rclcpp::ClientOptions & | options = {} |
||
| ) |
Create a callback-style service client (rclcpp async dispatch; Phase 189.M3.3.f). Arena-registered, so it owns a real executor handle and its response handler runs during spin_once — making options.sched_context functional. callback must be convertible to void(const S::Response&); send requests with Client<S>::async_send_request. The SFINAE guard keeps the future-style 3-arg overload unambiguous.
out is MOVABLE after this returns (phase-456 W3): the arena holds the HANDLER as its response context, not &out. What the move carries is {executor, handle_id}, which is what async_send_request needs.
| Result rclcpp::Node::create_client | ( | ::rclcpp::PollClient< S > & | out, |
| const char * | service_name, | ||
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::services() |
||
| ) |
Create a FUTURE-style service client.
phase-456 W9 — the out parameter is rclcpp::PollClient<S>, not rclcpp::Client<S>. This overload creates a client the CALLER owns, in the caller's own storage, drained with send_request() / call() / call_polling() and probed with wait_for_service(); the dispatch overload below registers a response handler into the executor arena and the caller's one verb is async_send_request. One class used to be both, behind a callback_mode_ flag, which meant wait_for_service() was offered on objects whose storage the arena never filled.
| S | Service type (must define nested Request and Response with TYPE_NAME/TYPE_HASH). |
|
inline |
| typename::rclcpp::Client< S >::SharedPtr rclcpp::Node::create_client | ( | const char * | , |
| F | , | ||
| const ::rclcpp::QoS & | = ::rclcpp::QoS::services() |
||
| ) |
REFUSED — upstream's shared_ptr handler shape.
|
inline |
| ::rclcpp::Owned<::rclcpp::PollClient< S > > rclcpp::Node::create_client | ( | const char * | name, |
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::services() |
||
| ) |
Future-style service client (create_client<S>(name, qos)); see the std::string overload's note on the divergence.
|
inline |
| typename::rclcpp::Client< S >::SharedPtr rclcpp::Node::create_client | ( | const char * | name, |
| F | callback, | ||
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::services() |
||
| ) |
Callback-style service client (void(const S::Response&)).
|
inline |
Create a guard condition for cross-thread signaling.
The callback fires during spin_once() when guard.trigger() is called.
| out | Receives the initialized guard condition. |
| callback | C function pointer invoked when triggered. |
| context | User context passed to the callback (may be nullptr). |
| Result rclcpp::Node::create_polling_action_client | ( | ::rclcpp::PollingActionClient< A > & | out, |
| const char * | action_name | ||
| ) |
Phase 122.3.d.b — Create an L1 polling-mode action client.
| Result rclcpp::Node::create_polling_action_server | ( | ::rclcpp::PollingActionServer< A > & | out, |
| const char * | action_name | ||
| ) |
Phase 122.3.d.b — Create an L1 polling-mode action server. Caller drives the lifecycle (no executor callback). See polling_action_server.hpp for usage.
| Result rclcpp::Node::create_polling_subscription | ( | ::rclcpp::PollingSubscription< M > & | out, |
| const char * | topic, | ||
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::default_profile() |
||
| ) |
Issue 0278 — Create a latest-value polling subscription (the nano-ros analog of autoware_utils::InterProcessPollingSubscriber): a poll-mode subscription plus a retained last value, read repeatably via PollingSubscription<M>::take_data() / take_new_data(). See polling_subscription.hpp.
| Result rclcpp::Node::create_publisher | ( | ::rclcpp::Publisher< M > & | out, |
| const char * | topic, | ||
| const ::rclcpp::QoS & | qos, | ||
| const ::rclcpp::PublisherOptions & | options | ||
| ) |
Create a publisher with rclcpp-style named options (Phase 189.M3.1).
options sits alongside qos (rclcpp convention). PublisherOptions is currently a reserved/empty struct, so this overload is observably identical to the qos-only form — it exists for API symmetry and as the seam for future intra-process / loaned-message knobs.
| M | Message type (must define TYPE_NAME and TYPE_HASH). |
| out | Receives the initialized publisher. |
| topic | Topic name (null-terminated). |
| qos | QoS profile. |
| options | Named publisher options. |
| Result rclcpp::Node::create_publisher | ( | ::rclcpp::Publisher< M > & | out, |
| const char * | topic, | ||
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::default_profile() |
||
| ) |
Create a publisher for a topic.
| M | Message type (must define TYPE_NAME and TYPE_HASH). |
| out | Receives the initialized publisher. |
| topic | Topic name (null-terminated). |
| qos | QoS profile (default: reliable, keep-last(10)). |
| typename::rclcpp::Publisher< M >::SharedPtr rclcpp::Node::create_publisher | ( | const char * | topic, |
| ::size_t | depth | ||
| ) |
create_publisher<M>(topic, depth) — the integer-depth spelling.
|
inline |
|
inline |
| typename::rclcpp::Publisher< M >::SharedPtr rclcpp::Node::create_publisher | ( | const char * | topic, |
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::default_profile() |
||
| ) |
create_publisher<M>(topic, qos) — available on every target.
|
inline |
Create a publisher, returning it BY VALUE — the ours-only shape.
Was ComponentNode::create_publisher<M>(topic, qos). Move it into a member: pub_ = create_publisher_in<M>("/topic"). Latches ok()=false on failure instead of throwing.
|
inline |
Create a publisher in a callback group (API symmetry; RFC-0047).
Publishers have no dispatched callback — the group parameter is accepted for API symmetry but has no scheduling effect (documented in RFC-0047 §OQ1 follow-up).
| M | Message type. |
| group | Callback group (accepted for symmetry; no scheduling effect). |
| out | Receives the initialized publisher. |
| topic | Topic name. |
| qos | QoS profile. |
| Result rclcpp::Node::create_service | ( | ::rclcpp::PollService< S > & | out, |
| const char * | service_name, | ||
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::services() |
||
| ) |
Create a POLL-style service server.
phase-456 W5 — the out parameter is rclcpp::PollService<S>, not rclcpp::Service<S>. This overload creates a server the CALLER owns, in the caller's own storage, drained with take_request() / send_response(); the dispatch overload below registers a handler into the executor arena and the caller invokes nothing. One class used to be both, behind a callback_mode_ flag, which meant take_request() was offered on objects whose storage the arena never filled.
| S | Service type (must define nested Request and Response with TYPE_NAME/TYPE_HASH). |
| Result rclcpp::Node::create_service | ( | ::rclcpp::Service< S > & | out, |
| const char * | service_name, | ||
| F | callback, | ||
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::services(), |
||
| const ::rclcpp::ServiceOptions & | options = {} |
||
| ) |
Create a callback-style service server (rclcpp dispatch model; Phase 189.M3.3.e). Unlike the poll-style overload above, this arena-registers the service so it owns a real executor handle and its request handler runs during spin_once — making options.sched_context functional. callback must be convertible to void(const S::Request&, S::Response&) (a plain function pointer or empty-capture lambda); it fills response from request. The SFINAE guard keeps the poll-style 3-arg overload unambiguous (a QoS is not convertible to the handler type).
out is MOVABLE after this returns (phase-456 W3): the arena holds the HANDLER as its dispatch context, not &out, so nothing of the caller's is referenced after registration.
|
inline |
| typename::rclcpp::Service< S >::SharedPtr rclcpp::Node::create_service | ( | const char * | , |
| F | , | ||
| const ::rclcpp::QoS & | = ::rclcpp::QoS::services() |
||
| ) |
REFUSED — upstream's shared_ptr handler shape. See NROS_RCLCPP_REFUSE_SHARED_PTR_SERVICE_CALLBACK.
|
inline |
| ::rclcpp::Owned<::rclcpp::PollService< S > > rclcpp::Node::create_service | ( | const char * | name, |
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::services() |
||
| ) |
Poll-style service server (create_service<S>(name, qos)). Not an upstream signature; see the std::string overload's note.
|
inline |
| typename::rclcpp::Service< S >::SharedPtr rclcpp::Node::create_service | ( | const char * | name, |
| F | callback, | ||
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::services() |
||
| ) |
Callback-style service server (void(const S::Request&, S::Response&)).
| Result rclcpp::Node::create_subscription | ( | ::rclcpp::PollSubscription< M > & | out, |
| const char * | topic, | ||
| const ::rclcpp::QoS & | qos, | ||
| const ::rclcpp::SubscriptionOptions & | options | ||
| ) |
Create a subscription with rclcpp-style named options (Phase 189.M3.1).
options sits alongside qos (rclcpp convention) and carries the non-QoS creation axes. NEITHER reaches a poll subscription: sched_context binds an executor HandleId and a poll subscription registers no arena entry, and message_info is reserved (M3.4). See SubscriptionOptions, and the definition in rclcpp/polling_subscription.hpp for why phase-456 W2b makes the first one structural instead of a branch that could never be taken.
| M | Message type (must define TYPE_NAME and TYPE_HASH). |
| out | Receives the initialized subscription. |
| topic | Topic name (null-terminated). |
| qos | QoS profile. |
| options | Named subscription options. |
| Result rclcpp::Node::create_subscription | ( | ::rclcpp::PollSubscription< M > & | out, |
| const char * | topic, | ||
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::default_profile() |
||
| ) |
Create a POLL subscription for a topic — the caller owns the subscriber and drains it with take(); nothing dispatches.
phase-456 W2b — the out parameter is rclcpp::PollSubscription<M>, not Subscription<M>. Defined in rclcpp/polling_subscription.hpp, beside the type it creates.
| M | Message type (must define TYPE_NAME and TYPE_HASH). |
| out | Receives the initialized subscription. |
| topic | Topic name (null-terminated). |
| qos | QoS profile (default: reliable, keep-last(10)). |
| Result rclcpp::Node::create_subscription | ( | ::rclcpp::Subscription< M > & | out, |
| const char * | topic, | ||
| const ::rclcpp::QoS & | qos, | ||
| F | callback, | ||
| const ::rclcpp::SubscriptionOptions & | options = {} |
||
| ) |
Create a callback-style subscription (rclcpp dispatch model; Phase 189.M3.x). The executor arena owns the subscriber and invokes callback during spin_once() on each new sample, so options.sched_context is functional (poll-style subscriptions have no dispatched callback to schedule). callback must be convertible to void(const M&) (a plain function pointer or empty-capture lambda); the SFINAE guard keeps the poll-style overloads unambiguous (a QoS is not convertible to the handler type).
CONSTRAINT: do not move out after this returns — the executor arena holds &out as the dispatch context.
ARGUMENT ORDER IS UPSTREAM'S: (out, topic, qos, callback, options) — the phase-467 RMW gap-closure design study's Row 12. It was (out, topic, callback, qos = default, options) until then, for no platform reason: the only force was the C++ rule that a defaulted parameter cannot precede a non-defaulted one, and upstream answers it by making qos MANDATORY, which is what we do now. The proof it was a preference and not a constraint was in this same header — the rclcpp::Node adapter at nros.hpp has always used upstream's order, so both orders coexisted, and log.hpp's own abort advisory told readers to write node.create_subscription(sub, topic, qos, cb), which did not compile. RFC-0036 does not allow recording an ordering preference as a divergence, and RFC-0089 clause 2 says not to trade one away.
COST, stated: the three-argument convenience create_subscription(sub, "chatter", cb) is gone. Write create_subscription(sub, "chatter", ::rclcpp::QoS(10), cb).
| M | Message type (must define TYPE_NAME, TYPE_HASH, ffi_deserialize). |
| out | Receives the initialized subscription (callback mode). |
| topic | Topic name (null-terminated). |
| qos | QoS profile. MANDATORY, as upstream's is. |
| callback | Handler invoked as callback(const M&) per sample. |
| options | Named subscription options (e.g. sched_context). |
CALLER-PLACED: fills out and returns Result, where upstream returns a Subscription<M>::SharedPtr and throws on failure (RFC-0018/0019: no exceptions, no heap). On a hosted build the ported spelling create_subscription<M>(topic, qos, cb) returns a SharedPtr and aborts, naming the topic, if the create fails.
| typename::rclcpp::Subscription< M >::SharedPtr rclcpp::Node::create_subscription | ( | const char * | topic, |
| ::size_t | depth, | ||
| Cb | cb | ||
| ) |
create_subscription<M>(topic, depth, callback).
|
inline |
| typename::rclcpp::Subscription< M >::SharedPtr rclcpp::Node::create_subscription | ( | const char * | topic, |
| const ::rclcpp::QoS & | qos, | ||
| Cb | cb | ||
| ) |
create_subscription<M>(topic, qos, callback) — any callable; the executor dispatches it. Available on every target.
|
inline |
| void rclcpp::Node::create_subscription_in | ( | const char * | topic, |
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::default_profile() |
||
| ) |
Create a typed member-callback subscription — the ours-only shape.
Was ComponentNode::create_subscription<M, C, Method>(topic, qos). Registers a raw subscription on the executor keyed on M::TYPE_NAME with a no-alloc deserialize-then-dispatch trampoline; the executor arena owns the subscriber, so there is no Subscription<M> storage to supply and nothing to park.
DECLARED here and DEFINED in component.hpp: the body calls rclcpp::bind_subscription, which lives there, and component.hpp includes THIS file — so defining it here would close an include cycle. nros.hpp pulls in component.hpp, so the definition is visible wherever the umbrella is.
| Result rclcpp::Node::create_subscription_in_group | ( | const ::rclcpp::CallbackGroup & | group, |
| ::rclcpp::Subscription< M > & | out, | ||
| const char * | topic, | ||
| const ::rclcpp::QoS & | qos, | ||
| F | callback, | ||
| const ::rclcpp::SubscriptionOptions & | options = {} |
||
| ) |
Create a callback-style subscription in a callback group (RFC-0047).
Like the callback-style create_subscription but associates the subscription with group so the executor binds it to the group's SchedContext via group_sched_table. Out-of-line definition in subscription.hpp.
Argument order follows the callback-style create_subscription above: qos before callback, and mandatory (Row 12 of the phase-467 RMW gap-closure design study — the siblings move together or the fix is the "fixed the reported site" failure).
| M | Message type (must define TYPE_NAME, TYPE_HASH, ffi_deserialize). |
| group | Callback group. |
| out | Receives the initialized subscription (callback mode). |
| topic | Topic name (null-terminated). |
| qos | QoS profile. MANDATORY, as upstream's is. |
| callback | Handler invoked as callback(const M&) per sample. |
| options | Named subscription options. |
| void rclcpp::Node::create_subscription_in_group | ( | const ::rclcpp::CallbackGroup & | group, |
| const char * | topic, | ||
| const ::rclcpp::QoS & | qos = ::rclcpp::QoS::default_profile() |
||
| ) |
The same, in a callback group (RFC-0047) — the group's SchedContext is resolved via group_sched_table. Also defined in component.hpp.
| Result rclcpp::Node::create_subscription_with_info | ( | ::rclcpp::Subscription< M > & | out, |
| const char * | topic, | ||
| const ::rclcpp::QoS & | qos, | ||
| F | callback, | ||
| const ::rclcpp::SubscriptionOptions & | options = {} |
||
| ) |
Create a callback-style subscription that also delivers each sample's wire attachment (Phase 189.M3.4 — the callback analogue of Subscription::take_serialized_with_attachment). Arena-registered like the callback overload above (so options.sched_context is functional), but the handler is invoked as callback(const M&, const uint8_t* attachment, size_t attachment_len); attachment_len == 0 means the sample carried none. Cross-RMW bridges read the bridge_origin tag from the attachment.
Argument order follows the callback-style create_subscription above: qos before callback, and mandatory (Row 12 of the phase-467 RMW gap-closure design study).
|
inline |
Bind a member void C::on_tick() as a timer on an explicit CLOCK — phase-430 W6, the member-binding half of create_timer.
A RCL_ROS_TIME clock follows /clock and stops when the bag stops; a RCL_STEADY_TIME one does not. create_wall_timer above is the steady verb and is unaffected by simulated time.
|
inline |
Create a repeating timer on a CLOCK — rclcpp::create_timer(node, clock,
period, callback), phase-425 W4.
create_wall_timer is the steady one: it advances with the executor's monotonic spin delta, so no simulator can slow it down. This one advances with clock, which is what a node in a simulation or a bag replay wants: a RCL_ROS_TIME timer stops while /clock is paused, tracks the replay rate, and restarts its period on a backwards jump rather than stalling for the length of it.
With no /clock source installed a ROS-time clock reads system time, the same fallback rclcpp::Clock has — a node written for simulation still runs standalone.
The node's own clock (get_clock()) is ROS time, as in rclcpp, so node.create_timer(t, *node.get_clock(), 100, on_tick) is the usual call.
| out | Receives the initialized timer. |
| clock | The clock that advances the timer. |
| period_ms | Timer period in milliseconds, ON THAT CLOCK. |
| callback | C function pointer invoked on each tick. |
| context | User context passed to the callback (may be nullptr). |
|
inline |
Bind a member void C::on_tick() as a timer IN a callback group (RFC-0047) — the member-binding half of create_timer_in_group.
|
inline |
Create a repeating timer in a callback group (RFC-0047).
Like create_wall_timer but associates the timer with group so the executor binds it to the group's SchedContext via group_sched_table. group.get_name() == nullptr or empty falls back to node default.
| group | Callback group (from create_callback_group). |
| out | Receives the initialized timer. |
| period_ms | Timer period in milliseconds. |
| callback | C function pointer invoked on each tick. |
| context | User context passed to the callback (may be nullptr). |
|
inline |
Create a one-shot timer.
The callback fires once after the specified delay.
| out | Receives the initialized timer. |
| delay_ms | Delay in milliseconds before the callback fires. |
| callback | C function pointer invoked once. |
| context | User context passed to the callback (may be nullptr). |
| ::rclcpp::TimerHandle rclcpp::Node::create_wall_timer | ( | ::rclcpp::Duration | period, |
| Cb | cb | ||
| ) |
create_wall_timer(period, callback) — upstream's shape, FREESTANDING.
phase-476 W2. Takes any callable (a capturing lambda, a std::bind result) and returns a two-word [rclcpp::TimerHandle]; the callable is copied into the executor arena, which destroys it when the timer is released, so nothing here allocates and nothing needs <memory> or <functional>. The node owns the timer: destroying the node releases it. Body in nros.hpp.
ADOPT-BOUNDED as before: the period is truncated to whole milliseconds, and a missed deadline catches up where rcl drops (see rclcpp::Timer).
|
inline |
|
inline |
Create a repeating WALL timer — rclcpp::Node::create_wall_timer.
The callback fires during spin_once() at the specified period, measured on the platform's monotonic clock. For a timer that follows simulated time, see create_timer above.
| out | Receives the initialized timer. |
| period_ms | Timer period in milliseconds. |
| callback | C function pointer invoked on each tick. |
| context | User context passed to the callback (may be nullptr). |
|
inline |
rclcpp::Node::declare_parameter<T>(name, default, descriptor).
Upstream's third argument is an rcl_interfaces message; ours is rclcpp::ParameterDescriptor, which borrows its text (see that type). Returns the value in effect, like the two-argument form; a descriptor that could not be attached leaves the parameter DECLARED with the value and reports nothing, which is upstream's behaviour for a descriptor whose range the default satisfies.
rclcpp::Node::declare_parameter<T>(name, default).
|
inline |
rclcpp::Node::describe_parameter(name), into caller storage.
text holds both strings; out.description and out.additional_constraints point into it. It is split in half, so a 128-byte buffer gives each text 64 bytes, and Result::FULL says a text was truncated — the text is still there, cut at a character boundary. Pass text = nullptr to read only the flags and the range.
|
inline |
The raw error code of the first latched failure, or 0.
The site of the first failure ("create_publisher_in", "node create", …), or nullptr when no failure was latched. For the boot diagnostic.
|
inline |
Phase 240.5 (RFC-0043) — the opaque executor handle this node was opened against (from nros_cpp_init). The component layer needs it for the raw FFI that is executor- rather than node-scoped (action server register / complete_goal / publish_feedback) — Node::create_* use it internally, but a stateful component binding those transports raw needs direct access. nullptr on an uninitialized node.
|
inline |
Phase 235.A — internal: raw FFI node handle for the Entry-pkg NodeContext runtime.
The declarative NodeContextOps boundary (<nros/node_pkg.hpp>) is type-erased — entities arrive as descriptor strings (type_name / type_hash), with no message type M available at the op-function-pointer callsite. The native runtime in <rclcpp/detail/main.hpp> therefore constructs publishers / subscriptions through the raw nros_cpp_{publisher,subscription}_create FFI, which takes a const nros_cpp_node_t*. This accessor hands that pointer to the runtime. Not part of the public rclcpp-style surface — user code creates entities via the typed create_publisher<M> / create_subscription<M> templates.
Returns nullptr on an uninitialized node.
|
inline |
What services one named node CALLS, with the types — rclcpp's NodeGraph::get_client_names_and_types_by_node(). Same discovery envelope as [get_node_names].
|
inline |
The node's clock — rclcpp::Node::get_clock().
rclcpp hands back a rclcpp::Clock::SharedPtr. There is no allocator and no shared_ptr here (RFC-0022), so the clock is a member of the node and this returns a pointer to it: node.get_clock()->now() and node->get_clock()->now() both keep their rclcpp spelling. The pointer is valid for as long as the node is.
The clock is ROS time, as rclcpp's node clock is. See rclcpp::Clock for what ROS time does and does not yet do here (issue 0789).
Const overload of get_clock().
|
inline |
This node's fully-qualified name — rclcpp::Node::get_fully_qualified_name.
Writes <namespace>/<name> into buf, null-terminated. The root namespace collapses, so a node named talker at / is /talker and never //talker.
A buffer rather than rclcpp's returned string: rclcpp hands back a const std::string & it already stores, and there is no allocator here to build one with. rclc_get_fully_qualified_name (the C entry point) is the std::string spelling where NROS_CPP_STD is on.
| out_len | Receives the length written, excluding the terminator — or, when the buffer is too small, the length that WOULD be written, so a caller can size a second attempt. May be nullptr. |
|
inline |
rclcpp::Node::get_logger() — the logger NAMED FOR THIS NODE.
phase-427 W5. The two spellings used to collide on an identical signature: this one returned the real nros_log::Logger handle keyed on the node's name, while the shim's returned a rclcpp::Logger built from the hardcoded sentinel "nros.compat" — same name, same arity, different observable behaviour. The merged accessor takes ROS 2's behaviour, because a logger that cannot say which node emitted a record is worse than the one it replaced.
ONE return type was forced by the merge (two get_logger() overloads differing only in return type are ill-formed), and the ported name keeps upstream's: rclcpp::Logger. That costs nothing at the call site — rclcpp::Logger converts implicitly to rclc_logger_t (const void*), so RCLC_LOG_INFO(node.get_logger(), …) and logger == nullptr both still compile and still carry the same opaque handle.
The handle is 'static and must NOT be freed; it is null on an uninitialized node.
The returned logger is rclcpp::Logger's bounded form: get_name(), set_level() and the RCLCPP_* macros work, get_child() does not compile (no allocator to build a child name), and the name is borrowed from the node.
|
inline |
Every node on the graph, with its namespace — rclcpp's Node::get_node_names().
visit(ctx, name, ns, enclave) runs once per node; enclave is nullptr where the backend tracks none, which is what lets one call answer both rmw_get_node_names forms. Every string is BORROWED for the duration of the call; return false to stop early.
rclcpp hands back a std::vector<std::string>. There is no allocator here (RFC-0022), so the same enumeration streams through a visitor — a plain function pointer plus ctx, because these headers compile -nostdinc++ against Zephyr's minimal libcpp, where <functional> does not exist (issue 0112).
Reports what has been DISCOVERED and never blocks: an empty enumeration means "nobody seen yet", not "nobody exists", and ErrorCode::Unsupported from a backend with no graph stays distinct from it.
|
inline |
rclcpp::Node::get_node_options(). FREESTANDING since phase-476 W3: NodeOptions has no data members, so every node's options are the same default, and a constant answers what the constructor was given.
Value-returning read; T() when the name is undeclared.
rclcpp::Node::get_parameter<T>(name, out) — upstream's channel is bool, so ours is too (RFC-0089's error-channel rule, last row).
rclcpp::Node::get_parameter_or<T>(name, out, fallback) — read with a caller-chosen fallback, where the value-returning get_parameter<T> falls back to T().
|
inline |
The declared TYPE of one parameter. PARAMETER_NOT_SET when the name is not declared on this node.
|
inline |
rclcpp::Node::get_parameter_types(names), into caller storage.
Upstream takes a std::vector<std::string> and returns a std::vector<ParameterType>; both need an allocator, so ours takes the names as an array and writes count types into out. A name that is not declared gets PARAMETER_NOT_SET, as upstream's service does.
|
inline |
What one named node PUBLISHES, with the types — rclcpp's NodeGraph::get_publisher_names_and_types_by_node(). Same discovery envelope as [get_node_names].
|
inline |
The publishers on topic_name, visited as [rclcpp::TopicEndpointInfo] — the rclcpp-shaped overload of the call above.
A pure conversion over the same query: the visitor sees an endpoint with rclcpp's accessor names (node_name(), endpoint_type(), endpoint_gid()) instead of the raw C struct. Every caveat of the nros_cpp_endpoint_info_visit_fn overload applies unchanged, including the absent QoS profile and the borrowed strings.
|
inline |
The publishers discovered on topic_name, one visit each — rclcpp's Node::get_publishers_info_by_topic().
The endpoint carries NO QoS profile: rclcpp's qos_profile() reports the GRANTED profile, no backend behind this API can read a remote's granted profile back, and reporting the remote's DECLARED one instead would be a confident wrong answer to the question ("why is nothing
arriving?") the field exists to answer. See [rclcpp::TopicEndpointInfo].
rclcpp also takes no_mangle; there is no such parameter here, because accepting one and ignoring it would silently drop configuration — exactly what RFC-0089's rule forbids.
Same discovery envelope as [get_node_names].
|
inline |
Every service on the graph, with its types — rclcpp's Node::get_service_names_and_types(). As [get_topic_names_and_types], over servers and clients.
|
inline |
What services one named node SERVES, with the types — rclcpp's Node::get_service_names_and_types_by_node(). Servers only, not clients, as upstream. Same discovery envelope as [get_node_names].
|
inline |
What one named node SUBSCRIBES to, with the types.
subscription, not subscriber: the C++ surface takes rclcpp's vocabulary (create_subscription, Subscription<T>, get_subscriptions_info_by_topic), and rclcpp::Executor spells it that way — this forwarder keeps our two spellings identical rather than introducing a third. The C surface says subscriber because rcl does, and the vtable slot because upstream rmw does.
Same discovery envelope as [get_node_names].
|
inline |
The subscriptions on topic_name, visited as [rclcpp::TopicEndpointInfo] — the rclcpp-shaped overload of the call above.
|
inline |
The subscriptions discovered on topic_name, one visit each — rclcpp's Node::get_subscriptions_info_by_topic(). See [get_publishers_info_by_topic] for the QoS, no_mangle and discovery envelopes.
|
inline |
Every topic on the graph, with the types on it — rclcpp's Node::get_topic_names_and_types().
visit(ctx, name, types, types_count) runs once per distinct TOPIC: a topic carrying two types is one call with two entries, not two calls. types_count may legitimately be 0 on a partially discovered graph. Same discovery envelope as [get_node_names].
rclcpp::Node::has_parameter(name).
Explicit-code construction — the channel a -fno-exceptions target needs in place of a throwing constructor. Pair with Node().
Re-initialising an already-initialised node is AlreadyExists rather than a silent re-open.
|
inline |
Construct on an EXPLICIT executor handle rather than the global one — what a generated entry writes, and what nros::ComponentNode's NodeHandle constructor used to be (RFC-0089 §"What this means for the
merge": construction is not identity).
|
inline |
The shim's own initialized() — the same answer as [ok] and [is_valid]. Kept so a file written against the pre-merge rclcpp::Node still compiles.
|
inline |
Check if the node is initialized and valid.
|
inline |
rclcpp::Node::list_parameters(prefixes, depth), into caller storage.
Upstream returns a ListParametersResult message. Ours writes into a RECTANGLE of max_names rows of name_stride bytes and always reports the TOTAL that matched in count, so passing max_names = 0 counts. One prefix rather than a vector, and no depth: our names have no separator semantics to recurse on.
|
inline |
The current time on the node's clock — rclcpp::Node::now().
Shorthand for get_clock()->now(), and the call a ported publisher makes to stamp a header:
|
inline |
The shim's nros_node() escape hatch. There is one node type now, so this is the identity; kept for the same reason initialized() is.
|
inline |
rclcpp::ok()'s spelling, asked of one node: did this node come up?
Replaces upstream's throw. See the constructor for the envelope.
phase-427 W4 — this now answers for the LATCH as well as for creation. A node whose create_* failed after a successful open is not ok, which is what the generated entry's post-construct check has always meant.
Issue #230 — SMP safety. The failure state is tracked as a has_error_ flag whose HEALTHY value is the zero-initialized default, so a reader on a different core than the constructing one (ASI FVP SMP-4) always sees a correct "ok" even before the constructor's stores propagate — no spurious "failed at ? (code=0)" boot line. A real failure is published with a release store and read here with an acquire load, so the dangerous direction (silently MISSING a failure) is closed too.
|
inline |
rclcpp::Node::remove_on_set_parameters_callback(handle).
RFC-0088 D4 — the serialization format this node's backend speaks ("cdr", "uorb"), as its cross-image identity string.
Per SESSION, not per image. A node created with an explicit rmw option sits on its own session, so an image linking two backends gets two answers here — the case where a compile-time constant has none.
Returns const char*, deliberately, and never std::string or std::string_view: this header must compile against Zephyr's minimal libcpp, where <string> does not exist and <string_view> is not reliably there either (the NROS_CPP_STD guard exists for exactly that). The pointer is static storage owned by the backend; callers must NOT free it.
Returns nullptr on an uninitialized node, or when the backend does not declare a format. nullptr does not mean "cdr".
Record the first creation failure (RFC-0044 Q2). Idempotent on the first failure — later failures don't clobber the original diagnostic.
PUBLIC rather than protected, unlike ComponentNode::set_error: the out-ref create_* family reports through Result, so a derived node that wires entities with it has no other way to join the same latch the entry's post-construct check reads.
Set a declared parameter. NOT upstream's signature — upstream takes a single rclcpp::Parameter and returns a SetParametersResult, and neither type exists here (both are generated ROS messages).
|
inline |
rclcpp::Node::set_parameters_atomically(parameters) — all or nothing.
We SERVED ~/set_parameters_atomically and offered it in no language, so the only way to reach our own atomic set was over the wire.
|
inline |
Phase 211.H (issue #52) — install the per-topic QoS override table the deploy plan lowered from qos_overrides.<topic>.<role>.<policy> launch params. Every publisher/subscription created on this node afterwards folds the matching (topic, role) entries into its QoS before the backend-compat check — the C++ mirror of Rust's NodeHandle::set_qos_overrides. Call once, before creating entities (a generated/hand-written entry does this before configure(node)).
overrides must outlive the node (e.g. a static array in the entry). Pass len == 0 to clear. No-op on an uninitialized node.
|
inline |
rclcpp::Node::shared_from_this().
ADOPT-BOUNDED. Upstream gets this from std::enable_shared_from_this<Node>, a BASE CLASS carrying a std::weak_ptr, 16 bytes of layout that exist only where <memory> does. So there is no base; the verb is a method, and it returns a handle that OBSERVES this. It does not extend the node's lifetime where upstream's shares ownership, and it never throws bad_weak_ptr (RFC-0018). It used to return an aliasing std::shared_ptr with an EMPTY owner, which was the same observe-only contract under a hosted type; phase-482 W2 made it freestanding.
|
inline |
Const overload of [shared_from_this].
|
inline |
Serve this node's parameters on the six rcl_interfaces/srv/* services under its fully-qualified name, so ros2 param reaches them. rclcpp starts them from NodeOptions::start_parameter_services(true); that option is refused here (NodeOptions carries no runtime state), so this is the ours-only call a node makes instead (RFC-0089, 2026-10-13: a user calls no nros_cpp_* FFI). Idempotent per executor.
rclcpp::Node::undeclare_parameter(name). Upstream returns void and throws; ours reports (RFC-0089's error-channel rule — there are no exceptions here).
|
friend |
|
friend |
|
friend |
|
friend |
|
friend |
|
friend |
|
friend |
|
friend |
|
friend |
|
friend |
|
friend |
|
friend |
|
friend |