Message Types

HORUS provides 60+ typed messages covering every common robotics domain. All types are available in both Rust (use horus::prelude::*;) and Python (from horus import TypeName).

Coming from ROS2?

ROS2 PackageROS2 MessageHORUS Equivalent
geometry_msgsTwist, Pose, Pose2D, TransformStamped, Vector3, QuaternionTwist, Pose3D, Pose2D, TransformStamped, Vector3, Quaternion
sensor_msgsImu, LaserScan, Image, PointCloud2, JointState, BatteryState, CameraInfoImu, LaserScan, Image, PointCloud, JointState, BatteryState, CameraInfo
nav_msgsOdometry, OccupancyGrid, PathOdometry, OccupancyGrid, NavPath + Waypoint
vision_msgsDetection2D, Detection3DDetection, Detection3D
audio_common_msgsAudioDataAudioFrame
std_msgsHeader(embedded — timestamp_ns and frame_id are fields on each message)

Key difference from ROS2: No separate Header message. Every HORUS message has timestamp_ns and frame_id as direct fields.

Message Categories

CategoryTypesUse Case
GeometryPose2D, Pose3D, Twist, Vector3, Point3, Quaternion, TransformStamped, AccelPosition, orientation, motion
SensorsImu, LaserScan, Odometry, JointState, BatteryState, Range, Temperature, MagneticFieldSensor data from hardware
ControlCmdVel, MotorCommand, ServoCommand, JointCommand, PidStateMotor and actuator commands
NavigationNavGoal, GoalResult, Waypoint, NavPath, OccupancyGrid, CostMap, VelocityObstaclePath planning and mapping
PerceptionDetection, Detection3D, TrackedObject, SegmentationMask, LandmarkArray, PlaneDetectionComputer vision and ML output
VisionCompressedImage, CameraInfo, RegionOfInterest, StereoInfoCamera configuration and compressed data
Force/HapticsWrenchStamped, ForceCommand, ContactInfo, ImpedanceParameters, HapticFeedbackForce sensing and control
DiagnosticsHeartbeat, DiagnosticStatus, NodeHeartbeat, SafetyStatus, EmergencyStopSystem health monitoring
AudioAudioFrameMicrophone data, speech, anomaly detection
InputJoystickInput, KeyboardInputHuman input devices

Custom Messages

Need a type that doesn't exist? Create your own:

// simplified
use horus::prelude::*;

message! {
    MotorStatus {
        rpm: f32,
        current_amps: f32,
        temperature_c: f32,
        fault_code: u32,
    }
}

// Now use it like any standard message
let topic: Topic<MotorStatus> = Topic::new("motor.status")?;

Design Decisions

Why fixed-size Pod types for most messages? Fixed-size types (#[repr(C)], Copy, Pod) can be placed directly in shared memory ring buffers with no serialization, allocation, or copying. This gives deterministic sub-microsecond latency. Variable-length types (Image, PointCloud) use a descriptor + pool pattern -- the descriptor is fixed-size and travels through the ring buffer, while bulk data lives in a separate memory pool.

Why no Header message like ROS2? ROS2's std_msgs/Header adds an indirection layer and allocation for every message. HORUS embeds timestamp_ns and frame_id directly as fields on each message type, eliminating the extra allocation and keeping messages flat and Pod-compatible.

Why categories instead of a flat namespace? Grouping by domain (geometry, sensor, control, navigation, perception, etc.) helps users discover the right type. The Rust use horus::prelude::* and Python from horus import X still provide flat access -- the categories are organizational, not API barriers.


See Also