AmebaMotors – 用手機控制有Ameba的4輪小車
材料準備
- Ameba x 1
- L298N H-Bridge x 1
- 4輪車 or 2輪車+萬向輪
- Android Phone
範例說明
這裡我們使用的範例是 “Files” -> “Examples” -> “AmebaMotors” -> “car2wd_mobile_control”
如果沒看到這個範例,請先下載library: AmebaMotors
下載之後,參考Arduino官方網站的教學文章將zip檔的library加入Ameba: https://www.arduino.cc/en/Guide/Libraries#toc4這個範例裡,我們做了幾件事:
1. 將控制小車的方式包成Car2wd的Class,裡面實作了OS thread、signal,讓小車的thread與main thread分開執行。
2. Ameba的main thread會啟動WiFi AP mode,並開啟TCP socket成為server 端,等待client端連進來並傳送控制小車的資料
3. 手機端在下載 “Ameba Car Remote”之後,將WiFi連到 ssid “mycar” 之後,打開 app,app會連上Ameba成為client端,使用者可以操作螢幕上的控制桿來控制小車
下載之後,參考Arduino官方網站的教學文章將zip檔的library加入Ameba: https://www.arduino.cc/en/Guide/Libraries#toc4這個範例裡,我們做了幾件事:
1. 將控制小車的方式包成Car2wd的Class,裡面實作了OS thread、signal,讓小車的thread與main thread分開執行。
2. Ameba的main thread會啟動WiFi AP mode,並開啟TCP socket成為server 端,等待client端連進來並傳送控制小車的資料
3. 手機端在下載 “Ameba Car Remote”之後,將WiFi連到 ssid “mycar” 之後,打開 app,app會連上Ameba成為client端,使用者可以操作螢幕上的控制桿來控制小車
我們一步一步完成操作:
1. 接線:接線的方式請參考範例 “用Ameba控制4輪小車” 。
2. 上傳程式碼:在將Micro USB接上Ameba之前,先將L298N的電源拔掉避免小車亂跑。然後編譯並上傳程式碼。上傳完之後再將L298N的電源接上
3. 手機下載app:請到google play,輸入關鍵字 “Ameba Car Remote”,可以找到有螃蟹圖案app。如果找不到的話,也可以在手機瀏覽器打開底下的網址: https://play.google.com/store/apps/details?id=app.akexorcist.joystickcontroller
4. 將手機連上Ameba:進入 “設定” -> “Wi-Fi”,在ssid列表中找到 ssid “mycar”,點選之後會要求輸入密碼,請輸入密碼 “12345678”,然後確認已連線。因為Ameba並沒有連到Internet,所以有些Android手機會跳出訊息說沒有網路能力,甚至自動地幫你斷線連到其它ssid,請注意是否正確連上。
5. 打開app:會看到底下的操作畫面
- 左邊的操縱桿往上拉,車子會往前走;往下拉,車子會倒退
- 右邊的操縱桿往右,車子會向右順時鐘旋轉;往左,車子向左逆時鐘旋轉
- 同時操作左邊與右邊操縱桿,車子會做出前進轉彎或後退轉彎
疑難排解:
– 如果發現操作App但車子沒有反應,請按手機的後退鍵離開app,檢查wifi的ssid是否還連著mycar。
– 如果還連著mycar,再打開app試看看。
– 如果mycar已經不見了,檢查Ameba開發板上的燈是否還亮著,如果沒亮代表Ameba可能因為瞬間電流造成電源無法反應、或電源無法供應太大的電流、也有可能MicroUSB的線材無法接受太大的電流(有些市面上的MicroUSB甚至只能接受0.2mA的電流)。
底下是我們demo的影片:
程式碼說明
- Car2wd與OS thread, signal的使用
Class Car2wd裡實作OS thread與signal,整個概念如下圖:- 在setup()裡面我們呼叫car.begin(),裡面使用 os_thread_create() 新增一個thread:
tid = os_thread_create(carTask, this, OS_PRIORITY_REALTIME, 1024);
– 第一個參數是function pointer,是thread起來之後要執行的程式,function pointer的prototype像這樣:void carTask(const void *arg)
。一般來說,RTOS的thread都會讓thread function一直執行,並且有它結束的方式。在結束之前,會用無窮迴圈放在裡面執行。
– 第二個參數是要帶給thread funtion的參數。參考第一個參數的carTask(const void *arg)
裡面的arg
,這邊我們將Class Car2wd指向self-instance的pointer帶給carTask, 讓carTask可以操作Car2wd的內容。
– 第三個參數是Thread的優先權。我們使用的OS底層是FreeRTOS,當有多個Thread的情況下,FreeRTOS會只執行優先權的值最高的Thread。如果這樣的Thread超過2個,那麼FreeRTOS會輪流執行(但不會執行優先權低的)。為了避免低優先權的Thread遇到Starvation,高優先權的Thread在執行完任務的時候,要經由non-busy delay釋放執行權。
– 第四個參數是這個Thread需要的memory。這個memory的內容包括stack與local memory。設定太小的話,有可能會在stack增加的時候覆蓋到local memory。
–os_thread_create()
的回傳值是新增的這個thread的thread id,讓main thread可以使用這個thread id對carTask做一些操作。 - 啟動Thread之後,會在carTask()裡面執行,一進去就執行這行等待signal:
evt = os_signal_wait(0, 0xFFFFFFFF);
– 第一個參數是要等待的signal。填0代表等待任何signal
– 第二個參數是要等待多久,單位是ms。填0xFFFFFFFF
代表沒有timeout,要一直等下去。
– 回傳值代表等帶的結果,內容包括是否timeout,等到的signal是什麼。
在執行os_signal_wait
之後,carTask就釋放執行權,讓其它thread可以執行。 - 通知carTask做事:我們在main thread呼叫
car.setAction(CAR_FORWARD, abs(yspeed));
在setAction
裡面(這時候還在main thread),我們只是設定好signal,然後使用os_signal_set
()通知carTaskos_signal_set(tid, sig);
– 第一個參數是被通知的thread id,我們填入carTask的thread id,第二個參數是signal的內容 - 在carTask裡面,原本在
os_signal_wait()
等待,這時候等待的signal出現了,就繼續往下執行,並且查看signal的內容做對應的工作
- 在setup()裡面我們呼叫car.begin(),裡面使用 os_thread_create() 新增一個thread:
- Ameba AP mode與建立TCP socket
開啟AP mode的方式請參考 Ameba wifi ap的範例。在開啟AP mode之後,我們建立tcp socket的方式與之前一樣
1. 設定server要聽的port
WiFiServer server(5001);
2. 設定server端
WiFiClient client = server.available();
3. 等待client連進來
while (client.connected()) {
4. 讀取client0傳送過來的資料
client.read(buffer, sizeof(buffer))
5. 我們parsing這份資料:我們會收到Android app “Ameba Car Remote”的資料,資料格式是文字:
Y:12 – 代表Y軸(前後)的值是12(值的範圍是 -12 ~ +12),車子會全速往前跑
Y:-6 – 車子會半速倒退
X:12 – 車子會全速向右順時鐘旋轉
Y:12, X:-6 – 車子會全速前進向左彎(當X跟Y都有速度的值時,使用Y的數值)
Copyrights ©瑞晟微电子(苏州)有限公司 2021. All rights reserved. Terms of Use