ラズパイの自作赤外線リモコンを動かすまでに試したこと

# はじめに
ラズパイを使って部屋の照明の赤外線リモコン作ろうとしていましたが，うまく動かないまま，2年くらい放置していました．様々なネットの記事を漁ってきましたが，どれも解決に至らず...
最近時間ができたので，ハードウェアからソフトウェアまでの設計を見直したところ，無事に照明の操作ができるようになったので，解決に至るまでに試した点を説明していきます．

# 試したこと
- **赤外線送信部の回路設計**  
信号強度に問題があると思い，赤外線送信の回路を改善．しかし，これだけでは解決しなかった．
- **信号のduty比の調整**  
調整すると，一部のラズパイで正しく動作するようになった．
- **pigpiodの設定**  
pigpioのデーモン起動時にオプションを加えると，所持している全てのモデルのラズパイで動作するようになった．

# 問題
主にこちらの記事を参考に，製作を進めていました．

https://qiita.com/takjg/items/e6b8af53421be54b62c9

赤外線の受信に関してはほぼ問題がなかったのですが，送信に関しては，何度試しても照明を制御することができませんでした．
プログラムは，[pigpioのサイト](http://abyz.me.uk/rpi/pigpio/examples.html)にて公開されているirrp.pyを使用していました．
ちなみに，私の部屋の照明はODELIC製です．

# 使用した機材・部品
- Raspberry Pi（Zero W，3B，3B+，4B）
- [赤外線LED OSI5FU5111C-40](https://akizukidenshi.com/catalog/g/gI-03261/)
- [赤外線リモコン受信モジュール OSRB38C9AA](https://akizukidenshi.com/catalog/g/gI-04659/)
- [NPNトランジスタ 2SC2655L-Y-T9N-K](https://akizukidenshi.com/catalog/g/gI-08746/)
- 抵抗 6.8Ω，220Ω
- ジャンパ線
- ブレッドボード

# 赤外線送信部の回路設計
## 赤外線LEDに流す電流について
ネット上で公開されている自作赤外線リモコンの記事を見ると，大体のものは，LEDに流す電流が百数十mA程度となっています．
はじめに動かなかった段階で，まずここを疑いました．LEDに大電流を流せば強く発光し，信号の飛距離が長くなります．

ここで，今回私が使用した赤外線LEDの[データシート](https://akizukidenshi.com/download/OSI5FU5111C-40.pdf)を見ると， 
> Pulse Forward Current 1000mA，Pulse Width≦100us，Duty≦1/100

と記述されています．
Pulse Widthはパルス波の周期で，Dutyはパルス波の周期のうちLEDが点灯する時間の割合を表しています．
周期100us，Dutyが1/100なので，LEDが点灯し続ける時間は，1usとなります．
つまり，赤外線LEDを**瞬時的に発光させる場合**は，**許容電流が1A**であることが分かります．
[赤外線リモコンの通信フォーマット](http://elm-chan.org/docs/ir_format.html)を見ると，大体のフォーマットが約38kHz，duty比1/3で通信しており，LEDが光り続ける時間は，

$$\frac{1}{38000}\times\frac{1}{3}\fallingdotseq 8.7719\ \mu\mbox{s}$$

となります．
赤外線リモコンにおいて，LEDに1A流すことには抵抗がありますが，瞬時的であれば，通常時の定格100mAより大きな電流を流しても問題ないと考えられます．

## 実際の赤外線リモコンのLEDに流れる電流
実際の赤外線リモコンを分解して回路を見てみます．
下の写真は，実際の赤外線リモコンの基板です．LEDが3本並列に，それぞれのLEDには1R2，つまり1.2Ωの抵抗が接続されています．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553486/662d14fa-2174-639d-3508-7b743d8aeef3.png)

電源は乾電池2本で3Vです．この赤外線LEDの順方向電圧を1.35Vと仮定すると，LEDに流れる電流は，
$$I = \frac{3-1.35}{1.2}=1.375 \mbox{ A}$$
となり，かなりの電流を流せることが分かります．
ただし，下段に接続されているトランジスタのベース電流などによって，LEDに流す電流が調節されている可能性があるため，実際に1.375Aが流れるとは言えません．

## 回路設計
ラズパイの5Vピンから供給できる電流は，ラズパイに供給する電源容量に依存するので，今回はそれも考慮して再設計しました．

トランジスタは，最大2Aまで流せる[2SC2655L-Y](https://akizukidenshi.com/catalog/g/gI-08746/)を選びました．赤外線LEDは，[OSI5FU5111C-40](https://akizukidenshi.com/catalog/g/gI-03261/)を使用します．
ラズパイに供給する電源は5V / 2Aのものを使用しています．USBテスターでチェックすると，無負荷時のラズパイの消費電流は大体0.4Aくらいでした．
そこで，残りの1.6Aを瞬時的に赤外線LEDに使用することにします．今回は2つの赤外線LEDを並列に接続し，各々に500mA程度，計1Aほど流す設計にします．

それでは，送信部の回路を設計していきます．以下に回路図を示します．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553486/460015ff-73fe-b658-01af-94ab8362049d.png)

### 解説
赤外線LEDの順方向電圧 $V_F$ は1.35V，赤外線LEDに流す電流 $I_F$ は500mAとします．
また，トランジスタの[データシート](https://akizukidenshi.com/download/ds/unisonic/2SC2655.pdf)より，コレクタ - エミッタ間電圧 $V_{CE}$ は0.5Vとします．
LEDの下についている抵抗 $R_C$ の値は，次のように決定します．

$$R_C=\frac{V_{CC}-(V_F+V_{CE})}{I_F}=\frac{5-(1.35+0.5)}{0.5}=6.3\mbox{ Ω}$$

計算上では6.3Ωとなりましたが，これにぴったりな抵抗がないことがあります．
今回は，手元にある抵抗が6.8Ωであったため，これを使用します．

続いて，ベース抵抗 $R_B$ を計算します．
トランジスタのコレクタに流れる電流は，LEDが2つ合流しているので $I_C$ は1Aです．$V_B$ はラズパイのGPIOの電圧なので，3.3Vです．
$h_{FE}$ は[データシート](https://akizukidenshi.com/download/ds/unisonic/2SC2655.pdf)のhFE - Ic特性より，周辺温度25℃，$I_C$ が1Aの時の $h_{FE}$ はおよそ140であることが分かります．
また，今回トランジスタはスイッチ用途として使用するので，$V_{BE}$ は，データシートよりベース - エミッタ間飽和電圧 1.2Vとします．
よって，ベース抵抗値は，

$$I_B=\frac{I_C}{h_{FE}} = \frac{1}{140} \fallingdotseq 7.14\times 10^{-3}$$
$$R_B=\frac{V_B-V_{BE}}{I_B}=\frac{3.3-1.2}{7.14\times10^{-3}} \fallingdotseq 294\mbox{ Ω}$$

となります．
手元にある抵抗で最も近いものが，220Ωであったため，これを使用します．
計算はこちらを参考にして行いました．

https://detail-infomation.com/base-resistance-base-emitter-resistance/

これで赤外線LEDの発光強度は改善されましたが，照明の制御を行うことができませんでした．

# 信号のduty比の調整
ラズパイの赤外線リモコン製作でよく使われる[IR Record and Playback (irrp.py)](http://abyz.me.uk/rpi/pigpio/examples.html)ですが，赤外線信号の波形を生成する部分を見てみましょう．

```python:irrp.py
def carrier(gpio, frequency, micros):
   """
   Generate carrier square wave.
   """
   wf = []
   cycle = 1000.0 / frequency
   cycles = int(round(micros/cycle))
   on = int(round(cycle / 2.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
```
この中の，

```python
on = int(round(cycle / 2.0))
```
ですが，これはduty比が1/2であることを表しています．
ここに問題があると考え，duty比を決め打ちで調整しました．
私の部屋の照明の赤外線通信フォーマットを解析したところ，NECフォーマットであることが分かりました．
[赤外線リモコンの通信フォーマット](http://elm-chan.org/docs/ir_format.html)より，NECフォーマットのキャリア周波数は38kHz，duty比は1/3です．
上記のプログラムでは，キャリア周波数を38kHzとすると，赤外線LEDのon時間，off時間ともに13usとなります．
これを，実際のフォーマットに従い，on時間とoff時間を調整します．
on時間は，
$$\frac{1}{38000}\times\frac{1}{3}\fallingdotseq 9\ \mu\mbox{s}$$
`pigpio.pulse()`の第3引数は整数値である必要があるため，切り上げます．
off時間は，
$$\frac{1}{38000}\times\frac{2}{3}\fallingdotseq 18\ \mu\mbox{s}$$
となります．
on，offをこの数値に置き換えます．
しかし，私の環境では`off = 18`だと制御できなかったため，`off = 19`としたところ，制御できるようになりました．

```python
on = 9
off = 19
wf.append(pigpio.pulse(1<<gpio, 0, on))
wf.append(pigpio.pulse(0, 1<<gpio, off))
```
これで，手持ちのラズパイZero W，4Bでは照明を制御できるようになりました．

# pigpiodの設定
しかし，手持ちのラズパイ3B，3B+では，duty比を調整しても動作しませんでした．
試しにラズパイ3B，3B+から送信した赤外線のコードを，irrp.pyと赤外線受信モジュールを用いてもう一度解析してみると，

```
Short code, probably a repeat, try again
```
と表示され，正しく解析できませんでした．
同じプログラムでも，ラズパイZero W，4Bでは正しく動作しているため，プログラムではなく，pigpio側に問題があると考えました．
[pigpiod](http://abyz.me.uk/rpi/pigpio/pigpiod.html)のオプションに，Clock peripheralというものがあります．

|option |name |choice |help|
|---|---|---|---|
|-t value | Clock peripheral|0=PWM, 1=PCM|Default PCM. pigpio uses one or both of PCM and PWM. If PCM is used then PWM is available for audio. If PWM is used then PCM is available for audio. If waves or hardware PWM are used neither PWM nor PCM will be available for audio.|

デフォルトではPCMとなっていますが，これが信号生成に影響していたようです．
ここで，Clock peripheralをPWMに変更してpigpioのデーモンを起動させます．

```sh
sudo pigpiod -t 0
```

pigpiodの自動起動を設定している場合は，`/lib/systemd/system/pigpiod.service`内の`ExecStart`を書き換えます．

```/lib/systemd/system/pigpiod.service
[Unit]
Description=Daemon required to control GPIO pins via pigpio
[Service]
ExecStart=/usr/bin/pigpiod -t 0
ExecStop=/bin/systemctl kill pigpiod
Type=forking
[Install]
WantedBy=multi-user.target
```

これで，ラズパイ3B，3B+でも照明を制御できるようになりました！
なお，なぜClock peripheralの設定がPCMで正しく動作しなかったかについては不明です...
手持ちのラズパイのハードウェア部分に問題があったのかもしれません．

# おわりに
本記事は，ラズパイを使った赤外線リモコンを作った際に生じた問題と，解決に至るまでに試した点についてまとめました．
今回私が遭遇した問題点は稀なケースではあると思いますが、何かのお役に立てれば幸いです！