mirror of
https://github.com/IS1DI/x0gp.git
synced 2026-07-16 20:47:55 +00:00
feat(hardware): initial hardware documentation, 3D models, and ESP32 client code
- Add initial versions of hardware bills of materials (BOM v1-v4), shopping lists, plan, and assembly guides. - Add STL models for 3D-printing the 1/27 scale OpenRC F1 car parts. - Add Blender 3D project files (.blend) and camera renders of the car design iterations. - Add ESP32 client firmware source (client.ino) for handling video streaming and car controls. - Ignore Blender backup files (*.blend1, *.blend2) and IDE directories.
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
#include "esp_camera.h"
|
||||
#include <WiFi.h>
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
// Конфигурация пинов (пример для 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);
|
||||
}
|
||||
Reference in New Issue
Block a user