ESP32-CAM with Capacitive Touch Buttons and OLED


A 3D printed camera with an OLED display, saving to SD card and capacitive touch button controls.

This is a Robot Zero Plus tutorial. The full code and 3D models are only available for Plus members.

ButtonCam 3D Printed Model

I designed the camera in Tinkercad. The front and back look like this:

TinkerCad Camera Front
TinkerCad Camera Rear

The 3D files need to flipped upside down in the slicer before printing:

Cura Camera Front
Cura Camera Rear

The final 3D prints look like this:

Button Cam Front 3D Print
Button Cam Back 3D Print


In addition to the ESP32-CAM. The project requires a microSD card, an SSD1306 OLED, three TTP223 capacitive touch switches, 15 dupont cables, a voltage booster, a 18650 battery and holder.

Project Components

The 18650 battery, holder and booster could be replaced with anything that can supply 5v to the ESP32-CAM.

Wiring Diagram

This content is for Plus members only.


It should be easy to install all the components as shown in the video. If you use a different part or something doesn’t fit, you can snap off the clips and just glue or Blu Tack the part in place.

The Code

C++ Code on the ESP32

In the Arduino loop, frames are constantly requested from the camera. Each JPG frame is decoded and the pixels converted to grey scale while saving into an array. This array is then processed a second time to create to a dithered monochrome array that is output to the OLED screen.

While this camera data is being streamed to the OLED the ESP32 also listens for button presses from the three capacitive touch buttons. If the trigger button is pressed, the camera switches to a higher resolution, captures a frame and this is saved to the microSD card and also briefly shown on the OLED screen.

If the left or right buttons are pressed the ESP32 reads the files before or after the current image on the microSD card and again, shows this on the OLED.

The HTML and JavaScript Code

In addition to the above, the ESP32 is also running a web server. This serves the page you see if you connect to the IP address shown on startup. The page contains a basic slide-show that is populated by images taken on the camera. When a new photo is taken, the Arduino code sends a websocket request containing the image ID of the new image to the web server. JavaScript on the web server then creates a new slide in the browser, requests the JPG file from the microSD card and displays it.

Demonstration Video

Fully assembled the project looks and functions like this:

Dithering Video for Monochrome Displays

Video passed directly from a camera to a monochrome screen can be difficult to make out. It needs to be dithered using error diffusion to break up the solid black and white areas. The Arduino code processes the image using the Floyd-Steinburg dithering algorithm.

When the frame size is set to QQVGA2 it is easy to decode the top part of the 128×160 frame to give 128×64 pixels to display on the OLED screen. The problem is that only the top part of the camera frame is shown on the screen.

I wanted to use frames from the full sensor so I set the resolution to QQVGA (160 × 120) and resampled the camera frames to create an array with the same resolution as the screen. However I discovered later than the minimum resolution that the ov2640 sensor outputs at full frame is CIF (352 x 288 pixels). I need to investigate this further.

OLED QQVGA2 No Dithering
128×160 resolution without dithering
OLED QQVGA No Dithering
160 × 120 resolution without dithering
OLED QQVGA2 Floyd-Steinburg Dithering
128×160 resolution with Floyd-Steinburg dithering
OLED QQVGA Floyd-Steinburg Dithering
160×120 resolution with Floyd-Steinburg dithering

It’s easier to see how effective using dithering can be with monochrome screens in the video below which shows the same two resolutions as above but with a moving image.

Monochrome Dithering Demonstration

ButtonCam MKII

Mark II of this project will have a power switch, the camera will be relocated and the code improved. The slide-show will probably be replaced with an image browser.

Code, 3D models, STL and Wiring Diagram

For full access to this tutorial including the code, 3D STL files and Tinkercad originals and the wiring diagram, please click here to subscribe to be a Plus member. More information about Plus membership can be found here.

Helpful Resources

Best guide to dithering I found –
Basic Floyd-Steinburg pseudocode –

2 Replies to “ESP32-CAM with Capacitive Touch Buttons and OLED”

  1. Robert Gwozdz says:

    sorry … my false of course … you wrote // 16 when psram off
    I forgot about it, now it starts up properly … 🙂

    1. WordBot says:

      My fault… I should have made it more obvious about pin 16. I’ll add a screenshot of the tools settings to the tutorial.

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