Творчески мазохизм = метод тыка в ИТ! Особо прошу обратить внимание на sdKconfig, который влияет на сборку пакетов и отладку. МНОГИЕ не оценили важность sdKconfig🤢🤮
Поиск решений = важная часть результата. Почему не обожаю СИ ? Да он просто разный. В восторге от assembler. PASCAL
😉Кто там предлагал грызть гранит НАУКИ ? ТРОЦКИЙ? Менделеев предлогам бродить не страшась усталости по тропам для поиска ВЕРШИН?
Счастливчики)))✔
ИТЕШКАМ никогда не бродить по науке и не грызнуть науку , а копать и рыть проблемы себе и разгребать и распутывать проблемы другим.? Так вот, чтобы творческого мазохизма не было продвинуто до маразма, то толкают языки другие , но не СИ. Под ПЛК и т.п. например Ld . IL FBD. CFS .SFX. verilog. HDLC..... Основная проблема это код чужой, который не всегда идеален и библиотеки , которые не всегда нормальны и полны. Ну естественно , когда с таким хозяйством сталкивается спец, то он тоже не идеален. К чему это всё? БУДЬТЕ СНИСХОДИТЕЛЬНЫ к себе и ДРУГИМ. ОСНОВНА проблема - это обеспечение повторяемости результата?😜 Ну вы прошли по тропинке , а потом забыли про её? Так у нас САДКО и СУСАНИН ещё те были? У КСТАТИ А АМЕРИКО? А ВИКИНГИ? Марко Поло, тот всё записал вроде? 😋
🤢Сидел долго на примерах, а наиболее удачный код излагается тут но не под espressif ЦЕЛЬ: опробовать пример в espressif 😊
https://esp32tutorials.com/esp32-cam-esp-idf-live-streaming-web-server/
ЗАПУСТИМ espressif если вы его установили , а ранее про это рассматривали и простую задачу решили. если кто не в курсах , то в просторах ИНЕТ много есть роликов и примеров!
Три пункта выполним?✔
Выполним ещё три пункта?
Два пункта и не сложно.🏳🌈
Удалим всё по пунктам , а их два.🚀
- КАК выделить текст знаете ? CTRL+C - скопировать CTRL+V - вставить.
Ниже код. Выделить и вставить в espressif!!!
#include <esp_system.h>
#include <nvs_flash.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_camera.h"
#include "esp_http_server.h"
#include "esp_timer.h"
#include "camera_pins.h"
#include "connect_wifi.h"
Кстати: PART_BOUNDARY - используется для разделения частей в HTTP-ответе. _STREAM_CONTENT_TYPE- определяет тип содержимого HTTP-ответа. _STREAM_BOUNDARY- используется для разделения частей в HTTP-ответе. _STREAM_PART - определяет формат части в HTTP-ответе.🚩
- КАК выделить текст знаете ? CTRL+C - скопировать CTRL+V - вставить. Ниже код. Выделить и вставить в espressif!!!
static const char *TAG = "esp32-cam Webserver"; #define PART_BOUNDARY "123456789000000000000987654321"
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";
#define CONFIG_XCLK_FREQ 20000000
🏳🌈НИЖЕ описана функция init_camera(void) , где определена структура и условия вставлены в данную структуру, а затем структура передана функции esp_camera_init(&camera_config) . Условия переданные структуре будут определены в файле с расширением .h Далее проверка и флаг на успех на возврат из функции.👌
- КАК выделить текст знаете ? CTRL+C - скопировать CTRL+V - вставить.
Ниже код. Выделить и вставить в espressif!!!
static esp_err_t init_camera(void) { camera_config_t camera_config = {
.pin_pwdn = CAM_PIN_PWDN, .pin_reset = CAM_PIN_RESET,
.pin_xclk = CAM_PIN_XCLK, .pin_sccb_sda = CAM_PIN_SIOD,
.pin_sccb_scl = CAM_PIN_SIOC, .pin_d7 = CAM_PIN_D7,
.pin_d6 = CAM_PIN_D6, .pin_d5 = CAM_PIN_D5,
.pin_d4 = CAM_PIN_D4, .pin_d3 = CAM_PIN_D3,
.pin_d2 = CAM_PIN_D2, .pin_d1 = CAM_PIN_D1,
.pin_d0 = CAM_PIN_D0, .pin_vsync = CAM_PIN_VSYNC,
.pin_href = CAM_PIN_HREF, .pin_pclk = CAM_PIN_PCLK,
.xclk_freq_hz = CONFIG_XCLK_FREQ, .ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0, .pixel_format = PIXFORMAT_JPEG,
.frame_size = FRAMESIZE_UXGA, .jpeg_quality = 12, .fb_count = 1,
.grab_mode = CAMERA_GRAB_WHEN_EMPTY};esp_err_t err=esp_camera_init(&camera_config);
if (err != ESP_OK) { return err; } return ESP_OK;
}
Всё должно выглядеть так как ниже ✔
ДАЛЕЕ Функция setup_server возвращает дескриптор HTTP-серверу, который можно использовать для управления сервером (например, остановить его, отменить регистрацию обработчиков URI).
- КАК выделить текст знаете ? CTRL+C - скопировать CTRL+V - вставить.
Ниже код. Выделить и вставить в espressif!!!👌
httpd_uri_t uri_get = { .uri = "/", .method = HTTP_GET, .handler = jpg_stream_httpd_handler, .user_ctx = NULL};
httpd_handle_t setup_server(void) {
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
httpd_handle_t stream_httpd = NULL;
if (httpd_start(&stream_httpd , &config) == ESP_OK) { httpd_register_uri_handler(stream_httpd , &uri_get); }
return stream_httpd;
}
Функция обработки прямой трансляции jpg_stream_httpd_handler
- это обработчик, которая вызывается для обработки запросов GET в корневом URI HTTP-сервера. Он транслирует видеоконтент в реальном времени, отправляя буфер кадров камеры в виде изображений JPEG в HTTP-ответе.
- ВНИМАТЕЛЬНО почитать: Начинается с установки типа содержимого HTTP-ответа в _STREAM_CONTENT_TYPE с помощью функции httpd_resp_set_type и входит в цикл, который захватывает кадр с камеры, при необходимости преобразует его в формат JPEG и отправляет его в виде фрагмента в HTTP-ответе. Цикл продолжается до тех пор, пока не произойдет ошибка или соединение не будет разорвано. На каждой итерации цикла функция сначала захватывает кадр с камеры, используя функцию esp_camera_fb_get . Если захват завершается неудачно, она регистрирует сообщение об ошибке и прерывает цикл. Если кадр был захвачен успешно, функция проверяет формат кадра. Если он не в формате JPEG, она преобразует его в JPEG с помощью функции frame2jpg. Если преобразование завершается неудачно, он регистрирует сообщение об ошибке, возвращает буфер кадров в камеру с помощью esp_camera_fb_return и прерывает цикл. Если кадр уже в формате JPEG или преобразование в JPEG прошло успешно, функция отправляет граничную строку, заголовок части (который включает тип содержимого и длину содержимого) и изображение JPEG в виде фрагментов в HTTP-ответе с использованием функции httpd_resp_send_chunk. Если какая-либо из этих операций завершается неудачей, она выходит из цикла. После отправки фрагментов функция возвращает буфер кадров в камеру с помощью esp_camera_fb_return и регистрирует размер и время обработки изображения в формате JPEG. Наконец, функция устанавливает переменной last_frame значение 0 и возвращает результат последней операции. Другими словами, эта функция фактически выполняет прямую трансляцию видео.
- КАК выделить текст знаете ? CTRL+C - скопировать CTRL+V - вставить.
Ниже код. Выделить и вставить в espressif!!!🌹
esp_err_t jpg_stream_httpd_handler(httpd_req_t *req){
camera_fb_t * fb = NULL; esp_err_t res = ESP_OK; size_t _jpg_buf_len;
uint8_t * _jpg_buf; char * part_buf[64]; static int64_t last_frame = 0;
if(!last_frame) { last_frame = esp_timer_get_time(); }
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if(res != ESP_OK){ return res; }
while(true){ fb = esp_camera_fb_get();
if (!fb) { ESP_LOGE(TAG, "Camera capture failed"); res = ESP_FAIL; break; }
if(fb->format != PIXFORMAT_JPEG){ bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
if(!jpeg_converted){ ESP_LOGE(TAG, "JPEG compression failed"); esp_camera_fb_return(fb); res = ESP_FAIL; } } else {_jpg_buf_len = fb->len; _jpg_buf = fb->buf; }
if(res == ESP_OK){ res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); }
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(fb->format != PIXFORMAT_JPEG){ free(_jpg_buf); }
esp_camera_fb_return(fb);
if(res != ESP_OK){ break; }
int64_t fr_end = esp_timer_get_time(); int64_t frame_time = fr_end - last_frame; last_frame = fr_end; frame_time /= 1000;
ESP_LOGI(TAG, "MJPG: %uKB %ums (%.1ffps)", (uint32_t)(_jpg_buf_len/1024), (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time);
}
last_frame = 0; return res;
}
В основной функции : Если камера была успешно инициализирована, функция настраивает веб-сервер прямой трансляции HTTP с помощью функции setup_server и регистрирует сообщение, указывающее, что сервер запущен. Если подключение к сети Wi-Fi не было успешным, он регистрирует сообщение, указывающее на сбой, и не запускает сервер.
- КАК выделить текст знаете ? CTRL+C - скопировать CTRL+V - вставить.
Ниже код. Выделить и вставить в espressif!!!🏴
void app_main() { esp_err_t err; esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } connect_wifi();
if (wifi_connect_status) { err = init_camera();
if (err != ESP_OK) { printf("err: %s\n", esp_err_to_name(err)); return; }
setup_server();
ESP_LOGI(TAG, "ESP32 CAM Web Server is up and running\n"); } else
ESP_LOGI(TAG, "Failed to connected with Wi-Fi, check your network Credentials\n");
}
Три пункта выполним?
два пункта выполним!
три пункта выполним?
создадим файл ? camera_pins.h файл определяет константы для назначения pin-кодов.
- КАК выделить текст знаете ? CTRL+C - скопировать CTRL+V - вставить.
Ниже код. Выделить и вставить в espressif!!!
#ifndef CAMERA_PINS_H_
#define CAMERA_PINS_H_
#define CONFIG_BOARD_ESP32CAM_AITHINKER 1
// Freenove ESP32-WROVER CAM Board PIN Map
#if CONFIG_BOARD_WROVER_KIT
#define CAM_PIN_PWDN -1 //power down is not used
#define CAM_PIN_RESET -1
//software reset will be performed #define CAM_PIN_XCLK 21
#define CAM_PIN_SIOD 26
#define CAM_PIN_SIOC 27
#define CAM_PIN_D7 35
#define CAM_PIN_D6 34
#define CAM_PIN_D5 39
#define CAM_PIN_D4 36
#define CAM_PIN_D3 19
#define CAM_PIN_D2 18
#define CAM_PIN_D1 5
#define CAM_PIN_D0 4
#define CAM_PIN_VSYNC 25
#define CAM_PIN_HREF 23
#define CAM_PIN_PCLK 22
#endif // ESP-EYE PIN Map
#if CONFIG_BOARD_CAMERA_MODEL_ESP_EYE
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 4
#define SIOD_GPIO_NUM 18
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 36
#define Y8_GPIO_NUM 37
#define Y7_GPIO_NUM 38
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 35
#define Y4_GPIO_NUM 14
#define Y3_GPIO_NUM 13
#define Y2_GPIO_NUM 34
#define VSYNC_GPIO_NUM 5
#define HREF_GPIO_NUM 27
#define PCLK_GPIO_NUM 25
#endif // AiThinker ESP32Cam PIN Map
#if CONFIG_BOARD_ESP32CAM_AITHINKER
#define CAM_PIN_PWDN 32
#define CAM_PIN_RESET -1 //software reset will be performed
#define CAM_PIN_XCLK 0
#define CAM_PIN_SIOD 26
#define CAM_PIN_SIOC 27
#define CAM_PIN_D7 35
#define CAM_PIN_D6 34
#define CAM_PIN_D5 39
#define CAM_PIN_D4 36
#define CAM_PIN_D3 21
#define CAM_PIN_D2 19
#define CAM_PIN_D1 18
#define CAM_PIN_D0 5
#define CAM_PIN_VSYNC 25
#define CAM_PIN_HREF 23
#define CAM_PIN_PCLK 22
#endif // TTGO T-Journal ESP32 Camera PIN Map
#if CONFIG_BOARD_CAMERA_MODEL_TTGO_T_JOURNAL
#define PWDN_GPIO_NUM 0
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 17
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#endif
#endif
Выполним два пункта с выше?
выполнить три пункта)
выполним два пункта.
connnect_wifi.h: заголовочный файл предоставляет функции для подключения устройства к сети Wi-Fi. Вы можете обратиться к этой статье для получения дополнительных объяснений функций и API, используемых в библиотеке
- КАК выделить текст знаете ? CTRL+C - скопировать CTRL+V - вставить. Ниже код. Выделить и вставить в espressif!!! connnect_wifi.h:
#ifndef CONNECT_WIFI_H_
#define CONNECT_WIFI_H_
#include <esp_system.h>
#include <nvs_flash.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "driver/gpio.h"
#include <lwip/sockets.h>
#include <lwip/sys.h>
#include <lwip/api.h>
#include <lwip/netdb.h>
extern int wifi_connect_status;
void connect_wifi(void);
#endif
выполним три пункта?
Два пункта выполнить?
- КАК выделить текст знаете ? CTRL+C - скопировать CTRL+V - вставить. Ниже код. Выделить и вставить в espressif!!! connnect_wifi.h:
#include "connect_wifi.h"
int wifi_connect_status = 0;
static const char *TAG = "Connect_WiFi";
int s_retry_num = 0;
#define WIFI_SSID "replace_with_your_ssid"
#define WIFI_PASSWORD "replace_with_your_password"
#define MAXIMUM_RETRY 5
EventGroupHandle_t s_wifi_event_group;
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static void event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
{ esp_wifi_connect(); }
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
{ if (s_retry_num < MAXIMUM_RETRY)
{ esp_wifi_connect(); s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
wifi_connect_status = 0; ESP_LOGI(TAG, "connect to the AP fail");
}
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
{ ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
wifi_connect_status = 1; }
}
void connect_wifi(void)
{ s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip));
wifi_config_t wifi_config = {
.sta = { .ssid = WIFI_SSID, .password = WIFI_PASSWORD,
.threshold.authmode = WIFI_AUTH_WPA2_PSK, }
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "wifi_init_sta finished.");
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE, pdFALSE, portMAX_DELAY);
if (bits & WIFI_CONNECTED_BIT)
{ ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
WIFI_SSID, WIFI_PASSWORD);
} else if (bits & WIFI_FAIL_BIT)
{ ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
WIFI_SSID, WIFI_PASSWORD);
} else { ESP_LOGE(TAG, "UNEXPECTED EVENT"); }
vEventGroupDelete(s_wifi_event_group);
}
ВАЖНО ОЧЕНЬ ДАЖЕ 🏳🌈 обратите внимание на строки в коде
#define WIFI_SSID "replace_with_your_ssid"
#define WIFI_PASSWORD "replace_with_your_password"
Это для идентификации ИМЯ и пароль к точки доступа (модем или роутер, который раздаёт ip адреса) если неправильно указать , то всё выше зря делали. ранее про список необходимого шла речь
#define WIFI_SSID "QQQ" //имя раздатчика ip адресов
#define WIFI_PASSWORD "!43405xaa" // пароль для его использования
это доступ к wifi . который даётся к ПК и раздаёт ip адреса свободные. esp32-cam будет станцией, которая подключится к раздатчику ip адресов и после этого станет открытым WEB сервером для всех получив свой ip адрес. Зная его подключимся к нему по wifi.
ПРИМ: Если точек доступа много , то выберите ту , которая вам раздаёт
ip адреса . Так, что выберете узнайте имя точки доступа - раздатчика ip адресов и пароль к нему? 😉 Введите данные!!! Пароль и имя точки ДОСТУПА)))👌 Ниже указано как настроить точку доступа wifi yota(😊
Запустим отладчик🏳🌈
Нажимаем на отладку! начнётся сборка.
А появился сам sdcconfig(🚩 два раз щёлк! ПО sdcconfig( клац, клац МЫШЕЙ?
ВЫПОЛНИМ пункты?
пункты два выполним!🚩
выберем камеру в два пункта😂 сохранимся - закроем - это третий пункт
Возникли две ошибки по первой ниже смотрим и выполняем - устраняем причину.
верхний код удалим , а ниже укажем
httpd_uri_t uri_get = {
.uri = "/",
.method = HTTP_GET,
.handler = jpg_stream_httpd_handler,
.user_ctx = NULL};
///----------------------
httpd_handle_t setup_server(void) {
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
httpd_handle_t stream_httpd = NULL;
if (httpd_start(&stream_httpd , &config) == ESP_OK)
{httpd_register_uri_handler(stream_httpd , &uri_get); }
return stream_httpd;
}
Устраним согласно стрелкам.
ESP_LOGI(TAG, "MJPG: %uKB %ums (%.1ffps)", (uint32_t)(_jpg_buf_len/1024), (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time);
(данный код чисто информирует и не важно на данном этапе насколько правильно) заменим
ESP_LOGI(TAG, "MJPG: %uKB %ums (%.1ffps)", (uint8_t)(_jpg_buf_len/1024), (uint8_t)frame_time, 1000.0 / (uint8_t)frame_time);
Запустим отладчик.
СНОВА в cdkconfig и далее по смыслу = сохраним?
Выполним три пункта 😉
ПОБЕДА? подсоединим esp32-cam
на плате перемычка стоит на прошивку стоит ? RZT - нажата?
По пунктам выполняем и смотрим результат.
Если проценты есть, то значит прошивка прошла.
Перемычку снимаем и REZET запускаем?
ЗАПУСТИ УТИЛИТУ ( НА ПРОСТОРАХ НАЙТИ МОЖНО
НА esp32-cam нажимаем RZT👌
ИЩЕМ IP АДРЕС. есть!!!!😃 = ПУНКТ 5😙