0

ubicomp環境での複雑なプログラミング

現実世界は複雑で主観的なので、正確にモデル化できない。
つまりプログラムの中にモデルとして現実世界の情報を取り込んで、modelの状態に従って処理の手順を分岐させていく方法には無理がある。
そのため、小さくて個別に独立動作するモジュールに分散させて、それぞれのモジュールが環境状態に対応する形で動く様に実装する方が良い。


■モードのあるプログラム

複数のモードがあるシステムを実装するとき、一番簡単な方法はglobal変数に状態名を保存しておく事だ。

例えば

String state;
state = “open_mode”;

とか書いておいて、

if(state == “open_mode”){
// 処理
}
else if(state == “wait_mode”){
// 処理
}

のようにする。

こういう方法はprocessingやflashで一番最初に作品を作ったりした場合に多くて、まあ楽なのでこれで良い。
processingだとthreadなどが無いのでdraw()ループ内でstateを判別して回すのが楽というのもある。

ただ、この方法には問題がある。

  • stateへのアクセス権限の制限が難しくて、アクセス元が多くなるとバグの元になる
  • 複雑なアプリだとstateの種類自体がものすごく増える
    ネットがつながっていて、かつログインしていて、かつ〜〜など。人語にするのも面倒なほどのたくさんの条件から、たくさんの内部状態ができる。


■モードが無いプログラム

わりと一番簡単なこの手のシステムの実装方法は、threadやtimerがある環境なら
小さいthreadとその連動のためのjob-queueを用意して実装するのが楽な気がする。

ひたすら、
(マイコン内)
1.ボタンの状態を読み続けて、ボタンの状態変化した時に現在時刻とボタンの状態をqueue保存するthread
2.queueを見続けて、何か処理して結果をqueueに保存するthread
3.処理結果を監視し続けて、新しい結果があったらPCにシリアル通信で送り続けるthread
(PC内)
4.シリアルポートを読み続ける
5.なんか処理する

のようにする。この例だと一直線に処理が流れてくるのでまったくqueueを使う必要が無いけど、例えばマイコンで無線の処理も同時にやって、センサ、PC、他のマイコンと3つ又に接続されるように拡張するには、この方法で実装しておいた方が拡張しやすい。queueを監視して処理するthreadをもう一つ足すだけで済むから。

この辺は実装経験の方が専攻していて理論面は最近ちょっと調べた程度なので感覚的なんだけど、
ポイントは、人間の体のように実装する事だと思う。


■隣を見るだけで全体が動くようにする

例えば熱い物を触ったときに頭で考えるよりも速く手をひっこめるように、あるいは階段で足を踏み外しても足が勝手にバランスを整えてしまうように、中央に大きな脳があるのではなく各モジュールに小さい脳があり、それが連動する事で人体を成しているようにプログラムを考える。

その手や足の中の脳は体全体や部屋全体を認識しているわけではなくて、皮膚の隣にある熱いコップや、肘ぐらいまでしか認識していない。
このせいでたまにカップ麺を投げて大惨事になったりするけど、最低限
・隣だけ認識する
・環境(外部)からの要因で自動的に動く
ようになっているおかげでなんとか俺は生きている。

グローバル領域にstate変数を置くような実装の場合、自分の中の状態を監視してコードは実行が分岐されるが、
小さなモジュールの中のコードの場合はそうではなく、モジュール自身の中に状態を持たずに環境の状態に応じて処理が分岐される。if条件文で判定される条件式は隣のモジュールへの問いかけになり、帰ってきたメッセージによってコード実行は分岐する
(もちろん実行速度のためにはメッセージの結果はキャッシュしてもいいが)

あと、綺麗にMVCにするには中にmodelを持つわけだけど、XMLのDOMとかと違ってセンサーとか使ってると綺麗にmodelを持つ事自体がすごく難しい事がある。ようはインタフェースからの入力をmodelにするわけだけど、現実世界の現象はそんなに綺麗にmodelになるわけでもないので、むしろ入力に対して適当にレスポンスして、例外的状況をたくさん定義しておく方が良かったりする。

ただし、実験的で何かに特化したプログラミング環境だと、関数をオブジェクトとして扱ったりとか、そういう普通のプログラミング言語として高機能な部分が無くて、こういう実装にはできない事も多い。

0

moxaのzigbee無線で距離を測る

zigbee無線で距離を測った。

moxaの無線は出力を変える事ができる。これを利用して、サンプルプログラムの中にあった距離が近づいたらLEDが点灯する奴を改造し、
・複数nodeをID識別
・距離の計測の高速化
を行った。

1つのanchorと複数のnodeとの間の距離を取る。たくさんプログラムを書きこむ羽目になるのでUSBハブが無いと大変。
DSCF2544

■しくみ
徐々に電波強度を上げていくと、「最も弱い出力で受信できた時」を距離とする事ができる。
電波強度は、無線通信のデータ本文に数値として含めておいて、受信側で文字列をparseして読み出す。

moxaはマイコン上でECMAScriptが使えるので、Stringを分解したり、Object型インスタンスに何でも突っ込んだり、配列に溜めたりするのが楽に出来るので通信プロトコルを作るのが楽だった。


■nodeのプログラム
徐々に電波強度を上げながらanchorに無線を送り続ける
node/source.js

var radio = new Object();
radio.id = 2; // id:2以降がnode
radio.group = 7;

var time = 1;
var power_borders = new Array();
power_borders = [1,2,3,4,11,12,13,30,31]; // 距離の境目リスト


function loop() {
       dist_send();
}

function dist_send(){
    for(p in power_borders){ // power
        radioInit(0xDEAD, radio.id, radio.group, p);
        message = "power:"+p+",time:"+time;
        radioSend(0xFFFF, message);
        sleep(1);
    }
    time++;
}

function sleep(count){
    for(var i = 0; i < count*10; i++){
    }
}

while(true){
    loop();
}


■プロトコル
powerを1から徐々に上げながら送信する。

“power:2,time:15”
“power:3,time:15”
“power:4,time:15”

という風にtimeという変数も合わせて送る事で、1セット分の無線送信試行を表している。

■距離の境目
実際にはpowerと無線の飛距離は正比例していなくて、簡単に調べた所
・power 4ぐらい → 4メートル以内ぐらい
・power 10前後 → 5~15メートルぐらい
・power 20前後 → 15~30メートルぐらい
・power 30前後 → それ以上
となっていた。なので、その境目あたりを重点的に送信するために

power_borders = [1,2,3,4,11,12,13,30,31]; // 距離の境目リスト

を使った。こうすると1から最大31まで全powerを試す必要が無くなり、3倍ぐらい速くなっても精度はあまり落ちない。


■anchorのプログラム
nodeからの最低出力で受信できた時のpowerを本文から取り出し、nodeのID毎に配列に保存しておく。
anchor/source.js

var radio = new Object();
radio.id = 1; // nodeはid:2以降
radio.group = 7;

var dist = new Object();
dist.lastTime = 0;
dist.lastPower = 0;

nodes = new Array(16);
nodes_init(nodes);

serialInit(9600);
radioInit(0xDEAD, radio.id, radio.group, 31);

function loop(){
}

function onRadioReceive(seq,id,pan,data,rss) {
    if(id < 2) return; // nodeからではない時
    commands = data.split(",");
    for(c in commands){
        tmp = c.split(":");
        if(tmp[0] == "power") distance = tmp[1];
        if(tmp[0] == "time") time = tmp[1];
    }
    
      if(nodes[id].lastTime != time){ // 新しいデータの時
          nodes[id].distance = distance;
          // nodeのidと距離を出力
          serialSend("id:"+id+",distance:"+distance+",time:"+time+"¥r¥n");
      }
      nodes[id].lastTime = time;
}

function nodes_init(nodes){
    for(i = 1; i < nodes.length; i++){
        var node = new Object();
        node.lastTime = 0;
        node.distance = 0;
        node.id = i;
        nodes[i] = node;
    }
}

function sleep(count){
    for(var i = 0; i < count*10; i++){
    }
}

while(true){
    loop();
}


■無線データの受信と解析
onRadioReceive(seq,id,pan,data,rss) という関数を宣言すると無線を受信できる。
こういうデータが来るので

“power:3,time:15”

splitで : と , を分けて、nodeオブジェクトに保存する。

    commands = data.split(",");
    for(c in commands){
        tmp = c.split(":");
        if(tmp[0] == "power") distance = tmp[1];
        if(tmp[0] == "time") time = tmp[1];
    }
    

また、引数 id に送信元のIDが入っているので、あわせて保存しておく。

■シリアルポートに出力
今回はanchorからパソコンにシリアル通信で出力した。

id:2,distance:10,time:18\r\n
id:6,distance:3,time:11\r\n
id:7,distance:13,time:7\r\n

こんな感じの文字列がきて、anchorとnodeの間の距離、IDがわかる。

距離計測、ついでにボタン状態も
ちなみに、node側でさらにボタンの押下状態なんかも付けられる。

4

C# – FeliCaリーダでIDを読む

felicalibとC#用ラッパーを使ってFelicaのIDを読んだ。
参考:felicalib C#での利用方法

Reading felica ID
MNPして使わなくなった(財布機能1回も使ってない)auのお財布ケータイW51Sを乗せたところ。

普段使ってるSuicaを読むと違うIDが出てきた。


■作ったもの
080811_Felica.zip (VisualStudio2008 / C#3.0)
.NET Framework3.5が必要


■準備
RC-S320を使った。付属のCDからドライバだけインストールしておく。

SONY RC-S320 非接触ICカードリーダ/ライタ PaSoRi 「パソリ」
ソニー
売り上げランキング: 99
おすすめ度の平均: 4.5
4 あれば便利かもしれないが、無くても困らない製品
5 便利アイテムです
5 便利です。
5 飛行機に乗れなくてもマイルが貯まる
4 edyを常用してる人ならお勧め


felicalibをダウンロードしてくる。中にC#用ラッパー(FelicaLib.cs)も入っているので自分のプロジェクトに追加。
felicalib.dllは「参照の追加」から使うのではなく、bin/Debug, bin/Releaseなどにファイルを直接コピペして置く。実行時にFelicaLib.csからP/Invokeで読み込まれる。

■コード
ラッパーを読み込んで

using FelicaLib;


IDmを読むとbyte配列が来るので、Stringに直す。

try
{
  using (Felica felica = new Felica())
  {
    felica.Polling(0xFFFF);
    byte[] data = felica.IDm();
    String id = "";
    for (int i = 0; i < data.Length; i++)
    {
      id += data[i].ToString("X2");
    }
    Console.WriteLine(id); // ID出力
  }
}
catch (Exception ex)
{
  Console.Error.WriteLine(ex.Message);
}

0

moxaを9V電池で動くように改造する

基本はUSB給電だが、内部にレギュレータがあるので9V電池をそのまま接続するだけで使えるようになる。

DSCF3388



■電源ケーブルを付け直す
上の写真にもある赤いケーブルが、PCのUSB端子からの5V給電をmoxaのレギュレータに送る役目をしている。
(上の写真では既に付け直した後だが)最初は基盤裏側に付けてあるのだけど、今回は下方向にピンヘッダを付けたかったので基盤表側につけなおした


基盤裏のピンヘッダ。赤い電源ケーブルははんだごてを当てながら抜けば簡単に外せる
DSCF3376

表側に付け直した。
DSCF3372


この状態で、まずは一回moxa基盤そのものがパソコンから認識できるかどうか確かめたりしておいた方が良い。電源まわりはバグの元なので。



■9V電池を接続する
図のように接続する。9Vのプラスとマイナスを間違えないように注意。
9v-moxa

外部にセンサーなどを接続する時は、右の3.3V出力を利用する。左側のUSBからの5V出力は当然動いていないので使えない。
あと、左側にもGNDがあるのでうまく利用すると良いかも。

今回作った基盤は裏から見るとこうなっている。電池からの給電をON/OFFするスイッチを、電池+→VIN間に付けた。
DSCF3389

0

chumby用wassrウィジェット

twitter widgetfavotter widgetと同じく、chumby用のwassrのウィジェットを作った

ここからdownload

DSCF2476

使い方はUSBメモリから起動で。profile.xmlのusernameの所を適当に修正してください

APIがtwitterとほぼ同じなので簡単だった。ただ顔アイコンが

http://wassr.jp/user/ユーザID/profile_img.png.128

などで128×128のアイコンが取れるんだけど(サイズは色々指定できて、GIF形式などもある)

Flashへの読み込みがすごく遅い。理由はよく分からない。小さいの指定しても駄目。

修正できなかったのでそのまま公開しました

wassrはイイネ/イラネやchannelなどがあるので、それらの機能もそのうち入れてバージョンアップしたらまた公開しますね