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

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

コメント

スクロール