こんにちは。今回は圧電スピーカーでメリーさんの羊を流したいと思います。
##用意するもの
- ラズパイ
- 圧電スピーカー
今回は秋月電子の[PKM13EPYH4000-A0]を使用しました。30円で購入できました!(2020年3月現在)
購入はこちら - ブレッドボード
- ジャンパーワイヤ オス―メス 2本
##rpi.gpioのインストール
rpi.gpioは標準でインストールされているので、アップデートしましょう。
コマンドプロンプトを起動し、以下のコマンドを入力してください。
sudo apt-get upgrade
もしインストールする場合は、以下のコマンドを実行しましょう。
##回路を組む
今回の回路はとてもシンプルです。
スピーカーの片方をGND(ground)、もう片方を好きなGPIOのピンにつなぎましょう。
=ピン配置はこちら
写真はGPIO21に挿してあります。
##コード
まずは適当な音を鳴らしてみましょう。
#coding:utf-8
import RPi.GPIO as GPIO
import time
pin = 21
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin,GPIO.OUT,initial=GPIO.LOW)
p = GPIO.PWM(pin,1)
p.start(50)
p.ChangeFrequency(220)
time.sleep(3)
p.stop()
GPIO.cleanup()
##解説
#coding:utf-8
日本語のコメント記述ができるようにしています。
import RPi.GPIO as GPIO
import time
使うライブラリをインポート。
pin = 21
自分のさしたGPIOピンの番号を指定します。
GPIO.setmode(GPIO.BCM)
GPIO.setmode()は、ピン番号の指定の仕方を決定します。
今回のGPIO.setmode(GPIO.BCM)は、役割ごとの番号で指定するという意味。GPIOの〇番という風に指定します。
ちなみに、GPIO.setmode(GPIO.BOARD)だと、左上から右下まで順に数えた番号(1~40)で指定します。
GPIO.setup(pin,GPIO.OUT,initial=GPIO.LOW)
GPIOを出力として指定します。引数は、(ピン番号,出力or入力,初期設定がLOWかHIGHか)
p = GPIO.PWM(pin,1)
p.start(50)
PWMのインスタンスをつくり、開始します。
ざっくりいうとスタートの方法みたいな感じです。
p.ChangeFrequency(220)
time.sleep(3)
周波数を変えます。ここではラに相当する220Hzに設定。
time.sleep(3)で3秒間続けます。
p.stop()
GPIO.cleanup()
stopで停止。
GPIO.cleanup()でもうそのピンを使わないよ~という意味です。これをしないと、次にこのピンを使用する際にエラーが出ます。
##メリーさんの羊のコード
#coding:utf-8
import RPi.GPIO as GPIO
import time
import math
pin = 21 #任意のピン番号
a0=27.500 #低いラの音
#n番目の音階の周波数を返す
def onkai(n):
return a0*math.pow(math.pow(2,1/12),n)
#それぞれの音の周波数を定義
DO=onkai(27)
RE=onkai(29)
MI=onkai(31)
SO=onkai(34)
#メロディとリズムを配列に
mery_merody=[MI,RE,DO,RE,MI,MI,MI,RE,RE,RE,MI,SO,SO,MI,RE,DO,RE,MI,MI,MI,RE,RE,MI,RE,DO]
mery_rhythm=[0.9,0.3,0.6,0.6,0.6,0.6,1.2,0.6,0.6,1.2,0.6,0.6,1.2,0.9,0.3,0.6,0.6,0.6,0.6,1.2,0.6,0.6,0.9,0.3,1.8]
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin,GPIO.OUT,initial=GPIO.LOW)
p = GPIO.PWM(pin,1)
p.start(50)
#なぜか最初の方は変な音がするので適当に鳴らす
p.ChangeFrequency(2)
time.sleep(2)
#配列の通りに鳴らす
for i, oto in enumerate(mery_merody):
p.start(50)
p.ChangeFrequency(oto)
time.sleep(mery_rhythm[i])
p.stop()
time.sleep(0.03)
p.stop()
GPIO.cleanup()
##解説
import math
def onkai(n):
return a0*math.pow(math.pow(2,1/12),n)
いちいち周波数を指定するのもあれなんで、関数作ってみました。
https://tomari.org/main/java/oto.html
このサイトによると、
'''
音階は、「音を高低の順番に並べたもの」あり、音の高低は周波数で表します。。
音は、周波数が半分になると1オクターブ低くなり、周波数が倍になると1オクターブ高くなります。
1オクターブには12の音があり(①ド、②ド#(レ♭)、③レ、④レ#(ミ♭)、⑤ミ、⑥ファ、⑦ファ#(ソ♭)、⑧ソ、⑨ソ#(ラ♭)、⑩ラ、⑪ラ#(シ♭)、⑫シ)、
その12の音は、隣り合う半音間での周波数の比率が同じです。(音階に対して等比数列的に増える)
音の周波数をa0,a1,a2・・・・a12とし、この等比数列の公比をrとすると、a12=a0r12=2a0であるから、r12=2よりr=12√2(r=1.059463094)、よってan=a0rn=a0*(2(1/12))nとなります。
'''
よって
an=a0*(2(1/12))n ※a0=27.50Hz(結構低いラ)
らしいので、nを引数にして、n番目の音の周波数を返す関数をかいてみました。
#それぞれの音の周波数を定義
DO=onkai(27)
RE=onkai(29)
MI=onkai(31)
SO=onkai(34)
結局ここでこう書いたら関数の意味なかったな…とおもう。
#メロディとリズムを配列に
mery_merody=[MI,RE,DO,RE,MI,MI,MI,RE,RE,RE,MI,SO,SO,MI,RE,DO,RE,MI,MI,MI,RE,RE,MI,RE,DO]
mery_rhythm=[0.9,0.3,0.6,0.6,0.6,0.6,1.2,0.6,0.6,1.2,0.6,0.6,1.2,0.9,0.3,0.6,0.6,0.6,0.6,1.2,0.6,0.6,0.9,0.3,1.8]
めりさんの羊の音階、それぞれの音をならす時間の配列です。ここをかえればお好きな曲をながせます。
四分音符を0.6にしてあります。皆さんのお好みの長さに変えてください。
#なぜか最初の方は変な音がするので適当に鳴らす
p.ChangeFrequency(2)
time.sleep(2)
なぜだかわからないのですが、実行して最初のほうだけ音がずれてたので、最初2秒くらい聞こえないくらい低い音鳴らしています。なくていいです。
#配列の通りに鳴らす
for i, oto in enumerate(mery_merody):
p.start(50)
p.ChangeFrequency(oto)
time.sleep(mery_rhythm[i])
p.stop()
time.sleep(0.03)
enumerateを使うことで、iに繰り返し回数が入ります。
もっといい書き方あったら教えてください。
otoの周波数に変えて、それをmery_rhythm[i]秒続けます。
p.stop()、time.sleep(0.03)で一回止めます。音が連続してるとつながってしまったので、この処理を書きました。
リズムずれますけどまあご愛敬…。
##まとめ
ということで、圧電スピーカーを鳴らしてみました。
次回は踏切の音をならしたいな~