☰
霍尔编码器电机速度环:增量式PID测速与参数整定实战
2026/9/29 9:42:21 网站建设 项目流程

1. 速度环到底在控什么:从需求到方案选型

电机控制里提到 PID 算法,很多人第一反应是调位置,但实际上速度环才是大多数场景里最先要啃下来的硬骨头。不管是霍尔编码器电机 PID 控制、PWM 控制电机做调速,还是做电流环、速度环、位置环三环串级,速度环都处在承上启下的位置。它拿到的输入是“我想要多快”,输出的是“该给电机多少电压或电流”,中间还要处理编码器测速、定时器采样、增量式 PID 算法程序代码实现这些细碎活儿。这篇内容就围绕速度环展开,适合已经知道 PID 大概公式、但一到真机就发现电机要么不转、要么疯转、要么转速飘忽不定的朋友。我会从方案选型一路写到代码落地、参数整定和排查记录,尽量把踩过的坑摊开讲。

速度环的目标很朴素:让电机实际转速跟上目标转速。听起来一句话,但做起来至少要解决四个问题。第一,转速怎么测,霍尔编码器输出的脉冲怎么变成可用的速度值;第二,PID 怎么算,是位置式还是增量式,积分项怎么限幅;第三,输出怎么给,PWM 占空比和电机端电压之间不是理想线性关系;第四,周期怎么定,速度环采样周期和电流环、位置环的节奏怎么配合。这四个问题里任何一个没处理好,光调 Kp、Ki 都救不回来。所以我一直觉得,速度环调试不是“调参玄学”,而是测速链路、控制周期和输出限幅三件事的共同结果。

方案选型上,速度环最常用的组合是“霍尔编码器 + 定时器编码器模式 + 增量式 PID + PWM”。为什么不是位置式 PID?因为速度环天然带积分属性,增量式输出的就是控制量的增量,天然抗积分饱和,也方便做输出限幅和手自动切换。为什么常用 PI 而不是 PID?因为速度信号里噪声比位置信号大得多,微分项会把编码器量化噪声放大成高频抖动,除非你给速度做了比较好的低通滤波,否则 D 项基本是负作用。至于三极管控制电机还是 MOS 驱动,那属于功率级选择,小功率场景用三极管也能跑,但要注意续流和发热,不然速度环调得再好,驱动级先饱和了也没意义。

注意:速度环不是独立存在的。如果你的电流环没有闭环,速度环输出直接给 PWM,那速度环实际上在替电流环干活,负载一变转速就会掉得厉害。先搞清楚你的系统里速度环输出给谁,再决定 PID 的限幅和积分策略。

1.1 为什么电流环、速度环、位置环要分开

三环分开的本质是时间尺度不一样。电流环响应最快,通常几十微秒到一百微秒就要算一次,因为它管的是电感电流,电流变化太快,周期长了根本来不及。速度环慢一些,一般 1ms 到 10ms 算一次,因为机械惯量比电磁惯量大得多,转速不会在几十微秒内突变。位置环更慢,常见 5ms 到 20ms,因为位置是速度的积分,再快也没有额外信息。三层环像三个不同节奏的齿轮,外环的输出作为内环的给定,内环快速跟踪外环指令。速度环的给定来自位置环,速度环的输出送给电流环作为电流指令。如果中间某一环周期乱掉,比如速度环和电流环共用一个中断但频率不匹配,外环就会给内环一个跳变的指令,内环拼命追,结果就是电流震荡、转速抖动。

从实现角度看,分开还有调试上的好处。你可以先把电流环闭起来,让电机在电流模式下能平滑输出力矩;再闭速度环,看转速阶跃响应;最后闭位置环。如果一上来三环全闭,出了问题根本不知道是哪一环。很多 DSP28379 电机控制代码例程里,三环的周期、限幅、滤波器都是分开配置的,这不是为了显得复杂,而是为了让每一环都有独立的调试入口。速度环在中间,往上要接受位置环的指令,往下要给电流环留出足够的动态余量。速度环输出限幅一般对应最大允许电流,而不是最大 PWM 占空比,这一点在带电流环的系统里尤其重要。

再补一个实际场景。霍尔编码器电机 PID 控制做调速时,如果只做速度单环,输出直接映射到 PWM,那么电机端电压会随电池电压波动而变化。同样的占空比,电池满电时转速高,电池快没电时转速低。速度环的积分项会慢慢把这个偏差补回来,但补的过程如果积分限幅太大,就会出现启动猛冲或者低速爬行。所以速度环的方案选型里,输出限幅、积分限幅、给定斜坡这三样最好一起考虑。给定斜坡不是 PID 本体,但能极大改善速度环的启动表现,尤其是目标转速从 0 跳到 3000rpm 这种阶跃工况。

1.2 速度环的输入输出与工程边界

速度环的输入一般有两个:目标转速和实际转速。目标转速可能来自上位机、遥控器、位置环输出或者固定值。实际转速来自编码器测速模块。输出通常是一个带符号的控制量,正数代表正转,负数代表反转。对于有刷直流电机,输出经过限幅后直接给 PWM 比较寄存器;对于无刷电机或带电流环的系统,输出作为 Iq 给定。边界条件要提前想清楚:最大转速多少、最大加速度多少、允许的转速误差是多少、堵转时怎么办、编码器线数和减速比是多少。这些参数不是写在 PID 代码里的,但会直接决定 PID 的输出范围。

我见过不少人写速度环时只定义了 PID 结构体,却没有定义“速度单位”。编码器读回来的是脉冲数,PID 算的是脉冲数误差,输出直接给 PWM。这样也能跑,但换个电机、换个减速比、换个采样周期,参数全部要重调。更好的做法是在测速环节就把脉冲数换算成 rpm 或者 rad/s,让 PID 处理有物理意义的量。比如 500 线编码器、四倍频、减速比 30、采样周期 1ms,读到的脉冲数是 N,那么转速 rpm = N × 60 / (500 × 4 × 30 × 0.001) = N × 1。这个例子里系数刚好是 1,但换个编码器就不一样了。把换算系数写成宏或者在线计算,代码可移植性会好很多。

工程边界还包括积分分离。目标转速和实际转速差得很大时,比如刚启动,积分项如果一路累加,很快会饱和到限幅值,等转速接近目标时积分项退不出来,就会超调。常见处理是误差大于某个阈值时只让 P 和 D 工作,误差小于阈值再引入 I。或者用变速积分,误差大时积分系数小,误差小时积分系数大。速度环里这两种方法都实用,具体用哪个看你的 MCU 资源。增量式 PID 本身对积分饱和有一定抵抗力,但如果输出限幅后继续累加增量,也会出现退饱和慢的问题,所以输出限幅和积分限幅最好同时做。

提示:速度环里“实际转速”的计算方向一定要和“输出正负”对应。编码器计数方向反了,速度环会变成正反馈,电机直接飞车。第一次上电建议用手转电机,观察速度符号和 PWM 输出方向是否一致。

2. 硬件与测速链路:霍尔编码器、定时器、PWM

速度环要跑起来,硬件链路比算法更值得先花时间。霍尔编码器输出 A、B 两相正交脉冲,有些还带 Z 相索引。A、B 相接到 MCU 的编码器接口或者外部中断,计时器对脉冲计数。定时器周期性触发速度环中断,读计数、算速度、跑 PID、更新 PWM。PWM 再经过驱动级控制电机。这条链路里,编码器信号质量、定时器计数模式、PWM 频率选择、驱动级响应速度都会影响最终效果。很多人调速度环时发现波形毛刺大,第一反应是 PID 参数不对,实际上可能是编码器信号没有滤波、地线没接好、PWM 频率太低导致电流纹波大。硬件问题不解决,算法层面再怎么补都是事倍功半。

霍尔编码器测速有两个基本方法:M 法和 T 法。M 法是在固定时间内数脉冲个数,适合高速;T 法是在固定脉冲数内测时间,适合低速。速度环周期固定的话,用 M 法最方便,定时器每个周期读一次计数差值,除以周期就是平均速度。低速时 M 法一个周期可能只数到几个脉冲,量化误差大,转速会一跳一跳。这时候可以延长测速周期,或者用 M/T 法,高速时用 M 法、低速时用 T 法。实际工程里,如果低速性能要求不高,M 法加一阶低通滤波就能用;如果要求低速平稳,就得认真做 T 法或者 M/T 法。霍尔编码器电机 PID 控制里,编码器线数、四倍频、减速比这三个参数一定要确认清楚,不然后面速度换算全错。

PWM 控制电机时,频率选择也有讲究。频率太低,电机电流纹波大,听觉上会有啸叫;频率太高,驱动级开关损耗增加,三极管方案可能发热严重。小功率有刷电机常用 15kHz 到 20kHz,避开人耳最敏感的范围。无刷电机 FOC 里常用 20kHz 甚至更高。占空比和电机端电压的关系在理想情况下是线性的,但实际有死区、管压降、电源内阻,所以速度环输出最好不要直接当占空比,而是经过一个标定或者限幅。三极管控制电机时,如果用的是 NPN 或者 PNP 做线性放大,功耗会很大,速度环输出还要考虑散热;如果是 PWM 开关驱动,续流二极管不能省,否则电机电感产生的反电动势会打坏管子。

2.1 霍尔编码器测速的两种算法与选择

M 法测速的本质是“定时数脉冲”。假设编码器四倍频后每转产生 2000 个脉冲,减速比 30,输出轴转一圈对应 60000 个脉冲。速度环周期 1ms,读到 60 个脉冲,那么输出轴转速就是 60 / 60000 / 0.001 = 1 转/秒,也就是 60rpm。这个计算里,脉冲数越少,量化误差越大。1ms 读到 1 个脉冲,转速就是 1rpm,读到 2 个脉冲就是 2rpm,分辨率只有 1rpm。如果目标转速是 5rpm,误差就很大。所以低速时要么延长采样周期,要么改用 T 法。T 法是在固定脉冲数内测时间,比如每来一个脉冲就记录定时器捕获值,两个脉冲之间的时间差就是 1/60000 转的时间,速度越低,时间差越大,分辨率反而越高。缺点是高速时捕获中断太频繁,CPU 扛不住。

实际项目里常用折中方案:速度环周期仍然固定,但测速模块内部判断。高速时用 M 法,低速时自动切 T 法。切换阈值根据编码器线数和允许的量化误差算。比如要求速度分辨率优于 1%,那么一个周期内至少数到 100 个脉冲。如果低于 100 个,就切 T 法。代码实现上,M 法用定时器编码器模式读 CNT,T 法用输入捕获或者外部中断读定时器值。DSP28379 的 eQEP 模块支持正交计数和单位定时器捕获,硬件上就能做 M/T 法,省了不少 CPU。霍尔编码器电机 PID 控制如果跑在 STM32 上,TIM 的编码器模式也很方便,但要注意计数溢出和方向判断。

一阶低通滤波在测速里几乎必加。编码器脉冲本身是数字量,M 法算出来的速度在每个周期会有 ±1 个脉冲的量化噪声,直接送进 PID,P 项会把这个噪声放大。低通滤波公式:y(k) = α × x(k) + (1 - α) × y(k-1),α 越小滤波越强,但相位滞后越大。速度环里 α 一般取 0.2 到 0.5,具体看你对动态响应的要求。如果用了增量式 PID,D 项本来就能抑制一部分超调,但也会放大噪声,所以滤波和 D 项要一起权衡。我的习惯是速度反馈先做低通,PID 里 D 项只给很小的值甚至不给,先保证不抖,再谈响应。

2.2 PWM 频率、死区与三极管/MOS 驱动注意点

PWM 频率的选择要结合电机电感和驱动级。有刷直流电机电感一般在几百微亨到几毫亨,PWM 频率 15kHz 时电流纹波可以接受。频率太低,电流断续,速度环输出和实际转速关系会变得非线性,PID 参数很难调。频率太高,三极管开关损耗和驱动电路功耗上升,小功率三极管可能烫得厉害。如果是 MOS 管驱动,频率可以高一些,但死区时间要设置合理。死区是为了防止上下桥臂直通,但死区会引入电压损失,占空比很小时尤其明显,速度环在低速段可能因此出现死区非线性。有刷电机单管驱动没有死区问题,但续流回路要设计好。

三极管控制电机和 MOS 控制电机的区别,在速度环调试里会体现在输出限幅和线性度上。三极管工作在开关状态时,饱和压降会吃掉一部分电源电压,速度环输出 100% 占空比时电机端电压也不是电源电压。如果速度环输出经过线性放大,三极管功耗等于管压降乘电流,小电流还行,大电流发热很严重。所以现在大部分速度环场景都用 PWM 开关驱动。PWM 输出给驱动芯片或者分立 MOS,电机两端电压平均值等于占空比乘电源电压,速度环的输出限幅就对应最大占空比。注意电机是感性负载,断电瞬间电流不能突变,续流二极管或者同步整流 MOS 必须要有,否则反电动势会击穿开关管。

注意:PWM 频率和速度环采样周期不要成整数倍关系,否则可能出现拍频现象,转速波形上会看到低频抖动。比如 PWM 20kHz、速度环 1kHz,正好 20 倍,某些占空比下每个速度环周期看到的电流纹波相位相同,反馈速度就会有周期性波动。把速度环周期设成 1.1ms 或者 PWM 设成 18kHz,往往能避开。

3. 增量式 PID 速度环的代码落地

代码实现是把前面所有设计串起来的地方。速度环用增量式 PID 还是位置式 PID,取决于你的输出对象和抗饱和需求。增量式 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)。它的优点是积分项隐含在累加里,不需要单独维护积分累加器,输出限幅时也不会有积分饱和退不出来的问题。缺点是如果输出限幅后还继续累加增量,需要做限幅处理,否则退饱和会变慢。速度环里通常输出对应 PWM 占空比或者电流给定,增量式很合适。

代码结构上,我会定义一个 PID 结构体,包含目标值、实际值、误差历史、输出、输出限幅、积分分离阈值等。速度环中断里做四件事:读编码器计数、计算实际转速、调用 PID 计算、更新 PWM。顺序不能乱,读计数后要立刻清零或者记录上一次值,否则会丢脉冲。计算转速时注意数据类型,脉冲数可能是 int16 或 int32,转速可能是 float 或 Q 格式。如果 MCU 没有浮点单元,建议用 Q 格式定点运算,比如 Q15,把系数放大 32768 倍,计算完再移位。DSP28379 有 FPU,直接用 float 没问题;STM32F1 没有 FPU,float 运算慢,速度环周期 1ms 可能勉强够,但中断里最好别做太多浮点。

参数整定是速度环的重头戏。我习惯先只给 P,让电机能转起来,观察转速阶跃响应。P 太小,转速上不去,静差大;P 太大,转速冲过头然后震荡。找到临界震荡的 P 值,取它的 60% 到 70% 作为初始 Kp。然后加 I,I 的作用是消除静差。I 太小,静差消得慢;I 太大,转速会围绕目标值来回摆。一般先给一个很小的 Ki,比如 Kp 的 1/100 到 1/10,看静差是否在可接受时间内消失。D 项最后加,速度环里 D 项很敏感,给 Kp 的 1/100 都可能有明显效果,也可能直接让电机叫起来。如果速度反馈噪声大,建议不加 D,用低通滤波代替。

3.1 位置式和增量式的取舍:为什么速度环更常用增量式

位置式 PID 的输出直接是控制量,u(k) = Kp×e(k) + Ki×∑e + Kd×[e(k)-e(k-1)]。它的积分项是一个累加器,如果输出限幅了但积分还在累加,就会积分饱和。速度环启动时误差很大,积分项很快冲到限幅值,等转速接近目标时,积分项要慢慢减下来,这个过程转速会超调甚至震荡。虽然可以用积分分离、抗饱和反馈解决,但代码量会多一些。增量式 PID 的输出是增量,积分作用通过累加自然实现,输出限幅时只要把 u(k) 限制住,下一次增量再算,不会出现积分项单独饱和的问题。所以速度环里增量式更省心。

不过增量式也有坑。如果输出限幅了,但 Δu 还在往同方向累加,下一次 u(k) 还是限幅值,看起来没问题,但一旦误差反向,Δu 需要先抵消掉之前被限幅吃掉的增量,退饱和会变慢。解决方法是输出限幅时同时限制增量,或者记录限幅标志,在限幅期间暂停积分累加。另外增量式 PID 的 Ki 和采样周期强相关,采样周期变了,同样的 Ki 积分效果完全不同。位置式也有这个问题,但增量式更明显,因为 Δu 里直接乘 Ki。所以速度环采样周期一旦确定,就不要随便改,改了要重新整定。

在实际代码里,我通常会把增量式 PID 写成宏或者内联函数,避免中断里函数调用开销。误差历史只需要三个变量,e0、e1、e2,每次计算后移位。输出限幅分两层:一层是最终输出限幅,对应 PWM 最大最小占空比;一层是增量限幅,防止单次变化太大。速度环输出给电流环时,最终限幅对应最大电流;输出给 PWM 时,限幅对应最大占空比。如果电机需要反转,输出范围是 -max 到 +max,PWM 需要能输出正反转,有刷电机用 H 桥,无刷电机用 SVPWM 的 Iq 给定。

3.2 结构体、定时器中断与完整 C 代码

下面给出一套速度环增量式 PID 的 C 代码,基于常见的 MCU 定时器中断场景,编码器用正交计数,PWM 用定时器比较输出。代码里假设已经有一个编码器读取函数和 PWM 设置函数,具体寄存器操作根据芯片替换。先定义 PID 结构体:

typedef struct { float target; // 目标转速,单位 rpm float actual; // 实际转速,单位 rpm float err0; // 当前误差 float err1; // 上一次误差 float err2; // 上上次误差 float kp; // 比例系数 float ki; // 积分系数 float kd; // 微分系数 float out; // 当前输出 float out_min; // 输出下限 float out_max; // 输出上限 float delta_max; // 单次增量限幅 float integral_sep; // 积分分离阈值 } PID_IncTypeDef;

初始化函数把误差历史和输出清零,设置限幅。注意 ki 的单位:如果采样周期是 T,那么代码里的 ki 实际等于 Kp × T / Ti,整定时直接调这个值即可。

void PID_Inc_Init(PID_IncTypeDef *pid, float kp, float ki, float kd, float out_min, float out_max) { pid->kp = kp; pid->ki = ki; pid->kd = kd; pid->target = 0.0f; pid->actual = 0.0f; pid->err0 = 0.0f; pid->err1 = 0.0f; pid->err2 = 0.0f; pid->out = 0.0f; pid->out_min = out_min; pid->out_max = out_max; pid->delta_max = (out_max - out_min) * 0.1f; pid->integral_sep = 50.0f; // 误差大于 50rpm 时暂停积分 }

增量式 PID 计算函数:

float PID_Inc_Calc(PID_IncTypeDef *pid, float target, float actual) { float delta_u; pid->target = target; pid->actual = actual; pid->err0 = pid->target - pid->actual; // 增量式 PID 公式 delta_u = pid->kp * (pid->err0 - pid->err1) + pid->ki * pid->err0 + pid->kd * (pid->err0 - 2.0f * pid->err1 + pid->err2); // 积分分离:误差大时削弱积分作用 if (pid->err0 > pid->integral_sep || pid->err0 < -pid->integral_sep) { delta_u = pid->kp * (pid->err0 - pid->err1) + pid->kd * (pid->err0 - 2.0f * pid->err1 + pid->err2); } // 增量限幅 if (delta_u > pid->delta_max) delta_u = pid->delta_max; if (delta_u < -pid->delta_max) delta_u = -pid->delta_max; pid->out += delta_u; // 输出限幅 if (pid->out > pid->out_max) pid->out = pid->out_max; if (pid->out < pid->out_min) pid->out = pid->out_min; // 更新误差历史 pid->err2 = pid->err1; pid->err1 = pid->err0; return pid->out; }

定时器中断里的调用流程,以 1ms 速度环周期为例:

void SpeedLoop_TIM_IRQHandler(void) { int16_t pulse; float actual_rpm; float pwm_out; // 1. 读取编码器计数并清零 pulse = Encoder_GetAndClear(); // 2. 计算实际转速,单位 rpm // 假设四倍频后每转 60000 个脉冲,1ms 周期 actual_rpm = (float)pulse * 60.0f / (60000.0f * 0.001f); // 3. 低速时用 T 法补充,这里简化为 M 法 // 4. 速度低通滤波 static float actual_filtered = 0.0f; actual_filtered = 0.3f * actual_rpm + 0.7f * actual_filtered; // 5. PID 计算 pwm_out = PID_Inc_Calc(&g_speed_pid, g_target_rpm, actual_filtered); // 6. 更新 PWM,注意死区和方向 PWM_SetDuty((int16_t)pwm_out); // 7. 清除中断标志 TIM_ClearITPendingBit(TIMx, TIM_IT_Update); }

编码器读取函数根据芯片不同,可能是读定时器 CNT 然后清零,也可能是读 eQEP 的位置计数器。注意 CNT 清零和读取之间可能有竞态,最好在读取时关闭中断,或者用硬件自动清零。

PWM 设置函数要注意有刷电机的正反转。如果输出正数,设置正转通道占空比,反转通道为零;输出负数则反过来。死区时间由硬件或软件插入,软件死区要注意在换向时先关断再开通。

3.3 参数整定:从 Kp 到 Ki 到 Kd 的顺序与实操记录

参数整定我用得最多的是“先 P 后 I 再 D”的顺序,但速度环里我会额外加一个步骤:先把目标转速设成 0,用手转电机,看实际转速反馈是否跟随手转方向。如果手正转时反馈是负数,说明编码器方向反了,必须先在代码里取反或者交换 AB 相。这个步骤不做,后面调参全是白费。确认方向后,给一个较低的目标转速,比如 500rpm,Kp 从 0 开始慢慢加。每加一次,观察电机是否起转、转速是否接近目标。Kp 太小,转速远低于目标;Kp 大到某一点,转速开始围绕目标上下摆动,这就是临界震荡。记下这个 Kp,取 0.6 倍作为初始值。

然后加 Ki。Ki 的作用是消除静差。比如 Kp 给好之后,目标 500rpm,实际只有 480rpm,静差 20rpm。慢慢增大 Ki,静差会逐渐缩小。Ki 太大,转速会在目标附近低频摆动,像呼吸一样,这就是积分震荡。找到静差刚好能在 0.5 秒内消除的 Ki 值,再稍微留一点余量。速度环里 Ki 通常比 Kp 小很多,因为速度环周期是毫秒级,积分累积很快。以我最近调的一个 500 线编码器、减速比 30 的电机为例,Kp 大约 8 到 12,Ki 大约 0.05 到 0.2,Kd 不用。这个参数不是通用的,换个电机、换个减速比、换个采样周期都要重调。

Kd 在速度环里我基本不用,除非速度反馈做得非常干净。如果一定要加,Kd 从 Kp 的 1/100 开始,加一点看转速超调是否减小。如果电机开始发出高频吱吱声,说明 D 项在放大噪声,立刻减掉。实测下来,速度环用 PI 加低通滤波,响应和抗扰已经够用。增量式 PID 的 D 项对噪声尤其敏感,因为公式里有 err0 - 2err1 + err2,相当于二阶差分,噪声会被放大四倍。所以我的建议是:速度环先不加 D,把 Kp、Ki 和滤波调好,实在需要再考虑。

提示:整定过程中每次只改一个参数,改完给一次阶跃指令,记录转速响应曲线。用串口或者 DAC 把目标转速和实际转速打出来,比盯着电机看靠谱得多。转速波形能看出超调量、调节时间、静差和震荡频率,这些信息直接告诉你该改哪个参数。

4. 实测调试与常见问题排查

速度环代码烧进去只是开始,真正的功夫在调试。调试阶段要准备几样东西:可调电源、示波器或者带波形显示的上位机、串口打印、一个能施加负载的装置。先空载跑,再带载跑。空载时转速容易冲高,带载时转速容易掉,两种工况下的 PID 表现可能差很多。如果空载调好了带载就震荡,说明 Kp 或 Ki 偏大,动态余量不够。如果带载调好了空载超调,说明积分偏强。速度环的鲁棒性来自合理的增益和足够的限幅,不是某一个参数万能。调试时还要注意电源电压变化,电池供电的系统电压从满电到欠压,同样占空比转速会差很多,速度环积分会补偿,但补偿速度受 Ki 限制。

波形观察是排查问题的核心手段。把目标转速和实际转速同时打到上位机,横轴时间,纵轴转速。正常的阶跃响应应该上升平滑、超调小、能回到目标值。如果实际转速上升后一直在目标上下等幅震荡,说明 Kp 太大或者 Ki 太大。如果上升很慢但最终能到目标,说明 Kp 太小。如果始终有静差,说明 Ki 太小或者积分被限幅了。如果转速波形上有高频毛刺,说明测速噪声大或者 PWM 干扰。如果转速周期性波动,频率和 PWM 频率成整数倍关系,可能是拍频。如果转速突然掉到零然后又恢复,可能是堵转保护或者驱动过热。这些波形特征比任何文字描述都直接。

负载测试也很重要。用手捏住电机输出轴,给一个固定转速指令,观察实际转速能否恢复。如果捏住后转速掉很多,松手后很久才恢复,说明积分作用弱或者输出限幅小。如果松手后转速冲很高,说明积分饱和了。堵转测试要小心,长时间堵转可能烧电机或者驱动。可以短暂堵转,看电流和转速反馈,确认保护逻辑是否生效。速度环输出限幅如果对应最大电流,堵转时输出会顶到限幅,电流达到最大值。如果没有电流采样,只能靠驱动芯片的保护或者温度保护。所以速度环调试时,最好配合电流采样或者至少加一个保险丝。

4.1 波形、噪声与滤波

速度环波形上的噪声来源主要有三个:编码器量化噪声、PWM 开关噪声、机械振动。编码器量化噪声来自 M 法测速的 ±1 脉冲误差,速度越低越明显。PWM 开关噪声通过电源和地线耦合到编码器信号线,表现为高频尖峰。机械振动来自电机本身的齿槽转矩或者联轴器偏心,表现为周期性波动。处理办法各不相同。编码器量化噪声用一阶低通或者滑动平均滤波;PWM 噪声用屏蔽线、磁珠、合理接地,或者在软件里避开 PWM 开关时刻采样;机械振动只能从机械结构上解决,软件滤波只能减轻。

一阶低通滤波是最常用的,实现简单,参数好调。公式前面给过,α 越小滤波越强,但相位滞后越大。速度环里相位滞后会降低相位裕度,可能引起震荡。所以滤波强度和 PID 增益要一起调。我的经验是先把滤波调到转速波形看不到明显毛刺,再调 PID。如果滤波太强导致响应变慢,可以适当提高 Kp 补偿,但不要为了提高响应把滤波去掉,否则电机噪声会进入 PID,听起来像电机在“咔咔”响。滑动平均滤波效果比一阶低通好,但需要存历史数据,占用 RAM 和 CPU。如果速度环周期 1ms,存 8 个点做滑动平均,计算量也不大,STM32F4 完全能承受。

还有一种情况是速度反馈方向正确但符号抖动,比如正转时反馈在 +10 和 -5 之间跳。这通常是编码器 A、B 相其中一相接触不良或者干扰导致计数方向误判。检查接线、上拉电阻、共地。如果编码器是集电极开路输出,一定要加上拉电阻,否则波形上升沿很慢,高速时丢脉冲。霍尔编码器电源最好单独稳压,不要和电机驱动共用一路,电机启停时电源波动会影响编码器输出。这些硬件细节看起来和 PID 无关,但速度环调不通时,十有八九是这里的问题。

4.2 常见问题速查表与避坑技巧

下面这张表是我在速度环调试中经常遇到的现象和对应排查方向,按可能性从高到低排列:

现象可能原因排查方法解决思路
电机不转,PWM 无输出目标转速为 0、PID 输出限幅为 0、驱动使能未开串口打印目标值、PID 输出值、驱动使能状态检查初始化顺序,先使能驱动再给目标
电机飞车,转速不可控编码器方向反了、速度反馈符号错、PID 正负号错手转电机看反馈符号,对比 PWM 输出方向交换编码器 AB 相或取反反馈,检查 PID 输出接法
转速围绕目标等幅震荡Kp 太大、Ki 太大、滤波太弱减小 Kp 或 Ki,增强滤波,看震荡频率先降 Kp 到临界值的 60%,再调 Ki
转速有静差,始终差一点Ki 太小、积分被限幅、输出限幅太小观察积分项是否顶到限幅,增大 Ki 或输出上限增大 Ki,检查输出限幅是否对应足够电压
启动超调大,冲过头再回来积分饱和、目标阶跃太猛、Kp 太大看启动时输出是否顶到限幅加积分分离、加目标斜坡、减小 Kp
低速时转速一跳一跳M 法量化误差大、采样周期太短看低速时每个周期脉冲数延长测速周期,改用 T 法或 M/T 法
高速时转速上不去输出限幅小、电源电压不够、PWM 频率太低看输出是否顶到限幅,测电源电压增大限幅,检查电源和驱动能力
转速波形有高频毛刺编码器干扰、PWM 噪声、地线问题示波器看编码器信号和电源纹波加滤波、屏蔽线、单点接地、上拉电阻
电机发出高频啸叫PWM 频率在人耳敏感区、D 项放大噪声改变 PWM 频率,去掉 D 项设 15kHz 以上,速度环用 PI
堵转后恢复慢积分饱和、输出限幅大、保护逻辑看堵转时输出和积分状态加积分限幅、堵转检测、快速退饱和

避坑技巧里,我最想强调的是“先开环再闭环”。速度环闭环之前,先让 PWM 开环输出,确认电机能正反转、转速随占空比变化、编码器读数正确。开环没问题了,再闭速度环。很多人跳过这一步,直接闭环,结果方向反了飞车,或者编码器没接好,调半天参数都是无用功。另一个技巧是“限幅从紧到松”。初始输出限幅给电源电压的 30%,确认方向和控制逻辑正确后再逐步放开。这样即使参数错了,电机也不会全速冲出去。还有“目标斜坡”,给目标转速加一个斜率限制,比如 1000rpm/s,启动会平顺很多,对机械结构也友好。

注意:速度环调试时不要长时间堵转。堵转时电流很大,电机和驱动都可能过热。如果必须测试堵转恢复,控制在 1 秒以内,并用手感受驱动温度。有条件的话,加上电流采样和过流保护,把速度环输出限幅和电流限幅联动起来。

5. 从速度环到多环串级:扩展思路与平台移植

速度环调通之后,往下可以接电流环,往上可以接位置环,形成完整的串级控制。速度环输出作为电流环的给定,电流环输出作为 PWM 占空比。这样速度环不用直接面对电源电压波动和电机参数变化,电流环会快速跟踪电流指令,速度环的负担小很多,动态性能也更好。位置环再往外,位置环输出作为速度环给定。三环周期一般是位置环 10ms、速度环 1ms、电流环 50μs。周期比例大概是 10 到 20 倍,外环慢内环快,保证内环能及时跟踪外环指令。如果周期比例不对,比如速度环和电流环都是 1ms,电流环来不及响应,速度环就会震荡。

做多环串级时,每一环的输出限幅都要对应下一环的合理输入范围。位置环输出限幅对应最大速度,速度环输出限幅对应最大电流,电流环输出限幅对应最大电压。这样任何一环饱和,下一环都知道自己该在什么范围内工作。速度环在中间,它的输出限幅尤其重要。如果速度环输出限幅对应最大电流,而电流环的电流采样量程只有一半,那速度环输出到一半就饱和了,实际最大电流只有一半。所以三环的限幅要统一单位,或者至少在代码注释里写清楚换算关系。否则调试时看波形,速度环输出顶到限幅,但电流环还没到最大,就会很困惑。

平台移植方面,DSP28379 电机控制代码里速度环通常跑在 CPU 定时器中断或者 ePWM 中断里,编码器用 eQEP,PWM 用 ePWM。eQEP 自带正交计数和单位定时器,测速很方便。速度环周期可以用 CPU Timer 配置,1ms 中断一次。代码结构上,把 PID 计算、编码器读取、PWM 更新分成独立模块,方便换平台。STM32 上用 TIM 编码器模式和 TIM 更新中断,思路一样,只是寄存器不同。不管是 DSP 还是单片机,速度环的核心逻辑都是:读计数、算速度、跑 PID、写 PWM。把这四步封装好,换芯片只需要改底层驱动。

最后分享一个我自己的习惯:速度环参数整定完之后,把 Kp、Ki、滤波系数、采样周期、编码器线数、减速比、输出限幅这些值全部写在一个配置结构体里,并加上注释说明测试条件。过几个月再回头看,或者换个人接手,能直接知道这组参数是在什么电机、什么电源、什么负载下调出来的。速度环的“手感”很依赖硬件,参数离开硬件环境就没有意义。记录清楚,比记住参数更重要。

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

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

立即咨询