Răsfoiți Sursa

Merge branch '合宙esp32s3摄像头测试' of hardware-development/ESP32S3 into xxy

xuxinyi 8 luni în urmă
părinte
comite
1f494d206a
5 a modificat fișierele cu 205 adăugiri și 163 ștergeri
  1. BIN
      image.png
  2. 1 11
      main/app_main.c
  3. 153 152
      main/camera.c
  4. 50 0
      python/main.py
  5. 1 0
      合宙的ESP32S3硬件图.md

BIN
image.png


+ 1 - 11
main/app_main.c

@@ -25,16 +25,6 @@ void app_main(void)
 
     // 等待Wi-Fi连接
     vTaskDelay(10000 / portTICK_PERIOD_MS);
+    xTaskCreate(take_photo, "take_photo", 1024 * 50, NULL, 20, NULL);
 
-    take_photo();
-    vTaskDelay(4*1000 / portTICK_PERIOD_MS);
-    ESP_LOGI(TAG, "测试");
-
-    while (true)
-    {
-        /* code */
-        // 执行HTTP GET请求
-        vTaskDelay(4*1000 / portTICK_PERIOD_MS);
-    }
-    
 }

+ 153 - 152
main/camera.c

@@ -1,148 +1,44 @@
-/**
- * This example takes a picture every 5s and print its size on serial monitor.
- */
-
-// =============================== SETUP ======================================
-
-// 1. Board setup (Uncomment):
-// #define BOARD_WROVER_KIT
-// #define BOARD_ESP32CAM_AITHINKER
-// #define BOARD_ESP32S3_WROOM
-
-/**
- * 2. Kconfig setup
- *
- * If you have a Kconfig file, copy the content from
- *  https://github.com/espressif/esp32-camera/blob/master/Kconfig into it.
- * In case you haven't, copy and paste this Kconfig file inside the src directory.
- * This Kconfig file has definitions that allows more control over the camera and
- * how it will be initialized.
- */
-
-/**
- * 3. Enable PSRAM on sdkconfig:
- *
- * CONFIG_ESP32_SPIRAM_SUPPORT=y
- *
- * More info on
- * https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/kconfig.html#config-esp32-spiram-support
- */
-
-// ================================ CODE ======================================
-
 #include <esp_log.h>
 #include <esp_system.h>
 #include <nvs_flash.h>
 #include <sys/param.h>
 #include <string.h>
-
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
-
-// support IDF 5.x
-#ifndef portTICK_RATE_MS
-#define portTICK_RATE_MS portTICK_PERIOD_MS
-#endif
-
+#include "esp_http_client.h"
 #include "esp_camera.h"
 
-#define ESP32_S3_KORVO 1 //ESP32-S3-KORVO-2_V3.0配套的自定义引脚
-
-// WROVER-KIT PIN Map
-#ifdef BOARD_WROVER_KIT
-
-#define CAM_PIN_PWDN -1  //power down is not used
-#define CAM_PIN_RESET -1 //software reset will be performed
-#define CAM_PIN_XCLK 21
-#define CAM_PIN_SIOD 26
-#define CAM_PIN_SIOC 27
-
-#define CAM_PIN_D7 35
-#define CAM_PIN_D6 34
-#define CAM_PIN_D5 39
-#define CAM_PIN_D4 36
-#define CAM_PIN_D3 19
-#define CAM_PIN_D2 18
-#define CAM_PIN_D1 5
-#define CAM_PIN_D0 4
-#define CAM_PIN_VSYNC 25
-#define CAM_PIN_HREF 23
-#define CAM_PIN_PCLK 22
-
-#endif
-
-// ESP32Cam (AiThinker) PIN Map
-#ifdef BOARD_ESP32CAM_AITHINKER
-
-#define CAM_PIN_PWDN 32
-#define CAM_PIN_RESET -1 //software reset will be performed
-#define CAM_PIN_XCLK 0
-#define CAM_PIN_SIOD 26
-#define CAM_PIN_SIOC 27
-
-#define CAM_PIN_D7 35
-#define CAM_PIN_D6 34
-#define CAM_PIN_D5 39
-#define CAM_PIN_D4 36
-#define CAM_PIN_D3 21
-#define CAM_PIN_D2 19
-#define CAM_PIN_D1 18
-#define CAM_PIN_D0 5
-#define CAM_PIN_VSYNC 25
-#define CAM_PIN_HREF 23
-#define CAM_PIN_PCLK 22
-
-#endif
-// ESP32S3 (WROOM) PIN Map
-#ifdef BOARD_ESP32S3_WROOM
-#define CAM_PIN_PWDN 38
-#define CAM_PIN_RESET -1   //software reset will be performed
-#define CAM_PIN_VSYNC 6
-#define CAM_PIN_HREF 7
-#define CAM_PIN_PCLK 13
-#define CAM_PIN_XCLK 15
-#define CAM_PIN_SIOD 4
-#define CAM_PIN_SIOC 5
-#define CAM_PIN_D0 11
-#define CAM_PIN_D1 9
-#define CAM_PIN_D2 8
-#define CAM_PIN_D3 10
-#define CAM_PIN_D4 12
-#define CAM_PIN_D5 18
-#define CAM_PIN_D6 17
-#define CAM_PIN_D7 16
-#endif
-
-// ESP32-S3-KORVO-2_V3.0 音频开发版
-#ifdef ESP32_S3_KORVO
-#define CAM_PIN_PWDN -1 //没用直接接高
-#define CAM_PIN_RESET -1   //software reset will be performed
-#define CAM_PIN_VSYNC 21
-#define CAM_PIN_HREF 38
-#define CAM_PIN_PCLK 11
-#define CAM_PIN_XCLK 40
-#define CAM_PIN_SIOD 17
-#define CAM_PIN_SIOC 18
-#define CAM_PIN_D0 13
+#define ESP32_S3_HEZHOU 1  // ESP32-S3-KORVO-2_V3.0配套的自定义引脚
+
+// ESP32-S3-合宙的开发板
+#ifdef ESP32_S3_HEZHOU
+#define CAM_PIN_PWDN -1      // 没用直接接高
+#define CAM_PIN_RESET -1     // software reset will be performed
+#define CAM_PIN_VSYNC 42
+#define CAM_PIN_HREF 41
+#define CAM_PIN_PCLK 36
+#define CAM_PIN_XCLK 39
+#define CAM_PIN_SIOD 21
+#define CAM_PIN_SIOC 46
+#define CAM_PIN_D0 34
 #define CAM_PIN_D1 47
-#define CAM_PIN_D2 14
-#define CAM_PIN_D3 3
-#define CAM_PIN_D4 12
-#define CAM_PIN_D5 42
-#define CAM_PIN_D6 41
-#define CAM_PIN_D7 39
+#define CAM_PIN_D2 48
+#define CAM_PIN_D3 33
+#define CAM_PIN_D4 35
+#define CAM_PIN_D5 37
+#define CAM_PIN_D6 38
+#define CAM_PIN_D7 40
 #endif
 
 static const char *TAG = "example:take_picture";
+#define BOUNDARY "----ESP32Boundary"
 
-#if ESP_CAMERA_SUPPORTED
 static camera_config_t camera_config = {
     .pin_pwdn = CAM_PIN_PWDN,
     .pin_reset = CAM_PIN_RESET,
     .pin_xclk = CAM_PIN_XCLK,
     .pin_sccb_sda = CAM_PIN_SIOD,
     .pin_sccb_scl = CAM_PIN_SIOC,
-
     .pin_d7 = CAM_PIN_D7,
     .pin_d6 = CAM_PIN_D6,
     .pin_d5 = CAM_PIN_D5,
@@ -154,60 +50,165 @@ static camera_config_t camera_config = {
     .pin_vsync = CAM_PIN_VSYNC,
     .pin_href = CAM_PIN_HREF,
     .pin_pclk = CAM_PIN_PCLK,
-
     .xclk_freq_hz = 20000000,  // XCLK 设置为 20MHz
     .ledc_timer = LEDC_TIMER_0,
     .ledc_channel = LEDC_CHANNEL_0,
-
-    .pixel_format = PIXFORMAT_JPEG, // RGB565 格式
-    .frame_size = FRAMESIZE_QVGA,     // 使用 QVGA (320x240)
-
-    .jpeg_quality = 2,   // JPEG 质量 (0-63, 低值=高质量)
-    .fb_count = 1,        // 降低到 2,减少 DRAM 负载
-    .fb_location = CAMERA_FB_IN_DRAM,  // 使用 DRAM (无 PSRAM)
+    .pixel_format = PIXFORMAT_JPEG, // 使用 JPEG 格式
+    .frame_size = FRAMESIZE_SVGA,    // 使用 QVGA (320x240)
+    .jpeg_quality = 60,   // JPEG 质量 (0-63, 低值=高质量)
+    .fb_count = 1,       // 帧缓存数量
+    .fb_location = CAMERA_FB_IN_DRAM, // 使用 DRAM
     .grab_mode = CAMERA_GRAB_WHEN_EMPTY,
 };
 
 static esp_err_t init_camera(void)
 {
-    //initialize the camera
     esp_err_t err = esp_camera_init(&camera_config);
     if (err != ESP_OK)
     {
         ESP_LOGE(TAG, "Camera Init Failed");
         return err;
     }
-
     return ESP_OK;
 }
-#endif
 
-void take_photo(void)
+// 上传图片到服务器
+#define MULTIPART_BOUNDARY "----WebKitFormBoundary7MA4YWxkTrZu0gW"  // 多部分表单的边界
+
+esp_err_t upload_picture(camera_fb_t *pic, long image_size)
 {
-#if ESP_CAMERA_SUPPORTED
-    if(ESP_OK != init_camera()) {
-        return;
+    esp_http_client_config_t config = {
+        .url = "http://60.204.139.57:7002/upload",  // 服务器地址
+        .timeout_ms = 20000,
+        .buffer_size = 1024 * 20,
+    };
+
+    // 初始化 HTTP 客户端
+    esp_http_client_handle_t client = esp_http_client_init(&config);
+    if (client == NULL) {
+        ESP_LOGE(TAG, "Failed to initialize HTTP client");
+        return ESP_FAIL;
+    }
+
+    esp_http_client_set_method(client, HTTP_METHOD_POST);
+    // 设置请求头(multipart/form-data)
+    esp_http_client_set_header(client, "Content-Type", "multipart/form-data; boundary=" MULTIPART_BOUNDARY);
+
+    // 请求头开始部分
+    char part1[256];
+    int part1_len = snprintf(part1, sizeof(part1),
+                             "--" MULTIPART_BOUNDARY "\r\n"
+                             "Content-Disposition: form-data; name=\"file\"; filename=\"image.jpg\"\r\n"
+                             "Content-Type: image/jpeg\r\n\r\n");
+
+    // 构建多部分表单数据的结束部分
+    char part2[64];
+    int part2_len = snprintf(part2, sizeof(part2), "\r\n--" MULTIPART_BOUNDARY "--\r\n");
+
+    // 设置总的Content-Length
+    long content_length = part1_len + image_size + part2_len;
+    char content_length_str[32];
+    snprintf(content_length_str, sizeof(content_length_str), "%ld", content_length);
+    esp_http_client_set_header(client, "Content-Length", content_length_str);
+
+    // 开始发送请求
+    int err = esp_http_client_open(client, content_length);
+    if (err != ESP_OK)
+    {
+        ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
+        esp_http_client_cleanup(client); // 清理 HTTP 客户端
+        return ESP_FAIL;
     }
 
-    while (1)
+    // 发送多部分表单数据的开始部分
+    esp_http_client_write(client, part1, part1_len);
+
+    // 发送文件数据
+    char buffer[1024];
+    size_t bytes_sent = 0;
+    while (bytes_sent < pic->len)
+    {
+        size_t to_send = (pic->len - bytes_sent < sizeof(buffer)) ? (pic->len - bytes_sent) : sizeof(buffer);
+        esp_http_client_write(client, (const char *)(pic->buf + bytes_sent), to_send);
+        bytes_sent += to_send;
+    }
+
+    // 发送多部分表单数据的结束部分
+    esp_http_client_write(client, part2, part2_len);
+
+    int response_length = esp_http_client_fetch_headers(client);
+    if (response_length < 0)
     {
+        ESP_LOGE(TAG, "HTTP client fetch headers failed");
+    }
+    else
+    {
+        ESP_LOGI(TAG, "HTTP client fetch headers succeeded, length=%d", response_length);
+    }
+
+    // 动态分配初始缓冲区
+    char *response_buffer = (char *)malloc(1024);
+    if (response_buffer == NULL)
+    {
+        ESP_LOGE(TAG, "Failed to allocate memory for response buffer");
+        esp_http_client_cleanup(client);
+        return ESP_FAIL;
+    }
+
+    // 读取响应内容
+    int read_len = esp_http_client_read(client, response_buffer, 1024 - 1);
+    if (read_len >= 0)
+    {
+        response_buffer[read_len] = '\0'; // 确保字符串以null字符结尾
+        ESP_LOGI(TAG, "HTTP Response: %s", response_buffer);
+    }
+    else
+    {
+        ESP_LOGE(TAG, "Failed to read response");
+    }
+
+    // 释放分配的内存
+    free(response_buffer);
+
+    // 清理
+    esp_http_client_close(client);
+    esp_http_client_cleanup(client);
+
+    return err;
+}
+
+
+
+// 拍照并上传
+void take_photo(void *param)
+{
+    if (ESP_OK != init_camera())
+    {
+        return;
+    }
+    while (true)
+    {
+        /* code */
         ESP_LOGI(TAG, "Taking picture...");
         camera_fb_t *pic = esp_camera_fb_get();
-        if ( pic == NULL) 
+        if (pic == NULL)
         {
-            /* code */
             ESP_LOGE(TAG, "Camera capture failed");
-            return; 
+            return;
         }
-        
-        // use pic->buf to access the image
+    
         ESP_LOGI(TAG, "Picture taken! Its size was: %zu bytes", pic->len);
+    
+        // 上传图片
+        esp_err_t err = upload_picture(pic,pic->len);
+        if (err != ESP_OK)
+        {
+            ESP_LOGE(TAG, "Failed to upload picture");
+        }
         esp_camera_fb_return(pic);
-
-        vTaskDelay(5000 / portTICK_RATE_MS);
+        vTaskDelay(10*60*1000 / portTICK_PERIOD_MS);
     }
-#else
-    ESP_LOGE(TAG, "Camera support is not available for this chip");
-    return;
-#endif
+    
+    vTaskDelete(NULL);
 }
+

+ 50 - 0
python/main.py

@@ -0,0 +1,50 @@
+注:同次提交下的esp32程序配套的上传拍照文件的python flask程序,提供上传接口。
+
+
+from flask import Flask, request, jsonify
+import os
+import datetime  # 导入 datetime 模块
+
+app = Flask(__name__)
+
+# 配置上传文件夹
+UPLOAD_FOLDER = 'uploads'
+app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
+
+# 设置允许上传的文件类型
+ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
+
+# 检查文件扩展名是否允许上传
+def allowed_file(filename):
+    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
+
+# 上传照片的路由
+@app.route('/upload', methods=['POST'])
+def upload_file():
+    if 'file' not in request.files:
+        return jsonify({'message': 'No file part'}), 400
+
+    file = request.files['file']
+
+    # 如果用户没有选择文件
+    if file.filename == '':
+        return jsonify({'message': 'No selected file'}), 400
+
+    if file and allowed_file(file.filename):
+        timestamp = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
+        extension = file.filename.rsplit('.', 1)[1].lower()
+        filename = f"{timestamp}.{extension}"
+        # 生成保存路径
+        file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
+        file.save(file_path)
+        return jsonify({'message': 'File uploaded successfully', 'filename': filename}), 200
+
+    return jsonify({'message': 'File not allowed'}), 400
+
+if __name__ == '__main__':
+    # 创建上传文件夹
+    if not os.path.exists(UPLOAD_FOLDER):
+        os.makedirs(UPLOAD_FOLDER)
+
+    # 启动 Flask 应用,并指定端口为 7002
+    app.run(debug=True, host='0.0.0.0', port=7002)

+ 1 - 0
合宙的ESP32S3硬件图.md

@@ -0,0 +1 @@
+![alt text](image.png)