HORUS vs ROS2
ROS2 is the industry standard for robotics middleware. It has a massive ecosystem, multi-machine networking, and 15 years of community packages. But its architecture — built around DDS, a distributed data service designed for enterprise networking — adds overhead that many single-machine robots don't need.
HORUS makes the opposite trade-off: it strips out the network layer entirely and uses shared memory for all communication. The result is 100–500x faster IPC, deterministic execution, and a simpler development experience — at the cost of a smaller ecosystem and no built-in multi-machine networking.
This page helps you decide which framework fits your project, or whether to use both.
Already using ROS2? See Coming from ROS2 for a migration guide with side-by-side code examples.
Quick Summary
| Aspect | HORUS | ROS2 |
|---|---|---|
| IPC Latency | ~85 ns (shared memory) | ~50–100 µs (DDS) |
| Architecture | Tick-based, deterministic | Callback-based, event-driven |
| Real-Time | Auto-detected from .rate() / .budget() | Manual DDS QoS configuration |
| Config Files | 1 file (horus.toml) | 3+ files (package.xml, CMakeLists.txt, launch) |
| Languages | Rust, Python | C++, Python |
| Ecosystem | Growing (core + package registry) | Massive (thousands of packages) |
| Multi-Machine | Not yet (single-machine) | Native (DDS network transport) |
| Visualization | horus monitor (web + TUI) | RViz2, Foxglove, rqt |
Performance
Message Latency
HORUS uses shared memory directly — no serialization, no kernel transitions, no DDS middleware layer.
| Message Type | Size | HORUS | ROS2 (FastDDS) | Speedup |
|---|---|---|---|---|
| CmdVel | 16 B | ~85 ns | ~50 µs | 588x |
| IMU | 304 B | ~400 ns | ~55 µs | 138x |
| Odometry | 736 B | ~600 ns | ~60 µs | 100x |
| LaserScan | 1.5 KB | ~900 ns | ~70 µs | 78x |
| PointCloud (1K pts) | 12 KB | ~12 µs | ~150 µs | 13x |
| PointCloud (10K pts) | 120 KB | ~360 µs | ~800 µs | 2.2x |
The speedup is most dramatic for small, frequent messages (CmdVel, IMU) — exactly the messages that matter for tight control loops above 100 Hz.
Throughput
| Metric | HORUS | ROS2 |
|---|---|---|
| Small messages (16 B) | 2.7M msg/s | ~20K msg/s |
| IMU messages (304 B) | 1.8M msg/s | ~18K msg/s |
Real-Time Metrics
| Metric | HORUS | ROS2 |
|---|---|---|
| Timing jitter | ±10 µs | ±100–500 µs |
| Per-node overhead | <5 µs | ~50–200 µs per callback |
| Deadline enforcement | Built-in (.budget(), .deadline()) | Manual (rmw QoS) |
| Emergency stop response | <100 µs (Event node) | Application-dependent |
Architecture
HORUS: Tick-Based, Deterministic
Every tick cycle, the scheduler executes all nodes in a guaranteed order:
Scheduler tick:
→ order 0: SafetyMonitor (always first)
→ order 1: SensorReader (always second)
→ order 2: Controller (always third)
→ order 3: Actuator (always last)
→ sleep to maintain tick rate
→ repeat
Node 2 (Controller) always sees Node 1's (SensorReader) latest data. The safety monitor always runs before the actuator. Every tick, guaranteed. Two runs of the same code produce the same execution order.
ROS2: Callback-Based, Event-Driven
Callbacks fire when events arrive. Execution order depends on timing, message arrival, and executor implementation:
Executor spin:
→ timer callback fires (sensor) ← order depends on event timing
→ subscription callback fires (ctrl) ← may fire before or after sensor
→ timer callback fires (actuator) ← under load, may be delayed
Under load, callbacks can be delayed or reordered. Two runs of the same code may execute callbacks in different orders. For a motor controller that reads IMU data, this means the IMU reading might arrive before or after the control computation.
For safety-critical systems (surgical robots, industrial cobots, autonomous vehicles), deterministic execution order eliminates an entire class of bugs — race conditions that only manifest under load, at full speed, in production.
Developer Experience
Project Setup
# horus.toml — single source of truth
[package]
name = "my-robot"
version = "0.1.0"
[dependencies]
serde = "1.0"
nalgebra = "0.32"
Node Definition
use horus::prelude::*;
struct MotorController {
commands: Topic<f32>,
}
impl Node for MotorController {
fn name(&self) -> &str { "Motor" }
fn tick(&mut self) {
if let Some(cmd) = self.commands.recv() {
set_motor_velocity(cmd);
}
}
}
HORUS: 10 lines, no shared pointers, no bind, no QoS depth parameter.
CLI Comparison
| Task | HORUS | ROS2 |
|---|---|---|
| Create project | horus new my_robot | ros2 pkg create my_robot + edit CMakeLists.txt |
| Build | horus build | colcon build |
| Run | horus run | ros2 run my_robot my_node |
| List topics | horus topic list | ros2 topic list |
| Echo topic | horus topic echo velocity | ros2 topic echo /velocity |
| Monitor | horus monitor | rqt (separate install) |
| Add dependency | horus add serde | Edit package.xml + CMakeLists.txt + rosdep install |
Feature Comparison
| Feature | HORUS | ROS2 |
|---|---|---|
| Pub/Sub Topics | Shared memory, 10 auto-selected backends | DDS middleware |
| Services (RPC) | Beta | Yes |
| Actions (long-running) | Beta | Yes |
| Transform Frames | TransformFrame (built-in) | tf2 |
| Recording/Replay | Built-in Record/Replay | rosbag2 |
| Monitoring | Web + TUI (built-in) | rqt, Foxglove (separate) |
| Launch System | YAML launch files | Python/XML/YAML launch |
| Package Manager | horus registry | rosdep, bloom |
| Deterministic Mode | SimClock + dependency graph | Partial (use_sim_time) |
| Safety Monitor | Built-in (watchdog, graduated degradation) | Application-level |
| Deadline Enforcement | Built-in (.budget(), .deadline()) | Manual (rmw QoS) |
| Multi-Machine | Not yet | DDS discovery |
| 3D Visualization | Not yet | RViz2 |
| Simulation | horus-sim3d (Bevy + native solver) | Gazebo, Isaac Sim |
| Message IDL | Rust structs with derives | .msg/.srv/.action files |
Safety & Failure Handling
In ROS2, if a node hangs or misses its deadline, nothing happens — the robot keeps running on its last command. DDS has LIVELINESS and DEADLINE QoS policies, but they only notify you; they don't take corrective action. Building equivalent safety requires writing a custom lifecycle manager and health monitoring node — hundreds of lines that every team writes differently (or skips entirely).
HORUS has this built into the scheduler: a graduated watchdog detects frozen nodes (warn → skip → isolate → safe state), deadline miss policies control what happens when a node overruns its budget (Miss::Warn, Skip, SafeMode, Stop), and fault tolerance handles node crashes with automatic restart, skip, or fatal policies.
See Safety Monitor for the full reference with configuration and code examples.
When to Use Each
Choose HORUS when:
- Sub-microsecond IPC latency matters (control loops > 100 Hz)
- Deterministic execution order is required (safety-critical systems)
- You want a single-file project config
- Your robot runs on a single machine
- You prefer Rust's safety guarantees
- You're starting a new project (no ROS2 migration debt)
Choose ROS2 when:
- You need multi-machine communication (distributed robots, fleet management)
- You need RViz2 for 3D visualization
- You depend on specific ROS2 packages (MoveIt2, Nav2, SLAM Toolbox)
- Your team already has ROS2 expertise
- You need the larger ecosystem (drivers, integrations, community support)
Use both:
- HORUS for real-time control on the robot (sensors, actuators, safety)
- ROS2 for high-level planning, visualization, fleet management on separate machines
- A bridge node translates between DDS topics and HORUS topics at the boundary
Migration Path
HORUS and ROS2 can coexist. Common strategies:
- Start new subsystems in HORUS — Keep existing ROS2 for high-level planning, add HORUS for real-time control
- Bridge approach — Run a bridge node that translates between DDS topics and HORUS topics
- Full migration — Replace ROS2 nodes one-by-one with HORUS equivalents
See Coming from ROS2 for detailed migration guidance with side-by-side code examples.
See Also
- Why HORUS? — Motivation and design philosophy
- Coming from ROS2 — Migration guide with concept mapping
- Benchmarks — Full performance data
- Installation — Get started in 5 minutes