Milkcocoaを使って、Wiiヌンチャクの状態をブラウザに表示してみた


つくったもの

Wiiヌンチャクのジョイスティックをグリグリすると画面のポインターも一緒に動き、ボタンを押すと色が変わる。体感できる程度のタイムラグはあるものの、0.3秒ぐらいの間隔で座標が更新されるので、思った以上にサクサク動いた。

デフォルト状態。

ジョイスティックを右上に倒したところ。

zボタンを押したところ。

ブラウザで取得された値。

使った技術・デバイス

Wiiヌンチャク

Wiiリモコンの拡張機能として使われるコントローラ。ジョイスティック1個とボタン2つ、3軸加速度センサーを備えている。

RaspberryPi

電子工作などで入出力に利用するGPIOピンを備えた小型のシングルボードコンピューター。Linuxが動作するため、普段使い慣れたツールやコマンドを使用できるので便利。今回はWiiヌンチャクとの通信、およびMilkcocoaへのデータ送信の役割を担う。

Milkcocoa

IoTデバイス・スマートフォン・PC間で簡単にリアルタイムなデータのやり取りが可能なクラウドプラットフォーム。今回はRaspberryPiのデータを受信し、ブラウザへ送信するために利用。

実装方法

WiiヌンチャクとRaspberryPiをi2c通信で接続

ヌンチャクは通常Wiiリモコンと接続して利用するが、実は両デバイスの通信にはi2cというシリアル通信規格を利用している。RaspberryPiやArduinoなどでサポートされており、簡単に利用できる。

Wiiヌンチャクの端子のピン配置はこちらを参考にした。端子の穴にジャンパー線のオスがちょうど挿さるので、これでRaspberryPiの3.3V、GND、SDA、SCLのピンと接続する。
http://blog.goo.ne.jp/silvernetworks/e/e8dcfa440c54e03812a23e02748c6b4d

Wiiヌンチャクとの通信方法を調べてみると、Python用のライブラリを作っている人がいたのでこれを利用させてもらう。このライブラリのおかげで、i2cを意識することなく実装できた。
https://github.com/Boeeerb/Nunchuck

以下、インストール方法。Pythonからi2c通信を利用するため、同時にpython-smbusもインストールしている。

sudo apt-get install python-smbus
git clone [email protected]:Boeeerb/Nunchuck.git
cd Nunchuck
sudo python setup.py install

ヌンチャクの状態をサーバーに送信

Milkcocoaから公式に用意されているPython SDKを利用した。他のリポジトリも見てみると、いろんなプラットフォームや言語のためのSDKやサンププログラムが用意されていて、非常に便利。
https://github.com/milk-cocoa/python_sdk

以下、インストール方法。

git clone [email protected]:milk-cocoa/python_sdk.git
cd python_sdk
sudo python setup.py install

SDKに含まれているサンプルプログラムを利用しつつ、先ほどのWiiヌンチャクのライブラリを組み込んで完成。今回の例ではジョイスティックのx軸・y軸の値と、zボタンのon/offを取得し、送信している。

nunchuck_cocoa.py
from nunchuck import nunchuck
import milkcocoa.milkcocoa as milkcocoa

# nunchuckとmilkcocoaの準備
wii = nunchuck()
milkcocoaClient = milkcocoa.Milkcocoa.connectWithApiKey("app-id.mlkcca.com", "API-key", "API-secret", useSSL=False, blocking=True)
datastore = milkcocoaClient.datastore("nunchuck")

while True:
  # ボタンとジョイスティックの状態を取得し、送信
  joyx = wii.joystick_x()
  joyy = wii.joystick_y()
  butz = wii.button_z()
  print joyx, joyy, butz
  datastore.send({"joyx":joyx, "joyy":joyy, "butz":butz})

app-id, API-key, API-secretは各自の値を入力すること。

はじめ、ループで回しているdatastore.send()のところで最初の1回しかデータ送信されずに困ったが、下記を参考にblocking=Trueとして解決した。
https://teratail.com/questions/25243

フロントエンドで受信

JavaScript用のMilkcocoa APIを使い、サーバーに送信されたデータを受信する。データが送信されたことをds.on("send", function(d) {})で捉えて、d.value.joyxなどで送信されたデータの中身を取得できる。

ここでは受信したジョイスティックやボタンの状態を元に、jQueryを使ってポインターの座標を更新したり、ポインターの色を変えたりしている。

index.html
<!DOCTYPE html>
<html>
<head>
    <title>Milkcocoaを使って、Wiiヌンチャクの状態をブラウザに表示してみた</title>
    <link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
    <div id="pointer"></div>
    <script type="text/javascript" src="http://cdn.mlkcca.com/v2.0.0/milkcocoa.js"></script>
    <script type="text/javascript" src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
    <script type="text/javascript" src="main.js"></script>
</body>
</html>
main.js
// ジョイスティックの出力値の範囲
var min_x =  34
var max_x = 226
var min_y =  25
var max_y = 217

// Milkcocoaの準備
var milkcocoa = new MilkCocoa("app-id.mlkcca.com");
var ds = milkcocoa.dataStore("nunchuck");

// データが送られた時の処理
ds.on("send", function(d) {
  var left = (d.value.joyx - min_x) / (max_x - min_x) * 100;
  var top  = (max_y - d.value.joyy) / (max_x - min_y) * 100;
  $('#pointer').animate({left: left+"%", top: top+"%", }, 300);
  $('#pointer').queue([]);
  if (d.value.butz == true) {
    $('#pointer').addClass('shoot');
  } else {
    $('#pointer').removeClass('shoot');
  }
});
main.css
#pointer {
  width: 50px;
  height: 50px;
  border-radius: 25px;
  background-color: #4e83ff;
  position: absolute;
  left: 50%;
  top: 50%;
  margin-left: -25px;
  margin-top: -25px;
}

.shoot {
  background-color: #ff4e4e !important;
}

感想

Milkcocoaが便利。ほんの数行書くだけでブラウザ・デバイス間のリアルタイム通信ができるので、ハードウェア関連でブラウザと連携したものをさくっと作りたい時に重宝しそう。