Cylon.jsでBB-8を動かす

# Cylon.jsとは
Cylon.jsはJavascriptから、（2016年5月現在で）43ものハードウェアデバイスをコントロールすることができるフレームワークで、npmモジュールとして提供されています。
[Cylon.js](https://cylonjs.com/)
利用するには

```
$ npm install cylon
```
とするだけ。

対応デバイスもたくさんあります。以下一部抜粋です。

* AR Drone
* Arduino
* Bebop
* Crazyfile
* Imp
* Intel Galileo
* Intel Edison
* Joystick
* Keyboard
* Leap Motion
* MiP
* Nest
* Neurosky
* Philips Hue
* Raspberry Pi
* Sphero
* etc...

# 動かしてみる

実際にCylon.jsでハードウェアデバイスを扱ってみます。

## Keyboard
まずはキーボード。PCのキーボードも当然ハードウェアデバイスです。
とはいっても、もちろんキーボード自体が動くわけではありません。
入力装置として、何かを動かすためのコントローラーとして使うことができそうです。

今回は矢印キーの検出をしてみます。
* 「↑」キー：「UP PRESSED!」と出力
* 「←」キー：「LEFT PRESSED!」と出力
* 「↓」キー：「DOWN PRESSED!」と出力
* 「→」キー：「RIGHT PRESSED!」と出力

※ このエントリーで紹介するコードはここにおいてあります。
https://github.com/donkeykey/bb8_cylon

```js:keyboard.js
var Cylon = require('cylon');

Cylon.robot({
    connections: {
        keyboard: { adaptor: 'keyboard' }
    },

    devices: {
        keyboard: { driver: 'keyboard' }
    },

    work: function(my) {
        my.keyboard.on('up', function(key) {
            console.log("UP PRESSED!");
        });
        my.keyboard.on('down', function(key) {
            console.log("DOWN PRESSED!");
        });
        my.keyboard.on('left', function(key) {
            console.log("LEFT PRESSED!");
        });
        my.keyboard.on('right', function(key) {
            console.log("RIGHT PRESSED!");
        });
    }
}).start();
```

仕様を見るとキーボードの大半のキーをイベントとして扱うことができるようです。（ファンクションキーもOK）

実行してみると、、、

```
$ node keyboard.js
UP PRESSED!
RIGHT PRESSED!
DOWN PRESSED!
LEFT PRESSED!
```

何の問題も無く、キーボードからの入力を検知することができました。
同じようにCylon.jsでは入力装置系のデバイスを扱うことができます。
Leap Motionとか持ってたら試してみたいところです。

## BB-8 （Sphero）
BB-8はスターウォーズ最新作「フォースの覚醒」に登場するロボットで、
Spheroというボール型のラジコンロボットを作っているメーカーが、BB-8のラジコンを作っています。

こいつです。あざとい…
![IMG_0194 のコピー 2.JPG](https://qiita-image-store.s3.amazonaws.com/0/105205/20885f5c-a8f2-ad9f-b2dc-7775b5571da5.jpeg)

BB-8はスマホからBLE通信でコントロールすることができて、専用のアプリから動かすことができるようになっています。
ちなみに「Sphero」として売られているものはBluetooth接続ですが、BB-8はBLE接続です。
Spheroは公式でSDKが公開されているのですが、接続方式の違いによってこのSDKがBB-8では使えないのです。
Cylon.jsではそれまでもSpheroをサポートしていたようなのですが、2016年1月くらいにBB-8にも対応したので、Node.jsからBB-8を動かすことができるようになったのです。

とりあえず動かしてみたいと思います。
以下の動作をする様にコードを書きました。

* 0秒〜 赤く光る & 0°の向きで前進（スピード60%）
* 〜1秒 90°の向きで前進（スピード60%）
* 〜2秒 180°の向きで前進（スピード60%）
* 〜3秒 270°の向きで前進（スピード60%）
* 〜4秒 ストップ & 右回転（スピード100%）
* 〜5秒 左回転（スピード100%）
* 〜6秒 ストップ & ランダムに色を変更

```js:bb8.js
var bb8Key = require('./bb8.json');
var Cylon = require('cylon');

Cylon.robot({
    connections: {
        bluetooth: { adaptor: 'central', uuid: bb8Key.uuid, module: 'cylon-ble'}
    },

    devices: {
        bb8: { driver: 'bb8', module: 'cylon-sphero-ble'},
    },

    work: (my) => {
        my.bb8.color(0xFF0000);
        my.bb8.roll(60, 0);
        after(1000, function() {
            my.bb8.roll(60, 90);
        });
        after(2000, function() {
            my.bb8.roll(60, 180);
        });
        after(3000, function() {
            my.bb8.roll(60, 270);
        });
        after(4000, function() {
            my.bb8.stop();
            my.bb8.spin('right', 100);
        });
        after(5000, function() {
            my.bb8.spin('left', 100);
        });
        after(6000, function() {
            my.bb8.stop();
            my.bb8.randomColor();
        });
    }
}).start();
```

## キーボードからBB-8を動かしてみる
先程のキーボード入力の例と組み合わせて、キーボード入力からBB-8を操作してみます。

操作方法は、以下のようにします。

* 「↑」キー：0°の向きで前進（スピード60%）
* 「←」キー：90°の向きで前進（スピード60%）
* 「↓」キー：180°の向きで前進（スピード60%）
* 「→」キー：270°の向きで前進（スピード60%）
* 「l」キー：左向きに回転（スピード100%）
* 「r」キー：右向きに回転（スピード100%）
* 「c」キー：ランダムにLEDの色を変更
* 「s」キー：停止

コードはこんな感じ。

```js:bb8_keyboard.js
var Cylon = require('cylon');
var bb8Key = require('./bb8.json');
var bb;

Cylon.robot({
    connections: {
        keyboard: { adaptor: 'keyboard' }
    },

    devices: {
        keyboard: { driver: 'keyboard' }
    },

    work: function(my) {
        my.keyboard.on('up', function(key) {
            console.log("UP PRESSED!");
            bb.bb8.roll(60, 0);
        });
        my.keyboard.on('down', function(key) {
            console.log("DOWN PRESSED!");
            bb.bb8.roll(60, 180);
        });
        my.keyboard.on('right', function(key) {
            console.log("RIGHT PRESSED!");
            bb.bb8.roll(60, 90);
        });
        my.keyboard.on('left', function(key) {
            console.log("LEFT PRESSED!");
            bb.bb8.roll(60, 270);
        });
        my.keyboard.on('l', function(key) {
            console.log("L PRESSED!");
            bb.bb8.spin('left', 100);
        });
        my.keyboard.on('r', function(key) {
            console.log("R PRESSED!");
            bb.bb8.spin('right', 100);
        });
        my.keyboard.on('c', function(key) {
            console.log("C PRESSED!");
            bb.bb8.randomColor();
        });
        my.keyboard.on('s', function(key) {
            console.log("S PRESSED!");
            bb.bb8.stop();
        });
    }
}).start();

Cylon.robot({
    connections: {
        bluetooth: { adaptor: 'central', uuid: bb8Key.uuid, module: 'cylon-ble'}
    },

    devices: {
        bb8: { driver: 'bb8', module: 'cylon-sphero-ble'},
    },

    work: (my) => {
        bb = my;
    }
}).start();
```

# おまけ：myThingsからBB-8を動かす
## その１：ボタントリガーを使って動かす
最近myThingsでボタントリガーが使えるようになったので何かに使ってみたかったんです。
ボタントリガー「ボタンが押されたら〜する」というとてもシンプルなトリガーを実装することができます。
今回は「ボタンが押されたらBB-8を動かす」をやってみます。
※ myThingsについてはこちらのエントリーでも詳しく説明しています。
[ESP8266を使ってmyThings連携して今日の降水確率をLEDの色で表現してみる](http://qiita.com/dkawashi/items/595de3cf9f21927360b7)

まずはボタンが押されたということをIDCF上のMQTTブローカーにpublishするために
スマホのアプリ上から設定をします。
以前のエントリーでIDCF上にMQTTブローカーを構築済み＆myThingsと連携済みなのでここはすんなりです。

次にnodeからpublishされたメッセージをsubscribeするように実装し、メッセージを受信したらCylon.jsでBB-8を動かします。
BB-8の挙動は先程のbb8.jsと同じです。

```js:bb8_myThings_button.js
var myThingsKey = require('./myThingsKey.json');
var bb8Key = require('./bb8.json');
var meshblu = require('meshblu');
var Cylon = require('cylon');
var conn1 = meshblu.createConnection(myThingsKey[0]);
var bb;

Cylon.robot({
    connections: {
        bluetooth: { adaptor: 'central', uuid: bb8Key.uuid, module: 'cylon-ble'}
    },

    devices: {
        bb8: { driver: 'bb8', module: 'cylon-sphero-ble'},
    },

    work: (my) => {
        bb = my;
    }
}).start();

conn1.on('ready', function(data){
    console.log('Ready1');

    conn1.on('message', function(data){
        console.log(data);
        bb.bb8.color(0xFF0000);
        bb.bb8.roll(60, 0);
        after(1000, function() {
            bb.bb8.roll(60, 90);
        });
        after(2000, function() {
            bb.bb8.roll(60, 180);
        });
        after(3000, function() {
            bb.bb8.roll(60, 270);
        });
        after(4000, function() {
            bb.bb8.stop();
            bb.bb8.spin('right', 100);
        });
        after(5000, function() {
            bb.bb8.spin('left', 100);
        });
        after(6000, function() {
            bb.bb8.stop();
            bb.bb8.randomColor();
        });
    });
});
```

## その2：天気情報をBB-8のLEDの色と連携させる
今日の降水確率をBB-8のLEDの色で表現したいと思います。
降水確率が0%に近いと緑っぽく、100%に近いと青っぽくなるようにします。
コレが実現できれば家で静かに眠っていたBB-8のラジコンが、myThingsと連携することで本物のBB-8のように人間の生活を助けるロボットに近づけることができます。
hueのように輝度はないですが同じようにフルカラーのLEDを積んでるし、動作で情報を伝えるなんてこともできます。
なんといってもかわいいのでhueより良いかもしれません。

コードはこんな感じです。
myThingsから今日の天気情報を取得し、メッセージ内に降水確率を含むように設定しているので
送られてきたjsonのデータをパースして数字を読み取ってカラーコードに変換しているという流れです。

```js:bb8_myThings_weather.js
var myThingsKey = require('./myThingsKey.json');
var bb8Key = require('./bb8.json');
var meshblu = require('meshblu');
var Cylon = require('cylon');
var conn3 = meshblu.createConnection(myThingsKey[2]);
var bb;

function colorGen (col) {
    var c = col.match(/\d+/g).map(function(a){return ("0" + parseInt(a).toString(16)).slice(-2)}).join("");
    return parseInt(c, 16);
}

Cylon.robot({
    connections: {
        bluetooth: { adaptor: 'central', uuid: bb8Key.uuid, module: 'cylon-ble'}
    },

    devices: {
        bb8: { driver: 'bb8', module: 'cylon-sphero-ble'},
    },

    work: (my) => {
        bb = my;
    }
}).start();

conn3.on('ready', function(data){
    console.log('Ready3');

    conn3.on('message', function(data){
        console.log(data.payload);
        var b = Math.floor(Number(data.payload) * (255/100));
        var g = Math.floor(255 - b);
        var r = 0;
        var rgb = "rgb(" + r + ", " + g + ", " + b + ")";
        console.log(rgb);
        bb.bb8.color(colorGen(rgb));
    });
});
```
テレビの横とかにBB-8置いて自然に目に入ってくるようにしておきたいので、Raspberry PiとかでnodeとCylon.jsインストールして置いておきたいです。

# ホントはコレもやりたかった
MYOというアームバンド型のデバイスをつかうと、筋電情報を計測して手の動きをセンシングできる。
「手を広げる」という動きを検知できるようなので、腕を前に伸ばして手を広げるとBB-8が動く、
とか、まるでフォースでBB-8を動かしているようなことがしたかったのですがうまくいかず、、、