From 33cb6f8f95555c03436649a3bb98d255536c411a Mon Sep 17 00:00:00 2001 From: DorBenHarush Date: Tue, 11 Aug 2020 21:27:26 +0300 Subject: [PATCH 01/17] esp32-camera * Example app for publishing information from camera * add camera option to menuconfig and allowing it. --- apps/take_picture/app-colcon.meta | 14 ++ apps/take_picture/app.c | 197 ++++++++++++++++++ .../main/Kconfig.projbuild | 65 ++++++ microros_esp32_extensions/sdkconfig.defaults | 1 + 4 files changed, 277 insertions(+) create mode 100644 apps/take_picture/app-colcon.meta create mode 100644 apps/take_picture/app.c diff --git a/apps/take_picture/app-colcon.meta b/apps/take_picture/app-colcon.meta new file mode 100644 index 00000000..7943f031 --- /dev/null +++ b/apps/take_picture/app-colcon.meta @@ -0,0 +1,14 @@ +{ + "names": { + "rmw_microxrcedds": { + "cmake-args": [ + "-DRMW_UXRCE_MAX_NODES=1", + "-DRMW_UXRCE_MAX_PUBLISHERS=1", + "-DRMW_UXRCE_MAX_SUBSCRIPTIONS=0", + "-DRMW_UXRCE_MAX_SERVICES=0", + "-DRMW_UXRCE_MAX_CLIENTS=0", + "-DRMW_UXRCE_MAX_HISTORY=1", + ] + } + } +} \ No newline at end of file diff --git a/apps/take_picture/app.c b/apps/take_picture/app.c new file mode 100644 index 00000000..becc299d --- /dev/null +++ b/apps/take_picture/app.c @@ -0,0 +1,197 @@ +/** + * This example takes a picture every 5s. + Example src: https://github.com/espressif/esp32-camera.git + */ + +#define BOARD_WROVER_KIT +#define BOARD_ESP32CAM_AITHINKER + + +// ================================ CODE ====================================== + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "esp_camera.h" + +// 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 + +static const char *TAG = "example:take_picture"; + + +#define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Aborting.\n",__LINE__,(int)temp_rc);vTaskDelete(NULL);}} +#define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Continuing.\n",__LINE__,(int)temp_rc);}} + +rcl_publisher_t publisher; +std_msgs__msg__Int32 msg; +camera_fb_t *pic; + +void timer_callback(rcl_timer_t * timer, int64_t last_call_time) +{ + UNUSED(last_call_time); + if (timer != NULL) { + RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL)); + // use pic->buf to access the image + msg.data = pic->len; + } +} + + +static camera_config_t camera_config = { + .pin_pwdn = CAM_PIN_PWDN, + .pin_reset = CAM_PIN_RESET, + .pin_xclk = CAM_PIN_XCLK, + .pin_sscb_sda = CAM_PIN_SIOD, + .pin_sscb_scl = CAM_PIN_SIOC, + + .pin_d7 = CAM_PIN_D7, + .pin_d6 = CAM_PIN_D6, + .pin_d5 = CAM_PIN_D5, + .pin_d4 = CAM_PIN_D4, + .pin_d3 = CAM_PIN_D3, + .pin_d2 = CAM_PIN_D2, + .pin_d1 = CAM_PIN_D1, + .pin_d0 = CAM_PIN_D0, + .pin_vsync = CAM_PIN_VSYNC, + .pin_href = CAM_PIN_HREF, + .pin_pclk = CAM_PIN_PCLK, + + //XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental) + .xclk_freq_hz = 20000000, + .ledc_timer = LEDC_TIMER_0, + .ledc_channel = LEDC_CHANNEL_0, + + .pixel_format = PIXFORMAT_JPEG, //YUV422,GRAYSCALE,RGB565,JPEG + .frame_size = FRAMESIZE_VGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG + + .jpeg_quality = 12, //0-63 lower number means higher quality + .fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG +}; + +static esp_err_t init_camera() +{ + //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; +} + +void appMain(void * arg) +{ + init_camera(); + rcl_allocator_t allocator = rcl_get_default_allocator(); + rclc_support_t support; + + // create init_options + RCCHECK(rclc_support_init(&support, 0, NULL, &allocator)); + + // create node + rcl_node_t node = rcl_get_zero_initialized_node(); + RCCHECK(rclc_node_init_default(&node, "freertos_pictureSize_publisher", "", &support)); + + // create publisher + RCCHECK(rclc_publisher_init_default( + &publisher, + &node, + ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32), + "freertos_pictureSize_publisher")); + + // create timer, + rcl_timer_t timer = rcl_get_zero_initialized_timer(); + const unsigned int timer_timeout = 1000; + RCCHECK(rclc_timer_init_default( + &timer, + &support, + RCL_MS_TO_NS(timer_timeout), + timer_callback)); + + // create executor + rclc_executor_t executor = rclc_executor_get_zero_initialized_executor(); + RCCHECK(rclc_executor_init(&executor, &support.context, 1, &allocator)); + + unsigned int rcl_wait_timeout = 1000; // in ms + RCCHECK(rclc_executor_set_timeout(&executor, RCL_MS_TO_NS(rcl_wait_timeout))); + RCCHECK(rclc_executor_add_timer(&executor, &timer)); + + msg.data = 0; + + while(1){ + rclc_executor_spin_some(&executor, 100); + usleep(100000); + //takes picture + pic = esp_camera_fb_get(); + vTaskDelay(5000 / portTICK_RATE_MS); + } + + // free resources + RCCHECK(rcl_publisher_fini(&publisher, &node)) + RCCHECK(rcl_node_fini(&node)) + vTaskDelete(NULL); +} diff --git a/microros_esp32_extensions/main/Kconfig.projbuild b/microros_esp32_extensions/main/Kconfig.projbuild index 06226d68..8192ff93 100644 --- a/microros_esp32_extensions/main/Kconfig.projbuild +++ b/microros_esp32_extensions/main/Kconfig.projbuild @@ -54,3 +54,68 @@ menu "WiFi Configuration" endmenu endmenu +menu "Camera configuration" + +config OV2640_SUPPORT + bool "OV2640 Support" + default y + help + Enable this option if you want to use the OV2640. + Disable this option to save memory. + +config OV7725_SUPPORT + bool "OV7725 Support" + default n + help + Enable this option if you want to use the OV7725. + Disable this option to save memory. + +config OV3660_SUPPORT + bool "OV3660 Support" + default y + help + Enable this option if you want to use the OV3360. + Disable this option to save memory. + +config OV5640_SUPPORT + bool "OV5640 Support" + default y + help + Enable this option if you want to use the OV5640. + Disable this option to save memory. + +config SCCB_HARDWARE_I2C + bool "Use hardware I2C for SCCB" + default y + help + Enable this option if you want to use hardware I2C to control the camera. + Disable this option to use software I2C. + +choice SCCB_HARDWARE_I2C_PORT + bool "I2C peripheral to use for SCCB" + depends on SCCB_HARDWARE_I2C + default SCCB_HARDWARE_I2C_PORT1 + + config SCCB_HARDWARE_I2C_PORT0 + bool "I2C0" + config SCCB_HARDWARE_I2C_PORT1 + bool "I2C1" + +endchoice + +choice CAMERA_TASK_PINNED_TO_CORE + bool "Camera task pinned to core" + default CAMERA_CORE0 + help + Pin the camera handle task to a certain core(0/1). It can also be done automatically choosing NO_AFFINITY. + + config CAMERA_CORE0 + bool "CORE0" + config CAMERA_CORE1 + bool "CORE1" + config CAMERA_NO_AFFINITY + bool "NO_AFFINITY" + +endchoice + +endmenu diff --git a/microros_esp32_extensions/sdkconfig.defaults b/microros_esp32_extensions/sdkconfig.defaults index 11698207..9ef1a8e6 100644 --- a/microros_esp32_extensions/sdkconfig.defaults +++ b/microros_esp32_extensions/sdkconfig.defaults @@ -1,3 +1,4 @@ CONFIG_ESP_MAIN_TASK_STACK_SIZE=3000 CONFIG_FREERTOS_UNICORE=y CONFIG_ESP_TASK_WDT=n +CONFIG_ESP32_SPIRAM_SUPPORT=y From 54e2aae47980d935a9e7e99c317dea4bc2bd8876 Mon Sep 17 00:00:00 2001 From: DorBenHarush Date: Tue, 11 Aug 2020 22:06:04 +0300 Subject: [PATCH 02/17] Update NOTICE --- NOTICE | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NOTICE b/NOTICE index 636722cf..090d6257 100644 --- a/NOTICE +++ b/NOTICE @@ -28,3 +28,6 @@ eProsima Robert Bosch GmbH Ralph Lange Raphael Vogelgsang + +Dor Ben Harush + Dor Ben Harush From 9b509c04d9b48137eccba1fb14162a9e7c5f46ef Mon Sep 17 00:00:00 2001 From: DorBenHarush Date: Wed, 12 Aug 2020 22:09:19 +0300 Subject: [PATCH 03/17] Add camera pinout choice * Now it is possible to choose camera pinout in the menuconfig Signed-off-by: Dor Ben Harush dor2981123@gmail.com --- apps/take_picture/app.c | 53 +------ apps/take_picture/boards.h | 49 +++++++ .../main/Kconfig.projbuild | 131 ++++++++++-------- 3 files changed, 127 insertions(+), 106 deletions(-) create mode 100644 apps/take_picture/boards.h diff --git a/apps/take_picture/app.c b/apps/take_picture/app.c index becc299d..12b208ef 100644 --- a/apps/take_picture/app.c +++ b/apps/take_picture/app.c @@ -3,8 +3,7 @@ Example src: https://github.com/espressif/esp32-camera.git */ -#define BOARD_WROVER_KIT -#define BOARD_ESP32CAM_AITHINKER + // ================================ CODE ====================================== @@ -29,54 +28,10 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "boards.h" + + -#include "esp_camera.h" - -// 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 static const char *TAG = "example:take_picture"; diff --git a/apps/take_picture/boards.h b/apps/take_picture/boards.h new file mode 100644 index 00000000..f8bad850 --- /dev/null +++ b/apps/take_picture/boards.h @@ -0,0 +1,49 @@ +#include "esp_camera.h" + +#define BOARD_WROVER_KIT CONFIG_BOARD_WROVER_KIT +#define BOARD_ESP32CAM_AITHINKER CONFIG_BOARD_ESP32CAM_AITHINKER + +// WROVER-KIT PIN Map +#if 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 + +// ESP32Cam (AiThinker) PIN Map +#elif 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 diff --git a/microros_esp32_extensions/main/Kconfig.projbuild b/microros_esp32_extensions/main/Kconfig.projbuild index 8192ff93..ec373b2c 100644 --- a/microros_esp32_extensions/main/Kconfig.projbuild +++ b/microros_esp32_extensions/main/Kconfig.projbuild @@ -54,68 +54,85 @@ menu "WiFi Configuration" endmenu endmenu -menu "Camera configuration" - -config OV2640_SUPPORT - bool "OV2640 Support" - default y - help - Enable this option if you want to use the OV2640. - Disable this option to save memory. -config OV7725_SUPPORT - bool "OV7725 Support" - default n - help - Enable this option if you want to use the OV7725. - Disable this option to save memory. - -config OV3660_SUPPORT - bool "OV3660 Support" - default y - help - Enable this option if you want to use the OV3360. - Disable this option to save memory. - -config OV5640_SUPPORT - bool "OV5640 Support" - default y - help - Enable this option if you want to use the OV5640. - Disable this option to save memory. - -config SCCB_HARDWARE_I2C - bool "Use hardware I2C for SCCB" - default y - help - Enable this option if you want to use hardware I2C to control the camera. - Disable this option to use software I2C. - -choice SCCB_HARDWARE_I2C_PORT - bool "I2C peripheral to use for SCCB" - depends on SCCB_HARDWARE_I2C - default SCCB_HARDWARE_I2C_PORT1 - config SCCB_HARDWARE_I2C_PORT0 - bool "I2C0" - config SCCB_HARDWARE_I2C_PORT1 - bool "I2C1" + menu "Camera configuration" -endchoice + config OV2640_SUPPORT + bool "OV2640 Support" + default y + help + Enable this option if you want to use the OV2640. + Disable this option to save memory. -choice CAMERA_TASK_PINNED_TO_CORE - bool "Camera task pinned to core" - default CAMERA_CORE0 - help - Pin the camera handle task to a certain core(0/1). It can also be done automatically choosing NO_AFFINITY. + config OV7725_SUPPORT + bool "OV7725 Support" + default n + help + Enable this option if you want to use the OV7725. + Disable this option to save memory. - config CAMERA_CORE0 - bool "CORE0" - config CAMERA_CORE1 - bool "CORE1" - config CAMERA_NO_AFFINITY - bool "NO_AFFINITY" + config OV3660_SUPPORT + bool "OV3660 Support" + default y + help + Enable this option if you want to use the OV3360. + Disable this option to save memory. + + config OV5640_SUPPORT + bool "OV5640 Support" + default y + help + Enable this option if you want to use the OV5640. + Disable this option to save memory. -endchoice + config SCCB_HARDWARE_I2C + bool "Use hardware I2C for SCCB" + default y + help + Enable this option if you want to use hardware I2C to control the camera. + Disable this option to use software I2C. + + choice SCCB_HARDWARE_I2C_PORT + bool "I2C peripheral to use for SCCB" + depends on SCCB_HARDWARE_I2C + default SCCB_HARDWARE_I2C_PORT1 + + config SCCB_HARDWARE_I2C_PORT0 + bool "I2C0" + config SCCB_HARDWARE_I2C_PORT1 + bool "I2C1" + + endchoice + + choice CAMERA_TASK_PINNED_TO_CORE + bool "Camera task pinned to core" + default CAMERA_CORE0 + help + Pin the camera handle task to a certain core(0/1). It can also be done automatically choosing NO_AFFINITY. + + config CAMERA_CORE0 + bool "CORE0" + config CAMERA_CORE1 + bool "CORE1" + config CAMERA_NO_AFFINITY + bool "NO_AFFINITY" + + endchoice + menu "Camera Pins" + choice CAMERA_MODEL + bool "Select Camera Pinout" + default BOARD_WROVER_KIT + help + Select Camera Pinout. + + config BOARD_WROVER_KIT + + bool "WROVER-KIT OV2640 Module" + config BOARD_ESP32CAM_AITHINKER + + bool "ESP32-CAM by AI-Thinker" + endchoice + endmenu endmenu From 2353ab1060b6070d43847072dd82b6216142547c Mon Sep 17 00:00:00 2001 From: Dor Ben Harush <69308426+DorBenHarush@users.noreply.github.com> Date: Mon, 24 Aug 2020 09:03:43 +0300 Subject: [PATCH 04/17] Update app.c --- apps/take_picture/app.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/take_picture/app.c b/apps/take_picture/app.c index 12b208ef..183d7c6f 100644 --- a/apps/take_picture/app.c +++ b/apps/take_picture/app.c @@ -141,12 +141,12 @@ void appMain(void * arg) rclc_executor_spin_some(&executor, 100); usleep(100000); //takes picture - pic = esp_camera_fb_get(); - vTaskDelay(5000 / portTICK_RATE_MS); + pic = esp_camera_fb_get(); + vTaskDelay(5000 / portTICK_RATE_MS); } // free resources RCCHECK(rcl_publisher_fini(&publisher, &node)) RCCHECK(rcl_node_fini(&node)) - vTaskDelete(NULL); + vTaskDelete(NULL); } From b9d4f39f09473292159ca832a7fbf9f16da0d3bc Mon Sep 17 00:00:00 2001 From: Dor Ben Harush <69308426+DorBenHarush@users.noreply.github.com> Date: Mon, 24 Aug 2020 09:13:59 +0300 Subject: [PATCH 05/17] Update app.c --- apps/take_picture/app.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/take_picture/app.c b/apps/take_picture/app.c index 183d7c6f..c99d06e5 100644 --- a/apps/take_picture/app.c +++ b/apps/take_picture/app.c @@ -148,5 +148,5 @@ void appMain(void * arg) // free resources RCCHECK(rcl_publisher_fini(&publisher, &node)) RCCHECK(rcl_node_fini(&node)) - vTaskDelete(NULL); + vTaskDelete(NULL); } From 90bf0d2c608017853a7d0a62ec13e2a277443375 Mon Sep 17 00:00:00 2001 From: Dor Ben Harush <69308426+DorBenHarush@users.noreply.github.com> Date: Mon, 24 Aug 2020 09:33:20 +0300 Subject: [PATCH 06/17] Update app.c --- apps/take_picture/app.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/take_picture/app.c b/apps/take_picture/app.c index c99d06e5..9ff39375 100644 --- a/apps/take_picture/app.c +++ b/apps/take_picture/app.c @@ -100,8 +100,8 @@ static esp_err_t init_camera() void appMain(void * arg) { - init_camera(); - rcl_allocator_t allocator = rcl_get_default_allocator(); + init_camera(); + rcl_allocator_t allocator = rcl_get_default_allocator(); rclc_support_t support; // create init_options From f147960af8f7e12f362ead38717f414c1dee1c7d Mon Sep 17 00:00:00 2001 From: Dor Ben Harush <69308426+DorBenHarush@users.noreply.github.com> Date: Mon, 24 Aug 2020 10:36:38 +0300 Subject: [PATCH 07/17] Update app.c --- apps/take_picture/app.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/take_picture/app.c b/apps/take_picture/app.c index 9ff39375..36462026 100644 --- a/apps/take_picture/app.c +++ b/apps/take_picture/app.c @@ -141,8 +141,8 @@ void appMain(void * arg) rclc_executor_spin_some(&executor, 100); usleep(100000); //takes picture - pic = esp_camera_fb_get(); - vTaskDelay(5000 / portTICK_RATE_MS); + pic = esp_camera_fb_get(); + vTaskDelay(5000 / portTICK_RATE_MS); } // free resources From a10820d3589a2b020627699767f38705df0070e3 Mon Sep 17 00:00:00 2001 From: Dor Ben Harush Date: Sat, 19 Sep 2020 13:16:41 +0300 Subject: [PATCH 08/17] Update app-colcon.meta --- apps/take_picture/app-colcon.meta | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/take_picture/app-colcon.meta b/apps/take_picture/app-colcon.meta index 7943f031..0ea8f085 100644 --- a/apps/take_picture/app-colcon.meta +++ b/apps/take_picture/app-colcon.meta @@ -7,8 +7,14 @@ "-DRMW_UXRCE_MAX_SUBSCRIPTIONS=0", "-DRMW_UXRCE_MAX_SERVICES=0", "-DRMW_UXRCE_MAX_CLIENTS=0", - "-DRMW_UXRCE_MAX_HISTORY=1", + "-DRMW_UXRCE_MAX_HISTORY=4", ] - } - } -} \ No newline at end of file + }, + "microxrcedds_client": { + "cmake-args": [ + "-DUCLIENT_UDP_TRANSPORT_MTU=32768", + + ] + } + } +} From 02846fa94dd7feafb8285df12f3f620aea591edd Mon Sep 17 00:00:00 2001 From: Dor Ben Harush Date: Sat, 19 Sep 2020 13:18:30 +0300 Subject: [PATCH 09/17] Update app.c --- apps/take_picture/app.c | 106 ++++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 30 deletions(-) diff --git a/apps/take_picture/app.c b/apps/take_picture/app.c index 36462026..4599e702 100644 --- a/apps/take_picture/app.c +++ b/apps/take_picture/app.c @@ -20,39 +20,26 @@ #include #include -#include +#include #include #include - #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "boards.h" - - +#define STRING_CAPACITY 20 static const char *TAG = "example:take_picture"; - #define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Aborting.\n",__LINE__,(int)temp_rc);vTaskDelete(NULL);}} #define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Continuing.\n",__LINE__,(int)temp_rc);}} rcl_publisher_t publisher; -std_msgs__msg__Int32 msg; +sensor_msgs__msg__Image* msg; camera_fb_t *pic; -void timer_callback(rcl_timer_t * timer, int64_t last_call_time) -{ - UNUSED(last_call_time); - if (timer != NULL) { - RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL)); - // use pic->buf to access the image - msg.data = pic->len; - } -} - static camera_config_t camera_config = { .pin_pwdn = CAM_PIN_PWDN, @@ -78,13 +65,21 @@ static camera_config_t camera_config = { .ledc_timer = LEDC_TIMER_0, .ledc_channel = LEDC_CHANNEL_0, - .pixel_format = PIXFORMAT_JPEG, //YUV422,GRAYSCALE,RGB565,JPEG - .frame_size = FRAMESIZE_VGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG + .pixel_format = PIXFORMAT_YUV422, //YUV422,GRAYSCALE,RGB565,JPEG + .frame_size = FRAMESIZE_QQVGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG .jpeg_quality = 12, //0-63 lower number means higher quality .fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG }; +void timer_callback(rcl_timer_t * timer, int64_t last_call_time) +{ + UNUSED(last_call_time); + if (timer != NULL) { + + } +} + static esp_err_t init_camera() { //initialize the camera @@ -100,23 +95,23 @@ static esp_err_t init_camera() void appMain(void * arg) { - init_camera(); - rcl_allocator_t allocator = rcl_get_default_allocator(); + init_camera(); + rcl_allocator_t allocator = rcl_get_default_allocator(); rclc_support_t support; - + msg = sensor_msgs__msg__Image__create(); // create init_options RCCHECK(rclc_support_init(&support, 0, NULL, &allocator)); // create node rcl_node_t node = rcl_get_zero_initialized_node(); - RCCHECK(rclc_node_init_default(&node, "freertos_pictureSize_publisher", "", &support)); + RCCHECK(rclc_node_init_default(&node, "freertos_picture_publisher", "", &support)); // create publisher RCCHECK(rclc_publisher_init_default( &publisher, &node, - ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32), - "freertos_pictureSize_publisher")); + ROSIDL_GET_MSG_TYPE_SUPPORT(sensor_msgs, msg, Image), + "freertos_picture_publisher")); // create timer, rcl_timer_t timer = rcl_get_zero_initialized_timer(); @@ -135,18 +130,69 @@ void appMain(void * arg) RCCHECK(rclc_executor_set_timeout(&executor, RCL_MS_TO_NS(rcl_wait_timeout))); RCCHECK(rclc_executor_add_timer(&executor, &timer)); - msg.data = 0; - + //takes picture in yuv422 format + pic = esp_camera_fb_get(); + + //set height, width, step and is_bigedian + msg->height = pic->height; + msg->width = pic->width; + msg->is_bigendian = 0; + msg->step = pic->width * 2; + + //set pixel format and frame id + char * encoding = "yuv422"; + msg->encoding.data = (char*)heap_caps_malloc(strlen(encoding) + 1, MALLOC_CAP_8BIT); + msg->header.frame_id.capacity = STRING_CAPACITY; + memset(msg->encoding.data, 0, strlen(encoding) + 1); + memcpy(msg->encoding.data, encoding, strlen(encoding)); + msg->encoding.size = strlen(encoding) + 1; + + char* frame_id = "AI_thinker_image"; + msg->header.frame_id.data = (char*)heap_caps_malloc(strlen(frame_id) + 1, MALLOC_CAP_8BIT); + msg->header.frame_id.capacity = STRING_CAPACITY; + memset(msg->header.frame_id.data, 0, strlen(frame_id) + 1); + memcpy(msg->header.frame_id.data, frame_id, strlen(frame_id)); + msg->header.frame_id.size = strlen(frame_id) + 1; + + + //allocate memory for data + msg->data.data = (uint8_t*)heap_caps_malloc(pic->len, MALLOC_CAP_8BIT); + msg->data.capacity = pic->len; + msg->data.size = msg->step * pic->height ; + printf("copying data...\n"); + if(msg->data.data == NULL){ + printf("failed to allocate memory. restating in 5 sec.\n"); + vTaskDelay(5000 / portTICK_RATE_MS); + esp_restart(); + } + memcpy(msg->data.data, pic->buf, pic->len); + + //msg->header.stamp ? + + printf("height: %d \n", msg->height); + printf("width: %d \n", msg->width); + printf("pixel format %s \n", msg->encoding.data); + printf("is bigendian %d \n", msg->is_bigendian); + printf("picture step %d \n", msg->step); + printf("frame id %s \n", msg->header.frame_id.data); + printf("buffer length %d \n", msg->data.size); + printf("pic->len %d \n", pic->len); + + while(1){ - rclc_executor_spin_some(&executor, 100); + rclc_executor_spin_some(&executor, 1000); usleep(100000); - //takes picture - pic = esp_camera_fb_get(); - vTaskDelay(5000 / portTICK_RATE_MS); + //publish picture + printf("publisher return value: %d \n", rcl_publish(&publisher, msg, NULL)); + vTaskDelay(1000 / portTICK_RATE_MS); } // free resources RCCHECK(rcl_publisher_fini(&publisher, &node)) RCCHECK(rcl_node_fini(&node)) + heap_caps_free(msg->encoding.data); + heap_caps_free(msg->header.frame_id.data); + heap_caps_free(msg->data.data); + sensor_msgs__msg__Image__destroy(msg); vTaskDelete(NULL); } From 1dfd87c27b2476c08b18805663d6a0afcf3ba2e7 Mon Sep 17 00:00:00 2001 From: Dor Ben Harush Date: Wed, 30 Sep 2020 04:48:30 +0300 Subject: [PATCH 10/17] Update sdkconfig.defaults this line : CONFIG_ESP32_SPIRAM_SUPPORT=y create a problem while creating firmware for esp32. Enable SPIRAM in `menuconfig`: Component config > ESP32-specific --- microros_esp32_extensions/sdkconfig.defaults | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microros_esp32_extensions/sdkconfig.defaults b/microros_esp32_extensions/sdkconfig.defaults index 9ef1a8e6..04607862 100644 --- a/microros_esp32_extensions/sdkconfig.defaults +++ b/microros_esp32_extensions/sdkconfig.defaults @@ -1,4 +1,4 @@ CONFIG_ESP_MAIN_TASK_STACK_SIZE=3000 CONFIG_FREERTOS_UNICORE=y CONFIG_ESP_TASK_WDT=n -CONFIG_ESP32_SPIRAM_SUPPORT=y + From 7e80a4896b16bee498cd5c09c5b5432b9471ed2a Mon Sep 17 00:00:00 2001 From: Dor Ben Harush Date: Wed, 30 Sep 2020 05:21:32 +0300 Subject: [PATCH 11/17] Update Kconfig.projbuild --- microros_esp32_extensions/main/Kconfig.projbuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microros_esp32_extensions/main/Kconfig.projbuild b/microros_esp32_extensions/main/Kconfig.projbuild index ec373b2c..9bf1f6f0 100644 --- a/microros_esp32_extensions/main/Kconfig.projbuild +++ b/microros_esp32_extensions/main/Kconfig.projbuild @@ -122,7 +122,7 @@ endmenu menu "Camera Pins" choice CAMERA_MODEL bool "Select Camera Pinout" - default BOARD_WROVER_KIT + default BOARD_ESP32CAM_AITHINKER help Select Camera Pinout. From a34c2350c0db9b311e04098ad119ce08bc3daece Mon Sep 17 00:00:00 2001 From: Dor Ben Harush Date: Wed, 30 Sep 2020 10:03:08 +0300 Subject: [PATCH 12/17] Update sdkconfig.defaults --- microros_esp32_extensions/sdkconfig.defaults | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microros_esp32_extensions/sdkconfig.defaults b/microros_esp32_extensions/sdkconfig.defaults index 04607862..d75d80c2 100644 --- a/microros_esp32_extensions/sdkconfig.defaults +++ b/microros_esp32_extensions/sdkconfig.defaults @@ -1,4 +1,4 @@ CONFIG_ESP_MAIN_TASK_STACK_SIZE=3000 CONFIG_FREERTOS_UNICORE=y CONFIG_ESP_TASK_WDT=n - +CONFIG_RTCIO_SUPPORT_RTC_GPIO_DESC=y From 0c340fc5019ea8550a338605b6df7e1c404e3e47 Mon Sep 17 00:00:00 2001 From: DorBenHarush Date: Wed, 28 Oct 2020 22:39:24 +0200 Subject: [PATCH 13/17] compressed image instead of raw --- apps/take_picture/app-colcon.meta | 9 +-- apps/take_picture/app.c | 99 ++++++++++++++----------------- 2 files changed, 48 insertions(+), 60 deletions(-) diff --git a/apps/take_picture/app-colcon.meta b/apps/take_picture/app-colcon.meta index 0ea8f085..09731019 100644 --- a/apps/take_picture/app-colcon.meta +++ b/apps/take_picture/app-colcon.meta @@ -7,14 +7,15 @@ "-DRMW_UXRCE_MAX_SUBSCRIPTIONS=0", "-DRMW_UXRCE_MAX_SERVICES=0", "-DRMW_UXRCE_MAX_CLIENTS=0", - "-DRMW_UXRCE_MAX_HISTORY=4", + "-DRMW_UXRCE_MAX_HISTORY=12" ] }, "microxrcedds_client": { "cmake-args": [ - "-DUCLIENT_UDP_TRANSPORT_MTU=32768", + "-DUCLIENT_UDP_TRANSPORT_MTU=4096", + ] - } - } + } + } } diff --git a/apps/take_picture/app.c b/apps/take_picture/app.c index 4599e702..ea01c81a 100644 --- a/apps/take_picture/app.c +++ b/apps/take_picture/app.c @@ -20,7 +20,8 @@ #include #include -#include +#include + #include #include @@ -29,15 +30,16 @@ #include "freertos/task.h" #include "boards.h" -#define STRING_CAPACITY 20 static const char *TAG = "example:take_picture"; + + #define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Aborting.\n",__LINE__,(int)temp_rc);vTaskDelete(NULL);}} #define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Continuing.\n",__LINE__,(int)temp_rc);}} rcl_publisher_t publisher; -sensor_msgs__msg__Image* msg; +sensor_msgs__msg__CompressedImage* msg; camera_fb_t *pic; @@ -65,8 +67,8 @@ static camera_config_t camera_config = { .ledc_timer = LEDC_TIMER_0, .ledc_channel = LEDC_CHANNEL_0, - .pixel_format = PIXFORMAT_YUV422, //YUV422,GRAYSCALE,RGB565,JPEG - .frame_size = FRAMESIZE_QQVGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG + .pixel_format = PIXFORMAT_JPEG, //YUV422,GRAYSCALE,RGB565,JPEG + .frame_size = FRAMESIZE_HVGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG .jpeg_quality = 12, //0-63 lower number means higher quality .fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG @@ -95,10 +97,10 @@ static esp_err_t init_camera() void appMain(void * arg) { - init_camera(); - rcl_allocator_t allocator = rcl_get_default_allocator(); + init_camera(); + rcl_allocator_t allocator = rcl_get_default_allocator(); rclc_support_t support; - msg = sensor_msgs__msg__Image__create(); + msg = sensor_msgs__msg__CompressedImage__create(); // create init_options RCCHECK(rclc_support_init(&support, 0, NULL, &allocator)); @@ -110,7 +112,7 @@ void appMain(void * arg) RCCHECK(rclc_publisher_init_default( &publisher, &node, - ROSIDL_GET_MSG_TYPE_SUPPORT(sensor_msgs, msg, Image), + ROSIDL_GET_MSG_TYPE_SUPPORT(sensor_msgs, msg, CompressedImage), "freertos_picture_publisher")); // create timer, @@ -130,69 +132,54 @@ void appMain(void * arg) RCCHECK(rclc_executor_set_timeout(&executor, RCL_MS_TO_NS(rcl_wait_timeout))); RCCHECK(rclc_executor_add_timer(&executor, &timer)); - //takes picture in yuv422 format - pic = esp_camera_fb_get(); - - //set height, width, step and is_bigedian - msg->height = pic->height; - msg->width = pic->width; - msg->is_bigendian = 0; - msg->step = pic->width * 2; - - //set pixel format and frame id - char * encoding = "yuv422"; - msg->encoding.data = (char*)heap_caps_malloc(strlen(encoding) + 1, MALLOC_CAP_8BIT); - msg->header.frame_id.capacity = STRING_CAPACITY; - memset(msg->encoding.data, 0, strlen(encoding) + 1); - memcpy(msg->encoding.data, encoding, strlen(encoding)); - msg->encoding.size = strlen(encoding) + 1; + char * encoding = "jpeg"; + msg->format.data = (char*)heap_caps_malloc(strlen(encoding) + 1, MALLOC_CAP_8BIT); + msg->format.capacity = strlen(encoding) + 1; + memset(msg->format.data, 0, strlen(encoding) + 1); + memcpy(msg->format.data, encoding, strlen(encoding)); + msg->format.size = strlen(encoding) + 1; char* frame_id = "AI_thinker_image"; msg->header.frame_id.data = (char*)heap_caps_malloc(strlen(frame_id) + 1, MALLOC_CAP_8BIT); - msg->header.frame_id.capacity = STRING_CAPACITY; + msg->header.frame_id.capacity = strlen(frame_id) + 1; memset(msg->header.frame_id.data, 0, strlen(frame_id) + 1); memcpy(msg->header.frame_id.data, frame_id, strlen(frame_id)); msg->header.frame_id.size = strlen(frame_id) + 1; - - - //allocate memory for data - msg->data.data = (uint8_t*)heap_caps_malloc(pic->len, MALLOC_CAP_8BIT); - msg->data.capacity = pic->len; - msg->data.size = msg->step * pic->height ; - printf("copying data...\n"); - if(msg->data.data == NULL){ - printf("failed to allocate memory. restating in 5 sec.\n"); - vTaskDelay(5000 / portTICK_RATE_MS); - esp_restart(); - } - memcpy(msg->data.data, pic->buf, pic->len); - - //msg->header.stamp ? - - printf("height: %d \n", msg->height); - printf("width: %d \n", msg->width); - printf("pixel format %s \n", msg->encoding.data); - printf("is bigendian %d \n", msg->is_bigendian); - printf("picture step %d \n", msg->step); - printf("frame id %s \n", msg->header.frame_id.data); - printf("buffer length %d \n", msg->data.size); - printf("pic->len %d \n", pic->len); - - while(1){ + + while(1) + { rclc_executor_spin_some(&executor, 1000); usleep(100000); + pic = esp_camera_fb_get(); + //allocate memory for data + msg->data.data = (uint8_t*)heap_caps_malloc(pic->len, MALLOC_CAP_8BIT); + msg->data.capacity = pic->len; + msg->data.size = pic->len; + printf("coopying data...\n"); + if(msg->data.data == NULL) + { + printf("failed to allocate memory. restating in 5 sec.\n"); + vTaskDelay(5000 / portTICK_RATE_MS); + esp_restart(); + } + memcpy(msg->data.data, pic->buf, pic->len); + + printf("pixel format %s \n", msg->format.data); + printf("frame id %s \n", msg->header.frame_id.data); + printf("buffer length %d \n", msg->data.size); + //publish picture printf("publisher return value: %d \n", rcl_publish(&publisher, msg, NULL)); - vTaskDelay(1000 / portTICK_RATE_MS); + vTaskDelay(200 / portTICK_RATE_MS); } - // free resources + // free resources RCCHECK(rcl_publisher_fini(&publisher, &node)) RCCHECK(rcl_node_fini(&node)) - heap_caps_free(msg->encoding.data); + heap_caps_free(msg->format.data); heap_caps_free(msg->header.frame_id.data); heap_caps_free(msg->data.data); - sensor_msgs__msg__Image__destroy(msg); + sensor_msgs__msg__CompressedImage__destroy(msg); vTaskDelete(NULL); } From 4fa0c53db515d153fecf23ce90db9f15e1340657 Mon Sep 17 00:00:00 2001 From: Dor Ben Harush Date: Thu, 29 Oct 2020 20:14:02 +0200 Subject: [PATCH 14/17] Update app.c --- apps/take_picture/app.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/take_picture/app.c b/apps/take_picture/app.c index ea01c81a..48b06d4f 100644 --- a/apps/take_picture/app.c +++ b/apps/take_picture/app.c @@ -1,11 +1,8 @@ /** - * This example takes a picture every 5s. - Example src: https://github.com/espressif/esp32-camera.git + * This example takes a picture every 1s. + For more information about esp32-camera - https://github.com/espressif/esp32-camera.git */ - - - // ================================ CODE ====================================== #include From 0013334fcda53c475c46690b0fe479432f570a80 Mon Sep 17 00:00:00 2001 From: DorBenHarush Date: Thu, 29 Oct 2020 22:19:54 +0200 Subject: [PATCH 15/17] create new README.md --- apps/take_picture/README.md | 34 +++++++++++++++++ apps/take_picture/view_images.py | 39 ++++++++++++++++++++ microros_esp32_extensions/sdkconfig.defaults | 2 +- 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 apps/take_picture/README.md create mode 100755 apps/take_picture/view_images.py diff --git a/apps/take_picture/README.md b/apps/take_picture/README.md new file mode 100644 index 00000000..e4211dbb --- /dev/null +++ b/apps/take_picture/README.md @@ -0,0 +1,34 @@ +* Step 1: create and configure + + The `create_firmware_ws.sh` is the same as esp32. + After the `create_firmware` step you need to add the esp32-camera repository to the esp-idf components directory with the following commands. + ``` + pushd microros_ws/firmware/toolchain/esp-idf/components + + git clone https://github.com/espressif/esp32-camera.git + + popd + ``` + The configuration step is also the same as esp32. +* Step 2: menuconfig +``` + Serial flasher config > Flash size (set to 4M) + + Component config > ESP32-specific > Support for external, SPI-connected RAM` (set to true) + + Component config > Driver configurations > RTCIO configuration (set to TRUE) + + Camera configuration > Camera pins. (BOARD_ESP32CAM_AITHINKER is default) + ``` + Another way to enable the above is with the `sdkconfig.defaults` file by adding these lines: + ``` + CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y + CONFIG_RTCIO_SUPPORT_RTC_GPIO_DESC=y + CONFIG_ESP32_SPIRAM_SUPPORT=y + **PICK ONE OPTION** + CONFIG_BOARD_ESP32CAM_AITHINKER=y **OR** CONFIG_BOARD_WROVER_KIT=y + ``` +* Step 3 : build, flash and run a micro-ros-agent + + +* Step 4 : Run `view_image.py` diff --git a/apps/take_picture/view_images.py b/apps/take_picture/view_images.py new file mode 100755 index 00000000..3a672dad --- /dev/null +++ b/apps/take_picture/view_images.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +import rclpy +from rclpy.node import Node +from std_msgs.msg import String +from cv_bridge import CvBridge, CvBridgeError +from sensor_msgs.msg import CompressedImage +import cv2 +import numpy as np + + + + +class MinimalSubscriber(Node): + + def __init__(self, ): + super().__init__('minimal_subscriber') + self.subscription = self.create_subscription(CompressedImage, 'freertos_picture_publisher', self.listener_callback, 10) + self.subscription # prevent unused variable warning + self.bridge = CvBridge() + def listener_callback(self, image_message): + self.get_logger().info('recieved an image') + + #recieve image and co nvert to cv2 image + cv2.imshow('esp32_image', self.cv_image) + cv2.waitKey(3) + + + + +def main(args=None): + rclpy.init(args=args) + minimal_subscriber = MinimalSubscriber() + + rclpy.spin(minimal_subscriber) + minimal_subscriber.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() diff --git a/microros_esp32_extensions/sdkconfig.defaults b/microros_esp32_extensions/sdkconfig.defaults index d75d80c2..04607862 100644 --- a/microros_esp32_extensions/sdkconfig.defaults +++ b/microros_esp32_extensions/sdkconfig.defaults @@ -1,4 +1,4 @@ CONFIG_ESP_MAIN_TASK_STACK_SIZE=3000 CONFIG_FREERTOS_UNICORE=y CONFIG_ESP_TASK_WDT=n -CONFIG_RTCIO_SUPPORT_RTC_GPIO_DESC=y + From 29b858ca9cb8a050aaa861650f24bc32f866c38f Mon Sep 17 00:00:00 2001 From: Dor Ben Harush Date: Thu, 29 Oct 2020 22:29:10 +0200 Subject: [PATCH 16/17] Update README.md --- apps/take_picture/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/take_picture/README.md b/apps/take_picture/README.md index e4211dbb..2593f26a 100644 --- a/apps/take_picture/README.md +++ b/apps/take_picture/README.md @@ -1,3 +1,5 @@ +# esp32-camera configuration + * Step 1: create and configure The `create_firmware_ws.sh` is the same as esp32. From 73c7f07b2f7770c841657ab97cd2961428845265 Mon Sep 17 00:00:00 2001 From: Dor Ben Harush Date: Thu, 29 Oct 2020 23:13:20 +0200 Subject: [PATCH 17/17] Update view_images.py --- apps/take_picture/view_images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/take_picture/view_images.py b/apps/take_picture/view_images.py index 3a672dad..96787188 100755 --- a/apps/take_picture/view_images.py +++ b/apps/take_picture/view_images.py @@ -19,7 +19,7 @@ def __init__(self, ): self.bridge = CvBridge() def listener_callback(self, image_message): self.get_logger().info('recieved an image') - + self.cv_image = self.bridge.compressed_imgmsg_to_cv2(image_message,'8UC3') #recieve image and co nvert to cv2 image cv2.imshow('esp32_image', self.cv_image) cv2.waitKey(3)