在本系列的第三部分也就是最後一部分,我們將為機器人添加最後一個部件:遙控器。此外,我們對支腳進行了一些細微的改進,使它們能夠在任何類型的基底表面都能更加穩定。首先,我們會介紹經過細微修改的支腿機制,然後將HC-05藍牙連接到Arduino以實現無線控制。最後,我們將編寫一個Processing應用程式,這樣我們就不必為ArduPod的每次移動使用書面指令了。
如果您第一次知道該項目,請先參考本項目的第一部分和第二部分,然後再進行下一步的操作:Arduino六足機器人第一部分—機械與佈線 以及 Arduino六足機器人第二部分:程式設計。
我自己製造六足機器人的時候,面臨的最大難題是支腿在光滑表面上很不穩定。通常,在支腿上添加某種防滑材料就可以很輕鬆地解決這個問題。但是,這個機器人的支腿與地面間的接觸面積太小了。增大支腿與地面的接觸面積對防滑效果大有幫助,同時還能改善支腿的整體穩定性。
在上圖中,您可以看到支腿的底部增加了一個支撐零件。與其他零件一樣,該零件也是使用黑色ABS材料通過3D印表機製造的。在我的GitHub上可以找到其他零件的模型。
現在我們可以在支腳底部添加防滑層了。我用了一塊綠色的凝膠墊。這種材料即使在非常輕的負載下也不會發生打滑。如果您無法獲取這種材料,其他選擇就非常少了(比如橡膠)。可以試試看哪種材料最適合您的機器人。然後從材料上切下六個圓圈,將這些圓圈粘在腳上,這一步就完成了!
我要做的下一個改進比支腳要複雜一些。在當前系統中,伺服只在一個地方與支腿連接。這會使結構中產生一個薄弱點,該薄弱點將會承受大部分的負載,這可能導致在某個時刻發生斷裂。在圖3中,您可以看到當前的附著系統和旁邊新的附著系統。
我們注意到所添加的新零件使伺服可以在兩個位置進行連接:軸上(之前的連接點)和伺服的相對側。將帶有旋鈕的小墊子粘貼到伺服上可以為伺服提供額外的支撐。現在,伺服連接在兩個位置上,負載分配在這兩點之間。這樣就可以進行更好的運動控制。
現在我們已經解決了支腿的問題,可以來連接HC-05藍牙模組了,通過該模組可以對機器人進行無線控制。由於所有的控制項都由Arduino來操控,我們的主要任務是向其發送指令。
與Arduino之間進行無線通訊的方法主要有以下幾種:
因此,我們將在該專案中使用藍牙模組。我使用HC-05藍牙模組,主要是因為它是最便宜、最常見的模組。由於該模組的作用就像一個串列COM埠,因此HC-05與Arduino的連接非常容易,如下面的Fritzing示意圖所示:
該模組由Arduino供電。HC-05的TX引腳直接連接到Arduino上的RX1引腳。但是,因為HC-05的邏輯電平為3.3V,而Arduino在5V下運行,所以HC-05的RX引腳上必須有一個簡易分壓器來降低電壓。R1的值應為1 kΩ,R2的值可以為1.8 kΩ或2.2 kΩ。我使用2.2 kΩ的電阻,因為找不到阻值為1.8 kΩ的電阻,但是對於該模組,使用兩種電阻的任何一個都可以正常工作。
目前,Arduino還不知道它正在通過藍牙模組進行通信。從Arduino的角度來說,這跟通過電纜連線完全相同。這就是為什麼我們不需要在Arduino上進行任何設置,因為該模組自行處理所有事情—至少在最常見的情形下是這樣。
下一步是設置HC-05藍牙模組。我使用的PC沒有內置的藍牙介面,因此必須使用USB藍牙適配器。
對於Windows 10,請參考以前的教程,該教程提供了有關將HC-05連接的PC的分步指南:製作自己的Arduino RFID門鎖—第二部分; 步驟1:連接藍牙。
首先,我們必須將PC與藍牙模組配對。
此時,最好驗證一下所有連接是否正確。啟動Arduino IDE並上傳以下草圖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
void setup() { Serial1.begin(9600); while(!Serial1); Serial1.println("Hello world!"); } String input; void loop() { if(Serial1.available() > 0) { input = Serial1.readString(); Serial1.println(input); } } |
上傳完成後,返回“設備和印表機”視窗,找到我們之前與PC配對的HC-05模組。按右鍵HC-05圖示,然後點擊“硬體”選項。在這裡,您會找到Windows分配給該模組的COM埠編號。這將是我們用於與ArduPod通信的COM埠。返回Arduino IDE,在功能表>工具>埠中選擇正確的COM埠,然後啟動串列監視器。輸入幾個字元,然後按下Enter鍵。這些字元將被發送到您剛剛指定的COM埠,並出現Arduino的回應。
到目前為止一切正常嗎?很好!現在我們已經完成了“困難”的部分,讓我們進行一些有趣的部分:在Processing中編寫圖形應用程式。
我假設正在閱讀本文的您已經對Processing的語言有基本的瞭解。雖然Processing的語言與Arduino語言非常相似—setup、loop/draw這些主函數都相同—但是它們還是不同的。Arduino語言幾乎與C++相同,而Processing是基於Java語言。因此,雖然語法相似,兩者之間還是存在重大差異。下面,我會盡我所能地把我所創建的應用程式描述出來。
顯然,我們希望該應用程式具有良好的圖形化使用者介面(GUI)。Processing非常著重於繪圖形狀(因此主迴圈函數名稱為—draw),所以對於圖形設計人員而言使用Processing很便捷。但是,我幾乎不具有該領域的任何技能,因此我將通過使用庫來幫助我創建外觀精美的GUI。
Processing有幾種庫,可以提供不同的設計方案,但是我個人最喜歡的是controlP5庫。您可以點擊此處訪問該網站,以詳細瞭解該庫的更多資訊。另外,該庫中幾乎包含了所有示例。您可以在網站上找到另一個有用的東西是完整版JavaDoc參考。網站上的下載版本已經有些過時,因此強烈建議您使用Processing的庫管理器。在編寫程式時我們將使用最新版的Processing,即Processing 3.2.3。該應用程式以及原始程式碼可在我的GitHub上找到。
現在,讓我們來看一下應用程式的實際外觀。
好吧,控制項有點多是不是?左側有一個大的灰色神秘盒子,有很多可以按下的按鈕,而右側則有點奇怪,看起來像是雷達。如您所見,我用紅色數位標記了所有部件,這是每個控制項的作用:
即使沒有相機,您也可以通過該功能快速簡便地瞭解周圍環境。
您可能已經想到了,這個應用程式比我們實際所需要的複雜得多,實在無法逐條解釋所有的內容。因此,我們將僅瞭解代碼中最重要的以下部分:控制事件處理,串列通信和Arduino端。
使用GUI編寫應用程式時,我們需要瞭解的第一件事是:“按一下按鈕後會發生什麼?”幸運的是,controlP5庫為我們處理了大多數事宜。讓我們從以下代碼中看一個簡單場景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
import controlP5.*; ControlP5 cp5; void setup() { size(400,400); cp5 = new ControlP5(this); cp5.addButton("click me!") .setValue(0) .setColorForeground(color(215, 0, 0)) .setColorBackground(color(175, 0, 0)) .setColorActive(color(255, 0, 0)) .setPosition(100,100) .setSize(200,200) ; } public void controlEvent(ControlEvent theEvent) { if(theEvent.getController().getName().equals("click me!")) { println("Why would you trust a big red button?!"); } } void draw() {} |
首先,我們必須導入庫並創建controlP5 類的實例。然後,在setup 函數中,我們創建一個名為“click me!”的新按鈕。最後一部分是 controlEvent 函數。每當任何 controlP5的元素創建事件時(在我們的示例中,是每次按一下按鈕時),都會調用該函數。然後,我們可以檢查是哪個元素導致了該事件的發生,如果是出於“click me!”按鈕,那麼將會列印出一些文本。controlP5庫包含了有關解釋如何使用其所提供的控制元素的示例,所以我們將會來簡單瞭解一下遠端控制應用程式中實際所包含的內容。
基本事件處理與上面的示例完全相同,都是通過controlEvent函數進行處理。除此之外,還增加了兩個函數 – keyPressed 以及 keyReleased,用於處理鍵W、A、S和D的輸入,以允許使用鍵盤進行移動控制。您可能會注意到,與示例不同,在setup函數中並沒有設置任何的控制元素。所有的元素設置都被移到了第二個選項卡guiElements中,並通過setupGui函數進行調用。因此,在主選項卡ardupodRemote中的代碼很少。通常,對不同的內容設計分隔的代碼塊是一種很好的程式設計習慣,因為這樣更易於閱讀和理解代碼。
現在,我們對圖形和控制項的工作原理有了基本的瞭解,可以嘗試解義那些將要通過埠傳輸的所有資料了。
我們已經在兩端都設置了藍牙連接,但是還需要創建雙方都遵循的某種盡可能簡明快捷的“協議”。由於所有從序列埠傳入的資料在兩端都會被釋義為字串資料型別,因此我創建了一個非常簡單的“資料包”結構。“輸入”資料包(Arduino發送給PC的資料包)的結構如下所示:
XYpayload
前兩個字元X 和 Y是該資料包的狀態碼,作用是讓應用程式知道有效負載中所包含資訊的種類。例如,如果應用程式接收到資料包“82Starting PWM … ”,它將在串行輸出框中寫入以下內容:“[INFO] [SETUP] Starting PWM … ”。下表列出了當前已經實現的代碼:
0 | |
1 | [ECHO] |
2 | [SETUP] |
3 | [TRACE] |
4 | [SR04] |
5 | [PWM] |
6 | [ERROR] |
7 | [WARN] |
8 | [INFO] |
9 | > |
10 | [CMD] |
11 | [APP] |
請注意,在該應用程式中,代碼40用於掃描資料,代碼41用於單次的距離測量。
“輸出”資料包(應用程式發送到Arduino的資料包)的結構更簡單一些:
Xpayload
像之前一樣,第一個字元X將用於確定如何處理有效負載。但是,這次我們只使用了少數的指令。
t | 將感測器轉到有效負載中的指定位置 |
m | 測量距離 |
n | 開始掃描 |
w[s] | 向前一步 |
a[s] | 向左一步 |
s[s] | 向後一步 |
d[s] | 向右一步 |
到目前為止,我們已經成功將藍牙連接到Arduino端和PC端,還編寫了一個很酷的GUI的應用程式,並創建了一個與Arduino通信的協議,但是仍然缺少一些東西:可能在我們發送資料的時候Arduino沒有回應。我們需要Arduino運行一個程式來定期檢查序列埠,以在出現可用資料時進行處理。讓我們來看一下之前用於驗證藍牙連接的代碼草圖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
void setup() { Serial1.begin(9600); while(!Serial1); Serial1.println("01Hello sir!"); } String input; void loop() { if(Serial1.available() > 0) { input = Serial1.readString(); switch(input.charAt(0)) { case ‘n’: //ultrasonic scan case ‘m’: //measure distance //and so on... } } } |
一旦將資料設置為input中的變數,我們就可以使用它來進行所有操作了。例如,如果要查看剛剛到達的指令類型,我們可以使用input.charAt(0)。此內置函數將返回字串輸入的第一個字元,該字元將與上表中的指令之一相對應。
請注意,通常,每次要將新的草圖上傳到Arduino時,都必須斷開HC-05模組的連接,但是由於我們使用的是Arduino Mega,就有了四個單獨的硬體序列埠!因此,我們只需要將藍牙連接到剩餘的埠之一就可以同時進行這些操作了。
需要記住的另外一件事是,與使用USB的連接不同,通過藍牙將Arduino連接到PC不會經常重置Arduino。為了正確啟動,您必須手動按下Arduino的重新開機按鈕!
六足機器人是一個相當複雜的項目。與往常一樣,該項目還有很大的提升空間。目前,唯一板載的感測器是超聲波測距儀,但是由於我們使用的Arduino Mega還有很多閒置處理能力,我們可以添加其他感測器以獲取更高級的功能。
對,您已經通過ArduPod的上一篇教程實現了!本教程分為三部分來盡可能全面地講述所有內容。如果您有任何疑問或者改進的建議,請隨時在我的GitHub上與我分享您的想法。您可以前往“Issues”區域創建一個新的問題。如果您已經進入到我的頁面中並且喜歡該專案,可以留下一顆星。當然,如果您打算構建自己的ArduPod,請一定要與世界分享您的創造!