M5Stack Gray에 GPS 모듈을 장착하여 센서 값을 LCD에 표시

목적



M5Stack GrayGPS 모듈 을 설치하여 센서 값(GPS 좌표, 가속도 센서, 자이로 센서)의 값을 LCD에 출력했으므로 코드 내용을 공유합니다. Arduino IDE를 사용한다고 가정합니다. 포착한 위성의 수, HDOP, 일시, GPS 좌표, 가속도·자이로 센서치를 화상과 같이 출력합니다.


코드



리포지토리

M5Stack Gray와 GPS 모듈을 준비하면 위 리포지토리의 코드로 위 이미지의 LCD 출력 표시력을 얻을 수 있습니다.

하드웨어 아래 준비


  • GPS 모듈을 그대로 사용하면 내부 안테나를 사용하는 설정이 되어 있기 때문에 위성을 포착(FIX)하는 데 시간이 걸립니다. 외부 안테나로하면 FIX가 빨라지므로 변경하는 것이 좋습니다.

  • 제공된 안테나를 붙이는 것만으로 전환하지 않고 이미지와 같이 GPS 모듈의 회색 선을 제거하고 검은 선을 연결해야합니다.
  • 회색 선의 전극은 움직여 쇼트를 발생시킬 가능성이 있으므로 테이프 등으로 절연하는 것이 좋다.
  • 외부 안테나의 선단은 창 근처에 설치하면 효과적. 실내에서도 1분 정도로 FIX했습니다.


  • 도서관 아래 준비



    TinyGPSPlus: h tp // // r 즈이에아나. 오 rg / ぃ b 라리 s / chi nygpsp ぅ s / 에서 라이브러리 다운로드(.zip)
    스케치 → 라이브러리 포함 → ZIP 형식 라이브러리 설치

    코드 해설



    샘플 예제 GPS_NEO_M8N → FullExample 코드를 기반으로 MPU9250의 센서 출력 설명을 더했습니다.
    #define M5STACK_MPU9250 
    
    #include <M5Stack.h>
    #include <TinyGPS++.h>
    
    static const uint32_t GPSBaud = 9600;
    
    // The TinyGPS++ object
    TinyGPSPlus gps;
    
    // The serial connection to the GPS device
    HardwareSerial ss(2);
    float accX = 0.0F;
    float accY = 0.0F;
    float accZ = 0.0F;
    
    float gyroX = 0.0F;
    float gyroY = 0.0F;
    float gyroZ = 0.0F;
    
    float pitch = 0.0F;
    float roll  = 0.0F;
    float yaw   = 0.0F;
    
    float temp = 0.0F;
    

    셋업에서 스피커를 끄면 스피커의 노이즈가 줄어듭니다.
    void setup()
    {
      M5.begin();
      dacWrite(25, 0); /* スピーカーオフにしてノイズを消す */
      M5.Power.begin();
      ss.begin(GPSBaud);
      M5.IMU.Init();
      M5.Lcd.setTextSize(1);
    }
    
    void loop()
    {
      M5.Lcd.setTextSize(1);
      M5.Lcd.setCursor(0, 0);
      M5.Lcd.setTextColor(WHITE, BLACK);
    
      M5.Lcd.print("Num of Sat[-]:");
      printInt(gps.satellites.value(), gps.satellites.isValid(), 5);
      M5.Lcd.print("HDOP[-]:");
      printInt(gps.hdop.value(), gps.hdop.isValid(), 5);
      M5.Lcd.print("DateTime[-]:");
      printDateTime(gps.date, gps.time);
      M5.Lcd.println();
    
      M5.Lcd.setTextColor(BLUE, BLACK);
      M5.Lcd.setTextSize(2);
      M5.Lcd.print("LAT[-]:");
      printFloat(gps.location.lat(), gps.location.isValid(), 11, 6);
      M5.Lcd.print("LNG[-]:");
      printFloat(gps.location.lng(), gps.location.isValid(), 12, 6);
    //  printInt(gps.location.age(), gps.location.isValid(), 5);
      M5.Lcd.print("ALT[-]:");
      printFloat(gps.altitude.meters(), gps.altitude.isValid(), 7, 2);
    //  printFloat(gps.course.deg(), gps.course.isValid(), 7, 2);
    //  printFloat(gps.speed.kmph(), gps.speed.isValid(), 6, 2);
    //  printStr(gps.course.isValid() ? TinyGPSPlus::cardinal(gps.course.deg()) : "*** ", 6);
    //  printInt(gps.charsProcessed(), true, 6);
    //  printInt(gps.sentencesWithFix(), true, 10);
    //  printInt(gps.failedChecksum(), true, 9);
    
      M5.Lcd.println();
    
      if (millis() > 5000 && gps.charsProcessed() < 10)
        M5.Lcd.println(F("No GPS data received: check wiring"));
    

    여기까지는 GPS 좌표의 취득과 표시. FIX할 때까지 표시가 ""가 됩니다. 「 」가 길게 계속되는 경우(1min 이상 걸리는)는, 안테나의 접속을 확인해, 위치를 바꾸어 보세요.

    여기에서 아래는 가속도·자이로 센서의 값을 취득·표시.
    - GPS 모듈은 1sec 간격으로 액세스해야 하며(간격이 짧으면 이상해짐), 1sec 동안은 가속도·자이로 센서의 값을 취득·표시합니다. 코드에서 1msec 간격으로 액세스하여 10회 평균을 계산하여 표시한 다음 100회 반복합니다. 평균화 횟수를 늘리면 업데이트 빈도가 줄어듭니다. 정밀도와 응답성의 트레이드 오프라고 생각하면 좋고, 적절하게 조정해 주세요.
    - 커서 설정을 하는 것은 값을 갱신하지 않은 GPS측의 값이 LCD에서 사라져 버리기 때문입니다.
    - 온도 센서를 출력해도 됩니다만, M5Stack 내부의 온도이므로 외기온과는 다릅니다(상당히 높음).
      int div_num = 10; //平均化回数
      int total_delay_num = 1000 / div_num; //平均化して1secになるようにループ回数を設定
    
      for(int ii = 0;ii < total_delay_num;ii++){
        float ave_accX = 0.0F;
        float ave_accY = 0.0F;
        float ave_accZ = 0.0F;
        float ave_gyroX = 0.0F;
        float ave_gyroY = 0.0F;
        float ave_gyroZ = 0.0F;
        float ave_pitch = 0.0F;
        float ave_roll  = 0.0F;
        float ave_yaw   = 0.0F;
        float ave_temp = 0.0F;
    
        //ジャイロ、加速度、温度センサーの平均化
        for(int jj = 0;jj < div_num;jj++){
          M5.IMU.getGyroData(&gyroX,&gyroY,&gyroZ);
          M5.IMU.getAccelData(&accX,&accY,&accZ);
          M5.IMU.getAhrsData(&pitch,&roll,&yaw);
          M5.IMU.getTempData(&temp);
    
          ave_accX  += accX;
          ave_accY  += accY;
          ave_accZ  += accZ;
          ave_gyroX += gyroX;
          ave_gyroY += gyroY;
          ave_gyroZ += gyroZ;
          ave_pitch += pitch;
          ave_roll  += roll;
          ave_yaw   += yaw;
          ave_temp  += temp;
    
          delay(1);
        }
    
        ave_accX  /= div_num;
        ave_accY  /= div_num;
        ave_accZ  /= div_num;
        ave_gyroX /= div_num;
        ave_gyroY /= div_num;
        ave_gyroZ /= div_num;
        ave_pitch /= div_num;
        ave_roll  /= div_num;
        ave_yaw   /= div_num;
        ave_temp  /= div_num;
    
        M5.Lcd.setCursor(0, 90);
        M5.Lcd.setTextColor(GREEN , BLACK);
        M5.Lcd.println("GYRO XYZ[o/s]");
        M5.Lcd.printf("%6.2f %6.2f %6.2f          ", ave_gyroX, ave_gyroY, ave_gyroZ);
        M5.Lcd.println("");
        M5.Lcd.println("ACC[G]");
        M5.Lcd.printf("%5.2f %5.2f %5.2f          ", ave_accX, ave_accY, ave_accZ);
        M5.Lcd.println("");
        M5.Lcd.println("P-R-Y[deg]");
        M5.Lcd.printf("%5.2f %5.2f %5.2f          ", ave_pitch, ave_roll, ave_yaw);
        M5.Lcd.println("");
    //    M5.Lcd.printf("Temperature[C] %.2f", ave_temp);
    //    M5.Lcd.println("");
      }
    }
    

    여기에서 아래는 내부 함수
    // This custom version of delay() ensures that the gps object
    // is being "fed".
    static void smartDelay(unsigned long ms)
    {
      unsigned long start = millis();
      do{
        while (ss.available())
          gps.encode(ss.read());
      }while(millis() - start < ms);
    }
    
    static void printFloat(float val, bool valid, int len, int prec)
    {
      if(!valid){
        while (len-- > 1)
          M5.Lcd.print('*');
        M5.Lcd.print(' ');
      }else{
        M5.Lcd.print(val, prec);
        int vi = abs((int)val);
        int flen = prec + (val < 0.0 ? 2 : 1); // . and -
        flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
        for (int i=flen; i<len; ++i){
          M5.Lcd.print(' ');
        }
      }
      M5.Lcd.println();
      smartDelay(0);
    }
    
    static void printInt(unsigned long val, bool valid, int len)
    {
      char sz[32] = "*****************";
      if(valid)
        sprintf(sz, "%ld", val);
      sz[len] = 0;
      for(int i=strlen(sz); i<len; ++i)
        sz[i] = ' ';
      if(len > 0) 
        sz[len-1] = ' ';
      M5.Lcd.print(sz);
      M5.Lcd.println();
      smartDelay(0);
    }
    
    static void printDateTime(TinyGPSDate &d, TinyGPSTime &t)
    {
      if(!d.isValid()){
        M5.Lcd.print(F("********** "));
      }else{
        char sz[32];
        sprintf(sz, "%02d/%02d/%02d ", d.month(), d.day(), d.year());
        M5.Lcd.print(sz);
      }
    
      if(!t.isValid()){
        M5.Lcd.print(F("******** "));
      }else{
        char sz[32];
        sprintf(sz, "%02d:%02d:%02d ", t.hour(), t.minute(), t.second());
        M5.Lcd.print(sz);
      }
    
      printInt(d.age(), d.isValid(), 5);
      smartDelay(0);
    }
    
    static void printStr(const char *str, int len)
    {
      int slen = strlen(str);
      for(int i=0; i<len; ++i){
        M5.Lcd.print(i<slen ? str[i] : ' ');
      }
      M5.Lcd.println();
      smartDelay(0);
    }
    


    끝에



    M5Stack을 오랜만에 제대로 사용해 보았습니다. 예제가 흩어져 있었기 때문에, 결합해 필요한 정보를 냈을 뿐입니다만, 무언가의 도움이 되었다면 LGTM 부탁합니다.

    좋은 웹페이지 즐겨찾기