#include "esp_camera.h" #include #include // Конфигурация пинов (пример для Seeed Studio XIAO ESP32S3 Sense) #define PWDN_GPIO_NUM -1 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 10 #define SIOD_GPIO_NUM 40 #define SIOC_GPIO_NUM 39 #define Y9_GPIO_NUM 48 #define Y8_GPIO_NUM 47 #define Y7_GPIO_NUM 13 #define Y6_GPIO_NUM 14 #define Y5_GPIO_NUM 12 #define Y4_GPIO_NUM 11 #define Y3_GPIO_NUM 17 #define Y2_GPIO_NUM 16 #define VSYNC_GPIO_NUM 41 #define HREF_GPIO_NUM 38 #define PCLK_GPIO_NUM 37 const char* ssid = "RT-WiFi-1712"; const char* password = "yt3xihY2Ci"; const char* serverIP = "192.168.0.11"; const int serverPort = 9999; const int localPort = 8888; // !!! УНИКАЛЬНЫЙ ID ДЛЯ КАЖДОЙ ПЛАТЫ (например, 1 для первой, 2 для второй и т.д.) const uint8_t DEVICE_ID = 1; WiFiUDP udpVideo; WiFiUDP udpCmd; camera_config_t config; void setup() { Serial.begin(115200); // Настройка камеры (QVGA для стабильности) 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_QVGA; config.pixel_format = PIXFORMAT_JPEG; config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; config.fb_count = 2; esp_camera_init(&config); // Подключение к Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); } Serial.println("Wi-Fi подключен!"); // Запуск прослушивания порта для команд udpCmd.begin(localPort); Serial.print("Ожидание команд на порту: "); Serial.println(localPort); } void checkIncomingCommands() { int packetSize = udpCmd.parsePacket(); if (packetSize > 0) { char packetBuffer[255]; int len = udpCmd.read(packetBuffer, 255); if (len > 0) { packetBuffer[len] = 0; } String command = String(packetBuffer); command.trim(); Serial.print("Получена команда: "); Serial.println(command); Serial.print("Получена команда: "); Serial.println(command); // Логика управления if (command == "left") { // Ваш код поворота налево } else if (command == "right") { // Ваш код поворота направо } else if (command == "start") { // Ваш код запуска моторов / логики } else if (command == "stop") { // Ваш код остановки } } } void loop() { checkIncomingCommands(); camera_fb_t * fb = esp_camera_fb_get(); if (!fb) return; size_t bufferSize = fb->len; uint8_t * buf = fb->buf; // Размер куска данных уменьшаем до 1023, чтобы вместе с 1 байтом ID пакет был 1024 байта size_t chunkSize = 1023; uint8_t packetBuffer[1024]; for (size_t i = 0; i < bufferSize; i += chunkSize) { size_t sendSize = chunkSize; if (i + chunkSize > bufferSize) { sendSize = bufferSize - i; } // Формируем пакет: первый байт — ID, дальше — видеоданные packetBuffer[0] = DEVICE_ID; memcpy(packetBuffer + 1, buf + i, sendSize); udpVideo.beginPacket(serverIP, serverPort); udpVideo.write(packetBuffer, sendSize + 1); // Отправляем данные вместе с ID udpVideo.endPacket(); } esp_camera_fb_return(fb); delay(10); }