2026寒假练 - 用人工智能硬件实验套件平台实现智能门禁与报警系统
该项目使用了Arduino IDE,实现了一个基于人工智能硬件实验套件平台的智能门禁与报警系统的设计,它的主要功能为:通过人脸识别、语音识别及超声波传感器、OLED、无源蜂鸣器、WS2812灯带、模拟按键、360舵机等模块实现门禁安全管理。
标签
嵌入式系统
ESP32S3
业余的猫
更新2026-03-24
52

一、 所选任务介绍

此次选择的任务是智能门禁与报警系统。

二、 项目介绍

本项目使用ESP32 S3 Sense为主控板,结合DVP摄像头、PDM麦克风、WS2812灯带、LED灯、无源蜂鸣器、ADC按键、OLED屏幕、SG90 360 度伺服电机、超声波传感器实现智能门禁与报警系统。

1.可以通过超声波传感器自动检测是否有人,并自动进入人脸识别检测及声音识别检测流程,过程中使用OLED屏幕显示互动信息,并在不同阶段通过LED灯展示进展,人脸识别及语音识别验证通过则驱动360舵机打开门锁并播放欢迎音乐和灯光。

2.可通过ADC按键在OLED屏幕上查看和删除异常访问记录,并同时启动WEB服务器。在WEB服务器中可以查看、删除异常访问记录的照片、可查看门外实时照片、可调整人脸识别阈值及门禁异常超时限值。

三、 所有使用到的硬件介绍

1. ESP32-S3 Sense

基于 ESP32-S3 芯片,双核、高算力,支持 WiFi / BLE。自带摄像头接口、麦克风模块。外设有GPIOPWMADCI2CSPIUART 等。在项目中用来作为主控,并通过摄像头及麦克风模块实现人脸识别,通过WIFI实现WEB服务器功能。

image.png

2. WS2812 灯带

内置驱动芯片的全彩 LED,单总线控制,只需要一根信号线即可控制每个灯珠的 RGB 颜色,亮度、颜色、动画,供电 5V。在项目中用来显示开门欢迎动画,使用的2号引脚,通过AdafruitNeoPixel库来控制。

image.png

3. 三色 LED

最基础的发光二极管,用来做简单指示。板上自带限流电阻,通过 GPIO 高低电平控制亮灭。在项目中用来指示门禁状态,使用44437号引脚控制。

image.png

4. 无源蜂鸣器

没有内置振荡电路,需要 MCU 输出一定频率的方波才能发声。可通过改变频率发出不同音调,做提示音、警报、简易音乐。在项目中用来播放欢迎音乐,用的是9号引脚,驱动直接使用arduinoTONE

image.png

5. ADC 按键

多个按键共用一个 ADC 输入引脚,通过不同分压电阻产生不同电压。节省 GPIO,适合按键多但 IO 紧张的项目。在项目中用来切换默认及简单设置,使用的引脚是1号,在RTOS任务中通过ADC来读取按键的电压值,区分不同的按键输入。

image.png

6. OLED 屏幕

0.96OLED屏幕,使用SSD1306驱动,具有自发光、对比度高、省电的特点,使用I2C接口。在项目中用来显示交互信息,使用的引脚是56

image.png

7. SG90 360 度伺服电机(连续旋转舵机)

360°舵机是连续旋转,PWM不再控角度,而是控舵机的转速和方向。在项目中用来执行开门动作,使用的是8号引脚,通过ESP32Servo库来驱动,当然直接使用LEDC也是可以的。

image.png

8. 超声波传感器(CS100A

通过发射和接收超声波,计算往返时间得到距离。典型量程 2cm500cm,适合避障、测距、接近检测。在项目中用来监控人员的靠近和离开,使用的引脚是43,通过中断来读取数据。

image.png

9. 转接底板

转接地板提供了各个传感器模块与主控之间的连接接口,可以方便的进行连接和调换。

image.png

最终成品图:

image.png

四、 案框图和项目设计思路介绍

1.      使用edgeimpulse训练图像识别模型,实现人脸识别功能。

2.      原计划继续使用edgeimpulse训练语音分类模型来实现语音识别,实际也训练成功了,但是在实际部署的时候发现edgeimpulse没有提供便捷的双模型部署工具和实际案例,操作起来难度很大,后面转为使用乐鑫预训练好的中文识别模型来实现语音识别。

3.      ADC按键通过RTOS进程了实时检测并通过队列来发送数据。

4.      超声波测距通过中断来实现,提高检测的准确性。

5.      通过WIFI连接网络实现时间同步和WEB服务功能

6.      由于语音识别、人脸识别还有WIFI这些都是比较占用内存和资源的程序,因此整体通过状态机来控制实现分时运行。整体的代码逻辑最终都放入loop循环中通过状态机及读取时间间隔的形式来实现非堵塞式运行。

硬件框图如下:

image.png

 

五、 调试软件及使用的编程语言说明、软件流程图及关键代码介绍

前面提到使用edgeimpulse来训练人脸识别模型,edgeimpulse支持直接生成Arduino库来快速部署到平台,因此这里使用的是Arduino IDE来实现整个项目。Arduino IDE的安装过程具体不再展示,我这里使用的ESP32核心库版本是3.3.4。软件流程图如下:

image.png

 

 

代码主要通过判断枚举变量currentState的值来切换语音识别、人脸识别及开门欢迎等不同的代码模块。同时因模块较多,为保证不阻塞主程序,代码中使用了大量时间变量用来判断运行时长和实现动画效果。另外在使用arduino中的ESP32核心库的ESP-SR时需要注意在启动命令识别模式后会阻塞整个循环,要通过时间等进行控制,避免卡顿。

void loop()

{

    static unsigned long personDetectedStartTime=0;

    int key_id = -1;

    if (xQueueReceive(keyEventQueue, &key_id, 0) == pdTRUE) {

        Serial.printf("Key %d pressed!\n", key_id);

        if( currentState != STATE_INFO ){

            currentState = STATE_INFO;

            ESP_SR.setMode(SR_MODE_OFF);

            ESP_SR.pause();

            u8g2.clearBuffer();

            u8g2.sendBuffer();

            setLedColor(0);

            startWiFi();//启动wifi

            startWebServer();

        }

        switch(key_id){

            case 0:

           

            loadAndShowLog();

            break;

            case 1:

            deleteLog();

            loadAndShowLog();

            break;

            case 2:

 

            break;

            case 3:

            if( currentState == STATE_INFO ){

                currentState = STATE_ULTRASONIC;

                u8g2.clearBuffer();

                u8g2.sendBuffer();

                stopWebServer();

                stopWiFi();//关闭wifi

            }

            break;

        }

    }

    welcomeLightShow();//更新ws2812状态

    updateBuzzer();//更新蜂鸣器状态

    updateLedFlash();//更新LED状态

    checkAndCloseServo();//更新舵机状态

    webServerloop();//更新web服务器

    if (millis() - lastTrigger >= 5000) {

        sonar.trigger();

       

        lastTrigger = millis();

    }

    if (sonar.isReady()) {

        float d = sonar.getDistanceCm();

        if(d>2 && d<80){

            personDetectedStartTime = millis();

            if(currentState == STATE_ULTRASONIC){

                currentState = STATE_FACE_RECOG;

                timeOutStart = millis();

            }    

        }else{

            if((currentState != STATE_ULTRASONIC) && (currentState != STATE_INFO)){

                if(millis()-personDetectedStartTime>10000){//无人则停止认证流程

                    currentState = STATE_ULTRASONIC;

                    ESP_SR.setMode(SR_MODE_OFF);

                    ESP_SR.pause();

                    u8g2.clearBuffer();

                    u8g2.sendBuffer();

                    setLedColor(0);

                }

            }

            if(closeDoor){

                closeDoor = false;//关门

                currentState = STATE_ULTRASONIC;

                setLedColor(0);

                openServoBackward();

                u8g2.clearBuffer();

                u8g2.sendBuffer();

            }

        }

    }

    if((currentState != STATE_ULTRASONIC) && (millis() - timeOutStart >totalTimeout*60000) &&(currentState != STATE_INFO)){//超时记录

        timeOutStart = millis();//触发后更新超时时间,防止重复触发

        setLedColor(3);

        abnCount++;

        saveLog(abnCount);

        camera_fb_t *fb = esp_camera_fb_get();

        takePhoto(fb,"/auto_photo.jpg");

        esp_camera_fb_return(fb);

    }

    if(currentState == STATE_FACE_RECOG){

        if(!inFaceProcessing){

            Serial.println("开始人脸识别");

            inFaceProcessing = true;

            startFaceProcessingTime = millis();

            drawIconString(1, 30, seq, sizeof(seq),2);//正在采集,请对准人脸

            setLedColor(1);

        }else{        

            face_reco();

        }

    }

    if(currentState == STATE_VOICE_RECOG){

        if(!inVoiceProcessing && millis() - waitforVoiceRecog>1000){//确保灯光动画完成

            inVoiceProcessing = true;

            drawIconString(30, 30, seq1, sizeof(seq1),5);//正在识别

            Serial.println("开始语音识别");

            ESP_SR.setMode(SR_MODE_COMMAND);

            ESP_SR.resume();

        }      

        if(millis() - waitforVoiceRecog>20000){

            ESP_SR.setMode(SR_MODE_OFF);

            ESP_SR.pause();

            currentState = STATE_FACE_RECOG;

            inVoiceProcessing = false;

        }

    }  

    if(currentState == STATE_MOTOR_RUN){

        if(!closeDoor){

            ESP_SR.pause();

            drawIconString(30, 30, seq2, sizeof(seq2),5);//欢迎光临

            startUnlockSound();

            startWelcomeLight();  

            setLedColor(0);

            openServoForward();

            closeDoor = true;

            timeOutStart = millis();

        }    

    }

}

六、 功能展示图及说明(实物展示、软件或工具调试)

1.模型训练

 

1.1数据采集及导入

为了方便训练,这里从往上搞了很多照片,便于对比,共计设置了4组人脸和一组未知数据,避免在无人的时候还显示是某个标签。

image.png

1.2模型设置

根据教程知道设置训练前置参数,基本什么都不用动,我这里使用的是灰度数据。


image.png

image.png

1.3数据训练

经过了多轮数据补充和调整,最后效果非常棒。

image.png

1.4部署模型

直接选Arduino library即可,可以看到最后已经到第11版了。其实我还训练了语音命令模型,但是因为不便于部署双模型最后未使用。

模型部署.jpg

2.功能展示

2.1检测到有人进入人脸识别,并显示提示信息。

image.png

2.2人脸识别提示信息结束后实时显示摄像头画面,方便对准人脸。

image.png

2.3人脸识别通过LED灯流水闪烁三次,OLED显示提示信息,进入语音识别阶段。

image.png

2.4语音识别通过,舵机动作,OLED显示欢迎信息,WS2812灯带播放动画,蜂鸣器播放音乐。      


image.png

image.png

2.5检测到无人,舵机归为,屏幕清空。

image.png

2.6按键进入查看信息页面并启动WIFIWEB服务器

image.png

2.7进入WEB服务器后可修改参数、查看实时照片、查看异常记录信息和照片等。

image.png

image.png

image.png

image.png



七、 项目中遇到的难题及解决方法

1.      u8g2崩溃处理

项目中使用OLED屏是通过u8g2库驱动的,在初步将u8g2整合进项目时出现了只要开启u8g2显示,就会导致内存崩溃的异常问题。将异常抛给AI,一一核对验证后确认是u8g2在显示文字前必须设置字体,否则会导致崩溃,不像LVGL有默认字体。

2.      WIFI连接不上

因为项目中用到了WEB服务器,主控需要连接网路。在测试中发现主控运行扫描程序时能正常扫描到网络,但是连接时一直提示找不到对应的接入点,只有和AP靠的很近,外加运气加持的情况下才能连接成功。自己也排查了软件设置、天线是否连接等问题,都没能解决。也通过学习群获得了群友的帮助和提醒,但是问题依旧。后来清空flash烧录单独的WIFI连接程序后正常,再烧录项目程序后还是不能正常连接手机、电脑等分享的网络,但是可以连接路由器的网络。所以只能确认是固件问题,但是根本原因未知(应该是语音识别部分的),先避开使用手机、电脑的共享网络。

image.png

扫描程序显示AP信号很强

image.png

执行连接时无法找到AP

3.      语音识别导致主程序卡顿问题

在项目整合阶段所有功能模块单独测试都正常运作,但是一合并发现出现灯光动画被打断、OLED显示画面不全等问题。这些单独功能模块中只有语音识别是后台运行-看不到运行状态的,因此拿他单独测试。测试程序中只有语音识别,然后在主循环里面循环打印字符,查看打印信息发现在语音识别进入命令识别阶段有5-6秒的时间会堵塞主循环,而且设置了语音识别为OFF模式也会出现这种情况,再查看语音识别库的语音识别API,里面有提供暂停和恢复语音识别任务的函数,增加这个函数外加时间轮询控制后整个工程方正常。

4.      舵机与灯带引脚冲突

在单独进行舵机与灯带测试时,两个例程和模块均能正常工作,而植入最终程序后要么灯带不工作,要么舵机不工作。后来仔细看原理图才发现,这两个模块用的是同一个引脚,真是粗心大意害死人,以后写程序前一定要线看原理图。之后更换灯带到温湿度引脚发现还是不能正常工作,直到换至光敏电阻引脚方才正常,难道GPIO3不能用于驱动WS2812吗,没搞明白。

5.      ADC按键超量程

测试ADC按键时发现第三个和第四个按键均达到了ADC4095,实际查看原理图发现按键是连接在5V电压上的,而本身电阻分压不足,导致主控读取到的电压已超过其量程。之后通过铁板烧的形式将第一颗分压电阻改为了3.3k欧,所有按键均能正常工作了。

八、 心得体会

通过这次活动我学习到了如何快速的训练、部署简单的自定义模型,多模块状态机如何处理,以及遇到问题的排查方向和思路,提高了个人对嵌入式开发的认识。感谢电子森林组织的这次2026年第6届“寒假在家一起练“活动。

附件下载
combine.zip
团队介绍
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号