4. 车载网络与总线

MQTT 在车云通信里,说白了就是最适合“瘦终端、弱网络、高频次”场景的协议。我最早接触车联网时,团队还在用 HTTP 长轮询做状态上报,结果一个月下来,基站侧投诉电话被打爆了。后来切到 MQTT,问题迎刃而解。

这一章,咱们就聚焦三个最典型的场景:车辆状态上报、远程诊断指令下发、OTA 升级。每个场景的 QoS 选型、Topic 设计、Payload 结构都不一样。我踩过的坑,也会一并说给你听。

4.1 车辆状态上报:QoS 1 + 离线保留

车辆状态上报,是车云通信里频率最高的场景。GPS 位置、车速、电量、发动机转速……这些数据每秒甚至每百毫秒就在产生。

Topic 设计原则:按车型 + VIN + 数据类型分层。

vehicles/{vin}/status/gps
vehicles/{vin}/status/can
vehicles/{vin}/status/battery

我个人习惯把 VIN 放在第二级,这样 Broker 可以按 VIN 做权限过滤,也方便后续做离线消息回放。

QoS 选择:QoS 1。

  • QoS 0 丢包率太高,尤其在地下车库或隧道场景,状态直接断档。
  • QoS 2 性能开销大,车载 MCU 扛不住每秒几百次的确认握手。
  • QoS 1 正好:至少一次送达,重复消息由云端去重。
我的经验:曾经有个项目,状态上报用了 QoS 0,结果某次 OTA 升级前,云端收到的最后一条电量数据是 80%,实际车辆已经亏电到 15%。升级到一半车辆断电变砖。从那以后,状态上报我再也不敢用 QoS 0。

Payload 结构:推荐用 Protobuf 或 FlatBuffers 压缩,不要裸传 JSON。

// 压缩前 JSON: 187 字节
{"vin":"LSVAU2A38N2100001","lat":31.2304,"lng":121.4737,"soc":85,"speed":0}

// 压缩后 Protobuf: 32 字节
0A 11 4C 53 56 41 55 32 41 33 38 4E 32 31 30 30 30 30 31 10 00 19 9A 99 99 41 21 00 00 00 00

车载端算力有限,但压缩带来的带宽节省非常可观。一台车每天上报 86400 条,每条省 150 字节,一个月就是 370MB 流量——对于 NB-IoT 套餐来说,这就是真金白银。

4.2 远程诊断指令下发:QoS 2 + 请求-响应模式

远程诊断不一样。这是“人等在屏幕前,等着看结果”的场景。指令丢了,或者重复执行了,都会出大问题。

Topic 设计:双向 Topic 配对。

// 云端下发指令
vehicles/{vin}/command/diag/req

// 车辆回复结果
vehicles/{vin}/command/diag/rsp

QoS 选择:QoS 2。

为什么?诊断指令通常只发一次,但结果必须精确。QoS 2 保证“恰好一次”,避免重复执行诊断动作——比如重复读取 DTC 故障码还好,但重复执行某个执行器动作(比如解锁车门)就会造成安全风险。

注意:QoS 2 的代价是 4 次报文交互(PUBLISH → PUBREC → PUBREL → PUBCOMP)。在信号差的区域,一次指令下发可能耗时 3-5 秒。所以远程诊断不适合做实时控制,只适合非紧急的查询类操作。

Payload 结构:必须包含请求 ID 和超时时间。

{
  "reqId": "DIAG-20250321-001",
  "cmd": "READ_DTC",
  "params": {
    "ecu": "BCM",
    "dtcMask": "0x01"
  },
  "timeout": 30
}

车辆端收到指令后,先回复 ACK,再执行诊断,最后上报结果。云端根据 reqId 做超时重试或超时失败处理。

4.3 OTA 升级场景:大文件分片 + 断点续传

OTA 升级是车云通信里最复杂的场景。一个固件包可能 2GB,车载网络可能只有 100kbps。怎么传?

核心思路:MQTT 只做控制信令,文件传输走 HTTP/HTTPS 或私有二进制通道。

Topic 设计:

// 云端通知升级
vehicles/{vin}/ota/notification

// 车辆请求分片
vehicles/{vin}/ota/chunk/req

// 云端下发分片
vehicles/{vin}/ota/chunk/rsp

// 车辆上报进度
vehicles/{vin}/ota/progress

QoS 选择:

  • 通知和进度上报:QoS 1
  • 分片请求和响应:QoS 2

分片数据一旦丢失或重复,整个升级包校验就会失败。所以分片传输必须用 QoS 2。

断点续传流程:

  1. 云端下发升级通知,包含固件版本、大小、校验值。
  2. 车辆检查本地已下载的分片索引,上报缺失分片列表。
  3. 云端按顺序下发缺失分片,每片 64KB-256KB。
  4. 车辆每收到一片,写入本地存储,并上报进度。
  5. 所有分片下载完成后,车辆做完整性校验,校验通过后进入安装阶段。
关键指标:分片大小直接影响传输效率。64KB 分片适合弱网环境(丢包重传代价小),256KB 分片适合高速网络(吞吐量高)。我一般建议根据车辆当前信号强度动态调整分片大小。

4.4 三个场景的对比总结

场景 QoS Topic 数量 Payload 大小 实时性要求 可靠性要求
车辆状态上报 QoS 1 3-5 个 32-256 字节 高(秒级) 中
远程诊断指令 QoS 2 2 个(req/rsp) 128-512 字节 中(秒级) 极高
OTA 升级 QoS 1 + QoS 2 4 个 64KB-256KB/片 低(分钟级) 极高

4.5 MQTT 在车云通信中的整体架构

下面这张图,是我在多个量产项目中沉淀下来的 MQTT 车云通信架构。你可以把它当作一个参考模板。

MQTT 车云通信架构图 MQTT 车云通信架构(状态上报 / 诊断 / OTA) 车载终端 (T-Box / IVI) 状态采集模块 诊断执行模块 OTA 下载引擎 MQTT Client 4G/5G/NB-IoT MQTT over TCP/TLS 云端平台 MQTT Broker (EMQX) 状态数据管道 诊断指令服务 OTA 分发服务 业务 API / 数据库 场景 Topic 示例 状态上报: vehicles/{vin}/status/+ 诊断指令: vehicles/{vin}/command/diag/+ OTA 升级: vehicles/{vin}/ota/+ QoS 选型建议 • 状态上报 → QoS 1 • 诊断指令 → QoS 2 • OTA 通知 → QoS 1 • OTA 分片 → QoS 2
架构要点:车载端 MQTT Client 只维持一条 TCP 连接,所有场景共用这条连接。云端 Broker 根据 Topic 前缀做路由分发。这样做的好处是——车载端资源占用最小,云端扩展性最好。

4.6 避坑指南

最后,分享几个我踩过的坑,希望能帮你少走弯路。

  • Keep Alive 设置不当:曾经把 Keep Alive 设成 300 秒,结果车辆在信号弱区频繁断连,Broker 侧积压了大量半开连接。后来改成 60 秒,配合 30 秒的 Ping 间隔,问题解决。
  • Payload 过大导致 Broker OOM:有同事把 OTA 分片直接塞进 MQTT Payload,单条消息 10MB,Broker 直接 OOM。记住:MQTT 不是为传输大文件设计的,超过 1MB 的 Payload 就要考虑分片或换通道。
  • Topic 层级过深:见过有人把 Topic 设计成 8 层,比如 vehicles/{brand}/{model}/{year}/{vin}/{type}/{subtype}/{action}。Broker 做通配符匹配时性能急剧下降。我建议不超过 4 层。
  • 忽略离线消息积压:车辆长时间离线后重新上线,Broker 会把积压的几千条消息全部推过去,导致车载端处理不过来。解决方案是设置消息过期时间(Message Expiry Interval),或者用 Last Will 清理无效会话。