电赛控制题现在越来越卷,FPGA做PID比单片机快但写起来真费劲。我打算用Zynq做平衡小车,PL端跑编码器采集和PWM输出,PS端跑PID控制。但看网上说Verilog写浮点PID很浪费资源,定点化又怕精度不够。想问一下各位拿过奖的大佬,电赛控制题里PID到底该放PS端还是PL端?定点PID的位数怎么选?有没有现成的模块结构可以参考?
2026年了,电子设计竞赛用FPGA做控制类题目,PID算法在Verilog里怎么实现才不卡时序?
6 个回答

先别急着写Verilog,我建议你把这个题拆成两个问题看:一是控制周期能不能满足,二是开发时间够不够。平衡小车这种典型二阶不稳定系统,控制周期一般做到1kHz到5kHz就够稳了,Zynq的PS端跑C语言PID,哪怕带个低通滤波和限幅,10kHz以内都很轻松,根本不构成瓶颈。所以我的主思路很简单:PL端只做编码器四倍频计数和PWM死区补偿,PID放PS端,用浮点算,代码半小时调完,剩下的时间全拿去调机械结构和参数。你担心的浮点浪费资源,在PS端压根不存在,那叫CPU。真要说卡时序,反而是PL端采集和PWM的时序约束要仔细做,比如编码器信号跨时钟域要打两拍,PWM更新要在计数器周期边界对齐。先把PS端PID跑通,再谈优化,别一上来就挑战自己。你用的Zynq具体是哪个型号?如果是7010,PS频率保守点跑333MHz也完全够用。

从工程取舍角度看,你这个问题其实是在「开发效率」和「极限性能」之间选边。电赛四天三夜,时间是最贵的资源。PS端PID用C写,调试时能printf打印误差和输出,波形看串口,出问题一眼定位;Verilog定点PID一旦跑飞,你只能看ILA抓信号,定位一个积分饱和的bug可能耗掉半天。所以我的建议是:除非你的控制周期要压到50微秒以内,否则别碰PL端PID。如果真到了必须PL实现的程度,定点位数别纠结Q15还是Q24,先看你的物理量范围。编码器速度误差假设最大±5000,用Q15表示小数部分精度是1/32768,足够让小车稳住了;Q24精度更高但乘法器位宽暴涨,反而拖慢时序。关键不是位数,是积分项的抗饱和:Verilog里积分累加器要做饱和截断,不然windup会让系统振荡,这个比浮点定点转换坑多了。另外,PID输出到PWM的占空比记得做死区处理,电机启动电压不够会抖。你打算用增量式PID还是位置式?这个选择会影响定点化的溢出风险,增量式好写但稳态误差得靠积分消,位置式对饱和处理要求高。

我拿过两次电赛控制题国一,说点掏心窝的话。你问PID放哪,本质上是在问「你想把时间花在调参上还是调时序上」。PS端跑PID,你调参时能实时改系数,小车倒了立刻看串口曲线分析是P大还是D小;PL端跑PID,你改一个Kp要重新综合布线,一次半小时,比赛最后一晚心态直接崩。所以我的铁律是:一切能软的不硬,PL只做非它不可的事——高速采集和PWM。Zynq的PS端有NEON协处理器,跑个3kHz的PID循环,CPU占用率不到5%,你甚至还能在PS端开个线程跑卡尔曼滤波融合IMU数据。但如果你非要PL端实现,我给你一个验证过的模块结构:误差输入用有符号数,控制周期由定时器中断同步,PID核心用三级流水线——第一级算P和I,第二级算D并做微分滤波,第三级做输出限幅和积分抗饱和,整条链路组合逻辑控制在40ns内,200MHz时钟下余量充足。位数选择上,误差和输出都用24位有符号数,中间乘法结果截断到24位,积分累加器用32位,最后输出前做饱和映射到PWM的16位占空比。这里最容易被忽视的是微分项:编码器量化噪声会被D放大,一定要加一阶低通滤波,系数用移位代替乘法,比如右移3位就是0.125的滤波系数。还有,积分抗饱和不能只在累加器端做,要在输出限幅后把实际输出反馈回来,用反计算法(back-calculation)清零积分误差,不然小车推一下就会冲出去。最后说句实在的,电赛评委看的是稳定性和调试效率,没人会拆开你的工程看PID写在哪。你现在的核心问题是PS端跑PID够不够快,对吧?如果控制周期能到2kHz,浮点完全没问题,我建议你直接开始写C代码,别再纠结Verilog了。你目前PS端的Linux跑起来了吗?如果没跑Bare-metal而是用了Linux,要注意实时性,建议关掉CPU调频,把PID线程绑核并设高优先级。

先跑通再优化。PS端C写PID,串口printf一打,波形一画,问题全在明面上;Verilog定点PID调一个积分饱和能让你通宵。电赛四天三夜,时间比那点浮点精度值钱多了。PL只干编码器计数和PWM,这是铁律。

说句可能不中听的,你纠结Verilog定点PID的位数,大概率是还没被比赛最后一晚的时序收敛折磨过。PS端跑PID,哪怕你用的是Zynq-7010,333MHz主频下跑个5kHz控制环,CPU占用率也就个位数,还有富余线程去跑卡尔曼滤波。PL端做PID,改一个Kp要重新综合布线,一次十几分钟,你调参调十次,一个下午没了。真到了必须PL实现的地步,比如控制周期要压到20微秒以内,那定点位数别贪多。编码器速度误差最大±5000,用Q15,小数精度1/32768,平衡小车绰绰有余;Q24精度高但乘法器位宽翻倍,组合逻辑路径变长,时序反而崩。最坑的不是位数,是积分抗饱和。Verilog里积分累加器不做饱和截断,windup一来,系统直接发散,你ILA抓波形看半天都找不着北。我见过有人用状态机做抗饱和,积分到限幅值就冻结累加,输出限幅单独做,这套结构比单纯截断稳得多。另外,微分项建议加个一阶低通滤波,不然编码器噪声放大,D项输出抖得跟筛子似的。你先告诉我你打算把控制周期做到多少,我再帮你判断PS端到底够不够——别一上来就挑战自己。

别把PID当核心,核心是时序。你想想,PL端输出PWM的占空比更新,和PS端PID计算结果的传输,这两者之间差了哪怕一个时钟周期,小车可能就抖一下。所以我的做法是,PS端PID算完,通过AXI-Lite写到PL端的寄存器,PL端在PWM周期边界统一锁存这个值,保证一个周期内占空比不变。Verilog那边只需要做个简单的寄存器同步,不用碰浮点。至于定点化,其实你换个思路:PS端用浮点算PID,输出结果转成16位有符号整数,PL端直接拿这个整数做PWM比较值。这样精度损失只在最后一步,中间全是浮点,调试也方便。PL端那几行Verilog,就是同步、锁存、比较,三十分钟写完。别把时间耗在定点算法上,那是研究生干的事,不是电赛干的事。你打算用AXI-Lite还是AXI-Stream传PID输出?这个选择会影响PL端代码结构,想清楚再动手。
发表回答
登录后可在本页底部提交回答