4. 电机控制算法:PID控制原理、速度曲线规划(梯形/S形)、堵转检测与保护逻辑

各位同学,今天我们来聊聊窗帘电机最核心的部分——控制算法。说实话,这部分内容我当年刚入行时也觉得挺玄乎的,什么PID、什么曲线规划,听着就头大。但做久了你会发现,这些东西说白了就是让电机听话的技术。

我个人习惯把电机控制分成三个层次:怎么转得稳(PID)、怎么转得顺(曲线规划)、转不动怎么办(堵转保护)。咱们一个一个来拆解。

4.1 PID控制原理——让电机精准听话

先问大家一个问题:你让电机转1000转/分钟,它真的能稳稳停在1000转吗?

答案是不能。负载变化、电压波动、摩擦力……这些因素都会让实际转速偏离目标值。那怎么办?PID就是干这个的。

PID的全称是比例-积分-微分控制。我给大家一个最直观的理解:

  • P(比例):看到偏差就使劲拉回来。偏差越大,出力越大。但光有P,容易过头,产生震荡。
  • I(积分):把过去的偏差累积起来。如果一直有微小偏差,I会慢慢加大力度,直到消除静差。
  • D(微分):预测未来的趋势。如果偏差变化太快,D会提前刹车,防止超调。

我在项目中遇到过这样一个情况:用纯P控制窗帘电机,结果窗帘在目标位置来回晃悠,像在跳舞。后来加了D项,立马稳了。嗯,这就是微分的作用——提前感知变化趋势。

下面是一个典型的增量式PID实现,我在STM32上跑过无数次:

typedef struct {
    float Kp;
    float Ki;
    float Kd;
    float target;    // 目标值
    float last_err;  // 上一次误差
    float integral;  // 积分累积
} PID_Controller;

float PID_Update(PID_Controller *pid, float current) {
    float err = pid->target - current;
    
    // 比例项
    float p_out = pid->Kp * err;
    
    // 积分项(带限幅,防止积分饱和)
    pid->integral += err;
    if (pid->integral > INTEGRAL_LIMIT) pid->integral = INTEGRAL_LIMIT;
    if (pid->integral < -INTEGRAL_LIMIT) pid->integral = -INTEGRAL_LIMIT;
    float i_out = pid->Ki * pid->integral;
    
    // 微分项
    float d_out = pid->Kd * (err - pid->last_err);
    pid->last_err = err;
    
    return p_out + i_out + d_out;
}
调参小技巧:我个人习惯先调P,让系统能响应但不震荡;再加I消除静差;最后加D抑制超调。千万别一上来三个参数一起调,你会疯的。

4.2 速度曲线规划——梯形 vs S形

你想想看,如果电机一启动就是全速,一停就急刹车,会发生什么?

窗帘会剧烈抖动,机械结构会磨损,甚至电机堵转。这就是为什么我们需要速度曲线规划。

说白了,就是让电机平滑地加速、匀速、减速

4.2.1 梯形速度曲线

梯形曲线是最简单的方案。分为三个阶段:

  • 加速段:速度从0线性增加到目标速度
  • 匀速段:保持目标速度运行
  • 减速段:速度线性下降到0

它的优点是实现简单,计算量小。缺点嘛……加速度在拐点处突变,会有冲击感。

我曾经在一个低成本项目里用了梯形曲线,结果客户反馈窗帘启动时“咯噔”一下。嗯,这就是加速度突变带来的问题。

梯形曲线的核心代码其实很简单:

// 梯形速度规划
float TrapezoidalProfile(float time, float accel_time, float total_time, float max_speed) {
    float speed;
    
    if (time < accel_time) {
        // 加速阶段
        speed = (max_speed / accel_time) * time;
    } else if (time < total_time - accel_time) {
        // 匀速阶段
        speed = max_speed;
    } else {
        // 减速阶段
        speed = (max_speed / accel_time) * (total_time - time);
    }
    
    return speed;
}

4.2.2 S形速度曲线

S形曲线就高级一些了。它把加速和减速过程又分成了加加速、匀加速、减加速三个阶段。说白了,就是让加速度本身也平滑变化。

这样做的好处很明显:

  • 启动和停止完全没有冲击感
  • 机械寿命更长
  • 噪音更小

但代价是计算量大了不少。在低端MCU上跑S形曲线,你得小心别把CPU时间吃光了。

我给大家一个简化的S形曲线实现思路:

// S形速度规划(简化版)
float SCurveProfile(float t, float T, float Vmax) {
    // 使用正弦函数近似S形
    float normalized_t = t / T;  // 归一化时间 [0, 1]
    
    if (normalized_t < 0.5f) {
        // 前半段:加速
        return Vmax * (1.0f - cosf(M_PI * normalized_t)) / 2.0f;
    } else {
        // 后半段:减速
        return Vmax * (1.0f + cosf(M_PI * (normalized_t - 0.5f))) / 2.0f;
    }
}
我的建议:如果MCU性能足够(比如Cortex-M4以上),优先用S形曲线。如果资源紧张,梯形曲线加个简单的滤波也能凑合。

4.3 堵转检测与保护逻辑

这是窗帘电机开发中最容易被忽视,但也是最要命的部分。

你想想看,如果窗帘被卡住了,电机还在拼命转,会发生什么?轻则烧电机,重则烧驱动板,甚至引发火灾。

所以,堵转检测不是可选项,是必选项。

4.3.1 堵转检测方法

常用的方法有三种:

方法 原理 优点 缺点
电流检测法 堵转时电流会急剧上升 简单可靠 需要电流采样电路
速度检测法 给定速度与实际速度偏差过大 无需额外硬件 响应较慢
位置检测法 给定时间内位置没有变化 最直观 需要编码器或霍尔

我个人习惯电流检测+速度检测双重保险。为什么?因为单一方法都有盲区。比如电流检测法,如果堵转发生在轻载情况下,电流变化可能不明显。

4.3.2 保护逻辑实现

堵转保护不能简单地“检测到就停机”,那样太粗暴了。我建议这样设计:

  1. 初级保护:检测到堵转后,先尝试反向转动一小段距离,看能否解除卡滞
  2. 次级保护:如果反向无效,降低速度再试一次
  3. 终极保护:多次尝试失败后,彻底停机并上报故障码
曾经踩过的坑:我曾经把堵转阈值设得太灵敏,结果窗帘在正常运行时因为风阻稍微大一点就触发保护。后来加了滤波和延时判断,才解决了误报问题。记住:堵转检测一定要做去抖处理!

下面是一个实用的堵转检测代码框架:

#define STALL_CURRENT_THRESHOLD  500  // 电流阈值,单位mA
#define STALL_TIME_THRESHOLD     200  // 堵转持续时间,单位ms
#define RETRY_COUNT              3    // 最大重试次数

typedef enum {
    STALL_NONE,
    STALL_DETECTED,
    STALL_RECOVERING,
    STALL_FAILED
} StallState;

StallState Stall_Detect(float motor_current, float motor_speed, float target_speed) {
    static uint32_t stall_timer = 0;
    static uint8_t retry_count = 0;
    
    // 条件1:电流超标
    // 条件2:速度偏差过大(实际速度远低于目标速度)
    if ((motor_current > STALL_CURRENT_THRESHOLD) && 
        (motor_speed < target_speed * 0.3f)) {
        
        stall_timer++;
        if (stall_timer > STALL_TIME_THRESHOLD) {
            // 确认堵转
            return STALL_DETECTED;
        }
    } else {
        stall_timer = 0;
    }
    
    return STALL_NONE;
}

4.4 三者如何协同工作

讲到这里,你可能觉得这三个模块是独立的。其实不然,它们需要紧密配合:

  • 曲线规划生成目标速度 → PID控制器跟踪目标速度 → 堵转检测监控运行状态
  • 一旦堵转检测触发,立即暂停PID输出,执行保护逻辑
  • 保护逻辑执行完毕后,重新从曲线规划的当前点开始运行

嗯,这里要注意:堵转恢复后,不要直接从断点全速运行,而是应该从低速重新加速。否则容易再次触发堵转。

好了,这一章的内容就到这里。下一章我们会讲电机驱动的硬件设计,包括MOS管选型、电流采样电路、以及PCB布局的注意事项。到时候我会分享一些我在EMC测试中吃过的亏,保证干货满满。