imu_gravity_detection v1.0 🧭 基于互补滤波的IMU重力方向

C++11/14 ROS Kinetic/Noetic Eigen3 · tf2 最后更新: 2026-03-19

一个轻量级ROS软件包,通过互补滤波融合加速度计与陀螺仪数据,实时估计IMU坐标系下的重力方向、俯仰/横滚角,并提供四元数姿态。专为Intel RealSense D455优化,支持RViz可视化。

📖 概述

imu_gravity_detection 提供了一个完整的ROS节点和可复用的C++库,用于从原始IMU数据(角速度和线加速度)中提取稳定的重力向量。它使用经典互补滤波(Mahony/Madgwick思想简化),有效抑制加速度计噪声,同时利用陀螺仪快速响应动态变化。输出包括:

🧭 重力方向向量

归一化的三维向量,表示当前IMU坐标系中重力指向(通常指向地心)。

📐 俯仰/横滚角

基于重力方向计算得到的倾斜角度(度),可用于姿态参考。

🔄 四元数姿态

从陀螺仪积分并经过加速度计校正的实时姿态。

🎯 TF与可视化

发布 gravity_direction 坐标系及RViz箭头标记,直观展示重力方向。

✨ 核心特性

⚡ 快速开始

使用RealSense D455运行完整示例:

# 启动重力检测与可视化 (需先连接D455)
roslaunch imu_gravity_detection gravity_visualization.launch

预期效果:终端打印重力向量和倾角,RViz窗口显示红色箭头指向重力方向。

仅运行重力检测节点(使用已有IMU话题):

rosrun imu_gravity_detection imu_gravity_node _frame_id:=camera_link

📦 编译与依赖

Ubuntu 20.04/22.04 (ROS Noetic)

# 安装依赖 (假设已安装ROS)
sudo apt install ros-${ROS_DISTRO}-tf2 ros-${ROS_DISTRO}-tf2-ros \
                 ros-${ROS_DISTRO}-visualization-msgs libeigen3-dev

# 创建工作空间并编译
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
git clone https://github.com/your/imu_gravity_detection.git
cd ..
catkin_make
source devel/setup.bash
⚠️ 如需连接D455,还需安装 realsense2_camera 驱动:sudo apt install ros-${ROS_DISTRO}-realsense2-camera

CMakeLists.txt 片段 (已提供)

find_package(catkin REQUIRED COMPONENTS roscpp sensor_msgs geometry_msgs ...)
find_package(Eigen3 REQUIRED)
add_library(imu_gravity_detection src/imu_gravity_detector.cpp)
add_executable(imu_gravity_node src/imu_gravity_node.cpp)
target_link_libraries(imu_gravity_node imu_gravity_detection ${catkin_LIBRARIES})

🏗️ 系统架构

数据流:realsense2_camera/camera/imuimu_gravity_node → 重力向量、TF、Marker → RViz。

📐 IMUGravityDetector 类

头文件: imu_gravity_detection/imu_gravity_detector.h

构造函数

IMUGravityDetector(float alpha = 0.98f);

alpha:互补滤波系数 (0: 完全信任加速度计, 1: 完全信任陀螺仪积分,通常0.95~0.98)。

核心方法

方法描述
void updateIMU(const Eigen::Vector3f& accel, const Eigen::Vector3f& gyro, float dt)输入加速度(m/s²)、角速度(°/s)和时间步长(s),更新内部状态。
Eigen::Vector3f getGravityDirection() const返回归一化的重力方向向量 (在IMU坐标系中指向下方)。
float getGravityMagnitude() const当前估计的重力大小 (通常≈9.8)。
void getTiltAngles(float& pitch, float& roll) const俯仰和横滚角(度)。
Eigen::Quaternionf getOrientation() const当前姿态四元数 (全局到IMU的旋转)。

实现细节

🎛️ ROS节点 imu_gravity_node

节点名称: imu_gravity_detection

订阅话题

话题类型描述
/camera/imusensor_msgs/Imu原始IMU数据(需包含线加速度和角速度)。

发布话题

话题类型描述
gravity_directiongeometry_msgs/Vector3Stamped当前重力方向向量(归一化)。
gravity_markervisualization_msgs/MarkerRViz箭头标记,红色,长度0.5m。
TFtf2_msgs/TFMessage发布从 frame_idgravity_direction 的旋转变换。

参数

参数默认值描述
~frame_id"camera_link"IMU所在的参考坐标系(重力方向相对于此坐标系)。
节点内部使用互补滤波系数0.98固定,如需调整请修改源码重新编译。

🚀 启动文件

d455_imu.launch

仅启动D455相机并开启IMU数据流(无彩色/深度)。

<include file="$(find realsense2_camera)/launch/rs_camera.launch">
    <arg name="enable_accel" value="true"/>
    <arg name="enable_gyro" value="true"/>
    <arg name="unite_imu_method" value="linear_interpolation"/>
    ...
</include>

gravity_visualization.launch

一键启动D455 IMU + 重力检测节点 + RViz(载入预设视图)。

roslaunch imu_gravity_detection gravity_visualization.launch

确保RViz配置文件 gravity_visualization.rviz 存在于 rviz/ 目录,显示TF和Marker。

👁️ 可视化与TF

TF树:节点发布从 frame_id (如camera_link) 到 gravity_direction 的静态旋转。该旋转使重力方向对齐到父坐标系的Z轴负方向。直观理解:gravity_direction 的Z轴指向地心。

Marker箭头:红色箭头起点在原点,方向与重力向量一致,长度0.5米,便于在RViz中观察重力指向。

RViz配置建议:添加TF显示,并添加Marker话题 /gravity_marker 为箭头类型。参考文件 gravity_visualization.rviz 已包含基本设置。

如果箭头不显示,检查frame_id是否匹配,并确保Marker有 lifetime (0.1秒持续刷新)。

⚙️ 参数配置

目前节点仅通过私有参数 frame_id 配置。如需修改互补滤波系数alpha或发布频率,可直接更改源码 imu_gravity_node.cpp 中的 gravity_detector_(0.98) 和订阅队列大小。

常见调整

目标修改位置
增加陀螺仪信任 (更动态)IMUGravityDetector(0.99)
增加加速度计信任 (更稳定)IMUGravityDetector(0.90)
改变箭头长度publishMarker() 中缩放系数 0.5

🔗 与Intel RealSense D455集成

本包专为D455设计,利用其内置IMU(BMI055)。关键点:

测试命令:rostopic echo /camera/imu 可查看原始数据。

💡 示例代码:自定义节点中使用Detector

#include "imu_gravity_detection/imu_gravity_detector.h"
#include <Eigen/Dense>
#include <iostream>

int main() {
    IMUGravityDetector detector(0.98f);
    float dt = 0.01f; // 假设100Hz

    // 模拟IMU数据 (静止)
    Eigen::Vector3f accel(0.0, 0.0, 9.8);
    Eigen::Vector3f gyro(0.0, 0.0, 0.0);

    detector.updateIMU(accel, gyro, dt);
    Eigen::Vector3f g = detector.getGravityDirection();

    std::cout << "重力方向: " << g.transpose() << std::endl;
    return 0;
}

🔍 故障排除

节点无输出/重力恒为零 检查IMU话题名是否为 /camera/imu。使用 rostopic list 确认。
RViz箭头不出现 确保在RViz中添加了Marker显示并选择正确的 /gravity_marker 话题。同时检查frame_id与TF树是否一致。
重力方向跳动或噪声大 降低互补滤波alpha值,让加速度计权重更大(如0.95),或在加速度校正中增加死区。
D455 IMU无数据 确认已安装 realsense2_camera 并设置 enable_accelenable_gyro 为true。

📊 性能调优建议

📝 更新日志

版本 1.0.0 (2026-03-19)

版本 0.9.0 (2026-02-15)

⚖️ 许可证

MIT License

Copyright (c) 2026 imu_gravity_detection Contributors

允许自由使用、修改、分发,包括商业用途,需保留版权声明。

© 2026 imu_gravity_detection · 文档生成于 2026-03-19 · 基于实际ROS包