一. GPS接口类型
GPS接口大体可以分为两类,一是单独的GPS接收器,通常为USB接口;二是与其他传感器集成,例如激光雷达或者imu,大多是USB或者网络接口,本文主要介绍USB接口实例。
二. 概念
这里有三个概念,需要明确下:驱动,SDK和ROS驱动。以USB GPS为例,GPS驱动是作为操作系统层面的驱动程序,一般需要事先安装,安装成功后,接入GPS设备时,会出现相应的设备文件,
通常为/dev/ttyUSBx,x是一个数字,代表设备号,与主机接入的设备个数和顺序有关。在驱动安装完成之后,我们就获得了设备文件。GPS SDK是一套应用层程序,可以从设备文件中获取设备数据,驱动和SDK一般都由厂家提供。
ROS驱动通常是基于SDK进行ROS封装而成,目前有不少传感器厂商和ROS社区提供了常用传感器的ROS驱动。
三.GPS ROS驱动获取
当我们拿到一个GPS之后,可以首先查下这款GPS有没有ROS驱动,可以咨询厂商或者到ros wiki查询,链接:
Sensors - ROS Wikiwiki.ros.org
如果没有现成的ROS驱动,可以基于厂商提供的SDK自己封装,可以参考同类型ros驱动设计。
四. nmea_navsat_driver
nmea_navsat_driver是一套用于获取并解析GPS数据的ROS驱动包,使用Python语言实现。GPS设备使用此包的条件是:遵守或者兼容NMEA0184协议。nmea_navsat_driver提供四个节点:nmea_topic_driver,
nmea_serial_driver,nmea_topic_serial_reader和nmea_socket_driver。
1. 文件结构
执行以下指令:
roscd nmea_navsat_driver
sudo apt install tree
tree -L 4
执行效果如图:
scripts目录存放顶层节点文件,对应上述四个节点,其中的文件只是调用main()函数,实际实现在src/nodes目录下对应文件名的Python文件中。launch目录存放启动nmea_serial_driver节点launch文件。
setup.py是Python语言ROS包编译配置文件,内容不要更改。
2. nmea_topic_serial_reader节点
此节点从串口读入GPS数据,然后封装为nmea_msgs/Sentence数据格式,发布话题nmea_sentence。
nmea_topic_serial_reader文件只有两行,如下:
import libnmea_navsat_driver.nodes.nmea_topic_serial_reader
libnmea_navsat_driver.nodes.nmea_topic_serial_reader.main()
第一行导入nodes目录下的nmea_topic_serial_reader.py文件,第二行调用nmea_topic_serial_reader.py中的main()函数。
nmea_topic_serial_reader.py文件内容如下,因为增加中文注释,所以需要包含“# -*- coding: UTF-8 -*-”。
# -*- coding: UTF-8 -*-
import serial #引入串口模块
from nmea_msgs.msg import Sentence #引入nmea_msgs/Sentence结构
import rospy #引入ROS的Python接口模块
from libnmea_navsat_driver.driver import RosNMEADriver #引入driver.py中的RosNMEADriver
def main():
rospy.init_node('nmea_topic_serial_reader') #初始化ros节点名
nmea_pub = rospy.Publisher("nmea_sentence", Sentence, queue_size=1) #定义发布者
serial_port = rospy.get_param('~port', '/dev/ttyUSB0') #设置串口设备文件名
serial_baud = rospy.get_param('~baud', 4800) #设置波特率
# Get the frame_id
frame_id = RosNMEADriver.get_frame_id() #设置frame_id
try:
GPS = serial.Serial(port=serial_port, baudrate=serial_baud, timeout=2) #调用python串口模块Serial
while not rospy.is_shutdown():
data = GPS.readline().strip() #从串口读入数据
sentence = Sentence() #创建nmea_msgs/Sentence结构变量sentence
sentence.header.stamp = rospy.get_rostime() #设置sentence的时间戳为当前时间
sentence.header.frame_id = frame_id #设置sentence的frame_id
sentence.sentence = data #设置sentence的sentence变量。
nmea_pub.publish(sentence) #发布sentence
except rospy.ROSInterruptException: #异常处理
GPS.close() # Close GPS serial port
文件添加了详细的注释,大家可以对比阅读。需要注意的是,在串口设置时需要根据实际情况,配置设备文件以及波特率。
3. nmea_topic_driver节点
此节点订阅话题nmea_sentence,然后根据NMEA0184协议解析,并发布解析后的数据,发布话题为:经纬度/fix,速度/vel,gps时间/time_reference和航向角/heading。
执行以下指令:
rosrun nmea_navsat_driver nmea_topic_driver
rqt_graph
执行效果如图
nmea_topic_driver节点文件流程同nmea_topic_serial_reader,顶层节点文件nmea_topic_driver调用nmea_topic_driver.py中的main函数,nmea_topic_driver.py内容如下:
# -*- coding: UTF-8 -*-
from nmea_msgs.msg import Sentence
import rospy
from libnmea_navsat_driver.driver import RosNMEADriver
def nmea_sentence_callback(nmea_sentence, driver):
try:
driver.add_sentence(
nmea_sentence.sentence,
frame_id=nmea_sentence.header.frame_id,
timestamp=nmea_sentence.header.stamp) #add_sentence()接收frame_id和时间戳,接收sentence并解析,发布解析后的时间,位置,速度和航向角信息。
except ValueError as e:
rospy.logwarn(
"Value error, likely due to missing fields in the NMEA message. "
"Error was: %s. Please report this issue at ros-drivers/nmea_navsat_driver, "
"including a bag file with the NMEA sentences that caused it." %
e)
def main():
rospy.init_node('nmea_topic_driver')
driver = RosNMEADriver() #实例化RosNMEADriver()类
rospy.Subscriber("nmea_sentence", Sentence, nmea_sentence_callback,driver) #订阅话题nmea_sentence,话题类型Sentence,回调函数nmea_sentence_callback,回调函数第二个参数driver。
rospy.spin()
这里比较关键的是add_sentence()函数,此函数是driver.py文件RosNMEADriver类的成员函数,主要功能是根据NMEA0184协议,对sentence数据进行解析,进而获取gps时间,位置,速度以及航向角信息,然后发布出来,
感兴趣的可以对照NMEA0184协议研究此函数,这里不再深入分析。
需要说明的是,虽然此函数提供了四个话题,但是不同的GPS设备,其提供的信息可能也不一样,所以有的话题可能是空的,例如heading和vel。
4. nmea_serial_driver节点
此节点从串口读数据,直接解析发布数据,相当于nmea_topic_driver节点和nmea_topic_serial_reader节点的结合体,有了上面两个基础,相信应该可以看懂这个程序,就不再介绍了。
此节点是通过网口读取gps数据,除了接口不同外,在拿到sentence之后的处理流程是一致的,这里就不在介绍,需要说明的是利用网口,只需要配置ip和端口号,不需要安装驱动。
五. 说明
虽然GPS设备输出数据兼容NMEA0184,但是不同厂家的设备,可能需要不同的配置,所以一个GPS ROS驱动不一定适应所有GPS设备,即使GPS设备遵守NMEA0184,nmea_navsat_driver包在Garmin GPS 18x以及
Venus Venus634LPx上测试,其他GPS设备未必可以直接使用,最终还是以厂家手册为准。
六. 参考
本篇参考wiki:
nmea_navsat_driver - ROS Wikiwiki.ros.org
代码取自其中的github仓库:
ros-drivers/nmea_navsat_drivergithub.com
,
添加了部分中文注释,修改后的代码提交到仓库:
https://github.com/ahuer2435/ros_program_melodic.gitgithub.com
七. 小结
本篇首先明确驱动,sdk以及ros驱动的概念,介绍了实现ros驱动的几种途径,然后以nmea_navsat_driver为例,介绍在ros系统中,如何获取,解析以及发布gps数据,由于没有实际硬件,所以没有运行串口读取的节点,有条件的话,大家可以自行测试。
GPS可以实现全球范围内定位,但是由于其频率较低,且易受外界影响,在实际使用中多与IMU配合使用,下一篇介绍GPS的黄金搭档:惯性测量单元IMU。