ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

室外无人车导航核心:RTK配置与经纬度转UTM坐标转换实战

室外无人车导航核心:RTK配置与经纬度转UTM坐标转换实战 还记得第一次把自研无人车拉到矿区测试那天车辆在规划好的直线路径上跑图传画面里的轨迹却像喝多了酒一样左右扭。排查了一晚上最后定位到源头GPS单点定位2到3米的误差落到控制环里就是半条车道的摇摆。从那以后我彻底意识到室外导航和室内导航完全是两码事——室内有激光雷达照着墙走就行室外几十米的误差自动驾驶系统连我在哪这个最基本的问题都答不了。这篇文章是无人驾驶系列第二篇专门讲室外导航里最核心的一环RTK配置与接入以及GPS经纬度和UTM平面坐标的转换。我会把整个链路掰开讲——从RTK硬件怎么选、怎么接线到串口协议怎么配、数据怎么解析再到经纬度转UTM的数学原理和代码实现最后是工程现场最容易踩的坑。内容偏向实操适合正在搞无人车、机器人室外导航、工程机械自动驾驶的朋友参考也适合想搞懂RTK到底是怎么把误差压到厘米级的初学者。1. 室外导航为什么离不开RTK误差真相与差分原理1.1 普通GPS的误差到底有多大手机导航大家天天用觉得GPS挺准的那是因为手机里还揉合了基站、Wi-Fi、惯性传感器等多重定位纯GPS单点定位远没有你想象中靠谱。普通GPS接收机通过伪距测量计算位置水平精度通常在2到10米之间这个误差来自几个方面卫星星历误差卫星广播的轨道参数和真实轨道有偏差大约1到3米量级。卫星钟差卫星原子钟和接收机时钟不同步带来等效距离误差。电离层延迟信号穿过电离层时传播速度变化白天强、夜间弱能造成几米的误差。对流层延迟大气中水汽和温度梯度导致信号弯曲误差也有1米左右。多径效应高楼、山体反射信号接收机收到反射路径的伪距产生大误差。最头疼的是多径效应尤其在矿区、港口、工地这种有大面积金属结构和混凝土地面的地方信号弹来弹去误差忽大忽小。你可以想象一下一辆无人车宽不到2米如果在窄路上靠边通行GPS给出2到3米的偏差车辆可能直接怼到墙上或者溜到沟里。所以无人驾驶的室外导航绝对不能直接用单点GPS作为位置依据。对工程机械无人驾驶来说这个矛盾更明显。矿山卡车、压路机、挖掘机车身巨大、作业路径相对固定但安全余量很小靠普通GPS做路径跟踪轨迹偏差大得离谱根本没法用。这也是为什么行业内提到室外导航定位第一反应就是上RTK。1.2 RTK是怎么把误差压到厘米级的RTK全称是实时动态差分定位Real-Time Kinematic核心思路很朴素误差在空间和时间上是相关的。如果我在一个坐标精确已知的点架一台接收机基准站它测出来的坐标和真实坐标之间的偏差就是当前时刻、当前区域的综合误差。把这个偏差通过电台或者网络实时发送给移动站移动站用同样的偏差修正自己的测量结果精度立刻大幅提升。RTK和普通DGPS的区别在于DGPS用伪距差分精度到亚米级RTK直接用载波相位观测值做差分L1载波的波长大约是19厘米相位观测精度能到波长的1%甚至更高所以理论精度能达到厘米级。但这里有一个关键门槛——整周模糊度求解。载波相位测量只能测到不足一个周期的小数部分整周数是个未知数RTK算法需要借助双差观测方程和最小二乘搜索把这个整周数解算出来。模糊度固定成整数了就是固定解Fix精度1到3厘米如果算法一直解不出来只能输出浮点解Float精度掉到20到50厘米左右。这就是为什么工程上判断RTK好不好用先看固定率和固定状态。RTK正常工作必须满足三个条件基准站坐标精确已知或者接入连续运行参考站CORS服务。基准站和移动站之间的差分数据链路通畅。常见的有电台433MHz/900MHz、4G网络走NTRIP协议、或者卫星链路。移动站天线处能同时收到足够数量的卫星通常要双频、多星座至少10颗以上并且没有严重的多径干扰。我之前在矿区做测试时基准站架在山坡上移动站车辆在坑底作业电台信号被地形挡住RTK直接失锁变成单点定位。后来解决方案是改用4G-NTRIP接入网络CORS配合双频多星座接收机情况才稳定下来。这个经验在后面常见问题章节还会细讲。2. RTK硬件接入与数据配置完整流程2.1 设备选型与接线注意事项市面上的RTK方案大致分两派。一派是测绘级成品如华测、中海达、千寻定位模块等出厂带基准站和移动站精度稳定、防水防尘适合工程现场直接用缺点就是贵。另一派是低成本开源性方案典型代表是u-blox F9P系列板卡本身支持双频RTK配合树莓派或工控机再买个支持RTCM输出的模块和天线一套低成本RTK移动站就出来了。如果只是学习验证F9P这套路线性价比非常高。从接入方式来看不管是成品RTK还是自己做的板卡和无人车计算平台的连接基本都走串口UART或RS232少数支持USB和网口。接线时要注意几个细节电平匹配大部分RTK板卡是3.3V TTL电平工控机串口如果是RS232电平中间必须加电平转换芯片直接连很容易烧板子。供电有的板卡可以直接从串口取电有的需要外部5V供电天线如果是有源天线还需要单独给天线馈电这个细节很多新手会忽略导致天线信号极差。天线位置这是整个定位链路里最容易被低估的地方。定位天线要装在车顶正中央或最高点周围留有足够的地平面前后左右尽量对称。天线旁边不要放金属支架、天线杆、大功率设备底盘走线也要避开电机和逆变器否则电磁干扰会把载波相位搞坏。顺带提一个热词里反复出现的GPS陶瓷片设计注意事项。如果你自己设计天线或者选型贴片陶瓷天线记住几个核心点陶瓷片的物理尺寸要和频率匹配GPS L1频段1575.42MHz对应的波长约19厘米常规选18x18mm或25x25mm的陶瓷贴片陶瓷片下方要有一块足够大的参考地地太小效率会明显下降馈电点位置、匹配电路的电感电容参数直接影响带内回波损耗最好用网络分析仪实测最后就是有源天线的LNA增益不要一味求高太高了会把带外噪声一起放大反而恶化信噪比。2.2 串口参数与NMEA数据协议解析硬件接好之后第一步是确认串口通没通。Linux环境下我一般先用dmesg | grep ttyUSB查看设备节点然后用stty配好波特率再直接cat看数据流stty -F /dev/ttyUSB0 115200 raw -echo cat /dev/ttyUSB0RTK接收机默认输出一般是NMEA 0183协议这是一套纯文本协议每一行以$开头以回车换行结束。常用语句有$GPGGA核心定位数据包含UTC时间、经纬度、定位质量指示、卫星数、海拔等信息。$GPRMC推荐最小定位数据包含经纬度、速度、航向、日期。$GPGSV可见卫星信息。$GPHDT航向角部分接收机支持。工程上解析最常用的就是GGA里面有一个字段专门表示定位状态判断RTK到底有没有固定定位质量字段含义是否可用于无人驾驶0无效定位不可用1单点定位普通GPS一般不直接用2DGPS/差分定位备用4RTK固定解Fix可用精度厘米级5RTK浮点解Float慎用精度几十厘米我写解析代码时会先把GGA整行按逗号切分定位质量字段是索引6从0开始卫星数是索引7HDOP是索引8。除了GGA我通常还会打开GST语句它包含位置误差的标准差能帮助系统判断当前定位质量是否满足路径跟踪要求。有些接收机还支持输出RTCM裸数据这是差分数据协议通常用于基站发送给移动站或者自己研发系统时把RTK输出重新转发给其他模块。RTCM是二进制协议解析起来比NMEA复杂但如果你用现成库比如rtklib或GPSD就没必要自己抠比特流了。2.3 把RTK数据接入无人驾驶系统接入方式取决于你的系统架构。如果你在用ROS方案很成熟nmea_navsat_driver包可以把NMEA语句解析成sensor_msgs/NavSatFix消息发布到/fix话题然后直接供导航、定位模块订阅。NavSatFix里的latitude、longitude是WGS84经纬度position_covariance可以用GST或RTK解算器给出的误差填进去让下游模块知道当前定位置信度。如果你不是ROS而是自研的C或Python定位模块建议这么设计数据流串口线程负责读串口原始数据按行拆包做校验和验证。协议解析线程从GGA/RMC里提取经纬度、UTC时间、定位质量、速度、航向。坐标转换模块把经纬度转成UTM平面坐标给控制模块用。时间同步模块把GPS时间换算成系统时间或对齐PPS秒脉冲供多传感器融合使用。这里有个原则解析层只做数据提取不掺业务逻辑坐标转换要单独封装成一个纯函数库方便在离线回放和在线运行中共用。我见过太多项目把坐标转换逻辑写在控制代码里最后要换个投影坐标系改到怀疑人生。还有一个容易被忽略的坑串口数据解析一定要做校验和验证。NMEA的校验和是$和*之间的字符异或很多新手直接按逗号切完就用了一旦数据帧被电磁干扰破坏解析出错误坐标无人车可能猛打方向。轻则吓一跳重则出事故。3. GPS经纬度到UTM平面坐标的精确转换3.1 为什么不能直接用经纬度做路径规划GPS原始输出是WGS84椭球下的经纬度这是一个球面坐标。你可以用它来表示地球上在哪但没法直接拿来做路径规划和横向控制。原因很简单经纬度不是等距的赤道上经度1度大约是111公里纬度60度处经度1度只有55公里左右。无人车控制算法需要的是以米为单位的平面坐标直接用经纬度会引入严重非线性。球面距离计算复杂虽然可以用Haversine公式算两点距离但路径规划、PID控制、轨迹插值这些运算如果每次都在球面上做代码又绕又慢。和传感器坐标难以统一激光雷达、相机、IMU输出的都是直角坐标定位模块如果把GPS经纬度直接丢给融合模块坐标系统一是个大麻烦。所以工程上通常把GPS经纬度投影到平面坐标系UTM就是最主流的选择。3.2 UTM投影参数与选带方法UTMUniversal Transverse Mercator通用横轴墨卡托投影把地球从西经180度开始按经度每隔6度划分一个投影带全球共60个带编号从1到60。每个带内以一条中央经线为基准采用横轴墨卡托投影这样整个带内的经纬度(lon, lat)可以被映射成平面坐标(x, y)单位是米且带内距离变形很小可以作为局部导航坐标系使用。在中国区域经度范围大约从东经72度跨越到东经138度对应的UTM带号是43到53。计算带号的公式很简单zone floor((lon 180) / 6) 1比如北京经度约116.4度floor((116.4 180) / 6) 1 floor(49.4) 1 50也就是50带中央经线是6 * 50 - 183 117度东经。UTM投影的关键参数如下椭球体WGS84长半轴6378137米扁率1/298.257223563。中央经线比例因子k00.9996这是为了让带内最大变形摊薄到边缘。东偏移量500000米保证带内所有东向坐标为正。北偏移量北半球为0南半球为10000000米。具体转换公式很复杂里面有大量三角级数展开项我不建议你自己手写直接用成熟的库即可。但理解思路对排查问题很有帮助——UTM本质上是先把经纬度转为球心直角坐标ECEF再投影到横轴墨卡托平面上中间还涉及子午圈曲率半径、卯酉圈曲率半径这些几何量。如果有一天你发现转出来的坐标在跨带处有明显跳变先想想是不是选错带号了。3.3 用pyproj完成坐标转换代码与注意事项Python环境下我最常用的库是pyproj它是PROJ坐标转换库的Python封装。安装很简单pip install pyproj基本用法如下from pyproj import Transformer # 从WGS84经纬度转到UTM 50N坐标 transformer Transformer.from_crs(EPSG:4326, EPSG:32650, always_xyTrue) lon 116.4 # 经度东经为正 lat 39.9 # 纬度 x, y transformer.transform(lon, lat) print(fUTM东向坐标: {x:.3f} m) print(fUTM北向坐标: {y:.3f} m)代码就这么多。但有几个细节必须注意always_xyTrue表示输入输出顺序都是(lon, lat)也就是先经度后纬度。很多新手默认参数输错顺序结果坐标跑到非洲去了。EPSG代码含义326xx系列是北半球UTM327xx系列是南半球xx是带号。比如50带北半球就是3265051带就是32651。生成带号时可以直接32600 zone。如果你不想每次算带号也可以动态构造带号import math from pyproj import Transformer def lonlat_to_utm(lon, lat): zone math.floor((lon 180) / 6) 1 crs_code fEPSG:326{zone:02d} if lat 0 else fEPSG:327{zone:02d} transformer Transformer.from_crs(EPSG:4326, crs_code, always_xyTrue) x, y transformer.transform(lon, lat) return zone, x, yC环境下同样可以用PROJ库接口风格类似#include proj.h PJ_CONTEXT *ctx proj_context_create(); PJ *transform proj_create_crs_to_crs(ctx, EPSG:4326, EPSG:32650, nullptr); PJ_COORD input proj_coord(lon_deg, lat_deg, 0, 0); PJ_COORD output proj_trans(transform, PJ_FWD, input); double x output.xy.x; double y output.xy.y; proj_destroy(transform); proj_context_destroy(ctx);需要提醒的是UTM坐标是局部平坦的但在跨带区域——比如车辆从50带往东驶入51带——坐标会突然跳变几百万米。对路径规划来说这是不可接受的。实际工程中我推荐两种方案一是在项目启动时把整个测试区域统一投影到某个固定带整个地图都基于这个带跨带区域用相邻带坐标做转换衔接二是以车辆起点作为本地坐标系原点先转UTM再减去起点的UTM坐标得到相对于起点的平面坐标东北坐标系控制模块只认这个相对坐标。第二种方案在无人驾驶中非常常用因为它天然和IMU、轮速里程计的姿态估计对齐起点附近误差最小。坐标转换还有一个隐藏细节UTM带内距离变形在外侧经线处最大比例因子约1.001也就是1公里会有1米误差。如果测试场地恰好跨带或者在带的边缘低精度场景可以忽略但高精度RTK融合导航时最好坐标准换到自定义的高斯投影或使用局域切平面坐标系。这里不展开但你要知道UTM不是万能的理解它的适用范围比死记转换代码更重要。4. 工程落地中的定位问题排查与防护建议4.1 RTK固定率低和坐标跳变的排查套路RTK接上之后最常见的问题就是固定率上不去或者明明显示固定解坐标还是跳。我在不同场景下踩过不少坑整理出一套排查思路先看卫星数和信噪比。GGA里的卫星数太低比如少于10颗多半是天线被遮挡或天线本身质量差。在车辆上货斗、驾驶室铁皮、货架都会遮挡信号天线的安装位置要尽量高、尽量开阔。再看DBHZ信噪比——通过GSV语句能看到每颗卫星的信噪比正常在35dBHz以上如果多颗卫星低于30dBHz说明天线的接收环境很差需要调整位置或换增益更高的有源天线。再看基准站和移动站的通信链路是否稳定。电台方式要检查基站发射功率、天线架设高度、移动站电台信号强度网络方式要检查4G信号和延迟NTRIP挂掉的时候移动站会立刻退化成单点定位。如果固定率时好时坏大概率是数据链路丢包或者延迟过大。还有一种非常坑的情况基准站坐标本身不准。当你自己架设基准站时如果基准站坐标是通过单点定位获取的误差有数米移动站即使显示固定解绝对坐标也是偏离的。这时需要用已知控制点或连续观测一段时间取平均值把基准站坐标校准到厘米级。很多团队忽略了这一步结果固定率100%但车辆实际位置偏了几米跟地图对不上。坐标跳变还有一个常见来源——天线相位中心偏差。RTK天线不是理想的几何点卫星信号进入天线的等效中心位置和天线的机械中心有偏差不同仰角的卫星、不同方向来波相位中心还会漂移。高质量天线会在出厂时做相位中心标定低价天线基本没有。信号好时这个偏差只有几毫米但在多径环境下可能放大到分米级表现为固定解下的厘米级抖动变成跳变。所以真要在无人车上用RTK天线别买太便宜的至少用测绘级或者车规级的双频天线。4.2 时间同步GPS数据与激光、视觉的融合基础多传感器融合时RTK坐标和激光雷达点云必须对应到同一个时刻。GPS接收机输出的NMEA里有UTC时间但经过串口传输和解析之后数据到达控制模块的时刻和传感器采集时刻已经不一致了。如果车辆开得慢比如工程机械10km/h以下几毫秒的延迟可以忽略但要跑高速或者急转弯时间不同步会导致定位结果滞后又超调融合出来的轨迹是扭曲的。正规做法是使用PPS秒脉冲信号。大多数RTK接收机会在整秒时刻输出一个高电平脉冲脉冲上升沿对应的就是GPS整秒时刻同时串口输出的GGA里带有这个整秒对应的UTC时间。系统侧可以把PPS信号接在GPIO上捕获上升沿时刻再用串口时间戳做软对齐这样能把时间误差压到亚毫秒级。简单一点的方案是在收到GGA的时间字段时立即给数据打上系统单调时钟的水印和IMU、里程计数据按最近邻查找对齐。还有一个常被忽略的点GPS时间系统和UTC时间之间有整数闰秒差。当前GPS时间比UTC快18秒如果系统里混用GPS周秒和UTC时间在融合时会引入固定偏差。RTK解算出的高程、坐标一般基于GPS时间基准而激光雷达、相机的时间戳一般用系统UTC时间。要么统一转GPS时间要么统一转UTC千万别混着用。4.3 信号欺骗干扰下的失效保护思路热词里提到的GPS生成式欺骗失效保护确实是个现实问题。生成式欺骗不比压制式干扰它不是简单地把GPS信号淹没而是生成一套伪造的GPS信号让接收机以为自己在某个虚假位置且定位质量可能还显示固定解。对无人驾驶来说这比信号丢失更危险——信号丢失至少能触发告警被欺骗时系统根本不知道自己在哪儿。实际防护不能只靠GPS接收机自身。行业里常用的策略是多源异构冗余不把RTK当作唯一的位置来源而是结合IMU、轮速里程计、激光雷达匹配定位比如LIO-SAM、FAST-LIO或者点云匹配里程计随时进行位置一致性校验。当RTK给出的位置和惯性递推/激光匹配结果出现持续偏差时系统判定RTK可疑降低它的权重甚至直接剔除。接收机层面也可以做一些检测多星座多频接收机更容易发现欺骗因为欺骗设备很难同时伪造GPS、北斗、Galileo多个系统的信号特征还可以监视载噪比一致性——真实信号的载噪比随仰角变化平滑欺骗信号往往有异常的高载噪比和突变特征。另外GBAS/SBAS和RTK解算本身的残差检验也可以辅助判断定位是否可信。我自己项目中用过一套简单有效的策略把RTK坐标和IMU/轮速推算的位置做差超过阈值就触发定位异常状态车辆进入安全停车流程。这个阈值根据场景调节园区低速物流车设1米矿山宽体车设2米宁可频繁告警也不要带病行驶。这个思路比任何高级检测都实用因为它不依赖特定接收机型号。4.4 从RTK到融合定位几点实战经验RTK只是外部定位的一种无人车的定位系统最终一定是一套多传感器融合结构。我的经验是把RTK当作低频率高精度修正源IMU和轮速计当作高频递推源激光/视觉里程计提供相对运动的另一路约束。典型的松耦合融合可以用扩展卡尔曼滤波或因子图优化RTK输出频率一般是10到20HzIMU是100到400Hz融合后的定位输出通常能做到50到100Hz且RTK短时间丢失时系统还可以靠IMU里程计维持几秒钟的可用定位。在融合中RTK还有一个重要参数是协方差。很多团队把RTK固定解的协方差设成固定值忽略了不同卫星几何、不同环境下的精度差异。建议用GST语句输出的位置误差标准差或者RTK解算器给出的精度指标动态填充协方差这样融合模块才能正确地信任或忽略RTK。信号差但偶尔固定时固定解的协方差也应该适当放大否则融合结果容易跳。另外初始化阶段一定要先等RTK进入固定解再让车辆运动。有些系统为了省时间单点定位也放行结果车辆跑出几十米地图和真实位置已经错开一大截再想拉回来很难。稳妥做法是定位系统就绪之前车辆不允许进入自主模式这是我在现场安全规程里写死的一条。5. 几个我后来踩过才明白的坑补充几个在RTK接入和坐标转换之后才会遇到的细节问题都是真实测试里碰到的。第一GPS数据里的海拔是椭球高不是海拔高。WGS84坐标系下输出的高程是相对于参考椭球面的高度而工程现场用的往往是基于似大地水准面的正常高两者在部分地区能差几十米。无人车如果只是平路导航影响不大但要做坡道控制或者用高程辅助判断地形必须做高程异常修正否则坡度和实际完全对不上。第二经纬度精度的小数位不能拍脑袋截断。GGA里的纬度格式是ddmm.mmmmmm也就是度分格式经度是dddmm.mmmmmm。很多新手把度分当成度直接用一算差了60倍。正确的做法是把分除以60加到度上得到十进制度再送进坐标转换函数。这个低级错误我见过不止一次排查时极度浪费时间。第三RTK坐标原点和UTM带号必须在系统配置里固化。车辆每次启动时如果都按当前经纬度现算带号车辆行驶到带号边界附近时坐标基准会来回切换控制模块的轨迹和地图全部乱套。正确的做法是项目立项阶段固定一个带号程序里写死地图和车辆定位统一下来。如果跨带测试再加一个带间转换接口而不是动态选带。第四GPS和RTK设备在车辆上的供电要单独处理。车辆发动时电池电压波动很大直接给RTK接收机供电很容易让它在关键瞬间重启定位状态全部丢失。我给RTK配了独立的稳压模块和超级电容保证发动机启动、大功率设备启停时供电不中断这个投入比换一台高端接收机更划算。这套链路——RTK硬件接入、NMEA解析、经纬度转UTM、多传感器融合——我现在几乎每个室外导航项目都会复用。如果你也正在被GPS误差和坐标转换折磨按照上面的步骤走一遍八成能少走很多弯路。等你这套定位系统稳定了后面再聊路径跟踪和控制就会顺很多。
返回列表