nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
Loading...
Searching...
No Matches
Getting Started

Prerequisites

  • A C++14 compiler (GCC 6+, Clang 5+, or arm-none-eabi-g++)
  • CMake >= 3.15
  • Rust nightly toolchain (needed to build libnros_cpp.a)
  • zenohd router (just build-zenohd in the nano-ros source tree, or install a matching version from zenoh releases)

1. Create a CMake Project

mkdir my-cpp-talker && cd my-cpp-talker
mkdir src

CMakeLists.txt (Phase 140 — add_subdirectory is the only consumption shape):

cmake_minimum_required(VERSION 3.22)
project(my_cpp_talker LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(NANO_ROS_PLATFORM posix)
set(NANO_ROS_RMW zenoh)
add_subdirectory(/path/to/nano-ros nano_ros)
# Generate C++ message bindings from .msg files
nano_ros_generate_interfaces(std_msgs
"msg/Int32.msg"
LANGUAGE CPP
SKIP_INSTALL
)
add_executable(my_cpp_talker src/main.cpp)
target_link_libraries(my_cpp_talker PRIVATE
NanoRos::NanoRosCpp
std_msgs__nano_ros_cpp
)
nros_platform_link_app(my_cpp_talker)

NanoRos::NanoRosCpp is the C++ INTERFACE target wired by the root CMake; nano_ros_generate_interfaces(... LANGUAGE CPP) becomes available the moment add_subdirectory(nano-ros) runs.

3. Code Generation

Generated message types use ROS 2 standard namespaces: std_msgs::msg::Int32, geometry_msgs::msg::Point, etc. Each generated type provides:

  • TYPE_NAME — fully-qualified ROS 2 type name (string literal)
  • TYPE_HASH — RIHS01 type hash, or TypeHashNotSupported on Humble
  • ffi_publish() / ffi_take() — codegen-emitted serialise + FFI calls

You never hand-write CDR serialisation. The generator handles it.

4. Write a Talker

src/main.cpp:

#include <cstdio>
#include <csignal>
#include <nros/nros.hpp>
#include "std_msgs.hpp"
static volatile sig_atomic_t g_running = 1;
static void on_signal(int) { g_running = 0; }
struct Ctx {
int count;
};
static void on_tick(void* ctx_ptr) {
auto* ctx = static_cast<Ctx*>(ctx_ptr);
std_msgs::msg::Int32 msg;
msg.data = ++ctx->count;
if (ctx->pub->publish(msg).ok()) {
std::printf("Published %d\n", ctx->count);
}
}
int main() {
NROS_TRY(nros::init("tcp/127.0.0.1:7447"));
nros::Node node;
NROS_TRY(nros::create_node(node, "cpp_talker"));
NROS_TRY(node.create_publisher(pub, "/chatter"));
Ctx ctx{ &pub, 0 };
nros::Timer timer;
NROS_TRY(node.create_timer(timer, 1000, on_tick, &ctx));
std::signal(SIGINT, on_signal);
while (g_running && nros::ok()) {
}
return 0;
}
Definition future.hpp:40
Definition node.hpp:158
Result create_timer(Timer &out, uint64_t period_ms, nros_cpp_timer_callback_t callback, void *context=nullptr)
Definition node.hpp:437
Result create_publisher(Publisher< M > &out, const char *topic, const QoS &qos=QoS::default_profile())
Definition publisher.hpp:272
Definition timer.hpp:42
Result spin_once(int32_t timeout_ms=10)
Definition nros.hpp:62
Result shutdown()
Definition node.hpp:663
bool ok()
Check if the nros session is initialized.
Definition node.hpp:717
Result init(const char *locator=nullptr, uint8_t domain_id=0)
Definition node.hpp:568
Result create_node(Node &out, const char *name, const char *ns=nullptr)
Definition node.hpp:728
Umbrella header — pulls in every public C++ API surface.
#define NROS_TRY(expr)
Definition result.hpp:90

NROS_TRY(expr) short-circuits on the first error — equivalent to the Rust ? operator. Available without NROS_CPP_STD.

5. Build and Run

mkdir build && cd build
cmake ..
cmake --build .
# Terminal 1
zenohd --listen tcp/127.0.0.1:7447
# Terminal 2
./my_cpp_talker

6. Listener

Replace the publisher loop with a subscription:

NROS_TRY(node.create_subscription(sub, "/chatter",
[](const std_msgs::msg::Int32& msg) {
std::printf("Received: %d\n", msg.data);
}));
while (nros::ok()) nros::spin_once(100);
Result create_subscription(Subscription< M > &out, const char *topic, const QoS &qos=QoS::default_profile())
Definition subscription.hpp:460

Zephyr Integration

In prj.conf:

CONFIG_NROS=y
CONFIG_NROS_CPP_API=y
CONFIG_NROS_RMW_ZENOH=y # or CONFIG_NROS_RMW_XRCE=y

In your application's CMakeLists.txt:

nros_generate_interfaces(std_msgs
"msg/Int32.msg"
LANGUAGE CPP
)
target_sources(app PRIVATE src/main.cpp)
target_link_libraries(app PRIVATE std_msgs__cpp)

See examples/zephyr/cpp/ for full Zephyr templates.

Std-Mode Convenience

For host platforms where the STL is available:

#define NROS_CPP_STD
#include <nros/nros.hpp>
#include <chrono>
using namespace std::chrono_literals;
nros::create_node(node, std::string("cpp_talker"));
node.create_subscription(sub, "/chatter",
std::function<void(const std_msgs::msg::Int32&)>{...});
node.create_timer(timer, 100ms, ...);

NROS_CPP_STD is opt-in; the freestanding surface remains the canonical API.