|
nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
|
Namespaces | |
| namespace | detail |
Classes | |
| class | ActionClient |
| class | ActionServer |
| class | Client |
| class | Executor |
| class | Expected |
| struct | FixedSequence |
| struct | FixedString |
| struct | format_of |
| class | Future |
| class | GuardCondition |
| struct | LeSpan |
| class | Node |
| class | NodeBuilder |
| class | OnShutdownCallbackHandle |
| class | PollingActionClient |
| class | PollingActionServer |
| class | PollingSubscription |
| class | PreShutdownCallbackHandle |
| class | Publisher |
| class | QoS |
| class | Result |
| class | Service |
| class | ShutdownCallbackHandle |
| struct | Span |
| class | Stream |
| struct | StringView |
| class | Subscription |
| class | Timer |
Typedefs | |
| using | ShutdownCallback = void(*)(void *context) |
Enumerations | |
| enum class | CancelResponse : int32_t { Reject = 0 , Accept = 1 } |
| enum class | CancelReturnCode : int8_t { Ok = 0 , Rejected = 1 , UnknownGoal = 2 , GoalTerminated = 3 } |
| enum | DurabilityPolicy { Volatile = 0 , TransientLocal = 1 } |
Durability policy. Matches DDS DURABILITY_QOS_POLICY. More... | |
| enum class | ErrorCode : int32_t { Ok = 0 , Error = -1 , Timeout = -2 , InvalidArgument = -3 , NotFound = -4 , AlreadyExists = -5 , Full = -6 , NotInitialized = -7 , BadSequence = -8 , ServiceFailed = -9 , PublishFailed = -10 , SubscriptionFailed = -11 , NotAllowed = -12 , Rejected = -13 , TryAgain = -14 , Reentrant = -15 , Unsupported = -16 , TransportError = -100 } |
| enum class | GoalResponse : int32_t { Reject = 0 , AcceptAndExecute = 1 , AcceptAndDefer = 2 } |
| Goal acceptance response returned from the user's goal callback. More... | |
| enum class | GoalStatus : int8_t { Unknown = 0 , Accepted = 1 , Executing = 2 , Canceling = 3 , Succeeded = 4 , Canceled = 5 , Aborted = 6 } |
| enum | HistoryPolicy { KeepLast = 0 , KeepAll = 1 } |
History policy. Matches DDS HISTORY_QOS_POLICY. More... | |
| enum | LivelinessPolicy { LivelinessNone = 0 , LivelinessAutomatic = 1 , LivelinessManualByTopic = 2 , LivelinessManualByNode = 3 } |
| enum | ReliabilityPolicy { Reliable = 0 , BestEffort = 1 } |
Reliability policy. Matches DDS RELIABILITY_QOS_POLICY. More... | |
| enum class | SerializationFormat : uint8_t { Cdr = 1 , Uorb = 2 } |
Functions | |
| Result | create_node (Node &out, const char *name, const char *ns=nullptr) |
| Result | create_node_on (Node &out, void *executor_handle, const char *name, const char *ns=nullptr) |
| void * | global_handle () |
| Result | init (const char *locator, uint8_t domain_id, const char *session_name) |
| Result | init (const char *locator=nullptr, uint8_t domain_id=0) |
| Result | init_with_launch (const char *path, int argc=0, char **argv=nullptr, const char *session_name=nullptr) |
| Result | init_with_launch_auto (int argc=0, char **argv=nullptr, const char *session_name=nullptr) |
| Result | init_with_rmw (const char *rmw, const char *locator=nullptr, uint8_t domain_id=0, const char *session_name="node") |
| constexpr SerializationFormat | linked_format () |
| constexpr const char * | linked_format_name () |
| Expected< Node > | make_node (const char *name, const char *ns=nullptr) |
| bool | ok () |
| Check if the nros session is initialized. | |
| Result | on_shutdown (ShutdownCallback callback, void *context=nullptr, OnShutdownCallbackHandle *out=nullptr) |
| Result | pre_shutdown (ShutdownCallback callback, void *context=nullptr, PreShutdownCallbackHandle *out=nullptr) |
| bool | remove_on_shutdown_callback (OnShutdownCallbackHandle handle) |
| bool | remove_pre_shutdown_callback (PreShutdownCallbackHandle handle) |
| Result | shutdown () |
| Result | spin () |
| Result | spin (uint32_t duration_ms, int32_t poll_ms=10) |
| Result | spin_once (int32_t timeout_ms=10) |
Variables | |
| constexpr uint8_t | kDomainIdExplicitZero = 255 |
| static constexpr size_t | PUBLISHER_TOPIC_NAME_MAX = 256 |
| static constexpr size_t | SUBSCRIPTION_TOPIC_NAME_MAX = 256 |
| using nros::ShutdownCallback = typedef void (*)(void* context) |
Signature of a shutdown callback: void callback(void* context).
rclcpp takes std::function<void()>, which is a heap allocation per registration and needs the STL. This is freestanding C++ with no allocator, so the callback is a plain function pointer plus an opaque context the callee casts back to its own state — the same shape every other callback in this API uses. Capture what you need in a struct and pass its address.
|
strong |
Per-goal cancel decision returned from the user's cancel callback.
Issue 0796 — this is NOT the action_msgs/srv/CancelGoal RPC status; that is CancelReturnCode below. The two carry different meanings on overlapping values (Reject and Ok are both 0), so never cast between them. C names them apart too (nros_cancel_response_t vs nros_cancel_return_code_t), and Rust now does (nros_core::CancelResponse vs nros_core::CancelReturnCode).
| Enumerator | |
|---|---|
| Reject | |
| Accept | |
|
strong |
action_msgs/srv/CancelGoal RPC return code — the WHOLE-REQUEST outcome (issue 0796).
Written by a polling-tier server into send_cancel_reply, and read by a client from ActionClient::try_recv_cancel_response. Distinct from the per-goal CancelResponse above; these four discriminants are the wire contract, fixed by action_msgs.
| Enumerator | |
|---|---|
| Ok | |
| Rejected | |
| UnknownGoal | |
| GoalTerminated | |
|
strong |
Error codes returned by nros-cpp functions.
Values match the C nros_cpp_ret_t enum in <nros/nros_cpp_generated.h>. Issue #229 — value-identical to the C NROS_RET_* codes AND the NROS_CPP_RET_* FFI codes (one numbering across all three spaces), so Result(<any C-ABI return>) is correct by identity. The static_assert pin tables below and in parameter.hpp fail the build on re-divergence.
| Enumerator | |
|---|---|
| Ok | Success. |
| Error | Generic failure not covered by a more specific code. |
| Timeout | Operation deadline elapsed before completion. |
| InvalidArgument | Null pointer, empty topic name, or out-of-range value. |
| NotFound | Entity not found (topic, parameter, service…). |
| AlreadyExists | Already exists (duplicate declare/register). |
| Full | Static pool exhausted (executor slots, subscription buffers, …). |
| NotInitialized |
|
| BadSequence | Operation invalid in the current state (bad call sequence). |
| ServiceFailed | Service request/reply failed. |
| PublishFailed | Publish failed. |
| SubscriptionFailed | Subscription create/take failed. |
| NotAllowed | Operation not allowed for this entity/backend. |
| Rejected | Request was rejected — the peer considered it and declined. A goal rejected by an action server, or a QoS/ABI incompatibility. Distinct from |
| TryAgain | Transient — no data ready yet (non-blocking take). Retry later. |
| Reentrant | A blocking call was made from inside a callback. |
| Unsupported | Operation not implemented by the active backend. |
| TransportError | Underlying zenoh-pico / DDS transport rejected the operation. |
|
strong |
|
strong |
| enum nros::HistoryPolicy |
Liveliness policy kind. Matches DDS LIVELINESS_QOS_POLICY.
The enumerators keep their Liveliness prefix because these are UNSCOPED enums at namespace scope: a bare Automatic / None in nros:: would be far worse names than the redundancy costs. nros::LivelinessPolicy:: LivelinessAutomatic also works, so a qualified rclcpp-shaped spelling compiles. LivelinessManualByNode is ours-only — rmw deprecated it, so rclcpp's LivelinessPolicy does not list it.
| Enumerator | |
|---|---|
| LivelinessNone | |
| LivelinessAutomatic | |
| LivelinessManualByTopic | |
| LivelinessManualByNode | |
|
strong |
The serialization formats this image can name.
RFC-0088 D2 — the discriminant is image-local. It is assigned per build from the formats declared in that image; the low values below are reserved for the in-tree formats for readability and nothing more. Never persist one, and never compare one against a value another image produced — the string (linked_format_name()) is the identity that crosses an image boundary.
| Enumerator | |
|---|---|
| Cdr | OMG CDR as ROS 2 puts it on the wire, encapsulation header included. |
| Uorb | PX4's in-memory struct, verbatim — no encoding step at all (RFC-0011). |
Create a node (convenience — uses the global executor).
This is the primary way to create nodes after calling nros::init().
|
inline |
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.
|
inline |
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(), ...).
|
inline |
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. |
|
inline |
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). |
|
inline |
Phase 212.L.5 Pattern 2 — explicit-path variant of [init_with_launch_auto].
Verifies path exists (so misspelled paths fail fast) but does NOT yet parse the XML — the env overlay is the active source today. See the auto variant's notes for the follow-up plan.
|
inline |
Phase 212.L.5 Pattern 2 — launch-aware init.
Resolves runtime knobs (domain id, locator, RMW choice) in this order:
$NROS_RUNTIME_OVERLAY (JSON sidecar emitted by nros launch --emit-runtime-overlay). NOT yet consumed — placeholder for the follow-up wave.<CARGO_MANIFEST_DIR>/launch/*.xml. NOT yet parsed — the runtime trusts the launcher to project params/remaps into the child env before exec().ROS_DOMAIN_ID, NROS_LOCATOR, RMW_IMPLEMENTATION / NROS_RMW. This is the active overlay channel today.argc / argv are reserved for the structured --ros-args parse that lands with the runtime-overlay wave. They are accepted and ignored for forward-compat.
session_name falls back to "nros_cpp" when null (matches the 2-arg init overload).
|
inline |
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.
|
constexpr |
The format the backend this image links speaks.
Only meaningful in a single-backend image. A bridge image links two backends and has no single answer; it asks per session instead, with nros::Node::serialization_format(). check-format-macro-scope refuses a bridge-linked translation unit that reaches the underlying macro.
|
constexpr |
The cross-image identity string of linked_format() (RFC-0088 D2).
const char*, so the header stays usable against Zephyr's minimal libcpp. Derived from the discriminant rather than emitted beside it: cbindgen maps no Rust &str to a C constant, so a second generated macro would be a second authored spelling with nothing tying the two together.
Phase 123.B.4 — value-returning factory. Wraps create_node in the Expected<Node> envelope so users can write auto n = nros::make_node("foo"); in the rclcpp-style.
|
inline |
Check if the nros session is initialized.
|
inline |
Register a callback to run AFTER the global session's entities are torn down — rclcpp::on_shutdown. Issue 0790.
The entities are gone by the time it runs; use [pre_shutdown] for anything that needs the wire.
|
inline |
Register a callback to run BEFORE the global session's entities are torn down — issue 0790.
rclcpp hangs the shutdown hooks on Context, which nano-ros does not have (phase-379's init stage records the collapse into one support object), so they live on the executor — here, the global one nros::init() opened and nros::shutdown() closes.
This is the phase with no workaround: the callback runs while every entity still works, so a node can publish a final state, answer a last request, park an actuator or release a bus. nros::on_shutdown below runs after teardown, when none of that is possible any more.
A CLEAN-STOP facility: a watchdog reset, a hard fault or an abort does not come through nros::shutdown(), so it does not come through here either.
| callback | Function to invoke. Must not be null. |
| context | Opaque pointer handed back to callback. Must stay valid until the callback runs or is removed. |
| out | Receives the removal handle. Optional. |
|
inline |
Remove a callback registered with [on_shutdown].
|
inline |
Remove a callback registered with [pre_shutdown]. true when handle named a live one — "it was not there" is an ordinary answer, as in rclcpp.
|
inline |
Shut down the nros session.
Closes the middleware connection and frees all resources.
|
inline |
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.
|
inline |
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). |
|
inline |
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). |
|
constexpr |
Issue #227 — pass as domain_id to request an EXPLICIT domain 0. Plain 0 is the UNSET sentinel (defers to ROS_DOMAIN_ID env on hosted, then the baked NROS_ENTRY_DOMAIN_ID macro, then the default — the #206 model-A ladder), so a literal domain 0 is otherwise unreachable once the image bakes a nonzero domain. Valid domains cap at 232, so 255 is unambiguous. Mirrors NROS_DOMAIN_ID_EXPLICIT_ZERO in the C API (nros_generated.h); hosted env still overrides it under model A.
|
staticconstexpr |
Maximum topic name length stored inside nros::Publisher<M> (256). The topic name is owned C++-side, not inside the runtime handle.
|
staticconstexpr |
Maximum topic name length stored inside nros::Subscription<M>. Mirrors PUBLISHER_TOPIC_NAME_MAX. Phase 87.6 thin-wrapper refactor: topic name owned C++-side, not inside a runtime handle.