sigfoxで茶畑のプロペラを監視する装置作ってみた

# 紹介動画
<iframe width="560" height="315" src="https://www.youtube.com/embed/PpmKrov1f0c" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# 概要
今回は茶畑のプロペラを監視したいというお話があり、
試作機を作ってみました。

# 背景
茶畑でプロペラを見たことがある方もいると思いますが
あのプロペラは、お茶に霜が降りないように設置されているとのことです。


しかし老朽化などでたまに故障していることがあるらしく
お茶畑の農家さんは、早朝に霜が降りないようプロペラの状態を
見に行っているとのことでした。

それは大変なのでSigfoxの力を借りて、
プロペラを監視することにしましょう！！

# BOM
- sigfoxモジュール　1台
- 傾きセンサー　　　1台
- 距離センサー　　　1台
- Arduino nano　　　1台


# 電子回路
![スクリーンショット 2022-03-30 22.20.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/5a3a381f-14d2-1b5a-581a-6f1a4f394b9e.png)
![スクリーンショット 2022-03-30 22.20.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/308405d0-c096-fb7f-f96a-2d2b1ef4eb05.png)


# ソフトウェア
```c

#include <Wire.h>
#include <VL6180X.h>
#include <SoftwareSerial.h>
#include <avr/sleep.h>                  // スリープライブラリ
#include <avr/wdt.h>                    // ウォッチドッグタイマー ライブラリ

#define SCALING 2
VL6180X sensor;

SoftwareSerial mySerial(8, 9); // RX, TX
#define PIN_RESET 2 

//volatile int wdt_cycle = 0;   //復帰回数カウント

int16_t bgx,bgy,bgz,bkyori = 0;      //前回のxyz値保持用
int count = 0;                    //停止期間監視用

//WF931用関数
void atcommand(String cmd){
  mySerial.write("0x00");
  delay(50);
  Serial.println(">" + cmd);
  mySerial.println(cmd);
  delay(100);
  result();
}

void result(){
  char c;
  if (mySerial.available()) {
    do{
      c = mySerial.read();
      Serial.write(c);
      if(c==0xFF){
        Serial.println("Error!");
        return;
      }
    }while(c!='\r');
    // for LF
    Serial.write(mySerial.read());
  }
}

void setup() {
  Serial.begin(9600); // PC-Arduino間のシリアル
  pinMode(13,OUTPUT);
  
  //------------WF931用の初期設定---------------
  while (!Serial) {;}
  mySerial.begin(9600); // ソフトウェアシリアル(Arduino-EM-WF931-02F間)

  // Configure reset pin
  pinMode(PIN_RESET, OUTPUT);

  // Do reset
  digitalWrite(PIN_RESET, LOW);
  delay(1000);

  // Release reset
  digitalWrite(PIN_RESET, HIGH);
  delay(1000);
  result();

  atcommand("AT$ID?");
  atcommand("AT$PAC?");
  atcommand("AT$SF=0"); //起動信号をサーバに送信

  //-------------VL6180Xの初期設定----------------
  Wire.begin();  //I2Cをマスタに設定

  sensor.init();
  sensor.configureDefault();
  sensor.setScaling(SCALING);
  sensor.setTimeout(500);

  //-------------GY-521の初期設定----------------
  Wire.beginTransmission(0x68); //アドレス0x68指定でMPU-6050を選択、送信処理開始
  Wire.write(0x6B);             //MPU6050_PWR_MGMT_1レジスタのアドレス指定
  Wire.write(0x00);             //0を書き込むことでセンサ動作開始
  Wire.endTransmission();       //スレーブデバイスに対する送信を完了

  delay(20);
}

void loop() {
  if (mySerial.available()) Serial.write(mySerial.read());  //W931からデータがあった場合はPC表示
  //if (Serial.available()) mySerial.write(Serial.read());

  Serial.print(sensor.readRangeSingleMillimeters());
  if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }

  Serial.println();
  
  // スタートアドレスの設定とデータの要求処理
  Wire.beginTransmission(0x68);     //アドレス0x68指定でMPU-6050を選択、送信処理開始
  Wire.write(0x3B);                 //ACCEL_XOUT_Hレジスタのアドレス指定
  Wire.endTransmission(false);      //false設定で接続維持
  Wire.requestFrom(0x68, 14, true); //MPU-6050に対して14byte分データを要求、I2Cバス開放
  
  int16_t ax, ay, az, gx, gy, gz, Temp; //符号付き整数を格納する16ビットの変数型の設定

  //シフト演算と論理和で16bitのデータを変数に格納
  //ax～gzまで、16bit(2byte) × 7 = 14byte
  ax = Wire.read() << 8 | Wire.read();    //x軸の加速度の読み取り 16bit
  ay = Wire.read() << 8 | Wire.read();    //y軸の加速度の読み取り 16bit
  az = Wire.read() << 8 | Wire.read();    //z軸の加速度の読み取り 16bit
  Temp  = Wire.read() << 8 | Wire.read(); //温度の読み取り 16bit
  gx = Wire.read() << 8 | Wire.read();    //x軸の角速度の読み取り 16bit
  gy = Wire.read() << 8 | Wire.read();    //y軸の角速度の読み取り 16bit
  gz = Wire.read() << 8 | Wire.read();    //z軸の角速度の読み取り 16bit

  //データの表示 1LSBの値はデータシートに記載
  //AFS_SEL設定 = 0, ±2g, 16384LSB/g
  //FS_SEL設定  = 0, ±250deg/s, 131LSB/deg/s 
  //Serial.print(ax/16384.0); Serial.print(" g,  ");     //1LSBを加速度(G)に換算してシリアルモニタに表示
  //Serial.print(ay/16384.0); Serial.print(" g,  ");     //1LSBを加速度(G)に換算してシリアルモニタに表示
  //Serial.print(az/16384.0); Serial.print(" g,  ");     //1LSBを加速度(G)に換算してシリアルモニタに表示
  Serial.print(gx); Serial.print(" deg/s,  ");   //1LSBを角速度(deg/s)に換算してシリアルモニタに表示
  Serial.print(gy); Serial.print(" deg/s,  ");   //1LSBを角速度(deg/s)に換算してシリアルモニタに表示
  Serial.print(gz); Serial.println(" deg/s,  "); //1LSBを角速度(deg/s)に換算してシリアルモニタに表示
  //Serial.print(Temp/340.00+36.53); Serial.println(" deg.");    //温度換算シリアルモニタに表示

  //絶対値を取得
  int agx = abs(gx - bgx);
  int agy = abs(gy - bgy);
  int agz = abs(gz - bgz);
  int akyori = abs(sensor.readRangeSingleMillimeters() - bkyori);
  Serial.print("x:");Serial.print(agx);
  Serial.print(" , y:");Serial.print(agy);
  Serial.print(" , z:");Serial.print(agz);
  Serial.print(" , d:");Serial.println(akyori);

  //前のデータと比較する
  if((agx < 500 && agy < 500 && agz < 500) || akyori < 8 ){
    if(count <= 10){
      count++;
      digitalWrite(13,HIGH);
      delay(100);
      digitalWrite(13,LOW);
    }
  }else{
    count = 0;
  }
  
  Serial.println(count);

  if(count == 10){
    atcommand("AT$SF=1"); //起動信号をサーバに送信0
  }
  
  //データを入れる
  bgx = gx;
  bgy = gy;
  bgz = gz;
  bkyori = sensor.readRangeSingleMillimeters();
  delay(5000);   //5秒待機
}

```