The Seeed Xiao is my favorite small form factor development board. I have quite a few of the original SAMD21 boards. They're great for prototyping sensors and the family has expanded to use many of the common MCU types - SAMD21, RP2040, nRF52840, ESP32C3 (RISC-V), and their latest uses an ESP32S3.
I've used ESP32-Cam boards in the past, but I was still surprised by the size and cost of the new Xiao ESP32S3 Sense module. The base Xiao ESP32S3 board costs $7.49 and the Sense option adds a piggyback board with an OV2640 (1600x1200) camera, digital microphone and SD card for an extra $6.50. That was something that I couldn't pass up, so I bought one and it just arrived.
Here is my unit with a quick case that I printed for it.
That's a huge WiFi antenna compared to the one that comes with the Nicla Vision .
Seeed has a github repo with sample applications for the module - https://github.com/limengdu/SeeedStudio-XIAO-ESP32S3-Sense-camera.
I decided to try out the CameraWebServer example. They do warn you that if you stream continuously that the module will get very hot (I've had that experience with ESP32-Cams also). I figured if the PLA case started melting that it would be time to stop...
CameraWebServer.ino
#include "esp_camera.h" #include <WiFi.h> #define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM #include "camera_pins.h" // =========================== // Enter your WiFi credentials // =========================== const char* ssid = "**********"; const char* password = "**********"; void startCameraServer(); void setupLedFlash(int pin); void setup() { Serial.begin(115200); while(!Serial); Serial.setDebugOutput(true); Serial.println(); 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.frame_size = FRAMESIZE_UXGA; config.pixel_format = PIXFORMAT_JPEG; // for streaming //config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; config.fb_location = CAMERA_FB_IN_PSRAM; config.jpeg_quality = 12; config.fb_count = 1; // if PSRAM IC present, init with UXGA resolution and higher JPEG quality // for larger pre-allocated frame buffer. if(config.pixel_format == PIXFORMAT_JPEG){ if(psramFound()){ config.jpeg_quality = 10; config.fb_count = 2; config.grab_mode = CAMERA_GRAB_LATEST; } else { // Limit the frame size when PSRAM is not available config.frame_size = FRAMESIZE_SVGA; config.fb_location = CAMERA_FB_IN_DRAM; } } else { // Best option for face detection/recognition config.frame_size = FRAMESIZE_240X240; #if CONFIG_IDF_TARGET_ESP32S3 config.fb_count = 2; #endif } // camera init esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed with error 0x%x", err); return; } sensor_t * s = esp_camera_sensor_get(); // initial sensors are flipped vertically and colors are a bit saturated if (s->id.PID == OV3660_PID) { s->set_vflip(s, 1); // flip it back s->set_brightness(s, 1); // up the brightness just a bit s->set_saturation(s, -2); // lower the saturation } // drop down frame size for higher initial frame rate if(config.pixel_format == PIXFORMAT_JPEG){ s->set_framesize(s, FRAMESIZE_QVGA); } // Setup LED FLash if LED pin is defined in camera_pins.h #if defined(LED_GPIO_NUM) setupLedFlash(LED_GPIO_NUM); #endif WiFi.begin(ssid, password); WiFi.setSleep(false); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); startCameraServer(); Serial.print("Camera Ready! Use 'http://"); Serial.print(WiFi.localIP()); Serial.println("' to connect"); } void loop() { // Do nothing. Everything is done in another task by the web server delay(10000); }
The program brings up a browser interface at the module ip address.
It allows you to stream and take stills at the different camera resolutions up to the max 1600x1200, but you can't get great frame rate at the higher resolutions.
It also has Face Detection and Face Recognition capability, but only up to QVGA (320x240) resolution which is on par with other ML models I've used.
Sorry I don't have a better looking subject...
A short video showing the max resolution down to face detection. Just realized that the horizontal is flipped (like doing a selfie).
I can see lots of possibilities for this module. Made me think of scottiebabe 's birdhouse .