Arduino と Ruby で温湿ネットロガー

 気象情報収集の手始めとして、温度と湿度を記録するための仕組みを製作しました。センサーは、ストロベリー・リナックスで販売されている、SHT11 を使用し、Arduino でセンサーにアクセスします。データは Ethrenet Shield を使いサーバに送信します。データの受信は Ruby で作る TCPサーバが受け取ります。

 SHT11 は温度センサーと湿度センサーが一体となったモジュールで、シリアル通信によりマイコンで値を読み出せるものです。その他、湿度センサーとして秋月で販売されている HS-15P も検討しました。しかし、これは湿度を読み出すまでのアナログ回路がなかなかめんどくさいのでやめました。

◆Arduino 用のライブラリがあった

 さて、SHT11 の使い方はネットに多くの情報があります。エレキジャックの HP では、なんと7回に渡った記事が掲載されており大変参考になります。

 シリアル通信をシコシコ作るのめんどくさいなぁと思いつつ更にネットを徘徊すると、SHT1X シリーズにアクセスするための Arduino のライブラリを発見しました。

http://timothytwillman.com/?page_id=213(2012/10/15現在リンク切れ)

 Arduino を使おうと思っていたので渡りに船です。早速ライブラリをダウンロードします。sht1x.tgzを解凍し、フォルダーごと arduino-001x/hardware/libraries 以下にコピーします。SHT11 のクロックを DP2 に、データを DP3 につなぎそれぞれ 10k でプルアップします。以上で準備完了です。ページに紹介されているサンプルスケッチをコピペするとあっさり動きました。

◆Arduino のコード

 ここまでくれば終わったも同然です。SHT11 のサンプルを改造して、Ethrenet Shield を使った TCP/IP のクライアントプログラムを作ります。ソースコードを公開します。以下のソースを利用する場合は、各定義をそれぞれの環境に合わせて編集してください。

#include <Ethernet.h>
#include "sht1x.h"

/* サーバのポート番号を定義 */
#define PORT 12345

/* 自身のマックアドレスを定義 */
byte mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
/* 自身のアドレスを定義 */
byte ip[] = { 192, 168, 0, 10 };
/* デフォルトゲートウェイを定義 */
byte gw[] = { 192, 168, 0, 1 };
/* ネットマスクを定義 */
byte snet[] = { 255, 255, 255, 0 };
/* 接続先のサーバアドレスを定義 */
byte server[] = { 192, 168, 0, 100 };

unsigned long c,p;

Client client = Client(server, PORT);

void setup()
{
  Serial.begin(9600);
  Ethernet.begin(mac, ip, gw, snet);

  delay(11);  
  sht1x_init();

  if (sht1x_read_humidity() < 0) {
    Serial.println("soft reset");
    sht1x_reset();
  }
}

void send_ht(unsigned int h,unsigned int t)
{
  client.print( millis() );
  client.print(",");
  client.print(h);
  client.print(",");
  client.println(t);
  client.flush();
}

void loop() 
{
  unsigned int h = sht1x_read_humidity();
  unsigned int t = sht1x_read_temp();
  
  while ( ((c = millis()) % 1000 && p + 1000 > c ) || p ==c );
  p = c;

  if( client.connected() ){
    send_ht(h,t);
  }else if( client.connect() ){
    send_ht(h,t);
  }else{
    Ethernet.begin(mac, ip, gw, snet);
    Serial.println(c, DEC);
  }
}

◆サーバのコード

 サーバは Ruby を使って書きます。Arduino が送信する文字列を受信しセンサーが出力した数値を得るわけですが、SHT11 は人間が使っている温度や湿度で出力してくれないので、センサー値を摂氏やパーセントに変換する必要があります。以下のソースコードは、変換した値を標準出力に表示するサンプルになります。

#!/usr/bin/env ruby
require 'socket'

def tcp_service(port)
  gs = TCPServer.open(port)
  loop do
    Thread.new(gs.accept){|s|
      receive(s)
    }
  end
end

def receive(s)
  while(cmd = s.gets)
    buf = cmd.split(",")
    t = -40.0 + 0.01 * buf[2].to_i
    h1 = buf[1].to_i
    h = -4.0 + 0.0405 * h1 - 2.8e-6 * h1 * h1
    printf("%s t=%.2f h=%.2f\%\n",buf[0],t,h)
  end
end

tcp_service(12345)

 実行結果はこんな感じ、一番左は、millis() の出力をそのまま出しています。

◆短いソースは気持ちいい!

 Arduino はライブラリも充実していてやりたいことが短く書けるところが素晴らしいです。今回サーバに使った Ruby も同じです。Ruby で作っておけば、プロセスをデーモン化したり、ファイルや DB に値を格納をすることも比較的簡単にできますからね。


Latest update at 2009/5/7