Wio LTE로 놀아 본다(그 7:간이 지진계를 개선한다)

Grove IoT 스타터 키트 for SORACOM 에서 놀아 본다.
알아차리면 이제 7번째다.
  • 첫회:환경 구축+L치카
  • 두 번째: 온습도 센서
  • 세 번째: 버튼 + 버저
  • 네 번째: 자기 스위치와 초음파 거리 센서
  • 다섯 번째: 3축 디지털 가속도 센서 및 GPS
  • 여섯 번째: 간이 지진계를 만들어 보자

  • 이번 내용


  • 흔들림 감지 메커니즘 개선
  • 위치 정보 취득

  • 흔들림 감지의 구조 개선



    흔들림 감지 부분(구체적으로는 흔들림을 수치화하는 부분)이 지금 하나 확실히 오지 않기 때문에 개선시킨다.

    현재 로직
    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;
    
    if(before_g_ave!=0 && abs(before_g_ave-currnet_g_ave) >= G_AVE_LIMIT)
    {
        //揺れてる
        SerialUSB.println(">>> Shake!! <<<");
    }
    

    처리적으로는 N회분의 수치를 평균하여 전회 판정시의 값과 비교하여 일정값 이상의 차분이 있으면 「흔들림」으로 간주하고 있다.

    다시 데이터 시트
    h tp // w w. 아나 g. 이 m / jp / p 로즈 cts / 전선 rs-메 ms / 아세오 로메 rs / 오 dxl345. HTML
    h tp // w w. 아나 g. 코 m/메아아/jp/테 ch나 l도쿠멘들 온/다타-시에 ts/아 DXL345_jp. pdf
    h tp // w w. 아나 g. 이 m/메아아/jp/테 ch나 l-쿠쿠멘타치 온/아 pぃ카치온-s/an-1077_jp. pdf





    음. .
    이만큼 읽어도 모르겠어. .

    이 사이트가 이해하기 쉬웠다.
    h tp : /// x x p 리메. 하테나 bぉg. 코m/엔트리/2016/12/07/193213

    요컨대 Accel.readXYZ로부터 취득할 수 있는 수치는 LSB이므로 3.9 mg/LSB를 걸어 버리는 것일까.

    286 LSB * 3.9 mg/LSB/1000

    이것을 데이터시트 에서 어떻게 읽으면 좋을까. . .

    글쎄, 그 근처는 제쳐두더라도, 일단 이것으로 단위를 중력 가속도(g)로 할 수 있게 된 것이다.

    데모 코드



    센서 페이지를 보면
    h tp // 우우키. 그래, ds. 이 m/G로ゔぇ-3ーあぃs_ぢぎたl_아세로로 r-16g/Step3: If you have the library installed, Open the demo code directly by the path: ** File(文件) -> Example(示例) ->DigitalAccelerometer_ADXL345->ADXL345_demo_code. **그리고 지금부터 데모 코드를 살펴보자.
    void loop(){
    
        //Boring accelerometer stuff   
        int x,y,z;  
        adxl.readXYZ(&x, &y, &z); //read the accelerometer values and store them in variables  x,y,z
        // Output x,y,z values 
        Serial.print("values of X , Y , Z: ");
        Serial.print(x);
        Serial.print(" , ");
        Serial.print(y);
        Serial.print(" , ");
        Serial.println(z);
    
        double xyz[3];
        double ax,ay,az;
        adxl.getAcceleration(xyz);
        ax = xyz[0];
        ay = xyz[1];
        az = xyz[2];
        Serial.print("X=");
        Serial.print(ax);
        Serial.println(" g");
        Serial.print("Y=");
        Serial.print(ay);
        Serial.println(" g");
        Serial.print("Z=");
        Serial.print(az);
        Serial.println(" g");
        Serial.println("**********************");
        delay(500);
    
    }
    

    ···아래의 [getAcceleration] 라고 가속도를 취득할 수 있는 함수가 아닌가?
    이것으로 좋다.

    이 가장자리를 기반으로 합성 가속도를 계산하여 그 차이를 확인하기로 결정했습니다.

    환경이・・・



    여기까지 하고 재수정한 것을 반영하려고 하면, 보드에의 기입을 할 수 없다.
    WindowsUpdate 때문에?
    어디에서 다시 시도하는지 모르는 것이 약간 화가 난다.

    기기 관리자를 참조하면,
    DFU 모드에서 [STM32 BOOTLOADER]가 범용 직렬 버스 장치에서 사라졌습니다.
    Zadig 2.3 작업을 다시 시작합니다.
    이제 OK.

    GPS 관련



    김에 지난 선반 올렸던 GPS 관련. 우선 시행착오.

    단순히 스크래치 예라면 그대로 데이터 취득할 수 있는 주제에 그것을 이식하면 취득할 수 없거나 하는 것이 가장 모른다.

    이었지만, 없어도 좋은 것 같은 처리를 거절해 가면 뭔가 데이터를 취득할 수 있게 되었다.
    무엇이 바뀌었는지 솔직히 잘 모르겠다. . .
    bool GpsRead()
    {
      while (GpsSerial->available()) 
      {
        if(gps.encode(GpsSerial->read()))
        {
          if (gps.location.isValid())
          {
            latitude = gps.location.lat();
            longitude = gps.location.lng();
            return true;
          }
        }
      }
      return false;
    }
    

    요약



    이것으로 하려고 하고 있던 각 처리는 완성되었으므로 결합해 Harvest에 흩어져 본다.
      // 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)
    
      //500:12分ぐらい
      #define LARGE_LOOP_LIMIT  (500)  //ここの数字が大きいとHelthCheckまでの間隔が長くなる
    
      #define G_AVE_LIMIT  (0.03) //ここの値でどれくらいの揺れ?を検知するかをチューニングする
      #define G_AVE_LOOP_LIMIT  (20)  //何回分の加速度を集計して平均値を算出するか?
    
    
      //状態に対する色設定
      #define COLOR_SETUP 0, 10, 0
      #define COLOR_NONE 0, 0, 0
      #define COLOR_GPS 10, 0, 10
      #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;
      double  before_g_ave;
      double  latitude;
      double  longitude;
      volatile int mode = 0;
    
      void setup()
      {
        delay(500);
    
        SerialUSB.println("### I/O Initialize.");
    
        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()
      {
        if(GpsRead())
        {
          SerialUSB.print("LAT= "); 
          SerialUSB.print(latitude, 6);
          SerialUSB.print(" / LON= ");
          SerialUSB.println(longitude, 6);
        }else
        {
          SerialUSB.println("GPS Data INVALID");
          latitude = 0;
          longitude = 0;
        }
        delay(500);
    
        unsigned long start = micros();
    
        CheckShake();
        delay(500);
    
        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,"{\"lat\":%.6lf,\"lon\":%.6lf,\"temp\":%.1f,\"humi\":%.1f,\"g_ave\":%.3lf,\"mode\":%d}", latitude, longitude, 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);
    
        double g_sum = 0;
        for(int cnt=0;cnt<G_AVE_LOOP_LIMIT;cnt++)
        {
          g_sum += Accelerometer();
        }
        double currnet_g_ave = g_sum / G_AVE_LOOP_LIMIT;
        SerialUSB.print("before_g_ave : ");
        SerialUSB.print(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();
      }
    
    
      ////////////////////////////////////////////////////////////////////////////////////////
      //
    
      // 加速度センサー
      //void Accelerometer()
      double Accelerometer()
      {
        double xyz[3];
        double ax,ay,az;
        Accel.getAcceleration(xyz);
        ax = xyz[0];
        ay = xyz[1];
        az = xyz[2];
    
        double res = sqrtf(ax * ax + ay * ay + az * az); 
    
        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[200];
      char GpsDataLength;
    
      void GpsBegin(HardwareSerial* serial)
      {
        GpsSerial = serial;
        GpsSerial->begin(9600);
        GpsDataLength = 0;
      }
    
      bool GpsRead()
      {
        SerialUSB.println("### GpsRead Start");
        Wio.LedSetRGB(COLOR_GPS);
    
        while (GpsSerial->available()) 
        {
          if(gps.encode(GpsSerial->read()))
          {
            if (gps.location.isValid())
            {
              latitude = gps.location.lat();
              longitude = gps.location.lng();
              return true;
            }
          }
        }
        return false;
      }
    
      void displayGPSInfo()
      {
        SerialUSB.println("-- -- -- ");
        if (gps.location.isValid()) 
        {
          SerialUSB.print("LAT= "); SerialUSB.println(gps.location.lat(), 6);
          SerialUSB.print("LON= "); SerialUSB.println(gps.location.lng(), 6);
        }else
        {
          SerialUSB.println(F("INVALID"));
        }
      }
      ////////////////////////////////////////////////////////////////////////////////////////
    

    긴.
    이런 식으로 Harvest에 등록된다.





    우선 지도에도 제대로 표시된다.
    위치가 약간 다른 것은 GPS 모듈 쪽의 문제일까?
    라고 할까, 이 GPS 모듈이나 SORACOM측의 측지계는 세계 측지계로 좋을까?

    그리고는, 이 Harvest 이외에서도 가시화하고 싶은 곳.
    Beam을 통해 외부 앱으로 전송할까.
    하고 싶은 일로는, Beam에서 복수의 송신처에 전송 할 수 있으면 좋지만, 아무래도 그런 느낌이 들지 않기 때문에 뭔가를 생각할 필요가 있을지도 모른다.

    좋은 웹페이지 즐겨찾기