AVR446_Linear speed control of stepper motor步进电机曲线分析

Posted csczq54

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AVR446_Linear speed control of stepper motor步进电机曲线分析相关的知识,希望对你有一定的参考价值。

 

 

技术图片

技术图片

技术图片

技术图片

技术图片

技术图片

技术图片

 

 

 

 

 

 

技术图片

 技术图片

 

 

 

技术图片

 技术图片

技术图片

技术图片

技术图片

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仿真曲线()

  1. 假设运动无限远距离,速度一般,计算达到最大速度的理论步数与实际步数
  2. 其中速度 加速度 减速度 都是放大10倍的
  3. 问题点: max_s_lim为理论加速步数,accel为实际加速步数,

/* 类型定义------------------------------------------------------------------*/

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));

   }

}

 技术图片

 

以上是关于AVR446_Linear speed control of stepper motor步进电机曲线分析的主要内容,如果未能解决你的问题,请参考以下文章

如何在 avr-gcc 中定义定时器

avr频率占空比可调波形输出子函数

只用@property定义一个属性speed,子类不能直接用_speed,需要在interface的成员变量列表里写上_speed

Codeforces446C - DZY Loves Fibonacci Numbers

CF446CDZY Loves Fibonacci Numbers (线段树 + 斐波那契数列)

在STM32F中GPIO_Speed_10MHz = 1,那GPIO_Speed_2MHz, GPIO_Speed_50MHz等多少呢?