C++ API Reference
The HORUS C++ API provides first-class access to the real-time scheduler, zero-copy IPC, services, and actions. The bindings are generated from the Rust core via a C FFI layer (horus_c.h), so the C++ API has identical semantics to Rust and Python -- same shared memory transport, same scheduling guarantees, same message types.
Rust: See Rust API Reference for the native API. Python: See Python API for the scripting API.
// simplified
#include <horus/horus.hpp>
using namespace horus::literals;
Quick Reference -- All Classes
Core
| Class | Header | Description |
|---|---|---|
Scheduler | scheduler.hpp | Real-time scheduler -- creates, configures, and runs nodes |
NodeBuilder | scheduler.hpp | Builder for configuring a node before registration |
Node | node.hpp | Base class for struct-based nodes (like Rust impl Node) |
LambdaNode | node.hpp | Declarative node with builder pattern (like Python horus.Node) |
Communication
| Class | Header | Description |
|---|---|---|
Publisher<T> | topic.hpp | Sends messages to a topic via zero-copy SHM |
Subscriber<T> | topic.hpp | Receives messages from a topic via zero-copy SHM |
LoanedSample<T> | topic.hpp | Writable zero-copy buffer for publishing |
BorrowedSample<T> | topic.hpp | Read-only zero-copy buffer from subscribing |
Services and Actions
| Class | Header | Description |
|---|---|---|
ServiceClient | service.hpp | Synchronous request/response RPC client |
ServiceServer | service.hpp | Request/response RPC server with handler callback |
ActionClient | action.hpp | Long-running task client with goal tracking |
ActionServer | action.hpp | Long-running task server with accept/execute handlers |
GoalHandle | action.hpp | Handle to a running action goal |
GoalStatus | action.hpp | Enum: Pending, Active, Succeeded, Aborted, Canceled, Rejected |
Support Types
| Type | Header | Description |
|---|---|---|
Frequency | duration.hpp | Frequency in Hertz, created via 100_hz literal |
Duration | duration.hpp | Alias for std::chrono::microseconds |
Miss | error.hpp | Deadline miss policy: Warn, Skip, SafeMode, Stop |
Include Patterns
Single Include (Recommended)
#include <horus/horus.hpp>
using namespace horus::literals; // 100_hz, 5_ms, 200_us
This pulls in all headers: scheduler, node, topic, messages, services, actions, duration, and error types.
Selective Includes
#include <horus/scheduler.hpp> // Scheduler, NodeBuilder
#include <horus/node.hpp> // Node, LambdaNode
#include <horus/topic.hpp> // Publisher, Subscriber, LoanedSample, BorrowedSample
#include <horus/messages.hpp> // All 51 message types
#include <horus/service.hpp> // ServiceClient, ServiceServer
#include <horus/action.hpp> // ActionClient, ActionServer, GoalHandle
#include <horus/duration.hpp> // Frequency, Duration, literals
Message Category Includes
#include <horus/msg/geometry.hpp> // Point3, Vector3, Quaternion, Twist, Pose2D, Pose3D, ...
#include <horus/msg/sensor.hpp> // LaserScan, Imu, Odometry, JointState, BatteryState, ...
#include <horus/msg/control.hpp> // CmdVel, MotorCommand, JointCommand, PidConfig, ...
#include <horus/msg/navigation.hpp> // NavGoal, GoalResult, Waypoint, PathPlan
#include <horus/msg/diagnostics.hpp> // Heartbeat, DiagnosticStatus, EmergencyStop, ...
#include <horus/msg/detection.hpp> // Detection, Detection3D, TrackedObject, Landmark, ...
#include <horus/msg/vision.hpp> // CameraInfo, StereoInfo, RegionOfInterest
#include <horus/msg/force.hpp> // WrenchStamped, ForceCommand, ContactInfo, ...
#include <horus/msg/time.hpp> // Clock, TimeReference, SimSync, RateRequest
#include <horus/msg/input.hpp> // KeyboardInput, JoystickInput, AudioFrame
Minimal Example
#include <horus/horus.hpp>
using namespace horus::literals;
int main() {
auto sched = horus::Scheduler()
.tick_rate(100_hz)
.name("my_robot")
.prefer_rt();
auto cmd_pub = sched.advertise<horus::msg::CmdVel>("motor.cmd");
auto scan_sub = sched.subscribe<horus::msg::LaserScan>("lidar.scan");
sched.add("controller")
.rate(50_hz)
.budget(5_ms)
.on_miss(horus::Miss::Skip)
.tick([&] {
auto scan = scan_sub.recv();
if (!scan) return;
auto cmd = cmd_pub.loan();
cmd->linear = scan->ranges[0] > 1.0f ? 0.5f : 0.0f;
cmd->angular = 0.0f;
cmd_pub.publish(std::move(cmd));
})
.build();
sched.spin(); // blocks until Ctrl+C
}
Build Integration
HORUS C++ projects use horus.toml as the single source of truth. The CLI generates CMakeLists.txt into .horus/:
# horus.toml
[package]
name = "my_robot"
language = "cpp"
version = "0.1.0"
[dependencies]
horus = "0.1"
horus build # generates .horus/CMakeLists.txt, compiles
horus run # builds + runs
Duration and Frequency Literals
HORUS provides user-defined literals that match the Rust DurationExt trait. Import them with using namespace horus::literals;:
| Literal | Type | Example |
|---|---|---|
_hz | Frequency | 100_hz = 100 Hz tick rate |
_ms | Duration (microseconds) | 5_ms = 5000 us |
_us | Duration (microseconds) | 200_us = 200 us |
_ns | std::chrono::nanoseconds | 500_ns = 500 ns |
_s | Duration (microseconds) | 5_s = 5000000 us |
using namespace horus::literals;
auto freq = 100_hz; // Frequency(100.0)
auto dur = 5_ms; // std::chrono::microseconds(5000)
auto us = 200_us; // std::chrono::microseconds(200)
// Frequency helper methods
auto period = freq.period(); // 10000 us (10 ms)
auto budget = freq.budget_default(); // 8000 us (80% of period)
auto deadline = freq.deadline_default();// 9500 us (95% of period)
Cross-Language Equivalence
The C++ API mirrors Rust and Python exactly. Code written in one language can be ported line-by-line:
| Concept | Rust | C++ | Python |
|---|---|---|---|
| Scheduler | Scheduler::new() | horus::Scheduler() | horus.Scheduler() |
| Tick rate | .tick_rate(100.hz()) | .tick_rate(100_hz) | tick_rate=100 |
| Publish | topic.send(&msg)? | pub.send(msg) | node.send("topic", msg) |
| Subscribe | topic.recv() | sub.recv() | node.recv("topic") |
| Node | impl Node for T | class T : public horus::Node | horus.Node(name, tick) |
| Run | scheduler.spin() | sched.spin() | horus.run(node) |
All three languages share the same SHM transport. A Rust publisher and a C++ subscriber on the same topic communicate with zero serialization overhead.
Ownership and Move Semantics
All core types (Scheduler, Publisher<T>, Subscriber<T>, LoanedSample<T>, BorrowedSample<T>, ServiceClient, ServiceServer, ActionClient, ActionServer, GoalHandle) are move-only. Copy constructors and copy assignment are deleted. This matches Rust's ownership model -- each resource has exactly one owner.
auto pub = sched.advertise<horus::msg::CmdVel>("cmd");
// auto pub2 = pub; // COMPILE ERROR: copy deleted
auto pub2 = std::move(pub); // OK: ownership transferred
See Also
- Scheduler API -- Builder pattern, node registration, execution
- Node API -- Lifecycle, struct-based and lambda-based nodes
- Publisher and Subscriber API -- Zero-copy messaging, loan pattern
- Services and Actions API -- RPC and long-running tasks
- C++ Real-Time Guide -- Budget, deadline, miss policies, SCHED_FIFO
- C++ Error Handling -- Error types and recovery
- C++ Performance -- Benchmarks and optimization