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
| Field | Type | Unit | Description |
|---|---|---|---|
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/s | Angular 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_ns | u64 | ns | Timestamp in nanoseconds since epoch |
Quick Reference — Methods
| Method | Returns | Description |
|---|---|---|
new() | Imu | Creates with identity orientation, zero values, current timestamp |
set_orientation_from_euler(roll, pitch, yaw) | () | Sets orientation quaternion from Euler angles |
has_orientation() | bool | Checks if orientation data is available |
is_valid() | bool | Checks if all values are finite |
angular_velocity_vec() | Vector3 | Returns angular velocity as a Vector3 |
linear_acceleration_vec() | Vector3 | Returns 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()returnsfalse)angular_velocity:[0.0; 3]linear_acceleration:[0.0; 3]- All covariances:
[0.0; 9] timestamp_ns: current time viatimestamp_now()
Panics
Never.
Behavior
- The
orientation_covariance[0]is set to-1.0, meaning no orientation is available by default. Callset_orientation_from_euler()or setorientationdirectly to provide orientation data, then setorientation_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
| Name | Type | Required | Description |
|---|---|---|---|
accel_x | f64 | yes | Linear acceleration X-axis (m/s²) |
accel_y | f64 | yes | Linear acceleration Y-axis (m/s²) |
accel_z | f64 | yes | Linear acceleration Z-axis (m/s²) |
gyro_x | f64 | yes | Angular velocity X-axis (rad/s) |
gyro_y | f64 | yes | Angular velocity Y-axis (rad/s) |
gyro_z | f64 | yes | Angular velocity Z-axis (rad/s) |
timestamp_ns | u64 | no | Timestamp 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
| Name | Type | Required | Description |
|---|---|---|---|
roll | f64 | yes | Roll angle in radians (rotation about X-axis) |
pitch | f64 | yes | Pitch angle in radians (rotation about Y-axis) |
yaw | f64 | yes | Yaw 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.orientationas[x, y, z, w] - Does NOT automatically update
orientation_covariance— setorientation_covariance[0]to a non-negative value manually if you wanthas_orientation()to returntrue
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: settingorientation_covariance[0]to-1.0signals that orientation is unavailable (e.g., gyro-only sensor) - Consumers should always call
has_orientation()before reading theorientationquaternion
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
- Sensor Messages (Rust) — Full Rust API for all sensor types
- Sensor Messages (Python) — Python sensor API
- IMU Reader Recipe — Complete IMU integration guide
- Sensor Node Tutorial — Build an IMU node step by step
- Odometry — Combine with IMU for dead reckoning