MAVROS GPS Listener 📸 无人机传感器数据采集与图像元数据写入
C++14
ROS Melodic/Noetic
MAVROS
Exif/XMP
OpenCV
一个完整的ROS功能包,用于订阅无人机传感器数据(GPS、IMU、姿态、位置),并通过服务调用将当前图像帧与传感器数据保存到图片元数据中,支持GPS坐标写入EXIF,扩展数据写入XMP或UserComment。
📖 概述
MAVROS GPS Listener 是一个基于ROS的无人机数据采集功能包,专为无人机航测、视觉定位、数据归档等场景设计。核心功能是订阅MAVROS发布的传感器话题和相机图像话题,当用户调用服务时,捕获当前图像帧,并将实时传感器数据(GPS坐标、姿态角、位置速度等)写入图像的元数据中(EXIF/XMP)。
📡 GPS数据
纬度、经度、海拔、卫星数、定位类型、HDOP/VDOP
🌀 姿态数据
Roll/Pitch/Yaw(弧度)、角速度
📍 位置数据
本地坐标系位置(X,Y,Z)、速度
📸 图像元数据
EXIF GPS标签 + XMP扩展数据 / UserComment JSON
🛠️ 服务接口
/capture_image 服务,支持自定义文件名/路径
🐍 跨平台查看
Python脚本 + PyQt5可视化工具
✨ 核心特性
- 多话题订阅 — GPS Fix、GPS RAW、IMU、本地位置/速度
- 图像捕获服务 — 通过ROS服务触发,支持自定义图片名称和路径
- 元数据写入 — GPS数据写入EXIF标准标签,扩展数据写入UserComment(JSON)和XMP双备份
- 实时数据采集 — 每次服务调用时捕获最新传感器数据和图像帧
- 线程安全 — 使用互斥锁保护共享数据
- 灵活配置 — 支持launch文件配置图像话题和保存路径
- 跨平台查看 — 提供Python脚本和PyQt5可视化工具,支持Windows/Linux
- 完善的错误处理 — 即使XMP写入失败,图像和JSON数据仍可保存
⚡ 快速开始
最简单的使用方式: 启动节点后调用服务即可
# 终端1: 启动MAVROS
roslaunch mavros px4.launch fcu_url:=/dev/ttyACM0:921600
# 终端2: 启动相机驱动(根据实际相机)
roslaunch usb_cam usb_cam-test.launch
# 终端3: 启动GPS监听节点
roslaunch mavros_gps_listener gps_listener.launch
# 终端4: 调用服务捕获图像
rosservice call /capture_image "image_name: 'flight_001' image_path: ''"
# 查看结果
exiv2 -p e ~/gps_ws/images/flight_001.jpg | grep GPS
🏗️ 架构设计
功能包采用模块化设计,主要包含以下组件:
GPSListener— 主节点类,负责订阅话题、管理共享数据、提供服务GPSMetadataWriter— 元数据写入类,封装Exiv2库操作,支持EXIF/XMP/UserCommentSensorData— 传感器数据结构体,存储GPS、姿态、位置等所有数据CaptureImage.srv— 服务定义,包含请求/响应结构
数据流: MAVROS → 话题回调 → 互斥锁保护 → 共享数据 → 服务触发 → 图像捕获 → 元数据写入 → 保存文件
📡 ROS话题订阅
节点默认订阅以下话题(可通过launch文件重映射):
| 话题名称 | 消息类型 | 数据内容 |
|---|---|---|
/uav1/mavros/global_position/global | sensor_msgs/NavSatFix | GPS经纬度、海拔 |
/uav1/mavros/global_position/raw/fix | mavros_msgs/GPSRAW | 卫星数、定位类型、HDOP/VDOP |
/uav1/mavros/global_position/raw/gps_vel | geometry_msgs/Vector3Stamped | GPS速度 |
/uav1/mavros/imu/data | sensor_msgs/Imu | 姿态(四元数)、角速度 |
/uav1/mavros/local_position/pose | geometry_msgs/PoseStamped | 本地位置 |
/uav1/mavros/local_position/velocity_local | geometry_msgs/TwistStamped | 本地速度 |
/uav1/camera/image_raw | sensor_msgs/Image | 图像帧 |
话题名称可通过launch文件中的
image_topic参数配置。🛠️ 服务接口
/capture_image [mavros_gps_listener/CaptureImage]
请求参数
string image_name— 图片名称(不含路径,可选,不提供则使用时间戳)string image_path— 完整保存路径(可选,优先级高于image_name)
响应参数
bool success— 是否成功string message— 响应消息string saved_image_path— 实际保存的图片路径int32 capture_time— 捕获时间戳(秒)
# 调用示例
rosservice call /capture_image "image_name: 'waypoint_001' image_path: ''"
# 返回: success: True, saved_image_path: "/home/amov/gps_ws/images/waypoint_001.jpg"
📸 图像元数据结构
保存的图像包含以下元数据:
EXIF GPS标签(标准GPS数据)
Exif.GPSInfo.GPSLatitude— 纬度(度分秒有理数)Exif.GPSInfo.GPSLatitudeRef— 纬度参考(N/S)Exif.GPSInfo.GPSLongitude— 经度(度分秒有理数)Exif.GPSInfo.GPSLongitudeRef— 经度参考(E/W)Exif.GPSInfo.GPSAltitude— 海拔(有理数)Exif.GPSInfo.GPSAltitudeRef— 海拔参考Exif.GPSInfo.GPSTimeStamp— GPS时间Exif.GPSInfo.GPSDateStamp— GPS日期
UserComment JSON(扩展传感器数据)
{
"latitude": 39.9042,
"longitude": 116.4074,
"altitude": 50.5,
"roll": 0.04999,
"pitch": -0.02356,
"yaw": 2.79048,
"roll_rate": 0.00191,
"pitch_rate": 0.00093,
"yaw_rate": -0.00026,
"position_x": 10.5,
"position_y": 20.3,
"position_z": 50.2,
"velocity_x": 0.5,
"velocity_y": 0.3,
"velocity_z": 0.1,
"gps_velocity_x": 0.52,
"gps_velocity_y": 0.31,
"satellites_visible": 12,
"fix_type": 3,
"hdop": 1.2,
"vdop": 1.5,
"timestamp": 1774250591.408
}
XMP标签(可选,双备份)
Xmp.drone.Roll
Xmp.drone.Pitch
Xmp.drone.Yaw
Xmp.drone.PositionX
Xmp.drone.VelocityX
Xmp.drone.SatellitesVisible
Xmp.drone.Timestamp
🚀 使用指南
1. 创建功能包
cd ~/catkin_ws/src
catkin_create_pkg mavros_gps_listener roscpp sensor_msgs geometry_msgs mavros_msgs cv_bridge image_transport
2. 编译
cd ~/catkin_ws
catkin_make
source devel/setup.bash
3. 配置launch文件
<launch>
<arg name="image_topic" default="/uav1/camera/image_raw" />
<arg name="save_path" default="/home/amov/gps_ws/images" />
<node name="gps_listener_node" pkg="mavros_gps_listener" type="gps_listener_node" output="screen">
<param name="image_topic" value="$(arg image_topic)" />
<param name="save_path" value="$(arg save_path)" />
</node>
</launch>
4. 运行
roslaunch mavros_gps_listener gps_listener.launch
5. 调用服务
rosservice call /capture_image "image_name: 'test' image_path: ''"
📌 示例程序
| 示例文件 | 描述 |
|---|---|
gps_listener_node.cpp | 主节点实现,包含话题回调和服务处理 |
gps_metadata_writer.cpp | 元数据写入实现,封装Exiv2操作 |
test_client.py | Python服务调用示例 |
read_metadata.py | Python读取图片元数据脚本 |
viewer.py | PyQt5可视化工具,支持批量查看 |
🐍 Python数据读取脚本
#!/usr/bin/env python3
import exiv2
import json
def read_image_metadata(image_path):
image = exiv2.ImageFactory.open(image_path)
image.readMetadata()
# 读取GPS
exif = image.exifData()
if 'Exif.GPSInfo.GPSLatitude' in exif:
print(f"GPS: {exif['Exif.GPSInfo.GPSLatitude']}")
# 读取UserComment JSON
if 'Exif.Photo.UserComment' in exif:
comment = exif['Exif.Photo.UserComment'].toString()
json_start = comment.find('{')
if json_start != -1:
data = json.loads(comment[json_start:])
print(f"Roll: {data['roll']:.2f} rad")
print(f"Pitch: {data['pitch']:.2f} rad")
print(f"Yaw: {data['yaw']:.2f} rad")
if __name__ == '__main__':
read_image_metadata('capture_20260323_152311.jpg')
需要安装:
pip install python-exiv2📊 数据可视化工具
提供基于PyQt5 + Matplotlib的可视化工具,支持:
- 图像缩略图浏览
- 传感器数据表格展示
- 姿态仪表盘(Roll/Pitch/Yaw可视化)
- 姿态变化曲线(随时间变化)
- 位置轨迹(X-Y平面)
- GPS轨迹(经纬度地图)
python3 viewer.py
# 选择包含图片的文件夹,自动加载所有图片元数据
⚙️ 配置参数
| 参数名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
image_topic | string | /uav1/camera/image_raw | 图像话题名称 |
save_path | string | /home/amov/gps_ws/images | 图片保存目录 |
📦 编译与依赖
依赖项
- ROS Melodic/Noetic
- OpenCV (≥3.2)
- Exiv2 (≥0.27)
- Eigen3 (≥3.3)
- cv_bridge, image_transport
# Ubuntu 安装依赖
sudo apt install ros-${ROS_DISTRO}-mavros ros-${ROS_DISTRO}-mavros-extras
sudo apt install ros-${ROS_DISTRO}-cv-bridge ros-${ROS_DISTRO}-image-transport
sudo apt install libopencv-dev libeigen3-dev libexiv2-dev
# 编译
cd ~/catkin_ws
catkin_make --only-pkg-with-deps mavros_gps_listener
🔧 常见问题
Q: 服务调用返回"没有可用的图像数据"
A: 检查图像话题是否正确,使用
A: 检查图像话题是否正确,使用
rostopic list | grep image查看实际话题名称,并在launch文件中配置。
Q: GPS数据为0
A: 检查MAVROS连接状态和GPS信号,使用
A: 检查MAVROS连接状态和GPS信号,使用
rostopic echo /mavros/global_position/global查看是否有数据。
Q: 编译时找不到exiv2
A: 安装libexiv2-dev:
A: 安装libexiv2-dev:
sudo apt install libexiv2-dev
Q: UserComment中的JSON缺少开头的{
A: 这是已知问题,已在新版本中修复。可使用Python脚本自动修复解析。
A: 这是已知问题,已在新版本中修复。可使用Python脚本自动修复解析。
Q: 如何查看写入的元数据?
A: 使用
A: 使用
exiv2 -p e image.jpg | grep GPS查看GPS,使用exiv2 -p x image.jpg | grep drone查看XMP。
⚖️ 许可证
MIT License
Copyright (c) 2025 MAVROS GPS Listener Contributors
允许自由使用、修改、分发,需保留版权声明。不提供任何担保。
📡 MAVROS GPS Listener · 文档生成于 2026-03-23 · 基于实际代码库
支持版本: ROS Melodic/Noetic | 最后更新: 2026-03-23