web socketドロンくん その後-

Post on 05-Dec-2014

1.007 Views

Category:

Documents

3 Downloads

Preview:

Click to see full reader

DESCRIPTION

nodejsを利用し、マイコンを使わずにモータで動くおもちゃを遠隔制御してみる実験。

TRANSCRIPT

WebSocketドロンくん~その後~

『Webアプリによるフィジカルコンピューティング』

SAKURAボードユーザ会 あなたの心もSAKURA色 葉桜の木の下de交流会

2013/4/4

Yuuichi Akagawa

自己紹介

• Yuuichi Akagawa (あかがわ ゆういち)

• USBホストネタ大好き

• 本業は某SI企業でインフラ担当

• 電子工作やプログラミングは趣味での活動

• 仕組みを知ることが好きなので、最終的な作品に至ることがほとんど無い

Copyright©2013 Yuuichi Akagawa 2

OSC2012東京Fallで発表しました

Copyright©2013 Yuuichi Akagawa 3

• WebSocket(Node.js + Socket.IO)を利用した遠隔制御の実験

• Webアプリでフィジカルコンピューティングという提案

• みんなBluetoothでやってるからちょっと斜めで

• 当初はAndroid側をアプリとして実装したものの、後にJavaScriptのみでイケるということに気付く

• 実用性よりも「ネタ」を重視で

• 昨年の東京Node学園祭2012に出せればウケたのに

ちょっとおさらい

Copyright©2013 Yuuichi Akagawa 4

WebSocketとは

• リアルタイムWeb

– 現在多く利用されている、XMLHttpRequest(XHR)によるAjaxポーリングやCometを代表とするロングポーリングではTCPハンドシェイクが都度発生したりHTTPコネクションを長時間占有するなど、Webサーバの負荷が高いという欠点がある。

– これを解決するためにHTML5の一部としてブラウザから直接TCP接続を実現する独自プロトコルの策定が始まった。(現在はHTML5とは独立。RFC6455)

– 2011年末にようやく仕様確定し、メジャーなブラウザでは問題無く利用できる状況にある。

Copyright©2013 Yuuichi Akagawa 5

主要ブラウザのWebSocketサポート状況

プラットフォーム ブラウザ バージョン

Desktop OS Internet Explorer 10以上

Firefox 6以上

Chrome 14以上

Safari 6以上

Opera 12.1以上

Android 標準ブラウザ 未サポート

Chrome 18以上

Firefox 7以上

Opera mobile 12.1以上

iOS Safari 6以上

Copyright©2013 Yuuichi Akagawa 6

ほぼどれでも使える。Android版ChromeはOSが4.0以上で無いと動作しないが、Firefoxであれば2.2以上で使えるので、なんとかなるかと。

Node.jsとは

• サーバサイドJavaScript実行環境

http://nodejs.org

Google V8 JavaScriptエンジン採用

シングルスレッド(JavaScriptだもんね)

イベント駆動(非同期)モデル

nvmというバージョンマネージャやnpmというパッケージマネージャが揃っている

サーバサイドもJavaScriptでコードが書けるのは素敵だと思う

Copyright©2013 Yuuichi Akagawa 7

Socket.IOとは

• クロスプラットフォームリアルタイムWebライブラリ

http://socket.io

Node.js用のライブラリ

サポートプロトコルWebSocketが使えないブラウザでもXHR等に自動フォールバック

• WebSocket

• XHR

• Flash Socket

• JSONP Polling

Copyright©2013 Yuuichi Akagawa 8

Copyright©2013 Yuuichi Akagawa 9

WebSocketドロンくん

ドロンくんとは今岡通博氏考案のAndroid端末による音声認識ロボット。

http://www.ospn.jp/press/20110516no10-useit-oss.html

DTMFによる制御や、ブレッドボードで回路を実装するというお手軽構成。

今回は音声認識の代わりにWebSocket経由でコントロールできるようにしました。

Copyright©2013 Yuuichi Akagawa 10

DTMF (Dual-Tone Multi-Frequency)

• 説明するまでもないとは思いますが、電話の「ピ・ポ・パ」ってやつです

• 正式には「ITU-T勧告Q.24」

• これを4bitのI/Oとして取り出すDTMFデコーダを活用する(2個 ¥300)

高群(Hz)

1209 1336 1477 1633

低群(Hz) 697 1 2 3 A

770 4 5 6 B

852 7 8 9 C

941 * 0 # D

DTMFモータドライバ回路図

Copyright©2013 Yuuichi Akagawa 11

ブレッドボードにちょうど載る規模

Copyright©2013 Yuuichi Akagawa 12

Copyright©2013 Yuuichi Akagawa 13

コマンド送信

HTML5 ready Web Browser(スマホのブラウザでもOK)

Socket.IO module

EC2

コマンド配信(ブロードキャストも可能)

プロトコルはWebSocket

orXHR(Ajax)

DTMF

Node.js + Socket.IOを利用したWebSocketによる遠隔制御

DTMFデコーダ+

モータードライバ

DTMF_0.ogg...

DTMF_#.ogg

Firefox var audio = new Audio(“/sounds/”+file);audio.play()

DTMF音声ファイルダウンロード

サーバサイドコード例

Copyright©2013 Yuuichi Akagawa 14

var express = require('express‘) , routes = require('./routes');

var app = module.exports = express.createServer();

// Configurationapp.configure(function(){

app.set('views', __dirname + '/views');app.set('view engine', 'jade');app.use(express.bodyParser());app.use(express.methodOverride());app.use(app.router);app.use(express.static(__dirname + '/public'));

});

app.configure('development', function(){app.use(express.errorHandler({ dumpExceptions: true, showStack:

true }));});

app.configure('production', function(){app.use(express.errorHandler());

});

// Routesapp.get('/control', function(req, res) {

res.render('control', {title:'Socket.IO Control'});});app.get('/recv', function(req, res) {

res.render('recv', {title:'Socket.IO Receiver'});});

// Socket.IOvar io = require('socket.io').listen(app);var chats = [];var sockets = {};

// broadcast functionfunction broadcast(method,message) {

for (var n in sockets) {sockets[n].emit(method,message);}chats.pop;

}

io.of('/in').on('connection', function(socket) {

sockets[socket.id] = socket;socket.on('control.add', function(data) {

data.time = Date.now();chats.push(data);broadcast('control.add', data);

});socket.on('disconnect', function() {

delete sockets[socket.id];});

});

app.listen(8001);

app.js

これだけでWebサーバとして動作する。

ここがサーバ実装部分

・コネクション受付・データ受信・データ配信全部やってる。

fork()とかpthread_create()とかなにそれって感じ。

操作画面ページコード例

Copyright©2013 Yuuichi Akagawa 15

script(src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js')script(src='/socket.io/socket.io.js')script(type='text/javascript')

// add chat logfunction addlog(data) {var date = new Date(data.time);console.log(date);$('li#log').replaceWith( '<li id="log">' +data.cmd+ ' (' + date.getHours() + ':' + date.getMinutes()+ ':' + date.getSeconds() + ')</li>');

}var socket = io.connect('http://example.com:8001/in');

socket.on('control.add', function(data) {addlog(data);

});function send(data) {socket.emit('control.add', {cmd:data} );return false;

}

h3 WebSocketドロンくんdiv

tabletrtd

input(type='button',class='btn',value='FwdL', onClick='send(1)')td

input(type='button',class='btn',value='Forward', onClick='send(2)')td

input(type='button',class='btn',value='FwdR', onClick='send(3)')trtd

input(type='button',class='btn',value='Turn L', onClick='send(4)')td

input(type='button',class='btn',value='Stop', onClick='send(5)')td

input(type='button',class='btn',value='Turn R', onClick='send(6)')trtd

input(type='button',class='btn',value='BkL', onClick='send(7)')td

input(type='button',class='btn',value='Back', onClick='send(8)')td

input(type='button',class='btn',value='BkR', onClick='send(9)')div

ulli#log

views/control.jade

Express(Webフレームワーク)+ Jade(テンプレートエンジン)を利用。

※http://example.com:8001/controlにアクセスするとこれを返す。

制御用ページコード例

Copyright©2013 Yuuichi Akagawa 16

script(src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js')script(src='/socket.io/socket.io.js')script(type='text/javascript')//DTMF mapvar DTMFtable = [];DTMFtable['1'] = '4';DTMFtable['2'] = '5';DTMFtable['3'] = '1';DTMFtable['4'] = '6';DTMFtable['5'] = 'D';DTMFtable['6'] = '9';DTMFtable['7'] = '8';DTMFtable['8'] = '0';DTMFtable['9'] = '2';//DTMFaudiovar DTMFaudio = null;var SOUND_PATH = "/sounds/";// Get supported sound formatvar AUDIO_EXT = (function(){

var audio = new Audio();var ext = "";if (audio.canPlayType("audio/ogg") == 'maybe') { ext="ogg"; }return ext;

})();//Sound playvar play = function(tone) {

// Get Filenamevar name = 'DTMF_' + DTMFtable[tone];var file_path = SOUND_PATH + name + '.' + AUDIO_EXT;if(DTMFaudio != null){

DTMFaudio.pause();DTMFaudio.currentTime = 0;DTMFaudio = null;

}DTMFaudio = new Audio(file_path);DTMFaudio.play();

};

//Sound playvar play = function(tone) {

// Get Filenamevar name = 'DTMF_' + DTMFtable[tone];var file_path = SOUND_PATH + name + '.' + AUDIO_EXT;if(DTMFaudio != null){

DTMFaudio.pause();DTMFaudio.currentTime = 0;DTMFaudio = null;

}DTMFaudio = new Audio(file_path);DTMFaudio.play();

};

var socket = io.connect('http://176.34.45.101:8009/in');

socket.on('control.add', function(data) {play(data.cmd);

});function send(data) {

socket.emit('control.add', {cmd:data} );return false;

}

h1 HTML5 Delonkun

views/tank.jade ※http://example.com:8001/tankにアクセスするとこれを返す。

今後の予定

• Android端末側

Android端末のカメラの画像をWebSocketで送信して操作画面に表示したい。

音声ファイル再生ではなく、Web Audio APIで自力発音したい。

• サーバ側スクリプト

操作側と操作される側のペアリングを実現したい

Copyright©2013 Yuuichi Akagawa 17

で、それから半年が過ぎた。

Copyright©2013 Yuuichi Akagawa 18

要素技術の動向

• WebRTC (getUserMedia)

Desktop OSでのサポート状況はまずまず

AndroidではChromeβとOpera mobileで利用可能

• Web Audio API

Desktop OSのサポート状況はまずまず

Androidでは未だ使えない

iOSのSafariではサポート→DTMFダイヤラの実装例あり!

Copyright©2013 Yuuichi Akagawa 19

主要ブラウザのサポート状況

プラットフォーム ブラウザ WebScoketAudioのAutoPlay

WebRTCgetUserMedia

Web Audio API

Desktop OS Internet Explorer ○ ○ × ×

Firefox ○ ○ ○ ×

Chrome ○ ○ ○ ○

Safari ○ ○ × ○

Opera ○ ○ ○ ×

Android 標準ブラウザ × × × ×

Chrome ○ × △ ×

Firefox ○ ○ × ×

Opera mobile ○ × ○ ×

iOS Safari ○ × × ○

Copyright©2013 Yuuichi Akagawa 20

2013/4/3現在

主要ブラウザのサポート状況

プラットフォーム ブラウザ WebScoketAudioのAutoPlay

WebRTCgetUserMedia

Web Audio API

Desktop OS Internet Explorer ○ ○ × ×

Firefox ○ ○ ○ ×

Chrome ○ ○ ○ ○

Safari ○ ○ × ○

Opera ○ ○ ○ ×

Android 標準ブラウザ × × × ×

Chrome ○ × △ ×

Firefox ○ ○ × ×

Opera mobile ○ × ○ ×

iOS Safari ○ × × ○

Copyright©2013 Yuuichi Akagawa 21

どちらかが両方サポートされてないと困る。

2013/4/3現在

○○

○×

××

××

×

モバイルでの対応はもう一息

• Desktop OSでは動作可能なレベル

• ○が2つ付いてるブラウザが無いんだな

• Androidはブラウザ毎にWebRTCかAudio APIのどちらかしかサポートされていない

• しかも、Audioのautoplayに対応しているのはFirefoxだけ→その他ブラウザではユーザの介入が必要

Copyright©2013 Yuuichi Akagawa 22

Chromeβ for Androidに実装してみる

• 映像取得処理

getUserMedia()でカメラと接続

カメラからの映像をCanvasに描画

CanvasのデータをtoDataURL()でエンコード

上記で取得したデータをそのままWebSocketで送出

• 音声再生

コマンドに応じて、Audioのsrcにパスを設定

autoplay非対応なので、最初だけ再生ボタンを押す必要あり

Copyright©2013 Yuuichi Akagawa 23

Copyright©2013 Yuuichi Akagawa 24

コマンド送信

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に引っ越し

まとめ

• JavaScriptだけでなんとか画像配信までできた

• なぜか画像がモノクロだけど

• ちょっと荷が重いので高レイテンシーだぞ

• あと半年くらい待てば、Androidでもフル機能がサポートがされるのではないかと期待

• WebRTCがきちんと実装されれば、WebSocetではなくStreaming APIで滑らかな映像配信ができるはず

• 次回はWeb Audio APIでDTMFもね❤Copyright©2013 Yuuichi Akagawa 25

マイコンもコンパイラもいらない

Webアプリでフィジカルコンピューティング

。*:゜☆ヽ(*’∀’*)/☆゜:。*。

Copyright©2013 Yuuichi Akagawa 26

おしまい

Copyright©2013 Yuuichi Akagawa 27

top related