Esp32 cam с API Chat GPT Vision выдает сбой или имеет проблемы с подключением.

Вопрос или проблема

Я делаю проект, используя API видения chat gpt с esp32cam. Работает в первом цикле (первая фотография, которую он делает и отправляет в chat gpt), но esp32 зависает (Ошибка гуро- медитации: ядро 1 паниковало (LoadProhibited). Исключение не обработано.) или возникает “ошибка соединения” с chat gpt, когда я пытаюсь сделать еще одну фотографию. Нужна помощь. Вот мой код на данный момент: (Я использовал chat gpt, чтобы попытаться исправить код, но это не сработало)

#include "esp_camera.h"
#include "FS.h"
#include "SD.h"
#include "SPI.h"
#include "WiFi.h"
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include "Base64.h"
#include "ChatGPT.hpp"
#include "credentials.h" // Учетные данные WiFi и API-ключ OpenAI

#define CAMERA_MODEL_XIAO_ESP32S3 // Имеет PSRAM

#include "camera_pins.h"

int imageCount = 1;                // Счетчик файлов
bool camera_sign = false;          // Проверка состояния камеры
bool sd_sign = false;              // Проверка состояния sd
int button = 0;    
const int buttonPin = 3;           // Пин, к которому подключена кнопка  

WiFiClientSecure client;  // WiFiClientSecure для HTTPS соединения
ChatGPT<WiFiClientSecure> chatGPT_Client(&client, "v1", openai_api_key, 90000);  // Использовать WiFiClientSecure для HTTPS

void connectToWiFi() {
    WiFi.begin(ssid, password);
    Serial.println("Подключение к WiFi...");

    // Ждем, пока устройство подключится к WiFi
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println();
    Serial.print("Подключено! IP-адрес: ");
    Serial.println(WiFi.localIP());
}

// Функция для удаления всех файлов в корневом каталоге
void deleteAllFiles(fs::FS &fs) {
    File root = fs.open("/");
    File file = root.openNextFile();
    while (file) {
        fs.remove(file.name());  // Удалить каждый файл
        file = root.openNextFile();
    }
    Serial.println("Все файлы удалены с SD-карты.");
}

// Функция для создания необходимых папок
void createFolders(fs::FS &fs) {
    if (!fs.exists("/pictures")) {
        fs.mkdir("/pictures");
        Serial.println("Создана папка: /pictures");
    }
    if (!fs.exists("/encoded")) {
        fs.mkdir("/encoded");
        Serial.println("Создана папка: /encoded");
    }
}

// Файл записи на SD-карте
void writeFile(fs::FS &fs, const char * path, uint8_t * data, size_t len){
    Serial.printf("Запись файла: %s\r\n", path);

    File file = fs.open(path, FILE_WRITE);
    if(!file){
        Serial.println("Не удалось открыть файл для записи");
        return;
    }
    if(file.write(data, len) == len){
        Serial.println("Файл записан");
    } else {
        Serial.println("Ошибка записи");
    }
    file.close();
}

// Сохранение фотографий на SD-карте и отправка в GPT-4o Mini Vision API
void photo_save_and_analyze(const char * fileName) {
    // Сделать фотографию
    camera_fb_t *fb = esp_camera_fb_get();
    if (!fb) {
        Serial.println("Не удалось получить буфер кадра камеры");
        delay(1000);  // Задержка, чтобы предотвратить быстрые попытки
        return;
    }

    // Кодировать изображение в Base64
    String encodedImage = base64::encode(fb->buf, fb->len);

    // Сохранить фото в файл в директории /pictures
    writeFile(SD, fileName, fb->buf, fb->len);

    // Освобождение буфера изображения
    esp_camera_fb_return(fb);

    if (!SD.exists(fileName)) {
        Serial.println("Не удалось сохранить фото на SD-карту");
        return;
    }

    Serial.println("Фото сохранено в файл");

    // Добавить префикс base64 к закодированному изображению
    String base64Image = "data:image/jpeg;base64," + encodedImage;
    encodedImage = "";  // Освободить память, очистив строку

    // Теперь отправляем закодированное изображение Base64 в GPT-4o Vision API
    String result;
    Serial.println("\n\n[ChatGPT] - Задаем вопрос о видении");

    client.setInsecure();  // Пропустить проверку сертификата (используйте с осторожностью)

    if (!client.connected()) {
        Serial.println("Переподключение WiFi клиента...");
        client.stop();
        connectToWiFi();  // Восстановление соединения WiFi
    }

    if (chatGPT_Client.vision_question("gpt-4o-mini", "user", "text", "Что на этом изображении?", "image_url", base64Image.c_str(), "auto", 5000, true, result)) {
        Serial.print("[ChatGPT] Ответ: ");
        Serial.println(result);
    } else {
        Serial.print("[ChatGPT] Ошибка: ");
        Serial.println(result);
    }

    base64Image = "";  // Обеспечить освобождение выделенной памяти после кодирования
}

void setup() {
    Serial.begin(115200);
    while(!Serial); // Когда сериал-монитор включен, программа начинает выполняться

    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.frame_size = FRAMESIZE_UXGA;
    config.pixel_format = PIXFORMAT_JPEG; // для потоковой передачи
    config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
    config.fb_location = CAMERA_FB_IN_PSRAM;
    config.jpeg_quality = 12;
    config.fb_count = 1;

    // Если PSRAM IC присутствует, инициализировать с разрешением UXGA и более высоким качеством JPEG
    if(config.pixel_format == PIXFORMAT_JPEG){
        if(psramFound()){
            config.jpeg_quality = 10;
            config.fb_count = 2;
            config.grab_mode = CAMERA_GRAB_LATEST;
        } else {
            // Ограничить размер кадра, когда PSRAM недоступен
            config.frame_size = FRAMESIZE_SVGA;
            config.fb_location = CAMERA_FB_IN_DRAM;
        }
    } else {
        // Лучшая опция для обнаружения/распознавания лиц
        config.frame_size = FRAMESIZE_240X240;
    #if CONFIG_IDF_TARGET_ESP32S3
        config.fb_count = 2;
    #endif
    }

    // инициализация камеры
    esp_err_t err = esp_camera_init(&config);
    if (err != ESP_OK) {
        Serial.printf("Ошибка инициализации камеры 0x%x", err);
        return;
    }

    camera_sign = true; // Проверка инициализации камеры прошла

    // Инициализация SD-карты
    if(!SD.begin(21)){
        Serial.println("Не удалось смонтировать карту");
        return;
    }
    uint8_t cardType = SD.cardType();

    // Определить, доступен ли тип SD-карты
    if(cardType == CARD_NONE){
        Serial.println("Карта SD не подключена");
        return;
    }

    Serial.print("Тип карты SD: ");
    if(cardType == CARD_MMC){
        Serial.println("MMC");
    } else if(cardType == CARD_SD){
        Serial.println("SDSC");
    } else if(cardType == CARD_SDHC){
        Serial.println("SDHC");
    } else {
        Serial.println("UNKNOWN");
    }

    sd_sign = true; // Проверка инициализации SD прошла

    // Удалить все файлы и создать папки
    deleteAllFiles(SD);      // Удалить все файлы при загрузке
    createFolders(SD);       // Создать папки "pictures" и "encoded"

    Serial.println("Фотографии начнутся через минуту, будьте готовы.");

    // Подключиться к WiFi
    connectToWiFi();
}

void loop() {
    if (touchRead(4) <= 25000) {
        button = 0;
    }  

    // Если прошло больше минуты с последнего снимка, сделать фотографию, сохранить на SD-карту и проанализировать с помощью GPT-4o Mini Vision API
    if (touchRead(4) >= 25000 && button == 0) {  
        delay(500);
        if (touchRead(4) >= 25000 && button == 0) {
            char filename[64];
            sprintf(filename, "/pictures/image%d.jpg", imageCount);  // Сохранить только в папку pictures
            photo_save_and_analyze(filename);
            Serial.printf("Сохранено и проанализировано изображение: %s\r\n", filename);
            delay(5000);  
            imageCount++;
            button = 1;
        }
    }
    delay(50);
}

Я использовал chat gpt, чтобы помочь мне исправить это, я новичок, не имею большого опыта. Код создан путем копирования и вставки примерных кодов из библиотек GitHub или найденных в Google, но я понимаю большую часть того, как это работает. Я пытался переподключать его к WiFi после каждой сделанной фотографии, очищал переменные base64 и добавлял задержки, чтобы дать GPT время на ответ. Ничего не сработало.

Ответ или решение

Проблема с подключением ESP32-CAM к API ChatGPT Vision: Решение и рекомендации

Введение

Вы столкнулись с проблемами при использовании ESP32-CAM для передачи изображений в API ChatGPT Vision. В частности, вы получаете ошибку «Guru Meditation Error: Core 1 panic’ed (LoadProhibited)» или «Connection error» при попытке повторно отправить изображение. Давайте разберем возможные причины этих ошибок и предложим решения.

Анализ кода и возможные проблемы

  1. Управление памятью: Основная ошибка, с которой вы столкнулись, связана с управлением памятью в ESP32. Сообщение о панике обычно указывает на то, что вы пытаетесь обратиться к памяти, которая не доступна. Убедитесь, что вы корректно освобождаете память после использования переменных. Как видно из вашего кода, вы очищаете строки encodedImage и base64Image, однако стоит обратить внимание на другие места, где может происходить утечка памяти.

  2. Повторные соединения с Wi-Fi: Каждое время, когда вы пытаетесь отправить изображение, ваш код проверяет соединение с Wi-Fi и переподключается, если оно прервано. Возможно, это создает дополнительную нагрузку на устройство и приводит к сбоям. Попробуйте оптимизировать этот процесс, сохранив постоянное соединение и проверяя его только при старте программы или через определенные промежутки времени.

  3. Считывание изображения: Убедитесь, что после того, как изображение было получено и отправлено, вы правильно освобождаете память с помощью esp_camera_fb_return(fb). Эта ошибка может вызвать проблемы при повторных попытках захвата изображения.

  4. Задержки и тайм-ауты: Вы можете установить не только задержку после отправки изображения, но и обеспечить обработку ответа от сервера. Возможно, API ChatGPT Vision не успевает ответить, и ваше устройство перезапускает попытку отправки изображения. Попробуйте добавить более длительные задержки или использовать асинхронные вызовы, если это возможно.

  5. Использование правильного формата изображения: Убедитесь, что формат изображения соответствует требованиям API ChatGPT. Если вы получаете ошибки, связанные с форматом, это может привести к сбоям в глубоком анализе изображений.

Рекомендации по улучшению кода

  • Устранение утечек памяти: Используйте специализированные инструменты для анализа кода и управления памятью, чтобы предотвратить возможные утечки.

  • Исключение сбоя Wi-Fi: Вместо постоянного переподключения вы можете устанавливать соединение один раз при инициализации и просто проверять его статус, чтобы избегать излишней нагрузки на Wi-Fi.

  • Асинхронная обработка: Попробуйте встроить свою программу в асинхронную обработку запросов. Это может помочь избежать сбоев во время задержек для ожидания ответа от ChatGPT API.

  • Улучшение обработки изображений: Проверьте настройки камеры и параметры перед настройкой для оптимизации захвата изображений и уменьшения нагрузки на память.

Пример улучшенного способа обработки

Измените функцию photo_save_and_analyze, чтобы сохранять соединение с ChatGPT и избегать постоянных переподключений:

if (!client.connected()) {
    Serial.println("WiFi client is not connected. Attempting to reconnect...");
    // Переходим к проверкам соединения без остановки
    if (WiFi.status() != WL_CONNECTED) connectToWiFi(); 
} else {
    Serial.println("WiFi client is connected");
}

Заключение

Эти предложения помогут вам улучшить стабильность вашего проекта на ESP32-CAM с доступом к API ChatGPT Vision. Убедитесь, что вы следите за использованием памяти и управляете состоянием соединения более эффективно. Если проблема сохранится, пользуйтесь опытным сообществом разработчиков на форумах, таких как GitHub или StackOverflow, где вы можете получить дополнительную помощь и советы.

Оцените материал
Добавить комментарий

Капча загружается...