Home > Make | arduino > arduino と xbee(digimesh mode)で温度計測

arduino と xbee(digimesh mode)で温度計測

digimesh化したxbeeを,以下のような流れで通信テストした.

  1. 遠隔地に設置したarduinoで温度を計測
  2. 計測値は,各所に配置されたxbeeを経由し,ホスト側となるEthernet Shieldを積んだarduinoへ送信
  3. 測定結果を受けとったarduinoは,所定のサーバーに数値をアップデート

今回のテストで使用したものは,ざっと以下のとおり.

  • arduino
  • Ethernet Shield
  • Xbee Shield
  • LM35DZ(高精度IC温度センサ)
  • Xbee 802.15.4モジュール(シリーズ1)

Xbeeのdigimesh化

x-ctuにて,ファームウェアをXB24-DMに書き換えることで使用できる.
詳しくというか,メモが以下にある.

※メモ
テスト時点では,最新ファームは8003であったが,現在804Bがリリースされた模様.
今回のアップデートは,X-CTUで見る限り,I/Oとsleep周りが強化されたような感じがある.ただし,ドキュメントなどは未だ8003ベースなので,詳細は不明.

計測側arduinoのスケッチ

RIMG0114
計測側のarduinoが行なうことは,温度を計測し,xbee経由でホスト側へ計測値を送信することとなる.
温度計測には,LM35DZを使用したが,これについては建築農業工作ゼミ2009: 温度センサを参考にした.

#include <stdio.h>

//ホスト側xbeeのアドレス
long addr64f=0x0013****;
long addr64l=0x4053****;

//温度関係(LM35DZ)
int    a_pin=0;  //analog入力pin
int    a_val;     //analog入力値(0~1023)
int    a_ave;
float  v=5; //基準電圧(V)
long  tempc=0;  //摂氏値(℃)
int    nloop = 10;

void setup(){
  Serial.begin(9600);
  digitalWrite(13,LOW);
}

void loop(){
  a_ave = 0;
  //1Hzで10秒間測定
 for(int i=0;i<nloop;i++){
    a_val = analogRead(a_pin);
    a_ave += a_val;
    delay(1000);
  }
 //平均化
 a_ave /= nloop;
 //温度に変換
  tempc=((v*a_ave)/1024)*10000;
 //ホストへ値を送信
  senddata(addr64f,addr64l,tempc);
}

byte getlength(long data){
  byte buf = sizeof(long)+14;
  return(buf);
}

byte checksum(long addr64f,long addr64l,long data){
  byte buf;

  for(int i=0;i<7;i++){
    switch(i){
      case 0:  //API identifier
        buf = 0x10;
        break;
      case 1:  //Frame ID
        break;
      case 2:
        for(int j=0;j<sizeof(addr64f);j++){
          buf += lowByte(addr64f);
          addr64f = addr64f>>8;
        }
        break;
      case 3:
        for(int j=0;j<sizeof(addr64l);j++){
          buf += lowByte(addr64l);
          addr64l = addr64l>>8;
        }
        break;
      case 4:
        buf += 0xFF;
        buf += 0xFF;
        break;
      case 5:
        buf += 0x08;
        break;
      case 6:
        for(int j=0;j<sizeof(data);j++){
          buf += lowByte(data);
          data = data>>8;
        }
        break;
    }
  }
  buf = 0xFF - buf;
  return(buf);
}

void senddata(long addr64f,long addr64l,long data){
  char str[100];
  char strbuf[10];
  Serial.flush();
  delay(100);
  Serial.print(0x7E,BYTE);
  Serial.print(0x00,BYTE);
  byte dl = getlength(data);
  Serial.print(dl,BYTE);
  Serial.print(0x10,BYTE);
  Serial.print(0x00,BYTE);
  print_longhex(addr64f);
  print_longhex(addr64l);
  Serial.print(0xFF,BYTE);
  Serial.print(0xFF,BYTE);
  Serial.print(0x00,BYTE);
  Serial.print(0x08,BYTE);
  print_longhex(data);
  byte cs = checksum(addr64f,addr64l,data);
  Serial.print(cs,BYTE);
  Serial.flush();
  delay(20);
  return;
}

void print_longhex(long addr)
{
  byte buf[4];
  int i,n=4;
  char str[2];

  for(i=0;i<n;i++){
    int j = n-i-1;
    buf[j] = lowByte(addr);
    addr = addr>>8;
  }
  for(i=0;i<n;i++){
    Serial.print(buf[i],BYTE);
  }
 return;
}

ホスト側のスケッチ

RIMG0114
ホスト側arduinoは,xbeeより受信したコマンドから測定結果のみを抽出し,Ethernet Shield経由でローカルサーバーにアップデートしていく.
基本的には建築農業工作ゼミ2009: Arduinoで計測した値を指定のwebサーバに送信、保存するを参考にした.
違いを出すという意味で,こちらはrailsで測定結果の表示部分まで作成してみた.

テスト中,xbeeで送られてくるコマンドがRF Dataのみではないことに気付いた.
とりあえず,oklablog – digimeshでの通信コマンドでメモしたとおり,Receive Packetの16byte以降を読むようにした.
(適当だ...)

#include <Ethernet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

byte mac[] = { 0x00, 0x50, 0xC2, 0x97, 0x**, 0x** };
byte ip[] = { 192, 168, 0, *** };
byte gateway[] = { 192, 168, 0, 1 };
byte subnet[] = { 255, 255, 255, 0 };
byte server[] = { 192, 168, 0, *** };
byte  buf[30];

int flg=0;
int strn=0;

Client client(server, 3000);

void setup()
{
  Ethernet.begin(mac, ip, gateway, subnet);
  Serial.begin(9600);

  delay(1000);
  Serial.flush();
  Serial.println("connecting...");
}

void loop(){
  int c,buf[200];
  int i,j;
  int imax=20;
  long data;

  if(Serial.available()>imax-1){
    i=0;
    do{
      c = Serial.read();
      buf[i] = c;
      i++;
    }while(c != -1);
    i--;
    data = 0;
    for(j=0;j<3;j++){
      data += 256*(3-j) * buf[15+j];
    }
    data += buf[18];

    Serial.println(data);
    data_post(data);
  }

  delay(1000);
}

void data_post(long buf)
{
  char str[100];

  if(client.connect()){
    Serial.println("connected");

    sprintf(str,"%d",buf);

    client.print("GET /push/push?id=");
    client.print(str);
    client.println(" HTTP/1.0");
    client.stop();
  }
  else{
    Serial.println("connection failed");
    client.stop();
  }
  return;
}

railsで測定結果の表示

測定結果
今までグラフといえばphp+jpgraphだったが,rubyでもGruffみたいなものがあるようで,データのポストと表示部分をrailsで作成した.
見よう見まねで作成したのでおかしいところがありそうだけど,とりあえず動いたのでよしとする.

しかし,phpで作成していたよりもシンプルなコードで書けるので驚いた.
今回を機に,phpからrubyへシフトしていこうかと思う.

push_controller.rb

class PushController < ApplicationController
  def push
    db = Product.new
    db.data = params[:id]
    db.save
    @data = "ok!"
  end
end

push.html.erb

<html>
  <head>
    <title>data push</title>
  </head>
  <body>
    <%= @data %>
  </body>
</html>

pict_controller.rb

class PictController < ApplicationController
  def show
    ndata = 10
    buf1=Array.new(ndata,0)
    buf2=Array.new(ndata,0)
    db = Product.find :all,:order=>'id desc',:limit=>ndata
    i=0
    db.each {|id|
      buf1[i]=(id.created_at+32400).strftime('%y/%m/%d %H:%M:%S')
      buf2[i]=id.data.to_f/100
      i=i+1
    }
    @time = buf1
    @data = buf2
  end

  def image1
        g=Gruff::Line.new 640
        g.font = "/usr/share/fonts/japanese/TrueType/sazanami-gothic.ttf"
        g.title = "計測結果 by arduino + xbee(digimesh)"
        g.title_font_size=24
        ndata = 200

        g.x_axis_label = "計測時間"
        g.y_axis_label = "温度"
        g.hide_legend = true
        g.hide_dots = true
        g.maximum_value=40
        g.minimum_value=10

        buf = Array.new(ndata,0)
        i = 0
        db = Product.find :all,:order=>'id desc', :limit=>ndata
        db.each {|id|
          buf[ndata-1-i]=id.data.to_f/100
          case i
          when 0,ndata-1
              g.labels[ndata-1-i]=(id.created_at+32400).strftime('%m/%d\n%H:%M:%S')
          end
          i=i+1
        }

        g.data("random data",buf)

        g.theme_37signals

        g.sort = false

        g.margins=50

        send_data(g.to_blob,:type=>'image/png',:disposition=>'inline')
  end
end

show.html.erb

<center>
  <%= image_tag url_for(:action=>'image1') %><br \>
</center>
<table border=2 width=300 align=center>
  <tr bgcolor="$cccccc">
    <th>計測時間</th>
    <th>温度</th>
  </tr>
  <% for i in 0..@data.length-1 -%>
  <tr align=center>
    <th><%= @time[i] %></th>
    <th><%= @data[i] %></th>
  </tr>
  <% end -%>
</table>

結論

とりあえず,当初計画していたことが一通りができた.
今回のテストを通して得た収穫は,以下のとおり.

  • digimesh modeで複数のxbeeを経由して通信可能
  • ただし,経由したデータは一部欠損が生じており,改良の必要あり
  • ruby,railsが予想以上におもしろく,使える

今後は,2のデータ欠損を改善していくとともに,省電力稼動のためsleepを活用していく予定.

  

Popular Entries

  
blog comments powered by Disqus

Home > Make | arduino > arduino と xbee(digimesh mode)で温度計測

Search
Feeds

Meta

Return to page top