https://www.diyengineers.com/blog/
歡迎使用ESP32-CAM的完整指南!在這篇文章中,我介紹了基礎知識,如何使用,銷釘,布線,寫程式,拍照,上傳到本地層級,甚至在另一台裝置上進行電腦視覺分析。
ESP32-CAM是一個小型相機模組,可在ESP32-S晶片上運行並使用OV2640相機。 ESP32_CAM也可以使用OV7670相機,但是OV2640更好(更高解析度和內建的JPEG編碼,它從ESP32-S中刪除了處理任務)。
內容目錄
ESP-32 CAM規格
ESP-32
它具有Wi-Fi(802.11b/g/n)
藍牙能力(4.2,BLE)
內建LED閃光燈
9 IO連接埠
支援UART,SPI,I2C和PWM
內建的微型SD讀取器
輸入功率:3.3V / 5V(據報道,用5V供電比3.3V更穩定)
OV2640相機
2百萬像素
陣列大小:UXGA(1600 x 1200)
透鏡大小:1/4英吋(6.35mm)
最大圖像傳輸速率:15幀/秒
ESP32-CAM引腳
電源: 5V或3.3V(建議使用5V!)
GND: 地面
VCC: 輸出3.3V
IO PIN#16: 可以在沒有問題的情況下使用GPIO
IO引腳#1&#3: 用作UART介面。由於ESP32-CAM沒有USB連接埠,因此用於將代碼推入其中。這些 不能用於其他任何東西 。
其他IO引腳: 也用於其他目的(微型SD卡引腳,一些由WiFi驅動程式等),因此,如果您嘗試使用它們(特別是在啟動期間),則可能會遇到問題。

ESP32-CAM連線用於寫程式
如前所述,ESP32-CAM沒有內建的USB連接埠(有助於保持尺寸較小),因此,我們必須使用FTDI程式員對ESP32-CAM進行寫程式。如圖所示,將ESP32-CAM接線,然後通過USB將FTDI與電腦連線到電腦以推動代碼。
*請注意,我們將IO#0與GND連線起來,因為此引腳在閃爍過程中必須很低。
確保將 FTDI跳線設定為正確的設定 。對於上面的設定,您需要將其設定為5V。
ESP32-CAM组件前/背面
正如您在下面的两个图像上看到的那样,ESP32-CAM的前部包含相机连接器端子,LED闪光灯和microSD卡套接字。在背面,我们有内置的天线,可选的外部天线连接器和一个重置按钮。请注意,销钉在后面,因此,如果将ESP32-CAM放在无焊面包板上,您将无法访问重置按钮。
正面

后退

Arduino的ESP32-CAM编程
添加ESP32 JSON文件链接到Arduino IDE
使用带有Arduino的ESP32-CAM需要在Arduino IDE中添加适当的JSON文件链接。这是在Arduino IDE中完成的 – >首选项。在“设置”选项卡中,您将看到“其他董事会经理URL”。当前,我的ESP8266董事会只有JSON文件链接,我以前在其他项目中使用过。现在,我需要添加ESP32-CAM的链接。单击下图中显示的框,将打开一个流行窗口,您可以在其中输入JSON文件的URL。由于我有多个URL,因此我用逗号将它们分开,然后将它们分开输入,然后单击“确定”。请参阅下面的图像(单击图像以扩大它们):
JSON文件链接: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
将ESP32板添加到Arduino IDE
一旦将正确的JSON文件链接添加到Arduino IDE中,就需要在Arduino IDE董事会经理中选择适当的板。第一步是将ESP32董事会添加到Arduino IDE董事会经理中。这样做转到工具 – >董事会 – >董事会经理(请参见下图)。流行窗口打开后,键入ESP32以搜索板,然后通过Espressif Systems安装ESP32 One。根据您的下载速度,安装可能需要一段时间。
安装后,转到工具 – > board – > ESP32 Arduino – > AI思想家ESP32-CAM。请注意,董事会的列表很长,因此请仔细向下滚动以免错过它。请参阅下面的屏幕截图。

ESP32-CAM示例
将视频发送到计算机
如前所述,您需要使用FTDI程序员来对我们的ESP32-CAM进行编程。因此,请确保使用图像所示的FTDI程序员可用并设置。
接下来,将ESP32-CAM连接到FTDI程序员,将FTDI程序员连接到您的计算机(通过USB电缆),请确保选择正确的端口(工具 – >端口),然后转到Arduino IDE,然后转到文件 – >>示例 – >示例 – > ESP32 – >相机 – > Camerawebserver。您将看到下面显示的Arduino代码:
如您所见,在代码开始时,有一些部分可以选择相机模型并输入WiFi凭据。
对于相机型号,让我们选择“ camera_model_ai_thinker ”,请删除“ //”以输入此行,然后添加“ //”以评论其他模型。
对于WiFi凭据,在“ SSID”旁边的报价中输入您的WiFi网络名称,然后在“密码”旁边的报价中输入密码。
接下来,单击Arduino IDE中的“上传”按钮(圆圈指向右侧)。上传代码后, 将IO#0引脚从ESP32-CAM上的GND引脚断开连接 。您只需要在代码上传期间连接它们。

接下来,打开串行显示器并确保将波特率设置为115200,然后按ESP32-CAM背面的重置按钮。您会看到在串行显示器上打印的文本,应该有一条线说“相机准备就绪!使用…”,并将为您提供连接的IP地址。
来自ESP32-CAM的访问视频
转到您的浏览器,然后输入我们的Arduino IDE串行显示器中提供的地址。从上一个图像中,您可以看到我的是“ http://192.168.1.244”,所以我将其复制并粘贴到了浏览器中。转到提供的IP地址后,您将看到一个用户界面。第一步是单击“开始流”。完成后,您将看到来自ESP-32凸轮的图像!请参阅下面的我。
如您所见,您还可以编辑许多参数,例如分辨率,亮度,对比度,饱和等。您还可以水平反映或垂直镜像。也有面部检测/识别功能。
拍照并保存SD卡
在此示例中,我们将使用我们的ESP32-CAM拍照,并将其保存到microSD卡(使用内置microSD卡插槽)。请注意,ESP32-CAM额定功率可使用高达4GB的SD卡,尽管据报道它的工作量高达16GB。该程序将在睡眠模式下具有ESP32-CAM休息,然后我们将通过重置按钮将其唤醒,然后拍摄图片,并将图片保存在microSD卡上。

格式化microSD卡
在此示例中,步骤1是取我们的microSD卡并将其格式化为FAT32。为此,将SD卡连接到您的计算机,请转到“此PC”,然后右键单击SD卡的图标。单击选项以格式化SD卡。您将看到一个带有选项的弹出窗口。在文件系统下,请确保选择 FAT32 并在格式选项下选择“快速格式”的选项,然后单击“开始”。您会看到警告说,如果您格式化,您将丢失SD卡中的所有数据。如果这不是问题,请单击确定。等待,一点,然后您的microSD卡将被格式化。
成功格式化microSD卡后,请转到Arduino IDE并复制/粘贴以下代码:
#include “esp_camera.h”
#include “Arduino.h”
#include “FS.h” // SD Card ESP32
#include “SD_MMC.h” // SD Card ESP32
#include “soc/soc.h” // Disable brownour problems
#include “soc/rtc_cntl_reg.h” // Disable brownour problems
#include “driver/rtc_io.h”
#include <EEPROM.h> // read and write from flash memory
// define the number of bytes you want to access
#define EEPROM_SIZE 1
// Pin definition for CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#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
int pictureNumber = 0;
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
Serial.begin(115200);
//Serial.setDebugOutput(true);
//Serial.println();
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_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// Init Camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf(“Camera init failed with error 0x%x”, err);
return;
}
//Serial.println(“Starting SD Card”);
if(!SD_MMC.begin()){
Serial.println(“SD Card Mount Failed”);
return;
}
uint8_t cardType = SD_MMC.cardType();
if(cardType == CARD_NONE){
Serial.println(“No SD Card attached”);
return;
}
camera_fb_t * fb = NULL;
// Take Picture with Camera
fb = esp_camera_fb_get();
delay(1000);//This is key to avoid an issue with the image being very dark and green. If needed adjust total delay time.
fb = esp_camera_fb_get();
if(!fb) {
Serial.println(“Camera capture failed”);
return;
}
// initialize EEPROM with predefined size
EEPROM.begin(EEPROM_SIZE);
pictureNumber = EEPROM.read(0) + 1;
// Path where new picture will be saved in SD Card
String path = “/picture” + String(pictureNumber) +“.jpg”;
fs::FS &fs = SD_MMC;
Serial.printf(“Picture file name: %s\n”, path.c_str());
File file = fs.open(path.c_str(), FILE_WRITE);
if(!file){
Serial.println(“Failed to open file in writing mode”);
}
else {
file.write(fb->buf, fb->len); // payload (image), payload length
Serial.printf(“Saved file to path: %s\n”, path.c_str());
EEPROM.write(0, pictureNumber);
EEPROM.commit();
}
file.close();
esp_camera_fb_return(fb);
// Turns off the ESP32-CAM white on-board LED (flash) connected to GPIO 4
pinMode(4, OUTPUT);
digitalWrite(4, LOW);
rtc_gpio_hold_en(GPIO_NUM_4);
esp_deep_sleep_start();
}
void loop() {
}
|
提醒
请记住,ESP32-CAM必须以不同的方式进行编程与正常操作:
编程

正常操作

确保您的设置准备好进行编程后,请继续并单击Arduino IDE中的“上传”按钮(圆圈指向右侧)。上传代码后, 将IO#0引脚从ESP32-CAM上的GND引脚断开连接 。当然,您不必使用FTDI进行正常操作。您可以用另一个电源源为电源,也不需要黄色和绿色电缆,但是至少您需要从GND断开IO#0。
测试
在从GND上编程并断开IO#0的编程并断开连接之后,请为您的ESP32-CAM供电,并通过按下内置的重置按钮拍摄几张照片。拍照后,请关闭ESP32-CAM,卸下microSD卡,然后插入计算机。如果需要,请使用USB适配器。检查文件,您应该看到名称为“ image1”,“ image2”,“ image3”等文件,依此类推。
触发PIR运动传感器并保存在SD卡上时拍照
此示例与上面的示例相同,除非现在每当PIR传感器检测到运动时拍摄图片。您可以用任何其他传感器代替,这些传感器基本上可以在您希望拍摄图片时提供高度(甚至可能是外部开关)。对于此示例,我们将使用PIR传感器模仿安全摄像机。有关如何使用PIR传感器的更多详细信息,请查看 此帖子 。

与我们的系统接线
在我们跳入此之前,要考虑到一些重要的事情,并且ESP32-CAM已经使用了一堆IO引脚和SD卡,所以当我们选择添加另一个IO时,事情会变得艰难进入混合。此外,从以前的代码中,请记住,我们基本上是在拍照,并将ESP32-CAM发送到深度睡眠中。然后,我们将其醒来拍另一张照片,然后重新入睡!因此,以前,我们正在使用重置按钮将其唤醒,但是现在我们使用的是外部信号。那么,我们可以使用哪些引脚?
当ESP32-CAM处于深度睡眠状态时,只有系统的低功率部分正在运行(这非常适合节省功率!)。结果,我们只能使用IO PIN 2、4、12、13、14或15唤醒它。此外,我提到了相机和SD卡使用许多引脚,因此当我们不尝试重置ESP32-CAM时,我们选择的销钉都需要免费。为此,我们将添加一个2N2222晶体管( 请参阅此帖子 ),如下所示。目的是将我们的IO PIN链接到地面时,要重置ESP32-CAM(拍照),然后在其他时间将其隔离。在尝试别人没有运气之后,我选择了IO PIN 13。
当一个尝试测试多个引脚时,我使用按钮测试了系统,然后我使用实际的PIR传感器进入了系统。有关两者的详细信息,请参见下文。
Arduino代码
#include “esp_camera.h”
#include “Arduino.h”
#include “FS.h” // SD Card ESP32
#include “SD_MMC.h” // SD Card ESP32
#include “soc/soc.h” // Disable brownour problems
#include “soc/rtc_cntl_reg.h” // Disable brownour problems
#include “driver/rtc_io.h”
#include <EEPROM.h> // read and write from flash memory
// define the number of bytes you want to access
#define EEPROM_SIZE 1
RTC_DATA_ATTR int bootCount = 0;
// Pin definition for CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#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
int pictureNumber = 0;
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
Serial.begin(115200);
Serial.setDebugOutput(true);
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;
pinMode(4, INPUT);
digitalWrite(4, LOW);
rtc_gpio_hold_dis(GPIO_NUM_4);
if(psramFound()){
config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// Init Camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf(“Camera init failed with error 0x%x”, err);
return;
}
Serial.println(“Starting SD Card”);
delay(500);
if(!SD_MMC.begin()){
Serial.println(“SD Card Mount Failed”);
//return;
}
uint8_t cardType = SD_MMC.cardType();
if(cardType == CARD_NONE){
Serial.println(“No SD Card attached”);
return;
}
camera_fb_t * fb = NULL;
// Take Picture with Camera
fb = esp_camera_fb_get();
delay(1000);//This is key to avoid an issue with the image being very dark and green. If needed adjust total delay time.
fb = esp_camera_fb_get();
if(!fb) {
Serial.println(“Camera capture failed”);
return;
}
// initialize EEPROM with predefined size
EEPROM.begin(EEPROM_SIZE);
pictureNumber = EEPROM.read(0) + 1;
// Path where new picture will be saved in SD Card
String path = “/picture” + String(pictureNumber) +“.jpg”;
fs::FS &fs = SD_MMC;
Serial.printf(“Picture file name: %s\n”, path.c_str());
File file = fs.open(path.c_str(), FILE_WRITE);
if(!file){
Serial.println(“Failed to open file in writing mode”);
}
else {
file.write(fb->buf, fb->len); // payload (image), payload length
Serial.printf(“Saved file to path: %s\n”, path.c_str());
EEPROM.write(0, pictureNumber);
EEPROM.commit();
}
file.close();
esp_camera_fb_return(fb);
delay(1000);
// Turns off the ESP32-CAM white on-board LED (flash) connected to GPIO 4
pinMode(4, OUTPUT);
digitalWrite(4, LOW);
rtc_gpio_hold_en(GPIO_NUM_4);
esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 0);
delay(500);
esp_deep_sleep_start();
Serial.println(“This will never be printed”);
}
void loop() {
}
|
测试结果(按钮和PIR传感器)

ESP32-CAM带有视觉处理的OpenCV
在此示例中,我们将重新使用将视频发送到您的计算机(我们介绍的第一个示例)时,然后使用OpenCV将视频通过Python进行处理。
步骤1将是下载Anaconda,然后我们将在Anaconda中下载Python,然后从那里下载。
要下载Anaconda,请访问www.anaconda.com,特别是以下链接:
www.anaconda.com/products/distribution#downloads
从那里下载适合您的计算机的文件。我将安装Windows的一个:


安装Anaconda后,打开Anaconda PowerShell提示。在那里,继续输入以下内容:
conda创建 – 名称Virtuald Python = 3.11
这将导致安装多个软件包:
当被问及是否要继续时,请输入“ Y”。

完全下载和安装后,它将指示这些过程已经完成,并将显示一条消息,要激活虚拟环境,您将需要键入并输入“ Conda激活Virtualenv ”并停用活动环境,您需要输入并输入输入“ Conda停用 ”。

接下来,继续输入和输入“ Conda激活Virtualenv ”,然后键入“ PIP INSTALS OPENCV-CONTRIB-PYTHON ”,进入虚拟环境。此安装可能需要一段时间才能完成。

接下来,输入并输入“ PIP安装请求 ”:

接下来,输入并输入“ PIP Install Cvlib ”::

接下来,输入并输入“ PIP安装TensorFlow ”

接下来,输入并输入“ PIP Install Matplotlib ”

安装了所有这些后,请在下面使用Python代码,然后将其保存在计算机中的文件夹中。
例如Python代码
import cv2
import numpy as np
import requests
import time
import queue
import threading
import cvlib as cv
import matplotlib.pyplot as plt
from cvlib.object_detection import draw_bbox
class VideoCapture:
def __init__(self, name):
self.cap = cv2.VideoCapture(name)
self.q = Queue.Queue()
t = threading.Thread(target=self._reader)
t.daemon = True
t.start()
def _reader(self):
while True:
ret, frame = self.cap.read()
if not ret:
break
if not self.q.empty():
try:
self.q.get_nowait()
except Queue.Empty:
pass
self.q.put(frame)
def read(self):
return self.q.get()
URL = “http://192.168.1.244”
cap = cv2.VideoCapture(URL + “:81/stream”)
if __name__ == ‘__main__':
requests.get(URL + “/control?var=framesize&val={}”.format(8))
while True:
if cap.isOpened():
ret, frame = cap.read()
cv2.imshow(“Output”, frame)
#imgnp=np.array(bytearray(cap.read()),dtype=np.uint8)
#im = cv2.imdecode(imgnp,-1)
bbox, label, conf = cv.detect_common_objects(frame)
im = draw_bbox(frame, bbox, label, conf)
cv2.imshow(‘Output',im)
key = cv2.waitKey(3)
if key == 27:
break
cv2.destroyAllWindows()
cap.release()
|
测试示例
要测试示例,请按照以下步骤:
- 完成示例#1下列出的所有步骤(将视频发送到您的计算机), 但不要通过计算机Web浏览 r连接到ESP32-CAM。
- 打开Anacoda(如果关闭),并通过“ Conda激活Virtualenv ”激活虚拟环境,如果还没有活动。
- 最后,键入“ Python”,然后输入文件路径,您保存了上面显示的Python代码。对我来说,这将是“ python c:\ users \ danie \ downloads \ test.py ”。

接下来,将打开一个窗口,视频实时视频将开始使用计算机视觉。

此示例中使用的组件
*作为亚马逊和eBay助理,我从合格的购买中赚取。
成分 | 关联 |
ESP32-CAM | https://amzn.to/4cZfz4G |