リモコンが家電を動かす仕組みを理解する【ラズパイで遊ぼう！】

# 初めに
普段みなさんが何気なく使っている「**リモコン**」ってなぜ動くの？
どうやってテレビをつけているの？
そんなことを考えたことありませんか()
リモコンが赤外線を家電に飛ばしている。ここまでは知っている人が多いかと思います。
ですが、実際に「**赤外線はどのような情報を送信しているか**」「**どうやって送っているか**」まで知っている人は少ないと思います。
今回はその部分を紐解いて、行きたいと思います。

# 利用したもの
- RaspberryPi 4B(https://www.switch-science.com/catalog/5680/)
- 赤外線受信モジュール（https://www.amazon.co.jp/gp/product/B07TNDLH86）
- ジャンパーワイヤー(https://www.switch-science.com/catalog/2354/)
**※はんだ付けできる人は不要です。**

# RaspberryPi OS のインストール
RaspberryPiの公式サイトに「[Raspberry Pi Imager](https://www.raspberrypi.com/software/)」という便利なものがあります。

これを使って**RaspberryPi OS**のインストールをしましょう。
**※別端末からアクセスしたい場合は、SSHの有効を忘れずに！**

# RaspberryPiの起動前に
RaspberryPiを起動させる前に、赤外線受信を行うための配線を行いましょう。
**※起動後に配線を行うと、「感電」や「HWの故障」に繋がります。**

[**配線図イメージ**]
<img width="350px" alt="配線図.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469819/2eec5dd5-ce70-137d-453e-6dd89c46fbc8.png">

- 5V: VCC
- Ground: GND
- GPIO12: OUT

# 赤外線情報を取得する

赤外線を取得する前に、赤外線情報はどのように送られているかを説明します。
赤外線の信号は基準時間「**T**」を1単位とし、赤外線のON/OFF時間と基準時間を割った単位数によって情報を表しています。
例えば、
- 基準時間：430μsec
- 赤外線ONの時間：430μsec
- 赤外線OFFの時間：1290μsec
の場合は、**1T,3T**という情報を表しています。

つまりリモコンはのボタンを押した際、赤外線のON/OFF信号を大量に送ることで情報を送っています。
```sh
# イメージ
ボタン押下 -> 赤外線送信「1T,3T,1T,1T....」 -> 電気をつける
```

## 必要なパッケージをインストール
HWの準備ができたので、次はソフトウェアのインストールを行います。

```sh
# 必要パッケージのインストール
$ sudo apt install pigpio python3-pigpio

# pigpiodを有効化
$ sudo systemctl enable pigpiod
$ sudo systemctl start pigpiod
```

赤外線のON/OFFを計測してくれるスクリプトが公開されているので、こちらもインストールします。
```sh
# 赤外線のON/OFF時間を計測するためのpythonスクリプトをcurl
$ curl http://abyz.me.uk/rpi/pigpio/code/irrp_py.zip | zcat > irrp.py
```

## 赤外線情報の計測実行
先ほどcurlした`irrp.py`を実行します。
ちなみに`irrp.py`は、`pigpio`を作った人と同じ人らしいです...(すごい)

https://abyz.me.uk/rpi/pigpio/examples.html

```py
$ python3 irrp.py -r -g12 -f codes tv --post 130 --no-confirm
Recording
Press key for 'tv'
Okey
```

|  オプション|  内容  |
| ---- | ---- |
|  -r|  受信した信号を記録するモード|
|  -g12|  GPIO12を使って信号を受信する|
|  -f codes|  受信した信号を出力するファイル名を指定する|
|  tv|  信号の識別子。わかりやすい名前をつける|
|  --post 130|  130ms無信号の場合に信号が終わったと判断する|
|  --no-confirm|  デフォルトだとリモコンの信号を再確認するので、1回だけで済むように。|

スクリプトの実行が完了したら、`codes`というファイルが作成されています。
中を見てみると赤外線ON/OFFの切り替わり時間が記録されているのが確認できます。
これをもとに赤外線の解析を行っていきます。

```json:codes
{"tv": [8890, 4418, 577, 560, 577, 560, 577, 1642, 577, 1642, 577, 560, 577, 560, 577, 560, 577, 560, 577, 1642, 577, 1642, 577, 1642, 577, 560, 577,1642, 577, 1642, 577, 1642, 577, 560, 577, 560, 577, 560, 577, 560, 577, 1642,577, 1642, 577, 560, 577, 1642, 577, 1642, 577, 1642, 577, 1642, 577, 1642, 577,560, 577, 560, 577, 1642, 577, 560, 577, 560, 577]}
```

# 赤外線の解析をする
赤外線の取得ができましたので、早速解析していきましょう！

## 赤外線リモコンの規格
解析をする前にリモコンの規格について少し説明します。
日本の赤外線リモコンは、基本的に3つの規格に分類されます。

- NECフォーマット
- 家製協(AEHA)フォーマット
- SONYフォーマット

先ほど取得した赤外線信号を確認してみると、最小値が「**560**」ですので、「**1T = 約560**」だと推測されます。
T換算すると以下のようになりますね。
```
16T, 8T, 1T, 1T, 1T, 1T, 1T, 3T, 1T, 3T, 1T, 1T, 1T, 1T...
```

以下のリンクを確認してみると、今回は「**NECフォーマット**」を利用していることが分かりました。
[赤外線リモコンの通信フォーマット - Elm-chan.org](http://elm-chan.org/docs/ir_format.html)

[**NECフォーマット**]
![NEC.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469819/cd019a72-6494-b9ad-a3d2-025970035844.png)

赤外線の規格が分かったので、見やすくするために成形したいと思います。

## 赤外線情報を成形する
先ほど生成した赤外線ファイルに書かれた情報を見やすくしましょう。
簡単なPythonスクリプトを作成したので、実行してみます。

<details>
<summary>Pythonコード(長いので折りたたんでます)</summary>

```py:decode.py
import json
import argparse

p = argparse.ArgumentParser()
p.add_argument("-t", "--time", help="Base Time", required=True, type=int)
p.add_argument("-f", "--file", help="Filename", required=True)
p.add_argument("id", nargs="+", type=str, help="IR codes")

args = p.parse_args()

# 16進数変換
def hexadecimal(l):
  target = iter(l)
  new_list = []

  for h, i, j, k in zip(target, target, target, target):
    new_list.append(format(h*8 + i*4 + j*2 + k, "X"))
  return new_list

# 2進数変換
def binary(l):
  target = iter(list(filter(lambda x: x <= 3, l)))
  new_list = []

  for i, j in zip(target, target):
    if i + j == 2:
      new_list.append(0)
    else:
      new_list.append(1)
  return new_list

# T単位変換
def normalize(l):
  new_list = [x//args.time for x in l]
  return new_list

# デコード
def decode(l):
  t = normalize(l)
  print("T: "+ str(t))
  bina = binary(t)
  print("bin: " + str(bina))
  hexa = hexadecimal(bina)
  print("hex: " + str(hexa))


with open(args.file, "r") as f:
  records = json.load(f)

for arg in args.id:
  if arg in records:
    code = records[arg]

    decode(code)
```

</details>


```sh
python3 decode.py -t 540 -f codes tv
# result
T: [16, 8, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 3, 1, 1, 1, 3, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1]
bin: [0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0]
hex: ['3', '0', 'E', 'E', '1', 'B', 'E', '4']
```

|  オプション|  内容  |
| ---- | ---- |
|  -t|  1Tあたりの基準時間(μsec)|
|  -f codes|  読み取るファイル名を指定する|
|  tv|  読み取るファイル内でデコードを行う信号名|

16進数に変換すると見やすいですね！！
NECフォーマットは**8bitデータと反転させた8bitデータ**を送ることでエラーチェックを行っているようですが、きちんと送っているのがわかります。

```sh
# デコードの結果(16進数)
hex: ['3', '0', 'E', 'E', '1', 'B', 'E', '4']

# 16bit
カスタマーコード(メーカーコード)：30EE
# 8bit:反転8bit
データ：1B:E4
```

# 最後に
息抜きにセンサー周りを久しぶりにやったのですが、面白かったです！
数千円あれば簡単に電子工作ができるので、皆さんもこれを機に始めてみてはいかがでしょうか？

今回使った`irrp.py`は赤外線の**読み取りだけでなく送信も可能**なので、自作スマートリモコンが簡単に作れちゃいます。
気になった人は作ってみてはいかがでしょうか！！

# 勉強会のおしらせ
最後まで記事を見ていただきありがとうございます！
株式会社Relicでは、定期的にオンラインイベントを行っています。
デザイナー、フロントエンドエンジニア、サーバーサイドエンジニア、インフラエンジニアがRelicで得た知見を発表しています。

興味がある内容がありましたら是非ご参加ください！

**直近開催されるイベント**

https://relic-inc.connpass.com/event/{近日開催されるイベントを紹介する}/


**Relicが主催している勉強会はこちらから確認できます**

https://relic-inc.connpass.com/