{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "オリジナルの作成: 2014/05/03" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 06-赤外線を使ってみる\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 赤外線リモコンのフォーマット\n", "赤外線リモコンには、以下の3つのフォーマットがありますが、ここではNEC方式を使用します。 \n", "[1](#Ref_1)\n", "\n", "- NEC(現ルネサスエレクトロニクス)フォーマット\n", "- AEHA(家製協)フォーマット\n", "- SONYフォーマット" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### NECフォーマットについて\n", "最もよく使われているNECフォーマットを使って実験することにします。\n", "\n", "NECフォーマットでは、ビット情報は38KHz(1/3duty)で送信され、Frameと呼ばれるデータ単位 に続いてRepeatと呼ばれるFrameの終わりを表すデータがボタンが押されている間繰り返されます。\n", "\n", "Frameは、以下の形式を持っています。データが1の時には、0.56msのON, 1.69msのOFFを送り、 データが0の場合には、0.56msのON, 1.69msのOFFを送ります。\n", "\n", "- Leader(9msのON, 4.5msのOFF)\n", "- Customer Code(16bitのカスタマコードをLSBから順に送信)\n", "- Data(8bit)\n", "- Dataのビット反転値(8bit)\n", "- EStopビット" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Arduinoを使ってNECフォーマットのデータを送る\n", "38KHzでオン・オフを繰り返すには、digitalWriteでは時間がかかるため、PORTDに直接ビットをセットします。 このため使用可能なデジタルピンは、0から7番までとなっています。\n", "\n", "Arduinoを使って赤外線リモコンを送信する例題は、いくつかありましたが、今回参考にさせて頂いたのは、以下の3サイトです。\n", "\n", "- Arduinoで遊ぶページの \n", "[赤外線リモコンの実験](http://garretlab.web.fc2.com/arduino/lab/infrared_controller/index.html)\n", "- 戸田よろず研究所の\n", "[赤外線リモコンの複製2(38 kHzをソフトウェアで制御)](http://tyk-systems.com/ircopy2/ircopy2.html)\n", "- セミコロンラボの\n", "[Arduinoで赤外線リモコン送信](http://www.cjpr.sakura.ne.jp/arduino/irrcsend.html)\n", "\n", "ここでは、Arduinoで遊ぶページをメインに参考にさせて頂き、東芝REGZAの電源オン・オフを試みます。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### リモコン側のブレッドボード\n", "ちょっと乱暴ですが、動作を確認するだけなので、赤外線LEDの線の長い方を直接2番と短い方をGNDに接続して試してみます。\n", "\n", "今回使った赤外線LEDは、スイッチサイエンスの \n", "[SIR-34ST3F](http://www.switch-science.com/catalog/1484/)\n", "です。\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### リモコン側のスケッチ\n", "使用するスケッチは、以下の様にします。\n", "\n", "```C++\n", "class IrControlNecFormat {\n", " public:\n", " // constructor\n", " IrControlNecFormat(byte ledPin, byte custom0, byte custom1);\n", " void sendCommand(byte data);\n", " private:\n", " byte _ledPinMask; // the pin mask which the LED is connected\n", " byte _custom0; // custom code\n", " byte _custom1; // custom code'\n", " \n", " void sendData(byte date);\n", " void on(int num);\n", "};\n", "\n", "IrControlNecFormat::IrControlNecFormat(byte ledPin, byte custom0, byte custom1) {\n", " _ledPinMask = 1 << ledPin;\n", " _custom0 = custom0;\n", " _custom1 = custom1;\n", " \n", " pinMode(ledPin, OUTPUT); // set the ledPin as an OUTPUT\n", "}\n", "\n", "void IrControlNecFormat::sendCommand(byte data){\n", " on(346); // leader code(ON)\n", " delayMicroseconds(4500); // leader code(OFF)\n", " \n", " sendData(_custom0); // custom code\n", " sendData(_custom1); // custom code\n", " \n", " sendData(data); // data\n", " sendData(~data); // ~data\n", " \n", " on(22); // stop bit\n", "}\n", "\n", "void IrControlNecFormat::sendData(byte data) {\n", " for(int i = 0; i < 8; i++) {\n", " on(22);\n", " int delayU_Sec = ( data & 0x01 ) ? 1690 : 565;\n", " delayMicroseconds( delayU_Sec );\n", " data = data >> 1;\n", " }\n", "}\n", "\n", "void IrControlNecFormat::on(int num) {\n", " for(int i = 0; i < num; i++) {\n", " PORTD |= _ledPinMask;\n", " delayMicroseconds(9);\n", " PORTD &= ~_ledPinMask;\n", " delayMicroseconds(17);\n", " }\n", "}\n", "\n", "// 赤外線LEDを2番ピンとGNDに接続\n", "// 東芝REGZAのカスタマコードは、 0x40, 0xBF\n", "IrControlNecFormat controller(2, 0x40, 0xBF);\n", "\n", "void setup() {\n", "}\n", "\n", "void loop() {\n", " // REGZAの電源コードは、0x12\n", " controller.sendCommand(0x12);\n", " // 5秒間隔でオン・オフを繰り返す\n", " delay(5000);\n", "}\n", "```\n", "\n", "スケッチの以下の部分で2番ピンにカスタマコードとして、0x40, 0xBFとして、IrControlNecFormatクラスのインスタンスを生成します。\n", "\n", "```C++\n", "IrControlNecFormat controller(2, 0x40, 0xBF);\n", "```\n", "\n", "これで、東芝REGZAのコントロールができるcontrollerができます。 これに、0x12(電源のコード)をsendCommandで送ると電源のオン・オフを繰り返します。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 実際に動かしてみる。\n", "ブレッドボードを組み立てて、LEDをテレビに向けてリセットスイッチを押してみて下さい。 5秒間隔でオン・オフを繰り返します。\n", "[2](#Ref_2)\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 他の操作方法\n", "上記のスケッチのカスタマコードとコードを変えるといろんな処理ができるようになります。\n", "\n", "以下のPDFに各種テレビのカスタムコードとデータの意味がまとめられています。\n", "\n", "- [NECフォーマット 赤外線リモコン コード表](http://www.ne.jp/asahi/o-family/extdisk/ATBextension/ATBIRrecvNEC/ATBIRrecvNEClst.pdf)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 赤外線受信機\n", "赤外線リモコンのコードが公開されていない場合には、どうしたらよいのでしょう。\n", "\n", "今回は、スイッチサイエンスの \n", "[RPM6938リモコン受光モジュール](http://www.switch-science.com/catalog/list/?keyword=RPM6938)\n", "を使って実験してみます。\n", "\n", "\n", "\n", "ピンの配置は、データシートから引用します。丸い突起のある面の左からRout, GND, Vccとなっています。\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 赤外線受光器のブレッドボード\n", "以下の様にブレッドボードを組み立てます。受光モジュールが同じものがなかったので、形の似たもので表示しています。\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 赤外線コード解析\n", "Arduinoで遊ぶページの\n", "[赤外線リモコンコード解析(NECフォーマット) ](http://garretlab.web.fc2.com/arduino/make/infrared_sensor_nec_format/)\n", "に紹介されている赤外線リモコン解析スケッチが重宝します。\n", "\n", "以下に引用して表示します。\n", "\n", "```C++\n", "#define COUNT_NUM 68\n", "\n", "const int pin = 2; /* 赤外線センサの出力を接続するデジタルピン */\n", "unsigned long time[COUNT_NUM]; /* 時刻を格納する配列 */\n", "\n", "void setup () {\n", " pinMode(pin, INPUT);\n", " Serial.begin(9600);\n", "}\n", "\n", "void loop () {\n", " int repeat = 0;\n", " int mode; /* 読み取るデータを決める */\n", " char str[64];\n", " \n", " /* 68回データを読み取る */\n", " mode = HIGH; /* 最初はHIGH */\n", " for (int i = 0; i < COUNT_NUM; i++) {\n", " while(digitalRead(pin) == mode) { /* 状態が変わるまで待つ */\n", " ;\n", " }\n", " time[i] = micros(); /* 時刻を記録する */\n", " \n", " if (mode == HIGH) { /* onとoffが交互に来るので,待つべき状態を変える */\n", " mode = LOW;\n", " } else {\n", " mode = HIGH;\n", " }\n", " \n", " /* リーダコードのoffが2.25msだと次にストップビットが来て終了 */\n", " /* 3000ms以下かどうかで判定 */\n", " if ((i == 3) && ((time[2] - time[1])) < 3000) {\n", " repeat = 1;\n", " break;\n", " }\n", " }\n", " \n", " /* データの出力 */\n", " Serial.print(\"--------- BEGIN ---------\\n\");\n", " \n", " sprintf(str, \"Leader:\\n HIGH %dms\\n\", (time[1] - time[0]));\n", " Serial.print(str);\n", " sprintf(str, \" LOW %4dms\\n\\n\", (time[2] - time[1]));\n", " Serial.print(str);\n", " \n", " if(repeat) {\n", " Serial.println(\"Repeat\");\n", " } else {\n", " Serial.println(\"Custom Code:\");\n", " print_data(2);\n", " print_data(18);\n", "\n", " Serial.println(\"\");\n", " \n", " Serial.println(\"Data:\");\n", " print_data(34);\n", " print_data(50);\n", " \n", " Serial.print(\"--------- END ---------\\n\\n\");\n", " }\n", "}\n", "\n", "void print_data(int start) {\n", " int code = 0;\n", " char str[32];\n", " \n", " sprintf(str, \" \");\n", " for (int i = 0; i < 8; i++) {\n", " if ((time[2 * i + start + 2] - time[2 * i + start]) > 1500) {\n", " code |= 1 << i;\n", " sprintf(&str[2 * (i + 1)], \"1 \");\n", " } else {\n", " sprintf(&str[2 * (i + 1)], \"0 \");\n", " }\n", " }\n", " \n", " sprintf(&str[17], \", %02x\", code);\n", " Serial.println(str);\n", "}\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 赤外線コード解析を動かしてみる\n", "それでは、赤外線コード解析スケッチを動かしてみます。\n", "\n", "\n", "\n", "シリアルモニターを起動し、テレビ(REGZA)の電源ボタンを押すと以下の様に返ってきます。\n", "\n", "\n", "\n", "最初に作った通り、カスタマコード0x40, 0xBFとデータ0x12が受信されていることが確認できます。\n", "\n", "これを使えば、他のリモコンの解析もできます。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 再確認\n", "小出さまのご質問で、再度実験をしてみました。\n", "\n", "もしかしてCPUのクロックが影響しているのかと思い、今回はDuemilanoveを使いました。\n", "\n", "\n", "\n", "起動直後は、きちんと動いていましたが、蛍光灯の明かりを消すと急に以下の様にシリアスコンソールに 表示されました。\n", "\n", "```Console\n", "--------- BEGIN ---------\n", "Leader:\n", " HIGH 2152ms\n", " LOW 324ms\n", "\n", "Repeat\n", "--------- BEGIN ---------\n", "Leader:\n", " HIGH 80ms\n", " LOW 2572ms\n", "\n", "Repeat\n", "```\n", "\n", "出力を遡ってみると、東芝のリモコンを押したときには、きちんとCustom Codeの出力でていました。\n", "\n", "```Console\n", "--------- BEGIN ---------\n", "Leader:\n", " HIGH 72ms\n", " LOW -18344ms\n", "\n", "Custom Code:\n", " 1 1 1 1 1 1 1 1, ff\n", " 0 1 0 1 1 1 1 0, 7a\n", "\n", "Data:\n", " 1 0 0 0 0 1 0 0, 21\n", " 0 0 0 1 0 1 0 0, 28\n", "--------- END ---------\n", "```" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## 脚注\n", "- 1 \n", "[赤外線リモコンの通信フォーマット](http://elm-chan.org/docs/ir_format.html)\n", "を参考にしました\n", "- 2 どうもREGZAでは電源オフで上手くできないことがあります" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.13" } }, "nbformat": 4, "nbformat_minor": 0 }