Python API

Complete Python API documentation for HORUS. The Python bindings are built with PyO3, exposing the core Rust framework to Python with zero-copy shared memory IPC.

Python Bindings

Full reference for the HORUS Python bindings:

  • Node — Create nodes with tick, init, and shutdown callbacks
  • Topic — Unified pub/sub with typed messages (CmdVel, Pose2D, Imu, etc.)
  • Scheduler — Node execution with priority ordering and rate control
  • Scheduler configuration — tick_rate, rt, deterministic, watchdog_ms, blackbox_mb, recording, cores, net keyword arguments
  • TransformFrame / Transform — Coordinate frame management
  • TensorPool / Tensor — Zero-copy shared memory tensors; .numpy() and .torch() share the buffer via the array interface

Custom Messages

Create your own typed messages in Python:

  • Dict topics — no build step: node.send('robot.status', {'battery': 85, 'ok': True}), node.recv('robot.status') returns a dict
  • Compiled messageshorus.msggen.register_message() + build_messages() (runs maturin develop --release, needs a horus_py source checkout). A real Rust type with named fields, but it still travels over the generic MessagePack path, not the zero-copy backend the built-in types use — see Custom Messages
  • YAML schema support for team projects

Async Nodes

Asynchronous Python nodes for non-blocking I/O operations.


Quick Reference

Core Classes

ClassDescription
NodeComputation unit with tick/init/shutdown callbacks
TopicUnified pub/sub channel with typed messages
SchedulerNode execution orchestrator
Scheduler kwargsConstructor keyword arguments: tick_rate, rt, deterministic, watchdog_ms, blackbox_mb, recording, cores, net
NodeStateNode lifecycle states

There is no importable horus.NodeInfo or horus.Priority — neither name is part of the public Python API. Runtime context and logging reach you through the node object passed to init / tick / shutdown: node.log_info(), node.log_warning(), node.log_error(), node.log_debug() (these only emit while the scheduler is driving the node). Node(order=...) sets the registration priority, and Node(priority=...) is the SCHED_FIFO real-time priority (1-99, where higher is more urgent).

order does not sequence ticks in Python. Every Python node carries a rate — 30 Hz by default — which makes it real-time and gives it its own thread, so nodes run concurrently regardless of order. It sequences ticks only under deterministic=True.

Runtime Helpers

NameDescription
budget_remaining()Seconds left in this tick's budget — for a node that wants to bail out before overrunning
rng_float()Random float in [0.0, 1.0) from the deterministic per-tick RNG
timestamp_ns()Current time in nanoseconds, for stamping messages

Exceptions

NameRaised when
HorusNotFoundErrorA topic, frame or node is not found
HorusTimeoutErrorA blocking operation times out
HorusTransformErrorA coordinate transform fails (extrapolation, stale data)

Message Types

ClassFieldsDefault Topic
CmdVellinear, angular"cmd_vel"
Pose2Dx, y, theta"pose"
Imuaccel_x/y/z, gyro_x/y/z"imu"
Odometryx, y, theta, linear_velocity, angular_velocity"odom"
LaserScanranges, angle_min/max, range_min/max"scan"

Transform System

ClassDescription
TransformFrameCoordinate frame tree with transform lookups
Transform3D transformation (translation + quaternion rotation)
TransformFrameConfigTransformFrame configuration with size presets

Perception Types

These live in the horus.perception submodule, which must be imported explicitly — import horus alone does not bind it, so horus.perception.Detection raises AttributeError unless you import the submodule first:

import horus.perception as perception       # or: from horus.perception import Detection
ClassDescription
DetectionObject detection result (bbox, class, confidence)
DetectionListCollection of detections with filtering
BoundingBox2D2D bounding box with IoU calculation
PointCloudBufferPoint cloud with NumPy integration
TrackedObjectObject tracking with velocity estimation
Landmark2D landmark/keypoint for pose estimation
COCOPoseCOCO keypoint indices
PointXYZ3D point (x, y, z)
PointXYZRGB3D point with RGB color

Tensor System

ClassDescription
TensorPoolShared memory tensor pool allocation
TensorZero-copy tensor with NumPy/PyTorch interop

Networking

The Python bindings do not do networking. Both of the APIs that look like they should are inert:

APIWhat actually happens
Topic(msg, endpoint="topic@host:port")The @ and everything after it is discarded; you get an ordinary shared-memory topic named topic. No socket is opened.
Scheduler(net=True) / horus.run(..., net=True)Accepted, then dropped. At run() the wrapper looks for a native replicator hook that the module does not export, emits a RuntimeWarning, and runs without replication.

The net=True warning is a RuntimeWarning, which Python hides by default outside __main__ — so a service can request replication, not get it, and print nothing. Run with -W always::RuntimeWarning if you need to see it.

Cross-machine replication is a Rust-side feature: build with --features net or use horus run --net, and let the replicator mirror the shared-memory topics your Python nodes already publish to. See Network Backends.


Installation

pip install horus-robotics

Minimal Example

import horus

def my_tick(node):
    node.send("greeting", "Hello from Python!")
    msg = node.recv("greeting")
    if msg:
        print(msg)

node = horus.Node(
    name="MyNode",
    pubs=["greeting"],
    subs=["greeting"],
    tick=my_tick,
    rate=10
)

horus.run(node)