赞
踩
使用加减速的目的是:防止步进电机的启动频率过快而无法正常启动,避免控制脉冲频率变化过大造成电机丢步或过冲。
空载启动频率,即步进电机在空载情况下能够正常启动的脉冲频率,如果脉冲频率高于该值,电机不能正常启动,可能发生丢步或堵转。在有负载的情况下,启动频率应更低。如果要使电机达到高速转动,脉冲频率应该有加速过程,即启动频率较低,然后按一定加速度升到所希望的高频(电机转速从低速升到高速)。
步进电机的基本概念及控制模式参考如下链接:
https://www.elecfans.com/d/1294049.html
通过梯形加减速要达到的效果:
梯形加减速的算法实现
梯形加减速的位移、速度、加速度曲线如图1所示,速度曲线分为加速、匀速、减速三个部分。
图1 梯形加减速示意图
图2所示,对直线加速段进行离散,在0-ta之间插入若干中间速度值,控制速度从小到大取值,即可实现直线加速。本次设计采用对0-ta进行n等分,每一份的时间为t_s=ta/n,也是将期望速度(speed)进行n等分,即在加速段均匀插入n-1个中间速度值,每经过时间t_s,对当前速度加 speed/n ,直到达到期望速度speed。减速过程与之相反。
本次设计只实现图2所示的加减速情况,n=100。
图2 离散化后的直线加减速速度变化曲线
梯形加减速模块框图如图3所示
图3
功能说明:上位机传送电机目标位置、目标速度、加速时间、减速时间,经过加减速模块后,能够在目标位置准确停下。
引脚说明
Clk | 系统时钟50MHz |
Rst_n | 复位信号,低电平有效 |
Step | 电机目标位置,输入脉冲个数。示例代码中为64000 |
Speed | 电机目标速度,输入脉冲频率(hz)。示例代码中为100khz |
T_accel | 加速时间(ms)。示例代码中为300ms |
T_decel | 减速时间(ms)。示例代码中为400ms |
Pul | 输出脉冲信号 |
各个模块定义
1. 定时计数模块
在加速或减速控制开启状态下启动该计数器,加速计数的时间为t_s=ta/n,减速计数的时间为
t_s=(tc-tb)/n。
代码:
- assign T_clk = 26'd50_000_000;
- assign CNT_up = (t_accel*T_clk)/100000; //acc time;计数器的计数值
- assign CNT_dn = (t_decel*T_clk)/100000; //dec time
- always@(posedge clk or negedge rst_n)
- begin
- if (!rst_n)
- cnt_up <= 'b0;
- else if(cnt_up == CNT_up - 1'b1)
- cnt_up <= 'b0;
- else if(up_en)
- //加速使能有效时才开始计数,所以speed_current赋值条件为cnt_up == 0
- cnt_up <= cnt_up + 1'b1;
- end
- always@(posedge clk or negedge rst_n)
- begin
- if (!rst_n)
- cnt_dn <= 'b0;
- else if(cnt_dn == CNT_dn - 1'b1)
- cnt_dn <= 'b0;
- else if(down_en)
- cnt_dn <= cnt_dn + 1'b1;
- end
2. 加减速使能模块
通过比较当前脉冲数与加速阶段的总脉冲数和需要减速时的脉冲数,确定加速使能信号up_en和减速使能信号down_en。
图2所示,加速阶段的总脉冲数为红线下方的面积,即CNT_sup=1/2×Vt×(ta-ta/n)
注意单位转换:hz X s,得到的是脉冲数,减速阶段同理。
代码:
- assign CNT_con= step_target - speed_target*(t_decel-t_decel/100)/2000;
- //when dec time ,减速的时间点,总脉冲数减去加减速总共所需的脉冲数,hz x s,得出的才是脉冲个数
- assign CNT_sup= speed_target*(t_accel-t_accel/100)/2000;
- //加速阶段的脉冲总数
-
- always@(posedge clk or negedge rst_n) //加减速的使能条件要合理布置,用速度作为判断条件时容
- //易出错
- begin
- if(!rst_n) begin
- up_en <= 'b0;
- down_en <= 'b0;
- end
- else if (cnt_con <= CNT_sup) //当输出脉冲个数小于等于加速阶段的总脉冲数时,置一
- up_en <= 1'b1;
- else if (cnt_con > CNT_con && speed_current > 'b0)
- //when dec,当到达减速点时,给减速使能置一,同时条件还必须包括speed_current > 'b0,
- //减速到0时,该条件会永远满足,一直减速下去
- down_en <= 1'b1;
- else begin
- up_en <= 1'b0;
- down_en <= 1'b0;
- end
- end
3. 加减速变化模块
当加速使能信号up_en为真时,对当前速度加speed/n,当减速使能信号down_en为真时,对当前速度减speed/n。
代码:
- always@(posedge clk or negedge rst_n)
- begin
- if(!rst_n)
- speed_current <= 'b0;
- else if(up_en && cnt_up == 0) //必须是在up_en刚刚有效时就进行加减速
- speed_current <= speed_current + speed_target/100;
- else if(down_en && cnt_dn == 0)
- speed_current <= speed_current - speed_target/100;
- else
- speed_current <= speed_current ;
- end
4. 脉冲输出模块
计算出当前速度对应的脉冲周期,进而计算出计数器计数到周期值所对应的计数值。
CNT_per= T_clk/speed_current;
代码:
- assign CNT_per= T_clk/speed_current; //pulse out,当前速度对应的脉冲周期的计数值
-
-
- always@(posedge clk or negedge rst_n) //输出脉冲的周期计数器
- begin
- if (!rst_n)
- cnt_per <= 'b0;
- else if(cnt_per == CNT_per - 1'b1 || cnt_up == CNT_up - 1'b1
- || cnt_dn == CNT_dn - 1'b1) //清零条件要加上 cnt_up和cnt_dn计数到最大值减一时,
- //因为下一段的速度值与前一段不同,速度变化后要重新开始
- //对输出脉冲周期的计数
- cnt_per <= 'b0;
- else cnt_per <= cnt_per + 1'b1;
- end
- //pulse out
- always@(posedge clk or negedge rst_n)
- begin
- if(!rst_n)
- pul <= 'b0;
- else if(cnt_per == CNT_per/2-1 || cnt_per == CNT_per-1) //脉冲输出,中间结束各翻转一次
- pul <= ~pul;
- else pul <= pul;
- end
5. 脉冲计数模块
记录输出脉冲的个数,且只能计数到目标位置。
- always@(posedge clk or negedge rst_n)
- begin
- if (!rst_n)
- cnt_con <= 'b0;
- else if(cnt_per == CNT_per - 1'b1 && cnt_con != step_target)
- // 脉冲周期计数器计满且输出脉冲个数不等于要求个数时才加1,
- // 计数器只计数一次的写法
- cnt_con <= cnt_con + 1'b1;
- else cnt_con <= cnt_con;
- end
仿真结果
满足预期的功能要求。
图4 直线加减速仿真结果图
完整代码如下:
Rtl:
- module linear_acc_dec(
- input clk,
- input rst_n,
- input [15:0] step_target, // pulse_count
- input [16:0] speed_target, // hz
- input [8:0] t_accel, // ms
- input [8:0] t_decel,
- output reg pul
- );
- //0-speed_target Insert 100 intermediate values
- wire [33:0] CNT_up; //counter 3ms/20ns
- wire [34:0] CNT_dn; //声明位宽时,不能只看结果值,要能容下计算过程中的最大值
- reg [17:0] cnt_up;
- reg [17:0] cnt_dn;
- reg [16:0] speed_current;
- reg up_en;
- reg down_en;
- wire [15:0] CNT_per;
- reg [15:0] cnt_per; //T-pul period
- wire [15:0] CNT_con;
- reg [15:0] cnt_con; //pulse count
- wire [15:0] CNT_sup;
- wire [25:0] T_clk ;
-
- assign T_clk = 26'd50_000_000;
- assign CNT_up = (t_accel*T_clk)/100000; //acc time
- assign CNT_dn = (t_decel*T_clk)/100000; //dec time
- assign CNT_per= T_clk/speed_current; //pulse out
- assign CNT_con= step_target - speed_target*(t_decel-t_decel/100)/2000;
- //when dec time
- assign CNT_sup= speed_target*(t_accel-t_accel/100)/2000;
- always@(posedge clk or negedge rst_n)
- begin
- if (!rst_n)
- cnt_up <= 'b0;
- else if(cnt_up == CNT_up - 1'b1)
- cnt_up <= 'b0;
- else if(up_en)
- cnt_up <= cnt_up + 1'b1;
- end
- always@(posedge clk or negedge rst_n)
- begin
- if (!rst_n)
- cnt_dn <= 'b0;
- else if(cnt_dn == CNT_dn - 1'b1)
- cnt_dn <= 'b0;
- else if(down_en)
- cnt_dn <= cnt_dn + 1'b1;
- end
- //100 intermediate values
- always@(posedge clk or negedge rst_n)
- begin
- if(!rst_n)
- speed_current <= 'b0;
- else if(up_en && cnt_up == 0)
- speed_current <= speed_current + speed_target/100;
- else if(down_en && cnt_dn == 0)
- speed_current <= speed_current - speed_target/100;
- else
- speed_current <= speed_current ;
- end
- //up_en,down_en
- always@(posedge clk or negedge rst_n)
- begin
- if(!rst_n) begin
- up_en <= 'b0;
- down_en <= 'b0;
- end
- else if (cnt_con <= CNT_sup)
- up_en <= 1'b1;
- else if (cnt_con > CNT_con && speed_current > 'b0)//when dec
- down_en <= 1'b1;
- else begin
- up_en <= 1'b0;
- down_en <= 1'b0;
- end
- end
- //pulse count
- always@(posedge clk or negedge rst_n)
- begin
- if (!rst_n)
- cnt_con <= 'b0;
- else if(cnt_per == CNT_per - 1'b1 && cnt_con != step_target)
- cnt_con <= cnt_con + 1'b1;
- else cnt_con <= cnt_con;
- end
-
- //cnt_pulse out
- always@(posedge clk or negedge rst_n)
- begin
- if (!rst_n)
- cnt_per <= 'b0;
- else if(cnt_per == CNT_per - 1'b1 || cnt_up == CNT_up - 1'b1
- || cnt_dn == CNT_dn - 1'b1)
- cnt_per <= 'b0;
- else cnt_per <= cnt_per + 1'b1;
- end
- //pulse out
- always@(posedge clk or negedge rst_n)
- begin
- if(!rst_n)
- pul <= 'b0;
- else if(cnt_per == CNT_per/2-1 || cnt_per == CNT_per-1)
- pul <= ~pul;
- else pul <= pul;
- end
- endmodule
Tb:
- `timescale 1ns/1ns
- `define clk_period 20
- module tb();
- reg clk ;
- reg rst_n ;
- reg [15:0] step_target ;
- reg [16:0] speed_target ;
- reg [8:0] t_accel ;
- reg [8:0] t_decel ;
- wire pul ;
- initial begin
- clk <= 'b0;
- rst_n <= 'b0;
- #(`clk_period)
- rst_n <= 'b1;
- step_target <= 64000;
- speed_target<=100000;
- t_accel <= 300;
- t_decel <= 400;
- #(`clk_period*50000000)
- $stop ;
- end
- always #(`clk_period/2) clk<=~clk;
- linear_acc_dec
- u1
- (
- .clk (clk ),
- .rst_n (rst_n ),
- .step_target (step_target ),
- .speed_target (speed_target ),
- .t_accel (t_accel ),
- .t_decel (t_decel ),
- .pul (pul )
- );
- endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。