Skip to content

imu

Where IMU measurements come from and how far they can be trusted. This also holds the transform to the LiDAR. Both that transform and the noise figures are measurements, and the calibration section of the documentation covers how to take them.

Option Default Starter
topic "/ouster/imu" yes
qos.reliability Reliable yes
initial_setup 100ms
lidar_only false
ahrs_filtering.method Disable
gravity 9.81
covariance_gyroscope 0.1
covariance_gyroscope_bias 0.0001
covariance_acceleration 0.1
covariance_acceleration_bias 0.0001
driver
  type Disabled
  xsens
    port "/dev/ttyUSB0"
    baudrate 115200
    frame_id "imu"
    output_rate 400
    coordinate_system Enu
    configure_device true
    timestamp
      mode Utc
      max_host_skew 20ms
      startup_timeout 15s
from_lidar_transform
  use_tf_tree false
  translation see below
  rotation see below
  estimate_online false
calibration
  gyroscope true
  gyroscope.samples 100
  parameter_file ""
  time_offset 0s

imu.topic

Topic carrying sensor_msgs/msg/Imu. Ignored while imu.driver.type selects an in-process driver. This has to be the raw device output. Calibrating against an orientation-filtered topic produces a wrong result.

Part of the starter configuration.

imu.qos.reliability

Anything other than Reliable drops messages under load and is not supported.

Accepted values: besteffort, reliable, systemdefault

Accepted values are case-insensitive.

Part of the starter configuration.

imu.initial_setup

How long to collect IMU measurements before the first scan is processed. These samples give the filter its initial gravity direction, so the platform has to stand still for at least this long after start-up.

Type: time.

imu.lidar_only

Ignore the IMU entirely and run the odometry on the Lidar alone, with the filter propagating at a constant twist between scans.

This exists to produce a trajectory for calibrating the IMU against, which is circular if the IMU helped produce it. It is not a navigation mode: with no IMU the gravity direction is unobservable, so roll and pitch are relative to wherever the sensor started and not to level, and there is nothing to carry the estimate through a stretch where the geometry is degenerate. The covariances below stop describing sensor noise and start describing how much the constant-twist model can be trusted, so raise them.

Type: boolean.

imu.ahrs_filtering.method

Orientation filtering Pelorus applies to incoming IMU measurements. Leave it at Disable when the driver or the device already filters, which is the usual case. The result is published on output.imu_ahrs_filtered_topic and is never fed back into the odometry.

Accepted values: createorientationonly, filteraccelerationandcreateorientation, filteraccelerationonly, disable

Accepted values are case-insensitive.

imu.gravity

Magnitude of gravity in m/s^2, used as the starting point for the filter. 9.81 is close enough everywhere on Earth. The filter refines it from there.

Type: number.

imu.covariance_gyroscope

How far the filter trusts the IMU between LiDAR corrections. Larger values mean less trust, so the scan match pulls the estimate further on each update.

The defaults are the FAST-LIO tuning values and are not a noise model of any particular sensor. dedrunk imu noise prints values measured from your own IMU.

Type: number.

imu.covariance_gyroscope_bias

Process noise on the gyroscope bias, i.e. how fast the filter lets that bias wander.

Type: number.

imu.covariance_acceleration

How far the filter trusts the accelerometer between LiDAR corrections.

Type: number.

imu.covariance_acceleration_bias

Process noise on the accelerometer bias.

Type: number.

imu.driver

imu.driver.type

Disabled keeps the existing external IMU input configured by imu.topic. Xsens and Ouster enable in-process drivers and require Pelorus to be built with their matching feature (or the aggregate sensor-drivers feature).

Accepted values: disabled, xsens, ouster

Accepted values are case-insensitive.

imu.driver.xsens

Serial connection to an Xsens MTi. Only used when type = Xsens.

imu.driver.xsens.port

Serial device path. A stable /dev/serial/by-id/... path is recommended over /dev/ttyUSB0 because USB enumeration order can change between boots.

imu.driver.xsens.baudrate

Serial baud rate in bits per second. Must be positive and must match the device.

Type: integer.

Minimum: 1 (inclusive).

Maximum: 4294967295 (inclusive).

imu.driver.xsens.frame_id

Frame assigned to native IMU measurements.

imu.driver.xsens.output_rate

Requested MTData2 output frequency in Hz when configure_device is true. Must be in 1..=2000 and supported by the connected Xsens model and baud rate.

Type: integer.

Minimum: 1 (inclusive).

Maximum: 2000 (inclusive).

imu.driver.xsens.coordinate_system

World-coordinate convention requested for orientation output: Acceleration and rate-of-turn remain expressed in the IMU body frame.

Accepted values: enu, ned, nwu

Accepted values are case-insensitive.

imu.driver.xsens.configure_device

If true, put the device in configuration mode, request UTC, calibrated acceleration, rate-of-turn, and quaternion MTData2 fields at output_rate, then return it to measurement mode. If false, the device must already emit all required fields in compatible precision and coordinates.

Type: boolean.

imu.driver.xsens.timestamp

imu.driver.xsens.timestamp.mode

Utc requires a present and valid MTData2 UTC field and rejects measurements whose clock differs from the host beyond max_host_skew. Host timestamps a complete decoded frame at receipt time and is useful before GNSS/UTC becomes valid, but includes serial transport and scheduling latency.

Accepted values: utc, host

Accepted values are case-insensitive.

imu.driver.xsens.timestamp.max_host_skew

Maximum accepted absolute difference between Xsens UTC and host UTC. Must be positive. Used by Utc mode. Host mode already uses host time.

Type: time.

Minimum: 0s (exclusive).

imu.driver.xsens.timestamp.startup_timeout

Maximum positive duration to wait for usable MTData2 input during startup. If Utc cannot be satisfied, Pelorus fails startup and says so.

Type: time.

Minimum: 0s (exclusive).

imu.from_lidar_transform

Where the IMU sits relative to the LiDAR. Measure this. A value taken from a drawing is often a few millimetres out, and a wrong lever arm shows up as drift that scales with how hard the platform turns. See the calibration section of the documentation.

imu.from_lidar_transform.use_tf_tree

Look the transform up in the TF tree instead of using the values below. The lookup happens once, when the first IMU message arrives.

Type: boolean.

imu.from_lidar_transform.translation

Transform from the LiDAR frame into the IMU frame, so a point in LiDAR coordinates becomes a point in IMU coordinates. dedrunk extrinsics lidar-imu prints both values in this form, ready to paste.

Type: array<length>.

imu.from_lidar_transform.rotation

Transform from the LiDAR frame into the IMU frame, so a point in LiDAR coordinates becomes a point in IMU coordinates. dedrunk extrinsics lidar-imu prints both values in this form, ready to paste.

Type: array<array<number>>.

imu.from_lidar_transform.estimate_online

Keep refining the extrinsic in the filter instead of holding it at the values above, which then serve as the starting point.

This is refinement, not calibration: the filter needs a starting guess close enough to converge, and the extrinsic is only observable while the platform is actually being excited. On a robot that mostly drives straight it will drift along the unobservable directions and get worse. Leave it off unless you know the motion excites all axes, and check the result against what you started with.

Type: boolean.

imu.calibration

Corrections applied to every IMU sample before the filter sees it.

imu.calibration.gyroscope

Measure the gyroscope bias at start-up and subtract it. The platform has to stand still while the first samples measurements arrive. Stored bias figures drift with temperature and between power cycles, so a value measured at start-up is more accurate than one read from a file.

Type: boolean.

imu.calibration.gyroscope.samples

How many measurements the start-up bias estimate averages over.

Type: integer.

Minimum: 0 (inclusive).

imu.calibration.parameter_file

Kalibr-format IMU calibration to apply to every sample: scale factors, axis misalignment and biases. Relative path "./" from this config file, or absolute "/".

Produced by https://codeberg.org/stelzo/dedrunk, or by Kalibr itself with --imu-models scale-misalignment.

imu.calibration.time_offset

Seconds the IMU clock runs ahead of the Lidar clock, as reported by dedrunk extrinsics lidar-imu. Pelorus subtracts it from every IMU timestamp, so paste the number exactly as dedrunk prints it, sign included.

This is a constant skew between the two sensors' clocks, not jitter. It matters most while turning: at 1 rad/s, 10 ms of skew smears the scan by about half a degree, which the registration then has to absorb.

Type: time.