霍尔编码器电机速度环:增量式PID测速与参数整定实战

发布时间:2026/9/29 9:42:30
霍尔编码器电机速度环:增量式PID测速与参数整定实战 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 法用定时器编码器模式读 CNTT 法用输入捕获或者外部中断读定时器值。DSP28379 的 eQEP 模块支持正交计数和单位定时器捕获硬件上就能做 M/T 法省了不少 CPU。霍尔编码器电机 PID 控制如果跑在 STM32 上TIM 的编码器模式也很方便但要注意计数溢出和方向判断。一阶低通滤波在测速里几乎必加。编码器脉冲本身是数字量M 法算出来的速度在每个周期会有 ±1 个脉冲的量化噪声直接送进 PIDP 项会把这个噪声放大。低通滤波公式y(k) α × x(k) (1 - α) × y(k-1)α 越小滤波越强但相位滞后越大。速度环里 α 一般取 0.2 到 0.5具体看你对动态响应的要求。如果用了增量式 PIDD 项本来就能抑制一部分超调但也会放大噪声所以滤波和 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 没有 FPUfloat 运算慢速度环周期 1ms 可能勉强够但中断里最好别做太多浮点。参数整定是速度环的重头戏。我习惯先只给 P让电机能转起来观察转速阶跃响应。P 太小转速上不去静差大P 太大转速冲过头然后震荡。找到临界震荡的 P 值取它的 60% 到 70% 作为初始 Kp。然后加 II 的作用是消除静差。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 到 maxPWM 需要能输出正反转有刷电机用 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 相。这个步骤不做后面调参全是白费。确认方向后给一个较低的目标转速比如 500rpmKp 从 0 开始慢慢加。每加一次观察电机是否起转、转速是否接近目标。Kp 太小转速远低于目标Kp 大到某一点转速开始围绕目标上下摆动这就是临界震荡。记下这个 Kp取 0.6 倍作为初始值。然后加 Ki。Ki 的作用是消除静差。比如 Kp 给好之后目标 500rpm实际只有 480rpm静差 20rpm。慢慢增大 Ki静差会逐渐缩小。Ki 太大转速会在目标附近低频摆动像呼吸一样这就是积分震荡。找到静差刚好能在 0.5 秒内消除的 Ki 值再稍微留一点余量。速度环里 Ki 通常比 Kp 小很多因为速度环周期是毫秒级积分累积很快。以我最近调的一个 500 线编码器、减速比 30 的电机为例Kp 大约 8 到 12Ki 大约 0.05 到 0.2Kd 不用。这个参数不是通用的换个电机、换个减速比、换个采样周期都要重调。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 中断里编码器用 eQEPPWM 用 ePWM。eQEP 自带正交计数和单位定时器测速很方便。速度环周期可以用 CPU Timer 配置1ms 中断一次。代码结构上把 PID 计算、编码器读取、PWM 更新分成独立模块方便换平台。STM32 上用 TIM 编码器模式和 TIM 更新中断思路一样只是寄存器不同。不管是 DSP 还是单片机速度环的核心逻辑都是读计数、算速度、跑 PID、写 PWM。把这四步封装好换芯片只需要改底层驱动。最后分享一个我自己的习惯速度环参数整定完之后把 Kp、Ki、滤波系数、采样周期、编码器线数、减速比、输出限幅这些值全部写在一个配置结构体里并加上注释说明测试条件。过几个月再回头看或者换个人接手能直接知道这组参数是在什么电机、什么电源、什么负载下调出来的。速度环的“手感”很依赖硬件参数离开硬件环境就没有意义。记录清楚比记住参数更重要。