GROVEジョイスティック+littleBits KoshianBitをSORACOM経由でMilkcocoaに記録するメモ

これはソラコムSoftware Design 誌 巻頭特集記念リレーブログ 4/28分です

Wifiがつながりにくい室内環境やそもそもWifiのない屋外環境で、ゲーム的な操作を記録できないかなということで、GROVEジョイスティック+littleBits KoshianBitをSORACOM経由でMilkcocoaに記録してみたメモです。

やりたいこと

すしルート#3で「すし×うごく」ネタで登壇してきましたで行った曲げセンサー情報をBluetoothに送るのがかなりゲーム的だったので、ジョイスティックだとどうだろうかという想起です。

以下にように実装をします。

  • GROVEジョイスティック+littleBits KoshianBitでジョイスティックの傾きをBluetooth無線化する
  • RaspberryPi 3の内蔵BluetoothでKoshianBitで無線化された数値をNodeJS nobleで検出する
  • RaspberryPi 3で内蔵Bluetoothで検出した値をSORACOM経由でMilkcocoaに送信する

soracom_joystick_value_koshianbit_milkcocoa_record_9

GROVE ジョイスティック+littleBits KoshianBitでジョイスティックの傾きをBluetooth無線化する

最近、制作したGROVE のデジタル・アナログ入力と連携できる個人開発したGROVE INPUT Bitを使ってGROVEとlittleBitsが連携することが出来ます。

soracom_joystick_value_koshianbit_milkcocoa_record_6

こちらをKoshianBitと連携して接続し、ジョイスティックの一方向の傾きのみ検出しました。

soracom_joystick_value_koshianbit_milkcocoa_record_8

GROVE ジョイスティックの仕様で、通常時50%、最小25%~最大75%を検出できます。

soracom_joystick_value_koshianbit_milkcocoa_record_7

RaspberryPi 3の内蔵BluetoothでKoshianBitで無線化された数値をNodeJS nobleで検出

RaspberryPi 3では内蔵Bluetoothがあるので、追加アダプタ無しですぐにつながるのが素敵でした。NodeJSでBLE通信ができるnobleライブラリでkonashiとつなげたメモをベースに、検出するようにします。

soracom_joystick_value_koshianbit_milkcocoa_record_10

今回はインストール時に、Raspberry Pi デフォルトのNodeJSはv0.10でnobleがうまく入らなかったため、本家の v4 のインストール記事をベースにバージョンアップしてから入れました。

ソースコードは以下のとおりです。

var express = require('express');
var app = express();
var MILKCOCOA_APP_ID = "      ";
var MILKCOCOA_DATASTORE_ID = "grove_joystick";

console.log("MILKCOCOA_APP_ID:" + MILKCOCOA_APP_ID);
console.log("MILKCOCOA_DATASTORE_ID:" + MILKCOCOA_DATASTORE_ID);

// milkcocoa /////////////////////////////////
var MilkCocoa = require("./node_modules/milkcocoa/index.js");
var milkcocoa = new MilkCocoa(MILKCOCOA_APP_ID + ".mlkcca.com");
// dataStore作成 デフォルトのデータストアID
var sampleDataStore = milkcocoa.dataStore(MILKCOCOA_DATASTORE_ID);
// データがpushされたときのイベント通知
sampleDataStore.on("push", function(datum) {
  // 内部のログ
  console.log('[push complete]');
  console.log(datum);
});
//////////////////////////////////////////////

var express = require('express');
var bodyParser = require('body-parser');
var app = express();

app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());

app.get('/', function(request, response) {
  response.send('Hello World!');
});

app.listen(app.get('port'), function() {
  console.log('Node app is running on port', app.get('port'));
});


var noble = require('noble');

// KONASHI自体のサービスID
var KONASHI_SERVICE_UUID = '229bff0003fb40da98a7b0def65c2d4b';
// 操作したいpinのID
var KONASHI_ANALOG_INPUT_PINID   =  '229b300803fb40da98a7b0def65c2d4b';
var KONASHI_PIO_SETTING_PINID    =  '229b300003fb40da98a7b0def65c2d4b';
var KONASHI_PIO_OUTPUT_PINID     =  '229b300203fb40da98a7b0def65c2d4b';
// 各CHARACTERISTICSをUUIDから判断してcharacteristic格納する変数
var KONASHI_CHARACTERISTICS_ANALOG_READ;
var KONASHI_CHARACTERISTICS_PIO_SETTINGS;
var KONASHI_CHARACTERISTICS_PIO_OUTPUT;

// LED ON/OFF
var led_toggle = false;

// 状態がパワーONだったらスキャンに移行
noble.on('stateChange', function(state) {
  console.log('on -> stateChange: ' + state);

  if (state === 'poweredOn') {
    noble.startScanning();
  } else {
    noble.stopScanning();
  }
});

noble.on('scanStart', function() {
  console.log('on -> scanStart');
});

noble.on('scanStop', function() {
  console.log('on -> scanStop');
});

// discover 機器が発見されたら
noble.on('discover', function(peripheral) {
  console.log('on -> discover: ' + peripheral);
  // まずスキャンをとめる
  noble.stopScanning();

  // KONASHI接続時のイベント
  peripheral.on('connect', function() {
    console.log('on -> connect');
    this.discoverServices();
  });
  // KONASHI切断時のイベント
  peripheral.on('disconnect', function() {
    console.log('on -> disconnect');
  });

  // 見つけたサービス(機器)へのアクセス
  peripheral.on('servicesDiscover', function(services) {

    for(i = 0; i < services.length; i++) {

      // サービスがKONASHI_SERVICE_UUIDと一致した時だけ処理
      if(services[i]['uuid'] == KONASHI_SERVICE_UUID){

        // サービスのcharacteristic捜索
        services[i].on('includedServicesDiscover', function(includedServiceUuids) {
          console.log('on -> service included services discovered [' + includedServiceUuids + ']');
          this.discoverCharacteristics();
        });

        // characteristic取得イベント
        services[i].on('characteristicsDiscover', function(characteristics) {

          // characteristics配列から必要なCHARACTERISTICSをUUIDから判断してcharacteristic格納
          for(j = 0; j < characteristics.length; j++) {
            // アナログ入力 characteristic
            if( KONASHI_ANALOG_INPUT_PINID == characteristics[j].uuid ){
              console.log("KONASHI_CHARACTERISTICS_ANALOG_READ exist!!");
              KONASHI_CHARACTERISTICS_ANALOG_READ = characteristics[j];
            }
          }

          setInterval(function(){
            // ANALOG_READ
            KONASHI_CHARACTERISTICS_ANALOG_READ.read(function(error, data) {
              if (data) {
                // 実際のジョイスティックの値検知
                var value = (data[1] + data[0]*256)/1000;
                console.log( 'value:' + value );
                // Milkcocoaに送る
                sampleDataStore.push({ player : 'A' , value : value });
              }
            });

          }, 1000);

        });

        services[i].discoverIncludedServices();
      }
    }

  });

  // 機器との接続開始
  peripheral.connect();
});

RaspberryPi 3で内蔵Bluetoothで検出したジョイスティック値をSORACOM経由でMilkcocoaに送信する

Milkcocoaの記録と内蔵Bluetoothで検出したジョイスティック値の連動が出来ました。いよいよ、SORACOMを装着してWifiを関係のない場所でジョイスティックを動かしてみます。

soracom_joystick_value_koshianbit_milkcocoa_record_5

無事、送られています!

soracom_joystick_value_koshianbit_milkcocoa_record_2

Milkcocoa側でも無事記録されています。グイグイ傾いていますね。

soracom_joystick_value_koshianbit_milkcocoa_record_3

FreeBoardで値をグラフ化してみるとより分かりやすくなりました。

soracom_joystick_value_koshianbit_milkcocoa_record_4

おわりに

なかなかレスポンスが良く、BluetoothとSORACOMでのダブルの無線規格によってやや屋外で配線や場所に縛られにくく、複数台のジョイスティックをみんなで動かすようなネタに妄想が膨んできました。

また、GROVEの入力は水センサー・傾きセンサー・タッチセンサーなど面白いセンサーがあるので、そこから取得できるいろいろなデータをSORACOM経由でMilkcocoaに貯めるのも面白そうです。

soracom_joystick_value_koshianbit_milkcocoa_record_1

それではよき SORACOM + KoshianBit + GROVE Joystick + Raspberry Pi3 Lifeを!