# ros-gio **Repository Path**: hf26023/ros-gio ## Basic Information - **Project Name**: ros-gio - **Description**: 用于无人机和地面车辆的GNSS和imu融合定位的代码仓库 - **Primary Language**: Unknown - **License**: BSD-3-Clause - **Default Branch**: test - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2026-05-15 - **Last Updated**: 2026-08-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 适用于无人机、车辆的GNSS+IMU的EKF融合定位包 ## 测试方案:UM982 GPS + 航向 + IMU 融合 直接使用下面这套 launch: ```bash roslaunch robot_localization um982_gps_heading_imu_ekf.launch ``` 这套方案会串起以下节点: - `um982_nmea_converter`:把 `/um982/nmea/raw` 转成 GPS 和可融合的航向 IMU - `navsat_transform_node`:把经纬度 GPS 转成世界坐标系下的 `odometry/gps` - `ekf_localization_node`:融合 GPS 位置、UM982 绝对航向和原始 IMU **核心特性**: - 最终输出话题是 `/odometry/filtered` - 由原始 IMU `imu0` 触发滤波更新 - IMU 来一帧,就处理并发布一帧 - GPS 和 UM982 航向作为低频绝对观测参与校正 **默认输入话题**: - `/um982/nmea/raw`:`std_msgs/String`,UM982 原始 NMEA/heading 串口数据 - `/mavros/imu/data`:`sensor_msgs/Imu`,原始 IMU 数据 **中间话题**: - `/um982/global_position/raw/fix`:`sensor_msgs/NavSatFix` - `/um982/global_position/compass_hdg`:`std_msgs/Float64` - `/um982/global_position/heading_imu`:`sensor_msgs/Imu` - `/odometry/gps`:`nav_msgs/Odometry` **最终输出话题**: - `/odometry/filtered`:`nav_msgs/Odometry` ### 最简启动 ```bash cd /home/hf/gio catkin_make --pkg robot_localization source devel/setup.bash roslaunch robot_localization um982_gps_heading_imu_ekf.launch ``` ### 常用启动示例 ```bash roslaunch robot_localization um982_gps_heading_imu_ekf.launch \ input_topic:=/um982/nmea/raw \ imu_topic:=/mavros/imu/data ``` 如果你的 IMU 频率不是默认值,可以显式指定: ```bash roslaunch robot_localization um982_gps_heading_imu_ekf.launch \ imu_topic:=/mavros/imu/data \ imu_frequency:=200.0 ``` ### 关键参数 - `imu_frequency`:EKF 期望的 IMU 更新频率,建议填真实 IMU 频率 - `magnetic_declination_radians`:磁偏角补偿 - `yaw_offset`:航向零点补偿,单位弧度 - `heading_offset_deg`:UM982 航向零点补偿,单位度 - `heading_stddev_deg`:UM982 航向标准差,影响航向融合权重 - `gnss_xyz` / `gnss_rpy`:`base_link -> gnss_frame` 的静态外参 ### 对应文件 - Launch:`launch/um982_gps_heading_imu_ekf.launch` - EKF 参数:`params/um982_gps_heading_imu_ekf.yaml` - navsat 参数:`params/um982_navsat_transform.yaml` - UM982 转换:`launch/um982_nmea_converter.launch` --- ## 普通gps+imu方案 ```bash mkdir -p gio/src cd gio/src #复制该功能包到src cd ../.. catkin_make source devel/setup.bash roslaunch robot_localization gps_imu_ekf.launch ``` ### 相关参数 **Launch 文件**:`gps_imu_ekf.launch` 该方案同时使用 `navsat_transform_node` 和 `ekf_localization_node` 实现更好的融合: ```bash roslaunch robot_localization gps_imu_ekf.launch ``` 播放包的指定话题 ``` rosbag play your.bag --topic /mavros/imu/data /mavros/global_position/raw/fix ``` **输入话题**: - `gps/fix` (sensor_msgs/NavSatFix):原始 GPS 数据 - `imu/data` (sensor_msgs/Imu):IMU 姿态和角速度 - `target/gps/fix` (sensor_msgs/NavSatFix):目标点 GPS 数据(可选) (可以在launch中remap名称) **输出话题**: - `odometry/filtered` (nav_msgs/Odometry):融合后的位置和姿态估计(世界坐标系) - `odometry/gps` (nav_msgs/Odometry):由 GPS 转换得到的机器人位置(中间过程) - `target/position` (nav_msgs/Odometry):目标 GPS 转换到当前世界坐标系后的位姿(可选) ## UM982 原始串口转换 如果你的原始话题是 `/um982/nmea/raw` 的 `std_msgs/String`,可以直接启动这个转换节点: ```bash roslaunch robot_localization um982_nmea_converter.launch rosbag play /home/hf/gio/dataset/bag2_2026-05-29-10-49-39_nortcm.bag --clock ``` 默认会把 `GNGGAH` 转成 `/mavros/global_position/raw/fix`,把 `UNIHEADINGA` 转成 `/mavros/global_position/compass_hdg`。 **处理流程**: 1. `navsat_transform_node` 将 GPS 坐标(经纬度)转换到世界坐标系(map) 2. `ekf_localization_node` 融合转换后的 GPS 位置和 IMU 姿态 3. 如果接入 `target/gps/fix`,`navsat_transform_node` 还会把目标 GPS 转换到当前世界坐标系并发布到 `target/position` **优点**: - 灵活的融合:可通过协方差矩阵调整 GPS 和 IMU 的权重 - 卡尔曼滤波输出更平滑 - 更好地处理 GPS 信号丢失和 IMU 漂移 **缺点**: - 配置相对复杂 - 增加了一个节点的开销 **需要调整的关键参数**(`params/gps_imu_ekf.yaml`): - yaw相关: - `magnetic_declination_radians`:当地磁偏角,单位为弧度。用于把 IMU 基于磁北的航向修正到真北/ENU 坐标系 - `yaw_offset`:IMU 航向零点补偿,单位为弧度。用于把 IMU 的 yaw 零点对齐到 ENU 约定的“朝东为 0” - 额外的 EKF 参数: - `process_noise_covariance`:对运动模型的信任度 - `initial_estimate_covariance`:位置和姿态的初始不确定度 - EKF 中的传感器配置(设置每个传感器测量哪些状态变量) ### 磁偏角和 yaw_offset 在代码中的作用 在 ROS/mavros 的标准地理坐标系(ENU:东-北-天)中: - $Yaw = 0$ 代表机头朝正东 - $Yaw = 90^\circ$ 代表机头朝正北 - $Yaw = 180^\circ / -180^\circ$ 代表机头朝正西 - $Yaw = -90^\circ$ 代表机头朝正南 `magnetic_declination_radians` 用来补偿当地磁偏角。若 IMU 输出的是相对磁北的航向,该参数会把它修正到系统使用的 ENU 世界坐标系航向。 `yaw_offset` 用来补偿 IMU 自身的零点定义差异。`navsat_transform_node` 默认假设 yaw 在“朝东”时为 0;如果你的 IMU 在“朝北”时读数为 0(很多设备都是这样),通常需要把 `yaw_offset` 设为 `pi/2`,使修正后的航向满足 ENU 约定。 在 `navsat_transform_node` 中,航向修正实际按下面公式执行: $$ yaw_{used} = yaw_{imu} + magnetic\_declination + yaw\_offset + utm\_meridian\_convergence $$ 也就是: - `magnetic_declination_radians` 负责把“磁北参考”纠正为“真北参考” - `yaw_offset` 负责把“传感器自己的零点定义”纠正为“朝东为 0” 对应代码位置: - `src/navsat_transform.cpp` 中读取参数:`nh_priv.getParam("magnetic_declination_radians", magnetic_declination_)` - 航向修正计算:`yaw += (magnetic_declination_ + yaw_offset_ + utm_meridian_convergence_)` 如果该参数配置错误,常见现象包括: - 地图坐标下轨迹整体偏转一个固定角度 - 机器人朝向与实际前进方向不一致 - GPS 与 IMU 融合后出现“斜着走”或长期方向偏差 --- ## 位姿曲线绘制 仓库内提供了一个 Python 绘图节点 `plot_odometry_pose.py`,用于订阅 `nav_msgs/Odometry` 并实时绘制: - XY 平面轨迹 - x、y、z 随时间变化曲线 - roll、pitch、yaw 随时间变化曲线 脚本会自动把四元数姿态转换为 RPY;默认角度单位为度。 **默认订阅话题**:`/odometry/filtered` **使用方法**: ```bash cd gio catkin_make source devel/setup.bash rosrun robot_localization plot_odometry_pose.py ``` **订阅其他里程计话题**: ```bash rosrun robot_localization plot_odometry_pose.py _topic:=/your/odometry/topic ``` **常用参数**: - `_topic`:要订阅的里程计话题,默认 `/odometry/filtered` - `_max_points`:缓存并显示的最大采样点数,默认 `3000` - `_use_degrees`:是否将 RPY 以角度显示,默认 `true`,设为 `false` 时显示弧度 **示例**: ```bash rosrun robot_localization plot_odometry_pose.py _topic:=/odometry/gps _max_points:=5000 _use_degrees:=true ``` 如果运行时报 matplotlib 缺失,请先安装 Python 版 matplotlib。 --- ## 故障排除 **查看可用话题**: ```bash rostopic list | grep -E 'odometry|gps|imu' ``` **监控融合输出**: ```bash rostopic echo /odometry/filtered # 方案 2 的输出 # 或 rostopic echo /odometry/gps # 方案 1 的输出 ``` **对于自定义话题名称**,在 launch 文件中重映射: ```xml ``` --- ## 双 EKF*(轮速+imu) + GPS 如需更完整的例子(包含轮速里程计、IMU 和 GPS),参考 `dual_ekf_navsat_example.launch` 及其配置文件 `params/dual_ekf_navsat_example.yaml`。该示例会同时产出本地里程计系和全局地图系的估计。