无人驾驶(二)---室外导航之RTK配置与接入及GPS与UTM坐标转换
1. 为什么无人驾驶室外导航离不开RTK,靠普通GPS真的会翻车
去年我做了一台无人小车,在园区里跑得好好的,一出园区大门就开始“画龙”。不是电机的问题,也不是转向标定的问题,最后用日志一看,定位轨迹在整个路口来回跳了七八米。那一刻我意识到,室外无人驾驶的精度天花板,根本不在于控制算法,而在于位置传感器本身。普通消费级GPS在开阔地带大概能到2到5米的精度,在树荫、楼群附近直接变成“薛定谔的定位”——每一帧数据都不可信,而无人驾驶需要的是厘米级别的定位,尤其是在车道保持、自动泊车、精准停靠这些动作里,30厘米的误差就足以让车辆骑上马路牙子。
这就是为什么RTK(Real-Time Kinematic,实时动态载波相位差分)成了室外导航的主力方案。RTK和普通GPS的本质区别在于,它不依赖GPS卫星播发的伪距码,而是直接利用卫星信号的载波相位做差分计算。用一个比喻来说,普通GPS是靠“大约在几点”来估算距离,RTK则是用“从几点几分几秒到几微秒”来精确测量距离。再加上一个已知坐标的基准站做差分,把大气误差、卫星钟差这些公共误差全部抵消掉,移动站在开阔环境下能稳定达到厘米级固定解。
RTK配置和接入看起来就是接天线、连串口、配波特率、发RTCM数据,真正落地时会遇到一堆离谱问题:固定解出不来、坐标跳变、转换后轨迹扭曲、天线安装位置不合适导致多路径效应……这篇文章我先讲清RTK为什么是刚需,再把从硬件选型到接入配置、从坐标转换到实测排障的完整思路串起来,给准备在室外无人平台上用RTK的朋友一个可以参考的路径。
2. RTK硬件选型与天线安装的实用心得
2.1 基准站和移动站:两个站缺一不可
RTK系统至少需要一个基准站和一个移动站。基准站的位置必须是已知的,它接收卫星信号并计算观测误差,然后通过电台、WiFi或4G把修正数据发给移动站。移动站装在车上,也接收卫星信号,同时接收基准站发来的差分数据,两边的载波相位做差,消除公共误差,得到高精度坐标。
选型时两个站要一起考虑。对我这个项目来说,选的是某款u-blox F9P模块,因为它原生支持RTK解算,同时输出原始观测数据和RTCM 3.3格式,价格也不算离谱。如果你只是想快速验证,也可以买成品的RTK套件(比如千寻、中海达、华测的移动端),配一个CORS账号,省去自建基准站的麻烦。但自建基准站能帮你理解整个链路,后续调试更顺手。
2.2 天线安装位置:所有“玄学”问题的大本营
RTK天线听起来就是“粘在车顶就行”,实际上它是全车最容易出Bug的器件。我踩过的最大一个坑是天线装在了车顶金属横梁旁边,导致多路径效应严重。多路径效应是卫星信号打到地面、墙体、金属架上再反射进天线,相当于天线听到了回音,相位观测值被污染,固定解频繁丢失,定位轨迹一抖一抖。
天线安装的几个硬性规则:
- 尽可能放在车身最高点,四周270度范围内不要有遮挡物,天线自身的接地面要水平。
- 远离大块金属面、光伏板、金属货架、摄像头支架,至少保证50厘米以上的净空。
- 陶瓷天线更要注意接地,如果天线底部没有直接和车身金属接触,信号重心会偏低,固定的效果很糟糕。
- 线缆尽量用原装的低损耗同轴线,不要自己压接头,接头处进了一次水整条链路就报废。
当时我们测过同一个天线放在车顶中间和放在行李箱边缘的位置,固定解的比例从92%降到了64%,这个数据比任何理论解释都直观。
2.3 核心参数:波特率、数据格式、天线相位中心
大多数RTK模块通过串口或USB口输出数据,接入时先确认波特率是否匹配(常见的有38400、115200,也有默认9600的)。数据格式方面,移动站最容易忽视的是要输出带质量标识的GGA语句,其中第6个字段“定位质量标识”能区分单点解、浮点解和固定解,这是排查问题的第一入口。
天线相位中心和机械中心之间其实存在一个偏移量,高精度场景下必须校准。简单做法是把天线固定在一个已知点(比如用全站仪测过的地钉),静止采集两分钟以上,把输出坐标和已知坐标的差值作为一个常数修正。如果你只是做室外导航、不追求绝对地理坐标的厘米级,这个偏移量可以暂时忽略,但别忽略之后拿全站仪来“打假”,不然落差会非常尴尬。
3. RTK配置与接入的完整操作流程,照着做就能跑通
3.1 从零开始搭建一套迷你RTK
这里以u-blox F9P + 树莓派为例,写一遍我实际用过的配置过程。前提是树莓派里装好了串口工具,比如Python的pyserial。
第一步是接线。F9P开发板上有5V和GND排针,串口TX/RX分别接树莓派的RX/TX,别反接,我当时把TX接TX,结果什么都没有,还以为是模块坏了。接好之后在树莓派上执行ls /dev/ttyAMA0确认串口节点存在,如果用的是USB转串口,那可能是/dev/ttyUSB0。
第二步是配置输出消息。F9P在上电后默认可能不放任何数据,需要用U-Center软件(Windows)先连接一次,在UBX-CFG-MSG里面把NMEA里的GGA、GST、RMC打开,同时设置输出频率——我一般设10Hz,太高占带宽,太低控制算法会滞后。
第三步是启动基准站。基准站需要知道自己的精确坐标,常见方式有两种:一种是根据官方状态查询到的坐标输入进去;另一种是在同一位置连续静态采集10分钟以上,用模块自带的Survey-in模式自动收敛出一个坐标。我推荐先用静态采集一次,然后手动固定坐标,避免重复收敛慢的问题。
第四步是启动移动站的base station数据输入。如果你是自建链路,基准站的RTCM 3.3仿真数据通过串口或者TCP传到移动站;如果购买CORS账号,则通过ntrip协议拉取差分数据。
第五步是确认固定解。看GGA输出中的第6个字段,值为4代表固定解,值为5代表浮点解,值为1代表单点解。如果你看到浮点解持续了好几分钟,先检查天线遮挡和差分数据质量,而不是调整代码参数。
3.2 实测中的数据流与配置项检查
我用一个表格整理我常用的检查项,每次接入新硬件都能靠它快速定位问题:
| 检查项 | 预期状态 | 异常可能的根因 |
|---|---|---|
| 串口连接 | 能持续输出NMEA或UBX帧 | 接线反了、波特率不一致、串口号错误 |
| GGA语句存在 | 每秒10帧左右 | 配置消息未开启,重新用U-Center配置 |
| 卫星数 | 至少10颗以上 | 环境遮挡严重,天线位置不对 |
| 信噪比 | 40 dBHz以上 | 天线损坏、线缆接头松动、天线未接地 |
| 差分数据输入 | 移动站能接收到RTCM帧 | 基准站未启动、端口或网络不通、协议格式错误 |
| 定位质量标识 | 固定解(4) | 基线长度超过20km、大气扰动大、差分中断 |
这里有一条容易忽略的链路问题:如果你用笔记本电脑连接移动站,直接用USB转串口模块供电,电流不够可能导致模块自动降频或者重启,时不时掉固定解。换个质量好的、能提供500mA以上电流的电源就好很多。
3.3 罗盘与惯导的初步融合:RTK不是万能的
RTK的更新频率一般到10Hz,在车辆高速运动时是不够的,而且在隧道、立交桥底、高楼区信号会被完全遮挡。就算固定解一直存在,RTK给出的坐标也有“噪声毛刺”,直接拿去做路径跟踪,车辆会轻微抖动。建议把RTK当成一个绝对位置观测值,用扩展卡尔曼滤波或因子图融合IMU(惯性测量单元)和轮速计,才能得到平滑、高速率、鲁棒的定位结果。
我自己的经验是,在融合前先对RTK坐标做一步粗处理后验处理:如果与上一帧位移超过2米同时车速小于0.5m/s,大概率是跳变,直接丢掉这一帧。别小看这个暴力删帧,它对IMU融合初期的稳定性帮助特别大。
4. 从GPS到UTM:坐标系背后的原理与转换实现
4.1 经纬度和米制坐标,谁更适合无人驾驶
GPS卫星直接给出的是WGS84坐标系下的经度、纬度和高度,单位是度,而无人驾驶控制层和路径规划通常希望坐标是米制单位。你可以用正弦余弦算两点的距离,但每帧都这么做,代码冗长且容易出错。更好的办法是把经纬度投影到平面坐标,最常用的是UTM(Universal Transverse Mercator,通用横轴墨卡托)坐标系。
UTM的原理可以这样理解:把地球按经度每6度分一个带,全球共60个带,然后用一个横轴圆柱去切地球,把带内区域投影到平面上。为了控制变形,UTM规定中央经线比例因子为0.9996,这样在中央经线附近长度变形最小,偏离中央经线越远变形越大。对无人驾驶这种“局部区域作业”的场景,跨带情况很少,用UTM非常合适。
4.2 手写一个WGS84转UTM的可直接用的函数
写转换代码时,直接调用PROJ库最省事,但如果你只是做快速验证,不想引入大依赖,我这里给一个Python实现,基于标准椭球参数推导,精度在亚毫米级。
import math def wgs84_to_utm(lat, lon): # WGS84椭球参数 a = 6378137.0 f = 1.0 / 298.257223563 k0 = 0.9996 zone = int((lon + 180) // 6) + 1 lon0 = (zone - 1) * 6 - 180 + 3 # 中央经线 lat_rad = math.radians(lat) lon_rad = math.radians(lon) lon0_rad = math.radians(lon0) e2 = 2 * f - f * f e_prime2 = e2 / (1 - e2) N = a / math.sqrt(1 - e2 * math.sin(lat_rad) ** 2) T = math.tan(lat_rad) ** 2 C = e_prime2 * math.cos(lat_rad) ** 2 A = math.cos(lat_rad) * (lon_rad - lon0_rad) M = a * ((1 - e2 / 4 - 3 * e2 ** 2 / 64 - 5 * e2 ** 3 / 256) * lat_rad - (3 * e2 / 8 + 3 * e2 ** 2 / 32 + 45 * e2 ** 3 / 1024) * math.sin(2 * lat_rad) + (15 * e2 ** 2 / 256 + 45 * e2 ** 3 / 1024) * math.sin(4 * lat_rad) - (35 * e2 ** 3 / 3072) * math.sin(6 * lat_rad)) x = k0 * N * (A + (1 - T + C) * A ** 3 / 6 + (5 - 18 * T + T * T + 72 * C - 58 * e_prime2) * A ** 5 / 120) y = k0 * (M + N * math.tan(lat_rad) * (A ** 2 / 2 + (5 - T + 9 * C + 4 * C * C) * A ** 4 / 24 + (61 - 58 * T + T * T + 600 * C - 330 * e_prime2) * A ** 6 / 720)) # 北半球Y偏置 y += 10000000.0 if lat < 0 else 0.0 x += 500000.0 # X方向偏置 return x, y, zone这个函数的输出是UTM东向(Easting)和北向(Northing),单位为米。有了这个局部平面坐标,你可以直接计算车辆当前位置和路径点之间的距离、航向角,做路径跟踪时不再有“经度和纬度怎么相加”的尴尬。
4.3 UTM转换中必须避开的三个坑
UTM看起来简单,实际使用时有几个非常容易踩的坑。第一是中央经线没设对:如果车在120度附近,自动算出来zone=50,中央经线=117度,但RTK输出的经纬度可能略有波动,导致zone号在49和50之间跳变,坐标跳变上万米。这时需要强制固定一个zone,不能动态切换。
第二是处理y轴偏置:南半球需要加10000000米,北半球不加。如果你在国内工作,忘了加偏置也不会马上发现,但一旦做全球部署就会出错。我建议不管在哪,代码里都显式判断纬度正负。
第三是使用基准面的微小差异:WGS84和CGCS2000在绝大多数情况下差值小于1米,对室外导航够用,但如果你做进港靠泊之类的厘米级项目,就需要做七参数转换,否则绝对位置会整体偏移。
5. 实测中的坐标漂移问题与完整排查链路
5.1 一次“固定解消失”的现场复盘
有一次我们在一个新建园区测试,固定解比例只有30%,严重时几分钟都回不来。现场环境很开阔,理论上传星条件很好。我当时的排查顺序是:
- 先看卫星数量:正常情况下12颗以上,现场却有30多颗,但信噪比普遍低于35dBHz。这个现象说明不是数量问题。
- 再看差分数据:基准站输出的RTCM帧在电脑上解码正常,但移动站接收后没有任何响应。我以为是蓝牙不匹配,换两根串口线、调半天,还是不行。
- 最后重新扫描了天线,发现天线正上方2米处有一根高压电线,强电场干扰了信号接收,天线整体放在了车顶空调外机和新风管道之间,形成了严重的电磁干扰和多路径混合。
处理办法:把天线挪到车顶最前方,远离高压线路,重新启动,固定解比例恢复到95%以上。
这个案例给我最大的启发是:RTK调试不要盯着代码看,先看物理环境。任何“软件不管用”的问题,80%都是“硬件安装不过关”。
5.2 坐标转换之后的轨迹偏移排查
当RTK坐标转成UTM后,如果轨迹和实际道路之间出现“整体偏移几米”的情况,最该检查的是UTM带的中央经线。有一个真实案例:车辆在zone 49和zone 50交界的城市运行,代码里自动算zone的时候偶发跳变,导致轨迹在某个路口忽然从X=140000跳到X=500000,整个路径全部错乱。
解决方法是固定一个区域用的zone,比如整个城市固定为zone 50,然后做一个全网校验。另一个容易被忽略的是RTK模块输出经纬度时,某些固件默认输出的是WGMS84也未开启度分秒格式,导致纬度从31.123456写成31°12'34.56'',转换时直接偏了一个数量级。用转换工具前先打印原始GGA语句,看到底是十进制度数还是度分格式,确保无误。
5.3 常见误区与经验总结
- 误区一:RTK固定解就是绝对精确。实际上固定解的定位噪声在1到3厘米,但累计漂移和坐标转换误差会叠加,需要定期用全站仪或地面标识校验。
- 误区二:UTM坐标是平面直线。UTM是投影坐标,在大范围路径规划时必须考虑跨带切换,不能把两个不同带的坐标直接相减求距离。
- 误区三:CORS账号一定稳定。实际使用中运营商网络波动会导致差分数据中断,固定解会降级成浮点解甚至单点解,一定要在代码里对定位质量做降级处理。
6. 把RTK接入无人驾驶系统的最后一步
这篇文章讲到的内容,其实就是我在做室外无人车时最常用到的一条完整链路:选天线、装天线、配模块、看GGA质量、确认差分数据、转UTM坐标、排查漂移。整个过程看起来琐碎,但每部都会有惊喜。记得有一次在楼群环绕的停车场,RTK固定解只剩不到10%,我一度怀疑模块坏了,后来发现是基准站在楼顶被一个塔吊结构挡住了天空。
个人体会最深的一次是,把RTK融入闭环之后,发现车辆在路口的停靠精度从半米直接提升到十几厘米,那种“肉眼可见”的变化让我觉得前面所有折腾都值得。如果你刚开始接触RTK和UTM,建议不要一上来就追求高大全,先搭一个最简单的静态基准站加移动站,在露天场地把固定解搞到90%以上,再考虑动态融合。
下次我再展开讲讲怎么把RTK和IMU做松耦合融合,以及如何处理一段时间内RTK信号丢失时定位连续性不崩的方法。这个系列我会持续更新,希望这篇能帮你少走一点弯路的弯头。