Wio LTE로 놀아 본다(그 6:간이 지진계를 만들어 보자)

Grove IoT 스타터 키트 for SORACOM 에서 놀아 본다.
  • 첫회:환경 구축+L치카
  • 두 번째: 온습도 센서
  • 세 번째: 버튼 + 버저
  • 네 번째: 자기 스위치와 초음파 거리 센서
  • 다섯 번째: 3축 디지털 가속도 센서 및 GPS

  • 지금까지의 것을 조합해 간이적 지진계를 만들어 본다.

    〇구성



    3축 디지털 가속도 센서
    버튼
    온습도
    GPS

    우선 이 근처의 센서를 사용할 예정.
    이러한 센서 외에 LTE로 우선은 SORACOM의 Harvest에 송신.
    ※궁극적으로는 BEAM으로 다른 어느쪽으로 전송도 하고 싶다.

    이미지적으로는
    ・데이터 송신 계기로서 이하를 상정
    가속도 센서로 흔들림을 검지한 경우: 본래의 목적
    버튼을 누르면 : 검증 등
    정기적인 타이밍:건강 체크용
    ・데이터 송신시에 송신하는 데이터
    흔들림에 관한 데이터:무엇을 보내면 좋을지는 현재 불명
    온습도:건강 체크시에 정기적으로 무엇인가 보고 싶다면 이 근처인가
    위치정보 : 우선

    〇시행착오



    우선 깊이 생각하지 않고 지금까지의 스케치를 조합해 본다.
    하지만, 어쩐지 잘 안된다.
    구체적으로는 GPS의 값을 잘 표시할 수 없다.
    이전 코드를 읽어 보면 잘 얻을 수 없습니다.
    왜. . 이런 때는 한 번 떨어져 보인다.

    우선 현상으로 만들고 싶은 시스템적으로는 GPS는 마스트가 아니기 때문에 이것에 관한 부분을 날려 다양하게 수정.

    처음 때 에 Socket에 관한 처리만
    SORACOM에의 송신 처리를 할 수 있다고 생각했지만,
    역시 setup 안에서의 준비가 필요했다.

    Wio_LTE_for_Arduino 참조 매뉴얼
  • Wio.PowerSupplyLTEWio LTE上のLTEモジュールの電源供給をオン/オフします。 LTEモジュールは電源供給オンの後に、起動操作(TurnOnOrReset)しないと利用できません。 本関数を実行した後の、LTEモジュールの操作は0.5秒以上待ってください。(LTEモジュールの動作が安定するまで待つ。)
  • Wio.TurnOnOrResetWio LTE上のLTEモジュールを起動操作します。 LTEモジュールが電源オンしていないときは電源オン、電源オンしているときはリセットします。 本関数を実行する前に、LTEモジュールへ電源供給(PowerSupplyLTE)してください。

  • 다만, 여러가지 조사하고 있으면 아래와 같이 LTE 모듈을 상시 ON으로 하는 것보다는 필요시에만 ON으로 하는 편이 전력적으로 친절한 것일지도 모른다
    Wio LTE를 절전에 사용합시다.
    ※하지만, 이 근처는 과제라고 하는 것으로.
  • Activate(const char* accessPointName, const char* userName, const char* password)
  • 指定したAPN、ユーザー名、パスワードを使って、データ通信を有効にします。SORACOM으로 전송할 때 다음
    Wio.Activate("soracom.io", "sora", "sora")

    그래서, 우선 이런 느낌.


    // YuLetter
    
    #include <WioLTEforArduino.h>
    #include <ADXL345.h>          // https://github.com/Seeed-Studio/Accelerometer_ADXL345
    #include <TinyGPS++.h>
    #include <stdio.h>
    
    
    #define SENSOR_TemperatureAndHumidity_PIN    (WIOLTE_D38)
    #define BUTTON_PIN  (WIOLTE_D20)
    
    #define INTERVAL_LOOP (1000)
    #define INTERVAL_Accelerometer  (18000)
    
    #define INTERVAL_SEND   (1000)
    #define RECEIVE_TIMEOUT (10000)
    
    #define LARGE_LOOP_LIMIT  (500)  //ここの数字が大きいとHelthCheckまでの間隔が長くなる
    
    #define G_AVE_LIMIT  (4) //ここの値でどれくらいの揺れ?を検知するかをチューニングする
    #define G_AVE_LOOP_LIMIT  (20)  //何回分の加速度を集計して平均値を算出するか?
    
    
    //状態に対する色設定
    #define COLOR_SETUP 0, 10, 0
    #define COLOR_NONE 0, 0, 0
    #define COLOR_GPS 255, 51, 255
    #define COLOR_TempAndHumi 10, 10, 10
    #define COLOR_BUTTON 10, 10, 0
    #define COLOR_Accelerometer 10, 0, 0
    #define COLOR_Send 0, 0, 10
    #define COLOR_ERROR 255, 0, 0
    
    WioLTE Wio;
    TinyGPSPlus gps;
    ADXL345 Accel;
    
    int large_loop_count;
    int before_g_ave;
    volatile int mode = 0;
    
    void setup()
    {
      delay(500);
    
      SerialUSB.println("### I/O Initialize.");
      //GPSはいったん棚上げ
    //  GpsBegin(&Serial);
    
      delay(500);
      Wio.Init();
      Wio.LedSetRGB(COLOR_SETUP);
    
      SerialUSB.println("### Power supply ON.");
      Wio.PowerSupplyGrove(true);
      delay(500);
      Accel.powerOn();
      delay(500);
      pinMode(BUTTON_PIN, INPUT);
      delay(500);
      attachInterrupt(BUTTON_PIN, change_state, RISING);
    
      TemperatureAndHumidityBegin(SENSOR_TemperatureAndHumidity_PIN);
      delay(500);
    
      Wio.PowerSupplyLTE(true);
      delay(500);
    
      SerialUSB.println("### Turn on or reset.");
      if (!Wio.TurnOnOrReset()) {
        SerialUSB.println("### ERROR! ###");
        return;
      }
    
      SerialUSB.println("### Connecting to \"soracom.io\".");
      if (!Wio.Activate("soracom.io", "sora", "sora")) 
      {
        SerialUSB.println("### SORACOM Activate ERROR ###");
        return;
      }
    
      large_loop_count = 0;
      before_g_ave = 0;
      SerialUSB.println("### Setup completed.");
    
      SerialUSB.print("G_AVE_LOOP_LIMIT : ");
      SerialUSB.println(G_AVE_LOOP_LIMIT);
      SerialUSB.print("G_AVE_LIMIT : ");
      SerialUSB.println(G_AVE_LIMIT);
    
      Wio.LedSetRGB(COLOR_NONE);
    }
    
    void loop()
    {
      unsigned long start = micros();
    
      CheckShake();
      delay(500);
    
      // TODO ここの判定処理を回数ではなく時間にする
      large_loop_count ++;
    // 温度湿度についても一定時間ごとにチェックして送信
      if(large_loop_count >= LARGE_LOOP_LIMIT)
      {
        float temp;
        float humi;
        get_TemperatureAndHumidity(&temp, &humi);
    
        Wio.LedSetRGB(COLOR_Send);
        SerialUSB.println("### Send !! ");
        SendData(temp , humi);
        delay(500);
        mode = 0;
    
        //何もしないと平常値に戻るタイミングでもう一回送信してしまうので、ここで値を初期化しておく。
        before_g_ave = 0;
        large_loop_count = 0;
      }
    
      Wio.LedSetRGB(COLOR_NONE);
      delay(INTERVAL_LOOP);
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    //
    //データ送信
    void SendData(float temp , float humi)
    {
      char data[200];
      sprintf(data,"{\"temp\":%.1f,\"humi\":%.1f,\"g_ave\":%d,\"mode\":%d}", temp, humi, before_g_ave, mode);
    
      SerialUSB.print("- Open ");
      int connectId;
      connectId = Wio.SocketOpen("harvest.soracom.io", 8514, WIOLTE_UDP);
      if (connectId < 0) 
      {
        SerialUSB.println("### SocketOpen ERROR! ###");
        SerialUSB.println(connectId);
        goto err;
      }
    
      SerialUSB.println(" -- Send ");
      SerialUSB.println(data);
      if (!Wio.SocketSend(connectId, data)) 
      {
        SerialUSB.println("### SocketSend ERROR! ###");
        goto err_close;
      }
      SerialUSB.print(" --- Receive ");
      int length;
      length = Wio.SocketReceive(connectId, data, sizeof (data), RECEIVE_TIMEOUT);
      if (length < 0) 
      {
        SerialUSB.println("### SocketReceive ERROR! ###");
        goto err_close;
      }
      if (length == 0)
      {
        SerialUSB.println("### RECEIVE TIMEOUT! ###");
        goto err_close;
      }
    
    err_close:
      SerialUSB.println(" ---- Close ");
      if (!Wio.SocketClose(connectId))
      {
        SerialUSB.println("### SocketClose ERROR! ###");
        goto err;
      }
    
    err:
      delay(INTERVAL_SEND);
    
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    //
    //揺れチェック
    void CheckShake()
    {
      SerialUSB.println("### Accelerometer : CheckShake");
      Wio.LedSetRGB(COLOR_Accelerometer);
    
      int g_sum = 0;
      for(int cnt=0;cnt<G_AVE_LOOP_LIMIT;cnt++)
      {
        int x;
        int y;
        int z;
        Accel.readXYZ(&x, &y, &z);
        int res = sqrt(x * x + y * y + z * z); 
        g_sum = g_sum + res;
      }
      double currnet_g_ave = g_sum / G_AVE_LOOP_LIMIT;
      SerialUSB.print("before_g_ave : ");
      SerialUSB.println(before_g_ave);
      SerialUSB.print("currnet_g_ave : ");
      SerialUSB.println(currnet_g_ave);
    
      if(before_g_ave!=0 && abs(before_g_ave-currnet_g_ave) >= G_AVE_LIMIT)
      {
        //揺れてる
        Wio.LedSetRGB(COLOR_ERROR);
        SerialUSB.println(">>> Shake!! <<<");
        SetShakeState();
        mode = 2;
      }
    
      //差し替える
      before_g_ave = currnet_g_ave;
      Wio.LedSetRGB(COLOR_NONE);
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    //
    void SetShakeState()
    {
      large_loop_count = LARGE_LOOP_LIMIT;
    }
    ////////////////////////////////////////////////////////////////////////////////////////
    //
    //ボタンによる割込み処理
    volatile bool StateChanged = false;
    volatile bool State = false;
    
    void change_state()
    {
      SerialUSB.println(">>> Push Button <<<");
      Wio.LedSetRGB(COLOR_BUTTON);
      State = !State;
      StateChanged = true;
    
      mode = 1;
      SetShakeState();
    }
    
    
    ////////////////////////////////////////////////////////////////////////////////////////
    //
    
    // 加速度センサー
    int Accelerometer()
    {
    
      int x;
      int y;
      int z;
      Accel.readXYZ(&x, &y, &z);
      SerialUSB.print(x);
      SerialUSB.print(' ');
      SerialUSB.print(y);
      SerialUSB.print(' ');
      SerialUSB.println(z);
    
      int res = sqrt(x * x + y * y + z * z); 
      SerialUSB.println(res);
    
      return res;
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    //
    // 温湿度
    void get_TemperatureAndHumidity(float* temp, float* humi)
    {
      SerialUSB.println("### Temperature And Humidity");
      Wio.LedSetRGB(COLOR_TempAndHumi);
    
      if (!TemperatureAndHumidityRead(temp, humi)) {
        SerialUSB.println("ERROR!");
        goto err;
      }
    
      SerialUSB.print("Current humidity = ");
      SerialUSB.print(*humi);
      SerialUSB.print("%  ");
      SerialUSB.print("temperature = ");
      SerialUSB.print(*temp);
      SerialUSB.println("C");
    
    err:
      delay(1000);
    }
    
    int TemperatureAndHumidityPin;
    
    void TemperatureAndHumidityBegin(int pin)
    {
      TemperatureAndHumidityPin = pin;
      DHT11Init(TemperatureAndHumidityPin);
    }
    bool TemperatureAndHumidityRead(float* temperature, float* humidity)
    {
      byte data[5];
    
      DHT11Start(TemperatureAndHumidityPin);
      for (int i = 0; i < 5; i++) data[i] = DHT11ReadByte(TemperatureAndHumidityPin);
      DHT11Finish(TemperatureAndHumidityPin);
    
      if(!DHT11Check(data, sizeof (data))) return false;
      if (data[1] >= 10) return false;
      if (data[3] >= 10) return false;
    
      *humidity = (float)data[0] + (float)data[1] / 10.0f;
      *temperature = (float)data[2] + (float)data[3] / 10.0f;
    
      return true;
    }
    
    void DHT11Init(int pin)
    {
      digitalWrite(pin, HIGH);
      pinMode(pin, OUTPUT);
    }
    
    void DHT11Start(int pin)
    {
      // Host the start of signal
      digitalWrite(pin, LOW);
      delay(18);
    
      // Pulled up to wait for
      pinMode(pin, INPUT);
      while (!digitalRead(pin)) ;
    
      // Response signal
      while (digitalRead(pin)) ;
    
      // Pulled ready to output
      while (!digitalRead(pin)) ;
    }
    
    byte DHT11ReadByte(int pin)
    {
      byte data = 0;
    
      for (int i = 0; i < 8; i++) {
        while (digitalRead(pin)) ;
    
        while (!digitalRead(pin)) ;
        unsigned long start = micros();
    
        while (digitalRead(pin)) ;
        unsigned long finish = micros();
    
        if ((unsigned long)(finish - start) > 50) data |= 1 << (7 - i);
      }
    
      return data;
    }
    
    void DHT11Finish(int pin)
    {
      // Releases the bus
      while (!digitalRead(pin)) ;
      digitalWrite(pin, HIGH);
      pinMode(pin, OUTPUT);
    }
    
    bool DHT11Check(const byte* data, int dataSize)
    {
      if (dataSize != 5) return false;
    
      byte sum = 0;
      for (int i = 0; i < dataSize - 1; i++) {
        sum += data[i];
      }
    
      return data[dataSize - 1] == sum;
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    //
    // GPS
    #define GPS_OVERFLOW_STRING "OVERFLOW"
    
    HardwareSerial* GpsSerial;
    char GpsData[100];
    char GpsDataLength;
    
    void GpsBegin(HardwareSerial* serial)
    {
      GpsSerial = serial;
      GpsSerial->begin(9600);
      GpsDataLength = 0;
    }
    void displayInfo()
    {
        SerialUSB.print(F("Location: ")); 
        if (gps.location.isValid()) {
            SerialUSB.println(gps.location.lat(), 6);
            SerialUSB.println(gps.location.lng(), 6);
        } else {
            SerialUSB.println(F("INVALID"));
        }
    }
    
    const char* GpsRead()
    {
      SerialUSB.println("### GpsRead Start");
      Wio.LedSetRGB(COLOR_GPS);
    
      while (GpsSerial->available()) {
        char data = GpsSerial->read();
    
        if (gps.encode(data)) {
          displayInfo();
        }
    
        if (data == '\r') continue;
        if (data == '\n') {
          GpsData[GpsDataLength] = '\0';
          GpsDataLength = 0;
          SerialUSB.println("### GpsRead End Data Exist");
          return GpsData;
        }
    
        if (GpsDataLength > sizeof (GpsData) - 1) { // Overflow
          GpsDataLength = 0;
          SerialUSB.println("### GpsRead End Data Overflow");
          return GPS_OVERFLOW_STRING;
        }
        GpsData[GpsDataLength++] = data;
      }
    
      SerialUSB.println("### GpsRead End NULL");
      return NULL;
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////
    

    Harvest에 전송도 문제 없음.
    흔들렸는지의 검지도 일단은 되어 있고, 헬스 체크나 버튼 계기에서도 일단 OK



    도전


  • 중요한 "흔들림 감지"부분의 로직이 전혀 확고하지 않다.
    어쩌면 취득할 수 있던 값을 단순히 이런 느낌으로 값을 만들고 있는 것이 안될까.

  • Accel.readXYZ(&x, &y, &z);
    int res = sqrt(x * x + y * y + z * z);

    이 근처는 요 개선.
  • GPS 관련 선반
  • 헬스 체크 관련을 좀 더 어떻게 하고 싶다
    지금은 루프의 횟수가 상당히 많으면 전송 중이지만 시간이 지나면 어떻게 되나요?
  • 데이터시트의 견해를 잘 모르겠습니다
  • 전체적으로 노출
    어느 정도의 것이 완성되면 케이스적인 것도 검토할까 생각한다.
  • 좋은 웹페이지 즐겨찾기