2023-8-24 16:08:44 [显示全部楼层]
20325浏览
查看: 20325|回复: 0

[ESP8266/ESP32] FireBeetle 2 ESP32-S3试用——识别小猫咪

[复制链接]
本帖最后由 aramy 于 2023-8-24 16:08 编辑

上次用Arduino在vscode+platfomid下实现了读取摄像头成功玩转这个板子,经过两天努力,也解决了死机问题。其实很简单就是开辟任务时给的内存少了!
回到这次试用任务,在申请的时候就是想实现一个目的,那就是做一个自动的宠物投放装置。当猫来了,识别猫、狗,自动投喂食物。投喂食物比较简单,用舵机控制就好。宠物的识别就比较困难,需要用到机器学习才好使。在看乐鑫的官网时,有个esp-who的项目,乐鑫有提供的在esp32上实现了机器学习的例程。其中有一个cat_face_detection的项目,就是用来识别猫脸的工程。
首先将项目拉下来,项目是在github上,想要迅速地拉下来可以使用代理,这样拉取的成功率能大大提高。
  1. git clone --recursive https://ghproxy.com/https://github.com/espressif/esp-who.git
复制代码
如果拉取过程中出现了错误,导致部分文件夹没有拉取下来。就进入esp-who文件夹下执行
  1. git submodule update --init --recursive
复制代码
确保各个文件夹都拉取成功。

拉取完成后,在cat_face_detection下有三个项目,lcd是在屏幕上显示,我们这个板子没有屏幕,舍弃,termianl是在终端上显示,web是通过浏览器来显示,这里我选用web的项目。
第一步,先修改设备为ESP32-S3
FireBeetle 2 ESP32-S3试用——识别小猫咪图1

第二步,打开配置页面,修改配置项。这里要注意PSRAM项:

FireBeetle 2 ESP32-S3试用——识别小猫咪图2

这里芯片类型配置错误,会导致运行时出现这样的错误。
  1. E (185) quad_psram: PSRAM ID read error: 0x00ffffff
  2. E (186) cpu_start: Failed to init external RAM!
复制代码
怎么查看芯片集成的PSRAM是什么模式的SPI呢?由于ESP-32S3PSRAM是集成在封装内的,所以直接查看芯片数据手册,这里摘抄了相关的内容。

FireBeetle 2 ESP32-S3试用——识别小猫咪图3



摄像头设置,我选择ESP-S3-EYE,一会就按这个板子去修改摄像头的管脚。在config页面中设置好WIFI的sid和密码。其它部分flash的大小我修改为16M,关闭了语音相关的配置。
FireBeetle 2 ESP32-S3试用——识别小猫咪图4

先尝试编译,看是否能够编译成功。

编译没有问题后,来查看主函数

  1. static QueueHandle_t xQueueAIFrame = NULL;
  2. static QueueHandle_t xQueueHttpFrame = NULL;
  3. extern "C" void app_main()
  4. {
  5.     app_wifi_main();
  6.     app_mdns_main();
  7.     xQueueAIFrame = xQueueCreate(2, sizeof(camera_fb_t *));
  8.     xQueueHttpFrame = xQueueCreate(2, sizeof(camera_fb_t *));
  9.     register_camera(PIXFORMAT_RGB565, FRAMESIZE_QVGA, 2, xQueueAIFrame);
  10.     register_cat_face_detection(xQueueAIFrame, NULL, NULL, xQueueHttpFrame);
  11.     register_httpd(xQueueHttpFrame, NULL, true);
  12. }
复制代码
主函数非常简单,一个摄像头注册的方法,一个AI识别的方法,然后一个http服务的方法。顺着摄像头注册的方法找到components\modules\camera\who_camera.c文件。这个文件负责摄像头的初始化。

打开who_camera.h文件,修改摄像头管脚的定义。之前在配置中使用的esp32-s3-eye的配置,这里就修改这个板子对应的管脚配置。

  1. #elif CONFIG_CAMERA_MODULE_ESP_S3_EYE
  2. #define CAMERA_MODULE_NAME "ESP-S3-EYE"
  3. #define CAMERA_PIN_PWDN -1
  4. #define CAMERA_PIN_RESET -1
  5. #define CAMERA_PIN_VSYNC 6
  6. #define CAMERA_PIN_HREF 42
  7. #define CAMERA_PIN_PCLK 5
  8. #define CAMERA_PIN_XCLK 45
  9. #define CAMERA_PIN_SIOD 1
  10. #define CAMERA_PIN_SIOC 2
  11. #define CAMERA_PIN_D0 39
  12. #define CAMERA_PIN_D1 40
  13. #define CAMERA_PIN_D2 41
  14. #define CAMERA_PIN_D3 4
  15. #define CAMERA_PIN_D4 7
  16. #define CAMERA_PIN_D5 8
  17. #define CAMERA_PIN_D6 46
  18. #define CAMERA_PIN_D7 48
复制代码
然后再回到 who_camera.c文件中,在摄像头启动前,需要先打开一下电源,否则摄像头初始化一定会失败。这里摄像头电源是一颗AXP313A电源芯片控制的,通过IIC与之通讯。所以这里我们添加一段代码,用来打开电源。(需要留意这里是用esp-idf4.4版本编译的,貌似v5版本的i2c写法有点不一样,会编译不过去。)

  1. #include "who_camera.h"
  2. #include "esp_log.h"
  3. #include "esp_system.h"
  4. static const char *TAG = "who_camera";
  5. // ---------------------------------------------
  6. #include "driver/i2c.h"
  7. #define AXP313A_ADDR                 0x36  
  8. #define I2C_MASTER_SCL_IO           2
  9. #define I2C_MASTER_SDA_IO           1     
  10. #define I2C_MASTER_NUM              0
  11. #define I2C_MASTER_TX_BUF_DISABLE   0                          
  12. #define I2C_MASTER_RX_BUF_DISABLE   0
  13. #define I2C_MASTER_FREQ_HZ          400000
  14. #define I2C_MASTER_TIMEOUT_MS       1000
  15. static esp_err_t AXP313A_register_write_byte(uint8_t reg_addr, uint8_t data)
  16. {
  17.     int ret;
  18.     uint8_t write_buf[2] = {reg_addr, data};
  19.     ret = i2c_master_write_to_device(I2C_MASTER_NUM, AXP313A_ADDR, write_buf, sizeof(write_buf), I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);
  20.     return ret;
  21. }
  22. static esp_err_t i2c_master_init(void)
  23. {
  24.     int i2c_master_port = I2C_MASTER_NUM;
  25.     i2c_config_t conf = {
  26.         .mode = I2C_MODE_MASTER,
  27.         .sda_io_num = I2C_MASTER_SDA_IO,
  28.         .scl_io_num = I2C_MASTER_SCL_IO,
  29.         .sda_pullup_en = GPIO_PULLUP_ENABLE,
  30.         .scl_pullup_en = GPIO_PULLUP_ENABLE,
  31.         .master.clk_speed = I2C_MASTER_FREQ_HZ,
  32.     };
  33.     i2c_param_config(i2c_master_port, &conf);
  34.     return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
  35. }
  36. // ---------------------------------------------
  37. static QueueHandle_t xQueueFrameO = NULL;
  38. static void task_process_handler(void *arg)
  39. {
  40.     while (true)
  41.     {
  42.         camera_fb_t *frame = esp_camera_fb_get();
  43.         if (frame)
  44.             xQueueSend(xQueueFrameO, &frame, portMAX_DELAY);
  45.     }
  46. }
  47. void register_camera(const pixformat_t pixel_fromat,
  48.                      const framesize_t frame_size,
  49.                      const uint8_t fb_count,
  50.                      const QueueHandle_t frame_o)
  51. {
  52.     ESP_LOGI(TAG, "Camera module is %s", CAMERA_MODULE_NAME);
  53.     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  54.     //开启摄像头前,先打开电源
  55.     ESP_ERROR_CHECK(i2c_master_init());
  56.     ESP_LOGI(TAG, "I2C initialized successfully");
  57.     ESP_ERROR_CHECK(AXP313A_register_write_byte(0x00,0x04));
  58.     vTaskDelay(100);
  59.     ESP_ERROR_CHECK(AXP313A_register_write_byte(0x10,0x19));
  60.     ESP_ERROR_CHECK(AXP313A_register_write_byte(0x16,0x07));        //1.2v
  61.     ESP_ERROR_CHECK(AXP313A_register_write_byte(0x17,23));        //2.8v
  62.     ESP_LOGI(TAG, "I2C unitialized successfully");
  63.     vTaskDelay(1000);
  64.     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  65. #if CONFIG_CAMERA_MODULE_ESP_EYE || CONFIG_CAMERA_MODULE_ESP32_CAM_BOARD
  66.     /* IO13, IO14 is designed for JTAG by default,
  67.      * to use it as generalized input,
  68.      * firstly declair it as pullup input */
  69.     gpio_config_t conf;
  70.     conf.mode = GPIO_MODE_INPUT;
  71.     conf.pull_up_en = GPIO_PULLUP_ENABLE;
  72.     conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
  73.     conf.intr_type = GPIO_INTR_DISABLE;
  74.     conf.pin_bit_mask = 1LL << 13;
  75.     gpio_config(&conf);
  76.     conf.pin_bit_mask = 1LL << 14;
  77.     gpio_config(&conf);
  78. #endif
  79.     camera_config_t config;
  80.     config.ledc_channel = LEDC_CHANNEL_0;
  81.     config.ledc_timer = LEDC_TIMER_0;
  82.     config.pin_d0 = CAMERA_PIN_D0;
  83.     config.pin_d1 = CAMERA_PIN_D1;
  84.     config.pin_d2 = CAMERA_PIN_D2;
  85.     config.pin_d3 = CAMERA_PIN_D3;
  86.     config.pin_d4 = CAMERA_PIN_D4;
  87.     config.pin_d5 = CAMERA_PIN_D5;
  88.     config.pin_d6 = CAMERA_PIN_D6;
  89.     config.pin_d7 = CAMERA_PIN_D7;
  90.     config.pin_xclk = CAMERA_PIN_XCLK;
  91.     config.pin_pclk = CAMERA_PIN_PCLK;
  92.     config.pin_vsync = CAMERA_PIN_VSYNC;
  93.     config.pin_href = CAMERA_PIN_HREF;
  94.     config.pin_sscb_sda = CAMERA_PIN_SIOD;
  95.     config.pin_sscb_scl = CAMERA_PIN_SIOC;
  96.     config.pin_pwdn = CAMERA_PIN_PWDN;
  97.     config.pin_reset = CAMERA_PIN_RESET;
  98.     config.xclk_freq_hz = XCLK_FREQ_HZ;
  99.     config.pixel_format = pixel_fromat;
  100.     config.frame_size = frame_size;
  101.     config.jpeg_quality = 12;
  102.     config.fb_count = fb_count;
  103.     config.fb_location = CAMERA_FB_IN_PSRAM;
  104.     config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  105.     // camera init
  106.     esp_err_t err = esp_camera_init(&config);
  107.     if (err != ESP_OK)
  108.     {
  109.         ESP_LOGE(TAG, "Camera init failed with error 0x%x", err);
  110.         return;
  111.     }
  112.     sensor_t *s = esp_camera_sensor_get();
  113.     s->set_vflip(s, 0); // flip it back
  114.     // initial sensors are flipped vertically and colors are a bit saturated
  115.     if (s->id.PID == OV3660_PID)
  116.     {
  117.         s->set_brightness(s, 1);  // up the blightness just a bit
  118.         s->set_saturation(s, -2); // lower the saturation
  119.     }
  120.     xQueueFrameO = frame_o;
  121.     xTaskCreatePinnedToCore(task_process_handler, TAG, 2 * 1024, NULL, 5, NULL, 1);
  122. }
复制代码
接下来编译、烧写、运行。

  1. Waiting for the device to reconnect.
  2. I (1430) who_camera: I2C unitialized successfully
  3. W (1450) wifi:<ba-add>idx:0 (ifx:0, 0e:0d:9e:22:81:c4), tid:7, ssn:2, winSize:64
  4. I (2360) esp_netif_handlers: sta ip: 192.168.129.33, mask: 255.255.255.128, gw: 192.168.129.1
  5. I (2360) camera wifi: got ip:192.168.129.33
  6. W (2940) wifi:<ba-add>idx:1 (ifx:0, 0e:0d:9e:22:81:c4), tid:0, ssn:0, winSize:64
  7. I (11430) s3 ll_cam: DMA Channel=4
  8. I (11430) cam_hal: cam init ok
  9. I (11430) sccb: pin_sda 1 pin_scl 2
  10. I (11450) camera: Detected camera at address=0x30
  11. I (11450) camera: Detected OV2640 camera
  12. I (11450) camera: Camera PID=0x26 VER=0x42 MIDL=0x7f MIDH=0xa2
  13. I (11520) s3 ll_cam: node_size: 3840, nodes_per_line: 1, lines_per_node: 6
  14. I (11520) s3 ll_cam: dma_half_buffer_min:  3840, dma_half_buffer: 15360, lines_per_half_buffer: 24, dma_buffer_size: 30720
  15. I (11520) cam_hal: buffer_size: 30720, half_buffer_size: 15360, node_buffer_size: 3840, node_cnt: 8, total_cnt: 10
  16. I (11520) cam_hal: Allocating 153600 Byte frame buffer in PSRAM
  17. I (11520) cam_hal: Allocating 153600 Byte frame buffer in PSRAM
  18. I (11520) cam_hal: cam config ok
  19. I (11520) ov2640: Set PLL: clk_2x: 1, clk_div: 3, pclk_auto: 1, pclk_div: 8
  20. I (11590) camera_httpd: Starting web server on port: '80'
  21. I (11590) camera_httpd: Starting stream server on port: '81'
复制代码

然后打开同一个局域网内的电脑浏览器,用手机打开小猫咪的照片。

FireBeetle 2 ESP32-S3试用——识别小猫咪图6FireBeetle 2 ESP32-S3试用——识别小猫咪图7FireBeetle 2 ESP32-S3试用——识别小猫咪图5


FireBeetle 2 ESP32-S3就能够识别出猫咪图片,并且标记出猫咪在图片中的位置啦!



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail