两相步进电机的控制及其实现

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信号,在给定目标角度或速度的状态下可以看到可以自动加减速并换向。

************版权所有,转载请注明出处************

  • 16
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值