ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

直流减速电机PI闭环控制实战:从原理到参数整定

直流减速电机PI闭环控制实战:从原理到参数整定 1. 项目概述与控制方案选型P2阶段的任务说简单也简单就是把一台带编码器的直流减速电机从“给电就转”改成“说多少转就稳定在多少转”。我之前P1阶段一直用开环电压控制空载时还行一带负载转速马上掉一截电源电压从5V调到6V转速也会明显漂移跟同事联调时这个粗糙度根本拿不出手。所以P2的核心工作就是给速度环加上PI闭环控制这也是电机控制里最经典、最常用的闭环方式。这篇先记录方案选型、代码实现和调参踩坑给后面做类似项目的朋友一个可复用的参照。1.1 开环控制的三个典型痛点第一是负载扰动。P1阶段我给电机轴装了一个小型摩擦阻尼器空载时转速设定100rpm很稳可阻尼器一压上去转速直接掉到80rpm左右。开环情况下你根本不知道电机现在实际转多快自然也就没法补偿这个跌落。第二是电源波动。实验室用稳压电源还好一旦换到电池供电或者开关电源纹波比较大的场景供电电压稍微变化转速跟着变非常难搞。第三是电机个体差异即使是同一批电机绕组电阻、磁钢强度、轴承摩擦力都会有细微差别同一个PWM占空比在不同电机上产生的转速可能差出5rpm以上。所以纯粹靠“占空比对应转速”的开环思路在这个精度要求下已经走到头了。要做转速闭环就必须在电机轴上安装转速反馈器件把实际转速实时读回来和给定转速比较用偏差去修正PWM输出。1.2 为什么速度环用PI闭环就够很多初学者第一反应是上PID其实电机转速环绝大多数场景用PI就够了。比例项P按当前偏差大小给出修正量偏差越大修正越强但它有一个本质缺陷要产生足够的输出去抵消摩擦和负载就必须保留一个不为零的稳态偏差这就是所谓的静差。加大Kp可以减小静差但Kp过大会导致系统振荡甚至啸叫。积分项I把历史偏差累积起来只要偏差还存在积分就一直增长最终能把这个静差完全消除。反过来微分项D在速度环里的作用主要是提前抑制超调可它有一个很麻烦的副作用对编码器测速的高频量化噪声特别敏感信号稍微抖一抖D项输出就会剧烈跳动。这里放一张控制方式对比表方便直观选型控制方式能否消除稳态误差抗负载扰动能力调试难度对测速噪声敏感度纯P否一般低低PI能较强中低PID能强高高实际项目里只要不是对响应时间有极致要求速度环用PI闭环就够了。我这次的P2目标就是先把PI闭环控制电机转速跑通把稳态精度和抗扰能力做到可接受的范围所以没有引入D项。1.3 总体控制方案先说说整体链路STM32通过定时器输出20kHz的PWM给TB6612驱动模块驱动模块放大后送到直流减速电机电机尾轴上的霍尔编码器输出A、B两路正交信号接回STM32的编码器接口单片机里跑一个20ms周期的速度环PI控制把“目标转速-实际转速”的误差换算成PWM占空比闭环完成。之所以控制周期用20ms而不是常见的1ms主要是受编码器分辨率限制。我用的电机是13线霍尔编码器加30:1减速箱四倍频之后输出轴每转一圈是4×13×301560个计数。如果速度环跑1ms在300rpm时每个周期只有不到8个计数测速量化误差会大得离谱PI输出会抖成筛子。20ms周期时300rpm约有156个计数速度分辨率大约1.9rpm还在可接受范围内。2. PI控制原理与离散化处理PI控制的思路不复杂但真正落到单片机代码里很多细节需要想清楚。这一章把原理和离散化公式串一遍。2.1 比例项和积分项各自干了什么比例项对应“现在差多少”。假设当前实际转速是260rpm目标是300rpm误差是40rpm。如果Kp等于2比例项输出就是80%的占空比修正量。这个修正量方向是把转速往上拉误差越大出力越猛。比例项的问题在于当系统接近目标时误差变小输出也变小最后电机输出的扭矩恰好等于负载扭矩时系统就平衡了但此时的误差不是零而是某一个固定静差。积分项对应“之前欠了多少”。它把每个控制周期的误差乘以控制周期累加起来相当于一个持续累积的“历史欠账本”。如果系统长时间存在正误差积分就一直增长输出也会持续增加直到把转速顶到目标值。正是这个累积效应让PI闭环能够消除纯比例控制无法消除的静差。用开车类比比例项是你看到车身偏了就打方向盘积分项是发现长期跑偏后一直给方向盘一个持续的修正力直到路线完全归正。2.2 位置式PI与增量式PI怎么选离散化后PI控制器有两种常见写法。位置式直接计算当前应该输出的占空比u[k] Kp * e[k] Ki * Ts * sum_{j0}^{k} e[j]其中Ts是控制周期e是当前误差sum是历史误差累加。它的优点是直观输出就是PWM占空比方便做输出限幅和积分处理缺点是需要维护一个积分变量如果处理不好容易出现积分饱和。增量式计算的是相邻两次输出的变化量delta_u Kp * (e[k] - e[k-1]) Ki * Ts * e[k]实际输出用 u[k] u[k-1] delta_u。增量式的优点是输出变化是平滑叠加的即使误差突然跳变输出也不会立刻猛跳因为不需要保存历史积分和理论上不会出现积分溢出。缺点是不太好直接对输出限幅需要对u做钳位同时Ki为0时逻辑要小心。我这次选择的是位置式原因有两个第一PWM占空比的物理边界很明确位置式做限幅干净利落第二后面要做抗积分饱和位置式的积分变量可以直接干预调试起来更直观。2.3 采样周期和控制周期如何定采样周期指的是读取编码器计数的时基我这边用5ms定时中断做计数差采集控制周期是PI运算和PWM更新的周期设定为20ms相当于每4次采样执行一次PI计算。这样做的原因是编码器计数本身是离散脉冲采样太快反而导致“这次3个脉冲、下次5个脉冲”的剧烈抖动。选择控制周期还需要考虑系统响应和稳定性。速度环20ms对应50Hz更新率对于常规直流电机的转速响应带宽通常是几赫兹到十几赫兹来说足够。如果周期太长比如100ms以上系统对负载突变的反应会很迟钝转速跌落幅度变大恢复时间变长。如果周期太短比如1ms则编码器量化噪声占主导PI输出高频率抖动电机反而会发热和啸叫。所以周期不是越小越好要和传感器分辨率匹配。3. 硬件搭建与速度测量实现上一章把PI的公式讲清楚了但要闭环跑起来硬件接线和测速必须稳定。硬件不稳定参数再漂亮也是白搭。3.1 关键器件与接线我用的核心器件如下主控STM32F103C8T6最小系统板72MHz主频电机带霍尔编码器的直流减速电机减速比30:1编码器13线驱动TB6612FNG逻辑电源3.3V电机电源5V电源5V/3A稳压电源逻辑和电机电源共地调速接口TIM3_CH1输出PWMPSC0ARR3599PWM频率20kHz编码器接口TIM2_CH1和TIM2_CH2配置成正交编码器模式四倍频接线时最容易踩的坑是编码器A、B相的上拉电阻。霍尔编码器输出一般是开漏如果在STM32的GPIO配置里没使能内部上拉或者外部没加上拉A、B相会出现毛刺导致计数跳变速度反馈忽高忽低。我直接用了GPIO内部上拉实测没问题。还有一点电机电源和单片机逻辑电源一定要共地否则编码器脉冲的参考地不一致计数会乱。3.2 编码器倍频与测速原理正交编码器模式的倍频原理很简单A、B两路方波相位相差90°通过检测A、B的上升沿和下降沿组合一个完整的A方波周期内可以产生4个计数。我的是13线编码器经过四倍频后电机轴每转一圈是52个计数再经过减速比30:1输出轴每转一圈是1560个计数。速度计算方法用M法测频法rpm (delta_cnt / (控制周期 * 1圈计数)) * 60例如控制周期取0.02s一个周期内读到156个计数那么转速为raw_rpm 156 / (0.02 * 1560) * 60 ≈ 300rpm写成代码就是这样float rpm (float)delta_cnt * 60000.0f / (20.0f * 1560.0f);这里的60000是“秒转分钟”的换算系数20是控制周期毫秒数1560是输出轴每圈计数。对300rpm的目标转速20ms窗口大约有156个计数量化分辨率约1.9rpm低速时可以接受高速时精度还会更好。3.3 测速代码实现思路测速部分的代码核心在定时器中断里。我用TIM4做5ms时基中断每次中断读取TIM2的计数寄存器计算与上一次的差值然后把计数差保存到全局变量。每4次时基中断也就是20ms置一个控制标志位主循环里检测到这个标志后执行PI运算和PWM更新。代码骨架如下volatile uint16_t last_cnt 0; volatile uint16_t speed_cnt_delta 0; volatile uint8_t speed_control_flag 0; volatile uint8_t tick_5ms 0; void TIM4_IRQHandler(void) { if (TIM_GetITStatus(TIM4, TIM_IT_Update) ! RESET) { TIM_ClearITPendingBit(TIM4, TIM_IT_Update); uint16_t now_cnt TIM2-CNT; speed_cnt_delta (uint16_t)(now_cnt - last_cnt); last_cnt now_cnt; if (tick_5ms 4) { tick_5ms 0; speed_control_flag 1; } } }注意now_cnt - last_cnt要用无符号减法并且变量位宽一致这样即使计数器回绕也能得到正确的差值。编码器方向只在正转场景下工作如果要支持反转需要额外处理有符号计数后面扩展时会提到。3.4 电源和接线注意事项电机是感性负载启停瞬间电流变化很快如果电源滤波不足容易在逻辑电源上产生尖峰干扰轻则测速抖动重则单片机重启。我加了一个470uF电解电容并在电机电源端并联一个0.1uF瓷片电容大幅改善了干扰问题。别小看这两个电容很多时候转速反馈不稳定并不是算法问题而是电源噪声把编码器脉冲带偏了。4. PI控制器代码实现与关键细节测速稳定之后PI控制本身实现起来就不难了但有几个细节值得单独说。4.1 PI控制器数据结构和初始化我定义了一个结构体把PI参数和中间变量包起来方便后面做多速度环扩展或者串级控制时复用typedef struct { float Kp; float Ki; float Ts; float integral; float out_min; float out_max; float out; } PI_Controller;初始化时先设置一组偏保守的初始值Kp2.0Ki0.1Ts0.02输出上限80.0输出下限0.0跑通后再按第5章的流程整定为Kp2.8、Ki0.15。注意在把PI参数写死之前先通过串口printf把目标转速和实际转速打印出来确认测速方向正确否则你调参再久也是在跟一个错误的反馈对抗。4.2 位置式PI加抗积分饱和实现我直接共享实际用到的核心函数float PI_Update(PI_Controller *pi, float target, float actual) { float err target - actual; pi-integral err * pi-Ts; float out pi-Kp * err pi-Ki * pi-integral; if (out pi-out_max) { out pi-out_max; if (pi-Ki 0.0f) { pi-integral (pi-out_max - pi-Kp * err) / pi-Ki; } } else if (out pi-out_min) { out pi-out_min; if (pi-Ki 0.0f) { pi-integral (pi-out_min - pi-Kp * err) / pi-Ki; } } pi-out out; return out; }这里的抗积分饱和不是简单把积分变量钳位而是做积分退饱和。当输出达到上限时反算出在当前比例项下积分项应该等于多少才能让输出刚好贴在上限。这样一旦误差开始缩小积分项已经处于一个合理位置系统不会在饱和解除后还拖着一个巨大的积分值继续超调。4.3 PWM输出映射与方向控制PI控制器输出的是占空比百分比范围0到80。映射到STM32定时器的比较寄存器CCR时直接按比例换算uint16_t ccr (uint16_t)(pi_out * 35.99f); __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, ccr);因为ARR设的是3599100%占空比对应3599所以换算系数是3599/10035.99。这里没用3600是避免出现超出ARR的数值。如果后续需要反向调速可以在PWM占空比基础上增加一个方向引脚通过改变H桥逻辑电平控制旋转方向。4.4 启动阶段和给定变化处理PI闭环调试中很容易出现的现象是一给使能电机就猛转一下。原因是编码器计数寄存器未清零、积分变量里残留了上一轮的数据。我在初始化时专门调用了一次清零函数把PI结构体的integral、out以及last_cnt全部清掉并先把占空比设置为0再使能驱动。现在很多产品要求目标转速不能一下从0跳到300rpm而是按斜坡上升比如每20ms增加2rpm这样能大幅减小启动电流和超调。5. 参数整定实战与阶跃响应分析代码写好之后真正的重头戏是参数整定。这部分我踩了不少坑也总结出一套比较实用的流程。5.1 先把积分关掉找到比例项的边界整定第一步Ki设为0Kp从很小的值开始比如0.5目标转速给300rpm观察转速响应。如果转速上升太慢、稳态误差比较大就逐步增大Kp。每调一次用串口示波器记录目标转速、实际转速和占空比三条曲线。当Kp增大到大概5.5左右时我观察到空载转速开始出现持续振荡振幅大约15rpm频率大约2Hz。这就是临界振荡点记下这个Kp_crit。实际使用的Kp可以取临界值的40%~60%我取了3.0此时转速能稳定但稳态误差大约有8rpm负载压上后误差能到16rpm。这个结果验证了纯比例控制无法消除静差的结论。注意不要为了追求小静差把Kp往临界值死推否则温度一变、负载一变系统就直接振荡。5.2 逐步加积分消除稳态误差保持Kp3.0Ki从0.05开始往上加。加入积分后最直观的变化是稳态误差开始下降Ki0.1时稳态误差降到2rpm左右Ki0.2时稳态误差基本消失但阶跃启动时开始出现超调超调量大约12%继续调到Ki0.35时空载低频振荡明显周期大约0.6秒转速在目标值附近来回摆。我把这个过程整理成一张速查表KpKi阶跃响应表现结论0.50上升慢稳态误差30rpmP太小3.00上升可接受稳态误差8rpm纯P有静差5.50空载持续振荡约15rpm临界增益3.00.1稳态误差2rpm超调5%偏向保守3.00.2稳态误差约0超调12%可进一步观察3.00.35空载低频振荡周期约0.6sKi过大最终我把Kp定在2.8、Ki定在0.15。这个组合下300rpm阶跃的调整时间大约0.8秒超调约6%加载后转速跌落不到5rpm且能在1秒内恢复。对于这个项目的后续联调需求已经够用。5.3 阶跃响应实测记录调参完成后我做了几组阶跃记录。空载从0rpm直接给定300rpm时转速上升过程比较平滑前200ms基本保持线性上升随后进入微调阶段大约0.8秒后稳定在目标值附近稳态波动±2rpm以内这已经包含编码器量化误差的影响。带载状态下我在电机输出轴施加了一组摩擦负载转速跌落约4rpmPI在0.6秒内把它拉回目标值。这里要特别强调转速波动不等于控制精度差需要区分量化噪声和真实波动。20ms窗口有156个计数1个计数对应的速度是1.9rpm所以±2rpm的波动很可能只是量化误差不代表实际转速真的波动这么大。判断方法是看占空比曲线的平滑程度如果占空比也在高频抖动说明PI参数对噪声敏感如果占空比稳定只有实际转速读数有±1~2rpm的跳变那基本就是量化噪声。5.4 抗积分饱和的作用验证在加上抗积分饱和逻辑之前我从0rpm直接给到300rpm启动瞬间PWM占空比顶到80%上限但因为误差一直很大积分变量持续累积等到实际转速追上目标时积分值已经积得非常高输出还维持在上限附近导致实际转速冲到了接近380rpm然后才一点点回落。这个就是典型的积分饱和引起的大超调。加入积分退饱和逻辑后同样从0rpm给到300rpm超调降到20rpm左右整个过程占空比会在转速接近目标前提前回落不会再出现“油门踩死不放”的现象。所以如果你在调试中发现低增益下依然有大超调优先检查是不是启动了积分饱和而不是继续盲目降低Kp。6. 常见问题排查与调试实录调PI闭环的过程中真正花时间往往不是算法本身而是一个个莫名奇妙的现象。我把自己遇到和同事经常问的问题整理了一下。6.1 占空比已经顶到上限转速仍然上不去这种情况最常出现在把PI输出上限设得过低或者PWM频率设置错误。我调试初期把PWM比较值写错了一位导致实际输出只有20kHz的10%占空比电机当然跑不到目标。排查方法很笨但有效先把闭环摘掉手动给一个固定占空比比如50%看电机转速是否随电压正常变化。如果开环时转速正常再检查PI方向如果开环都不正常优先查PWM配置和电源。另外要检查编码器方向。如果A、B相接反了速度反馈是负数PI会把占空比一直加上去现象也是“输出饱和但转速不对”。我给编码器接线时统一约定A相接PA0、B相接PA1同时用正向转动标定计数增长方向避免这个问题。6.2 低速时转速波动明显偏大低速是M法测速的天然弱点。目标转速50rpm时20ms窗口只有大约26个计数一个计数误差就是1.9rpm相对波动率接近4%。如果想优化低速性能可以用M/T法测速或者把控制周期适当加长到50ms让每个窗口的计数多一些。也可以牺牲一点响应速度对速度反馈做一次截止频率很低的低通滤波。如果你只是想在现有硬件上快速改善低速抖动我更推荐先做一个速度斜坡让电机在低速下不要长时间保持零速和极低速之间的来回切换这样即使PI输出有微抖实际转速也不会明显抖动。6.3 电机运转时发出高频啸叫啸叫大概率出在PWM占空比快速变化上。速度环PI输出如果对测速噪声敏感占空比会以一个很高的频率上下抖动机械系统跟着产生可听噪声。解决办法一是给测速加滤波二是给PI输出加一阶低通三是确认PWM频率本身是否低于20kHz。我把PWM频率设到20kHz后啸叫明显减少因为大部分人的听觉上限已经覆盖不到这个频段。6.4 上电瞬间电机猛转一下这个多数是初始化顺序不对。正确流程是先配置GPIO和定时器把PWM占空比设为0再清零编码器计数器和PI状态最后才给驱动模块使能。如果先使能驱动再软件初始化PWM电机在使能瞬间可能以未知电平猛转一下。这个小细节在联调时很容易被忽略但客户或测试人员拿到样机时第一感觉就是“这个设备不安全”。6.5 常见问题速查表现象可能原因解决办法转速上不去占空比饱和编码器方向反、PWM配置错误、电源不足开环测试定位检查方向低速波动大编码器量化误差加滤波、M/T法、拉长测速窗口高频啸叫占空比高频抖动、PWM频率低测速滤波、输出滤波、PWM提到20kHz上电猛转初始化顺序错、积分残留先PWM置0再使能、清PI状态阶跃超调大积分饱和加入积分退饱和处理稳态误差一直不消除Ki过小或未加到积分检查PI计算周期和Ki数值7. 后续可以扩展的方向与个人心得P2阶段把PI闭环控制电机转速跑通之后我发现后面能做的事还有很多而且每一项都是顺着这条技术线自然延伸的。7.1 从单闭环到串级PI单速度环在负载突变时还是会有明显跌落虽然能恢复但响应不够“硬”。如果把电流环作为内环、速度环作为外环电流环的快速响应能顶住大部分负载扰动速度环只负责修正慢变量系统抗扰能力会提升一个档次。实现层面其实就是在PI_Update外面再包一层PI_Update内环周期可以更快比如2ms采一次电流PI输出作为电流环的目标电流环的输出再驱动PWM。硬件上需要加一个采样电阻和电流放大电路用STM32的ADC同步采样。7.2 前馈补偿和自适应PI在目标转速变化时可以提前根据电机反电动势估算一个基础占空比叠加到PI输出上。这样的话PI只需要处理残差调节负担小很多阶跃响应也会更快超调更小。反电动势估算并不复杂用电压方程近似占空比基值约等于目标转速乘以一个标定系数这个系数可以在开环阶段通过几个转速点标定出来。另外带载不同、目标转速不同最优PI参数往往不一样。以后可以在不同转速区间、不同负载条件下切参数或者用简单的模糊规则在线调整Ki让系统在全工况范围内都保持稳定。比如高速段适当降低Ki避免振荡低速段适当提高Ki消除静差切换时做一下缓变过渡防止参数突变引起转速跳动。7.3 做完P2之后的一点心得PI闭环控制看着很简单公式不过一行但真正做好需要把传感器、执行器、控制周期和参数整定串起来综合考虑。很多时候你以为是调参不对实际是测速不对你以为是要上高级控制算法实际先解决积分饱和和量化噪声就能满足需求。把这个P2阶段做完最大的收获不是写出了PI_Update函数而是建立了“从现象反推系统问题”的排查习惯这套思路在后续做任何闭环系统里都用得上。
返回列表