こんにちは、ガジェット好きなエンジニアののびすけです。
みなさんは、映画『スター・ウォーズ』の最新作『スター・ウォーズ/フォースの覚醒(エピソード7)』をもう見ましたか? ファン待望の続編が昨年12月18日に全世界で封切りされてから、ものすごい盛り上がりを見せましたよね。最近やっと熱気が落ち着いてきた気がします。
僕も12月に見てきましたが、かなり面白かったです。2016年2月上旬の今でもまだ放映しているみたいなので、見ていない方はぜひ映画館へ行ってみてください! ネタバレは良くないので本編の内容は書きません!(笑)
前段はこれくらいにして、今日はJavaScriptを使い、エピソード7に新しく登場したドロイド「BB-8」をプログラムから制御してみたいと思います。
BB-8とは?
BB-8は『スター・ウォーズ/フォースの覚醒(エピソード7)』で初登場したドロイド(ロボット)です。従来の『スター・ウォーズ』シリーズで登場するドロイドといえば、C-3POやR2-D2が代表的でした。エピソード7では心機一転して新型ドロイドのBB-8が登場し、その可愛らしい姿からかなりの人気を博しています。
そんなBB-8ですが、なんとAmazonで購入することができます。
劇中のBB-8は人間の膝上ほどのサイズですが、販売されているBB-8は手の平サイズの小型でになっています。スマートフォンと連携して操作できるので、ラジコンのような感覚で扱うことができるんです。
一時は3万円くらいの値段でしたが、最近は2万円弱まで値下がりしたようです。
BB-8はどうやって作られたの?
『スター・ウォーズ』の世界から離れて現実世界の話に移ります。BB-8はSphero Japanが販売しているロボティクスボール「Sphero」というプロダクトが元となっています。
ロボティクスボール「Sphero」とは
「Sphero」とは、Sphero社が販売しているロボティクスボールです。ロボティクスボールが何なのかと言われると実は明確な答えがないのですが、スマホで操作可能なボール型のおもちゃという認識を持ってもらえれば大丈夫です。
こちらの「Sphero」の紹介動画を見ると雰囲気をつかみやすいかと思います!
つまり、BB-8はSpheroなの?
スターウォーズに登場するBB-8はSpheroと同じ機構を採用していて、実際に映画内で登場するBB-8も原点を辿るとSpheroなんだそうです。
確かに、改めて見てみると、Spheroに頭が付くとBB-8になるのが分かりますね。
今回つかうのは「Cylon.js」!
少し話は変わりますが、最近JavaScriptでロボットやマイコンボードなどのハードウェアを制御しようという動きの「JavaScript Robotics」という言葉が最近流行ってきています。Node.jsからさまざまなハードウェアを制御できるライブラリとして有名です。
余談ですが、僕も過去にJavaScriptがだいすきな男たちが集まるイベント「JSオジサン」で「Cylon.js」について発表しているので、よかったら上記スライドをご覧になってみてください。概要がつかめるかと思います。
Cylon.jsはSphero対応している
Cylon.jsはさまざまなガジェットやマイコンボードの制御に対応しているのですが、今回の記事に登場した「Sphero」にも対応しています。BB-8はSpheroが元になっているという話を先ほどしましたが、発売時からBB-8をCylon.jsで動かせないかなと思っていました。
実際に手元に届いてから試そうとしたところ、通信方式の違いでBB-8には非対応になっていました。 ところが先月(2016年1月)に対応されて、Node.jsからBB-8を制御することができるようになったんです。
https://github.com/orbotix/sphero.js/issues/26
Githubではこんなissueも立っていて、みんな待ち望んでいたと分かります。
僕が毎月主催しているイベント「#IoTLT」のvol.11で話をしてきたので、そのときLTしてきた資料も掲載します。タイミングから考えておそらくBB-8をJavaScriptで動かしたLTをしたのは日本で初めてだったと思います。
BB-8をブラウザから動かしてみよう!
さてさて話が長くなりましたが、BB-8はJavaScript制御ができるんです。では、実際に動かしてみましょう!
ざっくりとした構成図
BB-8はBLE(Bluetooth Low Enegy)でスマートフォンと連携しています。今回はMac上のNode.js+Cylon.jsでBLEを使いBB-8を制御した上で、Milkcocoaを使いブラウザとの連携もしてみようと思います。
最終的にはブラウザからBB-8を動かせるようにします。
のびすけ(執筆者)の環境
動作しないときの参考にしてみて下さい。
下準備
BB-8の制御にはBLEを使う必要があるのですが、BLEはけっこう難しいので全てを覚える必要はありません。
参考までに僕が作成したスライドを載せます。
$ npm i -g cylon-ble
まず
UUID
というデバイスの識別番号のようなIDを調べる必要があります。cylon-ble
というパッケージをnpm経由でグローバルインストールしましょう。$ npm i cylon-sphero-ble
また、SpheroやBB-8を扱うために
cylon-sphero-ble
をインストールしておきます。cylon-ble
のインストールが完了するとcylon-ble-scanコマンド
が使えるようになります。MacのBluetoothをオンにすることを忘れずに!sudo
で管理者権限としてコマンドを実行する必要があります。$ sudo cylon-ble-scan sudo cylon-ble-scan Password: Starting scan. Peripheral discovered! Name: undefined UUID: 28f97a8aeb034db4b82c0c3e960fc09e rssi: -85 Peripheral discovered! Name: undefined UUID: bdc6a5526bc24d6f850d47ecccc86ca0 rssi: -48 Peripheral discovered! Name: undefined UUID: 10a279a9999d464291b3ab00a4f5e3c1 rssi: -81 Peripheral discovered! Name: BB-XXXX UUID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx rssi: -57 ・ ・ ・ ・
Macがある場所を中心に周辺のデバイスが持っている
UUID
が一覧として表示されます。ここで表示されるName
には製品名が入ってくることが多いので、Name
の値でデバイスを判断すると良いです。BB-XXXX
のような名前を見つけたら、その下のUUID
を探します。xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
と書いたところが、今回の目当てのBB-8のUUID
になります。サンプルコードを動かしてみる
こちらにBB-8向けのサンプルコードが掲載されています。Spheroとは若干書き方が異なるので注意しましょう。
//app.js 'use sctrict' let Cylon = require('cylon'); Cylon.robot({ connections: { bluetooth: { adaptor: 'central', uuid: 'さっき見つけたUUIDをここに記述', module: 'cylon-ble'} }, devices: { bb8: { driver: 'bb8', module: 'cylon-sphero-ble'} }, work: (my) => { my.bb8.color(0x00FFFF); //BB-8のライトを水色に after(1000, () => { my.bb8.color(0xFF0000); //BB-8のライトを赤に }); after(3000, () => { my.bb8.roll(60, 0); //60のスピードで回転 }); after(2000, () => { my.bb8.roll(60, 180); //60のスピードで回転、180度ターン(?) }); after(3000, () => { my.bb8.stop(); //停止 }); } }).start();
MacとBB-8のコネクションが確立した後に、
work
で定義しているメソッドが実行されます。このサンプルコードだと、水色に光らせた後に1秒後に赤になり3秒後に移動……のような流れになります。さっそく実行してみましょう。$ node app.js
キター!! 動きましたね!
Cylon.jsとMilkcocoa連携
その次に、Cylon.jsとMilkcocoaを連携させてみましょう。
Milkcocoaはリアルタイム通信やIoTデバイスとの連携を簡単に実装できるサービス・ライブラリです。Milkcocoaのサイトからユーザー登録とアプリ登録をすればアプリIDを取得できます。基本的に無料で利用可能です。では、MilkcocoaのSDKを追加してみましょう。
$ npm i milkcocoa
先ほどの
app.js
にMilkcocoaに送られてくるデータとCylon.jsを連携させて書いてみます。Milkcocoaでは一つのクライアントがsendメソッド
を用いてMilkcocoaのサーバーにデータを送ることで、待ち受けしている別のクライアントにリアルタイムに情報を共有することができます。ds.on('send')
と書くことで待ち受けすることができます。//app.js 'use strict'; let Cylon = require('cylon'); let MilkCocoa = require('milkcocoa'); let milkcocoa = new MilkCocoa('<MilkcocoaのアプリID>.mlkcca.com'); let ds = milkcocoa.dataStore('bb8'); Cylon.robot({ connections: { bluetooth: { adaptor: 'central', uuid: 'さっき見つけたUUIDをここに記述', module: 'cylon-ble'} }, devices: { bb8: { driver: 'bb8', module: 'cylon-sphero-ble'} }, work: (my) => {main(my)} }).start(); function main(my){ ds.on('send', (sended) => { if(sended.value.v === 'red'){ console.log('red'); my.bb8.color(0xFF0000); } if(sended.value.v === 'green'){ console.log('green'); my.bb8.color(0x00FF00); } if(sended.value.v === 'blue'){ console.log('blue'); my.bb8.color(0x0000FF); } if(sended.value.v === 'forward'){ console.log('forward'); my.bb8.roll(60, 0); } }); }
v
というキーに対してred
という値が送られてきたらmy.bb8.color(0xFF0000);
でライトを赤くする、といった処理になります。Milkcocoa連携したブラウザ側のコントローラを作ってみる
これでBB-8側の準備はOKです。次はブラウザ側のコントローラを作ってみましょう。
http://stanko.github.io/skyblue/
サクッと作るために SkyBlueというCSSフレームワークを使ってみます。
こんな雰囲気のコントローラを作りました。ブラウザ側のJavaScriptコードはこうなっています。//controller.js var milkcocoa = new MilkCocoa('<MilkcocoaのアプリID>.mlkcca.com'); var ds = milkcocoa.dataStore('bb8'); $('.icon-angle-up-circle').on('click',function(){ ds.send({v:'forward'}, (err, sended) => { console.log(sended); }); }); $('.icon-angle-down-circle').on('click',function(){ ds.send({v:'back'}, (err, sended) => { console.log(sended); }); }); $('#red').on('click',function(){ ds.send({v:'red'}, (err, sended) => { console.log(sended); }); }); $('#green').on('click',function(){ ds.send({v:'green'}, (err, sended) => { console.log(sended); }); }); $('#blue').on('click',function(){ ds.send({v:'blue'}, (err, sended) => { console.log(sended); }); });
jQuery周りのコードの説明は割愛します。
//controller.js (ブラウザ側) ・ (省略) ・ ・ ds.send({v:'forward'}, (err, sended) => { console.log(sended); }); ・ ・ (省略) ・
Milkcocoaの使い方は
ds.send({v:'forward'}
でv
のキーに対して'forward'という値を送ることができます。
//app.js (Node.js側) ・ (省略) ・ ・ if(sended.value.v === 'forward'){ console.log('forward'); my.bb8.roll(60, 0); } ・ ・ (省略) ・
Node.js側では
forward
を受け取ったことを検知してBB-8へ命令を送ります。いよいよブラウザからBB-8を動かす!
説明はこんなところで、実際に動かしてみましょう。
$ node app.js 2016-02-03T09:56:18.749Z : [Robot 1] - Starting connections. 2016-02-03T09:56:18.752Z : [Robot 1] - Starting connection 'bluetooth'. 2016-02-03T09:56:22.179Z : [Robot 1] - Starting devices. 2016-02-03T09:56:22.180Z : [Robot 1] - Starting device 'bb8'. 2016-02-03T09:56:23.505Z : [Robot 1] - Working. ・ ・ ・
・
・
・
・
・
ブラウザからBB-8制御で遊ぶ n0bisukeさん(@n0bisuke)が投稿した動画 -
はい! これでブラウザからBB-8を制御することができました!!
まとめ
『スター・ウォーズ』ファンなら、BB-8がプログラミング制御できるなんてかなり胸アツですよね。
Cylon.jsでBLEデバイス制御をしてMilkcocoaでWebとつなげる組み合わせはいろいろなデバイスに応用できると思います。ハードウェアをWebエンジニアがJavaScriptで制御する敷居もだんだん下がってきた気がしますね。
ぜひ一度試してみて下さい。それでは!
おまけ
BB-8とSpheroを同時に動かしてみました。