Arduinoに接続したGPS受信機の測位データをSDカードに記録しました。

GPS受信機をどう使うの?

  • Arduino UNO R3にGPS受信機とSDデータロガーを接続しGPS測位データをSDカードに保存します。
  • 携帯性と操作性を向上するためにGPSシールドを自作します。
関連する記事は?

必要な部品は?

GPS受信機1個
Arduino UNO R31個
10KΩ抵抗1個
ダイオード1個
SDデータロガーシールド1個
関連する製品・商品の購入先は?

GPS受信機をSDデータロガーシールドと接続する回路図(接続図)は?

  • SDデータロガーシールドをArduino UNO R3に接続して、GPS受信機を接続します。
  • ArduinoとGPS受信機の通信はSoftware Serialを使用します。Arduinoの通信用ポートは、2Pin(RX)と3Pin(TX)を使います。

GPSシールドをどのように自作するの?

  • Arduino UNO用のユニバーサル基板を使ってGPSシールドを作成します。
  • ブレッドボードで配線しても動作して測定はできますが、移動させる場合は配線が外れたり、電気部品がショートしたりする心配があります。
  • ワイヤーで接続すると屋外に持ち出してGPS信号を取得する時にArduinoの設置や向きが制限されます。またPCの横に置いて測位するときにワイヤーがあると引っかけたりして気になります。扱いが簡単になるようにGPSシールドを自作しました。
  • GPSシールドはArduino UNO用のユニバーサル基板に部品を取り付け、配線して作ります。KiCADで回路図を描いて、部品間の距離や完成時の構成をイメージしながらPCBレイアウトをします。
  • KiCADは、オープンソースの電気回路設計・基板設計CADです。
  • PCBレイアウトが決まれば、それに従って部品と線材を半田付けします。SDデータロガーシールドに差し込み、さらにArduino UNO R3に差し込めば完成です。PCに接続して動作確認します。
KiCADを使ったPCBレイアウトに関連する記事は?

GPS受信機から送信されるデータの記録方法は?

  • GPS受信機から選択した測位データ(GPGGAセンテンス)を送信させて、SDカードに保存します。
スケッチの動作
  1. GPS受信機からGPGGAのみ2秒間隔で送信するように設定し、送信される信号は有効であるかどうか(測位しているかどうか)は判定せず、SDカードにデータを保存します。
  2. データファイルはRTC(実時間モジュール)から得た時間情報のタイムスタンプで保存します。
  • [jpegカメラで屋外の風景を撮影をしました]で風景を撮影した「せせらぎ公園」の周辺を歩いてGPS受信機から送信される測位データを取りました。作成したGPSシールドを差し込んだArduino UNO R3に携帯用のバッテーリーから給電して使いました。
  • GPGGAセンテンスのみ保存されています。
  • 完成したスケッチです。
//----------------------------------------------
//https://arduinomakesiteasy.com/
//----------------------------------------------

#include <SoftwareSerial.h>
#include <TimeLib.h>
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <DS3231.h>

//SoftwareSerial 
SoftwareSerial myGPSSerial(2,3); //rx=2 tx=3

//RTC(実時間) module
DS3231 clock;
RTCDateTime dt;

//SD module
const int chipSelect = 10;  //SDカードCS
File logFile;
char fileName[16];
int fileNum = 0;

//TimeStamp matrix (ファイル作成時のタイムスタンプ)
char timestamp[30];

//Variables
String GPSString;

//----------------------------------------------
//setup()
//----------------------------------------------
 
void setup(){
  Serial.begin(9600); //シリアルモニタの開始
  delay(500); //待ち時間 0.5秒 
  init_RTC(); //RTC初期化  
  init_GPS(); //GPS初期化
  init_SD();  //SDカード初期化
}

//----------------------------------------------
//loop()
//----------------------------------------------
 
void loop(){

  //実時間取得
  dt = clock.getDateTime();
  
  // ソフトウェアシリアルのデータは改行まで取り込みSDカードに保存する
  if (myGPSSerial.available()){
        GPSString = myGPSSerial.readStringUntil('\n');
        Serial.println(GPSString.c_str());

        logFile = SD.open(fileName, FILE_WRITE);
        logFile.write(GPSString.c_str()); 
        logFile.close();    
  }

  // ソフトウェアシリアルのデータがオーバーフローしている場合はメッセージを出す
  if (myGPSSerial.overflow()) {
      Serial.println("myGPSSerial overflow!");
  }    
}

//----------------------------------------------
//RTCの初期化
//----------------------------------------------

void init_RTC(void){

  Serial.print("RTC Start ---> ");

  // Initialize DS3231
  clock.begin();
 
  //スケッチのコンパイル時の時刻をRTCモジュールに書き込む
  //1回目はこのままコンパイル実行する、
  //2回目にコメントアウトして再度コンパイル実行する
  clock.setDateTime(__DATE__, __TIME__);    

  Serial.println("Done");
 
}

//----------------------------------------------
//GPSの初期化
//----------------------------------------------

void init_GPS(void){
  
  Serial.print("GPS Start ---> ");
   
  myGPSSerial.begin(9600); //GPSと通信開始、GPSデフォルトの通信レート9600

  //GPSモジュールの設定を行う。一回実行すればGPSモジュールに設定は残るので、コメントアウトして再度書き込めば良い。
  //myGPSSerial.print("$PMTK314,0,5,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n"); //$GGA、RMCのみ5秒間隔で送信
  //myGPSSerial.print("$PMTK314,-1*04\r\n"); //設定値のリセット
    
  myGPSSerial.print("$PMTK314,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*2A\r\n"); //$GGAのみ2秒間隔で送信

  //GPSモジュールのの設定後にGPSモジュールから返信があることを確認する
  while(!myGPSSerial.available()){
    delay(500);
  }

  //GGPSモジュールからの返信をバッファから除去する
  GPSString = myGPSSerial.readStringUntil('\n');
  
  Serial.println("Done");
}

//----------------------------------------------
//SDカード初期化とログファイル作成、タイムスタンプ設定
//----------------------------------------------

void init_SD(void){//SDカード初期化とログファイル作成、タイムスタンプ設定
  
  Serial.print("SD Start ---> ");
  
  while (!SD.begin(chipSelect)) {
    Serial.println("Failed during starting");
    //won't do anything later
    return;
  }
  Serial.println("Done");

  //ファイル作成・更新時のタイムスタンプを記録するスケッチ------------------------------
  SdFile::dateTimeCallback(dateTime);
  sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n",dt.hour,dt.minute,dt.second,dt.month,dt.day,dt.year-2000);
  //------------------------------------------------------------------------------

  boolean fileexist = false;
  String t;
  
  //既存のファイルのファイル名と重複しなければファイル名とする
  while(!fileexist){
    t = "GPS";
    if (fileNum < 10){
      t += "00";
    }
    else if(fileNum < 100){
      t += "0";
    }
    t += fileNum;
    t += ".LOG";
    t.toCharArray(fileName, 16);
    if(!SD.exists(fileName)) {
      fileexist = true;
    }
    fileNum++;
  }
  
  // ログファイルの1行目に”GPS NMEA Data ......”と書き込む
  logFile=SD.open(fileName, FILE_WRITE);
  logFile.println("GPS NMEA Data ......");
  logFile.close();
}

//----------------------------------------------
//call back for file timestamps
//----------------------------------------------

void dateTime(uint16_t *date, uint16_t *time) {
 sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n",dt.hour,dt.minute,dt.second,dt.month,dt.day,dt.year-2000);
 *date = FAT_DATE(dt.year,dt.month,dt.day); // return date using FAT_DATE macro to format fields
 *time = FAT_TIME(dt.hour,dt.minute,dt.second); // return time using FAT_TIME macro to format fields
}
  • 使用したライブラリと機能
#include <SoftwareSerial.h>
#include <TimeLib.h>
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <DS3231.h>
ライブラリ機能
SoftwareSerial.hGPS受信機とのシリアル通信を行う
TimeLib.hArduinoのシステム時間を扱う
SPI.hSPI通信を行う (SDカードへの記録のため)
SD.hSDカードへの書き込み
Wire.hI2C通信を行う(RTCモジュールとの通信のため)
DS3231.hRTCモジュールの操作
myGPSSerial.print("$PMTK314,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*2A\r\n");
  • 保存するファイルにRTC(実時間モジュール)からの時間情報を使ってタイムスタンプを設定する機能を加えています。
  • 初期設定: ライブラリの設定およびRTC(実時間)モジュールのインスタンス設定をする
#include <TimeLib.h>
#include <Wire.h>
#include <DS3231.h>

//RTC(実時間) module
DS3231 clock;
RTCDateTime dt;
  • setup()でSDファイルの設定をする箇所に下記を加える
  //ファイル作成・更新時のタイムスタンプを記録するスケッチ------------------------------
  SdFile::dateTimeCallback(dateTime);
  sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n",dt.hour,dt.minute,dt.second,dt.month,dt.day,dt.year-2000);
  //------------------------------------------------------------------------------
  • dateTime関数を加える
//----------------------------------------------
//call back for file timestamps
//----------------------------------------------

void dateTime(uint16_t *date, uint16_t *time) {
 sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n",dt.hour,dt.minute,dt.second,dt.month,dt.day,dt.year-2000);
 *date = FAT_DATE(dt.year,dt.month,dt.day); // return date using FAT_DATE macro to format fields
 *time = FAT_TIME(dt.hour,dt.minute,dt.second); // return time using FAT_TIME macro to format fields
}
  • loop()内で時間取得する
  //実時間取得
  dt = clock.getDateTime();
  • RTC(実時間モジュール)の時間設定はデータ書き込みの時間を書き込んでいる。このコードは一回ボードに書き込むとRTC(実時間モジュール)に時間を書き込む。このままにしておくと、PCに繋がない状態でもRTC(実時間モジュール)に時間を書き込む動作をしてしまうので、この行をコメントアウトしてコードをボードに書き込むことで時間を書き込む動作を実行しなくなる。
  clock.setDateTime(__DATE__, __TIME__);    
  • データバッファのオーバーフローに注意
  • GPS受信機からは連続でNMEAセンテンスが送信されています。Arduino UNO R3の通信用のバッファは64バイトしかないので、送信データの処理よりも送信データの送信量が多ければバッファがオーバーフローします。オーバーフローをしないように、処理速度を上げる、送信データを減らすなどの工夫が必要になります。
  • スケッチはオーバーフローした時に、シリアルモニタに””myGPSSerial overflow!”のメッセージを出力します。
  if (myGPSSerial.overflow()) {
      Serial.println("myGPSSerial overflow!");
  }    
GPS受信機の設定方法や測位データの扱い方に関連する記事は?

ご質問、誤植の指摘などありましたら。「問い合わせ 」のページからお願いします。