ゲームパッド

片手でゲームをしたい!;
…でも市販のゲームパッドはほぼ両手用。
ということで、今回はWiiのヌンチャクコントローラーをArduino Leonardoに接続して、USB接続のゲームパッドを作ってみます。
Windows PCからは何の変哲もない普通のゲームパッドに見えるので、ゲームとの相性問題が出ることもないはず。
ヌンチャクを使ったゲームパッド(≒ジョイスティック)なので、JoyChuckという名前にしました。
必要なもの
ハードウェア
項目 | 説明 |
---|---|
Arduino Leonardo | 比較的小型で安価で簡単に使えるマイコンボード。 なお、Arduino UnoでもUSB接続のHID(human interface device)を作ることはできますが、その場合ATMEGA8U2マイコンのファームウェアを書き換える必要があります。 難しそうなので、今回は素直にLeonardoを使用することにしました。 |
ヌンチャクコントローラー | 通常はWiiリモコンに接続して使うヌンチャクコントローラー。 |
WiiChuck | Arduinoにヌンチャクコントローラーを接続しやすくする基板。 なくても頑張れば接続できるでしょう。 |
ピンヘッダ(4P) | 何でも良いです。今回は 秋月電子通商で購入しました。 |
ソフトウェア
項目 | 説明 |
---|---|
chuck_funcs.h | ヌンチャクコントローラーの情報をArduinoで取得するための関数が定義されたヘッダファイル。 todbotさんのgithubからダウンロードしてください。 (「Raw」を右クリックして名前をつけて保存。) |
USBAPI.h | USB機器用ヘッダファイル。 Imaginary Industriesからダウンロードしてください。 または、&ref(USBAPI.h.diff,,USBAPI.hのパッチ);をお手持ちの環境のUSBAPI.hに当ててください。 |
HID.cpp | HID用プログラム。 Imaginary Industriesからダウンロードしてください。 または、&ref(HID.cpp.diff,,HID.cppのパッチ);をお手持ちの環境のHID.cppに当ててください。 |
leoJoy.ino | テスト用ランダム入力スケッチ。 Imaginary Industriesからダウンロードしてください。 |
JoyChuck.ino | ヌンチャクコントローラをゲームパッドにするスケッチ。 下記からダウンロードしてください。 |
手順
ソフトウェアの準備(Arduino Leonardoをゲームパッドとして認識させる)
- arduinoの開発環境をインストールしたディレクトリの配下のhardware\arduino\cores\arduinoを開く。 (私の場合は、「C:\Program Files (x86)\Arduino\hardware\arduino\cores\arduino」でした)
- 上記で示したUSBAPI.hとHID.cppをコピーする。
- USBケーブルを挿す。
- leoJoy.inoを開き、Arduino Leonardoに書き込む。
ソフトウェアの動作確認
- [コントロールパネル]>[デバイス マネージャー]>[ヒューマン インターフェース デバイス]を開く。
- 「HID 準拠ゲーム コントローラー」が表示されていることを確認する。 #clear
- [コントロールパネル]>[デバイスとプリンター]を開く。
- 「デバイス」欄に「Arduino Leonardo」が表示されていることを確認する。
- 右クリックし、「ゲームパッドの設定」をクリックする。
- 「プロパティ」ボタンをクリックする。
- 右のようなウィンドウが表示され、「軸」「ボタン」「ハットスイッチ」がランダムに入力されていることを確認する。 (leoJoy.inoはランダムな入力を発生させるスケッチです)



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

ソフトウェアの準備(ヌンチャクコントローラーをゲームパッドとして使えるようにする)
- JoyChuck.inoとchuck_funcs.hをJoyChuckというフォルダに格納する。
- 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
*/
} - JoyChuck.inoを開き、Arduino Leonardoに書き込む。
最終動作確認
- [コントロールパネル]>[デバイスとプリンター]を開く。
- 「デバイス」欄に「Arduino Leonardo」が表示されていることを確認する。
- 右クリックし、「ゲームパッドの設定」をクリックする。
- 「プロパティ」ボタンをクリックする。
- ヌンチャクコントローラーのジョイスティックの操作が、軸欄に反映されることを確認する。
- ヌンチャクコントローラーのCボタンの操作が、ボタン欄の1に反映されることを確認する。
- ヌンチャクコントローラーの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でオンオフを表現…という感じ。 各ボタンの同時押し込みは加算で表現する。 |
hatSw1 | POVキーに対応。上方向を0として、時計回りに0~7で指定。 |
デバイスとプリンターに表示される名称を変更したい
USBCore.cpp
のSTRING_IPRODUCT
とSTRING_IMANIFACTURE
を修正してください。
【発展】ボタンを増やす

ヌンチャクコントローラーのボタン数は2個。これではちょっと少ない。
そこで発展系としてボタンを増やしてみます。
Arduinoではマイコン内にプルアップ抵抗を持っていて、設定で使用できるため、スイッチのみ用意すればボタンを簡単に増やすことが出来ます。(参考)
右の写真は十字キーを増設してヌンチャクコントローラーと合体させたものです。
必要なもの
項目 | 説明 |
---|---|
タクトスイッチ | |
ユニバーサル基板 または ブレッドボード |
あるとよいもの
項目 | 説明 |
---|---|
DS LiteやPSPの保守パーツ | 十字キーやボタンの外装とラバードームを利用します。 秋葉原なら三月兎などで買えます。 |
Y字ドライバ | ヌンチャクコントローラーには特殊なネジが使われています。 頑張ればマイナスドライバでもネジを破壊しつつ開けられますが、安全に開けるにはこれが必要です。 秋葉原なら三月兎などで買えます。 |
手順
- ユニバーサル基板にタクトスイッチを挿す。
- タクトスイッチの =□= となっている4本の足のうち、=の1本ずつをGNDとデジタル端子に接続する。(下記ではデジタル10番ピンを使用) 複数のスイッチを設けたいときはGNDは共有しても大丈夫です。
- スケッチのinclude文の下辺りに下記を追加する。
#define PIN_SWITCH1 10
byte switch1; - スケッチのsetup()の中に下記を追加する。
pinMode(PIN_SWITCH1, INPUT_PULLUP);
- スケッチのloop()の中に下記を追加する。(下記はタクトスイッチが押されると、POVキー上が入力されるようになる)
switch1 = digitalRead(PIN_SWITCH1);
Serial.print(" SWITCH1:"); Serial.print(switch1);
if (switch1 == LOW) {
joySt.hatSw1 = 0;
} - DEBUG定数を1にしてArduinoに書き込むと、シリアルモニタに"SWITCH1:1"と表示され続け、スイッチを押すと"SWITCH1:0"に表示が変わるはずです。
- あとはお好みでラバードームと外装を両面テープで貼ってください。
- また、ヌンチャクコントローラと合体させたい場合は、Y字ドライバでコントローラを開けた後、外装を適当に切断し、埋め込んでください。

