二番煎じですが、エアコンの赤外線リモコンをラズベリーパイで代用させてみました。
それと前から欲しかったオシロスコープが5万円代に成っていたので購入して波形の確認を行ってみました。最初操作に戸惑いましたが1日くらいいじっていたら良い感じの波形を取れるように成りました。
アマゾンで購入したIRモジュール(回路図が入っていなかったので電圧がわからないのですが、ひとまずラズベリーパイの5Vに繋げます。発信器はラズベリーパイから5Vだと弱い気がします。安定化電源で5Vを入力すると動作しました。ただ、後から購入した裸の赤外線LEDだけの方が良いみたいです)
参考ページ
赤外線リモコンのフォーマット
http://elm-chan.org/docs/ir_format.html
下のコードを元に家製協(AEHA)フォーマットにカスタムしています。
http://abyz.me.uk/rpi/pigpio/examples.html#Python_irrp_py
受信機のPythonコード
コールバック関数で受信機のパルスのON・OFF時にパルスの幅を取得して、最後に425usで長さを割りプリント出力しています。
出力コードを送信機で処理します。
pi.set_watchdogで受信中か確認して、一定期間受信してなければTimeOutを発生させて処理を終える。
import time
import pigpio
IR_READ_PIN = 26
pi = pigpio.pi()
if not pi.connected:
print(f"cannot connect to pigpio")
exit()
pi.set_mode(LED_PIN, pigpio.OUTPUT)
pi.set_mode(IR_READ_PIN, pigpio.INPUT)
pi.set_glitch_filter(IR_READ_PIN, 100)
last_tick = 0
in_code = False
code = []
fetching_code = False
PRE_MS = 300
POST_MS = 20
POST_US = POST_MS * 1000
PRE_US = PRE_MS * 1000
SHORT = 20
T_US = 425
def end_of_code():
global code, fetching_code
entries = len(code) - 1
if entries > SHORT:
print("entries", entries)
code = [round(c / T_US) for c in code]
print("code", code)
fetching_code = False
else:
code = []
print("Short code, probably a repeat, try again")
def cbf(gpio, level, tick):
global last_tick, in_code, code, fetching_code
if level != pigpio.TIMEOUT:
edge = pigpio.tickDiff(last_tick, tick)
last_tick = tick
if fetching_code:
#print(gpio, level, tick, edge)
if (edge > PRE_US) and (not in_code): # Start of a code.
in_code = True
pi.set_watchdog(gpio, POST_MS) # Start watchdog.
#print("set_watchdog", gpio, POST_MS)
elif (edge > POST_US) and in_code: # End of a code.
in_code = False
pi.set_watchdog(gpio, 0) # Cancel watchdog.
end_of_code()
elif in_code:
code.append(edge)
else:
# print("timeout")
pi.set_watchdog(gpio, 0) # Cancel watchdog.
if in_code:
in_code = False
end_of_code()
cb1 = pi.callback(IR_READ_PIN, pigpio.EITHER_EDGE, cbf)
try:
while True:
code = []
fetching_code = True
while fetching_code:
time.sleep(0.1)
print("Okay")
time.sleep(0.5)
except KeyboardInterrupt:
print(f"cancelling")
cb1.cancel()
pi.stop()
送信機のPythonコード
受信機で取得したコードを赤外線で送ります。
carrier関数ないで425us内にデューティ1/3、38KHzのパルスを作成してます。
(試しに38KHzのパルスを単にONのままにして送信したみましたが、それだと受信しないものですね)
write_command関数ないで赤外線のコード処理を行っています。配列の先頭をIndex:0として、偶数をON、奇数をOFFとしてパルスを発生させています。
import time
import pigpio
IR_WRITE_PIN = 26
FREQ = 38.0
T_US = 425
GAP_MS = 100
GAP_S = GAP_MS / 1000.0
AIRCON_OFF = [8, 4, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 3, 1, 1, 1]
AIRCON_ON = [8, 4, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, 1, 3, 1, 1, 1]
TEST_PULSE = AIRCON_ON # AIRCON_ON # [1, 1, 1]
def carrier(gpio, frequency, micros):
"""
Generate carrier square wave.
"""
wf = []
cycle = 1000.0 / frequency
cycles = int(round(micros/cycle))
on = int(round(cycle / 3.0))
sofar = 0
for c in range(cycles):
target = int(round((c+1)*cycle))
sofar += on
off = target - sofar
sofar += off
wf.append(pigpio.pulse(1 << gpio, 0, on))
wf.append(pigpio.pulse(0, 1 << gpio, off))
return wf
def write_command():
pi.wave_add_new()
# Create wave
emit_time = time.time()
marks_wid = {}
spaces_wid = {}
code = TEST_PULSE
wave = []
for i, ci in enumerate(code):
pulse_len = ci * T_US
if i & 1: # Space
if True or ci not in spaces_wid:
pi.wave_add_generic([pigpio.pulse(0, 0, pulse_len)])
spaces_wid[ci] = pi.wave_create()
wave.append(spaces_wid[ci])
else: # Mark
if ci not in marks_wid:
wf = carrier(IR_WRITE_PIN, FREQ, pulse_len)
pi.wave_add_generic(wf)
marks_wid[ci] = pi.wave_create()
wave.append(marks_wid[ci])
delay = emit_time - time.time()
if delay > 0.0:
time.sleep(delay)
pi.wave_chain(wave)
while pi.wave_tx_busy():
time.sleep(0.002)
emit_time = time.time() + GAP_S
for i in marks_wid:
pi.wave_delete(marks_wid[i])
for i in spaces_wid:
pi.wave_delete(spaces_wid[i])
pi.wave_clear()
pi = pigpio.pi()
if not pi.connected:
print(f"cannot connect to pigpio")
exit()
pi.set_mode(LED_PIN, pigpio.OUTPUT)
pi.set_mode(IR_WRITE_PIN, pigpio.OUTPUT)
try:
write_command()
except Exception as e:
print(f"Exception {e}")
pi.stop()
送信機の出力結果
家電の赤外線受信機に向けて、ラズベリーパイの送信で赤外線コマンドを発射すると操作可能なことを確認出来ました。
パルスの計測
水平軸の単位を20usとして周期が26us、ONが1/3くらいに成っているので、carrier関数の生成に成功しています。
コマンドの計測
先頭のパルスが[8, 4, 1, 3, 1, でOn:8t,Off:4t, On:1t, 0ff:3t, On:1tと続いているので正しい動作と成っています。