Arduino的なもので作る、環境センサIoT(ダストセンサ編)
2017年04月05日 水曜日
CONTENTS
こんにちは。ビッグデータ技術課で「IIJ IoTサービス」を担当しているsnaraです。
本サービスは昨年末にサービスインし、順調に引き合いをいただいております。
ところで、みなさんは「IoT」と聞いてどのようなことを思いつくでしょうか?
「何かすごいことができそう」と言うような印象をお持ちの方は多いと思いますが、具体的に何ができるのかピンと来ない方がまだ多いのではないかと思います。
IIJ IoTサービスは、センサなどから取得したデータを閉域のモバイル回線で送信し、そのデータを可視化(グラフ化)したり、データ保存して分析に活用したり、というプラットフォームを提供するサービスです。
あくまで提供するものは「プラットフォーム」ですので、それをどのように利用するのかはユーザ様次第です。ビジネスに繋げるためにIoTを利用して何をしたいのかを考えるのではなく、ビジネスをする上でIoTをいかに役立てるのかを考える必要があります。
弊社のIIJ IoT特設ページに書かれている通り、IoTはさまざまな場面で利用可能です。
工場の機械のメンテナンス時期を把握するために稼働状況をセンサで取得して全機械の状況を一元で可視化したい、というのはよくある話です。
弊社内で出てきた話としては、会議室が予約されているのに実際には使われていない場面がよく見受けられるので、会議室に人感センサを設置して利用状況を可視化できないか、と言うものもありました。
実際にセンサ機器を作ってみる
今回は、IIJ IoTサービスを使うにあたり一番最初に課題になるであろう、IIJ IoTサービスにデータを送るためのセンサ機器を作ってみようと思います。
センサ機器は素人でも自作することが可能です。
今回はごく一般的に入手できる機器・部品を使ってセンサ機器を試作してみます。
ちなみに、私自身は文系出身のソフトウェアエンジニアであり、今回のようなハードウェア関係の作業にはほとんど携わったことはありません。
果たしてこのようなド素人な私でもセンサ機器は作れるものなのでしょうか。
なお、本来はビジネス用途で使用されるセンサ機器は過酷な環境下で稼働することが多く、それを考慮したハードウェアが使われます。
今回はあくまでプロトタイプを作成するようなイメージでお考えください。
今回はオフィス環境の可視化を目的に
今回は、オフィス内にどれだけのダスト(ほこり)が舞っているのかを確認するためのセンサ機器を作成し、IIJ IoTサービスを使用して空気の綺麗さを可視化しようと思います。
IIJ IoTサービスで使用するセンサ機器を作成していくにあたり、必要なものは以下の通りです。
- センサ
狭義で言うセンサのハードウェアです。
ICチップや小型基板などで提供されたり、大掛かりなハードウェアが使用されたりなど、センサの種類により形はまちまちです。
今回は、SHARP製のGP2Y1010AU0Fという型番のダストセンサを使用します。 - デバイスゲートウェイ
センサから取得した値を、通信機器を利用してIIJ IoTサービスにデータ送信するためのハードウェアです。
PCを使っても良いのですが、通常はIoTに適した小型なマイコン機器が利用されます。
今回は、Arduino互換機として使えるESP-WROOM-02開発ボードを使用します。 - 通信機器
IIJ IoTサービスは閉域のモバイル通信でデータを送受信します。
IIJ IoTサービス専用のデータ通信SIMが提供されますので、モバイルデータ通信機器が必要です。
今回はNTTドコモのモバイルWi-Fiルータを使用します。 - その他
配線に必要なワイヤーやブレッドボード(基板)、ハンダなど、基本的なパーツ類も用意します。
組み立てと配線とソースコード実装
今回はArduino互換機を使用してセンサ機器を作成します。
ArduinoとはArduino社が開発したマイコンボードで、安価かつ容易に使えることもあり、世界中の多くの電子工作愛好家たちに利用されています。あくまでPCではなくマイコンボードですので、ファームウェアに書き込んだ1本のプログラムを単独で動かすようなイメージです。
今回は、純正のArduinoではなく互換機のESP-WROOM-02開発ボード(以下ESPと略します)を使用します。
ESPは本来はWi-Fi通信させるためのパーツの1つなのですが、ファームウェアを書き換えることでArduino互換機に変身します。
詳しくは検索すれば多くの情報がありますのでここでは省略しますが、ESPはWi-Fi通信ができる安価なArduino互換機として重宝されています。
このESPにピンをハンダ付けするところから開始です。
自分がハンダ付けをしたのは、ウン十年前の中学の技術の授業以来だと記憶しています。
慣れない手つきで時間をかけて、なんとかハンダ付けは終了。
明らかに見た目は悪い結果になってしまいましたが、動作は確認できたので問題なしです。
非常に残念なハンダ付けがされた、ESP-WROOM-02開発ボード
このESPをブレッドボードに差し込んだあとは、ダストセンサをESPに配線する作業です。
このダストセンサは6本のワイヤーがあり、当然ながらすべて決められた通りに配線しないと正しく動作しません。
しかし、この手のセンサには説明書がついていない場合がほとんどで、多くの場合はインターネットからダウンロードできる「データシート」が頼りになります。
なお、今回は単にワイヤーを配線するだけでなく抵抗やコンデンサも使用する必要がありました。
今回の配線図は以下の通りです。
(この図はフリーソフトのfritzingで作成しました。非常に有用なソフトです。)
配線図だときれいに見えるのですが、実物はこちら。
全体像
上から
SHARP GP2Y1010AU0F ダストセンサを正面から
…と言った感じで、非常に残念な見た目です(笑)
なお、ダストセンサは縦置きする必要があるため、ブロックで「台座」を作りました。
配線の次は、ソースコードの実装です。
センサから値を取得し、モバイルWi-Fiルータを介してIIJ IoTサービスにデータを送信するためのプログラムを作成します。
Arduino(互換機)はC/C++ライクな(と言うかほぼC/C++)言語が用いられます。
ESPのソースコードの実装はArduino純正のIDEが使用できますし、さまざまな関数・ライブラリ類があらかじめ用意されているため、比較的簡単に実装可能です。
今回作成したソースコードは以下の通りです。
#include <ESP8266Wi-Fi.h> #include <ESP8266HTTPClient.h> #include <list> #define DEBUG 0 /* ------------------------------------------------------------- Wi-Fi settings -------------------------------------------------------------*/ #define Wi-FiSSID "********" //IDとパスワードはマスクしてあります #define PASSWORD "****************" void Wi-Fi_setup(void) { #if !DEBUG Wi-Fi.begin(Wi-FiSSID, PASSWORD); while (Wi-Fi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("Wi-Fi connected"); Serial.print("IP address: "); Serial.println(Wi-Fi.localIP()); #endif } /* ------------------------------------------------------------- Dust sensor variable -------------------------------------------------------------*/ #define LED_PIN 2 #define DUST_PIN A0 #define SAMPLINGTIME 280 #define DELTATIME 40 #define SLEEPTIME 9680 #define DUST_HISTORY_MAX 5 std::list<float> dustDensityHistory; float dust = 0.; /* ------------------------------------------------------------- Dust sensor setup -------------------------------------------------------------*/ void GP2Y1010_setup() { pinMode(LED_PIN, OUTPUT); } /* ------------------------------------------------------------- Dust sensor loop -------------------------------------------------------------*/ void GP2Y1010_loop() { digitalWrite(LED_PIN, LOW); delayMicroseconds(SAMPLINGTIME); float analogvalue = analogRead(DUST_PIN); //read analog pin / Dust value delayMicroseconds(DELTATIME); digitalWrite(LED_PIN, HIGH); delayMicroseconds(SLEEPTIME); // culc dust density float nowdust = (0.17 * (analogvalue * (5.0 / 1024.0)) - 0.1) * 1000.; Serial.println("-----------------------"); Serial.print("analog: "); Serial.println(analogvalue); Serial.print("dust: "); Serial.print(nowdust); Serial.println(" ug/m3"); // culc average dustDensityHistory.push_front(nowdust); while ( dustDensityHistory.size() > DUST_HISTORY_MAX ) { dustDensityHistory.pop_back(); } float avg = 0.; for (auto itr = dustDensityHistory.begin(); itr != dustDensityHistory.end(); ++itr) { avg += *itr; } dust = avg / dustDensityHistory.size(); Serial.print("dust avg: "); Serial.print(dust); Serial.println(" ug/m3"); } /*--------------------------------------------------------- send data to IIJ IoT Service ----------------------------------------------------------*/ const char* ioturi = "http://gw.iot.iij.jp/v1"; const char* iot_namespace = "sample"; const char* iot_name = "ホコリ"; const char* sensor_name = "GP2Y1010AU0F"; void sendDataToIoT() { #if !DEBUG if (Wi-Fi.status() != WL_CONNECTED) { Wi-Fi_setup(); } #endif char workarea[1024]; Serial.println("-----------------------"); Serial.println("data send to IoT Service."); createJson(iot_namespace, iot_name, &dust, sensor_name, workarea); #if !DEBUG HTTPClient http; http.begin(ioturi); http.addHeader("Content-Type", "application/json;charset=UTF-8"); int res = http.POST(workarea); #endif Serial.print("sent: "); Serial.println(workarea); #if !DEBUG Serial.print("response code="); Serial.println(res); http.end(); #endif } char* createJson( const char* ns, const char* n, const float* v, const char* s, char* workarea ) { char dtos[32]; sprintf(workarea, "{" "\"namespace\":\"%s\"," "\"name\":\"%s\"," "\"value\":%s," "\"tags\":{\"sensor\":\"%s\"}" "}" , ns , n , dtostrf(*v, 4, 2, dtos) , s ); return workarea; } /*--------------------------------------------------------- main ----------------------------------------------------------*/ //*********************setup******************************** void setup() { Serial.begin(9600); Wi-Fi_setup(); GP2Y1010_setup(); Serial.println(""); } //******************loop************************************ #define DATA_SEND_CYCLE ((60 * 1000) * 2) // 2分ごとにデータ送信 long datasend_time = millis(); void loop() { if ( (millis() - datasend_time) > DATA_SEND_CYCLE ) { //get dust sensor value GP2Y1010_loop(); //send data sendDataToIoT(); datasend_time = millis(); } delay(10); }
IIJ IoTサービスへは2分ごとにデータ送信しています。
データは特定のJSON形式で送信するとIIJ IoTサービス側でグラフ化されますので、そのように実装してあります。
ダストの検知量は意外と上下するため、5回の取得値の平均値を計算してデータ送信するようにしています。
このように工夫すると見やすいグラフになります。
モバイル回線を接続する部分はモバイルWi-Fiルータに任せて、プログラムとしてはWi-Fiのアクセスポイントに接続してセンサ機器から取得したデータをHTTPで送信しているだけの、いたってシンプルな内容です。
データの可視化
さて、これでハードもソフトも完成しました。
早速このダストセンサの機器を半日ほど弊社オフィス内に設置してみました。
結果、IIJ IoTサービスのコントロールパネル(管理画面)により以下のように可視化(グラフ化)できました。
だいたい、弊社には180~260μg/m3程度のダストが舞っているようです。
一般的な基準だと、オフィス内は0.15mg/m3(=150μg/m3)以下のダスト量が適切のようですので、弊社は少しほこりっぽい環境であることが可視化できました(苦笑)
ちょうど冬から春に移りゆく季節なので、花粉が多いのかもしれませんね(と言い訳しておく)。
これはあくまでIoTのごく一部
今回は、センサ機器の作成と、センサから取得したデータの送信から可視化までを紹介いたしました。
しかし、これはあくまでIoTのごく一部にすぎません。
今回のIoTはダスト量を可視化すると言ういたってシンプルな取り組みでしたが、前述の通り機械のメンテナンス時期を可視化し故障の前兆を分析できれば機会損失の削減につながりますし、また会議室利用状況の可視化による利便性の向上、一般家庭内の可視化による安否確認や防犯対策など、IoTの用途は無限です。
もしご興味がある場合は、弊社担当営業かお問い合わせフォームよりご連絡いただければ、ご説明にお伺いいたします。
御社のビジネスにIIJ IoTサービスをご活用いただければ幸いです。
おまけ
現在、IIJ社内では以下のようなセンサ機器がテスト稼働中です。
いろいろなセンサを試してみようと思いどんどん追加していったところ、このようなゴテゴテな見た目になってしまいました。
このセンサ機器より7種類のデータを取得して可視化・分析をしています。
手前の黒い箱の中にはRaspberry Piが入っています。
ArduinoだけでなくRaspberry Piでも問題なくIIJ IoTサービスを利用可能です。