javascriptでいいじゃなイカ
DESCRIPTION
ADK BOOTCAMP#3 ASAKUSAで発表した資料です。TRANSCRIPT
JavaScriptでいいじゃなイカ『Webアプリによるフィジカルコンピューティング』
ADK BOOTCAMP #3 ASAKUSA2013/5/26
Yuuichi Akagawa
JavaScriptでいいじゃなイカWebアプリによるフィジカルコンピューティング
自己紹介
• Yuuichi Akagawa (あかがわ ゆういち)
• USBホストネタ大好き
• 本業は某SI企業でインフラ担当
• 電子工作やプログラミングは趣味での活動
• 仕組みを知ることが好きなので、最終的な作品に至ることがほとんど無い
Copyright©2013 Yuuichi Akagawa 2
気分転換に
Copyright©2013 Yuuichi Akagawa 3
• たまにはADK/USB以外のネタでも
• がじぇるねでマイコンはおなかいっぱいだし
• Androidアプリ書く気力も無いし
• コンパイルしたりデバイスに転送したりは面倒だし
• 気晴らしにNode.jsで遊んでみたら意外と面白かった
• HTML5 + JavaScriptだけでも結構イケる
※Titanium MobileとかPhoneGapの話ではないでゲソ
Copyright©2013 Yuuichi Akagawa 4
WebSocketドロンくん
ドロンくんとは今岡通博氏考案のAndroid端末による音声認識ロボット。
http://www.ospn.jp/press/20110516no10-useit-oss.html
DTMFによる制御や、ブレッドボードで回路を実装するというお手軽構成。
音声認識の代わりにWebSocket経由でコントロールできるようにしてみた。
WebSocketドロンくん
Copyright©2013 Yuuichi Akagawa 5
• Node.js + Socket.IOを利用した遠隔制御の実験
• Webアプリでフィジカルコンピューティングという提案
• みんなBluetoothでやってるからちょっと斜めで
• 実用性よりも「ネタ」を重視で(レイテンシー大なの)
• WebRTCの実装が進み、JavaScriptでカメラの画像も取得できちゃう
• しかもマイコンいらない
DTMFモータドライバ回路図
Copyright©2013 Yuuichi Akagawa 6
ブレッドボードにちょうど載る規模
Copyright©2013 Yuuichi Akagawa 7
Copyright©2013 Yuuichi Akagawa 8
コマンド送信
HTML5 ready Web Browser(スマホのブラウザでもOK)
Socket.IO module
さくらのVPS
コマンド配信
DTMF
WebSocketを利用したJavaScriptによる遠隔制御
DTMFデコーダ+
モータードライバ
DTMF_0.ogg...
DTMF_#.ogg
Chrome for Android
DTMF音声ファイルはキャッシュマニフェストを利用してローカルに保存
キャプチャ画像送信
キャプチャ画像配信
WebRTCを利用して内蔵カメラからの映像を取得する
急激な円安進行により、AWSが割高になったのでさくらのVPSに引っ越し
コマンドに対応した
音声ファイルを再生
Chromeβ for Androidに実装してみた
• 映像取得処理
getUserMedia()でカメラと接続
カメラからの映像をCanvasに描画
CanvasのデータをtoDataURL()でエンコード
上記で取得したデータをそのままWebSocketで送出
• 音声再生
音声ファイルは初回アクセス時にローカル保存
コマンドに応じて、Audioのsrcにパスを設定
autoplay非対応なので、最初だけ再生ボタンを押す必要あり
Copyright©2013 Yuuichi Akagawa 9
Chromeβ for Androidに実装してみた
• こんな感じ
Copyright©2013 Yuuichi Akagawa 10
スマホのカメラの映像がここに表示されている
サーバサイドコード例
Copyright©2013 Yuuichi Akagawa 11
var express = require('express'), app = express(), path = require('path'), http = require('http'), server = http.createServer(app), io = require('socket.io').listen(server);
// Configurationapp.configure(function(){
app.set('views', __dirname + '/views');app.set('view engine', 'jade');app.use(express.favicon());app.use(express.bodyParser());app.use(express.methodOverride());app.use(app.router);app.use(express.static(path.join(__dirname, 'public')));app.disabled('view cache');
});
app.configure('production', function(){app.use(express.errorHandler());io.set('log level', 1);
});// Routesapp.get('/controlv', function(req, res) {
res.render('controlv', {title:'Socket.IO Control'});});app.get('/tankv', function(req, res) {
res.render('tankv', {title:'HTML5 Delonkun'});});
// Socket.IOvar sockets = {};// broadcast functionfunction broadcast(method,message) {
for (var n in sockets) {sockets[n].emit(method,message);}
}
io.of('/in').on('connection', function(socket) {
sockets[socket.id] = socket;socket.on('control.add', function(data) {
data.time = Date.now();broadcast('control.add', data);
});socket.on('control.video', function(data) {
broadcast('control.video', data);});socket.on('disconnect', function() {
delete sockets[socket.id];});
});
server.listen(8009);
app.js
これだけでWebサーバとして動作する。
ここがサーバ実装部分
・コネクション受付・データ受信・データ配信全部やってる。
操作画面ページコード例
Copyright©2013 Yuuichi Akagawa 12
socket.on('control.video', function(data) {var img = document.getElementById('camera_image1');img.src = data.video;
});
divimg#camera_image1(src='')
画像表示周り抜粋
制御用ページコード例
Copyright©2013 Yuuichi Akagawa 13
divvideo#camera(width='160', height='120', autoplay)canvas#camera_canvas(style='display:none;', width='160', height='120')
映像配信部分抜粋
$(function(){navigator.getMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||navigator.mozGetUserMedia ||navigator.msGetUserMedia );
var video = document.getElementById('camera');var canvas = document.getElementById('camera_canvas');var ctx = canvas.getContext('2d');var image1 = document.getElementById('camera_image1');navigator.getMedia ({ video:true, audio:false }, function(stream) {
video.src = window.URL.createObjectURL(stream);}, function(err){console.log(err);});
setInterval(function(){if(navigator.getMedia){var canvas_image = ctx.drawImage(video,0,0,160,120);canvas_image = ctx.getImageData(0, 0, 160, 120);ctx.putImageData(canvas_image, 0, 0);var dataURL = canvas.toDataURL("image/octet-stream");socket.emit('control.video', {video:dataURL});
}, 500);
マイコンと一緒
Copyright©2013 Yuuichi Akagawa 14
マイコンと一緒
Copyright©2013 Yuuichi Akagawa 15
• DTMFだけでは限界が…
• やっぱりマイコンも使おう
• 接続方法はお手軽なUARTで決まり!(無線化はXBeeで)
• マイコンでTCP/IPとか扱うの面倒でしょ。そういうのは汎用OSにお願いしよう。
Raspberry PiでNode.js
Copyright©2013 Yuuichi Akagawa 16
• Linuxだから当たり前の様に動く
• だけど、非力なのでビルドに時間かかる
• インストールは以下の手順で$ git clone git://github.com/creationix/nvm.git ~/.nvm
$ . ~/.nvm/nvm.sh
$ nvm install v0.8.23
$ echo '. ~/.nvm/nvm.sh' >> ~/.bashrc
$ echo 'nvm use v0.8.23' >> ~/.bashrc
node serialport
Copyright©2013 Yuuichi Akagawa 17
• Node.jsでシリアルポートが使えるhttps://github.com/voodootikigod/node-serialport
• インストールはnpmで
• これだとちょっとプリミティブすぎるので…
$ npm install serialport
node firmata
Copyright©2013 Yuuichi Akagawa 18
• Firmataが使えるよhttps://github.com/jgautier/firmata
• こちらもnpmでインストール可能$ npm install firmata
var ledPin = 5;var firmata = require('firmata');
var board = new firmata.Board('/dev/ttyUSB0', function(err) {if (err) {
console.log(err);return;
}var ledOn = true;board.pinMode(ledPin, board.MODES.OUTPUT);setInterval(function(){
if (ledOn) {board.digitalWrite(ledPin, board.HIGH);
}else {
board.digitalWrite(ledPin, board.LOW);}ledOn = !ledOn;
},500);});
スタンドアローンなLチカ
RPi + Arduino
Copyright©2013 Yuuichi Akagawa 19
• Raspberry PiにArduino繋げてFirmataで制御(スクリプトは前ページのもの)
Cloud9 IDE
Copyright©2013 Yuuichi Akagawa 20
• Node.jsに対応したJavaScript統合開発環境https://c9.io/https://github.com/ajaxorg/cloud9
• BeagleBoneは標準装備
PCでもNode.js
Copyright©2013 Yuuichi Akagawa 21
• わざわざワンボードPC買わなくても、手元のPCでNode.jsを動作させれば良い
• 公式サイトでWindowsやMac OS X用のバイナリを配布してる
• でもWindowsは(ry
Webブラウザ✕マイコン
Copyright©2013 Yuuichi Akagawa 22
chrome.serial
Copyright©2013 Yuuichi Akagawa 23
• Google Chrome Appでシリアルポートが使える
chrome.serial
Copyright©2013 Yuuichi Akagawa 24
• manifest.jsonでパーミッションを与える
• こんな感じで動く
"permissions": ["serial"],
chrome.usb
Copyright©2013 Yuuichi Akagawa 25
• USBホストも使える(ADKは作らないよ)
chrome.bluetooth
Copyright©2013 Yuuichi Akagawa 26
• Bluetoothも使えるようになるらしい
と、いうわけでJavaScriptでやってみなイカ?
Copyright©2013 Yuuichi Akagawa 27
おしまい
Copyright©2013 Yuuichi Akagawa 28