#include "esp_camera.h" #include #include #include "esp_system.h" #include "driver/i2c_master.h" #include "src/lipton/cci.h" #include "src/lipton/vospi.h" #include "src/lipton/lepton_system.h" #include "src/lipton/lepton_utilities.h" #include "esp_log.h" #include "driver/uart.h" #include "mbedtls/base64.h" // // WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality // Ensure ESP32 Wrover Module or other board with PSRAM is selected // Partial images will be transmitted if image exceeds buffer size // // You must select partition scheme from the board menu that has at least 3MB APP space. // Face Recognition is DISABLED for ESP32 and ESP32-S2, because it takes up from 15 // seconds to process single frame. Face Detection is ENABLED if PSRAM is enabled as well // =================== // Select camera model // =================== //#define CAMERA_MODEL_WROVER_KIT // Has PSRAM //#define CAMERA_MODEL_ESP_EYE // Has PSRAM #define CAMERA_MODEL_ESP32S3_EYE // Has PSRAM //#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM //#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM //#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM //#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM //#define CAMERA_MODEL_M5STACK_UNITCAM // No PSRAM //#define CAMERA_MODEL_M5STACK_CAMS3_UNIT // Has PSRAM //#define CAMERA_MODEL_AI_THINKER // Has PSRAM //#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM //#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM // ** Espressif Internal Boards ** //#define CAMERA_MODEL_ESP32_CAM_BOARD //#define CAMERA_MODEL_ESP32S2_CAM_BOARD //#define CAMERA_MODEL_ESP32S3_CAM_LCD //#define CAMERA_MODEL_DFRobot_FireBeetle2_ESP32S3 // Has PSRAM //#define CAMERA_MODEL_DFRobot_Romeo_ESP32S3 // Has PSRAM #include "camera_pins.h" // // LEP Task constants // // Number of consecutive VoSPI resynchronization attempts before attempting to reset #define LEP_SYNC_FAIL_FAULT_LIMIT 10 // Reset fail delay before attempting a re-init (seconds) #define LEP_RESET_FAIL_RETRY_SECS 5 // // Code start // int vsync_count = 0; int sync_fail_count = 0; int reset_fail_count = 0; int64_t vsyncDetectedUsec; WiFiServer lipSrv(8078); // =========================== // Enter your WiFi credentials // =========================== const char *ssid = "CansatDev"; const char *password = "plechovka"; void startCameraServer(); void setupLedFlash(int pin); void setup() { gpio_config_t usb_phy_conf = { .pin_bit_mask = (1ULL << 19) | (1ULL << 20), .mode = GPIO_MODE_OUTPUT, .pull_up_en = GPIO_PULLUP_ENABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE, }; gpio_config(&usb_phy_conf); printf("[MAIN] Start task\n"); LEP_CONFIG = { .agc_set_enabled = true, .emissivity = 100, .gain_mode = LEP_GAIN_AUTO}; // initialize spi, i2c and gpio for lepton if (!lepton_io_init()) { printf("[MAIN] Error: I/O init failed"); while (1) { delay(100); } } // allocate lepton buffers if (!lepton_buffer_init()) { printf("[MAIN] Error: Memory init failed"); while (1) { delay(100); } } // wait for lepton to initialize delay(1000); // Attempt to initialize the VoSPI interface if (vospi_init() != ESP_OK) { printf("[MAIN] Error: Lepton VoSPI initialization failed\n"); while (1) { delay(100); } } // initialize lepton if (!lepton_init()) { printf("[MAIN] Error: Lepton CCI initialization failed\n"); while (1) { delay(100); } } // disable data from lepton digitalWrite(LEP_CSN_PIN, 1); printf("LEPTON INIT DONE"); 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_sccb_sda = -1; config.pin_sccb_scl = -1; config.sccb_i2c_port = I2C_MASTER_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; config.frame_size = FRAMESIZE_UXGA; config.pixel_format = PIXFORMAT_JPEG; // for streaming //config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; config.fb_location = CAMERA_FB_IN_PSRAM; config.jpeg_quality = 12; config.fb_count = 1; // if PSRAM IC present, init with UXGA resolution and higher JPEG quality // for larger pre-allocated frame buffer. if (config.pixel_format == PIXFORMAT_JPEG) { if (psramFound()) { config.jpeg_quality = 10; config.fb_count = 2; config.grab_mode = CAMERA_GRAB_LATEST; } else { // Limit the frame size when PSRAM is not available config.frame_size = FRAMESIZE_SVGA; config.fb_location = CAMERA_FB_IN_DRAM; } } else { // Best option for face detection/recognition config.frame_size = FRAMESIZE_240X240; #if CONFIG_IDF_TARGET_ESP32S3 config.fb_count = 2; #endif } #if defined(CAMERA_MODEL_ESP_EYE) pinMode(13, INPUT_PULLUP); pinMode(14, INPUT_PULLUP); #endif // camera init esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { printf("Camera init failed with error 0x%x", err); return; } sensor_t *s = esp_camera_sensor_get(); // initial sensors are flipped vertically and colors are a bit saturated if (s->id.PID == OV3660_PID) { s->set_vflip(s, 1); // flip it back s->set_brightness(s, 1); // up the brightness just a bit s->set_saturation(s, -2); // lower the saturation } // drop down frame size for higher initial frame rate if (config.pixel_format == PIXFORMAT_JPEG) { s->set_framesize(s, FRAMESIZE_QVGA); } #if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM) s->set_vflip(s, 1); s->set_hmirror(s, 1); #endif #if defined(CAMERA_MODEL_ESP32S3_EYE) s->set_vflip(s, 1); #endif // Setup LED FLash if LED pin is defined in camera_pins.h #if defined(LED_GPIO_NUM) setupLedFlash(LED_GPIO_NUM); #endif WiFi.begin(ssid, password); WiFi.setSleep(false); printf("WiFi connecting\n"); while (WiFi.status() != WL_CONNECTED) { delay(500); printf("."); } printf("\n"); printf("WiFi connected\n"); startCameraServer(); printf("Camera Ready! Use 'http://"); printf(WiFi.localIP().toString().c_str()); lipSrv.begin(); printf("' to connect\n"); } uint8_t *take_picture() { digitalWrite(LEP_CSN_PIN, 0); delay(10); while (1) { // Spin waiting for vsync to be asserted int t = 0; while (digitalRead(LEP_VSYNC_PIN) == 0 && t++ < 11000) { } vsyncDetectedUsec = esp_timer_get_time(); // Attempt to process a segment if (t >= 11000 || vospi_transfer_segment(vsyncDetectedUsec)) { // Got image vsync_count = 0; if (t >= 11000) printf("LEPOVF%d\n", t); else { printf("LEPNOVF%d\n", t); } // Copy the frame to the current half of the shared buffer and let rsp_task know vospi_get_frame(&rsp_lep_buffer); // Hold fault counters reset while operating sync_fail_count = 0; // disable lepton again digitalWrite(LEP_CSN_PIN, 1); return rsp_lep_buffer.lep_bufferP; } else { if (++vsync_count >= 36) { vsync_count = 0; printf("[MAIN] Could not get lepton image\n"); delay(185); if (sync_fail_count++ == LEP_SYNC_FAIL_FAULT_LIMIT) { return nullptr; } } } } return nullptr; } void lepton_restart() { while (1) { delay(LEP_RESET_FAIL_RETRY_SECS * 1000); printf("LEPRESET\n\a"); #ifdef LEP_RESET_PIN digitalWrite(LEP_RESET_PIN, LEP_RESET_ON); delay(10); digitalWrite(LEP_RESET_PIN, LEP_RESET_OFF); #endif // Delay for Lepton internal initialization (max 950 mSec) delay(1000); // if successfully initialized, break out if (lepton_init()) break; } } void loop() { WiFiClient client = lipSrv.available(); if (client) { printf("Got client %s\n", client.remoteIP().toString().c_str()); while (client.connected()) { if (client.available() && client.read() == 'F') { uint8_t *picture = take_picture(); if (picture) { client.write(picture, LEP_NUM_PIXELS); } else { printf("Failed to take picture\n"); } } } // close the connection: client.stop(); } // if (picture) { // pic_to_uart(picture); // } else { // lepton_restart(); // } }