本篇文章示範如何使用 App Inventor 之 BLE (Bluetooth Low Energy) 元件控制 Arduino 101 機器手臂 (架構比照 mearm,為四個自由度之桌上型機器手臂)。請注意,BLE元件尚未正式發布,請用 http://ble-test.apinventor.mit.edu 這個測試用伺服器來測試。
相關文章請點我
| [Make雜誌國際中文版]Arduino 101 介紹 | Arduino 101 BLE 第二課 LED呼吸燈(PWM) |
硬體架構
- Arduino 101
- Android 手機
- MeArm 或任何類似架構的四軸裝上型機器手臂,請參考我們的說明
App Inventor 程式說明
Designer頁面
使用到的元件除了 BLE 之外,其他幾乎都是 Button / Label 等基礎元件。概念上就是一大堆按鈕, 您可以自由安排版面的配置,本app操作的概念是按下某個按鈕就會發送訊號讓 Arduino 機器手臂執行某個動作,只要放開按鈕就會馬上停止,這是使用 Button 的 TouchUp / TouchDown 事件。

Blocks頁面
初始化:程式啟動時,要求 BLE 元件進行掃描。

連線與斷線:按下連線按鈕時,對指定 BLE 裝置 (Arduino 101) 發起連線,成功的話會在 Screen1.Title 顯示相關訊息。斷線時則執行相反的操作,會讓畫面上所有的按鈕變成不可操作(Enabled = false)



按下按鈕:在此只介紹 ButtonArmB1 (伸出前臂的這個按鈕),請注意我們在此使用按鈕的 TouchUp 與 Touchdown 等兩個事件。畫面上一共有八個按鈕,搭配各自的TouchUp 與 Touchdown 等事件,畫面非常滿啊!
實際上這樣寫法也太冗長了,您可以使用副程式來管理,其實只是送入不同的參數而已,很容易就可以讓程式變得更清爽喔!
Arduino 101 code
[pastacode lang=”c” message=”Arduino 101 BLE robotarm” highlight=”” provider=”manual” manual=”%23include%20%3CServo.h%3E%0A%23include%20%3CSoftwareSerial.h%3E%0A%23include%20%3CCurieBLE.h%3E%0AServo%20Bottom%3B%0AServo%20Clamp%3B%0AServo%20ArmA%3B%0AServo%20ArmB%3B%0ABLEPeripheral%20blePeripheral%3B%0ABLEService%20MeArm(%2219B10010-E8F2-537E-4F6C-D104768A1214%22)%3B%0ABLEUnsignedIntCharacteristic%20readchar(%2219B10011-E8F2-537E-4F6C-D104768A1214%22%2C%20BLERead%20%7C%20BLEWrite%20%7C%20BLENotify)%3B%0A%23define%20Bottom_pin%20%203%0A%23define%20Clamp_pin%20%209%0A%23define%20ArmA_pin%20%205%0A%23define%20ArmB_pin%20%206%0A%0A%23define%20Bottom_max%20%20170%0A%23define%20Bottom_min%20%200%0A%23define%20Clamp_max%20%20140%0A%23define%20Clamp_min%20%2050%0A%23define%20ArmA_max%20%20150%0A%23define%20ArmA_min%20%2050%0A%23define%20ArmB_max%20%20210%0A%23define%20ArmB_min%20%20120%0A%0Aint%20Clamp_pos%20%3D%20Clamp_max%3B%0Aint%20Bottom_pos%20%3D%20(Bottom_max%20%2B%20Bottom_min)%2F2%3B%0Aint%20ArmA_pos%20%3D%20ArmA_min%3B%0Aint%20ArmB_pos%20%3D%20ArmB_max%3B%0Aint%20delta%20%3D%2010%3B%0A%0Avoid%20setup()%20%7B%0A%20%20Serial.begin(9600)%3B%0A%20%20blePeripheral.setLocalName(%22MeArm%22)%3B%0A%20%20blePeripheral.setAdvertisedServiceUuid(MeArm.uuid())%3B%0A%20%20blePeripheral.addAttribute(MeArm)%3B%0A%20%20blePeripheral.addAttribute(readchar)%3B%0A%20%20readchar.setValue(0)%3B%0A%20%20blePeripheral.begin()%3B%0A%20%20Init_Pin()%3B%0A%7D%0A%0Avoid%20loop()%20%7B%0A%20%20BLECentral%20central%20%3D%20blePeripheral.central()%3B%0A%20%20if%20(central)%20%7B%0A%20%20%20%20Serial.print(%22Connected%20to%20central%3A%20%22)%3B%0A%20%20%20%20Serial.println(central.address())%3B%0A%20%20%20%20while(central.connected())%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20if(readchar.written())%0A%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20Serial.println(readchar.value())%3B%0A%20%20%20%20%20%20%20%20switch%20(readchar.value())%7B%0A%20%20%20%20%20%20%20%20case%201%3A%0A%20%20%20%20%20%20%20%20%20%20Serial.println(%22Turn%20Left%22)%3B%0A%20%20%20%20%20%20%20%20%20%20stopp()%3B%0A%20%20%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20%20%20BottomLeft()%3B%0A%20%20%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20%20%20break%3B%0A%0A%20%20%20%20%20%20%20%20case%203%3A%0A%20%20%20%20%20%20%20%20%20%20Serial.println(%22Turn%20Right%22)%3B%0A%20%20%20%20%20%20%20%20%20%20stopp()%3B%0A%20%20%20%20%20%20%20%20%20%20BottomRight()%3B%0A%20%20%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20%20%20break%3B%0A%0A%20%20%20%20%20%20%20%20case%208%3A%0A%20%20%20%20%20%20%20%20%20Serial.println(%22Clamp%20Open%22)%3B%0A%20%20%20%20%20%20%20%20%20stopp()%3B%0A%20%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20%20ClampOpen()%3B%0A%20%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20%20break%3B%0A%0A%20%20%20%20%20%20%20case%205%3A%0A%20%20%20%20%20%20%20%20Serial.println(%22Clamp%20Close%22)%3B%0A%20%20%20%20%20%20%20%20stopp()%3B%0A%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20ClampClose()%3B%0A%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20break%3B%0A%0A%20%20%20%20%20%20case%207%3A%0A%20%20%20%20%20%20%20%20Serial.println(%22Arm%20A%20Up%22)%3B%0A%20%20%20%20%20%20%20%20stopp()%3B%0A%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20ArmAUp()%3B%0A%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20break%3B%0A%0A%20%20%20%20%20%20case%204%3A%0A%20%20%20%20%20%20%20%20Serial.println(%22Arm%20A%20Down%22)%3B%0A%20%20%20%20%20%20%20%20stopp()%3B%0A%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20ArmADown()%3B%0A%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20break%3B%0A%0A%20%20%20%20%20%20case%209%3A%0A%20%20%20%20%20%20%20%20Serial.println(%22Arm%20B%20Up%22)%3B%0A%20%20%20%20%20%20%20%20stopp()%3B%0A%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20ArmBUp()%3B%0A%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20break%3B%0A%0A%20%20%20%20%20%20case%206%3A%0A%20%20%20%20%20%20%20%20Serial.println(%22Arm%20B%20Down%22)%3B%0A%20%20%20%20%20%20%20%20stopp()%3B%0A%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20ArmBDown()%3B%0A%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%20%20break%3B%0A%20%20%20%20%20%20case%200%3A%0A%20%20%20%20%20%20%20%20Serial.println(%22Stop%22)%3B%0A%20%20%20%20%20%20%20%20stopp()%3B%0A%20%20%20%20%20%20%20%20delay(100)%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%2F%2Fif%0A%20%20%20%20%7D%2F%2Fwhile%0A%20%20%20%20Serial.print(F(%22Disconnected%20from%20central%3A%20%22))%3B%0A%20%20%20%20Serial.println(central.address())%3B%0A%20%20%7D%2F%2Fif%0A%20%20%0A%7D%0A%20%20%0Avoid%20Init_Pin()%20%7B%0A%20%20Bottom.attach(Bottom_pin)%3B%0A%20%20Clamp.attach(Clamp_pin)%3B%0A%20%20ArmA.attach(ArmA_pin)%3B%0A%20%20ArmB.attach(ArmB_pin)%3B%0A%7D%0A%0Avoid%20ClampOpen()%20%7B%0A%20%20Clamp_pos%20%3D%20Clamp_min%3B%0A%20%20Clamp.write(Clamp_pos)%3B%0A%20%20%0A%7D%0Avoid%20ClampClose()%20%7B%0A%20%20Clamp_pos%20%3D%20Clamp_max%3B%0A%20%20Clamp.write(Clamp_pos)%3B%0A%20%20%0A%7D%0A%0Avoid%20BottomRight()%20%7B%0A%20%20if(Bottom_pos%20-%20delta%20%3E%20Bottom_min)%20%0A%20%20%20%20Bottom_pos%20-%3D%20delta%3B%0A%20%20Bottom.write(Bottom_pos)%3B%0A%20%20%0A%7D%0Avoid%20BottomLeft()%20%7B%0A%20%20if(Bottom_pos%20%2B%20delta%20%3C%20Bottom_max)%20%0A%20%20%20%20Bottom_pos%20%2B%3D%20delta%3B%0A%20%20Bottom.write(Bottom_pos)%3B%0A%20%20%0A%7D%0A%0Avoid%20ArmAUp()%20%7B%0A%20%20if(ArmA_pos%20%2B%20delta%20%3C%20ArmA_max)%20ArmA_pos%20%2B%3D%20delta%3B%20ArmA.write(ArmA_pos)%3B%20%7D%20void%20ArmADown()%20%7B%20if(ArmA_pos%20-%20delta%20%3E%20ArmA_min)%0A%20%20%20%20ArmA_pos%20-%3D%20delta%3B%0A%20%20ArmA.write(ArmA_pos)%3B%0A%7D%0A%0Avoid%20ArmBUp()%20%7B%0A%20%20if(ArmB_pos%20-%20delta%20%3E%20ArmB_min)%0A%20%20%20%20ArmB_pos%20-%3D%20delta%3B%0A%20%20ArmB.write(ArmB_pos)%3B%0A%7D%0Avoid%20ArmBDown()%20%7B%0A%20%20if(ArmB_pos%20%2B%20delta%20%3C%20ArmB_max)%0A%20%20%20%20ArmB_pos%20%2B%3D%20delta%3B%0A%20%20ArmB.write(ArmB_pos)%3B%0A%7D%0Avoid%20stopp()%20%7B%0A%20%20Bottom.write(Bottom_pos)%3B%0A%20%20Clamp.write(Clamp_pos)%3B%0A%20%20ArmA.write(ArmA_pos)%3B%0A%20%20ArmB.write(ArmB_pos)%3B%0A%7D%0A”/]








