4. 安全需求工程

通信和信号,是电驱系统的神经末梢。信号传错了,或者传丢了,轻则报个故障,重则直接导致扭矩失控。这一章,我们重点聊聊怎么让这些神经信号不出错。

4.1 CAN通信安全:CRC、超时与Alive Counter

CAN总线在电驱系统里用得最多。但CAN本身只保证物理层和数据链路层的传输,应用层的安全机制,得我们自己搭。

4.1.1 CRC校验:别让一个比特坏了事

CRC(循环冗余校验)是通信安全的第一道防线。说白了,就是发送方给数据算个“指纹”,接收方收到后再算一遍,指纹对不上,说明数据被篡改了。

我个人习惯,在CAN报文的8字节数据域里,至少留2个字节给CRC。具体用哪种多项式?我推荐CRC-16-CCITT(0x1021),它在电驱这种中等速率、中等数据长度的场景下,检错能力足够,计算开销也小。

关键点:CRC只能检错,不能纠错。发现CRC错误后,接收方必须丢弃该帧,并触发相应的故障处理(比如请求安全状态)。

我在项目中遇到过一个问题:CRC算法实现时,初始值和异或值没统一。发送方用0xFFFF,接收方用0x0000,结果同样的数据算出来不一样。嗯,这里要注意,通信矩阵里必须把CRC的初始值、多项式、输出异或值都定义清楚。

4.1.2 超时监控:数据没来怎么办?

CRC管的是数据对不对,超时监控管的是数据来没来。电驱系统里,很多控制信号是有周期要求的,比如扭矩指令通常要求10ms发一次。如果超过20ms没收到,系统必须认为通信中断。

超时监控的实现很简单:接收方维护一个定时器,每次收到有效帧就复位。定时器溢出,就报超时故障。

信号类型 典型周期 超时阈值(建议) 故障响应
扭矩指令 10 ms 20 ms 请求安全状态
转速反馈 5 ms 10 ms 使用上次有效值
温度信号 100 ms 200 ms 使用默认值
诊断请求 无固定周期 500 ms 终止诊断会话

你想想看,如果扭矩指令超时了,还继续用旧值跑,那电机可能就失控了。所以,对于安全相关的信号,超时后必须立即进入安全状态,不能“将就”。

4.1.3 Alive Counter:防“卡死”的计数器

Alive Counter,也叫滚动计数器。它的作用是防止接收方“卡死”在某个旧值上。比如,发送方连续发了三帧数据,内容一模一样,但Alive Counter分别是1、2、3。接收方如果发现Alive Counter没变,就知道通信可能卡住了。

实现方式:发送方每发一帧,Alive Counter加1,溢出后回0。接收方检查Alive Counter是否按预期递增。如果连续几帧都没变,报错。

小技巧:Alive Counter通常占用1个字节,和CRC一起放在数据域的最后。我习惯把Alive Counter放在CRC前面,这样CRC也能覆盖到计数器,防止计数器被篡改。

我曾经遇到过一个坑:Alive Counter的初始值没定义好。发送方从0开始,接收方从0xFF开始,结果第一帧就报错。后来我们在通信矩阵里统一了初始值,问题解决。

4.2 SPI通信安全:片选、时钟与数据完整性

SPI在电驱系统里主要用于芯片间通信,比如主控芯片和旋变解码芯片、电流采样芯片之间的数据交换。SPI的物理层比CAN简单,但安全机制不能少。

4.2.1 SPI的CRC校验

很多SPI外设(比如TI的TMS570、NXP的S32K)都内置了硬件CRC模块。我建议优先使用硬件CRC,因为它不占用CPU时间。如果硬件不支持,那就得软件模拟了。

SPI的CRC计算方式和CAN类似,但要注意:SPI是全双工通信,发送和接收可以同时进行。所以,CRC要分别对发送数据和接收数据计算。

// SPI CRC计算示例(软件实现)
uint16_t spi_crc16(uint8_t *data, uint8_t len) {
    uint16_t crc = 0xFFFF;
    for (uint8_t i = 0; i < len; i++) {
        crc ^= data[i];
        for (uint8_t j = 0; j < 8; j++) {
            if (crc & 0x0001) {
                crc = (crc >> 1) ^ 0xA001;
            } else {
                crc >>= 1;
            }
        }
    }
    return crc;
}

4.2.2 SPI的超时与帧同步

SPI通信通常由主控芯片发起,从设备响应。如果从设备没响应,或者响应超时,主控必须能检测到。

我常用的方法:主控发送一个“读寄存器”指令后,启动一个硬件定时器。如果在规定时间内没收到从设备的响应,就认为通信失败。这个超时时间一般设为SPI时钟周期的10倍左右。

注意:SPI的片选信号(CS)必须严格管理。如果CS在传输过程中被意外拉高,从设备会认为本次传输结束,导致数据错位。我建议在每次SPI传输前后,都检查CS的电平状态。

4.3 传感器信号合理性检查

传感器信号是电驱系统的“眼睛”。眼睛看错了,系统就瞎了。所以,我们必须对传感器信号做合理性检查。

4.3.1 范围检查:别信离谱的值

范围检查是最基本的。每个传感器信号都有物理极限。比如,电流传感器的测量范围是±500A,如果读到600A,那肯定是错的。

范围检查分两种:

  • 硬限幅检查:信号值是否超出传感器的物理测量范围。
  • 软限幅检查:信号值是否超出系统正常运行的范围(比如,正常运行时电流不会超过300A)。

我建议两种都做。硬限幅检查用于检测传感器硬件故障,软限幅检查用于检测系统异常。

4.3.2 斜率检查:变化太快也不行

斜率检查,说白了就是看信号的变化率是否合理。比如,电机转速从0 rpm瞬间跳到10000 rpm,那肯定有问题。

实现方法:计算当前值和上次值的差值,除以采样周期,得到变化率。如果变化率超过预设阈值,报错。

// 斜率检查示例
bool check_slope(float current_val, float prev_val, float max_slope, float dt) {
    float slope = (current_val - prev_val) / dt;
    if (fabs(slope) > max_slope) {
        return false; // 斜率超限
    }
    return true;
}

我在项目中遇到过一个问题:电机急加速时,电流变化率确实很大,导致斜率检查误报。后来我们把斜率阈值设成了动态的,根据电机运行状态调整,误报就少了。

4.3.3 模型一致性检查:多传感器互相印证

模型一致性检查,是最高级的合理性检查。它利用系统模型,用多个传感器的数据互相印证。

举个例子:电机的扭矩可以通过电流传感器和转速传感器分别估算。如果电流估算的扭矩是100 Nm,转速估算的扭矩是50 Nm,那肯定有一个传感器出问题了。

模型一致性检查的步骤:

  1. 建立系统模型(比如电机扭矩模型、电压平衡模型)。
  2. 用不同的传感器数据,通过模型计算出同一个物理量。
  3. 比较计算结果,如果偏差超过阈值,报错。

核心思想:模型一致性检查不依赖单个传感器的绝对精度,而是依赖多个传感器之间的相对一致性。即使所有传感器都有误差,只要误差方向一致,系统也能正常工作。

我曾经用模型一致性检查发现过一个旋变传感器故障。当时电流和转速数据看起来都正常,但用模型一算,扭矩偏差很大。后来拆下来一看,旋变的励磁线松了。嗯,这个检查确实救过我的命。

4.4 本章知识体系

下面这张图,把本章的核心逻辑串起来了。通信安全和信号合理性检查,最终都是为了确保输入到控制算法的数据是可信的。

信号与通信安全知识体系 信号与通信安全知识体系 输入信号 通信安全 信号合理性检查 CRC校验 超时监控 Alive Counter 范围检查 斜率检查 模型一致性检查(多传感器印证) 可信数据 → 控制算法 所有安全机制的目标:确保输入到控制算法的数据是可信的