IoTでパンチの速さを計測したい

※この記事は[note](https://note.com/ryota_nomura/n/nf52b17da585a)で公開した、[UMITRONアドベントカレンダー](https://adventar.org/calendars/7398)の18日目の記事の再掲になります。

こんにちは。
キックボクシングを趣味として始めてからもう少しで1年が経過しそうな、ソフトウェアエンジニアの野村です。

突然ですが、昔の偉い人の名言に次のようなものがあります。

>What you measure is what you get
計測したものが実現される

速いパンチを打ちたい自分にとって、パンチの速さを計測することの重要性を感じ、そのようなデバイスを作ることにしました。

# 作成したデバイス

加速度を取得できるセンサーを手に取り付けられる形で実装することにしました。
センサーで取得した加速度の情報はPCでリアルタイムに確認できるようになっています。

https://youtu.be/6KXccNwa8xQ

本来のスピードに近い値を計測するために、ケーブル等は取り付けずにBluetooth経由でPCに情報を送るような仕組みにしました。
デバイスをなるべく軽量化することも意識しました。

# 実装方法
## ハードウェア

小型で、加速度センサーとBluetoothモジュールが組み込まれている、[Arduino Nano 33 BLE](https://www.switch-science.com/products/7667)を使いました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391115/d66754ae-e9bd-8771-9ff0-202bf77910e7.png)

ブレッドボードの裏側に両面テープで9V電池を取り付け、そこから給電するようにしました。
ゴム製のバンドで手に取り付けられるようになっています。

## ソフトウェア

デバイス側はArduinoに処理を実装しています。
加速度センサーから値を取得し、取れた値をBluetoothで送信するという処理をLoopするような実装になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391115/77f8ffdc-310d-0f4c-b9bf-4ff1be348f60.png)

サーバー側は[noble](https://github.com/noble/noble)という、node.jsのBluetoothを扱うライブラリを使って、デバイスが送ったセンサーのデータを取得しています。
取得したデータをリアルタイムにローカルのwebの画面に表示するような実装になっています。

## 速度の計測

当初は加速度を積分したら速度を計算できるんじゃないかと画策していたのですが、今回は断念しました。
一番の理由としては、重力加速度を考慮するために、難易度の高いデバイスの姿勢推定が必要になるためです。（詳細は後述します）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391115/2efbff1c-4f6c-c20b-93df-b701a5b8038d.png)

そのため、今回は簡略化し、x軸方向（パンチの進行方向）の加速度のみに着目することにしました。

https://youtu.be/A_gkeCj0x8U

動画にあるように、パンチの打ち始めでx軸方向の加速度が上昇し、パンチが相手に到達する、腕が伸びきったタイミングでx軸方向の加速度が極小値を迎えます。
この間の時間が短い = パンチが速いと今回は定義して計測を行いました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391115/97fedc58-8829-cee6-3db3-3c4a46b94598.png)

# 計測結果
## パンチ編

それでは早速計測結果を見ていこうと思います。
今回は以下の4種類のパンチで速さを計測し、3~4回打った時の分布を出しました。

```
1. `jab`: ジャブ。一番速いと言われるパンチ。
2. `straight`: 右手で打つストレート。ジャブと比べてパワーがあるパンチ。
3. `hook`: 左フック。横から回り込むような軌道で打つパンチ。
4. `power jab`: 力んだ状態で打ったジャブ。力を抜いた方が速くなるというアドバイスをよく受けるので、その妥当性を検証するために入れた。
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391115/2c41451d-5ad3-7ee2-c51c-197cc295bdf8.png)

結果としては、ジャブ → ストレート → フック の順で遅くなることがわかりました。
またアドバイスを受けた通り、力まない方が速いパンチが実際に打てていることもわかりました。

相手がフックを打ち始めたのに合わせてそれより速いストレートでカウンターを打つ、という場面を試合で見ることがあるのですが、これは100ms程度の時間差を利用しているということもなんとなく納得できました。

## キック編

冒頭の紹介のように、自分はキックボクシングをしています。
せっかくなのでキックの速さも同じ要領で計測してみることにしました。

キックの場合は足の甲にデバイスをつけ、キックの進行方向となるz軸方向で計測することにしました。

キックは以下の3種類のキックを計測してみました。

```
1. `low kick`: 相手の足を狙うキック
2. `middle kick`: 相手のボディを狙うキック
3. `high kick`: 相手の頭を狙うキック
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391115/f629fc9c-57fa-9a58-a80b-817cbdd07f9c.png)

結果としては、ローキック → ミドルキック → ハイキック の順で、蹴る高さが高くなるほど技の出が遅くなることがわかりました。
また、パンチと比較するとキックは全体的に遅くなる傾向がありそうです。

# 改善点

時間の関係もあって今回妥協した部分がいくつかあるのでメモとして残しておきます。

## 姿勢推定

姿勢推定をすることで重力加速度を考慮できるようになる、ということを先に述べました。
二次元に簡略化すると下図のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391115/6c36d89a-f21f-bc7d-a2dc-10e944d7a531.png)

姿勢（デバイスの角度）が推定できれば、重力加速度のかかっている向きが分かり、それを差し引くことでパンチによって生じた加速度成分を計算できるようになります。
これが計算できれば、加速度を積分して、親しみやすい単位である速度を計算する事ができるようになるはずです。

ちなみに今回使用したArduino Nanoに搭載されているセンサは、加速度センサ・ジャイロセンサ・地磁気センサが積まれている9軸センサなので、これらの情報をうまく組み合わせれば、そこそこの精度で姿勢推定することは可能なようです。

https://qiita.com/take4eng/items/da4d5dbbcd5a3fdfded8

また、精度高く姿勢推定する上ではデータのサンプルレートも重要になりそうです。
今回は約180Hzでデータが取れていましたが、センサの種類やCPUの性能を工夫することでさらに改善する余地がありそうです。

## さらなる軽量化

実装の容易さを考えてArduinoを使ったのですが、最低限のセンサ・電池を載せることでさらなる軽量化の余地がありそうです。

http://cpu4edu.net/18026.html

# 最後に

ウミトロンでは一緒に働く仲間を募集しています！
水産養殖×テクノロジーという非常にユニークな事業領域で、共に持続可能な水産養殖を地球に実装していきませんか？

https://umitron.com/ja/index.html