|
nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
|
Namespaces | |
| namespace | detail |
Classes | |
| class | Client |
| class | ClientHandle |
| class | ClockQoS |
rclcpp::ClockQoS — KEEP_LAST(1), BEST_EFFORT, VOLATILE. ADOPT. More... | |
| class | Executor |
| struct | FixedSequence |
| struct | FixedString |
| struct | format_of |
| class | Future |
| class | GuardCondition |
| struct | LeSpan |
| class | Node |
| class | NodeBuilder |
| struct | NodeHandle |
| class | NodeWithTimers |
| class | OnShutdownCallbackHandle |
| class | ParameterEventsQoS |
| class | ParametersQoS |
| class | PollClient |
| class | PollingActionClient |
| class | PollingActionServer |
| class | PollingSubscription |
| class | PollService |
| class | PollSubscription |
| class | PreShutdownCallbackHandle |
| class | Publisher |
| class | QoS |
| class | Rate |
| class | ResultOf |
| class | ResultOf< void > |
| class | RosoutQoS |
| class | SensorDataQoS |
rmw_qos_profile_sensor_data — KEEP_LAST(5), BEST_EFFORT, VOLATILE. ADOPT. More... | |
| class | Service |
| class | ServicesQoS |
| class | ShutdownCallbackHandle |
| struct | Span |
| class | Stream |
| struct | StringView |
| class | Subscription |
| class | SystemDefaultsQoS |
| class | Timer |
| class | TimerHandle |
| class | TimerOps |
Typedefs | |
| using | IntegrityStatus = ::nros_cpp_integrity_status_t |
| using | Result = ResultOf< void > |
| using | ShutdownCallback = void(*)(void *context) |
| using | WallRate = Rate |
Enumerations | |
| enum class | DurabilityPolicy : int { Volatile = 0 , TransientLocal = 1 , SystemDefault = 2 , Unknown = 3 } |
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 | FutureReturnCode { SUCCESS , TIMEOUT , INTERRUPTED } |
| enum class | HistoryPolicy : int { KeepLast = 0 , KeepAll = 1 , SystemDefault = 2 , Unknown = 3 } |
History policy. Matches DDS HISTORY_QOS_POLICY. More... | |
| enum class | LivelinessPolicy : int { SystemDefault = 0 , Automatic = 1 , ManualByTopic = 2 , ManualByNode = 3 , Unknown = 4 } |
| enum class | ReliabilityPolicy : int { Reliable = 0 , BestEffort = 1 , SystemDefault = 2 , Unknown = 3 } |
| enum class | SerializationFormat : uint8_t { Cdr = 1 , Uorb = 2 } |
Variables | |
| constexpr uint8_t | kDomainIdExplicitZero = 255 |
| static constexpr size_t | PUBLISHER_TOPIC_NAME_MAX = 256 |
| static constexpr size_t | SUBSCRIPTION_TOPIC_NAME_MAX = 256 |
rclcpp::Node::declare_parameter<T>(name, default) — declare, then read back, returning the value in effect.
Re-declaring is not an error: a launch-seeded parameter is DECLARED before user code runs, and upstream's contract is that declare adopts the override. That adoption is now the store's own ALREADY_EXISTS answer followed by the read-back below, rather than a helper that copied a value between two stores. On any other failure the code default is returned.
rclcpp::Node is named by the friend declaration below and by the out-of-line Node::create_* bodies further down. rclcpp/node.hpp (included below, after the class, so a consumer pays only for the entities it uses) has the definition; a qualified friend needs the name to EXIST first, which an unqualified friend class Node; used to supply implicitly.
phase-427 W7 — declared in rclcpp::, which is where the definition lives.
| using rclcpp::IntegrityStatus = typedef ::nros_cpp_integrity_status_t |
E2E message-integrity status of one received sample (issue 0073): the sequence gap since the previous in-order sample, duplicate, and crc_valid (1 ok, 0 mismatch, -1 no CRC on the wire). The C++ spelling of the FFI struct (RFC-0089, 2026-10-13: ours-only names take rclcpp::), a typedef rather than a mirror so the two can never drift.
The name every caller writes for the value-less case, and the name this header's macros expand to.
| using rclcpp::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.
rclcpp::WallRate — the steady-clock rate. Identical to Rate here; see the "same clock" bullet in the envelope above.
|
strong |
|
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 |
Mirror of rclcpp::FutureReturnCode (issue 0339).
spin_until_future_complete used to return void, so a caller could not tell success from timeout and the standard idiom
could not be written against the shim at all.
| Enumerator | |
|---|---|
| SUCCESS | |
| TIMEOUT | The deadline passed with the future still pending. |
| INTERRUPTED |
|
|
strong |
|
strong |
Liveliness policy kind. Matches DDS LIVELINESS_QOS_POLICY.
SystemDefault is discriminant 0, the value rmw gives RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT; this enumerator was spelled LivelinessNone before phase-483. ManualByNode is ours-only — rmw deprecated it, so rclcpp's LivelinessPolicy does not list it.
| Enumerator | |
|---|---|
| SystemDefault | |
| Automatic | |
| ManualByTopic | |
| ManualByNode | |
| Unknown | The backend could not determine this policy. An ABSENCE, reportable by |
|
strong |
Reliability policy. Matches DDS RELIABILITY_QOS_POLICY and rclcpp::ReliabilityPolicy.
enum class, as upstream's is (phase-483 W1). These were unscoped while they lived in nros::; in rclcpp:: an unscoped KeepLast enumerator would collide with upstream's rclcpp::KeepLast profile helper.
|
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). |
|
inline |
phase-474 I2 – the application's start-up is over: arm the contract monitors of every executor that waits for this (CONFIG_NROS_MONITOR_ARM_ON_CALL). Call it where the application enters its running state, e.g. an INIT/RUN state machine's RUN transition.
Safe from any thread and from inside a callback (it bumps one atomic; each executor arms at its next spin). Before arming a verdict is counted (suppressed_before_arm) but not stored, logged or traced. Does nothing on an image whose monitors arm at the first spin, which is the default.
|
inline |
Create a node (convenience — uses the global executor).
This is the primary way to create nodes after calling rclcpp::init().
| out | Receives the initialized node. |
| name | Node name. |
| ns | Node namespace; nullptr or "" = unset (inherit the executor's), "/" = the root. See rclcpp::Node::create (issue 1473). |
|
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 ::rclcpp::TimerHandle rclcpp::create_timer | ( | NodeT && | node, |
| ::rclcpp::Clock * | clock, | ||
| ::rclcpp::Duration | period, | ||
| CallbackT && | callback | ||
| ) |
rclcpp::create_timer(node, clock, period, callback) — humble's only clock-taking timer verb. FREESTANDING since phase-476 W2.
ADOPT-BOUNDED: the clock is rclcpp::Clock* (what node->get_clock() returns), not rclcpp::Clock::SharedPtr; the period is truncated to whole MILLISECONDS; Humble's optional trailing group argument is not taken; and the result is a rclcpp::TimerHandle (rclcpp::TimerBase::SharedPtr names the same type).
|
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(rclcpp::global_handle(), ...).
DEFINED in <rclcpp/node.hpp>, beside the free functions Node befriends: rclcpp::init_in(argc, argv) (node.hpp) calls it, and an inline function used in a TU that never sees its definition is a link error waiting for the first caller (issue 1682's branch, found by -Wall).
|
inline |
rclcpp::init() — the zero-argument form. ADOPT.
rclcpp::init(argc, argv) — ADOPT-BOUNDED: --ros-args -r is honoured, every other ROS argument ABORTS the process naming it.
argv is parsed with rcl's grammar by the same code as Rust's nros::Context::new (nros_node::ros_args, reached through nros_cpp_install_argv_remaps):
-r / --remap [node:]from:=to inside --ros-args ... -- — HONOURED, as the FALLBACK beneath any remap the launch file projected for the same name (the generated entry's nros_cpp_declare_remap calls). That is rcl's own local-before-global order (rcl_remap_topic_name).-p / --param / --params-file, __node / __name / __ns, -e / --enclave, the log flags, any unknown token — REFUSED. Runtime parameters belong to RFC-0015 section 9's channel; node identity is launch-authoritative (RFC-0046). rclcpp throws UnknownROSArgsError for what rcl leaves unparsed, so refusing is the upstream behaviour too.--ros-args → identical to rclcpp::init().Why a refusal ABORTS rather than returns. Upstream's init returns void and a ported main does not check it, so this call site has nowhere to put a failure, and continuing is the one outcome RFC-0089 forbids: a -p that compiles and is silently dropped. The vector is validated BEFORE the session opens. rclcpp::init_in(argc, argv) honours the same arguments and RETURNS the refusal as a Result, for a caller that wants to handle it.
|
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, rclcpp::kDomainIdExplicitZero = explicit domain 0. |
| session_name | Per-process session identifier. Must not be nullptr. |
|
inline |
Issue 1434 — [init] with the primary session's NAMESPACE.
nros_cpp_init has always taken a namespace; no rclcpp::init overload had one, so every C++ entry passed nullptr and a launch-declared namespace reached the blob and stopped there. This is the overload the generated entry's run_components call reaches, with nros_boot_config_namespace(&NROS_BOOT_CONFIG).
node_namespace is the BAKED rung of RFC-0045's precedence model A, exactly like session_name beside it: on a hosted target $NROS_NODE_NAMESPACE still wins. nullptr means the image declares none — NOT the empty namespace — and resolves to the root the same way the 3-arg overload does today. Passing "" is the same statement, because an empty C string cannot be told apart from "unset" at this edge.
Additive rather than a fourth parameter on the 3-arg overload: that one is called by user code and by every board adapter in <rclcpp/detail/main.hpp>, and a defaulted parameter would make the two declarations ambiguous.
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); rclcpp::kDomainIdExplicitZero (255) = explicitly domain 0 (issue #227). |
|
inline |
Initialize an nros session, honouring --ros-args — the Result-returning twin of rclcpp::init(argc, argv), which has nowhere to put a refusal and aborts instead.
Reads the domain id, locator and RMW choice from the environment (ROS_DOMAIN_ID, NROS_LOCATOR, RMW_IMPLEMENTATION / NROS_RMW), as the 2-arg init_in does. No launch file is read here: a launch tree reaches an image at BUILD time — nros sync resolves it into the SystemModel and the generated entry (nano_ros_entry(... LAUNCH ...)) installs its node identities, remaps and parameters.
argc / argv are parsed as --ros-args with rcl's grammar, exactly as Rust's nros::Context::new does: -r/--remap rules are installed as the FALLBACK beneath the launch rules the generated entry declares; -p and --params-file are installed as parameter overrides when the image has a parameter store (phase-482 W5); and any other ROS argument (__node, --log-level, an unknown token, or -p with no store) makes this return ErrorCode::InvalidArgument BEFORE a session opens, naming the token. (0, nullptr) — what every RTOS board passes — is a no-op.
session_name falls back to "nros_cpp" when null (matches the 2-arg init_in 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.
rclcpp::KeepAll(). Same ADOPT-BOUNDED note as KeepLast.
ADOPT-BOUNDED: upstream returns a QoSInitialization — a history/depth pair a QoS is then built from — and this returns a whole QoS carrying the default reliability and durability. The porting spellings that matter, rclcpp::QoS(rclcpp::KeepLast(10)) and passing it straight to create_publisher, both resolve to the same profile either way. What does NOT carry over is using it as an initialiser for a profile whose other policies you meant to keep — rclcpp::SensorDataQoS(rclcpp::KeepLast(1)) has no equivalent here; write rclcpp::QoS().best_effort().keep_last(1).
|
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 rclcpp::Node::serialization_format(). check-format-macro-scope refuses a bridge-linked translation unit that reaches the underlying macro.
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 ResultOf<Node> envelope so users can write auto n = rclcpp::make_node("foo"); in the rclcpp-style.
|
inline |
Check if the nros session is initialized — and, like rclcpp::ok(), not asked to stop: issue 1732 folds in a guarded SIGTERM / SIGINT, so every while (rclcpp::ok()) loop returns and its rclcpp::shutdown() closes the session. The flag is only ever set where a hosted runner installed the guard (nros_cpp_termination_guard_install).
|
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.
The negation of operator==, and written as its negation so the two cannot disagree.
true when both profiles state the same value for every policy.
A WHOLE-PROFILE comparison, which is upstream's: two profiles that would be granted the same thing by a backend still compare unequal if they were written differently, because this compares what was REQUESTED.
|
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 rclcpp::init() opened and rclcpp::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. rclcpp::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 rclcpp::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. |
rclcpp::qos_policy_kind_to_cstr — see the entry point above, which it forwards to unchanged.
One QoS policy's name — rclcpp::qos_policy_kind_to_cstr.
| policy | ONE NROS_RMW_QOS_POLICY_* bit, as declared in <nros/rmw_entity.h> and as a backend advertises through the vtable's supported_qos_policies slot. |
"RELIABILITY", "DEADLINE", … — borrowed, static lifetime, never freed — or nullptr when policy is not exactly one policy bit.What this is FOR. An NROS_CPP_RET_NOT_ALLOWED from a create_* means the backend declined a policy, and the return code alone does not say which — while rmw_vtable.h's own supported_qos_policies block told the reader those creates fail "naming a policy". The refusal is logged with this name now (nros_node's validate_qos_or_report), and this is how a C++ caller spells the same policy in its own message.
Two deliberate differences from rclcpp, both from the same constraint: upstream takes a rclcpp::QosPolicyKind enum and returns a const char* over std::string-free storage; ours takes the MASK BIT, because the bitmask is the vocabulary this tree has — one set of twelve values shared by QoSPolicyMask in Rust and NROS_RMW_QOS_POLICY_* in C, held equal by check-qos-mask-derivation. And upstream returns "Invalid" for its invalid enumerator where we return nullptr: we have no invalid enumerator, and "no policy was identified" is a real answer a caller must be able to tell apart from a policy that was.
The bytes are rclc_qos_policy_kind_to_cstr's, which are nros_rmw::QoSPolicyMask::NAMED's. This header declares the C entry point rather than including <rclc/detail/nros_generated.h> — qos.hpp is deliberately self-contained (see issue 0112 at the top of this file) — and a signature drift cannot hide: nros.hpp pulls both this header and rclc/types.h, which reaches the generated declarations, so every C++ example is a translation unit holding both spellings and the compiler compares them. The declaration is spelled EXACTLY as nros_generated.h spells it, NROS_PUBLIC included. A C-linkage function declared in two scopes is one entity, so the two must agree — and a visibility attribute that appears on only one of them is "ignored because it conflicts with previous
declaration", a warning that becomes an error on this tree's -Werror lanes and whose text points at neither file's real problem.
|
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 |
rclcpp::shutdown() — ADOPT-BOUNDED. Upstream's channel here is bool, so ours is too (RFC-0089's error-channel rule: a ported API keeps upstream's channel even when that is bool).
It used to discard rclcpp::shutdown()'s Result and answer true unconditionally (phase-428 W5 finding 9, one site over from the seven create_* verbs and the only one the compiler already pointed at: just check cpp carried a standing -Wunused-result). NROS_NODISCARD on Result is what pointed at it (phase-427 W8) — a fini that failed reported success, which is the exact silence the attribute exists to break.
The bound: upstream returns false when the context was never initialised; rclcpp::shutdown() answers success() for that case (it is a no-op), so we return true there. false here means the teardown itself failed.
|
inline |
Shut down the nros session.
Closes the middleware connection and frees all resources.
|
inline |
|
inline |
Phase 123.B.2 — block until rclcpp::ok() returns false.
Mirror of rclcpp::spin(node). The typical pattern in user code is: install a SIGINT handler that calls rclcpp::shutdown() (which flips ok() to false), then rclcpp::spin() from main.
Returns the first non-success spin_once result, or Result::success() after a clean shutdown.
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). |
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). |
|
inline |
|
inline |
rclcpp::spin_until_future_complete(node, future[, timeout]).
ADOPT-BOUNDED: the timeout is int32_t MILLISECONDS (-1 = unbounded, the default), not a std::chrono::duration, so a ported 1s argument does not compile. It spins the PROCESS executor in 10 ms spin_once slices — there is one executor per task (RFC-0002) and no executor argument — so the deadline is quantised to 10 ms. Returns upstream's FutureReturnCode.
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.
Maximum topic name length stored inside a publisher (256). The topic name is owned C++-side, not inside the runtime handle.
Stays in rclcpp::: RFC-0089's flip moves the nine TYPES, and this is an implementation bound of one of them, not a name upstream declares.
Maximum topic name length stored inside a subscription. Mirrors PUBLISHER_TOPIC_NAME_MAX. Phase 87.6 thin-wrapper refactor: topic name owned C++-side, not inside a runtime handle.
Stays in rclcpp::: RFC-0089's flip moves the nine TYPES, and this is an implementation bound of one of them, not a name upstream declares.