提示:该项目建立于ubuntu18.04版本,esp-idf版本为4.4.1,ESP32S3-EYE开发板由乐鑫公司提供,在此表示感谢。项目中的rPPG技术来源于github上的nasir,本项目所有代码均已开源放置于github中,链接在文章底部可以找到
文章目录
前言
本文记录了物联网竞赛的项目开发全过程,包含了ESP32S3-EYE使用模块,人脸识别和rPPG代码模块,数据库连接模块,以及基于APICloud开发的软件模块
一、ESP32-S3-EYE模块
硬件部分
-
开发板简介
ESP32-S3-EYE 是一款小型人工智能开发板,搭载 ESP32-S3 芯片和乐鑫 AI 开发框架 ESP-WHO。开发板配置一个 2 百万像素的摄像头、一个 LCD 显示屏和一个麦克风,适用于图像识别和音频处理等应用。板上还配有 8 MB 八线 PSRAM 和 8 MB flash,具有充足的存储空间。此外,开发板上的 ESP32-S3 芯片还提供了 Wi-Fi 图传和 USB 端口调试等功能。
-
本项目使用部分
摄像头:OV2640摄像头
LCD显示屏
Wi-Fi图传功能
软件部分
-
ESP-IDF环境搭建(ubuntu18.04)
由于国内网速问题,下载esp-idf时都会遇到各种克隆失败的问题,为了解决这个问题,借鉴了一些博主的方法,总结了一下esp-idf稳定下载的方法:
//下载gitee工具
git clone https://gitee.com/EspressifSystems/esp-gitee-tools.git
//下载指定版本的esp-idf(此处采用稳定版本V4.4)
git clone -b release/v4.4 https://gitee.com/EspressifSystems/esp-idf.git
//进入工具目录,执行命令更新子模块(user部分为你的用户名)
cd esp-gitee-tools
./submodule-update.sh ~/esp/esp-idf
//下载所需要的固件
cd ~/esp/esp-idf
export IDF_GITHUB_ASSETS="dl.espressif.com/github_assets"
./install.sh
//添加get_idf快捷方式
nano ~/.bashrc
alias get_idf='. $HOME/esp/esp-idf/export.sh'
之后就可以在任何地方打开get_idf 啦!
- ESP-WHO下载和使用
获取ESP-WHO
git clone --recursive https://github.com/espressif/esp-who.git
打开esp-who文件夹后打开esp-idf
cd esp-who
get_idf
设定目标芯片
idf.py set-target [SoC] #[SOC]替换成目标芯片,如esp32s3
编译并烧录程序(运行IDF监视器)
idf.py build
idf.py flash monitor
PermissionError: [Errno 13] Permission denied: ‘/dev/ttyACM0’
在烧录的过程中,可能会出现上面的问题,原因是只有root用户和属于dialout组的用户会有读写权限,因此需要开启
sudo usermod -aG dialout user //user为自己的用户名
reboot
这样就可以进行正常的烧录了
- Micropython & Pycharm & ESP32s3 环境搭建
因为我们的代码主要以python语言为主,所以刚开始小组采用的是配置一个micropython固件,这样方便后续代码编写
(1)配置pycharm环境
下载Micropython插件

配置Micropython接口,language->micropython->Enable micropython support,devicetype选择pybord(ESP32系列)device path选择esp32对应的接口:
COM7(Windows),/dev/ttyACM0(Ubuntu18.04)

(2)刷写ESP32S3固件
1.下载刷写工具
Windows10:esp刷写工具
Ubuntu18.04: esptool官方刷写工具
2.micropython固件下载
固件官网下载地址
根据自己的主控板选择对应的固件,注意下载".bin"格式的文件
3.开始刷写
首先进行擦除,其中/dev/ttyACM0为ubuntu系统中的接口地址
esptool.py --chip esp32 --port /dev/ttyACM0 erase_flash
然后进行烧录,board-20210902-v1.17.bin为自己下载的固件(务必在有固件的文件夹中进行刷写,否则找不到固件)
esptool.py --chip esp32s3 --port /dev/ttyACM0 write_flash -z 0 board-20210902-v1.17.bin
(3)将写好的程序烧录进芯片中

但是小组后面遇到一些网络连接问题,比如在尝试用Micropython中的WLAN模块实现WiFi连接时,出现无法连接的情况,因此最终决定在esp-idf的环境下进行编程
通信部分
-
传输方式确认
opencv的IP视频流传输测试:
一开始项目尝试用opencv去基于IP地址看能否直接获取到摄像机的视频流。但是经过反复尝试以及各类资料查找之后,我们认为opencv的视频流传输是基于IP-CAMERA的。但是ESP32-S3的摄像头应当只是挂载在芯片上的一个设备,虽然提供了连接的IP,但是不符合opencv的该方法要求。
确定此点的来源是由于在opencv的接收当中会指定一个URL,其内部有着用户名称和密码。然而在ESP32-S3配置过程中,没有涉及到该点。
基于网页抓取的图片获取测试:
项目萌生过采用python的网页抓取的技术将图片抓取到本地算法进行运行的思路。虽然该方法简单易执行,但是需要打开网页进行操作。这一特点有些违背了物联网的初衷,也同时没有发挥芯片的作用。
wireshack抓包分析和方法确定:
由于ESP32-S3提供的ESP-WHO示例当中有着能够在网页端的摄像机画面流获取。因此我们萌生出了同样的想法,基于此示例去进行我们的传输编写。
该方法需要解决以下问题:网页对芯片发回的数据处理成了什么格式?网页如何同芯片建立起的传输?芯片发回给网页的报文是什么格式?我们如何编写自己的传输方式?
(1)网页呈现格式的确定:
ESP32-S3的摄像头应当是OV2640的版本,在网页运行的情况下,其传输的呈现框位置和元素如下:

其实际上将接收到的数据设置为了img元素,即网页端也不是通过视频流直接显示,而是通过了某种报文将摄像头的画面存到了报文当中,再将其传送给网页解析。
(2)传输报文的确定:
由于在网页当中进行元素审查和脚本查找并不方便,所以我们根据该文件名字,在/esp-who/components/web/www下找到了index_ov2640.html即网页的源码。

同时,由于当前的文件夹下有着app_httpd和app_wifi的文件,我们敲定:该网站是要通过芯片联网之后,通过httpd的报文将其传输到网页端进行解析的。由于httpd实际就为apache下的http协议,所以我们的初步思路就为:可否截取芯片发送的报文?
这一思路需要我们进行发送报文的确定,然而由于芯片代码实际上是写死的,那其就相当于一个服务器,而我们只需要模拟用户端向其发送报文即可获得其返回的相机帧。
该点我们最终通过wireshack的抓包进行。思路如下:
1、先打开wireshack,让其接受一段时间的计算机报文,大致确定没有流传输的情况下报文的情况

2、随后,点击网页端的传输流开启按钮,再在wireshack当中看此时的报文特点。经过比对,我们发现在网页端显示的 IP为172.20.10.5的时候,以此为参考出现了大量的172.20.10.5和172.20.10.6的报文。由此,我们初步推测,该视频流的传输是建立在该两个IP上的传输。
3、将wireshack重启,重新获取报文,此时输入筛选条件ip.src=172.20.10.5 && ip.dst==172.20.10.6,之后,点击一次开始流传输之后立马点击关闭,wireshack当中出现了不少符合条件的报文。由于http实际基于tcp传输,则tcp一定会有一个建立传输的握手过程,通过源IP和目标IP的相互调换和调整,找到发出tcp连接请求的报文,即内容为SYN的报文,其源IP就是连接的请求端。通过这一方法我们确认了172.20.10.5为服务器端(芯片),172.20.10.6为客户端(网页)
4、通过客户端的发送报文,我们找到了触发芯片发送的HTTP报文如下:

即我们需要在程序内发送该报文,然后就能接收到来自芯片的流信息。且同时根据html的源码和报文的目标端口,我们确定了端口为81。即报文的传输目的地为172.20.10.5:81 -
芯片发送
虽然ESP提供了socket,但是在层层深入之后,我们发现实际上调用的是<sys/socket.h>头文件进行的再一步封装。则我们直接采用socket。
由于我们只需要图片的比特信息,所以删除了全部的测试报文发送。只要是能够正确进行jpg解码的即ESP_OK的状态,我们就直接开始建立图片的收发socket,而建立起httpd连接的socket只起到一个能够正确进入到图片socket建立的工具而在图片的传输过程中废用。
同样,基于之前连接局域网的方式,我们推测实际芯片的另外函数当中,也是允许局域网内的全部设备连接的。所以我们将socket设置为INADDR_ANY即可不用写死芯片的连接IP。连接之后,发送两个报文,第一个发送帧长度即Byte数,第二个发送fram的比特数据。发送完后为了后续连接的正确建立,则直接关闭socket。等待下一个http get /stream的报文进入在进行下一次发送。虽然存在tcp的建立开销,但是在局域网内该开销同图片传输处理的开销相比可以忽略
如下完成一次帧传输:
//解码成功的,创建socket
int serveSocket;
int clientSocket;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
socklen_t sin_size;
memset(&server_addr,0,sizeof(server_addr)); //数据初始化--清零
server_addr.sin_family=AF_INET; //设置为IP通信
server_addr.sin_addr.s_addr=INADDR_ANY;//服务器IP地址--允许连接到所有本地地址上
server_addr.sin_port=htons(8888); //服务器端口号
/*创建服务器端套接字--IPv4协议,面向连接通信,TCP协议*/
if((serveSocket=socket(PF_INET,SOCK_STREAM,0))<0)
{
ESP_LOGE(TAG, "socket error")

本文记录物联网竞赛项目开发全过程,涉及ESP32-S3-EYE模块,包括硬件、软件和通信部分;实现人脸识别和rPPG非接触式心率检测;完成服务器和数据库部署;采用APICloud开发软件模块,代码已开源。
最低0.47元/天 解锁文章
1916

被折叠的 条评论
为什么被折叠?



