6軸センサを用いて衝撃を検出する(M5StickC)

M5StickCは6軸センサが内蔵されているので衝撃を検出できるんじゃないかと思ったんですが、
ネットで検索しても出てこなかったので自分でなんとかしました。
需要があるか分かりませんが備忘録としてQiitaにまとめることにしました。

M5StickCに限らず6軸センサなら何でも大丈夫だと思います(加速度の単位は違うかもしれない)

##衝撃を検出するには？
衝撃ということはいわゆるGを検出すればいいので(異論は認める)静止時の重力加速度がどのように検出されているか確認します。

まず6軸センサの加速度を足せばいいんじゃないか？と思って足してみましたが・・・
角度によってはマイナスになるのでうまく行きません。

##ベクトルとして考える
簡単にするため2軸としてXとYがマイナスになるように45度傾けた図はこうなりますので、ベクトルとして考えればよさそうですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/0aea7f15-1570-2abb-cbf5-6bcf54483343.png)


というわけでXYZそれぞれの二乗を足して平方根を取ってみます。
ほぼサンプルのままです。

```cpp
#include <M5StickC.h>
float accX = 0;
float accY = 0;
float accZ = 0;

float gyroX = 0;
float gyroY = 0;
float gyroZ = 0;
float g = 0;

void setup() {
    M5.begin()
    M5.Lcd.setRotation(3);
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setTextSize(1);
    M5.Lcd.setCursor(40, 0);
    M5.Lcd.println("MPU6886 TEST");
    M5.Lcd.setCursor(0, 15);
    M5.Lcd.println("  X       Y       Z");
    M5.MPU6886.Init();
    pinMode(GPIO_NUM_10, OUTPUT); // internal LED
    digitalWrite(GPIO_NUM_10, HIGH);
}
void loop() {
    M5.MPU6886.getGyroData(&gyroX, &gyroY, &gyroZ);
    M5.MPU6886.getAccelData(&accX, &accY, &accZ);
    M5.Lcd.setCursor(0, 30);
    M5.Lcd.printf("%4.1f %4.1f %4.1f      ", gyroX, gyroY, gyroZ);
    M5.Lcd.setCursor(140, 30);
    M5.Lcd.print("o/s");
    M5.Lcd.setCursor(0, 45);
    M5.Lcd.printf("%4.1f %4.1f %4.1f      ", accX * 1000, accY * 1000, accZ * 1000);
    M5.Lcd.setCursor(140, 45);
    M5.Lcd.print("mg");
    M5.Lcd.setCursor(0, 60);

    // accX,accY,accZそれぞれの二乗和の平方根を取る
    g = sqrt(pow(accX, 2) + pow(accY, 2) + pow(accZ, 2)) * 1000;
    M5.Lcd.printf("mG : %4.1f ", g);

    if (2000 < g) {
        // 2Gより衝撃が大きいとき内蔵LEDを点灯
        digitalWrite(GPIO_NUM_10, LOW);
        delay(1000);
        digitalWrite(GPIO_NUM_10, HIGH);
    }
    delay(1);
}

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/097657f0-07d9-c950-d01a-0a0fb01afb5f.png)

こうすることで見やすいように1000倍してありますがだいたい1000=1Gくらいの値が出るようになりました。
写真では1120.5になってますが値がフラフラしてるので問題ないと思います。
ただしどの程度の精度が出てるかは不明です。

動作の様子
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/M5StickC?src=hash&amp;ref_src=twsrc%5Etfw">#M5StickC</a> の6軸センサによる衝撃検出(Impact detection)<br><br>これでソフト側のプロトタイプできたからハード側も作り込まないと(´・ω・`) <a href="https://t.co/Tg6N0ah1gS">pic.twitter.com/Tg6N0ah1gS</a></p>&mdash; もけ@ムギ㌠ (@coppercele) <a href="https://twitter.com/coppercele/status/1219245265682456576?ref_src=twsrc%5Etfw">January 20, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

下の画像はArduino IDEのシリアルプロッタでグラフにしてみたものです。
オレンジの線がGです。1000=(だいたい)1Gとなります。
赤矢印の区間はなるべく空中で動かないようにM5StickCを回転させました。
姿勢によってXYZの値は変わりますが加速度は1G付近をキープしています。

青矢印の部分でM5StickCを手に叩きつけています。
3000程度の値になってるので3Gくらいかかっていたようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/46b34646-ef3d-3326-82a1-852b3540d441.png)

というわけで衝撃を検出できるようになりましたので、
デスストランディングに出てくるダメージセンサーテープを作ってみました。
M5StickCで衝撃を検出してNeopixelテープを光らせています。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/deathstranding?src=hash&amp;ref_src=twsrc%5Etfw">#deathstranding</a> に出てくるダメージセンサーテープ作ったよー＼(^o^)／<br><br>プロトタイプと言うか思いつきなんで見た目は気にしないで(´・ω・`)<a href="https://twitter.com/hashtag/M5StickC?src=hash&amp;ref_src=twsrc%5Etfw">#M5StickC</a> <a href="https://t.co/iekF73Bp1U">pic.twitter.com/iekF73Bp1U</a></p>&mdash; もけ@ムギ㌠ (@coppercele) <a href="https://twitter.com/coppercele/status/1219605024440909824?ref_src=twsrc%5Etfw">January 21, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>