TinyOS + MICAz を使う TinyDB編
センサノードを使った遊び(実験)について忘れないようにメモします.
TinyDB編では,用語・使い方の説明.また,JAVAを使って簡単なアプリケーションも作ってみます.
TinyDBとは
TinyDB: A Declarative Database for Sensor Networks
TinyDBは,同じくカリフォルニア大学バークレイ校が開発する「Mote」チップ向けの問い合わせの仕組み。Moteは,木構造のネットワークをアドホックに形成する仕組みを備える。TinyDBは,木構造のネットワークの特性を生かしてデータを集める。例えば,温度(Temp)を10で割った値でグループ分けをし,それぞれについて照度(Light)の値の平均(AVG)を取るというクエリーを発行している。クエリーは,親から子へ,さらにその子へとすべてのノードに送られる。クエリーに合わせて,末端の子ノードは親ノードに自分の情報を報告する。親ノードはそれを集約し,さらに自分の親ノードへと報告する。
http://itpro.nikkeibp.co.jp/a/it/manabu/ma0621/ma_32.shtml
moteを利用する際にmote上のセンサからデータを収集し、シリアル経由でPCに渡し、それを
IP経由で計算機を介して使える用にするもの。
(中略)
SQLライクなクエリであるTinySQLを発行することで、モートに取り付けたセンサから情報を収集する、擬似データベース。
センサから出力される情報の頻度などを事前に指定できる。また、通信経路などは自動的に考慮し、消費電力も効率良く行ってくれるらしい。
http://www.ht.sfc.keio.ac.jp/~nandu/pukiwiki/pukiwiki.php?%5B%5BTinyDB%5D%5D
環境
- CygwinとTinyOSとJAVAが既にインストールされて設定も完了している環境(実験室).
- RS-232Cポートに接続したシリアルケーブル(COM1)にMICAzを接続できるようになっている.つまりmib510などの機器がCOM1に付いている.
- 3つ以上のセンサノード(MICAz)を用意する.一つはmib510に取り付け,Base(ノード番号0)として利用します.残りの二つにはセンサ基盤を取り付けて,周辺の環境をセンシングしてもらいます.
(下記はhttp://www.tinyos.net/tinyos-1.x/doc/tutorial/tinydb.htmlを参考にしています.)
TinyDBをMICAzにインストールする
cd tinyos-1.x/apps/TinyDBApp
に移動して,
make micaz
とコンパイルして,これを,すべてのノードにインストールしていきます.基地局(ノードID:0)にもインストールします.
make micaz reinstall,<nodeid> mib510,COM1
クリエを発行してみる
まずCLASSPATHを作ります.(これは起動時に毎回やってください)
export CLASSPATH=`path/opt/tinyos/tools/java/javapath`
ここでのpathはルートディレクトリからの絶対パスを指定します.
cd /tinyos-1.x/tools/java/net/tinyos/tinydb/ make
に移動して,コンパイルします.コンパイルにはかなり時間がかかります.続いて
cd ../../.. java net.tinyos.tinydb.TinyDBMain
/tinyos-1.x/tools/java/まで上って,上記のコマンドを実行してください.そうするとTinyDB GUIが表示されます.
以下の図に示しているような形に設定してゆきます.
以上の形に設定できたら,”Send Query”をクリックします.すると・・・
こんな形の結果が返ってきます.
JAVAでTinyDBにクエリを発行してみる
tools/java/net/tinyos/tinydb/DemoApp.java(下記にソースを記す)を
<DemoApp.javaの中身>
package net.tinyos.tinydb; import net.tinyos.tinydb.parser.*; import java.util.Vector; import java.io.*; public class DemoApp implements ResultListener{ public DemoApp() { try { TinyDBMain.initMain(); //parse the query q = SensorQueryer.translateQuery("SELECT light", (byte)1); //inject the query, registering ourselves as a listener for result System.out.println("Sending query."); TinyDBMain.injectQuery( q, this); } catch (IOException e) { System.out.println("Network error."); } catch (ParseException e) { System.out.println("Invalid Query."); } } /* ResultListener method called whenever a result arrives */ public void addResult(QueryResult qr) { Vector v = qr.resultVector(); //print the result for (int i = 0; i < v.size(); i++) { System.out.print("\t" + v.elementAt(i) + "\t|"); } System.out.println(); } public static void main(String argv[]) { new DemoApp(); } TinyDBQuery q; }
cd ../../.. java net.tinyos.tinydb.DemoApp
というコマンドで,先のTinyDBMainと同じように起動できます.結果は
Listening for client connections on port 9000 SerialPortIO: initializing Successfully opened COM1 client connected from localhost.localdomain (127.0.0.1) Sending query. 1 | 835 | 2 | 833 | 3 | 833 | 4 | 833 | 5 | 833 | 6 | 833 | 7 | 833 | ...
こんな感じで返ってきます.
DemoApp.javaを適当に改良してみる
<TinyDB_test_ligth2.javaの中身>
package net.tinyos.tinydb; import net.tinyos.tinydb.parser.*; import java.util.Vector; import java.io.*; public class TinyDB_test_ligth2 implements ResultListener{ static int buf1 = 0; //1回前のデータを保持 static int buf2 = 0; //2回前のデータを保持 static int buf3 = 0; static int resultCounter = 0; //何個のデータが来ているかを保持する. int aveLigth = 0; //平均値を保持 public TinyDB_test_ligth2() { try { TinyDBMain.initMain(); //parse the query q = SensorQueryer.translateQuery("SELECT light,nodeid FROM sensors", (byte)1); //inject the query, registering ourselves as a listener for result System.out.println("Sending query."); TinyDBMain.injectQuery( q, this); } catch (IOException e) { System.out.println("Network error."); } catch (ParseException e) { System.out.println("Invalid Query."); } } /* ResultListener method called whenever a result arrives */ public void addResult(QueryResult qr) { Vector v = qr.resultVector(); //print the result System.out.print("resultCounter:" + resultCounter + "\n"); if(resultCounter % 3 == 0 ){ buf1 = Integer.parseInt(v.elementAt(1).toString()); //ligthの値を保持 System.out.print("buf1:" + buf1 + "\n"); }else if(resultCounter % 3 ==1){ buf2 = Integer.parseInt(v.elementAt(1).toString()); //ligthの値を保持 System.out.print("buf2:" + buf2 + "\n"); }else if(resultCounter % 3 ==2){ buf3 = Integer.parseInt(v.elementAt(1).toString()); //ligthの値を保持 System.out.print("buf3:" + buf3 + "\n"); } if(resultCounter > 3){ aveLigth = (buf1 + buf2 + buf3)/3 ; System.out.print("AVE:" + aveLigth + "\n"); if( aveLigth < 300 ){ System.out.print("Negative!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); } } for (int i = 0; i < v.size(); i++) { System.out.print( "\t" + v.elementAt(i) + "\t|"); } resultCounter++;//データの個数を一個増やす System.out.println(); } public static void main(String argv[]) { new TinyDB_test_ligth2(); } TinyDBQuery q; }
こんな感じに改良してみました.
これは複数のノードへligthの値を送ってくるようにクリエを発行し,複数のノードから3つのligthの値の平均を求め,その値が300以下(全体的に暗くなったら)になったら,「Negative!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!」と表示するプログラムです.
これを/tinyos-1.x/tools/java/net/tinyos/tinydb/以下に置いて,javacでコンパイルした後,先と同じような形で起動させます.
結果は
454 | 13 | 1 | resultCounter:410 buf3:821 AVE:551 455 | 821 | 2 | resultCounter:411 buf1:11 AVE:281 Negative!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 455 | 11 | 1 | resultCounter:412 buf2:821 AVE:551 456 | 821 | 2 | resultCounter:413 buf3:14 AVE:282 Negative!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 456 | 14 | 1 | resultCounter:414 buf1:821 AVE:552 457 | 821 | 2 | resultCounter:415 buf2:779 AVE:538 457 | 779 | 1 | resultCounter:416 buf3:822 AVE:807
といった感じになります.これは部屋にセンサノードをばら撒いて,その部屋が全体的に暗くなったら→人がいなくなったと判断し,「エアコンを消す」などの動作をしたり,部屋が明るくなったら,人が入ってきたと判断して,サービスを提供することを目的としています.ユビキタスっぽいw
http://mia.ece.uic.edu/cgi-bin/lxr/http/source/?v=tinyOS
関連記事
TinyOS+MICAzを使う 基本編 - WebLab.ota
TinyOS+MICAzを使う Surge_Reliable編 - WebLab.ota
TinyOS + MICAz を使う MoteView編 - WebLab.ota
TinyOS + MICAz を使う TinyDB編 - WebLab.ota