概要
Raspberry Pi Pico W と赤外線受光モジュール(PL-IRM1838B)・赤外線 LED で、エアコンなどの学習リモコンを自作します。この記事では核になる2つの処理 ―― リモコン信号を生のパルス列として読み取る部分と、それを 38kHz のサブキャリアに乗せて再送信する部分 ―― の MicroPython コードだけを抜き出します。自作の温湿度見守り装置を外出先から操作したくて作ったものです。
つまずいたポイント
最初は NEC フォーマットのデコーダで信号を解析しようとしましたが、エアコンのリモコンはエアコン側の状態(モード・温度・風量)を毎回まとめて送るため、フレームが長く機種依存も大きく、デコードは手間の割に合いませんでした。
結局、信号の意味を解釈せず「HIGH/LOW が続いた時間(マイクロ秒)の配列」としてそのまま録って、そのまま再生する のが一番確実でした。ポイントは、再送信時に赤外線を 38kHz で点滅させる(サブキャリア変調) ことです。ただ光らせるだけでは、受光側が部屋の照明や太陽光と区別できず反応しません。
コア1: 信号をパルス列として読み取る
受光モジュールの出力を PULL_UP の入力ピンで受け、状態が変わるたびに経過時間を配列へ追加します。HIGH のまま約 200ms 経過したらフレーム終了とみなします。
import machine
import time
ir = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_UP)
def capture():
while ir.value() == 1: # 立ち下がり(信号開始)を待つ
pass
times = []
t0 = time.ticks_us()
last = 0
while True:
now = time.ticks_us()
v = ir.value()
if v != last:
times.append(time.ticks_diff(now, t0)) # 前回の変化からの経過us
t0 = now
last = v
if v == 1 and time.ticks_diff(time.ticks_us(), t0) > 200000:
return times # HIGHが200ms続いたら終了
print(capture()) で数百個の数値リストが得られるので、これをコピーして保存します。
コア2: 38kHz PWM で再送信する
times[0] を ON 時間、times[1] を OFF 時間……と交互に解釈し、ON の区間だけ 38kHz の PWM を出します。デューティ比は約 1/3(65535 // 3 ≒ 21845)にします。
TX_PIN = 17
def send_ir(times):
pwm = machine.PWM(machine.Pin(TX_PIN))
pwm.freq(38000) # 38kHzのサブキャリア
on = True
for us in times:
pwm.duty_u16(21845 if on else 0) # ON=点滅出力 / OFF=完全停止
time.sleep_us(us)
on = not on
pwm.duty_u16(0)
pwm.deinit()
pwm.freq(38000) は Pico のハードウェアタイマーが生成するため、Python の処理速度に関係なく正確な 38kHz が出ます。赤外線 LED は Pico の GPIO で直接駆動せず、トランジスタ(C1815 など)で 5V をスイッチングして電流を稼ぎます。
完全なソースコードと配線・手順はブログにまとめています
受信・送信回路の結線図と部品リスト(抵抗値・トランジスタの向き)、Get_IR.py / IR_Transmission.py の全文、実際に取得したエアコン信号データの例、「赤外線が届かない」ときの3つの原因(配線ミス・LED の指向性・USB 給電の電流不足)と対策まで、以下の記事に書いています。
