這篇博客不同於前面的樹莓派和底盤子系統的控制了,而是要進行講解分析如何通過arduino控制步進電機移動絲杆實現撥片架的水平移動了,那麼為什麼要實現這麼一個功能呢?
原因很簡單,因為我們的購物機器人依靠撥片撥取貨物,但是在貨架上或者倉庫裡的時候,購物機器人的撥片可能撥不到貨物,因此就需要依靠絲杆帶動撥片架去撥取貨物。
TB6600型驅動器接線方法
TB6600升級版步進電機驅動器的A+-和B+-是連接步進電機的黑綠紅藍,EN(使能端) DIR(方向信號線) PUL(脈衝線),驅動可以採用共陰極也可以採用共陽極,共陽共陰接好後只需用arduino給PUL送進脈衝信號以及給DIR送進方向信號即可,至於EN的信號端可以懸空,這樣比較方便,供電埠24V。
按照上述方法連接好信號線後,就可以編寫arduino程序控制步進電機了,在這裡我使用了2種方法控制步進電機。
按鍵控制
之前做電賽的時候還有一塊調參的板子,上面有按鍵還有撥碼,因此我就將其用作按鍵控制絲杆的調試工具了。
首先最主要的就是步進電機的控制方法了,線連接好之後,只需用arduino給PUL送進脈衝信號以及給DIR送進方向信號即可
#define pul1 9#define dir1 8#define speed_pul 4digitalWrite(pul1, HIGH); delayMicroseconds(speed_pul); digitalWrite(pul1, LOW); delayMicroseconds(speed_pul);可以看到程序的實現方法很簡單,就是通過給引腳輸送一個高電平,延時一段時間,再輸送一個低電平,再延時一段時間,從而產生方波信號。speed_pul這個參數就是方波中,高低電平的持續時間,那麼這個方波頻率的高低對於步進電機的運動會有怎樣的影響呢?
我設計了一個實驗,如圖所示,我測量了不同方波頻率下,絲杆從點1移動到點2所花費的時間橫坐標是運動完全程所花費的時間,縱坐標是speed_pul數值大小,因為當speed_pul小於3時,步進電機不能移動,因此就將這種情況下的時間設定為0,不做考慮。從圖中可以發現,隨著speed_pul數值的減小,步進電機移動完全程的時間也在減少,因此為了減少購物機器人在場上移動絲杆的時間,我將speed_pul參數設置為了4。
產生了方波信號之後,只需要再給步進電機方向它就可以運動了,於是乎控制步進電機左移的程序如下所示void turn_left(){ digitalWrite(dir1, HIGH); digitalWrite(pul1, HIGH); delayMicroseconds(speed_pul); digitalWrite(pul1, LOW); delayMicroseconds(speed_pul);}void turn_right(){ digitalWrite(dir1, LOW); digitalWrite(pul1, HIGH); delayMicroseconds(speed_pul); digitalWrite(pul1, LOW); delayMicroseconds(speed_pul);}至此完成了步進電機的驅動,接下來只需要結合按鍵即可,首先我們需要設置按鍵信號接入arduino的引腳
const int up_btn, down_btn, left_btn = 2, right_btn = 3;
接下來就是邏輯分析了,因為按鍵按下之後引腳呈現的是低電平,因此每檢測到一個低電平之後我就輸送50個方波信號給步進電機的驅動,從而控制步進電機帶動絲杆轉動一定距離,那麼為什麼是50個方波信號呢?其實也很好理解,一次性輸送的方波信號個數越多,相當於驅動步進電機轉動的時間越長,絲杆移動的距離也就越遠,撥片架移動的距離也就越遠。為了保證按鍵控制的精細度,我就設置了按一次按鍵發送50個方波信號。
具體實現如下int btn_move_dis = 50;void key_board(){ int i = 0; int left_flag; int right_flag; left_flag = digitalRead(left_btn); right_flag = digitalRead(right_btn); if (left_flag == LOW) { for (i = 0; i < btn_move_dis; i++) { turn_left(); } } else if (right_flag == LOW) { for (i = 0; i < btn_move_dis; i++) { turn_right(); } exeTime2 = millis() - exeTime1; }}在實際的運行過程中,都是由樹莓派發送指令控制其他子系統的,因此步進電機的控制數據肯定也是通過串口接收的,所以我們還要加一個串口控制的部分
while (Serial.available() > 0) { delay(100); move_ctl_dis = Serial.parseInt(); Serial.println(move_ctl_dis); } while (Serial.read() >= 0) {}這段程序還是比較簡單好搞明白的,那麼現在就是有一個問題。在按鍵控制步進電機的時候是arduino檢測到一個低電平就會就會發送50個方波信號,那麼發送了50個方波信號之後,絲杆實際上能移動多少我們不得而知。其實這其中的問題是我們目前還不能精細的控制步進電機的移動距離,而只能控制它往特定方向進行連續運動。因此我們就需要修改一下驅動程序
int move_ctl_dis;unsigned long cm_cnt = 32000; if (move_ctl_dis != 0) { if (move_ctl_dis > 0) { for (int i = 0; i < move_ctl_dis; i++) { for (unsigned long j = 0; j < cm_cnt; j++ ) { turn_left(); } } } else if (move_ctl_dis < 0) { move_ctl_dis = -move_ctl_dis; for (int i = 0; i < move_ctl_dis; i++) { for (unsigned long j = 0; j < cm_cnt; j++ ) { turn_right(); } } } move_ctl_dis = 0; }這段程序有什麼特別的呢?我們抓取主要的一部分來做特別分析
for (int i = 0; i < move_ctl_dis; i++) { for (unsigned long j = 0; j < cm_cnt; j++ ) { turn_left(); } }其中外循環的move_ctl_dis是arduino接收到的上層發送過來的移動距離,而內循環則代表了每發送cm_cnt個方波信號,絲杆就會帶動撥片架移動1cm,這個數據是通過實際測試得出的,因此move_ctl_dis的絕對值即撥片架實際移動的距離,正負不過是左右移動的區別而已,因此在主循環裡這樣寫就可以了
void loop(){ key_board(); CatchMove(); while (Serial.available() > 0) { delay(100); move_ctl_dis = Serial.parseInt(); Serial.print("Serial.parseInt:"); Serial.println(move_ctl_dis); move_ctl_dis = move_ctl_dis; } while (Serial.read() >= 0) {}}最後還有一個問題,那就是我們還不能知道撥片架的實際位置,這樣不利於我們進一步控制,因此我想了個辦法。那就是在剛開始的時候總是通過按鍵將撥片架移動到特定位置,那麼之後的位置都是相對於這個初始位置移動的,這樣我們就有了參照,才能準確、穩定控制撥片架照我們預想的方式運動。
《通過電機控制學習PID算法》本課程從最開始的電機部分再到核心的PID算法,一步一步循序漸進,通過這個課程的學習可以讓同學們認識到算法的重要性,同時本課程理論與實踐相結合,將難以理解的理論部分通俗的向大家分析講解。
點擊「閱讀原文」查看課程詳情