--> -->
#blog2navi() *ESP32-CAMで写真を撮ってサーバーに転送する [#g666f0c4] #title(ESP32-CAMで写真を撮ってサーバーに転送する) [[前回の記事:https://www.webdb.co.jp/~atsumi/skimemo/index.php?skimemo%20-%20%C6%FC%B5%AD%2F2021-05-14%2FRENOGY%20ROVER%20ELITE%A4%CE%BE%F0%CA%F3%A4%F2RS-485%B7%D0%CD%B3%A4%C7ESP32-WROOM%A4%CB%BC%F5%A4%B1%A4%C6WEB%A5%B5%A1%BC%A5%D0%A1%BC%A4%CB%C8%F4%A4%D0%A4%B9]]で味を占め、ESP32-CAMを使って定期的に写真を撮ってサーバーに転送してみました。~ ** ESP32-CAM [#bd08fbc4] 小さいのに写真が撮れて、フラッシュも点いて、Wifi通信もできる優れものです。~ 例によってAliExpressで送料込みで900円ほどです。~ https://ja.aliexpress.com/item/1005001970568846.html ~ #ref(camera.png)~ ~ このESP32-CAM(単体)は以下の点が要注意です。 + 技適未対応((■約800円のESP32-CAMで乾電池駆動のWebカメラサーバーを立てる&br;https://qiita.com/Nabeshin/items/b195cad1afe99ce29f1e))~ + USB接続には別ボードが必要~ 上記の商品はESP32-CAM-MBという開発用ボードがセットになっており、ここにUSB接続することでプログラムを書き込めます。~ ** ソース [#k40cdb00] HW的には特にすることは無いのでソースです。 #code2(c){{{ #include "esp_camera.h" #include <WiFiMulti.h> #include <HTTPClient.h> #include <SPIFFS.h> #include <FS.h> #define WIFI_SSID "[SSID]" #define WIFI_PASSWORD "[PASSWORD]" #define UPLOAD_INTERVAL 15000 // WEB upload interval(ms) #define STRING_BOUNDARY "ABCDEFG0123456789" #define STRING_MULTIHEAD1 "Content-Disposition: form-data; name=\"uploadFile\"; filename=\"./camera.jpg\"" #define STRING_MULTIHEAD2 "Content-Type: image/jpeg" #define STATUS_SUCCESS 0; #define STATUS_CAMERA_FAILED 1; #define STATUS_SAVE_FAILED 2; WiFiMulti wifiMulti; //TEST const int ledPin = 4; constexpr int kCameraPin_PWDN = 32; constexpr int kCameraPin_RESET = -1; // NC constexpr int kCameraPin_XCLK = 0; constexpr int kCameraPin_SIOD = 26; constexpr int kCameraPin_SIOC = 27; constexpr int kCameraPin_Y9 = 35; constexpr int kCameraPin_Y8 = 34; constexpr int kCameraPin_Y7 = 39; constexpr int kCameraPin_Y6 = 36; constexpr int kCameraPin_Y5 = 21; constexpr int kCameraPin_Y4 = 19; constexpr int kCameraPin_Y3 = 18; constexpr int kCameraPin_Y2 = 5; constexpr int kCameraPin_VSYNC = 25; constexpr int kCameraPin_HREF = 23; constexpr int kCameraPin_PCLK = 22; void setupCamera() { const camera_config_t config = { .pin_pwdn = kCameraPin_PWDN, .pin_reset = kCameraPin_RESET, .pin_xclk = kCameraPin_XCLK, .pin_sscb_sda = kCameraPin_SIOD, .pin_sscb_scl = kCameraPin_SIOC, .pin_d7 = kCameraPin_Y9, .pin_d6 = kCameraPin_Y8, .pin_d5 = kCameraPin_Y7, .pin_d4 = kCameraPin_Y6, .pin_d3 = kCameraPin_Y5, .pin_d2 = kCameraPin_Y4, .pin_d1 = kCameraPin_Y3, .pin_d0 = kCameraPin_Y2, .pin_vsync = kCameraPin_VSYNC, .pin_href = kCameraPin_HREF, .pin_pclk = kCameraPin_PCLK, .xclk_freq_hz = 20000000, .ledc_timer = LEDC_TIMER_0, .ledc_channel = LEDC_CHANNEL_0, .pixel_format = PIXFORMAT_JPEG, // .frame_size = FRAMESIZE_96X96, // .frame_size = FRAMESIZE_QQVGA, // .frame_size = FRAMESIZE_QCIF, // .frame_size = FRAMESIZE_QCIF, // .frame_size = FRAMESIZE_HQVGA, // .frame_size = FRAMESIZE_240X240, // .frame_size = FRAMESIZE_QVGA, // .frame_size = FRAMESIZE_CIF, // .frame_size = FRAMESIZE_HVGA, .frame_size = FRAMESIZE_VGA, // .frame_size = FRAMESIZE_SVGA, // .frame_size = FRAMESIZE_XGA, // .frame_size = FRAMESIZE_HD, // .frame_size = FRAMESIZE_SXGA, // .frame_size = FRAMESIZE_UXGA, .jpeg_quality = 12, .fb_count = 1, }; if(kCameraPin_PWDN != -1){ pinMode(kCameraPin_PWDN, OUTPUT); digitalWrite(kCameraPin_PWDN, LOW); } esp_err_t err = esp_camera_init(&config); Serial.printf("esp_camera_init: 0x%x\n", err); // init flash pin pinMode(ledPin, OUTPUT); } void flash(bool flag) { if(flag) { digitalWrite(ledPin, HIGH); } else { digitalWrite(ledPin, LOW); } } int post(camera_fb_t *fb, uint8_t msg) { String str = ""; // Wifi if ((wifiMulti.run() == WL_CONNECTED)) { String post = "status=" + String(msg); HTTPClient http; uint8_t httpCode; // POST http.begin("http://[SERVER_NAME]/post.php"); if(!fb) { char buf[512]; String post = "status=false"; post.toCharArray(buf, post.length()); http.addHeader("Content-Type", "application/x-www-form-urlencoded", false, true); httpCode = http.POST((uint8_t*)buf, strlen(buf)); } else { str = "multipart/form-data; boundary="; str += STRING_BOUNDARY; http.addHeader("Content-Type", str); // 構造定義 String head1 = "--"; head1 +=STRING_BOUNDARY; head1 += "\r\n"; head1 += STRING_MULTIHEAD1; head1 += "\r\n"; head1 += STRING_MULTIHEAD2; head1 += "\r\n\r\n"; uint32_t clen1 = head1.length(); String head2 = "\r\n--"; head2 += STRING_BOUNDARY; head2 += "--\r\n\r\n"; uint32_t clen2 = head2.length(); uint32_t clen = clen1 + clen2 + fb->len; uint8_t *uiB = (uint8_t *)malloc(sizeof(uint8_t)*clen); Serial.printf("length: head1=%d, head2=%d, fb=%d, total=%d",clen1,clen2,fb->len,clen); // POST for(int pos=0;pos<clen1;pos++){ uiB[0+pos]=head1[pos]; } for(int pos=0;pos<(fb->len);pos++){ uiB[clen1+pos]=(fb->buf)[pos]; } for(int pos=0;pos<clen2;pos++){ uiB[clen1+(fb->len)+pos]=head2[pos]; } httpCode = http.POST(uiB,clen); free(uiB); } // 結果確認 if(httpCode > 0) { Serial.printf("[HTTP] POST... code: %d\n", httpCode); // HTTP OK if(httpCode == HTTP_CODE_OK) { String payload = http.getString(); Serial.println(payload); } } else { Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str()); } http.end(); } else { Serial.printf("WIFI NOT CONNECTED.\n"); } } void setup() { Serial.begin(115200, SERIAL_8N1); // init camera setupCamera(); // Wifi wifiMulti.addAP(WIFI_SSID, WIFI_PASSWORD); } void loop() { uint16_t msg = 0; Serial.println("-----------------"); // take a picture Serial.println("Taking a photo..."); flash(true); camera_fb_t *fb = esp_camera_fb_get(); flash(false); if (!fb) { Serial.println("Camera capture failed"); msg = STATUS_CAMERA_FAILED; post(fb, msg); } else { msg = STATUS_SUCCESS; // post to wifi Serial.printf("Picture taken.Its size was: %zu bytes.\n",fb->len); post(fb, msg); esp_camera_fb_return(fb); } delay(UPLOAD_INTERVAL); } }}} ~カメラ部分はこのあたり((■ESP32-CAMで撮影してみた&br;https://qiita.com/yuyakato/items/dff67d3e97277666778d ))や、GitHubのサンプル((https://github.com/espressif/esp32-camera/blob/master/examples/take_picture.c ))を参考にすれば難しくありません。 ~POST部分は、ファイル転送は自前で作らないといけません。こちらのサイトを参考にしました。~ ~ ■Arduino HTTPClientでファイルのバイナリ送信~ https://qiita.com/dzonesasaki/items/1417b917751443994ffc ** 結果 [#fbbab58d] こんな感じで撮れます。 #ref(picture.png) #ref(picture.jpg) ** トラブル [#o73caedc] 17:21:33.824 -> Taking a photo... 17:21:37.806 -> [E][camera.c:1483] esp_camera_fb_get(): Failed to get the frame on time! ~当初、原因不明のエラーが出て、パラメータを試行錯誤でいじったりしましたが、原因はカメラの接続不良でした。カメラ部は未接続で送られてくるので、黒いパーツを垂直に起こしてカメラをはめ込み、再び戻すのですが、正しく装着できていないと上記エラーが出ます。 ~指で押さえてエラーが解消する場合は、それが原因です。 #htmlinsert(twitterbutton.html) RIGHT:Category: [[[修理>日記/Category/修理]]] - 09:09:48 ---- #htmlinsert(20210627_camera.html) ---- RIGHT:&blog2trackback(); #comment(above) #blog2navi()