Arduinoセンサステーションを作る

th_sensor_station_1

前回、ラピロにXBee通信機能つきの Arduinoシールドを装備させました。せっかく無線通信できるのだから、遠隔地のセンサ情報の取得とか機器制御もやってみたくなるのが人情(?)というものです。

というわけで、ラピロの通信相手となるセンサステーションを作ろうと思います。

搭載したセンサ諸々はこんな感じです。

 それぞれ精度とかはあまり求めていなくて、「おおよその値がわかればいいから簡単に使えそうなのがいいな」という基準で選定しています。

とりあえずブレッドボード上に組んでみた結果がこちら。ブレッドボード大好き。

 th_sensor_station_1

Arduino Fioの下はこんな感じ。

 th_sensor_station_2

左上のソケットは、ゆくゆくはXBeeをスリープ動作させる可能性もあるので、引っ張っておきました。こちらによれば、Arduino FioのDTRとかいう端子が、XBeeのスリープ制御用の端子に繋がっているそうなので。

Arduinoのソースは、前回ラピロのシールド用に作成したものをベースに、I2C通信関係とマイク関係を除いて、温度/湿度センサの取得コードの変更、開閉センサの値取得コード追加、圧電スピーカーのテストコード追加、という形で作成しています。

ちょっと困ったのが、温度/湿度センサのRHT03。Arduinoを使った工作では比較的メジャーなようで、いろいろ情報はあるのですが、提供されているライブラリがArduino Unoベース(16MHz, 5V駆動)のためか、Arduino Fio(8MHz, 3.3V駆動)で最初うまく値が取れませんでした。どちらも0になる。

ライブラリはいくつか存在するようで、最終的に以下で提供されているライブラリを使うと、Arduino Fioでも動作しました。

また、こちらによれば、ライブラリのソースを一部書き換える必要があるようなのですが、とりあえずそのままでも動作しました。ただ、2000ミリ秒間隔で値を取得しにいっても、取得に失敗することがそこそこあるので、そのときは前回取得値で補完するようにしました。

ということで、現状のソースを載せておきます。

#include "DHT.h"
#include "pitches.h"

#define DHTTYPE DHT22   // DHT 22  (AM2302)

int TEMP_HUMID_PIN = 10;
int ILL_PIN        = A7;
int DOOR_PIN       =  4;
int MOTION_PIN     = 12;
int SPEAKER_PIN    = 13; 

int XBEE_SLEEP_PIN =  3; // 0 ... Enable XBEE / 1 ... Disable XBEE

DHT dht;

float temp_avg   = 0.0;
float humid_avg  = 0.0;
float ill_avg    = 0.0;
int   motion_avg = 0;
int   door       = 0;

// すべてのセンサは、問い合わせ時点から過去1分間の出力値の平均値を返す。
// ただし、モーションセンサについては、平均値が0.2以上なら「人がいた」と判定して1、
// 0.2未満なら「人がいない」と判定して0を返す

const int SENSOR_LOG_NUM = 60;
float temp_log[SENSOR_LOG_NUM];
float humid_log[SENSOR_LOG_NUM];
float ill_log[SENSOR_LOG_NUM];
float motion_log[SENSOR_LOG_NUM];

int loop_count = 0;

void updateTemperatureAvg(){
  float sum = 0.0;
  for(int i=0;i<SENSOR_LOG_NUM;i++){
    sum += temp_log[i];
  }
  temp_avg = sum/SENSOR_LOG_NUM;
}

void updateHumidityAvg(){
  float sum = 0.0;
  for(int i=0;i<SENSOR_LOG_NUM;i++){
    sum += humid_log[i];
  }
  humid_avg = sum/SENSOR_LOG_NUM;
}

float getIlluminance(){
  int AMS302_Value = analogRead(ILL_PIN);
  float lx = AMS302_Value*(3300.0/1024.0)/1000.0/(0.26/100);
  return lx;
}

void updateIlluminanceAvg(){
  float sum = 0.0;
  for(int i=0;i<SENSOR_LOG_NUM;i++){
    sum += ill_log[i];
  }
  ill_avg = sum/SENSOR_LOG_NUM;
}

void updateMotionAvg(){
  float sum = 0.0;
  int flag = 0;
  for(int i=0;i<SENSOR_LOG_NUM;i++){
    sum += motion_log[i];
  }
  float avg = sum/SENSOR_LOG_NUM;
  if(avg < 0.2){
    flag = 0;
  }else{
    flag = 1;
  }
  motion_avg = flag;
}

void get_coin(){
  tone(SPEAKER_PIN,NOTE_B5,100);
  delay(100);
  tone(SPEAKER_PIN,NOTE_E6,850);
  //delay(800);
  delay(500);
  noTone(SPEAKER_PIN);
}

void mario_1up(){
  tone(SPEAKER_PIN,NOTE_E6,125);
  delay(130);
  tone(SPEAKER_PIN,NOTE_G6,125);
  delay(130);
  tone(SPEAKER_PIN,NOTE_E7,125);
  delay(130);
  tone(SPEAKER_PIN,NOTE_C7,125);
  delay(130);
  tone(SPEAKER_PIN,NOTE_D7,125);
  delay(130);
  tone(SPEAKER_PIN,NOTE_G7,125);
  delay(125);
  noTone(SPEAKER_PIN);
}

void fire_ball(){
  tone(SPEAKER_PIN,NOTE_G4,35);
  delay(35);
  tone(SPEAKER_PIN,NOTE_G5,35);
  delay(35);
  tone(SPEAKER_PIN,NOTE_G6,35);
  delay(35);
  noTone(SPEAKER_PIN);
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(57600);  // シリアル通信速度

  pinMode(ILL_PIN, INPUT);
  pinMode(MOTION_PIN, INPUT);
  pinMode(DOOR_PIN, INPUT);
  pinMode(SPEAKER_PIN, OUTPUT);
  pinMode(XBEE_SLEEP_PIN, OUTPUT);

  for(int i=0;i<SENSOR_LOG_NUM;i++){
    temp_log[i]   = 0.0;
    humid_log[i]  = 0.0;
    ill_log[i]    = 0.0;
    motion_log[i] = 0.0;
  }
  door = 0;

  digitalWrite(SPEAKER_PIN, LOW);
  digitalWrite(XBEE_SLEEP_PIN, LOW); // XBee Enable

  dht.setup(TEMP_HUMID_PIN);

  Serial.println("Ready.");
}

void loop() {

  delay(2000);

  if(loop_count == SENSOR_LOG_NUM){
    loop_count = 0;
  }
  temp_log[loop_count]   = dht.getTemperature();
  humid_log[loop_count]  = dht.getHumidity();
  ill_log[loop_count]    = getIlluminance();
  motion_log[loop_count] = (float)digitalRead(MOTION_PIN);
  door                   = digitalRead(DOOR_PIN);

  // Check if any reads failed and exit early (to try again).
  if (isnan(temp_log[loop_count]) || isnan(humid_log[loop_count])) {
    Serial.println("Failed to read from DHT sensor! Complement pre-measured value");
    fire_ball();
    if(loop_count > 0){
      temp_log[loop_count]  = temp_log[loop_count-1];
      humid_log[loop_count] = humid_log[loop_count-1];
    }else{
      temp_log[loop_count]  = temp_log[SENSOR_LOG_NUM-1];
      humid_log[loop_count] = humid_log[SENSOR_LOG_NUM-1];
    }
  }

  Serial.print(temp_log[loop_count]); Serial.print(" / "); 
  Serial.print(humid_log[loop_count]); Serial.print(" / ");
  Serial.print(ill_log[loop_count]); Serial.print(" / ");
  Serial.print(motion_log[loop_count]); Serial.print(" / ");
  Serial.println(door);

  loop_count++;
}

includeしている”pitches.h”は、Arduino IDEのサンプル”toneMelody”が使用しているものと同一です。複製して同じプロジェクト内に放り込んでやってください。

このソースでは、圧電スピーカーのテストとして、温度/湿度センサから値が取得できなったときに、なぜがマリオがファイアボールを投げる音が鳴るようになっています。。。いや、任天堂が好きなもんで。ちなみにこの音の部分のソースは、以下を参照させていただきました。

さて、次に個人的には難関の、XBeeの設定に入りたいと思います。省電力云々はまずは置いといて、とにかく通信できるようにしたいと思います。