4、执行器与通信故障诊断:电机堵转检测、通信总线(I2C/SPI/CAN)故障诊断、心跳包与超时机制

各位工程师朋友,咱们接着聊。上一节我们把传感器那点事儿捋清楚了,这一节轮到执行器和通信总线了。说实话,这两块出问题的概率,比传感器还要高。电机堵转、总线卡死、丢包……我在项目里没少跟它们打交道。

4.1 电机堵转检测:别让电机“憋死”

电机堵转,说白了就是电机转不动了。比如输液泵的管路被夹住,或者手术机器人的关节卡到异物。这时候电机还在使劲儿,电流会飙升,线圈温度瞬间就上去了。嗯,轻则烧驱动,重则起火。

怎么检测?我个人习惯用两种方法配合:

  • 电流检测法:在电机供电回路串一个小阻值采样电阻,或者用霍尔电流传感器。正常运行时电流在一个范围内波动,堵转时电流会突然增大并保持在高位。
  • 速度反馈法:用编码器或者霍尔传感器测实际转速。你给PWM信号让它转,结果编码器读数纹丝不动——那基本就是堵了。

关键点:堵转检测不能只看瞬时值。电机启动瞬间电流也很大,容易误判。我一般会加一个“持续超阈值”的判断,比如电流超过额定值2倍且持续200ms以上,才判定为堵转。

下面是一个简单的堵转检测逻辑,用伪代码表示:

// 电机堵转检测伪代码
float current_threshold = 2.0 * rated_current;  // 2倍额定电流
int timeout_ms = 200;                           // 持续200ms

while(1) {
    float current = read_motor_current();
    if (current > current_threshold) {
        stall_counter++;
        if (stall_counter >= timeout_ms / sample_interval_ms) {
            enter_fault_state("MOTOR_STALL");
            stop_motor();
            break;
        }
    } else {
        stall_counter = 0;  // 电流恢复正常,清零计数器
    }
    delay(sample_interval_ms);
}

避坑指南:我曾经在一个项目中,采样电阻选得太小,导致ADC分辨率不够,堵转电流和正常电流区分不开。后来换了大一点的电阻,但要注意功率和散热。另外,电机驱动芯片(比如DRV8833)本身就有过流保护引脚,直接用起来也很方便。

4.2 通信总线故障诊断:I2C/SPI/CAN

通信总线出问题,比电机堵转更隐蔽。有时候设备跑着跑着突然不响应了,你查半天发现是总线上的某个从机把SCL线拉死了。我遇到过好几次,每次排查都像破案一样。

4.2.1 I2C总线故障

I2C是开漏结构,靠上拉电阻维持高电平。常见故障有:

  • SCL/SDA被拉死:某个从机异常,一直把总线拉低。这时候主设备发不出起始信号。
  • 地址冲突:两个从机地址一样,总线会乱掉。
  • 时钟拉伸异常:从机把SCL拉低太久,主设备超时。

诊断方法

  1. 先看波形。用示波器抓SCL和SDA,看有没有正常的起始条件(SCL高时SDA下降沿)。
  2. 如果没有起始条件,大概率是总线被拉死了。这时候逐个断开从机,看哪个断开后总线恢复。
  3. 软件上可以加一个“总线恢复”流程:连续发送9个SCL时钟,让卡死的从机释放总线。

注意:I2C总线上的上拉电阻值很关键。电阻太大,上升沿太慢,通信速率上不去;电阻太小,功耗大,而且可能驱动不了。我一般用4.7kΩ,400kHz速率下表现不错。

4.2.2 SPI总线故障

SPI是全双工同步通信,没有应答机制,所以故障更难发现。常见问题:

  • 极性/相位不匹配:主从机的CPOL和CPHA设置不一致,数据全错。
  • 片选信号异常:片选没拉低,或者多个从机片选同时有效,导致总线冲突。
  • MISO/MOSI短路:硬件焊接问题,数据互相干扰。

诊断方法

  1. 用示波器看SCK、MOSI、MISO和片选信号。重点看片选信号是否在传输前拉低、传输后拉高。
  2. 发送一个已知数据(比如0x55或0xAA),看回读数据是否一致。如果不一致,检查极性和相位。
  3. 我习惯在SPI通信中加一个“回环测试”:把MISO和MOSI短接,看发送的数据能不能正确收回来。能收回来,说明主设备没问题;收不回来,查主设备配置。

4.2.3 CAN总线故障

CAN总线在医疗设备里用得很多,因为它可靠、抗干扰强。但也不是不会出问题。

  • 物理层故障:CAN_H和CAN_L短路、对电源短路、对地短路,或者终端电阻缺失。
  • 位填充错误:连续5个相同电平后,CAN控制器会自动插入一个相反电平。如果总线干扰导致这个机制失效,就会报错。
  • 总线关闭:错误太多,CAN控制器进入Bus Off状态,不再参与通信。

诊断方法

  1. 用CAN分析仪看总线波形。正常差分信号应该是CAN_H 2.5V~3.5V,CAN_L 1.5V~2.5V。
  2. 检查终端电阻:在总线两端各有一个120Ω电阻。用万用表量CAN_H和CAN_L之间的电阻,正常应该是60Ω(两个120Ω并联)。
  3. 软件上读取CAN控制器的错误计数器(TEC和REC)。如果REC持续增长,说明总线干扰大;如果TEC增长,说明本节点发送有问题。

个人经验:有一次现场设备频繁掉线,查了半天发现是CAN总线走线太长,而且没有用双绞线。后来换成屏蔽双绞线,终端电阻也换成120Ω,问题就解决了。CAN总线对布线要求其实挺高的,别图省事。

4.3 心跳包与超时机制:保命用的

心跳包,说白了就是“我还活着”的信号。主设备定期给从设备发一个短报文,从设备收到后回复一个确认。如果主设备连续几次没收到回复,就认为从设备挂了,进入安全状态。

为什么需要心跳包?你想想看,通信总线偶尔丢一两个包很正常,但要是连续丢包,那肯定出问题了。心跳包就是用来检测这种“连续丢包”的。

设计要点

  • 心跳间隔:不能太短,否则占用总线带宽;也不能太长,否则故障发现不及时。我一般设100ms~500ms,看系统实时性要求。
  • 超时次数:连续丢3~5次才判定故障,避免误判。比如心跳间隔200ms,超时次数3次,那600ms没收到回复就报警。
  • 心跳内容:可以带一些状态信息,比如设备温度、错误计数等,一举两得。
// 心跳包超时检测伪代码
#define HEARTBEAT_INTERVAL_MS  200
#define TIMEOUT_COUNT          3

int missed_heartbeats = 0;

void heartbeat_timer_callback() {
    send_heartbeat_request();
    missed_heartbeats++;
    if (missed_heartbeats >= TIMEOUT_COUNT) {
        enter_safe_state();  // 比如停止电机、关闭阀门
        log_error("Device communication lost");
    }
}

void on_heartbeat_reply() {
    missed_heartbeats = 0;  // 收到回复,清零计数器
}

重要提醒:超时后的安全动作一定要慎重。比如输液泵,如果通信断了就直接停泵,可能造成回血。我建议设计成“保持当前状态+报警”,让操作人员来判断。除非是明确的安全风险(比如电机失控),才自动停机。

好了,这一节的内容就这些。电机堵转、总线故障、心跳超时——这三块是嵌入式医疗设备里最容易出问题的地方。下一节我们聊聊电源管理与故障安全,那又是另一番天地了。