diff --git a/main/boards/common/camera.h b/main/boards/common/camera.h index 79e0f673..75c780c1 100644 --- a/main/boards/common/camera.h +++ b/main/boards/common/camera.h @@ -7,6 +7,8 @@ class Camera { public: virtual void SetExplainUrl(const std::string& url, const std::string& token) = 0; virtual bool Capture() = 0; + virtual bool SetHMirror(bool enabled) = 0; + virtual bool SetVFlip(bool enabled) = 0; virtual std::string Explain(const std::string& question) = 0; }; diff --git a/main/boards/common/esp32_camera.cc b/main/boards/common/esp32_camera.cc index eeaaf76b..d4889901 100644 --- a/main/boards/common/esp32_camera.cc +++ b/main/boards/common/esp32_camera.cc @@ -95,6 +95,39 @@ bool Esp32Camera::Capture() { } return true; } +bool Esp32Camera::SetHMirror(bool enabled) { + sensor_t *s = esp_camera_sensor_get(); + if (s == nullptr) { + ESP_LOGE(TAG, "Failed to get camera sensor"); + return false; + } + + esp_err_t err = s->set_hmirror(s, enabled); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set horizontal mirror: %d", err); + return false; + } + + ESP_LOGI(TAG, "Camera horizontal mirror set to: %s", enabled ? "enabled" : "disabled"); + return true; +} + +bool Esp32Camera::SetVFlip(bool enabled) { + sensor_t *s = esp_camera_sensor_get(); + if (s == nullptr) { + ESP_LOGE(TAG, "Failed to get camera sensor"); + return false; + } + + esp_err_t err = s->set_vflip(s, enabled); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set vertical flip: %d", err); + return false; + } + + ESP_LOGI(TAG, "Camera vertical flip set to: %s", enabled ? "enabled" : "disabled"); + return true; +} /** * @brief 将摄像头捕获的图像发送到远程服务器进行AI分析和解释 diff --git a/main/boards/common/esp32_camera.h b/main/boards/common/esp32_camera.h index d7a30d80..dc64c731 100644 --- a/main/boards/common/esp32_camera.h +++ b/main/boards/common/esp32_camera.h @@ -30,6 +30,9 @@ public: virtual void SetExplainUrl(const std::string& url, const std::string& token); virtual bool Capture(); + // 翻转控制函数 + virtual bool SetHMirror(bool enabled) override; + virtual bool SetVFlip(bool enabled) override; virtual std::string Explain(const std::string& question); }; diff --git a/main/boards/esp32s3-korvo2-v3/config.h b/main/boards/esp32s3-korvo2-v3/config.h index b4f8f0fa..b351ee8c 100644 --- a/main/boards/esp32s3-korvo2-v3/config.h +++ b/main/boards/esp32s3-korvo2-v3/config.h @@ -58,5 +58,24 @@ #define DISPLAY_BACKLIGHT_PIN GPIO_NUM_NC #define DISPLAY_BACKLIGHT_OUTPUT_INVERT false +/* Camera pins */ +#define CAMERA_PIN_PWDN -1 +#define CAMERA_PIN_RESET -1 +#define CAMERA_PIN_XCLK 40 +#define CAMERA_PIN_SIOD 17 +#define CAMERA_PIN_SIOC 18 +#define CAMERA_PIN_D7 39 +#define CAMERA_PIN_D6 41 +#define CAMERA_PIN_D5 42 +#define CAMERA_PIN_D4 12 +#define CAMERA_PIN_D3 3 +#define CAMERA_PIN_D2 14 +#define CAMERA_PIN_D1 47 +#define CAMERA_PIN_D0 13 +#define CAMERA_PIN_VSYNC 21 +#define CAMERA_PIN_HREF 38 +#define CAMERA_PIN_PCLK 11 + +#define XCLK_FREQ_HZ 20000000 #endif // _BOARD_CONFIG_H_ diff --git a/main/boards/esp32s3-korvo2-v3/esp32s3_korvo2_v3_board.cc b/main/boards/esp32s3-korvo2-v3/esp32s3_korvo2_v3_board.cc index 91518f9a..e031bd72 100644 --- a/main/boards/esp32s3-korvo2-v3/esp32s3_korvo2_v3_board.cc +++ b/main/boards/esp32s3-korvo2-v3/esp32s3_korvo2_v3_board.cc @@ -14,6 +14,7 @@ #include #include #include +#include "esp32_camera.h" #define TAG "esp32s3_korvo2_v3" @@ -48,6 +49,7 @@ private: i2c_master_bus_handle_t i2c_bus_; LcdDisplay* display_; esp_io_expander_handle_t io_expander_ = NULL; + Esp32Camera* camera_; void InitializeI2c() { // Initialize I2C peripheral @@ -225,6 +227,39 @@ private: }); } + void InitializeCamera() { + // Open camera power + + camera_config_t config = {}; + config.ledc_channel = LEDC_CHANNEL_2; // LEDC通道选择 用于生成XCLK时钟 但是S3不用 + config.ledc_timer = LEDC_TIMER_2; // LEDC timer选择 用于生成XCLK时钟 但是S3不用 + config.pin_d0 = CAMERA_PIN_D0; + config.pin_d1 = CAMERA_PIN_D1; + config.pin_d2 = CAMERA_PIN_D2; + config.pin_d3 = CAMERA_PIN_D3; + config.pin_d4 = CAMERA_PIN_D4; + config.pin_d5 = CAMERA_PIN_D5; + config.pin_d6 = CAMERA_PIN_D6; + config.pin_d7 = CAMERA_PIN_D7; + config.pin_xclk = CAMERA_PIN_XCLK; + config.pin_pclk = CAMERA_PIN_PCLK; + config.pin_vsync = CAMERA_PIN_VSYNC; + config.pin_href = CAMERA_PIN_HREF; + config.pin_sccb_sda = -1; // 这里写-1 表示使用已经初始化的I2C接口 + config.pin_sccb_scl = CAMERA_PIN_SIOC; + config.sccb_i2c_port = 1; + config.pin_pwdn = CAMERA_PIN_PWDN; + config.pin_reset = CAMERA_PIN_RESET; + config.xclk_freq_hz = XCLK_FREQ_HZ; + config.pixel_format = PIXFORMAT_RGB565; + config.frame_size = FRAMESIZE_VGA; + config.jpeg_quality = 12; + config.fb_count = 1; + config.fb_location = CAMERA_FB_IN_PSRAM; + config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; + + camera_ = new Esp32Camera(config); + } // 物联网初始化,添加对 AI 可见设备 void InitializeIot() { auto& thing_manager = iot::ThingManager::GetInstance(); @@ -238,6 +273,7 @@ public: InitializeI2c(); I2cDetect(); InitializeTca9554(); + InitializeCamera(); InitializeSpi(); InitializeButtons(); #ifdef LCD_TYPE_ILI9341_SERIAL @@ -268,6 +304,9 @@ public: virtual Display *GetDisplay() override { return display_; } + virtual Camera* GetCamera() override { + return camera_; + } }; DECLARE_BOARD(Esp32S3Korvo2V3Board); diff --git a/main/boards/kevin-sp-v3-dev/config.h b/main/boards/kevin-sp-v3-dev/config.h index 8f53749d..fd925493 100644 --- a/main/boards/kevin-sp-v3-dev/config.h +++ b/main/boards/kevin-sp-v3-dev/config.h @@ -41,5 +41,24 @@ #define ML307_RX_PIN GPIO_NUM_12 #define ML307_TX_PIN GPIO_NUM_13 +/* Camera pins */ +#define CAMERA_PIN_PWDN -1 +#define CAMERA_PIN_RESET -1 +#define CAMERA_PIN_XCLK 15 +#define CAMERA_PIN_SIOD 4 +#define CAMERA_PIN_SIOC 5 +#define CAMERA_PIN_D7 16 +#define CAMERA_PIN_D6 17 +#define CAMERA_PIN_D5 18 +#define CAMERA_PIN_D4 12 +#define CAMERA_PIN_D3 10 +#define CAMERA_PIN_D2 8 +#define CAMERA_PIN_D1 9 +#define CAMERA_PIN_D0 11 +#define CAMERA_PIN_VSYNC 6 +#define CAMERA_PIN_HREF 7 +#define CAMERA_PIN_PCLK 13 + +#define XCLK_FREQ_HZ 20000000 #endif // _BOARD_CONFIG_H_ diff --git a/main/boards/kevin-sp-v3-dev/kevin-sp-v3_board.cc b/main/boards/kevin-sp-v3-dev/kevin-sp-v3_board.cc index 184f9c11..13ddddaa 100644 --- a/main/boards/kevin-sp-v3-dev/kevin-sp-v3_board.cc +++ b/main/boards/kevin-sp-v3-dev/kevin-sp-v3_board.cc @@ -14,6 +14,7 @@ #include #include #include +#include "esp32_camera.h" #define TAG "kevin-sp-v3" @@ -27,6 +28,7 @@ private: i2c_master_bus_handle_t display_i2c_bus_; Button boot_button_; LcdDisplay* display_; + Esp32Camera* camera_; void InitializeSpi() { spi_bus_config_t buscfg = {}; @@ -91,6 +93,39 @@ private: }); } + void InitializeCamera() { + // Open camera power + + camera_config_t config = {}; + config.ledc_channel = LEDC_CHANNEL_2; // LEDC通道选择 用于生成XCLK时钟 但是S3不用 + config.ledc_timer = LEDC_TIMER_2; // LEDC timer选择 用于生成XCLK时钟 但是S3不用 + config.pin_d0 = CAMERA_PIN_D0; + config.pin_d1 = CAMERA_PIN_D1; + config.pin_d2 = CAMERA_PIN_D2; + config.pin_d3 = CAMERA_PIN_D3; + config.pin_d4 = CAMERA_PIN_D4; + config.pin_d5 = CAMERA_PIN_D5; + config.pin_d6 = CAMERA_PIN_D6; + config.pin_d7 = CAMERA_PIN_D7; + config.pin_xclk = CAMERA_PIN_XCLK; + config.pin_pclk = CAMERA_PIN_PCLK; + config.pin_vsync = CAMERA_PIN_VSYNC; + config.pin_href = CAMERA_PIN_HREF; + config.pin_sccb_sda = CAMERA_PIN_SIOD; // 这里写-1 表示使用已经初始化的I2C接口 + config.pin_sccb_scl = CAMERA_PIN_SIOC; + config.sccb_i2c_port = 1; + config.pin_pwdn = CAMERA_PIN_PWDN; + config.pin_reset = CAMERA_PIN_RESET; + config.xclk_freq_hz = XCLK_FREQ_HZ; + config.pixel_format = PIXFORMAT_RGB565; + config.frame_size = FRAMESIZE_VGA; + config.jpeg_quality = 12; + config.fb_count = 1; + config.fb_location = CAMERA_FB_IN_PSRAM; + config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; + + camera_ = new Esp32Camera(config); + } // 物联网初始化,添加对 AI 可见设备 void InitializeIot() { auto& thing_manager = iot::ThingManager::GetInstance(); @@ -100,14 +135,12 @@ private: } public: - KEVIN_SP_V3Board() : - // Ml307Board(ML307_TX_PIN, ML307_RX_PIN, 4096), - boot_button_(BOOT_BUTTON_GPIO) { + KEVIN_SP_V3Board() : boot_button_(BOOT_BUTTON_GPIO) { ESP_LOGI(TAG, "Initializing KEVIN_SP_V3 Board"); - InitializeSpi(); InitializeButtons(); InitializeSt7789Display(); + InitializeCamera(); InitializeIot(); GetBacklight()->RestoreBrightness(); } @@ -132,6 +165,10 @@ public: static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT); return &backlight; } + + virtual Camera* GetCamera() override { + return camera_; + } }; DECLARE_BOARD(KEVIN_SP_V3Board); diff --git a/main/boards/kevin-sp-v4-dev/config.h b/main/boards/kevin-sp-v4-dev/config.h index 4bdc0728..7ad6ed33 100644 --- a/main/boards/kevin-sp-v4-dev/config.h +++ b/main/boards/kevin-sp-v4-dev/config.h @@ -42,5 +42,25 @@ #define ML307_RX_PIN GPIO_NUM_12 #define ML307_TX_PIN GPIO_NUM_13 +/* Camera pins */ +#define CAMERA_PIN_PWDN -1 +#define CAMERA_PIN_RESET -1 +#define CAMERA_PIN_XCLK 15 +#define CAMERA_PIN_SIOD 4 +#define CAMERA_PIN_SIOC 5 + +#define CAMERA_PIN_D7 16 +#define CAMERA_PIN_D6 17 +#define CAMERA_PIN_D5 18 +#define CAMERA_PIN_D4 12 +#define CAMERA_PIN_D3 10 +#define CAMERA_PIN_D2 8 +#define CAMERA_PIN_D1 9 +#define CAMERA_PIN_D0 11 +#define CAMERA_PIN_VSYNC 6 +#define CAMERA_PIN_HREF 7 +#define CAMERA_PIN_PCLK 13 + +#define XCLK_FREQ_HZ 20000000 #endif // _BOARD_CONFIG_H_ diff --git a/main/boards/kevin-sp-v4-dev/kevin-sp-v4_board.cc b/main/boards/kevin-sp-v4-dev/kevin-sp-v4_board.cc index a6e280be..303a1c90 100644 --- a/main/boards/kevin-sp-v4-dev/kevin-sp-v4_board.cc +++ b/main/boards/kevin-sp-v4-dev/kevin-sp-v4_board.cc @@ -12,6 +12,7 @@ #include #include #include +#include "esp32_camera.h" #define TAG "kevin-sp-v4" @@ -24,10 +25,11 @@ private: Button boot_button_; LcdDisplay* display_; i2c_master_bus_handle_t codec_i2c_bus_; + Esp32Camera* camera_; void InitializeCodecI2c() { // Initialize I2C peripheral i2c_master_bus_config_t i2c_bus_cfg = { - .i2c_port = I2C_NUM_0, + .i2c_port = I2C_NUM_1, .sda_io_num = AUDIO_CODEC_I2C_SDA_PIN, .scl_io_num = AUDIO_CODEC_I2C_SCL_PIN, .clk_source = I2C_CLK_SRC_DEFAULT, @@ -104,6 +106,39 @@ private: }); } + void InitializeCamera() { + // Open camera power + + camera_config_t config = {}; + config.ledc_channel = LEDC_CHANNEL_2; // LEDC通道选择 用于生成XCLK时钟 但是S3不用 + config.ledc_timer = LEDC_TIMER_2; // LEDC timer选择 用于生成XCLK时钟 但是S3不用 + config.pin_d0 = CAMERA_PIN_D0; + config.pin_d1 = CAMERA_PIN_D1; + config.pin_d2 = CAMERA_PIN_D2; + config.pin_d3 = CAMERA_PIN_D3; + config.pin_d4 = CAMERA_PIN_D4; + config.pin_d5 = CAMERA_PIN_D5; + config.pin_d6 = CAMERA_PIN_D6; + config.pin_d7 = CAMERA_PIN_D7; + config.pin_xclk = CAMERA_PIN_XCLK; + config.pin_pclk = CAMERA_PIN_PCLK; + config.pin_vsync = CAMERA_PIN_VSYNC; + config.pin_href = CAMERA_PIN_HREF; + config.pin_sccb_sda = -1; // 这里写-1 表示使用已经初始化的I2C接口 + config.pin_sccb_scl = CAMERA_PIN_SIOC; + config.sccb_i2c_port = 1; + config.pin_pwdn = CAMERA_PIN_PWDN; + config.pin_reset = CAMERA_PIN_RESET; + config.xclk_freq_hz = XCLK_FREQ_HZ; + config.pixel_format = PIXFORMAT_RGB565; + config.frame_size = FRAMESIZE_VGA; + config.jpeg_quality = 12; + config.fb_count = 1; + config.fb_location = CAMERA_FB_IN_PSRAM; + config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; + + camera_ = new Esp32Camera(config); + } // 物联网初始化,添加对 AI 可见设备 void InitializeIot() { auto& thing_manager = iot::ThingManager::GetInstance(); @@ -119,6 +154,7 @@ public: InitializeSpi(); InitializeButtons(); InitializeSt7789Display(); + InitializeCamera(); InitializeIot(); GetBacklight()->RestoreBrightness(); } @@ -144,6 +180,10 @@ public: static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT); return &backlight; } + + virtual Camera* GetCamera() override { + return camera_; + } }; DECLARE_BOARD(KEVIN_SP_V4Board);