2017年1月31日火曜日

Arduino で赤外線信号を学習してエアコンを制御してみた

概要

Arduino + 赤外線受信モジュールを使ってリモコンの赤外線信号を学習しました
そして、その信号を赤外線 LED を使って送信することでエアコンを制御してみました
今回学習したリモコンは Panasonic の A75C3639 という型番になります

環境

対象のリモコン

信号を学習するリモコンは以下の通りです
とりあえず今回は冷房をつけたいので冷房ボタンを学習します
try_arduino_infrared_remocon.jpg

配線

  • Arduino と赤外線受信モジュール
  • Arduino と赤外線 LED
  • Arduino とタクトスイッチ

を配線します
タクトスイッチを押した時に赤外線を送信するようにします
try_arduino_infrared_circuit1.jpg

ブレッドボード側のアップです
try_arduino_infrared_circuit2.jpg

赤外線受信モジュールは 5V, GND, 2 番ピンを使っています
あとで説明しますが、赤外線受信モジュールは必ず 2 番ピンを使ってください
赤外線 LED は GND, 3 番ピンを使っています
これもあとで説明しますが、赤外線の送信は必ず 3 番ピンを使ってください
タクトスイッチはプルダウンで接続し 3V, GND, 7 番ピンを使っています

IRremote のインストール

Arduino IDE で赤外線を操作することができるライブラリをインストールします

スケッチ -> ライブラリをインクルード -> ライブラリを管理 -> IRremote と検索

するとライブラリが見るかるので選択してインストールしてください
try_arduino_infrared_install_lib.png

リモコンの信号を学習する

では、まずリモコンの赤外線信号を学習します
スケッチは以下の通りです

#define maxLen 800

volatile  unsigned int irBuffer[maxLen];
volatile unsigned int x = 0;

void setup() {
  Serial.begin(115200);
  attachInterrupt(0, rxIR_Interrupt_Handler, CHANGE);
}

void loop() {
  Serial.println(F("Press the button on the remote now - once only"));
  delay(5000);
  if (x) {
    Serial.println();
    Serial.print(F("Raw: ("));
    Serial.print((x - 1));
    Serial.print(F(") "));
    detachInterrupt(0);
    for (int i = 1; i < x; i++) {
      // if (!(i & 0x1)) Serial.print(F("-"));
      Serial.print(irBuffer[i] - irBuffer[i - 1]);
      Serial.print(F(", "));
    }
    x = 0;
    Serial.println();
    Serial.println();
    attachInterrupt(0, rxIR_Interrupt_Handler, CHANGE);
  }

}

void rxIR_Interrupt_Handler() {
  if (x > maxLen) return;
  irBuffer[x++] = micros();
}

これを Arduino に書き込んで赤外線受信モジュールにリモコンを向けてボタンを押すと信号の情報がシリアルモニタに表示されます
try_arduino_infrared_receive_ir.png

事前の配線で受信モジュールは 2 番ピンを使うようにしましたが上記のコードは暗黙で 2 番ピンを使うことになっています
( コード上でピン番号を指定している部分がないと思います )

送信時にこの情報を使用するのでメモしておいてください

ちょっとここで詳細に説明したいのですが、実はリモコンの学習はインストールした IRremote ライブラリを使ってもできます
ですが、101 個以上の信号を送信するリモコンを IRremote で学習することができません
https://github.com/z3t0/Arduino-IRremote/issues/137

IRremoteInt.h というファイル内で RAWBUF という変数を管理しており、これが受信できる信号の個数の MAX 値なのですが、この値をデフォルトの 101 から変更してもうまくそれ以上の信号が受信できないのです

なので、別途赤外線の信号を学習するスケッチを作成して、そこで学習できた信号の情報を使うことにしました

学習した信号を送信する

信号を学習できたら送信してみましょう
送信用のスケッチは以下の通りです

#include <IRremote.h>

int ON = 7;
int khz = 38;
IRsend irsend;

void setup() {
  pinMode(ON, INPUT);
  Serial.begin(9600);
}

void loop() {
  if (digitalRead(ON) == HIGH) {
    Serial.println("ON");
    unsigned int irSignal[440] = {3584, 1664, 532, 352, 524, 1228, 528, 388, 492, 392, 496, 384, 492, 388, 492, 392, 488, 396, 492, 388, 492, 388, 492, 388, 492, 392, 492, 388, 492, 1224, 528, 392, 492, 392, 492, 388, 492, 388, 492, 388, 492, 364, 520, 388, 492, 1228, 524, 1228, 528, 1232, 528, 388, 492, 388, 488, 1228, 532, 360, 524, 388, 488, 360, 524, 388, 492, 360, 524, 388, 492, 388, 496, 388, 488, 360, 524, 360, 524, 388, 492, 388, 412, 472, 492, 388, 492, 388, 492, 360, 520, 364, 520, 392, 492, 388, 488, 360, 524, 392, 492, 392, 488, 388, 496, 388, 416, 468, 412, 468, 412, 436, 524, 388, 492, 392, 492, 388, 488, 1232, 528, 1228, 524, 392, 492, 392, 412, 468, 488, 360, 520, 388, 492, 9956, 3584, 1660, 528, 392, 412, 1304, 528, 388, 492, 360, 524, 360, 520, 392, 492, 356, 444, 440, 520, 392, 488, 360, 524, 388, 416, 440, 520, 388, 492, 1228, 524, 392, 492, 392, 492, 388, 488, 396, 412, 468, 412, 472, 488, 392, 488, 1228, 524, 1228, 528, 1232, 528, 388, 492, 388, 488, 1232, 524, 364, 520, 392, 416, 464, 492, 388, 416, 468, 492, 392, 488, 360, 520, 360, 520, 364, 520, 360, 524, 388, 492, 388, 416, 468, 416, 1304, 448, 468, 488, 392, 488, 396, 488, 1228, 452, 1304, 448, 436, 448, 472, 412, 468, 412, 464, 492, 1228, 528, 360, 520, 1228, 452, 1304, 448, 468, 492, 360, 520, 392, 488, 396, 412, 468, 412, 472, 488, 356, 448, 468, 488, 392, 488, 1240, 524, 388, 416, 1304, 452, 464, 488, 364, 520, 360, 448, 464, 416, 1304, 524, 364, 448, 468, 412, 468, 488, 388, 492, 364, 520, 392, 412, 468, 412, 468, 416, 468, 488, 364, 444, 436, 444, 468, 488, 396, 412, 468, 412, 468, 488, 360, 448, 436, 448, 464, 412, 1304, 452, 1304, 528, 360, 524, 388, 416, 468, 412, 468, 412, 440, 444, 468, 412, 468, 416, 432, 448, 472, 412, 464, 488, 1228, 452, 1304, 452, 472, 412, 468, 412, 468, 488, 392, 412, 472, 412, 468, 488, 364, 444, 464, 416, 472, 412, 468, 412, 468, 412, 468, 412, 472, 416, 468, 412, 432, 448, 468, 412, 440, 444, 468, 412, 468, 412, 468, 412, 472, 416, 464, 416, 468, 412, 464, 416, 1308, 524, 396, 412, 464, 416, 468, 412, 472, 416, 468, 412, 468, 412, 468, 412, 472, 416, 464, 416, 1304, 448, 1304, 524, 400, 416, 432, 448, 464, 416, 468, 412, 472, 412, 1308, 448, 468, 412, 468, 412, 1308, 452, 1304, 452, 468, 412, 468, 412, 468, 412};
    irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz);
  }
  delay(500);
}

学習した信号情報をそのまま配列に格納すれば OK です
今回はこの配列の情報がリモコンの冷房ボタンの信号になります
なので、別のボタンを送信したい場合はここの配列の情報をそのまま書き換えてください

今回はタクトスイッチが HIGH になったときに赤外線の信号を送信するようにしています
赤外線情報を送信するときはインストールした IRremote を使用しています
で、配線時に赤外線 LED を 3 番ピンに接続しましたが、IRremote の sendRaw は勝手に 3 番ピンを使っています
なので、3 番ピンに接続しておかないと IRremote で信号がうまく送信できないということになってしまいます

動作確認

赤外線 LED をエアコンに向けてスイッチを押してみましょう
ちゃんと信号が学習できていれば、エアコンが反応するはずです
ちなみに今回紹介した信号の配列で送信してみたところ、ちゃんとエアコンが冷房ボタンと認識し冷房が付きました
なので、これで Arduino からエアコンをつけれるようになりました

最後に

紹介は以上です

やはり一番ハマったのは信号を学習する部分でした
初めはずっと IRremote の学習するスケッチを使っていたのですが、どうも信号が 101 個以上増えなく、エアコンもその情報だと反応しませんでした
おかしいなと思い、いろいろ調べたところ送信する赤外線の信号が 101 個以上長いケースがあるということがわかり、別途信号を学習するスケッチを作るということになりました

ただ、この方法はおそらくどのリモコンにも応用可能だと思います
学習用のスケッチで学習したデータを配列に突っ込んで、そのデータをそのまま送信しているだけなので、同じことを別のリモコンでやれば良いだけです

IRremote の関数とかを見ると Sony や NEC などメーカごとに用意された関数があるのですが、これはライブラリ内部ですでにリモコンの情報を持っているため、少しでも対応していないリモコンだと動かなくなります

そんな場合でも今回の方法を知っていれば簡単に対応できるようになる、と思います

あと、停止の信号を学習するのと ESPr 対応ができれば家の外からでもエアコンを制御できるようにできそうです
それもできたら紹介したいと思います

参考サイト

5 件のコメント:

  1. 記事とても参考になります。ありがとうございます。

    一つ教えてください。受信の説明ではリモコン信号の数が439となっていますが、送信の際には440となっています。どのような工夫をされているか教えて頂けないでしょうか?

    以上、宜しくお願い致します。

    返信削除
  2. 送信側の配列の要素数をカウントしてみたいのですが、確かに 439 しかないですね、、、
    試してないですがおそらく unsigned int irSignal[439] でもスケッチは動作すると思います。
    ちょっと記憶がないので申し訳ないですが、ただの typo かなと思います。

    返信削除
  3. ご回答ありがとうございます。

    すみません、少し改良していますが、unsigned int irSignal[439] でも440としてもエアコンが反応しませんでした。。同じエアコンリモコンです。

    他の方のプログラムも参考にして、リモコン送信ができました。

    ありがとうございました。

    返信削除
  4. とりあえず動いたということでよかったです。
    439 でも 440 でも動かなったですか、、、arduino によっては書き込めるスケッチの容量に上限低いので 439 以上の配列の情報が書き込めなかったのかもしれません
    ESP-WROOM-02 などは容量が大きいので 439 以上でも余裕で書き込めるとは思います
    逆に ATTiny など小さなマイコンだと書き込めないかなと思います

    返信削除
  5. お返事ありがとうございます。
    Espr(ESP-WROOM-02)、bme280、bh1750、赤外線ledを使って、環境測定と外出先エアコン制御しています。
    そろそろ暖房のコードが欲しいと思って、今回に至りました(冷房、停止は本文で書かれている440のコードをそのまま利用させて頂きました)
    説明不足ですみません。重ね重ねありがとうございます。

    返信削除