GNSS 双路径与系统时间:u-blox 与 Quectel 的选择与边界

作者:

在

结论:GNSS 在这套系统里是二选一的双路径:存在指定串口设备节点且未设置强制 Quectel 开关时选 u-blox,由 pigeond 与 ubloxd 同时运行,其余情况选 qcomgpsd;两条路径输出的定位主题名不同——u-blox 走 gpsLocationExternal,Quectel 走 gpsLocation,系统时间进程按参数选其中一条,不能只改名字就视为等价。时间校正本身条件严格:所选主题刚更新、logMonoTime 距当前不超过两秒、hasFix=True 且 GPS 时间在允许范围内才调用设置时间,且差值小于十秒不改。本文为固定源码快照 c8fb906 的静态阅读,未连接 u-blox、Quectel、天线或实板。

平台门与消息契约

平台选择由设备节点与持久化参数共同决定:存在指定串口设备节点且未设置强制 Quectel 开关时选 u-blox,此时 pigeond 和 ubloxd 同时运行,ublox() 还更新 UbloxAvailable 参数;其他情况下选 qcomgpsd。三者均受硬件与行车条件限制,设备节点判断不是芯片健康检测。需要注意的是,管理器会按当前设备节点重评 GNSS 生产者,但系统时间进程常驻且只在启动时选订阅主题,因此驻车与行车切换、运行中设备切换并不等价。

边界 已核对行为
平台门 串口设备节点存在且未设强制 Quectel 开关时选 u-blox,否则选 qcomgpsd
u-blox 定位主题 输出 gpsLocationExternal
Quectel 定位主题 输出 gpsLocation
原始/卫星主题 ubloxRaw 是串口字节包;ubloxGnss 与 qcomGnss 承载测量、星历、卫星状态与诊断
订阅选择 系统时间进程按 UbloxAvailable 选一条,且只在初始化时决定

ubloxRaw 是串口字节包,ubloxGnss 与 qcomGnss 承载测量、星历、卫星状态与诊断等结构,它们都不是 GpsLocationData 的替代品。两条服务的频率与字段来源不同,接入时不能假定可互换。

对比项 u-blox 路径 Quectel 路径
运行进程 pigeond 与 ubloxd 同时运行 qcomgpsd
物理链路 电源、复位、安全启动引脚与串口设备节点 AT 端口与 DIAG 串口,共享互斥锁文件
帧格式与校验 UBX 前导 B5 62、长度与 Fletcher 校验 HDLC 解转义与 CRC16-X25
定位主题 gpsLocationExternal gpsLocation
时间来源 NAV-PVT 的 UTC,异常时置零 固定 18 秒 GPS-UTC 差,留有闰秒待办

u-blox:供电、串口、UBX 与辅助定位

set_power() 与串口封装类管理电源使能、复位、安全启动引脚与串口设备节点。初始化先做电源循环,再由 init_baudrate() 把默认 9600 波特率切到 460800;init_pigeon() 用带 ACK 的配置报文设置输出频率、消息种类与导航参数,最多尝试十轮。run_receiving() 把串口块发布为 ubloxRaw,首字节为 0x00 时尝试重新初始化;后台线程等待有效系统时间与网络后,从 u-blox 服务或代理下载辅助数据并送设备,接收过程中每五分钟尝试保存星历备份。

UbxFramer.add_data() 从跨块字节流寻找 UBX 前导 B5 62、长度与 Fletcher 校验,坏帧丢首字节后重找;解析器parse_frame() 只处理 NAV-PVT、RXM-SFRBX、RXM-RAWX、NAV-SAT、MON-HW/HW2 等已列类型,其余返回空。NAV-PVT 映射把经纬度、海拔、速度、NED 速度和精度换算到 gpsLocationExternal,根据 flags 置 hasFix,UTC 日期异常时 Unix 时间置零。

有两个容易误判的静态边界:其一,init() 调用 init_pigeon() 却不检查其布尔返回,十轮失败后仍进入接收循环,因此应显式上报电源、UART、ACK、首定位与持续断流状态;其二,主循环记录上游包时间,却并未把它写回发布消息的 logMonoTime——后者由消息构造在解析时生成,所以日志时间不能代表卫星测量时刻,硬件替换时必须单独保留采样时刻与处理延迟。

Quectel:AT 与 DIAG 路径

wait_for_modem() 等 AT 端口及 GNSS 子系统应答;at_cmd() 在一个共享内存互斥锁文件上加锁,与蜂窝管理进程共享 AT 端口——这个锁是接口所有权边界,新板卡驱动不能绕过它并发发 AT 指令。setup_quectel() 通过 DIAG/NV 开启 OEMDRE 日志、关闭 GNSS 省电模式、设置 NMEA 输出与时间并启动 GNSS,cleanup() 在信号退出时关闭 GNSS 与日志并拉低电源引脚。

ModemDiag.hdlc_decapsulate() 对 DIAG 串口数据解转义并校验 CRC16-X25;主循环再按内外长度、日志类型和版本解析 OEMDRE、GPS 与 GLONASS 测量及位置,位置报告要求位置来源字段等于 2 且 GPS 周不是无效哨兵,海拔精度等于 500 时置 hasFix=False。位置映射把 ENU 速度转换到 NED 输出 gpsLocation,源码按固定 18 秒 GPS-UTC 差计算 Unix 时间,并留有闰秒更新待办;若把该路径作为设备时间源,必须验证当前闰秒、模组固件与真实 UTC 的一致性。

系统时间与硬件契约

系统时间进程发布 clocks,仅在所选 GPS 主题刚更新、logMonoTime 距当前不超过两秒、hasFix=True 且 GPS 时间在允许范围内时调用设置时间,差值小于十秒不改系统时间;该流程只处理系统 UTC,不保证相机帧起始、IMU 中断、DIAG 日志时间与卫星测量已经共时钟。面向硬件与插件化的最低契约是:每条 GNSS 提供方须声明物理链路、供电与复位、安全关机、协议及校验、观测时钟域、UTC 与闰秒来源、定位有效位与精度、首次定位及断流超时;gpsLocationExternal 与 gpsLocation 只能通过受控适配器切换,不能让任意插件覆盖系统时间或伪造定位有效位。

常见问题

系统怎么决定用 u-blox 还是 Quectel?

由设备节点与持久化参数共同决定:存在指定串口设备节点且未设置强制 Quectel 开关时选 u-blox,由 pigeond 与 ubloxd 同时运行并更新 UbloxAvailable;其他情况选 qcomgpsd。设备节点判断只是平台门,不是芯片健康检测。

gpsLocationExternal 和 gpsLocation 可以互换吗?

不能只改名互换。前者由 u-blox 的 NAV-PVT 映射产出,后者由 Quectel 的 DIAG 位置映射产出,两条服务频率与字段来源不同;系统时间进程按 UbloxAvailable 选其中一条,且只在初始化时决定,平台切换后要检查服务重启与参数同步。

日志里的时间等于卫星测量时刻吗?

不一定。u-blox 主循环并未把上游包时间写回发布消息的 logMonoTime,该字段由消息构造在解析时生成,因此日志时间不能代表卫星测量时刻,硬件替换时必须单独保留采样时刻与处理延迟。

为什么 hasFix=False 会出现?

两条路径都有置假条件:u-blox 根据 NAV-PVT 的 flags 置 hasFix 并在 UTC 日期异常时把 Unix 时间置零;Quectel 要求位置来源字段等于 2 且 GPS 周有效,海拔精度等于 500 时置 hasFix=False。因此有效位要连同来源与时间一起解读。

延伸阅读

参考资料

  • 项目 02 —— openpilot-research/GNSS_TIME_DEEP_DIVE.md(取用了平台门、两条定位主题、u-blox 与 Quectel 解析链、系统时间条件与硬件契约)。
  • 项目 02 —— openpilot-research/GNSS_BACKEND_SELECTION_SUBSCRIPTION_LIFECYCLE_DEEP_DIVE.md(仅用于确认订阅选择生命周期与运行中切换的边界)。

说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。

更新记录

首次发布 2026-10-11 最近核对:2026-10-11

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注