Skip to main content
Version: 1.0.2

IMU

Hardware

AutomatePro includes an onboard BNO085 9-axis MEMS IMU. The IMU combines a 3-axis accelerometer, 3-axis gyroscope, and 3-axis magnetometer. The driver publishes ROS 2 IMU data and, when enabled, magnetic-field and accuracy data.

The arrows on the device indicate the IMU vector directions:

AutomatePro IMU axis directions

IMU Specifications

ParameterValue
SensorBNO085
Sensing types3-axis gyroscope, 3-axis magnetometer, 3-axis accelerometer
Rotation vector error (dynamic)13.5 deg
Accelerometer accuracy10.3 m/s2
Gyroscope accuracy13.1 deg/s
Magnetometer accuracy11.4 uT
Default IMU sample rate100 Hz
Configurable IMU rateUp to 400 Hz, hardware dependent
Info

1 Based on IC manufacturer tests. Results on AutomatePro can vary by mounting, calibration, and magnetic environment. See the BNO080/BNO085 datasheet for manufacturer details.

ROS API

Node: automatepro_imu_driver

Publishers

TopicTypeDescription
/sensor/imu/datasensor_msgs/msg/ImuOrientation, angular velocity, and linear acceleration.
/sensor/imu/magnetic_fieldsensor_msgs/msg/MagneticFieldMagnetic field data, when magnetometer publishing is enabled.
/sensor/imu/accuracyautomatepro_imu_driver/msg/ImuAccuracyAccuracy levels for orientation, accelerometer, gyroscope, and magnetic-field reports.

Services

ServiceTypeDescription
/sensor/imu/save_tarestd_srvs/srv/TriggerPersists the current tare to sensor flash.
/sensor/imu/save_calibrationstd_srvs/srv/TriggerSaves Dynamic Calibration Data (DCD) to sensor flash.
/sensor/imu/reinitstd_srvs/srv/TriggerReinitializes the IMU driver and sensor.

Verify IMU Data

Run these checks from AutomatePro over SSH:

source /opt/ros/humble/setup.bash
ros2 node list | grep automatepro_imu_driver
ros2 topic echo /sensor/imu/data --once --qos-reliability best_effort

If accuracy publishing is enabled, check calibration state:

ros2 topic echo /sensor/imu/accuracy --once

Accuracy levels use:

ValueMeaning
0Unreliable
1Low
2Medium
3High
255Unknown

Configuration

Driver: automatepro_imu_driver
Container: automatepro-core-driver

info

Runtime ROS configuration is stored in /opt/automatepro/config/ros. Packaged defaults are stored in /opt/automatepro/defconfig/ros.

Edit the IMU parameter file:

sudo nano /opt/automatepro/config/ros/imu_params.yaml

Important parameters:

ParameterDefaultDescription
log_levelinfoDriver log level. Launch accepts debug, info, warn, error, or fatal.
frame_idlm450_imu_linkFrame ID stamped on published IMU messages.
rotation_vector_modegame_rotation_vectorOrientation report type. Use rotation_vector for magnetic absolute heading, game_rotation_vector for relative heading without magnetometer, or geomagnetic_rotation_vector for geomagnetic heading.
tare.on_startupfalseApplies one-shot tare when the node starts. Leave disabled after commissioning.
tare.axesxyzAxes included in tare.
tare.persistfalseSaves tare to flash when enabled.
tare.orientation.enabledtrueApplies the configured chip-to-body orientation mapping at startup and watchdog reinitialization.
tare.orientation.use_quaternionfalseUses qx, qy, qz, and qw instead of roll, pitch, and yaw when enabled.
tare.orientation.qx/qy/qz/qw0/0/0/1Quaternion orientation mapping when use_quaternion is true.
calibration.accelerometer.enabledtrueEnables BNO08x accelerometer dynamic calibration.
calibration.accelerometer.planarfalseEnables planar accelerometer calibration mode.
calibration.gyroscope.enabledtrueEnables BNO08x gyroscope dynamic calibration.
calibration.gyroscope.on_tabletrueEnables stationary on-table gyroscope calibration assist.
calibration.magnetic_field.enabledfalseEnables BNO08x magnetometer dynamic calibration. Enable only when magnetic heading is required and the environment is suitable.
calibration.save_dcdtruePeriodically saves Dynamic Calibration Data to flash.
i2c.enabledtrueUses I2C communication.
i2c.bus/dev/i2c-7I2C bus path.
i2c.address0x4BBNO08x I2C address.
uart.enabledfalseUses UART communication instead of I2C when enabled.
uart.device/dev/ttyACM0UART device path when UART transport is enabled.
publish.accuracy.enabledtruePublishes /sensor/imu/accuracy.
publish.imu.enabledtruePublishes /sensor/imu/data.
publish.imu.rate100Requested IMU report rate in Hz.
publish.magnetic_field.enabledfalsePublishes /sensor/imu/magnetic_field. Use --qos-reliability best_effort when echoing this topic from the CLI.
publish.magnetic_field.rate100Requested magnetometer report rate in Hz.
publish.imu.orientation_offset.enabledfalseApplies a software quaternion offset before publishing orientation.
Important

Restart automatepro-core-driver after changing the configuration. Configuration values are loaded when the driver container starts and are only applied after the service restarts.

sudo systemctl restart automatepro-core-driver

Default Configuration Shape

automatepro_imu_driver:
ros__parameters:
log_level: "info"
frame_id: "lm450_imu_link"
rotation_vector_mode: "game_rotation_vector"
tare:
on_startup: false
axes: "xyz"
persist: false
orientation:
enabled: true
roll_deg: 0.0
pitch_deg: 0.0
yaw_deg: -80.0
use_quaternion: false
qx: 0.0
qy: 0.0
qz: 0.0
qw: 1.0
calibration:
accelerometer:
enabled: true
planar: false
gyroscope:
enabled: true
on_table: true
magnetic_field:
enabled: false
save_dcd: true
i2c:
enabled: true
bus: "/dev/i2c-7"
address: "0x4B"
uart:
enabled: false
device: "/dev/ttyACM0"
publish:
accuracy:
enabled: true
magnetic_field:
enabled: false
rate: 100
imu:
enabled: true
rate: 100

Example

This example prints IMU and magnetic-field messages by subscribing to /sensor/imu/data and /sensor/imu/magnetic_field.

The tutorial package is available in the AutomatePro tutorials repository.

import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Imu, MagneticField


class ImuSubscriber(Node):
def __init__(self):
super().__init__("imu_subscriber")
self.imu_subscription = self.create_subscription(
Imu,
"/sensor/imu/data",
self.imu_callback,
10,
)
self.magnetic_field_subscription = self.create_subscription(
MagneticField,
"/sensor/imu/magnetic_field",
self.magnetic_field_callback,
10,
)

def imu_callback(self, msg):
self.get_logger().info(
"Received IMU message: orientation=%s, angular_velocity=%s, linear_acceleration=%s"
% (msg.orientation, msg.angular_velocity, msg.linear_acceleration)
)

def magnetic_field_callback(self, msg):
self.get_logger().info(
"Received MagneticField message: magnetic_field=%s" % msg.magnetic_field
)


def main(args=None):
rclpy.init(args=args)
node = ImuSubscriber()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()


if __name__ == "__main__":
main()

Run the node:

ros2 run automatepro_py_tutorials imu_node

Orientation Commissioning

Use this workflow when the IMU is remounted, when the reference orientation changes, or when a system needs a known rest pose.

Important

Perform tare and calibration only when the device is in its final mounting position and away from motors, steel structures, strong magnets, and current-carrying wires.

  1. Complete dynamic calibration.

    Move the device through several stable orientations for accelerometer calibration, leave it stationary for gyroscope calibration, and perform magnetic rotations only if magnetic-field calibration is enabled and required.

  2. Tare the reference pose.

    Place AutomatePro in the desired zero orientation. Temporarily set:

    tare:
    on_startup: true
    axes: "xyz"
    persist: true

    Restart the core driver and wait for tare completion in logs:

    sudo systemctl restart automatepro-core-driver
    sudo journalctl -u automatepro-core-driver -f

    After tare completes, set tare.on_startup: false so it is not applied on every boot.

  3. Set mounting orientation.

    Use tare.orientation.roll_deg, pitch_deg, and yaw_deg to map the chip axes to the device body frame. This orientation mapping is re-applied on startup and watchdog recovery.

  4. Apply software heading offset when needed.

    If the device in the rest pose should publish identity orientation (0, 0, 0, 1), capture the current quaternion:

    ros2 topic echo /sensor/imu/data --field orientation --once

    Set publish.imu.orientation_offset.* to the conjugate of that quaternion and enable publish.imu.orientation_offset.enabled.

  5. Verify the final output.

    Restart the core driver and verify that the rest pose and motion directions match your robot frame:

    sudo systemctl restart automatepro-core-driver
    ros2 topic echo /sensor/imu/data --field orientation --once
Developer Notes: rotation modes and persistence

rotation_vector_mode selects which BNO08x SH-2 report is enabled. game_rotation_vector does not use the magnetometer and reports relative heading. rotation_vector and geomagnetic_rotation_vector use magnetic information for heading.

Dynamic tare runs only on initial node startup when tare.on_startup is enabled. The fixed mounting orientation is re-applied on every sensor initialization, including watchdog recovery. The software orientation offset is applied as q_published = q_offset * q_sensor.

Troubleshooting

IMU Topic Is Missing

Check that the driver is enabled:

grep ROS_DRIVER_IMU /opt/automatepro/.env

Check logs:

sudo journalctl -u automatepro-core-driver -n 100 --no-pager

Orientation Is Correct After Startup but Wrong After Recovery

Verify tare.orientation.enabled: true. The fixed orientation mapping is the part reapplied on every sensor initialization.

Heading Drifts or Jumps

Check the rotation-vector mode and magnetic environment. If the system does not require magnetic absolute heading, game_rotation_vector is less sensitive to magnetic disturbances. If magnetic heading is required, calibrate in the deployment environment and monitor /sensor/imu/accuracy.