2018-06-01

Arduino 音Game控制器程式碼

適用Arduino Leonardo, 檔案放置處 Download

本頁的程式主要使用ArduinoJoystickLibrary,請先下載Library後以Arduino IDE安裝
https://github.com/MHeironimus/ArduinoJoystickLibrary/

․接線方式
一個旋轉編碼器需要2個I/O,按鈕則是訊號搭配LED控制所以一組也是2個I/O
Arduino Leonardo 從D0到D23共有12組I/O可使用,底下以SDVX為例

SDVX腳位分配範例
byte EncPins[] = {0, 1, 2, 3};
// button sorting = {Start,BT-A,-B,-C,-D,FX-L,-R,Extra}
byte SinglePins[] = {4, 6, 12,18,20,22,14,16};
byte ButtonPins[] = {5, 7, 13,19,21,23,15,17};

括號{}內數字代表文末附圖的水藍色DIGITAL編號
光學旋轉編碼器的訊號線各自接到EncPins後面指定的數字
一般常見為 綠白紅黑 四線組合
左旋鈕綠線接到0,白線接到1 / 右旋鈕綠線接到2,白線接到3
兩者的紅線一起接到標示為5V的位置(電源)
兩者的黑線一起接到標示為GND的位置(接地)

微動開關的NO腳位各自拉線接到ButtonPins後面指定的數字
Start鍵的微動NO接到5,BT-A鍵的微動NO接到7,依此類推
全部微動的COM腳位一起拉線接到標示為GND的位置(接地)

按鈕燈的正極各自拉線接到SinglePins後面指定的數字
Start燈的正極接到4,BT-A燈的正極接到6,依此類推
全部按鈕燈的負極一起拉線接到標示為GND的位置(接地)

每一個有寫GND的位置都可以接,全部都接到同一個GND也可以


․IIDX用: 1編碼器+11按鈕+11 HID可控式LED
1轉盤+7個主按鈕+3個功能鍵(START/EFFECT/VEFX)
基本功能共用掉11組I/O, 剩下1組可自由運用或省略
轉盤輸出為搖桿X軸類比訊號或可切換為按鈕,可相容HDD與Lunatic Rave 2
須設定數值
const int GEAR = 600; //編碼器ppr數或轉盤齒數,彩虹控2數值為60
const int TTdz = 0; //數位轉盤靈敏度deadzone(數值越小越靈敏)
const int TTdelay = 50; //數位轉盤停手後的按鍵釋放延遲(數值越小放越快,單位為毫秒)


․SDVX用: 2編碼器+10按鈕+10 HID可控式LED
2旋鈕+7個主按鈕(BT/FX/START)
基本功能共用掉9組I/O, 剩下3組可自由運用或省略
旋鈕輸出為搖桿X/Y軸類比訊號,可相容Arcade Dump與K-Shoot MANIA
此控制器可用迷你型的SparkFun Pro Micro代替Leonardo, I/O數量剛好夠用
須設定數值
const int PULSE = 600; //編碼器ppr數


․SDVX用: 2編碼器+8按鈕+8 HID可控式LED +1RGB
2旋鈕+7個主按鈕(BT/FX/START)+1組RGB控制訊號
基本功能共用掉9組I/O, 剩下的I/O拿來做RGB燈光控制用
因為使用硬體PWM,建議使用預設的腳位,並依RGB燈的顏色排序調整接腳順序
並設定 共陰極/共陽極 的切換變數rgbCommon
char rgbCommon = '+'; //加號,共陽極
char rgbCommon = '-'; //減號,共陰極


․IIDX+SDVX HYBRID控制器: 3編碼器+9按鈕+9 HID可控式LED
1轉盤+2旋鈕+9個主按鈕(IIDX 1~7/FX-L/FX-R)
基本功能用完全部的12組I/O, 請依照本文下方說明做D17改裝
旋鈕輸出為搖桿X/Y軸類比訊號,可相容HDD與K-Shoot MANIA
轉盤輸出為搖桿Z軸類比訊號,或可切換為按鈕輸出以相容Lunatic Rave 2
須設定數值
const int PULSE = 600; //編碼器ppr數
const int GEAR = 60; //編碼器ppr數或轉盤齒數
const int TTdz = 0; //數位轉盤靈敏度deadzone(數值越小越靈敏)
const int TTdelay = 50; //數位轉盤停手後的按鍵釋放延遲(數值越小放越快,單位為毫秒)


․MUSECA用: 5編碼器+7按鈕+7 HID可控式LED
5轉盤+6個主按鈕(轉盤/踏板)+1個功能鍵(START)
基本功能用完全部的12組I/O, 請依照本文下方說明做D17改裝
腳踏板不接LED的話可以在代碼內把D16/D17對調,讓開關改接到D16就不用改裝D17
燈光部分因為剩餘腳位數量不夠用,燈光模式的預設值改為單色LED連動式
前5組I/O供轉盤按壓及LED,旋轉或按壓皆觸發燈亮,預設延遲半秒熄燈
*未來預計新增第二塊Arduino作為燈光控制用
hidMode = !digitalRead(ButtonPins[0]); //預設按鍵連動式
須設定數值
const int LEDdelay = 500; //SinglePins[0]~[4] 延遲熄燈維持時間(millisecond)
const int PULSE = 600; //編碼器ppr數或轉盤齒數,光學或機械式皆可,原裝機台為20


․Groove Coaster用: 2搖桿+3按鈕+3 連動式LED 鍵盤訊號
2搖桿+2個主按鈕+1個功能鍵(ESC)
基本功能共用掉7組I/O, 剩下5組可自由運用或省略
此控制器電路板可用迷你型的SparkFun Pro Micro代替

․Groove Coaster用: 2搖桿+8按鈕+8 連動式LED 搖桿訊號
2搖桿+2個主按鈕
基本功能共用掉6組I/O, 剩下6組可自由運用或省略
此控制器電路板可用迷你型的SparkFun Pro Micro代替

․Pop'n Music用: 12按鈕+12 HID可控式LED
9個主按鈕
基本功能共用掉9組I/O, 剩下3組可自由運用或省略


․燈光模式與切換說明
上面標示HID可控式LED的都備有兩種燈光模式可以切換,HID控制或按鍵連動式
切換方式是開機時(插上USB線通電時)有沒有按下第一個按鈕來判斷
我的建議是按著按鈕再插USB線,燈號開始閃爍後就可以放開按鈕了
預設值什麼都沒按的話是HID控制,有按的話是按鍵連動燈光
可以在判斷式加上驚嘆號對調功能,附切換示範影片(影片還未實裝開機按著鈕的閃爍)
hidMode = digitalRead(ButtonPins[0]); //預設HID模式
hidMode = !digitalRead(ButtonPins[0]); //預設按鍵連動式

模式只在開機時判斷一次,若需切換模式請拔掉USB線重插或按電路板上的RESET按鈕

開機時按著燈光切換按鈕(或轉盤訊號切換按鈕)時,全部按鍵燈會一起閃爍
放開按鈕或沒按的話會撥放開機特效,預設是把按鍵燈來回掃一輪後全亮半秒熄滅
想要自訂燈光的人可以編輯下面這個區段的程式,提供兩種範本供參考
//boot light 來回掃描一次
for(int i=0; i<ButtonCount; i++) {
digitalWrite(SinglePins[i],HIGH);
delay(80);
digitalWrite(SinglePins[i],LOW);
}
for(int i=ButtonCount-2; i>=0; i--) {
digitalWrite(SinglePins[i],HIGH);
delay(80);
digitalWrite(SinglePins[i],LOW);
}

//boot light SDVX式7鍵來回掃描兩次,順序跟數量可以任意增減
int startup[] = {0,1,2,3,4,5,6,5,4,3,2,1,0,1,5,2,0,3,6,4,6,3,0,2,5,1};
for(int i=0;i<(sizeof(startup) / sizeof(startup[0]));i++){
digitalWrite(SinglePins[startup[i]],HIGH);
delay(80);
digitalWrite(SinglePins[startup[i]],LOW);
}

HID燈光部分有支援PWM調光
如果需要調整燈數的話需要在HIDLED.h裡手動設定下面兩項數值
#define NUMBER_OF_SINGLE //單色燈號數量
#define NUMBER_OF_RGB //彩色燈號數量


․IIDX轉盤模式與切換說明
IIDX部分的轉盤訊號輸出類型可以切換類比模式或數位模式
切換方式一樣是插上USB線通電時判斷按鍵,但讀取的是第二個按鈕
預設值什麼都沒按的話是類比訊號輸出,有按的話是轉為按鍵訊號輸出(適用LR2)

․編碼器選用說明
編碼器使用增量型光學編碼器或機械接點式編碼器皆可
常見的 白牌/OMRON(600ppr)/COPAL(50ppr)都屬於光學式
機械式較常見品牌為ALPS 24ppr,價格非常便宜
也可以直接讀取現成的IIDX控制器轉盤,拉線到光遮斷器就可以讀取訊號
這裡所有編碼器程式都有使用外部中斷功能(Interrupt),接腳位置建議沿用預設值

․其他註解
程式碼內預設有每迴圈700微秒的USB回報延遲,可自行調整數值或打開Serial視窗檢查
數值建議控制在1000Hz/s左右,此為USB介面的極速,完全足夠音樂遊戲高手使用
int ReportDelay = 700 //USB回報延遲;

․D17擴充改裝
如果碰到標準I/O數量不夠用的時候,可能會需要將訊號連接至D17
下圖為D17在電路板上的接腳位置,建議可以把接點拉線到IOREF旁的空腳位來使用
附帶一提,D17必須作為按鍵輸入用,作為LED輸出的話會被訊號傳輸的燈號干擾運作



․有關於HID光控Library
HID光控Library是由mon的Arduino-HID-Lighting改編而成
https://github.com/mon/Arduino-HID-Lighting
本來的程式雖然支援PWM調光的HID燈但不處理按鈕輸入等訊號
所以我把它改編成Library後整合在搖桿控制程式內

原作者在GitHub上雖然有提供Neopixel的範例讓你能輕鬆使用WS2812這類RGB燈
但我個人不太建議在控制器內整合使用WS2812這類產品
因為WS2812每一顆LED都需要各自花時間更新狀態,根據我自己實測發現
如果連接一個32顆LED的燈環,每迴圈會額外消耗約1ms的時間用來顯示顏色
原本1000Hz的USB回報速度將會減半為500Hz,明顯拖累控制器的整體反應速度
如果非得將WS2812與按鈕訊號合併的話,我建議每迴圈只更新一顆LED就好
並於下一迴圈再更新下一顆,依此類推掃描完全部的LED

另外,原作者提供的Neopixel範例是把每顆LED都配給了各自的HID通訊功能
但這樣設定時每顆都要手動選擇功能會很麻煩,而且最多只能使用63/3=21顆LED
應該把一定數量的LED設為一個群組一起動作,使用上會比較合理
把原本範例的程式

#define NUMBER_OF_RGB 3
#define NEOPIXEL_PIN 12
#define NEOPIXEL_BRIGHTNESS 50

volatile bool needs_update = false;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMBER_OF_RGB, NEOPIXEL_PIN, NEO_GRBW + NEO_KHZ800);

void light_update(SingleLED* single_leds, RGBLed* rgb_leds) {
for(int i = 0; i < NUMBER_OF_SINGLE; i++) {
// nothing do do, since all neopixels are RGB
}
for(int i = 0; i < NUMBER_OF_RGB; i++) {
strip.setPixelColor( i, strip.Color( rgb_leds[i].r, rgb_leds[i].g, rgb_leds[i].b ) );
}
needs_update = true;
}


改成

#define NUMBER_OF_RGB 3
#define NUMBER_OF_RGB_IN_AREA 3
#define NEOPIXEL_PIN 12
#define NEOPIXEL_BRIGHTNESS 50

volatile bool needs_update = false;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMBER_OF_RGB*NUMBER_OF_RGB_IN_AREA, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);

void light_update(SingleLED* single_leds, RGBLed* rgb_leds) {
for(int i = 0; i < NUMBER_OF_SINGLE; i++) {
// nothing do do, since all neopixels are RGB
}
for(int i = 0; i < NUMBER_OF_RGB; i++) {
for(int j = i * NUMBER_OF_RGB_IN_AREA; j < (i+1) * NUMBER_OF_RGB_IN_AREA; j++) {
strip.setPixelColor( j, strip.Color( rgb_leds[i].r, rgb_leds[i].g, rgb_leds[i].b ) );
}

}
needs_update = true;
}

以上會將NUMBER_OF_RGB從定義"燈總數"變成定義"要將燈切成多少區域"
新增NUMBER_OF_RGB_IN_AREA來定義"每區域有多少燈",
總燈數也就變成"區域數x每區域多少燈",另改設定NEO_GRBW為無白光的NEO_GRB


․參考項目
mon的Arduino-HID-Lighting
https://github.com/mon/Arduino-HID-Lighting

4yn的iivx混合控制器
https://github.com/4yn/iivx
支援HID燈但不支援PWM調光,除了按鈕數受限之外
類比訊號無法於Windows遊戲控制器視窗確認是我很不喜歡的一點

旋轉編碼器程式
https://www.geek-workshop.com/thread-28165-1-1.html
這個編碼器讀取程式可以同時相容光學式與機械式旋轉編碼器
並且能消除機械式編碼器的訊號彈跳問題

HTML5 Gamepad Tester
http://html5gamepad.com/
測試遊戲控制器的方便工具

Arduino Leonardo pinout


SparkFun Pro Micro pinout

沒有留言: