{
"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
}