はじめに
緊急事態宣言が発令中ですが皆さんはいかがお過ごしでしょうか?
突然ですが、新型コロナウイルス感染対策の1つに手のアルコール消毒があります。自分は適当な人間なので、外出中でも長時間消毒してないような場面が多々あります。マイ消毒液を持ち歩き定期的に手を消毒している人もいますが、中には意識しすぎて”消毒疲れ”になってる人もいるのではないでしょうか。そこで、意識することなく十分な手の消毒を促し、消毒の履歴を保存するウェアラブルデバイスを作成しました。
正直自分のような一般人がこのデバイスを使うのは感染対策として過剰すぎる気もしますが、医療や介護などの関係者の方々にとっては(少なくともコンセプトのレベルでは)十分使えるデバイスだと思います。例えば介護関係者の場合、介護する側の人は意識するだけで十分な可能性もありますが、介護される側の人の中には意思疎通が難しかったり、記憶があいまいな人が含まれます。そのような場合にこのデバイスを利用してもらうことで、適切な消毒及びその確認がスムーズに行えるようになると考えています。
構成
- ESP32
- Wi-FiおよびBluetoothを利用できるマイコン
- 匂いセンサ
- アルコールのにおいから手の消毒を検知
- 振動モータ
- 振動で利用者に消毒を促す
- フルカラーLED
- 手が消毒され手からの時間経過を色で表示
- Lipo
- デバイス駆動用電源
- 電源回路
- Lipoの充放電を行うための基板
(上記の回路を3Dプリンタで印刷したケースに収納)
- Google Apps Script
- Wi-Fi経由でGoogle Spread Sheetに書き込むためのスクリプト
- Google Spread Sheet
- 消毒履歴を保存・表示
このほかに、ESP32を用いたBluetoothビーコンを作成
動作
利用方法
- ビーコンを消毒スポット(建物の入り口や飲食スペースなどに置かれた消毒液の横)に置く
- 電源を入れたデバイスを腕時計と同じ要領で腕に装着する
動作の流れ
デバイスの利用者が手をアルコール消毒する
↓
匂いセンサで手のアルコール消毒を検知
↓
Wi-Fiで消毒履歴をGoogle Spread Sheetに記録
↓
消毒後時間が経つにつれ、側面のランプの色が緑→黄→赤と変化
↓
ビーコンに接近した場合/一定時間以上消毒が行われなかった場合、振動で消毒を促す
↓
(デバイスの利用者が手をアルコール消毒する)
回路
基本的にESP32、電源回路と直接配線しています
匂いセンサの回路は、匂いセンサを購入した秋月電子さんの商品ページに乗っているサンプル回路匂いセンサを購入した秋月電子さんの商品ページに乗っているサンプル回路と同じものを利用しています
コード
デバイス(Bluetooth:slave)
#include <BluetoothSerial.h> #include <Adafruit_NeoPixel.h> #if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) #error Bluetooth is not enabled! Please run `make menuconfig` to and enable it #endif BluetoothSerial SerialBT; WiFiClientSecure client; const char* ssid = "SSIDを入力"; const char* password = "パスワードを入力"; const char* server = "script.google.com"; const char* key = "スクリプトのキーを入力"; String point_name = "null_point"; int point_count = 0; int time_count = 0; int alc_P = 0; int che_P = 0; float V = 0.0; int val = 0; const int T = 100; #define PIN_HEATER 5 #define PIN_SENSOR 16 #define PIN_MOTOR 19 #define PIN_OUTPUT 35 #define LED_COUNT 1 #define DIGITAL_PIN 14 Adafruit_NeoPixel led = Adafruit_NeoPixel( LED_COUNT,DIGITAL_PIN , NEO_GRB + NEO_KHZ800); void wifi_conect(){ WiFiServer server(80); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); } server.begin(); } void a_acsess(){ String URL="https://script.google.com/macros/s/"; URL += key; URL += "/exec?"; URL += "&2_cell=used_alcohol"; if (!client.connect(server, 443)){ //Serial.println("Connection failed!"); } else { //Serial.println("Connected to server!\n"); client.println("GET " + URL); client.stop(); //Serial.println("finish."); } delay(1000); } void c_acsess(){ String URL="https://script.google.com/macros/s/"; URL += key; URL += "/exec?"; URL += "&2_cell=check_point"; if (time_count >= T/2){ URL += "&3_cell=warning!"; } if (!client.connect(server, 443)){ //Serial.println("Connection failed!"); } else { //Serial.println("Connected to server!\n"); client.println("GET " + URL); client.stop(); //Serial.println("finish."); } delay(1000); } void w_acsess(){ String URL="https://script.google.com/macros/s/"; URL += key; URL += "/exec?"; URL += "&3_cell=warning!"; if (!client.connect(server, 443)){ //Serial.println("Connection failed!"); } else { //Serial.println("Connected to server!\n"); client.println("GET " + URL); client.stop(); //Serial.println("finish."); } delay(1000); } void setup() { pinMode(PIN_HEATER,OUTPUT); pinMode(PIN_SENSOR,OUTPUT); pinMode(PIN_MOTOR,OUTPUT); pinMode(PIN_OUTPUT,OUTPUT); digitalWrite(PIN_HEATER,HIGH); digitalWrite(PIN_SENSOR,LOW); digitalWrite(PIN_MOTOR,LOW); digitalWrite(PIN_OUTPUT,LOW); //Serial.begin(115200); SerialBT.begin("ESP32test"); led.begin(); led.show(); led.setBrightness(1); led.setPixelColor(0, led.Color(255,255,255)); led.show(); } void loop() { if ((SerialBT.available()) && (point_count >= 0)){ point_name = SerialBT.readStringUntil(';'); point_count += 20; } if ((point_name == "alcohol") && (point_count >= 1)){ //Serial.println("alcohol point!"); if (alc_P >= 0){ led.setPixelColor(0, led.Color(0,255,255)); for (int j=1; j <= 5; j++){ if(time_count >= T*5/10){ digitalWrite(PIN_MOTOR,HIGH); } for (int i=1; i <= 10; i++){ led.setBrightness(i); led.show(); delay(50); } digitalWrite(PIN_MOTOR,LOW); for (int i=10; i >= 1; i--){ led.setBrightness(i); led.show(); delay(50); } } } alc_P += 1; } if ((point_name == "check") && (point_count >= 1)){ //Serial.println("check point!"); if (alc_P == 0){ led.setPixelColor(0, led.Color(0,0,255)); for (int j=1; j <= 5; j++){ if(time_count >= T*5/10){ digitalWrite(PIN_MOTOR,HIGH); } for (int i=1; i <= 10; i++){ led.setBrightness(i); led.show(); delay(50); } digitalWrite(PIN_MOTOR,LOW); for (int i=10; i >= 1; i--){ led.setBrightness(i); led.show(); delay(50); } } } wifi_conect(); c_acsess(); WiFi.disconnect(); che_P += 1; } if(point_count == 0){ //Serial.println("no point"); alc_P = 0; che_P = 0; } digitalWrite(PIN_HEATER,LOW); delay(10); digitalWrite(PIN_HEATER,HIGH); digitalWrite(PIN_SENSOR,HIGH); delay(3); val = analogRead(PIN_OUTPUT); delay(2); digitalWrite(PIN_SENSOR,LOW); V = V*0.95+float(val)*0.05; if((V-5 >= float(val)) && (time_count >= 20)){ led.setPixelColor(0, led.Color(0,255,0)); for (int j=1; j <= 10; j++){ for (int i=10; i >= 1; i--){ led.setBrightness(i); led.show(); delay(50); } digitalWrite(PIN_MOTOR,LOW); for (int i=1; i <= 10; i++){ led.setBrightness(i); led.show(); delay(50); } } time_count = 0; V = float(val); //Serial.println("used alcohol!"); wifi_conect(); a_acsess(); WiFi.disconnect(); } if(point_count > 0){ point_count -= 1; } time_count += 1; if(time_count > T){ wifi_conect(); w_acsess(); WiFi.disconnect(); led.setPixelColor(0, led.Color(255,0,0)); for (int j=1; j <= 5; j++){ digitalWrite(PIN_MOTOR,HIGH); for (int i=1; i <= 20; i++){ led.setBrightness(i); led.show(); delay(20); } digitalWrite(PIN_MOTOR,LOW); for (int i=20; i >= 1; i--){ led.setBrightness(i); led.show(); delay(20); } } time_count = T/2; } if(time_count <= T*2/10){ led.setPixelColor(0, led.Color(0,255,0)); led.setBrightness(11-(time_count*50/T)); } else if(time_count >= T*5/10){ led.setPixelColor(0, led.Color(255,0,0)); led.setBrightness((time_count*20/T)-9); } else{ led.setPixelColor(0, led.Color(255,255,0)); led.setBrightness(1); } led.show(); delay(990); }
ビーコン(Bluetooth:master)
#include "BluetoothSerial.h" BluetoothSerial SerialBT; String MACadd = "MACアドレスを入力"; uint8_t address[6] = {MACアドレスをuint8_tで入力}; String name = "OBDII"; char *pin = "1234"; //<- standard pin would be provided by default bool connected; void setup() { Serial.begin(115200); SerialBT.begin("ESP32test", true); connected = SerialBT.connect(address); if(connected) { Serial.println("Connected Succesfully!"); } else { while(!SerialBT.connected(10000)) { Serial.println("Failed to connect. Make sure remote device is available and in range, then restart app."); } } if (SerialBT.disconnect()) { Serial.println("Disconnected Succesfully!"); } SerialBT.connect(); delay(10000); for(int i=0; i < 5; i++){ String sendData = "alcohol;"; SerialBT.println(sendData); delay(500); } } void loop() { String sendData = "alcohol;"; SerialBT.println(sendData); Serial.println("send data"); delay(500); }
スクリプト
var id = 'SheetのIDを記入'; function doGet(e) { if (e.parameter == undefined) { result = 'Parameter undefined'; } else { var sheet = SpreadsheetApp.openById(id).getActiveSheet(); var newRow = sheet.getLastRow() + 1; // 次の行に入力する var rowData = []; rowData[0] = new Date(); //タイムスタンプ var d = new Date(); var h = d.getHours(); var min = d.getMinutes(); var s = d.getSeconds(); var now = h+":"+min+":"+s; rowData[1] = now; for (var param in e.parameter) { var value = e.parameter[param]; rowData[parseInt(param)] = value; } var newRange = sheet.getRange(newRow, 1, 1, rowData.length); newRange.setValues([rowData]); var result = 'Ok'// Text des Anworts } return ContentService.createTextOutput(result); }
おわりに
今回は匂いセンサを利用しましたが、匂いセンサは
1.検知が難しい(アルコールの蒸発具合や空気の流れに左右されやすい)
2. 電力消費が多い(センサ内部で加熱する必要がある)
といった欠点があるため、このデバイスのような使用用途ではあまり実用向きではないと感じました。人間ではなく消毒液のボトルの方にセンサを組み込み、個人個人が持つスマートフォンとボトルをBluetoothで接続することで、よりスマートな消毒管理システムを作れるのではないかと考えています。
投稿者の人気記事
-
ysys_Ba
さんが
2021/02/28
に
編集
をしました。
(メッセージ: 初版)
ログインしてコメントを投稿する