サイクルコンピュータを自作する #2 – みちびき対応 GPS と市販のサイコンの比較実験

先の記事で延べた日本の準天頂衛星システム(QZSS)『みちびき』とそれに対応した GPS モジュール GYSFDMAXB を使用すると、衛星電波から現在時刻や位置情報や高度を手軽に取得することが可能になります。

これによって得られた情報を無線で送信すれば盗難車の追跡にも利用できますし、受信データを記録媒体に書き残し、ケイデンスセンサ等の補助的なデータを付与して FIT ファイル形式にエンコーディングしてやれば、サイクルコンピュータ(サイコン)替わりにライド情報を記録する装置を自作することも難しくはありません。

もちろん、最近のサイコンは GPS データを受信できるものも少なくないので、そちらを購入すれば間違いないことは確かです。

わざわざ時間と労力をかけてサイコンを自作する意味はありませんが、たとえばブルベで一度に 300km 以上を走行したり、九州一周を一筆書きしたい場合などには、それなりに実用性があるかもしれません。

なにしろ自作なので、いくらでもバッテリ容量を増やせますし、ディスプレイなど不要だと思えば付けなくても構わないわけです。




GPS モジュール単体でも現在時刻や位置座標に加えて高度と移動速度を取得することが可能なので、サイコンと同様のデータを記録したければ、これに温度センサやケイデンスセンサなどを付け足せば、市販品と同じ記録装置ができるはずです。

それでは肝心の GPS モジュールの精度は、GPS 搭載サイコンと比較してどのようなものなのでしょうか。気になったので、手元にある GPS 端末と一緒に計測にいってきました。

比較対象は GARMIN の EDGE 520 (サイクルコンピュータ, 2015年発売)と OREGON 600 (ハンドヘルドデバイス, 2013年発売) そして ForeAthlete230J (ランニングウォッチ, 2016年発売) の3点です。

4つのデバイスを同じカバンに入れて御苑や皇居の周辺を歩いてきたのですが、なぜか最初は ForeAthlete230J の計測ができておらず、途中からは仮組みだけで溶接していなかった GPS モジュールが断線する(ジャンパワイヤが抜ける)というアクシデントが発生したので、結局、4つまとめての計測は行なえませんでした。

しかし、計測できた部分だけでも見比べてみると、それぞれの性質の違いがよく見えてきます。GPSモジュールの位置情報ログが黒、EDGE 520 のそれが赤、ForeAthelete230J 青、 OREGON 600 紫です。

実験前は『みちびき』対応の GPS モジュールが正確さで圧倒するものかと思えましたが、GARMIN が意外にも検討していますね。それでも高架下やトンネルに弱い点は、この結果だけで分かってしまいます。

GPS モジュールの『みちびき』対応の成果は交差点や曲がり角に見て取れます。一方でモジュールは振れ幅も大きく、実際に通った場所からみて反対車線を通行したことになっていたり、まったく無関係な位置情報を拾っていたりもします。この辺り、GARMIN は受信したデータを内部でフィルタリングしているのかもしれません。

いざサイコンを作ってみようとなると検討すべき項目がいろいろ出てきますね。


計測環境をより詳しく知りたい人は以下を見てください。

計測日時 2020年6月25日 17:06 – 18:26
天候 曇り/雨
気温 25℃
湿度 78%
風速 3m/s from SSE
出力 GYSFDMAXB TXT/CSV
EDGE 520 FIT
FOREATHLETE 230J FIT
OREGON 600 GPX

GPS モジュール GYSFDMAXB は単体ではデータを記録することはできませんので、マイコンボードを経由して microSD カードにGPS受信ログを記録させています。

ここではマイコンボードに Arduino (IDE ver. 1.8.13), microSDカードスロットに AE-MICRO-SD-DIP, 記録媒体に SanDisk Ultra PLUS SDHC 16GB を使用しています。

MicroSDカードを FAT Format でフォーマットすると AE-MICRO-SD-DIP を用いてマイコンから読み書きできるようになりますので、Arduino IDE の Files > Examples > SD > ReadWrite からサンプルスケッチを読み込み、ファイル書き込み部分に GPS モジュールの出力を入れると簡単に実装できます。

今回、使用したのは以下のスケッチです。

#include 
#include 

#include 
#include 

SoftwareSerial mySerial(9, 10); // RX, TX
TinyGPSPlus gps;

void setup() {
  Serial.begin(57600);
  mySerial.begin(9600);  // Open serial communications and wait for port to open:
  while (!mySerial) {
    Serial.print("waiting for serial port to connect");
  }
  Serial.print("Initializing SD card...");
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");
}

void loop() {
  if (mySerial.available()) {
    gps.encode(mySerial.read());
    if (gps.location.isUpdated())
    {
      // open the file. note that only one file can be open at a time,
      // so you have to close this one before opening another.
      File myFile = SD.open("test.txt", FILE_WRITE);
      // if the file opened okay, write to it:
      if (myFile) {
        // timestamp
        myFile.print(gps.date.year());
        myFile.print(',');
        myFile.print(gps.date.month());
        myFile.print(',');
        myFile.print(gps.date.day());
        myFile.print(',');
        myFile.print(gps.time.value());
        myFile.print(',');
        // location
        myFile.print(gps.location.lat(), 6);
        myFile.print(',');
        myFile.print(gps.location.lng(), 6);
        myFile.print(',');
        myFile.print(gps.altitude.meters(), 6);
        myFile.print(',');
        // ground speed
        myFile.print(gps.speed.mps());//in meters per second (double)
        myFile.print(',');
        myFile.print(gps.speed.mph());//in miles per hour (double)
        myFile.print(',');
        myFile.print(gps.speed.kmph());// in kilometers per hour (double)
        myFile.print(',');
        // satellite 
        myFile.print(gps.satellites.value()); // Number of satellites in use (u32)

        myFile.println();
        myFile.close();     // close the file:
      } else {
        // if the file didn't open, print an error:
        Serial.println("error opening test.txt");
      }
    }
  }
}

スケッチをマイコンボードに書き込みましたら、ボードとモジュールをワイヤで接続していきます。GPS モジュール GYSFDMAXB はスケッチで指定した SS に RXD, TXD を接続して 5V 出力と GND は素直にそれぞれを接続すれば問題ありません。

SD カードスロットの方は、ピンがたくさんあって少しだけ複雑です。SD カードの裏側の端子(金色の窓の部分)は、たしか1つづつ別の役割があって、それがこのピンの数だけ・・・ 何だったかなと思っていたら、良い記事がありました。


Arduinoでパーツやセンサを使ってみよう~SDカード編(その1) | Device Plus – デバプラ
https://deviceplus.jp/hobby/entry021/


この記事通りにやっておけば、間違いがなさそうです。

ただ1点だけ AE-MICRO-SD-DIP の取扱説明書に記載されている DAT1 と DAT2 はそれぞれ data line 1 と 2 で「使いません」というか、予約されていて使えませんというほうが正しかった気がします(要確認)。

AE-M-SD-DIP ARDUINO UNO Pin
#2 CD/DAT3 chip select D4 #4
#3 CMD/DI host command/data MOSI #11
#4 VDD supply voltage 3V3 3.3V
#5 CLK clock SCL #13
#6 VSS supply ground GND GND
#7 DAT0 host data/status MISO #12

とりあえずは使えることを優先して、配線して通電すると下のようなファイルが microSD カードに作成されます。上のスケッチで記述した通り、年、月、日、時刻、緯度、軽度、高度、移動速度、捕捉衛星数が書き込まれている事が分かります。

2020,6,25,8142100,35.688156,139.704177,19.200000,2.64,5.90,9.50,8
2020,6,25,8142200,35.688156,139.704162,19.200000,2.64,5.90,9.50,7
2020,6,25,8142200,35.688156,139.704162,19.200000,1.48,3.31,5.33,7
2020,6,25,8142300,35.688159,139.704162,19.100000,1.48,3.31,5.33,8
2020,6,25,8142300,35.688159,139.704162,19.100000,1.01,2.26,3.63,8
2020,6,25,8142400,35.688171,139.704147,18.899999,1.01,2.26,3.63,8
2020,6,25,8142400,35.688171,139.704147,18.899999,1.36,3.05,4.91,8
2020,6,25,8142500,35.688194,139.704086,19.299999,1.36,3.05,4.91,8
2020,6,25,8142500,35.688194,139.704086,19.299999,2.15,4.80,7.72,8
2020,6,25,8142600,35.688209,139.704040,19.399999,2.15,4.80,7.72,8
2020,6,25,8142600,35.688209,139.704040,19.399999,2.54,5.67,9.13,8
2020,6,25,8142700,35.688209,139.703994,19.299999,2.54,5.67,9.13,7

OREGON 600 が出力する GPX ファイルと比較すると、こんな風になります。GPX ファイルの中身がおよそ 1 秒おきに記録されているのと比較すると、GPS モジュール GYSFDMAXB のほうは重複なしに同時刻に2回記録されていることが少し気になります。

ちなみに OREGON 600 が出力する GPX ファイルは XML に他ならないので、XML parser を使うとカンマ区切りのテキストファイルに容易に変換できます。

const parser = require('xml2json');
const fs = require('fs');
const xml = fs.readFileSync(process.argv[2], 'utf-8');
const json = JSON.parse(parser.toJson(xml));
for (const trk of json.gpx.trk.trkseg.trkpt) console.log(trk.time + ',' + trk.lat + ',' + trk.lon + ',' + trk.ele);

ここから位置情報を地図上に描画するには、下の記事を参考にされてください。


Garmin / Strava の走行記録をまとめて表示する


GARMIN Edge や Forerunner/ForeAthlete の FIT ファイルを地図上に表示するには以下の記事を参考にされると簡単です。


アプリを使ってライド記録を地図上に描こう


ここまでで今回は GPS 位置座標を比較しましたが、GPS受信データにはまだ他に高度や移動速度などの項目が含まれています。新宿駅東口の海抜がおよそ 37m 程度、新宿御苑周辺の海抜が 33.5m 程度なので、一見すると高度には大きな誤差はなさそうに見えますが、詳しくは調べてみないと分かりませんね。

それからサイコンとして使用するからには晴天の日にも自転車での移動速度の計測してみたいところです。いまのところデータセットが足りていないので、比較検証のためには増やしたい一方、計測する側からすると負担が大きいので端末の数を減らしたいところです。

もう少しデータセット増やしたいんですけどねえ。

Leave a Reply

Your email address will not be published. Required fields are marked *