這篇文章來(lái)源于DevicePlus.com英語(yǔ)網(wǎng)站的翻譯稿。

歡迎回到ArduRover系列!在第一部分 和 第二部分中,我們已經(jīng)構(gòu)建了一個(gè)Arduino六輪驅(qū)動(dòng)漫游車。在最后一部分內(nèi)容中,我們將致力于編寫一個(gè)用于機(jī)器人控制的程序。在第二部分中,我們已經(jīng)介紹了一些代碼,但是那些代碼僅僅是用于控制電機(jī)運(yùn)行的。這一次,我們希望能夠得到所有傳感器的數(shù)據(jù),并且能夠通過(guò)使用Android手機(jī)來(lái)實(shí)現(xiàn)實(shí)際遠(yuǎn)程操控!
硬件
? 通過(guò)第一部分和 第二部分制作的ArduRover
軟件
? Arduino IDE 1.8.1
? Android Studio 3.0
? Arduino 庫(kù):
? LoRaLib – GitHub
? RohmMultiSensor – GitHub
? JPEGDecoder – GitHub
? Arduino 設(shè)計(jì)圖 – GitHub
? Android 應(yīng)用程序 – GitHub
對(duì)接線的修正
在本系列的上一部分里,除了部件的制作,我還介紹了邏輯電路(所有傳感器和模塊)的接線。那時(shí),我只測(cè)試了電機(jī),因?yàn)閂NH5019驅(qū)動(dòng)器是其中唯一我沒(méi)使用過(guò)的子系統(tǒng),當(dāng)然,我使用的代碼也只能用來(lái)控制它們。由于電機(jī)運(yùn)行得很好,我就以為直接把其他所有函數(shù)(例如控制傳感器、相機(jī)和伺服器的代碼)添加上去是沒(méi)有問(wèn)題的。所以您可以想象出當(dāng)我看到所有電機(jī)在添加了那些函數(shù)后馬上就停止運(yùn)行時(shí),我有多么驚訝。
當(dāng)類似這種問(wèn)題發(fā)生的時(shí)候,我們必須返回上一步,回顧一下一切運(yùn)行正常時(shí)的情況。我更改了代碼,這很簡(jiǎn)單,只需要上傳一個(gè)不同的Arduino設(shè)計(jì)圖就可以了,然后查看一下問(wèn)題是出在硬件還是軟件上。果然,電機(jī)在之前的代碼下恢復(fù)了運(yùn)行。通過(guò)對(duì)新代碼進(jìn)行謹(jǐn)慎的添加和刪除,我發(fā)現(xiàn)Servo庫(kù)在某種程度上導(dǎo)致了該錯(cuò)誤的發(fā)生。在調(diào)用servo.attach()函數(shù)后,電機(jī)就會(huì)停止運(yùn)轉(zhuǎn)。這似乎很奇怪,直到我意識(shí)到了信號(hào)傳輸?shù)膯?wèn)題:使用Servo庫(kù)的時(shí)候,電機(jī)控制部分好像完全沒(méi)有信號(hào)輸出。
VNH5019允許您通過(guò)使用脈沖寬度調(diào)制(PWM)來(lái)控制電機(jī)轉(zhuǎn)速。伺服器也使用PWM來(lái)將小型電機(jī)設(shè)定在某一位置并保持不變。事實(shí)證明,在Arduino Mega上,PWM控制具有一些沒(méi)有在官方文件中提及的特點(diǎn)。起初,我的伺服器PWM輸入端連接到Arduino Mega的引腳8和9上,電機(jī)PWM連接到引腳44和46。根據(jù)Arduino官方文件,這些引腳都是支持PWM的。但是,這些文件沒(méi)有提及的是,當(dāng)您通過(guò)引腳2和13使用Servo庫(kù)時(shí),會(huì)失去引腳44和46的PWM功能支持。這是因?yàn)镾ervo庫(kù)使用了一個(gè)ATmega2560定時(shí)器,該定時(shí)器同樣用于控制引腳44到46上的PWM,那么自然而然,定時(shí)器一次只能執(zhí)行一個(gè)任務(wù)。
考慮到這一點(diǎn),我修正了接線原理圖。如下圖所示,用于電機(jī)的PWM移至引腳5和6。經(jīng)過(guò)這次更改,伺服器和電機(jī)就可以同時(shí)工作了。

圖1:修正后的邏輯端原理圖
Arduino 程序結(jié)構(gòu)
在編寫控制如此復(fù)雜的系統(tǒng)的程序時(shí),最好把所有需要考慮的因素都寫下來(lái)。對(duì)于ArduRover,需要考慮的有以下內(nèi)容:
? 電機(jī)控制 – 這可能是最重要的部分,因?yàn)轱@然我們需要控制機(jī)器人的行進(jìn)方向。
? 傳感器控制 – 我們需要從連接在機(jī)器人上的所有傳感器中獲取一些數(shù)據(jù)。
? 相機(jī)控制 – 這部分包括拍攝、傳輸圖片,以及通過(guò)伺服器支架來(lái)轉(zhuǎn)動(dòng)相機(jī)。
? 數(shù)據(jù)記錄 – 我們有一個(gè)板載SD卡,可以通過(guò)它來(lái)記錄從傳感器和GPS獲取的信息。
一個(gè)潛在的問(wèn)題是回傳圖像數(shù)據(jù)。正如我們?cè)贏rduino教程JPEG解碼中所講的那樣,傳輸圖像數(shù)據(jù)會(huì)花費(fèi)很長(zhǎng)時(shí)間。如果機(jī)器人突然決定一次把整個(gè)圖像都傳送過(guò)去,那么它將會(huì)在相當(dāng)長(zhǎng)的一段時(shí)間內(nèi)處于無(wú)響應(yīng)狀態(tài)。因此,在每次運(yùn)行主循環(huán)時(shí),我們都需要決定是否傳輸圖像中的某些部分,或者是否對(duì)上次循環(huán)執(zhí)行期間傳達(dá)回來(lái)的最終指令作出響應(yīng)。
以上述要求為要領(lǐng),我總結(jié)出了以下程序邏輯框圖。

圖2:Arduino程序邏輯框圖
在主循環(huán)函數(shù)的每次迭代過(guò)程中,Arduino會(huì)首先更新所有當(dāng)前的傳感器數(shù)據(jù),并把它們記錄到SD卡中,包括ROHM傳感器、GPS以及流經(jīng)每個(gè)電機(jī)驅(qū)動(dòng)器的電流。然后,會(huì)檢查L(zhǎng)oRa模塊是否接收到了新的程序包。如果接收到了,那么程序包中的指令將會(huì)被執(zhí)行,作出的響應(yīng)將會(huì)再次通過(guò)LoRa模塊進(jìn)行傳輸。如果沒(méi)有接收到新的指令,程序會(huì)檢查是否有圖片需要被傳輸,如果有的話,就會(huì)傳輸一個(gè)圖片數(shù)據(jù)包,如果沒(méi)有需要傳輸?shù)膱D片,這一步會(huì)被跳過(guò)。最后,程序回到循環(huán)的開始,然后重復(fù)該過(guò)程。
我們必須意識(shí)到,使用這個(gè)邏輯結(jié)構(gòu),處理新的指令會(huì)比JPEG傳輸擁有更高的優(yōu)先級(jí)。這樣的話,我們就可以巧妙地避免上文中提到的機(jī)器人無(wú)響應(yīng)的問(wèn)題。指令與響應(yīng)之間的最長(zhǎng)延遲時(shí)間只會(huì)是傳輸一個(gè)圖像數(shù)據(jù)包的時(shí)間。
既然已經(jīng)有了程序邏輯結(jié)構(gòu)的總體思路,那么我們需要關(guān)注另一個(gè)關(guān)鍵的步驟了:這些指令將會(huì)是什么樣子?
指令和指令包結(jié)構(gòu)
既然我們使用LoRa來(lái)傳輸和接收數(shù)據(jù),就必須記住該技術(shù)的設(shè)計(jì)用途:小容量數(shù)據(jù)的遠(yuǎn)距離傳輸。這意味著我們要盡量精簡(jiǎn)我們的指令,因?yàn)槊恳粋€(gè)字節(jié)都會(huì)被計(jì)數(shù)。我們可以只發(fā)送一些字符串,例如“電機(jī)左側(cè)50”來(lái)將左側(cè)的電機(jī)設(shè)置為50%的轉(zhuǎn)速,但是這其實(shí)非常浪費(fèi)空間。這個(gè)字符串占用了14個(gè)字節(jié)的數(shù)據(jù)容量,但是僅僅傳輸了三個(gè)信息塊:該指令的子系統(tǒng)目標(biāo)(“電機(jī)”)中哪些電機(jī)會(huì)被影響(“左側(cè)”)以及它們將會(huì)被設(shè)置的轉(zhuǎn)速所占最大轉(zhuǎn)速的百分比(“50”)??梢钥隙ǖ卣f(shuō),我們可以做得更好。這種類型指令的優(yōu)點(diǎn)是非常易于閱讀,但其實(shí),再重申一下,只要系統(tǒng)運(yùn)行正常,在指令執(zhí)行這一塊是不需要人為干預(yù)的。
所以,我決定不使用那些長(zhǎng)的字符串,而是開發(fā)一種簡(jiǎn)單的指令系統(tǒng),在每個(gè)指令包中使用的指令最長(zhǎng)僅為4個(gè)字節(jié)。指令包中的第一個(gè)字節(jié)叫做首地址,將會(huì)被進(jìn)一步分為兩半:高四位包含來(lái)自控制系統(tǒng)的指令分類,低四位用來(lái)作為機(jī)器人的響應(yīng)。0表示成功,非零值是具有已知含義的錯(cuò)誤代碼。
| 第1個(gè)字節(jié) | 指令描述 |
| 0x00 | 停止所有電機(jī) |
| 0x10 | 設(shè)置所有電機(jī)的轉(zhuǎn)速和轉(zhuǎn)向 |
| 0x20 | 設(shè)置所有左側(cè)電機(jī)的轉(zhuǎn)速和轉(zhuǎn)向 |
| 0x30 | 設(shè)置所有右側(cè)電機(jī)的轉(zhuǎn)速和轉(zhuǎn)向 |
| 0x40 | 設(shè)置相機(jī)傾斜角度 |
| 0x50 | 設(shè)置相機(jī)平移距離 |
| 0x60 | 使用相機(jī)拍攝圖片 |
| 0x70 | 開始JPEG 傳輸 |
| 0x80 | 強(qiáng)制啟動(dòng)新傳感器測(cè)量 |
| 0x90 | 獲取最新傳感器數(shù)據(jù) |
| 0xA0 | 重新發(fā)送最終指令包 |
| 0xB0 | 設(shè)置LoRa調(diào)制調(diào)節(jié)器配置 |
| 0xC0 | 獲取當(dāng)前所有存在的錯(cuò)誤信息 |
| 0xD0 | 未被使用 |
| 0xE0 | 未被使用 |
| 0xF0 | 未被使用 |
指令包的下一部分內(nèi)容是有效負(fù)載 – 這也是在有關(guān)頭文件中指令的所有附加信息存儲(chǔ)的地方。這部分比首地址更簡(jiǎn)單一些,因?yàn)樗膬?nèi)容取決于指令類型:有些指令不需要任何附加信息,比如說(shuō)0x00(停止兩側(cè)電機(jī))。所以這些指令的有效負(fù)載為空。然而,一些命令要求額外數(shù)據(jù)不能超過(guò)三個(gè)字節(jié),比如指令0xD0(LoRa配置),要求每個(gè)主要設(shè)置,如帶寬、擴(kuò)頻因子、以及編碼率(有關(guān)LoRa細(xì)節(jié)請(qǐng)參考LoRaLib教程 或者 GitHub wiki)只占一個(gè)字節(jié)。下表描述了所有指令包的結(jié)構(gòu)。
| 第1個(gè)字節(jié) | 第2個(gè)字節(jié) | 第3個(gè)字節(jié) | 第4個(gè)字節(jié) |
| 0x00 | – | – | – |
| 0x10 | 左側(cè)PWM控制轉(zhuǎn)速 | 右側(cè)PWM控制轉(zhuǎn)速 | 轉(zhuǎn)向 |
| 0x20 | 左側(cè)PWM控制轉(zhuǎn)速 | 轉(zhuǎn)向 | – |
| 0x30 | 右側(cè)PWM控制轉(zhuǎn)速 | 轉(zhuǎn)向 | – |
| 0x40 | 傾斜角度 | – | – |
| 0x50 | 平移距離 | – | – |
| 0x60 | – | – | – |
| 0x70 | 圖片編碼 | – | – |
| 0x80 | 傳感器 ID(s) | – | – |
| 0x90 | 傳感器 ID(s) | – | – |
| 0xA0 | – | – | – |
| 0xB0 | 帶寬 | 擴(kuò)頻因子 | 編碼率 |
| 0xC0 | – | – | – |
| 0xD0 | – | – | – |
| 0xE0 | – | – | – |
| 0xF0 | – | – | – |
當(dāng)然,這些只是由控制系統(tǒng)發(fā)送然后機(jī)器人來(lái)接收的指令包。我們也希望機(jī)器人能夠作出響應(yīng)。對(duì)于某些指令,這種響應(yīng)可能非常簡(jiǎn)單,僅僅是為了讓控制系統(tǒng)知道指令是否被成功執(zhí)行。如果您仔細(xì)看上文中的表格,會(huì)注意到所有的指令都只用了第一個(gè)指令字節(jié)的高四位,這樣剩下的低四位可以用于響應(yīng)。這種方法有兩個(gè)顯著的優(yōu)勢(shì):首先,始終可以追蹤到每個(gè)響應(yīng)所屬的指令,因?yàn)橹噶钗豢偸亲鳛轫憫?yīng)值的一部分返回;其次,對(duì)于每一個(gè)指令,都有足夠的空間用于16種不同的響應(yīng)。
讓我們用一個(gè)例子來(lái)進(jìn)行說(shuō)明。假設(shè)我們想用相機(jī)拍攝一張圖片,那么我們會(huì)發(fā)送指令0x60。那么機(jī)器人有16種不同的方式來(lái)響應(yīng)。如果響應(yīng)是0x60,這意味指令已經(jīng)被成功執(zhí)行。所有其他類型的響應(yīng),0x61到0x6F,都意味著出現(xiàn)了錯(cuò)誤。這樣我們不僅知道指令執(zhí)行失敗了,還會(huì)知道為什么失敗并且進(jìn)行修正。當(dāng)然,這些響應(yīng)不一定總是只有一個(gè)字節(jié)的長(zhǎng)度,有些指令會(huì)要求機(jī)器發(fā)回一些附加信息,比如傳感器數(shù)據(jù)。下表顯示的是所有針對(duì)不同指令的響應(yīng)包。
| 指令 | 第1個(gè)字節(jié) | 第2個(gè)字節(jié) | 第3個(gè)字節(jié) | 第4~240字節(jié) |
| 0x00 | 0x00 | – | – | – |
| 0x10 | 0x10 | – | – | – |
| 0x20 | 0x20 | – | – | – |
| 0x30 | 0x30 | – | – | – |
| 0x40 | 0x40 | – | – | – |
| 0x50 | 0x50 | – | – | – |
| 0x60 | 0x6_ | – | – | – |
| 0x70 | 0x7_ | 圖像數(shù)據(jù) | 圖像數(shù)據(jù) | 圖像數(shù)據(jù) |
| 0x80 | 0x8_ | 發(fā)生錯(cuò)誤的傳感器 | 傳感器數(shù)據(jù) | 傳感器數(shù)據(jù) |
| 0x90 | 0x9_ | 發(fā)生錯(cuò)誤的傳感器 | 傳感器數(shù)據(jù) | 傳感器數(shù)據(jù) |
| 0xA0 | 0xA0 | – | – | – |
| 0xB0 | 0xB0 | – | – | – |
| 0xC0 | 0xC_ | 錯(cuò)誤標(biāo)志 | 錯(cuò)誤標(biāo)志 | – |
| 0xD0 | 0xD0 | – | – | – |
| 0xE0 | 0xE0 | – | – | – |
| 0xF0 | 0xF0 | – | – | – |
您可以注意到某些指令(主要是關(guān)于電機(jī)和伺服器的那些指令)只能返回0(成功)。這是因?yàn)楫?dāng)前版本中的板載電子設(shè)備無(wú)法判斷這些指令是否被成功執(zhí)行。為了達(dá)到驗(yàn)證的目的,我們需要增加新的設(shè)備來(lái)檢查電機(jī)是否在運(yùn)轉(zhuǎn),或者伺服器是否在正確的位置。這應(yīng)該不太困難,讓我們暫時(shí)忽略它,來(lái)看看那些可能會(huì)有報(bào)錯(cuò)響應(yīng)的指令:
? 0x60 (用相機(jī)拍攝照片)
這項(xiàng)指令有多種報(bào)錯(cuò)響應(yīng)。如果沒(méi)有相機(jī),那么機(jī)器人會(huì)返回0x61。如果有相機(jī)并且能夠正常工作,但是無(wú)法拍攝照片,那么會(huì)返回0x62。最后,如果成功拍攝了照片,但是不能存儲(chǔ),那么返回值為0x63。
? 0x70 (開始JPEG 傳輸)
這同樣是一個(gè)有多種返回值的指令。如果您能夠回想起我之前的文章 Arduino上的JPEG解碼,就知道第一個(gè)數(shù)據(jù)包里是有關(guān)圖片的信息,而非真實(shí)像素值。我們需要對(duì)這兩種類型進(jìn)行區(qū)分,所以說(shuō)如果數(shù)據(jù)包僅包含圖片信息,響應(yīng)值為0x70,后跟類似寬度、高度和單片機(jī)(MCU)計(jì)數(shù)的信息。如果數(shù)據(jù)包包含原始像素值,機(jī)器人的響應(yīng)值為0x71,后跟238字節(jié)的像素?cái)?shù)據(jù)。現(xiàn)在我們介紹報(bào)錯(cuò)代碼:如果響應(yīng)值是0x72,這意味著無(wú)法找到SD卡。如果是0x73,就表示SD卡沒(méi)問(wèn)題,但是無(wú)法找到請(qǐng)求的圖片。
? 0x80 (強(qiáng)制啟動(dòng)新傳感器測(cè)量)
該指令只有一種失敗模式—所請(qǐng)求的傳感器無(wú)法進(jìn)行測(cè)量。這種情況下,響應(yīng)值為0x81,后跟有包含暗示傳感器故障的一個(gè)字節(jié)。在這個(gè)字節(jié)中,位的索引對(duì)應(yīng)下列傳感器的順序(從MSB到LSB):左VNH5019,右VNH5019, BD1020HFV, ML8511A, BM1383GLV, KX022-1020, RPR-0521RS和BM1422GMV。比如,如果響應(yīng)的第二個(gè)字節(jié)是0x03 (0b0000 00011),表示傳感器RPR-0521RS 和 BM1422GMV故障。
? 0x90 (獲取最新傳感器數(shù)據(jù))
該指令與0x80非常相似—只有當(dāng)某些傳感器故障時(shí)才會(huì)顯示報(bào)錯(cuò)。如果那種情況發(fā)生,將會(huì)返回0x91,后跟有錯(cuò)誤標(biāo)志的相同字節(jié)。之后,將會(huì)有來(lái)自傳感器的最多46字節(jié)的數(shù)據(jù)。如果沒(méi)有傳感器發(fā)生故障,那么返回的第二個(gè)字節(jié)將會(huì)是簡(jiǎn)單的0x00,后跟有包含所有46字節(jié)的數(shù)據(jù)。
? 0xB0 (設(shè)置LoRa調(diào)制調(diào)節(jié)器配置)
這是目前應(yīng)用的指令中最后一個(gè)會(huì)報(bào)錯(cuò)的指令,雖然這項(xiàng)指令本不應(yīng)該會(huì)執(zhí)行失敗。該指令將設(shè)置新的LoRa調(diào)制調(diào)節(jié)器配置,LoRaLib檢驗(yàn)所提供配置的有效性。如果有一個(gè)或者更多的配置值無(wú)效,那么響應(yīng)字節(jié)中低四位之一將會(huì)被設(shè)置為相應(yīng)值。所以如果提供的帶寬是無(wú)效的,那么機(jī)器人將返回0xB1 (0b1011 0001)。如果提供的所有配置值都不正確,那么會(huì)返回0xB7 (0b1011 0111)。這項(xiàng)指令本不應(yīng)該會(huì)失敗,因?yàn)橛脩糁荒軓囊阎O(shè)定值中進(jìn)行選擇。但是,在執(zhí)行該指令時(shí)最好還是再檢查一遍。LoRa模塊是最關(guān)鍵的子系統(tǒng),沒(méi)有了它,就無(wú)法對(duì)機(jī)器人進(jìn)行控制。由于LoRa調(diào)制的屬性,兩個(gè)模塊上的設(shè)置必須相同,否則,接收器就無(wú)法對(duì)傳輸內(nèi)容進(jìn)行解調(diào)。
在解釋完所有內(nèi)容后,讓我們回到最開始的內(nèi)容。我們想要把左側(cè)電機(jī)的轉(zhuǎn)速設(shè)置為50%。我們已經(jīng)知道了指令首地址為0x20。所以根據(jù)表格內(nèi)容,我們可以填寫剩下的字節(jié),從控制器發(fā)送的指令包如下所示:
0x20 0x7F 0x00 0x00
第一個(gè)字節(jié)顯然是首地址—設(shè)置左側(cè)電機(jī)轉(zhuǎn)速。下一個(gè)字節(jié)是轉(zhuǎn)速。電機(jī)驅(qū)動(dòng)器通過(guò)PWM調(diào)制來(lái)改變電機(jī)轉(zhuǎn)速,所以數(shù)字0xF7(十進(jìn)制為127)對(duì)應(yīng)50%占空比或50%轉(zhuǎn)速。第三個(gè)字節(jié)是轉(zhuǎn)向—0x00表示正向,0x01表示逆向。最后一個(gè)字節(jié)僅用來(lái)占位—添加該字節(jié)來(lái)使指令包始終為四字節(jié)長(zhǎng)。一旦指令被接收并被機(jī)器人成功執(zhí)行,會(huì)返回以下指令包:
0x20
對(duì)于機(jī)器人上所運(yùn)行的Arduino程序,其指令系統(tǒng)的實(shí)現(xiàn)都可以在我的GitHub中查看。通常我在這上面發(fā)布實(shí)際代碼。不幸的是,代碼文件太大無(wú)法放在本文中。所以如果您對(duì)于代碼實(shí)現(xiàn)的細(xì)節(jié)有興趣的話,請(qǐng)查看實(shí)際代碼中的注釋。現(xiàn)在,我們來(lái)繼續(xù)看一些有趣的東西吧,那就是實(shí)現(xiàn)遠(yuǎn)程操控的應(yīng)用程序!
遠(yuǎn)程控制應(yīng)用程序
在ArduRover系列的最后一部分,我發(fā)布了一個(gè)機(jī)器人在計(jì)算機(jī)的控制下行駛的視頻。計(jì)算機(jī)上運(yùn)行的程序通過(guò)一個(gè)串行端口將數(shù)據(jù)發(fā)送給Arduino,然后Arduino傳送數(shù)據(jù)給機(jī)器人。但是,這種設(shè)置有幾個(gè)比較大的問(wèn)題。
首先,通過(guò)鍵盤來(lái)控制機(jī)器人是非常困難的。下圖是我在視頻中用來(lái)控制機(jī)器人的應(yīng)用程序的一個(gè)截圖。

圖3:測(cè)試電機(jī)的C#應(yīng)用程序
這是在Visual Studio 中的.NET框架下用C#語(yǔ)言來(lái)編寫的。雖然它能夠?qū)y(cè)試電機(jī)起到一些作用,但是對(duì)于一次只調(diào)整一側(cè)電機(jī)來(lái)控制機(jī)器人仍是一個(gè)挑戰(zhàn)。這真是令人心煩。用戶唯一可以控制的就是設(shè)置電機(jī)轉(zhuǎn)速的滑動(dòng)按鈕和使機(jī)器人立馬停止工作的按鈕。
我遇到的另一個(gè)比較大的問(wèn)題是用來(lái)測(cè)試的筆記本電腦比較重,不能用一只手拿著隨身攜帶,然后空出另一只手來(lái)控制機(jī)器人。好吧,一個(gè)隨身帶著筆記本電腦和寵物機(jī)器人的人看起來(lái)可能是有點(diǎn)奇怪。
為了使控制器變得更加簡(jiǎn)單和便攜,我需要一些可以連接到Arduino,并且重量輕、便于長(zhǎng)時(shí)間攜帶的、最好是可以手持的設(shè)備。如果隱蔽性比較好那就更好了。起初,我打算使用一個(gè)可以安裝在Arduino上的舊RC飛機(jī)控制器,但是后來(lái)我想到了一個(gè)更簡(jiǎn)單的解決方案:我的Android手機(jī)!它完美地符合所有要求:很輕并且可以手持。我們只需要通過(guò)USB端口或藍(lán)牙將其與Arduino連接即可。
我提出的下一個(gè)應(yīng)用程序是通過(guò)Android Studio用Java編寫的。這比上文中的C#語(yǔ)言應(yīng)用程序高級(jí)得多。它具有多個(gè)屏幕,允許用戶控制所有子系統(tǒng),而不僅僅是電機(jī)。讓我們來(lái)看一下其中一個(gè)屏幕上的布局。

圖4:基本的應(yīng)用程序布局
每個(gè)屏幕都會(huì)被分成幾個(gè)部分。在屏幕的兩側(cè),有兩個(gè)滑動(dòng)按鈕(上圖中1和2標(biāo)記的地方)來(lái)分別對(duì)左側(cè)和右側(cè)的電機(jī)設(shè)定轉(zhuǎn)向和轉(zhuǎn)速。這樣的布置可以使用戶能夠以更自然的方式來(lái)對(duì)機(jī)器人的移動(dòng)進(jìn)行控制:滑動(dòng)按鈕向上移動(dòng)使其前進(jìn),向下移動(dòng)使其后退。按鈕扭矩越大,那一側(cè)的電機(jī)轉(zhuǎn)速就越大。很簡(jiǎn)單!
接下來(lái)是下面(3)的一個(gè)大“停止”按鈕。它的作用看起來(lái)很好解釋:按下這個(gè)按鈕,電機(jī)就會(huì)停止。當(dāng)我用C#應(yīng)用程序測(cè)試機(jī)器人時(shí),這應(yīng)該是最有用的按鈕了,所以我決定在該應(yīng)用程序中保留這個(gè)設(shè)計(jì)。在應(yīng)用程序的頂部,有一個(gè)帶有多個(gè)標(biāo)簽的欄(4)。由于控制內(nèi)容太多,無(wú)法都呈現(xiàn)在一個(gè)屏幕上,這個(gè)條形欄可以使用戶在不同屏幕間切換。該屏幕中的內(nèi)容顯示在中心位置(5)。這意味著用戶可以通過(guò)任何屏幕上來(lái)控制機(jī)器人以及停止所有電機(jī)!
這些屏幕(按照應(yīng)用程序頂部條形欄中的排列順序)為:
? “相機(jī)”屏。 – 用戶可以更改相機(jī)位置,拍攝并保存圖片。目前相機(jī)的傾斜角度和水平位移也都顯示在這里。中間的藍(lán)色大框中還能顯示接收到的圖像。

圖5:相機(jī)屏
? “GPS”屏。 – 在當(dāng)前版本應(yīng)用程序中還未實(shí)現(xiàn)。這個(gè)想法是希望有一個(gè)地圖,可以顯示最近一次接收到的機(jī)器人位置。

圖6:GPS屏
? “圖形”屏。 – 同樣在最新版本中尚未實(shí)現(xiàn)。在這個(gè)屏幕中,傳感器的輸出將以圖形顯示,類似于Arduino IDE中的串行繪圖儀。

圖7:圖形屏
? “傳感器”屏。 – 該頁(yè)面顯示傳感器的最近一次輸出,同時(shí)也包含一些按鈕來(lái)強(qiáng)制啟動(dòng)傳感器進(jìn)行新的測(cè)量,或更新顯示值。

圖8:傳感器屏
? “監(jiān)視器”屏。 – 基本上與Arduino IDE中的串行監(jiān)視器相同:用戶打字輸入,監(jiān)視器顯示輸出。該屏幕也顯示所有發(fā)送的指令(黑色文本),機(jī)器人的所有響應(yīng)(藍(lán)色文本),所有報(bào)錯(cuò)(紅色文本),或者來(lái)自應(yīng)用程序的常規(guī)信息(灰色文本)。

圖9:監(jiān)視器屏
? “設(shè)置”屏。 – 包含多種設(shè)置,大部分與USB、藍(lán)牙和LoRa通信相關(guān)。此外,屏幕上有一個(gè)按鈕,我們可以用它來(lái)從機(jī)器人獲取當(dāng)前存在的所有錯(cuò)誤。

圖10:設(shè)置屏
結(jié)論
像往常一樣,我們呈現(xiàn)一些試駕的照片!






顯然,在許多地方仍然有很大的改進(jìn)空間。比如說(shuō),測(cè)試機(jī)器人的時(shí)候,我注意到抑制器會(huì)有向下垂的趨勢(shì)。

圖11:機(jī)器人移動(dòng)時(shí)的懸架細(xì)節(jié)可以注意到車身前部離地面較近
盡管這不是一個(gè)很大的問(wèn)題,但它表明出抑制器內(nèi)部的彈簧設(shè)置得有點(diǎn)松。彈簧設(shè)置更緊一些,機(jī)器人的車體就會(huì)更高一些,這樣在崎嶇地形中被困住的可能性會(huì)更小。
另一個(gè)可以改進(jìn)的是應(yīng)用程序。顯然,其中某些部分現(xiàn)在只是個(gè)占位符而已:GPS和圖形選項(xiàng)不包含任何內(nèi)容,所以如果能夠?qū)崿F(xiàn)這些功能就更好了。不幸的是,在編寫程序的時(shí)候,我還沒(méi)想到該怎么做,所以我可能還需要更多的Android Studio經(jīng)驗(yàn)才能找到方法。
最后,傳感器和相機(jī)的位置布局也是可以改善的部分。雖然通常的習(xí)慣是將相機(jī)放在機(jī)器人的前方,但是這樣還是有些暴露。可能通過(guò)使用某種桿來(lái)放在中間會(huì)更好一些,就像你在所有火星探測(cè)器上看到的那樣。既然說(shuō)到這里,添加一些太陽(yáng)能電池板并將整個(gè)設(shè)備用于某些太空任務(wù)可能也是個(gè)不錯(cuò)的注意!如果您有幾億美元的閑置資金并且愿意用來(lái)資助這項(xiàng)驚人的太空冒險(xiǎn)計(jì)劃,就跟我聯(lián)系吧!
言歸正傳,非常感謝您閱讀這篇文章以及對(duì)整個(gè)系列的關(guān)注。如果您對(duì)機(jī)器人有任何想法請(qǐng)?jiān)谙旅嬗懻搮^(qū)留言!如果您決定要親自構(gòu)建屬于您自己的ArduRover,請(qǐng)記得與全世界分享您的成果!

Jan Gromes
Jan 目前在布爾諾工業(yè)大學(xué)學(xué)習(xí)電氣工程。他有多年使用Arduino和其他微控制器來(lái)構(gòu)建項(xiàng)目的經(jīng)驗(yàn),對(duì)于機(jī)器人系統(tǒng)的機(jī)械設(shè)計(jì)十分感興趣。
審核編輯黃宇
-
編程
+關(guān)注
關(guān)注
90文章
3725瀏覽量
97467 -
Arduino
+關(guān)注
關(guān)注
190文章
6527瀏覽量
197541
發(fā)布評(píng)論請(qǐng)先 登錄
esp32-S3支持arduino編程嗎?
玩轉(zhuǎn)Arduino手機(jī)編程
自主漫游車的制作
Exxelia元件助力毅力號(hào)漫游車
Exxelia元件助力毅力號(hào)漫游車
基于Arduino UNO的自主導(dǎo)航漫游車
Arduino 101 BLE漫游者遙控器
關(guān)于幫助農(nóng)民的地球漫游車開源案例
Arduino探索漫游車2—電子設(shè)備與布線
AWS DeepRacer到自動(dòng)駕駛漫游車
用 樹莓派 Zero 打造的智能漫游車!
Arduino探索漫游車3—編程
評(píng)論