Custom Messages & Performance
Need a message type that doesn't exist in the standard library? Use the message! macro. HORUS handles all the optimization automatically — you never need to think about serialization or memory layout.
For performance-sensitive applications: standard fixed-size types transfer at ~50ns (zero-copy), variable-size types at ~167ns (serialized). No configuration needed.
Automatic Optimization
When you create a Topic<T>, HORUS inspects the message type at compile time and selects the fastest transfer strategy:
- Fixed-size types (no heap allocations) use raw memory copy — no serialization overhead
- Variable-size types (containing
String,Vec, etc.) use fast bincode serialization
You always use the same API. The optimization is invisible:
use horus::prelude::*;
// Fixed-size type — automatically uses zero-copy (~50ns cross-process)
let cmd_topic: Topic<CmdVel> = Topic::new("cmd_vel")?;
cmd_topic.send(CmdVel::new(1.0, 0.5));
// Variable-size type — automatically uses serialization (~167ns cross-process)
let log_topic: Topic<String> = Topic::new("log")?;
log_topic.send("Motor started".to_string());
Performance Comparison
| Type Category | Cross-Process Latency | Examples |
|---|---|---|
| Fixed-size (zero-copy) | ~50-85ns | CmdVel, Imu, Pose2D, Heartbeat |
| Variable-size (serialized) | ~167ns | String, Vec<f32>, HashMap<K,V> |
Same-process communication is fast for both categories since no shared memory serialization is needed.
For most applications, the ~167ns serialized path is more than fast enough. Only high-frequency control loops running at 1kHz+ benefit noticeably from the zero-copy path.
Custom Messages
Use the message! macro to define your own message types. Add #[fixed] for zero-copy shared memory transport (~50ns) when all fields are primitives:
use horus::prelude::*;
message! {
#[fixed]
/// Motor feedback — zero-copy via shared memory (~50ns)
MotorFeedback {
timestamp_ns: u64,
motor_id: u32,
velocity: f32,
current_amps: f32,
temperature_c: f32,
}
}
let feedback: Topic<MotorFeedback> = Topic::new("motor.feedback")?;
feedback.send(MotorFeedback {
timestamp_ns: 0,
motor_id: 1,
velocity: 3.14,
current_amps: 0.5,
temperature_c: 45.0,
});
For messages with String, Vec, or other dynamic data, omit #[fixed] — HORUS uses serialization transport automatically (~167ns):
message! {
/// Diagnostic log — flexible, serialized
DiagLog {
node_name: String,
message: String,
level: u8,
}
}
Built-in Message Types
All standard HORUS message types are pre-optimized. Fixed-size types automatically use the zero-copy fast path.
Geometry
| Message | Description |
|---|---|
CmdVel | 2D velocity command (linear + angular) |
Pose2D | 2D position and orientation |
Twist | 3D linear and angular velocity |
TransformStamped | 3D transformation with timestamp |
Point3 | 3D point |
Vector3 | 3D vector |
Quaternion | Rotation quaternion |
Sensors
| Message | Description |
|---|---|
Imu | Inertial measurement unit data |
LaserScan | 2D laser range data |
Odometry | Position/velocity estimate |
RangeSensor | Single distance measurement |
BatteryState | Battery level and status |
NavSatFix | GPS position |
Control
| Message | Description |
|---|---|
MotorCommand | Individual motor control |
DifferentialDriveCommand | Differential drive control |
ServoCommand | Servo position/velocity |
JointCommand | Joint-level control |
TrajectoryPoint | Trajectory waypoint |
PidConfig | PID controller parameters |
Diagnostics
| Message | Description |
|---|---|
Heartbeat | Liveness signal |
NodeHeartbeat | Per-node health status |
DiagnosticStatus | General status report |
EmergencyStop | Emergency stop signal |
SafetyStatus | Safety system state |
ResourceUsage | CPU/memory usage |
DiagnosticValue | Single diagnostic measurement |
DiagnosticReport | Full diagnostic report |
Navigation
| Message | Description |
|---|---|
NavGoal | Navigation goal |
GoalResult | Goal completion result |
Waypoint | Navigation waypoint |
NavPath | Sequence of waypoints |
PathPlan | Planned path |
VelocityObstacle | Velocity obstacle for avoidance |
VelocityObstacles | Set of velocity obstacles |
Force/Haptics
| Message | Description |
|---|---|
WrenchStamped | Force/torque measurement |
ForceCommand | Force control command |
ImpedanceParameters | Impedance control config |
ContactInfo | Contact detection data |
HapticFeedback | Haptic output command |
Input
| Message | Description |
|---|---|
JoystickInput | Gamepad/joystick state |
KeyboardInput | Keyboard key events |
Tensor
| Message | Description |
|---|---|
Tensor | Fixed-size tensor descriptor |
use horus::prelude::*;
// All built-in messages use the fastest available path automatically
let cmd: Topic<CmdVel> = Topic::new("cmd_vel")?;
let pose: Topic<Pose2D> = Topic::new("robot_pose")?;
let imu: Topic<Imu> = Topic::new("imu_data")?;
let estop: Topic<EmergencyStop> = Topic::new("emergency_stop")?;
See Also
- Topic — The unified communication API
- Message Types — Full message type reference
- Architecture — How communication fits into the HORUS architecture