ESP32-CAM Auto-Selfie Camera with TFT

ESP32-CAM Selfie Camera

A 3D printable camera with a TFT screen and web viewing and deleting of stored photos

For this tutorial I’ve used an ESP32 -CAM, a 1.8″ TFT screen, an 18650 USB powerbank and a 3D printed case to make a selfie camera that automatically takes a photo when it sees a person’s face. The project has a lot of steps but is fairly simple. You can make it version without having a 3D printer.

Setting up the Arduino IDE

Before uploading the code a few things need to be set up in the Arduino IDE. If this is your first time with the ESP32-CAM in the Arduino IDE you need to set up the ESP32 hardware libraries, learn to connect and test by following this tutorial ESP32-CAM in the Arduino IDE

There’s three libraries that need to be installed. The TFT_eSPI can easily be installed from the IDE library manager (Tools > Manage Libraries) by searching for TFT_eSPI. The TFT_eFEX and ESPAsyncWebserver libraries need to be installed by downloading the libraries using the the ‘Download ZIP’ link and in the IDE installing them with Sketch > Include Library > Add .ZIP Library.

The TFT_eSPI library needs to be configured to work with the ST7735S TFT panel. Copy the contents of the User_Setup.h file into the newly installed library file User_Setup.h file found in Documents > Arduino > libraries > TFT_eSPI. If you find the image quality is poor you can try other xxxxTAB versions. These refer to the colours of the tab on the screen protector but don’t match 100%.

If you want to use the countdown animation, the images for this need to be uploaded to the ESP32 memory. To do this follow the instructions to install the data folder uploader here: ESP32 Data Folder Uploader . Remember if you change the partition scheme in the IDE this data will be over-written.

Uploading the Sketch

Download the ZIP file from the project folder on Github https://github.com/robotzero1/esp32cam-selfiecam and unzip to your Arduino folder (In Windows 10 – Libraries > Documents > Arduino) in a directory named SelfieCam.

Inside the new directory, open the SelfieCam.ino in the IDE and then use the Tools > ESP32 Sketch Data Upload tool to upload the data directory.

You’ll need to reset the ESP32-CAM and then use the following settings in the IDE to upload the Sketch.

Board: ESP32 Dev Module
Upload Speed: 921600
CPU Frequency: 240Mhz
Flash Mode: QIO
Flash Size: 4MB
Partition Scheme: No OTA (2MB APP/2MB SPIFFS)
PSRAM: Enabled

Components

The project only needs a few components. An ESP32-CAM, a 1.8″ ST7735S TFT screen, 10 male to male dupont cables, a USB powerbank, one 18650 battery and a spare USB cable or terminal block.

Selfie Cam Components

ESP32 – TFT Wiring Diagram

The project is wired as below. You need to connect two dupont cables to one connector so you can use 3v on the ESP32 to power the LED and VCC pins on the display.

ESP32-CAM TFT Wiring Diagram

Before adding the components to the 3D model, the project looks like this. I used a USB terminal block (in green) instead of a spare USB cable.

Components Connected

SelfieCam 3D Printed Model

I created the model in Tinkercad, sliced in Cura and printed on a stock Ender 3.

The model needs to be flipped 180° so the front is flat on the print bed. The part where the USB powerbank fits will print better with supports – set the overhang at 85 degrees. I used the standard Ender 3 normal profile.

Cura Sliced

When printed the two sides of the model look like this:

3d Print Front and Back

Optionally there are two extra parts to print. A clip that holds the ESP32-CAM in place and a diffuser for the flash. The diffuser should be printed using a transparent filament.

Flash and Clip Prints

When everything is assembled it should look like this:

Assembled Back

Video Demonstration

Below is a quick video showing the the selfie capture sequence, starting with the face being detected, the flash lighting up, the photo being taken and finally the photo being displayed from the ESP32 SPIFFS storage:

Full tutorial video on YouTube – https://www.youtube.com/watch?v=j8lVFmjAARA

Browser to ESP32 Communication

The code uses a mixture of HTTP requests and WebSockets. When the browser first connects to the ESP32 the HTML interface is sent via HTTP with this code:

webserver.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    Serial.print("Sending interface...");
    AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_ov2640_html_gz, sizeof(index_ov2640_html_gz));
    response->addHeader("Content-Encoding", "gzip");
    request->send(response);
 });

In the browser the interface loads and opens a WebSocket connection to the ESP32. This replies with a list of files in the ESP32 storage – the results of the function below:

String filelist_spiffs()
{
  filelist = "";
  fs::File root = SPIFFS.open("/");
  fs::File file = root.openNextFile();
  while (file) {
    String fileName = file.name();
    filelist = filelist + fileName;
    file = root.openNextFile();
  }
  return filelist;
}

Back in the browser it processes the list with the code below. addSelfieToScreen() is a function that creates objects in the DOM and fills them to create the visible interface.

var filelistFromESP32 = message.data; // list of files from ESP32
var fileIDs = filelistFromESP32.substring(1).split("/"); // remove first / and then split on subsequent /

fileIDs.forEach(function(item){
	if (item.includes("_t_")){ // thumnail images
  		addSelfieToScreen(item);
	}
});
populateImgtags();

When all the objects in the interface are created, the populateImgtags() function runs. This uses the fetch() method to request the selfie images from the ESP32. The images are sent from the ESP32 storage to the browser via HTTP with this code:

 webserver.on("/image", HTTP_GET, [](AsyncWebServerRequest * request) {
    Serial.println("Requesting image from SPIFFS");
    if (request->hasParam("id")) {
      AsyncWebParameter* p = request->getParam("id");
      String imagefile = p->value();
      imagefile = imagefile.substring(4);
      request->send(SPIFFS, "/" + imagefile);
    }
 });

Every time a new selfie is taken another WebSocket message is sent to the browser using the command ws.textAll((char*)addtobrowser). Again on the browser a new DOM object is created with addSelfieToScreen() and the image is requested with populateImgtag() as above when the interface is first created.

Deleting an image. During the creation of the DOM each image has ‘X’ added which has an event listener attached with this code:

deleteItem.addEventListener("click", function() {
   ws.send("delete:" + selfieID);
});

When the ‘X’ is clicked, a WebSocket request is sent to the ESP32 which then processes this code:

String deletefile = incoming.substring(7);
incoming = "";
int fromUnderscore = deletefile.lastIndexOf('_') + 1;
int untilDot = deletefile.lastIndexOf('.');
String fileId = deletefile.substring(fromUnderscore, untilDot);
SPIFFS.remove("/selfie_t_" + fileId + ".jpg");
SPIFFS.remove("/selfie_f_" + fileId + ".jpg");
client->text("removed:" + deletefile);

The final line above sends a WebSocket message back. The browser then removes the photo from the interface:

function removeSelfieFromScreen(imageid){
     var imageItem = document.getElementById(imageid);
     imageItem.parentElement.remove(); // remove parent div and contents
}

More tutorials like this – https://robotzero.one/robot-zero-plus/


Resources

Project Code: https://github.com/robotzero1/esp32cam-selfiecam
Editable 3D Model in TinkerCad – https://www.tinkercad.com/things/5fHl1Nb8gHa
Flash and Clip 3D Models – https://www.tinkercad.com/things/bMHwKzBiP4A
STL File for 3D Printer: https://github.com/robotzero1/esp32cam-selfiecam/blob/master/SelfieCam.stl
HTML Thumbnail Grid: https://css-tricks.com/responsive-grid-magazine-layout-in-just-20-lines-of-css/
Async Webserver Docs: https://github.com/me-no-dev/ESPAsyncWebServer
TFT Library: https://github.com/Bodmer/TFT_eSPI
TFT Extras Library: https://github.com/Bodmer/TFT_eFEX
Countdown numbers: https://www.twinkl.es/resource/t-w-32902-numbers-0-31-on-robots

25 Replies to “ESP32-CAM Auto-Selfie Camera with TFT”

  1. Peter Russell says:

    I have followed this project and got it to work but with one major problem.
    I have a RED / BLUE reversal which I cannot resolve.
    I am using the orange ST7735S display, as shown in your description.
    I have tried all the various TAB’s, but none seem to make a difference.
    I have checked through the libraries as far as I can, but I can’t be sure that there is something in there that I haven’t spotted.
    (I did have to add tft.init(); to get the display to work)
    Please can you help.
    Thanks.

    1. WordBot says:

      Hi, I found someone with the same problem – https://github.com/Bodmer/TFT_eSPI/issues/639 Maybe one of the solutions there will work?

  2. Josef Havlicek says:

    Dear.
    I found you using the link FB: https://www.facebook.com/groups/esp8266microcontrollers/?ref=group_header
    I would need a design for Door Cam or DorrBell with ESP32-CAM – only.
    Don’t have a tip?
    Josef

    1. WordBot says:

      Hi. Check out the list of projects here: https://robotzero.one/esp32-camera-projects/ there’s various ESP32-CAM projects that might help you.

  3. Josef Havlíček says:

    Hi.
    Thanks.
    JH

  4. Thorsten says:

    Hi,
    have you ever came across the problem that it crashes with “matrix3du item alloc failed”?
    Looks like something the face dectection – but not sure how to solve that…
    Regards,

    1. WordBot says:

      Hi. Does it constantly do this? Do you have PSRAM enabled in the Tools menu?

  5. Thorsten says:

    ok…my fault. Seems I missed that option. Thanks

    1. WordBot says:

      No problem.. I only knew because I did the same thing last week.

  6. Ulrich says:

    Hello, I have never worked with the filesystem uploader and I need help.
    I currently see the streaming of the camera on the TFT. But I don’t know how photos are taken and how the countdown is displayed. I assume that you can then read the photos from the internal memory via the displayed URL.
    Who can give me tips on my problem.
    Thank you Ulli

  7. Ayhan Dayanik says:

    I’m getting an error message when face detected like this “CORRUPT HEAP: Bad head at 0x3ffddf64. Expected 0xabba1234 got 0x00000008
    abort() was called at PC 0x4008a5fd on core 1”
    My settings are as mentioned above.
    I could not find any solution about it. How can I solve this problem?
    Thanks for your help in advance.

    1. WordBot says:

      I don’t really know why you are seeing that error. The only thing I can suggest is to put in some print statements to narrow down which command crashes it. Something like
      Serial.println(“Before function xxxx”);

      1. Ayhan Dayanik says:

        Hi, when I saw your reply, I came back this project again and added check points after each command line in function face_detected then found where the program broke and restart.
        The problem was on the free(net_boxes->score); command inside if block. I searched again about it in the forums and found a solution.
        I just replaced the 4 free’s in each block with dl_lib_free.
        I hope this helps others.

        1. WordBot says:

          Hi, Thanks for coming back with the fix. It might be a newer ESP32 Hardware Library version has changed things.

  8. Summer says:

    Hi WordBot.
    I did’t see the pin define in your code, how can it work?
    Thanks

    1. WordBot says:

      Some of the pins are set up in the User_Setup.h file. Check out the https://github.com/Bodmer/TFT_eSPI page for help with this.

  9. summer says:

    a error of: SPIFFS Upload failed! when try to load data.
    I didn’t set data before.

    1. WordBot says:

      Did you set the partition to
      Partition Scheme: No OTA (2MB APP/2MB SPIFFS)
      ?

  10. summer says:

    Hi, WordBot,
    Can you just delete above last post please.
    Yes, I did setup.
    I found a link give a solution at: https://github.com/espressif/arduino-esp32/issues/2350
    by: I found a way to work around the problem. If I select Board:->Heltec ESP32 Arduino->WIFI_LoRa_32, the SPIFFS upload works properly.
    SPIFFS Image Uploaded.
    but still without showing any thing on TFT, a button on pin4 made flashing, and the TFT seems change a little when press button.

  11. Summer says:

    Hi Sir.
    sorry that I insert a SD card into the ESP32CAM ! works now!
    Thank you.

  12. Ali says:

    HI
    it seems “fd_forward.h” is not available in esp32-Arduino core right now
    How can I fix this problem

    1. WordBot says:

      HI, Did you install the ESP32 Hardware library? v1.0.4 or 5 should work.

  13. GIUSEPPE BIGONI says:

    Hello and sorry for the inconvenience.
    Congratulations on this beautiful project.
    I would like to test it and I have performed all your instructions.
    But now I have the following error:

    In file included from C:\_PROGETTO_E_SVILUPPO\SU-14\WEB-CAM\SelfieCam\SelfieCam.ino:5:
    c:\ARDUINO\Arduino-Library\libraries\esp32-fd_forward.h-main/fd_forward.h:31:10: fatal error: image_util.h: No such file or directory
    #include “image_util.h”
    ^~~~~~~~~~~~~~
    Do you know how I can fix the problem?
    Thank you very much for your kind cooperation.

    1. WordBot says:

      possibly the wrong ESP32 hardware library. Which one do you have installed?

  14. José Barreto says:

    I managed to run your code using platformio

    I used the following configuration:

    [env:esp32cam]
    platform = espressif32@2
    board = esp32cam
    framework = arduino
    lib_extra_dirs = ~/Documents/Arduino/libraries
    board_build.partitions = no_ota.csv
    board_build.filesystem = spiffs
    monitor_rts = 0
    monitor_dtr = 0
    monitor_speed = 115200
    upload_speed = 921600
    upload_port = /dev/ttyUSB0
    lib_deps =
    ottowinter/ESPAsyncWebServer-esphome@^2.0.1
    bodmer/TFT_eSPI@^2.2.6
    bodmer/TFT_eFEX@^0.0.8
    bodmer/JPEGDecoder@^1.8.1

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

scroll to top