(56)【連載2-1】リモコン作り:赤外線リモコンの信号パターンをキャプチャする。

投稿者: | 2024年11月27日

123 views

【1】やりたいこと

家電製品を制御するための赤外線リモコンが発信する信号のパターンをモニタリングしたい。

ただし…
ブラックボックスな便利ライブラリを使うのではなく、生の信号データをそのまま見たい。

以下、3回のブログ投稿で完成を目指す。
(56)【連載2-1】リモコン作り:赤外線リモコンの信号パターンをキャプチャする。 ←今回
(57)【連載2-2】リモコン作り:赤外線LEDで信号パターンを再生する。
(58)【連載2-3】リモコン作り:キャプチャ機能付きリモコンの完成!?

【2】使用材料

1) Raspberry Pi Pico 2

最初は Raspberry Pi 5で実装しようと考えたが、
・pigpioが使えない
・Raspberry Pi OSのオーバーヘッドが大きい且つ RTOSではない
などの問題があるため、リアルタイム性に優れている Raspberry Pi Pico 2 を使うことにした。
https://akizukidenshi.com/catalog/g/g129604/

https://www.raspberrypi.com/documentation/microcontrollers/pico-series.html#raspberry-pi-pico-2

以下、Raspberry Pi Pico 2 を Pico2 と表記する。

2) 赤外線受光ユニット

今回は 1個 50円と格安な以下のパーツ GP1UXC41QS を使う。
https://akizukidenshi.com/catalog/g/g106487/

データシートはこちら。
https://akizukidenshi.com/goodsaffix/GP1UXC4xQS_j.pdf

【3】回路の結線

Pin#GPIO#Signal
2116Vout
36-3V3(OUT)
38-GND

Voutには、1kΩの保護抵抗を入れておく。

【4】プログラミング

参考: ラズパイPico上でプログラムを実行する手順は、過去記事
(55) Raspberry Pi Pico2に起動時実行プログラム main.pyを置く。
を参照されたい。

Step 1 : シンプル実装(ポーリングによる信号変化の検出)

赤外線受光モジュールからの信号 Vout をポーリングし、LOW区間、HIGH区間それぞれの時間を記録する。
毎度のことだが、各行のコメントは ChatGPT大先生に自動で付与してもらった。

from machine import Pin         # Raspberry Pi PicoでGPIOピンを扱うためのモジュールをインポート
import time                     # 時間操作に必要なモジュールをインポート

ir_pin  = Pin(16, Pin.IN)       # GPIO16ピンを赤外線受信信号用に入力モードで設定
ir_data = []                    # 赤外線信号のデータを格納するリスト
TIMEOUT_DURATION_US = 1000000   # 信号が途切れたと判断するまでのタイムアウト時間をマイクロ秒で設定

class BreakLoop(Exception):     # 独自例外クラスを定義して処理終了を制御
    pass

# Active LOWの初回信号が入るまで待機するループ
while ir_pin.value() == 1:
    pass  # 何もせず、LOWになるまで待つ

try:
    while True:                 # 無限ループで赤外線信号を受信し続ける
        # 信号がHIGH(1)になるまでの時間(=LOWの時間幅)を測定
        ttStart = time.ticks_us()   # 現在の時刻(マイクロ秒)を取得
        while ir_pin.value() == 0:  # ピンがLOWの間ループ
            pass                    # 信号がHIGHになるまで待機
        pulse_length = time.ticks_diff(time.ticks_us(), ttStart)  # LOW状態の持続時間を計算
        ir_data.append(pulse_length)# 持続時間をデータリストに追加

        # 信号がLOW(0)になるまでの時間(=HIGHの時間幅)を測定
        ttStart = time.ticks_us()   # 現在の時刻(マイクロ秒)を再取得
        while ir_pin.value() == 1:  # ピンがHIGHの間ループ
            # 一定時間以上信号が来なければタイムアウトとして処理を終了
            if time.ticks_diff(time.ticks_us(), ttStart) > TIMEOUT_DURATION_US:
                raise BreakLoop     # タイムアウト例外を発生させる
        pulse_length = time.ticks_diff(time.ticks_us(), ttStart)  # HIGH状態の持続時間を計算
        ir_data.append(pulse_length)# 持続時間をデータリストに追加

except BreakLoop:               # タイムアウト例外が発生した場合の処理
    pass                        # 処理を終了する

print(ir_data)                  # 受信した赤外線信号のデータを出力

with open('ir_pattern.txt', 'w') as f:  # 受信した赤外線信号のデータをファイルに保存
    f.write(','.join(map(str, ir_data)))

Step 2 : 少し上級実装(割り込みによる信号変化の検出)

いろいろと改善の余地はあるが、まずはプログラムの骨格をわかりやすくするために正常系処理のみを実装する。
毎度のことだが、各行のコメントは ChatGPT大先生に自動で付与してもらった。

from machine import Pin             # Raspberry Pi PicoでGPIOピンを扱うためのモジュールをインポート
import time                         # 時間操作に必要なモジュールをインポート

ir_pin  = Pin(16, Pin.IN)           # GPIO16ピンを赤外線受信信号用に入力モードで設定

ir_data = []                        # 赤外線信号のデータを格納するリスト
last_time = 0                       # 前回の時間を記録する
is_first_pulse = True               # 初回のエッジを無視するフラグ
TIMEOUT_DURATION_S = 1              # 記録処理の実行時間(秒単位)

# 割り込みハンドラ
def record_pulse(pin):
    global ir_data                  # ir_dataリストをグローバル変数として使用
    global last_time                # last_timeをグローバル変数として使用
    global is_first_pulse           # is_first_pulseフラグをグローバル変数として使用
    current_time = time.ticks_us()  # 現在の時間をマイクロ秒単位で取得
    if is_first_pulse:              # 最初のエッジの場合
        last_time = current_time    # 現在の時間を記録
        is_first_pulse = False      # フラグをオフにする
        return                      # 処理を終了して次のエッジを待つ
    # パルスの長さを計算してリストに追加
    pulse_length = time.ticks_diff(current_time, last_time)  # 前回の時間との差分を計算
    ir_data.append(pulse_length)    # 計算結果をデータリストに追加
    last_time = current_time        # 現在の時間を次回用に保存

# 割り込みを設定(立ち上がりエッジと立ち下がりエッジをトリガーに設定)
ir_pin.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=record_pulse)
time.sleep(TIMEOUT_DURATION_S)      # 設定した時間(1秒間)だけ信号を記録
ir_pin.irq(handler=None)            # 割り込みを解除して記録処理を終了

print(ir_data)                      # 受信した赤外線信号のデータを出力

with open('ir_pattern.txt', 'w') as f:  # 受信した赤外線信号のデータをファイルに保存
    f.write(','.join(map(str, ir_data)))

【5】評価: ポーリング vs 割り込み

最優先事項は…
センサーが捕捉した信号変化を、ソフトウェアが高精度でデータ化できること
だ。

この目的を果たすためには、ポーリング vs 割り込みのどちらが良いか?
これについて実測値を使って確認&判断したい。

1) 検証方法

・Vout信号線の状態をオシロスコープでモニタリングする。
・上記の両プログラムの ir_data の中身を、オシロの測定値と比較する。 x 複数回
 ↓↓↓
こうして得られたデータを比較し、「どちらのプログラムが高精度でデータ取得できるか?」を判断する。

2) 検証結果

後日追記

参考情報

https://akizukidenshi.com/catalog/g/g104659/
https://akizukidenshi.com/catalog/g/g106487/


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です


日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)