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