资阳市网站建设_网站建设公司_营销型网站_seo优化
2026/1/17 3:45:51 网站建设 项目流程

从零打造智能门禁:用ESP32-CAM与Arduino实现人脸识别+RFID双重验证

你有没有遇到过这样的尴尬?出门忘带钥匙,站在家门口干着急;或者同事临时来访,你却没法远程开门。更别提那些密码容易被窥视、指纹识别失灵的糟心时刻了。

今天,我们就来亲手做一个真正“聪明”的门禁系统——不仅能识别人脸自动开门,还能刷卡通行,所有操作都能在手机上实时查看。最关键的是,整个系统成本不到200元,代码开源可改,硬件全部来自常见模块。

主角就是这块小小的ESP32-CAM模块,加上一个几块钱的 RFID 读卡器,再配上 Arduino 的灵活控制逻辑,就能构建出一套媲美商用产品的智能安防方案。


为什么是 ESP32-CAM?它到底强在哪?

市面上做图像识别的开发板不少,树莓派、Jetson Nano 都很强大,但它们贵、耗电高、体积大,不适合长期运行的门禁场景。

ESP32-CAM完全反其道而行之:便宜(不到60元)、小巧(比指甲盖略大)、功耗低,还自带 Wi-Fi 和摄像头接口。它不是为了跑复杂模型设计的,而是专为“边缘视觉”任务优化的——比如拍张照、识个人脸、传个视频流。

它的核心其实是乐鑫的 ESP32 芯片,双核处理器 + Wi-Fi/蓝牙双模通信,再外接一个 OV2640 摄像头传感器,支持最高 1600×1200 分辨率 JPEG 图像输出。虽然算力有限,但在本地运行轻量级人脸检测算法已经绰绰有余。

更重要的是,它完全兼容 Arduino IDE,意味着你可以像写 Blink 灯那样简单地开发视觉应用,不用折腾 Linux 系统和 Python 环境。

关键参数一览(选型必看)

特性参数
主控芯片ESP32-D0WDQ6
摄像头支持OV2640 / OV7670
最高分辨率1600×1200 (UXGA)
视频格式JPEG 编码输出
无线连接Wi-Fi 802.11 b/g/n, Bluetooth 4.2
接口资源UART, I2C, SPI, SD 卡槽, 多个 GPIO
工作电压3.3V
典型功耗~180mA(工作),~6μA(深度睡眠)
尺寸27mm × 18mm

看到没?它甚至还有 MicroSD 卡槽,可以本地存储照片或录像,断网也不怕丢数据。


视频流是怎么“飞”到你手机上的?

很多人以为要实现远程监控就得接云服务器、搞 RTSP 流、配 DDNS……其实对于局域网内的门禁系统来说,最简单的办法是:让 ESP32-CAM 自己当个小服务器

它启动后会连上你的家庭 Wi-Fi,然后开启一个 HTTP 服务,把摄像头画面以 MJPEG 格式实时推送到/stream这个网页路径下。只要你和它在同一网络,打开浏览器输入它的 IP 地址,就能看到实时画面。

这背后其实是两个技术的结合:
-MJPEG:不是真正的视频编码,而是连续发送 JPEG 图片帧,每秒十几张,看起来就像视频;
-异步 Web Server:使用ESPAsyncWebServer库,在不阻塞主程序的情况下处理多个客户端请求。

下面这段代码就是整个系统的“起点”:

#include "esp_camera.h" #include <WiFi.h> #include "esp_timer.h" #include "img_converters.h" #include "camera_index.h" #include "Arduino.h" #include "fb_gfx.h" #include "fd_forward.h" #include "fr_forward.h" #include "FS.h" #include "SD_MMC.h" #include "soc/soc.h" #include "soc/rtc_cntl_reg.h" #include "driver/rtc_io.h" #include "esp_http_server.h" // 摄像头引脚定义(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 // Wi-Fi 配置 const char* ssid = "YOUR_SSID"; const char* password = "YOUR_PASSWORD"; void startCameraServer(); // 声明摄像头服务器函数 void setup() { Serial.begin(115200); // 强制关闭射频模块供电干扰(重要!) WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); 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; // 设置帧缓冲区数量和分辨率 config.frame_size = FRAMESIZE_SVGA; // 800x600 config.jpeg_quality = 12; // 质量越高,延迟越大 config.fb_count = 2; // 双缓冲减少丢帧 // 初始化摄像头 esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed: 0x%x\n", err); return; } // 调整实际使用的分辨率(降低带宽压力) sensor_t *s = esp_camera_sensor_get(); s->set_framesize(s, FRAMESIZE_QVGA); // 320x240 s->set_contrast(s, 1); s->set_brightness(s, 1); // 连接Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); Serial.print("Connected! IP: "); Serial.println(WiFi.localIP()); // 启动摄像头服务器 startCameraServer(); Serial.println("Go to: http://" + WiFi.localIP().toString() + "/"); } void loop() { // 所有服务由RTOS后台任务处理,主循环空闲 }

提示startCameraServer()是官方示例中的标准函数,集成在esp32cam或自定义服务器库中,负责创建/,/stream,/capture等路由。

烧录完成后,打开串口监视器,你会看到类似这样的输出:

Connected! IP: 192.168.1.123 Go to: http://192.168.1.123/

复制这个地址到手机浏览器,就能看到实时画面了。是不是有点像小米摄像头的感觉?


加一道保险:用 RFID 实现刷卡开门

光靠人脸识别够吗?不够。光线差的时候识别不准,戴帽子口罩也可能失败。所以我们再加一层RFID 刷卡验证,形成“人脸 or 卡片”双通道认证。

这里用的是常见的MFRC522 模块,成本不到10元,支持 MIFARE 1K 卡(就是常见的校园卡、门禁卡)。它通过 SPI 与主控通信,读取卡片唯一的 UID 来判断身份。

接线很简单:

MFRC522ESP32-CAM
SDA (SS)GPIO 10
SCKGPIO 14
MOSIGPIO 13
MISOGPIO 12
RSTGPIO 9
3.3V3.3V
GNDGND

⚠️ 注意:ESP32-CAM 的 5V 引脚不能用来供电给其他模块!必须使用外部稳压源或单独供电。

核心代码逻辑如下:

#include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 #define SS_PIN 10 MFRC522 mfrc522(SS_PIN, RST_PIN); // 白名单UID列表(提前用工具读取合法卡的UID) byte authorizedUIDs[][4] = { {0xA1, 0xB2, 0xC3, 0xD4}, {0x12, 0x34, 0x56, 0x78} }; int userCount = 2; void setup() { Serial.begin(9600); SPI.begin(); mfrc522.PCD_Init(); pinMode(13, OUTPUT); // 内置LED或继电器 Serial.println("Waiting for card..."); } void loop() { if (!mfrc522.PICC_IsNewCardPresent()) return; if (!mfrc522.PICC_ReadCardSerial()) return; // 构建当前卡片UID字符串 String currentUid = ""; for (byte i = 0; i < mfrc522.uid.size; i++) { currentUid += String(mfrc522.uid.uidByte[i], HEX); } Serial.print("Detected UID: "); Serial.println(currentUid); // 匹配白名单 bool isAuthorized = false; for (int i = 0; i < userCount; i++) { bool match = true; for (byte j = 0; j < 4; j++) { if (mfrc522.uid.uidByte[j] != authorizedUIDs[i][j]) { match = false; break; } } if (match) { isAuthorized = true; break; } } if (isAuthorized) { Serial.println("✅ Access granted!"); digitalWrite(13, HIGH); delay(2000); digitalWrite(13, LOW); } else { Serial.println("❌ Access denied!"); } mfrc522.PICC_HaltA(); }

💡 实际项目中建议将 RFID 和摄像头共用同一个 ESP32,避免多设备通信延迟。ESP32 完全有能力同时处理 SPI 和 Camera 任务。


系统怎么联动?谁来做决策?

现在有两个身份验证方式:一个是 ESP32-CAM 在跑人脸识别,另一个是 MFRC522 在读卡。那最终要不要开门,由谁说了算?

有两种架构可以选择:

方案一:单主控集中决策(推荐新手)

全部功能集中在 ESP32 上完成:
- 摄像头采集人脸 → 本地匹配模板 → 输出结果
- RFID 读卡 → 匹配白名单 → 输出结果
- 任意一项通过 → 触发 GPIO 控制继电器 → 开锁

优点:结构简单,无需设备间通信;缺点:代码较复杂,资源占用高。

方案二:双控制器协同(适合扩展)

  • ESP32-CAM 专注图像处理,只负责上报“是否识别成功”
  • Arduino Mega 负责整合 RFID、接收 ESP32 的识别信号、控制继电器
  • 使用串口或 I2C 通信协调动作

优点:分工明确,便于后期加入更多传感器;缺点:需要解决同步问题。

我们推荐先从方案一入手,等稳定后再拆分功能。


继电器怎么控制电子锁?安全细节要注意!

识别通过后,怎么把“允许通行”变成“门开了”?靠的就是继电器模块

通常选用 5V 继电器,控制端接 ESP32 的某个 GPIO(如 GPIO 4),输出端串联电磁锁电源回路。当 GPIO 输出高电平,继电器吸合,电路导通,锁打开。

注意事项:

  • 电磁锁功率较高,必须外接独立电源(12V/2A),不能靠 ESP32 供电;
  • 继电器线圈侧建议加续流二极管防止反电动势损坏主板;
  • 锁体类型选择“断电开锁”还是“通电开锁”,根据安全需求决定(消防要求通常是断电开门);
  • 加入延时自动关门机制(如 3 秒后断开继电器)。

示例控制代码片段:

#define RELAY_PIN 4 void openDoor() { digitalWrite(RELAY_PIN, HIGH); // 吸合继电器 delay(3000); // 保持3秒 digitalWrite(RELAY_PIN, LOW); // 断开 }

实战经验:这些坑我替你踩过了

❌ 坑点1:摄像头初始化失败

常见错误提示:“Camera init failed with error 0xXXXXXXXX”

原因
- 接触不良(排针焊接松动)
- 电源不足(USB线太细导致电压跌落)
- 忘记关闭射频干扰(需添加WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);

秘籍:每次烧录前务必断电重启,最好用外部 5V/2A 电源直接供电。


❌ 坑点2:RFID 读不到卡

明明靠近了还是没反应?

排查步骤
1. 检查 SPI 接线是否正确(尤其 SCK/MOSI/MISO 是否接反)
2. 查看 RST 和 SDA 是否接到指定 GPIO
3. 用示例程序ReadUID先测试基础通信
4. 避免天线靠近金属物体或电源线


❌ 坑点3:视频流卡顿严重

画面一顿一顿的,根本没法看。

优化方法
- 降低分辨率至 QVGA(320x240)
- 提高 JPEG 质量等级(值越大压缩越狠,但CPU负担小)
- 减少帧率(修改xclk_freq_hz或软件限帧)
- 客户端不要同时打开超过2个连接


✅ 秘籍:如何提升人脸识别成功率?

虽然 ESP32-CAM 支持 TensorFlow Lite Micro,但要在资源受限环境下做人脸识别,建议采取以下策略:

  1. 先检测后识别:用 Haar-like 算法快速定位人脸区域,再裁剪送入模型;
  2. 模板比对代替分类:提前注册用户正脸照片,提取特征向量存入 Flash,实时比对欧氏距离;
  3. 多帧投票机制:连续5帧都识别成功才算通过,避免误触发;
  4. 动态曝光补偿:根据环境亮度自动调节摄像头增益,保证夜间也能看清人脸。

GitHub 上已有成熟项目如face_recognition可参考移植。


成本估算 & 可扩展方向

📦 物料清单(总价约 ¥180)

模块单价数量
ESP32-CAM 模块¥551
MFRC522 RFID 模块¥81
MIFARE 卡¥22
5V/2A 电源适配器¥151
继电器模块¥51
电磁锁(12V)¥601
杜邦线 + 面包板¥101套
外壳(可选3D打印)¥201

💬 如果只是学习演示,可用 LED 替代继电器,省去高压部分。


🚀 下一步还能怎么玩?

  • 微信通知:接入 ESP-NOW 或 MQTT,识别成功后推送消息到手机;
  • 本地存储记录:利用 SD 卡保存每次开门的时间、照片缩略图;
  • 远程OTA升级:固件更新不用拆机,直接在线下载;
  • 语音提示:加一个小喇叭播放“欢迎回家”、“验证失败”等语音;
  • 防尾随检测:通过视频分析判断是否有多人连续进入;
  • 太阳能供电版:搭配锂电池和充电模块,部署在无电源场所。

写在最后:这不是玩具,是真实的生产力工具

这套系统看似简单,但它已经具备了一个现代智能门禁的核心能力:
-生物识别 + 物理凭证双重认证
-本地处理 + 远程访问的混合架构
-低成本 + 易维护的开源模式

它不仅适用于家庭、办公室、实验室,还可以作为教学案例让学生理解物联网、嵌入式系统、安全协议的实际应用。

更重要的是,它是完全开放的。你可以自由修改代码、更换算法、增加功能,而不受厂商闭源系统的限制。

如果你正在寻找一个既能练手又能实用的 IoT 项目,那么这个基于 ESP32-CAM 与 Arduino 的门禁系统,绝对值得你花一个周末动手试试。

🔧 项目源码已整理上传至 GitHub,包含完整 wiring 图、配置指南和调试日志模板,欢迎 Star & Fork。

👉 评论区留下你的问题,我们一起解决实战难题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询