メインコンテンツまでスキップ

ゲームパッド

片手でゲームをしたい!;

…でも市販のゲームパッドはほぼ両手用。

ということで、今回はWiiのヌンチャクコントローラーをArduino Leonardoに接続して、USB接続のゲームパッドを作ってみます。

Windows PCからは何の変哲もない普通のゲームパッドに見えるので、ゲームとの相性問題が出ることもないはず。

ヌンチャクを使ったゲームパッド(≒ジョイスティック)なので、JoyChuckという名前にしました。

必要なもの

ハードウェア

項目説明
Arduino Leonardo比較的小型で安価で簡単に使えるマイコンボード。

なお、Arduino UnoでもUSB接続のHID(human interface device)を作ることはできますが、その場合ATMEGA8U2マイコンのファームウェアを書き換える必要があります。
難しそうなので、今回は素直にLeonardoを使用することにしました。
ヌンチャクコントローラー通常はWiiリモコンに接続して使うヌンチャクコントローラー。
WiiChuckArduinoにヌンチャクコントローラーを接続しやすくする基板。
なくても頑張れば接続できるでしょう。
ピンヘッダ(4P)何でも良いです。今回は 秋月電子通商で購入しました

ソフトウェア

項目説明
chuck_funcs.hヌンチャクコントローラーの情報をArduinoで取得するための関数が定義されたヘッダファイル。
todbotさんのgithubからダウンロードしてください。
(「Raw」を右クリックして名前をつけて保存。)
USBAPI.hUSB機器用ヘッダファイル。
Imaginary Industriesからダウンロードしてください。
または、&ref(USBAPI.h.diff,,USBAPI.hのパッチ);をお手持ちの環境のUSBAPI.hに当ててください。
HID.cppHID用プログラム。
Imaginary Industriesからダウンロードしてください。
または、&ref(HID.cpp.diff,,HID.cppのパッチ);をお手持ちの環境のHID.cppに当ててください。
leoJoy.inoテスト用ランダム入力スケッチ。
Imaginary Industriesからダウンロードしてください。
JoyChuck.inoヌンチャクコントローラをゲームパッドにするスケッチ。
下記からダウンロードしてください。

手順

ソフトウェアの準備(Arduino Leonardoをゲームパッドとして認識させる)

  1. arduinoの開発環境をインストールしたディレクトリの配下のhardware\arduino\cores\arduinoを開く。 (私の場合は、「C:\Program Files (x86)\Arduino\hardware\arduino\cores\arduino」でした)
  2. 上記で示したUSBAPI.hとHID.cppをコピーする。
  3. USBケーブルを挿す。
  4. leoJoy.inoを開き、Arduino Leonardoに書き込む。

ソフトウェアの動作確認

  1. [コントロールパネル]>[デバイス マネージャー]>[ヒューマン インターフェース デバイス]を開く。
  2. 「HID 準拠ゲーム コントローラー」が表示されていることを確認する。 #clear
  3. [コントロールパネル]>[デバイスとプリンター]を開く。
  4. 「デバイス」欄に「Arduino Leonardo」が表示されていることを確認する。
  5. 右クリックし、「ゲームパッドの設定」をクリックする。
  6. 「プロパティ」ボタンをクリックする。
  7. 右のようなウィンドウが表示され、「軸」「ボタン」「ハットスイッチ」がランダムに入力されていることを確認する。 (leoJoy.inoはランダムな入力を発生させるスケッチです)

ハードウェアの準備

  1. WiiChuckにピンヘッダを半田付けする。(labs.thingm.comと書いてある側からピンヘッダの短い方を差込み、逆側から半田付けする。)
  2. ArduinoのGNDピンに-、3.3Vピンに1. 、D2ピン((SDAピンでも可。))にd、D3ピン((SCLピンでも可。))にcを接続する。
  3. WiiChuckにヌンチャクコントローラを挿す。(ヌンチャクの金属端子の凹みがある方が上になるように挿す。)

ソフトウェアの準備(ヌンチャクコントローラーをゲームパッドとして使えるようにする)

  1. JoyChuck.inoとchuck_funcs.hをJoyChuckというフォルダに格納する。
  2. nunchuck_funcs.hの25行目~34行目は次のようにコメントアウトする。((Uno用の関数のため。))
    // Uses port C (analog in) pins as power & ground for Nunchuck
    static void nunchuck_setpowerpins()
    {
    /*
    #define pwrpin PORTC3
    #define gndpin PORTC2
    DDRC |= _BV(pwrpin) | _BV(gndpin);
    PORTC &= _BV(gndpin);
    PORTC |= _BV(pwrpin);
    delay(100); // wait for things to stabilize
    */
    }
  3. JoyChuck.inoを開き、Arduino Leonardoに書き込む。

最終動作確認

  1. [コントロールパネル]>[デバイスとプリンター]を開く。
  2. 「デバイス」欄に「Arduino Leonardo」が表示されていることを確認する。
  3. 右クリックし、「ゲームパッドの設定」をクリックする。
  4. 「プロパティ」ボタンをクリックする。
  5. ヌンチャクコントローラーのジョイスティックの操作が、軸欄に反映されることを確認する。
  6. ヌンチャクコントローラーのCボタンの操作が、ボタン欄の1に反映されることを確認する。
  7. ヌンチャクコントローラーのZボタンの操作が、ボタン欄の2に反映されることを確認する。

以上で終了です。お疲れ様でした :)

Arduinoの基板がむき出しだとトラブルの元なので、 ALTOIDSミントサイズ缶に穴を空けて線を通し、穴部分の切り口で線が切れないようにスポンジ(激落ちくんなどでも可)で保護するとスマートです。

スケッチ

/*
* JoyChuck
*
* 2013 http://cubic9.com
*
* original sketch is leoJoy
* by 2012 Connor,
* http://www.imaginaryindustries.com/blog/?p=80
* nunchuck_funcs.h
* by 2008 Tod E. Kurt,
* http://todbot.com/blog/2008/02/18/wiichuck-wii-nunchuck-adapter-available/
*
*/

#include <Wire.h>
#include "nunchuck_funcs.h"

#define DEBUG 0
#define INTERVAL 50

#define STICK_LEFT_DEFAULT 127
#define STICK_RIGHT_DEFAULT 127
#define POV_DEFAULT -1
#define BUTTON_DEFAULT 0

#define PAD_JOYX_MIN 0
#define PAD_JOYX_MAX 255
#define PAD_JOYY_MIN 0
#define PAD_JOYY_MAX 255

#define CHUCK_JOYX_MIN 24
#define CHUCK_JOYX_MAX 230
#define CHUCK_JOYY_MIN 33
#define CHUCK_JOYY_MAX 226

#define SERIAL_BPS 19200

JoyState_t joySt;
int loop_cnt = 0;
byte accx, accy, accz, zbut, cbut, joyx, joyy;

void setup()
{
#if DEBUG
Serial.begin(SERIAL_BPS);
#endif

nunchuck_init();

#if DEBUG
Serial.print("JoyChuck ready\n");
#endif

joySt.xAxis = STICK_LEFT_DEFAULT;
joySt.yAxis = STICK_LEFT_DEFAULT;
joySt.zAxis = STICK_RIGHT_DEFAULT;
joySt.xRotAxis = 0;
joySt.yRotAxis = 0;
joySt.zRotAxis = 0;
joySt.throttle = 0;
joySt.rudder = STICK_RIGHT_DEFAULT;
joySt.hatSw1 = POV_DEFAULT;
joySt.hatSw2 = POV_DEFAULT;
joySt.buttons = BUTTON_DEFAULT;

}


void loop()
{
if( loop_cnt > INTERVAL ) {
loop_cnt = 0;

nunchuck_get_data();

#if DEBUG
accx = nunchuck_accelx();
accy = nunchuck_accely();
accz = nunchuck_accelz();
#endif
zbut = nunchuck_zbutton();
cbut = nunchuck_cbutton();
joyx = nunchuck_joyx();
joyy = nunchuck_joyy();

#if DEBUG
Serial.print(" accx:"); Serial.print((byte)accx, DEC);
Serial.print(" accy:"); Serial.print((byte)accy, DEC);
Serial.print(" accz:"); Serial.print((byte)accz, DEC);
Serial.print(" zbut:"); Serial.print((byte)zbut, DEC);
Serial.print(" cbut:"); Serial.print((byte)cbut, DEC);
Serial.print(" joyx:"); Serial.print((byte)joyx, DEC);
Serial.print(" joyy:"); Serial.print((byte)joyy, DEC);
Serial.println();
#endif

joySt.xAxis = constrain(
map(joyx, CHUCK_JOYX_MIN, CHUCK_JOYX_MAX,
PAD_JOYX_MIN, PAD_JOYX_MAX),
PAD_JOYX_MIN, PAD_JOYX_MAX);
joySt.yAxis = constrain(
map(joyy, CHUCK_JOYY_MIN, CHUCK_JOYY_MAX,
PAD_JOYY_MAX, PAD_JOYY_MIN),
PAD_JOYY_MIN, PAD_JOYY_MAX);
joySt.buttons = cbut + zbut * 2;

Joystick.setState(&joySt);
}
loop_cnt++;
delay(1);
}

設定について

  • DEBUG定数を1にすると、シリアルモニタにヌンチャクのセンサの現在の値が表示されます。

JoyState_tのメンバ変数とゲームパッドの関係

JoyState_tのメンバ説明
xAxis, yAxis左スティックに対応。0-255の範囲で指定。
zAxis, rudder右スティックに対応。0-255の範囲で指定。
buttonsボタンのオンオフをビットで指定。
1番目のボタンは1/0でオンオフを表現、2番目のボタンは2/0でオンオフを表現、3番目のボタンは4/0でオンオフを表現…という感じ。
各ボタンの同時押し込みは加算で表現する。
hatSw1POVキーに対応。上方向を0として、時計回りに0~7で指定。

デバイスとプリンターに表示される名称を変更したい

USBCore.cppSTRING_IPRODUCTSTRING_IMANIFACTUREを修正してください。

【発展】ボタンを増やす

ヌンチャクコントローラーのボタン数は2個。これではちょっと少ない。

そこで発展系としてボタンを増やしてみます。

Arduinoではマイコン内にプルアップ抵抗を持っていて、設定で使用できるため、スイッチのみ用意すればボタンを簡単に増やすことが出来ます。(参考

右の写真は十字キーを増設してヌンチャクコントローラーと合体させたものです。

必要なもの

項目説明
タクトスイッチ
ユニバーサル基板 または ブレッドボード

あるとよいもの

項目説明
DS LiteやPSPの保守パーツ十字キーやボタンの外装とラバードームを利用します。
秋葉原なら三月兎などで買えます。
Y字ドライバヌンチャクコントローラーには特殊なネジが使われています。
頑張ればマイナスドライバでもネジを破壊しつつ開けられますが、安全に開けるにはこれが必要です。
秋葉原なら三月兎などで買えます。

手順

  1. ユニバーサル基板にタクトスイッチを挿す。
  2. タクトスイッチの =□= となっている4本の足のうち、=の1本ずつをGNDとデジタル端子に接続する。(下記ではデジタル10番ピンを使用) 複数のスイッチを設けたいときはGNDは共有しても大丈夫です。
  3. スケッチのinclude文の下辺りに下記を追加する。
    #define PIN_SWITCH1 10

    byte switch1;
  4. スケッチのsetup()の中に下記を追加する。
    pinMode(PIN_SWITCH1, INPUT_PULLUP);
  5. スケッチのloop()の中に下記を追加する。(下記はタクトスイッチが押されると、POVキー上が入力されるようになる)
    switch1 = digitalRead(PIN_SWITCH1);
    Serial.print(" SWITCH1:"); Serial.print(switch1);
    if (switch1 == LOW) {
    joySt.hatSw1 = 0;
    }
  6. DEBUG定数を1にしてArduinoに書き込むと、シリアルモニタに"SWITCH1:1"と表示され続け、スイッチを押すと"SWITCH1:0"に表示が変わるはずです。
  7. あとはお好みでラバードームと外装を両面テープで貼ってください。
  8. また、ヌンチャクコントローラと合体させたい場合は、Y字ドライバでコントローラを開けた後、外装を適当に切断し、埋め込んでください。

参考