前回は、GPSからの受信データを簡単に扱うことのできるライブラリ、TinyGPS++を使ってみました。今回はSDカードに書き込む部分を追加する予定でしたが、「TinyGPS++ の、location.isUpdated() がtrueのときに、緯度/経度/高度をSDカードに書き込む、という部分は、それほど難しくなく実装できるうえ、これでは時間の情報が残らないため、GPSのログとしては物足りません。なので、緯度/経度/高度だけでなく、日付や時間を一緒に残すように書き換えてみたいと思います。
Arduino IDEでは、ライブラリの中身をエディタから参照できないので(僕が知る限り)、ひとまずライブラリの中身をの覗いて作戦を立てます。
/Arduino/libraries/TinyGPSPlus/src/TinyGPS++.cppとヘッダ をXcodeで開いてツラツラと眺めてみたところ、時間が更新されたかどうかは、TinyGPSTimeのupdated というフラグを見てやるのがよさそうです。
TinyGPSDateという構造体もあって、日付をまたぐ場合は、こいつのupdatedを見ないといけないかな?とも思いましたが、それって基本的に時間も更新されてるはずなので、TinyGPSTime だけ見ればよいのかなと思います。ただ、日付が入っているGPSのセンテンスと、時間が入っているGPSのセンテンスが違ったような気がするので、必ずしも日付と時間が同じタイミングで更新されるかどうかはちょっと怪しいですね。深掘りした方がよいのでしょうが、とりあえず今の段階では、TinyGPS++の時間が更新されたタイミングで、日付、時刻、位置情報を書き込むことにします。なので、受信状態がよければ、基本的に1秒間隔のデータが出来上がるはずです。
ちょっと整えてみたものがこちら。(改行が多いとよく言われますが、僕としてはこれが読みやすいと思っています)
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <SD.h>
#define SERIAL_BAUD 9600
const int GPS_RX = 8;
const int GPS_TX = 9;
const int CHIP_SELECT = 4; //for SD
TinyGPSPlus gps;
SoftwareSerial gpsSerial(GPS_RX, GPS_TX);
void setup() {
Serial.begin(SERIAL_BAUD);
while (!Serial) {} // wait
Serial.println("serial initialized\n");
gpsSerial.begin(9600);
setupSD();
}
void loop() {
while (gpsSerial.available() > 0) {
char c = gpsSerial.read();
//Serial.print(c);
gps.encode(c);
if (gps.time.isUpdated()) {
writeData();
Serial.print("year : "); Serial.println(gps.date.year());
Serial.print("mon : "); Serial.println(gps.date.month());
Serial.print("day : "); Serial.println(gps.date.day());
Serial.print("hour : "); Serial.println(gps.time.hour());
Serial.print("min : "); Serial.println(gps.time.minute());
Serial.print("sec : "); Serial.println(gps.time.second());
Serial.print("lat : "); Serial.println(gps.location.lat(), 6);
Serial.print("lng : "); Serial.println(gps.location.lng(), 6);
Serial.print("alt : "); Serial.println(gps.altitude.meters());
}
}
}
void setupSD() {
Serial.print("Init SD.");
if (!SD.begin(CHIP_SELECT)) {
Serial.println("Card failed, or not present");
while (1);
}
Serial.println("SD initialized.");
}
void writeData() {
File dataFile = SD.open("gps.log", FILE_WRITE);
if (dataFile) {
String str;
str = String(gps.date.year());
str += "/";
str += String(gps.date.month());
str += "/";
str += String(gps.date.day());
str += ",";
str += String(gps.time.hour());
str += ":";
str += String(gps.time.minute());
str += ":";
str += String(gps.time.second());
str += ",";
str += String(gps.location.lat(), 6);
str += ",";
str += String(gps.location.lng(), 6);
str += ",";
str += String(gps.altitude.meters());
dataFile.println(str);
dataFile.flush();
} else {
Serial.println("error opening gps.log");
}
dataFile.close();
}
しばらく走らせてみて、出来上がったファイルはこんな感じです。
同じ時刻に2回保存されているのは、時間を更新するセンテンスが2回くるからですかね。。。最後に書き込んだ時刻を見て、重複する場合は書き込まない、とした方がきれいかもですね。
途中で信号が切れた場合どうなるのか、など、ちょっと挙動がわからない部分があるので検証が必要です。5日にSIAFラボのメンバーでちょっと長い距離を歩くので、それまでに動作確認したいと思います。