EPISODE · Jul 9, 2026 · 31 MIN
378 日記 | ロータリーエンコーダーで音量調節
from TanaRadio · host たな
まず,ロータリーエンコーダーをDIP化基板にハンダ付けして,それからこれを使って音量調整できるようにしました(フェーズ5I完了)。フェーズ5I 詳細マニュアル ロータリーエンコーダーで音量調整する 0. 今回の目標 今回追加する機能はこれです。 ロータリーエンコーダーを右に回す ↓ 音量アップ ロータリーエンコーダーを左に回す ↓ 音量ダウン 今回は、エンコーダーの押し込みによるミュートは扱いません。 たなさんの手元のロータリーエンコーダーは3端子タイプなので、 A C / GND / COM B の3本だけを使います。 1. 今回使うGPIO フェーズ5Gでは、次の構成で進んでいる前提にします。 再生/一時停止ボタン:GPIO17 戻るボタン:GPIO27 次へボタン:GPIO22 棚選びボタン:GPIO23 再生モードボタン:GPIO5 棚LED:GPIO24 モードLED:GPIO6 mpv IPCソケット: /tmp/tanaradio-mpv.sock 今回は、ロータリーエンコーダー用に次の2本を追加します。 エンコーダーA:GPIO20 エンコーダーB:GPIO21 エンコーダーC / COM:GND 物理ピンで言うと、Raspberry Piの40ピンヘッダーでは次の並びが使いやすいです。 GPIO20:物理ピン38 GND :物理ピン39 GPIO21:物理ピン40 ここが気持ちよく並んでいます。電子工作の神様が一瞬だけ優しい顔をしています。 gpiozeroの公式ドキュメントでも、ロータリーエンコーダーはA/BをGPIOへ、CつまりcommonをGNDへ接続する形で説明されています。 2. 配線する前にRaspberry Piを終了する まず、現在動いている tanaradio_5g.py があれば Ctrl + C で止めます。 そのあと、Raspberry Piを終了します。 sudo shutdown -h now 緑LEDの点滅が落ち着き、完全に止まったら電源ケーブルを抜きます。 GPIO配線は、必ず電源を抜いてから行います。 特に今回はGPIOが増えるので、ここは慎重でよいです。急がない。ラジオは逃げません。 3. ロータリーエンコーダーを配線する ロータリーエンコーダーの3端子を、次のようにつなぎます。 ロータリーエンコーダー A → GPIO20 ロータリーエンコーダー C → GND ロータリーエンコーダー B → GPIO21 DIP化基板に A、C、B のような表記があれば、それに従います。 もし表記が分かりにくい場合は、中央の端子が C / COM / GND であることが多いです。ただし、ここは部品によって違う可能性もあります。基板に印字があるなら印字を優先してください。 重要なのはこれです。 ロータリーエンコーダーには 5V をつながない 3.3V も今回はつながない C / COM は GND につなぐ A と B を GPIO20 / GPIO21 につなぐ 4. 起動して作業フォルダへ移動する 配線が終わったら、Raspberry Piの電源を入れます。 起動したらターミナルを開きます。 cd ~/tanaradio5 確認します。 pwd 次のように表示されればOKです。 /home/tana/tanaradio5 5. 必要パッケージを確認する 念のため、gpiozero関係を入れておきます。 sudo apt update sudo apt install -y python3-gpiozero python3-lgpio すでに入っていれば、そのままで大丈夫です。 6. ロータリーエンコーダー単体テスト まず、音量制御とは関係なく、エンコーダーを回したらPythonが反応するかだけ確認します。 nano test_encoder_5i.py 次を貼り付けます。 #!/usr/bin/env python3 from gpiozero import RotaryEncoder from signal import pause ENC_A_GPIO = 20 ENC_B_GPIO = 21 encoder = RotaryEncoder( ENC_A_GPIO, ENC_B_GPIO, max_steps=0, bounce_time=0.002 ) def rotated_clockwise(): print("右回し") def rotated_counter_clockwise(): print("左回し") encoder.when_rotated_clockwise = rotated_clockwise encoder.when_rotated_counter_clockwise = rotated_counter_clockwise print("ロータリーエンコーダーのテストを開始します。") print("つまみを左右に回してください。") print("終了するには Ctrl+C を押してください。") pause() 保存します。 Ctrl + O Enter Ctrl + X 実行できるようにします。 chmod +x test_encoder_5i.py 実行します。 ./test_encoder_5i.py つまみを右に回して、 右回し 左に回して、 左回し と出れば成功です。 終了は、 Ctrl + C です。 8. 5Gを動かしたまま音量制御テストをする 次に、tanaradio_5g.py はそのまま使い、別のテストプログラムからmpvへ音量命令を送ります。 mpvはIPCソケットで外部制御できます。mpvの公式マニュアルでも、外部プログラムから制御する場合は --input-ipc-server を使う方法が説明されています。 また、mpvの音量操作は add volume 5 / add volume -5 のようなコマンドで行えます。 まず、1つ目のターミナルで5Gを起動します。 cd ~/tanaradio5 ./tanaradio_5g.py 音が出る状態にしておきます。 次に、別のターミナルを開いて、同じフォルダへ移動します。 cd ~/tanaradio5 音量テスト用ファイルを作ります。 nano test_volume_5i.py 次を貼り付けます。 #!/usr/bin/env python3 import json import os import socket import time from gpiozero import RotaryEncoder from signal import pause MPV_SOCKET = "/tmp/tanaradio-mpv.sock" ENC_A_GPIO = 20 ENC_B_GPIO = 21 VOLUME_STEP = 5 MIN_VOLUME_INTERVAL = 0.04 last_volume_time = 0.0 encoder = RotaryEncoder( ENC_A_GPIO, ENC_B_GPIO, max_steps=0, bounce_time=0.002 ) def send_mpv_command(*command): if not os.path.exists(MPV_SOCKET): print("mpvのソケットが見つかりません。") print("先に別ターミナルで ./tanaradio_5g.py を起動してください。") return try: data = json.dumps({"command": list(command)}) + "\n" with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as client: client.connect(MPV_SOCKET) client.sendall(data.encode("utf-8")) try: response = client.recv(4096) if response: print(response.decode("utf-8").strip()) except Exception: pass except Exception as e: print(f"mpvコマンド送信エラー: {e}") def change_volume(delta): global last_volume_time now = time.monotonic() if now - last_volume_time < MIN_VOLUME_INTERVAL: return last_volume_time = now if delta > 0: print("音量アップ") else: print("音量ダウン") send_mpv_command("add", "volume", delta) def volume_up(): change_volume(VOLUME_STEP) def volume_down(): change_volume(-VOLUME_STEP) encoder.when_rotated_clockwise = volume_up encoder.when_rotated_counter_clockwise = volume_down print("ロータリーエンコーダー音量テストを開始します。") print("別ターミナルで tanaradio_5g.py が動いている必要があります。") print("つまみを右に回すと音量アップ、左に回すと音量ダウンです。") print("終了するには Ctrl+C を押してください。") pause() 保存します。 Ctrl + O Enter Ctrl + X 実行できるようにします。 chmod +x test_volume_5i.py 実行します。 ./test_volume_5i.py 5Gで音声を流したまま、つまみを回します。 右回し → 音量アップ 左回し → 音量ダウン になれば、フェーズ5Iの核心部分は成功です。 9. 5Gコードを5Iとしてコピーする ここから本体に統合します。 まず、5Gコードをコピーします。 cp tanaradio_5g.py tanaradio_5i.py バックアップも作っておきます。 cp tanaradio_5g.py tanaradio_5g_backup.py 編集します。 nano tanaradio_5i.py 10. RotaryEncoder をimportに追加する コードの上の方に、たぶん次のような行があります。 from gpiozero import Button, LED これを次のようにします。 from gpiozero import Button, LED, RotaryEncoder すでに RotaryEncoder が入っていたら、そのままでOKです。 11. GPIO設定を追加する GPIO番号を定義している部分に、次を追加します。 ENC_A_GPIO = 20 ENC_B_GPIO = 21 VOLUME_STEP = 5 MIN_VOLUME_INTERVAL = 0.04 last_volume_time = 0.0 VOLUME_STEP = 5 は、1クリックごとに音量を5ずつ変える設定です。 大きすぎると感じたら、あとで次のように小さくできます。 VOLUME_STEP = 3 または、 VOLUME_STEP = 2 12. 音量変更関数を追加する ボタンの処理関数が並んでいるあたりに、次を追加します。 def change_volume(delta): global last_volume_time now = time.monotonic() if now - last_volume_time < MIN_VOLUME_INTERVAL: return last_volume_time = now if delta > 0: print(f"音量アップ +{delta}") else: print(f"音量ダウン {delta}") send_mpv_command("add", "volume", delta) def volume_up(): change_volume(VOLUME_STEP) def volume_down(): change_volume(-VOLUME_STEP) ここで使っている send_mpv_command() は、5Gですでに使っているmpv制御関数です。 もし5Gコード内で関数名が違っていて、たとえば、 send_command(...) や、 mpv_command(...) のような名前になっている場合は、この部分だけ5G側の関数名に合わせてください。 つまり、この行です。 send_mpv_command("add", "volume", delta) ここを、5Gで使っている名前に合わせます。 13. エンコーダーを作成してイベントを登録する ボタンを作っている場所を探します。 たとえば次のような場所です。 play_button = Button(...) prev_button = Button(...) next_button = Button(...) shelf_button = Button(...) mode_button = Button(...) その近くに、次を追加します。 encoder = RotaryEncoder( ENC_A_GPIO, ENC_B_GPIO, max_steps=0, bounce_time=0.002 ) encoder.when_rotated_clockwise = volume_up encoder.when_rotated_counter_clockwise = volume_down もし5Gコードに setup_buttons() のような関数がある場合は、その関数の中に追加してください。 その場合、最後の return に encoder も含めておくと安全です。 例: def setup_buttons(): play_button = Button(PLAY_GPIO, pull_up=True, bounce_time=0.05) prev_button = Button(PREV_GPIO, pull_up=True, bounce_time=0.05) next_button = Button(NEXT_GPIO, pull_up=True, bounce_time=0.05) shelf_button = Button(SHELF_GPIO, pull_up=True, bounce_time=0.08) mode_button = Button(MODE_GPIO, pull_up=True, bounce_time=0.08) encoder = RotaryEncoder( ENC_A_GPIO, ENC_B_GPIO, max_steps=0, bounce_time=0.002 ) play_button.when_pressed = toggle_pause prev_button.when_pressed = previous_episode next_button.when_pressed = next_episode shelf_button.when_pressed = change_shelf mode_button.when_pressed = change_mode encoder.when_rotated_clockwise = volume_up encoder.when_rotated_counter_clockwise = volume_down return [ play_button, prev_button, next_button, shelf_button, mode_button, encoder, ] すでにLEDも同じ関数内で作っている場合は、LEDもreturnに残してください。 大事なのは、encoder を作ったあと、プログラム終了まで消えないようにすることです。 Pythonでは、作った部品オブジェクトを変数として保持しておく必要があります。 14. time がimportされているか確認する 今回の change_volume() では time.monotonic() を使います。 コードの上の方に、 import time があるか確認してください。 なければ追加します。 import time 15. 保存して実行する 保存します。 Ctrl + O Enter Ctrl + X 実行できるようにします。 chmod +x tanaradio_5i.py 5Gが動いている場合はいったん止めます。 Ctrl + C 5Iを実行します。 ./tanaradio_5i.py 確認することは次の通りです。 再生/一時停止ボタンが効く 戻るボタンが効く 次へボタンが効く 棚選びボタンが効く 再生モードボタンが効く 棚LEDが点滅する モードLEDが点滅する ロータリーエンコーダー右回しで音量アップ ロータリーエンコーダー左回しで音量ダウン これができれば、フェーズ5I成功です。 フェーズ5Iの成功条件 次の3つができれば成功です。 1. test_encoder_5i.py で右回し/左回しが表示される 2. test_volume_5i.py で5G再生中の音量を変えられる 3. tanaradio_5i.py 単体で、5ボタン・2LED・音量つまみが全部動く これで、TanaRadio Piはかなり「ラジオ」になります。 ボタンで番組の棚と時間順を選び、つまみで音量を調整する。ここまで来ると、もう単なるRaspberry Pi工作ではなく、手元の音声装置です。良いところまで来ています。#声日記 #TanaRadioPi LISTENで開く
Embed this episode
NOW PLAYING
378 日記 | ロータリーエンコーダーで音量調節
No transcript for this episode yet
Similar Episodes
No similar episodes found.
Similar Podcasts
No similar podcasts found.