syouwa-taroのアイコン画像
syouwa-taro 2022年10月10日作成 (2022年11月17日更新) © Apache-2.0
製作品 製作品 閲覧数 1270
syouwa-taro 2022年10月10日作成 (2022年11月17日更新) © Apache-2.0 製作品 製作品 閲覧数 1270

レーダーによる園児置き去り防止実験2 写真を撮りLINEで通報

レーダーによる園児置き去り防止実験2 写真を撮りLINEで通報

概要

前回ドップラーレーダーで人の動きを計測し、ネットでAmbientにデータを送り時系列で車内温度、動きが見える実験を行ったが緊急時関係者に通報する方法として「データー確認通報サービス」があったが有料で馴染みづらかった。
今回LINENotifyにより、動き検出すると写真を撮りLINE通報する仕組みを作った。写真により車内状況がより正確に伝わり、レーダーにより万一シートで隠れていても電波がシートを通し動きを検出しカメラや感熱センサだけよりも見逃しが防げる。

動作

RCWL_0516レーダー基板により動きがあるとドップラー信号波形が変化し、この波形をPro_Micro のAD入力で読み込み変化量を計算し一定の変化量を検出するとMOVEOUTに出力(動きあり:1 動きなし:0)
ESP32Camはこの出力を読み、動きがあると、写真を撮りLINE NotifyによりLINE通報する。着信音でLINEを受け取るとメッセージと写真が表示され緊急通報が行われる。
本実験ソフトでは電源を入れると一度確認用の試し撮り+LINE通報を行う。それ以降は動きがあるとLINE通報する。ただし一度写真を送ると次の写真は75秒以降になる:LINENotify仕様。
10,13追記 電源回路追加
置き去り防止回路の電源としてLi電池を使用。エンジンがかかり車内電気(シガーソケット)+12vからUSB変換し+5v 充電モジュールに入力し充電する。この時回路へ給電しないようにリレーによりSWOFFする。エンジンが切れ車内電気が切れるとリレーが反転しSWONし回路への給電を行い防止回路が作動始める。ESP32は消費電力が多いのでスリープで使うことが課題である。1日以上Batteryを持たせるのが必要と思われる。エンジンがかかると充電され継続的な動作が行うことが出来る。
10.17追記 ESP32 DeepSleep
ESP32を通常DeepSleepにしてリチウム電池の消費を減らす。動きtriggerによりwakeup
10.18追記 Pro_Micro 動き検出delay
エンジンを切った後driverが車のドアをロックするまでの時間 動き検出を遅らせる。

主な部品

部品 備考
ESP32Cam ESP32にカメラが付いた(¥800~ ) LINE Notifyにより写真を撮りWifiでLINE通報。Wifi起動するとアナログが読めずADマイコン追加して対応
注意 ESP32Camは技適未取得品です。短期間の実験を目的とする場合は、総務省のホームページから技適未取得機器を用いた実験等の特例制度の手続(届出)を行う事で、特例を受ける事ができます。
Pro_Micro 3.3V/8M レーダーのドップラー波形を読み変化量を計算し動き判定。5V/16M品もある。SparkFunでなくArduinoLeonard環境でもコンパイルできるが、転送ソフトが書き替えられ使えなくなることがあるようです。
RCWL_0516 ドップラーレーダー 4V~28V 3.2G 到達距離5~7m  @¥100~安価であるが、バラツキでかなり感度の悪い物もあった。ドップラー信号波形は改造してIC12pin(2out)から取り出す
注意 RCWL_0516は技適未取得品です。
Buzzer 車内から外部へのAlarmを発信する。実験ではうるさいのでLEDなどが良いです。
TP4056 10.13追記 Li電池充電モジュール (@60~ )エンジンがかかっている時充電し切れると回路に給電
Y14H-1C-5DS 10.13追記 5V小型リレー  エンジンがかかりシガー+12vからUSB変換した+5vの電気でコイルONし回路への電気SW_OFFさせる。エンジンが切れるとコイルOFFし回路への電源SW_ONさせる。
Li電池 10.13追記 実験では3.7v600mAHを使用 マイコンスリープで1日以上持つのが目標
シガーUSB変換ジャック 10.13追記 実際の車のシガーソケットから充電電源を取るのはまだ未実験

回路図(10.13 電源回路追記)

キャプションを入力できます

ここに動画が表示されます

Li電源キバン

考察

LINE通報するとき写真があることにより状況把握が確実にでき、有効な機能となることがわかります。
ドップラーレーダーによる検出は指向性が広く、シートも通過して動き検出し有効な方法と考えられます。
また車内温度情報は今回なかったが、より危険状況が把握でき有効な機能と考えられる(40℃車内で動きがあればかなり危険)
ESP32はWifi使用時消費i電力が多く通報以外ではdeep sleep mode にし、動きのtriggerでwakeupさせるなどがよさそうです。

参考にさせて頂いた記事

ESP32-CAMでWebカメラの設定をしてみた
ESP32-CAM_Linenotify.ino
LINEに写真を送る防犯カメラ
RCWL-0516マイクロ波レーダーセンサーを使ってみる
(Arduino) Pro Micro に関する記事です
ESP32のGPIO入力について
ESP32のディープスリープを調べる
LINEの着信音・通知音が鳴らない時の対処法と設定手順を解説

LPro_Micro10.18v

const int PIN_RADAR = 20; //A2:20pin A3:21pin const int PIN_MOVOUT = 9; //A9:9pin int r = 0; int rr = 0 ; int rs = 0; int rrs = 0; //radar 差分積算計算 void setup() { //pinMode pinMode(PIN_RADAR,INPUT); //Radar analog 入力 pinMode(PIN_MOVOUT,OUTPUT); //MOVOUT 出力 ➡ ESP32WakeUp digitalWrite (PIN_MOVOUT , LOW); //init Serial.begin(115200); delay(100000); //powON reset start から100秒(driver降りるまで)検出delayする } void loop() { int i; int s; int rrs=rs; int RSDS=0; //init for(i=0; i<100; i++ ) { //5sec動き積算 RSDS 45ms X 100 =4.5sec //********radar値積算 = ∑r/10 (300回)/45ms合計******** rs = 0; //rs init for ( s = 0; s < 300; s++) //rsum init { r = analogRead(PIN_RADAR); rs = r/10 + rs; } // Serial.println(rs); //****rs差分積算 = RSDS **** if (abs(rs-rrs) > 1000) //1000以下はノイズ 關地設定 { RSDS = abs(rs-rrs)-1000 + RSDS; //Serial.println(r-rr); if (RSDS > 10000) RSDS=10000; //30000以上計算不可 } rrs = rs; //**************radar Alarm 積算値R閾値設定 if (RSDS > 100 ) digitalWrite(PIN_MOVOUT,HIGH); else digitalWrite(PIN_MOVOUT,LOW); Serial.println(RSDS); } }

ESP32Cam10.17v

/* ESP32-CAM (Save a captured photo to Line Notify) Author : ChungYi Fu (Kaohsiung, Taiwan) 2021-7-4 13:30 https://www.facebook.com/francefu You could only send up to 50 images to Line Notify in one hour. The maximum size of post-upload image is XGA(1024*768). */ // Enter your WiFi ssid and password const char* ssid = "========="; //************your network SSID**************** const char* password = "========="; //************your network password************ RTC_DATA_ATTR int bootCount = 0; // RTCスローメモリに変数を確保 deepsleep wakeup 電源スタート(エンジンきったとき)時delay String lineNotifyToken = "============="; //************Line Notify Token***************** #include <WiFi.h> #include <WiFiClientSecure.h> #include "soc/soc.h" //用於電源不穩不重開機 #include "soc/rtc_cntl_reg.h" //用於電源不穩不重開機 #include "esp_camera.h" //視訊函式 //ESP32-CAM 安信可模組腳位設定 #define PWDN_GPIO_NUM 32 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 0 #define SIOD_GPIO_NUM 26 #define SIOC_GPIO_NUM 27 #define Y9_GPIO_NUM 35 #define Y8_GPIO_NUM 34 #define Y7_GPIO_NUM 39 #define Y6_GPIO_NUM 36 #define Y5_GPIO_NUM 21 #define Y4_GPIO_NUM 19 #define Y3_GPIO_NUM 18 #define Y2_GPIO_NUM 5 #define VSYNC_GPIO_NUM 25 #define HREF_GPIO_NUM 23 #define PCLK_GPIO_NUM 22 void setup() { WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //關閉電源不穩就重開機的設定 Serial.begin(115200); Serial.setDebugOutput(true); //開啟診斷輸出 Serial.println(); //10.17V************************************************************************************* if( bootCount == 0 ){ delay(1000); //電源スタート直後は運転手がでるまで***SEC動き検出をdelay // 起動回数カウントアップ bootCount++; deepsleep(); } //視訊組態設定 https://github.com/espressif/esp32-camera/blob/master/driver/include/esp_camera.h camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM; config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM; config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM; config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM; config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM; config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM; config.pin_sscb_sda = SIOD_GPIO_NUM; config.pin_sscb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; config.pixel_format = PIXFORMAT_JPEG; // // WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality // Ensure ESP32 Wrover Module or other board with PSRAM is selected // Partial images will be transmitted if image exceeds buffer size // // if PSRAM IC present, init with UXGA resolution and higher JPEG quality // for larger pre-allocated frame buffer. if(psramFound()){ //是否有PSRAM(Psuedo SRAM)記憶體IC config.frame_size = FRAMESIZE_UXGA; config.jpeg_quality = 10; config.fb_count = 2; } else { config.frame_size = FRAMESIZE_SVGA; config.jpeg_quality = 12; config.fb_count = 1; } //視訊初始化 esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed with error 0x%x", err); ESP.restart(); } //可自訂視訊框架預設大小(解析度大小) sensor_t * s = esp_camera_sensor_get(); // initial sensors are flipped vertically and colors are a bit saturated if (s->id.PID == OV3660_PID) { s->set_vflip(s, 1); // flip it back s->set_brightness(s, 1); // up the brightness just a bit s->set_saturation(s, -2); // lower the saturation } // drop down frame size for higher initial frame rate s->set_framesize(s, FRAMESIZE_SVGA); //解析度 UXGA(1600x1200), SXGA(1280x1024), XGA(1024x768), SVGA(800x600), VGA(640x480), CIF(400x296), QVGA(320x240), HQVGA(240x176), QQVGA(160x120), QXGA(2048x1564 for OV3660) //s->set_vflip(s, 1); //垂直翻轉 //s->set_hmirror(s, 1); //水平鏡像 //閃光燈(GPIO4) ledcAttachPin(4, 4); ledcSetup(4, 5000, 8); WiFi.mode(WIFI_AP_STA); //其他模式 WiFi.mode(WIFI_AP); WiFi.mode(WIFI_STA); //指定Client端靜態IP //WiFi.config(IPAddress(192, 168, 201, 100), IPAddress(192, 168, 201, 2), IPAddress(255, 255, 255, 0)); for (int i=0;i<2;i++) { WiFi.begin(ssid, password); //執行網路連線 delay(1000); Serial.println(""); Serial.print("Connecting to "); Serial.println(ssid); long int StartTime=millis(); while (WiFi.status() != WL_CONNECTED) { delay(500); if ((StartTime+5000) < millis()) break; //等待10秒連線 } if (WiFi.status() == WL_CONNECTED) { //若連線成功 Serial.println(""); Serial.println("STAIP address: "); Serial.println(WiFi.localIP()); Serial.println(""); for (int i=0;i<5;i++) { //flash light 若連上WIFI設定閃光燈快速閃爍 ledcWrite(4,10); delay(200); ledcWrite(4,0); delay(200); } break; } } if (WiFi.status() != WL_CONNECTED) { //若連線失敗 for (int i=0;i<2;i++) { //若連不上WIFI設定閃光燈慢速閃爍 ledcWrite(4,10); delay(1000); ledcWrite(4,0); delay(1000); } ESP.restart(); } //設定閃光燈為低電位 pinMode(4, OUTPUT); digitalWrite(4, LOW); //傳送影像 //Serial.println(sendCapturedImage2LineNotify(lineNotifyToken)); //傳送文字 Hello / World 2line under picture // Serial.println(sendRequest2LineNotify(lineNotifyToken, "message=\nHello\nWorld")); //傳送貼圖 "Hello World" above boy mascot //Serial.println(sendRequest2LineNotify(lineNotifyToken, "message=Hello World&stickerPackageId=1&stickerId=2")); //傳送網址 jpeg modelpicture X2 //String imageThumbnail = "https://s2.lookerpets.com/imgs/202008/14/11/15973742786521.jpg"; //String imageFullsize = "https://i.ytimg.com/vi/WLUEXiTAPaI/maxresdefault.jpg"; //Serial.println(sendRequest2LineNotify(lineNotifyToken, "message=Hello World&imageThumbnail="+imageFullsize+"&imageFullsize="+imageThumbnail)); /* // 起動方法取得 esp_sleep_wakeup_cause_t wakeup_reason; wakeup_reason = esp_sleep_get_wakeup_cause(); switch(wakeup_reason){ case ESP_SLEEP_WAKEUP_EXT0 : Serial.printf("外部割り込み(RTC_IO)で起動\n"); break; case ESP_SLEEP_WAKEUP_EXT1 : Serial.printf("外部割り込み(RTC_CNTL)で起動 IO=%llX\n", esp_sleep_get_ext1_wakeup_status()); break; case ESP_SLEEP_WAKEUP_TIMER : Serial.printf("タイマー割り込みで起動\n"); break; case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.printf("タッチ割り込みで起動 PAD=%d\n", esp_sleep_get_touchpad_wakeup_status()); break; case ESP_SLEEP_WAKEUP_ULP : Serial.printf("ULPプログラムで起動\n"); break; case ESP_SLEEP_WAKEUP_GPIO : Serial.printf("ライトスリープからGPIO割り込みで起動\n"); break; case ESP_SLEEP_WAKEUP_UART : Serial.printf("ライトスリープからUART割り込みで起動\n"); break; default : Serial.printf("スリープ以外からの起動\n"); break; } */ } void loop() { ledcWrite(4,10); Serial.println(sendCapturedImage2LineNotify(lineNotifyToken)); ledcWrite(4,0); delay(72000); //You could only send up to 50 images to Line Notify in one hour. deepsleep(); //10.17V deepsleep } //10.17V deepsleep **************************************************** void deepsleep() { // PIN_RADAR=GPIO12がHIGHになったら起動 pinMode(GPIO_NUM_12, INPUT); esp_sleep_enable_ext0_wakeup(GPIO_NUM_12, HIGH); // ディープスリープ esp_deep_sleep_start(); Serial.println("This will never be printed"); } String sendCapturedImage2LineNotify(String token) { camera_fb_t * fb = NULL; fb = esp_camera_fb_get(); if(!fb) { Serial.println("Camera capture failed"); delay(1000); ESP.restart(); return "Camera capture failed"; } WiFiClientSecure client_tcp; client_tcp.setInsecure(); //run version 1.0.5 or above Serial.println("Connect to notify-api.line.me"); if (client_tcp.connect("notify-api.line.me", 443)) { Serial.println("Connection successful"); String message = "\nバス内で人の動きがありました"; String head = "--Taiwan\r\nContent-Disposition: form-data; name=\"message\"; \r\n\r\n" + message + "\r\n--Taiwan\r\nContent-Disposition: form-data; name=\"imageFile\"; filename=\"esp32-cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n"; String tail = "\r\n--Taiwan--\r\n"; uint16_t imageLen = fb->len; uint16_t extraLen = head.length() + tail.length(); uint16_t totalLen = imageLen + extraLen; client_tcp.println("POST /api/notify HTTP/1.1"); client_tcp.println("Connection: close"); client_tcp.println("Host: notify-api.line.me"); client_tcp.println("Authorization: Bearer " + token); client_tcp.println("Content-Length: " + String(totalLen)); client_tcp.println("Content-Type: multipart/form-data; boundary=Taiwan"); client_tcp.println(); client_tcp.print(head); uint8_t *fbBuf = fb->buf; size_t fbLen = fb->len; for (size_t n=0;n<fbLen;n=n+1024) { if (n+1024<fbLen) { client_tcp.write(fbBuf, 1024); fbBuf += 1024; } else if (fbLen%1024>0) { size_t remainder = fbLen%1024; client_tcp.write(fbBuf, remainder); } } client_tcp.print(tail); esp_camera_fb_return(fb); String getResponse="",Feedback=""; int waitTime = 10000; // timeout 10 seconds long startTime = millis(); boolean state = false; while ((startTime + waitTime) > millis()) { Serial.print("."); delay(100); while (client_tcp.available()) { char c = client_tcp.read(); if (state==true) Feedback += String(c); if (c == '\n') { if (getResponse.length()==0) state=true; getResponse = ""; } else if (c != '\r') getResponse += String(c); startTime = millis(); } if (Feedback.length()>0) break; } Serial.println(); client_tcp.stop(); return Feedback; } else { return "Connected to notify-api.line.me failed."; } } /* String sendRequest2LineNotify(String token, String request) { request.replace("%","%25"); request.replace(" ","%20"); //request.replace("&","%20"); request.replace("#","%20"); //request.replace("\'","%27"); request.replace("\"","%22"); request.replace("\n","%0D%0A"); request.replace("%3Cbr%3E","%0D%0A"); request.replace("%3Cbr/%3E","%0D%0A"); request.replace("%3Cbr%20/%3E","%0D%0A"); request.replace("%3CBR%3E","%0D%0A"); request.replace("%3CBR/%3E","%0D%0A"); request.replace("%3CBR%20/%3E","%0D%0A"); request.replace("%20stickerPackageId","&stickerPackageId"); request.replace("%20stickerId","&stickerId"); WiFiClientSecure client_tcp; client_tcp.setInsecure(); //run version 1.0.5 or above Serial.println("Connect to notify-api.line.me"); if (client_tcp.connect("notify-api.line.me", 443)) { Serial.println("Connection successful"); Serial.println(request); client_tcp.println("POST /api/notify HTTP/1.1"); client_tcp.println("Connection: close"); client_tcp.println("Host: notify-api.line.me"); client_tcp.println("User-Agent: ESP8266/1.0"); client_tcp.println("Authorization: Bearer " + token); client_tcp.println("Content-Type: application/x-www-form-urlencoded"); client_tcp.println("Content-Length: " + String(request.length())); client_tcp.println(); client_tcp.println(request); client_tcp.println(); String getResponse="",Feedback=""; boolean state = false; int waitTime = 3000; // timeout 3 seconds long startTime = millis(); while ((startTime + waitTime) > millis()) { Serial.print("."); delay(100); while (client_tcp.available()) { char c = client_tcp.read(); if (state==true) Feedback += String(c); if (c == '\n') { if (getResponse.length()==0) state=true; getResponse = ""; } else if (c != '\r') getResponse += String(c); startTime = millis(); } if (getResponse.length()>0) break; } Serial.println(); client_tcp.stop(); return Feedback; } else return "Connection failed"; } */
ログインしてコメントを投稿する