3. 速度环与PWM的桥梁:速度环输出如何映射到PWM占空比

上一章我们把速度环的PID调明白了,输出了一个数值。但电机不认这个数值,它只认电压。那这个数值怎么变成电压?这就是我们今天要聊的——速度环输出到PWM占空比的映射关系。

说白了,就是一座桥。桥的一头是速度环算出来的控制量,另一头是功率管开关的时间比例。桥搭不好,环调得再漂亮也没用。

3.1 速度环输出到底是什么?

先搞清楚源头。速度环PID的输出,通常是一个无量纲的数值,范围取决于你的实现方式。我个人习惯把输出限幅在 [-1000, 1000] 之间,正负代表方向,绝对值代表力度。

核心认知:速度环输出 ≠ 占空比。它是一个控制量,需要经过映射才能变成PWM的脉宽值。

为什么不能直接用?因为PWM的寄存器通常要求整数,比如8位分辨率就是0~255,16位就是0~65535。速度环输出是浮点或定点数,直接塞进去会出问题。

3.2 映射的三种主流方式

我在项目里用过三种映射方式,各有各的适用场景。给你列个表,方便对比:

映射方式 计算公式 特点 适用场景
线性映射 占空比 = K × 速度环输出 简单直接,响应快 电源电压稳定、负载变化小的场合
非线性映射 占空比 = f(速度环输出) 可补偿死区、饱和区 低压启动、大惯量负载
归一化映射 占空比 = (输出 - 输出_min) / (输出_max - 输出_min) × PWM_max 通用性强,移植方便 多平台、多电压等级项目

你想想看,线性映射最常用,但坑也最多。我曾经在一个风机项目里直接用线性映射,结果低速时电机抖得像筛子——后来发现是死区没补偿。

3.3 完整的控制链路拆解

从速度环输出到PWM引脚,中间到底经历了什么?我画了一张图,把这条链路完整展示出来:

速度环 → PWM 控制链路 速度环输出 限幅处理 映射计算 死区补偿 PWM 寄存器写入 PWM 波形生成 功率管开关 电机运转 速度反馈(闭环) 💡 说明:虚线箭头表示反馈路径,实线箭头表示前向路径。 死区补偿在低速时尤其重要,我建议在映射计算后单独处理。

这条链路里,最容易出问题的就是映射计算和死区补偿这两个环节。我见过有人把映射系数设得太大,结果电机一启动就过流保护。嗯,这里要注意:映射系数不是越大越好,要结合母线电压和电机额定电压来算。

3.4 实战:线性映射的代码实现

给你看一段我常用的线性映射代码。这是基于STM32的HAL库写的,但逻辑可以移植到任何平台:

// 速度环输出到PWM占空比的线性映射
// speed_out: 速度环输出,范围 [-1000, 1000]
// pwm_period: PWM定时器的自动重装值(如 1000)
// 返回值: 占空比比较值,范围 [0, pwm_period]

uint16_t speed_to_pwm(int16_t speed_out, uint16_t pwm_period)
{
    // 1. 限幅
    if (speed_out > 1000) speed_out = 1000;
    if (speed_out < -1000) speed_out = -1000;
    
    // 2. 取绝对值
    uint16_t abs_out = (speed_out > 0) ? speed_out : (-speed_out);
    
    // 3. 线性映射:输出范围 0~1000 映射到 0~pwm_period
    uint16_t pwm_compare = (uint32_t)abs_out * pwm_period / 1000;
    
    // 4. 死区补偿(假设死区占空比为 5%)
    uint16_t dead_zone = pwm_period * 5 / 100;
    if (pwm_compare > 0 && pwm_compare < dead_zone) {
        pwm_compare = dead_zone;  // 跳过死区
    }
    
    // 5. 方向控制(由外部GPIO或另一路PWM处理)
    // direction = (speed_out > 0) ? FORWARD : REVERSE;
    
    return pwm_compare;
}

我的经验:死区补偿的阈值不要设成固定值。我建议在初始化时通过自检获取实际死区宽度,然后动态调整。不同批次MOS管的死区可能有差异,固定值容易翻车。

3.5 映射中的三个常见坑

做映射这件事,看着简单,踩坑的人不少。我总结三个最常见的:

  1. 分辨率不匹配:速度环输出分辨率高,PWM分辨率低,导致低速时占空比跳变。我曾经用8位PWM做伺服,低速时电机一卡一卡的,换成16位就好了。
  2. 非线性补偿缺失:PWM占空比和电机端电压不是严格的线性关系,尤其在轻载时。我建议在映射后加一个查表补偿。
  3. 方向切换时的零位处理:正反转切换时,占空比直接跳零再反向,电流冲击很大。我习惯加一个斜坡过渡,让占空比平滑过零。

警告:不要在中断服务函数里做复杂的映射计算!我曾经把浮点运算放在PWM中断里,结果中断执行时间超标,导致PWM波形抖动。映射计算建议放在速度环更新后的任务中完成,中断里只做寄存器赋值。

3.6 映射参数的调试方法

映射参数怎么调?我一般分三步走:

  • 第一步:开环标定。给电机一个固定的占空比,测实际转速。记录多组数据,画出占空比-转速曲线。这条线就是你的映射基准。
  • 第二步:死区测量。从0开始慢慢增加占空比,记录电机开始转动的临界点。这个点就是死区阈值。
  • 第三步:闭环验证。把标定好的映射参数放到速度环里,给一个目标转速,看实际响应是否平滑。

我记得有一次做无人机电调,开环标定做了整整一下午。结果发现不同电机的死区差了将近一倍——嗯,从那以后我再也不敢用固定死区值了。

3.7 小结一下

速度环输出到PWM占空比的映射,说白了就是把控制量翻译成功率管能听懂的语言。翻译得好不好,直接决定了整个控制系统的品质。

我个人觉得,映射这件事没有标准答案。线性映射简单够用,非线性映射性能更好。关键是你得理解自己的系统:电源电压多少?电机额定电压多少?PWM分辨率多少?把这些参数搞清楚,映射自然就顺了。