蛍の光をデータに落とすデータロガーを作ってみた。
データは、ホタルの明滅パターンを取るための、光の強度をサンプリングする光センサと、ホタルの光の色をRGBでサンプリングする、カラーセンサの2つのセンサからなっています。
これら2つのセンサからのデータをArduinoでA/D変換、サンプリングしてSDカードに記録するというもの。
回路図は、こんな感じ。
光センサは、S9648にLM358で増幅してArduinoでA/D変換、 カラーセンサは、S9706を使ってRGBのデータを取り込み、ロジックレベル変換モジュールを通して、SDカードに記録している。
センサは、ピンポン玉を半分に切って、底部にセンサをセットして、この中にホタルを入れて、少しの間ピンポン玉の中で光ってもらう。 一応、積分球のようにホタルが中で移動しても平均的な反射光をサンプリングするような効果を期待したけど、センサがむき出しなので、あまり意味はないかもしれない。まぁ、これでいいのだ!
これまでも同様の光センサで、明滅パターンを取っていたのだけど、これまでは、カラーセンサがなく、シリアル通信でPCと直結していたので、機動性に問題があった。また、ホタルの飛ぶところは、暗いので、PCのバックライトの明かりが明るすぎて、何かと問題が多いので、今回のものに改良してみた。
使い方は、電源をONにすると、LEDが3回点滅して、光の強度測定モードで始動します。
ロギング開始ボタンを押すと、光センサからのデータがAD変換されてSDカードにdatalog.txtというファイルに記録されます。
電源をONする際に、ロギング停止ボタンを押したまま電源を入れると、カラー測定モードで始動します。
同様にロギング開始ボタンを押すと、カラーセンサからのデータがcolorlog.txt というファイルに記録されます。
入力データが上限値をこえると、LEDが点灯して入力レベルの調整が必要なことを教えてくれます。
まぁ、詳細は、スケッチを追っていただければわかると思います。
カラー測定データをシリアルモニタで見る場合は、シリアルモニタを立ち上げる際にロギング停止ボタンを押しておかないと、強度測定モードになってしまうので注意が必要です。
Arduinoのスケッチは、これまた、あちこちのサイトを参考にさせてもらって、つぎはぎして、以下のようなものになった。
自分でも、どこのスケッチを引っ張ってきたのかわからなくなっちゃっているけど、カラーセンサに関しては、こちらのサイトから、主な部分は、ほぼ、そのまま引用させていただいている。
建築発明工作ゼミ2008: Arduino デジタルカラーセンサ S9706
他にもSDカードのライブラリとかA/D変換とかセンサの扱いとかいろいろとコピペさせていただいています。
まぁ、まさにスパゲッティのようなスケッチできれいに作れていないし、改良すべきところも沢山あるけど、ひとつの参考までに、以下、スケッチです。
#include <SD.h>
#define LED_PIN 4
#define STARTBUTTON 2
#define STOPBUTTON 3
#define PEAK_LED 7
#define RANGE 6
#define GATE 16
#define CK 5
#define DOUT 15
volatile int loggmode=0;
int red,green,blue;
const int chipSelect = 10;
unsigned long tm,ptm;
int mm;
volatile int loggsts=0;
volatile int datapos=0;
File dataFile;
void loggstrt()
{
loggsts=1;
digitalWrite(LED_PIN,HIGH);
datapos = 1;
}
void loggstp()
{
loggsts=0;
digitalWrite(LED_PIN,LOW);
digitalWrite(PEAK_LED,LOW);
datapos = 2;
}
void setup()
{
int i;
pinMode(LED_PIN,OUTPUT);
pinMode(PEAK_LED,OUTPUT);
pinMode(RANGE,OUTPUT);
pinMode(GATE,OUTPUT);
pinMode(CK,OUTPUT);
pinMode(DOUT,INPUT);
Serial.begin(9600);
Serial.print(F("Initializing SD card..."));
pinMode(SS, OUTPUT);
if (!SD.begin(chipSelect)) {
Serial.println(F("Card failed, or not present"));
while(1);
}
Serial.println(F("ok."));
SdFile::dateTimeCallback( &dateTime );
tm = millis();
mm=0;
pinMode(STARTBUTTON, INPUT_PULLUP);
pinMode(STOPBUTTON, INPUT_PULLUP);
loggmode = digitalRead(STOPBUTTON);
if (loggmode==0){
for(i=1;i<6;i++){
digitalWrite(LED_PIN,HIGH); digitalWrite(PEAK_LED,HIGH); delay(500);
digitalWrite(LED_PIN,LOW); digitalWrite(PEAK_LED,LOW); delay(500);
}
}
if (loggmode==1){
for(i=1;i<4;i++){
digitalWrite(LED_PIN,HIGH); digitalWrite(PEAK_LED,HIGH); delay(500);
digitalWrite(LED_PIN,LOW); digitalWrite(PEAK_LED,LOW); delay(500);
}
}
attachInterrupt(0,loggstrt,FALLING);
attachInterrupt(1,loggstp,FALLING);
loggsts=0;
}
void loop()
{
if(loggmode==1)
{
if(loggsts==1)
{
dataFile = SD.open("datalog.txt", FILE_WRITE);
if (dataFile) {
ptm=tm;
tm=millis();
int value = analogRead(0);
if(datapos == 1){dataFile.println("S");}
dataFile.print(tm-ptm);
dataFile.print(",");
dataFile.println(value);
if(datapos == 2){dataFile.println("E");}
datapos = 0;
dataFile.close();
Serial.print(tm-ptm);
Serial.print(",");
Serial.println(value);
if (value>730){digitalWrite(PEAK_LED,HIGH);}
else {digitalWrite(PEAK_LED,LOW);}
}
else {
Serial.println(F("error opening datalog.txt"));
}
}
}
if(loggmode==0)
{
if(loggsts==1)
{
dataFile = SD.open("colorlog.txt", FILE_WRITE);
if (dataFile) {
int val=1000;
digitalWrite(GATE,LOW);
digitalWrite(CK,LOW);
delayMicroseconds(2000);
digitalWrite(RANGE,HIGH);
digitalWrite(GATE,HIGH);
delay(val+1);
digitalWrite(GATE,LOW);
delayMicroseconds(4);
red=shiftIn();
green=shiftIn();
blue=shiftIn();
digitalWrite(GATE,HIGH);
ptm=tm;
tm=millis();
if(datapos == 1){dataFile.println("S");}
dataFile.print(tm-ptm);
dataFile.print(",");
dataFile.print(val,DEC);
dataFile.print(",");
dataFile.print(red,DEC);
dataFile.print(",");
dataFile.print(green,DEC);
dataFile.print(",");
dataFile.println(blue,DEC);
if(datapos == 2){dataFile.println("E");}
datapos = 0;
dataFile.close();
Serial.print(tm-ptm);
Serial.print(",");
Serial.print(val,DEC);
Serial.print(",");
Serial.print(red,DEC);
Serial.print(",");
Serial.print(green,DEC);
Serial.print(",");
Serial.println(blue,DEC);
if ((red>4000)||(green>4000)||(blue>4000)) {digitalWrite(PEAK_LED,HIGH);}
else {digitalWrite(PEAK_LED,LOW);}
}
else {
Serial.println(F("error opening datalog.txt"));
}
}
}
}
void dateTime(uint16_t* date, uint16_t* time)
{
uint16_t year = 2015;
uint8_t month = 7, day = 4, hour = 12, minute = 0, second = 0;
*date = FAT_DATE(year, month, day);
*time = FAT_TIME(hour, minute, second);
}
int shiftIn(){
int result=0;
for(int i=0;i<12;i++){
digitalWrite(CK,HIGH);
delayMicroseconds(1);
if(digitalRead(DOUT)==HIGH){
result+=(1<<i);
}
digitalWrite(CK,LOW);
delayMicroseconds(1);
}
delayMicroseconds(3);
return result;
}