FPGA实现电机转速PID控制

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

         通过纯RTL实现电机转速PID控制,包括电机编码器值读取,电机速度、正反转控制,PID算法,卡尔曼滤波,最终实现对电机速度进行控制,使其能够渐近设定的编码器目标值。

一、设计思路

        前面通过SOPC之NIOS Ⅱ实现电机转速PID控制(调用中断函数)对电机实现了PID控制,然后就可以按照其设计方式将上层的C语言实现的PID控制部分等全部转换成Verilog代码,最终实现纯RTL进行PID控制。
        在前文中,电机PWM控制,电机方向和编码器值的获取,卡尔曼滤波是通过Verilog语言编写,而电机速度控制、PID控制是通过Nios Ⅱ系统中的软件部分实现的,因此需要编写电机速度模块,实现对电机PWM控制模块传入速度信息;编写PID控制模块,实现对电机速度模块速度的校正。
        Nios Ⅱ中采用Avalon总线对各个底层Verilog代码进行读取和写入数据,因此也要对电机控制,电机方向和编码器值获取相关代码进行修改
        按照思路画出大概框图如下:

FPGA实现电机转速PID控制,一般人学不会的FPGA,FPGA,fpga开发,verilog,PID

二、PWM控制模块

在前文PWM模块中由于需要Avalon总线的控制,因此有片选信号、片选地址、读写地址等变量,而转为纯RTL后只需要输入方向以及PWM值就可以,因此需要对前文代码进行修改

reg motor_movement;         // 电机运动,1为开始、0为停止
reg motor_direction;        // 电机转向,1为向前、0为向后
reg motor_fast_decay;       // 电机减速,1为快制动、0为慢制动
 
always @(posedge clock or negedge reset_n)
begin
    if (~reset_n)
    begin
        // PWM
        high_dur <= 0;
        total_dur <= 0;
        
        // MOTOR
        motor_movement <= 1'b0;
        motor_direction <= 1'b1;
        motor_fast_decay <= 1'b1;
    end
    else if (en)
    begin
        total_dur <= 32'd2500;
        high_dur  <= speeddata;
        {motor_fast_decay, motor_direction, motor_movement} <= {1'b1,direction,1'b1};
    end
 
// 方向控制
always @(*)
begin
    if (motor_fast_decay)
    begin  
        if (motor_movement)
        begin
            if (motor_direction)
                {DC_Motor_IN2, DC_Motor_IN1, PWM} <= {1'b1, 1'b0, PWM_OUT};
            else
                {DC_Motor_IN2, DC_Motor_IN1, PWM} <= {1'b0, 1'b1, PWM_OUT};
        end
        else
            {DC_Motor_IN2, DC_Motor_IN1, PWM} <= {1'b1, 1'b1, 1'b0};
    end
 
// PWM 转速控制
reg             PWM_OUT;
reg     [31:0] total_dur;       // 总持续时间
reg     [31:0] high_dur;        // 高位时间,决定电机转速,控制 PWM 占空比,值越高,占空比越大,转速越快
reg     [31:0] tick;            // 计数器
 
always @(posedge clock or negedge reset_n)
begin
    if (~reset_n)
    begin
        tick <= 1;
    end
    else if (tick >= total_dur)
    begin
        tick <= 1;
    end
    else
        tick <= tick + 1;
end
 
always @(posedge clock)
begin
    PWM_OUT <= (tick <= high_dur) ? 1'b1 : 1'b0;
end

三、速度控制模块

速度控制模块的主要任务就是将PID模块传入的速度信息,转换为PWM值传入PWM控制模块,并根据速度的正负值计算电机的正转反转

 //速度控制逻辑
    always @(posedge clk or negedge reset_n) begin
        if (~reset_n) begin
            SpeedParam <= 32'd0;
            direction_reg <= 0;
        end else begin
            //计算PWM参数  CYCLE_WIDTH_MINI = 32'd50;CYCLE_WIDTH_MAX  = 32'd2500;
            if (Speed_in > 32'd0) begin
                SpeedParam <= CYCLE_WIDTH_MINI + (Speed_in * (CYCLE_WIDTH_MAX - CYCLE_WIDTH_MINI) / 32'd100);
		    end else if(Speed_in < 32'd0) begin
				SpeedParam <= CYCLE_WIDTH_MINI + ((-Speed_in) * (CYCLE_WIDTH_MAX - CYCLE_WIDTH_MINI) / 32'd100);
            end else begin
                SpeedParam <= 32'd0;
            end

            //设置电机的转向
            direction_reg <= Speed_in[31] ? 0 : 1;
        end
    end

四、PID控制模块  

首先要将PID参数中的小数进行缩放转为定点数;
然后因为用了50MHz的时钟,时钟周期是10ns,可能导致KP、KI、KD算不完,因此将其进行分频为25MHz;
然后就是对 KP、KI、KD进行计算,输出PID结果,即电机速度;
最后为了防止电机速度和累积误差过大,对其进行限幅。

    // 将Kp, Ki, Kd转化为定点数表示
	parameter KP = 32'd60; 			// 0.06
    parameter KI = 32'd1; 				// 0.001
    parameter KD = 32'd3400; 			// 3.4
	parameter SCALE_FACTOR = 1000;  //缩放因子
	 
	reg signed [31:0] error;
	reg signed [31:0] prev_error;
    reg signed [31:0] integral;
    reg signed [31:0] speed;
	reg signed [31:0] controlOutput;
	 
	reg signed [31:0] p;
	reg signed [31:0] i;
	reg signed [31:0] d;
	 
	wire signed [31:0] integral_next = integral + error;
	 
	reg clk_25m;   
	always @(posedge clk or negedge reset_n) begin
		if (~reset_n) begin
			clk_25m <= 0;
		end else begin
			clk_25m <= ~clk_25m;
		end
	end

    always @(posedge clk_25m or negedge reset_n) begin
        if (~reset_n) begin
            error 	  <= 0;
            integral   <= 0;
				speed 	  <= 0;
        end else begin
				
			error <= targetDistance - currentDistance;

			// Calculate control output
            p <= error * KP;
            i <= integral * KI;
            d <= (error - prev_error) * KD;
			controlOutput <= (p + i + d) / SCALE_FACTOR;
				
            // 将控制输出限制在电机速度范围内
            //speed <= initialSpeed + controlOutput;
			if(controlOutput > $signed(32'd100)) begin
				speed <= $signed(32'd100);
			end else if(controlOutput < $signed(-32'd100)) begin
				speed <= $signed(-32'd100);
			end else begin
				speed <= controlOutput;
			end
				
			//integral <= integrallimit + error;
			if(integral_next >= $signed(32'd800)) begin
				integral <= $signed(32'd800);
			end else if(integral_next <= $signed(-32'd800)) begin
				integral <= $signed(-32'd800);
			end else begin
				integral <= integral_next;
			end
        end
    end
	
	// 更新下次迭代的前一次误差和积分
	always @(posedge clk_25m or negedge reset_n) begin
	    if(~reset_n) begin
		    prev_error <= 0;
        end else if(error!= prev_error) begin
			prev_error <= error;
		end else begin
		     prev_error <= prev_error;
		end
	end

	assign speedout = speed;

五、电机方向和编码器值的获取

电机编码器值要根据电机方向进行自增和自减,因此要先通过AB方波确认电机方向

reg  DO_PULSE;                      //用于存储输出的电机脉冲信号
wire PULSE_XOR;                     //用于存储PHASE_A和PHASE_B进行异或结果
reg  PULSE_XOR_PREVIOUS;            //上一次的PULSE_XOR值
reg  DIRECTION;                     //用于存储电机方向信号
reg  DIRECT_PATCH;                  //用于存储DIRECT异或PHASE_A后取反的结果
 
//解码方向信号
always @(posedge DI_PHASE_A) DIRECTION <= DI_PHASE_B;                    //当有DI_PHASE_A的上升沿,将DI_PHASE_B的值赋给DIRECTION  
always @(posedge DI_PHASE_B) DIRECT_PATCH <= ~(DIRECTION ^ DI_PHASE_A);  //当有DI_PHASE_B的上升沿,将DIRECT和DI_PHASE_A进行异或后取反赋值给DIRECT_PATCH 
assign DO_DIRECT = DIRECTION | DIRECT_PATCH;                             //将DIRECTION和DIRECT_PATCH进行与运算 
 
//解码脉冲信号
assign PULSE_XOR = DI_PHASE_A ^ DI_PHASE_B;                         
always @(posedge DI_SYSCLK) 
begin
    if(PULSE_XOR != PULSE_XOR_PREVIOUS)                             
    begin                                                              
        DO_PULSE <= 1'b1;                                              
        PULSE_XOR_PREVIOUS <= PULSE_XOR;
    end
    else begin                                                         
        DO_PULSE <= 1'b0;
    end
    
end

 获取电机方向后,对其进行计数,得到电机编码器的值并将其输出

always @(posedge clock or negedge reset_n)
begin
    if(~reset_n) begin
        counter_enable <= 0;
    end
    else if (counter_enable) begin
        read_data <= pulse_counter;
    end  
end
 
always @(posedge clock)
begin
    if(DO_PULSE ) begin
        if(motor_direction) begin                         //如果电机正转  
            if(pulse_counter < $signed(32'h8000))
                pulse_counter <= pulse_counter + 1;      //counter随电机传回的脉冲数累加   
        end
        else if(!motor_direction) begin                  //如果电机反转
             if(pulse_counter > $signed(-32'h8000))
                pulse_counter <= pulse_counter - 1;      //counter随着电机传回的脉冲数递减    
        end
        else
            pulse_counter <= 0;                                
    end
end  

七、实验效果

整体的系统框图如下所示,左右两个电机的方波经过卡尔曼滤波后输入到motor_measure中,先获取其电机方向,然后对电机编码器进行计数并将左右两电机的编码器数值取平均值输入到PID控制模块中,与ISSP输入的目标编码器值进行计算出速度信息,将速度信息输入到set_speed中计算方向和PWM参数,输入到PWM控制模块进行电机控制

FPGA实现电机转速PID控制,一般人学不会的FPGA,FPGA,fpga开发,verilog,PID

通过signal tap和ISSP联合抓波形,得出来的效果还是不错的,会有一点点超调量 

FPGA实现电机转速PID控制,一般人学不会的FPGA,FPGA,fpga开发,verilog,PID文章来源地址https://www.toymoban.com/news/detail-705863.html

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

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

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

相关文章

  • tb6612电机驱动软件开发(代码pid实现,调试,控制实现)

    代码工程 https://download.csdn.net/download/weixin_52849254/87879043?spm=1001.2014.3001.5501 这段代码是一个PID算法的实现,用于控制电机的位置和速度。代码中包含了以下主要内容: 定义了全局变量,包括四个PID结构体变量,分别用于左电机的位置控制、左电机的速度控制、右电机的速度控

    2024年02月08日
    浏览(53)
  • 无刷电机FOC控制------转速计算、载波频率相关

      假设一个极对数为1的电机正在以转速为N运行,电机的某一相正弦电流的一个周期T表示于电机旋转了一圈,所以电机转速n = 1/T 转/s,即电流频率,实际常用的电机转速为rpm(转/min),算1对极的电机转速N = 60 f。   对于多对极(p)电机而言,电机机械角转了360°,电角度转了

    2024年02月14日
    浏览(50)
  • OpenMV数字识别进而控制直流电机转速【小白篇】

    第一次接触OpenMV也是第一次将理论用于实践,是老师让我实现的一个小测验,这几天完成后决定写下完整的过程。本文主要是当缝合怪,借鉴和参考了其他人的代码再根据我个人设备进行了一定的调整,此外还包括了我自身实践过程中的一些小意外。 !!!一定要根据个人器

    2024年02月14日
    浏览(34)
  • 基于51单片机直流电机转速数码管显示控制系统

    一、系统方案 本文主要研究了利用MCS-51系列单片机控制PWM信号从而实现对直流电机转速进行控制的方法。本文中采用了三极管组成了PWM信号的驱动系统,并且对PWM信号的原理、产生方法以及如何通过软件编程对PWM信号占空比进行调节,从而控制其输入信号波形等均作了详细的

    2024年02月12日
    浏览(49)
  • FPGA实现PID控制算法(含仿真)

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

    2024年02月15日
    浏览(35)
  • STM32 HAL库PID控制电机 第三章 PID控制双电机

    注:本文含全部PID控制代码,保证可以运行,如不能运行可以留言回复 1 基础配置 1.1 编码器电路图及配置 引脚 定时器通道 PA0 TIM2_CH1 PA1 TIM2_CH2 PB6 TIM4_CH1 PB7 TIM4_CH2 因此需要把TIM2、TIM4配置为编码器模式。在STM32CubeIDE中找到定时器2与定时器4,进行模式配置。以下以定时器2为

    2024年02月16日
    浏览(38)
  • FPGA实现PID控制器——基于Quartus prime 18.0

    目录  1. PID控制器和离散化PID控制器 1.1 PID控制器 1.1.1 P控制器 1.1.2 稳态误差和I控制器 1.1.3 超调和D控制器 1.2 离散式PID控制器——位置式PID控制器 2.PID控制系统Simulink仿真 3.Verilog代码编写和Modelsim仿真 3.1 误差计算模块和PID算法模块编写 3.1.1 误差计算模块 3.1.2 PID算法模块 3

    2024年02月03日
    浏览(44)
  • STM32CubeMX 直流电机串级PID位置速度控制、HAL库、cubemx、PID、串级PID、位置控制、速度控制、双环控制

    提示:本文章的串级PID位置速度控制,是在前两篇文章速度控制,位置控制的基础上实现的,这一章节中不需要额外的cubemx的配置,只需要写简单的代码即可,复杂的地方在于串级pid的调试过程。 pid是我们在学习单片机中首先要学会的控制算法,而串级pid又是在单pid的基础上

    2024年02月14日
    浏览(53)
  • 【RoboMaster】从零开始控制RM电机(4)-单环PID控制

    硬件以及软件环境: STM32Cube_FW_F4_V1.26.2 MDK-ARM 5.29.0.0 大疆RoboMaster开发板A型开发板(STM32F427IIHx)/C型开发板(STM32F407IGTx) 源码: RM_ctrl 本系列文章目录: 【RoboMaster】从零开始控制RM电机(2)-CAN通信原理及电调通信协议 【RoboMaster】从零开始控制RM电机(3)- 建立与电调的通

    2024年02月01日
    浏览(32)
  • 基于FPGA的永磁同步伺服控制系统的设计,在FPGA实现了伺服电机的矢量控制, 坐标变换,电流环,速度环,位置环,电机反馈接口,SVPWM

    一个基于FPGA的永磁同步伺服控制系统,利用Verilog语言在FPGA上实现了伺服电机的矢量控制、坐标变换、电流环、速度环、位置环以及电机反馈接口。这个系统具有很高的研究价值。 涉及到的知识点和领域范围主要包括:FPGA(现场可编程门阵列)、永磁同步伺服控制系统、矢

    2024年02月04日
    浏览(44)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包