Node Trait

MethodSignatureDefaultDescription
namefn name(&self) -> &strType nameUnique node identifier
initfn init(&mut self) -> Result<()>Ok(())Called once at startup
tickfn tick(&mut self)requiredMain loop, called repeatedly
shutdownfn shutdown(&mut self) -> Result<()>Ok(())Called once at cleanup
publishersfn publishers(&self) -> Vec<TopicMetadata>vec![]Topic metadata for pubs
subscribersfn subscribers(&self) -> Vec<TopicMetadata>vec![]Topic metadata for subs
on_errorfn on_error(&mut self, error: &str)Logs via hlog!Custom error recovery
is_safe_statefn is_safe_state(&self) -> booltrueSafety monitor query
enter_safe_statefn enter_safe_state(&mut self)No-opEmergency stop transition

NodeBuilder

MethodParameterDescription
orderu32Execution priority (lower = earlier). 0-9 critical, 10-49 high, 50-99 normal, 100+ low
rateFrequencyTick rate. Auto-derives budget (80%) and deadline (95%). Auto-enables RT for BestEffort nodes
budgetDurationMax tick execution time. Overrides auto-derived 80% budget
deadlineDurationAbsolute latest tick finish. Overrides auto-derived 95% deadline
on_missMissDeadline miss policy: Warn, Skip, SafeMode, Stop
computeParallel thread pool execution (CPU-bound work)
on&strEvent-triggered on topic update
async_ioTokio blocking pool execution (I/O-bound work)
failure_policyFailurePolicyPer-node failure handling: fatal(), restart(n, backoff), skip(), ignore()
priorityi32OS-level SCHED_FIFO priority (1-99). RT nodes only
coreusizePin RT thread to CPU core via sched_setaffinity
watchdogDurationPer-node watchdog timeout (overrides global)
buildFinalize and register node. Returns Result<&mut Scheduler>

Scheduler

MethodParameterDescription
Scheduler::new()Constructor with RT capability auto-detection
Scheduler::simulation()Constructor that skips RT detection (for tests)
name&strSet scheduler name (default: "Scheduler")
tick_rateFrequencyGlobal tick rate (e.g. 1000_u64.hz())
deterministicboolSequential execution, SimClock, fixed dt, seeded RNG
prefer_rtTry mlockall + SCHED_FIFO, degrade gracefully
require_rtPanic if RT unavailable
cores&[usize]Pin scheduler threads to CPU cores
watchdogDurationFrozen-node detection timeout
blackboxusizeFlight recorder size in MB
max_deadline_missesu64Emergency stop threshold (default: 100)
verboseboolEnable/disable executor thread logging
with_recordingEnable session recording
telemetry&strExport endpoint ("udp://host:port")
addimpl NodeReturns NodeBuilder for fluent configuration
set_node_rate(&str, Frequency)Change node rate at runtime
runStart the main loop (blocks)
run_forDurationRun for a fixed duration
run_ticksu64Run exactly N ticks
run_untilFnMut() -> bool, u64Run until predicate or max ticks
tick_onceSingle-tick execution (sim/test). Lazy-inits on first call
stopSignal scheduler to stop
statusHuman-readable status report

Topic<T>

MethodSignatureDescription
newfn new(name: impl Into<String>) -> Result<Self>Create topic with auto-detected backend
sendfn send(&self, msg: T)Fire-and-forget with bounded retry
try_sendfn try_send(&self, msg: T) -> Result<(), T>Non-blocking send, returns msg on failure
send_blockingfn send_blocking(&self, msg: T, timeout: Duration) -> Result<(), SendBlockingError>Blocking send with spin-yield-sleep strategy
recvfn recv(&self) -> Option<T>Receive next message
try_recvfn try_recv(&self) -> Option<T>Non-blocking receive (no logging)
read_latestfn read_latest(&self) -> Option<T> where T: CopyPeek latest without advancing consumer
namefn name(&self) -> &strTopic name
metricsfn metrics(&self) -> TopicMetricsSend/recv counts and failure counts

Services

TypeMethodDescription
ServiceClient<S>new() -> Result<Self>Create blocking client for service S
ServiceClient<S>call(req, timeout) -> Result<S::Response>Blocking RPC call
ServiceClient<S>call_with_retry(req, timeout, RetryConfig) -> Result<S::Response>Call with retry policy
AsyncServiceClient<S>new() -> Result<Self>Create non-blocking client
AsyncServiceClient<S>call_async(req) -> PendingResponseNon-blocking call, returns handle
ServiceServerBuilder<S>new() -> SelfStart building a server
ServiceServerBuilder<S>on_request(Fn(Req) -> Result<Res, String>) -> SelfSet request handler
ServiceServerBuilder<S>build() -> Result<ServiceServer<S>>Spawn background polling thread
ServiceServer<S>stop(&self)Stop server (also happens on drop)

Actions

TypeMethodDescription
ActionClientBuilder<A>new() -> SelfStart building an action client
ActionClientBuilder<A>build() -> Result<ActionClientNode<A>>Create client node
ActionClientNode<A>send_goal(goal) -> ClientGoalHandle<A>Send goal, get tracking handle
ActionClientNode<A>send_goal_with_priority(goal, GoalPriority) -> ClientGoalHandle<A>Send prioritized goal
ActionClientNode<A>cancel_goal(GoalId)Cancel a running goal
ClientGoalHandle<A>status() -> GoalStatusCurrent goal status
ClientGoalHandle<A>is_active() -> boolStill running?
ClientGoalHandle<A>is_done() -> boolTerminal state?
ClientGoalHandle<A>result() -> Option<A::Result>Get result if complete
ClientGoalHandle<A>last_feedback() -> Option<A::Feedback>Most recent feedback
ClientGoalHandle<A>await_result(timeout) -> Option<A::Result>Block until done or timeout
ClientGoalHandle<A>await_result_with_feedback(timeout, Fn(&Feedback))Block with feedback callback
ActionServerBuilder<A>new() -> SelfStart building an action server
ActionServerBuilder<A>on_goal(Fn(Goal) -> GoalResponse) -> SelfAccept/reject handler
ActionServerBuilder<A>on_cancel(Fn(GoalId) -> CancelResponse) -> SelfCancel handler
ActionServerBuilder<A>on_execute(Fn(ServerGoalHandle) -> GoalOutcome) -> SelfExecution handler
ActionServerBuilder<A>build() -> Result<ActionServerNode<A>>Create server node
ServerGoalHandle<A>goal() -> &A::GoalAccess goal data
ServerGoalHandle<A>is_cancel_requested() -> boolClient requested cancel?
ServerGoalHandle<A>should_abort() -> boolCancel or preempt requested?
ServerGoalHandle<A>publish_feedback(feedback)Send progress feedback
ServerGoalHandle<A>succeed(result) -> GoalOutcomeComplete successfully
ServerGoalHandle<A>abort(result) -> GoalOutcomeServer-side abort
ServerGoalHandle<A>canceled(result) -> GoalOutcomeAcknowledge cancellation
ServerGoalHandle<A>preempted(result) -> GoalOutcomePreempted by higher-priority goal

TransformFrame

MethodSignatureDescription
newfn new() -> SelfCreate empty TF tree (default config)
register_framefn register_frame(&self, name: &str, parent: Option<&str>) -> Result<FrameId>Add a frame to the tree
tffn tf(&self, src: &str, dst: &str) -> Result<Transform>Lookup latest transform between frames
tf_atfn tf_at(&self, src: &str, dst: &str, timestamp_ns: u64) -> Result<Transform>Lookup transform at a specific time
tf_at_strictfn tf_at_strict(&self, src: &str, dst: &str, timestamp_ns: u64) -> Result<Transform>Strict time lookup (no interpolation beyond tolerance)
tf_at_with_tolerancefn tf_at_with_tolerance(&self, src: &str, dst: &str, ts: u64, tol: u64) -> Result<Transform>Custom time tolerance
update_transformfn update_transform(&self, parent: &str, child: &str, ts: u64, tf: Transform) -> Result<()>Update a frame's transform
has_framefn has_frame(&self, name: &str) -> boolCheck if frame exists
all_framesfn all_frames(&self) -> Vec<String>List all registered frame names
frame_countfn frame_count(&self) -> usizeNumber of registered frames
tf_by_idfn tf_by_id(&self, src: FrameId, dst: FrameId) -> Option<Transform>Lookup by numeric ID (fast path)
tf_at_by_idfn tf_at_by_id(&self, src: FrameId, dst: FrameId, ts: u64) -> Option<Transform>Time-based lookup by ID

DurationExt

MethodInputOutputExample
nsu64, f64, i32Duration500_u64.ns()
usu64, f64, i32Duration200_u64.us()
msu64, f64, i32Duration1_u64.ms()
secsu64, f64, i32Duration5_u64.secs()
hzu64, f64, i32Frequency100_u64.hz()

Frequency methods: value() -> f64, period() -> Duration, budget_default() -> Duration (80%), deadline_default() -> Duration (95%).

Enums

ExecutionClass

VariantDescription
RtDedicated RT thread with spin-wait timing
ComputeParallel thread pool for CPU-bound work
Event(String)Triggered by topic updates
AsyncIoTokio blocking pool for I/O-bound work
BestEffortDefault -- main tick loop, sequential

Miss

VariantDescription
WarnLog warning and continue (default)
SkipSkip this tick, resume next cycle
SafeModeCall enter_safe_state(), continue ticking in safe mode
StopStop the entire scheduler

NodeState

VariantDescription
UninitializedCreated but not started
Initializinginit() in progress
RunningNormal operation
Stoppingshutdown() in progress
StoppedCleanly stopped
Error(String)Error occurred, still running
Crashed(String)Fatal error, unresponsive

HealthStatus

VariantDescription
HealthyOperating normally
WarningDegraded performance (slow ticks, missed deadlines)
ErrorErrors occurring but still running
CriticalFatal errors, about to crash
UnknownNo heartbeat received (default)

Standard Message Types

Geometry

TypeFieldsSize
Pose2Dx: f64, y: f64, theta: f6424 B
Pose3Dtranslation: [f64; 3], rotation: [f64; 4]56 B
Point3x: f64, y: f64, z: f6424 B
Vector3x: f64, y: f64, z: f6424 B
Quaternionx: f64, y: f64, z: f64, w: f6432 B
Twistlinear: [f64; 3], angular: [f64; 3]48 B
Accellinear: [f64; 3], angular: [f64; 3]48 B
TransformStampedparent: str, child: str, timestamp_ns: u64, transform: Transformvar
PoseStampedpose: Pose3D, timestamp_ns: u64, frame_id: strvar
PoseWithCovariancepose: Pose3D, covariance: [f64; 36]344 B
TwistWithCovariancetwist: Twist, covariance: [f64; 36]336 B
AccelStampedaccel: Accel, timestamp_ns: u64, frame_id: strvar

Sensors

TypeFieldsSize
Imuorientation: [f64;4], angular_velocity: [f64;3], linear_acceleration: [f64;3]80 B
LaserScanangle_min/max: f32, angle_increment: f32, ranges: Vec<f32>, intensities: Vec<f32>var
Odometrypose: Pose2D, twist: Twist, timestamp_ns: u64var
JointStateposition: Vec<f64>, velocity: Vec<f64>, effort: Vec<f64>, name: Vec<String>var
BatteryStatevoltage: f32, percentage: f32, current: f32, charging: bool, temperature: f3217 B
RangeSensorsensor_type: u8, range: f32, min_range: f32, max_range: f32, fov: f3217 B
NavSatFixlatitude: f64, longitude: f64, altitude: f64, status: i8, covariance: [f64;9]var
MagneticFieldfield: [f64; 3], covariance: [f64; 9]96 B
Temperaturetemperature: f64, variance: f6416 B
FluidPressurepressure: f64, variance: f6416 B
Illuminanceilluminance: f64, variance: f6416 B

Control

TypeFieldsSize
CmdVellinear: f32, angular: f328 B
MotorCommandleft: f64, right: f6416 B
ServoCommandservo_id: u8, position: f32, speed: f32, torque_limit: f3213 B
JointCommandname: Vec<String>, position: Vec<f64>, velocity: Vec<f64>, effort: Vec<f64>var
PidConfigkp: f64, ki: f64, kd: f64, output_min: f64, output_max: f6440 B
TrajectoryPointposition: [f64;3], linear_velocity: Vec3, angular_velocity: Vec3, time: f64var
DifferentialDriveCommandleft: f64, right: f64, timestamp_ns: u6424 B
TypeFieldsSize
NavGoaltarget_pose: Pose2D, position_tolerance: f64, angle_tolerance: f6440 B
GoalResultgoal_id: u32, status: GoalStatus, message: Stringvar
NavPathwaypoints: Vec<Waypoint>var
PathPlanposes: Vec<Pose2D>, cost: f64var
Waypointpose: Pose2D, speed: f64, tolerance: f6440 B
OccupancyGridwidth: u32, height: u32, resolution: f32, origin: Pose2D, data: Vec<i8>var
CostMapwidth: u32, height: u32, resolution: f32, origin: Pose2D, data: Vec<u8>var
VelocityObstacleposition: Point3, velocity: Vector3, radius: f6456 B

Vision

TypeFields
CompressedImageformat: String, data: Vec<u8>, timestamp_ns: u64
CameraInfowidth: u32, height: u32, fx: f64, fy: f64, cx: f64, cy: f64, distortion: Vec<f64>
RegionOfInterestx: u32, y: u32, width: u32, height: u32
StereoInfoleft: CameraInfo, right: CameraInfo, baseline: f64

Perception and Detection

TypeFields
BoundingBox2Dx: f32, y: f32, width: f32, height: f32
BoundingBox3Dcx: f32, cy: f32, cz: f32, length: f32, width: f32, height: f32, yaw: f32
Detectionclass_name: String, confidence: f32, bbox: BoundingBox2D
Detection3Dclass_name: String, confidence: f32, bbox: BoundingBox3D
Landmarkx: f32, y: f32, visibility: f32, index: u32
Landmark3Dx: f32, y: f32, z: f32, visibility: f32, index: u32
LandmarkArraylandmarks: Vec<Landmark>, landmarks_3d: Vec<Landmark3D>
SegmentationMaskwidth: u32, height: u32, class_ids: Vec<u8>
TrackedObjecttrack_id: u64, bbox: BoundingBox2D, class_id: u32, confidence: f32
PlaneDetectioncoefficients: [f64;4], center: Point3, normal: Vector3

Force and Haptics

TypeFields
WrenchStampedforce: Vector3, torque: Vector3, timestamp_ns: u64, frame_id: String
ForceCommandforce: Vector3, torque: Vector3, frame_id: String
ImpedanceParametersstiffness: [f64;6], damping: [f64;6], inertia: [f64;6]
HapticFeedbackforce: Vector3, vibration_frequency: f64, vibration_amplitude: f64
ContactInfostate: ContactState, force_magnitude: f64, contact_point: Point3, normal: Vector3

Diagnostics

TypeFields
Heartbeatnode_name: String, node_id: u32, timestamp_ns: u64, sequence: u64, health: HealthStatus
DiagnosticStatuslevel: StatusLevel, code: u32, message: String, values: Vec<DiagnosticValue>
DiagnosticReportstatuses: Vec<DiagnosticStatus>, timestamp_ns: u64
EmergencyStoptriggered: bool, source: String, reason: String, timestamp_ns: u64
SafetyStatusstate: NodeStateMsg, health: HealthStatus, violations: Vec<String>
ResourceUsagecpu_percent: f32, memory_bytes: u64, thread_count: u32
NodeHeartbeatnode_name: String, tick_count: u64, health: HealthStatus

Input

TypeFields
JoystickInputjoystick_id: u32, input_type: InputType, button_id/axis_id: u32, value: f32
KeyboardInputkey: String, code: u32, modifiers: Vec<String>, pressed: bool

Clock

TypeFields
Clocktimestamp_ns: u64, clock_type: ClockType
TimeReferencetime_ref_ns: u64, source_name: String, offset_ns: i64

Python API

Node (Functional)

ParameterTypeDefaultDescription
nameOptional[str]Auto-generated UUIDUnique node name
subsstr, list, or dictNoneTopics to subscribe to
pubsstr, list, or dictNoneTopics to publish to
tickCallable[[Node], None]NoneMain loop callback (can be async def)
initCallable[[Node], None]NoneStartup callback
shutdownCallable[[Node], None]NoneCleanup callback
on_errorCallable[[Node, Exception], None]NoneError handler
ratefloat30Tick rate in Hz

Node Methods

MethodSignatureDescription
has_msghas_msg(topic: str) -> boolCheck if messages available (peeks)
recvrecv(topic: str) -> Optional[Any]Receive next message
recv_allrecv_all(topic: str) -> List[Any]Drain all available messages
sendsend(topic: str, data: Any) -> boolSend data to topic
log_infolog_info(message: str) -> NoneLog info (during tick only)
log_warninglog_warning(message: str) -> NoneLog warning (during tick only)
log_errorlog_error(message: str) -> NoneLog error (during tick only)
log_debuglog_debug(message: str) -> NoneLog debug (during tick only)
request_stoprequest_stop() -> NoneRequest scheduler shutdown
publisherspublishers() -> List[str]List pub topic names
subscriberssubscribers() -> List[str]List sub topic names

Scheduler

MethodSignatureDescription
__init__Scheduler(*, tick_rate=1000.0, rt=False, deterministic=False, blackbox_mb=0, watchdog_ms=0, recording=False)Constructor
addadd(node, order=100, rate=None, rt=False, failure_policy=None, on_miss=None, budget=None, deadline=None) -> SchedulerAdd node with options
nodenode(node) -> NodeBuilderFluent builder API
runrun(duration=None) -> NoneRun scheduler (blocks). Pass seconds or None for forever
stopstop() -> NoneSignal stop
set_node_rateset_node_rate(name: str, rate: float) -> NoneChange node rate at runtime
get_node_statsget_node_stats(name: str) -> DictPer-node metrics
get_all_nodesget_all_nodes() -> List[Dict]All node metrics
get_node_countget_node_count() -> intNumber of registered nodes
has_nodehas_node(name: str) -> boolCheck node exists
get_node_namesget_node_names() -> List[str]All node names
statusstatus() -> strScheduler status string
capabilitiescapabilities() -> Optional[Dict]RT capabilities
has_full_rthas_full_rt() -> boolFull RT available?
safety_statssafety_stats() -> Optional[Dict]Budget overruns, deadline misses
current_tickcurrent_tick() -> intTick counter

horus.run()

ParameterTypeDescription
*nodesNodeNode instances to run (positional)
durationOptional[float]Seconds to run (None = forever)
tick_ratefloatGlobal tick rate in Hz (default: 1000.0)
deterministicboolSimClock, fixed dt, seeded RNG
rtboolEnable memory locking + RT scheduling
watchdog_msintWatchdog timeout (0 = disabled)
blackbox_mbintFlight recorder size (0 = disabled)
recordingboolEnable session recording

CLI Commands

CommandUsageDescription
horus newhorus new mybot [--python|--rust|--cpp]Create a new project
horus inithorus init [-n name]Initialize workspace in current directory
horus runhorus run [files...] [-r] [--record name]Build and run project
horus buildhorus build [files...] [-r] [-c]Build without running
horus testhorus test [FILTER] [-r] [--sim] [--integration]Run tests
horus checkhorus check [PATH] [--full] [--health]Validate manifest and sources
horus cleanhorus clean [--shm] [--all] [-n]Clean build artifacts and SHM
horus launchhorus launch file.yaml [--dry-run]Launch multiple nodes from YAML
horus topichorus topic list|echo|pub|infoTopic introspection
horus nodehorus node list|info|killNode management
horus paramhorus param get|set|list|deleteRuntime parameters
horus framehorus frame list|echo|treeTransformFrame operations (alias: horus tf)
horus servicehorus service list|call|infoService interaction
horus actionhorus action list|info|send-goal|cancel-goalAction interaction
horus msghorus msg list|show|fieldsMessage type introspection
horus loghorus log [NODE] [-l level] [-f] [-n N]View and filter logs
horus blackboxhorus blackbox [-a] [-f] [--json]Flight recorder inspection
horus monitorhorus monitor [PORT] [--tui]Live TUI/web dashboard
horus installhorus install name[@ver] [--driver|--plugin]Install package or driver