|
nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
|
#include <node.hpp>
Public Member Functions | |
| template<typename A > | |
| Result | create_action_client (ActionClient< A > &out, const char *action_name, const QoS &qos=QoS::services()) |
| template<typename A > | |
| Result | create_action_server (ActionServer< A > &out, const char *action_name, const QoS &qos=QoS::services(), const ActionServerOptions &options={}) |
| CallbackGroup | create_callback_group (const char *name) |
| template<typename S > | |
| Result | create_client (Client< S > &out, const char *service_name, const QoS &qos=QoS::services()) |
| template<typename S , typename F , typename = typename std::enable_if< std::is_convertible<F, void (*)(const typename S::Response&)>::value>::type> | |
| Result | create_client (Client< S > &out, const char *service_name, F callback, const QoS &qos=QoS::services(), const ClientOptions &options={}) |
| Result | create_guard_condition (GuardCondition &out, nros_cpp_guard_callback_t callback, void *context=nullptr) |
| template<typename A > | |
| Result | create_polling_action_client (PollingActionClient< A > &out, const char *action_name) |
| Phase 122.3.d.b — Create an L1 polling-mode action client. | |
| template<typename A > | |
| Result | create_polling_action_server (PollingActionServer< A > &out, const char *action_name) |
| template<typename M > | |
| Result | create_polling_subscription (PollingSubscription< M > &out, const char *topic, const QoS &qos=QoS::default_profile()) |
| template<typename M > | |
| Result | create_publisher (Publisher< M > &out, const char *topic, const QoS &qos, const PublisherOptions &options) |
| template<typename M > | |
| Result | create_publisher (Publisher< M > &out, const char *topic, const QoS &qos=QoS::default_profile()) |
| template<typename M > | |
| Result | create_publisher_in (const CallbackGroup &, Publisher< M > &out, const char *topic, const QoS &qos=QoS::default_profile()) |
| template<typename S > | |
| Result | create_service (Service< S > &out, const char *service_name, const QoS &qos=QoS::services()) |
| template<typename S , typename F , typename = typename std::enable_if<std::is_convertible< F, void (*)(const typename S::Request&, typename S::Response&)>::value>::type> | |
| Result | create_service (Service< S > &out, const char *service_name, F callback, const QoS &qos=QoS::services(), const ServiceOptions &options={}) |
| template<typename M > | |
| Result | create_subscription (Subscription< M > &out, const char *topic, const QoS &qos, const SubscriptionOptions &options) |
| template<typename M > | |
| Result | create_subscription (Subscription< M > &out, const char *topic, const QoS &qos=QoS::default_profile()) |
| template<typename M , typename F , typename = typename std::enable_if<std::is_convertible<F, void (*)(const M&)>::value>::type> | |
| Result | create_subscription (Subscription< M > &out, const char *topic, F callback, const QoS &qos=QoS::default_profile(), const SubscriptionOptions &options={}) |
| template<typename M , typename F , typename = typename std::enable_if<std::is_convertible<F, void (*)(const M&)>::value>::type> | |
| Result | create_subscription_in (const CallbackGroup &group, Subscription< M > &out, const char *topic, F callback, const QoS &qos=QoS::default_profile(), const SubscriptionOptions &options={}) |
| template<typename M , typename F , typename = typename std::enable_if< std::is_convertible<F, void (*)(const M&, const uint8_t*, size_t)>::value>::type> | |
| Result | create_subscription_with_info (Subscription< M > &out, const char *topic, F callback, const QoS &qos=QoS::default_profile(), const SubscriptionOptions &options={}) |
| Result | create_timer (Timer &out, const Clock &clock, uint64_t period_ms, nros_cpp_timer_callback_t callback, void *context=nullptr) |
| Result | create_timer_in (const CallbackGroup &group, Timer &out, uint64_t period_ms, nros_cpp_timer_callback_t callback, void *context=nullptr) |
| Result | create_timer_oneshot (Timer &out, uint64_t delay_ms, nros_cpp_timer_callback_t callback, void *context=nullptr) |
| Result | create_wall_timer (Timer &out, uint64_t period_ms, nros_cpp_timer_callback_t callback, void *context=nullptr) |
| void * | executor_handle () const |
| const nros_cpp_node_t * | ffi_handle () const |
| Clock * | get_clock () |
| const Clock * | get_clock () const |
Const overload of get_clock(). | |
| const void * | get_logger () const |
| const char * | get_name () const |
| Get the node name. | |
| const char * | get_namespace () const |
| Get the node namespace. | |
| bool | is_valid () const |
| Check if the node is initialized and valid. | |
| Node () | |
| Default constructor — creates an uninitialized node. | |
| Node (Node &&other) | |
| Time | now () const |
| Node & | operator= (Node &&other) |
| const char * | serialization_format () const |
| void | set_qos_overrides (const nros_cpp_qos_override_t *overrides, size_t len) |
| ~Node () | |
| Destructor — releases node resources. | |
Static Public Member Functions | |
| static Result | create (Node &out, const char *name, const char *ns=nullptr) |
Friends | |
| class | ComponentNode |
| Result | create_node (Node &out, const char *name, const char *ns) |
| Result | create_node_on (Node &out, void *executor_handle, const char *name, const char *ns) |
| class | Executor |
| void * | global_handle () |
| Result | init (const char *locator, uint8_t domain_id) |
| Result | init (const char *locator, uint8_t domain_id, const char *session_name) |
| Result | init_with_rmw (const char *rmw, const char *locator, uint8_t domain_id, const char *session_name) |
| class | NodeBuilder |
| bool | ok () |
| Check if the nros session is initialized. | |
| Result | shutdown () |
| Result | spin () |
| Result | spin (uint32_t duration_ms, int32_t poll_ms) |
| Result | spin_once (int32_t timeout_ms) |
Node — the primary interface for creating ROS entities.
Mirrors rclcpp::Node. Entities (publishers, subscriptions, services, etc.) are created through the node. The node holds a reference to the parent executor session.
Usage:
|
inline |
Default constructor — creates an uninitialized node.
|
inline |
Destructor — releases node resources.
|
inline |
| Result nros::Node::create_action_client | ( | ActionClient< A > & | out, |
| const char * | action_name, | ||
| const QoS & | qos = QoS::services() |
||
| ) |
| Result nros::Node::create_action_server | ( | ActionServer< A > & | out, |
| const char * | action_name, | ||
| const QoS & | qos = QoS::services(), |
||
| const 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, create_subscription_in, or create_publisher_in 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). |
| Result nros::Node::create_client | ( | Client< S > & | out, |
| const char * | service_name, | ||
| const QoS & | qos = QoS::services() |
||
| ) |
| Result nros::Node::create_client | ( | Client< S > & | out, |
| const char * | service_name, | ||
| F | callback, | ||
| const QoS & | qos = QoS::services(), |
||
| const 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.
CONSTRAINT: do not move out after this returns — the executor arena holds &out as the response dispatch context.
|
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 nros::Node::create_polling_action_client | ( | PollingActionClient< A > & | out, |
| const char * | action_name | ||
| ) |
Phase 122.3.d.b — Create an L1 polling-mode action client.
| Result nros::Node::create_polling_action_server | ( | 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 nros::Node::create_polling_subscription | ( | PollingSubscription< M > & | out, |
| const char * | topic, | ||
| const QoS & | qos = 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 nros::Node::create_publisher | ( | Publisher< M > & | out, |
| const char * | topic, | ||
| const QoS & | qos, | ||
| const 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. |
Phase 189.M3.1 — named-options overload. PublisherOptions is a reserved/empty struct (a publisher has no callback ⇒ no sched-context or message-info axis), so this simply forwards to the qos-only create. It exists for rclcpp symmetry and as the seam for future intra-process / loaned-message knobs.
| Result nros::Node::create_publisher | ( | Publisher< M > & | out, |
| const char * | topic, | ||
| const QoS & | qos = 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)). |
|
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 nros::Node::create_service | ( | Service< S > & | out, |
| const char * | service_name, | ||
| const QoS & | qos = QoS::services() |
||
| ) |
| Result nros::Node::create_service | ( | Service< S > & | out, |
| const char * | service_name, | ||
| F | callback, | ||
| const QoS & | qos = QoS::services(), |
||
| const 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).
CONSTRAINT: do not move out after this returns — the executor arena holds &out as the dispatch context.
| Result nros::Node::create_subscription | ( | Subscription< M > & | out, |
| const char * | topic, | ||
| const QoS & | qos, | ||
| const 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. options.sched_context (when set) lowers to a create-then-bind via nros_cpp_bind_handle_to_sched_context; options.message_info is reserved (M3.4). See SubscriptionOptions.
| 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. |
Phase 189.M3.1 — named-options overload. Delegates to the qos-only create, then lowers the non-QoS axes:
sched_context — when set (!= SCHED_CONTEXT_UNSET) and the created subscription exposes a bindable executor HandleId, create-then-bind via nros_cpp_bind_handle_to_sched_context; a failing bind tears the subscription back down and surfaces the FFI error. The current thin-wrapper subscription has no bindable handle (see Subscription<M>::has_sched_handle()), so the bind is skipped until a handle-returning create FFI lands (tracked with M3.4); the field is honoured transparently once that exists.message_info — reserved (M3.4); ignored today. | Result nros::Node::create_subscription | ( | Subscription< M > & | out, |
| const char * | topic, | ||
| const QoS & | qos = QoS::default_profile() |
||
| ) |
Create a subscription for a topic.
| 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 nros::Node::create_subscription | ( | Subscription< M > & | out, |
| const char * | topic, | ||
| F | callback, | ||
| const QoS & | qos = QoS::default_profile(), |
||
| const 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.
| M | Message type (must define TYPE_NAME, TYPE_HASH, ffi_deserialize). |
| out | Receives the initialized subscription (callback mode). |
| topic | Topic name (null-terminated). |
| callback | Handler invoked as callback(const M&) per sample. |
| qos | QoS profile. |
| options | Named subscription options (e.g. sched_context). |
| Result nros::Node::create_subscription_in | ( | const CallbackGroup & | group, |
| Subscription< M > & | out, | ||
| const char * | topic, | ||
| F | callback, | ||
| const QoS & | qos = QoS::default_profile(), |
||
| const 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.
| 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). |
| callback | Handler invoked as callback(const M&) per sample. |
| qos | QoS profile. |
| options | Named subscription options. |
| Result nros::Node::create_subscription_with_info | ( | Subscription< M > & | out, |
| const char * | topic, | ||
| F | callback, | ||
| const QoS & | qos = QoS::default_profile(), |
||
| const 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.
|
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 NROS_CLOCK_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 |
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). |
|
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 |
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 <nros/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 |
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 nros::Clock for what ROS time does and does not yet do here (issue 0789).
|
inline |
Const overload of get_clock().
|
inline |
Phase 88.12 — return the nros_log::Logger keyed on this node's name. The returned opaque handle is passed to the NROS_LOG_* macros in <nros/log.hpp>. Lifetime is 'static; callers must NOT free.
Returns NULL on an uninitialized node.
|
inline |
Get the node name.
|
inline |
Get the node namespace.
|
inline |
Check if the node is initialized and valid.
|
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 |
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".
|
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.
|
friend |
Create a node (convenience — uses the global executor).
This is the primary way to create nodes after calling nros::init().
|
friend |
Phase 274.W2 — create a node on an explicit executor handle.
Used by per-tier setup functions (emitted by nros codegen entry --lang cpp for multi-tier workspaces) where each tier's setup runs on the tier's borrowed executor, not the global one. The executor handle is the void* passed to the tier's setup(void* executor) callback.
|
friend |
|
friend |
Get the global executor handle for Future::wait().
Returns the raw storage pointer used by the global init()/spin_once() free functions. Use with Future::wait(nros::global_handle(), ...).
|
friend |
Initialize an nros session.
Opens a middleware connection. Must be called before creating nodes. Call shutdown() to clean up.
| locator | Middleware locator (e.g., "tcp/127.0.0.1:7447"), or nullptr for default. |
| domain_id | ROS domain ID (0-232). 0 = unset (env > baked macro > default decide); nros::kDomainIdExplicitZero (255) = explicitly domain 0 (issue #227). |
|
friend |
Initialize the nros session with an explicit session name.
session_name is the process-wide identifier used by the XRCE-DDS RMW backend to derive a unique session key. Two processes connecting to the same XRCE Agent MUST use distinct session names — otherwise the agent treats them as the same client and topic publishes don't cross-route. For zenoh / DDS backends the value is informational only.
Pick a name that's stable for the process and distinct from every other nros process you intend to share an agent with. Typical choice: the process's primary node name (e.g. "talker", "listener").
| locator | Middleware locator, or nullptr for default. |
| domain_id | ROS domain ID (0-232); 0 = unset, nros::kDomainIdExplicitZero = explicit domain 0. |
| session_name | Per-process session identifier. Must not be nullptr. |
|
friend |
Issue 1050 defect (3) — init with an explicit RMW backend name.
rmw is the BAKED rung of RFC-0045's precedence model A: a hosted $NROS_RMW still wins over it, and nullptr (or "") means "this image
names no backend", which resolves only when exactly one is registered.
Use it when the image knows which backend it wants and the registry cannot be trusted to contain only that one. On a hosted target it cannot: a Rust backend compiled into libnros_cpp.a registers from its .init_array ctor, which runs BEFORE main and therefore before the generated nros_app_register_backends() — so an archive carrying a backend the image never declared registers first. That is how a PX4 module declaring BACKENDS uorb came to open zenoh.
The plain init overloads reach this automatically when the build bakes NROS_ENTRY_RMW (nano_ros_entry(... RMW <name>)); call it directly only to choose at run time.
|
friend |
|
friend |
Check if the nros session is initialized.
|
friend |
Shut down the nros session.
Closes the middleware connection and frees all resources.
|
friend |
Phase 123.B.2 — block until nros::ok() returns false.
Mirror of rclcpp::spin(node). The typical pattern in user code is: install a SIGINT handler that calls nros::shutdown() (which flips ok() to false), then nros::spin() from main.
Returns the first non-success spin_once result, or Result::success() after a clean shutdown.
|
friend |
Spin for a duration (blocking).
Repeatedly calls spin_once() until duration_ms has elapsed. Convenience wrapper around the global executor.
| duration_ms | Total time to spin, in milliseconds. |
| poll_ms | Individual spin_once timeout (default: 10ms). |
|
friend |
Drive transport I/O and dispatch callbacks.
Call this periodically so subscriptions can receive data. When using manual-poll (no callbacks), this drives the network layer.
| timeout_ms | Maximum time to block waiting for I/O (default: 10ms). |