English | 中文
Now, M5Stack has four types of camera units, there are respectively ESP32CAM, M5Camera (A Model), M5Camera (B Model), M5CameraX, M5CameraF.
The main differences between these cameras are memory, interface, lens, optional hardware and camera shell。
The code for this repository is for these boards, and each folder corresponds to a function.
mpu6050 -> Gyro routine after soldering MPU6050 chip (idf-3.3)
qr -> QR code recognition (idf-3.3)
wifi -> Routine for transferring images (idf-4.0)
face_recognize -> Face recognition routine (idf-3.3)
Please note that before compiling the downloaded code, you need to do the following to configure the appropriate board.
Step 1:build an ESP-IDF development environment
Step 2:After setting up the ESP-IDF environment, execute make menuconfig in the terminal.
Step 3:Configure camera model
Step 4:Open psram
Step 5:In the terminal Terminal, execute make to ensure that the compilation is correct
Step 6:In the terminal Terminal, execute make flash to download the program.
Step 7:In the terminal terminal, execute make monitor to open the serial port monitoring.
The picture below is their comparison table. (Note: Because the interface has many different pins, so I have made a separate table to compare.)
If you want to view the detailed defference with them, please click here.
If you want to download the detailed defference with them, please click here.
The following table shows interface difference between those camera boads based on the Interface Comparison table.
- Except when using CIF or lower resolution with JPEG, the driver requires PSRAM to be installed and activated.
- Using YUV or RGB puts a lot of strain on the chip because writing to PSRAM is not particularly fast. The result is that image data might be missing. This is particularly true if WiFi is enabled. If you need RGB data, it is recommended that JPEG is captured and then turned into RGB using
fmt2rgb888orfmt2bmp/frame2bmp. - When 1 frame buffer is used, the driver will wait for the current frame to finish (VSYNC) and start I2S DMA. After the frame is acquired, I2S will be stopped and the frame buffer returned to the application. This approach gives more control over the system, but results in longer time to get the frame.
- When 2 or more frame bufers are used, I2S is running in continuous mode and each frame is pushed to a queue that the application can access. This approach puts more strain on the CPU/Memory, but allows for double the frame rate. Please use only with JPEG.
- Clone or download and extract the repository to the components folder of your ESP-IDF project
Make
camera_fb_t*fb=NULL; // will get a img framefb=esp_camera_fb_get(); // img bufuint8_t*buf=fb->buf; // img buf lenunit32_tbuf_len=fb->len; /* --- do some something --- */// need return img bufesp_camera_fb_return(fb);sensor_t*s=esp_camera_sensor_get(); s->set_framesize(s, FRAMESIZE_VGA); s->set_quality(s, 10); ...Detailed view sensor.h
#include"esp_camera.h"staticcamera_config_tcamera_config={.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 .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_UXGA,//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 }; esp_err_tcamera_init(){//power up the camera if PWDN pin is definedif(CAM_PIN_PWDN!=-1){pinMode(CAM_PIN_PWDN, OUTPUT); digitalWrite(CAM_PIN_PWDN, LOW)} //initialize the cameraesp_err_terr=esp_camera_init(&camera_config); if (err!=ESP_OK){ESP_LOGE(TAG, "Camera Init Failed"); returnerr} returnESP_OK} esp_err_tcamera_capture(){//acquire a framecamera_fb_t*fb=esp_camera_fb_get(); if (!fb){ESP_LOGE(TAG, "Camera Capture Failed"); returnESP_FAIL} //replace this with your own functionprocess_image(fb->width, fb->height, fb->format, fb->buf, fb->len); //return the frame buffer back to the driver for reuseesp_camera_fb_return(fb); returnESP_OK}#include"esp_camera.h"#include"esp_http_server.h"#include"esp_timer.h"typedefstruct{httpd_req_t*req; size_tlen} jpg_chunking_t; staticsize_tjpg_encode_stream(void*arg, size_tindex, constvoid*data, size_tlen){jpg_chunking_t*j= (jpg_chunking_t*)arg; if(!index){j->len=0} if(httpd_resp_send_chunk(j->req, (constchar*)data, len) !=ESP_OK){return0} j->len+=len; returnlen} esp_err_tjpg_httpd_handler(httpd_req_t*req){camera_fb_t*fb=NULL; esp_err_tres=ESP_OK; size_tfb_len=0; int64_tfr_start=esp_timer_get_time(); fb=esp_camera_fb_get(); if (!fb){ESP_LOGE(TAG, "Camera capture failed"); httpd_resp_send_500(req); returnESP_FAIL} res=httpd_resp_set_type(req, "image/jpeg"); if(res==ESP_OK){res=httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg")} if(res==ESP_OK){if(fb->format==PIXFORMAT_JPEG){fb_len=fb->len; res=httpd_resp_send(req, (constchar*)fb->buf, fb->len)} else{jpg_chunking_tjchunk={req, 0}; res=frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL; httpd_resp_send_chunk(req, NULL, 0); fb_len=jchunk.len} } esp_camera_fb_return(fb); int64_tfr_end=esp_timer_get_time(); ESP_LOGI(TAG, "JPG: %uKB %ums", (uint32_t)(fb_len/1024), (uint32_t)((fr_end-fr_start)/1000)); returnres}#include"esp_camera.h"#include"esp_http_server.h"#include"esp_timer.h"#definePART_BOUNDARY "123456789000000000000987654321" staticconstchar*_STREAM_CONTENT_TYPE="multipart/x-mixed-replace;boundary="PART_BOUNDARY; staticconstchar*_STREAM_BOUNDARY="\r\n--"PART_BOUNDARY"\r\n"; staticconstchar*_STREAM_PART="Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n"; esp_err_tjpg_stream_httpd_handler(httpd_req_t*req){camera_fb_t*fb=NULL; esp_err_tres=ESP_OK; size_t_jpg_buf_len; uint8_t*_jpg_buf; char*part_buf[64]; staticint64_tlast_frame=0; if(!last_frame){last_frame=esp_timer_get_time()} res=httpd_resp_set_type(req, _STREAM_CONTENT_TYPE); if(res!=ESP_OK){returnres} while(true){fb=esp_camera_fb_get(); if (!fb){ESP_LOGE(TAG, "Camera capture failed"); res=ESP_FAIL} else{if(fb->format!=PIXFORMAT_JPEG){booljpeg_converted=frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len); if(!jpeg_converted){ESP_LOGE(TAG, "JPEG compression failed"); esp_camera_fb_return(fb); res=ESP_FAIL} } else{_jpg_buf_len=fb->len; _jpg_buf=fb->buf} } if(res==ESP_OK){size_thlen=snprintf((char*)part_buf, 64, _STREAM_PART, _jpg_buf_len); res=httpd_resp_send_chunk(req, (constchar*)part_buf, hlen)} if(res==ESP_OK){res=httpd_resp_send_chunk(req, (constchar*)_jpg_buf, _jpg_buf_len)} if(res==ESP_OK){res=httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY))} if(fb->format!=PIXFORMAT_JPEG){free(_jpg_buf)} esp_camera_fb_return(fb); if(res!=ESP_OK){break} int64_tfr_end=esp_timer_get_time(); int64_tframe_time=fr_end-last_frame; last_frame=fr_end; frame_time /= 1000; ESP_LOGI(TAG, "MJPG: %uKB %ums (%.1ffps)", (uint32_t)(_jpg_buf_len/1024), (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time)} last_frame=0; returnres}#include"esp_camera.h"#include"esp_http_server.h"#include"esp_timer.h"esp_err_tbmp_httpd_handler(httpd_req_t*req){camera_fb_t*fb=NULL; esp_err_tres=ESP_OK; int64_tfr_start=esp_timer_get_time(); fb=esp_camera_fb_get(); if (!fb){ESP_LOGE(TAG, "Camera capture failed"); httpd_resp_send_500(req); returnESP_FAIL} uint8_t*buf=NULL; size_tbuf_len=0; boolconverted=frame2bmp(fb, &buf, &buf_len); esp_camera_fb_return(fb); if(!converted){ESP_LOGE(TAG, "BMP conversion failed"); httpd_resp_send_500(req); returnESP_FAIL} res=httpd_resp_set_type(req, "image/x-windows-bmp") ||httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.bmp") ||httpd_resp_send(req, (constchar*)buf, buf_len); free(buf); int64_tfr_end=esp_timer_get_time(); ESP_LOGI(TAG, "BMP: %uKB %ums", (uint32_t)(buf_len/1024), (uint32_t)((fr_end-fr_start)/1000)); returnres}







