Two ESP32-CAM synchronously streaming to PI4

lukas1000
Posts: 7
Joined: Mon Jul 29, 2019 7:29 pm

Two ESP32-CAM synchronously streaming to PI4

Postby lukas1000 » Mon Jul 29, 2019 7:53 pm

Hi

I would like to stream two pictures captured synchronously by two ESP32-CAM to a Raspberry PI4.

Problems:
a) the two ESP32 blocking each other, the video stream is not stable.
b) Pictures are not taken synchronously.


my approaches:
@a
- reducing the frame rate, I don't need more than 1-2 frames / second
- streaming over two different WIFI channels, but than I would need to add two USB-WIFI-HotSpots to the PI
- external antennas increased the transfer rate, but doesn't improved the stability.

@b
- Idea is to connect both ESP32 with a wire and trigger an interrupt to capture synchronously the picture.
- Adding fb = esp_camera_fb_get() to the interrupt routine causes a watchdog error.
- I don't understand well how the server routine works, so no idea how to get this synchronously to the interrupt.

- Is it possible to stream just 1-2 frames/seconds or does this cause timeouts?
- delay in the main loop reduces the framerate, but is this the correct way?

- is there a way to add a counter to each frame?
Then the PI could check if both frames have the same timestamp.

How could I solve this?

Thanks for all hints and ideas :-)

On the PI I have installed opencv, would like to work with depth maps to control a robot.

I used the code from here:
https://randomnerdtutorials.com/esp32-c ... assistant/
I added a 1Hz output clock on pin4 and a input interrupt on pin12.

User avatar
HermannSW
Posts: 97
Joined: Fri Oct 27, 2017 6:58 am
Location: Eberbach, Germany
Contact:

Re: Two ESP32-CAM synchronously streaming to PI4

Postby HermannSW » Thu Aug 01, 2019 4:40 pm

lukas1000 wrote:
Mon Jul 29, 2019 7:53 pm
- Idea is to connect both ESP32 with a wire and trigger an interrupt to capture synchronously the picture.
- Adding fb = esp_camera_fb_get() to the interrupt routine causes a watchdog error.
- I don't understand well how the server routine works, so no idea how to get this synchronously to the interrupt.
interrupt routines need to be short, and capturing frame takes several 100s of milliseconds, that is too long.
- Is it possible to stream just 1-2 frames/seconds or does this cause timeouts?
800x600 resolution gives 6fps for my ESP32-CAM modules, so should suffice for 2x2fps.
- delay in the main loop reduces the framerate, but is this the correct way?
I don't currently know of a different method to reduce framerate.
Not nice, but if it does what you want, OK.
- is there a way to add a counter to each frame?
CamWebServer "Get Still" button calls esp_camera_fb_get(), so response is a JPEG image.
JPEG images have exif metadata that can be viewed with a exif reader or graphics program.
Click "Get Still" in CamWebServer, right click on frame received, open in new browser tab and store with eg. gimp.
Then use exif viewer to see whether timestamp is set, and what the resolution is.

I added a 1Hz output clock on pin4 and a input interrupt on pin12.
Because of the low framerate you should use 2Hz and actively wait for GPIO signal change on ESP32-CAM (simple loop with small delay), then capture image and wait again.

Because of both ESP32-CAMs triggered by same signal, esp_camera_fb_get() gets executed on both modules at roughly the same time. Execution time of esp_camera_fb_get() is different though, changes in 10% duration range for each call.

VladTheImpaler
Posts: 16
Joined: Fri Jul 05, 2019 4:35 am

Re: Two ESP32-CAM synchronously streaming to PI4

Postby VladTheImpaler » Thu Aug 01, 2019 9:42 pm

Insert a semaphore in "stream_handler" in between

Code: Select all

 while(true)
    {
and

Code: Select all

esp_camera_fb_get();
This will delay grabbing the picture until you sync it.

If you dont know semaphores a

Code: Select all

        while (!newpic) delay(10);
        newpic = false;
will do, you can set

Code: Select all

newpic = true;
in main loop with appropriate timing.

//-------------------------------------

More of a challenge would be to connect 2 cameras to one esp32.

lukas1000
Posts: 7
Joined: Mon Jul 29, 2019 7:29 pm

Re: Two ESP32-CAM synchronously streaming to PI4

Postby lukas1000 » Fri Aug 02, 2019 7:06 am

Hi thanks for your answers.

Yes, I did it like this some days ago and it's working quite good.
I tried to write a comment here, but posting always takes one day for moderator verification.

Without an active stream the timing runns perfect. (see the list below)
With an active stream the timing struggels, I'm not sure if it is stable enouth for the stereo depth maps algorithm.
(I don't have a timing list for active stream here, will post it later, but looks terrible)

Sometimes picture aren't be send withhin the period of the 500ms interrupt.
That causes corrupted pictures. I will test this again with a external wifi antenna and a dedicated router to encrease transfer rate.

Could anyone take a look at my code, is there something I can improve for the timing?

Is there a difference between those two while loops on ESP32?
while(!newpic) {} and while (!newpic) delay(10);
Can the delay be used for different tasks or is this just a counter as on 8Bit Atmegas and it makes no difference?

Both of my ESP32-Cam are getting quite warm. I sticked the camaras on the warm SD-card cage, but one of the camaras already died.
Don't know why, I have an ESD save workplace, power supply should be good enouth.
Today I should get a new one delivered, than I will start to setup the depth maps algorithm.

timing without active stream:

Code: Select all

2:47:52.068 -> rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
22:47:52.068 -> configsip: 0, SPIWP:0xee
22:47:52.068 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
22:47:52.068 -> mode:DIO, clock div:1
22:47:52.068 -> load:0x3fff0018,len:4
22:47:52.068 -> load:0x3fff001c,len:1100
22:47:52.068 -> load:0x40078000,len:10088
22:47:52.068 -> load:0x40080400,len:6380
22:47:52.068 -> entry 0x400806a4
22:47:55.061 -> ....
22:47:56.572 -> WiFi connected
22:47:56.572 -> Camera Stream Ready! Go to: http://192.168.1.166
terminal time ->  tt trigger time|ps picture capture|pc  pucture capture finished|pd end of main loop:
22:47:57.074 -> tt 4769122 | pd 4973231
22:47:57.547 -> tt 5269113 | ps 5269133 | pc 5269155 | pd 5269173
22:47:58.054 -> tt 5769113 | ps 5769157 | pc 5769175 | pd 5769193  <--
22:47:58.560 -> tt 6269114 | ps 6269141 | pc 6269159 | pd 6269177
22:47:59.064 -> tt 6769113 | ps 6769130 | pc 6769148 | pd 6769166
22:47:59.567 -> tt 7269113 | ps 7269130 | pc 7269148 | pd 7269166
22:48:00.071 -> tt 7769113 | ps 7769130 | pc 7769148 | pd 7769166
22:48:00.542 -> tt 8269113 | ps 8269130 | pc 8269148 | pd 8269166
22:48:01.083 -> tt 8769113 | ps 8769130 | pc 8769148 | pd 8769166
22:48:01.554 -> tt 9269113 | ps 9269130 | pc 9269148 | pd 9269166
22:48:02.057 -> tt 9769113 | ps 9769130 | pc 9769148 | pd 9769166
22:48:02.558 -> tt 10269113 | ps 10269131 | pc 10269149 | pd 10269167
22:48:03.062 -> tt 10769113 | ps 10769131 | pc 10769149 | pd 10769167
22:48:03.567 -> tt 11269113 | ps 11269131 | pc 11269149 | pd 11269167
22:48:04.073 -> tt 11769113 | ps 11769131 | pc 11769149 | pd 11769167
22:48:04.545 -> tt 12269113 | ps 12269155 | pc 12269174 | pd 12269192 <--
22:48:05.051 -> tt 12769113 | ps 12769131 | pc 12769149 | pd 12769167
22:48:05.554 -> tt 13269113 | ps 13269131 | pc 13269149 | pd 13269167
22:48:06.058 -> tt 13769113 | ps 13769131 | pc 13769149 | pd 13769167
22:48:06.561 -> tt 14269113 | ps 14269131 | pc 14269149 | pd 14269167
22:48:07.066 -> tt 14769113 | ps 14769131 | pc 14769149 | pd 14769167
22:48:07.576 -> tt 15269113 | ps 15269131 | pc 15269149 | pd 15269167
22:48:08.044 -> tt 15769113 | ps 15769131 | pc 15769149 | pd 15769167
22:48:08.551 -> tt 16269113 | ps 16269131 | pc 16269175 | pd 16269194 <--
22:48:09.055 -> tt 16769113 | ps 16769131 | pc 16769149 | pd 16769167
22:48:09.560 -> tt 17269113 | ps 17269131 | pc 17269149 | pd 17269167
22:48:10.062 -> tt 17769113 | ps 17769131 | pc 17769149 | pd 17769167
22:48:10.562 -> tt 18269113 | ps 18269131 | pc 18269149 | pd 18269167
22:48:11.064 -> tt 18769113 | ps 18769131 | pc 18769149 | pd 18769167
22:48:11.567 -> tt 19269113 | ps 19269131 | pc 19269149 | pd 19269167
22:48:12.071 -> tt 19769113 | ps 19769131 | pc 19769149 | pd 19769167
22:48:12.540 -> tt 20269113 | ps 20269131 | pc 20269149 | pd 20269167
22:48:13.078 -> tt 20769113 | ps 20769131 | pc 20769149 | pd 20769167
22:48:13.550 -> tt 21269113 | ps 21269131 | pc 21269149 | pd 21269167
22:48:14.055 -> tt 21769113 | ps 21769131 | pc 21769149 | pd 21769167
22:48:14.558 -> tt 22269113 | ps 22269131 | pc 22269149 | pd 22269167
22:48:15.061 -> tt 22769113 | ps 22769131 | pc 22769149 | pd 22769167
22:48:15.561 -> tt 23269113 | ps 23269131 | pc 23269149 | pd 23269167
22:48:16.068 -> tt 23769113 | ps 23769131 | pc 23769149 | pd 23769167
22:48:16.536 -> tt 24269113 | ps 24269131 | pc 24269149 | pd 24269167
22:48:17.079 -> tt 24769113 | ps 24769131 | pc 24769149 | pd 24769167
22:48:17.548 -> tt 25269113 | ps 25269131 | pc 25269149 | pd 25269167
22:48:18.056 -> tt 25769113 | ps 25769131 | pc 25769149 | pd 25769167
22:48:18.556 -> tt 26269113 | ps 26269131 | pc 26269149 | pd 26269167

Code: Select all

#include "esp_camera.h"
#include <WiFi.h>
#include "esp_timer.h"
#include "img_converters.h"
#include "Arduino.h"
#include "fb_gfx.h"
#include "soc/soc.h" //disable brownout problems
#include "soc/rtc_cntl_reg.h"  //disable brownout problems
#include "dl_lib.h"
#include "esp_http_server.h"

//Replace with your network credentials
const char* ssid = xx";
const char* password = "xx";

#define PART_BOUNDARY "123456789000000000000987654321"

#define CAMERA_MODEL_AI_THINKER


#if defined(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
#else
#error "Camera model not selected"
#endif

static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";

httpd_handle_t stream_httpd = NULL;
volatile bool i_pic = false;
volatile bool pic_done = false;
uint32_t low;

hw_timer_t * timer0 = NULL;
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len = 0;
uint8_t * _jpg_buf = NULL;
char * part_buf[64];
static esp_err_t stream_handler(httpd_req_t *req) {


  res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
  if (res != ESP_OK) {
    return res;
  }

  while (true) {

    if (true)
    {

      while (!pic_done)
      {

      }
      pic_done = false;
      if (res == ESP_OK) {
        size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
        res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
      }
      if (res == ESP_OK) {
        res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
      }
      if (res == ESP_OK) {
        res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
      }
      if (fb) {
        //esp_camera_fb_return(fb);
        //fb = NULL;
        //_jpg_buf = NULL;
      } else if (_jpg_buf) {
        //free(_jpg_buf);
        //_jpg_buf = NULL;
      }
      if (res != ESP_OK) {
        break;
      }

      Serial.print(" | se ");
      low = esp_timer_get_time() % 0xFFFFFFFF;
      Serial.print(low);
      //Serial.printf("  MJPG: %uB\n", (uint32_t)(_jpg_buf_len));

    }
  }
  return res;
}

void startCameraServer() {
  httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  config.server_port = 80;

  httpd_uri_t index_uri = {
    .uri       = "/",
    .method    = HTTP_GET,
    .handler   = stream_handler,
    .user_ctx  = NULL
  };

  //Serial.printf("Starting web server on port: '%d'\n", config.server_port);
  if (httpd_start(&stream_httpd, &config) == ESP_OK) {
    httpd_register_uri_handler(stream_httpd, &index_uri);
  }
}

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector

  Serial.begin(115200);
  Serial.setDebugOutput(false);

  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;

  if (psramFound()) {
    config.frame_size = FRAMESIZE_UXGA; //UXGA
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

  // 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;
  }
  // Wi-Fi connection
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  Serial.print("Camera Stream Ready! Go to: http://");
  Serial.print(WiFi.localIP());

  // Start streaming web server
  startCameraServer();
  timer0 = timerBegin(0, 80, true);
  timerAttachInterrupt(timer0, &ontimer0, true);
  timerAlarmWrite(timer0, 500000, true);
  timerAlarmEnable(timer0);
}

void loop() {

  while (!i_pic)
  {

  }
  pic_done = false;
  i_pic = false;
  if (fb) {
    Serial.print(" | ps ");
    low = esp_timer_get_time() % 0xFFFFFFFF;
    Serial.print(low);
    esp_camera_fb_return(fb);
    Serial.print(" | pc ");
    low = esp_timer_get_time() % 0xFFFFFFFF;
    Serial.print(low);
    fb = NULL;
    _jpg_buf = NULL;
  } else if (_jpg_buf) {
    free(_jpg_buf);
    _jpg_buf = NULL;
  }
  fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Camera capture failed");
    res = ESP_FAIL;
  } else {
    if (fb->width > 400) {
      if (fb->format != PIXFORMAT_JPEG) {
        bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
        esp_camera_fb_return(fb);
        fb = NULL;
        if (!jpeg_converted) {
          Serial.println("JPEG compression failed");
          res = ESP_FAIL;
        }
      } else {
        _jpg_buf_len = fb->len;
        _jpg_buf = fb->buf;
      }
    }
  }
  Serial.print(" | pd ");
  low = esp_timer_get_time() % 0xFFFFFFFF;
  Serial.print(low);
  pic_done = true;
  //Serial.println("pic!");
}
void ontimer0() {
  Serial.println();
  Serial.print("tt ");
  low = esp_timer_get_time() % 0xFFFFFFFF;
  Serial.print(low);
  i_pic = true;

}
Thanks

Lukas

User avatar
ESP_Me-no-dev
Posts: 77
Joined: Mon Jan 04, 2016 6:30 pm

Re: Two ESP32-CAM synchronously streaming to PI4

Postby ESP_Me-no-dev » Fri Aug 02, 2019 8:08 am

Hi Lucas,

As far as I can understand, you want to collect all frames in the loop and give the latest to the web server. Am I correct?
I will continue based on that assumption :)

You should not use busy loops inside threads, instead you should use one of the FreeRTOS objects that allow for threads to run while you are waiting for something. Such objects are mutexes, semaphores and queues. In the case I will describe, here is how things should go:
0. Create a queue that holds one pointer
1. In the loop() you grab a frame from the camera driver, then you decode that frame to jpeg if necessary
2. if the frame was decoded, then return the frame buffer to the driver
3. Create new object containing pointers to the jpeg data and to the frame buffer (NULL if returned) and the length of the jpeg data
4. If you want to print stats, do that here
5. If the queue has an object pointer already inside, get it out and return the frame buffer or free the jpeg buffer and at the end the pointer to the object
5. Put the new object into the queue
6. Go back to 1

web server thread
1. Instead of waiting for a flag in a loop, you read from the queue (wait while empty) a pointer to the last frame object
2. Send the image
3. Return the frame buffer or free the jpeg buffer and at the end the pointer to the object
4. Go back to 1

VladTheImpaler
Posts: 16
Joined: Fri Jul 05, 2019 4:35 am

Re: Two ESP32-CAM synchronously streaming to PI4

Postby VladTheImpaler » Fri Aug 02, 2019 2:10 pm

Lucas:

Code: Select all

while (!i_pic)
  {

  }

Code: Select all

while (!pic_done)
      {

      }
Thats a big NONO. Busy wait loop. 2 times. Dont. Put a delay in there.In my understanding the delay will allow other tasks o run.

Why do you grab in main loop and send in streamhandler loop? Do the grab in streamhandler too.

btw with 640x480 jpg i get 15K pictures and 80ms per cycle. Seems strange you cant send your pic in 500ms.

Code: Select all

MJPG: 14543B 77ms (13.0fps)
MJPG: 14611B 84ms (11.9fps)
MJPG: 14570B 78ms (12.8fps)

lukas1000
Posts: 7
Joined: Mon Jul 29, 2019 7:29 pm

Re: Two ESP32-CAM synchronously streaming to PI4

Postby lukas1000 » Fri Aug 02, 2019 7:39 pm

Thanks for all your answers, I will read them carfully and try to learn :-)

I the meantime some updates:

My current setup is:
ESP32-Cam_Board1: (master)
Pin 2: output 500ms on/off signal
Pin 14: Input for on/off signal
connected external WIFI antenna (changed jumper R)
connected FTDI Adpater

ESP32-Cam_Board2: (slave)
Pin 2: output 500ms on/off signal (not connected)
Pin 14: Input for on/off signal
connected external WIFI antenna (changed jumper R)

Board1_Pin2 is connected to Board1_Pin14 and Board2_Pin14
-> Goal is, that both boards take a picture at the same time.

I tried to attach an interrupt to Pin2, but I always got a panic (LoadProhibited)
So I added the following line to the server thread:

Code: Select all

while (digitalRead(trigger_in_pin) == pin_toggle_in)  { }
    pin_toggle_in = !pin_toggle_in;
Code is working, but delay is terrible, both received pictures do not match

Timing with only one ESP:
struggles at beginning, but than it runs quite accurate
pc (picture taken) is between ***192 and ***281, don't know if this is accurate enough.

Code: Select all

ets Jun  8 2016 00:22:57
20:47:33.188 -> 
20:47:33.188 -> rst:0x1 (POWERON_RESET),boot:0x1b (SPI_FAST_FLASH_BOOT)
20:47:33.188 -> configsip: 0, SPIWP:0xee
20:47:33.188 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
20:47:33.188 -> mode:DIO, clock div:1
20:47:33.188 -> load:0x3fff0018,len:4
20:47:33.188 -> load:0x3fff001c,len:1100
20:47:33.188 -> load:0x40078000,len:10088
20:47:33.188 -> load:0x40080400,len:6380
20:47:33.188 -> entry 0x400806a4
20:47:36.109 -> ....
20:47:37.618 -> WiFi connected
20:47:37.618 -> Camera Stream Ready! Go to: http://192.168.1.166a
20:47:37.618 -> b
20:47:38.126 -> 
20:47:38.126 -> tt 4701158
20:47:38.630 -> tt 5201154
20:47:39.098 -> tt 5701154
20:47:39.603 -> tt 6201154
20:47:40.111 -> tt 6701154
20:47:40.618 -> tt 7201154
20:47:41.119 -> tt 7701154
20:47:41.619 -> tt 8201154
20:47:42.125 -> tt 8701154
20:47:42.600 -> tt 9201154
20:47:43.109 -> tt 9701154
20:47:43.613 -> tt 10201154
20:47:44.112 -> tt 10701154
20:47:44.612 -> tt 11201154
20:47:45.112 -> tt 11701154
20:47:45.612 -> tt 12201154
20:47:46.113 -> tt 12701154 | pd 13127796
20:47:46.610 -> tt 13201172
20:47:47.108 -> tt 13701154
20:47:47.613 -> tt 14201154
20:47:48.115 -> tt 14701154
20:47:48.619 -> tt 15201154
20:47:49.120 -> tt 15701154 | se 15703006
20:47:49.591 -> tt 16201155 | ps 16201210 | pc 16201281 | pd 16201319 | se 16536059
20:47:50.133 -> tt 16701155 | ps 16701211 | pc 16701283 | pd 16701321
20:47:50.601 -> tt 17201154 | se 17295268 | ps 17295287 | pc 17295312 | pd 17295339
20:47:51.104 -> tt 17701158 | se 17770073 | ps 17770092 | pc 17770110 | pd 17770128 | se 18194480
20:47:51.607 -> tt 18201154 | ps 18201173 | pc 18201192 | pd 18201210
20:47:52.107 -> tt 18701158
20:47:52.612 -> tt 19201154 | se 19553159
20:47:53.115 -> tt 19701154 | ps 19701173 | pc 19701192 | pd 19701210
20:47:53.618 -> tt 20201158 | se 20298224 | ps 20298243 | pc 20298261 | pd 20298280 | se 20608384
20:47:54.118 -> tt 20701155 | ps 20701212 | pc 20701282 | pd 20701320 | se 21058077
20:47:54.624 -> tt 21201155 | ps 21201211 | pc 21201281 | pd 21201319
20:47:55.128 -> tt 21701154 | se 21916275 | ps 21916348 | pc 21916379 | pd 21916418
20:47:55.597 -> tt 22201154 | se 22601985 | ps 22602003 | pc 22602022 | pd 22602040
20:47:56.135 -> tt 22701158
20:47:56.604 -> tt 23201154 | se 23235166
20:47:57.103 -> tt 23701155 | ps 23701211 | pc 23701281 | pd 23701319
20:47:57.606 -> tt 24201154 | se 24643718 | ps 24643737 | pc 24643755 | pd 24643778
20:47:58.106 -> tt 24701158 | se 25063657 | ps 25063676 | pc 25063694 | pd 25063712
20:47:58.607 -> tt 25201164 | se 25605617 | ps 25605636 | pc 25605654 | pd 25605673
20:47:59.109 -> tt 25701158 | se 26063450 | ps 26063518 | pc 26063550 | pd 26063588
20:47:59.613 -> tt 26201154 | se 26455889 | ps 26455907 | pc 26455926 | pd 26455944
20:48:00.118 -> tt 26701158 | se 26924327 | ps 26924345 | pc 26924364 | pd 26924382
20:48:00.683 -> tt 27201162 | se 27372388 | ps 27372407 | pc 27372425 | pd 27372444
20:48:01.117 -> tt 27701158 | se 27745281 | ps 27745300 | pc 27745318 | pd 27745336 | se 28088722
20:48:01.620 -> tt 28201154 | ps 28201174 | pc 28201192 | pd 28201210
20:48:02.125 -> tt 28701158 | se 28919327 | ps 28919398 | pc 28919430 | pd 28919468
20:48:02.627 -> tt 29201154 | se 29260012 | ps 29260031 | pc 29260049 | pd 29260068
20:48:03.126 -> tt 29701158 | se 29824112 | ps 29824130 | pc 29824149 | pd 29824167
20:48:03.593 -> tt 30201158 | se 30233957 | ps 30233986 | pc 30234004 | pd 30234023
20:48:04.131 -> tt 30701158 | se 31059424 | ps 31059443 | pc 31059461 | pd 31059480
20:48:04.604 -> tt 31201158
20:48:05.110 -> tt 31701154 | se 31798560
20:48:05.615 -> tt 32201155 | ps 32201208 | pc 32201276 | pd 32201315 | se 32515782
20:48:06.115 -> tt 32701155 | ps 32701211 | pc 32701283 | pd 32701321 | se 33038717
20:48:06.620 -> tt 33201155 | ps 33201211 | pc 33201281 | pd 33201319
20:48:07.122 -> tt 33701154 | se 33841245 | ps 33841263 | pc 33841282 | pd 33841300
20:48:07.592 -> tt 34201158 | se 34542489 | ps 34542508 | pc 34542526 | pd 34542544
20:48:08.128 -> tt 34701158 | se 34846038 | ps 34846057 | pc 34846075 | pd 34846093
20:48:08.629 -> tt 35201158 | se 35318750 | ps 35318769 | pc 35318791 | pd 35318810 | se 35601899
20:48:09.102 -> tt 35701157 | ps 35701178 | pc 35701197 | pd 35701215 | se 36160949
20:48:09.604 -> tt 36201154 | ps 36201173 | pc 36201192 | pd 36201210 | se 36527453
20:48:10.135 -> tt 36701155 | ps 36701212 | pc 36701282 | pd 36701321 | se 37057160
20:48:10.607 -> tt 37201154 | ps 37201210 | pc 37201281 | pd 37201319 | se 37527759
20:48:11.110 -> tt 37701155 | ps 37701211 | pc 37701286 | pd 37701325 | se 37942758
20:48:11.611 -> tt 38201154 | ps 38201174 | pc 38201192 | pd 38201210 | se 38540239
20:48:12.110 -> tt 38701155 | ps 38701214 | pc 38701293 | pd 38701331 | se 38935499
20:48:12.615 -> tt 39201155 | ps 39201211 | pc 39201283 | pd 39201321 | se 39549983
20:48:13.118 -> tt 39701154 | ps 39701174 | pc 39701192 | pd 39701210 | se 40109853
20:48:13.621 -> tt 40201154 | ps 40201173 | pc 40201192 | pd 40201210 | se 40617563
20:48:14.119 -> tt 40701154 | ps 40701173 | pc 40701192 | pd 40701210 | se 40949433
20:48:14.620 -> tt 41201154 | ps 41201173 | pc 41201192 | pd 41201210 | se 41625085
20:48:15.126 -> tt 41701155 | ps 41701211 | pc 41701281 | pd 41701319 | se 41947639
20:48:15.596 -> tt 42201154 | ps 42201174 | pc 42201192 | pd 42201210 | se 42476039
20:48:16.103 -> tt 42701154 | ps 42701174 | pc 42701192 | pd 42701210 | se 42981356
20:48:16.604 -> tt 43201155 | ps 43201211 | pc 43201281 | pd 43201319 | se 43448524
20:48:17.109 -> tt 43701155 | ps 43701213 | pc 43701285 | pd 43701325 | se 43937224
20:48:17.613 -> tt 44201154 | ps 44201174 | pc 44201192 | pd 44201210 | se 44551234
20:48:18.113 -> tt 44701155 | ps 44701211 | pc 44701281 | pd 44701319 | se 44981864
20:48:18.612 -> tt 45201155 | ps 45201213 | pc 45201285 | pd 45201323 | se 45452893
20:48:19.113 -> tt 45701155 | ps 45701211 | pc 45701283 | pd 45701321 | se 45978720
20:48:19.614 -> tt 46201155 | ps 46201211 | pc 46201281 | pd 46201319 | se 46496186
20:48:20.114 -> tt 46701155 | ps 46701211 | pc 46701281 | pd 46701319 | se 46941761
20:48:20.618 -> tt 47201155 | ps 47201211 | pc 47201281 | pd 47201319 | se 47578445
20:48:21.122 -> tt 47701154 | ps 47701174 | pc 47701192 | pd 47701210 | se 48040545
20:48:21.592 -> tt 48201154 | ps 48201173 | pc 48201192 | pd 48201210 | se 48558969
20:48:22.129 -> tt 48701158 | ps 48701178 | pc 48701196 | pd 48701215 | se 49085881
20:48:22.599 -> tt 49201154 | ps 49201173 | pc 49201192 | pd 49201210 | se 49629599
20:48:23.103 -> tt 49701154 | ps 49701173 | pc 49701192 | pd 49701210 | se 50000865
20:48:23.607 -> tt 50201155 | ps 50201211 | pc 50201281 | pd 50201319 | se 50460546
20:48:24.107 -> tt 50701153 | ps 50701209 | pc 50701280 | pd 50701318 | se 51024843
20:48:24.612 -> tt 51201153 | ps 51201173 | pc 51201191 | pd 51201209 | se 51537020
20:48:25.112 -> tt 51701158 | ps 51701209 | pc 51701268 | pd 51701307 | se 52077294
20:48:25.622 -> tt 52201153 | ps 52201173 | pc 52201191 | pd 52201209 | se 52578533
20:48:26.130 -> tt 52701153 | ps 52701209 | pc 52701280 | pd 52701318 | se 53076743
20:48:26.603 -> tt 53201152 | ps 53201172 | pc 53201191 | pd 53201209 | se 53587590
20:48:27.104 -> tt 53701152 | ps 53701172 | pc 53701191 | pd 53701209 | se 53976094
20:48:27.607 -> tt 54201153 | ps 54201209 | pc 54201280 | pd 54201320 | se 54487047
20:48:28.114 -> tt 54701152 | ps 54701172 | pc 54701191 | pd 54701209 | se 55056499
20:48:28.617 -> tt 55201157 | ps 55201193 | pc 55201211 | pd 55201229 | se 55535478
20:48:29.118 -> tt 55701153 | ps 55701209 | pc 55701282 | pd 55701320 | se 55905039
20:48:29.620 -> tt 56201156 | ps 56201218 | pc 56201291 | pd 56201331 | se 56576375
20:48:30.120 -> tt 56701153 | ps 56701209 | pc 56701280 | pd 56701318 | se 56943346
20:48:30.626 -> tt 57201153 | ps 57201173 | pc 57201191 | pd 57201209 | se 57572715
20:48:31.098 -> tt 57701152 | ps 57701172 | pc 57701191 | pd 57701209 | se 58096635

Timing with both ESP active:
You can see, that timing of the server routine se is printed directly after trigger, looks like it is ~500ms delayed.

Code: Select all

20:59:30.072 -> tt 11755165
20:59:30.574 -> tt 12255165
20:59:31.076 -> tt 12755165
20:59:31.581 -> tt 13255165
20:59:32.079 -> tt 13755180 | pd 13928319
20:59:32.583 -> tt 14255167 | se 14563217 | ps 14563238 | pc 14563263 | pd 14563291 | se 14654807 | ps 14702941 | pc 14703012 | pd 14736270
20:59:33.084 -> tt 14755165 | se 14851103 | ps 15202899 | pc 15202917 | pd 15202935
20:59:33.587 -> tt 15255172 | se 15304066 | ps 15702935 | pc 15703008 | pd 15703049
20:59:34.089 -> tt 15755168 | se 15805884 | ps 16202937 | pc 16203013 | pd 16203053
20:59:34.589 -> tt 16255165 | se 16290817 | ps 16702889 | pc 16702907 | pd 16702926
20:59:35.088 -> tt 16755170 | se 16794487 | ps 17202887 | pc 17202906 | pd 17202924
20:59:35.593 -> tt 17255172 | se 17301098 | ps 17702926 | pc 17703001 | pd 17703040
20:59:36.063 -> tt 17755167 | se 17844896 | ps 18202879 | pc 18202898 | pd 18202916
20:59:36.560 -> tt 18255172 | se 18380561 | ps 18702921 | pc 18702996 | pd 18703035
20:59:37.101 -> tt 18755167 | se 18886039 | ps 19202878 | pc 19202896 | pd 19202914
20:59:37.568 -> tt 19255173 | se 19384545 | ps 19702910 | pc 19702983 | pd 19703022
20:59:38.067 -> tt 19755167 | se 19880184 | ps 20202913 | pc 20202992 | pd 20203033
20:59:38.570 -> tt 20255165 | se 20287538 | ps 20702863 | pc 20702881 | pd 20702900
20:59:39.072 -> tt 20755169 | se 20790233 | ps 21202913 | pc 21202992 | pd 21203033
20:59:39.575 -> tt 21255167 | se 21294388 | ps 21702899 | pc 21702976 | pd 21703021
20:59:40.079 -> tt 21755165 | se 21801682 | ps 22202854 | pc 22202872 | pd 22202890
20:59:40.582 -> tt 22255172 | se 22300583 | ps 22702891 | pc 22702965 | pd 22703005
20:59:41.081 -> tt 22755165 | se 22800160 | ps 23202891 | pc 23202966 | pd 23203008
20:59:41.580 -> tt 23255166 | se 23298388 | ps 23702914 | pc 23703030 | pd 23703086
20:59:42.084 -> tt 23755165 | se 23793842 | ps 24202883 | pc 24202959 | pd 24203000
20:59:42.589 -> tt 24255168 | se 24302013 | ps 24702838 | pc 24702856 | pd 24702874
20:59:43.096 -> tt 24755169 | se 24797716 | ps 25202876 | pc 25202946 | pd 25202989
20:59:43.567 -> tt 25255165 | se 25333917 | ps 25702875 | pc 25702951 | pd 25702992
20:59:44.071 -> tt 25755165 | se 25862551 | ps 26202828 | pc 26202846 | pd 26202865
20:59:44.576 -> tt 26255171 | se 26412536 | ps 26702865 | pc 26702938 | pd 26702980
20:59:45.079 -> tt 26755165 | se 26905678 | ps 27202862 | pc 27202932 | pd 27202971
20:59:45.581 -> tt 27255165 | se 27396961 | ps 27702891 | pc 27703010 | pd 27703066
20:59:46.080 -> tt 27755166 | se 27878512 | ps 28202861 | pc 28202938 | pd 28202980
20:59:46.582 -> tt 28255165 | se 28286290 | ps 28702854 | pc 28702930 | pd 28702971
20:59:47.079 -> tt 28755165 | se 28783443 | ps 29202853 | pc 29202937 | pd 29202982
20:59:47.584 -> tt 29255165 | se 29289408 | ps 29702847 | pc 29702924 | pd 29702964
20:59:48.092 -> tt 29755166 | se 29797051 | ps 30202802 | pc 30202820 | pd 30202839
20:59:48.565 -> tt 30255170 | se 30297965 | ps 30702841 | pc 30702913 | pd 30702951
20:59:49.098 -> tt 30755166 | se 30798257 | ps 31202796 | pc 31202814 | pd 31202833
20:59:49.568 -> tt 31255172 | se 31288826 | ps 31702864 | pc 31702981 | pd 31703042
20:59:50.072 -> tt 31755165 | se 31795681 | ps 32202831 | pc 32202908 | pd 32202948
20:59:50.572 -> tt 32255165 | se 32292408 | ps 32702830 | pc 32702904 | pd 32702942
20:59:51.074 -> tt 32755165 | se 32787911 | ps 33202783 | pc 33202801 | pd 33202820
20:59:51.575 -> tt 33255173 | se 33290345 | ps 33702781 | pc 33702800 | pd 33702818
20:59:52.073 -> tt 33755171 | se 33799841 | ps 34202782 | pc 34202800 | pd 34202818
20:59:52.571 -> tt 34255169 | se 34316207 | ps 34702818 | pc 34702890 | pd 34702928
20:59:53.073 -> tt 34755165 | se 34824995 | ps 35202817 | pc 35202889 | pd 35202930
20:59:53.576 -> tt 35255165 | se 35336020 | ps 35702767 | pc 35702787 | pd 35702806
20:59:54.075 -> tt 35755172 | se 35801241 | ps 36202815 | pc 36202891 | pd 36202931
20:59:54.578 -> tt 36255165 | se 36314716 | ps 36702808 | pc 36702886 | pd 36702926
20:59:55.078 -> tt 36755167 | se 36821669 | ps 37202799 | pc 37202878 | pd 37202918
20:59:55.585 -> tt 37255166 | se 37328601 | ps 37702758 | pc 37702782 | pd 37702801
20:59:56.086 -> tt 37755171 | se 37840446 | ps 38202758 | pc 38202778 | pd 38202797
20:59:56.558 -> tt 38255169 | se 38341147 | ps 38702752 | pc 38702771 | pd 38702791
20:59:57.095 -> tt 38755171 | se 38807446 | ps 39202744 | pc 39202763 | pd 39202788
20:59:57.597 -> tt 39255172 | se 39330338 | ps 39702741 | pc 39702759 | pd 39702782
20:59:58.064 -> tt 39755172 | se 39811314 | ps 40202837 | pc 40202913 | pd 40202954
20:59:58.564 -> tt 40255165 | se 40335772 | ps 40702739 | pc 40702757 | pd 40702777
20:59:59.100 -> tt 40755171 | se 40810687 | ps 41202741 | pc 41202760 | pd 41202782
20:59:59.571 -> tt 41255173 | se 41352240 | ps 41702733 | pc 41702751 | pd 41702772
21:00:00.074 -> tt 41755169 | se 41802066 | ps 42202725 | pc 42202743 | pd 42202762
21:00:00.581 -> tt 42255173 | se 42332156 | ps 42702723 | pc 42702742 | pd 42702760
21:00:01.081 -> tt 42755169 | se 42835222 | ps 43202758 | pc 43202889 | pd 43202931
21:00:01.581 -> tt 43255165 | se 43329169 | ps 43702738 | pc 43702756 | pd 43702777
21:00:02.081 -> tt 43755169 | se 43819667 | ps 44202759 | pc 44202886 | pd 44202927
21:00:02.580 -> tt 44255165 | se 44325933 | ps 44702756 | pc 44702839 | pd 44702879
21:00:03.081 -> tt 44755165 | se 44800700 | ps 45202752 | pc 45202830 | pd 45202869
21:00:03.583 -> tt 45255167 | se 45330316 | ps 45702747 | pc 45702826 | pd 45702866
21:00:04.088 -> tt 45755165 | se 45817833 | ps 46202741 | pc 46202817 | pd 46202858
21:00:04.591 -> tt 46255165 | se 46316351 | ps 46702738 | pc 46702814 | pd 46702853
21:00:05.097 -> tt 46755167 | se 46816611 | ps 47202719 | pc 47202737 | pd 47202755
21:00:05.568 -> tt 47255169 | se 47354503 | ps 47702694 | pc 47702712 | pd 47702731
21:00:06.069 -> tt 47755169 | se 47826374 | ps 48202728 | pc 48202807 | pd 48202848
21:00:06.573 -> tt 48255165 | se 48325709 | ps 48702683 | pc 48702701 | pd 48702720
21:00:07.078 -> tt 48755169 | se 48812898 | ps 49202718 | pc 49202807 | pd 49202848
21:00:07.578 -> tt 49255165 | se 49318084 | ps 49702681 | pc 49702699 | pd 49702718
21:00:08.079 -> tt 49755170 | se 49857605 | ps 50202673 | pc 50202692 | pd 50202710
21:00:08.578 -> tt 50255172 | se 50387991 | ps 50702701 | pc 50702759 | pd 50702804
21:00:09.081 -> tt 50755163 | se 50999787 | ps 51202702 | pc 51202778 | pd 51202818
21:00:09.586 -> tt 51255163 | se 51481676 | ps 51702663 | pc 51702681 | pd 51702699
21:00:10.088 -> tt 51755168 | se 51905158 | ps 52202707 | pc 52202787 | pd 52202827
21:00:10.559 -> tt 52255163 | se 52428234 | ps 52702694 | pc 52702773 | pd 52702813
21:00:11.098 -> tt 52755163 | se 52951617 | ps 53202689 | pc 53202759 | pd 53202804
21:00:11.597 -> tt 53255163 | se 53390871 | ps 53702650 | pc 53702668 | pd 53702686
21:00:12.064 -> tt 53755171 | se 53797474 | ps 54202646 | pc 54202665 | pd 54202710


Attached you can find my latest code.

Code: Select all

#include "esp_camera.h"
#include <WiFi.h>
#include "esp_timer.h"
#include "img_converters.h"
#include "Arduino.h"
#include "fb_gfx.h"
#include "soc/soc.h" //disable brownout problems
#include "soc/rtc_cntl_reg.h"  //disable brownout problems
#include "dl_lib.h"
#include "esp_http_server.h"

//Replace with your network credentials
const char* ssid = "xx";
const char* password = "xx";

#define PART_BOUNDARY "123456789000000000000987654321"


#define CAMERA_MODEL_AI_THINKER


#if defined(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
#else
#error "Camera model not selected"
#endif

static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";

httpd_handle_t stream_httpd = NULL;
volatile bool pic = false;
volatile bool pic_done = false;
uint32_t low;
boolean pin_toggle_out = false;
boolean pin_toggle_in = false;
const int trigger_out_pin = 2;
const int trigger_in_pin = 14;

hw_timer_t * timer0 = NULL;
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len = 0;
uint8_t * _jpg_buf = NULL;
char * part_buf[64];


static esp_err_t stream_handler(httpd_req_t *req) {


  res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
  if (res != ESP_OK) {
    return res;
  }

  while (true) {

    /* while (!pic)
      {

      }
    */
    while (digitalRead(trigger_in_pin) == pin_toggle_in)
    {

    }
    pin_toggle_in = !pin_toggle_in;
    //pic = false;
    if (fb) {
      Serial.print(" | ps ");
      low = esp_timer_get_time() % 0xFFFFFFFF;
      Serial.print(low);
      esp_camera_fb_return(fb);
      Serial.print(" | pc ");
      low = esp_timer_get_time() % 0xFFFFFFFF;
      Serial.print(low);
      fb = NULL;
      _jpg_buf = NULL;
    } else if (_jpg_buf) {
      free(_jpg_buf);
      _jpg_buf = NULL;
    }
    fb = esp_camera_fb_get();
    if (!fb) {
      Serial.println("Camera capture failed");
      res = ESP_FAIL;
    } else {
      if (fb->width > 400) {
        if (fb->format != PIXFORMAT_JPEG) {
          bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
          esp_camera_fb_return(fb);
          fb = NULL;
          if (!jpeg_converted) {
            Serial.println("JPEG compression failed");
            res = ESP_FAIL;
          }
        } else {
          _jpg_buf_len = fb->len;
          _jpg_buf = fb->buf;
        }
      }
    }
    Serial.print(" | pd ");
    low = esp_timer_get_time() % 0xFFFFFFFF;
    Serial.print(low);
    pic_done = true;
    //Serial.println("pic!");

    if (res == ESP_OK) {
      size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
      res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
    }
    if (res == ESP_OK) {
      res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
    }
    if (res == ESP_OK) {
      res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
    }
    if (fb) {
      //esp_camera_fb_return(fb);
      //fb = NULL;
      //_jpg_buf = NULL;
    } else if (_jpg_buf) {
      //free(_jpg_buf);
      //_jpg_buf = NULL;
    }
    if (res != ESP_OK) {
      break;
    }

    Serial.print(" | se ");
    low = esp_timer_get_time() % 0xFFFFFFFF;
    Serial.print(low);
    //Serial.printf("  MJPG: %uB\n", (uint32_t)(_jpg_buf_len));

  }

  return res;
}

void startCameraServer() {
  httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  config.server_port = 80;

  httpd_uri_t index_uri = {
    .uri       = "/",
    .method    = HTTP_GET,
    .handler   = stream_handler,
    .user_ctx  = NULL
  };

  //Serial.printf("Starting web server on port: '%d'\n", config.server_port);
  if (httpd_start(&stream_httpd, &config) == ESP_OK) {
    httpd_register_uri_handler(stream_httpd, &index_uri);
  }
}

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector

  Serial.begin(115200);
  Serial.setDebugOutput(false);

  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;

  if (psramFound()) {
    config.frame_size = FRAMESIZE_UXGA; //UXGA
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

  // 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;
  }
  // Wi-Fi connection
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  Serial.print("Camera Stream Ready! Go to: http://");
  Serial.print(WiFi.localIP());

  // Start streaming web server
  startCameraServer();
  pinMode(trigger_out_pin, OUTPUT);
  pinMode(trigger_in_pin, INPUT);
  Serial.println("a");
  //attachInterrupt(digitalPinToInterrupt(14), triggerin2, CHANGE); //DOes not work
  Serial.println("b");
  timer0 = timerBegin(0, 80, true);
  timerAttachInterrupt(timer0, &ontimer0, true);
  timerAlarmWrite(timer0, 500000, true);
  timerAlarmEnable(timer0);
}

void loop() {

  delay(1);
}
void triggerin()
{
  //Interrupt does not work!
  Serial.println();
  Serial.print("ti ");
  low = esp_timer_get_time() % 0xFFFFFFFF;
  Serial.print(low);
  pic = true;
}
void ontimer0() {
   Serial.println();
  Serial.print("tt ");
  low = esp_timer_get_time() % 0xFFFFFFFF;
  Serial.print(low);
  if (pin_toggle_out) {
    pin_toggle_out = false;
  } else {
    pin_toggle_out = true;
  }
  digitalWrite(trigger_out_pin, pin_toggle_out);
}
Attachments
ESP32_cam1.jpg
ESP32_cam1.jpg (386.99 KiB) Viewed 12470 times

lukas1000
Posts: 7
Joined: Mon Jul 29, 2019 7:29 pm

Re: Two ESP32-CAM synchronously streaming to PI4

Postby lukas1000 » Fri Aug 02, 2019 7:47 pm

Hihi, my wife stopped watching netflix.
WIFI camera delay is now much better :-)
But still a lot of things to improve.

Attached my first synchronously taken pictures with opencv edge detection script on the RP4.
But still 0.1 seconds delay between the pictures.
Attachments
52.6_53.0.jpg
52.6_53.0.jpg (46.11 KiB) Viewed 12464 times
51,4.jpg
51,4.jpg (43.66 KiB) Viewed 12464 times

VladTheImpaler
Posts: 16
Joined: Fri Jul 05, 2019 4:35 am

Re: Two ESP32-CAM synchronously streaming to PI4

Postby VladTheImpaler » Sat Aug 03, 2019 3:07 pm

People tell you busyloops are bad but you do busyloops anyway.

Mod edit: Nixed non-relevant image.

lukas1000
Posts: 7
Joined: Mon Jul 29, 2019 7:29 pm

Re: Two ESP32-CAM synchronously streaming to PI4

Postby lukas1000 » Sat Aug 03, 2019 5:23 pm

@Mr VladTheImpaler Super Brain: is posting such trash the reason why you are registered here?
If you are not interested on others projects I would recommend to find a different hobby.
And sorry I'm not from Germany, you have to find a new picture.

People above mentioned a lot of methods how to improve my project, thanks to all of you.
Unfortunately my day has only 24h and I haven't enough time since yesterday to learn all of this methods, but I will.
I just thought it would be nice to post some of my project achievements here for people who are interested on such things.

Adding a delay of 1ms to the loop will definitely add an additional inaccuracy of 1ms between trigger and capture.
The most important task in this project is to capture both pictures as simultaneously as possible.
My first solution without active WIFI had an divergence of less then 0.01ms. So looks like it should be possible.
Further the ESP32 has two cores, so why is it terrible to block one of this cores for the most important task?

Mr Super Brain, could you please tell me your solution how to improve the time accuracy for capturing both pictures simultaneously?

Next idea would be to add a 3rd camera in a wider distance. Then it should be possible to measure near range with the first 2 cameras and higher ranges with the 3rd one.

Thanks

Lukas

Who is online

Users browsing this forum: No registered users and 49 guests