☰
STM32F103上模糊自整定增量式PID电机调速实战
2026/10/17 15:09:30 网站建设 项目流程

简介:本资源面向STM32嵌入式初学者与电机控制方向开发者,提供一套基于STM32F103ZET6与编码器直流电机的模糊自整定增量式PID调速程序,用于解决传统增量式PID在速度控制中响应与超调难以兼顾的问题。代码沿用正点原子工程格式,分程序块编写并配有注释,便于对照学习与移植。压缩包共170个文件,约4.74MB,包含39个h头文件、38个c源文件,以及编译产生的o、d、crf等中间文件,另有uvprojx工程文件、hex烧录文件、map映射文件与bat批处理脚本,覆盖从源码到编译产物的完整工程结构。目前已有4281人学习下载。读者可从中获取模糊推理与增量式PID结合的完整实现思路、参数自整定逻辑、编码器测速与定时器配置方法,以及规范的工程组织方式,对算法优化与课程设计、毕业设计均有参考价值。

1. 电机调速里最容易被低估的一环:为什么固定参数 PID 会翻车

很多人第一次用 STM32F103 驱动编码电机做闭环调速时,都会经历同一个过程:调出一组看起来不错的 Kp、Ki、Kd,空载时转速稳得像钉在示波器上,一旦加上负载、换个电池电压、或者让电机从低速爬到高速,转速立刻开始抖、超调、甚至振荡。于是有人怀疑编码器分辨率不够,有人怀疑定时器配置有问题,有人干脆把 PID 输出限幅一压再压,结果响应慢得像蜗牛。

问题的根子往往不在硬件,而在「一组固定参数要覆盖整个工况」这件事本身就不成立。直流电机的传递函数随负载、温度、供电电压漂移,固定增益的 PID 只能在某个工作点附近表现良好。模糊自整定增量式 PID 要解决的,正是「让控制器自己根据误差和误差变化率实时微调参数」这件事。它把模糊推理和增量式 PID 缝在一起,用一套轻量的规则表在运行时修正 Kp、Ki、Kd,让 STM32F103 这种没有 FPU、主频只有 72MHz 的芯片也能跑得动。搞懂它为什么能 work,比抄一份能跑的代码重要得多。

2. 增量式 PID:为什么它比位置式更适合电机闭环

2.1 位置式与增量式的本质差别

位置式 PID 直接算出控制量的绝对值:

u(k) = Kp*e(k) + Ki*Σe(j) + Kd*(e(k)-e(k-1))

这个式子每一项都依赖历史误差的累加,积分项是一个不断增长的求和。在电机调速里,控制量最终映射到 PWM 占空比,而占空比是有物理边界的(0 到 ARR)。位置式一旦积分饱和,退出饱和需要时间,表现就是「冲过头再慢慢拉回来」。

增量式 PID 不算绝对值,只算这一拍相对上一拍要增加多少:

Δu(k) = Kp*(e(k)-e(k-1)) + Ki*e(k) + Kd*(e(k)-2e(k-1)+e(k-2)) u(k) = u(k-1) + Δu(k)

关键区别在于:积分项从「累加和」变成了「当前误差乘以 Ki」。历史累积被隐含在 u(k-1) 里,控制器天然带记忆,但不需要单独维护一个可能溢出的积分累加器。

2.2 增量式在嵌入式里的三个实际优势

第一,抗积分饱和更自然。因为输出是增量叠加,只要对 u(k) 做上下限钳位,饱和时增量自然被截断,不会像位置式那样在饱和期间继续「偷偷」累加积分项。

第二,切换无扰动。手动/自动切换、或者从开环切到闭环时,增量式只需要保证 u(k-1) 等于当前实际输出,就能平滑接管,不需要重新初始化积分器。

第三,数值范围可控。位置式的积分累加器在长时间运行后可能变得很大,定点运算下容易溢出;增量式每拍只处理最近三次误差,数值范围稳定,这对没有硬件浮点的 F103 很友好。

常见的实现思路是:把 u(k) 用 Q 格式定点数表示,比如 Q10 或 Q12,把浮点系数预先放大成整数,整个递推过程用 int32 完成,只在最后右移还原成 PWM 比较值。这样既避免了浮点开销,又保留了足够的精度。

2.3 增量式 PID 的代码骨架

// 增量式 PID 单步计算,输入误差序列,输出增量 // Kp/Ki/Kd 为 Q10 定点系数,e0/e1/e2 为当前、上一拍、上上拍误差 int32_t IncPID_Step(int32_t Kp, int32_t Ki, int32_t Kd, int32_t e0, int32_t e1, int32_t e2) { int32_t delta; // 三项分别计算,注意 Kd 项是二阶差分 delta = Kp * (e0 - e1); // 比例增量 delta += Ki * e0; // 积分增量 delta += Kd * (e0 - 2*e1 + e2); // 微分增量 return delta >> 10; // Q10 还原 }

这段代码里,e0 - e1是误差的一阶差分,对应比例作用的增量形式;e0 - 2*e1 + e2是二阶差分,对应微分作用。右移 10 位是因为系数用 Q10 表示,实际增益等于整数值除以 1024。参数说明:Kp 决定对误差变化的即时响应,Ki 决定消除稳态误差的速度,Kd 抑制超调但对噪声敏感。在电机调速里,编码器测速本身带量化噪声,Kd 通常给得很小,甚至先置零,靠模糊规则在需要时再引入。

3. 模糊自整定:规则表怎么在运行时改写 PID 参数

3.1 模糊控制器的输入输出定义

模糊自整定的核心是一张「误差 → 参数修正量」的映射表。输入通常取两个量:转速误差 e 和误差变化率 ec。输出是 Kp、Ki、Kd 三个参数的修正量 ΔKp、ΔKi、ΔKd。

每个输入先做模糊化:把连续的 e 和 ec 映射到若干模糊子集,常见的是 7 个等级——NB(负大)、NM(负中)、NS(负小)、ZO(零)、PS(正小)、PM(正中)、PB(正大)。隶属度函数一般用三角形,因为三角形计算简单,交点明确,适合在 MCU 上做定点查表。

模糊化的本质是把「误差很大」「误差在减小」这种语言描述,转成 0 到 1 之间的隶属度。比如误差是 -80 RPM,可能对 NB 的隶属度是 0.6,对 NM 的隶属度是 0.4。这一步在 F103 上通常用查表加线性插值实现,避免实时算三角函数或指数。

3.2 规则表的结构与推理方式

规则表是一个二维矩阵,行是 e 的模糊等级,列是 ec 的模糊等级,每个格子给出对应的输出模糊等级。以 ΔKp 为例,典型规则是:

e \ ecNBNMNSZOPSPMPB
NBPBPBPMPMPSZOZO
NMPBPBPMPSPSZONS
NSPMPMPMPSZONSNS
ZOPMPMPSZONSNMNM
PSPSPSZONSNSNMNM
PMPSZONSNMNMNMNB
PBZOZONMNMNMNBNB

这张表的逻辑是:当误差大且误差在朝同方向扩大时,需要强修正;当误差接近零时,修正要收敛,避免在目标附近来回震荡。ΔKi 和 ΔKd 各有自己的规则表,设计思路不同——ΔKi 通常在误差大时取小值防止积分饱和,误差小时取正值加快消除静差;ΔKd 则在误差变化剧烈时增大以抑制超调。

推理方式常用 Mamdani 或 Sugeno。Sugeno 更适合 MCU,因为输出是输入的线性组合或常数,去模糊化只需要加权平均,不需要计算输出隶属度函数的面积重心。

3.3 从模糊输出到 PID 参数的落地

去模糊化得到的是 ΔKp、ΔKi、ΔKd 的清晰值,然后叠加到基础参数上:

// 模糊推理得到修正量后,更新 PID 系数 // base_* 为离线整定的基础值,delta_* 为模糊输出 Kp = base_Kp + delta_Kp; Ki = base_Ki + delta_Ki; Kd = base_Kd + delta_Kd; // 参数限幅,防止模糊规则把参数推到不合理区间 if (Kp > KP_MAX) Kp = KP_MAX; if (Kp < KP_MIN) Kp = KP_MIN; // Ki、Kd 同理

这里有个容易被忽略的细节:模糊输出的修正量必须限幅。规则表设计得再合理,在极端工况下(比如电机堵转)也可能推出很大的修正量,如果不钳位,PID 参数会瞬间跑到发散区。常见的做法是给每个参数设一个合理的上下界,这个界来自离线整定时观察到的稳定范围。

另一个细节是模糊推理的周期。它不需要和 PID 计算同频。PID 可以每 1ms 跑一次,模糊自整定每 10ms 或 20ms 跑一次就够了,因为工况变化没那么快。这样能把模糊推理的 CPU 开销摊薄,F103 跑起来毫无压力。

4. 在 STM32F103 上落地:定时器、编码器与运算的配合

4.1 编码器测速与定时器分工

F103 的 TIM 资源要分三块用:一个高级定时器(TIM1 或 TIM8)出 PWM 驱动电机,一个通用定时器(TIM2 到 TIM5)的编码器模式接正交编码器,再一个定时器做周期中断触发 PID 计算。

编码器模式下的定时器会自动根据 A/B 相脉冲增减计数器,不需要 CPU 干预。测速的常见做法是「M 法」:固定周期 T 读取计数器差值,转速 = 差值 / (线数 × 减速比 × T)。在低速时 M 法分辨率差,可以切到「T 法」测脉冲间隔,但多数电机调速场景 M 法够用。

PID 计算放在定时中断里,周期 1ms 到 5ms。中断服务函数里只做三件事:读编码器差值算转速、跑增量式 PID、更新 PWM 比较寄存器。模糊自整定用一个软件计数器分频,比如每 10 次 PID 中断跑一次。

4.2 定点运算与 Q 格式的选择

F103 没有 FPU,浮点运算靠软件模拟,一次浮点乘加可能几十个周期。PID 和模糊推理如果全用 float,1ms 中断里可能跑不完。所以整个链路建议用定点。

Q 格式的选择要权衡精度和溢出。误差 e 的范围取决于转速量程,假设最高 3000 RPM,用 Q0 表示就是 0 到 3000,int16 够用。但 PID 系数通常小于 1,比如 Kp = 0.8,用 Q10 表示就是 819。三项乘积 Kp * (e0-e1) 最大可能是 819 × 6000 ≈ 5e6,int32 能扛住。右移 10 位后还原成控制量增量。

模糊推理里的隶属度也在 0 到 1 之间,同样用 Q10 或 Q8。规则表的输出等级可以预先映射成定点修正量,推理时只做加权平均,避免实时计算。

4.3 中断优先级与实时性

电机控制对实时性敏感,PID 中断的优先级要高于串口、I2C 这些通信外设。但也不能设成最高,否则会阻塞系统滴答。一般把 PID 中断放在中等偏上优先级,确保不会被长耗时中断打断。

中断服务函数要短。读编码器、算 PID、写 PWM 寄存器,这三步加起来应该控制在几微秒量级。模糊推理如果放在中断里,要确保最坏执行时间可预测——查表和定点乘加都是确定性的,不会像浮点除法那样有不确定延迟。

提示:调试时先用示波器看 PWM 占空比波形,再看转速响应。如果占空比在目标附近高频抖动,多半是 Kd 太大或测速噪声没滤;如果响应慢且有过冲,先调基础参数再开模糊自整定。

5. 避坑与排查:模糊 PID 调试中最容易踩的五个坑

5.1 现象:转速在目标值附近持续振荡,幅度不衰减

原因:Kd 项对编码器量化噪声敏感,微分作用被噪声放大。增量式 PID 的二阶差分e0 - 2e1 + e2在误差接近零时,噪声占主导,输出增量剧烈跳变。

解决:先对测速做一阶低通滤波,或者把 Kd 置零跑通比例积分,确认稳定后再逐步加 Kd。模糊规则里 ΔKd 的修正范围也要收窄,避免在误差小时引入过大微分。

5.2 现象:加负载后转速掉下去就回不来,稳态误差大

原因:Ki 太小,或者模糊规则在误差大时把 ΔKi 压得过低,导致积分作用长期不足。另一种可能是输出限幅把积分增量截断了,但 u(k-1) 没有相应补偿。

解决:检查 ΔKi 规则表,误差大时 Ki 可以小但不能为零。确认输出钳位逻辑:如果 u(k) 被限幅,应该把 u(k-1) 也钳到同一边界,否则下一拍增量会基于一个不存在的输出值计算。

5.3 现象:从低速切高速时超调严重,甚至触发过流保护

原因:模糊自整定周期太长,参数更新滞后于工况变化。或者 ΔKp 规则在误差大时给得过大,比例作用瞬间拉满。

解决:缩短模糊推理周期,或者让模糊推理和 PID 同频但只更新部分参数。检查 ΔKp 规则表在「误差大且误差变化率大」区域的输出,适当降低修正幅度。

5.4 现象:定点运算结果和浮点仿真对不上,实际响应差很多

原因:Q 格式选择不当导致中间结果溢出,或者右移时没有做舍入,累积误差。另一种常见情况是系数放大倍数不一致,Kp 用 Q10、Ki 用 Q8,混用后量纲错乱。

解决:统一所有系数的 Q 格式,中间乘积用 int64 暂存再截断。右移前加半个最低位做四舍五入。用固定输入序列在 PC 上跑浮点版本和定点版本对比,确认误差在可接受范围。

5.5 现象:电机低速时转速显示跳动大,闭环无法稳定

原因:M 法测速在低速时每周期脉冲数太少,量化误差大。比如 1ms 周期内只采到 2 个脉冲,差一个脉冲就是 50% 误差。

解决:低速段切换到 T 法测脉冲间隔,或者延长测速周期并在周期内做滑动平均。也可以降低 PWM 频率提高低速分辨率,但要注意电机噪声和发热。

6. 设计取舍:模糊自整定到底值不值得上

把模糊自整定加到增量式 PID 上,本质是用「规则表的先验知识」换「在线辨识的复杂度」。它不需要建立电机的精确数学模型,不需要递推最小二乘或者卡尔曼滤波那套在线辨识算法,只需要一张离线整定的规则表加定点查表,就能在 F103 这种资源受限的芯片上跑起来。这是它最大的工程价值。

但代价也很明确。规则表是人为设计的,它的覆盖范围和修正力度依赖调试经验。工况超出规则表覆盖的区域时,模糊推理可能给出不合理的修正量,反而不如固定参数稳定。所以参数限幅和规则表的边界设计,比规则表本身更重要。

另一个取舍是模糊推理的周期。周期越短,参数跟踪越快,但 CPU 开销越大,而且可能把测速噪声当成工况变化来响应。周期越长,越平滑,但滞后越明显。常见的折中是 PID 周期的 5 到 10 倍,具体要看电机的机械时间常数。

验证这套机制是否 work,最直接的方法是在不同供电电压、不同负载转矩下各跑一遍阶跃响应,记录超调量、调节时间、稳态误差,和固定参数 PID 对比。如果模糊自整定在宽工况下的综合表现明显更稳,那这张规则表就值了。如果只在某个工作点好,换个工况就崩,那多半是规则表设计有问题,而不是模糊本身不行。

我自己的习惯是:每次改完规则表,先在 PC 上用 Python 把浮点模型跑一遍,确认趋势对了,再移植到定点代码。移植后第一件事不是看转速,而是把 ΔKp、ΔKi、ΔKd 的实时值通过串口打出来,看它们在阶跃响应过程中是否按预期变化。参数轨迹对了,转速曲线一般不会差。从那以后我每次调模糊 PID,都强制先看参数轨迹再看转速,省了很多来回烧录的时间。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询