2018年5月9日水曜日

Arduinoで赤外線リモコンの値を読み取り、送信する方法


背景

Arduinoとは電子工作に利用しやすい、プログラムを書き込める装置です。
Arduinoを使って赤外線リモコンが送信する値を読み取り、読み取ったデータを送信してみました。
思っていた以上に手間だったので、備忘録を兼ねて方法を共有します。


この記事の内容では読取り切れないエアコンのリモコンの情報をコピーする方法を紹介する記事を書きました。
良かったらこちらもご覧ください。

Arduino(ESP32)でエアコンの赤外線リモコンの信号をコピーして発信する

全体像

  1. 利用するライブラリを紹介
  2. 使ったものを紹介
  3. ライブラリを準備
  4. 読み取り回路を作成
  5. リモコンの送信値を読み取り
  6. 送信回路を作成
  7. 読み取った値を送信
  8. まとめ

利用するライブラリを紹介

この記事ではIRremoteというライブラリを利用します。
このライブラリはデータの受信に関するサンプルプログラムがあるので、それを利用します。

使ったものを紹介

Arduino Uno

データ送信用Arduinoとデータ受信用Arduinoを作れれば、Arduinoから送信される信号がリモコンと同じことを確認できます。
リモコン対応機器で確認する場合は、Arduino1台でも構いません。

Arduino Uno Rev3

Arduino IDEをインストールしたPC

Arduino IDEとはArduino向けのプログラムを作成・コンパイル・書き込みが行えるソフトウェアです。
下記のリンクから、利用しているPCのOSに対応したArduino IDEをダウンロード・インストールしてください。

Download the Arduino IDE

赤外線受信モジュール

Arduinoでリモコンの値を読み取るのに利用します。
どちらかを準備してください。

赤外線リモコン受信モジュールOSRB38C9AA
赤外線リモコン受信モジュール SPS-444

赤外線LED + 抵抗

Arduinoから赤外線での情報を送信するのに利用します。
3mm砲弾型の赤外線LEDと100Ωの抵抗を使いました。
LEDを光らせるときは1kΩの抵抗を使うことが個人的に多いのですが、今回利用する赤外線LEDは100mAを許容しているため、抵抗として100Ωを使いました。
(可視光LEDは数十mAのものが多いですが、今回利用する赤外線LEDは50-100mA、瞬時なら1Aを許容しています。)

3mm赤外線LED 940nm OSI5FU3A11C
カーボン抵抗(炭素皮膜抵抗) 1/2W 100Ω

ブレッドボード + ジャンパワイヤ

Arduinoと部品の接続に利用します。

ブレッドボード
ジャンパワイヤ

赤外線リモコン

Arduinoで値を読み取ります。

オプトサプライ赤外線リモコン

MOSFET

ArduinoのGPIOからの電流では、赤外線LEDによっては十分に光らない場合があります。
そういう場合は、MOSFETやトランジスタを利用すると、LEDを十分な電流で光らせられます。
この記事では下記のMOSFETを利用しました。

MOSFET 2N7000

ライブラリを準備

Arduino IDEのライブラリマネージャでライブラリをインストールます。

インターネットに接続したPCでArduino IDEを起動し、スケッチ -> ライブラリをインクルード -> ライブラリを管理 を選択して、ライブラリマネージャを開きます。


ライブラリマネージャ上部の欄にIRremoteと入力して検索します。


IRremoteをクリックして、表示されるインストールボタンをクリックします。


記事更新時(2022.01)のライブラリのバージョンは3.5.2です。


記事作成時(2018.05)のライブラリのバージョンは2.2.3でした。
記事を作成した当初のコードを動かしたい場合は、2.2.3付近のバージョンのライブラリを利用してください。


読み取り回路を作成

Arduinoでリモコンから送信される情報を読み取る回路を作成します。



バージョンによってサンプルコードのピンの割当が異なるため、利用するライブラリのバージョンによってこのように接続先を変えてください。

センサの出力ピンの接続先
ライブラリ3.5.2前後の場合: GPIO2
ライブラリ2.2.3前後の場合: GPIO11

配線するとこうなりました。

ライブラリ3.5.2向けにGPIO2に接続した様子
ジャンパワイヤで受光部が隠れないように、受光部はArduinoが無い方を向いています。


ライブラリ2.2.3向けにGPIO11に接続した様子


リモコンの送信値を読み取り

ライブラリのサンプルプログラムを利用して、リモコンの送信値を読み取ります。

ライブラリバージョン3.5.2の場合

プログラムの書き込み

ファイル -> スケッチ例 -> IRremote -> IRrecvDump を選択してサンプルプログラムを開きます。


Arduino UnoでGPIO2以外を受信ピンとして利用したい場合は、PinDefinitionsAndMore.hのAVR向けのIR_RECEIVE_PINを書き換えてください。
(割り込み機能が無いピンだと動かない可能性があります。)


PCにUnoを接続し、ボード情報とポートを合わせます。


書き込みボタンを押してプログラムを書き込みます。


Arduino IDE右上にあるシリアルモニタアイコンをクリックして、シリアルモニタを開きます。


ReceiveDumpのシリアル通信速度は115200bpsなので、シリアルモニタの右下にある通信速度をそれに合わせます。

受信装置にリモコンを向けてボタンを押すと、情報が表示されると思います。


ノイズが入ることがあるので、何回か試して、再現性のある情報を見てください。


プロトコルの種類とデータの内容(addressとcommand)を送信時に利用します。
Protocol=NEC Address=0x10 Command=0xF8 Raw-Data=0x7F8EF10 32 bits LSB first
uint16_t address = 0x10;

uint16_t command = 0xF8;
uint32_t data = 0x7F8EF10;

なお、エアコンなど送信情報の多いリモコンを解釈しようとすると下記のような情報が表示されて解釈できません。
Overflow detected

Try to increase the "RAW_BUFFER_LENGTH" value of 112 in /home/asuki/Arduino/libraries/IRremote/examples/ReceiveDump/ReceiveDump.ino

上記の場合はメモリの多いマイコンでRAW_BUFFER_LENGTHやRECORD_GAP_MICROSを増やすと解釈できることがあります。
それをしたい場合は、エアコンの赤外線リモコンの信号をコピーして発信する記事が参考になると思います。

ライブラリバージョン2.2.3の場合

プログラムの書き込み

ファイル -> スケッチ例 -> IRremote -> IRrecvDumpV2 を選択してサンプルプログラムを開きます。


GPIO11以外のピンを信号受信に利用する回路を作成した場合は、プログラムの10行目位にあるrecvPinを、赤外線読み取り装置の信号ピンを接続したGPIOピンの番号にします。
記事を書いている時点では、サンプルプログラムの信号受信に利用するGPIOは11だったので、回路作成時にGPIO11を利用した場合は、編集せずそのままで良いです。


recvPinがGPIOピンの番号と合っていることを確認したら、プログラムを書き込みます。
Arduino Unoを使っているので、ボード情報を"Arduino / Genuino Uno"に、シリアルポートをArduino Unoのシリアルポートにします。


ボードとシリアルポートの設定ができたら、書き込みボタンをクリックするとプログラムを書き込めます。


Done Uploadingと表示されれば、書き込み成功です。

リモコンから送信された値を確認

Arduino IDE右上にあるシリアルモニタアイコンをクリックして、シリアルモニタを開きます。


先ほど書き込んだプログラムは9600bpsの通信速度でやりとりする設定になっているので、画面右下の通信速度を9600bpsにします。



受信装置にリモコンを向けてボタンを押すと、情報が表示されると思います。


ノイズが入ることがあるので、何回か試して、再現性のある情報を見てください。


空白行のあとに表示されている2行が重要です。
この情報を送信に利用するので、どこかに保存しておいてください。
Encoding  : NEC
Code      : 8F71FE0 (32 bits)

送信回路を作成

Arduinoで赤外線の信号を送信する回路を作成します。

ライブラリの標準設定でArduino UnoはGPIO3で信号を送信するので、赤外線LEDをGPIO3に接続します。

GPIOからの電流(数十mA)で十分な場合

Arduinoの赤外線出力用GPIO、LED、抵抗、GNDを直列に繋ぎます。


配線すると、こうなりました。


MOSFETを使って多くの電流を確保したい場合

Arduinoの赤外線信号出力用GPIOをMOSFETに接続し、MOSFETを通してLEDの点灯を制御します。
電流が多く流れるため、LEDの光り方が強くなります。
また、複数本を角度を変えて同時に光らせることで、赤外線の照射範囲を広げることもできます。


配線するとこうなりました。


この回路では多くの電流が流れるので、抵抗が無いとLEDが破損する場合があります。
抵抗をLEDに接続することを強くお勧めします。

読み取った値を送信

信号送信プログラムを書き込みます。

ライブラリ3.5.2の場合: プログラムを新規作成して書き込み

3.5.2の情報送信サンプルプログラムは混沌としているので、プログラムを新規作成して書き込みます。
Arduino IDEでファイル -> 新規作成 を選択してプロジェクトを作り、下記のプログラムを記述してください。
このプログラムは5秒ごとに先ほど取得した情報を送信します。

#define IR_SEND_PIN 2
#include <IRremote.hpp>

void setup() {
IrSender.begin();
}
// Protocol=NEC Address=0x10 Command=0xF8 Raw-Data=0x7F8EF10 32 bits LSB first
uint16_t address = 0x10;
uint16_t command = 0xF8;

void loop() {
IrSender.sendNEC(address, command, 0);
delay(5000);
}

要所を解説します。

IRremoteはIR_SEND_PINというマクロで送信ピンを指定可能です。
IRremote.hpp読込前にそれでPWM出力可能なピンを指定します。
#define IR_SEND_PIN 2
#include <IRremote.hpp>

読み取った情報はNEC形式だったので、sendNEC関数で送信します。
sendNEC関数の第3引数は繰り返し回数を意味します。
第3引数が無いと古い形式の関数呼び出しになってしまうので、繰り返し回数が0回でも0を渡す必要があります。
uint16_t address = 0x10;
uint16_t command = 0xF8;
IrSender.sendNEC(address, command, 0);

プログラムを書けたら書き込みボタンを押して、送信回路を取り付けたArduinoにプログラムを書き込みます。

ライブラリバージョン2.2.3の場合: サンプルプログラムを書き換えて書き込み

ファイル -> スケッチ例 -> IRremote -> IRsendDemo を選択して、ベースとするサンプルプログラムを開きます。

先ほど読み取ったリモコンの情報を見ると、NEC形式で「8F71FE0」(16進数表記)という32ビットの値を送信していることが分かります。
Encoding  : NEC
Code      : 8F71FE0 (32 bits)

loopを書き換えて、NEC形式で「8F71FE0」(16進数表記)という32ビットの値を5秒に1回送信するプログラムにします。
void loop() {
  irsend.sendNEC(0x8F71FE0, 32);
  delay(5000);
}


送信値を引数として管理したい場合は、このように書くことも出来ます。
void loop() {
  unsigned int data = 0x8F71FE0;
  irsend.sendNEC(data, 32);
  delay(5000);
}

読み取った信号の情報をもとにプログラムを書き換えたら、書き込みボタンを押して、送信回路を取り付けたArduinoにプログラムを書き込みます。

送信値を確認

Arduino1台で試している場合は、Arduinoに接続した赤外線LEDをリモコンの情報に応じて動作する機器に向けて、動作を確認してください。

Arduino2台で試している場合は、受信回路に対して送信回路の赤外線LEDを向けると、信号送信が成功していれば、リモコンと同じ値を確認できます。


終わり

Arduinoで赤外線リモコンの信号情報を読み取り、同じ信号を出せました。

参考になれば嬉しいです。

参考

Arduino-IRremote
第23回 Arduinoでパーツやセンサーを使ってみよう~赤外線リモコン(前編)

変更履歴

2020.01.25
値を送信するプログラムの送信値に「0x」を付け忘れて16進数表記になっていなかったので修正しました。

2021.12.06
新しく書いたArduino(ESP32)でエアコンの赤外線リモコンの信号をコピーして発信する記事のリンクを追加しました。

2022.01.14
記事作成時点のIRremoteライブラリのバージョン2.2.3と現在最新のバージョン3.5.2とでピンの割当やシリアル出力の解釈方法が異なっていたので、最新バージョンの使い方を追加しました。

4 件のコメント :

Always Basics さんのコメント...

irsend.sendNEC(8F71FE0, 32);
のところですが、0x付けないと怒られますよね?

Asuki Kono さんのコメント...

コンパイルエラーになる記述の指摘ありがとうございます。
修正しました。

Unknown さんのコメント...

すいません、IRrecvDumpV2 というスケッチ例が見つからないのですが、、、 
なぜでしょうか??

Asuki Kono さんのコメント...

コメントありがとうございます。
IRremoteのchange logの2020年10月公開に公開された2.8の情報として
Moved dump/print functions from example to irReceiver.
とあり、2.7.0ならIRrecvDumpV2があるのを確認しました。
(2.8.0にもありますが、2.8.1では無くなっているので、消し忘れだと思います。)

そのため、ライブラリのバージョンを2.7.0にすれば、この記事の内容に沿って動作確認できると思います。
最新のライブラリでも同様の機能をどれかのサンプルプログラムで呼び出せるのだとは思いますが、確認できていません。