ESP32 + Arducam

Hallo leute,

auf GitHub habe ich ein Code für ESP32 mit arducam bereitgestellt von "brunohorta82" gefunden.
Link zum originalen Code: GitHub - brunohorta82/ESP32_ARDUCAM: Projeto com ESP32 e ARDUCAM MINI 2 MP. Ligação ao Wi-Fi é feita com WifiManager utilizando um Captive portal e permite depois visualizar video directamente da câmera ou tirar fotos

Ich habe das selbe genommen allerdings mit dem Unterschied, dass ich das ESP32 als Access Point benutzen will.

Das Problem ist bei Video Streaming, dass es nur für ein paar Sekunden bis max 7 min funktioniert und dann nicht mehr. ESP32 ist immer noch als Access Point verfügbar man kann mit dem kommunizieren aber kein Video Streaming.

vielen Dank im voraus

#include <HTTP_Method.h>
#include <WebServer.h>
#include <Wire.h>
#include <SPI.h>
#include <WiFi.h>

#include <ArduCAM.h>
const int CS = 16;

const char* ssid     = "ESP32-Access-Point";
const char* password = "123456789";


WebServer server(80);
//SSD1306  display(0x3c, 5, 4);
ArduCAM myCAM(OV2640, CS);

static const size_t bufferSize = 4096;
static uint8_t buffer[bufferSize] = {0xFF};
uint8_t temp = 0, temp_last = 0;
int i = 0;
bool is_header = false;

int resolution = 3;
// resolutions:
// 0 = 160x120
// 1 = 176x144
// 2 = 320x240
// 3 = 352x288
// 4 = 640x480
// 5 = 800x600
// 6 = 1024x768
// 7 = 1280x1024
// 8 = 1600x1200



void start_capture() {
  myCAM.clear_fifo_flag();
  myCAM.start_capture();
}

void camCapture(ArduCAM myCAM) {
  WiFiClient client = server.client();
  uint32_t len  = myCAM.read_fifo_length();
  if (len >= MAX_FIFO_SIZE) //8M
  {
    Serial.println(F("Over size."));
  }
  if (len == 0 ) //0 kb
  {
    Serial.println(F("Size is 0."));
  }
  myCAM.CS_LOW();
  myCAM.set_fifo_burst();
  if (!client.connected()) return;
  String response = "HTTP/1.1 200 OK\r\n";
  response += "Content-Type: image/jpeg\r\n";
  response += "Content-len: " + String(len) + "\r\n\r\n";
  server.sendContent(response);
  i = 0;
  while ( len-- )
  {
    temp_last = temp;
    temp =  SPI.transfer(0x00);
    //Read JPEG data from FIFO
    if ( (temp == 0xD9) && (temp_last == 0xFF) ) //If find the end ,break while,
    {
      buffer[i++] = temp;  //save the last  0XD9
      //Write the remain bytes in the buffer
      if (!client.connected()) break;
      client.write(&buffer[0], i);
      is_header = false;
      i = 0;
      myCAM.CS_HIGH();
      break;
    }
    if (is_header == true)
    {
      //Write image data to buffer if not full
      if (i < bufferSize)
        buffer[i++] = temp;
      else
      {
        //Write bufferSize bytes image data to file
        if (!client.connected()) break;
        client.write(&buffer[0], bufferSize);
        i = 0;
        buffer[i++] = temp;
      }
    }
    else if ((temp == 0xD8) & (temp_last == 0xFF))
    {
      is_header = true;
      buffer[i++] = temp_last;
      buffer[i++] = temp;
    }
  }
}

void serverCapture() {
  delay(1000);
  start_capture();
  Serial.println(F("CAM Capturing"));

  int total_time = 0;

  total_time = millis();
  while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));
  total_time = millis() - total_time;
  Serial.print(F("capture total_time used (in miliseconds):"));
  Serial.println(total_time, DEC);

  total_time = 0;

  Serial.println(F("CAM Capture Done."));
  total_time = millis();
  camCapture(myCAM);
  total_time = millis() - total_time;
  Serial.print(F("send total_time used (in miliseconds):"));
  Serial.println(total_time, DEC);
  Serial.println(F("CAM send Done."));
}

void serverStream() {
  WiFiClient client = server.client();

  String response = "HTTP/1.1 200 OK\r\n";
  response += "Content-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n";
  server.sendContent(response);

  while (1) {
    start_capture();
    while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));
    size_t len = myCAM.read_fifo_length();
    if (len >= MAX_FIFO_SIZE) //8M
    {
      Serial.println(F("Over size."));
      continue;
    }
    if (len == 0 ) //0 kb
    {
      Serial.println(F("Size is 0."));
      continue;
    }
    myCAM.CS_LOW();
    myCAM.set_fifo_burst();
    if (!client.connected()) break;
    response = "--frame\r\n";
    response += "Content-Type: image/jpeg\r\n\r\n";
    server.sendContent(response);
    while ( len-- )
    {
      temp_last = temp;
      temp =  SPI.transfer(0x00);

      //Read JPEG data from FIFO
      if ( (temp == 0xD9) && (temp_last == 0xFF) ) //If find the end ,break while,
      {
        buffer[i++] = temp;  //save the last  0XD9
        //Write the remain bytes in the buffer
        myCAM.CS_HIGH();;
        if (!client.connected()) break;
        client.write(&buffer[0], i);
        is_header = false;
        i = 0;
      }
      if (is_header == true)
      {
        //Write image data to buffer if not full
        if (i < bufferSize)
          buffer[i++] = temp;
        else
        {
          //Write bufferSize bytes image data to file
          myCAM.CS_HIGH();
          if (!client.connected()) break;
          client.write(&buffer[0], bufferSize);
          i = 0;
          buffer[i++] = temp;
          myCAM.CS_LOW();
          myCAM.set_fifo_burst();
        }
      }
      else if ((temp == 0xD8) & (temp_last == 0xFF))
      {
        is_header = true;
        buffer[i++] = temp_last;
        buffer[i++] = temp;
      }
    }
    if (!client.connected()) break;
  }
}

void handleNotFound() {
  String message = "Server is running!\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  server.send(200, "text/plain", message);
}



///////////////////////////////////////////////////////
void setCamResolution(int reso)
{
  switch (reso)
  {
    case 0:
      myCAM.OV2640_set_JPEG_size(OV2640_160x120);
      break;

    case 1:
      myCAM.OV2640_set_JPEG_size(OV2640_176x144);
      break;

    case 2:
      myCAM.OV2640_set_JPEG_size(OV2640_320x240);
      break;

    case 3:
      myCAM.OV2640_set_JPEG_size(OV2640_352x288);
      break;

    case 4:
      myCAM.OV2640_set_JPEG_size(OV2640_640x480);
      break;

    case 5:
      myCAM.OV2640_set_JPEG_size(OV2640_800x600);
      break;

    case 6:
      myCAM.OV2640_set_JPEG_size(OV2640_1024x768);
      break;

    case 7:
      myCAM.OV2640_set_JPEG_size(OV2640_1280x1024);
      break;

    case 8:
      myCAM.OV2640_set_JPEG_size(OV2640_1600x1200);
      break;

  }
}

void comTest(){
  Serial.println("esp32 ist still connected");
}
void setup() {
  uint8_t vid, pid;
  uint8_t temp;
  pinMode(CS, OUTPUT);

  //I2C START SDA, SCL
  Wire.begin(4, 5);
  //display.init();
  //display.flipScreenVertically();
  //display.setFont(ArialMT_Plain_10);
  Serial.begin(115200);

  // initialize SPI: SCK, MISO, MOSI, SS
  SPI.begin(14, 0, 13, 16);
  SPI.setFrequency(4000000); //4MHz

  //Check if the ArduCAM SPI bus is OK
  myCAM.write_reg(ARDUCHIP_TEST1, 0x55);
  temp = myCAM.read_reg(ARDUCHIP_TEST1);
  if (temp != 0x55) {
    Serial.println(F("SPI1 interface Error!"));
    while (1);
  }

  //Check if the camera module type is OV2640
  myCAM.wrSensorReg8_8(0xff, 0x01);
  myCAM.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid);
  myCAM.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid);
  if ((vid != 0x26 ) && (( pid != 0x41 ) || ( pid != 0x42 )))
    Serial.println(F("Can't find OV2640 module!"));
  else
    Serial.println(F("OV2640 detected."));


  //Change to JPEG capture mode and initialize the OV2640 module
  myCAM.set_format(JPEG);
  myCAM.InitCAM();

  setCamResolution(resolution);
  myCAM.clear_fifo_flag();

  WiFi.softAP(ssid, password);
  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);

  // Start the server
  server.on("/capture", HTTP_GET, serverCapture);
  server.on("/stream", HTTP_GET, serverStream);
  server.on("/comTest", HTTP_GET, comTest);
  server.onNotFound(handleNotFound);
  server.begin();
  Serial.println(F("Server started"));
}
void loop() {

  server.handleClient();

}

ESP32_ARDUCAM.zip (2.39 KB)

Hi

Vorweg: Habe in diese Richtung keinerlei Erfahrung - aber wenn's eine Zeit lang klappt und dann nicht mehr, riecht Das nach Speicher.
'Funktioniert dann nicht mehr' ist aber auch etwas arg schwammig von Dir formuliert - kannst Du den Fehler weiter eingrenzen?
Kannst Du in Deinem Sketch erkennen, was wo ablaufen MÜSSTE und Dir z.B. seriell dir dortigen Werte anzeigen oder in ein LOG packen lassen?

MfG

Hallo,

die ArduCam habe ich nicht, aber laß Dir mal alle Sekunde den freien Speicher ausgeben:

void loop()

  static int lastms = 0;

  if (millis()-lastms > 1000)
  {
    lastms = millis();
    Serial.printf_P(PSTR("Running for %d seconds - Free mem=%d\n"), lastms/1000, ESP.getFreeHeap());
  }

//... Deine Loop-Sachen

Mit Deiner Auflösung sollte es keine Probleme geben, wenn er weniger als ca. 40kB free Heap hat wird das instabil.
Ansonsten siehe Post von postmaster-ino

Mach keine zu vielen und zu häufigen Seriellen Ausgaben gleichzeitig, damit kannst Du auch auf dem ESP32 (oder gerade) neue Fehler produzieren.
Da läuft ja ein RTOS drauf und dabekommt man durchaus nette time out in Sachen zustande, die man noch garnicht kennt.

Gruß aus Berlin
Michael

Hallo Postmaster-ino, Hallo Michael,

Danke für eure Antwort und sorry für die schwammige Formulierung.

ich kann mich mit dem ESP32 access point verbinden und bekomme dann das Bild im Browser mit "http://IP_von_ESP32/stream" für max 7 min. Danach wird die Seite vom Browser schwarz, also kein Bild auch wenn ich die Seite aktualisiere oder so bekomme ich das Bild nicht mehr
Aber ESP32 bleibt als access point verfügbar und mein Handy bleibt mit dem Verbunden. Ich kann auch weiter Strings an ESP32 schicken und die mit "Serial.print()" ausgeben lassen.

Ich habe das mit dem Speicher von Michael Probiert. Das Problem scheint nicht von Speicher zu sein.

MfG

Hallo,

ok. Du hast die ArduCam an einem ESP32 im AP-Mode. Mache ich wahlweise mit meiner M5Stack Cam auch so, ist auch kein prinzipilles Problem. Du wirst eingrenzen müssen, wer nicht mitspielt. Kommt kein Bild mehr von der Kamera, wird die Client-Anfrage noch sauber abgearbeiet und bis wohin usw.

Ich vermute jetzt mal, Du bekommst ein schwarzes Bild und es werden scheinbar vom Browser weiterhin Bilder geholt, also kein timout/nichterreichbar vom Webbrowser.
Den Zustand haben mein Bekannter und ich auch mit meiner Cam-Software auch schon erlebt, mit jedem getesteten Browser. Warum haben wir bisher aber noch nicht geschaut, war erstmal nur Spielerei. Wenn ich im Loop auf einem anderen ESP32 die Einzelbilder abhole und auf dem Display (odroid Go) anzeige, tritt der Fehler auch nach Stunden nicht auf.
Es könnte also mit dem multipart-Header zusammenhängen, aber alles noch nicht im Detail angeschaut...

Gruß aus Berlin
Michael