Arduinoでリモコン作成

エアコンの操作を行う。

エアコンのリモコンから出力されている信号を取得する。それと、同じ信号を出力すれば、エアコンを操作することも可能だ。

参考となったサイト

配線

以下の部品を買ってきた。

  • 赤外線LED:OSI5LA5113A (秋月
  • 赤外線リモコン受信モジュール:OSRB38C9AA (秋月
  • 抵抗 47Ω (秋月

こんな感じで配線を行う。左の黒いのが赤外線受信モジュール。この図では分かりにくいが、こちらを向いている。Arduinoの7番に繋がっている。右の緑色のLEDが赤外LEDだ。Arduinoの2番に繋がっている。

リモコンの信号を取得

ここからが一苦労だった。日経Linuxのサンプルソースでは動かず・・。どうやら信号を正確に受信できていなかったようだ。そこで、参考にさせてもらったのが「Arduinoで学習リモコン」のサイト。こちらのサンプルでは正常に動作した。

といっても、私好みのソースでなかったため、少し書き直した。

#define READ_PIN 7
  
#define LOW_STATE 0
  
#define HIGH_STATE 1

void setup(){
    
Serial.begin(57600);
    
pinMode(READ_PIN,INPUT);

Serial.println("Ready to receive");
  
}

void waitLow() {
    
while (digitalRead(READ_PIN)==LOW) {
      
;
    
}
  
}

int waitHigh() {
    
unsigned long start = micros();
    
while (digitalRead(READ_PIN)==HIGH) {
      
if (micros() – start > 5000000) {
        
return 1;
      
}
    
}
    
return 0;
  
}

unsigned long now = micros();
  
unsigned long lastStateChangedMicros = micros();
  
int state = HIGH_STATE;

void loop() {
      
if (state == LOW_STATE) {
        
waitLow();
      
} else {
        
int ret = waitHigh();
        
if (ret == 1) {
          
Serial.print("\n");
          
return;
        
}
      
}

now = micros();
      
Serial.print((now – lastStateChangedMicros) / 10, DEC);
      
Serial.print(",");
      
lastStateChangedMicros = now;
      
if (state == HIGH_STATE) {
        
state = LOW_STATE;
      
} else {
        
state = HIGH_STATE;
      
}
  
}

赤外線信号のオンオフの時間(10マイクロ秒単位)が出力される。シリアル出力の速度を”57600 bps”に変更して、リモコンを赤外線受信モジュールに近づけて、スイッチを押してみると・・

リモコンの信号が取得できる!

リモコンの信号を出力

次はリモコンの信号出力だ。こちらも、少しソースを書き直した。エアコンの信号は数が多いため、ソースに埋め込んだ。先ほど取得したリモコン信号を、data配列の初期値に書いて実行する。

int ir_out = 2;
  
int led = 9;

// エアコンオン(冷房、26度 微)
  
unsigned int data[] = {342,163,47,120,50,33,48,40,44,40,36,48,36,45,46,40,44,39,46,40,41,40,44,35,40,45,40,127,38,48,46,39,44,34,46,39,44,40,44,40,44,40,36,48,46,40,41,40,44,39,44,39,44,39,36,47,45,39,47,34,39,48,44,120,48,39,47,119,46,121,47,122,46,122,45,120,47,121,47,40,46,118,48,120,48,122,36,129,48,120,39,129,49,118,39,130,46,121,49,40,41,40,35,47,45,39,36,47,44,40,46,40,43,35,46,40,44,37,49,119,49,119,47,35,50,36,45,121,38,131,44,121,38,130,46,37,38,48,46,118,47,121,49,40,43,38,46,34,39,129,47,39,44,40,36,130,47,39,44,39,44,122,38,129,49,35,38,129,39,131,36,48,43,121,49,118,47,40,46,118,39,130,48,35,41,45,44,123,44,40,43,40,36,48,44,40,36,45,38,129,38,130,46,40,44,122,44,122,47,122,37,48,36,48,44,35,50,119,38,48,44,121,47,123,47,37,44,123,44,120,48,120,47,35,40,129,46,36,48,40,44,121,47,40,38,44,37,47,44,42,33,45,38,48,44,39,36,48,36,129,50,118,38,129,39,129,41,126,47,121,39,131,36,129,47,36,50,34,39,48,36,48,46,34,38,48,36,48,44,38,37,129,39,129,41,126,49,119,46,121,50,118,46,121,47,121,38,48,36,48,46,40,36,45,36,47,38,48,33,48,36,48,44,122,37,129,38,130,46,123,37,129,39,130,41,127,41,127,38,48,35,48,44,40,36,47,44,39,36,48,38,48,36,45,35,129,39,131,36,130,38,129,39,131,37,129,39,129,39,131,36,46,38,48,35,48,36,48,36,45,38,45,38,48,36,48,36,129,49,118,47,121,47,120,38,129,50,118,39,130,46,120,47,121,49,118,38,48,35,48,35,129,38,48,35,47,44,36,47,40,43,40,44,121,38,129,39,45,49,119,38,128,47,121,38,130,38,48,35,47,36,48,35,129,47,40,36,129,47,121,38,49,38,126,47,121,38,129,38,49,38,126,38,49,35,49,35,47,44,35,40,48,44,40,36,48,36,45,38,48,36,45,38,129,41,127,41,126,39,129,38,130,40,127,38,130,38,129,39,48,35,48,35,48,38,45,36,47,36,48,36,48,38,48,33,129,39,129,42,126,41,126,38,130,41,127,38,130,38,129,41};

// エアコンオフ
  
//unsigned int data[] = {347,158,53,114,53,28,55,28,56,28,56,26,57,35,49,26,57,26,57,26,57,26,57,26,57,28,56,115,53,34,49,27,56,28,55,28,55,26,56,28,55,28,56,26,57,28,56,26,58,34,48,26,57,26,57,28,56,26,57,28,56,26,57,115,53,35,48,117,51,115,53,115,53,116,52,115,52,115,53,28,55,115,52,115,53,115,53,115,53,115,53,117,50,117,51,116,52,115,52,28,56,28,55,26,57,28,55,29,54,28,56,26,57,28,56,29,54,28,56,116,52,115,52,28,55,28,56,116,52,115,53,115,53,115,52,28,56,28,55,115,53,115,52,28,55,28,55,28,55,115,53,28,55,29,55,116,52,28,56,28,55,116,52,115,52,29,55,115,53,115,53,27,55,116,52,115,53,28,55,115,53,115,53,28,55,29,55,116,52,28,55,26,57,28,55,28,55,29,55,116,52,116,52,28,55,115,53,114,53,115,53,28,55,28,55,28,56,116,52,28,55,115,53,116,52,28,55,116,52,117,51,116,53,28,55,115,53,34,48,28,55,116,52,28,55,28,55,26,57,28,56,28,55,28,55,35,48,28,56,116,52,115,52,116,52,116,53,115,53,115,52,116,52,115,53,28,55,28,56,28,56,28,55,28,55,28,55,28,55,28,55,116,52,116,52,116,53,115,52,115,53,115,53,115,52,115,52,29,55,28,56,28,55,28,55,28,55,29,55,28,55,29,55,116,52,115,53,116,52,115,53,115,53,115,52,115,53,115,53,27,56,29,55,28,56,28,55,28,55,28,56,28,56,28,55,116,52,115,53,116,52,115,52,115,53,119,49,115,53,115,52,26,57,28,55,26,57,28,56,29,55,28,55,28,55,29,54,117,50,115,52,116,52,116,53,115,53,115,52,115,53,115,53,115,52,115,53,28,55,28,56,28,55,28,56,115,52,28,55,28,56,29,55,116,52,116,52,116,53,115,52,28,56,115,52,116,53,28,55,28,56,28,56,28,56,28,56,115,52,116,52,28,55,115,53,115,53,115,53,115,52,115,53,27,56,28,56,28,56,28,55,29,55,26,57,28,55,28,56,26,57,28,56,115,53,115,52,116,51,115,52,117,51,116,53,115,53,115,52,28,55,29,55,29,55,28,56,28,56,28,55,28,55,28,55,115,53,115,53,117,51,115,52,115,53,117,50,115,53,115,52};

// Apple TV再生ボタン
  
//unsigned int data[] = {905,445,57,57,54,164,58,164,58,164,58,54,58,163,58,164,58,164,58,164,57,164,58,164,58,57,55,57,54,57,55,57,55,164,58,164,58,164,58,164,58,164,58,164,58,57,55,164,58,57,55,164,58,164,58,164,58,164,58,57,54,57,54,164,58,56,58,3390,905,444,58,54,58,164,58,164,58,164,58,56,55,164,58,164,58,164,60,162,58,164,58,164,58,57,54,57,55,57,55,54,57,164,58,164,58,56,55,164,57,54,58,54,57,57,55,54,57,54,58,164,58,164,58,164,58,164,61,51,57,57,55,164,58,58,55};

int last = 0;
  
unsigned long us = micros();

// セットアップ
  
void setup() {
    
pinMode(ir_out, OUTPUT);
    
pinMode(led, OUTPUT);
  
}

// dataからリモコン信号を送信
  
void sendSignal() {
    
int dataSize = sizeof(data) / sizeof(data[0]);
    
for (int cnt = 0; cnt < dataSize; cnt++) {
      
unsigned long len = data[cnt]*10; // dataは10us単位でON/OFF時間を記録している
      
unsigned long us = micros();
      
do {
        
digitalWrite(ir_out, 1 &#8211; (cnt&1)); // cntが偶数なら赤外線ON、奇数ならOFFのまま
        
delayMicroseconds(8); // キャリア周波数38kHzでON/OFFするよう時間調整
        
digitalWrite(ir_out, 0);
        
delayMicroseconds(7);
      
} while (long(us + len &#8211; micros()) > 0); // 送信時間に達するまでループ
    
}
  
}

void loop() {
    
digitalWrite(led, HIGH);
    
sendSignal();
    
digitalWrite(led, LOW);
    
delay(3000);
  
}
  

3秒おきに、信号を送信する。エアコンのオン・オフだけでなく、Apple TVの再生ボタンでも動作した。目的の高性能リモコン完成を目指すため、ここは深くは追わないことにした。これで動いたんだから、それで良し!

*注意(2012/08/04 追記)

Arduinoはメモリの制約が厳しく、大きい配列を用意するとプログラムが停止する可能性がある。参考:Arduinoで赤外線送信5 赤外線学習機能の追加(2): Reflection of my mindArduino – PROGMEMを参考にして、プログラムを組むと良い。

トラブルシューティング

いろいろと苦労したので、それも書いておく。

1つ目は、赤外線LEDが点灯しているか不明である点。赤外線は目に見えないため、目では判別できない。デジカメのレンズを通してみると、白く光っているはずだ。iPhoneのカメラでは写らなかったので注意。

2つ目は、赤外線LEDの方向。LEDは、上方向への光が強く、横方向への光が弱い。そのため、LEDの頭をエアコンに向けないといけないのだ。また、信号が弱いこともあるので、近づけないと反応しないこともある。

投稿日 2012年07月31日