整理 Qualcomm QDR(Dead Reckoning / 惯导)在 SA525M 类平台上的逻辑。需要先说清一点:
高通 QDR 融合算法本体在 Modem/定位引擎(MPSS,闭源 PE)里运行;AP 侧开源代码(含SlimSensorHalDaemonProvider.cpp)主要负责采集、对齐时间、注入传感器/车况、再把 DR 结果上报给应用。imu_sensor_api是另一条独立 IMU 通路,不参与 QDR。
一、总体架构(三层)
┌─────────────────────────────────────────────────────────────┐ │ Modem:QDR/PE 算法(闭源) │ │ 输入:GNSS 伪距/星历 + 注入的 IMU + 车速/里程/方向盘等 │ │ 输出:DR 位置 / DR SV / DR NMEA │ └───────────────▲──────────────────────────────▲──────────────┘ │ QMI Loc Inject │ Slim Remote IPC │ (传感器/运动/时间) │ (车速/里程等) ┌───────────────┴──────────────────────────────┴──────────────┐ │ AP:SLIM + Loc HAL + VNW(CAN) │ │ SensorHalDaemonProvider / VehicleNetworkProvider / … │ └───────────────▲─────────────────────────────────────────────┘ │ 物理层 IMU(SMI230) / CAN车速 / GNSS射频(在 Modem)二、输入数据类型(QDR 用哪些量)
| 类别 | 具体内容 | AP 侧主要来源 | 注入 Modem 方式 |
|---|---|---|---|
| 6DOF IMU | 加速度计、陀螺仪(常含未校准) | SensorHalDaemonProvider→ sensor-service | QMI_LOC_INJECT_SENSOR_DATA |
| IMU 温度 | Accel/Gyro 温度 | 同上 | 同上 |
| 磁力计(可选) | 校准/未校准磁场 | 同上 | 同上 |
| 车速 | speed(m/s) | CAN(VehicleNetwork) 或 Android Vehicle HAL(VNS) | Slim Remote → Modem |
| 轮速差分 DWS | 四轮差速 | CAN 配置解析 | Slim Remote |
| 档位 | Gear | CAN | Slim Remote |
| 方向盘角 | Steering wheel (deg) | CAN | Slim Remote |
| 里程计 Odometry | 累计行驶距离 (mm) | CAN 轮速积分 | Slim Remote |
| 运动状态 | 静止/运动概率等 | SLIM Motion 服务 | QMI_LOC_INJECT_MOTION_DATA |
| 计步(部分方案) | 步数/步频 | SLIM Pedometer | QMI_LOC_PEDOMETER_REPORT |
| 时间同步 | AP–Sensor 时间对齐 | SLIM Time Sync | QMI_LOC_INJECT_TIME_SYNC_DATA |
| GNSS | 伪距、星历、时间 | Modem 内部 GNSS,不经 AP 注入 | 引擎内部 |
| 初始位置/航向 | 首次 GNSS fix 等 | Modem 内部 / 配置 | 引擎内部 |
诊断里与输入相关的状态位(说明引擎期望什么)见LocationClientApiDiag.h:VEHICLE_SENSOR_SPEED_INPUT_*、ERROR_6DOF_SENSOR_UNAVAILABLE、ERROR_VEHICLE_SPEED_UNAVAILABLE、ERROR_GNSS_*等。
三、AP 侧:从“Modem 要数据”到“注入完成”(函数链)
A. Modem 发起传感器需求(QDR 会话启动后)
| 步骤 | 函数 | 作用 |
|---|---|---|
| 1 | LBSApiV02::eventCb() | 收到QMI_LOC_EVENT_SENSOR_STREAMING_READY_STATUS_IND_V02 |
| 2 | LBSApiV02::doSensorDataRequest() | 解析 Modem 要求的samplesPerBatch/batchesPerSecond |
| 3 | LBSApiBase::requestSensorData() | 转给 SLIM 适配层 |
| 4 | QLClientListener::requestSensorData() | 填slimEnableSensorDataRequestStructT(含reportRate、sampleCount) |
| 5 | ClientListener::processSensorDataRequest() | |
| 6 | slim_InternalEnableSensorData() | 进入 SLIM 核心 |
B. SLIM 打开 IMU 并按 QDR 频率采样
| 步骤 | 函数 | 作用 |
|---|---|---|
| 7 | MultiplexingProvider::enableSensorDataRequest() | 多客户端取最高reportRate × sampleCount |
| 8 | SensorHalDaemonProvider::doUpdateSensorStatus() | getNearestODR()→sensor_config()→sensor_control(ENABLE) |
| 9 | SensorClient::sensor_config()→sensor_hal_daemon::startBatching() | 配 HAL/驱动 ODR(SMI230 上多为100 Hz) |
| 10 | SensorHalDaemonProvider::eventCallback() | 收到 accel/gyro 事件 |
| 11 | MultiplexingProvider::isBatchReady() | QDR 用 count-based batch 组批 |
| 12 | MultiplexingProvider::routeIndication() | 送给 SLIM 客户端 |
C. IMU 注入 Modem(QMI)
| 步骤 | 函数 | 作用 |
|---|---|---|
| 13 | QLClientListener::handleSensorData() | SensorDataBundle:x/y/z + 时间戳 |
| 14 | QLClientListener::injectSensorData() | |
| 15 | LBSApiV02::injectSensorData() | 组qmiLocInjectSensorDataReqMsgT_v02(accel/gyro/mag/temp) |
| 16 | QMILOC_SEND_SYNC_REQ(InjectSensorData, …) | 送入 Modem QDR 引擎 |
同类注入还有:
QLClientListener::handleMotionData()→injectMotionData()→LBSApiV02::injectMotionData()QLClientListener::handlePedometerData()→injectPedometerData()→LBSApiV02::injectPedometerData()- 时间:
QLClientListener::injectTimeData()→LBSApiV02::injectTimeData()
四、车速 / 里程 / 方向盘(车况输入,函数链)
Modem 侧SlimRemoteProvider向 AP 要车况;AP 从 CAN 解析后再回传 Modem(不是走QLClientListener::injectSensorData)。
A. Modem 请求开启车速等服务
| 步骤 | 函数 | 作用 |
|---|---|---|
| 1 | remoteProv::doUpdateVehicleDataStatus() | Modem 侧发 enable(SPEED/DWS/GEAR/STEERING_WHEEL/ODOMETRY) |
| 2 | IPC→SlimIntClientIpcListener::onReceive() | eSLIM_CONTROL_MESSAGE_ID_VEHICLE_DATA_REQ |
| 3 | SlimIntClient::handleVehicleMotionRequest() | |
| 4 | slim_InternalEnableVehicleData() |
B. AP 采集 CAN 车速(示例)
| 步骤 | 函数 | 作用 |
|---|---|---|
| 5 | VehicleNetworkProvider::doUpdateVehicleDataStatus() | 打开对应 CAN 解析 |
| 6 | VehicleNetworkCONF1SpeedMP::OnNewCanFrameEvent() | 从 CAN 帧解 speed (m/s) |
| 7 | 填slimVehicleMotionDataStructT(sensorType = SPEED) | |
| 8 | VehicleNetworkProvider::routeIndication(eSLIM_SERVICE_VEHICLE_SPEED, …) |
其它车况:
- Odometry:
VehicleNetworkMessageProcessor里程相关 MP →eSLIM_SERVICE_VEHICLE_ODOMETRY - DWS / Gear / Steering:同类
VehicleNetwork*MP::OnNewCanFrameEvent() - Android 车机:
VNSListener订阅PERF_VEHICLE_SPEED→VNSProvider::routeIndication()
C. 回传 Modem
| 步骤 | 函数 | 作用 |
|---|---|---|
| 9 | SlimIntClient收到eSLIM_MESSAGE_ID_VEHICLE_*_IND | |
| 10 | SlimIntClient::slimIntClientVehicleMotionDataSendMsg() | Protobuf/IPC 发到 Modem |
| 11 | Modem 侧解码后送入QDR PE(闭源,QMI_LOC_INJECT_VEHICLE_SENSOR_DATA一类) |
QLClientListener/ClientListener::handleVehicleOdometryData()在 AP 上对 QMI 是“忽略”的;车况是Remote SLIM → Modem路径,不是 AP QMI 直注。
五、GNSS 输入(在 Modem 内部,不在 AP 注入链)
| 内容 | 说明 |
|---|---|
| GNSS 测量、星历、时钟 | Modem GNSS 子系统 → 直接进入 PE/QDR |
| 缺星历/无量测 | DR_SOLUTION_STATUS_ERROR_GNSS_EPH_UNAVAILABLE/GNSS_MEAS_UNAVAILABLE |
AP 的SlimSensorHalDaemonProvider不负责把 GNSS 伪距送给 QDR。
六、高通 QDR 算法(Modem 闭源)与输出
开源树里没有QDR 卡尔曼/融合源码(在pdapi/PE 预编译库)。从 API/诊断可推断引擎做:GNSS + IMU(6DOF) + 车速/里程约束的融合,并输出 DR 解。
输出类型 & AP 接收函数链
| 输出 | 流类型 | AP 接收(示例) |
|---|---|---|
| DR 融合位置 | IZAT_STREAM_DR(0x10) | registerLocationUpdater()→LocationClientApi回调 →locationUpdateCallback() |
| DR 卫星信息 | IZAT_STREAM_DR_SVINFO(0x40) | svInfoUpdateCallback() |
| DR NMEA | DR NMEA 掩码 | nmeaUpdateCallback() |
| 诊断状态 | drSolutionStatusMask | 车速是否用到、6DOF 是否可用、标定警告等 |
测试入口:IZatRemoteApiTest.cpp中-D 0x001/0x002/0x004对应 DR 位置 / SV / NMEA。
典型输出字段(izat_remote_api.cpp/GnssLocation):
- 经纬高、速度、航向、精度
techMask:含LOCATION_TECHNOLOGY_SENSORS_BIT时表示传感器/DR 参与- 扩展:DOP、可靠性、
drSolutionStatusMask等
应用层还可通过LocationClientApi/EnginePluginAPI对 QDR 发EP_COMMAND_PAUSE/RESUME/PAUSE_RETAIN(驻车保留状态,见EnginePluginAPI.h注释)。
七、与imu_sensor_api的对比(为何无关 QDR)
| 项目 | QDR(SLIM + Modem) | IMU API |
|---|---|---|
| 目的 | 供 Modem QDR 融合 | 应用直接读 IMU |
| 传感器类型 | Uncalibrated accel/gyro | Calibrated accel/gyro |
| 频率 | Modem 动态reportRate×sampleCount | 写死 104 Hz→100 Hz |
| 下游 | QMI 注入 PE | 仅sensor_hal_daemon回调 |
| 车速 | CAN/VNW → Modem | 无 |
| 输出 | DR 位置/惯导解 | 原始 IMU 回调 |
八、端到端函数
【启动 / 要传感器】 LBSApiV02::eventCb(SENSOR_STREAMING_READY) → LBSApiV02::doSensorDataRequest → QLClientListener::requestSensorData → ClientListener::processSensorDataRequest → slim_InternalEnableSensorData → MultiplexingProvider::enableSensorDataRequest → SensorHalDaemonProvider::doUpdateSensorStatus → SensorClient::sensor_config / sensor_control / sensor_read_events 【IMU 上行】 SensorHalDaemonProvider::eventCallback → MultiplexingProvider::isBatchReady → MultiplexingProvider::routeIndication → QLClientListener::handleSensorData → QLClientListener::injectSensorData → LBSApiV02::injectSensorData → QMI InjectSensorData → [Modem QDR] 【要车速 / CAN】 remoteProv::doUpdateVehicleDataStatus (Modem) → SlimIntClient::handleVehicleMotionRequest → slim_InternalEnableVehicleData → VehicleNetworkProvider::doUpdateVehicleDataStatus → VehicleNetwork*SpeedMP::OnNewCanFrameEvent → VehicleNetworkProvider::routeIndication(VEHICLE_SPEED) → SlimIntClient::slimIntClientVehicleMotionDataSendMsg → [Modem QDR 消费车况] 【GNSS】 [Modem GNSS] → [Modem QDR] (无 AP 函数) 【QDR 算法】 [Modem PE / QDR 闭源融合] 【结果下发】 [Modem] DR fix → LocationClientApi / LocApiV02 位置指示 → izat_remote_api::registerLocationUpdater 回调 → 应用 locationUpdateCallback / SV / NMEA九、结合驱动默认 IMU 100 Hz 的结论
- 驱动默认
SMI230_ACCEL_ODR_100_HZ/ Gyro 100 Hz - QDR 经
getNearestODR()把reportRate×sampleCount对齐到100 Hz档 sensors.conf里 104 Hz 在 SMI230 上也会被折到100 Hz
因此 QDR 路径上 IMU 与IMU API 请求 104 Hz 在硬件上通常都是~100 Hz 采样,差异在是否进入 Modem 融合以及是否有车速/GNSS 等其它输入。
若要继续往下追「 SA525 Modem 默认要的reportRate/sampleCount具体是多少」,可以在设备 log 里搜:
sensorUpdate service/Setting Configuration(doUpdateSensorStatus)SensorID.*InODR.*OutODR(getNearestODR)eSLIM_CONTROL_MESSAGE_ID_VEHICLE_DATA_REQ(车况 enable)
根据VehicleNetwork配置文件,把 CAN 里车速/里程对应的具体 signal 名如下:
结合代码里的VehicleNetwork 配置(主要在/etc/sap.conf,源码:src/gps/etc/sap.conf/MAXX/sap.conf),以及vnwconf的 signal 命名规范,整理如下。
配置分两套
| 配置文件 | 作用 | QDR 车速/里程是否用它 |
|---|---|---|
/etc/sap.conf里VN_*_CFG | SLIMVehicleNetworkProvider按 CAN ID + 位偏移直接解帧 | 是(QDR3 当前方案) |
vnwconf.xml(如vnwconf-SAMPLE.xml) | VNW 框架VehicleInterfaceData,用signal id(如 1061) | 否(除非走 Java VNW API,与 QDR SLIM 解帧并行) |
当前 QDR3 生效的是sap.conf,不是 SAMPLE 里0x7C+ signal1061那套。
一、当前生效配置(sap.confQDR3 段)
源码位置:
ap/LE.UM.7.4.1/src/gps/etc/sap.confap/LE.UM.7.4.1/src/gps/etc/MAXX/sap.conf(内容一致)
1. 车速VN_SPEED_CFG(CONF1,来自真实 CAN)
VN_SPEED_CFG=1:777,0,0,1,2,1,0.010000,0,40,8,32,8 VN_SPEED_CFG_BATCH_VALUE=50| 字段 | 值 | 含义 |
|---|---|---|
| 配置版本 | 1 | SpeedCONF1Config,按 CAN 位域解析 |
| CAN Frame ID | 777 (0x309) | 只处理该 ID 的报文 |
| unitOffset / unitLength | 0 / 0 | 不从报文读单位,用下面固定单位 |
| speedUnit | 2 | km/h(eSPEED_UNIT_KMPH) |
| unitValue | 1 | 与 unit 配套(unitLength=0 时仅作占位) |
| scale | 0.01 | 原始计数 × 0.01 → km/h |
| offset | 0 | |
| speedOffsetLowBits / speedLengthLowBits | 40 / 8 | 车速低 8 bit 起始位 |
| speedOffsetUpBits / speedLengthUpBits | 32 / 8 | 车速高 8 bit 起始位 |
解析公式(VehicleNetworkCONF1SpeedMP::OnNewCanFrameEvent):
speedBytes = (bits@32, len=8) << 8 | (bits@40, len=8) speed_kmh = (speedBytes - 0) * 0.01 speed_mps = speed_kmh * 0.2777778→ 上报 SLIM:eSLIM_SERVICE_VEHICLE_SPEED,slimVehicleMotionDataStructT.samples[].speed.data(m/s)。
在整车 DBC 里应对的信号名:需在你们实车 DBC中查CAN ID = 0x309 (777)、bit 32–47(或 byte 内等价布局)的车速信号;仓库内没有绑定到该 Frame 的 DBC,无法给出 OEM 信号名(如VehSpd等),只能给到ID + 位域 + 缩放。
2. 里程VN_ODOMETRY_CFG(当前不是CAN 里程)
VN_ODOMETRY_CFG=0:2,4.5 #VN_ODOMETRY_CFG_BATCH_VALUE=100| 字段 | 值 | 含义 |
|---|---|---|
| 版本 | 0 | OdometryConfig默认/仿真,不读 CAN |
| period | 2 | 定时器周期(秒) |
| averageSpeed | 4.5 | 配置用平均速度(m/s 量级参数,见CfgValid1–25) |
实现类:VehicleNetworkDefaultOdometryMP::OnNewTimerExpiryEvent(),上报固定占位距离(1/2/3 mm),不是轮速积分里程。
结论:当前 QDR 路径下没有启用真实 CAN 里程;若要用 CAN 里程,需改为 CONF1,例如:
VN_ODOMETRY_CFG=1:<CAN_ID>,<reverseBit>,<srcOffset>,<srcLen>,<distOffset>,<distLen>(格式见VehicleNetworkConfiguration.h中OdometryCONF1Config)
3. 档位VN_GEAR_CFG(CONF1,辅助 QDR,非车速)
VN_GEAR_CFG=1:422,20,4,0,3,1,9,0,1,2,3,4,5,6,7,8 VN_GEAR_CFG_BATCH_VALUE=50| 字段 | 值 | 含义 |
|---|---|---|
| CAN Frame ID | 422 (0x1A6) | |
| gearOffset / gearLength | 20 / 4 | 档位 4 bit 从 bit 20 起 |
| park / reverse / neutral | 0 / 3 / 1 | P/R/N 的 CAN 原始值 |
| numberDriveGear | 9 | 前进档映射个数 |
| driveValue0…8 | 0,1,2,3,4,5,6,7,8 | D 档各档位的 CAN 值 |
→eSLIM_SERVICE_VEHICLE_GEAR(slimVehicleMotionDataStructT,sensorType=GEAR)。
4. 未启用(注释掉的 QDR 相关项)
| 配置项 | 说明 |
|---|---|
VN_DWS_CFG | 四轮差速轮速(QDR2-DWT 示例用 CAN 555) |
VN_STEERINGWHEEL_CFG | 方向盘角(示例 frame 含 1050 等) |
VN_ODOMETRY_CFG=1:... | 真实 CAN 里程 |
二、vnwconf.xml中的 Signal 名(参考,非当前 QDR 车速源)
若使用vnwconf-SAMPLE.xml+VehicleInterfaceSignals.java,标准VIM 信号名 ↔ ID如下(与777/422无关):
| Signal 名(Java 常量) | Signal ID | SAMPLE 中 CAN Frame | 注释 |
|---|---|---|---|
VIM_SPEEDO_METER_SIGNAL | 1061 | 0x7C(124),byte0–1 | 车速 |
VIM_ODOMETER_SIGNAL | 1000 | 0x8B(139),byte0–3 float | 里程表 |
VIM_TRANSMISSION_GEAR_STATUS_SIGNAL | 1041 | 0x7Cbyte2 | 档位 |
VIM_STRNG_WHEEL_ANGLE_SIGNAL | 1050 | 0x90byte4–7 float | 方向盘角 |
VIM_TRIP_METER_1_MILEAGE_SIGNAL | 1063 | 0x7E | 小计里程 1 |
VIM_ENGINE_SPEED_SIGNAL | 1062 | 0x7D | 发动机转速 |
完整列表见:src/vnw/vehiclefwk/com/qualcomm/qti/VehicleInterfaceSignals.java。
三、与 QDR 相关的 SLIM 服务 ↔ 配置 ↔ 数据字段
| SLIM 服务 | sap.conf | CAN/来源 | 输出结构字段 |
|---|---|---|---|
eSLIM_SERVICE_VEHICLE_SPEED | VN_SPEED_CFG | Frame0x309,bit 解析 | slimVehicleMotionDataStructT.speed(m/s) |
eSLIM_SERVICE_VEHICLE_ODOMETRY | VN_ODOMETRY_CFG=0 | 定时器仿真,非 CAN | slimVehicleOdometryDataStructT.distanceTravelled[](mm) |
eSLIM_SERVICE_VEHICLE_GEAR | VN_GEAR_CFG | Frame0x1A6,bit20 起 4bit | slimVehicleMotionDataStructT.gear |
eSLIM_SERVICE_VEHICLE_STEERING_WHEEL | (未配) | — | — |
eSLIM_SERVICE_VEHICLE_DWS | (未配) | — | — |
四、如何在实车 DBC 里对上“信号名”
- 打开整车DBC / ARXML。
- 查Message ID = 777 (0x309):
- 找覆盖bit 32–47(或文档里的 start bit 40 len 8 + start 32 len 8)的 signal → 即QDR 车速。
- 查Message ID = 422 (0x1A6):
- bit 20,长度 4→QDR 档位。
- 里程:当前 sap.conf未映射 DBC;若要用 CAN 里程,需:
- 在 DBC 里选定里程/轮脉冲报文;
- 把
VN_ODOMETRY_CFG改成版本1并填OdometryCONF1Config各 bit 域。
五、配置里还留着的其它方案
| 用途 | sap.conf 注释行 | Frame ID (dec) |
|---|---|---|
| 旧车速方案 | #VN_SPEED_CFG=1:131,... | 131 (0x83) |
| QDR2-Gyro 车速 | #VN_SPEED_CFG=1:555,... | 555 (0x22B) |
| QDR2-DWT 车速 | #VN_SPEED_CFG=1:555,22,... | 555 |
简要结论:
- QDR 车速:CAN0x309 (777),16 bit @ bit32/40,scale0.01 km/h→ m/s;不是vnwconf 里的
VIM_SPEEDO_METER_SIGNAL (1061)。 - QDR 里程:未接 CAN,
VN_ODOMETRY_CFG=0:2,4.5为默认定时占位;要真实里程必须改 CONF1 并配 CAN 位域。 - 档位:CAN0x1A6 (422),bit20 起 4 bit。