学习笔记【STM32】|【K60】自动往返小车 步进电机
直接开始
普通42步进电机,A4988驱动
这边博主细布使用拨码开关硬件控制,单片机就接了DIR和pwm
pwm频率控制步进电机转速,但是不能直接改变频率到你的需要的频率,需要逐步增加,这里博主采用的是S型曲线加速方法,还有很多其他的方法梯形、SPA,DMA,slavetimer等等。S 曲线算法由于其加速度和速度曲线的连续性,能够保证步进电机在运动过程中速度和加速度没有突变,减小冲击,提高步进电机运动的平稳性。
网上很多讲这个的,讲的都很细致,这里就不过多介绍了,
https://blog.csdn.net/fengyu19930920/article/details/81043776
https://blog.csdn.net/tianjilieren/article/details/88419120
可以参考这两个博主的帖子,两个都讲的很好
博主的S型加速的c语言方程为
y=1./(1+exp(-x))
把x带入曲线中获得y。
起始点为起始频率Fstart,末尾为我们需要加到的频率Fstop。
'伪’s型加速:
可以把x自加一获得下一个点的频率,然后在32的TIM溢出中断中改变arr实现转速改变,通过一级一级的变化,可以使速度变快。
真s型加速
因为是为了防止加速度突变如果你x设置成等距离的在s的中间最抖的时候不就是突变了吗,所以应该在抖的地方x集中一些,则需要把这个s型曲线“拉伸”一下,在加速度小的x自然放宽,在加速度多的地方x收敛。 固定一个采样点的总数,将s分成两半。
(x - (num/2))
越靠近值越小。
先写这么多。。。。。。
/----------------2018/8/5-------------------------/
今天弄完舵机来更新一下这个
对s型曲线求导
即可以用x-num/2来表示s变化中的x点
这里发一个网上其他找到的
源码地址:https://github.com/MGDG/SLineControl
//len:S曲线的长度,即采样点个数
//FStart:曲线的起始值
//FStop: 曲线的结束值
//flexible:曲线的拉伸变换,越大代表压缩的最厉害,中间(x坐标0点周围)加速度越大;越小越接近匀加速。理想的S曲线 flexible的取值为4-6。
//index: 曲线索引点,区间[0,len]
//Fcurrent:索引点对应的曲线幅值
//
//当FStart len)index = len;
num = len/2;
melo = flexible * (index-num) / num;
deno = 1.0 / (1 + expf(-melo));
Fcurrent = FStart - (FStart-FStop) * deno;
return Fcurrent;
}
S型弄完了步进电机控制部分基本搞定了,然后我想想
uint8_t Front_arrive;
uint8_t Back_arrive;
我最开始是第二那样写的,可以用但是函数一旦多起来车子就不减速了
主要是这个标志位你如何处理
void read_init(u8 x)
{
switch(x)
{
case 0 : Front_arrive = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2) ;
Back_arrive = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3) ;
case 1 : Front_arrive = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3) ;
Back_arrive = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2) ;
}
}
void read_init(u8 x)
{
switch(x)
{
case 0 :
{
if(!GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2)) Front_arrive =1;
if(!GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3)) Back_arrive = 1;
}
case 1 :
if(!GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2)) Back_arrive =1;
if(!GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3)) Front_arrive =1;
}
}
然后判断在主函数的位置
int main(void)
.....
while(1)
{
read_init();
if(!flag&&Front_arrive)
flag = 1;
Front_arrive = 0;
if(flag&&Back_arrive )
{
flag = 0;
Back_arrive = 0;
counts++;
}
switch(counts)
{
case BC_line: status = 0;
break;
case CD_line: status = 0;
break;
case DE_line: status = 2;
break;
case EF_line: status = 0;
break;
case FG_line: status =1;
break;
case GH_line: status = 3;
break;
default: // status = 0;
break;
}
}
然后就是下一个关键点,pwm频率改变
不知道上面S型讲通顺没有,PWM加减速过程中在发生一个脉冲之后就该改变,所以我们在中断里面进行判断加减速度状态,然后进行加减速。
void TIM1_UP_IRQHandler(void)
{
timecount++;
TIM_ClearFlag(TIM1, TIM_FLAG_Update);
switch(status)
{
case 0 :
freq = (int16_t) motorPower_PowerSLine(400,719,100,4,sindex)/2;
sindex++;
last_freq = freq;
break; //addspeed
case 1 :
freq = last_freq;count = 0;
sindex++;
break; //avrspeed
case 2 :
freq = (int16_t) motorPower_PowerSLine(400,100, 7190,4,sindex)/2;
sindex++;
last_freq = freq;
break; //miuspeed
case 3 :
// TIM_ITConfig(TIM1, TIM_IT_Update, DISABLE);
TIM_CtrlPWMOutputs(TIM1, DISABLE);
// TIM_Cmd(TIM1, DISABLE);
finish_flag = 1;
break;
default: break;
}
//temp_arr=72000000/Frequency/(psc+1)-1
if(freq<200)freq =200;
if(freq>250)freq =250;
TIM1->ARR = freq;
TIM1->CCR4= freq>>1;
}