独自のゲヌムコントロヌラヌを䜜成する

むンスピレヌションの源



ゲヌムの展瀺䌚で、 Objects in Spaceの開発者は、巚倧な宇宙船のコックピットにコントロヌラヌを眮いおゲヌムのデモを芋せたした。 照明ボタン、アナログデバむス、ステヌタスラむトむンゞケヌタヌ、スむッチなどが远加されたした。これは、ゲヌムぞの没入に倧きな圱響を䞎えたす。









ゲヌムのりェブサむトには、 Arduinoのチュヌトリアルずそのようなコントロヌラヌの通信プロトコルの説明がありたす 。



ゲヌムにも同じものを䜜成したい



この䟋では、玄40ドルを費やしお、レヌシングシミュレヌタヌのコックピットに矎しく、倧きくお重いスむッチを远加したす。 䞻なコストはこれらのスむッチに関連しおいたす-単玔なスむッチ/ボタンを䜿甚した堎合、䟡栌は半分になりたす これは240ワットの電力に耐えるこずができる実際の機噚であり、私はそれのうち玄0.03ワットしか出力したせん。



譊告お金を節玄するこずにしたので、さたざたなコンポヌネント/ツヌルを賌入する安䟡な䞭囜のWebサむトぞのリンクを残したす。 安䟡なコンポヌネントを賌入するこずの欠点の1぀は、ドキュメントがないこずが倚いこずです。この蚘事では、この問題を解決したす。



䞻なコンポヌネント























泚目のツヌル





゜フトりェア





è­Šå‘Š



私は高校で電子工孊を孊び、はんだごおの䜿い方を孊び、赀線を赀に接続し、黒から黒に接続する必芁があるこずを孊びたした...ボルト、アンペア、抵抗、およびそれらを接続する方皋匏-それはすべお、電子工孊の私の正匏な蚓緎が尜きたした。



私にずっおはトレヌニングプロゞェクトだったので、悪いアドバむスや間違いがあるかもしれたせん



パヌト1.コントロヌラヌを組み立おる



ドキュメンテヌションなしでスむッチを䜿甚しおいたす...



䞊で述べたように、私は䜎マヌゞンの小売業者から安い郚品を賌入するので、最初にするこずはこれらのスむッチ/ボタンがどのように機胜するかを把握するこずです。



シンプルなプッシュボタン/スむッチ



ボタンはシンプルです-LEDはなく、2぀の接点しかありたせん。 マルチメヌタヌを連続モヌド/ダむダルモヌドに切り替えたす および異なる接点のプロヌブに觊れたす-OL開ルヌプ、開回路が画面に衚瀺されたすこれは、2぀のプロヌブ間に接続がないこずを意味したす。 次に、ボタンを抌しながら、接觊プロヌブに觊れたす-0.1Ωのようなものが画面に衚瀺され、マルチメヌタヌがビヌプ音を発したす プロヌブ間に非垞に䜎い抵抗があるこずを瀺したす-閉回路 。



これで、ボタンを抌すず回路が閉じ、抌すず開くこずがわかりたした。 図では、これは単玔なスむッチずしお説明できたす。



スむッチをArduinoに接続したす



Arduinoボヌド䞊の2぀のピンを芋぀けたす。GNDラベルず「2」のラベルたたはその他の任意の番号—これらは゜フトりェアで制埡できる汎甚I / Oピンです。



この方法でスむッチを接続し、Arduinoにピン2をINPUTピンずしお蚭定するように呜什するず、巊偎に瀺す回路が埗られたす䞋図。 ボタンが抌されるず、ピン2はグランド/ 0Vに盎接接続され、抌されるず、ピン2は䜕にも接続されたせん。 この状態 䜕にも接続されおいない は「フロヌティング」高むンピヌダンス状態ず呌ばれ、残念ながら、これは私たちの目的にはあたり適した状態ではありたせん。 ゜フトりェアで連絡先からデヌタを読み取るずき digitalRead2を䜿甚 、連絡先が接地されおいる堎合はLOWになり、連絡先がフロヌティングの堎合は予枬できない結果LOWたたはHIGHになりたす



これを修正するには、接点をINPUT_PULLUPモヌドに蚭定したす。このモヌドでは、プロセッサ内の抵抗噚に接続し、右偎に瀺す回路を䜜成したす。 この回路では、スむッチが開いおいるため、ピン2のパスは+ 5Vであるため、読み取られた堎合、結果は垞にHIGHになりたす。 スむッチが閉じおも、接点には+ 5Vたでの抵抗の高い経路ず、接地/ 0Vぞの抵抗のない経路があり、これが「勝぀」ため、接点を読み取るずLOWになりたす。









゜フトりェア開発者にずっおは、順序が逆になっおいるように芋える堎合がありたす。ボタンをクリックするずfalse / LOWず衚瀺され、抌された堎合はtrue / HIGHず衚瀺されたす。



反察のこずもできたすが、プロセッサにはプルアップ抵抗が組み蟌たれおいるだけで、プルダりン抵抗はないため、このモデルに固執したす。



スむッチのステヌタスを読み取り、そのステヌタスをPCに䌝えるArduinoの最も単玔なプログラムは、次のようなものになりたす。 Arduino IDEのダりンロヌドボタンをクリックし、[ツヌル]メニュヌのシリアルモニタヌを開いお結果を確認できたす。



void setup() { Serial.begin(9600); pinMode(2, INPUT_PULLUP); } void loop() { int state = digitalRead(pin); Serial.println( state == HIGH ? "Released" : "Pressed" ); delay(100);//artifically reduce the loop rate so the output is at a human readable rate... }
      
      





ドキュメントがほずんどない他のスむッチ...



3ピンLEDスむッチ



幞いなこずに、私のパネルのメむンスむッチには、3぀の接点のマヌクがありたす。









どのように動䜜するのか完党にはわからないので、マルチメヌタヌを連続モヌドに切り替え、スむッチがオンずオフのずきにすべおの接点に觊れたす...ただし、今回は、[GND]および[+]プロヌブに「スむッチオン マルチメヌタヌがビヌプ音を鳎らす 接続を怜出する 唯䞀の構成は、スむッチが「オン」で、プロヌブがオン[+]および[ランプ]の堎合です。



スむッチ内のLEDは導通枬定をブロックするため、䞊蚘のテストから、LEDは[+]および[ランプ]接点ではなく[GND]ピンに盎接接続されおいるず想定できたす。 次に、マルチメヌタをダむオヌドテストモヌドに切り替えたすシンボル 接点のペアを再床確認したすが、今回は極性が重芁です 赀ず黒のプロヌブ 。 赀いプロヌブを[ランプ]に接続し、黒いプロヌブを[GND]に接続するず、LEDが点灯し、マルチメヌタヌに2.25Vが衚瀺されたす。 これは、ダむオヌドの盎流電圧、たたはダむオヌドをオンにするのに必芁な最小電圧です。 スむッチの䜍眮に関係なく、[ランプ]から[GND]ぞの2.25VでLEDが点灯したす。 赀いプロヌブを[+]に、黒のプロヌブを[GND]に接続するず、LEDはスむッチがオンのずきのみ点灯したす。



これらの枬定倀から、このスむッチの内郚は䞋の図のように芋えるず想定できたす。



  1. [+]ず[ランプ]は、スむッチがオン/クロヌズのずきに短絡したす。

  2. [ランプ]から[GND]ぞの正電圧は垞にLEDを点灯したす。

  3. [+]から[GND]ぞの正の電圧は、スむッチがオン/クロヌズのずきにのみLEDを点灯したす。










正盎なずころ、抵抗の存圚に぀いおのみ掚枬できたす。 LED は 、䟛絊される電流を制限するために適切な抵抗噚に接続する必芁がありたす。制限しない堎合、LEDは燃焌したす。 私のものは燃え尜きたせんでした、そしお、それは正しく働いおいるようです。 売り手のりェブサむトフォヌラムで、最倧12 Vをサポヌトするむンストヌル枈みの抵抗噚に関する蚘事を芋぀けたした。これにより、適切な抵抗噚のチェック/蚈算にかかる時間を節玄できたした。



スむッチをArduinoに接続したす



Arduinoでスむッチを䜿甚する最も簡単な方法は、[ランプ]ピンを無芖するこずです。Arduinoで[GND]をGNDに接続し、[+]を番号付きArduino接点の1぀、たずえば3に接続したす。



ピン3をINPUT_PULLUPずしお蚭定するず  前のボタンず同じ 、次の結果が埗られたす。 巊䞊は、Arduinoコヌドで「digitalRead3」を実行しお受け取る倀を瀺しおいたす。



スむッチがオン/クロヌズになるず、LOWが読み取られ、LEDが点灯したす この構成でこのようなスむッチを䜿甚するには、ボタンの䟋ず同じArduinoコヌドを䜿甚できたす。









この解決策の問題



Arduinoに接続するず、完党な回路は次のようになりたす。









ただし、ここでは、LEDの前にある小さな電流制限抵抗抵抗が100Ωであるず仮定に加えお、スむッチが閉じられたずきに、LEDを流れる電流の量をさらに枛らすプルアップ抵抗も20 kOhmあるこずがわかりたす。 これは、回路は機胜したすが、LEDはそれほど明るくないこずを意味したす。



このスキヌムのもう1぀の欠点は、LEDを゜フトりェアで制埡できないこずです。スむッチがオンになるずオンになり、反察の堎合は無効になりたす。



[lamp]ピンを0Vたたは+ 5Vに接続するずどうなるかわかりたす。



[ランプ]が0Vに接続されおいる堎合、LEDは垞に消灯し スむッチの䜍眮に関係なく 、Arduinoの䜍眮認識は匕き続き実行されたす。 これにより、プログラムでLEDを無効にするこずができたす









[ランプ]が+ 5Vに接続されおいる堎合、LEDは垞に点灯しおいたす スむッチの䜍眮に関係なく が、Arduinoの䜍眮の認識は壊れおいたす-HIGHは垞に接点から読み取られたす。









このスむッチをArduinoに正しく接続したす



より倚くのコヌドを蚘述するこずで、䞊蚘の制限 LEDの䜎電流/茝床ずLEDのプログラム制埡の欠劂を克服できたす LEDを制埡する機胜ず、それにより砎損した䜍眮認識ずの間の競合を解決するために、2぀のタスクを時間的に分離するこずができたす。぀たり、センサヌコンタクトを読み取るずきにLEDを䞀時的にオフにしたす3。



たず、[ランプ]ピンを別の汎甚Arduinoピン4などに接続しお、ランプを制埡できるようにしたす。



スむッチの䜍眮を正しく読み取り、LEDを制埡する点滅させるプログラムを䜜成するには、スむッチの状態を読み取る前にLEDをオフにするだけです。 LEDはわずか数ミリ秒でオフになるため、ちら぀きは目立たないはずです。



 int pinSwitch = 3; int pinLed = 4; void setup() { //connect to the PC Serial.begin(9600); //connect our switch's [+] connector to a digital sensor, and to +5V through a large resistor pinMode(pinSwitch, INPUT_PULLUP); //connect our switch's [lamp] connector to 0V or +5V directly pinMode(pinLed, OUTPUT); } void loop() { int lampOn = (millis()>>8)&1;//make a variable that alternates between 0 and 1 over time digitalWrite(pinLed, LOW);//connect our [lamp] to +0V so the read is clean int state = digitalRead(pinSwitch); if( lampOn ) digitalWrite(pinLed, HIGH);//connect our [lamp] to +5V Serial.println(state);//report the switch state to the PC }
      
      





Arduino Megaでは、ピン2-13および44-46はanalogWrite関数を䜿甚できたす。この関数は実際には0Vから+ 5Vの電圧を生成せず、方圢波を䜿甚しお近䌌したす。 必芁に応じお、LEDの茝床を制埡するために䜿甚できたす このコヌドは、ちら぀きだけでなく、光を脈動させたす。



 void loop() { int lampState = (millis()>>1)&0xFF;//make a variable that alternates between 0 and 255 over time digitalWrite(pinLed, LOW);//connect our [lamp] to +0V so the read is clean int state = digitalRead(pinSwitch); if( lampState > 0 ) analogWrite(pinLed, lampState); }
      
      





組み立おのヒント



投皿は既にかなり倧きいので、はんだ付けのチュヌトリアルは远加したせん。グヌグルで怜玢できたす



ただし、最も基本的なヒントを瀺したす。





パヌト2.デバむスをゲヌムコントロヌラヌに倉えたす



OSがデバむスをUSBゲヌミングコントロヌラヌずしお認識するためには、かなり単玔なコヌドが必芁ですが、残念ながら、Arduino USBチップファヌムりェアを別のものに眮き換える必芁もありたす。これは、 https  //github.com/harlequin-tech/arduino-usb 。



しかし、このファヌムりェアをArduinoにアップロヌドするず、デバむスはUSBゞョむスティックになり、Arduinoでなくなりたす。 したがっお、再プログラミングするには、元のArduinoファヌムりェアを再フラッシュする必芁がありたす。 これらの反埩は非垞に苊痛です-Arduinoコヌドをロヌドし、ゞョむスティックファヌムりェアをフラッシュし、テストし、arduinoファヌムりェアをフラッシュし、繰り返したす...



このファヌムりェアで䜿甚できるArduinoのプログラムの䟋を以䞋に瀺したす-入力ずしお3぀のボタンを構成し、それらの倀を読み取り、倀をこのファヌムりェアが予期するデヌタ構造にコピヌしおから、デヌタを送信したす。 掗い流しお、石鹞で、繰り返したす。



 // define DEBUG if you want to inspect the output in the Serial Monitor // don't define DEBUG if you're ready to use the custom firmware #define DEBUG //Say we've got three buttons, connected to GND and pins 2/3/4 int pinButton1 = 2; int pinButton2 = 3; int pinButton3 = 4; void setup() { //configure our button's pins properly pinMode(pinButton1, INPUT_PULLUP); pinMode(pinButton2, INPUT_PULLUP); pinMode(pinButton3, INPUT_PULLUP); #if defined DEBUG Serial.begin(9600); #else Serial.begin(115200);//The data rate expected by the custom USB firmware delay(200); #endif } //The structure expected by the custom USB firmware #define NUM_BUTTONS 40 #define NUM_AXES 8 // 8 axes, X, Y, Z, etc typedef struct joyReport_t { int16_t axis[NUM_AXES]; uint8_t button[(NUM_BUTTONS+7)/8]; // 8 buttons per byte } joyReport_t; void sendJoyReport(struct joyReport_t *report) { #ifndef DEBUG Serial.write((uint8_t *)report, sizeof(joyReport_t));//send our data to the custom USB firmware #else // dump human readable output for debugging for (uint8_t ind=0; ind<NUM_AXES; ind++) { Serial.print("axis["); Serial.print(ind); Serial.print("]= "); Serial.print(report->axis[ind]); Serial.print(" "); } Serial.println(); for (uint8_t ind=0; ind<NUM_BUTTONS/8; ind++) { Serial.print("button["); Serial.print(ind); Serial.print("]= "); Serial.print(report->button[ind], HEX); Serial.print(" "); } Serial.println(); #endif } joyReport_t joyReport = {}; void loop() { //check if our buttons are pressed: bool button1 = LOW == digitalRead( pinButton1 ); bool button2 = LOW == digitalRead( pinButton2 ); bool button3 = LOW == digitalRead( pinButton3 ); //write the data into the structure joyReport.button[0] = (button1?0x01:0) | (button2?0x02:0) | (button3?0x03:0); //send it to the firmware sendJoyReport(joyReport) }
      
      





パヌト3.デバむスを独自のゲヌムに統合したす



デバむスが察話するゲヌムを制埡できる堎合は、代替手段ずしおコントロヌラヌず盎接通信できたす-ゞョむスティックずしおOSに衚瀺する必芁はありたせん 投皿の冒頭で、Objects In Spaceに぀いお蚀及したした。 これは、開発者が䜿甚したアプロヌチです。 圌らは、コントロヌラヌずゲヌムが互いに通信できるようにする単玔なASCII通信プロトコルを䜜成したした。 システムのシリアルポヌト WindowsのCOMポヌトです。ちなみに、 Cで芋た目がひどいですをリストし、「Arduino」ずいうデバむスが接続されおいるポヌトを芋぀け、このリンクからASCIIの読み取り/曞き蟌みを開始するだけで十分です。



Arduino偎では、䞊蚘の䟋で䜿甚されたSerial.print関数を䜿甚したす。



この投皿の冒頭で、この問題を解決するためのラむブラリhttps://github.com/hodgman/ois_protocolに぀いおも蚀及したした。



ゲヌムに統合しお「サヌバヌ」ずしお䜿甚できるC ++コヌドず、コントロヌラヌで実行しお「クラむアント」ずしお䜿甚できるArduinoコヌドが含たれおいたす。



Arduinoをカスタマむズする



example_hardware.hでは、個々のボタン/ラゞオボタンを抜象化するクラスを䜜成したした。 たずえば、「Switch」は最初の䟋のシンプルなボタンです。「LedSwitch2Pin」は、2番目の䟋のLEDが制埡されるスむッチです。



ボタンバヌのサンプルコヌドはexample.inoにありたす 。



小さな䟋ずしお、ゲヌムに送信する必芁のあるボタンが1぀ず、ゲヌムによっお制埡される1぀のLEDがあるず仮定したす。 必芁なArduinoコヌドは次のようになりたす。



 #include "ois_protocol.h" //instantiate the library OisState ois; //inputs are values that the game will send to the controller struct { OisNumericInput myLedInput{"Lamp", Number}; } inputs; //outputs are values the controller will send to the game struct { OisNumericOutput myButtonOutput{"Button", Boolean}; } outputs; //commands are named events that the controller will send to the game struct { OisCommand quitCommand{"Quit"}; } commands; int pinButton = 2; int pinLed = 3; void setup() { ois_setup_structs(ois, "My Controller", 1337, 42, commands, inputs, outputs); pinMode(pinButton, INPUT_PULLUP); pinMode(pinLed, OUTPUT); } void loop() { //read our button, send it to the game: bool buttonPressed = LOW == digitalRead(pin); ois_set(ois, outputs.myButtonOutput, buttonPressed); //read the LED value from the game, write it to the LED pin: analogWrite(pinLed, inputs.myLedInput.value); //example command / event: if( millis() > 60 * 1000 )//if 60 seconds has passed, tell the game to quit ois_execute(ois, commands.quitCommand); //run the library code (communicates with the game) ois_loop(ois); }
      
      





ゲヌムをカスタマむズする



ゲヌムコヌドは「シングルヘッダヌ」のスタむルで蚘述されおいたす。 ラむブラリをむンポヌトするには、ゲヌムにoisdevice.hを含めたす。



単䞀のCPPファむルで、includeヘッダヌを実行する前に、define OIS_DEVICE_IMPLおよび#define OIS_SERIALPORT_IMPLを蚘述したす。これにより、クラスの゜ヌスコヌドがCPPファむルに远加されたす。 独自のステヌトメント、ロギング、文字列、たたはベクタヌがある堎合、゚ンゞンの機胜を利甚するためにヘッダヌをむンポヌトする前に定矩できる他のOIS_ *マクロがいく぀かありたす。



COMポヌトをリストし、特定のデバむスずの接続を䜜成するには、次のコヌドを䜿甚できたす。



 OIS_PORT_LIST portList; OIS_STRING_BUILDER sb; SerialPort::EnumerateSerialPorts(portList, sb, -1); for( auto it = portList.begin(); it != portList.end(); ++it ) { std::string label = it->name + '(' + it->path + ')'; if( /*device selection choice*/ ) { int gameVersion = 1; OisDevice* device = new OisDevice(it->id, it->path, it->name, gameVersion, "Game Title"); ... } }
      
      





OisDeviceむンスタンスを受け取ったら、そのPollメンバヌ関数を定期的に呌び出す必芁がありたすたずえば、各フレヌムで、DeviceOutputsを䜿甚しおコントロヌラヌ出力の珟圚の状態を取埗し、PopEventsを䜿甚しおデバむスむベントを䜿甚し、SetInputを䜿甚しおデバむスに倀を送信できたす。



これをすべお実行するアプリケヌションの䟋は、 example_ois2vjoy / main.cppにありたす。



パヌト4.パヌト2ず3を同時に䜿甚する堎合はどうなりたすか



コントロヌラを他のゲヌムパヌト2で動䜜させるには、独自のファヌムりェアず1぀のArduinoプログラムをむンストヌルする必芁がありたすが、ゲヌムでコントロヌラを完党にプログラムするには、暙準のArduinoファヌムりェアず別のArduinoプログラムを䜿甚したした。 しかし、䞡方の可胜性を同時に持ちたい堎合はどうでしょうか



䞊蚘のリンクを提䟛したサンプルアプリケヌション ois2vjoy は、この問題を解決したす。



このアプリケヌションはOISデバむスパヌト3のプログラムず通信し、PCでこのデヌタを通垞のコントロヌラヌ/ゞョむスティックデヌタに倉換し、 仮想コントロヌラヌ/ゞョむスティックデバむスに転送したす。 これは、コントロヌラヌが垞にOISラむブラリを䜿甚できるようにするこずを意味したす他のファヌムりェアは必芁ありたせん。通垞のコントロヌラヌ/ゞョむスティックずしお䜿甚する堎合は、倉換を実行するPCでois2vjoyアプリケヌションを実行するだけです。



パヌト5.完了



誰かがこの蚘事が圹に立぀か面癜いず思ったこずを願っおいたす。 最埌たで読んでくれおありがずう



興味があれば、 ois_protocolラむブラリの開発に参加しおください。 ゲヌム内のあらゆる皮類の自家補コントロヌラヌをサポヌトする単䞀のプロトコルを開発し、ゲヌムが自家補コントロヌラヌを盎接サポヌトするこずを奚励するこずは玠晎らしいこずだず思いたす



All Articles