3. 基于电流检测的堵转算法
电流检测,说白了就是通过看电机吃了多少电,来判断它是不是卡住了。我最早接触这个思路是在做一款工业缝纫机驱动的时候——电机一堵转,电流瞬间飙升,比什么传感器都快。今天咱们就把这块掰开揉碎了讲清楚。
核心观点:堵转时反电动势消失,电机绕组近似短路,电流会急剧上升。检测这个电流变化,就是堵转检测最直接、最廉价的手段。
3.1 电流采样原理
电流采样,说白了就是怎么把电机线上的大电流,变成单片机ADC能读的小电压。常用的方案就三种:
| 方案 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 采样电阻 | 串联小阻值电阻,测其压降 | 成本低、响应快、精度高 | 有损耗、需隔离 |
| 霍尔电流传感器 | 利用霍尔效应测量磁场 | 隔离性好、无损耗 | 成本高、带宽有限 |
| 电流互感器 | 电磁感应原理 | 完全隔离、适合大电流 | 体积大、低频响应差 |
我个人习惯在低压直流电机上用采样电阻方案。便宜、直接,而且堵转检测对带宽要求不高,采样电阻完全够用。但要注意——电阻的功率要留够余量,我曾经在项目里选了个1W的采样电阻,结果堵转时电流一冲,电阻直接冒烟了。
采样电阻选型小技巧:阻值一般选1~10mΩ,功率按最大堵转电流的2倍余量来算。比如堵转电流10A,电阻5mΩ,功率就是10²×0.005=0.5W,选1W以上的才稳妥。
3.2 固定阈值法
这是最朴素的方法。设定一个电流阈值,比如额定电流的1.5倍,一旦采样值超过这个阈值,就判定为堵转。
// 固定阈值法伪代码
#define CURRENT_THRESHOLD 1.5f // 额定电流的1.5倍
uint8_t detect_stall_fixed(float current)
{
if (current > CURRENT_THRESHOLD) {
return 1; // 堵转
}
return 0; // 正常
}
简单吧?但实际用起来坑不少。我遇到过最典型的问题:电机启动瞬间电流也会冲高,固定阈值法很容易误报。你想想看,电机刚上电那会儿,电流可能冲到额定值的2~3倍,如果阈值设低了,一启动就报堵转;设高了,真堵转又检测不到。
避坑指南:固定阈值法必须配合延时判断。我曾经在一个项目中直接用了固定阈值,结果电机每次启动都报堵转,后来加了200ms的延时窗口才解决。但延时又带来了另一个问题——真堵转时响应变慢了。所以固定阈值法只适合对响应速度要求不高的场合。
3.3 滑动窗口平均法
为了解决固定阈值法容易受瞬时尖峰干扰的问题,滑动窗口平均法就派上用场了。它的思路很简单:取最近N个采样点的平均值,用这个平均值去跟阈值比较。
// 滑动窗口平均法实现
#define WINDOW_SIZE 10
float buffer[WINDOW_SIZE] = {0};
uint8_t index = 0;
float sum = 0.0f;
uint8_t detect_stall_sliding(float current)
{
// 更新滑动窗口
sum -= buffer[index];
buffer[index] = current;
sum += buffer[index];
index = (index + 1) % WINDOW_SIZE;
// 计算平均值
float avg = sum / WINDOW_SIZE;
// 判断堵转
if (avg > CURRENT_THRESHOLD) {
return 1;
}
return 0;
}
窗口大小怎么选?我一般建议取10~20个点。窗口太小,滤波效果不明显;窗口太大,响应变慢。嗯,这里要注意——滑动窗口平均法虽然能滤掉毛刺,但它对缓慢上升的电流变化反应迟钝。如果电机堵转后电流是慢慢爬升的,滑动窗口法可能会延迟检测。
经验值:采样频率1kHz时,窗口大小取10~20,对应10~20ms的检测延迟。这个延迟对大多数应用来说是可以接受的。
3.4 动态阈值法
动态阈值法,说白了就是让阈值跟着电机的运行状态自动调整。比如电机低速运行时,电流本来就大,阈值就应该高一些;高速轻载时,电流小,阈值就低一些。
我常用的动态阈值公式是这样的:
// 动态阈值法核心逻辑
float get_dynamic_threshold(float speed, float load)
{
// 基础阈值:额定电流的1.2倍
float base = 1.2f * RATED_CURRENT;
// 速度补偿:低速时提高阈值
float speed_factor = 1.0f + (1.0f - speed / MAX_SPEED) * 0.5f;
// 负载补偿:重载时提高阈值
float load_factor = 1.0f + load * 0.3f;
return base * speed_factor * load_factor;
}
这个方法我在做电动工具项目时用过。电钻在拧螺丝时,电流本来就大,如果还用固定阈值,稍微用力就报堵转。用了动态阈值后,误报率从30%降到了2%以下。但代价是——你需要知道当前的速度和负载信息,这增加了系统的复杂度。
三种方法对比:
- 固定阈值法:实现最简单,但容易误报,适合工况稳定的场合
- 滑动窗口平均法:能滤除尖峰干扰,但响应有延迟,适合电流波动大的场合
- 动态阈值法:自适应能力强,误报率最低,但需要额外传感器或算法支持
3.5 代码实现与仿真
下面我给出一个完整的C语言实现,把三种方法整合到一起,方便你对比测试。
#include <stdio.h>
#include <stdint.h>
#define RATED_CURRENT 1.0f
#define WINDOW_SIZE 10
// 固定阈值法
uint8_t stall_fixed(float current, float threshold)
{
return (current > threshold) ? 1 : 0;
}
// 滑动窗口平均法
typedef struct {
float buffer[WINDOW_SIZE];
uint8_t index;
float sum;
} SlidingWindow;
void sw_init(SlidingWindow *sw)
{
sw->index = 0;
sw->sum = 0.0f;
for (int i = 0; i < WINDOW_SIZE; i++) {
sw->buffer[i] = 0.0f;
}
}
uint8_t stall_sliding(SlidingWindow *sw, float current, float threshold)
{
sw->sum -= sw->buffer[sw->index];
sw->buffer[sw->index] = current;
sw->sum += sw->buffer[sw->index];
sw->index = (sw->index + 1) % WINDOW_SIZE;
float avg = sw->sum / WINDOW_SIZE;
return (avg > threshold) ? 1 : 0;
}
// 动态阈值法
float dynamic_threshold(float speed, float load)
{
float base = 1.2f * RATED_CURRENT;
float speed_factor = 1.0f + (1.0f - speed) * 0.5f;
float load_factor = 1.0f + load * 0.3f;
return base * speed_factor * load_factor;
}
// 仿真主函数
int main()
{
// 模拟电流数据:正常、尖峰、堵转
float test_data[] = {
0.8f, 0.9f, 1.0f, // 正常
2.5f, 0.9f, 0.8f, // 尖峰干扰
1.8f, 1.9f, 2.0f // 堵转
};
SlidingWindow sw;
sw_init(&sw);
printf("时间\t电流\t固定阈值\t滑动窗口\t动态阈值\n");
for (int i = 0; i < 9; i++) {
float cur = test_data[i];
float speed = 0.8f; // 假设速度80%
float load = 0.5f; // 假设负载50%
uint8_t f = stall_fixed(cur, 1.5f);
uint8_t s = stall_sliding(&sw, cur, 1.5f);
float dt = dynamic_threshold(speed, load);
uint8_t d = stall_fixed(cur, dt);
printf("t%d\t%.1f\t%d\t\t%d\t\t%d\n", i, cur, f, s, d);
}
return 0;
}
运行这段代码,你会发现:固定阈值法在t3时刻(电流尖峰2.5A)就误报了,而滑动窗口法因为取了平均,成功滤掉了这个尖峰。动态阈值法在堵转阶段(t6~t8)因为阈值自适应提高了,判断更准确。
从上面的知识体系图可以看出,三种方法各有适用场景。我个人建议:如果你刚开始做堵转检测,先从固定阈值法入手,跑通整个采样链路;然后根据实际测试数据,决定是否需要升级到滑动窗口或动态阈值。别一上来就搞复杂的,容易把自己绕进去。
重要提醒:仿真代码跑得再好,也替代不了实际硬件测试。我见过太多人在仿真环境里调得完美,一上硬件就各种问题——ADC噪声、电源纹波、温度漂移,这些在仿真里是看不到的。所以,仿真只是第一步,硬件调试才是真正的战场。