- 【丁丁歷險記】全篇索引
- 本節教大家解決在控制步進電機時如何讓多個步進電機以不同的速度不同的脈衝數同時工作。有些類似於3D打印機中Marlin固件的實現原理。可以做到變速精準控制。
一、4988控制電機原理
- 4988是在控制步進電機最常用的驅動。在RAMPS系列的控制板中支持的也非常好。其控制方法非常的簡單,在連接好電源的情況下在STEP引腳輸出一個脈衝即可,步進電機會朝着指定方向走一步。
- 一個驅動對應着一個電機,DIR引腳用於控制方向,ENA用於控制芯片的工作使能,默認爲低電平(啓動)。步進電機的4個引腳兩兩相通,如圖所示,可以使用電壓表的通斷檔進行測量。
二、控制問題分析
- 在控制一個電機時旋轉三個脈衝,只需要產生三次脈衝即可,以下均用僞代碼實現。
pin_Dir = HIGH; //給定一個方向
for(int i=0;i<3;i++){
pin_Step = HIGH; //高電平
delayUS(1500);
pin_Step = LOW; //低電平
delayUS(1500);
}
- 這樣會產生三個脈衝信號如下圖所示。
-
當使用兩個電機的時候,如果還用這個方法,實現同時運轉就不能控制每個電機運轉的步數,舉一個反例:
-
反例1:可以控制步數,不能同時運動
//電機一先運動 pin_Dir = HIGH; //給定一個方向 for(int i=0;i<3;i++){ pin_Step = HIGH; //高電平 delayUS(1500); pin_Step = LOW; //低電平 delayUS(1500); } //電機二再運動 pin2_Dir = HIGH; //給定一個方向 for(int i=0;i<3;i++){ pin2_Step = HIGH; //高電平 delayUS(1500); pin2_Step = LOW; //低電平 delayUS(1500); }
波形如下
可以看到輸出波形中,電機是先輸出第一個的控制信號再輸出第二個的。
-
反例2:同時控制,但是不能單獨進行電機脈衝的控制
pin_Dir = HIGH; //電機1運動方向
pin2_Dir = HIGH; //電機2運動方向
for(int i=0;i<3;i++){
pin_Step = HIGH; //電機1高電平
pin2_Step = HIGH; //電機2高電平
delayUS(1500);
pin_Step = LOW; //電機1低電平
pin2_Step = LOW; //電機2低電平
delayUS(1500);
}
很容易就可以理解上面是如何工作了的,就不補充波形了
- 反例3:最容易犯的錯誤,速度控制問題
- 可能有的同學看到反例1的時候就想使用微分的思想將 電機只運行一步,然後通過改變循環數量來控制電機,具體實現的方法多種多樣,但是如果你的代碼中出現以下部分,在大量的循環後就會出現問題。
pin_Step = HIGH; //電機1高電平
delayUS(1500);
pin_Step = LOW; //電機1低電平
delayUS(1500);
pin2_Step = HIGH; //電機2高電平
delayUS(1500);
pin2_Step = LOW; //電機2低電平
delayUS(1500);
只要你的函數中產生了這樣的循環體,那麼電機的運行速度上一定會出現問題。看起來延遲都是一樣的,但是電機1的脈衝在低電平的部分其實已經整合了電機2的延遲時間。也就是雖然延遲相同但是,電機1的高電平時間是1500ms,低電平的時間爲1500ms * 3 即4500ms;因此循環時則會產生速度不同的問題,切次方法的電機速度難以控制。
從佔空比的對比可以看出低電平一直都在整合前一個電機的高電平所使用的時間。雖然做到了同時控制,但是單個電機的運行速度始終受到其他電機的影響。
三、解決方案,利用時間軸控制
- 無論脈衝在何時產生,在何時結束,都會在時間上有所體現。在若將上述圖標中的橫座標看做成時間軸,那麼通過對IO在不同時間上的變換,就可以實現對多個電機的準確定時控制。
- 使用定時器來產生脈衝,通過對佔空比的計算將多個電機的輸出整合在時間軸上進行實現。
Motor.ioState //當前時間IO的輸出狀態,bool Motor.turnSpeed //電機旋轉的速度uint8 Motor.speedCopy //電機旋轉的速度uint8 Motor.step //需要旋轉的脈衝數量int void timeInterruption(){ countIndex += 1; /*xy軸輸出狀態*/ digitalWrite(X_STEP,MotorX.ioState); digitalWrite(Y_STEP,motorY.ioState); /*下面則是判斷在時間軸上電機的應該處於的狀態*/ if(MotorX.step> 0){ MotorX.turnSpeed -= 1 ; if(MotorX.turnSpeed <= 0){ MotorX.ioState= !MotorX.ioState; MotorX.turnSpeed = MotorX.speedCopy; MotorX.step-= 1; } } if(motorY.step> 0){ motorY.turnSpeed -= 1 ; if(motorY.turnSpeed <= 0){ motorY.ioState= !motorY.ioState; motorY.turnSpeed = motorY.speedCopy; motorY.step-= 1; } } if(MotorX.step<= 0 and motorY.step<= 0 ){ countIndex = 0; } }
- 以上則是通過判斷脈衝的時間狀態,來改變IO的ioState。
產生波形如上圖所示