谷动谷力

 找回密码
 立即注册
查看: 679|回复: 0
打印 上一主题 下一主题
收起左侧

详解FPGA实现PID控制算法

[复制链接]
跳转到指定楼层
楼主
发表于 2023-5-8 23:01:23 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
详解FPGA实现PID控制算法


一、简介

      相信大家对于PID控制算法都不陌生,平衡车就是靠它平衡起来的,还有飞控的平衡算法也是它,以及FOC中的闭环控制中也是用的它。它不仅简单,而且易于理解。那么本篇文章将简要介绍一下算法的原理,然后带大家使用FPGA来实现(C语言实现过程特别简单)。


二、PID算法

PID取自比例、积分、微分三个英文字母的首字母,意味着算法由这三部分组成。


1、P比例


运算过程为 期望值 减去 当前值 ,然后再乘上一个p系数,就得到了一个反馈值。比例的作用主要是为了让 期望值 与 当前值相等。


2、I积分


将误差值不断累加,然后再乘上一个I系数,就得到了一个反馈值。积分的作用主要是为了消去静态误差,但当前值接近 期望值的时候,这个时候,比例的作用就非常小了,可能会接近于0,而且相邻两次的误差值也近似为0,D微分也起不了多大作用,假如这时候系统外部的阻力和PD反馈值抵消了,这个时候就需要不断的累加这个误差值来使当前值等于期望值。


3、D微分


当前的误差值 减去 上一次运算的误差值,然后再乘上一个d系数,就得到了一个反馈值。微分的作用主要为了减少系统的震荡,在系统变化的方向上,施加一个反方向的反馈,使系统朝这个方向的变化得到抑制。
可以到,PID算法主要涉及到三种运算: 加法,减法和乘法。这三种运行在FPGA上也是很容易实现的。


三、FPGA实现


首先需要注意的是,PID的三个系数均为浮点数,为了便于实现,这里将浮点数扩大100倍,然后取整就可以了。然后将反馈的结果缩小100倍就可以了。


1、P比例实现


实现代码如下,只需要两个时钟周期即可完成。这里通过左移来实现缩小100操作,实际上是缩小了102.倍,不太会影响结果。为了和 I 积分 和 D 微分 运算周期数相同,这里打了一拍操作。//P -------------------------------------------------always@(posedge clk or negedge rst_n)begin   if( rst_n == 1'b0)       Kp_fb <= 1'b0;   else if( pid_en == 1'b1)       Kp_fb <= ( desired_value - current_value ) * Kp;   else       Kp_fb <= Kp_fb;end
always@(posedge clk or negedge rst_n)begin   if( rst_n == 1'b0)       Kp_fb_reduce <= 'd0;   else if( cal_delay_0 == 1'b1)       Kp_fb_reduce <= (Kp_fb >>> 7) + (Kp_fb >>> 9); // /102.4   else       Kp_fb_reduce <= Kp_fb_reduce;end
always@(posedge clk or negedge rst_n)begin   if( rst_n == 1'b0)       Kp_fb_reduce_d0 <= 'd0;   else if( cal_delay_1 == 1'b1)       Kp_fb_reduce_d0 <= Kp_fb_reduce;   else       Kp_fb_reduce_d0 <= Kp_fb_reduce;
end//--------------------------------------------------------------------
代码片段:可切换语言,无法单独设置文字格式。

2、I积分实现
实现代码如下,比P比例稍微辅助一点。这里考虑到了一个积分限幅的问题,如果积分值一直累加的话得,可能会导致系统稳定不下来,所以这里设置为3000
always@(posedge clk or negedge rst_n)begin   if( rst_n == 1'b0)       Ki_integral <= 'd0;   else if( pid_en == 1'b1)       if( Ki_integral > $signed('d3000) && ( desired_value - current_value ) > $signed('d0) )           Ki_integral <= Ki_integral;       else if( Ki_integral < $signed(-'d3000) && ( desired_value - current_value ) < $signed('d0) )           Ki_integral <= Ki_integral;       else           Ki_integral <= Ki_integral + ( desired_value - current_value );   else       Ki_integral <= Ki_integral;end
always@(posedge clk or negedge rst_n)begin   if( rst_n == 1'b0 )       Ki_fb <= 'd0;   else if( cal_delay_1 == 1'b1 )       Ki_fb <= Ki_integral * Ki;   else       Ki_fb <= Ki_fb;end
always@(posedge clk or negedge rst_n)begin   if( rst_n == 1'b0 )       Ki_fb_reduce <= 'd0;   else if( cal_delay_2 == 1'b1)       Ki_fb_reduce <= (Ki_fb >>> 7) + (Ki_fb >>> 9); // /102.4   else       Ki_fb_reduce <= Ki_fb_reduce;end
//-------------------------------------------------------------------
代码片段:可切换语言,无法单独设置文字格式。

3、D微分实现
D微分操作实现如下,按照公式来即可。//D    ---------------------------always@(posedge clk or negedge rst_n)begin   if( rst_n == 1'b0)       Kd_error <= 'd0;   else if( pid_en == 1'b1)       Kd_error <= ( desired_value - current_value );   else       Kd_error <= Kd_error;end
always@(posedge clk or negedge rst_n)begin   if( rst_n == 1'b0)       Kd_fb <= 'd0;   else if( cal_delay_0 == 1'b1)       Kd_fb <= (Kd_error - Kd_last_error) * Kd;   else       Kd_fb <= Kd_fb;end
always@(posedge clk or negedge rst_n)begin   if( rst_n == 1'b0)       Kd_last_error <= 'd0;   else if( cal_delay_0 == 1'b1)       Kd_last_error <= Kd_error;   else       Kd_last_error <= Kd_last_error;end
always@(posedge clk or negedge rst_n)begin   if( rst_n == 1'b0)       Kd_fb_reduce <= 'd0;   else if( cal_delay_1 == 1'b1)       Kd_fb_reduce <= (Kd_fb >>> 7) + (Kd_fb >>> 9); // /102.4   else       Kd_fb_reduce <= Kd_fb_reduce;end//--------------------------------
代码片段:可切换语言,无法单独设置文字格式。

四、仿真验证

测试代码如下,初始化当前值为500,然后根据期望值和PID输出的反馈值,来调节当前值。 always@(posedge clk or negedge rst_n) begin       if( rst_n == 1'b0)           current_value <= 'd500;       else if( pid_ack == 1'b1)           current_value <= current_value + out;       else           current_value <= current_value;   end
PID_Control PID_Control_i(   .clk            (   clk),   .rst_n          (   rst_n),
  .pid_en          (   1'b1),  .pid_ack         (   pid_ack),
   .desired_value  (   desired_value),   .current_value  (   current_value),
   .Kp             (   'd10),   .Ki             (   'd1),   .Kd             (   'd10),      .out            (   out));代码片段:可切换语言,无法单独设置文字格式。
仿真波形如下:

这个是设置了D为0的情况,可以看到系统的震荡。


+10
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-4-30 14:43 , Processed in 0.093923 second(s), 44 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表