Servidor de Streaming de VĂ­deo ESP32-CAM Conectando Monitores I2C e SPI

MĂłdulo CAM ESP-32 com cĂąmera da Diymore

Servidor de Streaming de VĂ­deo ESP32-CAM


Um exemplo de uso estĂĄ aqui .

VocĂȘ deve primeiro instalar as bibliotecas: Placa Esp32 no Arduino Ide Placa Windows / Esp32 no Arduino Ide Linux e Mac

ConfiguraçÔes detalhadas estão no artigo.

No meu caso, usei o mĂłdulo AI-THINKER tĂŁo descomentado
#define CAMERA_MODEL_AI_THINKER

A funcionalidade do reconhecimento de rosto nĂŁo funcionou para mim. O comentĂĄrio no artigo foi Ăștil.

Parece que o reconhecimento de faces nĂŁo estĂĄ mais funcionando (pelo menos com o programa de exemplo) ao usar o nĂșcleo 1.02 ESP. Revertendo para o nĂșcleo 1.01 e usando o programa de exemplo pertencente a esse nĂșcleo, ele serĂĄ corrigido

Depois de reverter para a versĂŁo anterior da biblioteca 1.01, tudo funcionou.


Eu tenho um par de displays I2C 128x64 e TFT SPI 128x128

Artigo OV7670 com FIFO como conectar a cĂąmera ao monitor se vocĂȘ nĂŁo possui um mĂłdulo CAM. Suporte cĂąmeras OV2640 e OV7670

No momento em que escrevi, o seguinte funcionou para mim

CĂąmera ESP32 + Servidor Wi-Fi + Tela I2C (AdaFruit)
CĂąmera ESP32 + Tela SPI 1,44 "TFT 128x128 v1.1 (AdaFruit)
CĂąmera ESP32 + Tela SPI 1,8 "TFT 128 * 160 (biblioteca Espressif)

O driver WiFi entra em conflito com o barramento SPI. Solução possível para usar uma biblioteca diferente. O problema surgiu no momento da inicialização do módulo WiFi.

O principal problema Ă© que o mĂłdulo ESP32-CAM possui um nĂșmero limitado de pernas livres. Parte das portas Ă© usada para a cĂąmera, parte em paralelo com o cartĂŁo SD. O conector da placa sd estĂĄ instalado na placa. Outra conclusĂŁo (IO4) Ă© a lanterna LED.

A tela I2C P / B nĂŁo Ă© de particular interesse para uso real com a imagem recebida da cĂąmera. Cor TFT e alta resolução. Nele vocĂȘ jĂĄ pode ver o rosto. Em um monitor ou com uma resolução um pouco mais alta, vocĂȘ pode fazer o Door Eye

Eu direi imediatamente que a biblioteca do AdaFruit nĂŁo Ă© a mais rĂĄpida. Consegui exibir alguns quadros por segundo. É mais promissor usar bibliotecas que funcionam em um nĂ­vel baixo. Mas nĂŁo consegui obter uma ESP32_TFT_library com a tela 1,44 "128x128 SPI V1.1. Talvez o ILI9163 nĂŁo seja suportado. Tirei 1,8" 128 * 160 SPI TFT e consegui espremer cerca de 12 FPS! Link

Existem algumas bibliotecas que funcionam mais rapidamente. Mas alguns nĂŁo sĂŁo portados para o esp-32 ( link ):

4,98 seg. Adafruit_ST7735
1,71 seg ST7735X_kbv
1,30 seg PDQ_ST7735

O vĂ­deo parece impressionante:



Ao usar duas portas, uma das portas de hardware HSPI ou VSPI no microcontrolador e a tela com o driver ILI9341 podem receber 30 quadros por segundo ( link ).



Mas, como eu disse anteriormente no mĂłdulo ESP32-CAM, apenas um SPI Ă© gratuito. É exibido nos seguintes PINS:

IO2 - CC (A0)
IO14 - CLK
IO15 - CS
IO13 - MOSI (SDA)
IO12 - MISO (entrada. NĂŁo usado)

IO0 - BCKL (luz de fundo. NĂŁo usado)
IO16 - RST





A primeira biblioteca que tentei foi o AdaFruit SSD1306

Tela OLED azul I2C 128x64



#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display; void init_display(){ pinMode(14,INPUT_PULLUP); pinMode(15,INPUT_PULLUP); Wire.begin(14,15); display = Adafruit_SSD1306(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64 Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } .... 

camera_capture ()
 #define BACKCOLOR 0x0000 // Black #define PIXELCOLOR 0xFFFF // White #define FRAME_WIDTH 320 #define FRAME_HEIGHT 240 uint16_t pixel_color = 0; esp_err_t camera_capture(){ //acquire a frame camera_fb_t * fb = esp_camera_fb_get(); if (!fb) { ESP_LOGE(TAG, "Camera Capture Failed"); return ESP_FAIL; } int i = 0; for(int y = 0; y < SCREEN_HEIGHT; y++){ for(int x = 0; x < SCREEN_WIDTH; x++){ i = y * FRAME_WIDTH + x; // FRAMESIZE_QVGA // 320x240 char ch = (char)fb->buf[i]; if (ch > 128) pixel_color = WHITE; else pixel_color = BLACK; // Draw a single pixel in white display.drawPixel(x, y, pixel_color); } } display.display(); //return the frame buffer back to the driver for reuse esp_camera_fb_return(fb); Serial.println("Capture frame ok."); return ESP_OK; } 


Ao trabalhar no esp32, a emulação de Software I2C é usada. IO14 e IO15 envolvidas. Quase todas as portas livres podem ser usadas, e não o barramento H / W.

Como conectar o monitor monocromĂĄtico de 0,96 "i2c OLED . VocĂȘ precisa prestar atenção ao endereço de exibição no barramento I2C. Nesse caso, 0x3C

Biblioteca SPI Display 1,8 "TFT 128 * 160 Espressif




Diagrama de fiação:

IO2 - A0
IO14 - SCK
IO15 - CS
IO13 - SDA
IO16 - RESET


A placa também possui um leitor de cartão SD

Configuração de E / S:

 // Configuration for other boards, set the correct values for the display used //---------------------------------------------------------------------------- #define DISP_COLOR_BITS_24 0x66 //#define DISP_COLOR_BITS_16 0x55 // Do not use! // ############################################# // ### Set to 1 for some displays, ### // for example the one on ESP-WROWER-KIT ### // ############################################# #define TFT_INVERT_ROTATION 0 #define TFT_INVERT_ROTATION1 0 // ################################################ // ### SET TO 0X00 FOR DISPLAYS WITH RGB MATRIX ### // ### SET TO 0X08 FOR DISPLAYS WITH BGR MATRIX ### // ### For ESP-WROWER-KIT set to 0x00 ### // ################################################ #define TFT_RGB_BGR 0x08 // ############################################################## // ### Define ESP32 SPI pins to which the display is attached ### // ############################################################## // The pins configured here are the native spi pins for HSPI interface // Any other valid pin combination can be used #define PIN_NUM_MISO 12 // SPI MISO #define PIN_NUM_MOSI 13 // SPI MOSI #define PIN_NUM_CLK 14 // SPI CLOCK pin #define PIN_NUM_CS 15 // Display CS pin #define PIN_NUM_DC 2 // Display command/data pin #define PIN_NUM_TCS 0 // Touch screen CS pin (NOT used if USE_TOUCH=0) // -------------------------------------------------------------- // ** Set Reset and Backlight pins to 0 if not used ! // ** If you want to use them, set them to some valid GPIO number #define PIN_NUM_RST 0 // GPIO used for RESET control #define PIN_NUM_BCKL 0 // GPIO used for backlight control #define PIN_BCKL_ON 0 // GPIO value for backlight ON #define PIN_BCKL_OFF 1 // GPIO value for backlight OFF // -------------------------------------------------------------- // ####################################################### // Set this to 1 if you want to use touch screen functions // ####################################################### #define USE_TOUCH TOUCH_TYPE_NONE // ####################################################### // ####################################################################### // Default display width (smaller dimension) and height (larger dimension) // ####################################################################### #define DEFAULT_TFT_DISPLAY_WIDTH 128 #define DEFAULT_TFT_DISPLAY_HEIGHT 160 // ####################################################################### #define DEFAULT_GAMMA_CURVE 0 #define DEFAULT_SPI_CLOCK 32000000 #define DEFAULT_DISP_TYPE DISP_TYPE_ST7735B //---------------------------------------------------------------------------- #define TFT_INVERT_ROTATION 0 #define TFT_INVERT_ROTATION1 1 #define TFT_INVERT_ROTATION2 0 

Instale o ambiente e ambiente de desenvolvimento da Espressif . InstruçÔes detalhadas sobre como fazer isso .

Instale a biblioteca . Duas correçÔes precisam ser feitas para montar a biblioteca.

Makefile:

 + CFLAGS += -Wno-error=tautological-compare \ + -Wno-implicit-fallthrough \ + -Wno-implicit-function-declaration 

components / tft / tftspi.c:

 + #include "driver/gpio.h 

→ Patch

Em seguida, instale o driver da cĂąmera ESP32 .

Configure:

#. $ HOME / esp / esp-idf / export.sh
# idf.py menuconfig




Permitir acesso Ă  porta USB para firmware e monitoramento:

#sudo chmod 777 / dev / ttyUSB0

Coletamos e preenchemos:

#make -j4 && make flash

12FPS é alcançado através da gravação de pacotes usando o método send_data. A gravação não é pixel por pixel, mas uma linha inteira igual à largura da tela:

 esp_err_t camera_capture(){ uint32_t tstart, t1, t2; tstart = clock(); //acquire a frame camera_fb_t * fb = esp_camera_fb_get(); if (!fb) { printf("Camera Capture Failed\n"); return ESP_FAIL; } t1 = clock() - tstart; printf("Capture camera time: %u ms\r\n", t1); int i = 0, bufPos = 0; uint8_t hb, lb; color_t color; color_t *color_line = heap_caps_malloc(_width*3, MALLOC_CAP_DMA); tstart = clock(); for(int y = 0; y < _height; y++) { bufPos = 0; for(int x = 0; x < _width; x++) { i = (y * FRAME_WIDTH + x) << 1; hb = fb->buf[i] ; lb = fb->buf[i + 1]; color.r = (lb & 0x1F) << 3; color.g = (hb & 0x07) << 5 | (lb & 0xE0) >> 3; color.b = hb & 0xF8; color_line[bufPos] = color; bufPos++; // TFT_drawPixel(0, 0, color, 1); } disp_select(); send_data(0, y, _width-1, y, _width, color_line); wait_trans_finish(1); disp_deselect(); } free(color_line); t1 = clock() - tstart; printf("Send buffer time: %u ms\r\n", t1); esp_camera_fb_return(fb); printf("Capture frame ok.\n"); return ESP_OK; } 

Configuração da cùmera
 // #if defined(CAMERA_MODEL_AI_THINKER) #define PWDN_GPIO_NUM 32 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 0 #define SIOD_GPIO_NUM 26 #define SIOC_GPIO_NUM 27 #define Y9_GPIO_NUM 35 #define Y8_GPIO_NUM 34 #define Y7_GPIO_NUM 39 #define Y6_GPIO_NUM 36 #define Y5_GPIO_NUM 21 #define Y4_GPIO_NUM 19 #define Y3_GPIO_NUM 18 #define Y2_GPIO_NUM 5 #define VSYNC_GPIO_NUM 25 #define HREF_GPIO_NUM 23 #define PCLK_GPIO_NUM 22 void camera_init_(){ camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM; config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM; config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM; config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM; config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM; config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM; config.pin_sscb_sda = SIOD_GPIO_NUM; config.pin_sscb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; config.fb_count = 2; // for display config.frame_size = FRAMESIZE_QVGA; config.pixel_format = PIXFORMAT_RGB565; // camera init esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { printf("Camera init failed with error 0x%x", err); return; } printf("Camera init OK\n"); } 


→ Gist

FRAME_WIDTH Ă© a largura do quadro de 320 pixels para QVGA

 config.frame_size = FRAMESIZE_QVGA; // 320x240 

De fato, vemos na janela de exibição 128 * 160 do quadro completo

Registre a configuração com um buffer de cùmera de vídeo (config.fb_count = 1)
Capturar tempo da cĂąmera: 32 ms
Tempo de buffer de envio: 47 ms
Capturar quadro ok.

Resultado
1000 / (32 + 47) = 12,65 FPS

Registre a configuração com dois buffers da cùmera de vídeo (config.fb_count = 2)
Capturar tempo da cĂąmera: 39 ms

Tempo de buffer de envio: 63 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 0 ms

Tempo de buffer de envio: 59 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 0 ms

Tempo de buffer de envio: 34 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 40 ms

Tempo de buffer de envio: 64 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 0 ms

Tempo de buffer de envio: 59 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 0 ms

Tempo de buffer de envio: 34 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 40 ms

Tempo de buffer de envio: 63 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 0 ms

Tempo de buffer de envio: 60 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 0 ms

Tempo de buffer de envio: 34 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 39 ms

Tempo de buffer de envio: 63 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 0 ms

Tempo de buffer de envio: 60 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 1 ms

Tempo de buffer de envio: 34 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 40 ms

Tempo de buffer de envio: 63 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 0 ms

Tempo de buffer de envio: 60 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 0 ms

Tempo de buffer de envio: 34 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 40 ms

Tempo de buffer de envio: 63 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 0 ms

Tempo de buffer de envio: 59 ms

Capturar quadro ok.
Capturar tempo da cĂąmera: 0 ms

Tempo de buffer de envio: 35 ms

Capturar quadro ok.

Usando o segundo buffer da cĂąmera de vĂ­deo, o buffer em alguns ciclos Ă© obtido instantaneamente. Inicialmente, o ciclo completo Ă© obtido em menos de um buffer, mas dessa vez "continua". O intervalo entre os ciclos Ă© flutuante.

Vårias vezes peguei nos registros "O detector de trincas foi acionado" e desliguei o detector. Porque no começo eu alimentei a tela de luz de fundo do pino ESP32-CAM de 3,3

 #include "soc/rtc_cntl_reg.h" ... WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector 

ConclusĂŁo


MĂłdulo funcional de baixo custo ESP32. HĂĄ uma falta catastrĂłfica de conclusĂ”es para as portas implementadas na versĂŁo CAM da placa; portanto, escolha a versĂŁo CAM se vocĂȘ realmente precisa de uma cĂąmera.

Source: https://habr.com/ru/post/pt463157/


All Articles