ESP32-CAM 实战教程:网页控制补光灯与远程抓拍

本文面向局域网学习项目:手机打开网页,控制补光灯并抓取一张 JPEG。不同 ESP32-CAM 板型的闪光灯 GPIO、摄像头引脚和供电能力不同,请以实际原理图为准。摄像头只能在获得授权的场景使用。

ESP32-CAM 网页补光与抓拍架构

一、项目目标

很多 ESP32-CAM 项目能显示视频,却没有一个清楚的“拍一张”按钮,也没有办法在暗处先开灯再拍照。本项目做一个简单的局域网页:显示在线状态、补光灯状态和最近一次抓拍时间;用户点击补光按钮后,设备切换 LED;点击抓拍按钮后,设备获取一帧 JPEG 并返回给浏览器。

它适合做工作台观察、植物记录、设备铭牌拍照和小型实验记录。它不是专业闪光灯,也不是公网监控系统。先把一张照片稳定地拍下来,再考虑上传、存储和多设备管理,排错会轻松很多。

二、硬件与供电

准备 ESP32-CAM、OV2640 摄像头、稳定 5 V 电源和 USB 转 TTL 烧录器。很多 AI Thinker 板把闪光灯接到 GPIO4,但其他板型可能不同,GPIO4 还可能与 SD 卡复用。补光 LED 不能由 GPIO 直接承受大电流,必要时使用三极管或 MOSFET 驱动。

摄像头启动、Wi-Fi 发射和补光同时发生时,电流会明显上升。供电线太细、USB 转 TTL 模块能力不足,都可能导致 brownout 和重启。烧录时 GPIO0 接地,完成后断开并重新上电;排线方向、PSRAM 和板型配置也要逐项确认。

三、网页请求流程

ESP32-CAM 补光抓拍流程

网页只发送三个简单请求:/light?on=1、/light?on=0 和 /capture。设备收到请求后先检查当前状态,再执行硬件动作。抓拍时如果补光刚打开,可以等待几十毫秒让画面稳定;如果相机正在被其他请求使用,则返回忙状态,而不是同时抢同一个帧缓冲。

四、帧缓冲与资源归还

esp_camera_fb_get() 返回驱动管理的帧缓冲。使用 JPEG 数据完成响应后,必须调用 esp_camera_fb_return(fb)。不能把指针长期保存,也不能归还后继续读取。抓拍接口的错误路径同样要归还帧,否则连续点击几次就可能把内存和缓冲耗尽。

五、最小代码骨架

下面示例展示关键接口,摄像头引脚配置请参考当前版本的 CameraWebServer 示例:

#include "esp_camera.h"
#include <WebServer.h>

WebServer server(80);
const int LIGHT_PIN = 4; // 按实际板型修改
bool lightOn = false;
uint32_t lastShot = 0;

void handleLight() {
  lightOn = server.arg("on") == "1";
  digitalWrite(LIGHT_PIN, lightOn ? HIGH : LOW);
  server.send(200, "application/json", lightOn ? "{\"light\":1}" : "{\"light\":0}");
}

void handleCapture() {
  if (millis() - lastShot < 1000) {
    server.send(429, "text/plain", "wait before next capture");
    return;
  }
  lastShot = millis();
  camera_fb_t *fb = esp_camera_fb_get();
  if (!fb) {
    server.send(503, "text/plain", "camera busy");
    return;
  }
  server.sendHeader("Content-Disposition", "inline; filename=capture.jpg");
  server.setContentLength(fb->len);
  server.send(200, "image/jpeg", "");
  server.client().write(fb->buf, fb->len);
  esp_camera_fb_return(fb);
}

void setup() {
  pinMode(LIGHT_PIN, OUTPUT);
  digitalWrite(LIGHT_PIN, LOW);
  server.on("/light", handleLight);
  server.on("/capture", handleCapture);
  server.begin();
}

void loop() { server.handleClient(); }

示例中的 server.client().write() 在不同 WebServer 版本上可能需要调整为分块发送。正式代码应检查每次写入结果,并给客户端断开设置超时。网页控制接口不要直接暴露到公网,学习阶段使用受控局域网即可。

六、网页界面设计

页面至少显示设备名称、IP 地址、补光灯当前状态、最近一次抓拍时间和错误提示。按钮点击后先禁用短时间,避免用户连续点击制造并发请求。抓拍结果可以用新的 <img> 标签显示,旧图片不必永久保留在浏览器内存。

七、冷却与互斥

补光灯和抓拍都需要节流。补光灯设置最长连续点亮时间,超过时间自动关闭;抓拍设置冷却时间,避免机械式连点不断占用摄像头。若同时提供视频流,抓拍和视频流应共享明确的访问策略,不要让两个处理函数各自以为自己独占摄像头。

八、常见问题

画面黑但请求成功,先检查曝光、补光 GPIO 和镜头排线;打开补光后重启,先换稳定电源并确认驱动电路;抓拍几次后失败,检查帧缓冲是否每条路径都归还;手机看不到页面,检查手机是否和设备在同一局域网,以及设备 IP 是否变化。

图片模糊不一定是网络问题,可能是夜间曝光时间变长或相机发生抖动。网页显示旧图片时,可以给请求 URL 加递增参数,例如 capture.jpg?seq=12,避免浏览器缓存干扰判断。

九、状态与日志

建议记录抓拍序号、请求时间、图片长度、补光状态、失败原因和空闲堆。页面请求 /status 返回 JSON 快照,视频和抓拍接口不要重复拼接状态字符串。设备重启后可把启动次数和最后一次故障原因显示在状态页,现场排查会比猜测快很多。

十、测试清单

  1. 冷启动后补光灯是否默认关闭;
  2. 连续点击抓拍时是否返回明确的冷却提示;
  3. 手机关闭页面后,设备是否释放客户端和帧缓冲;
  4. 补光灯连续点亮达到上限后是否自动关闭;
  5. 弱 Wi-Fi 和相机忙时是否不会卡死;
  6. 低照度、反光和移动物体下,图片是否满足用途;
  7. 未授权网络是否无法直接访问控制接口;
  8. 断电重启后是否回到安全默认状态。

十一、继续扩展

可以把抓拍图片保存到 SD 卡或上传到局域网服务器,给文件加入时间戳和事件编号;也可以增加光照传感器,让设备在暗处自动建议打开补光。若需要多人查看,把鉴权和存储放到更可靠的局域网主机,ESP32-CAM 只负责采集和响应。

十二、隐私与使用边界

摄像头拍到的内容可能包含人、住址、文件和设备信息。部署前确认拍摄范围、访问人员和保存期限,设置明显的工作指示。不要把无鉴权网页端口映射到公网,也不要在没有得到同意的场景拍摄他人。

十三、总结

这个项目的重点是把补光、抓拍、网页控制和资源释放做成一个可解释的闭环。先让单张 JPEG 稳定返回,再增加视频流、存储和上传;每一步都记录供电、帧大小、耗时和错误,摄像头才会从“能亮”变成“能长期使用的小设备”。

参考资料

打赏

如果这篇学习记录对你有帮助,欢迎扫码支持后续整理。

打赏码

打赏支持:王庆岩

posted on 2026-10-23 13:25  潇洒石头  阅读(8)  评论(0)    收藏  举报

导航