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

ClassHeaderDescription
Schedulerscheduler.hppReal-time scheduler -- creates, configures, and runs nodes
NodeBuilderscheduler.hppBuilder for configuring a node before registration
Nodenode.hppBase class for struct-based nodes (like Rust impl Node)
LambdaNodenode.hppDeclarative node with builder pattern (like Python horus.Node)

Communication

ClassHeaderDescription
Publisher<T>topic.hppSends messages to a topic via zero-copy SHM
Subscriber<T>topic.hppReceives messages from a topic via zero-copy SHM
LoanedSample<T>topic.hppWritable zero-copy buffer for publishing
BorrowedSample<T>topic.hppRead-only zero-copy buffer from subscribing

Services and Actions

ClassHeaderDescription
ServiceClientservice.hppSynchronous request/response RPC client
ServiceServerservice.hppRequest/response RPC server with handler callback
ActionClientaction.hppLong-running task client with goal tracking
ActionServeraction.hppLong-running task server with accept/execute handlers
GoalHandleaction.hppHandle to a running action goal
GoalStatusaction.hppEnum: Pending, Active, Succeeded, Aborted, Canceled, Rejected

Support Types

TypeHeaderDescription
Frequencyduration.hppFrequency in Hertz, created via 100_hz literal
Durationduration.hppAlias for std::chrono::microseconds
Misserror.hppDeadline miss policy: Warn, Skip, SafeMode, Stop

Include Patterns

#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;:

LiteralTypeExample
_hzFrequency100_hz = 100 Hz tick rate
_msDuration (microseconds)5_ms = 5000 us
_usDuration (microseconds)200_us = 200 us
_nsstd::chrono::nanoseconds500_ns = 500 ns
_sDuration (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:

ConceptRustC++Python
SchedulerScheduler::new()horus::Scheduler()horus.Scheduler()
Tick rate.tick_rate(100.hz()).tick_rate(100_hz)tick_rate=100
Publishtopic.send(&msg)?pub.send(msg)node.send("topic", msg)
Subscribetopic.recv()sub.recv()node.recv("topic")
Nodeimpl Node for Tclass T : public horus::Nodehorus.Node(name, tick)
Runscheduler.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