2. 系统架构设计:整体架构图、模块划分与数据流

好,咱们进入第二章。系统架构设计,说白了就是给整个多屏互动项目搭骨架。我见过不少团队,一上来就写代码,写到一半发现屏幕之间通信乱成一锅粥,最后不得不返工。嗯,咱们别走那条弯路。

我个人习惯,先画一张整体架构图,把大框框定下来。然后再拆模块,最后把数据怎么流、怎么转,一条条理清楚。这样后面写代码的时候,心里才有底。

2.1 整体架构图

先看这张图。它把整个系统分成三层:硬件底层、中间通信层、上层应用。每一层各司其职,层与层之间通过定义好的接口交互。

核心原则:高内聚、低耦合。显示只管显示,通信只管传数据,应用只管业务逻辑。谁也别越界。

车载多屏互动系统整体架构图 车载多屏互动系统 — 整体架构图 应用层 仪表盘应用 | 中控导航 | 副驾娱乐 | 后排影音 | HUD 抬头显示 空调控制 | 车辆设置 | 语音助手 | 应用商店 每个应用独立进程,通过中间件通信 通信中间件层 SOME/IP 服务发现 | DDS 数据分发 | 共享内存 (SHM) 服务注册/发现 | 消息路由 | 协议转换 | QoS 策略 屏蔽底层硬件差异,提供统一通信接口 显示管理层 窗口合成器 (Wayland/Weston) | 图层管理 | 分辨率适配 触摸事件分发 | 屏幕旋转/镜像 | HMI 框架 (Qt/QML) 管理物理屏幕资源,决定谁画在哪里 注意 每层只与相邻层交互

这张图我建议你存下来。每次做设计决策时,问自己一句:我这个改动,跨层了吗?如果跨了,八成有问题。

2.2 模块划分

架构图有了,咱们把每个模块拆开看看。我按三层来聊:显示管理、通信中间件、应用层。

2.2.1 显示管理模块

显示管理,管的是屏幕资源。车上有好几块屏,谁该显示什么,谁在前谁在后,分辨率不一样怎么办——这些都是它的事。

我记得有一次,客户说副驾屏显示内容被中控挡住了。查了半天,发现是图层优先级没配好。嗯,从那以后我特别强调图层管理。

子模块 职责 关键技术
窗口合成器 管理多个应用的显示窗口,合成最终画面 Wayland/Weston, SurfaceFlinger
图层管理 定义图层优先级、透明度、可见区域 Z-order, Alpha blending
分辨率适配 自动适配不同屏幕的物理分辨率 DPI scaling, 坐标映射
触摸事件分发 将触摸坐标正确路由到对应应用 Input dispatcher, 坐标变换
HMI 框架 提供 UI 组件和动画能力 Qt/QML, Flutter

我的经验:窗口合成器别自己造轮子。直接用 Weston 或 SurfaceFlinger,社区成熟,坑少。你想想看,车规级系统最怕什么?不稳定。用成熟方案能省一半调试时间。

2.2.2 通信中间件模块

通信中间件,是整个系统的血管。应用之间怎么说话?数据怎么传?延迟多少?全看它。

我曾经在一个项目里,用了简单的 Socket 通信。结果车跑起来之后,信号一抖,数据就丢包。后来换成 SOME/IP + DDS 双通道,才把问题解决。

子模块 职责 适用场景
SOME/IP 服务发现、远程过程调用 (RPC) 控制类消息、服务调用
DDS 数据分发、发布/订阅模式 高频数据流、传感器数据
共享内存 (SHM) 进程间高速数据共享 视频帧、大块数据
协议转换网关 桥接不同通信协议 CAN/LIN 与 IP 网络互转

避坑指南:别把所有数据都走 DDS。DDS 虽然灵活,但 QoS 配置复杂,搞不好反而增加延迟。我建议:控制类走 SOME/IP,数据流走 DDS,大块数据走共享内存。各取所长。

2.2.3 应用层模块

应用层,就是用户能看到的那些界面和功能。每个应用独立运行,通过中间件互相通信。

这里有个关键点:应用之间不能直接调用。比如仪表盘想显示导航信息,不能直接读导航 app 的内存,必须通过中间件发消息。这样任何一个应用挂了,不会拖垮整个系统。

  • 仪表盘应用:车速、转速、油量、报警灯。要求实时性高,刷新率 60fps。
  • 中控导航:地图渲染、路线规划、POI 搜索。数据量大,但实时性要求相对低。
  • 副驾娱乐:视频播放、音乐、游戏。独立进程,崩溃不影响驾驶。
  • 后排影音:类似副驾,但可能有多块屏同时播放不同内容。
  • HUD 抬头显示:车速、导航箭头、ADAS 警告。信息精简,延迟要求极高。

2.3 数据流设计

模块分好了,数据怎么流?我画了一张数据流图,把典型场景走一遍。

车载多屏互动数据流图 典型数据流:导航信息从中控流转到仪表盘和 HUD 中控导航 App 生成导航指令 通信中间件 SOME/IP 发布 仪表盘 App 订阅并显示 HUD 控制器 订阅并投射 数据流说明 中控导航 → 发布导航指令到 SOME/IP 主题 → 仪表盘和 HUD 分别订阅 → 各自渲染显示 仪表盘显示简化箭头,HUD 显示精简文字,中控显示完整地图

这个流程里,有几个关键点要注意:

  1. 发布/订阅解耦:中控只管发,不管谁收。仪表盘和 HUD 只管收,不管谁发。这样新增一个屏幕,不需要改已有代码。
  2. 数据精简:中控发的是「导航指令」,不是完整地图数据。每个订阅者按需渲染。仪表盘只画一个箭头,HUD 只显示距离文字,没必要传整张图。
  3. 延迟控制:导航指令从发出到 HUD 显示,延迟不能超过 100ms。我建议用 DDS 的 BEST_EFFORT 策略,牺牲一点可靠性换速度。

数据流设计口诀:谁生产谁发布,谁消费谁订阅。数据最小化,延迟可量化。接口标准化,扩展不用怕。