1. TanaRadio
  2. 378 日記 | ロータリーエンコ..
378 日記 | ロータリーエンコーダーで音量調節
2026-07-09 31:39

378 日記 | ロータリーエンコーダーで音量調節

spotify apple_podcasts

まず,ロータリーエンコーダーを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

サマリー

TanaRadio Pi製作シリーズのフェーズ5Iでは、ロータリーエンコーダーを使った音量調節機能の実装に挑戦しました。まず、DIP化基板へのハンダ付け作業を行い、Raspberry PiのGPIOピンに配線。その後、Pythonスクリプトでエンコーダーの単体動作と、既存の5Gプログラムと連携した音量制御テストを実施し、成功を確認しました。最終的に、5Gコードに音量調節機能を統合した5Iプログラムを作成し、初期エラーを解決して、全てのボタンとLED、そしてロータリーエンコーダーによる音量調節が正常に機能することを確認しました。

ロータリーエンコーダーのハンダ付け作業
では、TanaRadio Pi製作シリーズフェーズ5iに行きたいと思います。
今回はロータリーエンコーダーという部品を使いまして音量調節をするということで、一番工作の難易度としては高いものですね。
今回初めてハンダ付けをやることになります。
まずは、このロータリーエンコーダーという部品を買いましたらば、3本の足、ピンですね、これが出ていて、
これはそのままではブレンドボードに刺さりませんので、ブレンドボードに刺さるようなピンの間隔になるようなものを取り付けるということがまず必要です。
そのためにDIP化基板というのがありまして、小さな基板なんですが、それにロータリーエンコーダーをハンダ付けしまして、
さらにその基板にピンを3本、これはブレンドボードに刺さる間隔で取り付けられるんですが、その3本のピンを付けるということで、ハンダ付けが何箇所か必要になります。
まず最初にですね、それからハンダ付け用に、私今回ハンダゴテとハンダゴテの台を買いました。さらにハンダも買いました。
このハンダゴテはですね、温度設定ができるというもので、だいたい、このハンダの有点が書いてあるところによりますと190度となっていましたので、
ハンダゴテはそれよりも100度から150度ぐらい高い温度が良いということなので、300数十度ということですね。
このハンダゴテでは320度と370度の設定ができるんですが、その間には数字がないんですけれども、その間なのでだいたい350度ぐらいに設定しまして、電源を入れたらばLEDが点滅しています。
この点滅がしているということは、その設定温度になったということらしいです。ですので、もうハンダ付けができるわけですが。
まず基板にピンを、ピンヘッダーというんですかね、要するにオスのピン、これをハンダ付けするんですが、
この基板を買いましたら、ピンがたくさん付いていまして、これを3本使いますので、3本のところでちょっと折って切り離したいと思います。
パキッとちょうどよく折れるようになっていますね。
これを、この基板の3本のところの、穴は5個あるんですけど、その5個のうちの真ん中の3つのところにピンの短い方を入れまして、
これを3本だから3つハンダ付けするんですが、これが結構グラグラしますよね、ハンダ付けしていないと。
ですので、グラグラしないようにテープか何かで留めるといいというふうに、ネットなどで調べましたらば出ていましたので、
ちょっとこれを、医療用のテープを今家にいるんですけど、薬箱から取り出しまして、一応これを使ってピンを固定したところです。
一応、ピンの穴から短いピンが出ている状態になりましたので、ここにハンダ付けをしたいと思いますが、
もうこの小ささになると本当によく見えないですね。
よく見えないけれども、本当は蒸し目がないか何かで拡大しながらやったほうがいいんでしょうが、今はないので肉眼で、老眼鏡を外して肉眼でちょっとやりたいと思います。
えーと、もう全然ハンダが乗りませんね。これはどうしたものでしょう。
一応なんかちょっと付いた感じがしますが、本当だと富士山型にならないといけないんですけど、やっぱり団子になってしまいますね。これはあんまり良くない付き方です。
とりあえず付いたので、なんとか3ついきます。
もう何十年ぶりのハンダ付けですけど、なんとか付いたかな、これ。一応付いた感じです。固定用のテープをちょっと外したいと思います。
そんなに曲がっておらず、基板に垂直に付いた感じになっています。
次に、この基板にロータリーエンコーダーを付けるわけですが、ロータリーエンコーダーの方は電極がいっぱい付いていますね。
まず、固定するための金具みたいなものが2つありますので、ラジオペンチで曲げるだけで結構固定されます。
これもハンダ付けするといいと書いてあったので、ここでハンダ付けをしたいと思います。
やっぱりこの基板を固定するものがないと、机の上に基板を置いただけでは、基板がクルクル動いてしまってあんまり良くないですね。
専門の固定の台みたいなものがあるといいんですが、これでくっついたのかどうかわかりませんが、動かなくなったのでたぶんくっついたんだと思います。
それでは次に3つの電極ですね。
これを今度はハンダ付けしていきます。
これはハンダを盛りすぎると隣のとくっつきますので付けすぎに注意ですが、ものすごく細かいですね。
これは細かいところの作業なので難しいですね。
うまくくっついているのかどうか目がよく見えないのでわからないという非常につらい状況です。
でもなんとなくうまくいったような気がします。
ぐらぐらもしませんし、なんとかうまくいったんじゃないでしょうか、ハンダ付け。
何十年かぶりでやりましたが、なんとかうまくいきました。
一旦これでちょっと録音を止めまして、ブレンドボードに挿して、またTANRADIO PIEのボリューム調節の機能を実装していきたいと思います。
Raspberry Piへの配線と接続
今、Raspberry PIEのセッティングがだいたい終わりましたので、これに電源のコードを挿して動かしたいと思います。
ブラウザーが今立ち上がった状態で、これをいつも通りターミナルと並べて画面上に配置します。
ブラウザーではChat GPTの画面を出しまして、CHAPPYのマニュアル通りにまた進めていきたいと思います。
まずはこのロータリーエンコーダーを取り付けるというところから。
では、マニュアルのロータリーエンコーダーを配線するというところからいきたいと思うんですが、
ロータリーエンコーダーにはACBと3つの端子があるということで、
ACBと書いてありますね。左からACBとなっています。
これをまずはブレッドボードに挿すわけですね。挿します。
挿しまして、AをGPIOの20に繋ぎます。
今、ジャンパー線で繋ぎました。
次にBを21に繋ぎます。
はい、繋ぎました。
最後にCをグラウンドに繋ぎます。
はい、繋ぎました。
はい、これで配線は一応やったということになります。
ロータリーエンコーダー単体動作テスト
では今度はプログラムの方ですね。
プログラムはまず、ターミナルで作業用フォルダに移動ですね。
はい、移動しました。
で、必要なパッケージを確認するですが、これはもう前から何度もやっているので省略しまして。
次にロータリーエンコーダー単体テストということで、テスト用のPythonのプログラムを今作ります。
なので、テスト用のファイルを今作りますが、
例によりまして、これはChatGPTの書いてくれたコードをそのまま貼り付けます。
はい、保存しました。
そうしましたら、今度は実行権限ですね。
実行権限をいつも通り付けまして、実行します。
画面上にはロータリーエンコーダーのテストを開始します。
つまみを左右に回してくださいとありますので、まず左に回してみます。
左回しと出ました。
カチッカチッとクリック感があるんですが、一回クリック感があるところで一つ左回しが出ますね。
何度もずんずん回すとそれが増えてきます。
今度は右回し、逆方向に回します。
そうすると右回しがどんどん増えていくという感じですね。
これはもう成功です。
ロータリーエンコーダーの機能はOKということですね。
Ctrl-Cで終わります。
単体テスト終了時のエラー確認と解決
Ctrl-Cで終わったときに、何かエラーっぽいものが出ましたね。
これちょっと気になるので、ChatGPTにフィードバックしてみましょう。
これは6の単体テストですね。
6の単体テストで、以下のエラーのメッセージを貼り付けて送ってみます。
これは大丈夫ですと言われました。
表示されているものはエラーで止まったのではなく、
TANAさんがCtrl-Cを押してテストプログラムを終了したという意味です。
とのことで問題ないようです。
良かったですね。
既存プログラムでの音量制御テスト
では次行きたいと思います。
単体テストが終わったので、次のテストですが、
5Gを動かしたまま音量制御テストをするということで、
前回作りましたフェーズ5Gのファイルをそのまま使って音量調節のテストをするということですね。
1つ目のターミナルで5Gを起動して音を出した上で、
別のターミナルを開いて音量テスト用のファイルを作りますとあるので、
まず音量テスト用のファイルを作ってみますね。
なのでファイルを開いた後にコピー&ペーストで貼り付け保存しました。
このテスト用のファイルはできたので、実行権限をつけて実行ですね。
実行権限をつけました。
あとは実行してテストなんですが、また音が出ると録音しない方がいいかもしれないので録音は一旦止めてテストをしたいと思います。
今音量のテストをしたんですけれども、ちゃんとロータリーエンコーダーを右に回すと音量が上がり、左に回すと音量が下がるということを確認しました。
ということでこれはOKですね。
5Gコードの5Iへの統合準備
そうしましたら、コントロールCで終わるのかな。
そうしましたら今度は5Gのコードを5iとしてコピーするとあります。
この5Gのコードにボリュームを上げたり下げたりする機能を追加するということですかね。
まずはバックアップのコピーを取っておきましょう。
バックアップを取りました。
そして新しい5iのファイルを作ります。
マニュアルによりますと、5Gのファイルにいろいろと追加するように書いてあるんですが、
コピーをするのはなかなか間違いやすいので、コピーしたものを作るようにお願いしておきましたので、
それをそのまま貼り付けたいと思います。
ではこの全部をコピーしまして、貼り付けます。
保存しました。
これでまた実行すれば音量を変えたりできるわけですよね。
まず実行権限を付けますね。
この上で実行するんですが、また音が出ますので録音を止めたいと思います。
統合コードの実行と最終機能確認
実行したらものすごくたくさんのエラーが出ましたので、
これをまたChatGPTに返したいと思います。
コピーを取りまして、エラーを貼り付けて対処方法を聞きたいと思います。
答えはですね、GPIO17のピンが使用中だというエラーだということで、
これはRaspberry Piを再起動すればいいという話なので再起動してみます。
今再起動しました。
再起動しましたので、ブラウザとターミナルをまた並べて表示させます。
これでもう一回実行ですね。
まずは作業ディレクトリに移動しまして、こうします。
ちゃんと動いているようですね。
音が出るのに録音ボタンを停止するのを忘れていたのでちょっと入ってしまったかもしれませんが、
ここでテストをしたいので一旦録音を止めます。
今度はですね、ちゃんとボリュームのつまみ、ロータリーエンコーダーがですね、
機能しまして音量を変えることができました。
良かったです。
ということで、これでもうだいたい今回の目標は達成したということですね。
ロータリーエンコーダー、右左の回転によって音量はアップ、ダウンできたということになります。
ということで、今回の作業は終わりにしたいと思います。
それではまた。
31:39

コメント

スクロール