できること

第24回 Arduinoでパーツやセンサーを使ってみよう~赤外線リモコン(後編)

写真2 Arduinoイーサネットシールド

前回は、赤外線受信モジュールと赤外線LEDの使い方を学びました。今回は応用としてリモコン家電を操作する「スマートコントローラー」を作成してみます。リモコンで操作できる家電は皆さんの部屋の中にもいろいろあると思います。筆者も作成にあたって家の中のリモコンを片っ端から集めて作成します!

今回の電子工作レシピ

完成までの時間目安:90分
必要なパーツ

スマートコントローラーの仕様を決める

さっそく手を動かしたいところですが、まずは仕様を決めます。

  1. 光センサーや温度センサーと組み合わせてセンサーの数値を条件に自動操作
  2. PCやスマートフォンからスマートコントローラーを経由して家電を操作できる

というところでしょうか。今回はこのふたつの機能を実装してみます。

1)光センサーの数値を受けてリモコン信号を送信する

今回、制作を行っている部屋は、照明のリモコン操作が可能です。筆者はいつも気づいたら夕方で、少し暗くなった部屋の中でリモコンを探して照明をつける、なんてことが日常茶飯事なので、光センサーを利用してある一定の暗さになったら自動的に照明をつける信号が送信されるようにします。

Arduinoに照明を点灯させる信号を登録させます。前回と同じように、受信するプログラムをArduinoに書き込んで照明のリモコンを赤外線受信モジュールに向けてコードを解析します。

写真2 照明リモコンとArduino

写真2 照明リモコンとArduino

次に、送信プログラムをArduinoに書き込んで、Arduinoから照明を点灯できるか確認します。今回利用したリモコンの「全灯」を解析して、送信できるようにしました。

リモコン信号の準備ができたところで光センサーを回路に加え、光センサーからの値が暗くなった場合にリモコン信号を送信するプログラムにします。プログラムは、光センサーに人が一瞬横切った場合などに反応しないように、連続で暗い状態を検出した場合にのみリモコン信号を出すようにしています。(光センサーの詳しい回路説明は第5回を参照)

図1 光センサーと赤外線LED送信回路

図1 光センサーと赤外線LED送信回路

プログラム:光センサーの値で照明をONにするプログラム

Code-Example
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <IRremote.h>
 
IRsend irsend;
 
int pin = A1;
int count = 0;  //連続して暗い状態をカウント
 
void setup()
{
  Serial.begin(9600);
}
 
void loop() {
  int s = analogRead(pin);  //光センサーの値を入力
  Serial.println(s);
  if (s > 660) {  //指定の入力条件を満たした時(暗くなった時)
    count++;
    if(count > 5){
        Serial.println("Light ON");
        for (int i = 0; i < 3; i++) {
          irsend.sendNEC(0xa90, 12); // 照明のON
          delay(40);
        }
        count = 0;
    }
  }
  else{
    count = 0;  //途中で明るくなったらカウントをリセット
  }
  delay(5000);
}

これで、暗くなると仕様の1番目である「光センサーの状態でリモコン信号を発信できる機能」が整いましたね!

2)ネットワーク経由でリモコン信号を送信する

光センサーでリモコン信号を送信できるようになったので、次にネットワークを通じてスマートフォンやPCからリモコン信号を送信できるようにしてみます。これまでも度々出てきているイーサネットシールドを使い、Arduinoをサーバーにして、サーバーに表示されているHTMLからリモコン操作ができるようにしてみます。

写真3 Arduinoイーサネットシールド

写真3 Arduinoイーサネットシールド

はじめに、ArduinoをWEBサーバーとして動作させて、サーバーに接続した際に表示されるHTML上のボタンによってLEDをオンオフできるようにします。これができれば、LEDの部分をリモコン信号に置き換えてプログラムを書き換えます。

※今回プログラムでは、テキスト解析用ライブラリの「TextFinder」を利用しています。(ライブラリの追加方法は第20回を参照)

Code-Example
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <SPI.h>
#include <Ethernet.h>
#include "TextFinder.h"
 
byte mac[] = {
0x90, 0xA2, 0xDA, 0x0F, 0x3F, 0x0D
};
IPAddress ip(192,168,0,20);
 
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
 
int lightPin = A0;
int ledPin1 = 3;
int ledPin2 = 2;
 
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
 
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
 
}
void loop() {
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
 
//*******************************************
//* GET形式でデータの受け渡しがあったとき
//*******************************************
TextFinder finder(client);
if (finder.find("GET"))
{
while (finder.findUntil("mode", "\n\r"))
{
int val = finder.getValue();
Serial.println("val="+String(val));
//tv on
if (val == 1)
{
digitalWrite(ledPin1,HIGH);
delay(1000);
digitalWrite(ledPin1,LOW);
Serial.println(" ON");
}
//light on
else if (val == 2)
{
digitalWrite(ledPin2,HIGH);
delay(1000);
digitalWrite(ledPin2,LOW);
Serial.println(" ON");
}
}
}
//*******************************************
Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
//client.println("Refresh: 5"); // refresh the page automatically every 5 sec
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
 
//*************************************************
//* bootstrap
//*************************************************
client.println("<head>");
client.println("<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css'>");
client.println("<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css'>");
client.println("</head>");
//*************************************************
client.println("<body>");
 
client.println("<a class='btn btn-primary' href='/?mode=1'>TV ON</a> ");
client.println("<a class='btn btn-primary' href='/?mode=2'>Light ON</a><hr/>");
// output the value of each analog input pin
int sensorReading = analogRead(lightPin);
client.println("Light:");
client.println(sensorReading);
client.println("<br />");
client.println("</body>");
client.println("</html>");
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}
}
写真4 ウェブサーバーからLEDを光らせるテスト回路

写真4 WebサーバーからLEDを光らせるテスト回路

無事、WEBサーバーからLEDのオンオフができたので、LEDの代わりにリモコン信号を発信する回路・プログラムに変更します。イーサネットシールドを利用した場合、4、10〜13番ピンはイーサネットシールドが利用するため、それ以外のピンを利用して回路を作成します。最終的に、仕様 1. の光センサーの入力回路も合わせたプログラムは下記の通りです。発信する信号や出力するHTMLはお持ちのリモコンのものに変更して試してください。

プログラム:スマートコントローラー回路

Code-Example
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <SPI.h>
#include <Ethernet.h>
#include "TextFinder.h"
#include <IRremote.h>
 
IRsend irsend;
 
byte mac[] = {
  0x90, 0xA2, 0xDA, 0x0F, 0x3F, 0x0D
};  //利用しているイーサネットシールドのMACアドレスを記入
IPAddress ip(192,168,0,20);  //利用しているネットワーク帯のIPアドレス
 
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
 
int lightPin  = A1;
int count  = 0;
void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
 
}
 
void loop() {
 
  int sensorValue = analogRead(lightPin);
//*************************************************************
//* 指定した明るさより暗い場合が続いたとき照明をON
//*************************************************************
  if(sensorValue > 660){
    count++;
    if(count > 10){
     // 照明のオン
     for (int i = 0; i < 3; i++) {
        irsend.sendNEC(0xC318F7, 32);
        delay(40);
      }
      Serial.println(" ON");
      count = 0;
    }
  }
  else{
    count = 0;
  }
  delay(1000);
 
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
 
//*************************************************************
//* GET形式でデータの受け渡しがあったとき(ブラウザ側からの操作)
//*************************************************************
                TextFinder finder(client);
        if (finder.find("GET"))
        {
            while (finder.findUntil("mode", "\n\r"))
            {
                int val = finder.getValue();
                Serial.println("val="+String(val));
                                //tv on
                if (val == 1)
                {
                                   // テレビ電源ONの信号
                                   for (int i = 0; i < 3; i++) {
                                     irsend.sendSony(0xa90, 12);
                                     delay(40);
                                   }
                   Serial.println(" ON");
                }
                                //light on
                else if (val == 2)
                {
                                   // 照明のオン
                                   for (int i = 0; i < 3; i++) {
                                     irsend.sendNEC(0xC318F7, 32);
                                     delay(40);
                                   }
                   Serial.println(" ON");
                }
            }
        }
//*******************************************
 
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          //client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
 
 //*************************************************
//* bootstrap
 //*************************************************
          client.println("<head>");
          client.println("<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css'>");
          client.println("<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css'>");
          client.println("<script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js'></script>");
          client.println("</head>");
 //*************************************************
          client.println("<body>");
 
          client.println("<a class='btn btn-primary' href='/?mode=1'>TV ON</a> ");
          client.println("<a class='btn btn-primary' href='/?mode=2'>Light ON</a><hr/>");
          // output the value of each analog input pin
          int sensorReading = analogRead(lightPin);
          client.println("Light:");
          client.println(sensorReading);
          client.println("<br />");
          client.println("</body>");
          client.println("</html>");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disconnected");
  }
}

これで、WEBサーバーから操作ができましたね!

まとめ

無事2パターンの機能が実装できスマートコントローラーとして利用ができますね!これで、センサーの値によって自動で家電を制御したり、スマートフォンやPCから家電を制御することができるようになりました。今回光センサーを利用していますが、超音波センサーと組み合わせて人が通ると照明が点く、温度センサーと組み合わせて気温が高くなると扇風機が回る、といった機能を実装すると、よりスマートコントローラーとして面白い使い方ができると思います。

注意:スマートフォンでの操作や、自動で制御を行う場合は、暖房などの場合は火事などの事故を防ぐため必ず近くで実験を行ってください。

アバター画像

電子工作や新しいデバイスをこよなく愛するエンジニア。日常生活のちょっとしたことを電子工作で作って試して、おもしろく過ごしたいと日々考えています。

学生ロボコン2019出場ロボット解剖計画