作者介紹
Liz Looney
Liz Looney是本書(shū)的合著者之一。她是谷歌的軟件工程師,也是谷歌“機(jī)器人工作小組”(Robotics Task Force)的成員,作為App Inventor團(tuán)隊(duì)的初創(chuàng)成員,她領(lǐng)導(dǎo)了樂(lè)高頭腦風(fēng)暴機(jī)器人(LEGO MINDSTORMS)組件的開(kāi)發(fā)工作。Liz Looney是一位卓越的軟件工程師,有著超過(guò)25年的從業(yè)經(jīng)歷,曾先后在Borland、Oracle及Google公司工作。
本章將創(chuàng)建一個(gè)應(yīng)用,將Android手機(jī)變成LEGO MINDSTORMS NXT 機(jī)器人的遙控器。應(yīng)用中用按鈕來(lái)控制機(jī)器人前后移動(dòng)、左右轉(zhuǎn)動(dòng)和停止,如果機(jī)器人遇到障礙物,它還會(huì)自動(dòng)停止。應(yīng)用中使用具有藍(lán)牙功能的手機(jī)與機(jī)器人通信。
LEGO MINDSTORMS機(jī)器人不只是玩具,更是教具。After-school program 使用機(jī)器人來(lái)教小學(xué)和初中的孩子們掌握解決問(wèn)題的能力,并引導(dǎo)他們了解工程和計(jì)算機(jī)編程。NXT機(jī)器人也用于FIRST LEGO League 機(jī)器人競(jìng)賽,這項(xiàng)比賽允許9-14歲的孩子參加。
NXT可編程機(jī)器人套件中有一個(gè)“NXT智能積木”主單元,它可以控制三個(gè)電機(jī)及四個(gè)輸入傳感器。你可以用樂(lè)高的構(gòu)造元件、齒輪、車輪、電機(jī)和傳感器來(lái)組裝機(jī)器人。該套件自帶的軟件可以對(duì)機(jī)器人進(jìn)行編程,但現(xiàn)在我們將用App Inventor來(lái)創(chuàng)建Android應(yīng)用,通過(guò)藍(lán)牙連接來(lái)控制NXT機(jī)器人。
應(yīng)用中參與協(xié)作的機(jī)器人具有超聲波傳感器以及用于移動(dòng)的車輪,如Shooterbot 機(jī)器人。圖中所示,這款機(jī)器人通常是人們利用LEGO MINDSTORMS NXT 2.0套件建造的第一個(gè)機(jī)器人。它的左車輪與輸出端口C相連,右車輪與輸出端口B相連,顏色傳感器與輸入端口3相連,超聲波傳感器與輸入端口4相連。
本章用到了以下組件和概念:
BluetoothClient組件:用于建立Android設(shè)備與NXT機(jī)器人之間的藍(lán)牙連接;
ListPicker組件:為用戶提供機(jī)器人選擇列表,選中后開(kāi)始建立機(jī)器人到Android的連接;
NxtDrive組件:用于驅(qū)動(dòng)機(jī)器人的輪子;
NxtUltrasonicSensor組件:利用機(jī)器人的超聲波傳感器探測(cè)障礙物;
本章的應(yīng)用需要Android 2.0或以上版本。此外,出于安全原因,藍(lán)牙設(shè)備必須首先配對(duì)才能彼此連通。在開(kāi)始構(gòu)建應(yīng)用之前,需要按以下步驟使Android設(shè)備與NXT機(jī)器人配對(duì):
1. 在NXT上單擊向右箭頭,直到顯示“Bluetooth”,然后按下橙色方塊;
2. 點(diǎn)擊向右的箭頭,直到顯示“Visibility”,然后按下橙色方塊;
3. 如果“Visibility”值已設(shè)定為可見(jiàn),繼續(xù)步驟4;如果不可見(jiàn),請(qǐng)單擊向左或向右箭頭設(shè)置其值為可見(jiàn);
4. 在Android設(shè)備上,進(jìn)入設(shè)置→無(wú)線與網(wǎng)絡(luò);
5. 確保打開(kāi)藍(lán)牙功能;
6. 點(diǎn)擊“藍(lán)牙”;
7. 在“可用設(shè)備”中查找名為“NXT”的設(shè)備;
8. 如果機(jī)器人名字下顯示“已配對(duì)但未連接”字樣,則配對(duì)成功!否則,繼續(xù)執(zhí)行步驟9;
9. 如果機(jī)器人名字下顯示“與此設(shè)備配對(duì)”,則點(diǎn)擊它;
10. 在NXT上,要求輸入密碼,按下橙色方塊接受1234為密碼;
11. 在Android上,也會(huì)要求輸入PIN碼,輸入1234,然后按確定;
12. 現(xiàn)在應(yīng)該看到“已配對(duì)但未連接?!?,說(shuō)明配對(duì)成功!
注意:如果你曾經(jīng)修改過(guò)機(jī)器人的名字,則尋找機(jī)器人現(xiàn)在的名字,而非“NXT”。
連接到App Inventor網(wǎng)站,創(chuàng)建新項(xiàng)目“NXTRemoteControl”,將設(shè)置屏幕的標(biāo)題為“遙控機(jī)器人”,并連接測(cè)試手機(jī)。
在這個(gè)應(yīng)用中,我們需要分別創(chuàng)建可見(jiàn)組件及不可見(jiàn)組件,并分別定義它們的行為。
在創(chuàng)建用戶界面之前,先來(lái)創(chuàng)建表12-1中的不可見(jiàn)組件,如圖12-1所示,用來(lái)控制NXT。
表12-1 NXT“機(jī)器人遙控”應(yīng)用中的不可見(jiàn)組件
組件類型 | 面板中分組 | 命名 | 作用 |
---|---|---|---|
BluetoothClient | Connectivity | BluetoothClient1 | 建立Android與NXT的連接 |
NxtDrive | LEGO? MINDSTORMS? | NxtDrive1 | 驅(qū)動(dòng)機(jī)器人的輪 |
NxtUltrasonicSensor | LEGO? MINDSTORMS? | NxtUltrasonicSensor1 | 檢測(cè)障礙物 |
Notifier | User Interface | Notifier1 | 顯示錯(cuò)誤信息 |
圖 12-1 在組件設(shè)計(jì)器底部顯示的不可見(jiàn)組件
按以下方式設(shè)置組件的屬性:
1. 設(shè)置NxtDrive1及NxtUltrasonicSensor1的BluetoothClient屬性為 BluetoothClient1;(說(shuō)明輪子的驅(qū)動(dòng)與障礙物的偵測(cè)都需要依賴藍(lán)牙通信——譯者注)
2. 勾選NxtUltrasonicSensor1的BelowRangeEventEnabled屬性(近距離偵測(cè)障礙物功能可用);
3. 設(shè)置NxtDrive1的DriveMotors屬性
如果機(jī)器人的左輪電機(jī)與輸出端口C連接,右輪電機(jī)與輸出端口B連接,則保持默認(rèn)設(shè)置“CB”;
4. 設(shè)置NxtUltrasonicSensor1的SensorPort屬性
如果機(jī)器人的超聲波傳感器與輸入端口4連接,則保持默認(rèn)值“4”;
現(xiàn)在創(chuàng)建用戶界面組件,如圖12-2所示。
圖 12-2 組件設(shè)計(jì)器中的應(yīng)用
建立藍(lán)牙連接時(shí),Android設(shè)備需要訪問(wèn)NXT機(jī)器人具有唯一性的藍(lán)牙地址,但藍(lán)牙地址由8個(gè)用冒號(hào)分隔的2位數(shù)的十六進(jìn)制數(shù)(二進(jìn)制數(shù)的另一種表示方式)組成,輸入起來(lái)異常麻煩,而且每次運(yùn)行應(yīng)用都要在手機(jī)上輸入該地址。為了減少麻煩,使用ListPicker來(lái)顯示已經(jīng)與手機(jī)配對(duì)的機(jī)器人列表(列表項(xiàng)的值為機(jī)器人的名稱及藍(lán)牙地址),并從中選擇一個(gè)。
使用按鍵來(lái)驅(qū)動(dòng)機(jī)器人的前進(jìn)、后退、左右轉(zhuǎn)動(dòng)、停止和斷開(kāi)連接,使用VerticalArrangement來(lái)放置除ListPicker以外的所有組件,用HorizontalArrangement來(lái)放置左右轉(zhuǎn)向及停車按鈕。
按照表12-2中列出的組件來(lái)創(chuàng)建圖12-2所示的用戶界面。
表12-2 NXT機(jī)器人控制器應(yīng)用中的可見(jiàn)組件
組件類型 | 面板中分組 | 命名 | 作用 |
---|---|---|---|
ListPicker | User Interface | ConnectListPicker | 選擇要連接的機(jī)器人 |
VerticalArrangement | layout | VerticalArrangement1 | 布局容器,容納除ListPicker之外的組件 |
Button | User Interface | ForwardButton | 前進(jìn) |
HorizonalArrangement | layout | HorizonalArrangement1 | 布局容器,容納左轉(zhuǎn)、右轉(zhuǎn)、停止按鈕 |
Button | User Interface | LeftButton | 左轉(zhuǎn) |
Button | User Interface | StopButton | 停止 |
Button | User Interface | RightButton | 右轉(zhuǎn) |
Button | User Interface | BackwardButton | 后退 |
Button | User Interface | DisconnectButton | 與NXT斷開(kāi)連 |
按照?qǐng)D12-2所示來(lái)設(shè)置可視組件布局:將LeftButton、StopButton和RightButton放在HorizontalArrangement1中,將ForwardButton、HorizontalArrangement1、BackwardButton和DisconnectButton放在VerticalArrangement1中。 按下列方式設(shè)置組件屬性:
1. 取消勾選Screen1的Scrollable屬性(滾屏功能);
2. 設(shè)置ConnectListPicker和DisconnectButton的寬度為“Fill parent”;
3. 設(shè)置VerticalArrangement1、ForwardButton、HorizontalArrangement1、LeftButton、StopButton、RightButton及BackwardButton的Width與Height為“Fill parent”;
4. 設(shè)置ConnectListPicker的Text屬性為“連接”;
5. 設(shè)置ForwardButton的Text屬性為“∧”;
6. 設(shè)置LeftButton的Text屬性為“<”;
7. 設(shè)置StopButton的Text屬性為“—”;
8. 設(shè)置RightButton的Text屬性為“>”;
9. 設(shè)置BackwardButton的Text屬性為“∨”;
10. 設(shè)置DisconnectButton的Text屬性為“斷開(kāi)連接”;
11. 設(shè)置ConnectListPicker和DisconnectButton的FontSize屬性為30;
12. 設(shè)置ForwardButton、LeftButton、StopButton、RightButton及BackwardButton的FontSize屬性為40。
在這類應(yīng)用中,當(dāng)手機(jī)與NXT建立藍(lán)牙連接之前,應(yīng)該隱藏用戶的操作界面,為此取消勾選VerticalArrangement1的Visible屬性。不要擔(dān)心,當(dāng)NXT連通后,將重新顯示用戶界面。
本節(jié)將編程來(lái)設(shè)置應(yīng)用的行為,包括:
用戶從列表中選擇機(jī)器人,并與之建立連接;
斷開(kāi)機(jī)器人與應(yīng)用的連接;
使用控制按鈕來(lái)操控機(jī)器人;
添加第一個(gè)行為:連接到NXT。點(diǎn)擊 ConnectListPicker將顯示已配對(duì)的機(jī)器人列表,選中一個(gè),將在應(yīng)用與機(jī)器人之間建立藍(lán)牙連接。
使用ConnectListPicker組件來(lái)顯示機(jī)器人列表。ListPicker的外表像按鈕,被點(diǎn)擊后則顯示列表項(xiàng),并允許進(jìn)行單選。
使用BluetoothClient1.AddressesAndNames塊來(lái)提供列表,列表項(xiàng)是已經(jīng)與Android設(shè)備配對(duì)的藍(lán)牙設(shè)備的名稱及地址。由于NXT已經(jīng)將輪驅(qū)動(dòng)及超聲波組件的BluetoothClient屬性設(shè)定為BluetoothClient1,因此AddressesAndNames屬性列表中的設(shè)備會(huì)自動(dòng)限定為這類機(jī)器人,其他類型的藍(lán)牙設(shè)備(如耳機(jī))將不會(huì)出現(xiàn)在列表中。表12-3列出了所需要的塊。
表12-3 在應(yīng)用中添加ListPicker列表所需要的塊
塊的類型 | 所在抽屜 | 作用 |
---|---|---|
ConnectListPicker.BeforePicking | ConnectListPicker | 當(dāng)ConnectListPicker被點(diǎn)擊時(shí),觸發(fā)該事件 |
set ConnectListPicker.Elements to | ConnectListPicker | 為ConnectListPicker設(shè)置可供選擇的列表項(xiàng) |
點(diǎn)擊ConnectListPicker將觸發(fā)ConnectListPicker.BeforePicking事件,并顯示可選項(xiàng)列表。將ConnectListPicker.Elements屬性設(shè)置為 BluetoothClient1.AddressesAndNames塊,來(lái)設(shè)定可選項(xiàng);ConnectListPicker將顯示已經(jīng)與Android設(shè)備配對(duì)的機(jī)器人列表。
圖 12-3 顯示機(jī)器人列表
測(cè)試:在手機(jī)上點(diǎn)擊“連接”,看看會(huì)發(fā)生什么,你會(huì)看到所有已經(jīng)與手機(jī)配對(duì)的機(jī)器人列表。
如果只見(jiàn)黑屏,說(shuō)明手機(jī)尚未與任何機(jī)器人配對(duì);如果見(jiàn)到其他藍(lán)牙設(shè)備,如藍(lán)牙耳機(jī),說(shuō)明 NxtDrive1與 NxtUltrasonicSensor1的BluetoothClient屬性設(shè)置有誤。
從列表中選擇一個(gè)機(jī)器人,應(yīng)用將通過(guò)藍(lán)牙與機(jī)器人連接。如果連接成功,用戶界面將發(fā)生變化:隱藏ConnectListPicker,并顯示用戶界面的其余部分。如果機(jī)器人開(kāi)關(guān)沒(méi)有打開(kāi),則連接失敗,會(huì)彈出錯(cuò)誤信息。
使用call BluetoothClient1.Connect塊與機(jī)器人進(jìn)行連接。ConnectListPicker.Selection屬性提供了選中機(jī)器人的地址和名稱信息。
使用ifelse塊來(lái)測(cè)試連接是否成功。ifelse塊需要連接三個(gè)不同的塊:“if”、“then”及“else”?!癷f”與BluetoothClient1.Connect塊連接,“then”區(qū)域放置連接成功時(shí)要執(zhí)行的塊;“else”區(qū)域放置連接失敗時(shí)要執(zhí)行的塊。
如果連接成功,使用Visible屬性來(lái)隱藏 ConnectListPicker并顯示VerticalArrangement1(其中放置了除ConnectListPicker之外的所有組件)。如果連接失敗,則使用Notifier1.ShowAlert塊來(lái)顯示錯(cuò)誤信息。表12-4列出了設(shè)置上述行為所需的塊。
表12-4與機(jī)器人建立藍(lán)牙連接所需的塊
塊的類型 | 所在抽屜 | 作用 |
---|---|---|
ConnectListPicker.AfterPicking | ConnectListPicker | 當(dāng)從ConnectListPicker選中一個(gè)機(jī)器人時(shí)觸發(fā) |
ifelse | Control | 檢驗(yàn)藍(lán)牙連接是否成功 |
call BluetoothClient1.Connect | BluetoothClient1 | 連接到機(jī)器人 |
ConnectListPicker.Selection | ConnectListPicker | 選中的機(jī)器人的地址及名稱 |
set ConnectListPicker.Visible to | ConnectListPicker | 隱藏ConnectListPicker按鈕 |
false | Logic | 插入set ConnectListPicker.Visible to塊 |
set VerticalArrangement1.Visible to | VerticalArrangement | 顯示“連接”按鈕之外的所有組件 |
true | Logic | 插入set VerticalArrangement1.Visible to塊 |
Notifier1.ShowAlert | Notifier1 | 用來(lái)彈出錯(cuò)誤信息 |
“無(wú)法建立藍(lán)牙連接?!?/td> | Text | 錯(cuò)誤信息。 |
選中機(jī)器人后將觸發(fā)ConnectListPicker.AfterPicking事件,見(jiàn)圖12-4,BluetoothClient1.Connect塊用于建立與機(jī)器人之間的藍(lán)牙連接。如果連接成功,執(zhí)行“then”塊:隱藏ConnectListPicker按鈕并顯示VerticalArrangement1內(nèi)的所有組件,即,設(shè)置ConnectListPicker.Visible屬性為false,設(shè)置VerticalArrangement1.Visible屬性為true。如果連接失敗,執(zhí)行“else”塊:用Notifier1.ShowAlert塊彈出錯(cuò)誤信息。
圖 12-4 建立藍(lán)牙連接
讓Android設(shè)備與NXT機(jī)器人連接著實(shí)讓人興奮,不過(guò)“斷開(kāi)連接”是我們下面要添加的行為,這樣便于對(duì)連接與斷開(kāi)進(jìn)行連續(xù)測(cè)試。
當(dāng)點(diǎn)擊DisconnectButton時(shí),應(yīng)用將關(guān)閉藍(lán)牙連接,用戶界面將發(fā)生變化:ConnectListPicker按鈕將重新出現(xiàn),而用戶界面上的其余組件將被隱藏。
表12-5列出了構(gòu)建BluetoothClient1.Disconnect(斷開(kāi)藍(lán)牙連接)所需的塊。設(shè)置Visible屬性來(lái)顯示 ConnectListPicker按鈕并隱藏VerticalArrangement1中包含的所有組件。
表12-5 與機(jī)器人斷開(kāi)連接所需的塊
塊的類型 | 所在抽屜 | 作用 |
---|---|---|
DisconnectButton.Click | DisconnectButton | 當(dāng)點(diǎn)擊DisconnectButton時(shí)觸發(fā)該事件 |
BluetoothClient1.Disconnect | BluetoothClient1 | 斷開(kāi)與機(jī)器人的藍(lán)牙連接 |
set ConnectListPicker.Visible to | ConnectListPicker | 顯示ConnectListPicker(“連接”按鈕) |
true | Logic | 插入set ConnectListPicker.Visible to塊 |
set VerticalArrangement1.Visible to | VerticalArrangement | 隱藏用戶界面上的其余組件 |
false | Logic | 插入set VerticalArrangement1.Visible to |
點(diǎn)擊DisconnectButton將觸發(fā)DisconnectButton.Clicked事件,如圖12-5所示,斷開(kāi)藍(lán)牙連接要用BluetoothClient1.Disconnect塊,之后設(shè)置ConnectListPicker.Visible屬性為true來(lái)顯示 ConnectListPicker,設(shè)置VerticalArrangement1.Visible屬性為false來(lái)隱藏VerticalArrangement1。
圖 12-5 與機(jī)器人斷開(kāi)連接
測(cè)試:請(qǐng)確保機(jī)器人已經(jīng)打開(kāi),點(diǎn)擊手機(jī)上的“連接”按鈕,并選擇要連接的機(jī)器人。建立藍(lán)牙連接需要一點(diǎn)時(shí)間。一旦連接成功,用戶界面將顯示機(jī)器人的控制按鈕,以及“斷開(kāi)連接”按鈕。
單擊“斷開(kāi)連接”按鈕:控制機(jī)器人的按鈕會(huì)消失,“連接”按鈕則重新出現(xiàn)。
下面是真正有趣的部分:添加前進(jìn)、后退、左右轉(zhuǎn)動(dòng)及停止行為。不要忘記“停止”,否則你手中的機(jī)器人會(huì)失去控制!
NxtDrive組件提供了五個(gè)塊,用來(lái)驅(qū)動(dòng)機(jī)器人的電機(jī):
MoveForwardIndefinitely塊:驅(qū)動(dòng)兩個(gè)電機(jī)前進(jìn);
MoveBackwardIndefinitely塊:驅(qū)動(dòng)兩個(gè)電機(jī)后退;
TurnCounterClockwiseIndefinitely塊:驅(qū)動(dòng)機(jī)器人左轉(zhuǎn):讓右側(cè)電機(jī)向前而左側(cè)電機(jī)后退;
TurnClockwiseIndefinitely塊:驅(qū)動(dòng)機(jī)器人右轉(zhuǎn):讓左側(cè)電機(jī)向前而右側(cè)電機(jī)后退;
每個(gè)移動(dòng)及轉(zhuǎn)向塊都有一個(gè)Power參數(shù),需要與數(shù)字塊配合使用,來(lái)設(shè)定機(jī)器人電機(jī)的輸出功率,取值范圍可以從 0到100。但如果設(shè)置的功率太小,電機(jī)會(huì)發(fā)出吱吱聲而不運(yùn)轉(zhuǎn)。在本例中建議使用90(百分比)。表12-6中列出了所需的塊。
表12-6 用于控制機(jī)器人的塊
塊的類型 | 所在抽屜 | 作用 |
---|---|---|
ForwardButton.Clic | ForwardButton | 點(diǎn)擊ForwardButton時(shí)觸 |
NxtDrive1.MoveForwardIndefinitely | NxtDrive1 | 驅(qū)動(dòng)機(jī)器人前進(jìn) |
數(shù)字90 | Math | 功率值 |
BackwardButton.Click | BackwardButton | 點(diǎn)擊BackwardButton時(shí)觸發(fā) |
NxtDrive1.MoveBackwardIndefinitely | NxtDrive1 | 驅(qū)動(dòng)機(jī)器人后退 |
數(shù)字90 | Math | 功率值 |
LeftButton.Click | LeftButton | 點(diǎn)擊LeftButton時(shí)觸發(fā) |
NxtDrive1.TurnCounterClockwiseIndefinitely | NxtDrive1 | 驅(qū)動(dòng)機(jī)器人逆時(shí)針轉(zhuǎn)動(dòng) |
數(shù)字90 | Math | 功率值 |
RightButton.Click | RightButton | 點(diǎn)擊RightButton時(shí)觸發(fā) |
NxtDrive1.TurnClockwiseIndefinitely | NxtDrive1 | 驅(qū)動(dòng)機(jī)器人順時(shí)針轉(zhuǎn)動(dòng) |
數(shù)字90 | Math | 功率值 |
StopButton.Click | StopButton | 點(diǎn)擊StopButton時(shí)觸發(fā) |
NxtDrive1.Stop | NxtDrive1 | 讓機(jī)器人停止 |
如圖12-6所示,點(diǎn)擊ForwardButton按鈕時(shí)觸發(fā)ForwardButton.Clicked事件,此時(shí)調(diào)用NxtDrive1.MoveForwardIndefinitely塊,讓機(jī)器人以90%的功率前進(jìn),其余按鈕的事件處理程序與此類似,并以相同的功率驅(qū)動(dòng)機(jī)器人后退及左右轉(zhuǎn)動(dòng)。點(diǎn)擊StopButton時(shí)觸發(fā)StopButton.Clicked事件,調(diào)用NxtDrive1.Stop塊讓機(jī)器人停止運(yùn)動(dòng)。
圖 12-6 操控機(jī)器人
更多建議: