STM32通过TB6600驱动步进电机实现梯形加减速

您所在的位置:网站首页 42步进电机的扭矩 STM32通过TB6600驱动步进电机实现梯形加减速

STM32通过TB6600驱动步进电机实现梯形加减速

2024-07-12 06:52| 来源: 网络整理| 查看: 265

目录

1 注意事项

1.1 接线

1.2 电源选择

1.3 支架选择与转向

2 STM32的控制代码

2.1 输入参数

2.2 运行距离的计算

2.3 STM32与TB6600接线

2.4 代码

1 注意事项 1.1 接线

       使用梯形加减速能够使步进电机快速达到运行速度,适用于响应要求高,运行速度快的要求场景,在比赛中,步进电机也是常用的电机种类之一,是开环中运行精度最高的一档。实验中使用的步进电机为42步进电机,接线方式采用共阳极接线,即将TB6600驱动器的脉冲正(PUL+)、方向正(DIR+)、使能正(ENA+)三者接在一起、最后有使能正(ENA+)引出,其余的脉冲负(PUL-)、方向负(DIR-)、使能负(ENA-)各自接到控制信号的引脚上,即可完成步进电机的接线(接线图如下)。

       最后接电源线至TB6600即可,电源线应当注意正负极之分、不可反接,实验中的42步进电机使用的步进电机工作电压为24V、额定电流为

1.2 电源选择

       最后接电源线至TB6600即可,电源线应当注意正负极之分、不可反接,实验中的42步进电机使用的步进电机工作电压为24V、额定电流为1.5A、扭矩0.7nm。42步进电机的工作较小,网上购买的24V电池默认的DC接头都能输出最大3a的电流,可直接接入TB6600的电源接口。

       当使用的步进电机的运行电流超过3A时,普通的DC接头则不再满足使用需求,需要更换为XT60航空公母头接线的方式,更粗壮的电线在保证电池的额定输出电流时,也能保证步进电机的扭矩能正常。当电流过低,电压不足时,电机的扭矩会下降,因此,更换大功率步进电机后,电池也需要更换,电池输出线也要更换。

1.3 支架选择与转向

        步进电机的固定支架,小型的42步进电机,可直接选用购买时的默认支架,当使用体积的庞大,重量大的57(单电机质量5KG)、86(单电机质量10KG)步进电机时,需要考虑支架的强度,且在使用大体积,大质量步进电机时,单靠步进电机的差速无法实现转向,需要引进专门的转向机构。转向机构的选择可参考舵轮的转向结构

2 STM32的控制代码 2.1 输入参数

     stm32端的控制代码输入端较为简单,需要输入的参数有:运行距离、加速度、减速度、稳定运行时的速度,一般来说,比赛中需要变更的只有运行距离即可,通过上位机下发命令,运行指定的距离,为了抵达指定的运行距离而减少丢步。需要考虑步进电机的负载不可过大,步进电机的加速度,减速度和运行速度均不可过大,一旦过大,就会存在严重的丢步,导致运行距离达不到理想的位置。

2.2 运行距离的计算

       使用的步进电机为42步进电机,额定扭矩0.7Nm、步距角1.8度,额定电压24V,额定电流1.5A,假使输入的电压、电流都达到了额定值,负载在步进电机的承受范围内,则可根据代码调整TB6600的细分数,我使用的细分数是1600,即1600个脉冲旋转一圈。在代码中,步进电机的细分数为8细分。其计算值为

脉冲数=(圈数/步距角)*细分数

1600=(360/1.8)*8

当要根据赛场上的实际距离去计算时,则可进行距离的二次计算

设车轮的直径(d)为10cm,则其转一圈的位移为:s=\pi d=31.415926535897cm,即1600个脉冲使一个直径10cm的轮子位移了 31.415926535897cm,即可推算出一个脉冲可使轮子运行的距离为0.0196349540849cm,所以距离所需要的脉冲数最终计算公式为

                                                       脉冲数=(目标距离/单脉冲距离行程)

2.3 STM32与TB6600接线

         TB6600                        STM32F103c8t6

          PUL+

          DIR+                             VCC

          EN+ 

        PUL-                             PA6

        DIR-                              PB13

        EN-                               PB14

2.4 代码

Motor.c

#include "stm32f10x.h" // Device header #include "Motor.h" #include "Motor_Init.h" #include speedRampData srd= {STOP,0,0,0,0,0,0}; //加减速变量 uint8_t motor_sta = 0;//电机状态 /* step 移动步数(正数为正转,负数为逆时针) accel 加速度,实际值为accel*0.1*rad/sec^2 10倍并且2个脉冲算一个完整的周期 decel 减速度,实际值为decel*0.1*rad/sec^2 speed 最大速度,实际值为speed*0.1*rad/sec */ void MOTOR_Move(int32_t step, uint32_t accel, uint32_t decel, uint32_t speed) { uint16_t tim_count; //存放中断时刻的计数值 unsigned int max_s_lim; //达到最大速度时的步数 unsigned int accel_lim; //必须开始减速的步数(如果还没有加速度到最大速度时) if(motor_sta!= STOP) //只允许步进电机在停止的时候才继续 return; if(step < 0) //逆时针 { GPIO_SetBits(GPIOB,GPIO_Pin_13); //PA13为方向引脚,输出高电平 step = -step; } else //顺时针 { GPIO_ResetBits(GPIOB,GPIO_Pin_13); //PA13为方向引脚,输出低电平 } if(step == 1) // 如果只移动一步 { srd.accel_count = -1; // 只移动一步 srd.run_state = DECEL; // 减速状态 srd.step_delay = 1000; // 短延时 } else if(step != 0) // 步数不为零才移动 { srd.min_delay = (int32_t)(A_T_x10/speed); // 设置最大速度极限, 计算min_delay用于定时器的计数器的值min_delay = (alpha / tt)/ w srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10); // 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.01rad/sec^2 // step_delay = 1/tt * sqrt(2*alpha/accel) // step_delay = ( tfreq*0.69/10 )*10 * sqrt( (2*alpha*100000) / (accel*10) )/100 max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10)); //计算多少步之后达到最大速度的限制 max_s_lim = speed^2 / (2*alpha*accel) if(max_s_lim == 0) //如果达到最大速度小于0.5步,我们将四舍五入为0,但实际我们必须移动至少一步才能达到想要的速度 { max_s_lim = 1; } accel_lim = (uint32_t)(step*decel/(accel+decel)); // 计算多少步之后我们必须开始减速,n1 = (n1+n2)decel / (accel + decel) if(accel_lim == 0) // 我们必须加速至少1步才能开始减速 { accel_lim = 1; } if(accel_lim = 0) //检查是否为最后一步 是个负数所以要判断 大于等于零时 应该就是减速结束 { srd.run_state = STOP; } break; } srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值 } } } void TIM3_IRQHandler(void) { speed_decision(); }

Motor.h

#ifndef __Motor_H #define __Motor_H #include "stm32f10x.h" // Device header #include "math.h" typedef struct { uint8_t run_state; //电机旋转状态 uint8_t dir ; //电机旋转方向 int step_delay; //下个脉冲周期(时间间隔)启动时为加速度 int decel_start; //启动减速位置 int decel_val; //减速阶段步数 int min_delay; //最小脉冲周期(最大速度,即匀速段的速度) int accel_count; //加速阶段计数值 }speedRampData; #define TRUE 1 #define FALSE 0 /*电机速度决策中的四个状态*/ #define STOP 0 // 停止状态 #define ACCEL 1 // 加速状态 #define DECEL 2 // 减速状态 #define RUN 3 // 匀速状态 #define TIM_PRESCALER 32 #define T1_FREQ (SystemCoreClock/(TIM_PRESCALER+1)) //定时器频率 /*电机单圈参数*/ #define STEP_ANGLE 1.8 //步进电机的步距角 单位:度 #define FSPR 200 //步进电机单圈步数 #define MICRO_STEP 8 //细分器细分数 #define SPR (FSPR*MICRO_STEP) //16细分的步数 //数学常数,用于MSD_MOVE函数的简化计算 #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.69为误差修正值(计算过程,文档中有写) #define A_SQ ((float)(2*100000*ALPHA)) #define A_x200 ((float)(200*ALPHA)) void MOTOR_Move(int32_t step, uint32_t accel, uint32_t decel, uint32_t speed); extern void speed_decision(void); #endif

Motor_Init.c

#include "stm32f10x.h" // Device header #include "Motor_Init.h" #include "Motor.h" //GPIO口初始化 void MOTOR_GPIO_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启PA端口时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启PB端口时钟 /* 步进电机驱动器:脉冲输出PA6 */ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用输出 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /* 步进电机驱动器:方向控制 PB13*/ /* 步进电机驱动器:使能控制PB14 */ GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_14; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); } //定时器初始化 void MOTOR_TIM_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); TIM_InternalClockConfig(TIM3); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频因子,数字滤波采样频率的参数 TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period = 65536-1; //ARR TIM_TimeBaseInitStructure.TIM_Prescaler = TIM_PRESCALER; //PSC TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //高级定时器功能 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCStructInit(&TIM_OCInitStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle; //翻转模式 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0; //CCR 比较值 TIM_OC1Init(TIM3, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Disable); //关闭预装载 TIM_CCxCmd(TIM3,TIM_Channel_1,TIM_CCx_Disable); TIM_ClearFlag(TIM3,TIM_FLAG_CC1); //清除定时器3的通道1的标志位 TIM_ITConfig(TIM3,TIM_IT_CC1,ENABLE); //开启定时器3的通道1中断 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //分组 NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_Init(&NVIC_InitStructure); }

Motor_Init.h

#ifndef __Motor_Init_H #define __Motor_Init_H #include "stm32f10x.h" // Device header #include "math.h" #include "Motor.h" //输出比较模式周期设置为0xFFFF #define TIM_PERIOD 0xFFFF void MOTOR_GPIO_Init(void); void MOTOR_TIM_Init(void); #endif

main.c

#include "stm32f10x.h" // Device header #include "Delay.h" #include "Motor.h" #include "Motor_Init.h" uint32_t set_speed = 1000; // 最大速度设置 单位为0.1rad/sec uint32_t step_accel =25; // 加速度 单位为0.1rad/sec^2 uint32_t step_decel = 25; // 减速度 单位为0.1rad/sec^2 uint32_t step=1600; //extern uint8_t motor_sta ; int main(void) { MOTOR_GPIO_Init(); MOTOR_TIM_Init(); MOTOR_Move(step*20,step_accel,step_decel,set_speed); //需要时调用 while (1) { } }



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3