非接触で呼吸の回数をカウントする

# 概要

久しぶりのM5Stackネタ。Seeed Studio で [24GHz-mmWave-Radar-Sensor-Sleep-Breathing-Monitoring-Module](https://www.seeedstudio.com/24GHz-mmWave-Radar-Sensor-Sleep-Breathing-Monitoring-Module-p-5304.html) というのを見つけたので試してみた。

![](https://media-cdn.seeedstudio.com/media/catalog/product/cache/b2267b506d4e4594666ef83a79896a9a/1/0/101990885_back-06.jpg)

ドップラーレーダーで体の動きを拾うというもの。
仕組みはこちらなどで、

- https://www.kll.keio.ac.jp/ktm2015/pdf/01_ohtsukilab.pdf
- https://eetimes.itmedia.co.jp/ee/articles/1506/25/news099.html

# 試行

このボードは分析結果の数値をシリアルで渡してくれるので、M5Stackと [GROVE - 4ピン-ジャンパメスケーブル](https://www.switch-science.com/catalog/1048/) で繋いで読み取る。
Groveの21ピンをrx、22ピンをtxに割り当て、それぞれボードのtx、rxに接続する。

```cpp:main.cpp
#include <M5Stack.h>

HardwareSerial serial_ext(2);

#define MESSAGE_HEAD 0x55
int data[20] = {0};
int i, j = 0;
int Msg;

typedef union {
  unsigned char Byte[4];
  float Float;
} Float_Byte;

float bodysign(int ad1, int ad2, int ad3, int ad4) {
  Float_Byte fb;
  fb.Byte[0] = ad1;
  fb.Byte[1] = ad2;
  fb.Byte[2] = ad3;
  fb.Byte[3] = ad4;
  return fb.Float;
}

void setup() {
  M5.begin();
  M5.Lcd.fillScreen(TFT_NAVY);

  M5.Lcd.setTextColor(TFT_CYAN);
  M5.Lcd.setTextSize(2);
  M5.Lcd.drawString("Breathing rate:", 0, 0);

  serial_ext.begin(9600, SERIAL_8N1, 21, 22);

  Serial.print("Ready.");
}

void loop() {
  if (serial_ext.available() > 0) {
    Msg = serial_ext.read();
    if (Msg == MESSAGE_HEAD) {
      if (data[3] == 0x00) {
        //
      } else if (data[3] == 0x05 && data[4] == 0x01 && data[5] == 0x01) {
        M5.Lcd.fillRect(40, 40, 100, 100, TFT_NAVY);
        M5.Lcd.setCursor(40, 40);
        M5.Lcd.setTextSize(6);
        M5.Lcd.printf("%d", data[6]);
        Serial.printf("Breathing rate: %d\n", data[6]);
      } else if (data[3] == 0x05 && data[4] == 0x06 && data[5] == 0x01) {
        Serial.printf("Heart rate: %d\n", data[6]);
      } else if (data[3] == 0x05 && data[4] == 0x01 && data[5] == 0x04) {
        if (data[6] == 0x00) {
          Serial.printf("Breathing: Normal.\n");
        } else if (data[6] == 0x01) {
          Serial.printf("Breathing: Holding-abnormality.\n");
        } else if (data[6] == 0x02) {
          Serial.printf("Breathing: No.\n");
        } else if (data[6] == 0x04) {
          Serial.printf("Breathing: Movement-abnormalities.\n");
        } else if (data[6] == 0x05) {
          Serial.printf("Breathing: Shortness abnormal.\n");
        }
      } else if (data[3] == 0x04 && data[4] == 0x03 && data[5] == 0x05) {
        if (data[6] == 0x00) {
          Serial.printf("Environment: Unoccupied.\n");
        } else if (data[7] == 0x00) {
          Serial.printf("Environment: Stationary.\n");
        } else {
          Serial.printf("Environment: Moving.\n");
        }
      } else if (data[3] == 0x04 && data[4] == 0x03 && data[5] == 0x06) {
        Serial.printf("Motor sign: %f\n", bodysign(data[6], data[7], data[8], data[9]));
      } else if (data[3] == 0x04 && data[4] == 0x03 && data[5] == 0x07) {
        if (data[8] == 0x01) {
          Serial.printf("Approaching: None.\n");
        } else if (data[8] == 0x02) {
          Serial.printf("Approaching: Approach.\n");
        } else {
          Serial.printf("Approaching: For Away.\n");
        }
      } else if (data[3] == 0x04 && data[4] == 0x05 && data[5] == 0x01) {
        if (data[6] == 0x00) {
          Serial.printf("Heartbeat Pack: Unoccupied.\n");
        } else if (data[7] == 0x00) {
          Serial.printf("Heartbeat Pack: Stationary.\n");
        } else {
          Serial.printf("Heartbeat Pack: Moving.\n");
        }
      } else {
        for (j = 0; j < 20; j++) {
          Serial.printf("%02x ", data[j]);
        }
        Serial.println("");
      }
      i = 0;
      data[i] = Msg;
      i++;
    } else {
      data[i] = Msg;
      if (i < 19) i++;
    }
  } else {
    delay(25);
  }
}

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555397/91199047-e5e1-65ca-9308-c43b95997326.png)



めでたし。


# 課題

受信はできたものの、ボードに対してコマンド送信がまだうまくいかない。