myThingsでYahoo!天気から通知を受けた時にベゼリーを踊らせる


はじめに
-------

「[ベゼリー開発キット(BDK)](http://bezelie.com/)」と「[myThings](http://mythings.yahoo.co.jp/)」を連携させてIoTガジェットを作るハンズオンに参加してきました。

マイコンボードは好きなのを用意してくることになっていたのですが、見事にそれぞれ違うボードが集まり興味深かったです。その場では「[Intel Edison](http://edison-lab.jp/edison-arduino/)」を使っている人がいなかったので、やり方をメモしておこうと思います。

![fig1.png](https://qiita-image-store.s3.amazonaws.com/0/34793/ca3d8b70-9c3d-4548-7d49-b6c07a76f83c.png "fig1.png")

準備
----

myThingsはWebサービス同士を連携させるスマホアプリです。例えば、Yahoo!天気とGmailを組み合わせ、朝起きて雪が降っていた場合に「体調不良のため休みます」と会社にメールすることができるかもしれません。

myThingsでは組み合わせに使えるサービスがチャンネルとして登録されています。ベゼリーのようなガジェットと連携させるには「[IDCFチャンネル](http://www.idcf.jp/cloud/iot/)」を使います。

ということで、まずはmyThingsアプリとIDCFクラウドの準備をしておきます。

1. myThingsアプリをスマホにインストール
2. IDCFクラウドにサーバを立てる
3. myThingsアプリでチャンネルの組み合わせを作成しIDCFチャネルに紐付ける

参考
- [myThingsハンズオンの参考資料](http://qiita.com/yamamotomanabu/items/4812d5a5574219eb03af)
- [myThingsをはじめよう](http://www.idcf.jp/cloud/iot/detail01.html)


myThingsとの通信処理
------------------

Edisonで動かすプログラムはNode.jsを使いました。参考にしたのは「[【myThingsハンズオン】○○が☓☓だったら、LEDを光らせよう](http://qiita.com/yamamotomanabu/items/4818906490b0b0d12236)」です。

RaspberryPiの情報ですが、Node.jsなのでIDCFチャンネルとの接続はそのまま使えました。LEDを光らせる部分はEdison用にmraaライブラリを使って書き換える必要があります。

```websocket.js
var meshblu = require('meshblu');
var request = require('request');
var mraa    = require('mraa');

var myOnboardLed = new mraa.Gpio(13);
myOnboardLed.dir(mraa.DIR_OUT);
var ledState = true;

var conn = meshblu.createConnection({
  "uuid": "{action-1のuuid}",
  "token": "{action-1のtoken}",
  "server": "{IDCFのIPアドレス}",
  "port": 80
});

conn.on('ready', function(data){
  console.log('Ready');
  conn.on('message', function(data){
    myOnboardLed.write(1);    
    setTimeout(function(){
      myOnboardLed.write(0);
    }, 2000);

  });
});
```

ソース中の`uuid`と`token`についてはIDCFサーバにログインして、下のコマンドを実行することで調べます。

```
 # docker-compose run --rm iotutil list

 > iotutil@0.0.1 start /app
 > node app.js "list"

 ┌───────────┬──────────┬──────────────────────────────────────┐
 │ keyword   │ token    │ uuid                                 │
 ├───────────┼──────────┼──────────────────────────────────────┤
 ...省略...
 ├───────────┼──────────┼──────────────────────────────────────┤
 │ action-1  │ xxxxxxxx │ xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx │
 ├───────────┼──────────┼──────────────────────────────────────┤
 ...省略...
```

実行するとコンソールにReadyと表示され、myThingsからの通知を待っている状態になります。

```
 $ node websocket.js
 Ready         # IDCFチャンネルと接続できた

```

スマホから作成したmyThingsチャンネルを手動で実行すると、Edisonボード上のLEDが2秒間点灯して消えます。


ベゼリーのサーボモータ制御
----------------------

ハンズオンの時は、サーボの制御がまったくわからず時間切れになってしまいました。適当に信号を流したら、ベゼリーの首がいきなり「ギュンッ」と回って焦りました。

ベゼリーで使用されているサーボは「[SG-90](http://akizukidenshi.com/catalog/g/gM-08761/)」です。PWMで出力するパルス幅を調整することで回転角度をコントロールします。

- 赤: 5V
- 黒: GND
- オレンジ: PWM

ベゼリーには3つのサーボがあり、それらをPWM出力可能な3、5、6番ピンに接続しました。

サーボの制御は「[Johnny-Five](http://johnny-five.io/)」と、Edison用のプラグイン「[edison-io](https://www.npmjs.com/package/edison-io)」を使うと簡単です。SG-90もいい感じに動かすことができました。


```test.js
var five = require('johnny-five');
var Edison = require('edison-io');
var board = new five.Board({
  io: new Edison()
});

board.on('ready', function() {
  // 3番ピンに繋いだサーボを90℃回転させる
  board.servoWrite(3, 90);
});
```

ポイントだったのは、EdisonにACアダプタで給電することです。でないとサーボが動いたときにパワーが足りなくなってボードのリセットが掛かってしまいました。

また、ベゼリーに取り付ける際にサーボホーンを回してしまうと、プログラムから指定した角度と、実際の動きがずれてしまうので気をつけます。


Yahoo!天気から通知を受けた時にベゼリーを踊らせる
-----------------------------------------

サーボの動かし方が分かったので、myThingsと連携させます。
myThingsから15分間隔でメッセージを受け取るとベゼリーが踊ります。

ソースはこちら: [edison-mythings-bezelie](https://github.com/hisaitami/edison-mythings-bezelie)


```main.js
var conf = require('config');
var sleep = require('sleep');

/** required for myThigns */
var meshblu = require('meshblu');
var request = require('request');

/** required for controlling Bezelie with Edison */
var five = require('johnny-five');
var Edison = require('edison-io');
var board = new five.Board({
  io: new Edison()
});

/** define PWM pins */
var pwmPITCH = 3;
var pwmROLL  = 5;
var pwmYAW   = 6;

var moving = false;

board.on('ready', function() {
  var led = new five.Led(13);
  led.blink();

  defaultPosition();

  // connect to IDCF channel server
  var conn = meshblu.createConnection({
    "uuid": "{action-1のuuid}",
    "token": "{action-1のtoken}",
    "server": "{IDCFのIPアドレス}",
    "port": 80
  });
  conn.on('ready', function(data){
    console.log('Ready');

    // let Bezelie dance when receiving a new message
    conn.on('message', function(data){
      console.log(data);
      dance();
    });
  });
});

function defaultPosition() {
  roll(80, 0);
  yaw(80, 700);
  pitch(80, 700);
}

function dance() {
  if (moving) return;

  setTimeout(function() {
    pitch(70, 700);
    for (var i = 0; i < 3; i++) {
      roll(60, 700);
      roll(100, 700);
    }
    defaultPosition();
    moving = false;
  }, 100);
}

function pitch(degree, duration_ms) {
  board.servoWrite(pwmPITCH, degree);
  sleep.usleep(duration_ms * 1000);
}

function roll(degree, duration_ms) {
  board.servoWrite(pwmROLL, degree);
  sleep.usleep(duration_ms * 1000);
}

function yaw(degree, duration_ms) {
  board.servoWrite(pwmYAW, degree);
  sleep.usleep(duration_ms * 1000);
}
```



まとめ
------

通知を受け取って踊るという単純なデモでしたが、通知の内容に応じて動きを変えるなど、いろいろ遊んでみたいと思います。

- Webサービスとロボットを連携させた
- myThingsとEdisonの接続は簡単
- サーボを動かすのは`Johnny-Five`が便利