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,那肯定有一个传感器出问题了。
模型一致性检查的步骤:
- 建立系统模型(比如电机扭矩模型、电压平衡模型)。
- 用不同的传感器数据,通过模型计算出同一个物理量。
- 比较计算结果,如果偏差超过阈值,报错。
核心思想:模型一致性检查不依赖单个传感器的绝对精度,而是依赖多个传感器之间的相对一致性。即使所有传感器都有误差,只要误差方向一致,系统也能正常工作。
我曾经用模型一致性检查发现过一个旋变传感器故障。当时电流和转速数据看起来都正常,但用模型一算,扭矩偏差很大。后来拆下来一看,旋变的励磁线松了。嗯,这个检查确实救过我的命。
4.4 本章知识体系
下面这张图,把本章的核心逻辑串起来了。通信安全和信号合理性检查,最终都是为了确保输入到控制算法的数据是可信的。