Bill Porter寫了一個Sony PS2控制器的程式庫給Arduino控制板使用,可以讓Arduino讀取PS2控制器的類比搖桿和所有按鈕的數值與狀態。
PS2搖桿容易取得、按鈕多、價格也不貴(還有廉價的副廠牌可選)。如果你需要替你的Arduino機器人找一個控制器,PS2搖桿是個不錯的選擇。
改造Sony PS2控制器的USB轉接線連接Arduino
不過,PS2控制器採用特殊的介面接頭,沒辦法簡單地和Arduino控制板相連,除了將它的接頭剪斷之外,你可以找一個PS2控制器的轉接線來改造。像這一款Sony PS2手把轉USB的轉接線,有兩個PS2接頭,就很好用:
我將其中一個搖桿插座焊下來,再焊接到一個萬用PCB板(洞洞板)接Arduino,如此就不必剪斷PS2搖桿的連接線,而且Arduino還可以連接其他PS2相容的控制器(像吉他英雄的電吉他、太鼓達人打鼓機、跳舞墊、格鬥搖桿…),原本的USB轉接線仍可連接Windows或Mac電腦使用。
PlayStation 2控制器的接腳定義
Sony PS2控制器的接腳定義如下,圖說裡面的按鍵英文名稱是Arduino PS2控制器程式庫(按此連結下載)預設的常數名稱:
PS2控制器插座與Arduino控制板的連接示範圖(需搭配底下的程式碼):
3.3V直流電壓轉換電路(5/2更新)
上面自製Arduino控制板上方有兩個電解電容(10µF,耐電壓10V),它們都與電路板背後的AMS1117電壓調節元件相連(位於下圖中間下方),構成5V轉3.3V的電源迴路,提供電力給PS2搖桿。
AMS1117是電壓調節IC,它有不同的型號,像AMS1117-3.3可將4.75V~12V的直流輸入,降轉成3.3V輸出(最大輸出電流1A),AMS1117-1.5則可轉換輸出1.5V ,詳細請參閱AMS1117的技術文件(PDF格式)。AMS1117元件的外觀,以及3.3V直流電壓轉換電路如下:
Arduino的PS2控制器範例程式
底下的Arduino程式碼修改自PlayStation 2 Controller Arduino Library提供的範例程式,它將在Arduino程式開發工具(IDE)裡的「序列埠監控視窗」顯示PS2控制器的狀態。
#include// 目前是1.6版 PS2X ps2x; // 建立PS2控制器的類別實體 /* 此程式庫不支援熱插拔,亦即,你必須在連接控制器後重新啟動Arduino, 或者在連接控制器之後再次呼叫config_gamepad()函數。 */ int error = 0; byte type = 0; byte vibrate = 0; void setup(){ Serial.begin(57600); // ********注意!******** 1.6版的新語法: // 控制器接腳設置並驗證是否有錯誤: GamePad(時脈腳位, 命令腳位, 選取腳位, 資料腳位, 是否支援類比按鍵, 是否支援震動) error = ps2x.config_gamepad(13,11,10,12, true, true); if(error == 0) { // 如果控制器連接沒有問題,就顯示底下的訊息。 Serial.println("Found Controller, configured successful"); Serial.println("Try out all the buttons, X will vibrate the controller, faster as you press harder;"); Serial.println("holding L1 or R1 will print out the analog stick values."); Serial.println("Go to www.billporter.info for updates and to report bugs."); } else if(error == 1) // 找不到控制器,顯示底下的錯誤訊息。 Serial.println("No controller found, check wiring, see readme.txt to enable debug. visit www.billporter.info for troubleshooting tips"); else if(error == 2) // 發現控制器,但不接受命令,請參閱程式作者網站的除錯說明。 Serial.println("Controller found but not accepting commands. see readme.txt to enable debug. Visit www.billporter.info for troubleshooting tips"); else if(error == 3) // 控制器拒絕進入類比感測壓力模式,或許是此控制器不支援的緣故。 Serial.println("Controller refusing to enter Pressures mode, may not support it. "); type = ps2x.readType(); // 偵測控制器器的類型 switch(type) { case 0: Serial.println("Unknown Controller type"); // 未知的控制器類型 break; case 1: Serial.println("DualShock Controller Found"); // 發現DualShock控制器 break; case 2: Serial.println("GuitarHero Controller Found"); // 發現吉他英雄控制器 break; } } void loop(){ /* 你必須執行ps2x.read_gamepad()方法來獲取新的按鍵值,語法格式: ps2x.read_gamepad(小馬達開或關, 大馬達強度值從0~255) 如果不啟用震動功能,請執行 ps2x.read_gamepad(); 不需要任何參數。 你應該至少一秒鐘執行一次這個方法。 */ if(error == 1) // 如果沒發現任何控制器,則跳出迴圈。 return; if(type == 1) { // 這是標準的DualShock控制器 ps2x.read_gamepad(false, vibrate); // 讀取控制器並且命令大的震動馬達以"vibrate"變數值的速度旋轉 if(ps2x.Button(PSB_START)) // 查看「開始」鍵是否被按住 Serial.println("Start is being held"); if(ps2x.Button(PSB_SELECT)) // 查看「選擇」鍵是否被按住 Serial.println("Select is being held"); if(ps2x.Button(PSB_PAD_UP)) { // 若「上」按鍵被按著 Serial.print("Up held this hard: "); Serial.println(ps2x.Analog(PSAB_PAD_UP), DEC); } if(ps2x.Button(PSB_PAD_RIGHT)){ Serial.print("Right held this hard: "); Serial.println(ps2x.Analog(PSAB_PAD_RIGHT), DEC); } if(ps2x.Button(PSB_PAD_LEFT)){ Serial.print("LEFT held this hard: "); Serial.println(ps2x.Analog(PSAB_PAD_LEFT), DEC); } if(ps2x.Button(PSB_PAD_DOWN)){ Serial.print("DOWN held this hard: "); Serial.println(ps2x.Analog(PSAB_PAD_DOWN), DEC); } vibrate = ps2x.Analog(PSAB_BLUE); // 依據你按著X按鍵的力道來調整馬達的震動強度 if (ps2x.NewButtonState()) // 若「按下」或「放開」任何按鈕 { if(ps2x.Button(PSB_L3)) Serial.println("L3 pressed"); if(ps2x.Button(PSB_R3)) Serial.println("R3 pressed"); if(ps2x.Button(PSB_L2)) Serial.println("L2 pressed"); if(ps2x.Button(PSB_R2)) Serial.println("R2 pressed"); if(ps2x.Button(PSB_GREEN)) // 若被按下的是三角按鍵 Serial.println("Triangle pressed"); } if(ps2x.ButtonPressed(PSB_RED)) // 若「按下」圈圈按鍵 Serial.println("Circle just pressed"); if(ps2x.ButtonReleased(PSB_PINK)) // 若「放開」方塊按鍵 Serial.println("Square just released"); if(ps2x.NewButtonState(PSB_BLUE)) // 若「按下」或「放開」叉叉按鍵 Serial.println("X just changed"); if(ps2x.Button(PSB_L1) || ps2x.Button(PSB_R1)) // 若按著PSB_L1或PSB_R1按鍵 { // 顯示左右類比搖桿的值 Serial.print("Stick Values:"); Serial.print(ps2x.Analog(PSS_LY), DEC); Serial.print(","); Serial.print(ps2x.Analog(PSS_LX), DEC); Serial.print(","); Serial.print(ps2x.Analog(PSS_RY), DEC); Serial.print(","); Serial.println(ps2x.Analog(PSS_RX), DEC); } } delay(50); }
您好我最近一直在研究用PS2搖桿連接UNO~但我目前都會發生No found 和Unknown~想問一下這種情況有哪些原因
,我的搖桿是Sony的有線搖桿,我紅線是插在UNO的5V
hi 雷舞:
讀了你的留言,發現上文的Arduino與PS2搖桿的連接示意圖有誤,PS2搖桿的電源是3.3V,內文已修正、更新。請重接看看是否能正常運作,謝謝!
thanks,
jeffrey
您好我最近一直在研究用PS2搖桿連接UNO~但我目前都會發生No found ~想問一下這種情況有哪些原因
,我的搖桿是無限遙感
蛤?你用無線方式連結PS2搖桿和Uno板嗎?
是要插在3.3的
您好,看了您這篇文章有題到電壓調節的IC
所以想請問一下
我現在有一顆input voltage 是3.3v的mcu
想用鋰電池(工作電壓)3.7v來供電
電池和mcu之間的電路要怎麼接比較合適呢
(不知道可不可以在這裡問XD)
hi spot:
有些微控器,像Arduino Mini Pro的工作電壓也是3.3V,但我記得用3.7V也行。
你可以嘗試串接一個二極體,將電壓降到3.1V左右,看能不能運作。
如果都不行的話,那就要像上文一樣接一個電壓調節電路。
have fun!
jeffrey
依您的意思,是否直接使用ARDUINO UNO板和PS2連結,只要依上面算下來第四圖即可。因為UNO板有提供3.3V電源給PS2手把。
而您用洞洞板焊的ARDUINO板要再加一個電壓調整IC才行,這樣說對嗎?謝謝
hi tanj:
沒錯!可直接連接UNO板子上的3.3V,自製的板子需要額外連接5V電源(我大多採用USB電源供應器)。
thanks,
jeffrey
您好,我全部都照著做
結果只會出現Unknown Controller type
這要怎麼辦呢?
hi huan:
我用的是Sony原廠的SCPH-10010型號的控制器,使用上沒問題,我也不清楚原因,拍謝~
thanks,
jeffrey
你好
可以請你把arduino自制板的組件和電路也介紹一下嗎。其它零件我都買了,就那板子不會作,我知道網路上很多,但我不會電子,只會造著作。網路上的電路太清礎我真是看不懂。
可以麻煩你寄mail給我嗎,想秀給小孩看
謝謝
hi eddie:
如果您的目的是為了連接PS2控制把手,建議您參考上文的PS2控制器插座與Arduino控制板的連接示範圖,採用現成的Arduino控制板。
因為除非您購買的ATmega328p晶片已事先燒錄好bootloader(開機啟動程式),或者知道如何燒錄bootloade,否則自製的Arduino控制板將無法運作。
自製的Arduino控制板,核心電路很單純,請參閱「Arduino Yún Mini:改造TL-WR703N整合自製Arduino板」這篇文章,或者「用麵包板組裝Arduino微電腦實驗板」的電路,再加上一塊具備DTR接腳的「USB轉TTL序列訊號轉換板」即可。
thanks,
jeffrey
我比較好奇, 線路接法PS2 controller 電源是3.3v, 但Arduino 上電源是5V. 四條控制線是SPI介面, PS2 IO 只有3.3v(MISO)但Arduino IO是輸出5v(CS, MOSI & CLK), 這樣PS2 IC 會不會掛掉?
hi dirk:
我測試的結果是OK的,PS2應該可容許5V訊號,就像Wii左手把一樣。
thanks,
jeffrey
Hi Jeffrey,
Thanks.
Arduino是最近買來玩玩, 看到你網站上有熟悉的應用就測試看看.
我測試也是可以動作, 不過Arduino 板子上3.3v 電壓會被提升到3.9v(因該是Arduino IO 電壓 5v 倒灌回去的), 不過我用的PS2搖桿 & Arduino都不是原廠的. 我看網路上很多應用都是電源給3.3v IO 用5v, 這樣短期使用不會有問題, 但長期使用一定會壞掉.
另外此範例有第一行要改成 #include 才正確.
我查閱到的相關文件,都提到PlayStation第一代和第二代控制器,「應該」都能容許5V訊號輸入——說「應該」是因為沒有官方的技術文件,像這一篇第一代PS把手的文件,也沒看到接5V訊號而故障的貼文,提供你參考。
或者,你可以使用3.3V的Arduino控制板,就不用擔心這個問題了。
thanks,
jeffrey
請問一下 如果是用fpga版 我要輸入給psx 時脈幾hz 還有我不太懂ATT 和 ACK 能解釋一下嗎?
我是剛入門的新手
還有個按鈕的數值是多少 因為fpga版是數位的 需要知道 0跟1
hi dance:
FPGA的VHDL程式設計跟Arduino完全無關欸~PlayStation 2控制器採用SPI介面通訊,根據這個老外的測試,資料時脈介於100KHz~500KHz之間都行。
這是另一個老外的邏輯分析儀的測試結果。
thanks,
jeffrey
fpga版應該也可以控制吧 ?? 只是中間的連接程式要自己打??
可以,只是我對FPGA完全不熟~
thanks,
jeffrey
你好
請問你之前有遇過每幾秒鐘他就會自己刷新
然後顯示把全部的按鍵都同時按出現在序列阜
接著會暫時失連然後自動重連
即使換過電池還是會發生這樣的情況
請問這個問題有解嗎??
呃…我的控制器是有線的,沒遇過你說的問題。
thanks,
jeffrey
你好
有的時候連上線之後,ps2搖桿上的燈只有亮綠燈,或是按下搖桿中間的mode鍵會讓紅燈一直亮滅
這是否代表我沒連線成功,那可以怎麼解決~
拍謝,我不記得遇過這個問題,而且也好久沒用了。
thanks,
jeffrey
請問如果同時兩組以上的搖桿跟接收器(無線)
接收器如何設定連接特定的搖桿??
就是今天使用A接收器 我只想連接A搖桿
但是經測試接收器只要是遙桿誰先連到就會被誰占走
請問有辦法可以設定嗎??
感謝
拍謝~沒用過PS2的無線接收器。
thanks,
jeffrey
老師您好
想請問一下他是什麼介面呢??
因為我把他跟nRF24L01接一起時不能正常作動
麻煩老師有空時替我解惑
謝謝 !
PS2的介面是Sony自訂的專屬格式,nRF24L01使用SPI介面,接腳跟上文的PS2電路衝突。
請將PS2接在其他腳,再修改這個設定敘述試試:
ps2x.config_gamepad(13,11,10,12, true, true)
thanks,
jeffrey
老師您好 感謝您之前的回覆,我試過之後仍然不能工作,所以換了一個晶片 : JDY – 40,一樣是2.4G,不同處在他用串口通訊;試過之後發現一個非常有趣的現象 :
程式中一定要在 loop 裡加上
Serial.print(“here”);
Serial.println(uu);
uu++;
不燃反應會非常慢,甚至讀不到訊號,且這3行缺一不可
以下為完整程式碼,老師有空可以玩玩看XDD
#include
#include
PS2X ps2x; // 建立PS2控制器的類別實體
SoftwareSerial mySerial(A2, A1); // RX, TX
const byte Set_pin = A3;
int error = 0;
byte type = 0;
byte vibrate = 0;
String old_str, str;
String strr;
char msg[3];
int uu;
void setup() {
Serial.begin(9600);
mySerial.begin(9600);
pinMode(Set_pin, OUTPUT);
digitalWrite(Set_pin, HIGH);
error = ps2x.config_gamepad(13, 11, 10, 12, true, true);
}
void loop() {
Serial.print(“here”);
Serial.println(uu);
uu++;
ps2x.read_gamepad(false, 0);
if (ps2x.ButtonPressed(PSB_L3)) {
strr = “L3”;
Serial.println(strr);
}
if (ps2x.ButtonPressed(PSB_R3)) {
strr = “R3”;
Serial.println(strr);
}
if (ps2x.ButtonPressed(PSB_L2)) {
strr = “L2”;
Serial.println(strr);
}
if (ps2x.ButtonPressed(PSB_R2)) {
strr = “R2”;
Serial.println(strr);
}
if (ps2x.ButtonPressed(PSB_GREEN)) {
// 三角按鍵
strr = “Tr”;
Serial.println(strr);
}
if (strr != “”) {
Serial.print(“strr.length() + 1= “);
Serial.println(strr.length() + 1);
strr.toCharArray(msg, strr.length() + 1);
for (byte rr = 0; rr < 2; rr++) {
mySerial.write(msg[rr]);
}
mySerial.write('\n');
Serial.println("");
strr = "";
}
if (mySerial.available()) { // if JDY_40 return
String gg = mySerial.readString();
Serial.print("mySerial.read() = ");
Serial.println(gg);
}
if (Serial.available()) {
str = Serial.readStringUntil('\n');
Serial.println(str);
if (str == "AT") { // into AT mode
if (old_str != str) {
digitalWrite(Set_pin, LOW);
Serial.println("AT OK !");
}
} else if (str == "NAT") { // cancel AT mode
if (old_str != str) {
digitalWrite(Set_pin, HIGH);
Serial.println("NOT AT OK !");
}
} else {
mySerial.println(str); // "println" is only for AT mode
// if you mant to send msg , need to use mySerial.write();
}
old_str = str; // prevention repeat msg
}
}
非常感謝經驗分享!
thanks,
jeffrey
老師您好,最近把手頭上早期ps1時期十分稀有的釣魚竿控制器(HPS-97)從倉庫翻出來玩,基於他泛用的遊戲才一兩個,慢慢萌生一個想法,是否能夠把它轉成PC可用的釣魚竿控制器(模擬成手把?),才慢慢爬文了解到Arduino微電腦這個東西,小弟在公司半路出家算是會寫一些程式(C,VBA,ASP…),想投入精力試試看,請教大師,不知道這個想法有沒有太過激進,抑或有實現的可能性?
我相信可以,釣魚竿控制器上的各項操作介面應該都是對應到原始手把的某些按鍵和類比搖桿。