3. 信号丢失的软件检测机制
硬件层面的防护做完了,信号还是有可能丢。为什么?线缆老化、接头松动、强电磁干扰,这些在工业现场太常见了。我见过一个项目,编码器线缆被叉车压过一次,外表看不出问题,但信号就是时有时无。
所以软件层面必须有一套检测机制。说白了,就是让控制器自己判断:「当前这个编码器信号,到底还能不能用?」
下面这五种方法,是我在实际项目中反复验证过的。它们各有侧重,组合使用效果最好。
3.1 超时检测
这是最基础、最直接的方法。编码器在正常运行时,会持续输出脉冲。如果控制器在一段时间内没收到任何脉冲变化,那大概率是信号丢了。
具体怎么做?
- 设定一个时间阈值,比如 10ms、50ms 或 100ms
- 每次收到脉冲边沿,重置定时器
- 定时器溢出,触发超时报警
阈值怎么选?我一般这样定:
| 应用场景 | 典型转速 | 建议超时时间 | 说明 |
|---|---|---|---|
| 低速输送线 | < 100 rpm | 100 - 200 ms | 脉冲间隔长,阈值要放宽 |
| 通用伺服 | 1000 - 3000 rpm | 10 - 50 ms | 正常脉冲密集,超时响应快 |
| 高速主轴 | > 10000 rpm | 1 - 5 ms | 必须用硬件定时器实现 |
3.2 奇偶校验
奇偶校验在串行编码器(如 SSI、BiSS、EnDat)里很常见。每帧数据后面跟一个校验位,用来检测单比特错误。
原理很简单:
- 偶校验: 数据位 + 校验位中,1 的个数为偶数
- 奇校验: 数据位 + 校验位中,1 的个数为奇数
接收端收到数据后,重新计算校验位。如果对不上,说明数据在传输过程中被篡改了。
但说实话,奇偶校验只能检测奇数个比特的错误。如果两个比特同时翻转,它发现不了。所以它通常作为第一道防线,配合其他方法使用。
3.3 CRC 校验
CRC 比奇偶校验强得多。它能检测出多位错误、突发错误,甚至某些模式下的所有错误。
我习惯用 CRC-16 或 CRC-32。具体流程:
- 发送端对数据帧计算 CRC 值,附加在帧尾
- 接收端对收到的数据(含 CRC)重新计算
- 如果计算结果不为 0,说明数据出错
一个典型的 CRC 实现(C 语言风格):
uint16_t crc16_modbus(uint8_t *data, uint16_t len) {
uint16_t crc = 0xFFFF;
for (uint16_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;
}
3.4 信号幅值监控
这个主要针对正弦波编码器(Sin/Cos)。正常信号幅值在 1 Vpp 左右。如果幅值下降,说明信号质量在恶化。
幅值监控怎么做?
- 实时采样 Sin 和 Cos 信号的峰值
- 计算幅值:A = √(Sin² + Cos²)
- 设定上下限:比如 0.8 Vpp ~ 1.2 Vpp
- 超出范围,触发报警
我见过一个案例:电机振动导致编码器内部光栅盘轻微位移,信号幅值从 1.0 Vpp 慢慢掉到 0.6 Vpp。如果没有幅值监控,系统会一直运行,直到位置完全丢失才报错。有了幅值监控,提前就预警了。
| 幅值范围 | 状态 | 建议动作 |
|---|---|---|
| 0.9 - 1.1 Vpp | 正常 | 无操作 |
| 0.7 - 0.9 Vpp | 预警 | 记录日志,提示维护 |
| < 0.7 Vpp 或 > 1.3 Vpp | 故障 | 立即停机 |
3.5 位置跳变检测
这个机制我特别喜欢。它不依赖通信协议,纯靠逻辑判断。
原理:机械系统有物理极限。电机一秒内不可能从 0 度转到 180 度,除非编码器信号出问题了。
具体实现:
- 记录上一次有效位置 P_old
- 读取当前原始位置 P_raw
- 计算差值 ΔP = |P_raw - P_old|
- 如果 ΔP > 设定阈值(比如 10 度),判定为跳变
阈值怎么设?要考虑最大物理速度和采样周期:
// 示例:最大速度 3000 rpm,采样周期 1 ms
// 每毫秒最大角度变化 = 3000 * 360 / 60 / 1000 = 18 度
// 阈值可以设为 20 度,留一点余量
#define MAX_SPEED_RPM 3000
#define SAMPLE_MS 1
#define JUMP_THRESHOLD ((MAX_SPEED_RPM * 360) / (60 * 1000 / SAMPLE_MS) + 2)
if (abs(P_raw - P_old) > JUMP_THRESHOLD) {
// 位置跳变,触发安全动作
safety_stop();
}
知识体系总览
这五种检测机制,各有各的适用场景。我画了一张图,帮你理清它们的关系: