zigbee無線で距離を測った。
moxaの無線は出力を変える事ができる。これを利用して、サンプルプログラムの中にあった距離が近づいたらLEDが点灯する奴を改造し、
・複数nodeをID識別
・距離の計測の高速化
を行った。
1つのanchorと複数のnodeとの間の距離を取る。たくさんプログラムを書きこむ羽目になるのでUSBハブが無いと大変。
■しくみ
徐々に電波強度を上げていくと、「最も弱い出力で受信できた時」を距離とする事ができる。
電波強度は、無線通信のデータ本文に数値として含めておいて、受信側で文字列を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側でさらにボタンの押下状態なんかも付けられる。