網頁最後修改時間:2022/04/09
相較於用手機螢幕中的虛擬搖桿操作小車,直接用遊戲手把來控制小車,操作感受上有所不同,因此本篇要來介紹怎麼用 PS3/PS4 遊戲手把控制兩輪智能小車。
但要與 PS3/PS4 遊戲手把通訊,除了小車主控晶片要支援藍牙之外,還要特別撰寫與 PS3/PS4 遊戲手把藍牙通訊相關的程式。幸運的是,ESP32 不但支援藍牙通訊且已有封裝好這部分的函式庫可以用,剩下要做的就是,取得 PS3/PS4 遊戲手把的 MAC 地址,撰寫取得需要的按鈕和搖桿的程式後,就可以用來控制小車。
PS3/PS4 遊戲手把上,除了有多顆按鈕之外還有兩個搖桿。有的僅支援數位輸出,也有的不但支援數位輸出也支援類比輸出,而且內建單軸陀螺儀和三軸加速度計能支援體感操作,還能知道電池狀態等...,只要好好利用這些數據資料,就能搭配出不同的控制需求。
** PS3/PS4 遊戲手把除了使用的函式庫不同之外(PS4 功能比較多),本篇所說的步驟幾乎都是相同的,所以就不另外贅述!
本篇內容有:
- (01)取得 PS3/PS4 遊戲手把的 MAC Address
- (02)PS3/PS4 遊戲手把 ESP32 Arduino 函式庫
- (03)遊戲手把的小車動作組合鍵
- (04)遙控車程式框架說明
- (05)結論
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
有購買商品的使用者,網頁中所需相關資料已放置於雲端硬碟,請自行下載使用!
其餘的使用者,請自行依照提供之連結下載相關資料,程式碼複製貼上使用!
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
*********************************************************************************
更多機器人(多足、智能小車)相關商品,請至分類賣場。
*********************************************************************************
【(01)取得 PS3/PS4 遊戲手把的 MAC Address】
ESP32 要與 PS3/PS4 遊戲手把做藍牙通訊,首先要先知道 PS3/PS4 遊戲手把的 MAC 地址。雖然有很多方法可以用,但是並不是所有的方法、軟體、APP 所取出的 MAC 地址就是有效且可用的。
經過一些的測試之後發現,Sixaxis Pair Tool 所取得的是正確且有效的 MAC 地址。
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
*
(01-01)軟體操作步驟與使用說明:
在沒有插上 PS3/PS4 遊戲手把到電腦之前,安裝好 Sixaxis Pair Tool 之後打開它,會看到 Current Master: 出現 No device found... 的訊息。
插上 PS3/PS4 遊戲手把到電腦之後,若之前沒有安裝過驅動程式,則 Sixaxis Pair Tool 會自動安裝(安裝驅動程式需要一些時間,要耐心等等)。
若沒有驅動程式需要安裝的問題,那麼原本 Current Master: 地方就會出現 Searching... 的訊息,表示現在偵測到有東西插入到電腦的 USB 埠,軟體就會開始進行 PS3/PS4 遊戲手把的搜尋。
如果軟體有抓到 PS3/PS4 遊戲手把,則原本的 Current Master: 就會出現類似下圖 aa:bb:cc:dd:ee:ff 的 MAC 地址,而這就是下面 ESP32 Arduino 程式連線需要的 MAC 地址,要複製下來。
如果是原廠的 SONY PS3/PS4 遊戲手把,那麼若是有多支遊戲手把想要一起用的時候,作為相互之間辨識的最好方法就是修改 MAC 地址。Sixaxis Pair Tool 為此提供了修改 MAC 地址的功能,只要將要修改的 MAC 地址(例如,11:22:33:44:55:66)填入到 Change Master: 的欄位中,按下 "Update" 即可完成變更。
變更完成後,軟體畫面就會類似下圖所示,上下欄位值都會是一樣的(若是重開新的軟體視窗,至少 Current Master: 要是修改後的值 11:22:33:44:55:66)。
確認是否真的變更成功?建議直接拔掉 USB 線再重新插回電腦做確認。這時 Current Master: 會先變 Searching... 再變成 No device found...,插上 USB 線後就應該要出現類似與上圖同樣的 11:22:33:44:55:66 的欄位值,這樣才能保證被修改完成,也才能使用新修改的 MAC 地址,否則就不能用。
** 下面的程式碼使用修改後的 MAC 地址 11:22:33:44:55:66。
【(02)PS3/PS4 遊戲手把 ESP32 Arduino 函式庫】
PS4 遊戲手把的函式庫是以 PS3 遊戲手把的函式庫為基礎下去修改的,因此兩個函式庫使用的方法類似且差異不大,詳細可自行比較兩者的範例程式。
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
*
(02-01)函式庫下載:
如果有購買小車 ESP32 分類套件,函式庫已預先存放至雲端硬碟中,下載解壓縮即可使用。另外,若想自行下載,下載連結如下。
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
*
(02-02)遊戲手把的數據輸出範圍:
了解 PS3/PS4 遊戲手把的輸出數據範圍,對於小車動作的操作至關重要!
除了 "SELECT"、"START"、中間 "PS"、搖桿 "L3" 和 "R3" 這五顆按鈕沒有類比輸出數據之外,對於控制器其他的按鈕來說,輸出不但有數位(0 或 1)的數據,而且也有類比(0 至 255)的數據。
對於遊戲手把的兩個搖桿來說,輸出只有類比數據(-128 ~ 127),但要特別留意不同方向所代表的正負值和範圍。
另外,隱藏於遊戲手把內部的東西:陀螺儀 Z 軸和加速度計三軸的體感應用數據,還有就是鋰電池容量狀態等,都在這支遊戲手把裡。
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
*
(02-03)函式庫範例程式測試:
打開函式庫的範例程式 Ps3Demo,修改下圖中黃色背景的 MAC 地址。
編譯後上傳到 ESP32 開發板。
打開 "Serial Monitor",重啟 ESP32,最後按下遊戲手把上的 "PS" 按鈕,過幾秒後,遊戲手把就會和 ESP32 完成連線。這時遊戲手把上的四顆 LED 燈,就會開始由 player 1 至 10 輪流亮起。
按下和操作遊戲手把上的按鈕和搖桿,就能看到與下圖類似的訊息和數據的輸出。
關於小車 ESP32 UNO 開發板的 Arduino IDE 安裝版本和編譯選項的設定,請直接看雲端硬碟裡面的圖片照著安裝和設定即可。如果是使用其他不同的 ESP32 開發板,請自行修改相對應的編譯選項,這裡不再做贅述!
如果不清楚 Arduino IDE 如何安裝 ESP32 開發板套件,請看下面連結網頁中的說明。
** Arduino IDE 安裝 ESP32 開發板套件的說明
【(03)遊戲手把的小車動作組合鍵】
根據上一節 Ps3Demo 程式對遊戲手把的測試輸出訊息和數據,我對小車做了下面幾個動作的規劃:
-
左轉彎(左輪停止,右輪向前/向後)
按下 "L1" + 左搖桿上下控制小車右輪向前/向後的速度。 -
右轉彎(右輪停止,左輪向前/向後)
按下 "R1" + 左搖桿上下控制小車左輪向前/向後的速度。
-
逆時針(CCW)旋轉(左輪向後,右輪向前)
按下 "L2" + 左搖桿上同時控制小車兩個輪子的速度。 -
順時針(CW)旋轉(右輪向後,左輪向前)
按下 "R2" + 左搖桿上同時控制小車兩個輪子的速度。 -
兩個搖桿操作小車的速度和轉向
左搖桿上下控制小車向前/向後的速度,右搖桿左右控制小車的轉向,兩者相互搭配可控制小車行進的動作。
【(04)遙控車程式框架說明】
有了小車需要的動作組合鍵規劃之後,將這些動作結合 Ps3Demo 範例程式所測試出來的結果,程式可以這樣改寫。
Ps3HotKeyDetect.ino, line: 13 ~ 24, 122 ~ 145
#include <Ps3Controller.h>
//** VARIABLES **//
// Built-in LED
const uint8_t LED_BUILTIN = 2;
#define BUILTIN_LED LED_BUILTIN
// Offical PS3 Controller
const char* SONY_PS3_CONTROLLER_BT_MAC_ADDRESS = "11:22:33:44:55:66";
// Joystick Deadzone
const int8_t JOYSTICK_DEAD_ZONE = 10;
// others
bool _deviceConnected = false;
void setup() {
Serial.begin (115200);
//** 內建 LED 初始化 */
pinMode (BUILTIN_LED, OUTPUT); // power led is blue color
digitalWrite (BUILTIN_LED, LOW); // turn off red color led
//** 馬達驅動板初始化
// code here...
//
//** PS3 Controller 初始化 */
// MAC address comes from SixacixPairTool
Ps3.begin (SONY_PS3_CONTROLLER_BT_MAC_ADDRESS);
Ps3.attachOnConnect (onConnect);
Serial.print (F("The ESP32's Bluetooth MAC address is: "));
Serial.println (Ps3.getAddress());
Serial.println (F("Waiting for PS3 Controller Connection"));
}
void loop() {
checkHotKey();
checkBattery();
}
首先,在程式開頭宣告幾個常數和變數。其中,SONY_PS3_CONTROLLER_BT_MAC_ADDRESS 是從 Sixaxis Pair Tool 取得的 MAC 地址,要根據實際的數據填寫;JOYSTICK_DEAD_ZONE 是雙搖桿動作啟動的判斷值,只有在左搖桿上下值加上右搖桿左右值的加總超過此值,雙搖桿控制的動作才會被觸發和被執行。
setup() 就是硬體的初始化。其中,小車馬達驅動的方式,要依照你實際使用的馬達驅動板,將初始化的程式碼加入到這裡面來;另外,加入 onConnect() 事件,監控 PS3 遊戲手把與 ESP32 UNO 開發板是否已連線?
loop() 函式裡,無限循環監視組合鍵(checkHotKey())和電池(checkBattery())的狀態,一但條件達到設定值就會執行相對應的動作。
Ps3HotKeyDetect.ino, line: 26 ~ 40
void onConnect() {
Serial.println (F("PS3 Controll Connected"));
// 震動左右馬達
// Turn rumble on full intensity for 1 second
Ps3.setRumble (100.0, 1000);
delay(1000);
// Turn off rumble
Ps3.setRumble(0.0);
_deviceConnected = true;
// led
digitalWrite (BUILTIN_LED, HIGH); // turn on red color led
}
onConnect() 事件一但被觸發,如果遊戲手把有馬達的話,那麼會震動一秒鐘後停止;另外,原本在 ESP32 UNO 閃爍的紅色 LED 也會變成恆亮。
Ps3HotKeyDetect.ino, line: 91 ~ 120
void checkBattery() {
static uint16_t loopTime = 850;
static uint8_t loopCount = 10;
static unsigned long lastMillis = 0;
static int battery = 0;
if (millis () - lastMillis > loopTime) {
if (!_deviceConnected) {
digitalWrite (BUILTIN_LED, !digitalRead(BUILTIN_LED));
} else {
if (loopCount++ >= 10 && battery != Ps3.data.status.battery) {
battery = Ps3.data.status.battery;
loopTime = 1;
Serial.print("The controller battery is ");
if( battery == ps3_status_battery_charging ) Serial.println("charging");
else if( battery == ps3_status_battery_full ) Serial.println("FULL");
else if( battery == ps3_status_battery_high ) Serial.println("HIGH");
else if( battery == ps3_status_battery_low) Serial.println("LOW");
else if( battery == ps3_status_battery_dying ) Serial.println("DYING");
else if( battery == ps3_status_battery_shutdown ) Serial.println("SHUTDOWN");
else Serial.println("UNDEFINED");
}
}
lastMillis = millis();
}
} // checkBattery()
checkBattery() 函式,每隔 loopTime 檢查一次是否已連線,若沒有,改變 BUILTIN_LED 的開/關狀態,且每隔 10 次 loopTime 檢查一次遊戲手把的電池狀態並輸出。
Ps3HotKeyDetect.ino, line: 42 ~ 92
void checkHotKey() {
if (!Ps3.isConnected ()) return;
// 左轉彎
if (Ps3.data.button.l1 && abs(Ps3.data.analog.stick.ly)) {
//** 左轉彎程式碼
// code here...
//
Serial.print (F("Turn Left: ")); Serial.print (Ps3.data.analog.stick.ly, DEC);
Serial.println();
}
// 右轉彎
else if (Ps3.data.button.r1 && abs(Ps3.data.analog.stick.ly)) {
//** 右轉彎程式碼
// code here...
//
Serial.print (F("Turn Right: ")); Serial.print (Ps3.data.analog.stick.ly, DEC);
Serial.println();
}
// 逆時針旋轉
else if (Ps3.data.button.l2 && abs(Ps3.data.analog.stick.ly)) {
//** 逆時針旋轉程式碼
// code here...
//
Serial.print (F("Rotate CCW: ")); Serial.print (Ps3.data.analog.stick.ly, DEC);
Serial.println();
}
// 順時針旋轉
else if (Ps3.data.button.r2 && abs(Ps3.data.analog.stick.ly)) {
//** 順時針旋轉程式碼
// code here...
//
Serial.print (F("Rotate CW: ")); Serial.print (Ps3.data.analog.stick.ly, DEC);
Serial.println();
}
// 左右搖桿一起操作
else if (abs(Ps3.data.analog.stick.ly) + abs(Ps3.data.analog.stick.rx) > JOYSTICK_DEAD_ZONE) {
//** 左右搖桿一起控制程式碼
// code here...
//
Serial.print(" y="); Serial.print(Ps3.data.analog.stick.ly, DEC);
Serial.print(" x="); Serial.print(Ps3.data.analog.stick.rx, DEC);
Serial.println();
}
// 其他動作
else {
//** 小車停止程式碼
// code here...
//
}
} // checkHotKey()
checkHotKey() 函式裡列出了幾個要偵測的按鍵組合,每個按鍵有它的判斷條件,成立時觸發相對應的小車動作。例如,左轉彎被觸發時,小車左輪停止,小車右輪則根據左搖桿上下決定轉向和轉速:正負值決定轉向向前轉或向後轉,數值則乘以二並限制在 -255 ~ 255 之間, 作為 PWM 值輸出給小車右輪,如下範例程式碼所示。
void motor_turn_left (int8_t speedR){
leftDCMotor->setSpeed (0);
leftDCMotor->run (RELEASE);
if (speedR < 0) {
rightDCMotor->setSpeed (-map2 (speedR));
rightDCMotor->run (FORWARD);
}
else {
rightDCMotor->setSpeed (map2 (speedR));
rightDCMotor->run (BACKWARD);
}
}
motor_turn_left() 是小車左轉彎的實際程式碼,其中,map2() 的功用是將 speedR 乘以二,並限制範圍在 -255 ~ 255 之間;其他的函式,望文生義不難了解和實現。
全部程式碼如下所示:
【(05)結論】
文中說明了 PS3/PS4 遊戲手把怎麼與 ESP32 進行藍牙通訊,並且取得遊戲手把按鍵的組合。利用這些按鍵的組合,可定義出小車不同的動作。
馬達驅動板有多種形式,但只要掌握轉向和轉速的控制方式,要實現文中沒有特別列出的小車馬達驅動部分程式碼,就很容易!
若有購買 ESP32 系列的小車分類套件,展示影片中的程式碼在雲端硬碟中,請自行下載參照。
.
.
<<部落格相關文章>>
-
{04}兩輪智能小車-ESP32 PS3/PS4 遊戲手把控制遙控車
-
{03}兩輪智能小車-控制端軟體介紹與測試
- {02}兩輪智能小車-BLE(Bluetooth LE,低功耗藍牙)模組的設定
-
{01}兩輪智能小車-V1.0 DIY 套件組裝建議說明
- {00}兩輪智能小車-V1.0 DIY 套件 Arduino UNO / ESP32 BLE 遙控車、PID 循跡車展示影片
- { EP8266 WiFi 控制小車 } [ 1/3 ] - 智能避障循跡小車底盤構件組裝建議說明
- { EP8266 WiFi 控制小車 } [ 2/3 ] - 電路佈線與馬達轉向測試
- { EP8266 WiFi 控制小車 } [ 3/3 ] - 小車路試
- eZ430 運動手錶控制樹莓派小車 ( 開迴路控制 )
.
.
Thank you for giving me so much information that I can use. I can't wait for your next blog post. Proteus Design Suite
回覆刪除你好:有個兩輪農用自走車的專案, 想請你合作開發 。如何跟你取得聯繫?
回覆刪除您好:可以使用 GMail 電子郵件,或是露天賣場使用露露通直接溝通。
刪除