M5StickCを任意のWiFiに接続し,計測された加速度から求めた合成加速度と,合成加速度を高速フーリエ変換してもとめた周波数(5Hzでカットオフ)を,クラウドに送信し,その結果をリアルタイムで可視化します。
M5StickCを充電してください。
フル充電で連続45分程度の測定が出来ます。
長時間の測定には,別途充電池からの給電が必要です。
M5StickCの電源を入れます(この図で見て左上にあるボタンを長押しします)。 電源を入れると,このような画面が表示されます。 |
|
パソコンかスマートフォンを,画面に表示されているSSIDのアクセスポイント(M5StickCがアクセスポイントとして機能しています)を選択します。 | |
画面に表示されているSSIDのパスワードを入力し接続します。 |
M5StickCのOPEN THE URL BELOW の下に表示されているURLをブラウザで開きます。 |
|
接続したい任意のインターネットに接続されたWiFiのアクセスポイントのSSID,パスワード,利用者の名前を入力し,「接続する」を押します。 2.4GHz帯のアクセスポイントに接続してください。5GHz帯では接続できません。 |
|
接続試行中にはこのような表示となります。 | |
このような画面が出ると接続は成功です。 | |
これで,測定結果がクラウドに送信されます。 |
なお,以下のようなリストを用意しておき,URLをそのままブラウザに読ませるようにすると,複数の対象者に対応しやすいと思います。
SSID | パスワード | お名前 | URL |
---|---|---|---|
M5S-CHXX | 12345678 | THORNDIKE_EDWARD_L | http://192.168.4.1/connect?ssid=F660A-X2ac-G&password=qYLTNwxP&subject=THORNDIKE_EDWARD_L |
また,名前の入力は必要ではありません。M5StickCを対象者に配布しやすくするためだけのものです。名前はクラウドには送信されませんし,M5StickCの電源を落とすと,SSID,パスワードとともに消去されます。
名札ケースに格納し,首から提げます。 位置は胸のあたりがよいでしょう。 |
結果はAmbientで見ることができます。
例えば,この例にあるCH08と番号の振られた端末のデータは,以下のURLでリアルタイムで見ることができます。
https://ambidata.io/bd/board.html?id=23194
これをたくさん用意すると,こんな感じで,複数の対象者のデータをリアルタイムでモニタリングできるようになります。
#include <M5StickC.h>
#include <WiFi.h>
#include <WiFiUDP.h>
#include "time.h"
#include "Ambient.h"
//wifiinput
#include <ESPmDNS.h>
#include <WiFiClient.h>
String ssid = "M5S_CH08";
String password = "12345678";
String wifiSsid = "";
String wifiPassword = "";
String wifiName = "";
int inputstatus = 0;
int wifiStatus = WiFi.status();
WiFiServer server(80);
String getSsid(String path)
{
int start = path.indexOf("?ssid=");
int end = path.indexOf("&password=");
return path.substring(start + 6, end);
}
String getPassword(String path)
{
int start = path.indexOf("&password=");
int end = path.indexOf("&subject=");
return path.substring(start + 10, end);
}
String getwifiName(String path)
{
int start = path.indexOf("&subject=");
int end = path.length();
return path.substring(start + 9, end);
}
//wifiinput
//FFT
#include "arduinoFFT.h"
#define SAMPLING_FREQUENCY 50
const uint16_t FFTsamples = 256; // サンプル数は2のべき乗
double vReal[FFTsamples]; // vReal[]にサンプリングしたデーターを入れる
double vImag[FFTsamples];
double vLog[FFTsamples];
arduinoFFT FFT = arduinoFFT(vReal, vImag, FFTsamples, SAMPLING_FREQUENCY); // FFTオブジェクトを作る
unsigned int sampling_period_us;
//unsigned long microseconds;
float indextoHz;
int fftroop;
double vbat = 0.0;
int8_t bat_charge_p = 0;
#define MODE_A 0 // blank
#define MODE_B 1 // display
uint8_t disp_mode = MODE_B;
#define BTN_A_PIN 37
#define BTN_ON LOW
#define BTN_OFF HIGH
uint8_t prev_btn_a = BTN_OFF;
uint8_t btn_a = BTN_OFF;
const char* ntpServer = "ntp.jst.mfeed.ad.jp";
const int sport = 55998;
const int kport = 5556;
RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;
float accX = 0.0F;
float accY = 0.0F;
float accZ = 0.0F;
float acc;
int peak;
int mil;
int milf;
int mila;
uint8_t mac3[6];
WiFiUDP Udp;
char packetBuffer[800];
//Ambient
WiFiClient client;
Ambient ambient;
unsigned int AchannelId = 32595;
const char* AwriteKey = "fbddc1b79d31878d";
//Ambient
void sample(int nsamples) {
int i;
for (int i = 0; i < nsamples; i++) {
btn_a = digitalRead(BTN_A_PIN);
if(prev_btn_a == BTN_OFF && btn_a == BTN_ON){
if(disp_mode == MODE_A){
M5.Lcd.setCursor(0, 1, 2);
M5.Lcd.print("NAME: ");
M5.Lcd.println(wifiName);
M5.Lcd.setCursor(0, 16);
M5.Lcd.print("WIFI: ");
M5.Lcd.println(WiFi.localIP());
M5.Lcd.setCursor(0, 34);
M5.Lcd.printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac3[0], mac3[1], mac3[2], mac3[3], mac3[4], mac3[5]);
disp_mode = MODE_B;
}else{
M5.Lcd.fillScreen(BLACK);
disp_mode = MODE_A;
}
}
prev_btn_a = btn_a;
// put your main code here, to run repeatedly:
while(millis() < (mil + sampling_period_us)){
}
mil = millis();
mila = millis();
M5.IMU.getAccelData(&accX, &accY, &accZ);
acc = sqrt(sq(accX)+sq(accY)+sq(accZ));
Serial.print(mila);
Serial.print(", ");
Serial.print(acc);
Serial.print(", ");
Serial.print(peak);
Serial.print(", ");
float hz;
hz = (float)peak * indextoHz;
Serial.println(float(hz));
vReal[i] = acc;
vLog[i] = acc;
vImag[i] = 0;
M5.Rtc.GetTime(&RTC_TimeStruct);
M5.Rtc.GetData(&RTC_DateStruct);
if(disp_mode == MODE_B){
vbat = M5.Axp.GetVbatData() * 1.1 / 1000;
bat_charge_p = int8_t((vbat - 3.0) / 1.2 * 100);
if(bat_charge_p > 100){
bat_charge_p = 100;
}else if(bat_charge_p < 0){
bat_charge_p = 0;
}
M5.Lcd.setCursor(0, 50);
M5.Lcd.printf("C:%3d%% ", bat_charge_p);
M5.Lcd.printf("%02d-%02d ", RTC_DateStruct.Month, RTC_DateStruct.Date);
M5.Lcd.printf("%02d:%02d:%02d\n", RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes, RTC_TimeStruct.Seconds);
M5.Lcd.setCursor(0, 66);
M5.Lcd.printf("ACC:%5.2f FFT:%.2fHz ", acc, hz);
}
}
}
void setup() {
// put your setup code here, to run once:
M5.begin();
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(BLACK);
M5.Axp.ScreenBreath(8); // MIN7-MAX12
M5.IMU.Init();
pinMode(BTN_A_PIN, INPUT_PULLUP);
esp_read_mac(mac3, ESP_MAC_WIFI_STA);
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(1, 0, 2);
//wifiinput
Serial.println();
Serial.print("Configuring access point...");
WiFi.softAP(ssid.c_str(), password.c_str());
M5.Lcd.println("CONNECT TO");
M5.Lcd.println("SSID: " + ssid);
M5.Lcd.println("PASS: " + password);
M5.Lcd.println("OPEN THE URL BELOW");
M5.Lcd.println("http://192.168.4.1/");
IPAddress myIP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(myIP);
if (!MDNS.begin("esp32"))
{
Serial.println("Error setting up MDNS responder!");
while (1)
{
delay(1000);
}
}
Serial.println("mDNS responder started");
server.begin();
Serial.println("Web server started");
MDNS.addService("http", "tcp", 80);
while(inputstatus == 0){
wifiinput();
}
delay(1000);
//wifiinput
// Set ntp time to local
configTime(9 * 3600, 0, ntpServer);
// Get local time
struct tm timeInfo;
if (getLocalTime(&timeInfo)) {
// Set RTC time
RTC_TimeTypeDef TimeStruct;
TimeStruct.Hours = timeInfo.tm_hour;
TimeStruct.Minutes = timeInfo.tm_min;
TimeStruct.Seconds = timeInfo.tm_sec;
M5.Rtc.SetTime(&TimeStruct);
RTC_DateTypeDef DateStruct;
DateStruct.WeekDay = timeInfo.tm_wday;
DateStruct.Month = timeInfo.tm_mon + 1;
DateStruct.Date = timeInfo.tm_mday;
DateStruct.Year = timeInfo.tm_year + 1900;
M5.Rtc.SetData(&DateStruct);
}
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setCursor(0, 1, 2);
M5.Lcd.print("CH08: ");
M5.Lcd.println(wifiName);
M5.Lcd.setCursor(0, 16);
M5.Lcd.print("WIFI: ");
M5.Lcd.println(WiFi.localIP());
uint8_t mac3[6];
esp_read_mac(mac3, ESP_MAC_WIFI_STA);
M5.Lcd.setCursor(0, 34);
M5.Lcd.printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac3[0], mac3[1], mac3[2], mac3[3], mac3[4], mac3[5]);
Udp.begin(kport);
//FFT
// sampling_period_us = round(1000000*(1.0/SAMPLING_FREQUENCY));
sampling_period_us = round(1000*(1.0/SAMPLING_FREQUENCY));
indextoHz = (float)SAMPLING_FREQUENCY / FFTsamples;
fftroop = 5 / indextoHz + 1;
//FFT
mil = millis();
//ambient
ambient.begin(AchannelId, AwriteKey, &client);
//ambient
}
void DCRemoval(double *vData, uint16_t samples) {
double mean = 0;
for (uint16_t i = 1; i < samples; i++) {
mean += vData[i];
}
mean /= samples;
for (uint16_t i = 1; i < samples; i++) {
vData[i] -= mean;
}
}
void loop() {
sample(FFTsamples);
DCRemoval(vReal, FFTsamples);
FFT.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD); // 窓関数
FFT.Compute(FFT_FORWARD); // FFT処理(複素数で計算)
FFT.ComplexToMagnitude(); // 複素数を実数に変換
int i;
float peakm = 0;
for(i = 0; i < fftroop; i++){ //5HZ相当までしか判定しない
if(peakm<=vReal[i]){
peakm=vReal[i];
peak = i;
}
}
//UDP
milf = millis();
//ambient
ambient.set(1, acc);
ambient.set(2, peak * indextoHz);
ambient.send();
//ambient
}
void wifiinput()
{
if (wifiSsid.length() > 0 && wifiPassword.length() > 0)
{
if (wifiStatus != WL_CONNECTED)
{
M5.Lcd.setCursor(0, 0, 1);
M5.Lcd.fillScreen(BLACK);
Serial.println("SSID: " + wifiSsid);
Serial.println("Pass: " + wifiPassword);
Serial.println("Subject: " + wifiName);
WiFi.begin(wifiSsid.c_str(), wifiPassword.c_str());
while (wifiStatus != WL_CONNECTED)
{
delay(500);
wifiStatus = WiFi.status();
Serial.print(".");
M5.Lcd.setCursor(0, 0, 1);
M5.Lcd.setTextFont(2);
M5.Lcd.println("WiFi connecting");
}
M5.Lcd.setCursor(0, 0, 1);
M5.Lcd.setTextFont(2);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.println("Welcome");
M5.Lcd.println(wifiName);
M5.Lcd.println("Your cooperation is");
M5.Lcd.println("appreciated.");
// M5.Lcd.println("Connected!");
inputstatus = 1;
delay(1000);
Serial.print("WiFi connected\r\nIP address: ");
Serial.println(WiFi.localIP());
}
delay(1000);
}
else
{
WiFiClient client = server.available();
if (!client)
{
return;
}
Serial.println("");
Serial.println("New client");
if (client)
{
Serial.println("new client");
while (client.connected())
{
if (client.available())
{
String req = client.readStringUntil('\r');
Serial.print("Request: ");
Serial.println(req);
int addr_start = req.indexOf(' ');
int addr_end = req.indexOf(' ', addr_start + 1);
if (addr_start == -1 || addr_end == -1)
{
Serial.print("Invalid request: ");
Serial.println(req);
return;
}
String path = req.substring(addr_start + 1, addr_end);
Serial.print("Path: ");
Serial.println(path);
String s = "";
if (path == "/")
{
IPAddress ip = client.remoteIP(); // クライアント側のIPアドレス
String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);
s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
s += "<!DOCTYPE html>";
s += "<html lang=\"ja\">";
s += " <head>";
s += " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>";
s += " <style>";
s += " body {";
s += " font-size: 48px;";
s += " margin: 0;";
s += " background-color: #f2f2f2;";
s += " font-family: 'Arial',YuGothic,'Yu Gothic','Hiragino Kaku Gothic ProN','ヒラギノ角ゴ ProN W3','メイリオ', Meiryo,'MS ゴシック',sans-serif;";
s += " }";
s += " header {";
s += " width: 100%;";
s += " height: 120px;";
s += " line-height: 120px;";
s += " background-color: #F1B514;";
s += " text-align: center;";
s += " color: #f2f2f2;";
s += " font-weight: bold;";
s += " }";
s += " main {";
s += " padding-left: 24px;";
s += " padding-right: 24px;";
s += " }";
s += " input {";
s += " width: 100%;";
s += " height: 80px;";
s += " border: none;";
s += " font-size: 48px;";
s += " padding: 16px;";
s += " margin-top: 16px;";
s += " }";
s += " button {";
s += " width: 100%;";
s += " height: 120px;";
s += " background-color: #254DEA;";
s += " font-size: 48px;";
s += " color: #f2f2f2;";
s += " border: none;";
s += " border-radius: 60px;";
s += " margin-top: 40px;";
s += " font-weight: bold;";
s += " }";
s += " </style>";
s += " </head>";
s += " <body>";
s += " <header>授業研究用加速度計 WiFi接続 CH08</header>";
s += " <main>";
s += " <form method=\"GET\" action=\"/connect\">";
s += " <input type=\"text\" name=\"ssid\" placeholder=\"SSID\" />";
s += " <input type=\"password\" name=\"password\" placeholder=\"Password\" />";
s += " <input type=\"text\" name=\"subject\" placeholder=\"Subject's name\" />";
s += " <button type=\"submit\">接続する</button>";
s += " </form>";
s += " </main>";
s += " </body>";
s += "</html>";
Serial.println("Response 200");
}
else if (path.startsWith("/connect"))
{
Serial.println("send to /connect");
s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
s += "<!DOCTYPE html>";
s += "<html lang=\"ja\">";
s += " <head>";
s += " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>";
s += " <style>";
s += " body {";
s += " font-size: 48px;";
s += " margin: 0;";
s += " background-color: #f2f2f2;";
s += " font-family: 'Arial',YuGothic,'Yu Gothic','Hiragino Kaku Gothic ProN','ヒラギノ角ゴ ProN W3','メイリオ', Meiryo,'MS ゴシック',sans-serif;";
s += " }";
s += " header {";
s += " width: 100%;";
s += " height: 120px;";
s += " line-height: 120px;";
s += " background-color: #F1B514;";
s += " text-align: center;";
s += " color: #f2f2f2;";
s += " font-weight: bold;";
s += " }";
s += " main {";
s += " padding-left: 24px;";
s += " padding-right: 24px;";
s += " text-align: center;";
s += " }";
s += " input {";
s += " width: 100%;";
s += " height: 80px;";
s += " border: none;";
s += " font-size: 48px;";
s += " padding: 16px;";
s += " margin-top: 16px;";
s += " }";
s += " button {";
s += " width: 100%;";
s += " height: 120px;";
s += " background-color: #254DEA;";
s += " font-size: 48px;";
s += " color: #f2f2f2;";
s += " border: none;";
s += " border-radius: 60px;";
s += " margin-top: 40px;";
s += " font-weight: bold;";
s += " }";
s += " </style>";
s += " </head>";
s += " <body>";
s += " <header>授業研究用加速度計 WiFi接続 CH08</header>";
s += " <main>";
s += " <h4>WiFiに接続しています...</h4>";
s += " <h6>モニターにConnectedと表示されるまでお待ちください</h6>";
s += " </main>";
s += " </body>";
s += "</html>";
wifiSsid = getSsid(path);
wifiPassword = getPassword(path);
wifiName = getwifiName(path);
Serial.println("SSID: " + wifiSsid);
Serial.println("Pass: " + wifiPassword);
Serial.println("Subject: " + wifiName);
Serial.println("Response 200");
}
else
{
s = "HTTP/1.1 404 Not Found\r\n\r\n";
Serial.println("Sending 404");
}
client.print(s);
client.flush();
client.stop();
}
}
}
Serial.println("Done with client");
}
delay(1000);
}