Top/Devel/電子工作/Arduino/赤外線学習リモコンR2-D2

赤外線学習リモコンR2-D2はてなブックマーク

IR_R2-D2_01.jpg

夏は暑い。


外が暑い中を帰ってきて、自宅も暑いとうんざりする。


帰宅途中にエアコンをオンにできたらいいのに。


…そうだ!R2-D2に頼もう!

ということで、赤外線で色々な機器を操作するR2-D2を作ることに。


以前、Devel/電子工作/トラ技付録78K0 USBマイコン基板/赤外線学習リモコンR2-D2で作ったものがハードウェア故障とソース紛失で動作しなくなってしまったので、そのリベンジです。


この後、Raspberry Pi+irMagicianで作り直しました!

IR_R2-D2_02.jpg

機能

http://【ArduinoのIPアドレス】/【IRパケットの10進数表現】 にGETリクエストを送ると、任意の赤外線信号を送信できます。

材料

ir_shield.jpg

手順

  1. Arduino Uno、イーサネットシールド、IRシールドを順に接続する。
  2. IRシールドの赤外線LEDに拡散キャップを装着する。
  3. IRシールドのジャンパをすべて外す。
  4. 「赤外線信号を10進表現IRパケットに変換するスケッチ」をArduinoに書き込む。
  5. シリアルモニタを表示する。
  6. IRシールドのジャンパを2ピンと8ピンにつける。
  7. リモコンをIRシールドに向けて、ボタンを押す。
  8. シリアルモニタに表示された10進表現IRパケットをメモしておく。これを学習させたい信号分繰り返す。
  9. IRシールドのジャンパをすべて外す。
  10. 「ウェブサーバとして10進表現IRパケットを受信し、赤外線信号を送信するスケッチ」をArduinoに書き込む。
  11. IRシールドのジャンパを2ピンと8ピンにつける。
  12. 【動作確認】ブラウザを開き、http://【ArduinoのIPアドレス】/【10進数表現IRパケット】にアクセスしてみる。
  13. 正常に動作することが確認できたら、外装の製作に入る。
  14. Star Wars Bank R2-D2を切断する。
  15. IRシールドの赤外線LEDが露出するように穴を空ける。
  16. Star Wars Bank R2-D2にArduinoを格納する。

スケッチ

赤外線信号を10進表現IRパケットに変換するスケッチ

赤外線信号を受信し、シリアルモニタにIRパケット情報を10進数表現で表示します。

Jun様のいじわるリモコンスケッチの改変版です。Jun様ありがとうございます!

fileir_receiver.ino
/*
 * ir_reciever
 *
 * Date: 2012-08-05 23:55:00 +0900 (Sun, 05  Aug 2012)
 * Author: diabah( http://cubic9.com/ )
 * Original: jun ( http://www.geocities.jp/jun930/ele/irshield.html )
 */

#define DELIMITER "."

// IR packet
int hh,hl;
byte d1h,d1l;
byte d0h,d0l;
byte th,tl;
int len;
byte dat[50];

// last receive time
unsigned long last = 0;

int read_byte(){
  while(Serial.available() == 0);
  return Serial.read();
}

boolean rcv_pkt(){
  int i;
  byte cs = 0;
  
  if(read_byte() != 0xff) return false;
  cs += (i = read_byte());  hh = i * 256;
  cs += (i = read_byte());  hh += i;
  cs += (i = read_byte());  hl = i * 256;  
  cs += (i = read_byte());  hl += i;
  cs += (d1h = read_byte());
  cs += (d1l = read_byte());
  cs += (d0h = read_byte());
  cs += (d0l = read_byte());
  cs += (th = read_byte());
  cs += (tl = read_byte());
  cs += (i = read_byte());  len = i * 256;
  cs += (i = read_byte());  len += i;
  if (len > 400 || len <= 0) return false;
  for(i = 0;i < bytes(); i++){
    cs += (dat[i] = read_byte());
  }
  if(read_byte() != cs) return false;
  
  return true;
}

int bytes(){
  if(len == 0) return 0;
  return (len - 1) / 8 + 1;
}

byte checksum(){
  byte cs = 0;
  int i;
  
  cs += (byte)(hh >> 8) + (byte)(hh & 0xff);
  cs += (byte)(hl >> 8) + (byte)(hl & 0xff);
  cs += d1h + d1l + d0h + d0l + th + tl;
  cs += (byte)(len >> 8) + (byte)(len & 0xff);
  for(i = 0;i < bytes(); i++) cs += dat[i];

  return cs;
}

void snd_pkt(){
  Serial.write((byte)0xff);
  Serial.write((byte)(hh >> 8));
  Serial.write((byte)(hh & 0xff));
  Serial.write((byte)(hl >> 8));
  Serial.write((byte)(hl & 0xff));
  Serial.write(d1h);
  Serial.write(d1l);
  Serial.write(d0h);
  Serial.write(d0l);
  Serial.write(th);
  Serial.write(tl);
  Serial.write((byte)(len >> 8));
  Serial.write((byte)(len & 0xff));
  Serial.write(dat,bytes());
  Serial.write(checksum());
  read_byte();  // receive ACK
}

void setup(){
  pinMode(13,OUTPUT);
  Serial.begin(19200);
  len = 0;
}

void print_pkt(){
  Serial.println();
  Serial.print(int((byte)0xff));
  Serial.print(DELIMITER);
  Serial.print(int((byte)(hh >> 8)));
  Serial.print(DELIMITER);
  Serial.print(int((byte)(hh & 0xff)));
  Serial.print(DELIMITER);
  Serial.print(int((byte)(hl >> 8)));
  Serial.print(DELIMITER);
  Serial.print(int((byte)(hl & 0xff)));
  Serial.print(DELIMITER);
  Serial.print(int(d1h));
  Serial.print(DELIMITER);
  Serial.print(int(d1l));
  Serial.print(DELIMITER);
  Serial.print(int(d0h));
  Serial.print(DELIMITER);
  Serial.print(int(d0l));
  Serial.print(DELIMITER);
  Serial.print(int(th));
  Serial.print(DELIMITER);
  Serial.print(int(tl));
  Serial.print(DELIMITER);
  Serial.print(int((byte)(len >> 8)));
  Serial.print(DELIMITER);
  Serial.print(int((byte)(len & 0xff)));
  Serial.print(DELIMITER);
  int i;
  for(i = 0;i < bytes(); i++){
    Serial.print(int(dat[i]));
  Serial.print(DELIMITER);
  }
  Serial.print(int(checksum()));
  Serial.println();
}

void loop(){
  if (Serial.available() > 0){
    digitalWrite(13,HIGH);
    if(rcv_pkt()){
      last = millis();
    }
    digitalWrite(13,LOW);
  }
  
  if(millis() - last > 1000 && len > 0){
    digitalWrite(13,HIGH);
    snd_pkt();
    digitalWrite(13,LOW);
    Serial.end();

    delay(100);

    digitalWrite(13,HIGH);
    Serial.begin(9600);
    print_pkt();
    digitalWrite(13,LOW);
    Serial.end();

    delay(100);

    Serial.begin(19200);

    len = 0;
  }
}

ウェブサーバとして10進表現IRパケットを受信し、赤外線信号を送信するスケッチ

ウェブサーバとしてGETリクエストで10進数表現IRパケット情報を受信し、赤外線信号を送信します。

実際に使用する前にMACアドレスをご自身のArduinoイーサネットシールド貼付のMACアドレスに書き換えてください。IPアドレス、ポートも必要であれば変更してください。

ブロードバンドルータなどでポートマッピング設定(いわゆるポート開放)をするとインターネット経由でR2-D2を操作できるようになります。

fileir_sender.ino
/*
 * ir_sender
 *
 * Date: 2012-08-05 23:55:00 +0900 (Sun, 05  Aug 2012)
 * Author: diabah( http://cubic9.com/ )
 * Original: Arduino Ofiicial ( http://arduino.cc/en/Tutorial/WebServer )
 */

#include <SPI.h>
#include <Ethernet.h>

#define BEGINNING_OF_LINE 0
#define PREFIX_LENGTH 4
#define DELIMITER "."

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {  0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
IPAddress ip(192, 168, 0, 40);

// Initialize the Ethernet server library
// with the IP address and port you want to use 
// (port 80 is default for HTTP):
EthernetServer server(3000);

void setup() {
 // Open serial communications and wait for port to open:
  Serial.begin(19200);


  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
}


void loop() {
  char ir_code[255];
  int cusror = 0;
  int ir_cnt = 0;
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean beginflag = false;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        //Serial.write(c);
        if (cusror == BEGINNING_OF_LINE && c == 'G') {
          // if beginning of line is start with "GET"
          beginflag = true;
        } else 
        if (cusror == PREFIX_LENGTH + 1 && c == 'f') {
          // if GET request is getting favicon
          beginflag = false;
        } else
        if (cusror == BEGINNING_OF_LINE && c == '\r') {
          // if beggining of line is CR
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connnection: close");
          client.println();
          client.println("<html>");
          client.println("<body>");
          client.println(ir_code);
          client.println("</body>");
          client.println("</html>");

          char *part;
          for(part = strtok(ir_code, DELIMITER); part; part = strtok(NULL, DELIMITER)) {
            Serial.write(byte(atoi(part)));
          }
          break;
        } else
        if (beginflag == true) {
          if (cusror == PREFIX_LENGTH) {
            ir_cnt = -1;
          } else if (cusror > PREFIX_LENGTH){
            if (c == ' ') {
              // if current character is the space before "HTTP/1.1"
              ir_code[ir_cnt] = '\0';
              beginflag = false;
            } else {
              ir_code[ir_cnt] = c;
            }
          }
          ir_cnt++;
        }
        cusror++;
        if (c == '\n') {
          cusror = BEGINNING_OF_LINE;
        }
      }
    }
    
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
  }
}

自宅のIRパケット

操作型番10進数表現IRパケット
エアコン電源オフ東京ガス DCグリル-35CEA255.1.69.0.157.23.57.23.17.23.255.0.48.86.232.111.1.68.43.190
エアコン電源オン東京ガス DCグリル-35CEA255.1.69.0.157.23.57.23.18.23.255.0.48.86.232.111.1.68.24.172
シーリングライト電源オフPanasonic HHFZ4290255.0.139.0.62.21.47.21.13.20.255.0.40.52.74.144.236.124.224
シーリングライト電源オンPanasonic HHFZ4290255.0.139.0.62.21.47.21.13.21.255.0.40.52.74.144.44.188.97
テレビ電源オン/オフPanasonic TH-36FG15255.0.138.0.63.21.46.22.13.21.255.0.48.64.4.1.0.188.189.49
テレビ音量増Panasonic TH-36FG15255.0.138.0.63.21.47.21.13.20.255.0.48.64.4.1.0.4.5.192
テレビ音量減Panasonic TH-36FG15255.0.138.0.63.21.45.23.12.21.255.0.48.64.4.1.0.132.133.192
MDコンポ電源オン/オフPanasonic SA-PM35MD255.0.138.0.62.21.46.21.13.21.255.0.48.64.4.5.56.188.129.47
コンポ音量減Panasonic SA-PM35MD255.0.138.0.62.21.45.21.13.21.255.0.48.64.4.5.0.132.129.190
コンポ音量増Panasonic SA-PM35MD255.0.137.0.63.21.47.21.13.21.255.0.48.64.4.5.0.4.1.192
コンポCD再生Panasonic SA-PM35MD255.0.138.0.62.21.45.21.13.21.255.0.48.64.4.5.80.80.5.94
コンポMD再生Panasonic SA-PM35MD255.0.138.0.62.21.45.21.13.21.255.0.48.64.4.5.4.80.81.94
コンポ停止Panasonic SA-PM35MD255.0.137.0.62.21.46.21.13.21.255.0.48.64.4.5.56.0.61.46

備考

ソニーのブルーレイレコーダBDZ-AT950Wの信号は学習できませんでした (^^;

これはソニー製品の信号フォーマットは、家電協フォーマットやNECフォーマットとは違い、明滅の時間の長さによってビットを表現しており、IRレシーバで読み取れる方式ではないためです。

もちろん自前で実装すれば解決できます。特にビットを判定せず、読み取った波形をそのまま再現するようにすればよいのです。

しゃべらせる

しゃべらせたい場合、音声再生部品を別途調達する必要があります。

一般的なのはWaveシールドだと思うのですが、私が秋葉原に行ったときは見つけられませんでした。

そこで後述の通り、APLUS社の録音再生IC APR9600を利用した秋月電子通商のキットを使いました。

機能

http://【ArduinoのIPアドレス】/【IRパケットの10進数表現】 にGETリクエストを送ると、任意の赤外線信号を送信できます。

また、

http://【ArduinoのIPアドレス】/sound にGETリクエストを送ると、APR9600に録音された音声を再生します。

材料

手順

  1. K01-Aとアンプ基盤を組み立てて動作確認する。
  2. K01-Aの音質アップのためにオシレーターの周波数を決める抵抗(回路図のR7)を24kΩに差し替える。
  3. K01-Aの電源端子(基盤のJ3)の線を除去する。
  4. ArduinoのGNDをK01-Aの電源端子(基盤のJ3)に接続する。
  5. ST-20Aの白線をK01-Aのオーディオ出力(回路図のJ2)の+に接続する。
  6. ST-20Aの緑線をK01-Aのオーディオ出力(回路図のJ2)の-に接続する。
  7. ST-20Aの赤線をアンプ基盤のオーディオ入力(回路図のA)に接続する。
  8. ST-20Aの黒線をアンプ基盤のオーディオ入力(回路図のG)に接続する。
  9. スピーカーの+をアンプ基盤のオーディオ出力(回路図のP)に接続する。
  10. スピーカーの-をアンプ基盤のオーディオ出力(回路図のN)に接続する。
  11. ArduinoのDIGITAL2をK01-AのAPR9600の(回路図のM1)に接続する。
  12. Arduinoの5VをK01-Aの電源端子(基盤のJ3)に接続する。
  13. ArduinoのGNDをK01-Aの電源端子(基盤のJ3)に接続する。
  14. Arduinoの5Vをアンプ基盤の電源端子(回路図のV)に接続する。
  15. ArduinoのGNDをアンプ基盤の電源端子(回路図のG)に接続する。
  16. IRシールドのジャンパをすべて外す。
  17. 「赤外線信号を送信したり音声出力したりするスケッチ」をArduinoに書き込む。
  18. IRシールドのジャンパを2ピンと8ピンにつける。

※とりあえず組む場合、Arduinoのピンと何かを接続するにはICテストリードが便利です。

赤外線信号を送信したり音声出力したりするスケッチ

下記は前述の「ウェブサーバとして10進表現IRパケットを受信し、赤外線信号を送信するスケッチ」からの差分です。

fileir_sender_apr9600.diff
--- ir_sender.ino    Sun Sep 22 00:50:32 2013
+++ ir_sender_apr9600.ino    Sun Sep 22 00:52:44 2013
@@ -13,6 +13,8 @@
 #define PREFIX_LENGTH 4
 #define DELIMITER "."
 
+#define APR9600 2
+
 // Enter a MAC address and IP address for your controller below.
 // The IP address will be dependent on your local network:
 byte mac[] = {  0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
@@ -24,7 +26,12 @@
 EthernetServer server(3000);
 
 void setup() {
- // Open serial communications and wait for port to open:
+  // initialize the digital pin as an output.
+  pinMode(APR9600, OUTPUT);     
+  // reset digital pin connected to APR9600: 
+  digitalWrite(APR9600, HIGH);
+
+  // Open serial communications and wait for port to open:
   Serial.begin(19200);
 
 
@@ -55,6 +62,23 @@
           // if GET request is getting favicon
           beginflag = false;
         } else
+        if (cusror == PREFIX_LENGTH + 1 && c == 's') {
+          // if GET request is requsting sound
+          beginflag = false;
+          digitalWrite(APR9600, LOW);
+          delay(500);
+          digitalWrite(APR9600, HIGH);
+          client.println("HTTP/1.1 200 OK");
+          client.println("Content-Type: text/html");
+          client.println("Connnection: close");
+          client.println();
+          client.println("<html>");
+          client.println("<body>");
+          client.println("sound");
+          client.println("</body>");
+          client.println("</html>");
+          break;
+        } else
         if (cusror == BEGINNING_OF_LINE && c == '\r') {
           // if beggining of line is CR
           client.println("HTTP/1.1 200 OK");

コメント等ありましたらどうぞ :)

最新の10件を表示しています。 コメントページを参照

  • 通りすがり at 2012-08-06 (Mon) 10:06

    R2D2に組み込んだのが素敵ですw!

    • でぃあばぁ(管理人) at 2012-08-07 (Tue) 23:16

      ありがとうございます!簡単にできますので、お勧めです! :)

  • shiro at 2013-05-12 (Sun) 21:24

    あつくなってきて、arduinoと赤外シールドは持っているのでエアコン動かそうかと調べたらヒットしました。参考にさせて頂きます。

    • でぃあばぁ(管理人) at 2013-06-08 (Sat) 20:53

      わからないことがあれば、質問してください :)

name:

参考

関連

Amazon

差分 一覧