Make.

赤外線リモコンを作る

Pocket

Arduinoで赤外線リモコンを作ります。
シリアル通信で制御するため、Windows、Mac、Linuxのどの環境からも利用できます。
また、エアコンなどの長いコマンドにも対応した汎用性の高いリモコンを実現します。


赤外線リモコンについて

Arduinoで赤外線リモコンを作る前に、赤外線リモコンについて簡単に説明します。
赤外線は人の目には見えませんが、リモコンのボタンを押すと、赤外線がリモコンから出ています。
詳しい説明は、他のサイトを参考にしてもらえばよいです。

各メーカの違いを比べると難しいのでざっくりいうと、赤外線リモコンの動作を行います。
・赤外線リモコンは、赤外線のOn/Offの並びをデータとして送信する
・赤外線をON/OFFする時間で、0と1を示している
・リモコン送信することを知らせるため、Leader区間がある

*38kHzのキャリア周波数は、ここでは話がややこしくなるため割愛します。

これらの送信は、メーカー毎のフォーマットに従っており、フォーマットの規格はいくつか存在します。そこで、ここでは簡単なソフトを作成することで、メーカが違っても対応できるリモコンを作成します。


用意するもの

赤外線リモコンを作るために用意するものは以下になります。
・Arduino Uno
・赤外線LED
赤外線リモコン受信モジュール
・接続用の部品(ブレッドボード等)
構成はシンプルで、リモコン送信のみを行うならば、赤外線LED1つだけでよいです。また、Arduinoは純正でなくても良いため、約2500円で、安価に汎用リモコンを作ることができます。
赤外線LEDと赤外線リモコン受信モジュールは秋月で購入しました。


部品の接続

赤外線LEDと、受信用の赤外線リモコンモジュールを以下のように接続します。
Arduinoでは、送信用に13番、受信用に8番のポートを使用します。
接続は非常に簡単です。

00114

00119


機能

リモコンのデータを送るのではなく、on/offの時間をそのまま送るため、赤外線リモコンの規格に関係なく、ほとんどのリモコンに対応できます。
Arduino内にバッファを多くとっているため、エアコンなどのコマンドが長いリモコンにも対応できます。
単純なシリアル通信を使って、Arduinoと通信しているため、環境を選ばずWindows、Mac、Linuxのいずれの環境からもリモコンを利用することができます。


プログラム

Arduinoソフトは以下に格納しました。
右下の「Download ZIP」からまとめてダウンロードできます。
GitHub

ソースコードは以下になります。
types.hを読み込む必要があります。GitHubから取得してください。

//========================================================
// File Name: ir_controller
// URL      : http://make.bcde.jp
//========================================================
#include "types.h"

//========================================================
// Config
//========================================================

#define SERIAL_BPS             (57600)   /* Serial bps */
#define IR_IN                  (8)       /* Input      */
#define IR_OUT                 (13)      /* Output     */

#define TIMEOUT_RECV_NOSIGNAL  (50000)
#define TIMEOUT_RECV           (5000000)
#define TIMEOUT_SEND           (2000000)

//========================================================
// Define
//========================================================
#define STATE_NONE             (-1)
#define STATE_OK               (0)
#define STATE_TIMEOUT          (1)
#define STATE_OVERFLOW         (2)
#define DATA_SIZE              (800)

//========================================================
// Program
//========================================================
u2 data[DATA_SIZE];

void sendSignal(){
  u1 x;
  s1 state = STATE_NONE;
  u2 time = 0;
  u4 tmp = 0;
  u4 index = 0;
  u4 count = 0;
  u4 us = 0;

  us = micros();

  while(state == STATE_NONE){
    if(Serial.available() == 0){
      if((micros() - us) > TIMEOUT_SEND){
        state = STATE_TIMEOUT;
        break;
      }
    } else {
      x = Serial.read();
      if(x>='0' && x<='9'){
        /* 数字を受信した場合 */
        tmp *= 10;
        tmp += x - '0';
      } else {
        /* 数字以外を受信した場合 */
        if((tmp == 0) && (index == 0)){
          /* 最初の一文字目は読み飛ばす */
        } else {
          data[index] = (u2)tmp;
          if(tmp == 0){
            state = STATE_OK;
            break;
          } else if(index >= DATA_SIZE){
            state = STATE_OVERFLOW;
            break;
          }
          index++;
        }
        tmp = 0;
      }
    }
  }

  if(state == STATE_OK){
    for(count = 0; count < index; count++){
      time = data[count];
      us = micros();
      do {
        digitalWrite(IR_OUT, !(count&1));
        delayMicroseconds(8);
        digitalWrite(IR_OUT, 0);
        delayMicroseconds(7);
      }while(s4(us + time - micros()) > 0);
    }
    Serial.println("OK");
  } else {
    Serial.print("NG:");
    Serial.println(state);
  }
}

void recvSignal(){

  u1 pre_value = HIGH;
  u1 now_value = HIGH;
  u1 wait_flag = TRUE;
  s1 state = STATE_NONE;
  u4 pre_us = micros();
  u4 now_us = 0;
  u4 index = 0;
  u4 i = 0;

  while(state == STATE_NONE){
    now_value = digitalRead(IR_IN);
    if(pre_value != now_value){
      now_us = micros();
      if(!wait_flag){
        data[index++] = now_us - pre_us;
      }
      wait_flag = FALSE;
      pre_value = now_value;
      pre_us = now_us;
    }

    if(wait_flag){
        if((micros() - pre_us) > TIMEOUT_RECV){
          state = STATE_TIMEOUT;
          break;
        }
      } else {
        if((micros() - pre_us) > TIMEOUT_RECV_NOSIGNAL){
          state = STATE_OK;
          break;
        }
      }
  }

  if(state == STATE_OK){
    Serial.print("s,");
    for(i = 0; i<index; i++){
      Serial.print(data[i]);
      Serial.print(',');
    }
    Serial.println("0,");
  } else {
    Serial.println("NG");
  }
}

void setup(){
  Serial.begin(SERIAL_BPS);
  pinMode(IR_IN, INPUT);
  pinMode(IR_OUT, OUTPUT);
}

void loop(){
  u1 x;
  if(Serial.available()){
    x=Serial.read();
    switch(x){
      case 's':
        sendSignal();
        break;
      case 'r':
        recvSignal();
        break;
      default:
        break;
    }
  }
}

使い方

プログラムを書き込んだArduinoをUSB接続するだけで、準備完了です。
Arduinoで簡単に確認するためには、シリアルモニタを使用します。通信速度を57600bpsにしてください。
00115

シリアル通信を行うソフトならば、なんでもよいです。

リモコンの受信

リモコンを受信したい場合は「r」をArduinoに送信して受信モードにします。
受信モードにすると約5秒間信号を待ち受けるため、受光部にリモコンを向け、受信したいボタンを押します。
00116

受信に成功すると、以下のようにリモコンの波形データを送信してきます。
以下の信号はTOSHIBAのTVREGZAの電源ボタンのデータです。
00117

s,9016,4400,640,484,568,568,556,568,628,500,624,504,556,568,636,1528,624,564,564,1668,636,1588,636,1588,564,1664,640,1592,632,1592,632,492,568,1668,632,492,628,1596,564,564,564,564,564,1660,640,492,560,568,556,572,556,1668,564,564,564,1660,564,1668,556,572,556,1668,564,1644,584,1668,556,39700,9016,2172,564,0,

リモコンの送信

上記のPCから受信したリモコンデータはそのままリモコン送信に使うことができます。
リモコンを送信したい場合は、「s」コマンドを利用します。「s」の後に続けて、「s,3000,1700,450,300,0,」のように波形データを続けて記述します。数字は、リモコン波形の時間になっています。
最後の「0,」はコマンドの終端を示すため必ずつけるようにします。

00118

リモコン送信のデータが受付けられるとOKがArduinoから送信されます。
リモコン受信待ち受け中は、リモコン送信はできません。

受信モードでリモコンデータを受信して、そのデータをリモコンに送信することでそのまま使用することができます。

Pocket