前回、3GIMからサーバー側にデータを送信することができましたので、今回は以前利用したセンサ評価キットで実際にデータを取得して、それをサーバーに溜めていく「簡易データロガー」を作成してみます!
今回の電子工作レシピ
完成までの時間目安:60分
必要なパーツ
目次
- センサ評価キットとArduinoでデータを取得
- 取得したデータをサーバーに送信
- グラフ化してみる
- まとめ
1. センサ評価キットとArduinoでデータを取得
今回データロガーを作成するために、センサ評価キットのセンサは「第43回 複数のセンサを組み合わせた照明デバイス制作に挑戦!」で利用した気圧センサと温度センサを利用してみます。
第43回では温度センサ、気圧センサ、カラーセンサを搭載していますが、今回はカラーセンサを取り外して使います。ちなみに気圧センサと温度センサの電圧は3Vなので、センサ評価キットの電圧を決めるジャンパピンは3Vで設定します。
温度センサ・気圧センサの取得プログラムは下記のとおりです。
#include <Wire.h> #include <BD1020.h> //温度センサ用 #include <BM1383GLV.h> //気圧センサ用 BM1383GLV bm1383;//温度センサ用 int tempout_pin = A2; //温度センサ用ピン設定 BD1020 bd1020; //気圧センサ用 void setup() { Serial.begin(9600); while (!Serial); //温度センサ用 bd1020.init(tempout_pin); Serial.println("BD1020HFV Sample"); //気圧センサ用 byte rc; Wire.begin(); rc = bm1383.init(); } void loop() { //************************************ //温度センサ用 //************************************ float temp; bd1020.get_val(&temp); Serial.print("BD1020HFV Temp="); Serial.print(temp); Serial.print(" [degrees Celsius], ADC="); Serial.println(bd1020.temp_adc); delay(500); //************************************ //気圧センサ用 //************************************ byte rc; float press; rc = bm1383.get_val(&press); if (rc == 0) { Serial.write("BM1383GLV (PRESS) = "); Serial.print(press); Serial.println(" [hPa]"); Serial.println(); } delay(500); }
気圧と温度が正常に取得できていることが確認できたら、次はこのプログラムと3GIMの通信処理部分を組み合わせてみます。
2. 取得したデータをサーバーに送信
センサから取得したデータをサーバーに送信する部分を実装していきます。まず、回路に関してはセンサ評価キットシールドをArduinoの上に搭載したので、それを考慮しながら3GIMの配線をする必要があります。といっても、基本的にピン番号などは変える必要がないので、そのままArduinoに対応するセンサ評価キットのピン番号に配線すれば大丈夫です。
データを送信するプログラムは、前回のものをベースにして、データロガー自体の処理の流れとしては
- 各種センサから値を取得
- データを送信
- 一定時間待ってループ(1へ戻る)
となります。これを基本にして、センサの種類を増やしたり、データの送信部分を改良したり拡張を考えていくのがよいと思います。
センサデータ送信プログラム
// 3GIM(V2) sample sketch -- httpGET #include <SoftwareSerial.h> #include "a3gim.h" #include <Wire.h> #include <BD1020.h> //温度センサ用 #include <BM1383GLV.h> //気圧センサ用 BM1383GLV bm1383;//温度センサ用 int tempout_pin = A2; //温度センサ用ピン設定 BD1020 bd1020; //気圧センサ用 SoftwareSerial Serial3g(4,5); #define baudrate 9600UL const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.) const char *server = "deviceplus.jp"; const char *path = ""; int port = 80; char res[a3gsMAX_RESULT_LENGTH+1]; int len; String imei = ""; int rssi = 0; float lat = 0; float lng = 0; int height = 0; int utc = 0; int number = 0; int quality = 0; String date = ""; // setup AGPS function void setupAGPS() { char apn[20], user[20], password[20]; if (a3gs.getDefaultProfile(apn, user, password) == 0) { char atwppp[50]; sprintf(atwppp,"at+wppp=2,4,\"%s\",\"%s\"",user,password); Serial.println(atwppp); a3gs.enterAT(2); a3gSerial.println(atwppp); delay(200); Serial.println("Assisted GPS set OK"); } else Serial.println("NG: getDefaultProfile(), can't use AGPS.."); } void setup() { Serial.begin(baudrate); Serial3g.begin(38400); delay(3000); // Wait for Start Serial Monitor Serial.println("Ready."); //温度センサ用 bd1020.init(tempout_pin); Serial.println("BD1020HFV Sample"); //気圧センサ用 byte rc; Wire.begin(); rc = bm1383.init(); } void loop() { //************************************ //1.センサからデータを取得する //************************************ //温度センサのデータを取得 float temp; bd1020.get_val(&temp); Serial.print("BD1020HFV Temp="); Serial.print(temp); Serial.print(" [degrees Celsius], ADC="); Serial.println(bd1020.temp_adc); delay(500); //気圧センサのデータを取得 byte rc; float pressure; rc = bm1383.get_val(&pressure); if (rc == 0) { Serial.write("BM1383GLV (PRESS) = "); Serial.print(pressure); Serial.println(" [hPa]"); Serial.println(); } delay(500); //************************************ //2.3GIMでデータをサーバーに送信 //************************************ Serial.print("Initializing.. "); if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) { Serial.println("Succeeded."); delay(25000); // ウェイトを持たせる Serial.println("httpGET() requesting.. "); len = sizeof(res); //*************************************************** //get rssi //*************************************************** if (a3gs.getRSSI(rssi) == 0) { Serial.print("RSSI = "); Serial.println(rssi); if(rssi > 0 || rssi <= -113 ){ //電波強度が取得できない場合は最初から Serial.println("retry."); return; } } else{ //電波強度が取得できない場合は最初から Serial.println("retry."); return ; } //*************************************************** //get imei //*************************************************** char imei[a3gsIMEI_SIZE]; if (a3gs.getIMEI(imei) == 0) { Serial.print("IMEI: "); Serial.println(imei); } //*************************************************** //get time //*************************************************** char date[a3gsDATE_SIZE], time[a3gsTIME_SIZE]; if (a3gs.getTime(date, time) == 0) { Serial.print("DATE:"); Serial.print(date); Serial.print(" "); Serial.println(time); } //*************************************************** //GPS-location //*************************************************** setupAGPS(); char lat[15], lng[15], utc[7], height[8]; if (a3gs.getLocation2(lat, lng, height, utc, &quality, &number) == 0) { Serial.print("OK: "); Serial.print(lat); Serial.print(","); Serial.print(lng); Serial.print(","); Serial.print(height); Serial.print(","); Serial.print(utc); Serial.print(","); Serial.print(quality); Serial.print(","); Serial.println(number); } String pathStr = "/api.php?imei="; String tempS = String(temp); //温度センサの値 String pressureS = String(pressure); //気圧センサの値 String imeiS = String(imei); String rssiS = String(rssi); String latS = String(lat); String lngS = String(lng); String utcS = String(utc); String qualityS = String(quality); String numberS = String(number); String heightS = String(height); String dateS = String(date); String timeS = String(time); pathStr = pathStr+imeiS+"&rssi="+rssiS+"&rssi="+tempS+"&="+pressureS+"&utc="+utcS+"&lat="+latS+"&lng="+lngS+"&quality="+qualityS+"&number="+numberS+"&height="+height+"&datetime="+dateS+"%20"+timeS; int rst = a3gs.httpGET(server, port, pathStr.c_str(), res, len); Serial.print("URL:"); Serial.println(server); Serial.println(""); Serial.print("PATH:"); Serial.println(pathStr); Serial.print("RESULT:"); Serial.println(rst); if (rst == 0) { Serial.println("OK!"); Serial.print("["); Serial.print(res); Serial.println("]"); } else { Serial.print("Can't get HTTP response from "); Serial.println(server); } } else{ Serial.println("Failed."); } Serial.println("Shutdown.."); a3gs.end(); a3gs.shutdown(); } // END
シリアルモニタで正常に送信できていることが確認できました。ただ、今回コンパイルをした際に「スケッチで使用できるメモリが少なくなってしまっています。動作が不安定になる可能性があります」との表示がArduinoのソフトウェアに表示されました。
プログラムが処理が多くArduino内のメモリが少なくなると、Arduinoの実行時にメモリを多く使う処理などが走った際にArduinoが正常に動作しなくなってしまう可能性があります。このような場合は、メモリの多い別のArduinoを利用するか、無駄な処理をできるだけ削除してメモリを軽くするかどちらかの対策をとると良いです。
3. グラフ化してみる
せっかくなので、前回は表で表示するだけだったサーバー側も、少し手を加えてグラフで表示してみます。サーバーサイドでの表示は、プログラムや方法がいろいろあるので、自分がやりやすい方法を選択してもらえればよいのですが、手軽にグラフを表示できるサービスとして、Google Chartsを今回使ってグラフ化してみました。Google Chartsはjavascriptでシンプルな表記で様々な種類のグラフを表示することができるので、簡単にデータを表示したい場合などに適しています。
Google Chartsのページで紹介されているサンプルコードを見ていただくとわかるのですが、javascriptのプログラム部分に表示したいデータやグラフの設定を行い、表示したいタグのIDを指定することでグラフの表示が可能です。
実際に取得した気圧、温度をグラフにしたのが下記の図です。
グラフで表示されるとわかりやすくなりますね(今回の例ではあまり変動がありませんでしたが)。
まとめ
簡易的ですがデータロガーが完成しました。これでいつでも好きな場所でセンサデータを取得できるようになりましたが、まだ大きな課題が残されています。それはやはり「電源」。常時データロガーをオンにしておくと、電源が常に必要になってしまい、せっかく3G通信でどこでも通信できても電源の確保が必要になってしまいます。次回はデータロガーの電源周りの対策について考えてみます。
■関連記事
SORACOM Air×3GIMによるArduinoの3G通信〜センサ評価キットと組み合わせてデータロガー作成(3)
SORACOM Air×3GIMによるArduinoの3G通信〜Arduinoで3G通信をする方法(2)
SORACOM Airを使ってArduinoで通信できる?~Arduinoで3G通信をする方法(1)
ラズベリーパイとSORACOM Airでインターネット接続!(1)登録編