M5Stack とGPSまわり


使っているもの

とりあえずやってみたこと

  1. M5Stack標準のサンプルを実行 → 成功
    • tinygps++ を使う (exampleに付属しているためライブラリ追加)
  2. NeoGPS
    • GPSports.hを書く? 参考:Topic: Neo GPS Library complexity - /dev って人が詳しい。作者?
    • GPSports.hでデフォルトでincludeしているAltSoftSerialは、コンパイル通らないのでコメントアウト
    • M5StackのGPS ModuleはHardwareserial Serial2に接続されているっぽい
    • exampleを改造しつつ試行中...

もうちょっと真面目に

  1. GPS Module関連

  2. NEO-M8N

    • NEO-M8Nは、ublox u-centerというwindowsとかのソフトウェアでテストや設定変更可能 たとえば10Hz化とか

案1 M5Stack GPS Moduleへ直接接続

  • GPS Module単体をUSB-Serialと接続可能 (GND, VCC3.3V, GPIO16 (RX), GPIO17 (TX)の4線で接続可能)
  • この状態で u-centerから利用可能

案2 M5Stack越しにGPS Moduleへ接続

  • M5StackってSerialでPCと接続できるし、Serial2でGPS Moduleとつながってる
  • ということで、こんな感じのコードで、PC - M5Stack+GPS Moduleを接続して、PCからu-centerで接続可能
  • PC-M5Stack間とu-centerのSerialの速度は合わせること (115200とか)
#include <M5Stack.h>

void setup() {
  // put your setup code here, to run once:

  M5.begin();

  Serial.begin(115200);
  Serial2.begin(9600);

}

void loop() {
  // put your main code here, to run repeatedly:

 if(Serial.available()) {
   int ch = Serial.read();
   Serial2.write(ch);
 }

 if(Serial2.available()) {
   int ch = Serial2.read();
   Serial.write(ch);
 }

}

ublox protocol

  • ネタ元: 10Hz U-blox binary GPS data in 66 lines of code (arduino)
  • 参考資料: u-blox 8 / u-blox M8 Receiver Description Including Protocol Specification
  • u-centerからNEO-M8Nへ送信されている設定変更コマンドは、まぁ、シリアル見ていれば分かるレベル
  • u-centerにもそういうviewあるし
  • というわけで、u-centerで設定変更のメッセージをキャプチャして、M5Stackから直接送りつけてみるサンプル
  • 内容: いまの緯度経度を表示
    • NMEA messageをdisableし、UBX - POSLLH のみをenable
    • POSLLHの内容を画面に表示...するだけ
  • GPS moduleからのACKを見ていないので、まぁサンプルということで
#include <M5Stack.h>

// disable NMEA message
const unsigned char NMEA_msg1[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x0A, 0x00, 0x04, 0x23 };
const unsigned char NMEA_msg2[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x09, 0x00, 0x03, 0x21 };
const unsigned char NMEA_msg3[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x00, 0x00, 0xFA, 0x0F };
const unsigned char NMEA_msg4[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x01, 0x00, 0xFB, 0x11 };
const unsigned char NMEA_msg5[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x0D, 0x00, 0x07, 0x29 };
const unsigned char NMEA_msg6[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x06, 0x00, 0x00, 0x1B };
const unsigned char NMEA_msg7[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x02, 0x00, 0xFC, 0x13 };
const unsigned char NMEA_msg8[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x07, 0x00, 0x01, 0x1D };
const unsigned char NMEA_msg9[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x03, 0x00, 0xFD, 0x15 };
const unsigned char NMEA_msga[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x04, 0x00, 0xFE, 0x17 };
const unsigned char NMEA_msgb[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x0F, 0x00, 0x09, 0x2D };
const unsigned char NMEA_msgc[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x05, 0x00, 0xFF, 0x19 };
const unsigned char NMEA_msgd[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x08, 0x00, 0x02, 0x1F };
const unsigned char NMEA_msge[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF1, 0x00, 0x00, 0xFB, 0x12 };
const unsigned char NMEA_msgf[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF1, 0x01, 0x00, 0xFC, 0x14 };
const unsigned char NMEA_msgg[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF1, 0x03, 0x00, 0xFE, 0x18 };
const unsigned char NMEA_msgh[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF1, 0x04, 0x00, 0xFF, 0x1A };
const unsigned char NMEA_msgi[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF1, 0x05, 0x00, 0x00, 0x1C };
const unsigned char NMEA_msgj[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF1, 0x06, 0x00, 0x01, 0x1E };

// activate UBX - POSLLH
const unsigned char UBX_msg1[] = { 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x02, 0x01, 0x0E, 0x47};

const unsigned char UBX_HEADER[] = { 0xB5, 0x62 };

struct NAV_POSLLH {
  unsigned char cls;
  unsigned char id;
  unsigned short len;
  unsigned long iTOW;
  long lon;
  long lat;
  long height;
  long hMSL;
  unsigned long hAcc;
  unsigned long vAcc;
};

NAV_POSLLH posllh;

void calcChecksum(unsigned char* CK) {
  memset(CK, 0, 2);
  for (int i = 0; i < (int)sizeof(NAV_POSLLH); i++) {
    CK[0] += ((unsigned char*)(&posllh))[i];
    CK[1] += CK[0];
  }
}

bool processGPS() {
  static int fpos = 0;
  static unsigned char checksum[2];
  const int payloadSize = sizeof(NAV_POSLLH);

  while ( Serial2.available() ) {
    byte c = Serial2.read();
    if ( fpos < 2 ) {
      if ( c == UBX_HEADER[fpos] )
        fpos++;
      else
        fpos = 0;
    }
    else {
      if ( (fpos-2) < payloadSize )
        ((unsigned char*)(&posllh))[fpos-2] = c;

      fpos++;

      if ( fpos == (payloadSize+2) ) {
        calcChecksum(checksum);
      }
      else if ( fpos == (payloadSize+3) ) {
        if ( c != checksum[0] )
          fpos = 0;
      }
      else if ( fpos == (payloadSize+4) ) {
        fpos = 0;
        if ( c == checksum[1] ) {
          return true;
        }
      }
      else if ( fpos > (payloadSize+4) ) {
        fpos = 0;
      }
    }
  }
  return false;
}

void setup() {
  // put your setup code here, to run once:

  M5.begin();

  M5.Lcd.fillScreen(TFT_BLACK);
  M5.Lcd.setTextSize(1);
  M5.Lcd.setTextColor(TFT_YELLOW, TFT_BLACK);
  M5.Lcd.setCursor(0, 0);
  M5.Lcd.println("GPS Test");

  Serial.begin(9600);
  Serial2.begin(9600);


  Serial2.write(NMEA_msg1, 11);
  Serial2.write(NMEA_msg2, 11);
  Serial2.write(NMEA_msg3, 11);
  Serial2.write(NMEA_msg4, 11);
  Serial2.write(NMEA_msg5, 11);
  Serial2.write(NMEA_msg6, 11);
  Serial2.write(NMEA_msg7, 11);
  Serial2.write(NMEA_msg8, 11);
  Serial2.write(NMEA_msg9, 11);
  Serial2.write(NMEA_msga, 11);
  Serial2.write(NMEA_msgb, 11);
  Serial2.write(NMEA_msgc, 11);
  Serial2.write(NMEA_msgd, 11);
  Serial2.write(NMEA_msge, 11);
  Serial2.write(NMEA_msgf, 11);
  Serial2.write(NMEA_msgg, 11);
  Serial2.write(NMEA_msgi, 11);
  Serial2.write(NMEA_msgj, 11);

  Serial2.write(UBX_msg1, 11);

}

void loop() {
  // put your main code here, to run repeatedly:

  if ( processGPS() ) {
    M5.Lcd.setCursor(0, 10);
    M5.Lcd.printf("lat: %f", posllh.lat/10000000.0f);

    M5.Lcd.setCursor(0, 20);
    M5.Lcd.printf("lon: %f", posllh.lon/10000000.0f);

    M5.Lcd.setCursor(0, 30);
    M5.Lcd.printf("height: %f", posllh.height/1000.0f);

  }
}

メモ

  • 32.10.23 UBX-CFG-RATE (0x06 0x08) - 周期
    • 1000ms 1Hz
    • B5 62 06 08 06 00 E8 03 01 00 01 00 01 39 UBX CFG-RATE, Size 14, 'Rates'
    • B5 62 06 08 00 00 0E 30 UBX CFG, Size 8, 'Config'
    • 200ms 5Hz
    • B5 62 06 08 06 00 C8 00 01 00 01 00 DE 6A UBX CFG-RATE, Size 14, 'Rates'
    • B5 62 06 08 00 00 0E 30 UBX CFG, Size 8, 'Config'
  • 32.10.14 UBX-CFG-MSG (0x06 0x01) - メッセージ
    • B5 62 06 01 03 00 01 02 00 0D 46
    • NMEA treeの全部 Off
    • B5 62 06 01 03 00 F0 0A 00 04 23 x7
    • B5 62 06 01 03 00 F0 09 00 03 21 x7
    • B5 62 06 01 03 00 F0 00 00 FA 0F x7
    • B5 62 06 01 03 00 F0 01 00 FB 11 x7
    • B5 62 06 01 03 00 F0 0D 00 07 29 x7
    • B5 62 06 01 03 00 F0 06 00 00 1B x7
    • B5 62 06 01 03 00 F0 02 00 FC 13 x7
    • B5 62 06 01 03 00 F0 07 00 01 1D x7
    • B5 62 06 01 03 00 F0 03 00 FD 15 x14
    • B5 62 06 01 03 00 F0 04 00 FE 17 x7
    • B5 62 06 01 03 00 F0 0F 00 09 2D x7
    • B5 62 06 01 03 00 F0 05 00 FF 19 x7
    • B5 62 06 01 03 00 F0 08 00 02 1F x7
    • B5 62 06 01 03 00 F1 00 00 FB 12 x1
    • B5 62 06 01 03 00 F1 01 00 FC 14 x1
    • B5 62 06 01 03 00 F1 03 00 FE 18 x1
    • B5 62 06 01 03 00 F1 04 00 FF 1A x1
    • B5 62 06 01 03 00 F1 05 00 00 1C x1
    • B5 62 06 01 03 00 F1 06 00 01 1E x1
    • UBX NAV-POSLLH
    • B5 62 06 01 03 00 01 02 01 0E 47 R <- UBX NAV, Size 8, 'Navigation'
    • B5 62 05 01 02 00 06 01 0F 38
    • B5 62 0A 04 00 00 0E 34
  • 32.8.1 UBX-ACK-ACK (0x05 0x01) - GPS deviceからの返答 (Ack)
    • B5 62 05 01 02 00 06 01 0F 38

関連情報

その他