はじめに
PWM でモーターを回したついでに PWM で音を鳴らしてみる.
音階
仕組みが分かると楽しさ N 倍ということで,人間の耳は空気を伝搬する音波を聞いて,周波数成分を音の高低,振幅成分を音量として認識する.周波数においては一般的に 20Hz 〜 15kHz 程度が人間の可聴音域とされている.したがって今回発生させる PWM 信号の周波数はこの可聴音域の範囲内で生成すればいい.
音楽に明るい人であれば平均律や純正律といった言葉を聞いたことがあるかもしれない.これらの違いを考えるのは非常に興味深いものがあるが,ここでは 12 平均律を扱うことにする.
我々が普段耳にする音はフーリエ級数で表される様ないろいろな周波数成分で構成されている.フーリエ変換の計算は二度とやりたくないが,概念だけは理解しておいても後学のために良いかもしれない.次の動画がわかりやすく解説されている.
RasPi で生成する PWM (パルス幅変調, Pulse Width Modulation) 信号は,モータの制御を行ったように,パルス幅を変化させてスイッチの ON/OFF 比率を変化させたり,LEDの明るさを調整したりするなどの用途で利用される.波形という意味では音波と似た性質を持っているので,今回はこの PWM 信号を使ってスピーカーから音を鳴らしてみる.
どの周波数がなんの音に対応しているのかは次のページがよくまとめられている.波形のプルダウンを「矩形波」に設定することで,デューティ比を 50% の PWM 信号相当の音を確認することができる.
PWM で音を鳴らす
PWM 設定の有効化は以下を参照.
配線は次の通り.RasPi にスピーカーをつなげただけ.
今回使ったスピーカーはこれ.カムロボに組み込む想定でなるべく小さめの物を選んだ.
まずは指定した周波数を簡単に生成できるように適当なスクリプトを書く.こんな感じ.
#!/bin/bash
#############################
# usage: ./${shell-name} $freq
#############################
# INIT ######################
if [ $# -ne 1 ]; then
echo '[ERROR] invalid args'
echo "./$0 freq_as_Hz"
exit 1
fi
FREQ=$1 # FREQUENCY Hz
PERIOD=$((1000000000/$1)) # PERIOD nsec
PWIDTH=$(($PERIOD/2)) # PULSE WIDTH nsec
if [ $PERIOD -lt 20 ] || [ $PERIOD -ge 2000000000 ]; then # 20nsec <= $PERIOD < 2sec
echo '[ERROR] invalid range'
exit 1
fi
# MAIN ######################
# show param
echo FREQ=$FREQ Hz
echo PERIOD=$PERIOD nsec
echo PWIDTH=$PWIDTH nsec
# set param
echo 0 > /sys/class/pwm/pwmchip0/pwm1/duty_cycle
echo $PERIOD > /sys/class/pwm/pwmchip0/pwm1/period
echo $PWIDTH > /sys/class/pwm/pwmchip0/pwm1/duty_cycle
# tone
echo 1 > /sys/class/pwm/pwmchip0/pwm1/enable
sleep 1
echo 0 > /sys/class/pwm/pwmchip0/pwm1/enable
これを使って適当に音階を鳴らしてみる.こんな感じ.引数に Hz 単位の周波数を指定して実行する.うまく行けばドレミファソラシドと 8 音聞こえるはず.
#!/bin/bash
echo C5
./pwm_sound_test.sh 523
echo D5
./pwm_sound_test.sh 587
echo E5
./pwm_sound_test.sh 659
echo F5
./pwm_sound_test.sh 698
echo G5
./pwm_sound_test.sh 784
echo A5
./pwm_sound_test.sh 880
echo B5
./pwm_sound_test.sh 988
echo C6
./pwm_sound_test.sh 1047
おわりに
RasPi の PWM 信号を使って音を鳴らしてみた.余力があればデューティ比変えてみるとか工夫してみても楽しいかもしれない.
<おまけ> R2D2 っぽい音を鳴らす
せっかくカムロボに組み込むなら R2D2 っぽい音を鳴らせないものかと思案していたら,Arduino 用のコードを公開してくれている人がいた.
RasPi 用に適当に移植して鳴らしてみるとこんな感じ.R2D2 の音声は色々な周波数成分が含まれているので PWM 信号では完全再現出来ないが,まぁ及第点ということで.移植版コードは思い立ったらオリジナルのライセンスで公開するかもしないかも.
コメント