自転車の後方センサーを超音波センサーで自作する

## 概要
* 自転車の後方センサーで、サイクルコンピューターにBluetoothで通知するものは既にあるが高価
* まずはできるだけ安価なボードとセンサーの組み合わせで実現できるか、プロトタイプを作ってみることにした。
* 耐震性や防水性に懸念があるが、まず動作させてから考えることにする。

![IMG_9883.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701445/719dde43-2e7b-43ef-59e0-e43fbacf13ac.jpeg)

![49344519_2161981863857970_1286613666048770048_o.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701445/80deebe7-a777-c2ad-7ea1-215e21305b5e.jpeg)

![スクリーンショット 2020-10-13 9.21.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701445/17ab4a71-8672-c5e1-2885-065d32069ce6.png)


## 用意するもの
* M5Stack
* M5Stack用の電源
* 超音波センサー HY-SRF05
* Arduino IDEが動くPC (Mac/Windows)

## 環境構築

(1)Arduino IDEをインストール
https://www.arduino.cc/en/main/software
(2)M5Stack関連のライブラリをインストール
https://mag.switch-science.com/2018/02/28/getting-started-with-m5stack/

## 準備

* M5Stackと超音波センサーを下図のように接続する

![スクリーンショット 2020-10-13 9.48.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701445/bf60a27f-02ed-5cf3-2b8f-89c4317faac0.png)


## プログラミング

* 超音波センサーで距離を測定し、その値に応じたバーグラフとビープ音を発生させる
* バーグラフの表示は、極力負荷を軽くするため文字("|")を使う
* 当初は扇子のような形状のレーダーを描画しようとしていたが、画面更新のチラツキが大きく断念した。（円を描き中心座標を端にすることで扇子のような画像を描こうとした）

```C++:bike_rader.ino
#include <M5Stack.h>
#define GPIO_PIN 25

const unsigned int TRIG_PIN=2;
const unsigned int ECHO_PIN=5;
const unsigned int BAUD_RATE=9600;

uint32_t beep_last_time = 0;
uint8_t beep_volume = 10; //min 1, max 255
uint32_t beep_total_time = 0;

void setup() {
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  Serial.begin(BAUD_RATE);
  M5.begin();
  M5.Lcd.setBrightness(10);
  beep_total_time = millis();
}

void loop() {
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  
 const float duration= pulseIn(ECHO_PIN, HIGH);
 float distance= duration/29/2/100;
 if(duration==0){
   Serial.println("Warning: no pulse from sensor");
   } 
  else{
    if (distance < 6.0){
      M5.Lcd.setCursor(50,220);
      M5.Lcd.setTextSize(2);
      M5.Lcd.println(" m");
      double D001 = distance;
      M5.Lcd.setCursor(0,220);
      M5.Lcd.setTextSize(2);
      char D000[4];
      dtostrf(D001, 3, 2, D000);
      M5.lcd.print(D000);
      M5.Lcd.setTextSize(5);
      M5.Lcd.setCursor(0,110);
      for(int cnt = 0; cnt < (13 - int(distance * 3.5)); cnt++){
        M5.Lcd.print("|");
        if(cnt > 8){
          break;
        }
      }
      
      if ((distance) <= 4.0){
          beep_volume = 20 - int(distance * 5);
          if (beep_volume < 0){
            beep_volume = 0;
          }
          
          while(1){
            uint32_t b_period = millis() - beep_last_time;
            if( b_period < 25 ){
              dacWrite(GPIO_PIN, 0);
              delay(1); //約500Hz
              dacWrite(GPIO_PIN, beep_volume); 
              delay(1); //約500Hz
            }else if( b_period >= 25 && b_period < 50 ){
              dacWrite(GPIO_PIN, 0);
              break;
            }else{
              beep_last_time = millis();
            }
          }
      }else{
        M5.Lcd.clear();
        sleep(2);
      }
      for(int cnt = 0; cnt < (13 - int(distance * 3.5)); cnt++){
      M5.Lcd.print(" ");
      } 
    }
  }
  delay(100);
}
```

## 注意点
* M5Stackをバッテリー駆動した際に、1.5m以上が測定できなくなる事象が発生した。  
LCD画面の電力消費が激しいことが原因で、輝度を落とす(setBrightness(10))ことで解決した。

## その他
* 走行中に画面を見るのは危ないので、本体はサドルバッグに収納しランプとブザーは別体とした方が良いかもしれない。
* 小型化のためM5StickC Plus(ブザー・LEDあり)を使ってみたが50cm以上が測定できない。原因調査中。
* レンタルサイクルに装備し検出された回数と時間を集積すれば、事故防止の注意喚起や、道路の再整備に役立つのではないかと思う。