更新文档

This commit is contained in:
2026-05-01 23:03:42 +08:00
parent 5a31ff2179
commit a32baa96e3
14 changed files with 2799 additions and 1853 deletions
+348 -40
View File
@@ -1,49 +1,357 @@
# 项目总文档
# 人脸识别考勤系统项目总文档
## 1. 项目概览
本项目是“人脸识别考勤系统”多端协同工程,包含:
- STM32 固件端(设备控制与签到逻辑)
- K210 识别端(视觉识别与人脸管理)
- C++ 服务端(加密签到、数据管理、同步控制)
- Qt 管理端(后台管理与可视化)
## 1. 这是什么项目
## 2. 推荐运行链路
建议使用以下版本组合:
1. 服务端:`server/server_encrypted.cpp`(HTTP 8082)
2. STM32:`User/main.c`(加密上传 + 时间段同步)
3. K210:`k210/main.py`(识别 + 照片上传 + 同步)
4. Qt:`QT/CMakeLists.txt` 构建的客户端
本项目是一个多端协同的人脸识别考勤系统。它不是只有一个程序,而是由四个主要部分组成:
| 部分 | 所在目录 | 主要职责 | 可以把它理解成 |
| --- | --- | --- | --- |
| STM32 固件端 | `User/`、`Hardware/`、`System/`、`Library/`、`Start/` | 接收 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
{
"mappings": {
"1": "20240001",
"2": "20240002"
}
}
```
含义是:K210 本地人脸 `1` 对应真实学号 `20240001`。
### 2.2 签到时间段默认是空的
当前代码中,系统启动时不再自动创建“上午签到”“中午签退”“下午签到”“晚上签退”这四个默认时间段。
也就是说,新部署时:
```json
{
"time_slots": []
}
```
如果没有配置时间段,STM32 会认为当前不在任何考勤时段内,识别到人脸也不会允许签到。需要在 Qt 管理端“配置中心”里新增时间段并保存同步。
### 2.3 服务端是数据中心
当前服务端以 SQLite 数据库为主,数据库文件是:
```text
attendance.db
```
服务端还会使用以下本地资源:
| 文件或目录 | 作用 |
| --- | --- |
| `attendance.db` | 主数据库,保存记录、配置、映射、同步状态 |
| `faces/` | 人脸照片目录,保存 K210 上传的 `.jpg` |
| `backups/` | 数据库备份目录 |
| `attendance_database.csv` | 旧版本记录文件,首次初始化时可导入 |
| `timeslots_config.json` | 旧版本时间段配置,首次初始化时可导入 |
| `mapping_config.json` | 旧版本姓名/班级映射,首次初始化时可导入 |
| `face_id_mapping.json` | 旧版本人脸映射,首次初始化时可导入 |
| `pending_delete.json` | 旧版本待删除人脸列表,首次初始化时可导入 |
| `sync_request.json` | 旧版本同步请求标志,首次初始化时可导入 |
| `sync_version.txt` | 旧版本同步版本号,首次初始化时可导入 |
### 2.4 同步版本号是什么
服务端维护一个全局同步版本号 `sync_version`。当考勤记录、时间段、映射、人脸照片、删除任务等数据发生变化时,服务端会把版本号加一。
设备同步时会带上自己上次同步到的版本:
```text
GET /api/v1/sync/state?client=stm32&last_version=3
```
如果服务端当前版本还是 `3`,会返回 `changed:false`。如果服务端当前版本是 `4` 或更高,会返回 `changed:true` 并带上该设备需要的数据。
这样做的好处是:设备不用不停下载所有数据,只要版本没变就不用重新处理。
## 3. 总体架构
1. K210 识别人脸,经 UART 上报 STM32。
2. STM32 执行签到策略并加密上传服务端 `POST /api/v1/attendance/checkins`。
3. 服务端写入 `attendance.db` 并提供管理 API。
4. 服务端在 SQLite 中维护全局同步版本,作为各端同步的权威版本。
5. Qt 管理端通过统一同步接口拉取记录/统计、配置、人脸照片和映射。
6. STM32 与 K210 分别按本地 `last_version` 增量拉取时间段、人脸映射与待删除任务,保持端云一致。
## 4. 文档索引(分端)
- STM32 固件端:`docs/01_STM32固件端文档.md`
- K210 识别端:`docs/02_K210识别端文档.md`
- 服务端:`docs/03_服务端文档.md`
- Qt 管理端:`docs/04_Qt管理端文档.md`
- 项目审查问题清单:`docs/05_项目审查问题清单.md`
```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"]
```
## 5. 各端关键配置位置
- STM32 网络与班级配置:`User/main.c`
- K210 WiFi/服务器配置:`k210/main.py`
- Qt 默认服务地址与 API 封装:`QT/src/ApiClient.cpp`、`QT/src/AppController.cpp`
- 服务端端口与数据文件:`server/server_encrypted.cpp`
## 4. 数据流说明
## 6. 一致性要求
- AES Key/IV 必须在 STM32、服务端、Qt 三端一致。
- 服务端建议统一使用加密版本,避免接口行为不一致。
- 各端时间配置需统一时区(当前代码以 UTC+8 逻辑处理)。
### 4.1 正常签到流程
## 7. 快速部署顺序
1. 编译并启动服务端(确认 `:8082` 可访问)。
2. 启动 Qt,先做 `/api/v1/system/health` 连通性验证。
3. 烧录 STM32 固件并联网。
4. 启动 K210 脚本并确认识别/同步正常。
5. 用 Qt 检查签到记录、照片、映射与删除同步链路。
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/<face_id>.jpg`。
5. K210 将照片 ID 放入上传队列。
6. 网络任务空闲时,K210 通过 ESP8266 上传照片到服务端:
```text
POST /api/v1/faces/photos/<face_id>
```
7. Qt 管理端进入“人脸管理”,刷新后可以看到照片。
8. 管理员为该 face_id 填写真实学号并保存映射。
9. 服务端保存映射并触发同步。
10. K210 拉取同步状态后,把本地人脸名称从 `ID:<face_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
Reconstruct_Qt/
├── docs/ # 项目文档
├── server/
│ ├── server_encrypted.cpp # C++ HTTP 服务端,当前推荐版本
│ ├── regression_api_tests.ps1 # Windows API 回归检查脚本
│ └── tiny_aes.hpp # AES 辅助代码
├── QT/
│ ├── CMakeLists.txt # Qt 客户端构建配置
│ ├── main.cpp # Qt 程序入口
│ ├── qml/Main.qml # Qt 主界面
│ ├── src/ # Qt C++ 业务逻辑、网络客户端、模型
│ ├── android/ # Android 打包配置和图标
│ └── assets/ # 桌面端图标
├── k210/
│ ├── main.py # K210 主程序
│ └── view_attendance.py # 旧版/辅助查看本地记录脚本
├── User/
│ └── main.c # STM32 主循环
├── Hardware/ # STM32 外设驱动与业务模块
├── System/ # STM32 延时、调试等基础模块
├── Library/ # STM32 标准外设库
├── Start/ # 启动文件和芯片头文件
├── Project.uvprojx # Keil 工程文件
├── Project.uvoptx # Keil 选项文件
└── 连接图.md # 硬件接线表
```
## 6. 默认配置总览
| 配置项 | 当前值 | 所在位置 |
| --- | --- | --- |
| 服务端端口 | `8082` | `server/server_encrypted.cpp` |
| 服务端默认 API Token | `atk_nKfVWLhMjL0RGSfRll3R_sdJS6IrIjuV` | 服务端、Qt、STM32、K210 |
| 服务端默认 CORS 来源 | `http://localhost` | `server/server_encrypted.cpp` |
| STM32 WiFi SSID | `yzfh` | `User/main.c` |
| STM32 WiFi 密码 | `yzfhroot` | `User/main.c` |
| STM32 服务端 IP | `27.106.113.205` | `User/main.c` |
| STM32 班级编号 | `1` | `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、服务端、STM32 |
| AES 算法 | AES-128-CBC + PKCS#7 + Base64 | `Hardware/Crypto.c`、`server/server_encrypted.cpp`、`QT/src/CryptoUtils.cpp` |
注意:这些配置里包含真实网络信息和默认 Token。如果要部署到公网,建议改成自己的值,并用环境变量覆盖服务端和 Qt 的 Token。
## 7. 硬件连接概览
完整连接表在根目录 `连接图.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
除少数公开接口外,服务端要求请求头中带 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` |
STM32 上传签到使用加密请求。Qt 当前普通记录和统计请求使用 JSON 明文响应,代码仍保留了解密能力。
## 9. 推荐启动顺序
1. 启动服务端,确认 `http://服务器IP:8082/api/v1/system/health` 返回健康状态。
2. 启动 Qt 管理端,在配置中心填写服务端地址并点击“测试连接”。
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 同步后更新本地人脸名称 |
| 添加人脸 | 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 适配 |
| `docs/05_项目审查问题清单.md` | 当前实现状态、风险点、维护清单 |
| `docs/06_后端接口Windows测试命令.md` | Windows 下手动测试和回归检查命令 |