編集履歴一覧に戻る
nihsokのアイコン画像

nihsok が 2026年08月04日23時45分15秒 に編集

コメント無し

本文の変更

家電用のリモコンで使われている赤外線信号をコピーして、同じ信号をマイコン操作で送信できるようにする。 シンプルな構成にするため、単機能のみとする。今回はエアコン(クーラー)のリモコンを使用した。 前半記事:リモコンの信号を取得する。(このページ) 後半記事:取得した信号を送信する。(準備中) # 使用したもの - ESP-WROOM-02

-

- リモコン受光 OSRB38C9AA 2.7-5.5V 37.9kHz

+

- 赤外線受光モジュール OSRB38C9AA 2.7-5.5V 37.9kHz

- ジャンパワイヤ(3本) - USBケーブル(適宜) 赤外線モジュールはカホパーツセンターにて110円で購入。データシートは秋月より。(https://akizukidenshi.com/goodsaffix/OSRB38C9AA.pdf) ![キャプションを入力できます](https://camo.elchika.com/e29c2610a73a360abc0dca5e77ae28d4e2d81a03/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f66336238363735322d663630612d343866342d613963622d3331306133646133386665322f38336233303464342d653836622d343364662d383731302d363832633632353032316261/) ## リモコン エアコンはHITACHIの白くまくん、リモコンはRAR-8P2 3114

-

プロトコルは解析されている https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Hitachi.h

+

プロトコルは解析されているhttps://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Hitachi.h

HITACHI_AC424という53-byte/424-bitのメッセージが使われており、一般的なフォーマット (https://elm-chan.org/docs/ir_format.html) とは違いそう。 # セットアップ ## 配線 | | ESP32 | OSRB38C9AA | |:---:|:---:|:---:| | 赤 | VIN |VCC| | 黒 | GND |GROUND| | 緑 | GPIO13 |OUTPUT| ## 原理 38 kHzの赤外線を受けていないときはHIGH、受けているときはLOWが出力される。

-

直感とは逆だった。38 kHzの搬送波は無視してオン/オフのみ得られる。

+

自分の直感とは逆だった。38 kHzの搬送波は無視してオン/オフのみ得られる。

# 結果

-

time_pulse_us() でピンの状態の変化を取得し

+

time_pulse_us() でピンの状態の変化を取得してみる

```python:正負 from machine import Pin, time_pulse_us from array import array output = Pin(13,Pin.IN) data = array('H',[0]*1000) i = 0 while True: data[i] = time_pulse_us(output,0,10_000_000) i+= 1 t = time_pulse_us(output,1,1_000_000) if t<0: break data[i] = t i+= 1 print(data[:i],i) ``` > array('H', [30021, 49606, 3396, 1620, 454, 1194, 454, 349, 453, 349, 452, 350, 452, 349, 453, 349, 452, 350, 453, 351, 453, 345, 454, 348, 454, 348, 453, 349, 452, 1191, 456, 347, 437, 350, 453, 352, 452, 346, ... 値の入った配列長は853であったため、これを使い条件分岐のタイムロスを減らすことを考える。 ```python:改良版 from machine import Pin, time_pulse_us from array import array output = Pin(13,Pin.IN) data = array('H',[0]*1000) for i in range(0,860,2): data[i] = time_pulse_us(output,0,2_000_000) data[i+1] = time_pulse_us(output,1,1_000_000) print(data[:]) ``` >array('H', [29968, 49672, 3405, 1625, 460, 1199, 439, 377, 459, 354, 460, 353, 460, 352, 460, 354, 459, 355, 460, 357, 460, 350, 461, 353, 459, 353, 461, 354, 460, 1196, 461, 354, 459, 354, 460, 356, 459, 351, ...

-

あまり変わらない。time_pulse_usの特性上信号が継続して変化しているときにはタイムロスが避けられないので、オンオフどちらか片方だけ取ること考える。

+

あまり変わらない。time_pulse_usの特性上信号が継続して変化しているときにはタイムロスが避けられないので、オンオフどちらか片方だけ取ることで正確なタイミング測定する。

## オンの時間のみ取得

-

以下のようにするとループの中の処理はすべてオフのときに行われるはず。

+

以下のようにするとループの中の処理はすべてオフのときに行われ、オンの時間を正確に取得できるはず。

```python:オンのみ from machine import Pin, time_pulse_us from array import array output = Pin(13,Pin.IN) data = array('H',[0]*1000) i = 0 while True: data[i] = time_pulse_us(output,0,10_000_000) i+= 2 if i>30:break print(data[:i]) ``` > array('H', [29991, 0, 3395, 0, 425, 0, 427, 0, 423, 0, 426, 0, 426, 0, 425, 0, 427, 0, 425, 0, 426, 0, 425, 0, 426, 0, 426, 0, 427, 0, 425, 0]) array('H', [30037, 0, 3396, 0, 428, 0, 431, 0, 428, 0, 427, 0, 426, 0, 427, 0, 427, 0, 426, 0, 426, 0, 428, 0, 429, 0, 429, 0, 426, 0, 429, 0]) array('H', [30020, 0, 3429, 0, 457, 0, 456, 0, 454, 0, 455, 0, 454, 0, 455, 0, 455, 0, 454, 0, 455, 0, 454, 0, 454, 0, 455, 0, 454, 0, 457, 0]) array('H', [29968, 0, 3444, 0, 480, 0, 481, 0, 477, 0, 477, 0, 477, 0, 474, 0, 473, 0, 475, 0, 472, 0, 470, 0, 470, 0, 472, 0, 470, 0, 471, 0]) array('H', [30077, 0, 3485, 0, 518, 0, 516, 0, 518, 0, 520, 0, 520, 0, 518, 0, 516, 0, 519, 0, 519, 0, 520, 0, 513, 0, 515, 0, 521, 0, 518, 0]) array('H', [29730, 0, 3405, 0, 520, 0, 521, 0, 523, 0, 521, 0, 521, 0, 519, 0, 524, 0, 522, 0, 443, 0, 505, 0, 503, 0, 521, 0, 521, 0, 523, 0]) 何回か試したところ、値がブレている。 ## オフの時間のみ取得

-

同様にオフの時間のみ取得する。仕様上はオンの長さは一定で、オフので0と1とを区別するのでこちらの方が重要はず。

+

同様にオフの時間のみ取得する。一般的な仕様上はオンの長さは一定で、オフの時間ので0と1とを区別するためこちらの方が重要はず。

```python:オフのみ from machine import Pin, time_pulse_us from array import array output = Pin(13,Pin.IN) data = array('H',[0]*10000) i=-1 while True: data[i] = time_pulse_us(output,1,10_000_000) i+= 2 if i>30:break print(data[:i]) ``` > array('H', [0, 49660, 0, 1576, 0, 1132, 0, 272, 0, 293, 0, 320, 0, 293, 0, 342, 0, 318, 0, 277, 0, 321, 0, 293, 0, 1165, 0, 319, 0, 324, 0]) array('H', [0, 49669, 0, 1581, 0, 1171, 0, 327, 0, 327, 0, 335, 0, 325, 0, 327, 0, 421, 0, 337, 0, 327, 0, 342, 0, 328, 0, 1170, 0, 325, 0]) array('H', [0, 49754, 0, 1589, 0, 1259, 0, 340, 0, 335, 0, 337, 0, 338, 0, 415, 0, 416, 0, 420, 0, 412, 0, 415, 0, 337, 0, 337, 0, 1259, 0]) array('H', [0, 49775, 0, 1639, 0, 1235, 0, 389, 0, 340, 0, 388, 0, 388, 0, 387, 0, 390, 0, 391, 0, 388, 0, 390, 0, 388, 0, 389, 0, 1230, 0]) array('H', [0, 49719, 0, 1635, 0, 1234, 0, 389, 0, 390, 0, 389, 0, 388, 0, 388, 0, 389, 0, 392, 0, 386, 0, 387, 0, 388, 0, 388, 0, 1232, 0]) array('H', [0, 49753, 0, 1669, 0, 1265, 0, 418, 0, 417, 0, 418, 0, 416, 0, 416, 0, 418, 0, 419, 0, 415, 0, 418, 0, 417, 0, 417, 0, 1260, 0])

-

こちらも値がブレている。最後の方の1250くらいの長さのが1か?

+

こちらも値がブレている。始めの方と最後の1250くらいの長さのが1か?

## ここまででわかったこと オンは 420~520 us、オフは 270~420 usがひと単位と推測。

-

ばらつきが 100~150 usくらいあり気になる。キャリアが 38 kHz で30%のdutyだと1/38e6/2≈9 usのブレはありうるがそれよりも格段に大きい。 オフの時間の長さの方が重要なはずなので、(ヘッダ以外では)あま

+

ばらつきが 100~150 usくらいあり気になる。キャリアが 38 kHz で30%のdutyだとパルスのタイミングで1/38e6/2≈9 usのブレはありうるがそれよりも格段に大きい。 オフの時間の長さの方が重要なはずなので、(ヘッダ以外では)受信側でかな柔軟対応を行っると考えられる。

-

|| On (Leader) | Off (Leader) | On (Header) | Off (Header) | On | Off (1) | On | Off (0) | ...| |:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| |参照値|29784us|49290us|3416us|1604us|463us|1208us|463us|372us|...| |ざっくり版|30000us|49700us|3400us|1600us|500us|1200us|500us|400us|...| |推測|60H|130L|7H(少したりない)|4L|H|3L|H|L|...|

-

参照値は前述のGithubより (https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Hitachi.cpp) これで整数倍にはなっていない。

+

参照値は前述のGithubより (https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Hitachi.cpp)。どの長さきりのよい数字や整数倍にはなっていない。

とりあえず決め打ちで0と1にデコードしてみる ```python from machine import Pin, time_pulse_us from array import array output = Pin(13,Pin.IN) data = array('H',[0]*1000) head = array('H',[0]*2) for i in range(-1,2): head[i] = time_pulse_us(output,1,10_000_000) i = 0 while True: t = time_pulse_us(output,1,10_000_000) if t<0: break data[i] = 0 if t<1000 else 1 i+= 1 bits = "".join(str(b) for b in data[:i]) print(head,bits) ``` >array('H', [49718, 1633]) 10000000 00001000 00000000 00000010 11111101 11111111 00000000 00110011 11001100 00011001 11100110 11001000 00110111 00110110 11001001 00000000 11111111 00000000 11111111 00000000 11111111 00000000 11111111 00000000 11111111 11001000 00110111 00001111 11110000 00000000 11111111 00000000 11111111 00000001 11111110 11000000 00111111 10000000 01111111 00010001 11101110 00000000 11111111 00000000 11111111 11111111 00000000 11111111 00000000 11111111 00000000 11111111 00000000

-

53byteなので仕様通り(8bitずつ区切っている)。4byte目以降はビット反転とセット(誤り訂正のめの冗長化

+

53byteなので仕様通り(8bitずつ区切っ

+

4byte目以降はビット反転とセット:誤り訂正のための冗長化

13byte目の下位6bitに気温の情報が入っているとのことだが、 - 設定温度27度のとき (00)110110 - 設定温度28度のとき (00)001110 だったので、リトルエンディアンと考えれば整合的な結果になっている。 # まとめ エアコンの赤外線リモコンの信号を受信して解析した。

-

- パルス幅はあまり安定していない。 - パルスのオン・オフ(長・短)およびヘッダ部どれも整数倍にはなっていなさそう

+

- パルス幅は安定していない。 - パルスのオン・オフ(長・短)およびヘッダ部どれも整数倍にはなっていなかった。

- リピート信号のようなものは含まれていなさそう

-

これらが、今回の環境(HITACHI白くまくん)だけか、いうものなのかは今後要調査。 それでも大まかな構造はとらえられ、01にデコードした結果気温に対応した値も見つけられた。後半パートでは実際にこの信号を送信してみる。

+

これらが、今回の環境(HITACHI白くまくん)だけか、少し一般的なものかは今後要調査。 それでも大まかな構造はとらえられ、01にデコードした結果気温に対応した値も確認できた。後半パートでは実際にこの信号を送信してみる。