ArduinoでGPS

GPSモジュールの出力

GPSモジュールのシリアル出力はNMEAフォーマット。
上記モジュールはデフォルトでは9600ボー。

ライブラリ

TinyGPS++を利用する。

Arduino

ログをPCで取得するならシリアルが2系統必要。
SoftwareSerialでもよいが、今回はSerial1のあるGR-CITRUSを使用。
Serial(USB)をPCとの通信、Serial1(TX:0, RX:1)をGPSモジュールとの通信に使用。

結線

GPSモジュール GR-CITRUS 備考
5V 5V GR-CITRUSから給電する。ボタン電池は不使用。
GND GND
RX 0 Serial1のTX。3.3Vレベルであることに注意(※) 今回は不使用。
TX 1 Serial1のRX。3.3Vレベルであることに注意(※)
1PPS 接続しない 1秒周期のパルス出力。今回は不使用。

※ 5V系Arduinoの場合はレベル変換が必要。


LED・電池

モジュールに給電するとまず橙色LEDが弱く点灯する。しばらく待ってモジュールが衛星を捕捉すると橙色LEDが1秒周期で点滅するようになる。
バックアップ電池(CR2032)を付けておくと衛星情報などが保持されて、再起動時の測位開始にかかる時間を短縮できる。

スケッチ

#include <TinyGPS++.h>
 
TinyGPSPlus gps;
 
void setup()
{
    Serial.begin(115200);
    Serial1.begin(9600); // 秋月のGPSモジュールはデフォルト9600ボー
    
    while (!Serial) { ; }
}
 
void loop()
{
    while (Serial1.available() > 0){
        char c = Serial1.read();
        // Serial.print(c);

        // シリアル受信データを1文字づつ食わせる
        gps.encode(c);
        // 位置情報が更新されたか?
        if (gps.location.isUpdated()){
            // 緯度・経度・標高を取得
            Serial.print("LAT=");  Serial.println(gps.location.lat(), 6);
            Serial.print("LONG="); Serial.println(gps.location.lng(), 6);
            Serial.print("ALT=");  Serial.println(gps.altitude.meters());
        }
    }
}

isValid(), isUpdated(), age()

  • isValid() : データが有効か?
  • isUpdated():データが更新されたか? (変化したとは限らない)
  • age():最後の更新からの経過時間 [msec]

取得できるデータ

// 位置
Serial.println(gps.location.lat(), 6);  // 緯度[度] (double)
Serial.println(gps.location.lng(), 6);  // 経度[度] (double)
Serial.print  (gps.location.rawLat().negative ? "S" : "N"); // 南北 (bool)
Serial.println(gps.location.rawLat().deg);       // 整数部          (uint16_t)
Serial.println(gps.location.rawLat().billionths);// 小数部(1/10億)  (uint32_t)
Serial.print  (gps.location.rawLng().negative ? "W" : "E"); // 東西 (bool)
Serial.println(gps.location.rawLng().deg);       // 整数部          (uint16_t)
Serial.println(gps.location.rawLng().billionths);// 小数部(1/10億)  (uint32_t)
// 日付
Serial.println(gps.date.value());       // 日付(DDMMYY)   (uint32_t)
Serial.println(gps.date.year());        // 年(西暦下2桁)  (uint16_t)
Serial.println(gps.date.month());       // 月(1-12)       (uint8_t)
Serial.println(gps.date.day());         // 日(1-31)       (uint8_t)
// 時刻
Serial.println(gps.time.value());       // 時刻(HHMMSSCC) (uint32_t)
Serial.println(gps.time.hour());        // 時(0-23)       (uint8_t)
Serial.println(gps.time.minute());      // 分(0-59)       (uint8_t)
Serial.println(gps.time.second());      // 秒(0-59)       (uint8_t)
Serial.println(gps.time.centisecond()); // 1/100秒 (0-99) (uint8_t)
// 速度
Serial.println(gps.speed.value());      // 速度[1/100ノット] (int32_t)
Serial.println(gps.speed.knots());      // 速度[ノット]      (double)
Serial.println(gps.speed.mph());        // 速度[マイル/時]   (double)
Serial.println(gps.speed.mps());        // 速度[m/s]         (double)
Serial.println(gps.speed.kmph());       // 速度[km/h]        (double)
// 進路(方位)
Serial.println(gps.course.value());     // 方位[1/100度] (int32_t)
Serial.println(gps.course.deg());       // 方位[度]      (double)
// 標高
Serial.println(gps.altitude.value());       // 標高[cm]       (int32_t)
Serial.println(gps.altitude.meters());      // 標高[m]        (double)
Serial.println(gps.altitude.miles());       // 標高[マイル]   (double)
Serial.println(gps.altitude.kilometers());  // 標高[km]       (double)
Serial.println(gps.altitude.feet());        // 標高[フィート] (double)
// 利用できる衛星の数
Serial.println(gps.satellites.value()); // (uint32_t)
// HDOP(水平精度低下率)
Serial.println(gps.hdop.value());       // (LSB=0.01 int32_t)

応用

NMEAの特定のフィールドのデータを抽出して取得することもできる。
だだし、数値であっても解釈されず文字列 (char*) として返す。

#include <TinyGPSPlus.h>

TinyGPSPlus gps;

// $GNGSA の 15~17個目フィールドを抽出するオブジェクト
// ($GPGSA:GPSのみ, $GNGSA: GPS+GLONASS等)
TinyGPSCustom pdop(gps, "GNGSA", 15);
TinyGPSCustom hdop(gps, "GNGSA", 16);
TinyGPSCustom vdop(gps, "GNGSA", 17);

void setup() 
{
    Serial.begin(115200);
    Serial1.begin(9600);
    while (!Serial) { ; }
}

void loop() 
{
    while (Serial1.available() > 0) gps.encode(Serial1.read());
    
    if (pdop.isUpdated() || hdop.isUpdated() || vdop.isUpdated())
    {
        Serial.print(F(" PDOP=")); Serial.print(pdop.value()); 
        Serial.print(F(" HDOP=")); Serial.print(hdop.value()); 
        Serial.print(F(" VDOP=")); Serial.println(vdop.value());
    }
}

参考記事


【追記】M5Stack用GPSユニットでも動作確認OK