Dev Muscle を支える技術

この記事は <a href="https://qiita.com/advent-calendar/2019/brainpad">Brainpad Advent Calender 2019</a> 20日目の記事です。

懸垂とは関係ありませんが夏に自転車乗って、足と腕に日焼けあとがくっきり残ってしまった @ushi_198 です。
今回は 18 日に紹介した <a href="https://qiita.com/ushi_198/items/b2d0d4bbc6512e379873">Dev Muscle（懸垂をすると掛け声が飛び交う装置）</a>について、
お伝えしたいと思います。

## 紹介と秘話
IT系の企業ならどこにでもある「懸垂マシン」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309546/997a45d9-4ed6-97b2-47b9-2037869d23f4.png)

この懸垂マシンを有効活用して集まる人々。（割と集まる）。
<img width="600" alt="スクリーンショット 2019-12-20 1.06.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309546/b0fd2df7-68e5-61d9-44b0-b9d6c602fe3f.png">

とあるアニメに感化されて、結構前から活動を始めるメンバー（9月5日始動）。
<img width="1090" alt="スクリーンショット 2019-12-20 1.09.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309546/0f16ece1-60ea-401b-53a9-96f64cebcf59.png">

[![ビデオが開けなかった場合に表示されるテキスト](http://img.youtube.com/vi/Ez3BKRr6Zuk/sddefault.jpg)](https://www.youtube.com/embed/Ez3BKRr6Zuk)
（©2019 サンドロビッチ・ヤバ子，MAAM・小学館／シルバーマンジム／<a href="https://www.facebook.com/KADOKAWAanime/">KADOKAWAanime</a>）

---
...
こんなメンバーがいる会社ですが、興味ある方は、ぜひ <a href="http://www.brainpad.co.jp/recruit/">ブレインパッド </a>で一緒に働きましょう！

以上、紹介（宣伝CM）でした。

## Dev Muscle を支える技術

以下を利用しています。

- Raspberry Pi Zero 
- bluetooth スピーカー
- 人感センサー
- ジャンパー
- コーディング：python 

### 環境設定
環境設定です。

- python 環境設定
- bluetooth 環境設定
- 人感センサーの設定

の順に説明します。
python の環境設定をします。

#### python 環境構築
```
# python 関連 セットアップ
sudo apt install python3-dev -y
sudo pip3 install pipenv
```

python の確認

```
$ python3 -V
> Python 3.7.3
```

開発環境の構築

```
❯ mkdir workspace

~
❯ cd workspace

~/workspace
❯ pipenv --python 3.7

~/workspace
❯ pipenv install pygame gpiozero GPIO
```

#### 音声系の環境構築 bluetooth スピーカーの設定

bluetooth の接続設定は、コマンドでやると（macアドレスの特定が面倒である点から）大変です。GUI上からも接続設定すると楽に設定可能で、おすすめです。
ただ、コマンドをここに記載していきます。

bluetooth の関連チェックで、以下をインストール

```
sudo apt install bluealsa
```


bluetooth の環境構築ではMAC アドレスを必要とします。 ラズベリーパイの MAC アドレスと bluetooth スピーカーの MAC アドレスをメモします。
bluetoothctl で この２つの MAC アドレスを確認します。

以下コマンドを実行すると、専用の CUI へ遷移します。

```
bluetoothctl 
```

ここでは以下のコマンドが実行可能です。

- info
- show
- scan on/off
- pair
- trust
- connect
- remove

（参考：https://qiita.com/tshimizu8/items/fdb7e4d0e566790fac20）

以下の実行で、 ラズベリーパイのMACアドレス確認

```
[bluetooth]# show
Controller B8:27:EB:93:xx:xx (public)
	Name: raspberrypi
	Alias: raspberrypi
...
```

以下の実行で、スピーカーのMACアドレスを確認（近くの検知してしまうので、探すのが大変です。）
ここは、GUI上から接続していると楽にMACアドレスを知ることができるます。

```
[bluetooth]# scan on
Discovery started
[CHG] Controller B8:27:EB:93:xx:xx Discovering: yes
[CHG] Device 79:33:4B:B3:xx:xx RSSI: -76
[CHG] Device 62:99:3C:27:xx:xx RSSI: -74
[CHG] Device 62:99:3C:27:xx:xx TxPower: 12
[CHG] Device 60:7B:BB:34:xx:xx RSSI: -79
[CHG] Device 60:7B:BB:34:xx:xx TxPower: 12
```

GUIから接続していると、以下のようにできるイメージです。

```
bluetoothctl 
[SoundCore Boost]# (接続端末のエイリアス名（name?）が表示される)
[SoundCore Boost]# info
Device 00:22:37:56:xx:xx (public)
	Name: SoundCore Boost
	Alias: SoundCore Boost
...
```

aplay などに読み込まれるよう設定します。
ファイルの設定（`.asoundrc` の設定）

```
cat ~/.asoundrc
defaults.bluealsa.interface "hci0"
defaults.bluealsa.device "00:22:37:56:xx:xx" # bluetooth スピーカーの MACアドレス 
defaults.bluealsa.profile "a2dp"
defaults.bluealsa.delay 10000

pcm.bt-receiver {
  type bluealsa
  device "B8:27:EB:93:xx:xx" # ラズベリーパイのMACアドレス
  profile "a2dp"
}
```

接続と音声の出力確認をしてみます。
`amixer` 対象を bluealsa にして、設定状況を確認します。

```
amixer -D bluealsa

Simple mixer control 'SoundCore Boost - A2DP',0
  Capabilities: pvolume pswitch
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 127
  Mono:
  Front Left: Playback 127 [100%] [on]
  Front Right: Playback 127 [100%] [on]
Simple mixer control 'SoundCore Boost - SCO',0
  Capabilities: pvolume pvolume-joined cvolume cvolume-joined pswitch pswitch-joined cswitch cswitch-joined
  Playback channels: Mono
  Capture channels: Mono
  Limits: Playback 0 - 15 Capture 0 - 15
  Mono: Playback 15 [100%] [on] Capture 15 [100%] [on]
Simple mixer control 'SoundCore Boost | Battery',0
  Capabilities: pvolume pvolume-joined
  Playback channels: Mono
  Limits: Playback 0 - 100
  Mono: Playback 77 [77%]
```

音声設定できるか。
対象を `SoundCore Boost - A2DP` に設定してみる。

```
amixer -D bluealsa sset 'SoundCore Boost - A2DP' 50%

Simple mixer control 'SoundCore Boost - A2DP',0
  Capabilities: pvolume pswitch
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 127
  Mono:
  Front Left: Playback 64 [50%] [on]
  Front Right: Playback 64 [50%] [on]
```

50 ％と変更されていると ok です。
音を鳴らすこともできます。

```
$ sudo apt install mpg123 # mp3 音源扱えるライブラリ
$ mpg123 -w 変数変換はいずどん.wav 変数変換はいずどん.mp3

High Performance MPEG 1.0/2.0/2.5 Audio Player for Layer 1, 2, and 3.
Version 0.3.2-1 (2012/03/25). Written and copyrights by Joe Drew,
now maintained by Nanakos Chrysostomos and others.
Uses code from various people. See 'README' for more!
THIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY! USE AT YOUR OWN RISK!

Playing MPEG stream from 変数変換はいずどん.mp3 ...
MPEG 1.0 layer III, 256 kbit/s, 48000 Hz stereo

[0:03] Decoding of 変数変換はいずどん.mp3 finished.

$ aplay -D bluealsa 変数変換はいずどん.wav
再生中 WAVE '変数変換はいずどん.wav' : Signed 16 bit Little Endian, レート 48000 Hz, ステレオ
```

bluetooth のスピーカー接続と、音声が流れるかまでのチェックは終了です。

#### 人感センサーの設定

人感センサーの設定です。
以下を参考に設定しましょう。私達は、この腹筋8LDKから、「１」「39」「40」 に接続しました。
グランド、出力、入力の接続をミスしないように注意しましょう。
GPIO の接続が「40」であると、記載されている通り、プログラミングのセンサ設定では、「GPIO21」を参照することになります。こちらも合わせて注意しましょう。

<a href="http://akizukidenshi.com/download/ds/senba/SB412A.pdf">データシート</a>

<img width="774" alt="スクリーンショット 2019-12-20 3.16.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309546/3c700199-61a4-210b-fc2c-f321549278f4.png">
<img width="774" alt="スクリーンショット 2019-12-20 3.16.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309546/8e443496-810d-f528-9cc6-30affac7da04.png">

##### もう一点注意事項
データシート見るとわかりますが、以下の画像も合わせて注意しないといけません。
センサが反応している時間が、数秒続きます。
これに合わせてプログラム上で、 `time.sleep` を使って、一回しかセンサが反応しないということを設定とかしましょう。

<img width="668" alt="スクリーンショット 2019-12-20 3.23.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309546/b17704eb-9cfc-ee25-7832-cc81404b19b5.png">


### プログラム

接続等設定が終わったら以下のプログラムを書きます。
前回紹介したコードです。

```python
import glob

from gpiozero import MotionSensor
import random
import time

import pygame
from mutagen.mp3 import MP3 as mp3

# 使用するセンサ
sensor = MotionSensor(21)
# interval
interval = 0.1
# 音声リストを取得
cheer_music_list = glob.glob("./mp3/*")

pygame.mixer.init()
time.sleep(5) # エラー回避

def cheer_music():
    """ 応援音声を流す """
    file_name = random.choice(cheer_music_list)
    pygame.mixer.music.load(file_name)
    pygame.mixer.music.play(1)  # 一回実行
    time.sleep(mp3(file_name).info.length + 3)  # load の待機（センサ反応も合わせて）
    pygame.mixer.music.stop()


def detected():
    """ 焦電センサが検知したか """
    if (sensor.motion_detected):
        return True

    return False


if __name__ == "__main__":
    try:
        print("終了キャンセル:CTRL+C")
        cnt = 1
        while True:
            if detected():
                cheer_music()
            # sleep 処理を挟む
            time.sleep(interval)

    except KeyboardInterrupt:
        print("終了処理中...")
    finally:
        print("終了...")
```

コードはベタっと書いてます。

ここで重要なのは、

- `init` した際に音声流す処理するとエラーになる。（解決するために sleep で...）
- `time.sleep(mp3(file_name).info.length + 3)  # load の待機（センサ反応も合わせて）` で 2.4秒のセンサ反応を避けつつ、音声分の `sleep` しています。

割と単純なコードの実装になりました。

#### 自動実行
コードを自動的に実行するような設定は複数ありますが、私は以下を設定

クーロンの設定

```
$ crontab -e 
@reboot bash /home/pi/activate.sh
```

```shell 
# activate.sh の中身
#!/bin/bash

sleep 60
amixer -D bluealsa sset 'SoundCore Boost - A2DP' 50%
python3 /home/pi/workspace/main.py
```

あとは電源を接続すると、人感センサが反応して、音がなります。
「Dev Muscle」の完成です！

### 終わったあとに
割と bluetooth の設定が面倒でした。
分析系の会社だしカメラモジュールとか使って顔認識すればよかったかなぁとか、速度検知して懸垂早いぞと注意や、遅くなったら応援曲流せばよかったかなぁとか、人感センサの検知距離が長いから反応いいなぁとか、思いました。
~~あと、ここの記事で実はスマホ版のやつ作ろうかと考えてましたが、体力がなかったです。~~

あと、同期のエンジニアの野太い声じゃなくて、あのアニメの最後に流れる30秒くらいのトレーニング時に流れていた応援声を使うと心が洗われます。

...
...

---

みんなも準備はいい？

「これで理想の上半身は君のものだ!!!それじゃ、今日も」
「ナイスバルク!!!」


### 参考資料

https://qiita.com/t_oginogin/items/f0ba9d2eb622c05558f4
https://qiita.com/yuyakato/items/76a3d46d1bf57c6a4da6