Вопрос или проблема
Я делаю проект, используя 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» при попытке повторно отправить изображение. Давайте разберем возможные причины этих ошибок и предложим решения.
Анализ кода и возможные проблемы
-
Управление памятью: Основная ошибка, с которой вы столкнулись, связана с управлением памятью в ESP32. Сообщение о панике обычно указывает на то, что вы пытаетесь обратиться к памяти, которая не доступна. Убедитесь, что вы корректно освобождаете память после использования переменных. Как видно из вашего кода, вы очищаете строки
encodedImage
иbase64Image
, однако стоит обратить внимание на другие места, где может происходить утечка памяти. -
Повторные соединения с Wi-Fi: Каждое время, когда вы пытаетесь отправить изображение, ваш код проверяет соединение с Wi-Fi и переподключается, если оно прервано. Возможно, это создает дополнительную нагрузку на устройство и приводит к сбоям. Попробуйте оптимизировать этот процесс, сохранив постоянное соединение и проверяя его только при старте программы или через определенные промежутки времени.
-
Считывание изображения: Убедитесь, что после того, как изображение было получено и отправлено, вы правильно освобождаете память с помощью
esp_camera_fb_return(fb)
. Эта ошибка может вызвать проблемы при повторных попытках захвата изображения. -
Задержки и тайм-ауты: Вы можете установить не только задержку после отправки изображения, но и обеспечить обработку ответа от сервера. Возможно, API ChatGPT Vision не успевает ответить, и ваше устройство перезапускает попытку отправки изображения. Попробуйте добавить более длительные задержки или использовать асинхронные вызовы, если это возможно.
-
Использование правильного формата изображения: Убедитесь, что формат изображения соответствует требованиям 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, где вы можете получить дополнительную помощь и советы.