第一章 电机控制算法:从PWM到智能调速

各位工程师朋友,今天我们来聊聊剃须刀最核心的部件——电机控制。说实话,一把剃须刀好不好用,九成功力都在电机控制算法上。我做了十几年嵌入式开发,踩过的坑比走过的路还多,今天就把这些经验分享给你。

1.1 直流电机PWM调速原理

先说说PWM调速。说白了,就是通过快速开关电源,让电机"感觉"到不同的电压。你想想看,如果给电机通100%的电,它就全速转;给50%的电,它就半速转。但问题来了——怎么给50%的电?

答案就是PWM。我们用一个高频开关信号,让电机在"通电"和"断电"之间快速切换。比如10kHz的频率,每秒钟开关一万次。占空比50%,就相当于电机吃到了50%的能量。

核心公式:

电机平均电压 = 电源电压 × 占空比

比如5V电源,占空比60%,电机实际感受到的就是3V

// 我常用的PWM初始化代码(STM32为例)
void Motor_PWM_Init(void) {
    TIM_HandleTypeDef htim2;
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 71;      // 72MHz / 72 = 1MHz
    htim2.Init.Period = 999;        // 1MHz / 1000 = 1kHz PWM频率
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    HAL_TIM_PWM_Init(&htim2);
    
    // 设置占空比50%
    __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 500);
}

我的经验:PWM频率别选太高也别太低。太低会有噪音(人耳能听到),太高会增加MOS管开关损耗。我个人习惯用10kHz-20kHz,既听不到噪音,效率也还行。

1.2 恒功率控制策略

剃须刀最怕什么?胡子一多,电机就转不动了。这时候如果只是简单调压,用户体验会很差。我做过一个项目,用户反馈说"剃到浓密处就卡住了"——这就是典型的功率不足。

恒功率控制,就是让电机不管负载怎么变,输出功率都保持稳定。怎么实现?看公式:

功率 = 电压 × 电流

我们实时检测电流,如果电流增大(说明负载变重了),就适当降低电压,让功率保持恒定。反过来,电流小了就升压。

// 恒功率控制伪代码
void Constant_Power_Control(void) {
    uint16_t target_power = 3000;  // 目标功率,单位mW
    uint16_t current = Get_Motor_Current();
    uint16_t voltage = Get_Motor_Voltage();
    uint16_t actual_power = voltage * current / 1000;
    
    if (actual_power < target_power) {
        // 功率不足,升压
        pwm_duty += 5;
        if (pwm_duty > 1000) pwm_duty = 1000;
    } else if (actual_power > target_power + 100) {
        // 功率过高,降压
        pwm_duty -= 5;
        if (pwm_duty < 200) pwm_duty = 200;  // 最低不低于20%
    }
}

注意:恒功率控制有个坑——电流采样要准。我曾经用了一个便宜的采样电阻,温度一高阻值就漂,导致控制完全乱套。后来换了低温漂电阻,问题才解决。

1.3 堵转检测与保护

堵转,就是电机被卡住转不动了。剃须刀里最常见的情况是:刀网里卡了一根粗胡子,或者刀头被胡茬堵死。如果不做保护,电机电流会飙升,轻则烧MOS管,重则冒烟。

怎么检测堵转?我总结了三个方法:

  • 电流检测法:正常运行时电流在200-500mA,堵转时瞬间飙到2A以上
  • 转速检测法:用霍尔传感器测转速,如果设定转速和实际转速偏差超过30%,判定堵转
  • 反电动势检测法:电机断电后测反电动势,堵转时反电动势几乎为零

我个人最常用的是电流检测法,简单可靠。但要注意——不能只看瞬时电流,要加一个时间窗口。比如连续50ms电流超过阈值,才判定为堵转。为什么?因为启动瞬间也会有电流尖峰,别误判了。

// 堵转检测实现
#define STALL_CURRENT_THRESHOLD  2000  // 2A
#define STALL_TIME_THRESHOLD     50    // 50ms

uint8_t Check_Stall(void) {
    static uint16_t stall_count = 0;
    uint16_t current = Get_Motor_Current();
    
    if (current > STALL_CURRENT_THRESHOLD) {
        stall_count++;
        if (stall_count > STALL_TIME_THRESHOLD) {
            return 1;  // 堵转!
        }
    } else {
        stall_count = 0;
    }
    return 0;
}

void Stall_Protection(void) {
    if (Check_Stall()) {
        Motor_Stop();           // 立即停止
        Delay_ms(1000);         // 等待1秒
        Motor_Start_LowPower(); // 以低功率重启
    }
}

避坑指南:我曾经遇到过一个问题——堵转保护太灵敏,用户胡子稍微浓密一点就触发保护,体验很差。后来我加了一个"软启动"机制:检测到堵转后,先尝试以20%功率运行0.5秒,如果电流降下来了就继续,否则才彻底停机。这样既保护了电机,又不影响正常使用。

1.4 多档位平滑切换

现在的剃须刀都有好几个档位:轻柔模式、标准模式、强力模式。但档位切换如果做得不好,用户体验会很糟糕。你想想看,正剃着胡子,突然电机从低速跳到高速——"嗡"的一声,吓一跳不说,还可能刮伤皮肤。

平滑切换的核心思想是:不要让占空比突变,而是让它慢慢爬升或下降。我一般用两种方法:

方法 原理 优点 缺点
线性渐变 每次增加/减少固定步长 实现简单 加速感不够自然
S曲线渐变 用正弦曲线或指数曲线控制变化率 手感顺滑 计算量稍大
// 线性渐变切换
void Smooth_Switch(uint16_t target_duty) {
    static uint16_t current_duty = 0;
    int16_t step = 5;  // 每次变化5个单位
    
    if (current_duty < target_duty) {
        current_duty += step;
        if (current_duty > target_duty) current_duty = target_duty;
    } else if (current_duty > target_duty) {
        current_duty -= step;
        if (current_duty < target_duty) current_duty = target_duty;
    }
    
    __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, current_duty);
    Delay_ms(10);  // 每10ms变化一次
}

我的建议:档位切换时间控制在300-500ms比较合适。太快了感觉突兀,太慢了用户会以为机器坏了。另外,切换过程中最好保持恒功率控制开启,这样即使负载变化,转速也能平稳过渡。

嗯,以上就是电机控制算法的核心内容。说白了,PWM是基础,恒功率是灵魂,堵转保护是安全底线,平滑切换是体验加分项。把这四点做好了,你的剃须刀电机控制就基本合格了。

下一章我们聊聊传感器融合——怎么让剃须刀"感知"到用户的胡须密度和皮肤状态。敬请期待。