3. 核心功能模块划分:感知、决策、控制、通信、人机交互

各位同学,今天我们来聊聊列车自动驾驶软件最核心的骨架——功能模块划分。说实话,我见过不少刚入行的工程师,一上来就急着写代码,结果模块之间耦合得像一团乱麻。我个人习惯是,先花半天时间把模块边界画清楚,后面写代码反而快得多。

列车自动驾驶系统,说白了就是五个模块:感知、决策、控制、通信、人机交互。这五个模块各司其职,又紧密配合。我曾在一次项目中遇到过模块划分不清的情况,结果联调时出了问题,排查了整整三天才发现是感知模块把数据格式传错了。嗯,从那以后我对模块接口规范就特别较真。

3.1 感知模块——列车的「眼睛和耳朵」

感知模块负责收集列车周围的环境信息。你想想看,列车在轨道上跑,它得知道前方有没有障碍物、当前速度是多少、信号灯是什么颜色。这些信息从哪里来?

  • 传感器数据采集:雷达、激光雷达、摄像头、速度传感器、加速度计等
  • 轨道占用检测:通过轨道电路或应答器获取轨道占用状态
  • 信号系统接口:读取地面信号机的显示状态
  • 定位信息:GPS、里程计、信标校正等多源融合定位

重要提醒:感知模块的数据质量直接决定了后续决策的准确性。我在项目中遇到过传感器噪声导致误判的情况,所以一定要做数据滤波和有效性校验。

这里我给出一个简单的传感器数据融合伪代码示例:

// 传感器数据融合示例
function fuseSensorData(radarData, cameraData, odometerData) {
    // 时间戳对齐
    let alignedData = alignTimestamps(radarData, cameraData);
    
    // 数据有效性检查
    if (!isValid(alignedData)) {
        return { status: 'ERROR', message: '传感器数据异常' };
    }
    
    // 加权融合
    let fusedPosition = weightedAverage(
        radarData.position, 0.4,
        cameraData.position, 0.3,
        odometerData.position, 0.3
    );
    
    return { status: 'OK', position: fusedPosition };
}

3.2 决策模块——列车的「大脑」

决策模块是整个系统的核心。它接收感知模块传来的信息,然后决定列车该怎么走。说白了,就是回答三个问题:现在该加速还是减速?要不要紧急制动?下一站怎么停?

我建议把决策模块分成三个层次:

  1. 战略决策:运行计划、时刻表调整、线路选择
  2. 战术决策:速度曲线规划、停车点计算、节能策略
  3. 操作决策:牵引/制动指令、车门控制、空调调节
决策层级 时间尺度 典型决策内容
战略决策 分钟级 是否跳站、是否晚点调整
战术决策 秒级 目标速度、制动曲线
操作决策 毫秒级 牵引力大小、制动缸压力

个人经验:战术决策层最容易出问题。我曾经遇到过一个场景,列车在弯道上需要提前减速,但决策模块没有考虑线路曲率,结果乘客体验很差。后来我们在决策模型里加入了线路几何参数,才解决了这个问题。

3.3 控制模块——列车的「手脚」

控制模块负责把决策指令变成实际的物理动作。它直接跟列车硬件打交道,比如牵引系统、制动系统、车门系统等。

控制模块的核心是闭环控制。你想想看,决策模块说「加速到80km/h」,控制模块就得精确地调节牵引力,同时还要监控实际速度,形成一个反馈回路。

  • 牵引控制:调节电机输出扭矩
  • 制动控制:电制动与空气制动的协调
  • 车门控制:开关门时序、防夹检测
  • 空调控制:车厢温度调节

避坑指南:我曾经在控制模块里犯过一个低级错误——没有做输出限幅。结果有一次传感器故障,控制模块输出了一个巨大的牵引力指令,差点造成事故。从那以后,所有控制输出都必须经过安全限幅检查。

3.4 通信模块——列车的「神经网络」

通信模块负责列车内部和外部之间的信息交换。内部通信是各个子系统之间的数据传递,外部通信是列车与地面控制中心、其他列车之间的交互。

我个人习惯把通信模块分成三个子层:

  1. 物理层:无线通信(4G/5G、Wi-Fi)、有线通信(MVB、CAN总线)
  2. 协议层:TCP/IP、UDP、TRDP(列车实时数据协议)
  3. 应用层:数据格式定义、消息序列、心跳机制

这里要注意的是,列车通信对实时性和可靠性要求极高。我建议采用双冗余通信链路,一条主用一条备用,切换时间不能超过100毫秒。

// 通信心跳检测示例
function heartbeatCheck() {
    let lastHeartbeat = getLastHeartbeatTime();
    let currentTime = getCurrentTime();
    
    if (currentTime - lastHeartbeat > 2000) { // 2秒无心跳
        switchToBackupChannel();
        logWarning('主通信链路故障,切换到备用链路');
    }
}

3.5 人机交互模块——列车的「面孔」

人机交互模块是司机和乘客与系统打交道的界面。虽然说是自动驾驶,但人机交互依然不可或缺。司机需要监控系统状态,乘客需要获取出行信息。

我建议把HMI分成两个子模块:

  • 司机台HMI:速度表、信号显示、故障报警、手动干预接口
  • 乘客信息HMI:到站显示、换乘指引、紧急通话按钮

设计原则:人机交互要遵循「最少操作」原则。自动驾驶模式下,司机的主要任务是监控,而不是操作。所以界面设计要突出关键信息,减少不必要的干扰。

嗯,这里还要提一下,人机交互模块的响应时间很关键。司机按下紧急制动按钮后,系统必须在200毫秒内响应。我曾经测试过一个HMI原型,按钮按下后要等1秒才有反应,这显然是不合格的。

3.6 模块间的协作关系

五个模块不是孤立的,它们之间通过定义好的接口进行数据交换。我画了一张模块协作图(这里用文字描述):

  1. 感知模块采集数据,处理后发送给决策模块
  2. 决策模块根据感知信息做出决策,生成控制指令
  3. 控制模块执行指令,同时将执行结果反馈给决策模块
  4. 通信模块贯穿所有模块,提供数据传输通道
  5. 人机交互模块从各模块获取状态信息,并向司机/乘客展示

说白了,这就是一个闭环系统。感知→决策→控制→执行→反馈→再感知。任何一个环节出问题,整个系统都会受影响。

我的建议:在项目初期,一定要把模块间的接口协议定死。数据格式、传输频率、异常处理方式,这些都要写进设计文档里。我见过太多项目因为接口没定好,后期联调时改来改去,浪费了大量时间。

好了,这一章的内容就到这里。核心功能模块划分是架构设计的基石,把这五个模块的边界和职责搞清楚,后面的工作就会顺利很多。下一章我们会深入讲解感知模块的详细设计,包括传感器选型和数据融合算法。