M5Stack とGPSまわり

# 使っているもの
- [M5Stack](https://m5stack.com/) Gray - 4,860円 (amazon/スイッチサイエンス)
- [GPS Module with Internal & External Antenna (NEO-M8N)](https://m5stack.com/collections/m5-module/products/gps-module) v2って方 - 5,199円 (amazon/スイッチサイエンス)

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

# もうちょっと真面目に
1. GPS Module関連
    - [M5Stack GPS Module](https://docs.m5stack.com/#/en/module/gps)
    - GPSはubloxのNEO-M8Nを使用し、内部的にはUART2に接続

2. NEO-M8N
    - NEO-M8Nは、ublox [u-center](https://www.u-blox.com/en/product/u-center)というwindowsとかのソフトウェアでテストや設定変更可能 ***たとえば10Hz化とか***

## 案1 M5Stack GPS Moduleへ直接接続

- GPS Module単体をUSB-Serialと接続可能 (GND, VCC3.3V, GPIO16 (RX), GPIO17 (TX)の4線で接続可能)
- この状態で u-centerから利用可能
- ![screen1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274059/fbe07081-7485-59bb-2105-a66859843117.jpeg)


## 案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)](https://www.youtube.com/watch?v=TwhCX0c8Xe0)
- 参考資料: [u-blox 8 / u-blox M8 Receiver Description Including Protocol Specification](https://www.u-blox.com/sites/default/files/products/documents/u-blox8-M8_ReceiverDescrProtSpec_%28UBX-13003221%29_Public.pdf)
- 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


# 関連情報
- [NEO-M8N](https://www.u-blox.com/ja/product/neo-m8-series)
- [10Hz U-blox binary GPS data in 66 lines of code (arduino)](https://www.youtube.com/watch?v=TwhCX0c8Xe0)
- [Sensors/GPS - Paparazzi](http://wiki.paparazziuav.org/wiki/Sensors/GPS)
- [NEO-M8P、M8Tの設定方法](http://www.denshi.e.kaiyodai.ac.jp/gnss_tutor/pdf/st_190310_1.pdf)
- [GPS U-Blox Neo M8N parser ](https://forum.arduino.cc/index.php?topic=305867.0)
- [NeoGPS](https://github.com/SlashDevin/NeoGPS): NMEA and ublox GPS parser for Arduino, configurable to use as few as 10 bytes of RAM

# その他
- [LAP SHOT (ラップショット) LAP SHOTIII (リペアパーツ) 磁気センサー [品番] LAPS32](https://www.amazon.co.jp/%E3%83%A9%E3%83%83%E3%83%97%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-SHOTIII-%E3%83%AA%E3%83%9A%E3%82%A2%E3%83%91%E3%83%BC%E3%83%84-%E7%A3%81%E6%B0%97%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC-LAPS32/dp/B0057K4V0I) - 6,480円
- [LAP SHOT(LP-02)の磁気センサー信号](https://minkara.carview.co.jp/userid/447683/blog/22507167/)
- [初心者向けM5Stackの始め方（ArduinoIDE編）](https://raspberrypi.mongonta.com/howto-start-m5stack-arduinoide/)
- [M5Stackを使ってみる](http://itoi.jp/M5Stack.html)
- [M5Stackとmicro:bitを合体させてみる – その2 (M5Stack側で動かしているプログラム)](http://kako.com/blog/?p=37812) - Serial と Serial2を相互につなげているサンプル