1.步进电机如何控制
不同于传统的电机,步进电机是一种脉冲电机,即在不超载的情况下,电机不发生失步,此时电机转速只与驱动电机的脉冲相关。但电机的驱动转矩是有限的,负载又具有惯性,即转速是不能突变的,因而步进电机在加减速的过程需要控制驱动脉冲的频率。
对于两相四线混合型步进电机,内部电路可以简化为:
即电机内部具有两组线圈,AC与BD两相。每一个脉冲来临,转子经过短暂的转动后总会停在两相线圈合成磁场的方向。磁场大小与电流成正比,因而可以通过控制电流方向控制磁场方向。
传统的控制方法只对线圈电流方向而不对大小控制,有三种方法:
两相单四拍,两相双四拍,两相八拍。
假定电流从A流向C定义为X+,C流向A定义为X-,B流向D定义为Y+,D流向B定义为Y-,那么这三种方式中(假使运行方向不变)电流分别为:
单四拍:X+、Y+、X-、Y-按照顺序循环,磁场矢量如图:
双四拍:X+Y+、X-Y+、X-Y-、X+Y-按照顺序循环,磁场矢量如图:
八拍:X+、X+Y+、Y+、X-Y+、X-、X-Y-、Y-、X+Y-按照顺序循环
上图中红色箭头为磁场矢量,按照标号循环,X、Y正方向已经标示出来。
可以看出,双四拍比单四拍有更强的磁场,因而具有更大的力矩。当两相共同通电,合成磁场方向可以认为是单独磁场的矢量合成。
2.步进电机的震动及抑制办法
在上文中可以看到,稳态时传统驱动方法(八拍)力矩矢量在一个矩形上运行,存在力矩波动;同时,在两个稳态之间的过渡态,力矩矢量的模存在较大的变化,如下图:
绿色为过渡态时力矩的变化趋势,与过渡态时两相的具体电流有关。力矩的波动会带来受力的波动,而机械结构的不完全对称又会放大这种波动,从而发出噪声。要降低噪声就必须使用正弦电流驱动步进电机。
以TMC2209为例,使用两相相差90°相位的正弦电流驱动步进电机,可以实现力矩矢量在一个圆上旋转,从而减少力矩波动带来的震动。驱动电流如下图:
某一时刻的力矩矢量如图:
这样,可以实现改变力矩矢量的方向而不改变模,从而降低震动和噪音。
除去力矩波动,角加速度的波动也可能带来冲击并可能导致失步,而失步则可能导致开环控制系统中出现偏差,因而要尽可能消除角加速度的波动。常用的方式有两种:梯形调速和S形调速。
梯形调速中,角加速度恒定,但会在加、减速开始和停止时存在角加速度的突变,这也可能带来冲击;S形调速中,角加速度不存在突变,但对于非恒定速度的应用,每次加减速都需要重新计算速度曲线,存在计算量大的问题。两者对比如下:
3.梯形调速的实现
梯形调速的实现基于TMC2209及STM32F1系列。
TMC2209内置了正弦电流驱动,工作在PWM模式下,使用步进电机线圈作为H桥的电感。对STEP引脚施加脉冲,TMC2209会驱动电机转动一步,上升沿有效。
为了方便计算提高实时性,选用梯形调速。调速过程使用了查表法。通过定时器通道1生成驱动脉冲,脉冲周期5us。通道2用于对计时器周期进行修改。
数表如下:
每次脉冲都对下个脉冲的时刻进行查表,实现了逐周期调速。定时器的修改使用了定时器中断,实现部分代码如下:
调速数表如下:
const unsigned int SpeedTable[166] =
{19412,12980,10281,8737,7714,6976,6412,5963,5596,5288,5025,4798,4598,4421,4263,4121,3992,3874,3766,3666,3574,3488,3409,3334,
3264,3199,3137,3078,3023,2970,2920,2873,2828,2785,2743,2704,2666,2630,2595,2562,2529,2498,2468,2439,2411,2384,2358,2333,2309,
2285,2262,2240,2218,2197,2176,2156,2137,2118,2100,2082,2064,2047,2031,2015,1999,1983,1968,1953,1939,1925,1911,1897,1884,1871,
1858,1846,1834,1822,1810,1798,1787,1776,1765,1754,1744,1734,1724,1714,1704,1694,1685,1675,1666,1657,1648,1640,1631,1623,1614,
1606,1598,1590,1582,1574,1567,1559,1552,1545,1538,1530,1523,1517,1510,1503,1496,1490,1483,1477,1471,1465,1458,1452,1446,1440,
1435,1429,1423,1418,1412,1406,1401,1396,1390,1385,1380,1375,1370,1365,1360,1355,1350,1345,1340,1336,1331,1326,1322,1317,1313,
1308,1304,1300,1295,1291,1287,1283,1279,1275,1270,1266,1262,1259,1255,1251,1247};
//共165个数,单位us,5.8°/s ~ 90.2°/s,线性调速,400ms调速时间
中断服务程序如下:
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == htim1.Instance)
{
if(Stepper_state & BIT0) //Ready and not in Busy state
return;
if(__HAL_TIM_GetCompare(&htim1,TIM_CHANNEL_1)) //
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10)==GPIO_PIN_SET)
Pulse_Summator++;
else
Pulse_Summator--;
if(Pulse_Summator < 0)
Pulse_Summator += 3200;
if(Pulse_Summator > 3199)
Pulse_Summator -= 3200;
static int i = 0;
static int j = 0;
//***************Break procedure, high priority before completion***********
if(Stepper_state & BIT1) //Break procedure
{
if(i < 1)
{
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[0]);
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,0);
Curr_Period = 0;
Stepper_state &=~BIT1; //Break procedure completed
}
else
{
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[i]);
Curr_Period = SpeedTable[i];
i--;
}
return;
}
//********************************************Lock Mode**************************************************
if((Stepper_state & BIT3)&&(Stepper_state & BIT4))
{
}
//********************************************Position Mode********************
if((Stepper_state & BIT3)&&(!(Stepper_state & BIT4))) //Mode 0:1 ; Mode 1:0 , Position Mode
{
static int32_t Distance;
static int8_t Direction;
if(Pulse_Destination > Pulse_Summator)
{
Distance = Pulse_Destination - Pulse_Summator;
if(Distance > 1600)
{
Distance = Pulse_Summator - Pulse_Destination + 3200;
Direction = 0;
}
else
Direction = 1;
}
else
{
Distance = Pulse_Summator - Pulse_Destination;
if(Distance > 1600)
{
Distance = Pulse_Destination - Pulse_Summator + 3200;
Direction = 1;
}
else
Direction = 0;
}
if(!Distance)
{
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,0);
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[0]);
Stepper_state |= BIT3;
Stepper_state |= BIT4;
return;
}
if(((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10)==GPIO_PIN_SET)&&Direction)||((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10)==GPIO_PIN_RESET)&&(!Direction)))
{
if(Distance < i) //*****************方向相同但速度过快,减速准备换向******************************
{
if(i)
{
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,5);
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[i]);
i--;
if(i<0)
i = 0;
}
else
{
if(j) // 停车
{
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,0);
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[0]);
j++;
}
else // 减速到0
{
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[0]);
j++;
}
if(j > 1) // 开始换向
{
if(Stepper_state & BIT2)
Stepper_dir(0); //Backward
else
Stepper_dir(1); //Forward
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,5); //Enable pulse output
j = 0;
}
}
}
else //*********************方向相同,速度不过快***************************************
{
if(Distance - 3 > i) //加速
{
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,5);
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[i]);
i++;
if(i > 164)
i = 164;
}
else //减速
{
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,5);
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[i]);
if(i > 0)
i--;
}
}
}
else //*************方向相反,减速准备换向*****************************
{
if(i)
{
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[i]);
i--;
if(i<0)
i = 0;
if(!i)
j = 0;
}
else
{
switch(j)
{
case 0:
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,5);
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[0]);
j++;
break;
case 1:
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,0);
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[0]);
j++;
break;
case 2:
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_10);
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,5);
i++;
if(i > 164)
i = 164;
j = 0;
break;
default:
j = 0;
break;
}
}
}
}
//********************************Speed Mode******************************
if((!(Stepper_state & BIT3))&&(Stepper_state & BIT4)) //Mode 0:0 ; Mode 1:1 , Speed Mode
{
if(((Stepper_state & BIT2)&&(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10)==GPIO_PIN_SET))||((!(Stepper_state & BIT2))&&(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10)==GPIO_PIN_RESET)))
{ //Direction related affairs; Same direction
if(SpeedTable[i] > max_speed_period) //加速
{
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,5);
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[i]);
i++;
if(i>164)
i = 164;
}
else
if(SpeedTable[i] < max_speed_period) //减速
{
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[i]);
i--;
if(i<0)
i = 0;
if(!i)
{
switch(j)
{
case 0:
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,5);
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[0]);
j++;
break;
case 1:
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,0);
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[0]);
j++;
Stepper_state |= BIT3;
Stepper_state |= BIT4;
break;
default:
j = 0;
break;
}
}
}
else
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[i]);
}
else //指令方向与当前方向不同
{
if((!__HAL_TIM_GetCompare(&htim1,TIM_CHANNEL_1))&&(!j)) //已经停车,可以直接换向
{
if(Stepper_state & BIT2)
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10,GPIO_PIN_RESET);
}
else //减速停车,准备换向
{
if(i)
{
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[i]);
i--;
if(i<0)
i = 0;
if(!i)
j = 0;
}
else
{
switch(j)
{
case 0:
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,5);
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[0]);
j++;
break;
case 1:
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,0);
__HAL_TIM_SET_AUTORELOAD(&htim1,SpeedTable[0]);
j++;
break;
case 2:
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_10);
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,5);
i++;
if(i > 164)
i = 164;
j = 0;
break;
default:
j = 0;
break;
}
}
}
}
}
//*********************************Relase Mode*********************************
if((!(Stepper_state & BIT3))&&(!(Stepper_state & BIT4)))
{
Pulse_Summator = 0;
Pulse_DownCounter = 0;
Stepper_state &=~BIT5;
}
}
}
最终实现的驱动波形如下(带自动换向):
上波形为DIR信号,下波形为STEP信号,在给定目标角度或速度的状态下可以看到可以自动加减速并换向。
************版权所有,转载请注明出处************