Raspberry Pi 5 で「人を検知したらファミマの入店音を流す装置」を作る
はじめに
Rasberry Pi 5 のGPIOを活用した電子工作の練習として、簡単な装置を作りました。
人感センサーで人を検知すると、ファミリーマートの入店音を再生します。
この記事では、人感センサー・圧電スピーカーの使い方や、gpiozeroを活用して実装したプログラムについて紹介します。
環境
Raspberry Pi 5で動作を確認しています。
GPIO操作用ライブラリのgpiozero
が必須です。Raspberry Pi 5にラズパイOSをインストールした状態であれば標準で使えるはずです。
OSなど
- Raspberry Pi 5
- Raspberry Pi OS (64 bit) 12.5
- Python 3.11.2
必要な部品は以下のとおりです。人感センサーは型番が違っていても問題ないと思います。
電子部品
- 赤外線人感センサー HC-SR501
- 圧電スピーカー(型番不明、3V駆動)
- ブレッドボード、ジャンパー線
結線方法
人感センサーの信号線をGPIO23
に、圧電スピーカーのプラス線をGPIO17
に接続してください。
配線イメージ
プログラム
ソースコードの全文は以下のとおりです。
今回は、GPIOの操作用ライブラリ「gpiozero」の機能を活用しました。詳細な使い方はこの後に説明します。
from time import sleep
from gpiozero import MotionSensor, TonalBuzzer
from gpiozero.tones import Tone
BPM = 80
motion_sensor = MotionSensor(23)
buzzer = TonalBuzzer(17)
def play_sound(divide: int, tone: str = ""):
if tone == "":
buzzer.stop()
else:
buzzer.play(Tone(tone))
sleep((60 / BPM) / (divide / 4))
def play_famima_sound():
play_sound(8, "F#5") # ファ
play_sound(8, "D5") # レ
play_sound(8, "A4") # ラ
play_sound(8, "D5") # レ
play_sound(8, "E5") # ミ
play_sound(8, "A5") # ラ
play_sound(8)
play_sound(8, "E4") # ミ
play_sound(8, "E5") # ミ
play_sound(8, "F#5") # ファ
play_sound(8, "E5") # ミ
play_sound(8, "A4") # ラ
play_sound(4, "D5") # レ
play_sound(4)
def main():
while True:
motion_sensor.wait_for_active()
print("Motion!")
play_famima_sound()
if __name__ == "__main__":
main()
人感センサー
人感センサーは、人の動きを検知すると信号線がHighになるセンサーです。gpiozeroのMotionSensor
クラスを利用すると、この入力判定を楽に記述できます。
以下のように、motion_sensor.wait_for_active()
で人感センサーの信号線がHighになるのを待ちます。Highになるとプログラムが次に進み、検知後の処理を実行できます。
from time import sleep
from gpiozero import MotionSensor, TonalBuzzer
from gpiozero.tones import Tone
BPM = 80
motion_sensor = MotionSensor(23)
buzzer = TonalBuzzer(17)
# 省略
def main():
while True:
motion_sensor.wait_for_active() # 人感センサーがONになるまで待つ
print("Motion!")
play_famima_sound()
if __name__ == "__main__":
main()
検知結果のハンドリング方法は他にもいくつかあります。詳しくはgpiozeroのドキュメントを参照してください。
圧電スピーカー
圧電スピーカーは、数kHzの信号を入力することで音を鳴らすことができます。これはgpiozeroのTonalBuzzer
クラスを利用すると簡単に実装できます。
このクラスでは、Tone
で音色(周波数)を指定します。周波数を直接記載するほかに、英語の音階でも指定できます。
from gpiozero import TonalBuzzer
from gpiozero.tones import Tone
b = TonalBuzzer(17)
b.play(Tone(220.0)) # Hz
b.play(Tone("A4"))
今回は読みやすさを考慮して、音階での表記を採用しました。以下のような表記で書くことができます。「ファ#」も「#」を使って書けます。
音階 | 表記 |
---|---|
ド | C4 |
レ | D4 |
ミ | E4 |
ファ | F4 |
ファ | F#4 |
ソ | G4 |
ラ | A4 |
シ | B4 |
ド | C5 |
圧電スピーカーの詳しい使い方は公式ドキュメントを参考にしてください。
play_sound関数
与えられた音の長さと音程にしたがって、ブザーから音を出力する関数です。
tone
引数に音程を指定すると、その音を鳴らし、引数が空の場合は音を止めます。divide
引数は音の長さを表しています。四分音符の場合は4を入力します。
def play_sound(divide: int, tone: str = ""):
if tone == "":
buzzer.stop()
else:
buzzer.play(Tone(tone))
sleep((60 / BPM) / (divide / 4))
play_famima_sound関数
play_sound()
関数を使って、ファミリーマートの入店音のメロディーを再現しています。それぞれの音程と長さを指定して、play_sound()
関数を呼び出しています。
def play_famima_sound():
play_sound(8, "F#5") # ファ
play_sound(8, "D5") # レ
play_sound(8, "A4") # ラ
play_sound(8, "D5") # レ
play_sound(8, "E5") # ミ
play_sound(8, "A5") # ラ
play_sound(8)
play_sound(8, "E4") # ミ
play_sound(8, "E5") # ミ
play_sound(8, "F#5") # ファ
play_sound(8, "E5") # ミ
play_sound(8, "A4") # ラ
play_sound(4, "D5") # レ
play_sound(4)
なお、ファミマ入店音の楽譜はこちらのサイトを参考にさせていただきました。短音バージョンを利用しています。
単音で演奏できる楽譜であれば、他にも色々なメロディーを演奏できそうです。
まとめ
Raspberry PiのGPIOを利用して、センサーやブザーを制御するプログラムの基本が理解できました。
gpiozero
ライブラリを使えば、ハードウェア制御が簡単になることがわかります。
このライブラリには他にも入出力デバイスのためのクラスが用意されているので、簡単なコーディングで色々な電子工作を楽しむことができます。
公式ドキュメントの「Basic Recipes」には他にもさまざまな実装アイデアが掲載されているので、電子工作のアイデアにお悩みの方は一度読んでみると良いと思います。
参考文献
Discussion