Quantcast
Channel: はじめての電子工作超入門 – Device Plus –デバプラ
Viewing all 58 articles
Browse latest View live

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

$
0
0

前回は、SDカードの使い方を学びました。今回は、赤外線リモコン受信モジュールと赤外線LEDを利用し、赤外線リモコンを作成します。テレビやエアコンなどのリモコンの多くは、赤外線を使っています。このリモコン信号を解析し、Arduinoでリモコン信号を発信して家電を操作しましょう!

今回の電子工作レシピ

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

赤外線って何?

「赤外線通信」「赤外線カメラ」「遠赤外線ヒーター」などなど、「赤外線」というキーワードをよく目にすることがあると思いますが、この「赤外線」とは一体どのようなものでしょうか?wikipediaで調べてみます。

赤外線 – wikipedia

赤外線(せきがいせん)は、可視光線の赤色より波長が長く(周波数が低い)、電波より波長の短い電磁波のことである。ヒトの目では見ることができない光である。分光学などの分野で IR (infrared) と略称される。

電磁波を波長で分類すると下記の図のようになります。

図1 電磁波の帯域

図1 電磁波の帯域

赤外線通信の基本的なしくみ

では、この赤外線をどのように利用してリモコンなどの通信を行っているのでしょうか。

基本的には、赤外線LEDの点灯・消灯を切り替えて命令を送っています。

図2 リモコン信号の基本

図2 リモコン信号の基本

また、それらの切り替えのパターンは、家電などで利用されている赤外線リモコンの場合、一般的に定められた共通のフォーマットを利用している場合がほとんどです。代表的なフォーマットは下記の3種類で、国内のほとんどの家電の赤外線リモコンがこのフォーマットを採用しています。

代表的なフォーマット

  • NECフォーマット
  • 家製協フォーマット
  • SONYフォーマット
図3 NECフォーマットの概略図

図3 NECフォーマットの概略図

例えば、NECフォーマットでは、リモコンから命令を送る合図としてリーダー信号を発信します。その次に、データ信号を送り、最後にストップ信号を送るようなフォーマットになっています。基本的なフォーマットはこの3つのフォーマットを採用しています。リモコンのボタンを押し続けた場合や、信号を繰り返す場合の処理が違うなど、細かい取り決めが、各家電メーカーによってあります。実際に制作をする場合は、「学習リモコン」のように、既存のリモコン信号を直接読みとって解析をする必要です。

※詳しいフォーマットの解析に興味のある方は「赤外線リモコンコード」「赤外線 解析」などで検索すると色々なコードが見つかります。

リモコン信号の周波数について

赤外線は太陽や、照明などいたるところから発光されています。それらの光とリモコンの信号を見分ける工夫として、大抵の赤外線リモコンでは発光する周波数を38KHzと設定し、他の光と区別をしています。今回、利用する赤外線受信モジュールもこの38KHz対応のものを利用します。

Arduinoで赤外線を送受信してみる

では、Arduinoで赤外線を受信してみましょう。今回はテレビの受信部などにも使われる、赤外線リモコン受信モジュールSPS-440-1を使います。受信する周波数は38kHzで、必要な回路が内蔵されているためArduinoにそのまま接続できます。また、送信部には赤外線LEDを使います。

写真1 赤外線受信モジュール

写真1 赤外線受信モジュール

写真2 赤外線LED

写真2 赤外線LED

下記の図のように赤外線受信モジュールをArduinoに接続します。

図4 赤外線回路

図4 赤外線回路

写真3 赤外線受信モジュールとArduino

写真3 赤外線受信モジュールとArduino

次にプログラムです。今回赤外線の解析はGithubで公開されているIRライブラリを利用します。ソース一式は、右下のダウンロードボタンから取得できます。Githubを利用している場合は、通常の手順でソースを取得してください。ダウンロードしたソースは、メニューの「スケッチ」-「ライブラリを使用」-「Add Library」をクリックして、ダウンロードしたzipファイルを追加してください。再度「スケッチ」→「ライブラリを使用」を開いて、そこに「IRremote」が追加されていれば無事にライブラリの導入が完了です。うまくいかない方は、Arduinoのlibrariesディレクトリにzipを解凍したフォルダを移動してArduinoを再起動してください。

shirriff/Arduino-IRremote

https://github.com/shirriff/Arduino-IRremote

図5 右下のダウンロードからライブラリをダウンロード

図5 右下のダウンロードからライブラリをダウンロード

図6 ライブラリの追加

図6 ライブラリの追加

ライブラリを利用できるようになったのでプログラムを作成します。IRremoteライブラリには、サンプルプログラムが入っているので、それを利用して受信を試してみます。このプログラムでは、11番ピンに入力された赤外線信号を解析してフォーマットとデータ内容を表示するプログラムです。

プログラム:赤外線信号の解析

/*
* IRremote: IRrecvDump - dump details of IR codes with IRrecv
* An IR detector/demodulator must be connected to the input RECV_PIN.
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* http://arcfn.com
* JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
* LG added by Darryl Smith (based on the JVC protocol)
*/

#include <IRremote.h>

int RECV_PIN = 11;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
}

// Dumps out the decode_results structure.
// Call this after IRrecv::decode()
// void * to work around compiler issue
//void dump(void *v) {
// decode_results *results = (decode_results *)v
void dump(decode_results *results) {
int count = results->rawlen;
if (results->decode_type == UNKNOWN) {
Serial.print("Unknown encoding: ");
}
else if (results->decode_type == NEC) {
Serial.print("Decoded NEC: ");
}
else if (results->decode_type == SONY) {
Serial.print("Decoded SONY: ");
}
else if (results->decode_type == RC5) {
Serial.print("Decoded RC5: ");
}
else if (results->decode_type == RC6) {
Serial.print("Decoded RC6: ");
}
else if (results->decode_type == PANASONIC) { 
Serial.print("Decoded PANASONIC - Address: ");
Serial.print(results->panasonicAddress,HEX);
Serial.print(" Value: ");
}
else if (results->decode_type == LG) {
Serial.print("Decoded LG: ");
}
else if (results->decode_type == JVC) {
Serial.print("Decoded JVC: ");

}
else if (results->decode_type == AIWA_RC_T501) {
Serial.print("Decoded AIWA RC T501: ");
}
else if (results->decode_type == WHYNTER) {
Serial.print("Decoded Whynter: ");
}
Serial.print(results->value, HEX);
Serial.print(" (");
Serial.print(results->bits, DEC);
Serial.println(" bits)");
Serial.print("Raw (");
Serial.print(count, DEC);
Serial.print("): ");

for (int i = 0; i < count; i++) {
if ((i % 2) == 1) {
Serial.print(results->rawbuf[i]*USECPERTICK, DEC);
}
else {
Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC);
}
Serial.print(" ");
}
Serial.println("");
}

void loop() {
if (irrecv.decode(&results)) {
Serial.println(results.value, HEX);
dump(&results);
irrecv.resume(); // Receive the next value
}
}

プログラムをArduinoにアップロードした後、テレビなどのリモコンを赤外線受信モジュールに向かってボタンを押すと、シリアルモニタ上に信号データが表示されました。

図7 リモコンから出力された赤外線信号

図7 リモコンから出力された赤外線信号

では、次にリモコン信号の送信プログラムを試してみましょう。送信プログラムを利用するためには、ライブラリ側のソースに一手間加える必要があります。Arduinoの「libraries」-「IRremote」ディレクトリの中にあるIRremote.hを開いて、ソースの上部に青枠で囲った「#define 〜〜〜」を加えて上書き保存してください。これで、各種フォーマットに従った信号を送信できます。

図8 IRremote.hの編集

図8 IRremote.hの編集

IRremote.hの編集が完了しましたら、プログラムをArduinoに書き込みます。サンプルの例では、タクトスイッチを押した時にSonyフォーマットのテレビ電源ONの信号を3回発信するプログラムとなります。

プログラム 赤外線送信回路

 #include <IRremote.h>
IRsend irsend;
int sensorPin = A0;
void setup()
{
Serial.begin(9600);
}

void loop() {
int sensorValue = analogRead(sensorPin); 
//Serial.println(sensorValue);
if(sensorValue == 0){
for (int i = 0; i < 3; i++) {
irsend.sendSony(0xa90, 12); // Sonyフォーマットでテレビ電源ONの信号
delay(40);
}
}
}
図9 赤外線リモコン回路

図9 赤外線リモコン回路

写真4 赤外線送信回路

写真4 赤外線送信回路

実際にテレビに向けて信号を発信してみました(※ここではプログラムを少し変えて5秒おきに電源ON/OFFを繰り返す信号を送信しています)。

ArduinoからテレビのON/OFFができるようになりました!

まとめ

今回、赤外線受信モジュールと赤外線LEDを利用して、赤外線リモコン信号の送受信を試しました。次回は、赤外線信号と、温度センサや光センサなどのセンサを組み合わせて、家電を操作するスマートコントローラーを作成してみます。


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

$
0
0

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

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

今回の電子工作レシピ

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

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

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

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

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

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

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

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

写真2 照明リモコンとArduino

写真2 照明リモコンとArduino

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

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

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

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

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

#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 &gt; 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回を参照)


#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("<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");
}
}

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

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

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

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

#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から家電を制御することができるようになりました。今回光センサーを利用していますが、超音波センサーと組み合わせて人が通ると照明が点く、温度センサーと組み合わせて気温が高くなると扇風機が回る、といった機能を実装すると、よりスマートコントローラーとして面白い使い方ができると思います。

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

第25回 Arduinoでパーツやセンサーを使ってみよう~ソーラーパネルでArduinoを動かしてみる(前編)

$
0
0

P1190812

今回はちょっと趣向を変えて、Arduinoの電源を電池やUSBからの給電ではなく、自然エネルギーとして注目されているソーラーパネルを利用して動かしてみます。

どれくらいソーラーパネルが大きければArduinoが動くのか、継続的に安定して動かすにはどうすればよいのかなどを勉強しながら取り組んでみたいと思います。Arduinoで作ったガジェットがコンセントから遠かったり、PCにつなぎっぱなしにできない(したくない)場合にも、環境にもやさしいArduinoライフを送ることを目標に頑張ります!

今回の電子工作レシピ

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

Arduinoの動作電圧とソーラーパネルの電圧

Arduinoを動作させるために必要な電圧を供給する必要があることは第14回で触れました。今回利用するArduino Pro Mini互換機は3.3Vなので、ソーラーパネルからは安定して3.3Vを供給する必要があります。一方今回利用するソーラーパネルの仕様を確認すると、最大出力電力:300mW /  開放電圧:5.7V / 最大出力時電圧:4.5V / 短絡電流:74mA / 最大負荷時電流:65mAとあります。最大出力電力(300mW) = 最大出力時電圧(4.5V) × 最大負荷時電流(65mA)となっていますので、今回利用するArduino3.3Vに対してソーラーパネルの電圧(最大4.5V)が少し高くなってしまいます。電圧が高いままArduinoに電気を流し込むとArduinoを壊してしまう可能性があるので、電圧を制御する必要がありますね。

写真1.Arduino UNOとArduino Pro Mini互換機

写真1.Arduino UNO(5V)とArduino Pro Mini互換機(3.3V)

下の写真では、快晴時に電圧を測った結果(最大出力4.5Vが観測できています)と、屋内照明で電圧を測った結果(2.5V程度)です。晴れている日は問題ないですが、屋内照明の場合だと、Arduinoを動かすための3.3Vに届いていないため、ソーラーパネル1枚だと動かすことが難しそうです。ソーラーパネルを2枚直列でつなぐと、8.8~9V出力されましたので、天気が悪い日などを考慮するとArduinoを動かすのに2枚程度つなぐとよさそうですね。ちなみにソーラーパネルを並列で接続すると、電圧は変わりませんが、計測される電流の量が増えました(これは電池と同じしくみですね)。

図1.快晴時にソーラーパネルの電圧を測る

写真2.快晴時にソーラーパネルの電圧を測る

写真2.屋内照明下で電圧を測った結果

写真3.屋内照明下で電圧を測った結果

写真4.ソーラーパネルを2枚直列で接続

写真4.ソーラーパネルを2枚直列で接続

 

Arduinoにつなぐ前にソーラーパネルでLEDを光らせてみる

Arduinoにソーラーパネルをつなぐ前に、先にLEDをつなげて光らせてみましょう。今回利用した緑色LEDは準電圧が2.0Vなので、ソーラーパネルから2V以上計測できていればLEDが光ります。先ほどの屋内照明で計測した場合、約2.5Vあったので、ソーラーパネルをつないでみるとLEDが光ります。さらにこの状態で屋内照明に近づけたり、遠ざけたりすると明るさが変わりました。

写真4.ソーラーパネルにLEDを接続

写真5.ソーラーパネルにLEDを接続

 

図1.ソーラーパネルとLED回路

図1.ソーラーパネルとLED回路

ソーラーパネルが無事発電していることを確認できたので、Arduino側の準備をしていきます。

Arduinoに必要な電圧を用意する 3端子電圧レギュレータの使い方

太陽光の強さによって上下するソーラーパネルからの電圧をArduinoの3.3Vに安定的に流し込むために、3端子電圧レギュレータというものを今回使います。「3端子電圧レギュレータ」と文字でみるとなにやら難しそうな部品と思ってしまいますが、簡単に説明すると、入力された電圧がどんなものであろうと仕様に沿って一定の電圧を出力してくれる部品です。なので今回のような入力の電圧が安定していない場合などにもってこいの部品になります。

写真6.3端子電圧レギュレータ

写真6.3端子電圧レギュレータ

今回利用する3端子電圧レギュレータ(ROHM LDOレギュレータ – BA33DD0T)の仕様を確認すると、低損失用とあり、入力の電圧が3~4.0Vなどと低くても動作すると書かれています。また、入力電圧は最大25Vとありますので、ソーラーパネルを最大5枚(4.5V×5枚=22.5V)、直列につないでも利用ができますね。

LDOレギュレータ – BA33DD0T データシート
http://www.rohm.co.jp/web/japan/products/-/product/BA33DD0T

3端子電圧レギュレータの使い方は簡単です。3つある端子にはそれぞれIN / GND / OUTがありますので、INは入力側(ソーラーパネルの+端子)、OUTは出力側(ArduinoのVcc)に接続するだけでソーラーパネルから発電された電気が3端子電圧レギュレータを通じて、一定の電圧になってArduinoに送られます。

ただし、3端子電圧レギュレータを使うときに注意することがあります。3端子レギュレータはそのまま利用すると出力する電圧が波のように上下する「発振」状態となってしまいます。その発振を防ぐために、コンデンサを一緒に回路に組み込む必要があります。3端子電圧レギュレータを部品屋さんで買うとコンデンサもついてくることが多いです。回路は図3のようになります。コンデンサを2つ入れて発振を防ぎ、OUTから安定した電圧を取り出すことができます。

図2.3端子電圧レギュレータ

図2.3端子電圧レギュレータ

図3.3端子電圧レギュレータとコンデンサ

図3.3端子電圧レギュレータとコンデンサ

これで、Arduinoを動かす準備が整いました。

 

いざArduinoにつないで動作!

3端子電圧レギュレータの使い方がわかったところで、Arduinoに接続します。回路は下記のとおりです。今回ArduinoのプログラムはサンプルにあるBlinkなどの簡単なプログラムを使いました。屋内で起動させるには照明に近づけないと起動しないのがわかりますね。太陽のエネルギーの強さを実感します……。

 

図5.ソーラーパネルでArduinoを起動

図4.ソーラーパネルでArduinoを起動

写真7.ソーラーパネルでArduinoを起動

写真7.ソーラーパネルでArduinoが起動しました!

まとめ

今回はソーラーパネルを利用して、最小限の部品でArduinoを起動することができました。次回は、このソーラーパネル電源をもう少し追求して電池に充電して太陽が雲に隠れてしまったときも充電された電池から電力を補う仕組みを実装してみたいと思います。充電池やバッテリーへの充電が可能になれば、日中ためた電気で夜Arduinoを動かす、なんてことも可能になっちゃいます!

第26回 Arduinoでパーツやセンサーを使ってみよう~ソーラーパネルでArduinoを動かしてみる(中編)

$
0
0

P1190836

前回はソーラーパネルを使ってArduinoでLチカすることができました。晴れている日は問題なく動作することはわかりましたが、屋内照明や少しでも曇ってしまうとソーラーパネルからの電力が足りず、Arduinoを安定して動かすことができませんでしたね。今回は、ソーラーパネルからArduinoを安定的に動かすために、ソーラーパネルからの電力を充電をしながら動作させる方法を学んでみたいと思います。

今回の電子工作レシピ

時間目安:20分
必要なパーツ

そもそも、充電池ってなに?

私たちが普段何気なく使っている「電池」。乾電池、マンガン電池、アルカリ電池、充電池、蓄電池etc…いろいろな呼び名や種類の電池が思い浮かぶと思います。また、車やバイクなどに載っているバッテリー、これも電池なのでしょうか?

これら普段利用している電池の種類は、大まかに2種類に分けることができ、使い捨てタイプの「一次電池」(マンガン電池、アルカリ電池などが一般的)、充電して繰り返し利用できるのが「二次電池」(ニカド電池、ニッケル水素電池、リチウムイオン電池、鉛蓄電池などが一般的)と呼ばれます。(ちなみに車のバッテリーは一般的には鉛蓄電池になります)

今回、充電池に充電をしたいのですが、各種充電池の特性を確認してみます。

ニカド電池
  • 充電回数500回前後
  • 安定した放電(空になるまで安定した高出力)
  • メモリー効果を受けやすい
  • 自然放電が大きい
  • 低音でも電圧が下がらない
ニッケル水素電池
  • 充電回数500回前後
  • ニカド電池よりも大容量
  • 自然放電が少ない
リチウムイオン電池
  • 充電回数500回以上可能
  • 3つの中でもっとも大容量
  • 低温でも電圧が下がらない
  • 満充電状態で放置すると寿命が短くなる
  • 自己放電が少ない
  • 他の2つの電池(1.5V程度)に比べて電圧が高い(3.7V程度)

充電池といっても種類によってかなり違うんですね。

 

充電池に充電するには?

充電池にいろいろ種類があり、メリット・デメリットがあることがわかりました。では、充電池に充電するにはどうしたらよいのでしょうか?単純に考えると、電池に電力を流してあげれば良いのですが、調べてみると、充電池の電圧と同じ程度の電圧(単三充電池であれば1.5V程度)で電流を流してあげれば良いようです。電池は電力を使うと電圧が下がるので、電圧を水の高さに例えると、電圧の高いところ(充電器)から低いところ(充電池)に電流が流れていく、というイメージになりますね。さらに調べてみると、充電池を充電する際に、電圧が高すぎたり過充電状態(満充電からさらに充電しようとする)になると充電池に負荷がかかってしまい、液漏れや最悪の場合爆発するなど危険があるとでてきました。電池には「専用の充電器以外では充電しないでください」とも書かれています。ううむ、これはちょっと安易な考えでソーラーパネルから充電するのはやめたほうが良さそうですね。

また、充電池は種類やメーカーによって、充電のための仕様が違ったり、満充電状態を検出する方法が違ったりするので、ソーラーパネルから充電池に充電を試みるのは危険なため、手軽に充電することが難しいようです。

 

救世主、電気二重層コンデンサ。

いきなり壁にぶつかり困りました。充電池に充電をすることが難しいので他の方法を考えてみます。調べていると「電気二重層コンデンサ」というキーワードにたどり着きました。なんでしょう、この重厚で力強さを感じさせるキーワード(笑)。さらに調べてみると、「スーパーキャパシタ」「ウルトラキャパシタ」などとも呼ばれているようです。電気二重層というのはどういうことかわかりませんが、コンデンサというキーワードはよく見聞きしますね。

wikipediaで調べてみると…

電気二重層コンデンサ – wikipedia

電気二重層コンデンサ(でんきにじゅうそうコンデンサ、Electric double-layer capacitor、EDLC)は、電気二重層という物理現象を利用することで蓄電量が著しく高められたコンデンサ(キャパシタ)である。20世紀末から電気二重層キャパシタの開発が始まり、いくつかの分野で使用が始まっている。今後性能がさらに向上すれば一部のバッテリーを代替する可能性がある。 電気二重層キャパシタは陽極と陰極の2つの電極を持つが、この2つが二重層という名前の元となったわけではなく、両極それぞれの表面付近で起こる物理現象である「電気二重層」が元となっている。電気二重層キャパシタはウルトラ・キャパシタ(Ultracapacitor)やスーパー・キャパシタ(Supercapacitor)とも呼ばれる。

その中に「一部のバッテリーを代替する可能性がある」ということで、未来の充電池の代わりになるかもしれない、ということがわかりました。

簡単に電気二重層コンデンサの特徴を見てみると、

  • 短時間で充放電がおこなえる(電池に比べて内部抵抗が低いため)
  • 寿命が長い(充電・放電による劣化が少ない)
  • 自己放電の時間が早い
  • 充電・放電時の電圧変化が直線的
  • 電池に比べ低温でも動作可能

充電池をそっくりそのまま代用とはいかないかもしれませんが、これは期待が持てそうです。

 

 

あれ、そもそも、コンデンサって何?

よく見聞きするこの「コンデンサ」って何でしょう?前回も何気なく登場していますね。

写真1.真ん中と左側の部品がコンデンサ

写真1.真ん中と左側の部品がコンデンサ

 

再度wikipediaで調べてみると…

コンデンサ – wikipedia

コンデンサ(蓄電器、羅: condensare、独: Kondensator、英: capacitor キャパシタ)とは、静電容量(キャパシタンス)により電荷(電気エネルギー)を蓄えたり、放出したりする受動素子である。 静電容量の単位はF(ファラド)が使われる。通常使われるコンデンサは数pF – 数万μF程度であるが、電気二重層コンデンサなどでは数千Fオーバーの大容量な物もある。両端の端子に印加できる電圧(耐圧)は、2.5V – 10kV程度までさまざまである。

「静電容量(キャパシタンス)により電荷(電気エネルギー)を蓄えたり、放出したりする受動素子である。」とあります、これって充電池と同じ働きですよね!?基本的に充電池は異なる金属を電解溶液を通じて化学反応させてその中で電力を発生させるしくみですが、コンデンサは、2枚の金属の間に絶縁体を挟む構造で、その金属に電気を流すと電荷が蓄えられる(お互いの電荷が絶縁体を挟んで引き付け合う状態)というしくみになっています。コンデンサは化学反応で電荷を得る充電池と違い、電荷が最大までたまると電気が流れなくなるので、今回利用する電気二重層コンデンサでは充電する際も満充電の検出や過充電などの心配がないので手軽に扱うことができます。通常のコンデンサでは静電容量が極端に小さいことから交流電流を直流にする回路やノイズをカットする回路などで使われたりします。

 

図2.コンデンサのしくみ

図1.コンデンサのしくみ

コンデンサをもっと知るために、簡単な実験をしてみましょう。

 

コンデンサを作ってみる

2枚の金属の間に絶縁体を挟むのがコンデンサのしくみ、ということで適当な大きさのアルミホイルとラップを用意します。2枚の金属がくっつかないようにアルミホイルを挟んだ状態にします。

写真2.アルミホイルとラップ

写真2.アルミホイルとラップ

この状態で、電池のプラスマイナスをそれぞれのアルミホイルにつなげて電気を流したあと、電圧を測ってみると…

写真3.電池から電流を流したあと、電圧を測ってみると…

写真3.電池から電流を流したあと、電圧を測ってみると…

おお、0.036Vとなっていますが、わずかに電圧を持っていることがわかりました。金属同士の距離が近ければ近いほど、電荷の結びつきが強くなるとのことなので、2枚の金属にそれぞれ銅線をつなげたうえで2枚の金属が触れないように折りたたんでいきます。

写真4.自作コンデンサを折り畳んでいく

写真4.自作コンデンサを折り畳んでいく

折りたたんだ後、丸めていきます。

写真5.自作コンデンサを折りたたんでいく

写真5.自作コンデンサを丸めていきます

ある程度丸め終わったら、マスキングテープで固定して、万力などできちんと金属同士が近くなるようにつぶして圧縮します。

写真6.マスキングテープでぐるりと固定。

写真6.マスキングテープでぐるりと固定。

これで、自作コンデンサが完成しました。再度、自作コンデンサに電池から電気をためてみます。

ご注意ください!:電気をためる際は必ず電池1~4本程度を使って実験してください。家庭用のコンセントなどは危険なので絶対に使わないでください。

写真7.自作コンデンサに電気をためる

写真7.自作コンデンサに電気をためる

すぐに放電してしまいますが電気がたまっていることがわかりますね!実験を通してコンデンサのしくみがわかりました。

 

充電池と電気二重層コンデンサの違い

コンデンサのしくみを理解したところで、改めて充電池と電気二重層コンデンサの違いを整理してみます。

メリット デメリット
充電池
  • 充電容量が大きい
  • 価格が安価
  •  充電時間がかかる
  • 寿命が短い(500〜1,000回程度)
電気二重層コンデンサ
  • 短時間で充放電が行なえる
  • 寿命が長い(10万回〜)
  • 充電・放電時の電圧変化が直線的
  • 低温でも動作可能
  •  容量に対して値段が高い
  • 自己放電が早い

また、電気二重層コンデンサを使う場合、便利な点と注意点で下記の点が挙げられます。

  • 過充電の心配がない
  • 充電の際は電圧を一定にする
  • 充電の際には耐電圧を大きく超える電圧で充電しない

 

電気二重層コンデンサを使ってみる

今回使う電気二重層コンデンサは1F(ファラッド)、5.5Vのものを利用します。一般的に目にするコンデンサの単位はμF(マイクロファラッド)やnF(ナノファラッド)、pF(ピコファラッド)なので、その大きさがわかりますね。

1F = 1,000,000μF =  1,000,000,000nF = 1,000,000,000,000pF

先ほどの実験のように、コンデンサを電池から充電した後、LEDをつないで時間を測ってみます。単3電池4本だと6Vになってしまうので、これでも大丈夫ですがダイオードを2つ入れて電圧を5V程度に落とした状態で充電します。

写真8.電池から電気二重層コンデンサに充電

写真8.電池から電気二重層コンデンサに充電

写真9.充電後の電気二重層コンデンサ

写真9.充電後の電気二重層コンデンサ

 

電圧計で測りながらみていくとみるみる電圧が上がっていく様子がわかります。ある程度充電できていることがわかったので、実際にLEDをつけて試してみます。

写真10.LEDをつけてみるテスト

写真10.LEDをつけてみるテスト

無事光りましたね。LEDであればものの1分程度の充電でも数分は光っていました。

充電とLEDをスイッチをつけて交互に試せる回路にした場合は下記の通りとなります。

図3.電気二重層コンデンサの充電とLED点灯回路

図2.電気二重層コンデンサの充電とLED点灯回路

 

まとめ

電気二重層コンデンサは将来バッテリーの代わりになる可能性を秘めていることがわかりましたね。これを使って、次回はソーラーパネルからの電力を電気二重層コンデンサに貯めつつ、Arduinoを安定動作させるための実際の回路を作成していきたいと思います!

第27回 Arduinoでパーツやセンサーを使ってみよう~ソーラーパネルでArduinoを動かしてみる(後編)

$
0
0

P1190851

前回は、コンデンサのしくみを通じて、電気二重層コンデンサの充電方法について学びました。電気二重層コンデンサが短時間で充電が可能なことがわかりましたので、今回はその性質を利用してソーラーパネルで電力をためつつ、ソーラーパネルからの発電が弱まった際に電気二重層コンデンサから電力を供給してArduinoを安定的に動かしてみたいと思います。

今回の電子工作レシピ

時間目安:60分
必要なパーツ

電気二重層コンデンサの充電時間の計算

今回利用する電気二重層コンデンサは、25F、5.4Vを利用します。

写真1 25F、5.4Vの電気二重層コンデンサ

写真1 25F、5.4Vの電気二重層コンデンサ

これまでは1F、5.4Vでしたので、容量は約25倍ですね。LED一つ光らせるのであれば満充電状態であれば1時間以上光らせることができます。もちろん、充電もその分時間はかかってしまいますが、充電時間を簡単に計算してみましょう。

コンデンサの充電式:CV=It

  • C:静電容量(F=ファラド)
  • V:充電電圧(V=ボルト)
  • I:充電電流値(A=アンペア)
  • t:は充電時間(秒)

この式を元に、ソーラーパネルからの電圧を5V、電流を100mAと仮定して、充電時間を計算すると、

t = C × V ÷ I → t = 25F × 5V ÷ 0.1A

t = 1,250秒 = 約20分

となります。出力電流が500mAや1Aなどのソーラーパネルの場合、この2〜4分で充電が完了すると考えると、電気二重層コンデンサの充電時間がいかに短いかわかりますね。

 

ソーラーパネルから電気二重層コンデンサへの充電

さっそく、ソーラーパネルから電気二重層への充電回路を作成します。図1の左上の大きなコンデンサが電気二重層コンデンサとなります。この回路では、直列に接続された2枚のソーラーパネルから3端子電圧レギュレータ(5V)を通じて、5Vの定電圧を出力します。3端子電圧レギュレータから出力された電気は、電気二重層コンデンサとLEDに接続されています。

この時、実際の動作としては、3端子電圧レギュレータから出力された電気は、電流が流れやすい方(電圧が低い方)に流れていくので、空の状態の電気二重層コンデンサに流れていきます。その時電気二重層コンデンサは充電されていくので、徐々に電圧が上がっていきます。その状態がしばらく続いた後、電気二重層コンデンサよりもLEDへ流れる方が電圧の負荷が低ったタイミングで3端子電圧レギュレータからの出力はLEDに流れていき、LEDが光ります。ですので、電気二重層コンデンサを満充電に近い状態にしたい場合は、LEDの回路にかかる負荷電圧を約5.3〜5.4Vの間にすることで実現できますね。

 

図1 ソーラーパネルから電気2重層コンデンサへの充電回路

図1 ソーラーパネルから電気2重層コンデンサへの充電回路

写真2 ソーラーパネルと電気二十層コンデンサの充電回路

写真2 ソーラーパネルと電気二十層コンデンサの充電回路

 

Arduinoへの電力供給

次にArduinoへの電力供給部分に取り組みます。Arduino Pro Mini(3.3V)への入力電圧の推奨値は3.35V-12V(https://www.arduino.cc/en/Main/ArduinoBoardProMini)となっていますので、第25回で利用した3端子電圧レギュレーター(3.3V)でも問題なさそうですが、今回は5Vの3端子電圧レギュレーターを利用していますので、ArduinoのVccピンからはArduinoのモデルの電圧である3.3Vが供給されますが、RAWピンからは5Vの出力を得ることができるので、いろいろなパーツを使う際にも重宝しそうです。

この回路では、先ほどのLEDの代わりに出力先にArduinoのRAWピンを接続しています。こちらも同様に、最初は電気二重層コンデンサの負荷電圧が低いため、電気二重層コンデンサへ充電されますが、Arduinoの負荷電圧より電圧が高くなったタイミングで、Arduino側へ電流が流れ始めます。

また、ソーラーパネルからの電力が弱くなった場合は、電気二重層コンデンサの蓄えている電圧が上回り、電気二重層コンデンサからArduinoに電流が流れるようなしくみになっています。

 

図2 ソーラーパネルと電気二重層コンデンサのArduino回路

図2 ソーラーパネルと電気二重層コンデンサのArduino回路

写真3 ソーラーパネルと電気二十層コンデンサによるArduino動作回路

写真3 ソーラーパネルと電気二十層コンデンサによるArduino動作回路

 

いろいろな回路を試してみる!

ひとまずArduinoへの安定的な電源回路ができたので、いろいろな回路を動かしてみましょう。最初はLチカですね。9番ピンにLEDを接続して試します。

図3 充電回路でLチカ

図3 充電回路でLチカ

写真4 充電回路でLチカ

写真4 充電回路でLチカ

しっかり光ってますね!充電時間を計算した式を応用して、コンデンサにたまっている電力がどれくらいの時間でなくなるのか知るためにも、テスターを利用して消費電流を調べてみます。LEDがオフの時はArduinoだけの消費電流が約7mA、LEDがついた場合は12mAでしたので、ざっと計算しても2、3時間くらいは動きますね。実際に動かしてみると思った以上に役目を果たしてくれそうです!

次はサーボモータを動かしてみます。モーターは比較的消費電力の大きなパーツなので、どれくらい動くか心配です……。

Untitled vol27_04_ブレッドボード

図4 充電回路でサーボモータを動かす

写真5 充電回路でサーボモータを動かす

写真5 充電回路でサーボモータを動かす

サーボモータが動いている時の消費電流は約140mAでした。これであれば、常に稼働した場合も10分程度は動かすことができるので、蓄えた電気を使って、サーボモータを使ってスイッチを押したりするなどの利用もできそうですね。

 

まとめ

ソーラーパネルから電気二重層コンデンサに充電を行い、ソーラーパネルからの電力が弱くなったら充電電力を使ってArduinoを動作させる回路ができました。効率的に電力を充電する・利用するにはもっと回路を改良する必要がありますが、手軽に扱うことができるので、いろいろな応用にも生かせそうです。

今回、この充電回路を用いて、第22回に作成した植物監視水やりマシンを改良してみました。この水やりマシンは植物を陽に当てる関係上、窓辺に置きたかったのですが、コンセントを延長するのが美しくなかったので、今回の回路を組み入れることでArduinoと植物を単独で動作させることができました。

写真6 水やりマシン弐号機

写真6 水やりマシン弐号機

上記の例に限らず、これまで作成した回路をソーラーパネルと電気二重層コンデンサを使って電池やコンセントを必要とせずにArduinoを動かすことができますので、ぜひ挑戦してみてください。

番外編① XOceanを使ってみた〜ArduinoとEnOceanを使用した温湿度表示

$
0
0

みなさん、はじめまして。新米ライターの小西と申します。私、組み込み系の知識はあるものの電子工作の経験が浅いのですが、Makersブームの波にのって電子工作にチャレンジしたいと思います!

新米ライター小西

 
というのも、先日、上司に「君にEnOceanを扱えるかな……?フッフッフ」とバカにされちゃったのです。

上司

「な、なんだ!EnOceanって!汗」と思いつつも、彼にギャフンと言わせるべく、そして最後には「Good Job!」が聞きたい、という不純な動機で、この「超入門」の場をお借りして、記事を書き始めたのであります……。

そもそもEnOcean通信って、なんだろう……

http://www.enocean.com/jp/home/
http://www.rohm.co.jp/web/japan/enocean

EnOcean通信とは、エナジーハーベスト(環境発電)と無線通信が組み合わされた技術だそうです。スイッチを押す力を電気エネルギーに変換したり、室内照明の光を電気エネルギーに変換して、その電力をセンシングや無線通信に使うのだそうです。要するに、発電機構を内蔵した、無線センサなのですね。自分で発電して動くので、電池交換が不要。すなわち、一度置いたらほったらかしにしても良いということです。おもしろい技術ですね。

ググってみると、いろんな製品があります。

01

温度センサと湿度センサが環境測定としてはわかりやすそう。組み込みケースも用意されているのですね。これなら実際に設置も可能です。

というわけで、みなさんもお馴染みのArduinoと、ニューカマーのEnOceanで、温湿度センサを2回に渡って作ってみましょう。

今回はセンサ情報の収集をやってみたいと思います。

今回の電子工作レシピ

完成までの時間目安:120分 難易度:(★★★★☆)
必要なパーツ

さっそくコアスタッフで温湿度センサを買ってみました。
ケースに入った状態手に入れましたが、温湿度センサがどういった構成になっているか確認しましょう。中身の大きさは5cmくらい。意外と小さい印象。

02

温度センサモジュールと、湿度センサを接続します。
コネクタを合わせてあるので、ブスっと挿すだけで簡単に接続できます。

03

次にケースに組み込んでみました。これも、簡単に組めました。
意外とコンパクトで、存在感なくセンサが置けそうな気がします。

04

センサは、送信側になるので、受信側も準備が必要なのですね。Gateway開発KITのようなKITも出ているようですが、今回はArduinoを使います。

色々とネットで探していると、EnOceanが乗っている新しいモジュールが出るみたいです。それが題名にもある「XOcean」という、EnOcean通信モジュールです。こちらは2015年7月末よりコアスタッフで販売開始しているようなので、さっそくできたてホヤホヤを入手しちゃいました。(XOcean世界最速レポートなるか?)

06XOcean

XBee®コネクタにそのまま挿せるタイプなのですね。
黄色い配線は、アンテナか。TELECマークもついているので、電波法も問題なし、と。
持っていたArduino基盤に、XBeeコネクタがついていなかったので(汗)、まずはXBeeシールドに接続します。XBeeシールドのシルクに合わせて接続すれば良いようです。

07

続いてXBeeシールドをArduinoに接続しました。こちらもピンをArduinoのシールド用コネクタに合わせて接続するだけです。

09Arduino+XOcean

さらに同じようにLCDシールドを接続します。

10Arduino+XOcean+LCDシールド

これで、ハードウェアはそろいました!非常に簡単で、作業時間は5分もかかりませんでした。

それでは、さっそくソフトウェアの開発に移りましょう。いきなりLCDシールドまで接続して動作させようと思うとやることが多すぎて大変なので、ArduinoとXOceanでPCのディスプレイ上に温湿度センサのデータ表示をしましょう。一歩ずつ着実に……。

さて、EnOcean通信が電池不要で動くのはわかりましたが、実際どのようなデータが送られているかわからないので規格やプロファイルを調べました。

EnOceanの無線通信とシリアル通信規格、機器情報プロファイル

無線通信とシリアル通信の規格および機器情報プロファイルが決められています。
センサも色々あるので、無線データの配列を決めておかないと、無意味なデータになってしまいます。また、データ配列をいちいち覚えてられないので、機器情報も決められているのですねー。(EnOcean通信に限らず、無線としては、当たり前か…)

13EnOceanのエネルギーハーベスティング無線センサソリューション(EnOceanホームページより、一部追記)

無線通信はEnOcean Radio Protocol(ERP)、シリアル通信はEnOcean Serial Protocol(ESP)、機器情報プロファイルはEnOcean Equipment Profile(EEP)という名称で規定されていて以下URLからドキュメントをダウンロードできます。

ERP:http://www.enocean.com/erp2/
ESP:http://www.enocean.com/esp
EEP:http://www.enocean-alliance.org/eep/

ArduinoとXOceanはシリアル接続となるのでESP3の内容がわかればArduinoでEnOcean製品のセンサ情報が取得できますね。

XOceanのデータを受信する

XOceanはArduinoの1,2番ピンと接続されているようなので、Arduinoのハードウェアシリアルを使ってXOceanのデータを受信しました。

void setup() {
    Serial.begin(57600); // 57600bps-EnOcean Serial Protocol 3
}

ハードウェアシリアルのボーレート変更

EnOceanの製品はUARTというシリアル通信で接続されるみたいなので、このようにボーレートをEnOceanの製品に合わせ込みます。ボーレートの合わせ込みができればデータを受信できるようになりそうです。
それでは受信したデータを確認してみましょう。受信したデータをそのままArduino IDEのシリアルモニタ上に表示させています。

void loop()
{
  unsigned char dataReceive = 0 ;  //受信確認フラグ
  unsigned char aChar = 0 ;        //データ格納用変数
  char buf[1] ;

  while(Serial.available()>0){    // XOcean受信したか?
   delay(5);
   aChar = Serial.read(); // シリアルデータ取得
// シリアルモニタ出力
    sprintf(buf, "%02X", aChar);
    Serial.print(buf);
    Serial.print("  ");
    dataReceive = 1 ;
  }
  if(dataReceive ==1){
    Serial.println("");
  }

受信したデータを変数であるaCharに格納し、取得したデータを16進数の文字列としてArduino IDEのシリアルモニタを使ってディスプレイ上に出力させました。ちなみにArduinoのIDEのシリアルモニタはメニューバーの「ツール > シリアルモニタ」を選択して立ち上げることができます。

14シリアルモニタの立ち上げ

シリアルモニタを立ち上げた際、画面右下にあるボーレートを57600bpsへ変更するのを忘れずに!最初変な文字が出てきて焦りました…

15

ボーレートを変更してEnOceanからデータが送られてきました。

16EnOceanシリアルデータの表示

こんな感じでEnOceanの製品からデータが送られてきてるんですね。データが受信できただけでなんとなく出来た感がでます。うれしいです。

データ解釈~ESP3編

ただし、このままではただの文字列なのでどこにどんなデータが入っているかわかりません。文字列の解釈をするため、ESP3のドキュメントを読み解きます。

ESP3のシリアル信号(ドキュメントのP.13)、EnOceanのシリアル信号は一つのかたまりで「パケット」と呼ばれているようで構造は下の図のようになっています。

17ESP3のパケット構造

この図を読み解くと、主に“Header”、“Data”、“Optional Data”という3つの要素で構成されているようです。それでは先ほどのデータを当てはめてみましょう。

18

このようにHeaderとDataとOption Dataの切り分けができました。
パケットタイプとデータを確認することでセンサの情報を取得することができます。
温湿度センサが送信するデータはパケットタイプが0x0A→10なのでパケットタイプ10を見てみましょう。

19Packet type10(RADIO_ERP2) ESP3ドキュメントのP.73

20

Option DataはTelegram NumberとRSSIであることがわかりました。欲しいデータは温度と湿度の情報なので今はそれほど必要ではないですね。肝心のデータについてはERPに従うようです。次はERPのドキュメントを確認しましょう。

データ解析~ERP2編

ERP2のドキュメントを読み進めていきますと、データ構造について書かれているページがありました。

21ERPのデータ構造(ERPドキュメントのP.16)

図の内容を確認していくと温湿度センサは送信元IDが4バイト、信号の種類が4BS(4バイトのテレグラム)といった内容がわかりました。シリアル通信のようにこちらもデータを割り当ててみます。

22

4バイトのデータ(4BS)の中に温度と湿度の情報が入っています。4バイトのデータのうち、どの部分に入っているかはEEPのドキュメントと照らし合わせる事が必要です。この温湿度センサのEEPは製品を購入したコアスタッフさんより”A5-04-01”と伺ったので、該当部分を確認します。

データ解析~EEP編

EEPのドキュメントを確認して”A5-04-01”のプロファイルを確認しましょう。

23EEP “A5-04-01”

この図に従って取得したデータを温度、湿度の値に変換します。

00 : Not use
78 : 湿度  123(0x7B) × (100-0)/(250-0) = 49.20 %
A2 : 温度  159(0x9F) × (40-0)/(250-0) = 25.44 ℃
0A : Data Telegram ,Temperature sensor available

これで無事温湿度センサのデータ内容が把握できました!
あとはこの解析した内容をプログラムにするだけです。
ポイントは温湿度データを取得したいので、EnOceanから送られてくるデータの順番を把握してどのデータなのかを確認しています。

#define TEMPID  0x0040179BD          // EnOceanモジュールID
#define SYNC    0x55                 // SYNCバイト

void setup()
{
  //Pin 0/1
  Serial.begin(57600);              // 57600-EnOcean Serial Protocol 3
  Serial.println("Working");
}

void loop()
{
  unsigned char   dataReceive = 0 ;  //受信確認フラグ
  unsigned char   aChar = 0 ;        //データ格納用変数
  unsigned char   pos = 0 ;          //ESPデータ位置
  unsigned long   senderID = 0 ;     //温湿度モジュールのID
  unsigned short  dataLength = 0 ;   //データ長
  unsigned char   optLength = 0 ;    //オプションデータ長
  unsigned char   packettype = 0 ;    //パケットタイプ
  float Temp = 0 ;                 //温度データ
  float Hum = 0 ;                  //湿度データ
  char buf[1] ;

  while(Serial.available()>0){    // XOcean受信したか?
    aChar = Serial.read();
    switch(pos){
      case(0):
      if( SYNC == aChar){          // SYNCバイトだったら受信開始
        delay(5);
        pos++;                     // pos移動 SYNC -> dataLength
        dataReceive = 1 ;
      }
      break;
      case(1):
      dataLength = 0x00FF & aChar ;  // dataLength 上位1バイトです。
      pos++;                        // pos移動 dataLength -> dataLength
      break;
      case(2):
      dataLength = (dataLength<<8) + aChar ; // dataLength 下位1バイトです。
      pos++ ;                                // pos移動 dataLength -> optLength
      break;
      case(3):
      optLength = aChar ;          //  optionLength
      pos++ ;                      // pos移動 optLength -> packet type
      break;
      case(4):
      packettype = aChar ;        //   packettype
      pos++;                      // pos移動  packet type -> crc
      break;
      case(5):
      pos++;                      // pos移動 crc -> header
      break;
      case(6):
      pos++;                      // pos移動  header -> ID1
      break;
      case(7):
      senderID =  0x0000FF & aChar ;  // ID1バイト
      pos++;                      // pos移動  ID1 -> ID2
      break;
      case(8):
      case(9):
      case(10):
      senderID =  (senderID<<8) + aChar ;  // ID2-4バイト
      pos++;                      // pos移動  ID2 -> ID4 -> data1
      break;
      case(11):
      pos++;                      // pos移動  data1 -> data2
      break;
      case(12):
      Hum = (float)aChar * 100/250 ;    //  humdata
      pos++;                      // pos移動  data2(hum) -> data3(temp)
      break;
      case(13):
      Temp = (float)aChar * 40/250 ;    //  Tempdata
      pos++;
      break;
    default:
      break;
    }  

  }
  if(dataReceive ==1){
    if(TEMPID == senderID ){
      Serial.print("Temperature = ");
      Serial.print(Temp ,  2);
      Serial.println( " (deg)");
      Serial.print("Humidity = ");
      Serial.print(Hum ,  2);
      Serial.println( " (%)");
      Serial.println("");
    }
    dataReceive = 0 ;
  }

}

posという変数で位置を確認し、EnOceanから送られてくるデータを取得してみました。また、受信した後、モジュールが持っているIDの値と比較し、一致していたら値を表示させています。これで例え同じようなセンサがたくさんあっても確認したいセンサのみの情報を取ることができますね。いずれ来るEnOcean時代(?)のために対策しました。

11

 
 
これで前半戦が終了です。
ふう……これまでのArduinoの連載よりかなりの上級編と感じたのですが、「これも上司をギャフンと言わせるためだ」と自分に鞭を打ちつつなんとかデータ内容の把握/表示までやってやりました。

新米ライター小西

次回はここにLCDシールドを接続し、機器として自立した、「Arduino×EnOcean」で電池不要の温湿度センサモニタ機器を作っちゃいます!

第28回Arduino互換ボードのラズライト(Lazurite)で省電力を実現!

$
0
0

P1190888

前回まで続いたパーツやセンサーを使ってみようシリーズを一旦お休みして、今回からまたちょっと違った内容をお届けします!ということで、今回は、上の写真の製品をご紹介。何やらArduinoのような、でもちょっと違うような風貌……気づいたそこのあなたは勘が鋭い、そうです!この製品はArduinoではなく、ラピスセミコンダクタ社が販売するArduino互換のLazurite(ラズライト)と言います。

このラズライト、なんでもArduinoに比べてものすごく省電力で動作するという噂。今回は、デバプラ編集部に届いたこのラズライトをさっそく使ってみたいと思います!!

今回の電子工作レシピ

時間目安:60分
必要なパーツ

ラズライトってどんな特徴を持ってるの?

まず、ラズライトがどんな製品でどのような特徴を持っているのか、公式ウェブサイトをみて調べてみます。

写真1.Lazurite Basic / Sub-GHzウェブサイト

写真1.Lazurite Basic / Sub-GHzウェブサイト

「かんたんに使える♪」というキーワードが安心しますね、ロゴの下にあるようにArduino互換のラズライトは省電力が特徴のLazurite Basic(ラズライトベーシック)と、それに920MHz無線に対応したモジュールを加えたLazurite Sub GHz(ラズライト サブギガヘルス)の2種類あるのですね。それに加えて、ラズベリーパイ向けの無線通信モジュールの「Lazurite Pi Gateway」もあるとのことです。

  • Lazurite Basic (ラズライトベーシック) – 省電力が特徴!
  • Lazurite Sub GHz (ラズライト サブギガヘルツ) – Basicに無線モジュールが搭載!
  • Lazurite Pi Gateway (ラズライト パイ ゲートウェイ) – ラズベリーパイ用無線モジュール

ウェブサイトをさらに見てみるとわかりやすく4つの特徴が書かれていました。

写真2.ラズライトの特徴

写真2.ラズライトの特徴

1. すぐにプログラム開発できる

本当にこれは重要なことですね。Arduinoがここまで流行ったのも、今となっては当たり前の感覚ですが、PCにつないですぐ電子工作をはじめることができる、というのがとても重要なことでした。ラズライトでは専用のIDEがあってそれを利用するようですね。

2. すぐに無線通信できる

無線モジュールが搭載されているLazurite Sub GHzの製品では、手軽に無線通信が利用できるようです。今回編集部に届いたのはLazurite Basicの方でしたので、今後こちらを利用して無線通信も是非トライしてみたいと思います!

3. すぐに動作確認できる

これも1と同様に非常に大事なことですね。回路は作ったけどどうやってプログラムを書いたらいいかわからない、なんて問題も、サンプルプログラムが豊富だとそれを見ながら学んでいけますね。

4. オープンソース

Arduino自体もオープンソースですが、このラズライトもオープンソース。Arduinoではオープンソースの恩恵を受けて世界中の人が改良を続けていますので、ラズライトもどんどん発展的な展開になっていくのを期待したいですね。

 

さっそくラズライトを使ってみる

ラズライトの概要は把握できたので、さっそくラズライトを動かしてみたいと思います。今回デバプラ編集部に届いたのは省電力が特徴のLazurite Basic。箱を開封して中身を取り出してみます。

写真3.ラズライト開封の儀

写真3.ラズライト開封の儀

開封すると、本体とマニュアルが入っていました。本体はArduinoよりもややエメラルドグリーンに近い青色で、まさに鉱石のラズライトのような輝きを放っています。

ロゴもダイヤモンドでカッコイイですね!ちょっと調べてみると鉱石のラズライトの日本語名が「青金石(せいきんいし)」と言ってラピスラズリの主成分の鉱石とのことらしいです(さらに調べると、青金石 – Lazu”r”iteとLaz”l”ite – 天藍石の2種類があるようですが、カタカナだと同名で区別できないようです(笑))。

 

写真4.ロゴはダイヤモンド

写真4.ロゴはダイヤモンド

 

必要なソフトウエアの準備〜Lazurite IDEをインストール

準備を進めていきます。マニュアルに書かれているリンク先(http://www.lapis-semi.com/lazurite-jp/download.html)から表示されるページの上から2番目にある「Lazurite IDE」インストーラをダウンロードしてインストールします。

写真5.IDEのダウンロード

写真5.IDEのダウンロード

Lazurite IDEを使ってラズライトを動かしてみる

インストールが終わったらさっそくLazurite IDEを立ち上げてみます。新しいマイコンを手に入れたらやることは一つ!Lチカをしてみます。

図1.Lazurite IDEの全体画面

図1.Lazurite IDEの全体画面

Lazurite IDEは基本的にArduino IDEとほぼ同じ感覚で利用できますが、エディタ機能はついていないため、基本的にはメモ帳などをはじめとする皆さんが使い慣れたエディタでプログラムを作成して、拡張子を「.c」などで保存→Lazurite IDEから開いて利用する形となります。Arduino IDEでプログラムを書いている方としては、今後のバージョンアップでエディタ機能の搭載に期待ですね。他、各ボタンを確認すると、左からビルド(Arduinoだと検証)、マイコンに転送、マイコンをリセット、クリーン、開く、シリアルモニタとなっています。主に利用するのは、プログラムを開いてビルド→マイコンに転送、必要に応じて動作を確認するのにシリアルモニタを利用する、という感じでしょうか。

図2.Lazruite IDEのボタン

図2.Lazruite IDEのボタン

サンプルも用意されていますので、今回はサンプルのblue_ledを選択します。

図3.サンプルからblue_ledでLチカ

図3.サンプルからblue_ledでLチカ

ちなみに、Lチカのプログラムは下記になります(見やすくするためコメントは一部除いています)。プログラムを見ていただいてもわかるように、基本的にArduino互換なので書き方は同じようにかけるみたいですね。

#define BLUE_LED 26

void setup(void)
{
digitalWrite(BLUE_LED,HIGH);
pinMode(BLUE_LED,OUTPUT);
}

// Arduino loop sequence
void loop(void)
{
digitalWrite(BLUE_LED,HIGH);
delay(1000);
digitalWrite(BLUE_LED,LOW);
delay(1000);
}

 

最後に利用するシリアル通信ポートを接続しているラズライトのものに設定します。

 

図4.通信ポートの設定

図4.通信ポートの設定

 

準備が整ったので、ビルドボタンを押したのち、マイコンボードに転送ボタンを押して、マイコンに書き込んでみます。書き込みが終わった後、無事にラズライトのLEDがチカチカ光ればOK!

写真6.26番のLEDがチカチカ光っています

写真6.26番のLEDがチカチカ光っています

これでラズライトの使い方のおおよそがわかりました。

 

どれくらい省電力なのか?

使い方がわかったところで、実際にArduinoと比べてどれくらい省電力なのか計ってみます。

今回のLazurite BasicとArduino UNOの仕様の比較表が、公式サイトダウンロードページ内のLazurite Sub-GHz/Lazurite Pi Gatewayの使い方 (PDF)として掲載されていました(図6)。まずはそれを確認してみると……、消費電流がラズライトが10mA、Arduino UNOが20mAとでています。2倍違うようですね。スタンバイ中であれば2mAなので、それだと10倍違うことになりますね。

このPDFによれば、ラズライトの場合、動作中でもLEDをつけていないなど主だった命令がないときは、スタンバイモードとしてラズライトのみを最小限の電力で動かすしくみになっており、それで省電力を可能としているようです。

 

図6.Lazurite BasicとArduino UNOの比較表

図6.Lazurite BasicとArduino UNOの比較表

先ほどのLチカのプログラムで消費電流がどれくらい違うのか試してみます。電池駆動にして、Lazurite BasicとArduino UNOそれぞれに電力を供給する箇所の消費電流を計ってみたところ、Arduino UNOは消灯時54mA程度、点灯時60mA程度に対して、Lazurite Basicはなんと消灯時0.7mA程度、点灯時わずか2mA程度という驚愕の結果が出ました(笑)

Lazurite BasicのLチカ時の消費電流

Arduino UNOのLチカ時の消費電流

動作中は0.7mA程度なので、仕様表にかかれている2mAよりも省電力ですね!今回のLチカ、単純にずっとLEDを光らせて通常2mAの消費電流だと考えると、例えば2,000mAhのスマートフォン用モバイルバッテリーを使うと、大雑把にいうと1,000時間(約41日)動作させることができてしまうくらい省電力なんですね。

 

まとめ

今回ご紹介したラズライト、Arduino互換で使いやすいことはもちろん、これだけ省電力であれば、これまで電源問題に苦しんでいた方も、電池駆動や前回ご紹介したソーラーパネルと組み合わせて何か面白いものが作れるかも!?と、いうことで、次回はこれまでに何回か出てきている水やりマシンを再度登場させて「ラズライトで水やりマシンをスタンドアロンで稼働させてみる」を目標に取り組んでみたいと思います。これまでの水やりマシンは、ソーラーパネルの枚数が多く必要だったりする問題があったのですが、今回のラズライトを利用することでこれらの問題が一気に解決できそうな予感です!

※ラズライトの使い方などに関しては、公式ウェブサイトにたくさんの情報が掲載されています。本記事内でも紹介したラズライト公式ウェブサイトのダウンロードページの中にある「オープンワイヤレスによるモノづくり無料セミナー 配布資料」という箇所に、ラズライトの丁寧な使い方や解説が掲載されているので、そちらも参考にしてみてください。

第29回Arduino互換ボードのラズライト(Lazurite)でスタンドアローン水やりマシン!

$
0
0

P1190956

前回、Lazuriteの省電力っぷりに驚きましたが、今回はその特徴を活かしてスタンドアローンで動く水やりマシンを作ってみます!これまで制作物のケースはバルサ材などの木材や、LEGOなどを使っていましたが、今回はちょっと背伸びをして3Dプリンターでケースも作ってみました。その過程を、写真を多めでお送りいたします!

なお、水やりマシンの基本的なしくみや回路については第22回で紹介していますので、そちらも併せてご覧ください!

今回の電子工作レシピ

時間目安:60分
必要なパーツ

ケースをモデリングして3Dプリンターで出力!

まずはケースを作成します。水やりの対象となる植物に合わせて、ケースをデザインしていきます。ケースのモデリングで利用したソフトウェアはAutodesk社の「123D Design」です。Windows / Mac両方で利用できる無料の3Dのモデリングソフトウェアです。たまに「CAD – computer aided design」(キャド)という言葉を聞いたことがあるかもしれませんが、そのCADソフトウェアに分類されるのがこの123D Designです。

3Dプリンターのモデリングソフトウェアとしては、わかりやすく使いやすいので入門としてはお勧めのソフトウェアです。

図1.製作途中の水やりマシンのケース(上側)

図1.製作途中の水やりマシンのケース(上側)

 

図2.製作途中の水やりマシンのケース(下側)

図2.製作途中の水やりマシンのケース(下側)

モデリングが完了したら、実際に印刷していきます。今回ケースは、13cm×5cm×10cm程度のサイズで、3Dプリンターで大体一日かからないくらいの時間で出力できました。3Dプリンターは一回起動させてしまうと、止められないので、ケースのモデリングの構想や実際の作成に少し時間をかけて考えて設計するのがお勧めです。実際、3Dプリンターに慣れていないと、せっかくきれいに出力できても、構造がおかしかったりプリントをやり直さなければいけなくなるので設計はしっかりしましょう(筆者はこの形にたどり着くまで4回くらい失敗しました…)。

下記写真1が実際にモデリングしたデータを3Dプリンターで出力したものになります。

 

写真2.3Dプリンターで出力されたケース部品

写真1.3Dプリンターで出力されたケース部品

今回、水の供給部分のパーツに、サーボモーターではなく小型ポンプを使います。底のケースに水を入れて、必要に応じてポンプで植物に水をあげる仕組みにしました。ケースの上部にある穴を通じてポンプにつけたホースを出しています。(3Dプリンターの出力したそのままでは水漏れがしてしまったので、ちょっとかっこ悪いですが食品用ラップでカバーしています)

写真2.ポンプによる水の供給部分

写真2.ポンプによる水の供給部分

ケースの上部は、スタンドアローンで動作する水やりマシンなので、電力の供給源になる電気二重層コンデンサ(スーパーキャパシタ)の格納場所も用意してみました。

写真3.電気二重層コンデンサ(スーパーキャパシタ)格納場所

写真3.電気二重層コンデンサ(スーパーキャパシタ)格納場所

電気二重層コンデンサ(スーパーキャパシタ)の上に、ラズライトを設置します。このぴったりはまる感じが3Dプリンターで作成した場合に感じることのできる喜びですね。

写真4.スーパーキャパシタの上にラズライトを設置

写真4.電気二重層コンデンサ(スーパーキャパシタ)の上にラズライトを設置

今回のケースは、ラズライトの基板と植物が隣り合わせになるようなデザインにしてみました。もっと実用的なケースを、と最初考えたのですが、電子回路と植物を一緒に眺めながるのもすてきだな、と思い、このようなケースにしてみました。

写真5.ラズライトの基板と植物が隣り合わせ

写真5.ラズライトの基板と植物が隣り合わせ

 

回路を組み立てる

さて、出力したケースにラズライトがきちんと収まったので、回路を作成していきます。まず電源部分として、第27回で取り組んだソーラーパネルを使ってラズライトを動かしてみます。前回ラズライトがArduino UNOよりかなりの省電力で動くことがわかりましたので、ソーラーパネルの枚数も少なくても大丈夫です。ただし、利用しているソーラーパネル1枚あたりの最大出力電圧が約5Vなので、晴天など出ない場合、電圧が足りなくてラズライトが起動しない場合が多くなってしまうので、最初4枚でテストを始めて、最終的にソーラーパネルを2枚直列につなぎ、電圧を確保した上で、3端子電圧レギュレーターで5Vにすることにしました。

 

写真6.ソーラーパネルでラズライトの動作チェック

写真6.ソーラーパネルでラズライトの動作チェック

回路図は下記になります。(fritzingの関係上、基板がArduinoUNOになっていますが、ラズライトに置き換えて読んでください)

図2.ラズライトの電源回路

図2.ラズライトの電源回路

回路図が決まったら、久しぶりにシールド化に挑戦してみます。今回はArduinoのプロトシールド基板のみはこちら)を使ってパーツをハンダ付けします。

写真8.Arduinoプロトシールド

写真7.Arduinoプロトシールド

先ほどの回路図を見ながら、パーツをハンダ付けしていきます。

写真8.プロトシールド基板にハンダ付け

写真8.プロトシールド基板にハンダ付け

 

写真9.ソーラーパネルの取り付けが完了

写真9.ソーラーパネルの取り付けが完了

ハンダ付けが完了したら、正常に動作するか確認します。ここで、うまく動かない場合、ハンダ付けが失敗している可能性があるのでハンダ吸い取り器やハンダ吸い取り線などを使って、ハンダ付けをやり直しする必要があります。

写真10.ソーラーパネルでの起動テスト

写真10.ソーラーパネルでの起動テスト

ソーラーパネルでの起動確認ができたので、残りのパーツをつけていきます。電気二重層コンデンサ(スーパーキャパシタ)とポンプ、そして土壌センサーをつけます。今回も水やりマシンを少し改良して、水の供給をサーボモーターではなく小型ポンプに、土の水分を測るのには釘ではなく、土壌センサーを利用しています。この土壌センサーは基本的に、アナログ・デジタルどちらでも数値を受け取ることができるセンサーです。今回はこれまで利用していた釘と同じようにアナログで数値を受け取るようにしました。

写真11.回路部分を組み立て

写真11.回路部分を組み立て

 

図3.水やりマシン回路全体図

図3.水やりマシン回路全体図

 

ケースに回路を格納して完成!

回路部分ができたら、ケースに残りのパーツを配置していきます。ケースには、上部にソーラーパネルを挟み込む隙間を用意して、ソーラーパネルを斜めに配置できるデザインにしました。

写真12.シールドとソーラーパネルを設置

写真12.シールドとソーラーパネルを設置

土壌センサーをつけて、完成です!

写真13.Lazurite水やりマシン完成

写真13.ラズライト水やりマシン完成

 

まとめ

ラズライトを使って水やりマシンが完成しました!今回はデスクサイドに置けるような小ぶりなケースにしましたが、すでにある鉢に取り付けられるケースにしてみたり、これまでのようにサーボモーター方式で給水するタイプにしてみたりと、いろいろな水やりマシンができますので、ぜひ挑戦してみてください。また、ソーラーパネルも、もっと発電能力の高いものに変えたり、電気二重層コンデンサ(スーパーキャパシタ)を大きいものに変えれば、さらなる安定稼動ができます。

今回、水やりマシンのケースを3Dプリンターで出力したのですが、せっかくなので、ラズライトBasic専用のケースもモデリングして出力してみました!これで、今後は基板そのままむき出しで開発しなくてすみそうです。

写真14.Lazurite Basicケース

写真14.Lazurite Basicケース

 

写真14.Lazurite Basicケースのモデリング画面

写真14.Lazurite Basicケースのモデリング画面

資料:今回使った各種モデリングデータについて

今回モデリングしたケースのデータを下記に置いておきますので、3Dプリンターをお持ちで作成してみたい方はご活用ください。

http://www.123dapp.com/MyCorner/akagawa_sh_…-26766851/models


番外編② XOceanを使ってみた〜ArduinoとEnOceanを使用した温湿度表示(その2)

$
0
0

みなさん、こんにちは。新米ライターの小西です。前回はXOceanのデータ把握までを試行錯誤してやってみました。なかなかしんどい作業でしたが、これでどのようなEnOcean製品のデータでも理解できるようになりました。

今回はXOceanにカラー漢字LCDシールドを接続して、温湿度モニタリングシステムを作りたいと思います。これで独立した機器として動作しちゃいますね。

ちなみにLCDシールドの購入先やここまでの工程は、前回の記事にまとめています。ぜひ併せてご覧下さい!

では早速、完成形をお披露目します。表示が付くと一気に機器としてそれらしくなります。

entry-spinoff002_ph01

LCDシールドとこれまでに作ったArduino+XOceanとの接続をやっていきましょう! まずはLCDシールドについて調べました。

カラー漢字LCDシールドについて

LCDシールドについては作者の方のホームページに詳しく書かれています。
http://www.bs21-lab.com/products/p006-ColorKanjiLCD/

LCDシールドは画像の表示ができたり、2画面の重ね合わせができたりするようなので、いろいろ楽しいことができそうですが、今回はシンプルに温度と湿度の表示のみをさせます。このLCDシールドを動作させるサンプルスケッチが用意されているようなので、まずはサンプルスケッチをArduino IDEの中でライブラリ化します。ちなみにArduino IDEのバージョンは1.0.5までしか動作確認はされていないようなので、注意してください。

図1.カラー漢字LCDシールドのサンプルスケッチ取得

図1.カラー漢字LCDシールドのサンプルスケッチ取得。上記作者の方のホームページ中程にあります。

取得したサンプルスケッチをArduino IDEをインストールしたフォルダ内にある “library” というフォルダへコピーします。

図2.カラー漢字LCDシールドのライブラリをコピー

図2.カラー漢字LCDシールドのライブラリをコピー

コピーした後、Arduino IDEを起動して、”ファイル” → “スケッチの例” → “ColorKanjiLCD” を選択するとLCDシールド用のサンプルスケッチを立ち上げることができます。

図3.カラー漢字LCDシールドのサンプルスケッチ

図3.カラー漢字LCDシールドのサンプルスケッチ

スケッチがいろいろ入っているので試してみると、楽しくてついつい時間を忘れて遊んでしまいますが、目的はXOceanと接続してLCDに表示させないといけないので、一つサンプルを選びます。今回は “cklcd_mini_sketch”を選びました(一番簡単なサンプルスケッチです)。
それではいよいよソフトウェアを作成していきましょう。

LCDシールド+XOceanのソフトウェア

基本的には前回作成したソフトウェアを移植するだけで、あとは画面表示部分を追加するだけです。

/*
  Color Kanji LCD Shield - Minimum sketch example

  本スケッチは "カラー漢字 LCD シールド" の最小スケッチ例です。

  Circuit:
    pins A4(SDA), A5(SCL) for TWI communication in Arduino standard.
    pins SDA, SCL for TWI communication in Arduino UNO R3, Leonardo.

  created 15/july/2013 by I.Kato @ BS21 Lab

  This code is in the public domain.
*/

// TWI 通信用ライブラリ:必須です
#include <Wire.h>

// カラー漢字 LCD 用ライブラリ
#include <ColorKanjiLCD.h>

/********* EnOcean add *********/
#define TEMPID  0x040179BD           // EnOceanモジュールID
#define SYNC    0x55                 // SYNCバイト
float Temp=0 ;                 //温度データ
float pastTemp=0 ;             //前回の温度データ
float Hum=0 ;                  //湿度データ
float pastHum=0 ;             //前回の湿度データ

/********* EnOcean end *********/

// カラー漢字 LCD シールドの TWI アドレスを 0x3C 以外に設定した場合は、以下の値を書きかえてください。
// TWI 通信できていない時は、カラー漢字 LCD シールド自身に現在設定されている TWI(i2c) アドレスが
// 表示されているはずなので、御確認ください。
#define CKLCD_TWI_ADDR  0x3C


// カラー漢字 LCD のインスタンス生成
ColorKanjiLCD cklcd (CKLCD_TWI_ADDR); // カラー漢字 LCD シールドの TWI アドレスを指定する


// 初期化関数
void setup()
{
  // 必ず、最初に Wire ライブラリを初期化させておいてください。
  // 注意:"CKLCD_Wire" は Arduino Due では "Wire1" を、それ以外では "Wire" になります。
  CKLCD_Wire.begin();

  // 続いて、カラー漢字 LCD ライブラリを初期化します。
  // 符号化方式は UTF-8 方式がデフォルトなので、特に指定しなくても OK です。
  // 初期化に成功すると、画面はクリアされ、LCD 表示方向はランドスケープ(横向き) に、カーソル位置は (0,0) になります。
  // カラー漢字 LCD は、電源投入直後は自動的に Version と TWI アドレスを表示していますので、
  // 初期化に失敗した場合は、TWI アドレスが、上記の CKLCD_TWI_ADDR と一致しているか確認してください。
  // 仮想画面1(160×256) を背景面に設定します。仮想画面2(160×128) は使用しません。
  cklcd.begin (CKLCD_ORIENT_LANDSCAPE + CKLCD_DISP_SCREEN_B1);

  // 日本語のメッセージを表示させます(仮想画面1を使用)。
  // Arduino IDE の符号化方式は UTF-8 方式なので、これだけで表示できます。
  // ※ JIS 漢字規格の第一水準字~第三水準字のみ表示できます。第四水準字は表示できません。
  //  cklcd.v1.print ("日本語で表示");

  /**************** EnOcean add ****************/
      //Pin 0/1
  Serial.begin(57600);              // 57600-EnOcean Serial Protocol 3 

  cklcd.v1.print ("\n   XOcean \n\n");
  cklcd.v1.print ("温湿度モニタリング \n");
  cklcd.v1.print ("           システム \n");
  /**************** EnOcean end ****************/
  
}


// ループ関数
void loop()
{
/********* EnOcean add *********/
  unsigned char   dataReceive = 0 ;  //受信確認フラグ
  unsigned char   aChar = 0 ;        //データ格納用変数
  unsigned char   pos = 0 ;          //ESPデータ位置
  unsigned long   senderID = 0 ;     //温湿度モジュールのID
  unsigned short  dataLength = 0 ;   //データ長  
  unsigned char   optLength = 0 ;    //オプションデータ長
  unsigned char   packettype = 0 ;    //パケットタイプ
  char buf[1] ;

  while(Serial.available()>0){    // XOcean受信したか?
    aChar = Serial.read();
    switch(pos){
      case(0):
      if( SYNC == aChar){          // SYNCバイトだったら受信開始
        delay(5); 
        pos++;                     // pos移動 SYNC -> dataLength
        dataReceive = 1 ;
      }
      break;
      case(1):
      dataLength = 0x00FF & aChar ;  // dataLength 上位1バイトです。
      pos++;                        // pos移動 dataLength -> dataLength
      break;
      case(2):
      dataLength = (dataLength<<8) + aChar ; // dataLength 下位1バイトです。
      pos++ ;                                // pos移動 dataLength -> optLength
      break;
      case(3):
      optLength = aChar ;          //  optionLength  
      pos++ ;                      // pos移動 optLength -> packet type
      break;
      case(4):
      packettype = aChar ;        //   packettype
      pos++;                      // pos移動  packet type -> crc
      break;
      case(5):
      pos++;                      // pos移動 crc -> header 
      break;
      case(6):
      pos++;                      // pos移動  header -> ID1
      break;
      case(7):
      senderID =  0x0000FF & aChar ;  // ID1バイト
      pos++;                      // pos移動  ID1 -> ID2
      break;     
      case(8):
      case(9):
      case(10):
      senderID =  (senderID<<8) + aChar ;  // ID2-4バイト
      pos++;                      // pos移動  ID2 -> ID4 -> data1
      break;     
      case(11):
      pos++;                      // pos移動  data1 -> data2
      break;
      case(12):
      if(TEMPID == senderID ){
        pastHum = Hum ;
        Hum = (float)aChar * 100/250 ;    //  humdata
      }
      pos++;                      // pos移動  data2(hum) -> data3(temp)
      break;
      case(13):
      if(TEMPID == senderID ){
        pastTemp = Temp;
        Temp = (float)aChar * 40/250 ;    //  Tempdata
      }
      pos++;
      break;
    default:
      break;
    }  
  }
  if(dataReceive ==1){
    if(TEMPID == senderID ){
      cklcd.v1.clear(); // 一旦、仮想画面をクリアする
            
      cklcd.v1.print ("\nTemperature  前回 \n");
      cklcd.v1.print (" ");
      cklcd.v1.print (Temp , 2);
      cklcd.v1.print ("℃ ");
      cklcd.v1.print ("  ");
      cklcd.v1.print (pastTemp , 2);
      cklcd.v1.print ("℃ \n");
      cklcd.v1.print ("Humidity     前回 \n");
      cklcd.v1.print (" ");
      cklcd.v1.print (Hum , 2);
      cklcd.v1.print ("% ");
      cklcd.v1.print ("  ");
      cklcd.v1.print (pastHum , 2);
      cklcd.v1.print ("% \n\n");


    }
    dataReceive = 0 ;
  }

/********* EnOcean end *********/

}

前回と違う部分は表示部分をLCDシールドに合わせたところと、1回前の値も表示させるようにしたところです。

図4.動作結果

図4.動作結果

使ってみた感想

前回までのセッティングでEnOceanのデータが受信できるようになっていたのと、LCDシールドのサンプルスケッチが充実していたので、簡単にできちゃいました! EnOceanのセンサは買ってきたままの状態で動作しましたし、XOceanはデータを理解することさえクリアできれば、通信プロトコルは規格で決まっているので他のEnOceanセンサを使うときでもすぐに対応できそうです。使ってみると意外と簡単に動作するのが実感できました。

今回はLCDで表示をさせましたがモータとつないだり、照明とつないだりといろいろな機器と連動させて動作できそうです。ちょっとしたIoTやM2MがEnOceanでも実現できそうですね。夢が広がります。

図5.機器全体構成

図5.機器全体構成

図6.運用中(温湿度センサはパーティションに設置しています)

図6.運用中(温湿度センサはパーティションに設置しています)

また、EnOceanのラインナップとしては今回使用した温湿度センサの他にスイッチやマグネットコンタクトセンサがあるようなので、また機会を見つけてこれらの製品も動作させていこうと思います!

 


 

……さてと、さっそく完成したことを上司に報告だ!!

entry-spinoff002_ph02

上司「……(ニタニタ)」

entry-spinoff002_ph03

上司「GOOD JOB!やるねえ~!!」

や、やった!!
いただきました!GOOD JOB!

上司に認めてもらえたXOcean+Arduinoの電子工作のパワー恐るべし。

これからも精進することを心に決めた僕でした★

第30回 OSC通信でArduinoと他のアプリを連携させてみる。(前編)

$
0
0

DSC_0002

Arduinoは単体で開発してもとても面白いデバイスだということが、これまでいろいろなパーツやシールドを利用した例を紹介してきて見ていただいている方は、十分に感じているかとは思います。さらに一歩進んで、今回は、OSC通信という通信方法を利用して、Arduinoを外部のアプリケーションと通信連携する方法を試してみたいと思います。外部アプリケーションと連携することで、スイッチやボリュームなどの電子部品からのアクションを通じて、ビジュアル言語で画面を操作するなど、表現の幅がぐんっと広がることになります!

今回の電子工作レシピ

時間目安:90分
必要なパーツ

OSC通信ってなんだろう?

OSC通信とはどのような通信方式なのでしょうか?wikipediaで調べてみると…

Open Sound Control – wikipedia
OpenSound Control(OSC)とは、電子楽器(特にシンセサイザー)やコンピュータなどの機器において音楽演奏データをネットワーク経由でリアルタイムに共有するための通信プロトコルである。カリフォルニア大学バークレー校にある CNMAT(The Center for New Music and Audio Technologies)が開発した。

音楽演奏データをやりとりする目的で開発された通信方式ということがわかりました。音楽演奏データ通信といえば、聞いたことがある方も多いかもしれませんが、MIDI(Musical Instrument Digital Interface)が有名ですね。このMIDIは、1982年とはるか昔に開発されたこともあり、通信速度が低かったり、リアルタイム性に向いていないなどの理由から、昨今ではOSCが利用されるようになってきています。

では、なぜ今回音楽を扱うわけでもないのに、ArduinoでOSC通信なのでしょうか。実はこのOSC通信はその通信の柔軟さなどから音楽データ通信以外にもさまざまなケースに利用されるようになってきており、多くのソフトウェアでもOSCに対応したものが出てきています。

 

OSCのしくみ

さっそくOSCのしくみについて学んでいきましょう。OSCはとてもシンプルな構成です。OSCには大きく2つの種類のメッセージがあり、そのメッセージをアプリ間でやりとりしながら通信を行います。

図1 OSC通信の仕様

  • Message : メッセージの種別を示すもの。「/」で区切って階層構造を作ることが可能なので、複雑な通信でも見やすい形で通信フォーマットを作成することが可能です。
  • Arguments : メッセージの内容です。数値(int / float)や文字列(string)形式などのデータを受け渡すことができます。

 

ArduinoでOSCを利用するには?

ArduinoでOSCを利用するためには、ネットワークに繋がる環境を用意する必要がありますので、イーサネットシールドを使います。

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

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

また、ArduinoでOSC通信をするためには、ライブラリを必要とします。ArduinoでOSC通信をするためのライブラリはいくつかありますが、今回はArdOSCを利用します。(最新バージョンのArduinoの場合、エラーが出て正常に動作しない可能性がありますので、その場合は他のOSCライブラリをご利用ください。)ライブラリを追加後、下記の送信プログラムを記述します(ライブラリの追加の方法は以前の回を参考してください)。

OSC送信テストプログラム

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

#include <ArdOSC.h>

byte myMac[] = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };  //イーサネットのMACアドレスを記述
byte myIp[] = { 192, 168, 0, 9 };  //Arduinoに割り当てるIPアドレスを記述
int destPort=12000;  //送信先のポート番号
byte destIp[] = { 192, 168, 0, 2 };  //送信先のIPアドレス

OSCClient client;
OSCMessage global_mes;

void setup(){
Ethernet.begin(myMac ,myIp);   //イーサネットの設定
}

void loop(){
global_mes.setAddress(destIp,destPort); //送信設定
global_mes.beginMessage("/temperature");  //Message
global_mes.addArgString("29.0");  //Argument
client.send(&global_mes);   //データの送信
global_mes.flush(); //データのクリア
delay(500);
}

Arduino側の準備ができたら、次に外部アプリケーションの準備をします。今回、外部のアプリケーションには、Processing(プロセッシング)を使います。Processingはオープンソースプロジェクトの、メディアアートやビジュアルデザインのためのプログラミング言語です。Arduino同様、初心者が手軽にあつかえるグラフィックに特化した言語と言えます。Processingのウェブサイトから「Download Processing」を選択して、Processingをダウンロードしてインストールしてください。

図2 Processingウェブサイト

図2 Processingウェブサイト

Processingのインストールが完了したら、起動します。

図3 Processingアイコン

図3 Processingアイコン

図4 Processing起動画面

図4 Processing起動画面

起動すると、Arduinoに似た画面が表示されますね。Arduino同様、中央の箇所にプログラムを記述して再生ボタンでプログラムの実行、停止ボタンでプログラムを停止することができます。スケッチの例やライブラリの扱い方などもArduinoとほとんど同じですので違和感なく使うことができるかと思います。

さっそくProcessingに下記のOSC受信プログラムを記述します。

OSC受信プログラム(Processing)


import oscP5.*;
import netP5.*;
 
OscP5 oscP5;
NetAddress myRemoteLocation;

void setup() {
 size(500,500);
 frameRate(25);
 oscP5 = new OscP5(this,12000); //受信するポートの設定
 myRemoteLocation = new NetAddress("127.0.0.1",12001); //送信する場合の送信IPとポート
}

void draw() {
 background(0);
}

//OSC
void oscEvent(OscMessage theOscMessage) {
theOscMessage.print();
}

準備ができたら、Processingを実行した後に、Arduinoを実行すると、Processingのプログラムを記述する画面下のconsole枠にArduinoから送られてきたメッセージが表示されれば成功です。

図5 Processing実行結果

図5 Processing実行結果

気温湿度を外部アプリケーションに受け渡してみる

OSC通信を使ってArduinoで気温湿度を計測結果を、外部のアプリケーションに渡してみます。

Arduino側の準備として、気温湿度パーツのDHT11を利用して計測します。DHT11はArduinoのライブラリが用意されていますので、DHT11のライブラリを追加します。

写真2 気温湿度センサDHT11

写真2 気温湿度センサDHT11

ダウンロードしたDHT11のライブラリには、サンプルファイルが用意されていますので、そのサンプルをもとにDHT11で気温湿度が正常に計測できるかどうか確認します。

図6 気温湿度センサ回路

図6 気温湿度センサ回路

気温湿度計測のプログラム


#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT11   // DHT 11

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600);
  Serial.println("DHT11");
  dht.begin();
}

void loop() {
  delay(2000);

  float h = dht.readHumidity();
  float t = dht.readTemperature();
  float f = dht.readTemperature(true);

  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  float hif = dht.computeHeatIndex(f, h);
  float hic = dht.computeHeatIndex(t, h, false);

  Serial.print("Humidity: ");
  Serial.print(h);
  Serial.print(" %\t");
  Serial.print("Temperature: ");
  Serial.print(t);
  Serial.print(" *C ");
  Serial.print(f);
  Serial.print(" *F\t");
  Serial.print("Heat index: ");
  Serial.print(hic);
  Serial.print(" *C ");
  Serial.print(hif);
  Serial.println(" *F");
}
図7 実行結果

図7 実行結果

正常に計測が確認できたら、OSC通信用にプログラムを修正します。

気温湿度OSC送信プログラム

#include &amp;lt;SPI.h&amp;gt;
#include &amp;lt;Ethernet.h&amp;gt;
#include &amp;lt;ArdOSC.h&amp;gt;
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT11 // DHT 11

DHT dht(DHTPIN, DHTTYPE);
byte myMac[] = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };
byte myIp[] = { 192, 168, 0, 9 }; 

int destPort=12000;
byte destIp[] = { 192,168,0,10 };

OSCClient client;
OSCMessage global_mes;
 
void setup(){ 
 Ethernet.begin(myMac ,myIp); 
 dht.begin();
}
 
void loop(){ 
 delay(2000);

 float h = dht.readHumidity();
 float t = dht.readTemperature();
 float f = dht.readTemperature(true);

 if (isnan(h) || isnan(t) || isnan(f)) {
 Serial.println("Failed to read from DHT sensor!");
 return;
 }

// float hif = dht.computeHeatIndex(f, h);
// float hic = dht.computeHeatIndex(t, h, false);

 global_mes.setAddress(destIp,destPort);
 //温度を送信
 global_mes.beginMessage("/temperature");
 global_mes.addArgFloat(t); 
 client.send(&amp;amp;global_mes);
 global_mes.flush(); //object data clear
 delay(5000);
 
 //湿度を送信
 global_mes.flush(); //object data clear
 global_mes.setAddress(destIp,destPort);
 global_mes.beginMessage("/humidity");
 global_mes.addArgFloat(h); 
 client.send(&amp;amp;global_mes);
 delay(1000);

 global_mes.flush(); //object data clear
 
}

受信側プログラム(Processing)

import oscP5.*;
import netP5.*;
 
OscP5 oscP5;
NetAddress myRemoteLocation;

void setup() {
 size(500,500);
 frameRate(25);
 oscP5 = new OscP5(this,12000);
 myRemoteLocation = new NetAddress("127.0.0.1",12001);
}

String str1 = "";
String str2 = "";
float val = 0;

void draw() {
 background(0);
 fill(256,256,256);
 text(str1,50,20);
 text(str2,50,40);
 
 fill(val,256,256);
 rect(20,10,20,32);
}

//OSC
void oscEvent(OscMessage theOscMessage) {
 /* print the address pattern and the typetag of the received OscMessage */
 print("### received an osc message.");
 theOscMessage.print();
 str1 = "OSC Message : "+theOscMessage.addrPattern();
 str2 = "OSC Arguments : "+theOscMessage.get(0).floatValue();
 val = theOscMessage.get(0).floatValue();
}

両方のプログラムを実行すると、Processingの画面に下記のように温度・湿度が繰り返し表示されれば完成です。

図8 OSC通信実行結果

図8 OSC通信実行結果

まとめ

今回はArduinoと外部アプリケーションを連携する方法の一つであるOSC通信を紹介しました。OSC通信を利用しなくても、独自に相互のアプリケーション同士で通信規約などを決めて通信することも可能ですが、OSC通信を利用することで、世にある数多くのソフトウェアやデバイスと連携することが可能になります。次回は、今回の基礎を発展させてOSC通信を利用することで広がるArduinoの使い方を紹介したいと思います。

第47回 植物育成デバイスをArduino Createでつくってみる 〜Arduino+センサの開発が劇的に楽になる!ローム・センサ評価キットを試してみた

$
0
0

45

数回にわたり続けてきたローム・センサ評価キットのお試しシリーズ、今回は前回の照度センサ・近接センサや他のセンサなどを組み合わせて植物育成デバイスのパワーアップ化を図ります!

そして、デバプラ編集部からもニュース記事が配信されましたが、Arduino界ではかなり大きな出来事になるであろう「Arduino Create」が2016年8月18日に正式にリリースされました!このArduino Create、雑に言ってしまえば「Arduinoもmbedみたいにオンライン上でソースを書いて書き込みまでできちゃう」というようなものなのですが、Arduinoでもそれができるのは本当に嬉しいニュースです。

Arduino Createは次回以降に詳しい内容を取り上げたいと思いますが、今回はセンサ評価キットの実装で早速Arduino Createを使ってデバイスの実装をしてみたいと思います。

今回の電子工作レシピ

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

※ロームセンサ評価キットは下記サイトから購入できます!
チップワンストップ
ザイコストア

目次

  1. 植物育成デバイスのパワーアップ仕様を考える
  2. Arduino Create×ローム・センサ評価キットで開発!
  3. いざ、工作!実装!
  4. まとめ

1.植物育成デバイスのパワーアップ仕様を考える

今回、植物育成デバイスのパワーアップを目指すということで、これまでのセンサをどう使えば植物にとって素敵なデバイスになるでしょうか。各種センサの詳しい役割や使い方はこれまでの記事を見ていただくことにして、ざっとこれまで扱ったセンサの役割と植物育成デバイスで使えそうか考えてみましょう…

図1 センサ評価キットのセンサ一覧

図1 センサ評価キットのセンサ一覧

  • 加速度センサ:傾きや動き、振動などを検出 → 今回は出番がなさそうかな…
  • 気圧センサ:気圧を検出 → 気圧と天気の関係から、植物にちょっと関係がありそう。
  • 地磁気センサ:方位を検出 → 太陽の方角に合わせて植物の向きを変えるとかできるかな。
  • 近接照度センサ:近づいた物体を検出、明るさを検出 → 暗いときにはデバイスは動かさないなどのような使い方ができるかな。
  • カラーセンサ:色を検出 → 葉っぱが枯れてきたら、なども頑張ればできそう…。
  • ホールセンサ:磁気で物体を検出 → 今回は出番がなさそうかな…
  • 温度センサ:温度を検出 → 温度が高すぎる、低すぎるときに水やりの制御とかできそう…
  • 紫外線センサ:紫外線を検出 → 太陽光が強すぎる・弱すぎるなどの状態を通知したい…

 

一通りのセンサの役割をおさらいすると、植物育成デバイスに関係ありそうな、かつ機能として実装できそうなセンサがたくさんありますね。どんなセンサをどう組み合わせてデバイスを作るか、今度は育成される植物の気持ちになって考えて見ましょう…

 

図2 一般的な観葉植物の育て方

図2 一般的な観葉植物の育て方

 

植物の気持ちになると、どういうことが嬉しくて、どういうことが駄目なのか、センサをどう使ったらよいか参考になりますね。
余談ですが、私が育てていた観葉植物もたまには元気に日光いっぱいの外で気分転換させてやろう!と思って夏場の快晴の中に置いてたらその後数日で枯れてしまいました…(涙)

これらの情報をもとに今回植物育成デバイスの仕様を考えてみると…

  • 日当たり条件 → 紫外線センサと温度センサを使って、温度が高く・紫外線が強い場合は太陽光を弱める仕組みにする
  • 水やりルール → 土の乾きを検出して、鉢のサイズに応じた水を与える
  • 温度について → 対象の植物の特性を調べて温度が高すぎる・低すぎる場合はアラートで教えてくれる
  • 風通しについて → 屋内で風があまりない場所の場合は、風を送る

という機能を目標にしてデバイスを作ってみましょう!

 

海外にはこんなデバイスも…

植物育成デバイス、といえば、世界をみるとこんな大掛かりな植物育成デバイスを作っている方もいました。このサイズだと巨大なレーザーカッターや3Dプリンターみたいですね。動画をみるとPC制御でどこにどの植物を植えるのかなどの作付け管理もできるみたいですね。外でデバイスを動かすのは長期で雨風土などの厳しい条件の中で動かすのでなかなかスムーズに実現するのは大変そうですが、夢がありますね!(目的は植物を育てるということなのに、なぜか毎回デバイスのメンテナンスばかりしている…なんていうのはよくある話のわけで…)

FARMBOT GENESIS – https://farmbot.io/

 

Arduino Create×ローム・センサ評価キットで開発!

プログラム・回路の製作を行っていくのですが、今回はリリースされたばかりのArduino Createをさっそく使ってみます。オンライン上でコードがかけて、かつSNS機能などもついて共有なんかもできちゃう、まだ少ししか触っていないですがこれはまた今後が面白くなりそうな予感がしますね。

 

写真2 オンラインでArduinoが使える「Arduino Create」

写真2 オンラインでArduinoが使える「Arduino Create」

Arduino Createウェブサイト

Arduino Createのはじめかた

Arduino Createで開発を進めるにあたり、簡単な手順を紹介します。まず、既存のArduinoと違うのは、ソースコードをウェブブラウザで書くことができるようになった、ということです。これまではArduinoのソフトウェアをダウンロードして、PCにインストールして、ソフトウェアを起動してArduino本体に書き込む、という流れでしたが、Arduino Createの場合は、

  1. ブラウザを開いて、Arduino Createのウェブサイトを開く
  2. Arduino Createにユーザー登録(最初のみ)
  3. 登録情報を入力~承認メールのURLをクリックして登録完了(最初のみ)
  4. ブラウザとArduino本体をつなぐ「ArduinoCreateAgent」をインストール(最初のみ)
  5. ウェブエディタ上でArduino開発スタート。

となります。PC版のソフトウェアとの大きな違いは、

  • インターネットがつながっていればどこでもすぐにこれまで書いたソースコードを参照できる
  • ライブラリもオンライン上に登録されるのでPCが変わっても同じライブラリを再度インストールしなくてもよい

などなど便利なことだらけになっています!(これだけでは全然ないのですが、次回以降の記事で)
あえて、一つデメリットをあげるのであれば、インターネットにつながっていないと使えない!ということでしょうか。その場合は、おとなしくこれまでどおり既存のソフトウェア版を使いましょう。

 

Arduino Createの主な画面とセンサ評価キットライブラリを動かしてみる

ユーザー登録が完了したら、何はともあれウェブエディタを開いてみます。

図3 Arduino Createウェブエディタ

図3 Arduino Createウェブエディタ

ブラウザということもあり、これまでの縦長の画面から横長でメニューなどもすっきり見やすくなった印象がありますね。ソフトウェアの場合、ウィンドウが多くなりすぎてソースを開きすぎると目的のソースがどこにいったかわからなくなっていたのですが、その問題も解消されそうです。

左のメニューに、これまで上にあったメニューが一通り揃っていますね。

 

図4 Arduino Createウェブエディタ-基本機能

図4 Arduino Createウェブエディタ-基本機能

よく使う機能を確認してみます。左メニューの「Examples」からまずはLチカこと「Blink」ソースコードを開いてみます。そして、画面中央上にある、Arduino種類・ポートの選択から、つなげているArduinoのポート番号と種類を選択して、「コンパイル」→「書き込み」を 試してみると、ソフトウェア版と同じようにArduinoに書き込みされてLチカができました!

 

センサ評価キットライブラリの追加

無事動いたので、次にセンサ評価キットのライブラリを追加して動作を確認します。ライブラリの追加は左メニューの「Libraries」から選択して、上にある「ADD ZIP LIBRARY」をクリックすると、zipファイルをアップロードできるので、追加したいライブラリのzipファイルを選択することで追加が完了します。センサ評価キットのライブラリ(zipファイル)はこちらから各センサのものをダウンロードできます。

 

図5 Arduino Createウェブエディタ-ライブラリの追加

図5 Arduino Createウェブエディタ-ライブラリの追加

 

やった、センサ評価キットも簡単にうごきました!

センサ評価キットも動くことが確認できたので、プログラムと回路の作成をしていきます。

今回デバイスの仕様を下記のようにしたいのでそれに合わせてパーツやセンサを組み合わせていきます。

  • 日当たり条件 → 紫外線センサと温度センサを使って、温度が高く・紫外線が強い場合は太陽光を弱める仕組みにする
    →サーボモーターで日陰をつくる!
  • 水やりルール → 土の乾きを検出して、鉢のサイズに応じた水を与える
    →土壌センサとポンプで水やりを可能に!
  • 温度について → 対象の植物の特性を調べて温度が高すぎる・低すぎる場合はアラートで教えてくれる
    →LEDを光らせて教えてくれる!(将来的にはネットワーク越しで通知したい!)
  • 風通しについて → 屋内で風があまりない場所の場合は、扇子であおいで風を送る
    →夏らしく、サーボモーターで扇子をあおぐ

ということを踏まえて、下記のような回路にしました。

図6 回路図(Arduinoの上にはセンサ評価キットが載っている想定です)

図6 回路図(Arduinoの上にはセンサ評価キットが載っている想定です)

 

プログラムのポイントとしては、loopの前半で各センサの値を取得した後、そのセンサの値に応じてサーボやLEDを動かして目的の動作を実現するような流れになっています。各センサの反応する閾値が鉢のサイズや植物によって違うので、それは各自育てたい植物を調べて数値を調整してみてください。

 

プログラム – 植物育成デバイス

#include <Wire.h>
#include <Servo.h>
#include <RPR-0521RS.h>
#include <BD1020.h>
#include <ML8511A.h>
#include <BM1383GLV.h>

//***********************************************
//閾値の設定
//***********************************************
int moi_threshold   = 500;  //水の乾き具合を設定できます。(湿っている←0~1023→乾いている)
int upper_temp_threshold  = 30;   //高温検出-高いと赤いLEDが光る
int under_temp_threshold  = 10;   //低温検出-低いと青いLEDが光る
int uv_threshold  = 4;   //紫外線の強さ設定-超えると日陰にする
int send_wind_sec  = 30; //風を送る大体の間隔(秒数) 
//***********************************************

Servo uvServo;              
Servo windServo;              
Servo waterServo;              

int redLedPin   = 13;       
int blueLedPin   = 12;
int moisture_pin = A0;
int tempout_pin = A2;
int uvout_pin = A0;

int counter = 0;
bool uvFlg = false;

BD1020 bd1020;
RPR0521RS rpr0521rs;
ML8511A ml8511a;
BM1383GLV bm1383;

//***********************************************************
void setup() {
  Serial.begin(9600);
  while (!Serial);
  Wire.begin();

  byte rc;  
  rc = rpr0521rs.init();
  rc = bm1383.init();

  pinMode(redLedPin,OUTPUT);
  pinMode(blueLedPin,OUTPUT);
  uvServo.attach(9);
  windServo.attach(10);
  waterServo.attach(11);
  bd1020.init(tempout_pin);
  ml8511a.init(uvout_pin);
}

//***********************************************************
void loop() {
    //*********************************
    //土壌センサ
    int moi = analogRead(moisture_pin);
    Serial.write("MOISTURE = ");
    Serial.println(moi);
    Serial.println();
   
    //*********************************
    //温度センサ
    float temp;
    bd1020.get_val(&temp);
    Serial.print("BD1020HFV Temp=");
    Serial.print(temp);
    Serial.print("  [degrees Celsius], ADC=");
    Serial.println(bd1020.temp_adc);

    //*********************************
    //紫外線センサ
    float uv;
    ml8511a.get_val(&uv);    
    Serial.write("ML8511A UV = ");
    Serial.print(uv);
    Serial.println(" [mW/cm2]");
    Serial.println();    

    //*********************************
    //気圧センサ
    byte cp;
    float press;
    
    cp = bm1383.get_val(&press);
    if (cp == 0) {
      Serial.write("BM1383GLV (PRESS) = ");
      Serial.print(press);
      Serial.println(" [hPa]");
      Serial.println();
    }
    
    //*********************************
    //照度・近接センサ
    byte rc;
    unsigned short ps_val;
    float als_val;
    byte near_far;
    
    rc = rpr0521rs.get_psalsval(&ps_val, &als_val);
    if (rc == 0) {
      Serial.print(F("RPR-0521RS (Proximity)     = "));
      Serial.print(ps_val);
      Serial.print(F(" [count]"));
      near_far = rpr0521rs.check_near_far(ps_val);
      if (near_far == RPR0521RS_NEAR_VAL) {
        Serial.println(F(" Near"));
      } else {
        Serial.println(F(" Far"));
      }
      
      if (als_val != RPR0521RS_ERROR) {
        Serial.print(F("RPR-0521RS (Ambient Light) = "));
        Serial.print(als_val);
        Serial.println(F(" [lx]"));
        Serial.println();
      }
    }

    //***********************************
    //センサの値に応じて各処理

    //土が乾いたら水をあげる
    if(moi > moi_threshold){
      Serial.println("Water Servo start.");
      for(int m=0;m < 10;m++){ waterServo.write(0); //サーボモーターを0度に動かす
            delay(1500); //1.5秒待つ 
            waterServo.write(90); //サーボモーターを90度に動かす 
      } 
    } //温度による動作 
    if(upper_temp_threshold > temp){
      digitalWrite(redLedPin, HIGH);  //LEDを光らせる
      delay(moi);                     //渇きの具合をLEDの光る時間にする
      digitalWrite(redLedPin, LOW);   //LEDを消す
    }
    if(under_temp_threshold < temp){
      digitalWrite(blueLedPin, HIGH);  //LEDを光らせる
      delay(moi);                     //渇きの具合をLEDの光る時間にする
      digitalWrite(blueLedPin, LOW);   //LEDを消す
    }

    //日差しが強いときに日陰にする
    if(uv < uv_threshold && !uvFlg){ 
        waterServo.write(90); 
        uvFlg = true;
    }
    else if(uv >= uv_threshold && uvFlg){
        waterServo.write(0);    
        uvFlg = false;
    }

    //一定時間で風を送る
    if(counter > send_wind_sec){
      Serial.println("Wind Servo start.");
      for(int n=0;n < 10;n++){
        waterServo.write(0);
        delay(1000);        
        waterServo.write(90);
      }
      counter = 0;
    }

    counter++;
    delay(1000);
}

 

いざ、工作!実装!

プログラムと回路ができたので、組み合わせてハードウェアを完成させていきます!

写真3 今回対象となる観葉植物

写真3 今回対象となる観葉植物

まず今回はこの植物を。

 

写真4 日陰の構造

写真4 日陰部分の構造

紫外線が強くなったらサーボモータに取り付けたパネルを90度回転させて、窓からの日光をさえぎるようにします。

 

2016-08-22 07.43.24

水をあげる部分は今回スプレーをサーボモータで引っ張って実現しました。

 

送風の様子。夏っぽく扇子で。

 

写真5 植物育成デバイス全体像

写真5 植物育成デバイス全体像

ひとまず組み立ててこんな感じになりました。サーボでアナログな感じにしちゃいましたが、もっとハイテクにするのであれば、水やりを小型ポンプ、送風部分を小型扇風機やPCファンなどにするなども良いかもしれません。また、室内で窓がない場合などは、植物用LEDと照度センサを組み合わせて、室内が暗くなったら植物用LEDもオフにするなんてアイデアもありかもしれませんね。

 

まとめ

今回、センサ評価キットを組み合わせて植物育成デバイスをパワーアップすることができました。記事内で紹介したようなすごいデバイスもあるので、これで完成ではなくもっと良い・面白いアイデアをもとにどんどん改良していくことで、楽しみながら開発することができると思います。

次回は、Arduino Createをもう少し詳しく使いながら、センサ評価キットの最後となった、加速度センサを体験してみます!

第48回 加速度センサで色んな動きを検出してみる! 〜Arduino+センサの開発が劇的に楽になる!ローム・センサ評価キットを試してみた

$
0
0

1-DSC_1358

たくさんのセンサを手軽に扱うことができるローム・センサ評価キットのお試しシリーズ、今回はいよいよ最後のセンサとなりまして、加速度センサを使ってみたいと思います。

加速度センサは第17回18回で基本的なセンサの役割やしくみなどを紹介していますので、今回はまずセンサ評価キットで動作させてみるところからはじめてみたいと思います! また今回もプログラムの開発は、前回も触れた「Arduino Create」で進めていきたいと思います。

今回の電子工作レシピ

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

※ロームセンサ評価キットは下記サイトから購入できます!
チップワンストップ
ザイコストア

目次

  1. 加速度センサって何?
  2. 加速度センサを動かしてみる
  3. TFT液晶モニタに加速度センサの値を表示してみる
  4. まとめ

1.加速度センサって何?

第1718回でも紹介していますが加速度センサのおさらいをしておきましょう。加速度センサは、「傾き」・「衝撃」・「振動」などといったセンサの動きの状態を検出することができるセンサです。センサには1軸2軸3軸などの種類があり、たとえば1軸だと1方向(縦だけ)の検出、2軸だと2方向(縦と横)、3軸だと3方向(縦と横と高さ)の検出ができるようになっています。

加速度センサの仕組みで下記の動画が英語ですがわかりやすく紹介されていますね。

 

センサ評価キットに搭載されている加速度センサは3軸なので、XYZの検出が可能です。

写真1 加速度センサ

写真1 加速度センサ

センサ評価キットに付属している加速度センサは3軸センサになっているので、地磁気センサと同じようにセンサ基板の上にXYZの表示があります。

 

2.加速度センサを動かしてみる

まずは加速度センサを動かしてみます。いつもどおり、ロームセンサ評価キットのウェブサイトから、加速度センサのページを開き、ページ最下部にある、「ソフトウェア」の項目からライブラリをダウンロードします。

写真2 加速度センサのページ

写真2 加速度センサのページ

 

今回もプログラムの開発はArduino Createで進めていこうと思うので、ダウンロードしたライブラリのzipファイルをArduino Createのライブラリの追加から追加します。Arduino Createの簡単な使い方は前回の記事を参考にしてください。

 

写真2 Arduino Createのライブラリ追加画面

写真3 Arduino Createのライブラリ追加画面

 

ライブラリの追加が完了したら、センサ評価キットに加速度センサを取り付けて(I2C/IFエリア)、サンプルプログラムを動かしてみます。加速度センサは1.8Vまたは3.0Vの電圧に設定してください。

図2 センサ評価キットのセンサの取り付け

図1 センサ評価キットのセンサの取り付け

 

写真3 加速度センサをキットに取り付け

写真4 加速度センサをキットに取り付け

 

サンプルプログラムはArduino Createのライブラリ画面から、exampleを選択するとプログラムを開くことができます。

 

図3 サンプルプログラムを開く

写真5 サンプルプログラムを開く

 

コンパイルして、Arduino本体にアップロードすると無事動きました!

 

写真6 シリアルモニタで確認

写真6 Arduino Createのシリアルモニタで確認

 

3.TFT液晶モニタに加速度センサの値を表示してみる

サンプルプログラムが動いたところで、このままだとちょっと物足りないので、1.8インチの小型のTFT液晶モニタに加速度センサの値を表示させてみたいと思います。このTFT液晶モニタは解像度が126px × 160pxと少し小型ではありますが、Arduinoなどで数値や文字を表示する場合に重宝するパーツとなります。これまでは、7セグメントLEDを使って数値のみの表現より、たくさんの表現が可能となるので、今回は、加速度センサの数値に加えてグラフの表示も挑戦してみました。

 

写真7 1.8インチTFT液晶モニタ

写真7 1.8インチTFT液晶モニタ

 

写真8 裏側にはSDカードのスロットも

写真8 裏側にはSDカードのスロットも

 

写真9 センサ評価キットにTFTモニタを接続

写真9 センサ評価キットにTFTモニタを接続

 

TFTモニタを利用する場合、利用するTFTモニタそれぞれの仕様にあわせて接続方法や、プログラムで利用するライブラリが違ったりする場合があります。今回利用したTFTモニタはsainsmart社のST7735Rというモニタです。ウェブサイトにはArduino以外にもRaspberry Piに接続して動かしたりしているサンプルも公開されていますね。

このモニタを使ってArduinoでプログラムを動作させるためにはダウンロードしたライブラリに少し手を加える必要があるので、モニタの使い方に関しては、次号で紹介いたします。
モニタを上手に扱えるようになると、下記のように数値を好きな場所に出したり、グラフを描画したりと電子工作の世界がまた一歩広がる感じを味わえると思います!

 

 

まとめ

次回は、センサ評価キットを使って、加速度センサの数値をTFTモニタに表示する方法や、グラフプログラムの作り方をはじめとして、加速度センサとTFTモニタを使った簡単なデバイスを作ってみたいと思います。

第49回 加速度センサとTFT液晶パネルを使ったゲームを作ってみる! 〜Arduino+センサの開発が劇的に楽になる!ローム・センサ評価キットを試してみた

$
0
0

dsc_1494

前回加速度センサの計測結果をTFT液晶パネルに表示しましたが、今回はそのプログラムの中身を読み解いていきながらTFTモニタの扱いを学んでいきたいと思います!

今回の電子工作レシピ

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

※ロームセンサ評価キットは下記サイトから購入できます!
チップワンストップ
ザイコストア

目次

  1. ArduinoでTFT液晶モニタに表示する
  2. 加速度センサの数値をグラフにしてみる
  3. まとめ

1.ArduinoでTFT液晶モニタに表示する

今回利用したTFTモニタはsainsmart社のST7735Rというモニタです。このモニタはArduino以外でもRaspberry Piなどでも利用が可能な小型のディスプレイになっています。microSDカードのスロットも実装されているのでデータの読み書きもできるのですが、今回はTFTモニタの表示のみ試してみます。

まず、ArduinoとTFTモニタを接続していきます。

写真1 TFTモニタ

写真1 TFTモニタ

 

写真2 TFTモニタの裏側

写真2 TFTモニタの裏側

ちなみに、基板に書かれているピンの名称や役割ですが、

  • VCC – 電源入力(Correction Voltage)
  • GND – グランド(Ground)
  • SCL – シリアルクロックライン(Serial Clock Line)
  • SDA – シリアルデータライン(Serial Data Line)
  • RS/DC – コマンド/データセレクション(Command/Data Selection)
  • RES – リセット(LCD Controller Reset)
  • CS – チップ選択(Chipselect for TF Card)

という感じになっているようです。

ArduinoとTFTモニタの接続が完了したらサンプルプログラムを動かしてみます。

 

TFTモニタのライブラリをArduino用に適用する

このTFTモニタはST7735Rというライブラリを利用してArduinoで表示をすることができるのですが、このST7735RはそのままではArduinoで利用することができないため、ライブラリファイルの一部を変更する必要があります。

SainSmart 1.8 ST7735R TFT LCD Module with MicroSD LED Backlight For Arduino Raspberry Pi
ライブラリのダウンロード(ST7735R V0.2)

上記のURLからページの最下部にダウンロードリンクがあるので、そこから「Download Link」と書かれたリンクをクリックするとライブラリやサンプルコード、ドキュメントなどの一式をダウンロードすることができます。ダウンロードが完了したら、圧縮ファイルを解凍した後、必要なファイルを書き換えていきます。

「ST7735.h」をテキストが編集できるエディタで開いた後、4行目の図で示している部分を変更します。これでArduinoでも利用することができます。

gf02

 

ファイルの変更が完了したら、解凍した「TFT18」ディレクトリを再度zipなどで圧縮して、Arduino(もしくはArduino Create)のAdd Libraryからライブラリとして追加するか、Arduinoのインストールされているディレクトリにある「libraries」ディレクトリの配下に設置してライブラリを読み込んでください。

読み込みが完了したら、スケッチのサンプルから「TFT18」-「graphictest」を動かしてみます。

サンプルプログラムを見るとなかなかスムーズに表示されているのが確認できますね。
サンプルプログラム – graphictest

//ピンの設定
#define sclk 4
#define mosi 5
#define cs 6
#define dc 7
#define rst 8

//利用する色番号
#define	BLACK           0x0000
#define	BLUE            0x001F
#define	RED             0xF800
#define	GREEN           0x07E0
#define CYAN            0x07FF
#define MAGENTA         0xF81F
#define YELLOW          0xFFE0  
#define WHITE           0xFFFF

#include <ST7735.h>
#include <SPI.h>

ST7735 tft = ST7735(cs, dc, mosi, sclk, rst);  


void fillpixelbypixel(uint16_t color) {
  for (uint8_t x=0; x < tft.width; x++) {
    for (uint8_t y=0; y < tft.height; y++) {
      tft.drawPixel(x, y, color);
    }
  }
  delay(100);
}

void setup(void) {
  Serial.begin(9600);
  Serial.print("hello!");
  tft.initR();               // initialize a ST7735R chip

  Serial.println("init");
  tft.writecommand(ST7735_DISPON);
  
  uint16_t time = millis();
  tft.fillScreen(BLACK);
  time = millis() - time;
  
  Serial.println(time, DEC);
  delay(500);
  
  //
  tft.fillScreen(BLACK);
  testdrawtext("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a tortor imperdiet posuere. ", WHITE);
  delay(1000);
  
  //a single pixel
  tft.drawPixel(tft.width/2, tft.height/2, GREEN);
  delay(500);
  
  // line draw test
  testlines(YELLOW);
  delay(500);    
  
  // optimized lines
  testfastlines(RED, BLUE);
  delay(500);    

  testdrawrects(GREEN);
  delay(500);

  testfillrects(YELLOW, MAGENTA);
  delay(500);

  tft.fillScreen(BLACK);
  testfillcircles(10, BLUE);
  testdrawcircles(10, WHITE);
  
  Serial.println("done");
  delay(1000);
}

void loop() {
  tft.writecommand(ST7735_INVON);
  delay(500);
  tft.writecommand(ST7735_INVOFF);
  delay(500);
}

void testlines(uint16_t color) {
   tft.fillScreen(BLACK);
   for (uint16_t x=0; x < tft.width; x+=6) {
     tft.drawLine(0, 0, x, tft.height-1, color);
   }
   for (uint16_t y=0; y < tft.height; y+=6) {
     tft.drawLine(0, 0, tft.width-1, y, color);
   }
   
   tft.fillScreen(BLACK);
   for (uint16_t x=0; x < tft.width; x+=6) {
     tft.drawLine(tft.width-1, 0, x, tft.height-1, color);
   }
   for (uint16_t y=0; y < tft.height; y+=6) {
     tft.drawLine(tft.width-1, 0, 0, y, color);
   }
   
   tft.fillScreen(BLACK);
   for (uint16_t x=0; x < tft.width; x+=6) {
     tft.drawLine(0, tft.height-1, x, 0, color);
   }
   for (uint16_t y=0; y < tft.height; y+=6) {
     tft.drawLine(0, tft.height-1, tft.width-1, y, color);
   }

   tft.fillScreen(BLACK);
   for (uint16_t x=0; x < tft.width; x+=6) {
     tft.drawLine(tft.width-1, tft.height-1, x, 0, color);
   }
   for (uint16_t y=0; y < tft.height; y+=6) {
     tft.drawLine(tft.width-1, tft.height-1, 0, y, color);
   }
   
}

void testdrawtext(char *text, uint16_t color) {
  tft.drawString(0, 0, text, color);
}

void testfastlines(uint16_t color1, uint16_t color2) {
   tft.fillScreen(BLACK);
   for (uint16_t y=0; y < tft.height; y+=5) {
     tft.drawHorizontalLine(0, y, tft.width, color1);
   }
   for (uint16_t x=0; x < tft.width; x+=5) {
     tft.drawVerticalLine(x, 0, tft.height, color2);
   }
}

void testdrawrects(uint16_t color) {
 tft.fillScreen(BLACK);
 for (uint16_t x=0; x < tft.width; x+=6) { tft.drawRect(tft.width/2 -x/2, tft.height/2 -x/2 , x, x, color); } } void testfillrects(uint16_t color1, uint16_t color2) { tft.fillScreen(BLACK); for (uint16_t x=tft.width-1; x > 6; x-=6) {
   tft.fillRect(tft.width/2 -x/2, tft.height/2 -x/2 , x, x, color1);
   tft.drawRect(tft.width/2 -x/2, tft.height/2 -x/2 , x, x, color2);
 }
}

void testfillcircles(uint8_t radius, uint16_t color) {
  for (uint8_t x=radius; x < tft.width; x+=radius*2) {
    for (uint8_t y=radius; y < tft.height; y+=radius*2) {
      tft.fillCircle(x, y, radius, color);
    }
  }  
}

void testdrawcircles(uint8_t radius, uint16_t color) {
  for (uint8_t x=0; x < tft.width+radius; x+=radius*2) {
    for (uint8_t y=0; y < tft.height+radius; y+=radius*2) {
      tft.drawCircle(x, y, radius, color);
    }
  }  
}

上記のプログラムの中で、TFTの操作で中心となる関数は下記になります。

  • tft.drawPixel(x,y,color); - 指定した位置(x,y)に指定した色(color)のドットを表示します。
  • tft.drawCircle(x, y, radius, color); - 指定した位置(x,y)で指定した半径(radius)の円を描きます。
  • tft.fillRect(x1,y1, x2, y2, color); - 指定した位置1(x1,y1)から位置2(x2,y2)までの幅と高さで長方形を塗ります。
  • tft.drawString(x, y, text, color); - 指定した位置(x,y)に指定した色(color)でテキストを表示します。
  • tft.fillScreen(0x0000); - 指定した色でモニタ全体を塗ります

他にもいくつか関数はありますが、基本的にこれだけ使うだけでも豊かな表現が可能です。

 

2.加速度センサの数値をグラフにしてみる

TFTモニタの動作が確認できたら、次は加速度センサの値をTFTモニタに表示してみます。センサ評価キットの場合、加速度センサをキットに取り付けさえすれば、基本的にTFTモニタ側の配線は変更する必要はありません。

写真2 加速度センサとTFTモニタ

写真3 加速度センサとTFTモニタ

 

加速度センサの数値を表示するプログラム

#include <Wire.h>
#include <KX022.h>
#include <ST7735.h>
#include <SPI.h>


// You can use any (4 or) 5 pins 
#define sclk 4
#define mosi 5
#define cs 6
#define dc 7
#define rst 8  // you can also connect this to the Arduino reset

// Color definitions
#define	BLACK           0x0000
#define	BLUE            0x001F
#define	RED             0xF800
#define	GREEN           0x07E0
#define CYAN            0x07FF
#define MAGENTA         0xF81F
#define YELLOW          0xFFE0  
#define WHITE           0xFFFF

ST7735 tft = ST7735(cs, dc, mosi, sclk, rst);  

KX022 kx022(KX022_DEVICE_ADDRESS_1E);

int _cnt = 0;
//グラフ初期位置
int _xc = 120;
int _yc = 130;
int _zc = 140;


void fillpixelbypixel(uint16_t color) {
 for (uint8_t x=0; x < tft.width; x++) {
 for (uint8_t y=0; y < tft.height; y++) {
 tft.drawPixel(x, y, color);
 }
 }
 delay(100);
}

void setup(void) {
 byte rc;

 Serial.begin(9600);
 while (!Serial);
 Wire.begin();
 tft.initR(); // initialize a ST7735R chip
 rc = kx022.init();
 tft.fillScreen(BLACK);
 
 1.DEVICE PLUSの文字を表示
 testdrawtext("DEVICE PLUS!!", WHITE,25,50);
 delay(1000);
 tft.fillScreen(BLACK);
}

void loop() {
 //KX022
 byte rc;
 float acc[3];

//2.加速度センサの値を取得する
 rc = kx022.get_val(acc);
 if (rc == 0) {
 Serial.write("KX022 (X) = ");
 Serial.print(acc[0]);
 Serial.println(" [g]");
 Serial.write("KX022 (Y) = ");
 Serial.print(acc[1]);
 Serial.println(" [g]");
 Serial.write("KX022 (Z) = ");
 Serial.print(acc[2]);
 Serial.println(" [g]");
 Serial.println();

 //float型をchar型に変換
 char xVal[10];
 dtostrf(acc[0], 5, 2, xVal);
 char yVal[10];
 dtostrf(acc[1], 5, 2, yVal);
 char zVal[10];
 dtostrf(acc[2], 5, 2, zVal);

 //TFT液晶に変換
 //tft.fillScreen(BLACK);
 tft.fillRect(0,0, 120, 60, BLACK); 
 testdrawtext("X:", RED, 5, 15);
 testdrawtext(xVal, WHITE, 30, 15);
 testdrawtext("Y:", BLUE, 5, 30);
 testdrawtext(yVal, WHITE, 30, 30);
 testdrawtext("Z:", GREEN, 5, 45);
 testdrawtext(zVal, WHITE, 30, 45);

 //3.グラフを描画
 int x = int(acc[0]*100)+120;
 int y = int(acc[1]*100)+130;
 int z = int(acc[2]*100)+40;
 tft.drawLine(_cnt-1, _xc, _cnt, x, RED);
 tft.drawLine(_cnt-1, _yc, _cnt, y, BLUE);
 tft.drawLine(_cnt-1, _zc, _cnt, z, GREEN);

 _cnt++;
 //画面の端までいったらリセット
 if(_cnt > 120){
 _cnt = 0;
 tft.fillScreen(BLACK);
 }

 _xc = x;
 _yc = y;
 _zc = z;
 
 delay(10);
 }
 delay(10);
}

void testlines(uint16_t color) {
   tft.fillScreen(BLACK);
   for (uint16_t x=0; x < tft.width; x+=6) {
     tft.drawLine(0, 0, x, tft.height-1, color);
   }
   for (uint16_t y=0; y < tft.height; y+=6) {
     tft.drawLine(0, 0, tft.width-1, y, color);
   }
   
   tft.fillScreen(BLACK);
   for (uint16_t x=0; x < tft.width; x+=6) {
     tft.drawLine(tft.width-1, 0, x, tft.height-1, color);
   }
   for (uint16_t y=0; y < tft.height; y+=6) {
     tft.drawLine(tft.width-1, 0, 0, y, color);
   }
   
   tft.fillScreen(BLACK);
   for (uint16_t x=0; x < tft.width; x+=6) {
     tft.drawLine(0, tft.height-1, x, 0, color);
   }
   for (uint16_t y=0; y < tft.height; y+=6) {
     tft.drawLine(0, tft.height-1, tft.width-1, y, color);
   }

   tft.fillScreen(BLACK);
   for (uint16_t x=0; x < tft.width; x+=6) {
     tft.drawLine(tft.width-1, tft.height-1, x, 0, color);
   }
   for (uint16_t y=0; y < tft.height; y+=6) {
     tft.drawLine(tft.width-1, tft.height-1, 0, y, color);
   }
}

void testdrawtext(char *text, uint16_t color,int x,int y) {
  tft.drawString(x, y, text, color);
}

void testfastlines(uint16_t color1, uint16_t color2) {
   tft.fillScreen(BLACK);
   for (uint16_t y=0; y < tft.height; y+=5) {
     tft.drawHorizontalLine(0, y, tft.width, color1);
   }
   for (uint16_t x=0; x < tft.width; x+=5) {
     tft.drawVerticalLine(x, 0, tft.height, color2);
   }
}

void testdrawrects(uint16_t color) {
 tft.fillScreen(BLACK);
 for (uint16_t x=0; x < tft.width; x+=6) { tft.drawRect(tft.width/2 -x/2, tft.height/2 -x/2 , x, x, color); } } void testfillrects(uint16_t color1, uint16_t color2) { tft.fillScreen(BLACK); for (uint16_t x=tft.width-1; x > 6; x-=6) {
   tft.fillRect(tft.width/2 -x/2, tft.height/2 -x/2 , x, x, color1);
   tft.drawRect(tft.width/2 -x/2, tft.height/2 -x/2 , x, x, color2);
 }
}

void testfillcircles(uint8_t radius, uint16_t color) {
  for (uint8_t x=radius; x < tft.width; x+=radius*2) {
    for (uint8_t y=radius; y < tft.height; y+=radius*2) {
      tft.fillCircle(x, y, radius, color);
    }
  }  
}

void testdrawcircles(uint8_t radius, uint16_t color) {
  for (uint8_t x=0; x < tft.width+radius; x+=radius*2) {
    for (uint8_t y=0; y < tft.height+radius; y+=radius*2) {
      tft.drawCircle(x, y, radius, color);
    }
  }  
}

上記のプログラムを起動させると、前回紹介した加速度センサの値のグラフが表示されます。

 

プログラムの流れとしては

  1. setup内で「DEVICE PLUS!!」の文字を表示
  2. 加速度センサの値を取得して整数に直す
  3. 値をもとにグラフとテキストを表示

という流れになっています。今回はフレームごとにx軸に1を足して左から右にグラフが描画されるようにしています。端っこの120pxまでいった場合はグラフをdrawrectでクリアしています。また、上部の数字も同じようにフレーム毎に、drawrectで更新をかけています。

 

まとめ

センサ評価キットを使って、これまでたくさんのセンサや部品を扱ってきました。今回の小型のTFTモニタもそうですが、ArduinoやRaspberry Piなどの小さなコンピュータが手軽に扱えることで、普段私達が使っている普通のパソコンではできないことがアイデア次第でできるようになりました。普通のパソコンは高価なのでなかなか乱暴に扱うことができませんが、Arduinoなどは普通のパソコンに比べて比較的安価なので、たとえば今回のTFTモニタとArduino Pro miniなどを組み合わせて時計や小型ゲームを作ってみることもできますし、センサ評価キットのセンサを載せてデータロガーを作成するなんてことも可能です。

 

第50回 フルカラーLEDテープを使ったちょっとお洒落な電子工作 〜Arduinoでパーツやセンサーを使ってみよう

$
0
0

1-dsc_1726

前回まではロームセンサ評価キットを使っていろいろとセンサを使う方法を学びました。今回から、またArduinoでいろいろなパーツや他のセンサも扱っていきます!

近頃、すっかり外も寒くなってきて、ハロウィーンやクリスマスといったイベントが近づいていますね。……というわけで、そんな場に欠かせないイルミネーションでの飾り付けを作ります。もちろんチカチカだけではなく、1つ1つのLEDが制御できるフルカラーLEDを使って、Arduinoならではの工夫をしてみたいと思います!

今回の電子工作レシピ

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

※ロームセンサ評価キットは下記サイトから購入できます!
チップワンストップ
ザイコストア

目次

  1. LEDテープって何?普通のLEDとの違いについて
  2. LEDテープの接続方法、使い方
  3. 実際に光らせてみる
  4. まとめ

1.LEDテープって何?普通のLEDとの違いについて

今回利用するのは、LEDテープというパーツを使います。LEDテープはいつも本連載で使っているLEDとはちょっと違い、LEDがいくつもテープ上に連なっているパーツになっています。通常販売されているものは長さは30cmくらいのものから5mくらいまでが一般的に発売されています。

写真1 LEDテープ本体

写真1 LEDテープ本体

LEDテープの種類と特徴について

LEDテープの種類は主に2種類あります。一つ目はLEDテープの上のLEDが全てオンオフが同期しているタイプのもの。もう一つは、LEDテープのLEDを信号に応じて1つずつ個別に制御することができる制御ICが載っているものがあります。前者はLEDの数がたくさんついているものの、基本的には通常のLED同様プラスマイナスの端子のみがあるだけです。後者のLEDテープは下記写真3のように端子がプラスマイナスの他、信号用などを含めて合計4、5端子のものが一般的です。

また、LEDテープの特徴として、写真2の黄色の点線部分の接触部分を切ることで長さを調整することができます。(それ以外の部分を切ってしまうとプラスマイナス端子などの接続ができなくなります)

 

写真2 フルカラーLEDテープの仕様

写真2 フルカラーLEDテープの仕様

 

写真3 フルカラーLEDテープの端子

写真3 フルカラーLEDテープの端子

 

LEDテープ形状の面では、LEDテープは写真1のような形状以外にもイルミネーションでよく使われるようなタイプのものなど、多くの種類が存在します。

 

写真4 イルミネーションタイプのLEDテープ

写真4 イルミネーションタイプのLEDテープ

 

今回は、ハロウィンに合わせたイルミネーションをしてみたいので、このイルミネーションタイプのLEDテープを使って取り組んでみます。

 

2.LEDテープの接続方法、使い方

フルカラーLEDテープを光らせるためには、信号を制御する必要があるのですが、その処理が手軽にできる便利なライブラリがあります。下記URLのページを開き、中段にある「Download Adafruit_NeoPixel for Arduino」 と書いてあるボタンをクリックすることでライブラリのダウンロードができます。ライブラリの追加方法については、これまで何度か出てきていますので、そちらをご覧ください。

Arduino Library Installation – adafruit
https://learn.adafruit.com/adafruit-neopixel-uberguide/arduino-library-installation

図1 Adafruitのページからライブラリをダウンロード

図1 Adafruitのページからライブラリをダウンロード

zip形式のファイルがダウンロードできたら、Arduino Createの場合はライブラリページでアップしてインストール、アプリケーションを動作させている場合は、上部メニュー「スケッチ」から入っていってライブラリを追加してください。追加が完了したらLEDテープとArduinoの接続を試みます。

 

フルカラーLEDテープの接続方法

今回利用するLEDテープは5Vで、端子が4つありました。ドキュメントを確認すると、プラスマイナス(GND)とに加えて、基板側には信号端子とGND端子がありました。LEDの入力電圧は5VなのでArduinoの5Vを使いたいところですが、LEDテープはLEDの数がとても多いため、必要とする電流も多く、Arduinoの5Vを使うとArduinoに負担がかかって壊れてしまうので、外部電源で5Vを用意してください。

図2 フルカラーLEDテープの回路図

図2 フルカラーLEDテープの回路図

 

3.実際に光らせてみる

回路の準備ができたらプログラムを作成しましょう。基本的にはAdafruitのページにサンプルが掲載されていますので、それをベースにしています。

 

 

LEDテープのサンプルプログラム

#include <Adafruit_NeoPixel.h>

#define PIN 6       //信号端子のピン番号
#define LED_NUM 50  //LEDの数

Adafruit_NeoPixel ledtape = Adafruit_NeoPixel(LED_NUM, PIN, NEO_GRB + NEO_KHZ800);  //3つめのパラメータは使うLEDテープの制御ICがWS2812ならNEO_KHZ800 / WS2811ならNEO_KHZ400

void setup() {
  ledtape.begin();
  ledtape.show();   //一旦全てOFFの状態で反映
}

void loop() {
 uint16_t i, j;

 for(j=0; j <256; j++) {
   for(i=0; i < ledtape.numPixels(); i++) {
     ledtape.setPixelColor(i, rotateColor((((i) * 256 / ledtape.numPixels()) + j) & 255));
   }
   ledtape.show();
   delay(20);
 }
}

//RGBの色の移り変わり関数
uint32_t rotateColor(byte WheelPos) {
  if(WheelPos < 85) {
   return ledtape.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   return ledtape.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170;
   return ledtape.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

きちんとつながってプログラムが正常だと色鮮やかな表現でLEDが光ると思います!

写真5 ArduinoのLEDテープを光らせる

写真5 ArduinoのLEDテープを光らせる

 

また、ちょっとプログラムを変えれば1つずつ順々にLEDを光らせることも可能です。

1つずつ光らせるプログラム

#include <Adafruit_NeoPixel.h>

#define PIN 6       //信号端子のピン番号
#define LED_NUM 50  //LEDの数

Adafruit_NeoPixel ledtape = Adafruit_NeoPixel(LED_NUM, PIN, NEO_GRB + NEO_KHZ800);  //3つめのパラメータは使うLEDテープの制御ICがWS2812ならNEO_KHZ800 / WS2811ならNEO_KHZ400

void setup() {
  ledtape.begin();
  ledtape.show();   //一旦全てOFFの状態で反映
}

void loop() {
  uint16_t i, j;

//for分でLED全ての色の状態をセットして、showで光らせる
 for(i=0; i < ledtape.numPixels(); i++) {
   ledtape.setPixelColor(i, Wheel((((i) * 256 / ledtape.numPixels()) + j) & 255));
   ledtape.show();
   ledtape.setPixelColor(i, ledtape.Color(0,0,0));
   delay(20);
   ledtape.show();
 }
}

//RGBの色の移り変わり関数
uint32_t rotateColor(byte WheelPos) {
  if(WheelPos < 85) {
   return ledtape.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   return ledtape.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170;
   return ledtape.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

ハロウィンかぼちゃと一緒に組み合わせると、一気に雰囲気がでますね。

 

まとめ

今回はLEDテープの使い方の基本を学びました。次回はこれまで利用してきたロームセンサ評価キットのセンサや他のセンサを利用して、センサから入力した値をもとにLEDテープを操作するデバイスを作ってみたいと思います。

手軽に操作できてかっこいいLEDテープ、ちょっとインタラクティブなハロウィン、クリスマス、やってみませんか?

 

第51回 センサに反応して光る!フルカラーLEDテープを使ったイルミネーション電子工作 〜Arduinoでパーツやセンサーを使ってみよう

$
0
0

dsc_1759

前回はLEDテープの光らせ方の基本を学びました。今回は、センサから入力された値に応じて光り方が変わる、インタラクティブなイルミネーションを作ってみたいと思います!

今回の電子工作レシピ

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

※ロームセンサ評価キットは下記サイトから購入できます!
チップワンストップ
ザイコストア

目次

  1. センサ評価キットのセンサを使ってLEDテープを光らせる
  2. プログラムのカスタマイズについて
  3. 実際に光らせてみる
  4. まとめ

1.センサ評価キットのセンサを使ってLEDテープを光らせる

センサ評価キット本体をArduinoに装着して、センサパーツを取り付けます。第46回でも紹介した近接センサを使ってみます。完成のイメージは近接センサに手を近づけると、放射状に配置したLEDテープが手元から光を放つようなイメージで作成をしてみます。

写真1 センサ評価キットに近接センサを搭載

写真1 センサ評価キットに近接センサを搭載

いつもどおり下記の図にて、センサの取り付け箇所とセンサに必要な電圧を設定します。近接センサはI2C I/Fエリアなので青いエリアに取り付けを行い、ウェブサイトに必要電圧が書かれているのでそれを確認、近接センサは3Vなのでジャンパピンを真ん中の3Vの位置に設定します。

図1 センサ評価キットのセンサ取り付け箇所

図1 センサ評価キットのセンサ取り付け箇所

 

LEDテープの電源は前回と同様に5Vの電源を別に用意します。ArduinoのVCCや5Vから取ろうとすると、LEDテープで消費される電流が多い為、Arduinoが停止や故障してしまう可能性があるので注意してください。

 

写真2 LEDテープの電源は前回と同様に5Vの別の電源を確保します

写真2 LEDテープの電源は前回と同様にArduinoとは別に電源アダプタで5V電源を確保します

 

前回はLEDテープを1本だけつけましたが、今回はLEDテープを3本並列に接続します。接続方法は、並列なので1本の時と同じように信号線や電源、GNDは全て共通になります。接続して増やせる本数はLEDテープで実際に光らせるLEDの個数と、電源アダプターの電流容量によって変わります。

今回は、LEDテープのLED1個あたりで20mA程度、供給電流は1.3Aなので単純計算で65個くらいは一斉に点灯できますね。

図2 LEDテープの並列接続

図2 LEDテープの並列接続

 

写真2 Arduino本体から伸びるLEDテープ

写真2 Arduino本体から伸びるLEDテープ

ハード側の準備が整ったので、次はプログラムです。

 

2.プログラムのカスタマイズについて

フルカラーLEDテープを光らせるための信号制御は、「NeoPixel」というライブラリを使えば手軽にできることを前回紹介しました。今回も同様にNeoPixelを利用して進めていきます。

近接センサを入力にしたLEDテープ出力のプログラム

#include <Wire.h>
#include <RPR-0521RS.h>
#include <Adafruit_NeoPixel.h>


#define PIN 6       //信号端子のピン番号
#define LED_NUM 50  //LEDの数

RPR0521RS rpr0521rs;
Adafruit_NeoPixel ledtape = Adafruit_NeoPixel(LED_NUM, PIN, NEO_GRB + NEO_KHZ800);  //3つめのパラメータは使うLEDテープの制御ICがWS2812ならNEO_KHZ800 / WS2811ならNEO_KHZ400

int wait = 200;

void setup() {
  ledtape.begin();
  ledtape.show();   //一旦全てOFFの状態で反映
  
  byte rc;
  Serial.begin(9600);
  while (!Serial);
  Wire.begin();
  rc = rpr0521rs.init();
}

void loop() {
  byte rc;
  unsigned short ps_val;
  float als_val;
  byte near_far;
  Serial.println("=============================");
  
  rc = rpr0521rs.get_psalsval(&ps_val, &als_val);
  //センサの値が取得できたとき
  if (rc == 0) {
    Serial.print("PS:");
    Serial.print(ps_val);
    Serial.println();

    //近づいたときにLEDを発光させる
    if(ps_val > 5){
      ps_val  = 500 - ps_val;
      if(ps_val < 0){
         ps_val = 0;
      }
      simpleLED(ps_val/10);
    }
  
    if (als_val != RPR0521RS_ERROR) {
      Serial.print("ALS:");
      Serial.print(als_val);
      Serial.println();
    }
  }
  delay(5);  
}

int LEDtale[10];  //LEDの軌跡用配列

//
//個別で光らせる
//
void simpleLED(int delaytime){
  uint16_t i, j;
  j=0;
  for(i=0; i < ledtape.numPixels(); i++) {
    ledtape.setPixelColor(i, rotateColor(((i) * 256 / ledtape.numPixels()) & 255));
    LEDtale[0]  = rotateColor(((i) * 256 * 9/10 / ledtape.numPixels()) & 255);

    for(j=1; j < 10; j++){
      LEDtale[j]  = rotateColor(((i) * 256 * (10-j)/10 / ledtape.numPixels()) & 255);
      uint16_t m = i-j;
      if(m < 0){
        m += 50;
      }
      ledtape.setPixelColor(m, LEDtale[j]);
    }

    ledtape.show();
    for(j=1; j < 10; j++){
      uint16_t m = i-j;
      if(m < 0){
        m += 50;
      }
      delay(0);
      ledtape.setPixelColor(m, ledtape.Color(0,0,0));
      ledtape.show();
    }
    ledtape.setPixelColor(i, ledtape.Color(0,0,0));
    ledtape.show();
  }
  ledtape.show();
  delay(delaytime);
}


//RGBの色の移り変わり関数
uint32_t rotateColor(byte WheelPos) {
  if(WheelPos < 85) {
   return ledtape.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   return ledtape.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170;
   return ledtape.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

 

前回のプログラムと変更点は大きく2点ほどあります。1つ目は、近接センサの入力処理を加えていること、2つ目はLEDテープの光り方を変えていることです。

1つ目の近接センサの入力はセンサ評価キットのサンプルスケッチおよび、以前の記事を確認していただければと思います。ポイントはセンサから入力された数値をどう扱うかですが、単純にif文などでセンサに反応があったらLEDテープを光らせるオン/オフだけでも良いのですが、センサの値をLEDテープを光らせる関数に渡して、LEDテープの光らせ方を変えるとより一層インタラクティブ感が演出できます。

//近づいたときにLEDを発光させる
    if(ps_val > 5){
      ps_val  = 500 - ps_val;
      simpleLED(ps_val/10); //センサの値をLEDテープの光らせ方に使う
    }

 

simpleLED関数がLEDテープを光らせる関数なのですが、LEDテープの始点から終点まで1つずつ光らせる処理にしています。ただ、それだと少し演出として弱いので、今回さらに配列を利用してLEDテープがある程度線状に光るようにしています。配列には、今現在光っているLEDの位置から数えて10個前まで光り方を配列に保存しておいて、光らせるようにしています。

int LEDtale[10];  //LEDの軌跡用配列

 

この光らせ方のプログラムは、実際にいろいろ試行錯誤しながら素敵!と思うような演出にカスタマイズしてみてください。

 

3.実際に光らせてみる

準備が整ったので、光らせてみます。

手を近づけるとLEDテープがほとばしっていますね。近づける距離が変わるとLEDテープからの光の速さも変わるようになっています。

また、暗い場所で光らせると手から光が放たれているようにみえますね。

 

まとめ

今回は、センサ評価キットと組み合わせて手軽にできるインタラクティブなイルミネーションを作ってみました。これを発展させて、照明デバイス作成の回で紹介したセンサを組み合わせて気温や湿度で色や光り方を変えたり、ひたすら大きく、LEDの数も多くするなど演出次第で大規模なイルミネーションもできちゃいます。

冬シーズンに向けて街中のイルミネーションに負けずにDIYイルミネーションデバイスを作ってみてはいかがでしょうか?

 


第52回 SORACOM Airを使ってArduinoで通信できる?〜Arduinoで3G通信をする方法

$
0
0

dsc_2350

今回のテーマは、SORACOM(ソラコム)です。

昨年から何かと話題で、ArduinoやRaspberry piを使っている人であればその名前を目にしたことがあるのではないでしょうか。ひと言で言えば、「モバイルデータ通信プラットフォーム」。今回はSORACOM Airってどういうもの?という基本から、SORACOMのSIMカードを利用して、Arduinoから携帯電話と同じ通信方式の3G通信をするための方法などについて勉強していきたいと思います!

目次

  1. SORACOM(ソラコム)って何?
  2. SORACOMを使うとこれまでとどう違うの?便利なの?
  3. Arduinoで3G通信ができるシールド製品
  4. まとめ

1.SORACOM(ソラコム)って何?

まずSORACOM(ソラコム)って何でしょうか?簡単に言ってしまうならば、

IoTデバイスが3G通信する際に最適な管理機能を持ち、かつ低料金で利用できるSIMカードを備えたMVNOサービス

となります。さらに乱暴に言ってしまうならば、ArduinoやRaspberry piで作った自作デバイスに手軽に携帯電話と同じような通信機能を追加し、低料金でSIMカードを利用するためのサービスです。

写真1 SORACOMの公式ウェブサイト

写真1 SORACOMの公式ウェブサイト

IoTデバイス…?IoTって何だっけ?おさらいしてみましょう。

IoT(Internet of Things)は、これまでのコンピュータやスマートフォンなどの一般的な通信機器だけでなく、世の中のあらゆるモノ(Things)をインターネットで通信できるようにして、モノを自動制御したり、センサなどの数値で監視・計測したりすることですが、この「インターネットで通信できるように」というのが日本国内はこれまではなかなか環境が整っておらず、難しい現状がありました。そのインターネットの通信部分を手軽にかつ低料金で多様なIoTの用途に合わせて便利に扱うことができるのが、SORACOMのサービスです。

 

SORACOMの各種サービスについて

SORACOMには各種サービスがあるのですが、自作デバイスで利用する場合などは「SORACOM Air」というサービスの利用がメインになると思います。公式サイトに記載してあるSORACOM Airの特徴をみてみると、

  • LTE/3G データ通信
    (NTT ドコモのエリアで利用可能です)
  • 従量課金
    (日本向けSIMの場合、基本料金 1 日 1 枚 10 円、データ通信料は 1MB あたり 0.2 円)
  • ユーザーコンソール、API から多数の SIM を一括操作
    (ウェブ管理画面からそれぞれのSIMの様々な操作が可能)
  • 1 枚でも、1000枚以上でも、SIM をすぐに調達可能
    (使いたいと思ったらamazonですぐ注文できるのが魅力的)

となっています。

格安SIMを提供している会社はSORACOM以外にもたくさんありますが、SORACOMの場合、従量課金ということがポイントです。IoTデバイスは、基本的にデバイスの制御や計測が主となり、やりとりされるデータはコマンドや計測データです。そのデータサイズは種類にもよりますが、例えば気温・湿度・気圧・光量・風速などのようなデータを1時間に1回サーバーに送る場合を考えてみると、1回1キロバイトにも満たず、1日24Kバイトだと考えても1MB/月間に届きません。実質基本料金(1日10円×30日)=月額300円程度でSIMを利用することが可能です。

 

ということで、さっそくSORACOM Airを注文してみると…

 

写真2 SORACOM AirのSIMカード

写真2 SORACOM AirのSIMカード

このようなSIMカードが届きます。このSIMカードを、
・付属した用紙のURLと設定情報から登録を行い、
・Raspberry PiやArduinoで利用するデバイスにさして、
・設定をすると、
通信が可能になる、という流れになります。

参考:SORACOMの利用方法の流れ

では、実際にArduinoで使う場合、何がメリットで、どのようにすればよいでしょうか?

 

 

SORACOMを使うとこれまでとどう違うの?便利なの?

具体的な例として、第10回で作成した、「Arduinoで作る簡易百葉箱」を挙げてみます。この百葉箱で取得したデータを、サーバー上に常に送信してデータを蓄積していく、という機能拡張の例で考えてみましょう。

写真1 第10回で作成したArduino百葉箱

写真3 第10回で作成したArduino百葉箱

これまで本連載で扱った方法で実装を考える場合、有線・無線LANでのインターネット通信が思い浮かびます。連載当初に扱った有線LANによるイーサネットシールドを使った例や、無線LANを利用したESP-WROOM-02を使った例などがあります。これらの方法でも問題はないのですが、有線の場合は、LANケーブルの長さに依存したり、無線LANも無線LANルーターから出る電波の距離などの制限があるため、実質的には、屋内(もしくは屋内に近い屋外)での利用のみの想定になるかと思います。

 

Arduinoからサーバーへの通信方法(これまでの紹介例)

図1 これまでのサーバーへ通信する場合の方法

図1 これまでのサーバーへ通信する場合の方法

この百葉箱のようなケースでは、屋外で計測したい場合、無線LANの電波が届くところは良いですが、届かないところで使いたい場合は、近くまで無線LANルーターを持っていくか、もしくはモバイルルーターなどをセットにして設置するなどの必要があります。

 

SORACOM Airを使った場合の通信方法

図2 SORACOMを使ったサーバーへ通信する場合の方法

図2 SORACOMを使ったサーバーへ通信する場合の方法

SORACOM Airを使った場合は、図2のような構成になります。SIMカードを通じて直接3G通信を行ってサーバーにアクセスをするので、図1のように中間にインターネットへの中継をしてくれるルーターを設置する必要がありません。そのため、デバイスには電源だけ供給することができれば、通信面は場所の制限なく(NTTドコモの圏内)利用可能となります。

 

Arduinoで3G通信ができるシールド製品

では、実際にArduinoでSORACOM AirのSIMが使えるシールド製品にはどのようなものがあるか調べてみます。SORACOMにはRaspberry Piなどでも利用できるUSBドングルがあるのですが、ArduinoではUSBは利用できないため、対応している製品が限られます。

その他の形式のものはSORACOM認定モジュール一覧ページで確認することができます。その中でArduinoで比較的手軽に利用できるのは下記の製品が該当します。

写真4 SORACOM認定デバイス一覧

写真4 SORACOM認定デバイス一覧

 

d3gray
3GIM V2.0 (Tabrain社)
ATコマンド内蔵で手軽に通信設定が可能なことと、GPSモジュールが搭載されていることが特長です。マニュアルも豊富です。教育機関向けの販売などもあります。

 

その他のArduino 3G通信モジュールを利用する場合の注意点について上記の製品以外でも、「Arduino 3Gモジュール」などで検索をした場合、3G対応シールドが見つかるかと思います。しかし、その際に ひとつ注意することがあり、それは利用する3G通信モジュールが「技術基準適合証明」(通称 技適に登録)されているかどうかです。対応しているかどうか技適マーク giteki_mark が製品に表示されているか、もしくは総務省のウェブサイトから型番で確認することができます。この「技適が通っている製品」は、日本の電波法に基づいた仕様で電波を扱うことができる製品なので、利用範囲内で改造などをしない限り利用することができますが、技適が通っていない製品を利用した場合、違法行為となってしまうことがあるので注意してください。詳しくは下記の総務省のウェブサイトを参照してください。

参考:技適マーク、無線機の購入・使用に関すること – 総務省

 

まとめ

今回は、SORACOMの基本的なことから、Arduinoで利用する場合のモジュールの選択肢などについて紹介しました。Arduino × 3G通信(SORACOM Air)の組み合わせは電源だけ確保できれば場所を問わずにArduinoでIoTの可能性を持つ魅力的な組み合わせですね。充電池やバッテリーとソーラー発電などと組み合わせてどこでもおけるArduinoのIoTデバイスの開発をしてみてはいかがでしょうか。

 

■関連記事
ラズベリーパイとSORACOM Airでインターネット接続!(1)登録編

第53回 SORACOM Air×3GIMによるArduinoの3G通信〜Arduinoで3G通信をする方法

$
0
0

dsc_0071

前回紹介したSORACOM(ソラコム)のSORACOM AIRのSIMカードを利用して、今回は実際にArduinoで3G通信を試してみます。今回利用する3G通信のためのモジュールはSORACOM認定モジュールにもなっているTABrain社の3GIMを使います。

今回の電子工作レシピ

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

目次

  1. Arduinoで使える3G通信モジュール「3GIM」について
    1. 3GIMの特徴
    2. 3GIMでできること
  2. 3GIMをArduinoで使ってみる
    1. 本体の接続について
    2. SORACOM Air側の準備
    3. プログラム側の準備
    4. サンプルスケッチを動かしてみる
  3. まとめ

1. Arduinoで使える3G通信モジュール「3GIM」について

写真1 TABrain社の3GIM(Ver2.1)

写真1 TABrain社の3G通信モジュール3GIM(Ver2.1)

前回もSORACOM認定モジュール一覧のところで紹介しましたが、現在Arduinoで3G通信を考えた場合、選択肢があまりないのが現状です。その中でも、技適が通っていて国内で利用が可能なモジュールの一つであるTABrain社の3GIMを今回使ってArduinoで3G通信をしてみます。

この3GIMはNTTドコモ社のMVNO回線を利用したSIMカードを利用して3G通信が可能なモジュールで、2016年12月現在、IIJmio、SORACOM Air、DTI、So-net(0SIM含む)、BiglobeなどのSIMカードでの利用が可能になっています。

3GIMの特徴

3GIMの特徴をあげると、

  • サイズが小さい
  • 電力消費量が少ない
  • Arduinoでのライブラリ・サンプルスケッチなどが充実している
  • UART通信が可能
  • GPSモジュールも搭載している

という点があげられます。特に今回利用するArduinoのサンプルやドキュメントはサイト上およびマニュアルでかなり充実しているので、Arduinoで3G通信をするのに最適なモジュールとなっています。

[関連リンク]

3GIMでできること

実際に3GIMでできることをあげると、

  1. HTTP/GET・HTTP/POST機能(SSLも利用可)
  2. 現在時間の取得
  3. IMEI(ネットワーク利用制限携帯電話機照会)の取得
  4. 電波受信強度(RSSI)の取得
  5. UART通信速度設定など
  6. TCP/IP機能
  7. SMS送信機能
  8. SIMカードプロファイル設定機能
  9. 機内モード設定機能
  10. HL8548-GのATコマンドスルーパスモード切換え機能
  11. GPS位置情報(GPS/GGLONASS)の取得

と、豊富な機能を利用することが可能です。

 

2. 3GIMをArduinoで使ってみる

ある程度の概要がわかったところで、さっそく3GIMを使ってArduinoで3G通信をしてみたいと思います。

本体の接続について

写真2 3GIM本体と3G用アンテナ・GPS用アンテナ

写真2 3GIM本体と3G用アンテナ・GPS用アンテナ

3GIMは、本体に3G通信用のアンテナと、GPSアンテナ(別売)を接続して利用します。

写真3 アンテナ接続箇所

写真3 アンテナ接続箇所

また、本体には端子が6つあり、それぞれ写真のような役割を持っています。実際に利用する場合は、同封されているピンヘッダをこの6ピンに対してはんだ付けしてブレッドボードなどにさして利用すると便利です。

写真4 3GIMのピン配置

写真4 3GIMのピン配置

 

ピン番号 名称 機能など Arduino側
1 PWR_ON 電源のON/OFF制御(開放または0でON、1でOFF) 任意
2 RX UARTインタフェース(RX) D5ピン
3 TX UARTインタフェース(TX) D4ピン
4 IOREF PWR_ON,RX,TXのロジック電圧(1.8v~5V) 3.3V or 5V
5 VCC 電源電圧(3.3V~4.2V) ※1 3.3V
6 GND グラウンド GND

※1. 2016年12月5日より3GIMのversion2.1の販売が開始されています。V2.1では、これまでのバージョンでは最低電圧が3.3V~4.2Vではなく3.6V~4.2Vだったため、Arduinoから直接電源を取ることができず電源回路を作成する必要があったのですが、今回のバージョンから下が3.3Vとなったため、Arduinoと直接つなぐことができ(電流は1A程度の確保が必要)、回路がすっきりするようになりました。

 

3GIMはArduinoとUARTによるシリアル通信を行い操作が可能であり、送信のやりとりを行うUARTのインタフェースRX(受信)、TX(送信)はArduinoのD4、D5ピンを利用します。

写真4 3GIMとArduinoを接続

写真5 3GIMとArduinoを接続

今回1番のPWR_ONは後ほどプログラム側で指定しますがD7ピンを接続しました。

これで、Arduinoと3GIMの接続が完了したので、SIMカードとプログラムの準備に移ります。

 

SORACOM AIR側の準備

今回はSORACOM AirのSIMカードを利用することにしましたので、SORACOM AirのSIMカードを利用できる状態にしておきます。SIMカードの登録などの手順はSORACOMのサイトラズベリーパイ入門で詳しく取り上げていただいているので、そこを参考に進めてみてください。3GIMで利用できるSIMカードのサイズはmicroSIMのサイズなので、nanoSIMなどの場合は、写真のようにアダプタを装着する必要があります。

写真6 3GIM本体のSIMソケットとSIMカード

写真6 3GIM本体のSIMソケットとSIMカード

 

プログラム側の準備

プログラム側では、3GIMのサイトからライブラリをダウンロードして追加しておく必要があります。

最新版のライブラリは下記のページのダウンロード・技術情報の項目からダウンロードが可能です。2016年12月現在、Arduino UNOで利用するライブラリは「a3gim_R4.1.zip」が最新です。

3GIM(3G IoT Module) Ver2 について

写真7 Arduino UNO用3GIMライブラリ

写真7 Arduino UNO用3GIMライブラリ

ダウンロードしたzipをArduinoのIDEの上部メニュー「スケッチ」-「ライブラリをインクルード」-「.zipのライブラリをインストール」を選択して追加してください。

Arduino側へのライブラリの追加が完了したら、Arduinoで3GIMを使うための準備が完了です。

 

サンプルスケッチを動かしてみる

実際にサンプルスケッチを動かしてみます。ライブラリの追加が完了しているとArduino IDEの「ファイル」-「スケッチの例」のリストに「a3gim」という項目ができていますので、その中のサンプルを動かして、3GIMを動作させてみます。具体的な関数の役割など関しては、次回以降、実際にプログラムを作成しながら理解していきます。

サンプルプログラム – blink_led

まず3GIMが正常に接続できているか確認する意味でも、3GIMモジュール上のLEDをLチカさせるプログラムです。


// 3GIM(V2) sample sketch -- setLED

#include <SoftwareSerial.h>
#include <a3gim.h>

#define INTERVAL 1000 // Blink interval
#define baudrate 9600UL
const int powerPin = 7; // 3gim power pinIf not using power control, 0 is set.

void setup()
{
Serial.begin(baudrate);
delay(3000); // Wait for Start Serial Monitor
Serial.println("Ready.");

_retry:
Serial.print("Initializing.. ");
if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0)
Serial.println("Succeeded.");
else {
Serial.println("Failed.");
Serial.println("Shutdown..");
a3gs.end();
a3gs.shutdown();
delay(30000);
goto _retry; // Repeat
}
Serial.println("Blinking..");
}

void loop()
{
a3gs.setLED(true);
delay(INTERVAL);
a3gs.setLED(false);
delay(INTERVAL);
}

// END

setup関数内で3GIMの初期化や利用のための設定を行った後、loop関数内a3gs.setLED(true);とa3gs.setLED(false);部分でLEDをオンオフしているプログラムとなっていますね。動作させると動画のようにLEDがチカチカします。

 

サンプルプログラム-シリアルモニターで3GIMの操作

次は、3GIMに搭載されているコマンドをシリアルモニターを利用して操作するプログラムです。3GIMのマニュアルに掲載されているコマンド一覧をもとに、SORACOMのSIMカードを3GIMに設定してみます。


#include <SoftwareSerial.h>
SoftwareSerial Serial3g(4, 5);
const unsigned long baudrate = 9600;
void setup() {
Serial.begin(baudrate);
Serial3g.begin(baudrate);
pinMode(7,OUTPUT);
digitalWrite(7,HIGH); delay(5);
digitalWrite(7,LOW); //3GIMシールド電源ON
Serial.println("Ready.");
}
void loop() {
if (Serial3g.available() > 0) {
char c = Serial3g.read();
Serial.print(c);
}
if (Serial.available() > 0) {
char c = Serial.read();
Serial.print(c); // Echo back
Serial3g.print(c);
}
}

このプログラムをArduinoに書き込むとシリアルモニターに「Ready.」と表示されたあと10秒程度待って3GIMの準備ができると「Welcom to 3GIM(v2)」と表示されますので、その後コマンド入力が可能です。コマンド送信のためシリアルモニターの改行コードを「CRおよびLF」にした上で、$から始まるコマンドを送信してみてください。ここでは、下記のコマンドを入力した結果になります。

$YT – 現在の時刻を取得
$YV – ファームウェアのバージョンを表示
$PS – 「APNホスト ユーザー名 パスワード」を引数にして、SIMカードのAPN設定

 

図1 シリアルモニターでのコマンド送信

図1 シリアルモニターでのコマンド送信

最初、準備が完了する前に$YTコマンドを送信していますが、準備完了前なので、反応がなく、何も出力は表示されていません。その後、「WELCOM~」で準備完了後に再度$YTコマンドを送信していますが、今度は「NG 122 +GET」となっています。これは、SIMカードの3GIMへの設定がまだなので、NGとなっています。ですので、そのあと通信を必要としない$YVでバージョン情報はきちんと表示されることを確認したのち、$PSコマンドでSORACOM AirのAPN設定をします。設定が完了後、改めて$YTコマンドで現在の時刻取得を行うと成功して現在の時刻が表示されていることがわかります。

SORACOM Airの管理画面を確認すると、時刻取得時に発生した、データ通信が計測されていることが確認できました。

図2 SORACOM Airのデータ通信料

図2 SORACOM Airのデータ通信料

 

これで、Arduinoで3GIM使って3G通信、ようやくスタートラインに立つことができましたね!

 

まとめ

今回は3GIMの準備から簡単なサンプルスケッチの動作までを学びました。次回からはほかのサンプルのほか、Arduinoで3G通信ができるとどんなことができるのか3GIMを使っていろいろ試していきたいと思います!

 

■関連記事

SORACOM Airを使ってArduinoで通信できる?~Arduinoで3G通信をする方法
ラズベリーパイとSORACOM Airでインターネット接続!(1)登録編

第54回 SORACOM Air×3GIMによるArduinoの3G通信 その2〜Arduinoで3G通信をする方法

$
0
0

dsc_0064

前回3GIMで実際に3G通信ができるようになったので、今回はその使い方について、実例をもとに深めてみたいと思います。

今回の電子工作レシピ

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

目次

  1. 3GIMでよく利用するコマンド一覧
    1. 電波強度(RSSI)の取得(getRSSI)
    2. 通信モジュールID(固有番号)の取得(getIMEI)
    3. GPS情報の取得(getLoaction/getLocation2)
    4. SIMカードのプロファイル設定(getDefaultProfile/setDefaultProfile)
    5. HTTPによるデータの取得(httpGET/httpPOST)
  2. 定期的にデータをサーバーに蓄積してみる
  3. まとめ

1. 3GIMでよく利用するコマンド一覧

3GIMには、詳しく利用方法が書かれたマニュアルと充実したサンプルスケッチが用意されています。用途によって他にもたくさん利用するコマンドはあるのですが、今回はその中でもサーバーにデータを蓄積する例などで一般的に利用することが多いコマンドについて勉強してみます。

図1 3GIM(v2.1)のマニュアル

図1 3GIM(v2.1)のマニュアル

 

電波強度(RSSI)の取得(getRSSI)

3G通信を行う上で、通信するための電波強度を取得することができます。値は常にマイナスで、下記の数値の目安になります。主に電波強度が確保されていない場合(-113)は、通信をしないなどの判定に利用できますね。

[電波強度の目安]

  • -113:アンテナが接続されていないとき
  • -112~-90:電波受信状態が悪い状況
  • -89~-51:電波受信状態が良い状況

サンプルスケッチの場所
「ファイル」-「スケッチの例」-「a3gim」-「check_rssi」

a3gs.getRSSI(rssi)関数が実際に電波強度を取得する部分です。戻り値が0の場合、正常に取得され、関数に渡した引数(ここではrssi)に電波強度が格納されます。

※サンプルスケッチの★部分にdelay(15000);を加えています。これは、3G通信の準備が完了する前にgetRSSI関数を走らせると、RSSIがプラス値で返るなど正常に電波強度が返ってこないため、delayを入れて3G通信準備が完了するのを待ちます。


// 3GIM(V2) sample skech -- getRSSI

#include <SoftwareSerial.h>
#include "a3gim.h"

#define baudrate 9600UL
const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.)

void setup()
{
 Serial.begin(baudrate);
 delay(3000); // Wait for Start Serial Monitor
 Serial.println("Ready.");

Serial.print("Initializing.. ");
 if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) {
 Serial.println("Succeeded.");
 delay(15000); //★通信準備が整うまで待つ
 int rssi;
 if (a3gs.getRSSI(rssi) == 0) {
 Serial.print("RSSI = ");
 Serial.print(rssi);
 Serial.println(" dBm");
 }
 }
 else
 Serial.println("Failed.");

Serial.println("Shutdown..");
 a3gs.end();
 a3gs.shutdown();
}

void loop()
{
}

// END

図2 電波強度の取得

図2 電波強度の取得

成功するとこのように、電波強度が表示されます。

 

 

通信モジュールID(固有番号)の取得(getIMEI)

3GIMモジュールのID(固有番号)を取得できます。このIDはモジュール単体の固有番号になるので、複数設置した場合など、どのモジュールからデータが送られてきているか判別するケースなどに利用することができます。3GIMモジュールの表面にも固有番号が記載されています(写真1)。

写真1 IMEI番号

写真1 IMEI番号

サンプルスケッチの場所
「ファイル」-「スケッチの例」-「a3gim」-「get_imei」

a3gs.getIMEI(imei)関数の部分が実際に固有番号を取得する部分です。


// 3GIM(V2) sample sketch -- getIMEI

#include <SoftwareSerial.h>
#include <"a3gim.h">

#define baudrate 9600UL
const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.)

void setup()
{
 Serial.begin(baudrate);
 delay(3000); // Wait for Start Serial Monitor
 Serial.println("Ready.");

 Serial.print("Initializing.. ");
 if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) {
 Serial.println("Succeeded.");
 char imei[a3gsIMEI_SIZE];
 if (a3gs.getIMEI(imei) == 0) {
 Serial.print("IMEI: ");
 Serial.println(imei);
 }
 }
 else
 Serial.println("Failed.");

 Serial.println("Shutdown..");
 a3gs.end();
 a3gs.shutdown();
}

void loop()
{
}

// END

図3 3GIMの固有番号を取得

図3 3GIMの固有番号を取得

 

GPS情報の取得(getLoaction/getLocation2)

3GIMに搭載されているGPSモジュールで位置情報を取得することができます。位置情報の取得方法は、GPSのみを利用した位置情報の取得と、3G通信の基地局情報による取得、GPSと3G通信を併用した位置情報の取得です。用意されている関数はgetLocation – 緯度経度の取得のみと、getLocation2 – 緯度経度のほかに高度や使用GPS数、品質、時刻などの詳細情報を取得できる2種類があります。

 

サンプルスケッチの場所
「ファイル」-「スケッチの例」-「a3gim」-「get_location」 – getLocationの場合
「ファイル」-「スケッチの例」-「a3gim」-「get_location_agps」 – getLocation2の場合

a3gs.getLocation(a3gsMPASSISTED, lat, lng)関数の部分が実際に位置情報を取得する部分です。getLocation関数の第一引数には、a3gimMPBASED(GPS+3G通信) / a3gimMPASSISTED(3G通信のみ) / a3gimMPSTANDALONE(GPSのみ)を指定することができます。

// 3GIM(V2) sample sketch -- getLocation

#include <SoftwareSerial.h>
#include "a3gim.h"

#define baudrate 9600UL
const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.)

void setup()
{
 Serial.begin(baudrate);
 delay(3000); // Wait for start serial monitor
 Serial.println("Ready.");

 Serial.print("Initializing.. ");
 if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) {
 Serial.println("Succeeded. It maybe takes several minutes.");
 delay(15000); //3G通信準備が整うまで待つ
 char lat[15], lng[15];
 if (a3gs.getLocation(a3gsMPASSISTED, lat, lng) == 0) {
 Serial.print("OK: ");
 Serial.print(lat);
 Serial.print(", ");
 Serial.println(lng);
 }
 else
 Serial.println("Sorry, I don't know this location.");
 }
 else
 Serial.println("Failed.");

 Serial.println("Shutdown..");
 a3gs.end();
 a3gs.shutdown();
}

void loop()
{
}

// END

 

SIMカードのプロファイル設定(getDefaultProfile/setDefaultProfile)

前回シリアルモニターでも設定した、SIMカードの通信プロファイルを設定です。APNサーバー情報、ユーザー名、パスワードを3GIMに登録することができます。一度登録されたプロファイル情報は、書き換えされるまで有効となります。

今回利用しているSORACOM AirのSIMの場合は、プロファイル設定は下記のとおりになります。

  • APNサーバー情報: soracom.io
  • ユーザー名:sora
  • パスワード:sora

サンプルスケッチの場所
「ファイル」-「スケッチの例」-「a3gim」-「set_defaultprofile」

a3gs.setDefaultProfile(newApn, newUser, newPassword)関数の部分がプロファイル設定をする箇所です。
※このプログラムにもサンプルスケッチから3G通信状態の準備が完了するためのウェイトを持たせるなど少し変更を加えています。


// 3GIM(V2) sample sketch -- setDefaultProfile and getDefaultProfile

#include <SoftwareSerial.h>
#include "a3gim.h"

#define baudrate 9600UL
const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.)
// New profile
const char *newApn = "soracom.io";
const char *newUser = "sora";
const char *newPassword = "sora";

void setup()
{
Serial.begin(baudrate);
delay(3000); // Wait for Start Serial Monitor
Serial.println("Ready.");

Serial.print("Initializing.. ");
//******************************************************************
// 1.3GIMの初期設定
if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) {
Serial.println("Succeeded 1.");
delay(15000); // Wait for Start Serial Monitor

//******************************************************************
// 2.現在の3GIMに設定されているデフォルトのプロファイル情報を読み込み
char apn[20], user[20], password[20];
if (a3gs.getDefaultProfile(apn, user, password) == 0) {
Serial.print("Default Profile Number is ");
Serial.print(apn);
Serial.print(",");
Serial.print(user);
Serial.print(",");
Serial.println(password);
}
else{
Serial.println("Failed getDefaultProfile.");
}
//******************************************************************
// 3.新たにプロファイル情報をSORACOM AIRのものに設定する
// if (a3gs.setDefaultProfile(newApn, newUser, newPassword) == 0) {
int error_no = 0;
error_no = a3gs.setDefaultProfile("soracom.io", "sora", "sora");
if (error_no == 0) {
Serial.println("Succeed setDefaultProfile.");
}
else{
Serial.print(error_no);
Serial.println(":Failed setDefaultProfile.");
}

}
else{
Serial.println("Failed begin.");
}

Serial.println("Shutdown..");
a3gs.end();
a3gs.shutdown();
}

void loop()
{
}

// END

図4 3GIMのプロファイル設定

図4 3GIMのプロファイル設定

プロファイル設定が無事完了すると上記のような表示となります。

 

HTTPによるデータの取得(httpGET/httpPOST)

3G通信でウェブからデータを取得する関数です。Arduinoで利用する場合は、ウェブサイトを開いてみるという使い方よりも、APIにGET/POST形式でデータを送信する、という使い方がメインになると思います。ここでは、GET形式で通信するサンプルを例にしてみます。

 

サンプルスケッチの場所
「ファイル」-「スケッチの例」-「a3gim」-「http_get」

 

a3gs.httpGET(server, port, path, res, len)関数の部分が実際に通信をする箇所になります。引数には

  • server-ホスト(deviceplus.jpなど)
  • port-ポート(通常のhttp://で始まる場合は80、https://は443を指定)
  • path-パス(ドメイン以下のパス情報)
  • res-レスポンス内容(ここに結果が入る)
  • len-レスポンスの長さ(通常はa3gsMAX_RESULT_LENGTH+1で指定)

となります。

 


// 3GIM(V2) sample sketch -- httpGET

#include <SoftwareSerial.h>
#include "a3gim.h"

#define baudrate 9600UL
const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.)
const char *server = "www.arduino.org";
const char *path = "";
int port = 80;

char res[a3gsMAX_RESULT_LENGTH+1];
int len;

void setup()
{
Serial.begin(baudrate);
delay(3000); // Wait for Start Serial Monitor
Serial.println("Ready.");

Serial.print("Initializing.. ");
if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) {
Serial.println("Succeeded.");
Serial.print("httpGET() requesting.. ");
len = sizeof(res);
delay(15000); //3G通信の準備ができるまで待つ
if (a3gs.httpGET(server, port, path, res, len) == 0) {
Serial.println("OK!");
Serial.print("[");
Serial.print(res);
Serial.println("]");
}
else {
Serial.print("Can't get HTTP response from ");
Serial.println(server);
}
}
else
Serial.println("Failed.");

Serial.println("Shutdown..");
a3gs.end();
a3gs.shutdown();
}

void loop()
{
}

// END

 

図5 3GIMによるhttp通信

図5 3GIMによるhttp通信

 

正常に接続できた場合、lenで指定したサイズ分だけres変数に結果が格納されて表示されます。

 

2. 定期的にデータをサーバーに蓄積してみる

これまで学んだコマンドをまとめて、定期的にサーバーにデータを送信して蓄積するプログラムを書いてみます。サーバー側のプログラムに関しては、次回説明するとして、Arduino側の3GIMのプログラムは下記のようになります。

このプログラムでは、RSSI、IMEI、現時刻、GPS情報などを取得して、指定したURLにGET形式でデータを送信しています。最初に、RSSIで電波強度が確認できない場合は、再度設定をやり直すようにしています。


#include <SoftwareSerial.h>
#include "a3gim.h"

#define baudrate 9600UL
const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.)
const char *server = "deviceplus.jp"; //接続先のドメイン
const char *path = "";
int port = 80;

char res[a3gsMAX_RESULT_LENGTH+1];
int len;

String imei = "";
int rssi = 0;
float lat = 0;
float lng = 0;
int height = 0;
int utc = 0;
int number = 0;
int quality = 0;
String date = "";

void setup()
{
Serial.begin(baudrate);
delay(3000); // Wait for Start Serial Monitor
Serial.println("Ready.");
}

void loop()
{
Serial.print("Initializing.. ");
if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) {
Serial.println("Succeeded.");

delay(25000); // ウェイトを持たせる
Serial.println("httpGET() requesting.. ");
len = sizeof(res);

//***************************************************
//get rssi
//***************************************************
if (a3gs.getRSSI(rssi) == 0) {
Serial.print("RSSI = ");
Serial.println(rssi);
if(rssi < 0 || rssi <= -113 ){
//電波強度が取得できない場合は最初から
Serial.println("retry.");
return 0;
}
}
else{
//電波強度が取得できない場合は最初から
Serial.println("retry.");
return 0;
}

//***************************************************
//get imei
//***************************************************
char imei[a3gsIMEI_SIZE];
if (a3gs.getIMEI(imei) == 0) {
Serial.print("IMEI: ");
Serial.println(imei);
}
//***************************************************
//get time
//***************************************************
char date[a3gsDATE_SIZE], time[a3gsTIME_SIZE];
if (a3gs.getTime(date, time) == 0) {
Serial.print("DATE:");
Serial.print(date);
Serial.print(" ");
Serial.println(time);
}

//***************************************************
//GPS-location
//***************************************************
setupAGPS();
char lat[15], lng[15], utc[7], height[8];
if (a3gs.getLocation2(lat, lng, height, utc, &quality, &number) == 0) {
Serial.print("OK: ");
Serial.print(lat);
Serial.print(",");
Serial.print(lng);
Serial.print(",");
Serial.print(height);
Serial.print(",");
Serial.print(utc);
Serial.print(",");
Serial.print(quality);
Serial.print(",");
Serial.println(number);
}

 String pathStr = "/api.php?imei=";
 String imeiS = String(imei);
 String rssiS = String(rssi);
 String latS = String(lat);
 String lngS = String(lng);
 String utcS = String(utc);
 String qualityS = String(quality);
 String numberS = String(number);
 String heightS = String(height);
 String dateS = String(date);
 String timeS = String(time);

 pathStr = pathStr+imeiS+"&rssi="+rssiS+"&utc="+utcS+"&lat="+latS+"&lng="+lngS+"&quality="+qualityS+"&number="+numberS+"&height="+height+"&datetime="+dateS+" "+timeS;

 int rst = a3gs.httpGET(server, port, pathStr.c_str(), res, len);

Serial.print("RESULT:");
Serial.println(rst);
if (rst == 0) {
Serial.println("OK!");
Serial.print("[");
Serial.print(res);
Serial.println("]");
}
else {
Serial.print("Can't get HTTP response from ");
Serial.println(server);
}
}
else{
Serial.println("Failed.");
}
Serial.println("Shutdown..");
a3gs.end();
a3gs.shutdown();
}

// setup AGPS function
void setupAGPS()
{
char apn[20], user[20], password[20];
if (a3gs.getDefaultProfile(apn, user, password) == 0) {
char atwppp[50];
sprintf(atwppp,"at+wppp=2,4,\"%s\",\"%s\"",user,password);
Serial.println(atwppp);
a3gs.enterAT(2);
a3gSerial.println(atwppp);
delay(200);
Serial.println("Assisted GPS set OK");
}
else
Serial.println("NG: getDefaultProfile(), can't use AGPS..");
}

// END

図6 サーバーに蓄積されたデータ

図6 サーバーに蓄積されたデータ

 

まずはこれで、サーバーにデータをためれるようになりました!

まとめ

サーバーにデータがためられる環境ができましたので、次回からはセンサ評価キットやほかのセンサなどを拡張させて、スタンドアローンで動作するデータロガーを作成してみたいと思います。

 

■関連記事

SORACOM Air×3GIMによるArduinoの3G通信〜Arduinoで3G通信をする方法(2)
SORACOM Airを使ってArduinoで通信できる?~Arduinoで3G通信をする方法(1)
ラズベリーパイとSORACOM Airでインターネット接続!(1)登録編

第55回 SORACOM Air×3GIMによるArduinoの3G通信 その3~センサ評価キットと組み合わせてデータロガー作成

$
0
0

DSC_0073-2

前回、3GIMからサーバー側にデータを送信することができましたので、今回は以前利用したセンサ評価キットで実際にデータを取得して、それをサーバーに溜めていく「簡易データロガー」を作成してみます!

目次

  1. センサ評価キットとArduinoでデータを取得
  2. 取得したデータをサーバーに送信
  3. グラフ化してみる
  4. まとめ

1. センサ評価キットとArduinoでデータを取得

今回データロガーを作成するために、センサ評価キットのセンサは「第43回 複数のセンサを組み合わせた照明デバイス制作に挑戦!」で利用した気圧センサと温度センサを利用してみます。

写真1 ロームセンサ評価キット

写真1 ロームセンサ評価キット

第43回では温度センサ、気圧センサ、カラーセンサを搭載していますが、今回はカラーセンサを取り外して使います。ちなみに気圧センサと温度センサの電圧は3Vなので、センサ評価キットの電圧を決めるジャンパピンは3Vで設定します。

写真2 第43回では気圧センサとカラーセンサ、温度センサを搭載

写真2 第43回では気圧センサとカラーセンサ、温度センサを搭載

温度センサ・気圧センサの取得プログラムは下記のとおりです。


#include <Wire.h> 
#include <BD1020.h> //温度センサ用
#include <BM1383GLV.h> //気圧センサ用

BM1383GLV bm1383;//温度センサ用
int tempout_pin = A2; //温度センサ用ピン設定
BD1020 bd1020; //気圧センサ用

void setup() {

Serial.begin(9600);
while (!Serial);

//温度センサ用
bd1020.init(tempout_pin);
Serial.println("BD1020HFV Sample");

//気圧センサ用
byte rc;
Wire.begin();
rc = bm1383.init();

}

void loop() {

//************************************
//温度センサ用
//************************************
float temp;
bd1020.get_val(&temp);
Serial.print("BD1020HFV Temp=");
Serial.print(temp);
Serial.print(" [degrees Celsius], ADC=");
Serial.println(bd1020.temp_adc);

delay(500);

//************************************
//気圧センサ用
//************************************
byte rc;
float press;

rc = bm1383.get_val(&press);
if (rc == 0) {
Serial.write("BM1383GLV (PRESS) = ");
Serial.print(press);
Serial.println(" [hPa]");
Serial.println();
}
delay(500);
}

 

図1 気圧と温度が表示

図1 気圧と温度が表示

気圧と温度が正常に取得できていることが確認できたら、次はこのプログラムと3GIMの通信処理部分を組み合わせてみます。

 

2. 取得したデータをサーバーに送信

センサから取得したデータをサーバーに送信する部分を実装していきます。まず、回路に関してはセンサ評価キットシールドをArduinoの上に搭載したので、それを考慮しながら3GIMの配線をする必要があります。といっても、基本的にピン番号などは変える必要がないので、そのままArduinoに対応するセンサ評価キットのピン番号に配線すれば大丈夫です。

写真3 Arduinoの上にセンサ評価キットシールドを載せて、3GIMと接続

写真3 Arduinoの上にセンサ評価キットシールドを載せて、3GIMと接続

データを送信するプログラムは、前回のものをベースにして、データロガー自体の処理の流れとしては

  1. 各種センサから値を取得
  2. データを送信
  3. 一定時間待ってループ(1へ戻る)

となります。これを基本にして、センサの種類を増やしたり、データの送信部分を改良したり拡張を考えていくのがよいと思います。

 

センサデータ送信プログラム


// 3GIM(V2) sample sketch -- httpGET
#include <SoftwareSerial.h>
#include "a3gim.h"
#include <Wire.h>
#include <BD1020.h> //温度センサ用
#include <BM1383GLV.h> //気圧センサ用

BM1383GLV bm1383;//温度センサ用
int tempout_pin = A2; //温度センサ用ピン設定
BD1020 bd1020; //気圧センサ用

SoftwareSerial Serial3g(4,5);

#define baudrate 9600UL
const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.)
const char *server = "deviceplus.jp";
const char *path = "";
int port = 80;
char res[a3gsMAX_RESULT_LENGTH+1];
int len;

String imei = "";
int rssi = 0;
float lat = 0;
float lng = 0;
int height = 0;
int utc = 0;
int number = 0;
int quality = 0;
String date = "";

// setup AGPS function
void setupAGPS()
{
char apn[20], user[20], password[20];
if (a3gs.getDefaultProfile(apn, user, password) == 0) {
char atwppp[50];
sprintf(atwppp,"at+wppp=2,4,\"%s\",\"%s\"",user,password);
Serial.println(atwppp);
a3gs.enterAT(2);
a3gSerial.println(atwppp);
delay(200);
Serial.println("Assisted GPS set OK");
}
else
Serial.println("NG: getDefaultProfile(), can't use AGPS..");
}

void setup()
{
Serial.begin(baudrate);
Serial3g.begin(38400);

delay(3000); // Wait for Start Serial Monitor
Serial.println("Ready.");
//温度センサ用
bd1020.init(tempout_pin);
Serial.println("BD1020HFV Sample");

//気圧センサ用
byte rc;
Wire.begin();
rc = bm1383.init();

}

void loop()
{
//************************************
//1.センサからデータを取得する
//************************************

//温度センサのデータを取得
float temp;
bd1020.get_val(&temp);
Serial.print("BD1020HFV Temp=");
Serial.print(temp);
Serial.print(" [degrees Celsius], ADC=");
Serial.println(bd1020.temp_adc);

delay(500);

//気圧センサのデータを取得
byte rc;
float pressure;

rc = bm1383.get_val(&pressure);
if (rc == 0) {
Serial.write("BM1383GLV (PRESS) = ");
Serial.print(pressure);
Serial.println(" [hPa]");
Serial.println();
}
delay(500);

//************************************
//2.3GIMでデータをサーバーに送信
//************************************
Serial.print("Initializing.. ");
if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) {
Serial.println("Succeeded.");

delay(25000); // ウェイトを持たせる
Serial.println("httpGET() requesting.. ");
len = sizeof(res);

//***************************************************
//get rssi
//***************************************************
if (a3gs.getRSSI(rssi) == 0) {
Serial.print("RSSI = ");
Serial.println(rssi);
if(rssi > 0 || rssi <= -113 ){
//電波強度が取得できない場合は最初から
Serial.println("retry.");
return;
}
}
else{
//電波強度が取得できない場合は最初から
Serial.println("retry.");
return ;
}

//***************************************************
//get imei
//***************************************************
char imei[a3gsIMEI_SIZE];
if (a3gs.getIMEI(imei) == 0) {
Serial.print("IMEI: ");
Serial.println(imei);
}
//***************************************************
//get time
//***************************************************
char date[a3gsDATE_SIZE], time[a3gsTIME_SIZE];
if (a3gs.getTime(date, time) == 0) {
Serial.print("DATE:");
Serial.print(date);
Serial.print(" ");
Serial.println(time);
}

//***************************************************
//GPS-location
//***************************************************
setupAGPS();
char lat[15], lng[15], utc[7], height[8];
if (a3gs.getLocation2(lat, lng, height, utc, &quality, &number) == 0) {
Serial.print("OK: ");
Serial.print(lat);
Serial.print(",");
Serial.print(lng);
Serial.print(",");
Serial.print(height);
Serial.print(",");
Serial.print(utc);
Serial.print(",");
Serial.print(quality);
Serial.print(",");
Serial.println(number);
}

String pathStr = "/api.php?imei=";
String tempS = String(temp); //温度センサの値
String pressureS = String(pressure); //気圧センサの値
String imeiS = String(imei);
String rssiS = String(rssi);
String latS = String(lat);
String lngS = String(lng);
String utcS = String(utc);
String qualityS = String(quality);
String numberS = String(number);
String heightS = String(height);
String dateS = String(date);
String timeS = String(time);

pathStr = pathStr+imeiS+"&rssi="+rssiS+"&rssi="+tempS+"&="+pressureS+"&utc="+utcS+"&lat="+latS+"&lng="+lngS+"&quality="+qualityS+"&number="+numberS+"&height="+height+"&datetime="+dateS+"%20"+timeS;

int rst = a3gs.httpGET(server, port, pathStr.c_str(), res, len);

Serial.print("URL:");
Serial.println(server);
Serial.println("");
Serial.print("PATH:");
Serial.println(pathStr);

Serial.print("RESULT:");
Serial.println(rst);
if (rst == 0) {
Serial.println("OK!");
Serial.print("[");
Serial.print(res);
Serial.println("]");
}
else {
Serial.print("Can't get HTTP response from ");
Serial.println(server);
}
}
else{
Serial.println("Failed.");
}
Serial.println("Shutdown..");
a3gs.end();
a3gs.shutdown();
}

// END

 

図2 温度センサと気圧センサの値を送信

図2 温度センサと気圧センサの値を送信

 

シリアルモニタで正常に送信できていることが確認できました。ただ、今回コンパイルをした際に「スケッチで使用できるメモリが少なくなってしまっています。動作が不安定になる可能性があります」との表示がArduinoのソフトウェアに表示されました。

10851711163c8349f328d1648b8086d7

プログラムが処理が多くArduino内のメモリが少なくなると、Arduinoの実行時にメモリを多く使う処理などが走った際にArduinoが正常に動作しなくなってしまう可能性があります。このような場合は、メモリの多い別のArduinoを利用するか、無駄な処理をできるだけ削除してメモリを軽くするかどちらかの対策をとると良いです。

 

3. グラフ化してみる

せっかくなので、前回は表で表示するだけだったサーバー側も、少し手を加えてグラフで表示してみます。サーバーサイドでの表示は、プログラムや方法がいろいろあるので、自分がやりやすい方法を選択してもらえればよいのですが、手軽にグラフを表示できるサービスとして、Google Chartsを今回使ってグラフ化してみました。Google Chartsはjavascriptでシンプルな表記で様々な種類のグラフを表示することができるので、簡単にデータを表示したい場合などに適しています。

 

図3 Google Charts

図3 Google Charts

Google Chartsのページで紹介されているサンプルコードを見ていただくとわかるのですが、javascriptのプログラム部分に表示したいデータやグラフの設定を行い、表示したいタグのIDを指定することでグラフの表示が可能です。

実際に取得した気圧、温度をグラフにしたのが下記の図です。

図4 気圧・温度をグラフで表示

図4 気圧・温度をグラフで表示

グラフで表示されるとわかりやすくなりますね(今回の例ではあまり変動がありませんでしたが)。

 

まとめ

簡易的ですがデータロガーが完成しました。これでいつでも好きな場所でセンサデータを取得できるようになりましたが、まだ大きな課題が残されています。それはやはり「電源」。常時データロガーをオンにしておくと、電源が常に必要になってしまい、せっかく3G通信でどこでも通信できても電源の確保が必要になってしまいます。次回はデータロガーの電源周りの対策について考えてみます。

 

■関連記事

SORACOM Air×3GIMによるArduinoの3G通信〜センサ評価キットと組み合わせてデータロガー作成(3)
SORACOM Air×3GIMによるArduinoの3G通信〜Arduinoで3G通信をする方法(2)

SORACOM Airを使ってArduinoで通信できる?~Arduinoで3G通信をする方法(1)
ラズベリーパイとSORACOM Airでインターネット接続!(1)登録編

第56回 SORACOM Air×3GIMによるArduinoの3G通信 その4~Arduinoのsleepモードで省エネ実装

$
0
0

DSC_0081

前回、3GIMとセンサ評価キットを使って簡易のデータロガーを作成しました。今回は、実際の運用をする場合を想定して一番のネックになる電源について、Arduinoのスリープ機能を使って省電力での稼働を目的に実装を行ってみたいと思います。

目次

  1. スリープ機能ってなに?
  2. 基本的なスリープ処理の流れと種類
  3. 実際にスリープを試してみる
  4. まとめ

1. スリープ機能(sleep)ってなに?

スリープ機能(sleep)は、その名のとおりArduinoの処理を停止(寝かせる)する機能です。みなさんもパソコンを利用されていれば電源を消そうとする際に「シャットダウン」・「スリープ」(または休止)などという選択肢で見たことがあると思います。詳細は後述するとして、スリープ機能はArduinoの動作を必要最低限にして、消費電力を節約するときに利用します。

データロガーなどのように、実際にデータを取得して送信して、また3分後に同じ処理を繰り返すなどといった動作の場合、その3分間はArduinoは何の処理もしていない状態なので、これまでの場合であればdelay(180000);として、3分間待つようにしています。しかし、Arduinoの基本的な電力は消費されている状態です。このような場合にスリープ機能が役に立ちます。
※実際にはArduinoの基盤には色々な機能をもった部品が動いているため、極限まで省エネで稼働させる場合はCPUと最小限の部品の状態で稼働させる必要があります。

図1 通常稼動とスリープ機能を稼動させた場合

図1 通常稼動とスリープ機能を稼動させた場合

 

 

2. 基本的なスリープ処理の流れと種類

Arduinoには色々なモードのスリープ機能を使うことができます。スリープの実行中はArduinoに処理をさせることができないため、再度処理をさせたい場合は、スリープから復帰させる必要があります。復帰の方法は「割り込み」処理をしたり、Arduino自体をリセットさせるなどスリープの種類で変わってきます。

スリープ機能自体は、Arduinoのこのページに、基本的な説明とサンプルが記載されています。

 

「割り込み」ってなに?

割り込み処理とは、たとえるならばAさんがある一つの作業をやっているところに、Bさんから「Aさんちょっとその作業よりも僕の作業をお願いしたいのだけれども」と作業を依頼された際に、自分の作業よりもBさんの作業を優先(割り込み)させて処理するのが、割り込み処理のイメージになります。

これまでのArduinoのプログラムであれば、loop関数の中で、上から順に処理を実行して、たとえばセンサのデータを取得する関数が呼ばれた際に、その値を取得していましたが、割り込み処理を担った場合、任意のタイミング(たとえばボタンを押された場合)で割り込み処理を発生させて、データの取得を優先させる、などということも可能になります。

この割り込み処理を使って、スリープ状態のArduinoに割り込み処理で復帰を実行することができます。

Arduinoでの割り込み処理

この割り込み処理はArduinoの場合、attachinterrupt()という関数を使って実現できます。この関数は、Arduinoで割り込み処理が可能な2番ピン・3番ピンの信号が変化した場合(※1)、割り込み処理を実行することができるようになっています。
※1.Arduinoの種類や搭載されているCPUによっては他のピンも動作させることが可能です


attachInterrupt([1.利用するピン設定], [2.実行する関数], [3.割り込み発生のタイミング設定])

  1. 利用するピン設定
    0-2番ピン、1-3番ピンを設定します。
  2. 実行する関数
    割り込み処理が発生したときに実行したい関数を指定することができます。
  3. 割り込み発生のタイミング設定
    信号がどのように変化した時に割り込み処理を発生させるかを設定できます。設定できるタイミングは下記の4つです。
    LOW:信号がLOWの状態(入力がない場合)、LOWの限りは割り込み処理が何回でも発生します。
    CHANGE:LOW⇔HIGHで変化したときに発生
    RISING:LOW→HIGHに変化したときに発生
    FALLING:HIGH→LOWに変化したときに発生

 

下記のプログラムでは、割り込み処理を使って、2番ピンの入力信号が変わったらLEDを光らせる例です。

割り込み処理のサンプルプログラム


int ledPin = 13; //LEDのピン番号
volatile int state = LOW; //割り込みピン信号の状態

void setup(){
pinMode(ledPin, OUTPUT);
attachInterrupt(0, blink, CHANGE); //0-2番ピンを指定して、信号変化の際にblink関数を実行
}

void loop(){
digitalWrite(ledPin, state); //割り込みピン信号の状態をそのままLED表示に
}

void blink(){
state = !state; //割り込み処理が呼ばれたら状態を変更させる
}

図2.割り込み処理の回路

図2.割り込み処理の回路

写真1 割り込み回路

写真1 割り込み回路

トグルスイッチを切り替えると2番ピンがLOW-HIGHと切り替わるので、それによって割り込み処理が発生してLEDが光ったり消えたりするのが確認できますね。

基本的にはこの割り込み処理を使って、スリープ状態からArduinoを復帰させることができます。割り込み処理に関しては、もっと詳しく学んでいくと色々な制約や使い方ができますので、気になる方は調べてみてください。

 

スリープの種類

Arduinoのスリープ機能は下記の5種類あるようです。スリープの種類によって省エネ効率や、復帰できる方法が違うようですね。復帰の方法は各モードで違うようですが、基本的には先ほどの割り込みでいけるようなので、実際に動かしながら試してみたいと思います。

モード 説明 省エネ効率
SLEEP_MODE_PWR_IDLE アイドル状態、システムクロックは停止するが、内臓タイマーや外部割込み、シリアルポートなどの機能は動作します。復帰方法は外部割込み、ウォッチドッグタイマー、ADCの入力変化、リセットピンによる復帰が可能 普通
SLEEP_MODE_PWR_ADC AD変換ノイズ低減用に利用されます(ADC対応のAVRでないと利用不可)
SLEEP_MODE_PWR_DOWN パワーダウンモード、最低限の動作のみのもっとも消費電力が少なくなるモード。外部割込み、ウォッチドッグタイマー、リセットピンによる復帰が可能。 もっとも高い
SLEEP_MODE_PWR_SAVE パワーセーブモード、タイマー用の外部発信器は動作しているので、外部割込み、ウォッチドッグタイマー、リセットピンによる復帰が可能。 高い
SLEEP_MODE_PWR_STANDBY スタンバイモード、パワーダウンと比べて、メインクロックが動作しているので復帰が少しだけ早いモードです。 かなり高い

3. 実際にスリープを試してみる

スリープ機能の一連の流れがわかったところで、実際にプログラムを動かして試してみます。このプログラムでは、先ほどの割り込み処理の回路を使って、シリアルモニターから「S」が入力されるとスリープモードに入り、トグルスイッチをLOWの状態にするとスリープモードから復帰するような流れになっています。

 

vol56-1

 

スリープ機能のサンプルプログラム


#include <avr/sleep.h>
int wakePin = 2; //割り込み用のピン番号

void wakeUpNow(){
Serial.println("wake up!"); //復帰時にシリアルモニターに表示
delay(500);
}

void setup()
{
pinMode(wakePin, INPUT);
Serial.begin(9600);
}

void sleepNow(){
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //スリープモードの設定
sleep_enable(); //スリープを有効にする

attachInterrupt(0,wakeUpNow, LOW); //割り込み処理の設定
sleep_mode(); //指定したモードでスリープを開始
sleep_disable(); //割り込みによってスリープから復帰
detachInterrupt(0); //割り込み処理を解除する
}

void loop()
{
if (Serial.available()) { //シリアルモニターからの入力があった場合
int val = Serial.read();
if (val == 'S') { //"S"が入力された場合にスリープモードにする
Serial.println("Goodnight!");
delay(100);
sleepNow(); //スリープモードにする
}
}
Serial.println("Awake!"); //動作中の表示
delay(500);
}

図3 Sleep状態→復帰の様子

図3 Sleep状態→復帰の様子

シリアルモニタ上で「S」を入力するとGoodnight!の表示とともに、Arduinoがスリープモードに入ります。その後、トグルスイッチでスリープモードから復帰していることが確認できました。

では、スリープは実装できたようですが、実際に一定時間動かすためにはどうすれば良いでしょうか?それにはスリープ時でも一定時間計測して、一定時間経過すると割り込み処理をしてくれるウォッチドッグタイマという機能を利用します。

ウォッチドッグタイマのプログラムは今回ラジオペンチさんのブログで紹介されているdelayWDTという関数を利用してウォッチドッグを使ったスリープの実装を試してみます。この関数では最大8秒間スリープをかけることができるので、8秒毎にスリープモードから復帰させた際にカウントアップをさせた変数を見てデータの取得タイミングであればその処理を、違うのであれば再度スリープに入る、という処理を組み入れることで、一定時間毎での処理が可能となります。

 

定期的なスリープ実装プログラム

#include <avr/sleep.h>
#include <avr/wdt.h>
int wakePin = 2; //割り込み用のピン番号
int ledPin = 13;

volatile int wdt_cycle = 0; 
volatile int wdt_counter = 0; 

/*
 * ウォッチドッグ処理の参考元:2014/11/17 ラジオペンチさん http://radiopench.blog96.fc2.com/
 */
void delayWDT_setup(unsigned int ii) { // ウォッチドッグタイマーをセット。
 // 引数はWDTCSRにセットするWDP0-WDP3の値。設定値と動作時間は概略下記
 // 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms
 // 6=1sec, 7=2sec, 8=4sec, 9=8sec
 byte bb;
 if (ii > 9 ){ // 変な値を排除
 ii = 9;
 }
 bb =ii & 7; // 下位3ビットをbbに
 if (ii > 7){ // 7以上(7.8,9)なら
 bb |= (1 << 5); // bbの5ビット目(WDP3)を1にする
 }
 bb |= ( 1 << WDCE );

 MCUSR &= ~(1 << WDRF); // MCU Status Reg. Watchdog Reset Flag ->0
 // start timed sequence
 WDTCSR |= (1 << WDCE) | (1<<WDE); // ウォッチドッグ変更許可(WDCEは4サイクルで自動リセット)
 // set new watchdog timeout value
 WDTCSR = bb; // 制御レジスタを設定
 WDTCSR |= _BV(WDIE);
} 

ISR(WDT_vect) { // WDTがタイムアップした時に実行される処理
 // wdt_cycle++; // 必要ならコメントアウトを外す
}


void delayWDT(unsigned long t) { // パワーダウンモードでdelayを実行
 Serial.println("Goodnight!"); //動作中の表示
 delay(100);

 delayWDT_setup(t); // ウォッチドッグタイマー割り込み条件設定
 ADCSRA &= ~(1 << ADEN); // ADENビットをクリアしてADCを停止(120μA節約)
 set_sleep_mode(SLEEP_MODE_PWR_DOWN); // パワーダウンモード
 sleep_enable();

 sleep_mode(); // ここでスリープに入る

 sleep_disable(); // WDTがタイムアップでここから動作再開 
 ADCSRA |= (1 << ADEN); // ADCの電源をON } void setup() { pinMode(wakePin, INPUT); Serial.begin(9600); } void loop(){ Serial.println("Awake!"); //動作中の表示 delay(50); delayWDT(9); // 8sec wdt_counter++; if( wdt_counter > 10 ){
 digitalWrite(ledPin,HIGH);
 delay(3000);
 digitalWrite(ledPin,LOW);
 wdt_counter=0;
 }
 Serial.print("WakeUp!:"); //動作中の表示
 Serial.println(wdt_counter);
}
図4 スリープ毎にカウントアップして10になったらLEDを光らせて最初から

図4 スリープ毎にカウントアップして10になったらLEDを光らせてカウントリセット

これで、スリープ機能の実装が完了したので、これまで実装したデータロガーと組み合わせてみます。最終的なプログラムはこちらです。前回のプログラムからは、ウォッチドッグによるスリープの追加と、時刻の取得をサーバーサイドに任せて3GIM側では取得しないようにしたこと、送信のパラメータを省略して送付するデータ量を調整しています。

データロガープログラム

// 3GIM(V2) sample sketch -- httpGET
#include <SoftwareSerial.h>
#include "a3gim.h"
#include <Wire.h> 
#include <BD1020.h> //温度センサ用
#include <BM1383GLV.h> //気圧センサ用
#include <avr/sleep.h>
#include <avr/wdt.h>

BM1383GLV bm1383;//気圧センサ用
int tempout_pin = A2; //温度センサ用ピン設定
BD1020 bd1020; //温度センサ用

//スリープ・ウォッチドッグ用
int wakePin = 2; //割り込み番号指定(実際は0→1ピンを指定/1→2ピンを指定)
bool initFlg = true;
volatile int wdt_cycle = 0; 
volatile int wdt_counter = 0; 

SoftwareSerial Serial3g(4,5);

#define baudrate 9600UL
const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.)
const char *server = "deviceplus.jp";
const char *path = "";
int port = 80;

char res[a3gsMAX_RESULT_LENGTH+1];
int len;

String imei = "";
int rssi = 0;
float lat = 0;
float lng = 0;
int height = 0;
int utc = 0;
int number = 0;
int quality = 0;
String date = "";

/*****************************************/
/*
 * ウォッチドッグ処理の参考元:2014/11/17 ラジオペンチさん http://radiopench.blog96.fc2.com/
 */
/*****************************************/
void delayWDT_setup(unsigned int ii) { // ウォッチドッグタイマーをセット。
 // 引数はWDTCSRにセットするWDP0-WDP3の値。設定値と動作時間は概略下記
 // 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms
 // 6=1sec, 7=2sec, 8=4sec, 9=8sec
 byte bb;
 if (ii > 9 ){ // 変な値を排除
 ii = 9;
 }
 bb =ii & 7; // 下位3ビットをbbに
 if (ii > 7){ // 7以上(7.8,9)なら
 bb |= (1 << 5); // bbの5ビット目(WDP3)を1にする
 }
 bb |= ( 1 << WDCE );

 MCUSR &= ~(1 << WDRF); // MCU Status Reg. Watchdog Reset Flag ->0
 // start timed sequence
 WDTCSR |= (1 << WDCE) | (1<<WDE); // ウォッチドッグ変更許可(WDCEは4サイクルで自動リセット)
 // set new watchdog timeout value
 WDTCSR = bb; // 制御レジスタを設定
 WDTCSR |= _BV(WDIE);
} 

ISR(WDT_vect) { // WDTがタイムアップした時に実行される処理
 // wdt_cycle++; // 必要ならコメントアウトを外す
}


void delayWDT(unsigned long t) { // パワーダウンモードでdelayを実行
 Serial.println("Goodnight!"); //動作中の表示
 delay(100);

 delayWDT_setup(t); // ウォッチドッグタイマー割り込み条件設定
 ADCSRA &= ~(1 << ADEN); // ADENビットをクリアしてADCを停止(120μA節約)
 set_sleep_mode(SLEEP_MODE_PWR_DOWN); // パワーダウンモード
 sleep_enable();

 sleep_mode(); // ここでスリープに入る

 sleep_disable(); // WDTがタイムアップでここから動作再開 
 ADCSRA |= (1 << ADEN); // ADCの電源をON (|=が!=になっていたバグを修正2014/11/17)

}
/*****************************************/
/* END WATCH DOG / SLEEP */
/*****************************************/

// setup AGPS function
void setupAGPS()
{
 char apn[20], user[20], password[20];
 if (a3gs.getDefaultProfile(apn, user, password) == 0) {
 char atwppp[50];
 sprintf(atwppp,"at+wppp=2,4,\"%s\",\"%s\"",user,password);
 Serial.println(atwppp);
 a3gs.enterAT(2);
 a3gSerial.println(atwppp);
 delay(200);
 Serial.println("Assisted GPS set OK");
 }
}



void setup()
{
 Serial.begin(baudrate);
 Serial3g.begin(38400);
 pinMode(wakePin, INPUT);

 delay(3000); // Wait for Start Serial Monitor
 
 //温度センサ用
 bd1020.init(tempout_pin);
 
 //気圧センサ用
 byte rc;
 Wire.begin();
 rc = bm1383.init();
}

void loop()
{
 wdt_counter++;
 //初回を除き、カウンターが10以下なら再度スリープ状態へ
 if(!initFlg && wdt_counter < 10 ){ delayWDT(9); // 8sec return; } if(wdt_counter >= 10 ){
 wdt_counter = 0;
 }
 initFlg = false;

 //************************************
 //1.センサからデータを取得する
 //************************************

 //温度センサのデータを取得
 float temp;
 bd1020.get_val(&temp);

 //気圧センサのデータを取得
 byte rc;
 float pressure; 
 rc = bm1383.get_val(&pressure);

 //************************************
 //2.3GIMでデータをサーバーに送信
 //************************************
 if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) {

 delay(25000); // ウェイトを持たせる
 len = sizeof(res);

 //***************************************************
 //get rssi
 //***************************************************
 if (a3gs.getRSSI(rssi) == 0) {
 if(rssi > 0 || rssi <= -113 ){
 //電波強度が取得できない場合は最初から
 Serial.println("retry.");
 return;
 }
 }
 else{
 //電波強度が取得できない場合は最初から
 Serial.println("retry.");
 return ;
 }

 //***************************************************
 //get imei
 //***************************************************
 char imei[a3gsIMEI_SIZE];
 if (a3gs.getIMEI(imei) == 0) {
 }


 //***************************************************
 //GPS-location
 //***************************************************
 setupAGPS();
 char lat[15], lng[15], utc[7], height[8];
 if (a3gs.getLocation2(lat, lng, height, utc, &quality, &number) == 0) {
 }

 String pathStr = "/api.php?i=";
 String tempS = String(temp);
 String pressureS = String(pressure);
 String imeiS = String(imei);
 String rssiS = String(rssi);
 String latS = String(lat);
 String lngS = String(lng);
 String utcS = String(utc);
 String qualityS = String(quality);
 String numberS = String(number);
 String heightS = String(height);
 String dateS = String(date);

 pathStr = pathStr+imeiS+"&r="+rssiS+"&p="+pressureS+"&t="+tempS+"&u="+utcS+"&lat="+latS+"&lng="+lngS+"&q="+qualityS+"&n="+numberS+"&h="+height;

 Serial.println(pathStr);

 int rst = a3gs.httpGET(server, port, pathStr.c_str(), res, len);

 
// Serial.print("RESULT:");
 Serial.println(rst);
 if (rst == 0) {
 Serial.println("OK!");
 }
 }
 else{
 Serial.println("Failed.");
 }
 Serial.println("Shutdown..");
 a3gs.end();
 a3gs.shutdown();
}

// END
写真2 モバイルバッテリーでデータロガーを稼働

写真2 モバイルバッテリーでデータロガーを稼働

これで、定期的にデータを取得してサーバーに送信するデータロガーが完成しました。これであればデータの取得間隔を1日数回などにすればモバイルバッテリーや電池などでも長期間の運用が可能ですね。ソーラーパネルで発電することで、さらに長期間安定した運用なども可能になるかと思います。

 

まとめ

今回、実際の長期間の運用も想定してデータロガーにスリープ機能を実装して定期的な観測が可能になりました。使い方や工夫次第でやりたいことが実現できるArduino、ラズパイやmbedなど他にも色々なマイコンがありますが、それぞれ長所・短所があるので、それらを学びながらArduinoをもっと楽しめるようになりたいと思います!

 

■関連記事

SORACOM Air×3GIMによるArduinoの3G通信〜センサ評価キットと組み合わせてデータロガー作成(3)SORACOM Air×3GIMによるArduinoの3G通信〜Arduinoで3G通信をする方法(2)
SORACOM Airを使ってArduinoで通信できる?~Arduinoで3G通信をする方法(1)
ラズベリーパイとSORACOM Airでインターネット接続!(1)登録編

Viewing all 58 articles
Browse latest View live