見出し画像

自作のゲームパッドを作った話 その2

こんにちは!

今回は前回の記事の続きとして、自作のゲームパッドをつくったことについて書いていきたいと思います。今回はブレッドボードを使ったプロトタイピングが中心で、Arduinoのキーボード操作の部分について説明したいと思います。

前回の記事はこちら。初回では全体感と使用するマイコンについて書いています。


ソースコード

まずはいつもどおりソースコードのリポジトリをこちらで紹介します。Joystickフォルダーに入っている「.ino」ファイルがarduinoのプログラムで、直下に入っているpythonのコードがGUI用のプログラムですね。今回の記事ではarduinoプログラムについて書いていきますが、GUIプログラムについてもおいおい書いていく予定です。


ブレッドボードを使ったプロトタイピング

いきなりモノをつくるのは無理なので、ブレッドボードでプログラムの動作確認をしつつ、電気回路部分の試作とプログラムのコーディングを進めていきます。全体の構成としては以下の通り。

- 上下左右のキーは左手側にジョイスティックで実装
- 右手側に4ボタンを配置(Play Stationでいう◯×△□)
- 中央部にも1ボタンを配置
- 上部の左右(いわゆるLRボタンの位置)に1ボタンずつ配置
- 下部にモード選択スイッチ(トグル)を配置

電気回路にするとこんな感じです。

回路

そんなに複雑なことをやっているわけではないので詳細な解説は割愛します。単純に計7個のボタンと1個のトグルスイッチをArduinoのDigital IOにつなげ、ジョイスティックの出力をAnalog IOに繋いでいるだけですね。

これを設計し始めた段階ではPro Microが届いていたなかったので、手元にあったAruduino UNOを使って簡単に動作確認。UNOではキー入力はできませんが、結線等はこれで確認できるので、初期段階ではこれでコーディングや接続の確認を行っていました。こちらはジョイスティック1つとボタン4つで実験しているところ。

画像2


Pro Microが届いたら、その他のボタンやスイッチもどんどん取り付けていきます。回路的には大したことないですが、やはり結線の量が多いので、どうしてもごっちゃごちゃしますねw

画像3

赤いボタンが右手用のバタン4つ+中心部のボタン1つ、LR部分のボタンは緑色の小さいものを使っています。次の章で紹介するプログラムを含め、こちらで動作確認ができたので、ひとまずプロトタイピングは完了です。ここまでできた段階で電気回路的な部分は決まったので、次回のハードウェアづくりに繋がります。


Arduinoプログラムについて

ソースコードはGithubを見ていただいても良いのですが、それもちょっとめんどうだと思うので、メインの操作部分に関してはそのままコードを貼り付けます。

#include "Keyboard.h"

const int sw_pin = 9;
const int Button[7] ={2,3,4,5,6,7,8};
const int Toggle = 10;
const int x_pin = A1;
const int y_pin = A0;
const float move_max = 10;

int sw = 0;
int x_pos = 0;
int y_pos = 0;
int BTN[7] = {0};
int Count[7] = {0};
int Count_arrow[2] = {0};
int TGL = 0;
int flug = 0;

byte buf[8]; 
char key_assign[7] = {'x','z','a','s',KEY_ESC,'q','w',};

// スティックの読み取り値からカウンタ値を返す関数
int count_arrow_memory(float Distance){

 if (Distance > 2){
   return 1;
 } else if (Distance < -2){
   return -1;
 } else {
   return 0;
 }
 
}

// スティックの読み取り値とカウンタ値から方向キーの入力をする関数
void arrow_input(float Distance, int count, int up, int down){

 if (Distance > 2 && count == 1){
   Keyboard.release(down);
   Keyboard.press(up);
 } else if (Distance < -2 && count == -1) {
   Keyboard.release(up);
   Keyboard.press(down);
 } else if (Distance >= -2 && Distance <=2 && count == 0){
   Keyboard.release(up);
   Keyboard.release(down);
 }
 
}

void setup() {
 // put your setup code here, to run once:
 
 pinMode(sw_pin, INPUT_PULLUP);
 for (int i=0; i<7; i++){ 
   pinMode(Button[i], INPUT);
 }
 pinMode(Toggle, INPUT);
 Serial.begin(9600);
 Keyboard.begin();
}

void loop() {
 // put your main code here, to run repeatedly:
 // 各入力の読み取り
 x_pos = analogRead(x_pin);
 y_pos = analogRead(y_pin);
 for (int i=0; i<7; i++){
   BTN[i] = digitalRead(Button[i]);
 }
 TGL = digitalRead(Toggle);
 
 float xDistance = -1 * ((float)x_pos / 1023.0f * move_max - 5);
 float yDistance = -1 * ((float)y_pos / 1023.0f * move_max - 5);
 
 // トグルがonのときのみキーボード入力をする
 if (TGL == HIGH){
 
   // ボタンの入力操作
   for (int i=0;i<7;i++){
     // 入力状態がonかつカウンタがonならキーを押下
     if(BTN[i]==HIGH && Count[i]==1){
       Keyboard.press(key_assign[i]);
     // 入力状態がoffかつカウンタがoffならキーを離す
     } else if (BTN[i]==LOW && Count[i]==0){
       Keyboard.release(key_assign[i]);
     }
   }
   
   // スティックの入力操作
   arrow_input(xDistance, Count_arrow[0],KEY_RIGHT_ARROW, KEY_LEFT_ARROW);
   arrow_input(yDistance, Count_arrow[1],KEY_UP_ARROW, KEY_DOWN_ARROW);
   
 } else {
   Serial.println ("Off");
   # 通信の実装部分。今回の記事では省略
 }
 
  // カウンタの更新
 for (int i=0; i<7; i++){
   if (BTN[i]==HIGH){
     Count[i] = 1;
   } else {
     Count[i] = 0;
   }
 }

 Count_arrow[0] = count_arrow_memory(xDistance);
 Count_arrow[1] = count_arrow_memory(yDistance);
 
 delay(10);

}

こちらも詳細は割愛しますが、ポイントだけ紹介したいと思います。

ポイントのひとつは、やはりスイッチのチャタリング対策ですね。スイッチの物理接点の部分では、オンオフの切り替えがきれいにできるわけではなく、押した瞬間はミクロなレベルで接点が閉じたり開いたりを繰り返すチャタリングと言う現象が発生するため、これが誤動作の要因になります。この現象自体は入力デバイス全般に現れる問題であり、調べてみると対策の仕方は色々と見つかりました。

ただ、今回の実装ではかなりシンプルな形で対策しています。少し使ってみていますが、特に困っていないのでそこまでシビアなモノが求められるものでなければそこまで大したことをしなくても大丈夫みたいです。

その対策というのは単純に各ボタンに対してカウンターを入れて、「二回続けてonが入力されたら入力とみなす」という形ですね。この形式だとミクロなレベルの誤差はどうしても発生してしまうので、本当にシビアな入力が要求される場合にはもう少しきちんと対処する必要はあるだろうとは思いますw

もう一つのポイントは、ArduinoのKeybordライブラリです。コード中に「KEY_*」という変数が幾つか出てきますが、これはこのライブラリに組み込まれている変数となります。アルファベットに関しては、「Keyborad.press()」でシンプルに書けるわけですが、それ以外のキー(例えば方向キーやctrl、alt、enterなど)を入力したいときはこの「KEY_*」という変数を使えばOK。詳しくは公式のドキュメントから確認できます。


まとめ

今回は自作ゲームパッドの第二弾ということで、プロトタイピングとArduinoのプログラムについて紹介しました。前回はやや抽象的な全体感のはなしだったので少しわかりにくかったかも知れませんが、今回からは実際の製作の話がすすむので、少しづつイメージしやすくなってきたかなと思います。

次回はコントローラーのハードウェア部分の製作について書く予定です。楽しみにしている人がどれくらいいるのかはわかりませんがw、興味のあるかたはお楽しみに!

> 後日追記 次回の記事を書きました↓!

それでは、また!

この記事が気に入ったらサポートをしてみませんか?