# 人脸识别考勤系统项目总文档 ## 1. 这是什么项目 本项目是一个多端协同的人脸识别考勤系统。它不是只有一个程序,而是由四个主要部分组成: | 部分 | 所在目录 | 主要职责 | 可以把它理解成 | | --- | --- | --- | --- | | STM32 固件端 | `stm32/` | 接收 K210 识别结果、判断是否允许签到、加密上传记录、控制 OLED/蜂鸣器/指示灯/补光灯 | 考勤机主控板 | | K210 识别端 | `k210/` | 摄像头采集、人脸检测、人脸特征比对、添加/删除本地人脸、上传人脸照片、同步人脸档案 | 摄像头和 AI 识别模块 | | C++ 服务端 | `server/` | 提供 HTTP API、保存考勤记录、时间段、学生班级档案、人脸档案、照片和同步状态 | 中心服务器 | | Qt 管理端 | `QT/` | Windows/Android 图形管理界面,用于查看记录、统计、配置时间段、管理班级、人脸照片和照片对应学生信息 | 管理后台 | 整个系统的目标是: 1. K210 看到人脸并识别出一个人。 2. K210 通过串口把识别结果发给 STM32。 3. STM32 判断当前是否在允许签到的时间段内,并检查是否重复签到。 4. 如果允许签到,STM32 将签到数据用 AES-128-CBC 加密后通过 ESP8266 发给服务端。 5. 服务端保存数据,并提供给 Qt 管理端查看、统计、导出和管理。 6. Qt 管理端修改的配置会同步给服务端,再由 STM32 或 K210 拉取。 ## 2. 新手先理解几个概念 ### 2.1 人脸 ID 和学号不是同一个东西 K210 本地添加人脸时,会生成一个原始人脸编号,例如 `ID:1`、`ID:2`。这个编号只表示 K210 本地第几个录入的人脸。 真实考勤需要的是学号,例如 `20240001`。所以项目里通过人脸档案维护“人脸 ID 到学号”的绑定: ```json { "face_profiles": [ { "face_id": "1", "student_id": "20240001" }, { "face_id": "2", "student_id": "20240002" } ] } ``` 含义是:K210 本地人脸 `1` 对应真实学号 `20240001`。 ### 2.2 签到时间段默认是空的 系统默认不创建“上午签到”“中午签退”“下午签到”“晚上签退”等固定时间段。新部署时: ```json { "time_slots": [] } ``` 如果没有配置时间段,STM32 会认为当前不在任何考勤时段内,识别到人脸也不会允许签到。需要在 Qt 管理端“配置中心”里新增时间段并保存同步。 ### 2.3 服务端是数据中心 当前服务端以 SQLite 数据库为主,数据库文件是: ```text attendance.db ``` 服务端还会使用以下本地资源: | 文件或目录 | 作用 | | --- | --- | | `attendance.db` | 主数据库,保存记录、配置、学生班级档案、人脸档案、同步状态 | | `faces/` | 人脸照片目录,保存 K210 上传的 `.jpg` | | `backups/` | 数据库备份目录 | 服务端数据以 SQLite 为准,考勤记录、时间段配置、学生班级档案、人脸档案和同步状态都保存在 `attendance.db` 中。 ### 2.4 同步版本号是什么 服务端维护一个全局同步版本号 `sync_version`。当考勤记录、时间段、学生档案、班级信息、人脸档案、人脸照片、删除任务等数据发生变化时,服务端会把版本号加一。 设备同步时会带上自己上次同步到的版本: ```text GET /api/v1/sync/state?client=stm32&last_version=3 ``` 如果服务端当前版本还是 `3`,会返回 `changed:false`。如果服务端当前版本是 `4` 或更高,会返回 `changed:true` 并带上该设备需要的数据。 这样做的好处是:设备不用不停下载所有数据,只要版本没变就不用重新处理。 ## 3. 总体架构 ```mermaid flowchart LR Camera["摄像头"] --> K210["K210 识别端"] K210 -->|"UART1: ID, NAME, CONF"| STM32["STM32 主控"] STM32 -->|"USART1 AT 指令"| ESP1["ESP8266"] ESP1 -->|"HTTP + AES 签到"| Server["C++ 服务端 8082"] K210 -->|"UART2 AT 指令"| ESP2["K210 侧 ESP8266"] ESP2 -->|"HTTP 上传照片/同步人脸档案"| Server Qt["Qt 管理端 Windows/Android"] -->|"HTTP API"| Server Server --> SQLite["attendance.db"] Server --> Faces["faces/*.jpg"] ``` ## 4. 数据流说明 ### 4.1 正常签到流程 1. K210 摄像头采集画面。 2. K210 使用三个 KPU 模型执行人脸检测、关键点定位和特征提取。 3. K210 将当前人脸特征与 SD 卡中的 `recordftr.txt` 做比对。 4. 如果分数大于阈值,K210 认为识别成功。 5. K210 通过 UART1 发送给 STM32: ```text ID:20240001,NAME:20240001,CONF:0.95 ``` 6. STM32 解析串口数据。 7. STM32 检查置信度是否超过 `0.75`。 8. STM32 检查当前时间是否落在已启用的时间段内。 9. STM32 检查本地缓存、今日记录缓存和服务端查重结果,避免同一个学生在同一时段重复签到。 10. STM32 生成 JSON: ```json { "student_id": "20240001", "name": "20240001", "confidence": 0.95, "status": "success", "class_id": "1" } ``` 11. STM32 使用 AES-128-CBC 加密并做 Base64 编码。 12. STM32 通过 ESP8266 发送: ```text POST /api/v1/attendance/checkins X-Api-Token: ... X-Encrypted: AES128-CBC ``` 13. 服务端解密、校验字段、写入 SQLite。 14. Qt 管理端刷新后可以看到新记录。 ### 4.2 新增人脸流程 1. 在 K210 正常识别界面短按按键,进入添加人脸模式。 2. 摄像头检测到陌生人脸后,再短按确认。 3. K210 将人脸特征保存到 SD 卡 `recordftr.txt`。 4. K210 将对应照片保存到 `/sd/face_photos/.jpg`。 5. K210 将照片 ID 放入上传队列。 6. 网络任务空闲时,K210 通过 ESP8266 上传照片到服务端: ```text POST /api/v1/faces/photos/ ``` 7. Qt 管理端进入“人脸管理”,刷新后可以看到照片。 8. 管理员在该 face_id 的编辑弹窗中填写真实学号、姓名和班级,并保存人脸档案。 9. 服务端保存人脸档案并触发同步。 10. K210 拉取同步状态后更新本地 `face_mapping.txt`,识别发送时把 `face_id` 转成真实学号,`recordftr.txt` 中的原始 `ID:` 保持不变。 ### 4.3 删除人脸流程 1. Qt 管理端删除某个学生或人脸。 2. 服务端删除照片、解除人脸绑定,按需要删除考勤记录。 3. 服务端写入待删除任务 `pending_delete`,并提升同步版本。 4. K210 定期检查同步请求或拉取统一同步状态。 5. K210 在本地删除对应特征和照片。 6. K210 向服务端发送 ACK: ```text POST /api/v1/sync/ack ``` 7. 服务端移除待删除任务。 ## 5. 目录结构 ```text code/ ├── docs/ # 项目文档 ├── server/ │ ├── server_encrypted.cpp # C++ HTTP 服务端,当前推荐版本 ├── QT/ │ ├── CMakeLists.txt # Qt 客户端构建配置 │ ├── clear_qt_cache.ps1 # 清理 Qt Creator/CMake 项目缓存 │ ├── main.cpp # Qt 程序入口 │ ├── qml/Main.qml # Qt 主界面 │ ├── src/ # Qt C++ 业务逻辑、网络客户端、模型 │ ├── android/ # Android 打包配置和图标 │ └── assets/ # 桌面端图标 ├── k210/ │ └── main.py # K210 主程序 └── stm32/ ├── User/ │ └── main.c # STM32 主循环 ├── Hardware/ # STM32 外设驱动与业务模块 ├── System/ # STM32 延时、调试等基础模块 ├── Library/ # STM32 标准外设库 ├── Start/ # 启动文件和芯片头文件 ├── Project.uvprojx # Keil 工程文件 ├── Project.uvoptx # Keil 选项文件 └── 连接图.md # 硬件接线表 ``` ## 6. 默认配置总览 | 配置项 | 当前值 | 所在位置 | | --- | --- | --- | | 服务端端口 | `8082` | `server/server_encrypted.cpp` | | 服务端、STM32、K210 默认 API Token | `atk_nKfVWLhMjL0RGSfRll3R_sdJS6IrIjuV` | `server/server_encrypted.cpp`、`stm32/User/main.c`、`k210/main.py` | | 服务端默认 CORS 来源 | `http://localhost` | `server/server_encrypted.cpp` | | STM32 WiFi SSID | `yzfh` | `stm32/User/main.c` | | STM32 WiFi 密码 | `yzfhroot` | `stm32/User/main.c` | | STM32 服务端 IP | `27.106.113.205` | `stm32/User/main.c` | | STM32 班级编号 | `1` | `stm32/User/main.c` | | K210 WiFi SSID | `yzfh` | `k210/main.py` | | K210 WiFi 密码 | `yzfhroot` | `k210/main.py` | | K210 服务端 IP | `27.106.113.205` | `k210/main.py` | | Qt 默认服务端地址 | `http://127.0.0.1:8082` | `QT/src/ApiClient.cpp`、`QT/src/AppController.cpp` | | Qt API Token 来源 | 本地 `QSettings` 或环境变量 `ATTENDANCE_API_TOKEN` | `QT/src/AppController.cpp`、`QT/src/ApiClient.cpp` | | 默认签到时间段 | 空数组 | Qt、服务端、STM32 | | AES 算法 | AES-128-CBC + PKCS#7 + Base64 | `stm32/Hardware/Crypto.c`、`server/server_encrypted.cpp`、`QT/src/CryptoUtils.cpp` | 注意:这些配置里包含真实网络信息和默认 Token。如果要部署到公网,建议改成自己的值;服务端可用环境变量覆盖 Token,Qt 可在配置中心保存 Token 或读取环境变量,STM32 与 K210 需要改代码后重新烧录或上传脚本。 ## 7. 硬件连接概览 完整连接表在 `stm32/连接图.md`。常用连接如下: | 模块 | STM32 引脚 | 功能 | | --- | --- | --- | | ESP8266 | PA9 / PA10 | USART1,STM32 通过 AT 指令访问 WiFi 和 HTTP | | K210 | PB10 / PB11 | USART3,K210 把识别结果发给 STM32 | | OLED | PB8 / PB9 | I2C 显示 | | 调试串口 | PA2 / PA3 | USART2 调试输出 | | 成功 LED | PB4 | 高电平点亮 | | 蜂鸣器 | PB5 | 低电平触发 | | 光敏传感器 | PB0 | ADC 输入 | | 补光灯 | PB1 | 高电平点亮 | | DS1302 CLK/DAT/RST | PA4 / PA5 / PA6 | 软件模拟时序 | K210 侧: | 模块 | K210 引脚 | 功能 | | --- | --- | --- | | STM32 UART | 24 / 25 | UART1,发送识别结果给 STM32 | | ESP8266 UART | 34 / 35 | UART2,上传照片和同步配置 | | 按键 | 16 | 短按添加,长按删除,超长按删除全部 | | RGB LED | 12 / 13 / 14 | 状态提示 | ## 8. 加密与鉴权 ### 8.1 API Token 除 `OPTIONS` 预检请求外,服务端要求业务接口请求头中带 Token: ```text X-Api-Token: atk_nKfVWLhMjL0RGSfRll3R_sdJS6IrIjuV ``` 服务端可用环境变量覆盖: ```powershell $env:ATTENDANCE_API_TOKEN="你的新Token" ``` Qt 端也会读取同名环境变量;STM32 和 K210 目前是写在代码里的常量,需要改代码后重新烧录或上传脚本。 ### 8.2 AES 参数 三端必须保持完全一致: | 参数 | 值 | | --- | --- | | 算法 | AES-128-CBC | | 填充 | PKCS#7 | | 编码 | Base64 | | Key | `2b 7e 15 16 28 ae d2 a6 ab f7 15 88 09 cf 4f 3c` | | IV | `00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f` | 业务 JSON 接口统一使用 AES-128-CBC + PKCS#7 + Base64 传输。POST JSON 请求体需要携带 `X-Encrypted: AES128-CBC`,GET/DELETE/POST 的 JSON 响应由服务端加密后返回 `X-Encrypted: AES128-CBC`。K210 人脸照片 JPEG 因体积和分块传输限制保留原始二进制上传/下载,照片列表、同步状态、删除确认等 JSON 仍走加密链路。 ## 9. 推荐启动顺序 1. 启动服务端,用 Qt 或带 Token 与 AES 解密能力的客户端确认 `/api/v1/system/health` 返回健康状态。 2. 启动 Qt 管理端,在配置中心填写服务端地址和 API Token,点击“保存”后再点“测试连接”。 3. 在 Qt 管理端新增签到时间段并保存。 4. 烧录并启动 STM32,确认 OLED 显示系统就绪。 5. 启动 K210,确认摄像头画面、模型加载和 WiFi 连接正常。 6. 在 K210 添加人脸,等待照片上传到服务端。 7. 在 Qt 管理端为照片对应的人脸 ID 点击“编辑”,填写真实学号、姓名和班级并保存人脸档案。 8. K210 同步人脸档案后,再让同一人进行识别签到。 9. 在 Qt 管理端查看考勤记录和统计结果。 ## 10. 一键理解各端关系 | 你想做的事 | 应该操作哪里 | 背后发生什么 | | --- | --- | --- | | 改服务端地址 | Qt 配置中心、STM32/K210 代码常量 | 各端 HTTP 请求指向新服务器 | | 设置允许签到的时间 | Qt 配置中心 | Qt 保存到服务端,STM32 定期下载 | | 给人脸维护学生信息 | Qt 人脸管理 | 服务端保存学生档案和人脸档案,K210 同步后更新本地 `face_mapping.txt`,识别发送时转换成学号 | | 添加人脸 | K210 按键短按 | K210 保存特征和照片,照片上传服务端 | | 删除人脸 | Qt 人脸管理或 K210 删除模式 | Qt 删除会生成服务端同步任务;K210 本地删除只影响本地 | | 查看记录 | Qt 考勤记录页 | Qt 从服务端读取最近记录 | | 导出报表 | Qt 记录页或统计页 | Qt 把当前加载/筛选结果写成 CSV | ## 11. 新手常见问题 ### 11.1 为什么识别成功但没有签到成功 常见原因: 1. 没有配置签到时间段。 2. 当前时间不在任何启用的时间段内。 3. STM32 时间不正确,DS1302 失效且网络对时失败。 4. 同一学生在当前时间段已经签过。 5. K210 发给 STM32 的 ID 不是想要的真实学号。 6. 置信度低于 `0.75`。 7. STM32 无法连接服务端,记录暂存在本地等待同步。 ### 11.2 为什么 Qt 看不到 K210 的照片 可能原因: 1. K210 侧 ESP8266 没连上 WiFi。 2. K210 服务端 IP 或 Token 不正确。 3. K210 本地照片保存在 `/sd/face_photos`,但还没轮到网络队列上传。 4. 服务端 `faces/` 目录没有写入权限。 5. Qt 配置的服务端地址不是 K210 上传照片的那个服务端。 ### 11.3 为什么删除后 K210 还认识这个人 Qt 删除会先在服务端生成待删除任务,K210 需要同步后才会删除本地 SD 卡中的特征。可以等待 K210 定期同步,也可以通过服务端同步请求接口触发。 ### 11.4 为什么改了 Token 后有的端还能用,有的端不能用 服务端和 Qt 可以读取环境变量 `ATTENDANCE_API_TOKEN`。STM32 与 K210 的 Token 写在代码里,必须同步修改并重新烧录或上传脚本。 ## 12. 文档索引 | 文档 | 内容 | | --- | --- | | `docs/00_项目总文档.md` | 总体介绍、架构、运行顺序、概念说明 | | `docs/01_STM32固件端文档.md` | STM32 固件、硬件模块、签到判断、加密上传 | | `docs/02_K210识别端文档.md` | K210 人脸识别、按键操作、照片上传、同步 | | `docs/03_服务端文档.md` | 服务端 API、SQLite、同步版本、部署安全 | | `docs/04_Qt管理端文档.md` | Qt 界面功能、数据模型、本地缓存、PC/Android 适配 |