梯形加减速算法原理优缺点及对步进电机的控制

2024-04-03 08:52

本文主要是介绍梯形加减速算法原理优缺点及对步进电机的控制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

步进电机梯形加减速实现

1. 梯形加减速算法原理详解

1.1. 算法特点

1.2. 算法基础概念及方程

1.3. 直线加减速模型解析

1.4. 脉冲时间间隔的精确计算

1.5. 加减速度与步数的关系

1.6. 算法理论实现

1.6.1. 设置计算

1.6.2. 加减速情况分析

1.6.3. 第一种情况

1.6.4. 第二种情况

1.7. 中断状态区分

2. 梯形加减速算法实现


步进电机梯形加减速实现

加减速使用的场景有那些呢?

为什么要使用加减速呢?当硬件驱动细分器与软件的细分参数或定时器分频参数设置不当时启动电机时, 会遇见步进电机有啸叫声但是不会转动,这是因为软件产生脉冲的频率大于步进电机的启动频率,步进电机有一个很重要的技术参数: 空载启动频率,也就是在没有负载的情况下能够正常启动的最大脉冲频率,如果脉冲频率大于该值,步进电机则不能够正常启动, 发生丢步或者堵转的情况;或者也可以理解为由于步进脉冲变化过快,转子由于惯性的作用跟不上电信号的变化。 所以要使用加减速来解决启动频率低的问题,在启动时使用较低的脉冲频率,然后逐渐的加快频率。

步进电机加减速使用的场景有有哪些呢?步进电机加减速使用的场景可以说是多种多样,但是大部分在一些工业上,例如CNC雕刻机、 3D打印机、车床等。只要是在工业上使用到步进电机的都会涉及到加减速,可见加减速算法的重要性。

1. 梯形加减速算法原理详解

1.1. 算法特点

为了使得不出现丢步或者超步现象并且提高效率,需要使得步进电机先以固定的加速度达到目标速度,然后以这个速度运行, 快到达目标步数时再减到最低速;整个过程是一个梯形的模型,所以以它的数学模型命名的加减速算法。

梯形加减速基本数学模型

从模型中即可反映出算法的特点,数学模型中一共分为三个阶段,OA加速部分、AB匀速部分和BC减速部分。

  • 在OA加速过程中,由低于步进电机的启动频率开始启动(模型中由0启动),以固定的加速度增加速度到目标值;

  • 在AB匀速过程中,以最大速度匀速运动;

  • 在BC减速部分中,以加速度不变的速度递减到0;

这种算法是一种在加速过程和减速过程中加速度不变的匀变速控制算法, 由于速度变化的曲线有折点,所以在启动、停止、匀速段中很容易产生冲击和振动。

1.2. 算法基础概念及方程

步进电机的转动需要控制器发送脉冲,如果控制器以恒定速度发送脉冲,那么步进电机就以恒定速度转动; 如果控制器以加速度运动,那么步进电机就以加速度运动;所以只要改变脉冲的频率就可以改变速度的变化, 也就是说调整脉冲之间的时间间隔就可以改变速度。

../_images/step_pluse.png

上图为步进电机与时间的示意图,其中

  • t0 表示脉冲发送的起始时刻

  • t1 表示脉冲发送的第二个时刻

  • t2 表示脉冲发送的第三个时刻

  • tt 表示定时器的计数周期

  • c0 表示定时器从t0~t1时刻的定时器计数值

  • c1 表示定时器从t1~t2时刻的定时器计数值

  • δt 表示两个脉冲之间的间隔时间

以stm32的高级定时器8为例,定时器8的时钟频率为168MHZ,如果将分频值设置为5,那么定时器的时钟频率则为:ft=168/(5+1)=28MHZ, 相当于计数28M次正好为一秒,周期与频率为倒数关系,所以分频值为5的定时器8的计数周期为:1/ft;

../_images/基础公式1.png

其中 :

  • n 为步进电机所转的脉冲数

  • s 为时间单位 秒

  • spr 为步进电机所转一圈的脉冲数

  • rad 为弧度单位 (1rad = (180/π)° ≈ 57.3°)

  • rad/sec 弧度每秒; 1圈(revolutions) = 2 * 3.1415弧度(rad); (1 rad/sec = 60*1/(2*3.1415) rev/min = 9.55 rpm); 1 rad/sec=9.55 rpm;

1.3. 直线加减速模型解析

在本章的一开始就已经简单的介绍了一下加减速算法的模型

模型阶段分析:

../_images/直线模型.png

要使得步进电机平稳的启动和停止,则需要控制好步进电机的加速度和减速度,控制好加速度和减速度就可得到好的曲线模型, 上图中一共是三个不同变量与时间的变化曲线,分别是 加速度与时间、速度与时间和位置与时间的曲线

在三个模型中的跳变位置已经画上对应的虚线,分别为虚线a、虚线b、虚线c和虚线d

  1. 起始点~a:在这阶段中,速度、加速度、位置都没有变化;

  2. a~b阶段:从虚线a开始,在这阶段中加速度不变,速度与位置不断上升,并且速度是以恒定加速度上升,上升到最大速度也就是速度曲线与虚线b的交点;

  3. b~c阶段:在这阶段中,以不变的速度在运行,由于速度不变,则加速度为零,并且位置在这阶段呈现一个一次函数的上升阶段;

  4. c~d阶段:在这阶段中,速度开始呈匀减速的状态,所以加速度为负值,但是位置依旧上升,但上升曲线逐渐变慢;

进一步理解:

在已经对模型的几个阶段有所了解后,下面对加速部分进一步讲解;

../_images/速度时间脉冲位置.png

上图中分别是对 ω-t和θ-t 的变化图:

在 ω-t 图中是梯形加减速模型中的加速部分中,红色竖线表示的是脉冲发生的位置,由加速的方向看(从左到右), 在图上两个相邻之间的脉冲之间的距离越来越近,根据 δt=ct 计数周期不变,计数值越来越小也就意味着脉冲之间的间隔时间变短了, 频率变快了,直接影响步进电机转的变快了;所以说脉冲之间的定时器计数值是影响脉冲频率变化的重要因素。

在 θ-t 图中,脉冲每产生一次就对应着θ轴上的一小格,ω-t 图中工产生6次脉冲就对应 θ-t 中的6次位置的变化。

1.4. 脉冲时间间隔的精确计算

脉冲间隔决定速率变化,所以对于脉冲的时间间隔计算 就显得尤为重要。

时间间隔的计算由以下几个公式推导出来:

../_images/位置.png

注:n表示脉冲个数;α表示步距角;

在第n个时刻的脉冲角度,所以  就是n个脉冲实际旋转的角度;这里可以说是角度也可以说是位置,单纯说一个脉冲那就是一个步距角, 那么电机与丝杆滑台联系到一起那最终作用到的就是滑台的位置移动了。

../_images/位移与速度公式.png

对于这个公式应该都不陌生,物理学中的匀加速运动的距离公式,在梯形加减速中加速部分就是匀加速运动。 当v0=0,并且将相关变量带入得:

../_images/匀加速直线运动.png

注: S表示位移;w表示加速度;tn表示时间点

将上述公式整理为:

../_images/时间公式.png

可以将上述理解为两个时间点,那么相邻脉冲的时间点的差值就是脉冲的时间间隔; 所以计数器的时间间隔公式为:

../_images/计数器时间间隔.png

将n与n+1带入公式4并且提出公因式即可得到公式6,将公式6左右两侧除以tt,即可得到公式7。

../_images/公式8-9.png

当n=0带入公式7,括号内的数值为1,并且算出第一次产生脉冲的计数值C0;仔细观察公式8与公式7,发现可以将公式8直接带入到公式7,即可得到公式9; 此时第n次的脉冲间隔的计数值只与第一次的计数值和次数有关。

由于计算的过程中需要进行开方运算,微控制器的计算能力有限,因此在此使用泰勒公式进行泰勒级数逐级逼近的方法。 在这里主要是用的是泰勒公式的特例—— 麦克劳林公式 ;具体如下图:

../_images/公式10.png

为构造与麦克劳林相同的公式将 n-1 ,并且与公式9做比值处理,并进行化简计算,具体如下图所示:

../_images/公式推导.png

公式推导一共分为以下5个步骤推导:

  1. 步骤1是将 n 与 n-1 分别带入到公式9;

  2. 分子分母提出C0和根号n,并将其约掉;

  3. 整理化简根号下的内容;

  4. 将麦克劳林公式带入;

  5. 忽略无穷下余项,化简求得;

将其化简为关于Cn的式子如下:

../_images/公式11.png

这样就避免了开方两次的问题,由于在化简时舍弃了无穷小余项,所以验证下化简前后的误差:

../_images/误差计算.png

当 n=1 时,分别带入以上两个式子,求得其结果,发现出现偏差,但是可以通过将化简后的C0乘以一个0.69的参数进行矫正这个误差。

1.5. 加减速度与步数的关系

根据上一小节推导的公式可得:

../_images/加速度与步数关系.png

  1. 这是初速度为0的匀加速运动的基础方程,只不过其中一些变量是与具体参数有关的,具体可以参考上一小节的公式;

  2. 步距角与步数的乘积相当于旋转角度,或者位置;

  3. 将(1)与(2) 的关系式联系起来就是公式(3);

  4. 根据V=V0+at,初始速度为0得V=at,再将其带入相关变量;

  5. 将公式(4)带入公式(5)

在上述公式中有相关变量分别为:步数、加速度、速度和步距角四个变量,由于步距角是一个固定值, 所以当速度设置为最大值时步数就与加速度成反比,也就是当加速度小的时候需要较多的步数,当加速度大的时候需要较少的步数就可以到达目标速度。

由于步进电机 加速到最大的时候速度与其刚开始减速时的速度一样 ,具体看下图:

../_images/updown.png

根据上图,我们只要修改步数就可以修改加速度的数值, 所以有以下公式:

../_images/公式12.png

当初始速度和末速度都为0并且给定步数时,为了得到加速的步数,将公式12整理得:

../_images/公式13.png

  1. 将公式12写到这里;

  2. 将等式两端分别加上同一项,保证等式;

  3. 将等式两端分别提出公因式;

  4. 将左侧除n1外多余的项移到右侧;即可得到公式13;

1.6. 算法理论实现

由于算法在计算过程中涉及到一些浮点型运算,大量的浮点型运算会使得效率大大降低为了使在计算浮点型的速度得到更好的优化, 所以这一小节主要讲解由算法到代码的一些变量参数的放大转换过程和一些相关算法的不同情况。

../_images/速度模型.png

控制步进电机需要四个描述速度曲线的参数;速度曲线从零速度开始,加速到给定速度并持续到减速开始,并且最后减速至零给定步数的速度。

  • step 需要移动的步数

  • accel 加速度

  • decel 减速度

  • speed 最大速度

1.6.1. 设置计算

最小间隔

根据前几小节可有一下公式:

../_images/最小时间间隔.png

在上图中最终得出的是间隔时间与速度的函数关系式;其中步距角与定时器的频率为定值,所以说速度与脉冲时间间隔成反比;

最小时间间隔公式

在这里将步距角与定时器的频率放大100倍,并将数值赋值给变量 A_T_x100 所以最小的时间间隔的公式就为 min_delay=A_T_x100/speed ;

C0

以下是加速度相关的参数:

../_images/T1_FREQ_148.png

../_images/step_delay.png

../_images/C0公式.png

以上两个关于C0的是带入参数后的式子和原始的式子,在 step_delay 中参数 T1_FREQ_148 矫正了误差并且将其缩 小10的两次方倍,将A_SQ放大10十次方倍,由于放大倍数是在根号下放大的10的10次方,开根号后就是5次方,加速度也放大10的二次方倍, 在除以100,正好就是与原始相等;(具体运算如下图)

../_images/放大倍数的公式推导.png

  • 步骤(1)中是原始式子

  • 步骤(2)矫正误差并且将放大的倍数分解

  • 步骤(3)整理分解的倍数

  • 步骤(4)最后的结果只与原始有误差矫正的区别

以上的整理说明,即使放大或者缩小了部分参数的倍数只要保证结果不变,会给计算带来很大的便利。

1.6.2. 加减速情况分析

对于加减速的情况来说,由于已经设定好了步进电机加速度、减速度、最大速度和步数,所以说一共分为两种情况:

第一种情况:持续加速到最大速度然后再减速到0

第二种情况:在没达到最大速度之前就需要开始减速到0

1.6.3. 第一种情况

../_images/情况一.png

根据上图可以很明显的看到7个参数,其中

  • speed: 算法设置的最大速度;

  • accel:加速度;

  • decel:加速度;

  • step :总步数;

以上的参数都是程序里面直接给出的,不需要求解。

  • max_s_lim:速度从0加速到speed所需的步数;

  • accel_lim:在忽略虽大速度的情况下,开始减速之前的步数,也可以理解为加速度曲线与减速度曲线的交点;

  • decel_val:实际减速的步数;

以上的参数都是需要根据前面的计算推导求解的。

max_s_lim:

根据速度与路程的物理公式,所以有以下公式:

../_images/速度路程-2ax.png

并将其图中相关参数带入,具体如下图:

../_images/速度平方.png

注:speed是扩大100倍后的数值,那么平方就是10000倍,所以分子需要乘以100,才能保证结果不变

accel_lim:

最大的加速步数公式推导可以参考 加减速度与步数的关系 章节;

../_images/accel_lim.png

如果 max_s_lim <accel_lim ,则通过达到所需速度来限制加速度;所以 减速度取决于此,在这种情况下,通过以下方法找到decal_val:

decel_val:

根据公式12可以直接推出decel_val的表达式;但是由于是减速度的步数,所以需要带上负号,具体公式如下图:

../_images/decel_val.png

1.6.4. 第二种情况

../_images/情况二.png

这种情况是在还未达到最大速度时就已经开始减速了;其中 accel_lim、max_s_lim 不需要重复计算了;

当 max_s_lim>accel_lim 时,如上图加速受减速开始的限制,所以 decel_val 表达式为:

../_images/decal_val2.png

1.7. 中断状态区分

../_images/梯形状态图.png

上图表现的是速度在数学模型中的几个阶段性速度,具体看上图。

../_images/状态机.png

上图是这几个状态机之间切换的的关系图:

  • 第一种情况 :当步数为1时,毫无疑问直接进入到减速阶段然后到停止状态

  • 第二种情况 :当步数大于1,并且会加到最大速度,会经过:加速状态->匀速状态->减速状态->停止状态

  • 第三种情况 :当步数大于1,并且不会加到最大速度,会经过:加速状态->减速状态->停止状态

对于加减速的每一步来说,都需要重新计算下一步的时间,计算的过程中可能会出现除不尽的项式, 为了更有利的加减速,可以采用加速向上取整,减速向下取整的原则来做运算,也可以采用余数累计的方法, 在这里使用的是将余数累计的方法来提高间隔时间的精度和准确性。

根据公式11可有:

../_images/new_step_delay.png

2. 梯形加减速算法实现

stepper_init.h

#ifndef __BSP_STEP_MOTOR_INIT_H
#define	__BSP_STEP_MOTOR_INIT_H#include "stm32f4xx.h"
#include "stm32f4xx_hal.h"
#include "./stepper/bsp_stepper_T_speed.h"/*宏定义*/
/*******************************************************/
//宏定义对应开发板的接口 0、1 、2 、3 、4
#define CHANNEL_SW 0#if(CHANNEL_SW == 0)
//Motor 方向 
#define MOTOR_DIR_PIN                  	GPIO_PIN_14
#define MOTOR_DIR_GPIO_PORT            	GPIOB  
#define MOTOR_DIR_GPIO_CLK_ENABLE()   	__HAL_RCC_GPIOB_CLK_ENABLE()//Motor 使能 
#define MOTOR_EN_PIN                  	GPIO_PIN_12
#define MOTOR_EN_GPIO_PORT            	GPIOB                      
#define MOTOR_EN_GPIO_CLK_ENABLE()    	__HAL_RCC_GPIOB_CLK_ENABLE()//Motor 脉冲
#define MOTOR_PUL_IRQn                  TIM8_CC_IRQn
#define MOTOR_PUL_IRQHandler            TIM8_CC_IRQHandler#define MOTOR_PUL_TIM                   TIM8
#define MOTOR_PUL_CLK_ENABLE()          __TIM8_CLK_ENABLE()#define MOTOR_PUL_PORT                  GPIOC
#define MOTOR_PUL_PIN                   GPIO_PIN_6
#define MOTOR_PUL_GPIO_CLK_ENABLE()     __HAL_RCC_GPIOC_CLK_ENABLE()#define MOTOR_PUL_GPIO_AF               GPIO_AF3_TIM8
#define MOTOR_PUL_CHANNEL_x             TIM_CHANNEL_1#define MOTOR_TIM_IT_CCx                TIM_IT_CC1
#define MOTOR_TIM_FLAG_CCx              TIM_FLAG_CC1#elif(CHANNEL_SW == 1)
//Motor 方向 
#define MOTOR_DIR_PIN                  	GPIO_PIN_7   
#define MOTOR_DIR_GPIO_PORT            	GPIOE                    
#define MOTOR_DIR_GPIO_CLK_ENABLE()   	__HAL_RCC_GPIOE_CLK_ENABLE()//Motor 使能 
#define MOTOR_EN_PIN                  	GPIO_PIN_0
#define MOTOR_EN_GPIO_PORT            	GPIOD                       
#define MOTOR_EN_GPIO_CLK_ENABLE()    	__HAL_RCC_GPIOD_CLK_ENABLE()//Motor 脉冲
#define MOTOR_PUL_IRQn                  TIM1_CC_IRQn
#define MOTOR_PUL_IRQHandler            TIM1_CC_IRQHandler#define MOTOR_PUL_TIM                   TIM1
#define MOTOR_PUL_CLK_ENABLE()  		    __TIM1_CLK_ENABLE()#define MOTOR_PUL_PORT       			      GPIOE
#define MOTOR_PUL_PIN             		  GPIO_PIN_9
#define MOTOR_PUL_GPIO_CLK_ENABLE()		  __HAL_RCC_GPIOE_CLK_ENABLE()#define MOTOR_PUL_GPIO_AF               GPIO_AF1_TIM1
#define MOTOR_PUL_CHANNEL_x             TIM_CHANNEL_1#define MOTOR_TIM_IT_CCx                TIM_IT_CC1
#define MOTOR_TIM_FLAG_CCx              TIM_FLAG_CC1
#elif(CHANNEL_SW == 2)
//Motor 方向 
#define MOTOR_DIR_PIN                  	GPIO_PIN_12   
#define MOTOR_DIR_GPIO_PORT            	GPIOE                    
#define MOTOR_DIR_GPIO_CLK_ENABLE()   	__HAL_RCC_GPIOE_CLK_ENABLE()//Motor 使能 
#define MOTOR_EN_PIN                  	GPIO_PIN_10
#define MOTOR_EN_GPIO_PORT            	GPIOE                       
#define MOTOR_EN_GPIO_CLK_ENABLE()    	__HAL_RCC_GPIOE_CLK_ENABLE()//Motor 脉冲
#define MOTOR_PUL_IRQn                  TIM1_CC_IRQn
#define MOTOR_PUL_IRQHandler            TIM1_CC_IRQHandler#define MOTOR_PUL_TIM                   TIM1
#define MOTOR_PUL_CLK_ENABLE()  		    __TIM1_CLK_ENABLE()#define MOTOR_PUL_PORT       			      GPIOE
#define MOTOR_PUL_PIN             		  GPIO_PIN_11
#define MOTOR_PUL_GPIO_CLK_ENABLE()		  __HAL_RCC_GPIOE_CLK_ENABLE()#define MOTOR_PUL_GPIO_AF               GPIO_AF1_TIM1
#define MOTOR_PUL_CHANNEL_x             TIM_CHANNEL_2#define MOTOR_TIM_IT_CCx                TIM_IT_CC2
#define MOTOR_TIM_FLAG_CCx              TIM_FLAG_CC2
#elif(CHANNEL_SW == 3)
//Motor 方向 
#define MOTOR_DIR_PIN                  	GPIO_PIN_15   
#define MOTOR_DIR_GPIO_PORT            	GPIOE                    
#define MOTOR_DIR_GPIO_CLK_ENABLE()   	__HAL_RCC_GPIOE_CLK_ENABLE()//Motor 使能 
#define MOTOR_EN_PIN                  	GPIO_PIN_9
#define MOTOR_EN_GPIO_PORT            	GPIOD                       
#define MOTOR_EN_GPIO_CLK_ENABLE()    	__HAL_RCC_GPIOD_CLK_ENABLE()//Motor 脉冲
#define MOTOR_PUL_IRQn                  TIM1_CC_IRQn
#define MOTOR_PUL_IRQHandler            TIM1_CC_IRQHandler#define MOTOR_PUL_TIM                   TIM1
#define MOTOR_PUL_CLK_ENABLE()  		    __TIM1_CLK_ENABLE()#define MOTOR_PUL_PORT       			      GPIOE
#define MOTOR_PUL_PIN             		  GPIO_PIN_13
#define MOTOR_PUL_GPIO_CLK_ENABLE()		  __HAL_RCC_GPIOE_CLK_ENABLE()#define MOTOR_PUL_GPIO_AF               GPIO_AF1_TIM1
#define MOTOR_PUL_CHANNEL_x             TIM_CHANNEL_3#define MOTOR_TIM_IT_CCx                TIM_IT_CC3
#define MOTOR_TIM_FLAG_CCx              TIM_FLAG_CC3
#elif(CHANNEL_SW == 4)
//Motor 方向 
#define MOTOR_DIR_PIN                  	GPIO_PIN_8   
#define MOTOR_DIR_GPIO_PORT            	GPIOD                    
#define MOTOR_DIR_GPIO_CLK_ENABLE()   	__HAL_RCC_GPIOD_CLK_ENABLE()//Motor 使能 
#define MOTOR_EN_PIN                  	GPIO_PIN_10
#define MOTOR_EN_GPIO_PORT            	GPIOD                       
#define MOTOR_EN_GPIO_CLK_ENABLE()    	__HAL_RCC_GPIOD_CLK_ENABLE()//Motor 脉冲
#define MOTOR_PUL_IRQn                  TIM1_CC_IRQn
#define MOTOR_PUL_IRQHandler            TIM1_CC_IRQHandler#define MOTOR_PUL_TIM                   TIM1
#define MOTOR_PUL_CLK_ENABLE()  		    __TIM1_CLK_ENABLE()#define MOTOR_PUL_PORT       			      GPIOE
#define MOTOR_PUL_PIN             		  GPIO_PIN_14
#define MOTOR_PUL_GPIO_CLK_ENABLE()		  __HAL_RCC_GPIOE_CLK_ENABLE()#define MOTOR_PUL_GPIO_AF               GPIO_AF1_TIM1
#define MOTOR_PUL_CHANNEL_x             TIM_CHANNEL_4#define MOTOR_TIM_IT_CCx                TIM_IT_CC4
#define MOTOR_TIM_FLAG_CCx              TIM_FLAG_CC4
#endif/****************************************************************/#define HIGH GPIO_PIN_SET	      //高电平
#define LOW  GPIO_PIN_RESET	    //低电平#define ON  HIGH	              //开
#define OFF LOW	                //关#define CW 	LOW		              //顺时针
#define CCW HIGH      	        //逆时针//控制使能引脚
/* 带参宏,可以像内联函数一样使用 */
#define MOTOR_EN(x)					HAL_GPIO_WritePin(MOTOR_EN_GPIO_PORT,MOTOR_EN_PIN,x)
#define MOTOR_PUL(x)				HAL_GPIO_WritePin(MOTOR_PUL_GPIO_PORT,MOTOR_PUL_PIN,x)
#define MOTOR_DIR(x)				HAL_GPIO_WritePin(MOTOR_DIR_GPIO_PORT,MOTOR_DIR_PIN,x)#define MOTOR_EN_TOGGLE     HAL_GPIO_TogglePin(MOTOR_EN_GPIO_PORT,MOTOR_EN_PIN)
#define MOTOR_PUL_TOGGLE    HAL_GPIO_TogglePin(MOTOR_PUL_PORT,MOTOR_PUL_PIN)//输出比较模式周期设置为0xFFFF
#define TIM_PERIOD                   0xFFFF//函数以及变量声明
extern TIM_HandleTypeDef TIM_TimeBaseStructure;
void stepper_Init(void);
void stepper_move_T(int32_t step, uint32_t accel, uint32_t decel, uint32_t speed);#endif

速度决策

/**
* @brief  速度决策
*   @note   在中断中使用,每进一次中断,决策一次
* @retval 无
*/
void speed_decision()
{uint32_t tim_count=0;uint32_t tmp = 0;// 保存新(下)一个延时周期uint16_t new_step_delay=0;// 加速过程中最后一次延时(脉冲周期).static uint16_t last_accel_delay=0;// 总移动步数计数器static uint32_t step_count = 0;static int32_t rest = 0;//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲static uint8_t i=0;if(__HAL_TIM_GET_IT_SOURCE(&TIM_TimeBaseStructure, MOTOR_TIM_IT_CCx) !=RESET){// 清楚定时器中断__HAL_TIM_CLEAR_IT(&TIM_TimeBaseStructure, MOTOR_TIM_IT_CCx);// 设置比较值tim_count=__HAL_TIM_GET_COUNTER(&TIM_TimeBaseStructure);tmp = tim_count+srd.step_delay;__HAL_TIM_SET_COMPARE(&TIM_TimeBaseStructure,MOTOR_PUL_CHANNEL_x,tmp);i++;     // 定时器中断次数计数值if(i==2) // 2次,说明已经输出一个完整脉冲{i=0;   // 清零定时器中断次数计数值switch(srd.run_state){/*步进电机停止状态*/case STOP:step_count = 0;  // 清零步数计数器rest = 0;        // 清零余值// 关闭通道TIM_CCxChannelCmd(MOTOR_PUL_TIM, MOTOR_PUL_CHANNEL_x, TIM_CCx_DISABLE);__HAL_TIM_CLEAR_FLAG(&TIM_TimeBaseStructure, MOTOR_TIM_FLAG_CCx);status.running = FALSE;break;/*步进电机加速状态*/case ACCEL:step_count++;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);// 计算余数,下次计算补上余数,减少误差//检查是够应该开始减速if(step_count >= srd.decel_start) {srd.accel_count = srd.decel_val;srd.run_state = DECEL;}//检查是否到达期望的最大速度else if(new_step_delay <= srd.min_delay) {last_accel_delay = new_step_delay;new_step_delay = srd.min_delay;rest = 0;srd.run_state = RUN;}break;/*步进电机最大速度运行状态*/case RUN:step_count++;new_step_delay = srd.min_delay;//检查是否需要开始减速if(step_count >= srd.decel_start){srd.accel_count = srd.decel_val;//以最后一次加速的延时作为开始减速的延时new_step_delay = last_accel_delay;srd.run_state = DECEL;}break;/*步进电机减速状态*/case DECEL:step_count++;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);// 计算余数,下次计算补上余数,减少误差//检查是否为最后一步if(srd.accel_count >= 0){srd.run_state = STOP;}break;}/*求得下一次间隔时间*/srd.step_delay = new_step_delay;}}
}

代码讲解:

8~18行 在函数内部定义临时变量和静态变量,用于中断内算法的相关计算推导;

20~23行 判断当前是否为 TIM_TimeBaseStructure 中断的通道1;

26~28行 在26行中使用HAL库函数 __HAL_TIM_GET_COUNTER() 来获取当前计数器的数值,并且将其返回给 tim_count 并且计算下一次需要的数值,使用 __HAL_TIM_SET_COMPARE() 设置比较值;

30~33行 由于进入中断两次才能输出一个完整脉冲,所以在这只对进入中断的次数进行一个偶数化;

37~45行 接下来这部分就是对步进电机的运行状态的分析,

37~45行是 STOP 状态,在停止状态主要是关闭当前步进电机的通道以及清除中断标志位;

47~65行 这部分是加速状态,在加速状态中需要时刻计算下一次的脉冲间隔时间,由于加减速分为两种情况,这两种情况可以参考 加减速情况分析 所以需要判断当前的步数是否到达了需要减速步数或者已经达到了设置的最大速度需要开始减速了,根据不同条件判断下一状态;

67~81行 这部分是以最大速度运行的状态;如果说在加速阶段判断下一阶段可以达到最大速度,那么就会跳转到这个状态中,那么这个状态的下一状态一定是减速, 所以说需要在这部分使用步数 step_count 的条件来判断是否到达了减速阶段;

83~94行 这部分是以减速度运行的状态,有可能是从匀速状态或者是加速状态跳转过来的,并且求得下一次的脉冲时间间隔;

97行 将新求得的间隔时间赋值给结构体成员,方便下一次调用;

stepper_move_T() 这个函数主要是对给定步数和加减速度等参数的计算,将加减速整个过程的最大速度位置最小速度位置以及到达加减速区域的步数等。 具体的代码实现,可以看以下代码。

/*! \brief 以给定的步数移动步进电机*  通过计算加速到最大速度,以给定的步数开始减速*  如果加速度和减速度很小,步进电机会移动很慢,还没达到最大速度就要开始减速*  \param step   移动的步数 (正数为顺时针,负数为逆时针).*  \param accel  加速度,如果取值为100,实际值为100*0.01*rad/sec^2=1rad/sec^2*  \param decel  减速度,如果取值为100,实际值为100*0.01*rad/sec^2=1rad/sec^2*  \param speed  最大速度,如果取值为100,实际值为100*0.01*rad/sec=1rad/sec*/
void stepper_move_T( int32_t step, uint32_t accel, uint32_t decel, uint32_t speed)
{//达到最大速度时的步数.unsigned int max_s_lim;//必须开始减速的步数(如果还没加速到达最大速度时)。unsigned int accel_lim;/*根据步数和正负判断*/if(step == 0){return ;}else if(step < 0)//逆时针{srd.dir = CCW;step = -step;}else//顺时针{srd.dir = CW;}      // 输出电机方向MOTOR_DIR(srd.dir);// 如果只移动一步if(step == 1){// 只移动一步srd.accel_count = -1;// 减速状态srd.run_state = DECEL;// 短延时srd.step_delay = 1000;// 配置电机为运行状态status.running = TRUE;}// 步数不为零才移动else if(step != 0){// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。// min_delay = (alpha / tt)/ wsrd.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) )/100srd.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;}// 使用限制条件我们可以计算出第一次开始减速的位置//srd.decel_val为负数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;status.running = TRUE;}/*获取当前计数值*/int tim_count=__HAL_TIM_GET_COUNTER(&TIM_TimeBaseStructure);/*在当前计数值基础上设置定时器比较值*/__HAL_TIM_SET_COMPARE(&TIM_TimeBaseStructure,MOTOR_PUL_CHANNEL_x,tim_count+srd.step_delay);/*使能定时器通道*/TIM_CCxChannelCmd(MOTOR_PUL_TIM, MOTOR_PUL_CHANNEL_x, TIM_CCx_ENABLE);MOTOR_EN(ON);
}

11~15行 定义最大速度需要的步数和开始减速的步数变量;

17~30行 这部分是对步数的判断和方向的设置;

46~106行 这部分是针对加减速模型所需要的的一些计算;具体推导过程可以参考 算法基础概念及方程 章节中的内容;

108~113行 获取当前计数值,根据计算设置第一次的比较值并开启使能驱动器;

这篇关于梯形加减速算法原理优缺点及对步进电机的控制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/872462

相关文章

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

hdu4407(容斥原理)

题意:给一串数字1,2,......n,两个操作:1、修改第k个数字,2、查询区间[l,r]中与n互质的数之和。 解题思路:咱一看,像线段树,但是如果用线段树做,那么每个区间一定要记录所有的素因子,这样会超内存。然后我就做不来了。后来看了题解,原来是用容斥原理来做的。还记得这道题目吗?求区间[1,r]中与p互质的数的个数,如果不会的话就先去做那题吧。现在这题是求区间[l,r]中与n互质的数的和

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费