Odometry

Combines a 2D pose (position + heading) with a twist (velocity) and covariance. The standard output from wheel encoders, visual odometry, or any localization system.

When to Use

Use Odometry when you need to publish or consume the robot's estimated position and velocity. Typically published by a drive node that integrates wheel encoder counts, and consumed by planners, fusion nodes, or logging systems.

ROS2 Equivalent

nav_msgs/Odometry — similar structure (pose + twist + covariances).

Rust Example

use horus::prelude::*;

// Robot at (1.5, 2.0) heading 45 degrees, moving forward at 0.3 m/s
let odom = Odometry {
    pose: Pose2D { x: 1.5, y: 2.0, theta: 0.785 },
    twist: Twist {
        linear: [0.3, 0.0, 0.0],
        angular: [0.0, 0.0, 0.05],
        timestamp_ns: 0,
    },
    pose_covariance: [0.0; 36],
    twist_covariance: [0.0; 36],
    timestamp_ns: 0,
};

let topic: Topic<Odometry> = Topic::new("odom")?;
topic.send(odom);

Python Example

import horus

odom = horus.Odometry(
    pose=horus.Pose2D(x=1.5, y=2.0, theta=0.785),
    twist=horus.Twist(linear=[0.3, 0.0, 0.0], angular=[0.0, 0.0, 0.05]),
)

Fields

FieldTypeUnitDescription
posePose2Dm, radCurrent position and heading estimate
twistTwistm/s, rad/sCurrent velocity estimate
pose_covariance[f64; 36]--6x6 covariance for pose (x, y, z, roll, pitch, yaw)
twist_covariance[f64; 36]--6x6 covariance for velocity
timestamp_nsu64nsTimestamp

Common Patterns

Publish from Drive Node

fn tick(&mut self) {
    // Read wheel encoders
    let left_ticks = self.read_left_encoder();
    let right_ticks = self.read_right_encoder();

    // Integrate to get pose
    self.x += dx * self.theta.cos();
    self.y += dx * self.theta.sin();
    self.theta += dtheta;

    self.odom_pub.send(Odometry {
        pose: Pose2D { x: self.x, y: self.y, theta: self.theta },
        twist: Twist {
            linear: [self.speed, 0.0, 0.0],
            angular: [0.0, 0.0, self.omega],
            timestamp_ns: 0,
        },
        pose_covariance: [0.0; 36],
        twist_covariance: [0.0; 36],
        timestamp_ns: 0,
    });
}

Fuse with IMU

See Multi-Sensor Fusion — combines odometry heading with IMU yaw using a complementary filter.

  • Pose2D — 2D position and heading
  • Twist — 3D velocity
  • CmdVel — Velocity commands (input to drive)