LPWA(LoRa)を使ってサーボモータを動かしてみた ES920LR

今回会社でプロジェクションマッピングを行うことになった。

しかし問題が発生！！
なんと人が通ったときに眩しいとの苦情が！！

それを避けるためにそこを通る二箇所通路に人が来たことを
人感センサーで検知してプロジェクタのレンズ部分に幕を下ろす装置を
開発した。
## 購入したもの
・LoRaモジュール：ES920LR2 3台
・arduino nano every 1台
・ATMega328ｐ（3.3Ｖ　内蔵8MHｚ仕様）　2個
https://akizukidenshi.com/catalog/g/gI-12775/
・PIRセンサー（3.3V対応品）　2個
https://akizukidenshi.com/catalog/g/gM-14064/
・４ビット双方向ロジックレベル変換モジュール
https://akizukidenshi.com/catalog/g/gK-13837/
・トランジスタ　２ＳＣ１８１５ＧＲ
https://akizukidenshi.com/catalog/g/gI-11344/
・積層セラミックコンデンサー　０．０１μＦ６３０Ｖ
https://akizukidenshi.com/catalog/g/gP-10148/
・両面スルホール・ガラス・ユニバーサル基板金フラッシュＣタイプ１．２７ｍｍピッチ（７２×４８ｍｍ）
https://akizukidenshi.com/catalog/g/gP-11605/
・その他　抵抗、LED、配線、ブレッドボード、リチウム電池単3：3.6V　etc

## 回路図
### 親機
![スクリーンショット 2021-04-17 20.11.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/18105772-deb6-5973-38d6-0ecb7bfdb8e1.png)
![スクリーンショット 2021-04-17 20.11.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/1a03b0bb-037f-9f21-5966-666dca02cf4e.png)

### 子機
![スクリーンショット 2021-04-17 20.14.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/fb49dd1e-4ff3-4cce-0455-baa7421e2f6b.png)
![スクリーンショット 2021-04-17 20.21.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/d121c433-2a1b-3572-3c37-1229b25168a3.png)
（なんでか子機の回路図は少しバグってる。。。破線は気にしないで）
## ソースコード
### 親機

```c:mastar.ino
#include <Servo.h>
#include <SoftwareSerial.h>
#include <string.h>

Servo myservo;//Servoオブジェクトの宣言
static const int LoRa_Rst = 3;

void LoRa_reset(void) {
    digitalWrite(LoRa_Rst, HIGH);
    delay(100);
    digitalWrite(LoRa_Rst, LOW);
}

int LoRa_recv(char *buf) {
    char *start = buf;
    char tmp;
Serial.println("受信開始");
    while (true) {
        delay(10);
        while (Serial1.available() > 0) {
            tmp =  Serial1.read();
            *buf++ = tmp;
Serial.print(tmp);
            if (*(buf-2) == '\r' && *(buf-1) == '\n') {
                *buf = '\0';
                return (buf - start);
            }
        }
    }
}

int LoRa_send(char * msg) {
    char *start = msg;
    while (*msg != '\0') {
        Serial1.write(*msg++);
    }
    return (msg - start);
}

int sendcmd(char *cmd) {
    unsigned long t;
    char buf[64];

    LoRa_send(cmd);

    while (true) {
        LoRa_recv(buf);      
        if (strstr(buf, "OK")) {
Serial.print(buf);
            return true;
        } else if (strstr(buf, "NG")) {
Serial.print(buf);
            return false;
        }
    }
}

void setMode(int bw, int sf) {
    char buf[64];

Serial.println("LoRa module set start");

    LoRa_send("config\r\n");
    delay(100);
    LoRa_reset();
    delay(1000);
Serial.println("Reset");
    while (true) {
        LoRa_recv(buf);
Serial.println(buf);
        if (strstr(buf, "Mode")) {
            break;
        }
    }

    sendcmd("2\r\n");     //オペレーションモードに移行
Serial.println("Mode 2\r\n");
    sprintf(buf, "bw %d\r\n", bw);
    sendcmd(buf);         //帯域設定
    sprintf(buf, "sf %d\r\n", sf);
    sendcmd(buf);         //拡散率設定
    sendcmd("a 1\r\n");   //ノード：親機設定
    sendcmd("f 0\r\n");   //自ノード設定：0番
    sendcmd("q 2\r\n");   //動作モードをオペレーションに設定
    sendcmd("w\r\n");     //EEPROMにセーブ
    sendcmd("z\r\n");     //start
    
    //LoRa_reset();
Serial.println("LoRa module set to new mode");
    delay(1000);
}

void setup()
{
    myservo.attach(9);//servo変数をピンに割り当てる、ここでは9番ピン
    pinMode(LED_BUILTIN, OUTPUT);
    Serial.begin(115200);
    delay(20);

    Serial1.begin(19200);
    delay(20);

    pinMode(LoRa_Rst, OUTPUT);
    setMode(4, 7);   //4=125kHz,7=拡散率7
}

void loop()
{
    char buf[64];
Serial.println("loop");
    digitalWrite(LED_BUILTIN, HIGH);
    while (true) {
        myservo.write(0);
        LoRa_recv(buf);
        if (strstr(buf, "2")) {
Serial.print(buf);
          myservo.write(90);
          delay(10000);
        }
    }
}
```

### 子機
```c:SLAVE.ino
#include <SoftwareSerial.h>
#include <string.h>

static const int LoRa_Rst = 10;
static const int LoRa_Sleep = 9;
static const int test_in = 7;
static const int PIR_ON = 8;

void LoRa_reset(void) {
    digitalWrite(LoRa_Rst, LOW);
    delay(200);
    digitalWrite(LoRa_Rst, HIGH);
}

int LoRa_recv(char *buf) {
    char *start = buf;
    char tmp;
    
    while (true) {
        delay(10);
        while (Serial.available() > 0) {
            tmp =  Serial.read();
            *buf++ = tmp;
            if (*(buf-2) == '\r' && *(buf-1) == '\n') {
                *buf = '\0';
                return (buf - start);
            }
        }
    }
}

int LoRa_send(char * msg) {
    char *start = msg;
    while (*msg != '\0') {
        Serial.write(*msg++);
    }
    return (msg - start);
}

int sendcmd(char *cmd) {
    unsigned long t;
    char buf[64];

    LoRa_send(cmd);

    while (true) {
        LoRa_recv(buf);      
        if (strstr(buf, "OK")) {
            return true;
        } else if (strstr(buf, "NG")) {
            return false;
        }
    }
}

void setMode(int bw, int sf) {
    char buf[64];

    LoRa_send("config\r\n");
    delay(100);
    LoRa_reset();
    delay(1500);
    while (true) {
        LoRa_recv(buf);
        if (strstr(buf, "Mode")) {
            break;
        }
    }

    sendcmd("2\r\n");     //オペレーションモードに移行

    sprintf(buf, "bw %d\r\n", bw);
    sendcmd(buf);         //帯域設定
    sprintf(buf, "sf %d\r\n", sf);
    sendcmd(buf);         //拡散率設定
    sendcmd("a 2\r\n");   //ノード：子機設定
    sendcmd("f 2\r\n");   //自ノード設定：2番
    sendcmd("q 2\r\n");   //動作モードをオペレーションに設定
    sendcmd("w\r\n");     //EEPROMにセーブ
    sendcmd("z\r\n");     //start

    delay(1000);
}

void setup()
{
    pinMode(test_in, OUTPUT);

    //起動点灯
    digitalWrite(test_in, HIGH);
    delay(300);
    digitalWrite(test_in, LOW);

    Serial.begin(19200);
    delay(20);



    pinMode(LoRa_Rst, OUTPUT);
    pinMode(LoRa_Sleep,OUTPUT);
    digitalWrite(LoRa_Rst, HIGH);
    digitalWrite(LoRa_Sleep, HIGH);
    
    setMode(4, 7);   //4=125kHz,7=拡散率7

    digitalWrite(test_in, HIGH);
    delay(200);
    digitalWrite(test_in, LOW);
    delay(200);
    digitalWrite(test_in, HIGH);
    delay(200);
    digitalWrite(test_in, LOW);
}

void loop()
{
    char buf[64];
    
    if(digitalRead( PIR_ON ) == HIGH){
      digitalWrite(test_in, HIGH);   // turn the LED on (HIGH is the voltage level)
      delay(400);
      digitalWrite(test_in, LOW);
      sendcmd("2\r\n");
      delay(10000);
    }else{
      digitalWrite(7, LOW);   // turn the LED on (HIGH is the voltage level)
    }
}
```
## 完成品
### 親機
![DSC_0587.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/d207fb20-e8f6-ecf3-b3bc-fe92baae57f2.jpeg)

### 子機
![DSC_0586.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/ef7a71ee-5f12-ae08-f24c-7c7dcc95bfe5.jpeg)

### ATMega328P書き込み装置（自作）
![DSC_0588.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/c4bfac3f-3cc9-8007-0339-a3881c83731b.jpeg)

## 苦労した点
### LoRaモジュールの半田めっちゃムズ！！
まじで半端なかった。。。
ES920LR2のピッチが1.27mmだ。普通にブレッドボード刺さんねえ・・・
わざわざ1.27mmピッチのユニバーサル基板買って取り付けました。
（めんどくせえ。EASELさん2.54mmピッチのモジュールにしてくれ）
### Arduino nano everyがボーレート115200で通信できねえ！
nanoとES920でUART通信するんですが全然できねえ！！
オシロスコープで信号を見たら正常に送っている。。。
なぜだ？
試しに持っていたArduino mega2560で通信してみたら・・・
「いや正常に動作するやないかい！！」
多分だがnanoのソフトウェアシリアル通信をしていたのが駄目だったみたい。
（速度的に対応していない？）
なのでmega2650で一度ES920と通信をしてボーレートを115200→19200に変更。
やっとnanoとES920間で通信できました。なんか怖いのでATMega326Pの方に
使うES920も一尾19200に変更しときました。
### 配線が抜けそうで怖え！！
開発中にちょいちょいATMega328Pを抜いていたんですが衝撃で他のピンも抜けそう。
持ち運びの時とか抜けないだろうな・・・？
怖かったのでグルーガンで全体を接着したら結構安定しました。
最初からやっておけばよかった・・・
### ATMega328Pへの書き込み
以下の記事を参考にAruduino nano every版を作成！
http://portaltan.hatenablog.com/entry/2018/01/04/132617
しかしブートローダの書き込みは、以下の方法でやりました。
![スクリーンショット 2021-04-18 12.35.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/b433f20e-eecd-a1a3-bea2-1bdc6a06dfaf.png)
あとは毎回プログラムを変更して、設定は変えずに「マイコンボードに書き込む」ボタンを
押すだけでATMegaに書き込みをしてくれます。

## 最後に
九州で個人的に製品開発を行っております。
「こういうの作りたい」「こういうものがあれば」など
何か作りたいものがありましたらコメント欄でお気軽にご相談ください。