Table of Contents
Today, we will learn how to use the MicroSD card on the ESP32-CAM board to store images. We’ll put our skills to use by building both a motion-activated and time-lapse camera.
Introduction
The ESP32-CAM is certainly a perfect example of just how much electronics you can pack onto a tiny circuit board for an incredibly low price. The only thing better than getting a 2 MP camera along with a 32-bit microcontroller with integrated WiFi and Bluetooth for about 10 bucks is that it also comes with a great example sketch that essentially turns it into a surveillance camera with face-detection capabilities.
A pretty incredible board, and it also has a MicroSD card.
We tend to overlook the MicroSD card for all the other amazing capabilities of the ESP32-CAM board, especially as the CameraWebServer example doesn’t use a MicroSD. This is a shame, as it’s an obvious place to store images captured by the camera.
Today, I’ll show you how easy it is to use the MicroSD card in the ESP32-CAM board to do exactly that – store images captured by the camera. We’ll also build a motion-sensitive camera and a time-lapse camera.
Using the ESP32-CAM MicroSD Card
In order to save images onto the ESP32-CAM MicroSD card, we need to know a few things:
- How to properly format a MicroSD card.
- How to get images from the camera and turn them into a JPEG file
- How to write that file to a MicroSD card.
Once we are clear on all of that, we can start using the MicroSD card in our ESP32-CAM projects.
MicroSD Card Preparation
Before we can write anything to a MicroSD card, it needs to be formatted.
Specifically, it needs to be formatted in FAT32. Not exFAT, which is likely how it was formatted at the factory, but FAT32.
Formatting a MicroSD card in FAT32 may or may not be easy, depending upon the size of the card and what kind of computer you have access to. Specifically, formatting is a lot easier with Microsoft Windows than it is with any other operating system. And it’s much easier if your MicroSD card is smaller than 32 GB.
If you have Windows and a card that is smaller than 32GB then you’re all set, assuming your computer has an adapter for MicroSD or TF cards. If it doesn’t, you can get a USB one.
Just plug the MicroSD card in and Windows will detect it and offer to format it. Go to the Format menu and make sure that FAT32 is selected, which it likely will be by default. Then just format it, a Quick Format will be fine.
If you have a MicroSD card that is 32GB or larger, however, then it’s more of a challenge. There is a utility from Verbatim that can be used to format MicroSD cards with FAT32, regardless of size. We’ve used it with some of our Raspberry Pi experiments before.
But consider this – you’ll only be able to use 4GB of the card with the ESP32, so using a large MicroSD card is really just a waste of space. In fact, if you can find 4GB cards that would be ideal, but they are pretty rare these days.
I used 16GB cards in the experiments I performed, and they worked well.
Programming the ESP32-CAM
We’ll be using the Arduino IDE for our programming tasks, I’ll be using the classic (Version 1.8x) IDE, but you could also use the newer Arduino IDE Version 2.0. If you’re more comfortable in an alternate environment like PlatformIO, then by all means feel free to use it instead.
You will need to have your IDE configured to use the ESP32, if you are using the Arduino IDE please see my article about Getting Started with the ESP32 for more details regarding adding the ESP32 Boards Manager code.
I’m sure that you have already noticed that your ESP32-CAM does not have a MicroUSB or USB-C connector, so you’ll require an FTDI adapter to convert your USB signals to TTL-level signals for the ESP32.
You can buy an adapter to do the job, or you can use a stand-alone FTDI board.
If you choose the latter, I have completed instructions for hooking it up in the article on Getting Started with the ESP32-CAM, which you should probably read anyway. Make sure to note the point about the jumper wire from the ground to GPIO0, which needs to be in place if you want to program the board. You’ll also need to press the Reset button after the program compiles so that the upload can begin.
The stand-alone adapters don’t need jumpering or the Reset button, so they are easier to program with.
Programming for the MicroSD Card
We have covered Arduino programming for SD and MicroSD cards before, and the principles are identical for the MicroSD card on the ESP32-CAM board.
The MicroSD card contains a non-volatile serial RAM memory chip that is connected to its host using the SPI bus. The connection is made using the contacts on the card.
Internally, the card interface is wired to the ESP32 SPI bus.
The ESP32-CAM is only capable of working with 4GB of MicroSD storage. If you have a larger card it will work, providing it is formatted with FAT32, but it will only store 4GB of data.
In your code, you’ll use two libraries to work with the MicroSD card:
- FS.h – The file system library.
- SD_MMC.h – The SD card library for ESP32.
You’ll write your code to load the libraries and then initialize the MicroSD drive. Assuming it initializes and finds a compatible MicroSD card, you then open a file for writing. You write it to the MicroSD card and then close the file.
Programming for the Camera
As we want to obtain picture data, it would make sense to learn a bit about the camera on the ESP32-CAM board, and how we interface with it.
The camera is an OV2640 2MP camera module. It has a ¼ inch sensor with an array of 1600 x 1200 elements. At top speed, it can stream 1600 x 1200 video at 15 FPS.
The camera is connected internally to the hESP32 GPIO. The pin definitions are something you need to include within your code.
To work with the camera, you define those GPIO pinouts, and then configure a number of camera parameters. You then set up a frame buffer, after which you can read the camera data from the frame buffer.
The esp_camera.h library does most of the work here, it needs to be included in your code.
The CameraWebServer example included in the ESP32 sample code is a great way to learn how to use the camera.
Storing Pictures
So now that we know how to work with the camera and MicroSD card, let’s create a few sketches that use both of them.
We will start with a basic sketch that takes a picture when you press a button, in other words, a very simple camera. The image will be stored on the MicroSD card in JPEG format, and the files will be named sequentially.
As the ESP32 isn’t doing anything else, we’ll put it to sleep after we store our image. Pressing the button will wake it up and take a picture.
This is an especially good technique to use when you power the ESP32-CAM with a battery.
Simple Camera Hookup
Here is how we will hook up our simple camera.
Note that we are using a pull-up resistor and that the resistor is connected to the VCC pin on the ESP32. The VCC pin will output 3.3-volts, regardless of whether you power your ESP32-CAM with 5 or 3.3 volts.
Simple Camera Code
Here is the sketch we will use for our simple camera.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
/* ESP32 CAM Camera with MicroSD storage esp32cam-microsd.ino Take picture when button pressed Store image on MicroSD card DroneBot Workshop 2022 https://dronebotworkshop.com */ // Include Required Libraries // Camera libraries #include "esp_camera.h" #include "soc/soc.h" #include "soc/rtc_cntl_reg.h" #include "driver/rtc_io.h" // MicroSD Libraries #include "FS.h" #include "SD_MMC.h" // EEPROM Library #include "EEPROM.h" // Use 1 byte of EEPROM space #define EEPROM_SIZE 1 // Counter for picture number unsigned int pictureCount = 0; // Pin definitions for 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 configESPCamera() { // Configure Camera parameters // Object to store the camera configuration parameters 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.pixel_format = PIXFORMAT_JPEG; // Choices are YUV422, GRAYSCALE, RGB565, JPEG // Select lower framesize if the camera doesn't support PSRAM if (psramFound()) { config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA config.jpeg_quality = 10; //10-63 lower number means higher quality config.fb_count = 2; } else { config.frame_size = FRAMESIZE_SVGA; config.jpeg_quality = 12; config.fb_count = 1; } // Initialize the Camera esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed with error 0x%x", err); return; } // Camera quality adjustments sensor_t * s = esp_camera_sensor_get(); // BRIGHTNESS (-2 to 2) s->set_brightness(s, 0); // CONTRAST (-2 to 2) s->set_contrast(s, 0); // SATURATION (-2 to 2) s->set_saturation(s, 0); // SPECIAL EFFECTS (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) s->set_special_effect(s, 0); // WHITE BALANCE (0 = Disable , 1 = Enable) s->set_whitebal(s, 1); // AWB GAIN (0 = Disable , 1 = Enable) s->set_awb_gain(s, 1); // WB MODES (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) s->set_wb_mode(s, 0); // EXPOSURE CONTROLS (0 = Disable , 1 = Enable) s->set_exposure_ctrl(s, 1); // AEC2 (0 = Disable , 1 = Enable) s->set_aec2(s, 0); // AE LEVELS (-2 to 2) s->set_ae_level(s, 0); // AEC VALUES (0 to 1200) s->set_aec_value(s, 300); // GAIN CONTROLS (0 = Disable , 1 = Enable) s->set_gain_ctrl(s, 1); // AGC GAIN (0 to 30) s->set_agc_gain(s, 0); // GAIN CEILING (0 to 6) s->set_gainceiling(s, (gainceiling_t)0); // BPC (0 = Disable , 1 = Enable) s->set_bpc(s, 0); // WPC (0 = Disable , 1 = Enable) s->set_wpc(s, 1); // RAW GMA (0 = Disable , 1 = Enable) s->set_raw_gma(s, 1); // LENC (0 = Disable , 1 = Enable) s->set_lenc(s, 1); // HORIZ MIRROR (0 = Disable , 1 = Enable) s->set_hmirror(s, 0); // VERT FLIP (0 = Disable , 1 = Enable) s->set_vflip(s, 0); // DCW (0 = Disable , 1 = Enable) s->set_dcw(s, 1); // COLOR BAR PATTERN (0 = Disable , 1 = Enable) s->set_colorbar(s, 0); } void initMicroSDCard() { // Start the MicroSD card Serial.println("Mounting MicroSD Card"); if (!SD_MMC.begin()) { Serial.println("MicroSD Card Mount Failed"); return; } uint8_t cardType = SD_MMC.cardType(); if (cardType == CARD_NONE) { Serial.println("No MicroSD Card found"); return; } } void takeNewPhoto(String path) { // Take Picture with Camera // Setup frame buffer camera_fb_t * fb = esp_camera_fb_get(); if (!fb) { Serial.println("Camera capture failed"); return; } // Save picture to microSD card fs::FS &fs = SD_MMC; File file = fs.open(path.c_str(), FILE_WRITE); if (!file) { Serial.println("Failed to open file in write mode"); } else { file.write(fb->buf, fb->len); // payload (image), payload length Serial.printf("Saved file to path: %s\n", path.c_str()); } // Close the file file.close(); // Return the frame buffer back to the driver for reuse esp_camera_fb_return(fb); } void setup() { // Disable brownout detector WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // Start Serial Monitor Serial.begin(115200); // Initialize the camera Serial.print("Initializing the camera module..."); configESPCamera(); Serial.println("Camera OK!"); // Initialize the MicroSD Serial.print("Initializing the MicroSD card module... "); initMicroSDCard(); // initialize EEPROM with predefined size EEPROM.begin(EEPROM_SIZE); pictureCount = EEPROM.read(0) + 1; // Path where new picture will be saved in SD Card String path = "/image" + String(pictureCount) + ".jpg"; Serial.printf("Picture file name: %s\n", path.c_str()); // Take and Save Photo takeNewPhoto(path); // Update EEPROM picture number counter EEPROM.write(0, pictureCount); EEPROM.commit(); // Bind Wakeup to GPIO13 going LOW esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 0); Serial.println("Entering sleep mode"); delay(1000); // Enter deep sleep mode esp_deep_sleep_start(); } void loop() { } |
We start by including all the required libraries for the camera and MicroSD card. We also include the EEPROM library, as we are going to use a byte of EEPROM to store the number of our last photo.
Next, we define a counter to count the picture number, then we add the definitions for our camera connections. The camera connection definitions were copied from the CameraWebServer example sketch included with the ESP32 board, and they are for the AI THINKER camera.
Next, we define a number of functions. The first one is configESPCamera. This function configures all the camera parameters, and once again a lot of the code is from the CameraWebServer example sketch. The function also initializes the camera.
We also break out all the configuration parameters for the camera. You can use these to adjust your camera’s image quality. A good way to do this is to run CameraWebServer and use the controls to set the camera. Note the settings and edit the function as required.
The next function is initMicroSDCard, and its purpose is to initialize the MicroSD card. It mounts the card and verifies the card type.
takeNewPhoto is the next function, and as its name implies, it is the function that takes a picture and saves it to the MicroSD card. The function creates a frame buffer to capture an image, after which it creates a new file with that information and writes it to the MicroSD card.
The actual (action) in our sketch is within the Setup routine. Here we will set up everything, take a picture and then go to sleep.
Setup starts by initializing the serial monitor, the camera, the MicroSD card, and the EEPROM. We then read the EEPROM to get the number of the last photo we took, which we increment to use for the new photo.
The next step is to call the takeNewPhoto to take and save the picture. We pass the filename to this function. After the photo is taken, we update the EEPROM with the new picture number.
Now we come to the part of the code that wakes up the ESP32 when it is asleep.
The statement esp_sleep_enable_ext0_wakeup binds an input pin event to a wake-up call for the ESP32. We have attached it to GPIO pin 13, which is where we have our pushbutton switch attached. The last parameter, the “0”, indicates that the trigger will occur when this signal is LOW, which is what will happen when you press the pushbutton.
And after that, we print to the serial monitor and put the ESP32 to sleep using the command esp_deep_sleep_start.
Testing the Simple Camera
Load the sketch to the ESP32-CAM board. Once you’ve done that, open your Serial Monitor.
You should see some diagnostic messages, including ones regarding the camera and MicroSD card. Assuming nothing is wrong, the messages will end, and we’ll be waiting to take our first picture.
Aim the camera at something interesting and press the button, while observing the serial monitor. You should see a message with the filename of the image, followed by a confirmation that the file was saved to the MicroSD card.
Take as many pictures as you want, and note how the filename increments for each one.
When you have done with your photo session, power down the ESP32-CAM board and remove the MicroSD card. Now transfer the card to a computer with a MicroSD card reader, and open up the file management utility to take a look at it.
You should see the image files. Open them with the image viewer of your choice and see if they are acceptable. If they aren’t, you can try adjusting some camera parameters in the sketch.
Congratulations, you have built a camera!
Motion-Activated Camera
We can easily adapt the camera we just built to create a motion-activated camera.
Essentially, we are replacing the pushbutton switch with an IR Motion Sensor, so if it gets triggered then we will take a picture.
This can be a great way to find out who has been sneaking around your desk, or who ate the last piece of cheesecake!
If motion sensing isn’t what you need, you can also use this example to trigger the camera with just about any external signal, so keep that in mind.
Choosing a Motion Sensor
You can read up on IR sensors in the article I wrote about them, essentially they detect changes in infrared energy such as those caused by people and animals when they enter a room.
The motion sensor I’m using is an AM312, which is a simple device that is typical of most infrared motion sensors. This sensor runs on 3.3-volts, so it is ideal for use with the ESP32.
Another sensor you could consider is the SR505. Like the AM312 it outputs 3.3-volts, but this one requires 4.5 to 20 volts for power, so you’ll need a 5-volt supply to power it.
Motion-Activated Camera Hookup
The hookup of the PIR sensor is very similar to that of the pushbutton switch.
Note that we are still using GPIO pin 13 as a sensor input.
Motion-Activated Camera Code
Not only does the circuit of or motion-activated camera resemble the simple camera hookup, but we can also reuse the same code for this project.
We just need to make one modification.
The PIR sensor will output HIGH when it detects someone, which is the opposite of how our switch worked. So we need to wake up the hESP32 on a HIGH, instead of a LOW.
We can do that by changing this statement in the Setup section (line 220):
1 |
esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 0); |
This is the statement that binds the Wakeup to GPIO pin 13. The “)” at the end indicates it is triggered by a LOW input. So we just need to change that zero to a one, as follows:
1 |
esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 1); |
Now, the ESP32 will wake up when the sensor triggers it, and will then take a picture of your jellybean thief!
Time-Lapse Photography
We have already seen how we can use a Raspberry Pi to perform time-lapse photography. While the Pi gives us a much better choice of sensors and lenses, for simple surveillance tasks the ESP32-CAM and its 2 MP sensor will suffice.
Of course, our camera will be leaving an image on the MicroSD card. You can specify the time between images.
Once we have all of our images, we can use FFmpeg to stitch them together as a video file.
There is no hookup diagram for this project, as we can just use the ESP32-CAM on its own without any additional hardware.
Time-Lapse Camera Code
Here is the code we will use to create our time-lapse camera:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
/* ESP32-CAM Time-lapse camera esp32cam-timelapse.ino Takes time-lapse pictures with ESP32-CAM Saves images to MicroSD Card DroneBot Workshop 2022 https://dronebotworkshop.com */ // Include Required Libraries // Camera libraries #include "esp_camera.h" #include "soc/soc.h" #include "soc/rtc_cntl_reg.h" #include "driver/rtc_io.h" // MicroSD Libraries #include "FS.h" #include "SD_MMC.h" // Pin definitions for 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 // Counter for picture number unsigned int pictureCount = 0; // Delay time in millieconds unsigned int delayTime = 10000; void configESPCamera() { // Configure Camera parameters // Object to store the camera configuration parameters 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.pixel_format = PIXFORMAT_JPEG; // Choices are YUV422, GRAYSCALE, RGB565, JPEG // Select lower framesize if the camera doesn't support PSRAM if (psramFound()) { config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA config.jpeg_quality = 10; //10-63 lower number means higher quality config.fb_count = 2; } else { config.frame_size = FRAMESIZE_SVGA; config.jpeg_quality = 12; config.fb_count = 1; } // Initialize the Camera esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed with error 0x%x", err); return; } // Camera quality adjustments sensor_t * s = esp_camera_sensor_get(); // BRIGHTNESS (-2 to 2) s->set_brightness(s, 0); // CONTRAST (-2 to 2) s->set_contrast(s, 0); // SATURATION (-2 to 2) s->set_saturation(s, 0); // SPECIAL EFFECTS (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) s->set_special_effect(s, 0); // WHITE BALANCE (0 = Disable , 1 = Enable) s->set_whitebal(s, 1); // AWB GAIN (0 = Disable , 1 = Enable) s->set_awb_gain(s, 1); // WB MODES (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) s->set_wb_mode(s, 0); // EXPOSURE CONTROLS (0 = Disable , 1 = Enable) s->set_exposure_ctrl(s, 1); // AEC2 (0 = Disable , 1 = Enable) s->set_aec2(s, 0); // AE LEVELS (-2 to 2) s->set_ae_level(s, 0); // AEC VALUES (0 to 1200) s->set_aec_value(s, 300); // GAIN CONTROLS (0 = Disable , 1 = Enable) s->set_gain_ctrl(s, 1); // AGC GAIN (0 to 30) s->set_agc_gain(s, 0); // GAIN CEILING (0 to 6) s->set_gainceiling(s, (gainceiling_t)0); // BPC (0 = Disable , 1 = Enable) s->set_bpc(s, 0); // WPC (0 = Disable , 1 = Enable) s->set_wpc(s, 1); // RAW GMA (0 = Disable , 1 = Enable) s->set_raw_gma(s, 1); // LENC (0 = Disable , 1 = Enable) s->set_lenc(s, 1); // HORIZ MIRROR (0 = Disable , 1 = Enable) s->set_hmirror(s, 0); // VERT FLIP (0 = Disable , 1 = Enable) s->set_vflip(s, 0); // DCW (0 = Disable , 1 = Enable) s->set_dcw(s, 1); // COLOR BAR PATTERN (0 = Disable , 1 = Enable) s->set_colorbar(s, 0); } void initMicroSDCard() { // Start the MicroSD card Serial.println("Mounting MicroSD Card"); if (!SD_MMC.begin()) { Serial.println("MicroSD Card Mount Failed"); return; } uint8_t cardType = SD_MMC.cardType(); if (cardType == CARD_NONE) { Serial.println("No MicroSD Card found"); return; } } void takeNewPhoto(String path) { // Take Picture with Camera // Setup frame buffer camera_fb_t * fb = esp_camera_fb_get(); if (!fb) { Serial.println("Camera capture failed"); return; } // Save picture to microSD card fs::FS &fs = SD_MMC; File file = fs.open(path.c_str(), FILE_WRITE); if (!file) { Serial.println("Failed to open file in write mode"); } else { file.write(fb->buf, fb->len); // payload (image), payload length Serial.printf("Saved file to path: %s\n", path.c_str()); } // Close the file file.close(); // Return the frame buffer back to the driver for reuse esp_camera_fb_return(fb); } void setup() { // Disable brownout detector WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // Start Serial Monitor Serial.begin(115200); // Initialize the camera Serial.print("Initializing the camera module..."); configESPCamera(); Serial.println("Camera OK!"); // Initialize the MicroSD Serial.print("Initializing the MicroSD card module... "); initMicroSDCard(); Serial.print("Delay Time = "); Serial.print(delayTime); Serial.println(" ms"); } void loop() { // Path where new image will be saved in MicroSD card String path = "/image" + String(pictureCount) + ".jpg"; Serial.printf("Picture file name: %s\n", path.c_str()); // Take and Save Photo takeNewPhoto(path); // Increment picture count pictureCount++; // Delay for specified period delay(delayTime); } |
As you can see, this code uses a number of the same functions as the previous code sample, which makes sense as we are essentially doing the same thing – saving camera data to the MicroSD card.
We start with the same libraries for the MicroSD card and camera. We don’t use an EEPROM for this project, so its library was not included.
The pin definitions for the AI THINKER camera module are next, followed by an integer we will use as a picture count number.
We also create an integer to represent the number of milliseconds we want in between each image. I’ve set the value to 10,000, which is a 10-second delay, but of course, you can set it differently.
The three functions we used in the previous sketch are also used in this one:
- configESPCamera – Configures and initializes the camera module.
- initMicroSDCard – Initializes the MicroSD card.
- takeNewPhoto – Takes a photo and stores it on the MicroSD card.
In the Setup routine, we set up the serial monitor and initialize the camera and MicroSD card. We also print back our delay time.
In the Loop, we create a filename for the new image and then pass that filename to the takeNewPhoto function to take an image. Then we simply delay by the desired delay time and then do it again.
Pretty basic, but it gets the job done!
Time-Lapse Camera Testing
Testing the camera is pretty simple.
First, set the time delay to something fairly small, like the 10-seconds I used in my code. Once you have determined that everything is working, you can increase the value, it’s much easier to experiment with short time periods.
The camera will start working as soon as you reset the ESP32-cam. If you have used it already, it will overwrite the existing images.
After you get a number of images, power off the ESP-32 Cam module and remove the MicroSD card. Insert it into a computer and check out the images.
Remember, you can use the configuration parameters in configESPCamera to tweak the camera settings.
Now find something to watch over a period of time and leave your camera in front of it!
Conclusion
The inexpensive ESP32-CAM module is a powerful board that can be used in a number of applications, and as we have seen it is also pretty easy to work with. Being able to store your images onto a MicroSD card is a great feature, one that you can now use in your own projects.
Smile for the camera!
Parts List
Here are some components that you might need to complete the experiments in this article. Please note that some of these links may be affiliate links, and the DroneBot Workshop may receive a commission on your purchases. This does not increase the cost to you and is a method of supporting this ad-free website.
COMING SOON!
Resources
Code for this article – All the code used in the article, packaged in a ZIP file.
SmartDisk FAT32 Formatting – A Windows utility distributed by Verbatim.
ESP32-CAM Video Recording – Code for saving video on the MicroSD card (I had problems with it, but you may find it useful)
ESP32-CAM Video Recording 2 – Another ESP32-CAM video recorder project.
Hi I have tried to verify your code and the libruaries you have used are nowhere to be found
// Camera libraries
#include “esp_camera.h”
#include “soc/soc.h”
#include “soc/rtc_cntl_reg.h”
#include “driver/rtc_io.h”
// MicroSD Libraries
#include “FS.h”
#include “SD_MMC.h”
// EEPROM Library
#include “EEPROM.h”
so where did you get them from
Hi,
these are the standard Libs from the ESP32-Core. If you use the ArduinoIDE you have to install them via Tools->BoardManager the packge ESP32 (current v2.03). If you do not see this package, you have to add this link to your file->setup->Additional Board Manager urls:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json
Then you have to choose from Tools->Boards the board ESP32-Dev for the ESP32-Cam or if you have n other version the appropriate board. The the program(s) compile(s) without problems
where do Ifind the libruaries you have used
I didn’t need to “find” them, every library used in this article is already included in your Arduino IDE when you install the ESP32 boards manager.
Bill,
When you post these articles would you also make them available as a downloadable PDF file with the resources attached (at least the code files & other .pdf files you might reference)?
Thanks,
Bob
Check out the One-Click-Installer of ESP32-VideoCam … it is a simpler and newer version than the one mentioned in the show notes, that installs from your browser without downloading and compiling the code
https://jameszah.github.io/ESP32-CAM-VideoCam/
Also has links to the github source code.
The bits and bobs version was my first attempt a few years ago. 😀
Lengthy Instructions to Install and Operate ESP32-CAM-VideoCam
https://jameszah.github.io/ESP32-CAM-VideoCam/instruct
Hello, Is there a way to disable the flash?
Thanks.
Alan
In <code> void initMicroSDCard() <code/>, you have to add : <code> “/sdcard”, true <code/> inside the <code> SD_MMC.begin() <code/> parenthesis.
So all the block looks like this :
<code>
void initMicroSDCard() {
// Start the MicroSD card
Serial.println(“Mounting MicroSD Card”);
if (!SD_MMC.begin(“/sdcard”, true)) {
Serial.println(“MicroSD Card Mount Failed”);
return;
}
uint8_t cardType = SD_MMC.cardType();
if (cardType == CARD_NONE) {
Serial.println(“No MicroSD Card found”);
return;
}
}
<code/>
This gets around the fact that the flash led uses the same pin as the SD card.
Hi Bill, I really enjoyed this one! I have been experiencing problems with the setting options of the camera, but I have more or less figured it out. I basically adjust these settings depending if the camara is indoors or outdoors. That way I can avoid the pictures being too dark or bright. It’s a shame that there is no auto-settings options (at least it doesn’t work for me). I would like to see a project where you take advantage of the WiFi and Bluetooth functionalities of the ESP32Cam. Perhaps a project where you take a picture and it is… Read more »
It is a beautiful post that has been of great help to us. We will use part of the code in our cansat in CanSat Argentina.
Thanks for sharing.
@Renesatees40
Hello Bill, the add on board you have looks very similar to the ones I purchased from Banggood. The boards I have: 1) Do NOT supply 3.3vdc to the ESP module, the 5vdc from the usb port is connected to the 5vdc on the ESP. Brownout is still a thing. 2) Require the switch marked IO0 be closed during upload. 3) The reset switch on the board has NO effect and reset is still done with the switch on the ESP.
Hi Bill,
Happy new year!!
I really enjoy your workshops and learned already a lot.
Currently I try to get the camera running with SD card and motion sensor. It seem that I have a conflict with the suggested GPIO13 as an input for the motion sensor to wakup the camera.
Seems this GPIO is used for the SD card interface already.
Unfortunatly the GPIO1, GPIO3 and GPIO16 are not RTC GPIOs to wakeup the Camera.
Do you have experienced the same issues as well and did you find a solution?
Thanks a lot
Bernhard
Hi Bill,
I have tried your code and pin connections for the motion camera and it is not working for me. When power is applied to the camera (from Macbook usb or Arduino 5v) it constantly takes images, one after the other.
I copied your Camera (Button) Code and modified the line. esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 1);
I have a ESP32-CAM Ai Thinker,
ESP32-MB Shield,
PIR AM312,
ARDUINO Uno R3,
18650 Battery Shield supplying power
Any Ideas? So far I have lost 1 ESP32-CAM and 2 FTDI Chips trying to get the camera motion sensing, using guides in https://randomnerdtutorials.com/esp32-cam-pir-motion-detector-photo-capture
I have the exact same issue
I’m haveing the same problem as Darren Cuzner. It just keeps taking pics about every second.
Many objects emit in the infrared spectrum (lamps, electronic equipment etc.), not only animals and humans.
You can isolate your AM312 from the surrounding IR by hiding it under a ceramic bowl or wrapping it in aluminum foil (be careful to avoid short circuits !).
If your ESP32 continues to take pictures, it is also possible that the power supply is not stable. AM312 needs a stable power supply. Adding a capacitor between the VIN and GND pins can reduce false positives.
Hi,
If I use the ESp32 Cam on the development board can I add also the PIR Motion Module HC-SR505?
If yes, do you have any instructions on how I should modify the development board?
Thank you.
Hello, I am new to using ESP32 and I am currently using your code for time lapse. However, I am having some difficulties adapting an auxiliary light that is activated by a relay. Would you have any suggestions or advice that could help me with this? Thank you very much.
Hello, the pir sensor project is very good, I have done it but I can only record 256 photos on the card, is there a way to record more, thanks…
Probably change the EEPROM to 2 instead of 1.
I’m only guessing though.
Thanks, I’ll try it and tell you
a greetings.
I just tried it and it doesn’t work, when you record 256 re-record 1
Bill, thank you for another excellent presentation.
After using a different PC utility to format the card, which created writable partitions that wouldn’t mount on the ESP32-cam, I downloaded SmartDisk via the link in the written version of the presentation. This worked fine.
Now my tomato seedlings are under timelapse surveillance.
Hi! M5stack.Can you make its video?
Hi. I have used several of your tutorials in my projects. Well written and explained. Thank you!
I am however having an issue with the esp32 cam using the sd card and Pir sensor. The code uploads fine and I am able to save images. My issue is with pir sensor. On running the program, the board’s LED flashes repeatedly and does not save images. I have tried turning off my desk lamp, leaving the room etc. No change in behavior. I must be missing something here.
Any ideas?
Doug