简介:本资源是一套面向嵌入式AI初学者与课程设计者的完整项目实践方案,聚焦无接触式红外体温监测与多模态身份识别场景,解决公共场所防疫测温、人脸核验与口罩佩戴合规性判断等实际需求。压缩包共198个文件,含41个C语言源码(.c)与39个头文件(.h),覆盖STM32F103底层驱动(如usart.c、i2c.c、adc.c、tim.c)、OpenMV图像处理逻辑及神经网络模型推理接口;另有30个编译中间文件(.o/.d)、3个Python脚本(用于模型训练或数据预处理)、2个Word文档(含系统说明与硬件连接图)及Keil工程文件(uvprojx/uvoptx)等,整体8.03MB,结构清晰、模块解耦明确。已有60人学习下载,提供可直接烧录的hex与axf镜像、GY906DCI红外测温校准代码、基于Adaboost的轻量口罩检测实现、以及适配OpenMV的TinyML人脸识别tflite模型,配套OLE集成接口便于对接上位机系统,是嵌入式+AI融合开发的典型教学级工程范例。
1. 项目概述与核心价值
最近在捣鼓一个挺有意思的玩意儿,一个集成了无接触测温、人脸识别和口罩检测的嵌入式系统。核心就是一块经典的STM32F103C8T6最小系统板,加上一个OpenMV Cam H7摄像头模组,再外挂一个GY-906 DCI红外测温模块。这组合听起来是不是有点“复古”搭配“新潮”的感觉?STM32F103作为十年前就火遍大江南北的MCU,至今在成本敏感、性能要求不极致的场景里依然有顽强的生命力,而OpenMV则让复杂的机器视觉开发变得像搭积木一样简单。
这个项目的核心目标很明确:在特定出入口或通道,实现非接触式的快速体温筛查,并同步完成身份核验与口罩佩戴检查。想象一下,在办公楼大堂、学校宿舍楼入口或者小型诊所的预检分诊台,人员走过,系统能自动完成“体温正常/异常”、“是谁”、“是否佩戴口罩”这三重判断,并将结果实时显示在一块小屏幕上,甚至通过串口上报给上位机。这比单纯拿个额温枪一个个测,效率要高得多,也减少了人员近距离接触的风险。
我选择STM32F103,就是看中了它的稳定、便宜和资料海量。虽然它的主频只有72MHz,内存也只有20KB的SRAM,处理复杂的图像算法肯定力不从心,但作为整个系统的“大脑”和“调度中心”却绰绰有余。它负责读取GY-906的温度数据、通过串口与OpenMV进行指令交互和数据接收、控制外围设备(比如报警蜂鸣器或指示灯)、管理OLED显示屏的刷新。而所有“重体力活”——人脸检测与识别、口罩检测——都交给了OpenMV。OpenMV内置的MicroPython解释器和丰富的机器视觉库,让我们可以用高级语言快速开发视觉算法,其专用的图像传感器和处理器为这些任务做了优化,性能远超在STM32上裸跑同类算法。
GY-906 DCI模块选用的是MLX90614 ESF-BCC这款传感器,它通过I2C接口通信,能测量物体表面温度,精度在±0.5℃以内(在医疗级校准后),测量距离大致在2-5厘米到数米不等(取决于光学镜头),完全满足无接触测温的需求。整个系统的难点和乐趣,就在于如何让这三个性格迥异的模块协调工作,稳定、准确地完成既定任务。
2. 系统整体设计与硬件选型思路
2.1 核心架构与通信链路设计
整个系统的架构可以看作一个主从式结构。STM32F103作为主机(Master),承担系统控制核心的角色;OpenMV和GY-906作为从设备(Slave)。它们之间的通信链路是系统的血管,设计好坏直接决定系统的稳定性和响应速度。
1. STM32F103 与 OpenMV 的通信:这是数据流的核心。我选择了异步串口(UART)作为通信方式。为什么不选SPI或I2C?主要基于以下几点考虑:
- 协议简单,容错性好:UART是异步通信,不需要时钟线,连接简单(仅需TX、RX、GND三线)。在OpenMV端,我们可以直接用
pyb.UART类来读写;在STM32端,使用HAL库的HAL_UART_Transmit和HAL_UART_Receive函数即可。协议可以自定义,例如,STM32发送一个字节的命令码(如0xA1代表请求人脸识别),OpenMV收到后执行相应任务,并将结果(如识别到的ID号、置信度)打包成特定格式的数据帧回传。 - 带宽足够:对于传输识别结果、坐标、温度值等小数据包,115200bps甚至9600bps的波特率都绰绰有余,远高于实际需求。
- 开发调试方便:双方都可以方便地通过串口打印调试信息到PC,便于联调。
在实际连接时,需要特别注意电平匹配。STM32F103的IO口是3.3V电平,OpenMV Cam H7的UART引脚也是3.3V,因此可以直接相连。连接方式是:STM32的USART1_TX (PA9) 接 OpenMV的RX引脚;STM32的USART1_RX (PA10) 接 OpenMV的TX引脚。务必交叉连接,并共地。
2. STM32F103 与 GY-906 的通信:GY-906(MLX90614)模块使用I2C接口。这是一个标准的、低速的、半双工的同步串行总线。STM32F103的硬件I2C(如I2C1)配置起来相对直接,使用HAL库的HAL_I2C_Mem_Read函数可以很方便地读取传感器内部RAM中的温度数据。
- 引脚连接:STM32的I2C1_SCL (PB6) 接 GY-906的SCL;STM32的I2C1_SDA (PB7) 接 GY-906的SDA。同样需要上拉电阻(通常模块板上已集成),并共地。
- 地址问题:MLX90614的默认7位I2C地址是0x5A(写地址0xB4,读地址0xB5)。如果总线上只有一个传感器,直接使用这个地址即可。
3. 显示与交互:选用一块0.96寸或1.3寸的OLED显示屏(SSD1306驱动),通过I2C或SPI与STM32连接。I2C方式更省IO口(仅需2根数据线),适合本项目。显示屏用于实时显示测温结果、识别出的姓名、口罩佩戴状态以及系统状态提示。
2.2 关键硬件模块深度解析
STM32F103C8T6最小系统板:这是项目的“老黄牛”。它的资源规划是关键:
- USART1 (PA9/PA10):用于与OpenMV通信。这是全双工串口,稳定性好。
- I2C1 (PB6/PB7):一拖二。同时连接GY-906测温模块和OLED显示屏。这里需要注意I2C总线的负载和上拉电阻强度。两个设备地址不同(GY-906: 0x5A, SSD1306: 0x3C),不会冲突。
- GPIO口:分配几个IO口用于控制LED状态灯、蜂鸣器(用于体温超标报警)或按键输入。
- 时钟与电源:确保使用外部8MHz晶振,并通过PLL倍频到72MHz,以获得稳定性能。整个系统的供电需要稳定,建议使用AMS1117-3.3V等LDO为STM32、OpenMV(其内部有DCDC)、OLED和GY-906提供干净的3.3V电源。注意总电流需求,OpenMV在峰值运行时耗电可能超过250mA。
OpenMV Cam H7:这是项目的“智慧之眼”。OpenMV H7相比前代M7,核心升级为STM32H7系列MCU,主频更高,内置的硬件JPEG编码器和专用图像处理外设使其处理图像流更加流畅。我们需要在其上运行两个核心任务:
- 人脸识别:使用OpenMV IDE自带的
Face Recognition库。这个库底层基于LBP(局部二值模式)特征和级联分类器,虽然不如深度学习模型准确,但在嵌入式端速度极快。你需要先采集用户的人脸图像作为样本,然后训练一个识别模型。训练好的模型文件(例如person.pgm)会存储在OpenMV的Flash中。 - 口罩检测:这是本项目的一个亮点。OpenMV官方库可能不直接提供口罩检测模型。一种经典方法是使用Haar-like特征和Adaboost算法训练一个级联分类器。你可以使用PC上的工具(如OpenCV)收集大量戴口罩和不戴口罩的人脸正负样本,训练生成一个
.xml格式的级联分类器文件,然后将其加载到OpenMV中,使用image.find_features()函数进行检测。另一种更现代、可能更准确的方法是使用TensorFlow Lite Micro,将一个小型的、针对口罩检测优化的神经网络模型(如MobileNetV2-SSD)转换成C数组,集成到OpenMV的固件中。但这需要一定的模型转换和固件编译能力。
GY-906 DCI红外测温模块:关键点在于理解其工作原理和校准。MLX90614内部包含一个红外热电堆传感器和一个用于测量环境温度的PTAT传感器。它通过测量物体发射的红外能量和环境温度,运用内置的DSP和算法计算出物体表面温度。
- DCI与非DCI:DCI代表“数字控制接口”,通常指带有一个简单的光学镜头,能提供较小的视场角(如约10°),实现更精确的定点测量,适合本项目这种需要对特定区域(如额头)测温的场景。
- 精度与校准:出厂校准是针对特定距离和发射率的(通常默认发射率为0.95,适用于大多数人体皮肤)。对于高精度医疗应用,可能需要在一个已知温度的黑体辐射源前进行二次校准,以修正传感器之间的个体差异和环境漂移。在代码中,我们读取的是传感器RAM中的
TOBJ1(物体1温度)和TA(环境温度)寄存器值。
3. 软件实现与核心代码剖析
3.1 STM32端主控程序框架
STM32的程序使用STM32CubeIDE开发,基于HAL库,整体采用前后台(超级循环)架构,结合中断处理异步事件。
// 主循环伪代码框架 int main(void) { // HAL初始化、时钟配置、外设初始化(UART, I2C, GPIO等) System_Init(); OLED_Init(); OLED_ShowString(0, 0, "System Booting..."); // 初始化状态变量 float body_temp = 0.0; uint8_t face_id = 0xFF; // 0xFF表示未识别 uint8_t mask_status = 0; // 0:未知,1:佩戴,2:未佩戴 uint32_t last_check_time = 0; while (1) { // 1. 定时读取温度(例如每秒一次) if (HAL_GetTick() - last_check_time > 1000) { if (MLX90614_ReadTemp(&body_temp) == HAL_OK) { OLED_ShowTemp(body_temp); if (body_temp > TEMP_THRESHOLD) { // 例如37.3℃ Buzzer_Alert(ON); } else { Buzzer_Alert(OFF); } } last_check_time = HAL_GetTick(); } // 2. 向OpenMV发送指令,请求执行视觉任务 // 可以设计为轮询或由外部事件触发(如人体传感器) UART_SendCmd(CMD_FACE_AND_MASK_DETECT); // 3. 接收并解析OpenMV返回的数据 if (UART_RxFlag) { // 串口接收完成中断置位标志 Parse_OpenMV_Data(rx_buffer, &face_id, &mask_status); UART_RxFlag = 0; // 更新显示 OLED_ShowFaceID(face_id); OLED_ShowMaskStatus(mask_status); } // 4. 其他任务,如按键扫描、状态灯控制等 Key_Scan(); // ... HAL_Delay(10); // 防止CPU空转过快 } }串口通信协议设计示例:为了保证数据可靠传输,需要设计一个简单的帧结构。
- STM32 -> OpenMV(命令帧):
帧头(0xAA) + 命令字(1字节) + 帧尾(0x55)- 命令字定义:0xA1 - 执行人脸识别;0xA2 - 执行口罩检测;0xA3 - 执行人脸+口罩检测。
- OpenMV -> STM32(数据帧):
帧头(0xBB) + 数据长度(1字节) + 人脸ID(1字节) + 口罩状态(1字节) + 置信度(1字节,可选) + 校验和(1字节) + 帧尾(0xCC)- 校验和可以是前面所有字节的简单累加和取低8位。
3.2 OpenMV端视觉算法实现
OpenMV端的代码使用MicroPython编写,在OpenMV IDE中开发。核心是一个状态机,等待串口命令,执行相应任务并返回结果。
# OpenMV 主程序框架 (main.py) import sensor, image, time, pyb from pyb import UART # 初始化摄像头 sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) # 320x240,平衡速度与精度 sensor.skip_frames(time = 2000) # 初始化串口 uart = UART(3, 115200) # 使用UART3,根据实际接线调整 uart.init(115200, bits=8, parity=None, stop=1) # 加载人脸识别模型和口罩检测分类器 face_cascade = image.HaarCascade("frontalface", stages=25) # 人脸检测 # 假设我们已经训练好了人脸识别模型 face_recog_model = image.load_model("person.pgm") # 加载口罩检测的Haar Cascade或初始化神经网络模型 mask_cascade = image.HaarCascade("mask_cascade.xml") # 需要自己训练 def find_face_and_mask(): img = sensor.snapshot() faces = img.find_features(face_cascade, threshold=0.5, scale=1.25) result = {'face_id': 0xFF, 'mask': 0} if faces: for face in faces: # 在每个人脸区域进行识别和口罩检测 # 1. 人脸识别 face_img = img.copy(roi=face).compress(quality=90) # 裁剪人脸区域 # 这里需要将face_img转换为模型接受的格式,具体取决于模型 # face_id, confidence = face_recog_model.recognize(face_img) # 简化示例:假设识别结果 face_id = 1 confidence = 85 # 2. 口罩检测 (在脸部的下半部分区域进行) # 假设口罩区域在人脸下半部分 mouth_roi = (face[0], face[1] + face[3]//2, face[2], face[3]//2) masks = img.find_features(mask_cascade, roi=mouth_roi, threshold=0.4) mask_status = 1 if masks else 2 # 1:有口罩特征,2:无 result['face_id'] = face_id result['mask'] = mask_status # 画框和标签(用于本地调试预览) img.draw_rectangle(face, color=(0, 255, 0)) img.draw_string(face[0], face[1]-10, "ID:%d M:%d" % (face_id, mask_status), color=(255, 0, 0)) break # 假设只处理检测到的第一个人脸 return result while(True): if uart.any(): cmd = uart.read(1) if cmd == b'\xa3': # 接收到人脸+口罩检测命令 data = find_face_and_mask() # 打包数据帧 frame = bytearray([0xBB, 0x03, data['face_id'], data['mask'], 0x00]) # 长度3字节 checksum = sum(frame[1:-1]) & 0xFF # 计算校验和,排除帧头 frame.append(checksum) frame.append(0xCC) uart.write(frame)注意:上面的口罩检测部分使用了Haar Cascade作为示例,实际效果受训练数据质量影响极大。对于更可靠的效果,强烈建议探索集成TensorFlow Lite Micro模型。OpenMV官方有相关教程,需要将
.tflite模型转换为C数组,并编写对应的推理代码。
3.3 温度读取与数据处理
STM32端读取GY-906温度的代码相对标准。
#define MLX90614_ADDR (0x5A << 1) // HAL库I2C地址是7位地址左移1位 HAL_StatusTypeDef MLX90614_ReadTemp(float *temp) { uint8_t data[3] = {0}; uint16_t temp_raw; float temp_celsius; // 读取物体温度寄存器 TOBJ1 (地址 0x07) if (HAL_I2C_Mem_Read(&hi2c1, MLX90614_ADDR, 0x07, I2C_MEMADD_SIZE_8BIT, data, 3, HAL_MAX_DELAY) != HAL_OK) { return HAL_ERROR; } // 数据格式:低8位、高8位、PEC校验(本项目暂忽略PEC) temp_raw = (data[1] << 8) | data[0]; // 原始数据是Kelvin * 0.02, 转换为摄氏度 temp_celsius = (float)temp_raw * 0.02 - 273.15; *temp = temp_celsius; return HAL_OK; }温度滤波:红外测温容易受到环境气流、被测物体表面反射率(发射率)波动的影响,读数可能会有跳动。可以在STM32端加入简单的软件滤波,例如滑动平均滤波或一阶低通滤波。
#define FILTER_ALPHA 0.2f // 滤波系数,越小越平滑,响应也越慢 float filtered_temp = 0.0; void LowPass_Filter(float new_sample, float *old_value) { *old_value = FILTER_ALPHA * new_sample + (1 - FILTER_ALPHA) * (*old_value); } // 在主循环中调用 LowPass_Filter(body_temp, &filtered_temp); OLED_ShowTemp(filtered_temp); // 显示滤波后的温度4. 系统集成、调试与性能优化实战
4.1 多模块联调与问题定位
当所有硬件连接好,代码分别烧录后,真正的挑战才开始。联调时最常见的问题:
通信不通:
- 现象:OLED不显示,OpenMV无反应,温度读数为0。
- 排查:
- 电源第一:用万用表测量各模块的VCC和GND引脚电压是否为稳定的3.3V。特别是OpenMV,启动电流大,劣质USB线或供电不足会导致反复重启。
- 接线复查:这是最常出错的地方。务必确认UART的TX-RX是交叉连接,I2C的SDA/SCL线是否接反,所有GND是否共地。
- 逻辑分析仪/示波器是神器:接上逻辑分析仪,看UART/I2C总线上是否有波形。如果没有波形,检查STM32代码中对应外设的初始化、时钟使能。如果有波形但乱码,检查波特率、数据位、停止位设置是否两端一致。
OpenMV识别不稳定:
- 现象:人脸时而被识别,时而不能;或者识别ID跳变。
- 解决:
- 光照是魔鬼:机器视觉极度依赖光照。确保测试环境光线均匀,避免强逆光、侧光造成的面部阴影或过曝。可以考虑在OpenMV摄像头周围加一圈柔光LED补光灯。
- 调整检测阈值:
img.find_features()中的threshold参数和scale参数需要根据实际场景微调。阈值越低,检测越敏感(但也更容易误检);scale因子越小,检测越细致(但速度越慢)。 - 训练数据质量:为人脸识别模型采集训练样本时,要包含同一个人不同角度、不同表情、戴眼镜/不戴眼镜的图片,提高模型泛化能力。样本数量建议每人20-30张。
口罩检测误报率高:
- 现象:没戴口罩被判为戴了,或者手、衣领等物体被误判为口罩。
- 解决:
- 优化检测区域(ROI):不要在全图搜索口罩。先检测到人脸,然后只在下半部分人脸区域(鼻子到下巴)进行口罩检测,这能极大减少误检。
- 使用更先进的模型:Haar Cascade方法在复杂场景下局限性明显。如果OpenMV的Flash和RAM空间允许,移植一个轻量级的神经网络模型(如针对口罩检测优化的Tiny-YOLO或MobileNet-SSD)会获得质的提升。这需要用到OpenMV的TensorFlow Lite Micro支持。
4.2 性能瓶颈分析与优化策略
这个系统的实时性要求是“准实时”,不需要毫秒级响应,但最好在1-2秒内完成一次完整的“测温-识别-显示”循环。
STM32与OpenMV的通信延迟:
- 问题:串口通信和OpenMV处理图像都需要时间,如果STM32发送命令太频繁,OpenMV可能来不及处理,导致命令堆积或丢失。
- 优化:采用请求-响应模式,而非持续轮询。STM32发送一个命令后,等待并解析OpenMV的回复,然后再发送下一个命令。可以在OpenMV端,处理完一帧图像并返回结果后,才去检查串口缓冲区是否有新命令。
OpenMV图像处理速度:
- 问题:在QVGA分辨率下进行人脸检测、识别和口罩检测,帧率可能只有5-10fps,影响系统响应速度。
- 优化:
- 降低分辨率:尝试使用
QQVGA (160x120)或QQQVGA (80x60)。对于近距离人脸识别,较低分辨率可能已足够。 - 跳帧处理:不需要处理每一帧。可以每2帧或3帧处理一次。
- 优化算法顺序:先进行轻量级的人脸检测,只有检测到人脸后,才对该区域进行更耗时的人脸识别和口罩检测。
- 使用灰度图:如果颜色信息不重要,可以设置
sensor.set_pixformat(sensor.GRAYSCALE),能减少数据量,提升处理速度。
- 降低分辨率:尝试使用
STM32端的任务调度:
- 问题:如果所有任务都塞在
while(1)循环里,可能会因为某个任务阻塞(如等待串口超时)而影响其他任务(如温度定时读取)。 - 优化:引入更简单的时间片或状态机思想。为每个任务(测温、通信、显示刷新)设置独立的时间戳,利用
HAL_GetTick()判断是否到执行时间,非阻塞地执行。
- 问题:如果所有任务都塞在
// 简单的时间片调度示例 typedef struct { uint32_t last_run; uint32_t interval; void (*task)(void); } sTask; sTask task_list[] = { {0, 1000, Task_ReadTemperature}, // 每秒读一次温度 {0, 200, Task_UpdateDisplay}, // 每200ms刷新一次显示 {0, 50, Task_CheckUART}, // 每50ms检查串口 }; void Scheduler_Run(void) { uint32_t now = HAL_GetTick(); for(int i=0; i<sizeof(task_list)/sizeof(task_list[0]); i++) { if(now - task_list[i].last_run >= task_list[i].interval) { task_list[i].task(); task_list[i].last_run = now; } } } // 在主循环中调用 Scheduler_Run();5. 常见问题排查与经验心得
在实际部署和调试这个系统的过程中,我踩过不少坑,也积累了一些“教科书上不会写”的经验。
问题一:温度读数偶尔出现极大值(如85℃)或负值。
- 原因:这通常是I2C通信受到干扰,数据读取错误导致的。MLX90614的数据是16位的,如果某个bit在传输中翻转,就会解码成一个完全错误的温度值。
- 排查与解决:
- 硬件上:检查I2C走线,是否过长(建议<20cm),是否靠近电机、继电器等大电流干扰源。确保SDA和SCL线上有足够强的上拉电阻(通常4.7kΩ-10kΩ)。可以在STM32和传感器之间的I2C线上串联一个几十欧姆的小电阻,有助于抑制信号振铃。
- 软件上:在
MLX90614_ReadTemp函数中增加数据有效性检查。物体温度正常范围通常在20-45℃之间(对于人体),如果读出的值超出这个范围(例如>50℃或<15℃),可以丢弃该次读数,并重试一次,或者使用上一次的有效值。 - 加入CRC/PEC校验:MLX90614传输的第三个字节是PEC(包错误校验)字节。实现PEC校验算法,可以有效过滤掉传输错误的数据。虽然HAL库的
Mem_Read不自动处理这个,但我们可以读取3个字节后,自己计算并比对PEC。
问题二:人脸识别在室外强光或室内暗光下失效。
- 原因:OpenMV的传感器动态范围有限,过亮或过暗都会导致图像细节丢失,人脸特征无法提取。
- 解决:
- 启用自动曝光控制(AEC):
sensor.set_auto_exposure(True)。但有时自动曝光也不够。 - 手动设置曝光和增益:针对固定场景,可以手动调整到最佳值。使用OpenMV IDE的“镜头”工具,在真实环境下调整
sensor.set_auto_exposure(False),然后手动设置sensor.set_exposure_us()和sensor.set_gain_db(),直到人脸区域清晰可见。 - 增加物理遮光或补光:这是最有效的方法。为摄像头做一个遮光罩,避免阳光直射镜头。在光线不足的室内,增加补光灯,最好是漫射光源,避免在人脸上产生高光点。
- 启用自动曝光控制(AEC):
问题三:系统运行一段时间后死机或重启。
- 原因:可能是电源问题、堆栈溢出或看门狗未处理。
- 排查:
- 电源负载:用示波器观察系统3.3V电源轨的波形,在OpenMV执行图像捕捉和处理的瞬间,是否有大幅压降(跌落到3.0V以下)。如果有,说明电源带载能力不足,需要更换输出电流更大的LDO或直流电源模块,并在电源入口加大电容(如100uF电解并联0.1uF陶瓷电容)储能。
- 内存泄漏(OpenMV端):在MicroPython中,如果在循环里不断创建新的对象(如
image.Image())而不释放,可能导致内存耗尽。确保在函数内部创建的临时对象会随着函数结束而被垃圾回收,或者显式地使用del删除大对象。 - 看门狗:STM32的IWDG(独立看门狗)如果启用,必须在主循环中定期“喂狗”(
HAL_IWDG_Refresh(&hiwdg)),否则会导致复位。如果没启用看门狗却复位,重点查电源和硬件连接。
关于Adaboost与神经网络模型选择的个人体会:在OpenMV上,Haar Cascade + Adaboost方案实现口罩检测,优点是速度快、资源占用极低,整个.xml文件可能只有几十KB,加载和运行都很快。但它的缺点是需要大量正负样本进行训练,且特征设计相对固定,对于口罩的款式、颜色、佩戴方式(如露出鼻子)的泛化能力较弱,容易误检漏检。
而神经网络模型(如TFLite Micro),只要有一个足够好的训练数据集,它能学习到更本质、更鲁棒的特征,准确率通常更高。但代价是模型文件较大(几百KB到几MB),推理速度更慢,会显著增加OpenMV的循环时间。对于本项目,如果对准确率要求极高,且OpenMV H7的Flash有足够空间(比如4MB版本),我推荐花时间走神经网络路线。如果追求极致的速度和低成本,可以先用Haar Cascade方案快速验证原型,同时收集实际场景数据,为后续训练神经网络模型做准备。
最后,这个项目最有趣的地方不在于任何一个单一模块的使用,而在于如何让STM32、OpenMV、传感器这三个“伙伴”高效、可靠地对话。调试过程就像在解一个多维的谜题,硬件、软件、算法交织在一起。当系统终于稳定运行,屏幕上清晰地显示出正确的体温、姓名和“口罩已佩戴”的提示时,那种成就感是单纯调用一个库函数无法比拟的。它带给你的,是对嵌入式系统全链条的深入理解,从电路板上的信号,到C语言和Python的代码逻辑,再到最终的智能决策输出。
本文还有配套的精品资源,点击获取