web版lindaによる実世界コンピューティング
DESCRIPTION
プログラミングシンポジウム2014夏の発表資料です 発表時の内容に加えて、質疑応答やtwitterでの反応への返答なども含めて更新しています。TRANSCRIPT
Web版Lindaによる
実世界コンピューティング
@shokai
プログラミングシンポジウム 2014夏
自己紹介
•@shokai
•橋本 翔
•慶應SFC増井研
実世界コンピューティングとは
電子工作とかセンサーとか使うやつのこと
(大雑把に言うと)
実世界コンピューティングとWebを接続したい
色んな言語・デバイスで接続したい 安定して動かして毎日使いたい 常に拡張しやすくしておきたい
!
という便利ツールが出来たので紹介する発表に来ました
Lindaとは?
Lindaとは?•プロセス間の共有メモリでデータを読み書きして並列・分散処理する
• 1990年ごろ流行った、らしい • out (書き込み) • rd (読み出す)、rdp (ノンブロックで読み出す) • in (読み出しつつ削除)、inp (ノンブロックで削除) • だけで大抵の処理が書ける
Tuple Space Tuple
Lindaとは?(2)TupleSpace["買い物", "牛乳"]
["user", "shokai"]["買い物", "鳥肉"]
Tuple["買い物", "卵"]
書き込み
["買い物", "肉"]
読み出し
• TupleSpaceにTupleを読み書きする •配列の前方一致で読み出す • [“買い物"] で読みだすと、どれかが取れる
何でも書き込める
Tuple
Lindaとは?(3)•既存の実装 • C、Java、Ruby、Python、Lua、Erlangなどで実装されている
•画像処理のパイプライン等 !
•それぞれプロトコルが違うので相互接続できない問題がある
Node.js + Socket.IO でLindaを作った
https://npmjs.org/linda
元々Rubyで実装していたが 疲れたのでNodeにした
インストール
% npm install linda -g
-gでグローバルインストールすると 実行コマンドも入って便利!
Linda使用例
研究室間 センサ情報通知
•1. 照度センサTuple • 2. 明るくなった/暗くなったTuple
• 3. Sayしろ/Yoしろ/チャットに通知しろTuple
• 増井研、部屋が分かれてるので一体感を出したい • shokai自宅も参加している
という風にTupleの読み書き連鎖で連動する
近づいたらドアが開く•0. iBeaconで接近検知 • 1. 誰がどこにいるかTuple • 2. ドア開けろTuple • 3. サーボ回しましたTuple • 4. sayしろ/チャット通知しろTuple
iBeaconから直接ドア開け しないので 拡張しやすい
チャットでも見れる
起きたら通知•0. 起きる • 1. Jawbone UP24で睡眠Tupleを書き込み
• 2. チャット通知Tuple !
•寝坊したら起こしてもらえる可能性高い
Terminalで作業→Hue電球
•0. shellのヒストリ追う • 1. 作業したTuple、git commitしたぞTuple等
• 2. Hueを少し色変える • 3. 何もしてないと段々暗くなる
俺がプログラミングがんばってる感が自宅に伝わる
階層型コンテンツビューア
階層型コンテンツビューア
ダイヤル パドル
ハードウェアとWebアプリの接続
BabaScript
結果
プログラム
人間を関数呼び出しできるDSL
多いので省略
Node-Lindaで
プログラミング
linda-server% npm install linda -g% linda-server
ローカルでサーバー起動
http://localhost:8931で起動する
Herokuに新しくlindaサーバー作る (無料)
READMEの ボタンから作れる https://github.com/node-linda/linda
白菜が好き
SFCのdelta棟から 流れているTupleが見える
http://linda-server.herokuapp.com/delta
ブラウザからTuple書き込める
ダミーデータ流せるので開発時に便利
接続クライアント (Node.js)var LindaClient = require('linda').Client;var socket = require(‘socket.io-client’).connect("http://localhost:8931");var linda = new LindaClient().connect(socket);
• socket.ioは接続切れても自動的に繋ぎ直したりしてくれて便利 • Node、ブラウザJS、Ruby、Android用などのクライアントライブラリがある
•最近Socket.IOを1.0.に上げたらiOS用が動かなくなった…
接続
クライアント (ブラウザJS)<script src="http://localhost:8931/socket.io/socket.io.js"></script><script src="http://localhost:8931/linda/linda.js"></script>
var socket = io.connect("http://localhost:8931");var linda = new Linda().connect(socket);
接続
クライアント (Ruby)require 'linda-socket.io-client'!linda = Linda::SocketIO::Client.connect 'http://localhost:8931'
接続
クライアント (Android Java)https://github.com/node-linda/linda-socket.io-client-java
Node-LindaのTuple操作
•write • read • take • watch • の4つだけ
writevar ts = linda.tuplespace("foo");ts.write({"type":"sensor", "name":"明るさ", "value": 1234});
{"type":"sensor", "name":"明るさ", "value": 1234}
{"type":"sensor", "name":"明るさ", "value": 1234}
書き込み
{"type":"sensor", "name":"明るさ", "value": 1400}
{"type":"sensor", "name":"温度", "value": 1400}
TupleSpace
Tuple
• Tuple = JSONシリアライズできるオブジェクト • 10分ぐらいで消える、expireプロパティで指定可能
readvar ts = linda.tuplespace("foo");ts.read({"type":"sensor", "name":"明るさ"}, function(err, tuple){ console.log(tuple.data); console.log(tuple.from);});
{"type":"sensor", "name":"明るさ", "value": 1234}
{"type":"sensor", "name":"明るさ", "value": 1400}
{"type":"sensor", "name":"温度", "value": 1400}
TupleSpace
オブジェクトの部分一致
• callbackなので、matchする物が無かったら現れるまで待つ •先にreadしておいて、後からwriteされても読める
{"type":"sensor", "name":"明るさ", "value": 1234}
{"type":"sensor", “name”:"明るさ"}に部分一致する物を1つ読み出し
take (削除しつつread)var ts = linda.tuplespace("foo");ts.take({"type":"sensor", "name":"明るさ"}, function(err, tuple){ console.log(tuple.data); console.log(tuple.from);});
{"type":"sensor", "name":"明るさ", "value": 1400}
{"type":"sensor", "name":"温度", "value": 1400}
TupleSpace
•読んだTupleは削除される{"type":"sensor", "name":"明るさ", "value": 1234}
{"type":"sensor", “name”:"明るさ"}で1つだけ読み出し
{"type":"sensor", "name":"
watch (監視)var ts = linda.tuplespace("foo");ts.watch({"type":"sensor", "name":"明るさ"}, function(err, tuple){ console.log(tuple.data); console.log(tuple.from);});
TupleSpace
• pub-sub が簡単に作れる{"type":"sensor", "name":"明るさ", "value": 1234}
{"type":"sensor", "name":"明るさ", "value": 1234}
writeした瞬間に
{"type":"sensor", “name”:"明るさ"}にマッチするTupleがすぐ出てくる
{ ~~~~ }{ ~~~~ } { ~~~~ }
cancelvar ts = linda.tuplespace("foo");var cid = ts.take({"type":"sensor", "name":"明るさ"}, function(err, tuple){ console.log(tuple.data);});!/** 2秒待って、take出来なかったらキャンセル **/setTimeout(function(){ ts.cancel(cid);}, 2000);
• read, take, watchを中止できる
•元祖Lindaのブロックしないread/takeは、Tupleが無ければnullが返るので、無ければ~~というコード書いたりする。しかしJavaScriptではブロックするコード書けない
• cancelで同等の事ができる
昨年実装したRuby版Lindaには「tupleが無ければすぐnullを返すread/take」があったのだが、cancelで同等の事ができるので機能削除した。
これによりクライアントライブラリの実装が小さくなり、Rubyは114行、jsは86行で済むようになった。クライアントライブラリ作りやすくする為に仕様を小さくするのは色々な言語で使えるために重要。
ドア開けるプログラム例ts = linda.tuplespace('delta')!linda.io.on 'connect', ->! ## watchで監視 ts.watch {type: 'door', cmd: 'open'}, (err, tuple) -> return if err or tuple.data.response? door_open_throttled -> res = tuple.data res.response = 'success' ts.write res ## 開けましたよ、とレスポンス!## ドア開ける関数door_open = (onComplete = ->) -> arduino.servoWrite 9, 0 # Arduinoのサーボ回す setTimeout -> arduino.servoWrite 9, 180 # サーボ戻す onComplete() , 2000!## ドア開ける関数をunderscoreで5秒にthrottleするdoor_open_throttled = _.throttle door_open, 5000, trailing: false
Tupleの例
温度センサーが毎秒流すTuple
{ "type": "sensor”, "name": "temperature", "value":25.6 }
人が来た
{ "type": "region", "action":"enter", "who": "shokai" }
人が去った
{ "type": "region", "action":"leave", "who": "shokai" }
ドア開けリクエスト
{ "type":"door", "cmd": "open", "who": "shokai" }
ドア開け成功
{ "type":"door", "cmd": "open", "who": "shokai", "response": "success" }
Tuple設計の知見•Tupleのプロパティに色々書いておくと柔軟になる。
•リクエストのTupleを原型とし、レスポンス値を追加したTupleを返すとわかりやすい
•物理的な部屋・場所毎にTupleSpaceを分けてみたが、全部屋の温度をwatchするプログラムが複雑になってしまった。”where”というプロパティを持たせれば良かったかも
• Tupleのプロパティに色々書いておくと柔軟になる。
•リクエストのTupleを原型とし、レスポンス値を追加したTupleを返すとわかりやすい
•物理的な部屋・場所毎にTupleSpaceを分けてみたが、全部屋の温度をwatchするプログラムが複雑になってしまった。”where”というプロパティを持たせれば良かったかも
Tupleのプロパティに色々書いておくと柔軟になる。
リクエストのTupleを原型とし、レスポンス値を追加したTupleを返すとわかりやすい
物理的な部屋・場所毎にTupleSpaceを分けてみたが、全部屋の温度をwatchするプログラムが複雑になってしまった。”where”というプロパティを持たせれば良かったかも
他の工夫 !
Webと接続したい 色んな言語・デバイスで接続したい 安定して動かして毎日使いたい 常に拡張しやすくしておきたい
安定して
動かしたい
全部Herokuで動かせば安定する
• linda-serverはすぐHerokuで動かせる !
•音を出す、モーターを回す等はその場にあるマシンで動かさないとならない
• Tupleをreadして(何か判断して)writeするようなのは、どこで動いていてもいいが、数がかなり多くなる
linda-worker• https://github.com/masuilab/linda-worker • Hubot風にLindaのスクリプトを1プロセスに詰め込んでHerokuで動かす
常に拡張しやすく
しておきたい
ことごとくTupleにして書き込めば 拡張性高くなる
•明るさセンサのTuple • 電気ついた・消えたTuple • 人がいるらしいぞTuple • sayしろ/Yoしろ/チャットに通知しろTuple • など全てTupleにして書き込むと、途中のどこからでも拡張可能
•速度は十分出るので、アメリカと毎回通信しているとか考えない
よくある質問
認証
•変なTuple書き込まれたくないんだけど? !
• Socket.IOの認証でどうにかしたい、調査中 • tuple.fromでリモートホスト見れるよ
マイコンとNode等はどう接続してるの?
•各言語の中にArduinoコードが書けるライブラリ作った • https://npmjs.org/package/arduino-firmata • https://npmjs.org/package/ble-firmata • http://rubygems.org/gems/arduino_firmata • http://shokai.github.io/ArduinoFirmata-Android/
Tupleはどこに保存されているの?
•Nodeプロセスのオンメモリに保存されてます •溢れないようにexpireを3分毎にチェックしている •永続化はしない方針 • 4ヶ月ぐらい動かし続けても安定しているので(研究室程度の規模なら)大丈夫だと思う
複数のTupleがマッチする場合、どれが取れるの?
•一番新しいTuple、つまり最後に書き込まれたTupleが取れます
•古いTupleを取りたい場合、何回もtakeしていくしかない
• Tupleを全てtakeするには34ページのcancelとsetTimeoutを使ってください
take/read/watchの順番•先にtake/read/watchのリクエストが来ていて、その後writeされた場合
• readとtakeとwatchを、先着順に評価する • Tupleがtakeで削除された場合、それ以降のreadとwatchには配信されない
•質疑応答の時に、まずwatchにmatchするクライアント全員に配信されると言いましたが勘違いでした!!
悪い人がtakeしたら?
•takeされたら、そのTupleは消えます • read/watch/takeは先着順に評価されるので、watchしておけばtakeされてもwriteを全部取れる
• takeできないtupleを作る、とか権限とか考えたけど、シンプルさが無くなるのでやめました
•ルールを守って楽しいLinda
ぶっちゃけwatchしか使わないのでは?
•センサーデータを流して色々デバイスを動かすような場合は、writeとwatchしか使いませんでした
•こういう最新のデータを返すような場合にreadが便利 !
!
!
• takeはタスク分散以外であまり使わないかも
MongoDBとの違い•書き込まれたTupleをすぐ配信できる(watchでpub-subできる)
• 1プロセスにたくさん接続できる •ブラウザJSが直接接続できる •実はNodeアプリにライブラリとして読み込めて、既存のSocket.IO接続と共存できるのでちょっとしたツールを作るのにも便利
MQTTとの違い•MQTTでもいいのではないかと思う •MQTTはコネクションしっかり貼らないセンサネットワーク等でも使えるようになっているが、lindaはSocket.IO前提
•しかしIBMのMQTT broakerはwebsocketでも接続できるので、ブラウザJSからも使えるようです
•もっと調査します •MQTTぱっと見た感じ、pub側に権力が集中しすぎに見える。QoSもデータ量もpub側次第になるけど、subにどんなアプリケーションが来るかわかっていない状況で「とりあえずデータ流しておこう」という用途には難しそう。ガジェットが増える毎に自宅の仕様は変わる。設計が常にベータ版な環境で建て増しを続けられるのか?
Herokuのステマ?•はい • Herokuは最高 • Herokuで動かしやすいように作っておくと、どこでも動かせる感じがして好き
• linda-workerとlinda-serverが互いに通信しあってherokuプロセスが寝ないようになっている
まとめ
まとめ
•色々な言語から使えるLinda実装を作った •センサー読んですぐアクチュエータ動かさずに、細かくTupleにして連鎖させると拡張しやすい
•なるべくHeroku等で動かすと安定する
おわり