Imu

Provides three-axis linear acceleration, three-axis angular velocity, and an optional orientation quaternion from an IMU sensor. The primary message for motion sensing, sensor fusion, and orientation estimation on mobile robots, drones, and manipulators.

Python: Available via horus.Imu(accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z). See Python Sensor Messages.

ROS2 equivalent: sensor_msgs/Imu — identical field layout (orientation quaternion + angular velocity + linear acceleration + covariance matrices).

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

Quick Reference — Fields

FieldTypeUnitDescription
orientation[f64; 4]Quaternion [x, y, z, w]. Default: identity [0, 0, 0, 1]
orientation_covariance[f64; 9]3x3 row-major covariance. [0] = -1.0 means no orientation data
angular_velocity[f64; 3]rad/sAngular velocity [x, y, z]
angular_velocity_covariance[f64; 9]3x3 row-major covariance matrix
linear_acceleration[f64; 3]m/s²Linear acceleration [x, y, z]
linear_acceleration_covariance[f64; 9]3x3 row-major covariance matrix
timestamp_nsu64nsTimestamp in nanoseconds since epoch

Quick Reference — Methods

MethodReturnsDescription
new()ImuCreates with identity orientation, zero values, current timestamp
set_orientation_from_euler(roll, pitch, yaw)()Sets orientation quaternion from Euler angles
has_orientation()boolChecks if orientation data is available
is_valid()boolChecks if all values are finite
angular_velocity_vec()Vector3Returns angular velocity as a Vector3
linear_acceleration_vec()Vector3Returns linear acceleration as a Vector3

Constructor Methods

new()

Creates a new IMU message with identity orientation, zero acceleration and velocity, and the current timestamp.

Signature

// simplified
pub fn new() -> Self

Parameters

None.

Returns

Imu — with these defaults:

  • orientation: [0.0, 0.0, 0.0, 1.0] (identity quaternion)
  • orientation_covariance: [-1.0; 9] (no orientation data — has_orientation() returns false)
  • angular_velocity: [0.0; 3]
  • linear_acceleration: [0.0; 3]
  • All covariances: [0.0; 9]
  • timestamp_ns: current time via timestamp_now()

Panics

Never.

Behavior

  • The orientation_covariance[0] is set to -1.0, meaning no orientation is available by default. Call set_orientation_from_euler() or set orientation directly to provide orientation data, then set orientation_covariance[0] to a non-negative value.

Example

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

let mut imu = Imu::new();
imu.linear_acceleration = [0.0, 0.0, 9.81]; // gravity on Z
imu.angular_velocity = [0.0, 0.0, 0.1];     // yawing slowly

let topic: Topic<Imu> = Topic::new("imu.data")?;
topic.send(&imu);

Python Constructor

Creates an IMU message from individual axis values.

Signature

Imu(accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z, timestamp_ns=0)

Parameters

NameTypeRequiredDescription
accel_xf64yesLinear acceleration X-axis (m/s²)
accel_yf64yesLinear acceleration Y-axis (m/s²)
accel_zf64yesLinear acceleration Z-axis (m/s²)
gyro_xf64yesAngular velocity X-axis (rad/s)
gyro_yf64yesAngular velocity Y-axis (rad/s)
gyro_zf64yesAngular velocity Z-axis (rad/s)
timestamp_nsu64noTimestamp in nanoseconds. Default: 0.

Returns

Imu instance.

Example

from horus import Imu, Topic

# Stationary sensor measuring gravity
imu = Imu(0.0, 0.0, 9.81, 0.0, 0.0, 0.1)

topic = Topic(Imu)
topic.send(imu)

# Access individual axes (read/write)
print(f"Accel Z: {imu.accel_z}")  # 9.81
imu.gyro_z = 0.2

The Python constructor defaults timestamp_ns to 0, while Rust's new() uses the current time. Set timestamp_ns explicitly if your pipeline depends on accurate timing.


Methods

set_orientation_from_euler(roll, pitch, yaw)

Sets the orientation quaternion from Euler angles. Automatically marks orientation as available.

Signature

// simplified
pub fn set_orientation_from_euler(&mut self, roll: f64, pitch: f64, yaw: f64)

Parameters

NameTypeRequiredDescription
rollf64yesRoll angle in radians (rotation about X-axis)
pitchf64yesPitch angle in radians (rotation about Y-axis)
yawf64yesYaw angle in radians (rotation about Z-axis)

Returns

Nothing (()).

Panics

Never. NaN/infinite angles produce a NaN quaternion — check with is_valid().

Behavior

  • Converts Euler angles to quaternion via Quaternion::from_euler()
  • Stores result in self.orientation as [x, y, z, w]
  • Does NOT automatically update orientation_covariance — set orientation_covariance[0] to a non-negative value manually if you want has_orientation() to return true

Example

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

let mut imu = Imu::new();
imu.set_orientation_from_euler(0.0, 0.0, std::f64::consts::FRAC_PI_2); // 90° yaw
imu.orientation_covariance[0] = 0.01; // mark orientation as available
assert!(imu.has_orientation());

has_orientation()

Checks whether orientation data is available.

Signature

// simplified
pub fn has_orientation(&self) -> bool

Parameters

None.

Returns

true if orientation_covariance[0] >= 0.0. false if orientation_covariance[0] < 0.0 (the default from new()).

Behavior

  • Convention follows ROS2 sensor_msgs/Imu: setting orientation_covariance[0] to -1.0 signals that orientation is unavailable (e.g., gyro-only sensor)
  • Consumers should always call has_orientation() before reading the orientation quaternion

When to use

  • Before reading the orientation quaternion — avoids using stale identity values
  • Filtering in fusion nodes — only fuse orientation if the sensor provides it

Example

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

fn process_imu(imu: &Imu) {
    if imu.has_orientation() {
        let q = imu.orientation; // safe to use
    } else {
        // Gyro-only — compute orientation from angular velocity integration
    }
}

is_valid()

Checks whether all acceleration, velocity, and orientation values are finite.

Signature

// simplified
pub fn is_valid(&self) -> bool

Parameters

None.

Returns

true if all values in orientation, angular_velocity, and linear_acceleration are finite (not NaN, not infinite). false otherwise.

When to use

  • Validating sensor data before publishing — hardware faults can produce NaN
  • Input validation in fusion nodes — reject corrupted readings

Example

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

fn tick(&mut self) {
    let imu = read_hardware_imu();
    if imu.is_valid() {
        self.imu_pub.send(imu);
    } else {
        hlog!(warn, "Invalid IMU reading — hardware fault?");
    }
}

angular_velocity_vec()

Returns angular velocity as a Vector3 struct.

Signature

// simplified
pub fn angular_velocity_vec(&self) -> Vector3

Parameters

None.

Returns

Vector3 — with x, y, z fields matching angular_velocity[0], [1], [2].

When to use

  • When you need named field access (.x, .y, .z) instead of array indexing
  • Passing velocity to functions that accept Vector3

linear_acceleration_vec()

Returns linear acceleration as a Vector3 struct.

Signature

// simplified
pub fn linear_acceleration_vec(&self) -> Vector3

Parameters

None.

Returns

Vector3 — with x, y, z fields matching linear_acceleration[0], [1], [2].


Common Patterns

Sensor Fusion Pipeline

IMU hardware → Imu message → complementary/Kalman filter → Pose3D (orientation)
                            └→ dead reckoning → Odometry (position estimate)

Fall Detection

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

fn check_freefall(imu: &Imu) -> bool {
    let accel = imu.linear_acceleration_vec();
    let magnitude = (accel.x * accel.x + accel.y * accel.y + accel.z * accel.z).sqrt();
    magnitude < 1.0 // Near-zero gravity = freefall
}

Covariance Convention

Set orientation_covariance[0] to -1.0 when orientation is not available (e.g., gyro-only sensor). Consumers should call has_orientation() before reading the quaternion. This matches the ROS2 sensor_msgs/Imu convention.


See Also