先日、子供の勉強時間を記録するためのWebプログラムをつくりました(記事は こちら)。
勉強を始めた時と、勉強が終わった時に、ボタンをタップすることで、その日の勉強時間をグラフで確認することができるというものです。
1日の勉強時間を「見える化」することで、子供自身が勉強時間を意識するようになることを狙っています。
ただ、実際に子供に使わせてみると、ついつい、ボタンを押すのを忘れがちになってしまうようです。
そんな訳で、ボタンを押さなくても、センサか何かで勉強時間を計測できないかと、少し考えてみました。
今回試してみたのは、M5StickCを使って計測する方法です。
鉛筆の軸に、M5StickCを取り付けます。M5StickCには加速度センサが搭載されているので、それを使えば、鉛筆の向きを測定することができます。
1分毎に鉛筆の向きを測定し、鉛筆が立っていたら勉強中、寝ていたら勉強していないと判定します。
今回はM5StickCにケーブルなどを繋がずに使いたいので、まず最初に、M5StickCをdeep sleepさせる方法を確認しました。
以下のようなスケッチをつくりました。
マイコンなどから送られたセンサデータを、簡単に受信・蓄積・グラフ化できる「Ambient」というWebサービスがありますが、ここでは、この「Ambient」を使います。
Ambientに適当なデータを送信し、それが終わると、10秒間deep sleepする、という処理を繰り返します。
#include <M5StickC.h> #include "Ambient.h" WiFiClient client; Ambient ambient; #define SLEEP_TIME 10 // スリープ時間(秒) const char* ssid = "XXXXXXXX"; const char* password = "XXXXXXXX"; unsigned int channelId = XXXXX; const char* writeKey = "XXXXXXXX"; RTC_DATA_ATTR int cnt = 0; void setup() { M5.begin(); M5.Axp.ScreenBreath(8); M5.Lcd.setRotation(1); M5.Lcd.setCursor(0, 0, 2); M5.Lcd.printf("### SEND: %d\n", cnt); WiFi.begin(ssid, password); while(WiFi.status()!=WL_CONNECTED) { delay(500); } ambient.begin(channelId, writeKey, &client); ambient.set(1, cnt); ambient.send(); cnt++; WiFi.disconnect(); M5.Lcd.printf("### SLEEP\n"); M5.Axp.ScreenBreath(0); esp_deep_sleep(SLEEP_TIME*1000000); } void loop() { }
このスケッチで、データがきちんとAmbientに送信できることが確認できました。
なお、このスケッチを動作させている時のM5StickCの消費電流を、テスタで測定してみたところ、Wi-Fi通信している数秒間は100mA程度、deep sleep中は16mA程度でした。
M5StickCの内蔵バッテリーは80mAhなので、ずっとdeep sleepさせていても、5時間で電池がなくなる計算です。
次に、M5StickCの加速度センサについて確認しました。
以下のようなスケッチをつくり、M5StickCの置き方を、さまざまな向きに変えて、表示される値を確認しました。
#include <M5StickC.h> float accX, accY, accZ; void setup() { M5.begin(); M5.IMU.Init(); M5.Lcd.setRotation(1); } void loop() { M5.Lcd.fillScreen(BLACK); M5.Lcd.setCursor(0, 0, 2); M5.IMU.getAccelData(&accX, &accY, &accZ); M5.Lcd.print("X: "); M5.Lcd.println(accX); M5.Lcd.print("Y: "); M5.Lcd.println(accY); M5.Lcd.print("Z: "); M5.Lcd.println(accZ); delay(1000); }
結果は以下のとおりです。M5StickCが縦を向いているか、横を向いているかを判定するためには、「accY」を見れば良いことがわかりました。
これらを踏まえて、以下のようなスケッチを作成しました。
加速度センサで傾きを測定し、その値が「0.3以上」または「-0.3以下」のときに「勉強中」であると判定します。
その結果をWebサーバに送信し、データ送信が終わると1分間deep sleepします。
#include <M5StickC.h> #include <WiFi.h> #define SLEEP_TIME 60 // スリープ時間(秒) const char* ssid = "XXXXXXXX"; const char* password = "XXXXXXXX"; RTC_DATA_ATTR int cnt = 0; float accX, accY, accZ; void setup() { M5.begin(); M5.IMU.Init(); M5.Axp.ScreenBreath(8); M5.Lcd.setRotation(1); M5.Lcd.setCursor(0, 0, 2); M5.Lcd.printf("### SEND: %d\n", cnt); M5.IMU.getAccelData(&accX, &accY, &accZ); M5.Lcd.print("Y: "); M5.Lcd.println(accY); WiFi.begin(ssid, password); while(WiFi.status()!=WL_CONNECTED) { M5.Lcd.print("."); delay(500); } M5.Lcd.println(""); int event_flag=0; if(accY>=0.3 || accY<=-0.3) event_flag=1; sendRequest(event_flag); cnt++; WiFi.disconnect(); M5.Lcd.printf("### SLEEP\n"); M5.Axp.ScreenBreath(0); esp_deep_sleep(SLEEP_TIME*1000000); } void loop() { } boolean sendRequest(int event_flag) { : // (省略) }
Webサーバに置いているWebプログラムでは、これまでボタンのタップで勉強しているかどうかの情報を受信していたのと同様に、M5StickCから送信された情報も受信し、データベースに蓄積します。
試してみた結果は以下のとおりです。
M5StickCの電池がすぐになくなってしまうにも関わらず、電池がなくなったかどうかが分かりにくいため、画面上に、データ更新時刻も表示するようにしておきました。
データ自体はいい感じに取れているようです。
あとは、M5StickCのバッテリーがもう少し持てばよいのですが(せめて朝から夕方までの12時間程度)、今のところ、これ以上消費電流を下げる方法が分かりません。
なお、私がM5Stack、M5StickCの使い方を習得するのにあたっては、以下の書籍を参考にさせていただきました。
ごく基本的なところから、かなり複雑なスケッチや、ネットワーク接続など、比較的高度なものまで、つまづかずに読み進めていけるような構成になっており、大変わかりやすい本です。
このサイトで書いている、M5Stackシリーズ(M5Stack、M5StickCなど)に関するブログ記事を、「さとやまノート」という別のブログページに、あらためて整理してまとめました。
他のM5Stackシリーズの記事にも興味のある方は「さとやまノート」をご覧ください。