基于FPGA的PID控制器设计

这篇具有很好参考价值的文章主要介绍了基于FPGA的PID控制器设计。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 知识背景

PID控制应该算是应用非常广泛的控制算法了。常见的比如控制环境温度,控制无人机飞行高度速度等。PID我们将其分成三个参数,如下:
P-比例控制,基本作用就是控制对象以线性的方式增加,在一个常量比例下,动态输出,缺点是会产生一个稳态误差。
I-积分控制,基本作用是用来消除稳态误差,缺点是会产生超调现象
D-微分控制,基本作用是减弱超调现象,加大惯性响应速度。

PID控制系统原理框图
fpga pid,专题研究,fpga开发,FPGA PID,PID教程,PID仿真,Verilog PID

PID公式
fpga pid,专题研究,fpga开发,FPGA PID,PID教程,PID仿真,Verilog PID

总的来说,当得到系统的输出后,将输出经过比例,积分,微分三种运算方式再叠加到输入中,从而形成一个闭环控制系统。在真正的实践中,最难的是如何确定三个项的系数,这就需要大量的实验以及经验来确定了,通过不断的尝试和思考,就能选取合适的参数,从而做出一个优良的PID控制器。

2 系统框架

理论说得再多,不如亲自动手实践一下,我做了一个简单的PID控制模型,因为采用的是用PID控制PWM占空比,输出的PWM占空比和采集到的占空比基本不会存在误差,所以和真正的PID闭环控制还有一些差别。仅以此例说明如何用FPGA做一个简易的PID算法,然后可通过Modelsim仿真观察到调节占空比的曲线变化,最后在开发板上验证,用示波器测试输出的PWM占空比,与我们设置的目标占空比一致。假如我们要控制电机速度,有摩擦阻力以及速度采集误差,此时就需要我们对Kp,Ki,Kd进行调节,以达到最佳的控制效果。模型框图如下所示:
fpga pid,专题研究,fpga开发,FPGA PID,PID教程,PID仿真,Verilog PID

targe:目标值
actual:实际值

3 实验需求及目的

产生频率固定,占空比可通过按键进行调节的PWM信号。按下KEY1占空比加10%,按下KEY2占空比减10%,每个PWM周期进行一次PID计算

4 所需硬件

  1. ALOGIC_V4 FPGA开发板
  2. FPGA下载器
  3. 示波器

5 公式分析

前面我们列出了PID理论的公式,但是光看理论公式我们要用Verilog语言将其实现出来还是有点摸不着头脑,所以我们需要将公司稍做变化,转成方便用FPGA实现PID的公式:
fpga pid,专题研究,fpga开发,FPGA PID,PID教程,PID仿真,Verilog PID

Kp:比例项参数
Ki:积分项参数
Kd:微分项参数
error:误差,targe-actual
sum_error:error的总和
error-last_error:当前error减去上一次error

6 程序设计

程序框图如下:

fpga pid,专题研究,fpga开发,FPGA PID,PID教程,PID仿真,Verilog PID

key_xd:按键消抖模块,该模块直接调用我们开发板的消抖例程。
targe_gen:目标值生成模块,即生成想要的占空比数值。由于FPGA无法处理小数,所以为了方便处理将此数据扩大了100倍,假如设置的数值是980,那实际占空比就是9.8%。

module targe_gen(
	input	clk,
	input	rst_n,
	input	key_add,
	input	key_sub,
	output	reg	rst_n_out,
	output	reg	[15:0]	targe
	);
	reg		[7:0]	rst_cnt;
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			targe<=3500;
			rst_n_out<=0;
		end else if(key_add)begin
			targe<=targe+1000;
			rst_n_out<=0;
		end else if(key_sub)begin
			targe<=targe-1000;
			rst_n_out<=0;
		end else if(rst_cnt==100)begin
			rst_n_out	<=1;
		end
	end
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			rst_cnt<=0;
		else if(key_add||key_sub)
			rst_cnt<=0;
		else if(rst_n_out==0)
			rst_cnt<=rst_cnt+1;
		else
			rst_cnt<=0;
	end
endmodule

zkb_calc:占空比检测模块,计算实际输出的PWM占空比,即targe值。由于FPGA无法处理小数,所以为了方便处理将此数据扩大了100倍,假如设置的数值是980,那实际占空比就是9.8%。该模块需要用到除法,我们不能直接在代码里面用"/"来进行计算,而是需要调用除法器IPCORE来进行计算。

module zkb_calc(
	input				clk			,
	input				rst_n		,
	input				pwm_in		,//反馈信号
	output	reg	[15:0]	pwm_zkb		,//计算的PWM占空比
	output	reg			pwm_zkb_vld	 //PWM占空比有效标志
	);
	parameter	ST0			=4'd0;
	parameter	ST1			=4'd1;
	parameter	CALC_ST		=4'd2;
	parameter	RESULT_ST	=4'd3;
	parameter	time_out_num=500;//采样时间
	reg	[3:0]	curr_st;
	reg	[31:0]	pwm_hcnt;
	reg	[31:0]	pwm_hlcnt;
	reg	[31:0]	div_dividend;
	reg	[31:0]	div_divisor;
	reg			div_ce;
	reg	[31:0]	time_out_cnt;
	reg			pwm_in_ff1,pwm_in_ff2,pwm_in_ff3;
	wire[39:0]	quotient;
	reg			rdy;
	assign	pwm_in_rise=pwm_in_ff2&&(pwm_in_ff3==0);
	always@(posedge clk)pwm_in_ff1<=pwm_in;
	always@(posedge clk)pwm_in_ff2<=pwm_in_ff1;
	always@(posedge clk)pwm_in_ff3<=pwm_in_ff2;
	always@(posedge clk)rdy<=div_ce;
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			pwm_zkb		<=0;
			pwm_zkb_vld <=0;
		end else if(rdy)begin
			pwm_zkb		<=quotient[15:0];
			pwm_zkb_vld <=1;
		end else 
			pwm_zkb_vld<=0;
	end
			
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			curr_st	<=ST0;
			div_ce	<=0;
			div_dividend<=0;
			div_divisor<=0;
		end else case(curr_st)
			ST0:begin
				if(time_out_cnt==1)
					curr_st<=ST1;
				else;
			end
			ST1:begin
				if(time_out_cnt==1)
					curr_st<=CALC_ST;
				else;
			end
			CALC_ST:begin
				curr_st<=RESULT_ST;
				div_dividend<={pwm_hcnt,13'h0}+{pwm_hcnt,10'h0}+{pwm_hcnt,9'h0}+{pwm_hcnt,8'h0}+{pwm_hcnt,4'h0};//x10000
				div_divisor<=pwm_hlcnt;
				div_ce<=1;
			end
			RESULT_ST:begin
				div_ce<=0;
				curr_st<=ST0;
			end
			default:;
		endcase
	end
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			time_out_cnt<=0;
		else if(time_out_cnt==time_out_num-1)
			time_out_cnt<=0;
		else 
			time_out_cnt<=time_out_cnt+1;
	end
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			pwm_hcnt<=0;
		else if(curr_st==RESULT_ST)
			pwm_hcnt<=0;
		else if(curr_st==ST1&&pwm_in_ff3)
			pwm_hcnt<=pwm_hcnt+1;
		else;
	end
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			pwm_hlcnt<=0;
		else if(curr_st==ST0)
			pwm_hlcnt<=0;
		else if(curr_st==ST1)
			pwm_hlcnt<=pwm_hlcnt+1;
		else;
	end
	DIV U_DIV(
	.denom	({8'b0,div_divisor}),//被除数
	.numer	({8'b0,div_dividend}),//除数
	.quotient(quotient),
	.remain  ()
	);
endmodule

pid_ctrl:pid计算模块,按照上面的公式,需要用到加法和乘法,加法我们可直接在代码里面用"+"来进行计算,乘法就需要调用乘法器的IPCORE(由于误差是有正负之分,所以我们的乘法器IPCORE也需要设置成有符号的,这一点一定要注意,否则计算会出问题),最终计算出占空比数值,由于FPGA无法处理小数,所以Kp,Ki,Kd都扩大了100倍,假如Kp=10,真实值即为0.1。根据公式我们知道最终的PWM占空比数值扩大了10000倍。

module pid_ctrl(
	input				clk			,
	input				rst_n		,
	input		[15:0]	targe		,//x100
	input		[15:0]	actual		,//x100
	input				actual_vld	,
	output	reg	[31:0]	pwm_zkb		,	//x10000,因为targe,actual乘以100,Kp,Ki,Kd乘以100,所以结果放大了10000
	output	reg			pwm_zkb_vld
	);
	parameter		IDLE	=8'd0;
	parameter		STEP1	=8'd1;
	parameter		STEP2	=8'd2;
	parameter		STEP3	=8'd3;
	parameter		STEP4	=8'd4;
	parameter		STEP5	=8'd5;
	parameter		STEP6	=8'd6;
	parameter		Kp		=10;//x100;
	parameter		Ki		=10;//x100;
	parameter		Kd		=15;//x100;
	reg	[7:0]	curr_st;
	reg	[31:0]	sum_error;
	reg	[31:0]	last_error;
	reg	[31:0]	error	;
	reg	[31:0]	mul1_a,mul2_a,mul3_a;
	reg	[31:0]	mul1_b,mul2_b,mul3_b;
	reg			mul1_ce,mul2_ce,mul3_ce;
	wire[31:0]	mul1_result,mul2_result,mul3_result;
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			curr_st			<=IDLE;
			sum_error	<=0;
			last_error		<=0;
			error			<=0;
			pwm_zkb			<=0;
			mul1_a			<=0;
			mul1_b			<=0;
			mul1_ce			<=0;
			mul2_a			<=0;
			mul2_b			<=0;
			mul2_ce			<=0;
			mul3_a			<=0;
			mul3_b			<=0;
			mul3_ce			<=0;
			pwm_zkb_vld		<=0;
		end else case(curr_st)
			IDLE:begin
				pwm_zkb_vld<=0;
				if(actual_vld)begin
					curr_st<=STEP1;
				end else;
			end
			STEP1:begin
				last_error<=error;
				curr_st<=STEP2;
			end
			STEP2:begin
				error<=targe-actual;
				curr_st<=STEP3;
			end
			STEP3:begin
				sum_error<=sum_error+error;
				curr_st<=STEP4;
			end
			STEP4:begin
				mul1_a<=Kp;
				mul1_b<=error;
				mul1_ce<=1;
				mul2_a<=Ki;
				mul2_b<=sum_error;
				mul2_ce<=1;
				mul3_a<=Kd;
				mul3_b<=error-last_error;
				mul3_ce<=1;
				curr_st<=STEP5;
			end
			STEP5:curr_st<=STEP6;
			STEP6:begin
				mul1_ce<=0;
				mul2_ce<=0;
				mul3_ce<=0;
				pwm_zkb<=mul1_result+mul2_result+mul3_result;
				pwm_zkb_vld<=1;
				curr_st<=IDLE;
			end
			default;
		endcase
	end
	MUL_SIGN_32X32 U_MUL1(
	.clock		(clk		), // input clk
	.aclr		(~rst_n		),
	.dataa		(mul1_a		), // input [15 : 0] a
	.datab		(mul1_b		), // input [15 : 0] b
	.clken		(mul1_ce	), // input ce
	.result		(mul1_result) // output [31 : 0] p
	);
	MUL_SIGN_32X32 U_MUL2(
	.clock		(clk		), // input clk
	.aclr		(~rst_n		),
	.dataa		(mul2_a		), // input [15 : 0] a
	.datab		(mul2_b		), // input [15 : 0] b
	.clken		(mul2_ce	), // input ce
	.result		(mul2_result) // output [31 : 0] p
	);
	MUL_SIGN_32X32 U_MUL3(
	.clock		(clk		), // input clk
	.aclr		(~rst_n		),
	.dataa		(mul3_a		), // input [15 : 0] a
	.datab		(mul3_b		), // input [15 : 0] b
	.clken		(mul3_ce	), // input ce
	.result		(mul3_result) // output [31 : 0] p
	);
endmodule

pwm_drv:根据pid_ctrl模块计算出的占空比,输出PWM信号,PWM信号一分为二,一路通过FPGA管脚输出,可以用示波器观测到波形,另一路直接传给zkb_calc模块,这样就构成了一个闭环系统。该模块需要用到乘法和除法计算,需要调用相应的IPCORE。

module pwm_drv(
	input	clk,
	input	rst_n,
	input	[31:0]	pwm_zkb,//x10000
	input			pwm_zkb_vld,
	output	reg	pwm
	);
	parameter	period_num=500;//FREQ 10K,频率越大,可调占空比精度越低,实测如果频率是100K,占空比只能精确到个位,频率是10K,可确到小数点后1位。
	reg	[19:0]	period_cnt;
	reg	[31:0]	hcnt;
	reg	[35:0]	div_dividend;
	reg	[31:0]	div_divisor;
	reg			div_ce;
	wire[31:0]	quotient;
	reg			rdy;
	reg	[31:0]	mul_a,mul_b;
	reg			mul_ce;
	wire[63:0]	mul_result;
	reg	[3:0]	curr_st;
	always@(posedge clk)rdy<=div_ce;
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			hcnt<=0;
		else if(rdy)
			hcnt<=quotient[31:0];
		else;
	end
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			period_cnt<=0;
		else if(period_cnt==period_num-1)
			period_cnt<=0;
		else
			period_cnt<=period_cnt+1;
	end
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			curr_st<=0;
			mul_a<=0;
			mul_b<=0;
			mul_ce<=0;
			div_ce<=0;
			div_dividend<=0;
			div_divisor<=0;
		end else case(curr_st)
			0:begin
				div_ce<=0;
				if(pwm_zkb_vld)
					curr_st<=1;
				else 
					;
			end
			1:begin
				mul_a<=period_num;
				mul_b<=pwm_zkb;
				mul_ce<=1;
				curr_st<=2;
			end
			2:begin
				mul_ce<=0;
				curr_st<=3;
			end
			3:begin
				div_dividend<=mul_result[63:0];
				div_divisor<=1000000;//占空比扩大100倍,360就是3.6%,0.036,此处引起误差
				div_ce<=1;
				curr_st<=0;
			end
			default:;
		endcase
	end

	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			pwm<=0;
		else if(period_cnt<hcnt[15:0])
			pwm<=1;
		else
			pwm<=0;
	end
	MUL_UNSIGN_32X32 U_MUL(
	.clock	(clk		), // input clk
	.aclr	(~rst_n		),
	.dataa	(mul_a		), // input [15 : 0] a
	.datab	(mul_b		), // input [15 : 0] b
	.clken	(mul_ce	), // input ce
	.result	(mul_result) // output [31 : 0] p
	);
	DIV U_DIV(
	.denom	({8'b0,div_divisor}),
	.numer	({4'b0,div_dividend[35:0]}),
	.quotient(quotient),
	.remain  ()
	);
endmodule

7 仿真(通过Modelsim仿真观察调节效果)

我们设置的占空比目标值是980,即9.8%。

7.1 第一组PID参数

Kp=0.1,Ki=0.03,Kd=0;
设置如下图:
fpga pid,专题研究,fpga开发,FPGA PID,PID教程,PID仿真,Verilog PID
仿真如下图所示:
fpga pid,专题研究,fpga开发,FPGA PID,PID教程,PID仿真,Verilog PID

通过仿真可以看到,pid_ctrl模块输出的占空比值(pwm_zkb)是一条平滑的曲线,从0缓慢上升到98160,然后稳定下来。实验测出的占空比(actual)等于980,与目标值相等。在这个过程中误差(error)也慢慢减小,直到误差等于0,这就是一个闭环调节过程。

7.2 第二组PID参数

Kp=0.1,Ki=0.15,Kd=0;
参数设置如下:
fpga pid,专题研究,fpga开发,FPGA PID,PID教程,PID仿真,Verilog PID

仿真如下图所示:
fpga pid,专题研究,fpga开发,FPGA PID,PID教程,PID仿真,Verilog PID

我们将Ki参数调大了,发现信号上升的坡度变陡了,这样的好处是缩短了调节时间,便信号能更快的达到我们的目标值,但是信号出现了振荡(超调)现象,即先是超过了目标值(980),然后才慢慢趋于稳定。Kp参数越大,超调现象越严重,在实际使用中我们是不允许有严重振荡现象出现,因为这样会造成我们的控制系统出现问题。比如我们控制无人机,比如我们设置1000米的高度,如果振荡严重,那么无人机会突然一下上升到1000多米的高度,然后再降到1000米,在振荡过程中,如果1200米处有一个障碍物,那无人机就撞上障碍物了,导致严重的后果,所以我们要避免出现严重的超调现象。解决超调现象需要Ki和Kd两个参数来调节。

7.3 第三组PID参数

Kp=0.1,Ki=0.1,Kd=0.15;
设置如下图:
fpga pid,专题研究,fpga开发,FPGA PID,PID教程,PID仿真,Verilog PID

仿真如下图所示:
fpga pid,专题研究,fpga开发,FPGA PID,PID教程,PID仿真,Verilog PID

可明显观察到超调现象减弱了很多。

8 上板验证

用我们ALOGIC_V4开发板验证,占空比可以达到我们的目标值。如下图所示:
fpga pid,专题研究,fpga开发,FPGA PID,PID教程,PID仿真,Verilog PID

fpga pid,专题研究,fpga开发,FPGA PID,PID教程,PID仿真,Verilog PID文章来源地址https://www.toymoban.com/news/detail-780508.html

到了这里,关于基于FPGA的PID控制器设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Matlab】简单PID 控制器设计(控制系统工具箱)

    这里展示如何设计一个简单的PID控制器。 传递函数如下: s y s = 1 ( s + 1 ) 3 sys=frac{1}{(s+1)^3} sys = ( s + 1 ) 3 1 ​ 首先,创建模型并选用PI控制器: 生成结果如下: (交叉频率约为0.52 rad/s,相位裕度为60) 检查受控系统的闭环阶跃响应: 为了缩短响应时间,可以设置比自动选择

    2024年02月06日
    浏览(53)
  • 基于ROS实现的机器人运动PID控制器

    下面是一个基于ROS实现的机器人运动PID控制器的例子: 首先,需要定义机器人的运动控制器节点,例如: 其中, cmd_vel_pub 是一个发布器,用于发布机器人的运动控制指令; odom_sub 是一个订阅器,用于接收机器人的里程计信息。 然后,需要实现一个PID控制器的类,例如: 其

    2024年02月13日
    浏览(54)
  • 基于Matlab自抗扰控制器及其PID控制(附上完整源码+数据)

    自抗扰控制器(Active Disturbance Rejection Control, ADRC)是一种新型的控制策略,它具有强大的抗干扰能力和良好的控制性能。与传统的PID控制器相比,ADRC能够更好地抑制系统的干扰,提高控制系统的稳定性和鲁棒性。 在ADRC中,核心思想是引入一个扰动观测器(Disturbance Observer,

    2024年02月16日
    浏览(51)
  • 基于 RK3399+fpga 的 VME 总线控制器设计(二)硬件和FPGA逻辑设计

    3.2 FPGA 最小系统设计 FPGA 最小系统是指可以使 FPGA 正常工作的最基本的系统,主要包括电源电 路、配置电路、时钟和复位电路。本次设计使用的 FPGA 为紫光同创的 PG2L100H, 接下来具体介绍 FPGA 最小系统各个部分的电路设计。 ( 1 )电源电路设计 FPGA 所需要的电源电压有 3.3V

    2024年02月12日
    浏览(50)
  • 基于 STM32+FPGA 的多轴运动控制器的设计

    运动控制器是数控机床 、 高端机器人等自动化设备控制系统的核心 。 为保证控制器的实用性 、 实时性和稳定 性, 提出一种以 STM32 为主控制器 、 FPGA 为辅助控制器的多轴运动控制器设计方案 。 给出了运动控制器的硬件电路设计 , 将 S 形加减速算法融入运动控制器 ,

    2024年01月17日
    浏览(77)
  • 基于 RK3399+fpga 的 VME 总线控制器设计(一)总体设计

    2.1 需求分析及技术指标 2.1.1 需求分析 VME 总线控制器需要实现数据传输、中断处理、测量显示等功能。同时还需 要具有操作系统、底层驱动程序以及功能接口等,以方便用户进行上层应用软件开 发及使用。 本课题需要实现 VME 控制器的国产化开发,因此需要选择一款国产处

    2024年02月14日
    浏览(50)
  • 基于ARM+FPGA的驱控一体机器人控制器设计

    目前市场上工业机器人,数控机床等多轴运动控制系统普遍采用运动控制器加 伺服驱动器的分布式控制方式。在这种控制方式中,控制器一方面完成人机交互,另 一方面进行 NC 代码的解释执行,插补运算,继而将计算出来的位置指令通过轴组模 块下发给各个伺服驱动器。下

    2024年02月14日
    浏览(52)
  • 基于FPGA和Verilog实现的9层电梯控制器仿真设计

    资源下载地址:https://download.csdn.net/download/sheziqiong/85628810 资源下载地址:https://download.csdn.net/download/sheziqiong/85628810 电梯最少可以往返于0—9层楼。 乘客要去的楼层数A可手动输入并显示,按取消键可清除本次输入。 可自动显示电梯运行的楼层数B 当AB时,电梯上升; 当AB时,

    2024年02月02日
    浏览(70)
  • 基于 STM32+FPGA 的通用工业控制器设计(一)系统方案设计

    本章首先介绍了现有 PLC 系统的概况,然后提出了本文设计的通用工业控制器的 整体方案架构,分析了硬件和软件上需要实现的功能,最后对各部分功能进行分析并提 出具体的实现方案。 2.1 PLC 系统简介 可编程逻辑控制器( Programmable Logic Controller , PLC )是以微处理器为基

    2024年02月15日
    浏览(66)
  • 【抗扰PID控制】干扰抑制PID控制器研究(Matlab代码实现)

    💥💥💞💞 欢迎来到本博客 ❤️❤️💥💥 🏆博主优势: 🌞🌞🌞 博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️ 座右铭: 行百里者,半于九十。 📋📋📋 本文目录如下: 🎁🎁🎁 目录 💥1 概述 📚2 运行结果 🎉3 参考文献 🌈4 Matlab代码、Simulink、文

    2024年02月11日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包