如:1rad/1s,1分钟转过的弧度为=1rad*60,则每分钟转数:(1rad*60分钟/2π)=9.55rpm 步距角为1.8°则:1.8/360=x/2*π-->步距角弧度为单位:0.0314 rad 所以:转过的角度/位置θ=n*α=(ω*t)=(1/2 *a*t*t)----a为加速度,所以前n个脉冲的时间: t=√2*n*α/a=√(2*α/a)*√n,所以第n个脉冲用时间为: tn+1-tn=√(2*α/a)*(√n-√(n-1)) 因:定时器计数值C * 定时器时钟周期T =第n个脉冲的时间,即:Cn*Tn=tn+1-tn ==> Cn*Tn=tn+1-tn=√(2*α/a)*(√n+1-√(n)) 第n个脉冲定时器的计数值为:Cn=(1/Tn)*√(2*α/a)*(√n+1-√(n)) 进而:第一个脉冲(即n=0)定时器计数值:C0=(1/T0)*√(2*α/a) 因在调速过程中,定时器的时钟频率T不会改变,只是改变定时器的计数值,故 第n个脉冲定时器值为:Cn=T0*√(2*α/a)
accel_lim是达到最大速度时的减速步数,而decel_val是当前速度降到0需要的步数; 将上图减速参数带入上面公式n=v*v/2ωα中:decel_va=speed*speed/2α*decel*100,此式和上面max_s_lim公式相除,得出: decel_val=-max_s_lim*accel/decel 此图中:减速步数为decel_val=step-accel_lim,带入上面公式n=v*v/2ωα accel_lim=speed*speed/2*accel*α decel_val=speed*speed/2*decel*α=step-accel_lim,2式相除: decel_val=accel_lim*(step-accel_lim)/decel 1.1. 单片机代码处理// 定义定时器预分频,定时器实际时钟频率为:72MHz/(STEPMOTOR_TIMx_PRESCALER+1) #define STEPMOTOR_TIM_PRESCALER 3 // 步进电机驱动器细分设置为: 32 细 // 定义定时器周期,输出比较模式周期设置为0xFFFF #define STEPMOTOR_TIM_PERIOD 0xFFFF #define FALSE 0 #define TRUE 1 #define CW 0 // 顺时针 #define CCW 1 // 逆时针 #define STOP 0 // 加减速曲线状态:停止 #define ACCEL 1 // 加减速曲线状态:加速阶段 #define DECEL 2 // 加减速曲线状态:减速阶段 #define RUN 3 // 加减速曲线状态:匀速阶段 #define T1_FREQ (SystemCoreClock/(STEPMOTOR_TIM_PRESCALER+1)) // 频率ft值 #define FSPR 200 //步进电机单圈步数 #define MICRO_STEP 32 // 步进电机驱动器细分数 #define SPR (FSPR*MICRO_STEP) // 旋转一圈需要的脉冲数 // 数学常数 #define ALPHA ((float)(2*3.14159/SPR)) // α= 2*pi/spr// #define A_T_x10 ((float)(10*ALPHA*T1_FREQ)) #define T1_FREQ_148 ((float)((T1_FREQ*0.676)/10)) // 0.676为误差修正值 #define A_SQ ((float)(2*100000*ALPHA)) #define A_x200 ((float)(200*ALPHA)) /** * 函数功能: 相对位置运动:运动给定的步数 * 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针). accel 加速度,实际值为accel*0.1*rad/sec^2 decel 减速度,实际值为decel*0.1*rad/sec^2 speed 最大速度,实际值为speed*0.1*rad/sec * 返 回 值: 无 * 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始 * 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且 * 速度很慢,那还没达到最大速度就要开始减速 */ void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed) { __IO uint16_t tim_count; // 达到最大速度时的步数 __IO uint32_t max_s_lim; // 必须要开始减速的步数(如果加速没有达到最大速度) __IO uint32_t accel_lim; if(step < 0) // 步数为负数 { srd.dir = CCW; // 逆时针方向旋转 STEPMOTOR_DIR_REVERSAL(); step =-step; // 获取步数绝对值 } else { srd.dir = CW; // 顺时针方向旋转 STEPMOTOR_DIR_FORWARD(); } if(step == 1) // 步数为1 { srd.accel_count = -1; // 只移动一步 srd.run_state = DECEL; // 减速状态. srd.step_delay = 1000; // 短延时 } else if(step != 0) // 如果目标运动步数不为0 { // 我们的驱动器用户手册有详细的计算及推导过程 // 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。 // min_delay = (alpha / tt)/ w srd.min_delay = (int32_t)(A_T_x10/speed); // 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.1rad/sec^2 // step_delay = 1/tt * sqrt(2*alpha/accel) // step_delay = ( tfreq*0.676/10 )*10 * sqrt( (2*alpha*100000) / (accel*10) )/100 srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10); // 计算多少步之后达到最大速度的限制 // max_s_lim = speed^2 / (2*alpha*accel) max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10)); // 如果达到最大速度小于0.5步,我们将四舍五入为0 // 但实际我们必须移动至少一步才能达到想要的速度 if(max_s_lim == 0){ max_s_lim = 1; } // 计算多少步之后我们必须开始减速 // n1 = (n1+n2)decel / (accel + decel) accel_lim = (uint32_t)(step*decel/(accel+decel)); // 我们必须加速至少1步才能才能开始减速. if(accel_lim == 0){ accel_lim = 1; } // 使用限制条件我们可以计算出减速阶段步数 if(accel_lim <= max_s_lim){ srd.decel_val = accel_lim - step; } else{ srd.decel_val = -(max_s_lim*accel/decel); } // 当只剩下一步我们必须减速 if(srd.decel_val == 0){ srd.decel_val = -1; } // 计算开始减速时的步数 srd.decel_start = step + srd.decel_val; // 如果最大速度很慢,我们就不需要进行加速运动 if(srd.step_delay <= srd.min_delay){ srd.step_delay = srd.min_delay; srd.run_state = RUN; } else{ srd.run_state = ACCEL; } // 复位加速度计数值 srd.accel_count = 0; } MotionStatus = 1; // 电机为运动状态 tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR); __HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay); // 设置定时器比较值 TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_ENABLE);// 使能定时器通道 STEPMOTOR_OUTPUT_ENABLE(); } 1.2. VS2008仿真曲线()
/* 类型定义------------------------------------------------------------------*/ typedef struct { uint8 run_state ; // 电机旋转状态 uint8 dir ; // 电机旋转方向 int32 step_delay; // 下个脉冲周期(时间间隔),启动时为加速度 uint32 decel_start; // 启动减速位置 int32 decel_val; // 减速阶段步数 int32 min_delay; // 最小脉冲周期(最大速度,即匀速段速度) int32 accel_count; // 加减速阶段计数值 }speedRampData; // 定义定时器预分频,定时器实际时钟频率为:MHz/(STEPMOTOR_TIMx_PRESCALER+1) #define STEPMOTOR_TIM_PRESCALER 3 // 步进电机驱动器细分设置为: 32 细分 //#define STEPMOTOR_TIM_PRESCALER 7 // 步进电机驱动器细分设置为: 16 细分 //#define STEPMOTOR_TIM_PRESCALER 15 // 步进电机驱动器细分设置为: 8 细分 //#define STEPMOTOR_TIM_PRESCALER 31 // 步进电机驱动器细分设置为: 4 细分 //#define STEPMOTOR_TIM_PRESCALER 63 // 步进电机驱动器细分设置为: 2 细分 //#define STEPMOTOR_TIM_PRESCALER 127 // 步进电机驱动器细分设置为: 1 细分 // 定义定时器周期,输出比较模式周期设置为xFFFF #define STEPMOTOR_TIM_PERIOD 0xFFFF #define FALSE 0 #define TRUE 1 #define CW 0 // 顺时针 #define CCW 1 // 逆时针 #define STOP 0 // 加减速曲线状态:停止 #define ACCEL 1 // 加减速曲线状态:加速阶段 #define DECEL 2 // 加减速曲线状态:减速阶段 #define RUN 3 // 加减速曲线状态:匀速阶段 #define T1_FREQ (72000000/(STEPMOTOR_TIM_PRESCALER+1)) // 频率ft值 #define FSPR 200 //步进电机单圈步数 #define MICRO_STEP 32 // 步进电机驱动器细分数 #define SPR (FSPR*MICRO_STEP) // 旋转一圈需要的脉冲数 // 数学常数 #define ALPHA ((float)(2*3.14159/SPR)) // α= 2*pi/spr #define A_T_x10 ((float)(10*ALPHA*T1_FREQ)) #define T1_FREQ_148 ((float)((T1_FREQ*0.676)/10)) // 0.676为误差修正值 #define A_SQ ((float)(2*100000*ALPHA)) #define A_x200 ((float)(200*ALPHA)) #include "stdafx.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "motor.h" #include "math.h" MOTOR_DATA MotorData; int32 step=20000000; uint32 accel=15000;//rad/s uint32 decel=15000;//rad/s uint32 speed=1200;//rad/s char buff[30]; char buff1[30]; speedRampData srd; //假设距离无限远,那么肯定可以达到最大速度,计算加速到最大速度的步数 void MotorInit(FILE *fp) { //uint16 tim_count; //达到最大速度时的步数 uint32 max_s_lim; //必须要开始减速的步数 uint32 accel_lim; float step_delay; //float min_delay; // min_delay = (alpha / tt)/ w srd.min_delay = (int32_t)(A_T_x10/speed); //min_delay=(A_T_x10/speed); // 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.1rad/sec^2 // step_delay = 1/tt * sqrt(2*alpha/accel) // step_delay = ( tfreq*0.676/10 )*10 * sqrt( (2*alpha*100000) / (accel*10) )/100 srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10); step_delay = ((T1_FREQ_148 * sqrt(A_SQ / accel))/10); // 计算多少步之后达到最大速度的限制 // max_s_lim = speed^2 / (2*alpha*accel) max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10)); accel_lim = (uint32_t)(step*decel/(accel+decel)); sprintf(buff,"max_s_lim=%d accel_lim=%d\r",max_s_lim,accel_lim); fwrite(buff,sizeof(buff),1,fp); srd.accel_count = 0; } void Timer_Scan(FILE *fp) { uint16_t tim_count=0; // 保存新(下)一个延时周期 uint16_t new_step_delay=0; // 加速过程中最后一次延时(脉冲周期). static uint16_t last_accel_delay=0; // 总移动步数计数器 static uint32_t step_count = 0; // 记录new_step_delay中的余数,提高下一步计算的精度 static int32_t rest = 0; //定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲 static uint8_t i=0; srd.accel_count++;// 加速计数值加1 ////计算新(下)一步脉冲周期(时间间隔) new_step_delay = srd.step_delay - (((2 *srd.step_delay) + rest)/(4 * srd.accel_count + 1)); // 计算余数,下次计算补上余数,减少误差 rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1); srd.step_delay=new_step_delay; while(new_step_delay >= srd.min_delay)//超过当前速度时退出计算 { srd.accel_count++; new_step_delay = srd.step_delay - (((2 *srd.step_delay) + rest)/(4 * srd.accel_count + 1)); rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1); srd.step_delay = new_step_delay; sprintf(buff,"new_step_delay=%d count=%d\r",new_step_delay,srd.accel_count); fwrite(buff,sizeof(buff),1,fp); printf("%s %s \r",buff,buff1); memset(buff,0x00,sizeof(buff)); } } int main() { FILE *fp; fp=fopen("Timer.txt","w"); MotorInit(fp);//参数初始化 Timer_Scan(fp); fclose(fp); system("pause"); return 0; } void Timer_Scan(FILE *fp) { uint16_t tim_count=0; // 保存新(下)一个延时周期 uint16_t new_step_delay=0; // 加速过程中最后一次延时(脉冲周期). static uint16_t last_accel_delay=0; // 总移动步数计数器 static uint32_t step_count = 0; // 记录new_step_delay中的余数,提高下一步计算的精度 static int32_t rest = 0; //定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲 static uint8_t i=0; double a; //srd.accel_count++;// 加速计数值加1 new_step_delay=srd.min_delay;// while(new_step_delay >= srd.min_delay)//超过当前速度时退出计算 { srd.accel_count++; //new_step_delay=(int32)(srd.step_delay*sqrt((double)(srd.accel_count+1)); new_step_delay=(int32)(srd.step_delay*(sqrt((double)(srd.accel_count+1))-sqrt((double)(srd.accel_count)))); sprintf(buff,"new_step_delay=%d count=%d\r",new_step_delay,srd.accel_count); fwrite(buff,sizeof(buff),1,fp); printf("%s %s \r",buff,buff1); memset(buff,0x00,sizeof(buff)); } }
|
|