STM32HAL库实现步进电机的S型曲线加速

硬件

STM32F407VGT6、步进电机驱动、步进电机

为什么需要S型曲线加速

如果电机直接告诉启动时可能存在震动、丢步,甚至无法启动的现象,此时使用合适的S型加速曲线,使得电机能够缓慢启动
S型曲线加速是指步进电机的启动速度按照S型曲线逐渐增加,以达到设定的最大速度。具体的S型曲线方程如下:
y = 1/(1+e^x);
使用StepperAccelerationGenerat.exe生成

此工具下载网址

https://www.newasp.com/soft/434323.html可以根据个人需求进行相关参数的设置

CUBEMX配置

###定时器1配置

基本配置在这里插入图片描述

###时钟配置
中断选择

###定时器频率计算
50M/((50-1)*(2000-1))≈500Hz
后期可以根据需求进行修改
###工程管理
选择合适的位置进行存储

##源代码实现
###speed.c

#include "speed.h"
#include "stdio.h"
//#include "data.h"

Motor_t Motor;
extern TIM_HandleTypeDef htim1;
//extern volatile uint16_t AccStep[ACC_STEP_NUM];
uint16_t period_1[SIZE1]={0};

enum
{
	SPEED_INCREASE,
	SPEED_STABLE,
	SPEED_DECREASE
};
//功能:S加速曲线初始化
//参数1 *pbuff          计算出的定时器的周期
//参数2 fre_max        最大频率 Hz
//参数3 fre_min        最小频率 Hz
//参数4 len            加速需要的脉冲数
void CurveS_init(uint16_t *pbuff,uint32_t fre_max,uint32_t fre_min,int16_t len)
{
      int16_t i;
      uint16_t flexible =4;
	  //uint16_t pbuff_1[500]={0}; 
      float delt = fre_max-fre_min;
      float deno ;
      float melo ;
      float fre;
#if CHANGE_MODE
	for(i=0;i<len;i++)
	{	
		pbuff[i] = AccStep[i];
		printf("%d, ",AccStep[i]);		
	}
//	memcpy(pbuff,(const void *)AccStep,800);
	printf("\r\n");
	for(i=0; i<len; i++)
	{
		printf("%d, ",pbuff[i]);
	}
#else
	for(i=0; i<len; i++)
	{
		melo = flexible* (i-len/2) / (len/2);
		deno = 1.0f / (1 + expf(-melo));  //
		fre = delt * deno + fre_min;
		pbuff[i] = (unsigned short)(TIM1_CLOCK_FREQ / fre);
		printf("%d, ",pbuff[i]);
	}
#endif
}
//速度调节函数
volatile uint8_t RUN_FLAG = 0;
void SpeedAdjust(void)
{
  switch(Motor.Status)
  {
    /*加速*/            
    case SPEED_INCREASE:
      if(Motor.Count < Motor.CountMax)
      {
        __HAL_TIM_SET_AUTORELOAD(&htim1,period_1[Motor.Count]);//计算下一个PWM的周期
        htim1.Instance->CCR2 = period_1[Motor.Count]/2;//占空比50%
        Motor.Count++;//加速次数
      }
      else
      {
        Motor.Status = SPEED_STABLE; 
        Motor.Count--;
      }
      break;
    /*匀速*/  
    case SPEED_STABLE:
      if(Motor.PWMcount >= (Motor.PWMneed - Motor.Count))
      {    
        Motor.Status = SPEED_DECREASE;
      }
      break;
    /*减速*/  
    case SPEED_DECREASE:
      if(Motor.Count >= 0)
      {
        __HAL_TIM_SET_AUTORELOAD(&htim1,period_1[Motor.Count]);//计算下一个PWM的周期
        htim1.Instance->CCR2 = period_1[Motor.Count]/2;
        Motor.Count--;  
      }
      if(Motor.PWMcount >= Motor.PWMneed)
      {
        HAL_TIM_PWM_Stop_IT(&htim1,TIM_CHANNEL_2);
//		RUN_FLAG = 1;
      }      
      break;
    default :
      break;
  }
}

//PWM--需要输出的脉冲个数
void StartPWM(uint32_t PWM)
{      
       Motor.PWMcount = 0;
       Motor.PWMneed = PWM;
       Motor.Count = 0;
       Motor.Status = SPEED_INCREASE;
       Motor.CountMax = PWM_Count_Max;
       //初始化加速曲线
       CurveS_init(period_1,PWM_FREQ_MAX,PWM_FREQ_MIN,Motor.CountMax);
       __HAL_TIM_SET_AUTORELOAD(&htim1,period_1[0]);
       htim1.Instance->CCR2 = period_1[0];
       HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_2);  //启动定时器PWM输出
}

###speed.h

#ifndef _SPEED_H
#define _SPEED_H


#include "main.h"

typedef struct{
  uint8_t Status;   //状态
  int32_t Count;     //加减速过程脉冲计数
  int32_t CountMax;  //最大加速脉冲数
  uint32_t PWMcount;//PWM计数
  uint32_t PWMneed; //需要输出的PWM总数
}Motor_t;
void CurveS_init(uint16_t *pbuff,uint32_t fre_max,uint32_t fre_min,int16_t len);
void SpeedAdjust(void);
void StartPWM(uint32_t PWM);
#endif


#ifndef _SPEED_H
#define _SPEED_H

###main.h中新增

#define TIM1_CLOCK_FREQ 1000000 //定时器1的时钟频率

#define PWM_NUM         20000		//要输出的PWM的步数
#define PWM_Count_Max   8000		//加速度需要的步数

#define PWM_FREQ_MAX	1000	//最大频率
#define PWM_FREQ_MIN    800		//最小频率
#define SIZE1 			PWM_NUM

###main.c中

/* USER CODE BEGIN Includes */
#include "speed.h"
/* USER CODE END Includes */
/* USER CODE BEGIN 0 */
extern Motor_t Motor;
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
StartPWM(PWM_NUM);
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
	/*S型曲线加速*/
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
	/*S型曲线加速*/
	Motor.PWMcount++;
	SpeedAdjust();//速度调节

}

##程序功能描述
程序启动后,累计输出PWM_NUM(20000)个脉冲,其中加速步数PWM_Count_Max个(8000),最大频率为PWM_FREQ_MAX(1000Hz),最小频率为PWM_FREQ_MIN(800Hz)定时器1的时钟频率1000000是50M经过50分频之后的结果。
其中PWM_NUM为总的脉冲数,PWM_Count_Max为S型曲线加速中的前一部分,最大频率1000Hz决定了加速过程中的最大速度。PWM_FREQ_MIN决定了加速过程中的最小速度,因为步进电机的速度在一定范围内和脉冲的频率呈正相关。
如果想要在S型曲线加速结束后步进电机还能继续转动,把SpeedAdjust()函数中的HAL_TIM_PWM_Stop_IT(&htim1,TIM_CHANNEL_2);注释掉即可。

### 实现步进电机不同运动模式的Simulink仿真 #### 直线运动仿真的实现 对于直线运动,可以采用线性插值的方法来生成所需的位移随时间的变化关系。在线性插值下,物体沿一条直线移动,在起始位置和目标位置之间均匀加速或减速直到达到恒定的速度[^1]。 在Simulink环境中创建模时,可以通过加入`Ramp`模块作为输入信号源,该模块能够提供随着时间线性增加或者减少的输出,非常适合用来模拟这种类的运动。接着连接一个积分器(Integrator),它会将斜坡函数转换成相应的位移量。最后通过设置合适的增益(Gain)调整速度大小并将其接入到代表负载系统的子系统中去完成整个闭环控制系统的设计。 ```matlab % 创建一个新的SIMULINK模文件 new_system('Straight_Line_Motion') open_system('Straight_Line_Motion') % 添加必要的组件 add_block('simulink/Sources/Ramp', 'Straight_Line_Motion/Ramp'); add_block('simulink/Continuous/Integrator', 'Straight_Line_Motion/Position Integrator'); % 设置参数 set_param('Straight_Line_Motion/Ramp','Slope','0.5'); % 斜率决定速度 connect_blocks({'Ramp','Position Integrator'},'Straight_Line_Motion'); ``` #### S运动仿真的实现 为了实现更自然流畅的启动停止过程,通常会选择使用具有连续可导特性的S形曲线来进行轨迹规划。这可通过引入三次样条或者其他高阶多项式形式来达成目的;特别是当涉及到多个关节协调运作的情况下更为重要。 具体来说,在Simulink里构建这样的路径规划算法,推荐利用MATLAB Function block编写自定义代码片段计算每一步所需的位置增量Δθ(t)=f(t),其中t表示当前时刻而f()则是预先设定好的数学表达式描述了理想状态下角位移随时间演化的规律。之后再经过一系列微分运算得到瞬时角速度ω以及角加速度α供后续环节调用即可形成完整的控制回路结构。 ```matlab function theta_dot = fcn(t, T_total) %% 定义S曲线方程 a = (pi / 2); b = pi; k = @(tau)((a * sin(b*tau)) + ((b/(2*a))*(cos(2*b*tau)-1))); tau = t/T_total; if tau >= 1, theta_dot = 1; elseif tau <= 0, theta_dot = 0; else theta_dot = k(tau); end end ``` #### 正弦曲线运动仿真的实现 如果希望让执行机构按照周期性波动的方式运行,则可以选择基于正弦波的形式设计其动作指令序列。这种方式不仅简单直观而且易于理解和实施,只需要借助于内置的Sinusoidal Waveform Generator元件就能轻松搞定一切工作。 需要注意的是为了让实际效果更加逼真贴近真实情况往往还需要额外考虑诸如相位偏置Phase Offset、频率Frequency调节等因素的影响从而使得最终呈现出的画面既美观又实用。 ```matlab % 打开现有的SIMULINK项目 open_system('Sine_Curve_Motion') % 插入正弦发生器 add_block('simulink/Sources/Sine Wave', 'Sine_Curve_Motion/SinGen'); % 调整属性以匹配需求 set_param('Sine_Curve_Motion/SinGen',... 'Amplitude','1',... 'Bias','0',... 'Frequency','0.5',... 'Phase','90'); connect_blocks({'SinGen','Motor Control System'},'Sine_Curve_Motion'); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值