3. 信号丢失的软件检测机制

硬件层面的防护做完了,信号还是有可能丢。为什么?线缆老化、接头松动、强电磁干扰,这些在工业现场太常见了。我见过一个项目,编码器线缆被叉车压过一次,外表看不出问题,但信号就是时有时无。

所以软件层面必须有一套检测机制。说白了,就是让控制器自己判断:「当前这个编码器信号,到底还能不能用?」

下面这五种方法,是我在实际项目中反复验证过的。它们各有侧重,组合使用效果最好。

核心思路: 软件检测不是替代硬件防护,而是给系统增加一道「自检」能力。信号丢失后,控制器要能快速识别并进入安全状态。

3.1 超时检测

这是最基础、最直接的方法。编码器在正常运行时,会持续输出脉冲。如果控制器在一段时间内没收到任何脉冲变化,那大概率是信号丢了。

具体怎么做?

  • 设定一个时间阈值,比如 10ms、50ms 或 100ms
  • 每次收到脉冲边沿,重置定时器
  • 定时器溢出,触发超时报警

阈值怎么选?我一般这样定:

应用场景 典型转速 建议超时时间 说明
低速输送线 < 100 rpm 100 - 200 ms 脉冲间隔长,阈值要放宽
通用伺服 1000 - 3000 rpm 10 - 50 ms 正常脉冲密集,超时响应快
高速主轴 > 10000 rpm 1 - 5 ms 必须用硬件定时器实现
我的经验: 超时检测一定要用硬件定时器,别用软件循环计数。我在一个项目里吃过亏——CPU 负载一高,软件定时就不准了,导致误报警。

3.2 奇偶校验

奇偶校验在串行编码器(如 SSI、BiSS、EnDat)里很常见。每帧数据后面跟一个校验位,用来检测单比特错误。

原理很简单:

  • 偶校验: 数据位 + 校验位中,1 的个数为偶数
  • 奇校验: 数据位 + 校验位中,1 的个数为奇数

接收端收到数据后,重新计算校验位。如果对不上,说明数据在传输过程中被篡改了。

但说实话,奇偶校验只能检测奇数个比特的错误。如果两个比特同时翻转,它发现不了。所以它通常作为第一道防线,配合其他方法使用。

注意: 奇偶校验不能用于增量式编码器(HTL/TTL 脉冲输出),它只适用于带数据帧的串行编码器。

3.3 CRC 校验

CRC 比奇偶校验强得多。它能检测出多位错误、突发错误,甚至某些模式下的所有错误。

我习惯用 CRC-16 或 CRC-32。具体流程:

  1. 发送端对数据帧计算 CRC 值,附加在帧尾
  2. 接收端对收到的数据(含 CRC)重新计算
  3. 如果计算结果不为 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;
}
避坑指南: 我曾经在 CRC 计算时忘了考虑字节序。编码器发的是大端,控制器默认小端,结果 CRC 永远对不上。排查了整整一天……后来我养成了一个习惯:先确认通信双方的字节序和 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 度,除非编码器信号出问题了。

具体实现:

  1. 记录上一次有效位置 P_old
  2. 读取当前原始位置 P_raw
  3. 计算差值 ΔP = |P_raw - P_old|
  4. 如果 Δ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();
}
注意: 位置跳变检测不能单独使用。如果编码器信号完全丢失(一直保持高电平或低电平),位置不会跳变,但系统已经失控了。必须配合超时检测一起用。

知识体系总览

这五种检测机制,各有各的适用场景。我画了一张图,帮你理清它们的关系:

信号丢失软件检测机制总览 信号丢失软件检测机制 编码器信号 超时检测 奇偶校验 CRC 校验 幅值监控 位置跳变检测 组合使用建议 增量式编码器:超时检测 + 位置跳变检测 | 串行编码器:CRC + 超时 + 幅值监控