More Related Content
Similar to IoTデバイス センサデータ分析システム
Similar to IoTデバイス センサデータ分析システム (20)
IoTデバイス センサデータ分析システム
- 2. 目次
1. 目的 .......................................................................................................................1
2. システム概要 .........................................................................................................1
3. センサの種類と型、アクチュエータの種類 ...........................................................2
• センサ ..................................................................................................................... 2
• アクチュエータ ....................................................................................................... 2
• 動作の様子 .............................................................................................................. 2
4. Arduino ソースコード............................................................................................3
5. Python 送信側コード .............................................................................................6
6. Node.js 受信側コード............................................................................................7
7. Python グラフ可視化コード...................................................................................8
8. 生成されるグラフの例 .........................................................................................10
9. 考察と今後の発展 ................................................................................................11
10. 苦労した点 .......................................................................................................11
11. 参考 URL..........................................................................................................12
- 3. 1
1. 目的
本レポートは,Arduino を用いて得たセンサデータをクラウドに送信し,それらを
グラフ化することによりセンサデータを可視化するための手法および結果を述べるこ
とを目的とする.
2. システム概要
本システムは,図1に示すように,ローカル側とクラウド側で構成されている.ま
ずローカルでは Arduino を用いて取得したセンサデータを PC 等の端末で受信し
MQTT を用いて Cloud Pub/Sub に送信する 1)
.そしてクラウド上では受け取ったデ
ータを Cloud Functions 経由で Firestore に送信する 2),3)
.また,蓄積されたデータは
HTTP アクセスをトリガーとして閲覧することが可能となっている 4)
.
今回は Firebase Hosting と Vue.js を用いて以下の閲覧用サイトを作成した.
なお最新の画像および動作時の動画には以下の URL からアクセス可能である.
https://spherical-voice-251409.firebaseapp.com/
(2020 年 4 月までアクセス可能であることを保証します)
図1 システムの概要
- 4. 2
3. センサの種類と型、アクチュエータの種類
今回は IoTAB シールドに含まれている部品を使用したため,Arduino と距離センサ
を接続したシールドのみで再現することが可能である.
• センサ
温度センサ STS30 I2C 接続(アドレス: 0x4A)
照度センサ BH1780 I2C 接続(アドレス: 0x29)
加速度センサ MMA8452Q I2C 接続(アドレス: 0x1C)
距離センサ HC-SR04 デジタル入力/出力: D12/D13
可変抵抗器 3386K-EY5-103TR アナログ入力: A3
• アクチュエータ
LCD AQM0802A-RN-GBW I2C 接続(アドレス: 0x7C)
LED OSYG1608C1A デジタル出力: D3〜D8
• 動作の様子
Raspberry Pi は Wi-Fi でネットワークに接続できるため,モバイルバッテリーを
用いることにより完全な無線化が可能である.
図2 動作の様子
距離に応じて変化
温度と加速度
(x,y 軸)を表示
LED 変化の
大きさを変更
距離センサ
温度センサ
シリアル通信
- 5. 3
4. Arduino ソースコード
//*******************************************
//* センサネットワークと組み込み技術 最終課題
//* 2020/1 17FI552 二瓶雄貴
//*******************************************
// I2C に必要
#include <Wire.h>
// 温度センサに必要
#include <STSSensor.h>
STSSensor sts30(Wire);
// 定数の定義
#define ACCaddr 0x1C // 加速度センサ
#define LightAddr 0x29 // 照度センサ
#define echoPin 12 // Echo ピン
#define trigPin 13 // Trigger ピン
#define volPin 3 // 可変抵抗ピン
// 変数の宣言と初期化
double Duration = 0; // 超音速を受信した間隔
int LEDLevel = 0; // LED で表せる距離の範囲
double Distance = 0; // 距離
double Temp = 0; // 温度
double TempOld = 0; // 過去の温度
int Light = 0; // 照度
int LightOld = 0; // 過去の照度
void setup() {
Wire.begin();
lcd_init();
// 加速度センサの初期化
Wire.beginTransmission(ACCaddr);
Wire.write(0x2A);
Wire.write(0x00);
Wire.endTransmission();
Wire.beginTransmission(ACCaddr);
Wire.write(0x2A);
Wire.write(0x01);
Wire.endTransmission();
Wire.beginTransmission(ACCaddr);
Wire.write(0x0E);
Wire.write(0x00); // Set range to +/- 2g
Wire.endTransmission();
delay(300);
- 6. 4
// 温度センサの初期化
sts30.init(Wire);
// 照度センサの初期化
Wire.beginTransmission(LightAddr);
Wire.write(0x80);
Wire.write(0x03);
Wire.endTransmission();
Serial.begin(9600); // シリアル通信の初期化
pinMode(echoPin, INPUT); // Echo ピンを入力に設定
pinMode(trigPin, OUTPUT); // Trigger ピンを出力に設定
for(int i=3; i<9; i++)
pinMode(i,OUTPUT); // LED を出力に設定
}
void loop() {
// 加速度センサからの入力を受け取る
unsigned int accData[5];
Wire.requestFrom(ACCaddr, 5);
// staus, xAccl lsb, xAccl msb, yAccl lsb, yAccl msb
if(Wire.available() == 5)
for (int i=0; i<5; i++) accData[i]= Wire.read();
// 加速度を変数に格納する
int xAcc = accl(&accData[1]);
int yAcc = accl(&accData[3]);
//温度センサからの入力を受け取る
sts30.readSample();
Temp = sts30.getTemperature();
// 照度センサからの入力を受け取る
Light = i2c_readlux();
// 超音波を出力する
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds( 10 );
digitalWrite(trigPin, LOW);
// 超音速センサからの入力を受け取る
Duration = pulseIn(echoPin, HIGH);
LEDLevel = analogRead(volPin)/32+1;
// 距離によって LED を点灯させる
if (Duration > 0) {
Duration = Duration / 2; // 往復距離を半分にする
Distance = Duration * 340 * 100 / 1000000; // 音速を 340m/s に設定
- 7. 5
if (Distance <= 450) { // 測定可能距離は 450cm まで
for(int i=0; i<6; i++)
digitalWrite(i+3, (int)(Distance/LEDLevel)>i?HIGH:LOW);
}
}
// 1 行目を生成
char tempbuf[6]; // 温度を格納する変数
// 小数はそのまま表示できないため一度文字列に変換
dtostrf(Temp, 5, 2, tempbuf); // %5.2f と同様の文字列を生成
// LCD 表示部
char pr[8]; // 1 行分を格納する変数
lcd_clear();
lcd_setCursor(0,0); // カーソルを 1 行目の先頭に
sprintf(pr,"%s[C]",tempbuf); // 温度を表す文字列
lcd_printStr(pr); // 1 行分を表示
lcd_setCursor(0,1); // カーソルを 2 行目の先頭に
sprintf(pr,"%4d%4d",xAcc/10,yAcc/10);// 加速度を表す文字列
lcd_printStr(pr); // 1 行分を表示
// データ送信部
if(abs(Temp - TempOld) > 0.5 || abs(Light - LightOld) > 5) {
// 温度変化が 0.5 度を超えたか照度変化が 5Lx を超えたら
writeSerial(Temp, Light); // センサデータを送信
TempOld = Temp; // 比較対象の温度を更新
LightOld = Light; // 比較対象の温度を更新
}
delay(300); // 1 秒待機
}
// センサデータを送信する関数
void writeSerial(double temp, int light) {
Serial.write("STARTn");
char buf[1];
String str;
str = (temp != -1 ? String(temp) : "") + "n";
str += (light != -1 ? String(light) : "") + "n";
str.toCharArray(buf, str.length() + 1);
Serial.write(buf);
Serial.write("ENDn");
}
// 加速度を変換する関数
int accl(int d[]) {
- 8. 6
int val = ((d[0]*256+d[1]))/16;
if (val > 2047) val -= 4096;
return val;
}
// 照度を読み取る関数
uint16_t i2c_readlux() {
uint16_t val;
Wire.beginTransmission(LightAddr);
Wire.write(0x8D);
Wire.endTransmission();
Wire.beginTransmission(LightAddr);
Wire.requestFrom(LightAddr,2);
delay(150);
val = Wire.read();
Wire.endTransmission();
val <<=8;
Wire.beginTransmission(LightAddr);
Wire.write(0x8C);
Wire.endTransmission();
Wire.beginTransmission(LightAddr);
Wire.requestFrom(LightAddr,2);
delay(150);
val |= Wire.read();
Wire.endTransmission();
return val;
}
LCD の制御に必要なライブラリを https://github.com/JanStegenga/Arduino-STS-lib
からダウンロードしインストールする必要がある.
5. Python 送信側コード
実行するためには,pip を用いた pyserial と google-cloud-pubsub のインストールが
必要である.また,認証情報を格納した json ファイルへのパスを環境変数
GOOGLE_APPLICATION_CREDENTIALS に格納しておく必要がある.
# Arduino からセンサの値を受け取って Google Cloud Pub/Sub に MQTT で送信する
プログラム
# 2020/1 17FI552 二瓶雄貴
import serial
from google.cloud import pubsub_v1
# パブリッシャーの設定
publisher = pubsub_v1.PublisherClient()
# トピックの設定
- 9. 7
project_id = 'spherical-voice-251409'
topic_name = 'iot-sensor-data'
topic_path = publisher.topic_path(project_id, topic_name)
if __name__ == "__main__":
# Arduino の接続ポートを書く
ser = serial.Serial("/dev/cu.usbmodem14201", 9600)
data = []
flag = False
while True:
message = ser.readline().decode("utf-8").replace("n", "")
if message == "START":
flag = True
elif message == "END":
flag = False
# データをバイト列にエンコードして送信
future = publisher.publish(topic_path,
",".join(data).encode("utf-8"))
# print(future.result())
data = []
else:
if flag:
print(message)
data.append(message)
6. Node.js 受信側コード
Cloud Functions 上の Node.js 8 以上でのみ動作するコードが含まれている.
index.js
/**
* Triggered from a message on a Cloud Pub/Sub topic.
*
* @param {!Object} data Message on a topic.
* @param {!Object} context Metadata for the event.
*/
const functions = require('firebase-functions')
// cloud function で firestore を使うのに必要な設定は以下の2行
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)
- 10. 8
// データベースの参照を作成
var db = admin.firestore()
exports.subscribe = (data, context) => {
var message = Buffer.from(data.data, 'base64').toString();
// console.log("Message: ", message);
var docRef = db.collection('record');
docRef.add({
"timestamp": parseInt(Date.now()/1000),
"temp": message
});
};
package.json
{
"name": "iot2firestore",
"version": "1.0.0",
"dependencies": {
"@google-cloud/firestore": "^0.16.1",
"firebase-admin": "^6.0.0",
"firebase-functions": "^1.0.0"
}
}
7. Python グラフ可視化コード
Cloud Functions 以外での実行には認証情報が必要である.
main.py
from flask import make_response
import datetime
import operator
import matplotlib.pyplot as plt
from matplotlib import rcParams
from matplotlib.backends.backend_agg import FigureCanvasAgg
from google.cloud import firestore
from io import BytesIO
def make_graph(request):
# フォントの設定
- 11. 9
rcParams['font.family'] = 'sans-serif'
rcParams['font.sans-serif'] = ['Noto Sans CJK JP', 'Hiragino
Sans', 'Hiragino Maru Gothic Pro', 'Yu Gothic']
# 最新 20 件のコレクション取得
db = firestore.Client()
query =
db.collection(u'record').order_by(u'timestamp',direction=firestore.Query.D
ESCENDING).limit(20)
results = query.stream()
# データを取得する
lists = {}
for result in results:
res = result.to_dict()
lists[datetime.datetime.fromtimestamp(res['timestamp'],
datetime.timezone(datetime.timedelta(hours=9)))] = (float(res['temp']) ,
int(res['light']))
# 時刻順に並び替える
lists = sorted(lists.items())
# グラフ生成
fig, ax = plt.subplots()
ax.set_title(u'センサデータ')
# リストからデータを抽出
x = list(map(operator.itemgetter(0), lists))
y = list(map(operator.itemgetter(1), lists))
# y 軸のデータを分割しプロット
y1 = list(map(operator.itemgetter(0), y))
ax.plot(x, y1, label='温度 [℃]', color='b', linewidth=2)
y2 = list(map(operator.itemgetter(1), y))
ax.plot(x, y2, label='輝度 [Lx]', color='r', linewidth=2)
# 凡例の位置を自動で変更
plt.legend(loc='best')
# 軸ラベルの設定
plt.xlabel('時刻')
# x 軸を回転させる
plt.xticks(rotation=70)
# 余白を調整
plt.subplots_adjust(left=0.07, right=0.97, bottom=0.21, top=0.93)
# グリッドを設定
plt.grid()
# グラフの画像を生成
- 12. 10
canvas = FigureCanvasAgg(fig)
buf = BytesIO()
canvas.print_png(buf)
data = buf.getvalue()
# HTTP レスポンスを生成
response = make_response(data)
response.headers['Content-Type'] = 'image/png'
response.headers['Content-Length'] = len(data)
# キャッシュ設定 ブラウザごとに 5 分,CDN に 10 分
response.headers['Cache-Control'] = 'public, max-age=300, s-
maxage=600'
return response
requirements.txt
matplotlib
google-cloud-firestore
8. 生成されるグラフの例
7.で示したコードにより図3に示すようなグラフが生成される.今回はセンサを屋
内の窓際に設置した.日射により温度と輝度が変化している.
図3 センサデータを元に生成されたグラフ
- 14. 12
11. 参考 URL
1) 「クイックスタート: Pub/Sub システム機能の構築」
https://cloud.google.com/pubsub/docs/quickstart-py-mac?hl=ja
2) 「Firebase を使って IoT データをリアルタイム可視化する」
https://camp.isaax.io/ja/examples/firebase-realtime-visualization
3) 「IoT Core から Cloud Functions 経由で Firestore にデータを追加する」
https://qiita.com/bathtimefish/items/1f4885c130d23eb63710
4) 「Google Cloud Functions の HTTP トリガーで matplotlib を使って生成した
画像を返す」
https://qiita.com/tanabee/items/2bfee85f9659be097750
5) 「GitHub - JanStegenga/Arduino-STS-lib」
https://github.com/JanStegenga/Arduino-STS-lib#integrating-it-into-your-sketch
6) 「Google Cloud IoT Core の環境構築ではまったところ(デバイス側)
」
http://chinoppy.hatenablog.com/entry/2019/01/06/190530
7) 「Cloud Functions の nodejs6 を nodejs8 に移行するとき、バックグラウンド関数
を使っているときは引数を修正する」
https://qiita.com/itatibs/items/5540c0ac94582ab4851e
8) 「Cloud Firestore のデータを Python で取得する」
https://qiita.com/yusukeito58/items/c77feaa25fbbe37e9953