使用ESP32CAM和VLC播放器DIY監(jiān)控閉路電視攝像機
基于ESP32-CAM的CCTV攝像機是一個項目,允許您使用ESP32-CAM模塊和VLC播放器創(chuàng)建遠程監(jiān)控攝像機。ESP32- cam板是ESP32微控制器和相機模塊OV2640的流行組合,適用于捕獲圖像和流媒體視頻。該項目引入了ESP32 CAM模塊,這是一個小型但功能強大的相機模塊,配備了ESP32微控制器,并利用Wi-Fi功能,使項目具有成本效益和經(jīng)濟實惠。
在這個項目中,我們的CAM模塊與Wi-Fi網(wǎng)絡(luò)無縫集成,將直播視頻傳輸?shù)綗o線通信中,由連接相同WiFi的設(shè)備接收。用戶可以通過使用實時監(jiān)控攝像頭饋送的VLC流媒體平臺無線觀看直播。
在整個項目中,我們將了解設(shè)置過程、連接圖和演示,以編碼ESP32CAM來捕獲視頻,并展示啟動VLC流的步驟。
查看所有以前使用ESP32-CAM創(chuàng)建的監(jiān)控和流媒體項目:使用Arduino IDE的基于ESP32 CAM的監(jiān)控機器人
組件的要求
?ESP32凸輪模塊
?USB到UART TTL串行轉(zhuǎn)換器/ FTDI模塊
?連接電線
?外部5v電源
ESP32凸輪模塊
ESP32- cam模塊(由AI-Thinker開發(fā))使用ESP32微控制器和OV2640相機傳感器,支持Wi-Fi和藍牙連接,一些關(guān)鍵規(guī)格如下:
微控制器:ESP32-D0WDQ6,雙核32位,時鐘速度高達240 MHz。
攝像頭:OV2640, 200萬像素分辨率(1600 × 1200像素)。
內(nèi)存:4mb閃存,大約520-600 KB RAM,外部8MB PSRAM。
支持SD卡讀卡器高達4GB。
ESP32-S芯片總共提供32個GPIO引腳;然而,由于其中相當一部分是預留給內(nèi)部使用的,ESP32-CAM模塊只提供10個可用的GPIO引腳。盡管有這種限制,但這些引腳是通用的,可用于接口UART, SPI, I2C, PWM, ADC, DAC和Touch功能,使ESP32-CAM成為各種應(yīng)用的強大而靈活的平臺。
電源引腳包括5v和3.3v。它有一個內(nèi)置的3.3電壓調(diào)節(jié)器。
FTDI模塊
由于ESP32 CAM板沒有USB到TTL串行轉(zhuǎn)換器IC。因此唯一的選擇是使用FTDI模塊使用PC對ESP32板進行編程。下面的圖表給你一個關(guān)于它的引腳和接口的想法。
一般來說,該模塊有6個引腳與微控制器通信。
GND:接地引腳
5V:輸出5V版本,輸入3.3V版本
TXD:傳輸數(shù)據(jù)(從模塊輸出)
RXD:接收數(shù)據(jù)(輸入到模塊)
CTS:清除發(fā)送(輸入到模塊)
DTR:數(shù)據(jù)終端就緒(從模塊輸出)
ESP32 CAM和FTDI編程電路圖
采用串行通信技術(shù),利用FTDI (USB-to-UART)模塊對ESP32 Cam進行編程。FTDI模塊作為計算機的USB到ESP-32 CAM的UART接口之間的串行轉(zhuǎn)換器,允許您上傳代碼并與模塊進行交互。
根據(jù)連接圖,可以將ESP32-CAM與FTDI模塊連接,進行編程:
連接FTDI模塊的GND和ESP32-CAM的GND。
連接FTDI模塊的RX到ESP32-CAM的U0TXD。
將FTDI模塊的TX連接到ESP32-CAM的U0RXD。
將FTDI模塊上的VCC連接到ESP32-CAM的5V電源引腳上。
重要:將ESP32-CAM的GPIO0到GND排序,使板處于啟動模式以進行編程。稍后,必須在程序上傳成功后刪除排序。
在某些ESP32-CAM板中,您可能會遇到檢測器斷電錯誤,這通常是由FTDI (USB轉(zhuǎn)UART)模塊供電不足引起的。為了解決這個問題,建議將外部5V電源直接接入ESP32-CAM板。該外部電源將確保ESP32-CAM獲得足夠的電壓,并且可以在不觸發(fā)斷電檢測器錯誤的情況下運行,如下圖所示:
ESP32-CAM閉路電視攝像機的Arduino編程代碼
我們將使用Arduino IDE對開發(fā)板進行編程。該程序為相機模塊設(shè)置了各種接口引腳,并創(chuàng)建了一個基于網(wǎng)絡(luò)的流媒體鏈接,將用于在VLC上進行流媒體。為此,我們需要下載代碼草圖。你可以在GitHub上找到完整的代碼。
下載zip文件中的完整代碼,然后解壓縮文件夾并解壓縮它。打開文件夾后,您將找到一個名為esp32_camera_mjpeg的ino文件,這是我們的代碼草圖文件。
在Arduino IDE中打開草圖文件。由于這是原始代碼,因此我們必須根據(jù)我們的環(huán)境對代碼進行一些修改。讓我們一起來看看:
在代碼的開頭,您將找到特定相機模型硬件的定義。默認情況下,將有CAMERA_MODEL_ESP_EYE選擇,但我們的模塊使用CAMERA_MODEL_AI_THINKER。因此,對前面選擇的模型進行注釋,并取消對CAMERA_MODEL_AI_THINKER模型的注釋。
指定正確的網(wǎng)絡(luò)憑據(jù),包括SSID和Password,以成功連接到加密的網(wǎng)絡(luò)。確保您的網(wǎng)絡(luò)帶寬為2.4 GHz,使其與開發(fā)板兼容。
OV2640的圖像質(zhì)量和幀大小可以通過下面的代碼部分進行調(diào)整。
(1600 x 1200)
qvga (320 x 240)
jpeg_quality的取值范圍從0到63,數(shù)值越小表示圖像質(zhì)量越高。但是,為jpeg_quality設(shè)置一個非常低的數(shù)字,特別是在更高的分辨率下,可能會導致諸如圖像損壞,奇怪的顏色,甚至ESP32-CAM崩潰之類的問題。
為了避免這些問題,在圖像質(zhì)量和內(nèi)存約束之間找到一個平衡是至關(guān)重要的。如果您注意到使用ESP32-CAM拍攝的圖像被截成兩半,包含奇怪的顏色,或者模塊正在經(jīng)歷崩潰,請考慮增加jpeg_quality值以改善圖像輸出和穩(wěn)定性。
既然代碼已經(jīng)完成了所有必要的更改,現(xiàn)在是時候繼續(xù)編譯和上傳代碼了。
在上傳代碼到ESP32-CAM板之前,請選擇正確的板和COM端口。要做到這一點,請遵循以下步驟:
進入Arduino IDE菜單中的“Tools”。
點擊“Board”,點擊“ESP32 Arduino”,在可選板列表中選擇“AI Thinker ESP32- cam”。
注意:如果你在主板中沒有找到“ESP32 Arduino”,這意味著主板沒有安裝在你的IDE中。這是以前的教程,讓您深入了解安裝ESP32板。
此外,確保FTDI編程器正確連接到模塊。此外,請確保GPIO0也接地。GPIO0的接地對于將ESP32-CAM置于編程模式至關(guān)重要。
一旦所有這些都完成了,您可以繼續(xù)編譯和上傳過程后,選擇正確的板和COM端口。
通過Web界面監(jiān)控直播
上傳完成后,將單板從PC上拔下。從ESP32-CAM板上拆除IO0和GND跳線連接,然后將其再次插入PC。打開串口監(jiān)視器,按下單板上的復位按鈕。通過這樣做,ESP32-CAM模塊將嘗試連接到配置的WiFi網(wǎng)絡(luò)。
串行監(jiān)視器上將顯示MPEG鏈接。復制鏈接并在任何瀏覽器中搜索。你會發(fā)現(xiàn)直播開始了。
在VLC上配置直播
現(xiàn)在讓我們在VLC媒體應(yīng)用程序上直播視頻。你們中的許多人可能已經(jīng)在Android或Windows上使用過VLC媒體播放器。我們正在使用這個多功能播放器流媒體,這承諾是一個有趣的,創(chuàng)造性的,和實用的實現(xiàn)。如果你還沒有安裝播放器,你可以很容易地從Android的Play Store下載,或者使用任何Windows的web瀏覽器下載。
在您的設(shè)備(Android、Windows或任何其他平臺)上打開VLC媒體播放器。
在VLC中,進入菜單中的“媒體”,選擇“打開網(wǎng)絡(luò)流”。
在“網(wǎng)絡(luò)”選項卡中,輸入直播視頻流的URL。URL應(yīng)該與顯示在串行監(jiān)視器上或用于web流媒體上的URL相同。
點擊“播放”開始直播。
注意:請確保直播流設(shè)備連接到與ESP32-CAM板相同的網(wǎng)絡(luò)。
希望你喜歡和享受這個項目,并從中學到一些有用的東西。
/*
This is a simple MJPEG streaming webserver implemented for AI-Thinker ESP32-CAM and
ESP32-EYE modules.
This is tested to work with VLC and Blynk video widget.
Inspired by and based on this Instructable: $9 RTSP Video Streamer Using the ESP32-CAM Board
(https://www.instructables.com/id/9-RTSP-Video-Streamer-Using-the-ESP32-CAM-Board/)
Board: AI-Thinker ESP32-CAM
*/
#include "src/OV2640.h"
#include
#include
#include
// Select camera model
//#define CAMERA_MODEL_WROVER_KIT
//#define CAMERA_MODEL_ESP_EYE
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE
#define CAMERA_MODEL_AI_THINKER
#include "camera_pins.h"
#define SSID1 "Semicon Media 2.4"
#define PWD1 "cdfiP29to665"
OV2640 cam;
WebServer server(80);
const char HEADER[] = "HTTP/1.1 200 OK\r\n" \
"Access-Control-Allow-Origin: *\r\n" \
"Content-Type: multipart/x-mixed-replace; boundary=123456789000000000000987654321\r\n";
const char BOUNDARY[] = "\r\n--123456789000000000000987654321\r\n";
const char CTNTTYPE[] = "Content-Type: image/jpeg\r\nContent-Length: ";
const int hdrLen = strlen(HEADER);
const int bdrLen = strlen(BOUNDARY);
const int cntLen = strlen(CTNTTYPE);
void handle_jpg_stream(void)
{
char buf[32];
int s;
WiFiClient client = server.client();
client.write(HEADER, hdrLen);
client.write(BOUNDARY, bdrLen);
while (true)
{
if (!client.connected()) break;
cam.run();
s = cam.getSize();
client.write(CTNTTYPE, cntLen);
sprintf( buf, "%d\r\n\r\n", s );
client.write(buf, strlen(buf));
client.write((char *)cam.getfb(), s);
client.write(BOUNDARY, bdrLen);
}
}
const char JHEADER[] = "HTTP/1.1 200 OK\r\n" \
"Content-disposition: inline; filename=capture.jpg\r\n" \
"Content-type: image/jpeg\r\n\r\n";
const int jhdLen = strlen(JHEADER);
void handle_jpg(void)
{
WiFiClient client = server.client();
cam.run();
if (!client.connected()) return;
client.write(JHEADER, jhdLen);
client.write((char *)cam.getfb(), cam.getSize());
}
void handleNotFound()
{
String message = "Server is running!\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
server.send(200, "text / plain", message);
}
void setup()
{
Serial.begin(115200);
//while (!Serial); //wait for serial connection.
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;
// Frame parameters
config.frame_size = FRAMESIZE_UXGA;
//config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 12;
config.fb_count = 2;
#if defined(CAMERA_MODEL_ESP_EYE)
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
#endif
cam.init(config);
IPAddress ip;
WiFi.mode(WIFI_STA);
WiFi.begin(SSID1, PWD1);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(F("."));
}
ip = WiFi.localIP();
Serial.println(F("WiFi connected"));
Serial.println("");
Serial.println(ip);
Serial.print("Stream Link: http://");
Serial.print(ip);
Serial.println("/mjpeg/1");
server.on("/mjpeg/1", HTTP_GET, handle_jpg_stream);
server.on("/jpg", HTTP_GET, handle_jpg);
server.onNotFound(handleNotFound);
server.begin();
}
void loop()
{
server.handleClient();
}
本文編譯自iotdesignpro