我们组今年电赛控制题选了国产高云FPGA,用PID做直流电机调速。代码下载后电机低速时抖动特别明显,高速反而还行。检查了PWM频率和死区设置,也看了编码器AB相反馈,感觉都正常。但就是低速稳不住,电机一顿一顿的。有经验的学长说是反馈信号没有同步到PWM周期里,导致PID计算用的速度值忽高忽低。想问问大家,这种问题到底是PWM死区配置的锅,还是编码器反馈采样时序不对?如果是时序问题,在RTL层面怎么改才能让速度环稳定?
2026年了,FPGA大赛电赛控制题用国产FPGA做PID电机调速,代码下载后电机抖动厉害,是PWM死区没配好还是编码器反馈时序有问题?
7 个回答

低速抖动先别赖死区,死区只影响换向瞬间那一下。你学长说的方向是对的,编码器计数没和PWM周期对齐,速度值就会在相邻周期里一会多计一会漏计,PID拿这个算肯定一顿一顿。做法就是速度窗口取PWM周期的整数倍,在PWM计数器归零那个沿锁存编码器计数值,这样每次算出来的速度才是同一个物理时刻的。你先把这个改了再看效果吧。

其实高速还行、低速抖,这个现象基本就把死区排除了。死区配置错了通常是换向瞬间电流尖峰或者转矩突变,不会只在低速出现。你现在的核心问题是速度采样窗口和PWM周期错位——编码器计数是连续累积的,但PID每个周期读到的增量可能横跨了两次PWM更新,导致转速计算出现周期性偏差。RTL层面的改法很直接:把速度计算使能信号和PWM的周期计数对齐,比如PWM用N分频计数产生周期脉冲,你就用这个脉冲同时去触发编码器锁存和PID计算。注意锁存要用寄存器打一拍,避免组合逻辑竞争。另外建议速度窗口至少覆盖4到8个PWM周期,窗口太短的话低速时每个窗口只有几个编码器脉冲,量化误差会放大抖动。你可以先用逻辑分析仪抓一下PWM更新时刻和编码器计数锁存时刻,看是不是差了一个周期左右,基本一眼就能确认。

这个问题我建议你先做个实验把嫌疑分开:把PID输出固定成一个常量,不闭环,只让电机开环转。如果开环低速还是抖,那问题在PWM或驱动板,跟编码器时序无关;如果开环很稳,闭环才抖,那基本就是反馈时序或PID参数的事。按你描述的现象,大概率是后者。高云的FPGA和Altera在PWM生成上没本质区别,但要注意你用的PWM模块是不是带死区插入的那种,有些IP在死区配置时会把PWM周期也顺带改了,导致你实际PWM频率跟寄存器里写的不一样。另外编码器反馈还有个常见坑:AB相如果是正交解码,采样时钟频率至少要高于编码器最高脉冲频率的4倍以上,否则会丢脉冲。低速时脉冲本来就少,丢一两个就相当于速度值跳变百分之几十,PID当然稳不住。你可以把编码器计数值和PID输出同时用ILA抓出来看,如果计数值在相邻两个PID周期里出现比如12、5、13这种跳变,基本就是采样窗口没对齐。至于改法,楼上说的锁存对齐是对的,我再补一个细节:锁存之后最好把速度值做一次低通滤波,比如一阶IIR,系数取0.2到0.3,这样即使有个别周期量化误差大,也不会直接激励PID产生力矩波动。你用的是高云哪个型号?不同系列的PLL和时钟资源布局不一样,如果方便的话说下型号,我可以帮你看看具体怎么把PWM周期脉冲引出来做同步。

个人感觉你学长说的八成是对的,但你先别急着改RTL,先确认一个事:你PID计算周期是多少?如果你PID是1kHz跑,PWM是20kHz,那中间差了20倍,编码器计数窗口如果刚好是PID周期的整数倍还好,不是的话每个PID周期里包含的PWM周期数不一样,速度自然跳。最简单的验证方法就是固定PWM占空比让电机开环转,然后用示波器量一下编码器脉冲间隔是不是均匀的——如果均匀,说明编码器和电机本身没问题,问题就在你数字逻辑里怎么采样和计算。RTL层面其实不用搞太复杂,很多国产FPGA的PWM模块都带一个周期中断标志,你把那个标志接到编码器计数的锁存使能上,再用一个计数器统计两个中断之间的编码器脉冲数,这样每次算出来的都是完整整数个PWM周期里的平均速度,低速时也基本不抖。至于死区,你只要确认换向的时候没有短路电流冲击就行,平时稳态运行死区根本不参与,别在这上面浪费时间了。

你这问题让我想起当年我们队用高云FPGA做循迹车,也是低速抖到怀疑人生,最后发现是编码器用的AB相,但解码模块里忘了做滤波,电机换向瞬间的毛刺被当成有效脉冲计进去了。低速时毛刺占比高,速度值就乱跳。你先用示波器看编码器A相在电机低速时的波形,如果边沿有抖动或者振铃,那就在RTL里加个简单的同步器和边沿检测,采样时钟用系统时钟,打两拍再去判断上升沿或下降沿,这样能滤掉大部分毛刺。另外你提到PWM频率和死区都检查了,但我想问一下你PWM频率是多少?如果低于10kHz,那低速时PWM的纹波本身就很大,电机转矩脉动会直接反映在转速上,这种情况就算反馈时序完美,抖动也压不下去。一般直流电机调速PWM至少20kHz以上,听不到声音而且纹波小。如果频率没问题,那回到时序:把你的速度环PID更新时刻和PWM周期起始时刻严格同步,具体做法是在PWM计数器归零时生成一个脉冲,用这个脉冲作为PID计算的触发,同时锁存编码器计数,这样PID的输出更新和PWM占空比更新天然对齐,不会出现PID算完但PWM还没来得及更新,下一轮又用旧值的情况。你可以先试试把PID周期改成PWM周期的整数倍,比如PWM 20kHz,PID跑2kHz,然后看是否改善,这算最省事的验证方法。最后问下你们PID参数是怎么调的?如果是手调的,低速抖动也可能是因为积分项饱和或者微分项放大噪声,可以先去掉微分只留PI试试。

这个问题在电赛圈子里太经典了,几乎每个队都会踩一次。我直接说结论:死区配置错的话高速也会出问题,不会只在低速抖,所以你先别管死区。编码器反馈时序不对才是低速抖的典型特征——低速时每个PWM周期里编码器脉冲数很少,比如只有几个,如果你采样窗口没对齐,相邻两次采样可能一次多计一次少计,算出来的速度就差很多,PID一看误差这么大就拼命调整,电机就抖了。RTL改法我给你一个具体的:假设PWM模块用计数器cnt从0到N-1循环,你在cnt==N-1这个条件时生成一个pwm_cycle_pulse,用这个脉冲去锁存编码器计数器的值,然后清空计数器重新开始计。PID模块的时钟就用这个pulse作为使能,每个pulse算一次速度更新一次占空比。这样速度窗口严格等于一个PWM周期,低速时虽然脉冲少,但至少每次算的都是同一个物理时段的平均值,不会跳变。如果觉得一个周期脉冲太少,可以每4个或8个pulse才触发一次PID,但窗口必须总是PWM周期整数倍。你先按这个改,大概率能解决。另外提醒一句,编码器计数器的清零和锁存要在同一个pulse沿处理,最好用非阻塞赋值写,避免出现锁存到清零后的值这种race condition。你们用的是高云哪个型号?如果是小封装的,可能时钟资源有限,但单纯做这个同步不需要PLL,直接用系统时钟分频就行。

别急着改代码,先把你PWM模块的datasheet翻出来看看死区寄存器是不是默认值。高云的某些PWM IP在没配置死区时会自动插入一个固定死区,而且这个死区值可能大得离谱,比如几十微秒,对20kHz的PWM来说占了快一半周期,低速时占空比本来就小,死区一叠加有效占空比就变得很不连续,电机自然一顿一顿的。你可以用示波器直接测电机两端波形,看低占空比时是不是出现一段全低电平的间隙,正常PWM应该是有窄脉冲的,如果出现明显空隙,那死区配置肯定有问题。不过死区只影响占空比精度,不会让速度反馈乱跳,所以如果波形正常,那还是编码器采样时序的事。给你一个排查顺序:先测PWM波形确认死区和占空比正确,再开环测编码器脉冲均匀性,最后才闭环调PID。别一上来就怀疑时序,先把硬件层面排干净。另外国产FPGA的PLL锁定时间比进口的长,你代码下载后如果没等PLL锁定就启动PID,初始几个周期里时钟不稳定也会导致抖动,检查一下你的复位逻辑是不是等locked信号拉高了才释放。
发表回答
登录后可在本页底部提交回答