Esp32cam works with 1 code not the other

Hi, i'm trying to use this code, but the logs show me : failed capture.
To see if the camera works i ran the example -> esp32 camera -> webserver and it works perfectly. So i'm not sure why it doesn't work in this one.

Does anyone know why?

/**
   ESP32-CAM Directional Motion Detection (https://www.youtube.com/watch?v=NIbiG6at01g)
   Learn more on Makers Mashup - https://youtube.com/MakersMashup
   Licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
   http://creativecommons.org/licenses/by-sa/4.0/

   PLEASE NOTE YOU WILL NEED TO ADD THE TaskSchedule and TinySTepper libarires to 
   run this code unaltered.  Use TOOLS->Manage Libraries in the arduino IDE.
   Also use the board manager and make sure you select ESP32 as an available
   board. The one I used specifically was https://amzn.to/3m2dJrl
   
*/
#include <TaskScheduler.h>
#include <TinyStepper_28BYJ_48.h>


#define CAMERA_MODEL_AI_THINKER                                       // look in camera_pins.h to find the camera type you have
#include "camera_pins.h"                                              // Must include this after setting
#include "esp_camera.h"
#include "FS.h"                // SD Card ESP32
#include "SD_MMC.h"            // SD Card ESP32

#define   FRAME_SIZE                        FRAMESIZE_QVGA            // Frambuffer size (matches resolution below)
#define   WIDTH                             320                       // Resolution Width
#define   HEIGHT                            240                       // Resolution height
#define   BLOCK_SIZE                        4                         // Size of each sensor block on the display (reduced granularity for speed)
#define   W                                 (WIDTH / BLOCK_SIZE)
#define   H                                 (HEIGHT / BLOCK_SIZE)
#define   BLOCK_DIFF_THRESHOLD              1.5
#define   IMAGE_DIFF_THRESHOLD              0.1                       
#define   DEBUG                             0                         // Good for making changes
#define   INFO                              1                         // Good to see whats happening (turn off to save CPU)
#define   VIEWPORT_PIXELS                   WIDTH/BLOCK_SIZE          // 320/4 = 80 Positions to look at in left to right view plane [-------X------] X is where motion exists
#define   STEPS_PER_DEGREE                  6                         // How many degrees per block to turn 11.37
#define   STEPS_PER_SECOND                  4096                      // How fast the stepper turns
#define   ACCELLERATION_STEPS_PER_SECOND    256                       // How quickly the movement accellerates
#define   FLASH_PIN                         4                         // Pin of ESP32 Flash (Led)
#define   FLASH_MODE                        0                         // 0 = 0ff , 1 = flash, 2 = steady


uint16_t prev_frame[H][W] = { 0 };
uint16_t current_frame[H][W] = { 0 };
uint16_t empty_frame[H][W] = { 0 };
long motionView[VIEWPORT_PIXELS];

// stepper
const uint8_t MOTOR_IN1_PIN = 12;
const uint8_t MOTOR_IN2_PIN = 13;
const uint8_t MOTOR_IN3_PIN = 14;
const uint8_t MOTOR_IN4_PIN = 15;
int  moveTo=0;
int currentPos=0;

TinyStepper_28BYJ_48 stepper;

// Scheduler
Scheduler tasks;


void moveSteppers();
Task tmvStepper (250, TASK_FOREVER, &moveSteppers, &tasks, true );

// === 1 =======================================
void moveSteppers() {
  
    // Stepper Movement - Move by steps so we capture more motion frames. 
    if(currentPos>moveTo){
        currentPos-=ceil((currentPos-moveTo)/2);
        if(ceil((currentPos-moveTo)/2)==0) currentPos=moveTo;
    }else if(currentPos<moveTo){
        currentPos+=floor((moveTo-currentPos)/2);
        if(floor((moveTo-currentPos)/2)==0) currentPos=moveTo;
    }else {
      currentPos=moveTo;
    }
#if INFO
    if(currentPos!=moveTo){
        Serial.print("MOVETO: ");   
        Serial.print(moveTo);   
        Serial.print(" CURRENT: ");   
        Serial.println(currentPos);   
    }
#endif
    stepper.moveToPositionInSteps(currentPos);

}

long viewPortToRegion(long mv[]){
  int maxVal=0;
  int region=0;
  int tmpVal=0;
  char str_tmp[9];
  // Fill each char arry with the 8 bits of the 10 regions
  for(int i=0;i<10;i++){
    for(int j=0;j<8;j++){
          str_tmp[j]=(mv[((i*8)+j)]==1) ? '1' : '0';      
        //  Serial.println(((i*8)+j));
    }
#if INFO
    Serial.print("Block: ");
    Serial.print(i);
    Serial.print(" STR=");
    Serial.print(str_tmp);    
    Serial.print(" Value: ");
    tmpVal=readBinaryString(str_tmp);
    Serial.println(tmpVal);
#endif    
    if(tmpVal>maxVal){
      maxVal<=tmpVal; // Set new uppper mark
      region=i; // Which viewport has the most movement. 
    }
  }
  Serial.print("Most activity in block region:");
  Serial.println(region);
  return region;
}

/**
 *
 */
void setup() {
    uint32_t Freq = 0;
    Serial.begin(115200);
    Freq = getCpuFrequencyMhz();
    Serial.print("CPU Freq = ");
    Serial.print(Freq);
    Serial.println(" MHz");
    Freq = getXtalFrequencyMhz();
    Serial.print("XTAL Freq = ");
    Serial.print(Freq);
    Serial.println(" MHz");
    Freq = getApbFrequency();
    Serial.print("APB Freq = ");
    Serial.print(Freq);
    Serial.println(" Hz");
    Serial.println("Begin Setup...");
    for(uint16_t i=0;i<VIEWPORT_PIXELS;i++){
      motionView[i]=0; // Setup Pixel Array
    }
    pinMode (FLASH_PIN, OUTPUT);
//    Serial.println(setup_camera(FRAME_SIZE,    PIXFORMAT_JPEG) ? "OK" : "ERR INIT");
    Serial.println(setup_camera(FRAME_SIZE,PIXFORMAT_GRAYSCALE) ? "OK" : "ERR INIT");

    stepper.connectToPins(MOTOR_IN1_PIN, MOTOR_IN2_PIN, MOTOR_IN3_PIN, MOTOR_IN4_PIN);
    stepper.setSpeedInStepsPerSecond(STEPS_PER_SECOND);
    stepper.setAccelerationInStepsPerSecondPerSecond(ACCELLERATION_STEPS_PER_SECOND);        
    // on startup move the full field of view. 
    stepper.moveToPositionInSteps(0);
    stepper.moveToPositionInSteps(STEPS_PER_DEGREE*10);
    stepper.moveToPositionInSteps(0);
    Serial.println("End Setup...");
    tasks.startNow();
}

/**
 *
 */
void loop() {
    if(FLASH_MODE==2)
      digitalWrite(FLASH_PIN, HIGH);
    if (!capture_still()) {
#if INFO
        Serial.println("Failed capture");
#endif
        return;
    }

    if (motion_detect()) {
#if INFO
        Serial.println("Motion detected");   
#endif
    }
    update_frame();
    
    tasks.execute();
}

/**
 * Capture image and do down-sampling
 */
bool capture_still() {

if(FLASH_MODE==1)
  digitalWrite(FLASH_PIN, HIGH);
camera_fb_t *frame_buffer = esp_camera_fb_get();
if(FLASH_MODE==1)
  digitalWrite(FLASH_PIN, LOW);
    if (!frame_buffer)
        return false;
    // set all 0s in current frame
    memcpy( empty_frame, current_frame, sizeof(empty_frame)); // FAST! Memcopy vs iterations so much faster. 

    // down-sample image in blocks
    for (uint32_t i = 0; i < WIDTH * HEIGHT; i++) {
        const uint16_t x = i % WIDTH;
        const uint16_t y = floor(i / WIDTH);
        const uint8_t block_x = floor(x / BLOCK_SIZE);
        const uint8_t block_y = floor(y / BLOCK_SIZE);
        const uint8_t pixel = frame_buffer->buf[i];
        const uint16_t current = current_frame[block_y][block_x];
        // average pixels in block (accumulate)
        current_frame[block_y][block_x] += pixel;
    }

    // average pixels in block (rescale)
    for (int y = 0; y < H; y++)
        for (int x = 0; x < W; x++)
            current_frame[y][x] /= BLOCK_SIZE * BLOCK_SIZE;

#if DEBUG
    Serial.println("Current frame:");
    print_frame(current_frame);
    Serial.println("---------------");
#endif

    return true;
}

/**
 * Compute the number of different blocks
 * If there are enough, then motion happened
 */
bool motion_detect() { 
    uint16_t changes = 0;
    int lastBlock=0;
    const uint16_t blocks = (WIDTH * HEIGHT) / (BLOCK_SIZE * BLOCK_SIZE);
    for (uint16_t y = 0; y < H; y++) {
        for (uint16_t x = 0; x < W; x++) {
            float current = current_frame[y][x];
            float prev = prev_frame[y][x];
            float delta = abs(current - prev) / prev;

            // Fill only those areas that meet the threashold. 
            if (delta >= BLOCK_DIFF_THRESHOLD) {
#if DEBUG
                Serial.println(delta);
                Serial.print("diff\t");
                Serial.print(y);
                Serial.print('\t');
                Serial.println(x);
#endif 

              motionView[x]=1;
              changes++;
            }
        }
    }
    if(changes==0) return false; // don't need to go any further

    // Change screen data into linear (left to right) expression of data.

    moveTo=((10-viewPortToRegion(motionView))*10)*STEPS_PER_DEGREE;

// Display updates for informational purposes.
#if INFO
    Serial.print(":::");
#endif
    // Clear viewport to zero for next detection phase
    for(uint16_t i=0;i<VIEWPORT_PIXELS;i++){
#if INFO
      Serial.print(motionView[i]);
#endif
       motionView[i]=0;
    }
#if INFO
    Serial.println(":::");
    Serial.print("Changed ");
    Serial.print(changes);
    Serial.print(" out of ");
    Serial.println(blocks);

    Serial.print("MoveTo:");
    Serial.println(moveTo);
#endif
    return (1.0 * changes / blocks) > IMAGE_DIFF_THRESHOLD;
}

/**
 * Copy current frame to previous
 */
void update_frame() {
    memcpy( prev_frame, current_frame, sizeof(prev_frame)); // FAST! Memcopy vs iterations so much faster. 
}

/**
 * For serial debugging
 * @param frame
 */
void print_frame(uint16_t frame[H][W]) {
    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {
            Serial.print(frame[y][x]);
            Serial.print('\t');
        }

        Serial.println();
    }
}

/**
 *  Camera configuration values
 */
bool setup_camera(framesize_t frameSize,pixformat_t PIXEL_FORMAT) {
    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 = PIXEL_FORMAT;
    config.frame_size = frameSize;
    config.jpeg_quality = 12;
    config.fb_count = 1;

    esp_camera_deinit();
    bool ok = esp_camera_init(&config) == ESP_OK;

    sensor_t *sensor = esp_camera_sensor_get();
    sensor->set_framesize(sensor, frameSize);

    return ok;
}
int readBinaryString(char *s) {
  int result = 0;
  while(*s) {
    result <<= 1;
    if(*s++ == '1') result |= 1;
  }
  return result;
}

void captureSnapshotToSD(){
      Serial.println(setup_camera(FRAME_SIZE,    PIXFORMAT_JPEG) ? "OK" : "ERR INIT");
      esp_camera_fb_get();
     Serial.println(setup_camera(FRAME_SIZE,PIXFORMAT_GRAYSCALE) ? "OK" : "ERR INIT");

}

Why run a task scheduler with an ESP32 when the built in OS, freeRTOS, is a task scheduler?

the code is not mine, and im not really knowledgeable in coding.
Would it be ok to remove that #include <TaskScheduler.h>?

If you feel you can, it OK. But the code will need to be re arranged/ re coded to run.

ok :).
but is that somehow related to the failed to capture image, or is this a separate issue?

It could be an issue.

The ESP32 is running a task scheduler running a task scheduler which may be an issue.

My guess would be that the one that doesn't work is designed for a different model camera than the library example that does work. I would compare the library example to the "setup_camera()" function to see if they set different values.

Thanks for the pointer.

the only difference seems to be:

Not working code:
config.pixel_format = PIXEL_FORMAT;
config.frame_size = frameSize;

Working code:
config.pixel_format = PIXFORMAT_JPEG;
config.frame_size = FRAMESIZE_UXGA;

i changed it in the non working code, but still the same failed capture message.

In the not-working code "frameSize" is passed the value FRAME_SIZE which has the value FRAMESIZE_QVGA. The "PIXEL_FORMAT" argument to the function is passed either PIXFORMAT_GRAYSCALE or PIXFORMT_JPEG.

I don't know enough about how the ESP32_CAM works to know if either or both differences are causing the problem. Or if some other part of the code is the problem.

Maybe you can find a different example on which to base your sketch.

1 Like

thanks for helping though as i am not familiar in this at all.

could it have something to do with this part:

void loop() {
    if(FLASH_MODE==2)
      digitalWrite(FLASH_PIN, HIGH);
    if (!capture_still()) {
#if INFO
        Serial.println("Failed capture");

as it writes the pin high? or is this un related.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.