آموزش ESP32 45/55 - سرور پخش سفارشی با کنترل LED CAM-3 l کیت آموزش ESP32 سانفاندر
در این آموزش، به چگونگی راهاندازی یک سرور استریمینگ سفارشی با استفاده از بورد افزونه ESP32 از SunFounder میپردازیم. این پروژه به شما اجازه میدهد ویدیو زنده را به مرورگر خود استریم کنید و در عین حال یک LED را بهطور مستقیم از رابط کنترل کنید. این ترکیب از ویژگیها تجربه یادگیری عملی با فناوریهای اینترنت اشیاء و وب را ممکن میسازد.
ما از قابلیتهای Wi-Fi داخلی ESP32 استفاده خواهیم کرد تا یک سرور وب ایجاد کنیم که ویدئو را پخش کرده و دستورات کنترل LED را مدیریت کند. این پروژه شامل برنامهنویسی، سیمکشی و درک نحوه تعامل اجزا است. اگر میخواهید درک روشنی از تنظیمات داشته باشید، حتماً ویدئو را در (در ویدئو در :00) تماشا کنید.
سختافزار توضیح داده شده
اجزای اصلی این پروژه شامل میکروکنترلر ESP32، ماجیول دوربین، یک LED و یک مقاومت است. ESP32 یک میکروکنترلر چندکاره با Wi-Fi و بلوتوث داخلی است که آن را برای برنامههای اینترنت اشیا مناسب میسازد. ماجیول دوربین به ما امکان ضبط ویدئو را میدهد، در حالی که LED یک دستگاه خروجی ساده برای کنترل فراهم میکند.
LED از طریق یک مقاومت به نوعی متصل شده است که جریان را محدود میکند و از آسیب به LED و میکروکنترلر جلوگیری میکند. این طرح به ما امکان میدهد تا LED را از طریق رابط وب خود روشن و خاموش کنیم و قابلیتهای ESP32 را در مدیریت ورودیها و خروجیها از طریق یک شبکه نمایش دهیم.
جزئیات برگ اطلاعات
| تولید کننده | اسپرسیف |
|---|---|
| شماره قطعه | ESP32-WROOM-32 |
| ولتاژ منطقی/ورودی و خروجی | ۳.۳ ولت |
| ولتاژ تأمین | 3.0-3.6 ولت |
| جریان خروجی (به ازای هر کانال) | ۱۲ میلی آمپر |
| جریان اوج (به ازای هر کانال) | 40 میلیآمپر |
| راهنمایی فرکانس PWM | 1 کیلوهرتز |
| آستانههای منطقی ورودی | ۰.۲ ولت (کم) / ۰.۸ ولت (زیاد) |
| افت ولتاژ / RDS(on)سهم اشباع | 0.2 ولت (معمولی) |
| محدودیتهای حرارتی | حداکثر دمای تقاطع: ۱۲۵ درجه سانتیگراد |
| بسته | QFN48 |
| یادداشتها / انواع | در پیکربندیهای مختلف در دسترس است |
- اطمینان حاصل کنید که ESP32 با منبع تغذیه پایدار ۳.۳ ولت تأمین میشود.
- از یک مقاومتی که محدود کننده جریان است (۲۲۰ اهم) به همراه LED استفاده کنید تا از آسیب جلوگیری شود.
- اتصالات مناسب را حفظ کنید تا از ورودیهای شناور جلوگیری شود.
- اطمینان حاصل کنید که مشخصات Wi-Fi صحیح و حساس به حروف بزرگ و کوچک است.
- از یک منبع برق پایدار برای عملکرد ثابت استفاده کنید.
- انتشار حرارت در فضاهای محصور را در نظر بگیرید.
دستورالعملهای کابلکشی

برای اتصال ESP32 و LED، ابتدا پایه بلند LED را به یک پایه GPIO مناسب وصل کنید، در این مورد، از پایه 14 استفاده خواهیم کرد. پایه کوتاه باید به خط زمین در بورد سوراخ دار شما متصل شود. سپس یک مقاومت 220 اهمی را به صورت سری با LED قرار دهید و یک سر آن را به پایه GPIO (پایه 14) و سر دیگر را به زمین وصل کنید. مطمئن شوید که ESP32 به درستی تأمین برق شده است، چه از طریق پورت میکرو USB یا با استفاده از باتری لیتیومی 18650.
برای ماجیول دوربین، اطمینان حاصل کنید که پایههای لازم را طبق مدل دوربینی که استفاده میکنید متصل کنید، زیرا کابلکشی ممکن است کمی متفاوت باشد. ESP32 جریان ویدئو را از طریق قابلیتهای داخلی خود مدیریت خواهد کرد و کنترل LED از طریق رابط وبی که در شِفر (کود) تنظیم خواهیم کرد، انجام خواهد شد.
نمونههای شِفر (کود) و راهنمایی
این برنامه با شامل کردن کتابخانههای ضروری و تعریف اعتبارنامههای Wi-Fi آغاز میشود. شما باید جایگزین کنیدssidوpasswordبا اطلاعات واقعی Wi-Fi خود برای اتصال ESP32 به شبکهتان.
const char* ssid = "SSID";
const char* password = "PASSWORD";بعدی، پایه LED را تعریف میکنیم و تنظیمات دوربین را راهاندازی میکنیم. پایهای که برای LED استفاده میشود به صورت زیر تعریف شده استLED_PINکه بعداً در شِفر (کود) برای کنترل وضعیت LED استفاده خواهد شد.
#define LED_PIN 14
pinMode(LED_PIN, OUTPUT);در پردازش درخواست برای کنترل LED، فرمان دریافتی از رابط وب را بررسی میکنیم. بسته به اینکه فرمان "روشن" یا "خاموش" باشد، ما استفاده میکنیمdigitalWrite(LED_PIN, 1);برای روشن کردن LED وdigitalWrite(LED_PIN, 0);آن را خاموش کردن.
if(!strcmp(variable, "on")) {
Serial.println("ON");
digitalWrite(LED_PIN, 1);
}
else if(!strcmp(variable, "off")) {
Serial.println("OFF");
digitalWrite(LED_PIN, 0);
}این منطق به رابط وب اجازه میدهد تا بهطور مؤثر با ESP32 ارتباط برقرار کند و کنترل بلادرنگ LED را بر اساس تعاملات کاربر امکانپذیر سازد. شِفر (کود) کامل در زیر مقاله برای بررسی بیشتر بارگذاری میشود.
نمایش / چه انتظاری باید داشته باشیم
پس از اینکه همه چیز راه اندازی شد و شِفر (کود) بارگذاری شد، باید بتوانید آدرس IP ESP32 را در مرورگر وب خود دسترسی پیدا کنید. ویدئوهای پخش شده ظاهر خواهد شد و میتوانید LED را با استفاده از دکمههای روی رابط کنترل کنید. کلیک کردن بر روی "ON" LED را روشن میکند، در حالی که "OFF" آن را خاموش میکند. مطمئن شوید که ESP32 و رایانه شما به یک شبکه متصل هستند تا عملکرد صحیح تضمین شود (در ویدئو در 12:30).
زمانبندی ویدیو
- ۰۰:۰۰ شروع
- ۱:۵۱ مقدمهای بر پروژه
- صفحه مستندات 2:31
- ۳:۳۳ توضیح سیمکشی
- شِفر (کود) آردوینو توضیح داده شده 5:08
- انتخاب برد ESP32 و پورت COM در محیط برنامهنویسی آردوینو :28
- ۱۵:۱۰ نمایش
/*
* بدین وسیله اجازه رایگان به هر شخصی که کپی ای از این نرمافزار و فایلهای مستندات مرتبط را دریافت کند، داده میشود. اطلاعیه حق چاپ فوق و این اجازهنامه باید در تمام کپیها یا بخشهای عمده نرمافزار گنجانده شود.
*/
#include "esp_camera.h"
#include <WiFi.h>
#include "esp_timer.h"
#include "img_converters.h"
#include "Arduino.h"
#include "fb_gfx.h"
#include "soc/soc.h" // مشکلات افت ولتاژ را غیرفعال کنید
#include "soc/rtc_cntl_reg.h" // مشکلات افت ولتاژ را غیرفعال کنید
#include "esp_http_server.h"
// متغیرهای بعدی را با ترکیب SSID/گذرواژه خود جایگزین کنید.
const char* ssid = "SSID";
const char* password = "PASSWORD";
#define PART_BOUNDARY "123456789000000000000987654321"
#define CAMERA_MODEL_AI_THINKER
// #define CAMERA_MODEL_M5STACK_PSRAM
// #define CAMERA_MODEL_M5STACK_WITHOUT_PSRAM
// #define CAMERA_MODEL_M5STACK_PSRAM_B
// #define CAMERA_MODEL_WROVER_KIT
#if defined(CAMERA_MODEL_WROVER_KIT)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 21
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 19
#define Y4_GPIO_NUM 18
#define Y3_GPIO_NUM 5
#define Y2_GPIO_NUM 4
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
#elif defined(CAMERA_MODEL_M5STACK_PSRAM)
#define PWDN_GPIO_NUM -1
#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 32
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#elif defined(CAMERA_MODEL_M5STACK_WITHOUT_PSRAM)
#define PWDN_GPIO_NUM -1
#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
#elif defined(CAMERA_MODEL_AI_THINKER)
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM 33
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
#elif defined(CAMERA_MODEL_M5STACK_PSRAM_B)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 22
#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 32
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#else
#error "Camera model not selected"
#endif
#define LED_PIN 14
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";
httpd_handle_t camera_httpd = NULL;
httpd_handle_t stream_httpd = NULL;
static const char PROGMEM INDEX_HTML[] = R"rawliteral(
<html>
<head>
<title>ESP32-CAM Robot</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: Arial; text-align: center; margin:0px auto; padding-top: 30px;}
table { margin-left: auto; margin-right: auto; }
td { padding: 8 px; }
.button {
background-color: #2f4468;
border: none;
color: white;
padding: 10px 20px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 18px;
margin: 6px 3px;
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
img { width: auto ;
max-width: 100% ;
height: auto ;
transform: rotate(180deg);
}
</style>
</head>
<body>
<h1>ESP32 CAMERA</h1>
<img src="" id="photo" >
<table>
<tr><td align="center"><button class="button" onmousedown="toggleCheckbox('on');" ontouchstart="toggleCheckbox('on');onmouseup="toggleCheckbox('on');" ontouchend="toggleCheckbox('on');">ON</button></td>
<td align="center"><button class="button" onmousedown="toggleCheckbox('off');" ontouchstart="toggleCheckbox('off');onmouseup="toggleCheckbox('off');" ontouchend="toggleCheckbox('off');">OFF</button></td></tr>
</table>
<script>
function toggleCheckbox(x) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/action?go=" + x, true);
xhr.send();
}
window.onload = document.getElementById("photo").src = window.location.href.slice(0, -1) + ":81/stream";
</script>
</body>
</html>
)rawliteral";
static esp_err_t index_handler(httpd_req_t *req){
httpd_resp_set_type(req, "text/html");
return httpd_resp_send(req, (const char *)INDEX_HTML, strlen(INDEX_HTML));
}
static esp_err_t stream_handler(httpd_req_t *req){
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len = 0;
uint8_t * _jpg_buf = NULL;
char * part_buf[64];
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if(res != ESP_OK){
return res;
}
while(true){
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
res = ESP_FAIL;
} else {
if(fb->width > 400){
if(fb->format != PIXFORMAT_JPEG){
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
esp_camera_fb_return(fb);
fb = NULL;
if(!jpeg_converted){
Serial.println("JPEG compression failed");
res = ESP_FAIL;
}
} else {
_jpg_buf_len = fb->len;
_jpg_buf = fb->buf;
}
}
}
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(res == ESP_OK){
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
if(fb){
esp_camera_fb_return(fb);
fb = NULL;
_jpg_buf = NULL;
} else if(_jpg_buf){
free(_jpg_buf);
_jpg_buf = NULL;
}
if(res != ESP_OK){
break;
}
// Serial.printf("MJPG: %uB\n",(uint32_t)(_jpg_buf_len));
}
return res;
}
static esp_err_t cmd_handler(httpd_req_t *req){
char* buf;
size_t buf_len;
char variable[32] = {0,};
buf_len = httpd_req_get_url_query_len(req) + 1;
if (buf_len > 1) {
buf = (char*)malloc(buf_len);
if(!buf){
httpd_resp_send_500(req);
return ESP_FAIL;
}
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
if (httpd_query_key_value(buf, "go", variable, sizeof(variable)) == ESP_OK) {
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
free(buf);
} else {
httpd_resp_send_404(req);
return ESP_FAIL;
}
sensor_t * s = esp_camera_sensor_get();
int res = 0;
if(!strcmp(variable, "on")) {
Serial.println("ON");
digitalWrite(LED_PIN, 1);
}
else if(!strcmp(variable, "off")) {
Serial.println("OFF");
digitalWrite(LED_PIN, 0);
}
else {
res = -1;
}
if(res){
return httpd_resp_send_500(req);
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
void startCameraServer(){
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.server_port = 80;
httpd_uri_t index_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = index_handler,
.user_ctx = NULL
};
httpd_uri_t cmd_uri = {
.uri = "/action",
.method = HTTP_GET,
.handler = cmd_handler,
.user_ctx = NULL
};
httpd_uri_t stream_uri = {
.uri = "/stream",
.method = HTTP_GET,
.handler = stream_handler,
.user_ctx = NULL
};
if (httpd_start(&camera_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(camera_httpd, &index_uri);
httpd_register_uri_handler(camera_httpd, &cmd_uri);
}
config.server_port += 1;
config.ctrl_port += 1;
if (httpd_start(&stream_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(stream_httpd, &stream_uri);
}
}
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // خاموش کردن دستگاه تشخیص افت ولتاژ
pinMode(LED_PIN, OUTPUT);
Serial.begin(115200);
Serial.setDebugOutput(false);
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.pixel_format = PIXFORMAT_JPEG;
if(psramFound()){
config.frame_size = FRAMESIZE_VGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// راه اندازی دوربین
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
// اتصال Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("Camera Stream Ready! Go to: http: // ");
Serial.println(WiFi.localIP());
// سرور وب پخش زنده را راهاندازی کنید
startCameraServer();
}
void loop() {
}
Common Course Links
Common Course Files
منابع و مراجع
-
مستنداتآموزش ESP32 45/55 - صفحه سند SunFounder برای سرور پخش سفارشیdocs.sunfounder.com
فایلها📁
هیچ فایلی موجود نیست.