Files
bishe-docs/02_K210识别端文档.md
T
2026-05-05 00:16:39 +08:00

298 lines
9.8 KiB
Markdown

# K210 识别端文档
## 1. K210 在系统中做什么
K210 负责“看见人脸并判断是谁”。它不直接决定能不能签到,最终签到判断由 STM32 完成。
K210 的职责包括:
1. 初始化摄像头和 LCD。
2. 加载人脸检测、关键点检测、特征提取三个 KPU 模型。
3. 从 SD 卡读取已经录入的人脸特征。
4. 实时检测画面中的人脸。
5. 将识别结果通过 UART1 发给 STM32。
6. 通过按键添加或删除本地人脸。
7. 保存新增人脸照片到 SD 卡。
8. 通过 K210 侧 ESP8266 上传照片到服务端。
9. 从服务端同步人脸 ID 到学号的映射。
10. 从服务端同步待删除任务,并删除本地特征。
## 2. 相关文件
| 文件 | 作用 |
| --- | --- |
| `k210/main.py` | K210 主程序,包含识别、添加、删除、同步、上传照片 |
K210 程序依赖 SD 卡上的模型文件:
```text
/sd/FaceDetection.smodel
/sd/FaceLandmarkDetection.smodel
/sd/FeatureExtraction.smodel
```
如果模型文件不存在或路径错误,程序会在加载 KPU 模型时报错。
## 3. 代码中的主要配置
位置:`k210/main.py`
| 配置 | 当前值 | 说明 |
| --- | --- | --- |
| `WIFI_SSID` | `yzfh` | K210 侧 ESP8266 要连接的 WiFi |
| `WIFI_PASSWORD` | `yzfhroot` | WiFi 密码 |
| `SERVER_IP` | `27.106.113.205` | 服务端 IP |
| `SERVER_PORT` | `8082` | 服务端端口 |
| `API_TOKEN` | `atk_nKfVWLhMjL0RGSfRll3R_sdJS6IrIjuV` | 服务端鉴权 Token |
| `SYNC_CHECK_INTERVAL_MS` | `50000` | 每 50 秒检查一次服务端同步请求 |
| `NETWORK_FRAME_INTERVAL` | `300` | 每 300 帧处理一次网络任务 |
| `LOCAL_FACE_PHOTO_DIR` | `/sd/face_photos` | 本地照片缓存目录 |
| `CAMERA_HMIRROR` | `1` | 水平镜像 |
| `CAMERA_VFLIP` | `1` | 垂直翻转 |
## 4. 硬件连接
| 功能 | K210 引脚 | 说明 |
| --- | --- | --- |
| 发给 STM32 | 24 | UART1 TX |
| 收 STM32 | 25 | UART1 RX |
| 发给 ESP8266 | 34 | UART2 TX |
| 收 ESP8266 | 35 | UART2 RX |
| 蓝/绿/红 LED | 12 / 13 / 14 | 状态提示 |
| 按键 | 16 | 添加、删除、删除全部 |
UART 参数:
```text
115200, 8 data bits, no parity, 1 stop bit
```
## 5. SD 卡文件
| 文件或目录 | 作用 |
| --- | --- |
| `/sd/recordftr.txt` | 人脸特征库,每行一个人脸 |
| `/sd/face_mapping.txt` | face_id 到学号的本地映射 |
| `/sd/sync_version.txt` | K210 已同步到的服务端版本号 |
| `/sd/face_photos/` | 新增人脸时保存的本地照片 |
| `/sd/FaceDetection.smodel` | 人脸检测模型 |
| `/sd/FaceLandmarkDetection.smodel` | 人脸关键点模型 |
| `/sd/FeatureExtraction.smodel` | 人脸特征提取模型 |
`recordftr.txt` 的一行大致是:
```text
ID:1#[0.0123, -0.0456, ...]
```
程序只解析安全的浮点数组文本,不执行任意表达式。
当前同步映射不会把 `recordftr.txt` 中的 `ID:1` 改成学号;真实学号保存在 `/sd/face_mapping.txt`,识别发送给 STM32 前再转换。
## 6. 启动流程
K210 启动后主要执行:
1. 设置堆内存到 1MB。
2. 初始化 UART1 和 UART2。
3. 初始化 K210 侧 ESP8266,尝试连接 WiFi。
4. 加载本地映射 `/sd/face_mapping.txt`。
5. 加载本地同步版本 `/sd/sync_version.txt`。
6. 加载三个 KPU 模型。
7. 初始化 LCD 和摄像头。
8. 初始化按键中断。
9. 加载本地人脸特征库 `/sd/recordftr.txt`。
10. 扫描本地照片目录,把未上传照片加入队列。
11. 如果 WiFi 可用,执行一次统一同步。
12. 进入主循环。
## 7. 人脸识别流程
每一帧画面大致按下面处理:
1. 摄像头采集图像。
2. `task_fd` 做人脸检测。
3. `task_ld` 做关键点定位。
4. 根据关键点做仿射变换,把人脸对齐到 128x128。
5. `task_fe` 提取人脸特征。
6. 与 `peoples` 中的本地特征逐个比对。
7. 如果最高分大于 `85`,认为识别成功。
8. 如果识别成功,LCD 画绿色框;陌生人画红色框。
9. 每隔 `SEND_INTERVAL_MS = 1000` 毫秒,向 STM32 发送一次状态变化。
发给 STM32 的格式:
```text
ID:<学号或face_id>,NAME:<显示名>,CONF:<置信度>
```
示例:
```text
ID:20240001,NAME:20240001,CONF:0.95
```
如果陌生人:
```text
UNKNOWN
```
## 8. 按键操作
| 操作 | 程序状态 | 作用 |
| --- | --- | --- |
| 短按 | 正常识别界面 | 进入添加人脸模式 |
| 长按约 2 秒 | 正常识别界面 | 进入删除人脸模式 |
| 超长按约 5 秒 | 正常识别界面 | 进入删除全部人脸模式 |
| 添加模式中短按 | 检测到陌生人脸时 | 确认添加 |
| 添加模式中长按 | 添加模式 | 退出添加模式 |
| 删除模式中短按 | 删除模式 | 切换候选项 |
| 删除模式中长按 | 删除模式 | 确认删除当前项 |
## 9. 添加人脸流程
1. 正常识别界面短按按键。
2. LCD 显示 `Add Face Mode`。
3. 摄像头检测到陌生人脸后显示 `Ready`。
4. 再短按确认添加。
5. K210 分配一个未使用的 `face_id`,例如 `1`。
6. 特征写入 `/sd/recordftr.txt`,名称为 `ID:1`。
7. 当前画面压缩为 JPEG。
8. JPEG 保存到 `/sd/face_photos/1.jpg`。
9. `1` 加入照片上传队列。
10. 后续网络任务会上传到服务端。
服务端接收接口:
```text
POST /api/v1/faces/photos/1
```
## 10. 人脸档案同步
新增人脸后,K210 只知道它是 `ID:1`,不知道真实学号。管理员需要在 Qt 管理端把 `1` 绑定到学号,服务端通过 `/api/v1/face_profiles` 保存人脸档案:
```json
{
"face_profiles": [
{
"face_id": "1",
"student_id": "20240001",
"status": "active"
}
]
}
```
K210 同步后会:
1. 拉取服务端 `face_profiles`。
2. 修改本地 `face_mapping.txt`。
3. 保持 `recordftr.txt` 中的原始 `ID:<face_id>` 不变。
4. 识别成功后先取原始 `face_id`,再通过 `face_mapping.txt` 转成真实学号发送给 STM32。
5. 已录入但未绑定学号的人脸会回退使用原始 `face_id` 和默认名称 `FACE_<face_id>` 发送给 STM32,例如 `ID:1,NAME:FACE_1,CONF:0.88`;只有未录入或匹配失败的人脸才发送 `UNKNOWN`。
## 11. 照片上传队列
K210 不会在识别每一帧时都做网络请求,因为网络请求会阻塞画面。它采用“分时网络任务”:
1. 新照片先保存到 SD 卡。
2. 只把 face_id 放入 `photo_upload_queue`。
3. 每隔一定帧数,主循环处理一个网络任务。
4. 如果上传失败,重新放回队列。
这样可以减少卡顿,并且即使网络临时不可用,照片也不会丢,因为原始 JPEG 还在 SD 卡。
## 12. 服务端同步
K210 主要使用统一同步接口:
```text
GET /api/v1/sync/state?client=k210&last_version=<本地版本>
```
如果有变化,服务端返回 K210 需要的数据:
```json
{
"version": 5,
"changed": true,
"state": {
"face_profiles": [
{
"face_id": "1",
"student_id": "20240001",
"status": "active",
"has_photo": true
}
],
"pending_delete": ["1"],
"delete_tasks": [
{
"task_id": "delete-1",
"face_id": "1"
}
]
}
}
```
K210 会先处理删除任务,再应用映射。删除成功后发送 ACK:
```json
{
"client": "k210",
"version": 5,
"deleted": ["1"],
"task_ids": ["delete-1"]
}
```
如果 ACK 失败,K210 不会推进本地版本号,下一次还会重试。
## 13. 删除人脸
K210 本地删除有两种来源:
### 13.1 K210 按键本地删除
这只会删除 K210 本地 `recordftr.txt` 和本地照片,不会自动删除服务端记录。适合现场维护。
### 13.2 Qt 管理端远程删除
Qt 删除会在服务端创建待删除任务。K210 同步后删除本地人脸,并向服务端确认。适合后台统一管理。
## 14. K210 常用接口
K210 与服务端之间的业务 JSON 请求和响应使用 AES-128-CBC + PKCS#7 + Base64。`esp_http_get` 会请求加密响应并在本地解密,`esp_http_post_json` 会先加密 JSON 请求体再发送。人脸照片 JPEG 仍按 `image/jpeg` 原始二进制上传,避免在 K210/ESP8266 分块传输中引入过高内存占用。
| 方法 | 路径 | 用途 |
| --- | --- | --- |
| `POST` | `/api/v1/faces/photos/<face_id>` | 上传 JPEG 照片 |
| `GET` | `/api/v1/faces/photos` | 查询服务端已有照片 |
| `GET` | `/api/v1/face_profiles` | 拉取人脸档案与学号绑定关系 |
| `GET` | `/api/v1/sync/state?client=k210&last_version=N` | 统一拉取人脸档案、删除任务与同步版本 |
| `POST` | `/api/v1/sync/ack` | 统一同步确认 |
| `GET` | `/api/v1/sync/request` | 查询 Qt/服务端是否请求同步 |
| `POST` | `/api/v1/sync/request/ack` | 确认收到同步请求 |
## 15. 常见问题
| 现象 | 可能原因 | 处理 |
| --- | --- | --- |
| 模型加载失败 | SD 卡缺少 `.smodel` 文件 | 把三个模型放到 `/sd/` 根目录 |
| WiFi 连接失败 | SSID/密码错误、ESP8266 未启动、波特率不匹配 | 看串口日志,代码会尝试多个波特率 |
| 添加人脸失败 | 没检测到陌生人脸、SD 卡不可写、照片保存失败 | 检查光照、SD 卡和日志 |
| Qt 看不到照片 | 上传队列未完成、服务端地址不一致、Token 错误 | 看 K210 `[PHOTO]`、`[NET]`、`[ESP]` 日志 |
| 删除后仍识别 | K210 尚未同步或 ACK 失败 | 等待同步,检查 `/api/v1/sync/state` |
| 发给 STM32 的还是 `ID:1` | 人脸档案没有保存或 K210 未同步 | Qt 保存人脸档案后触发同步 |
## 16. 修改配置时要注意
1. K210 的服务端 IP、端口、Token 必须和服务端一致。
2. K210 的 WiFi 配置和 STM32 可以相同,也可以不同,但都要能访问服务端。
3. K210 侧照片上传使用自己的 ESP8266,不依赖 STM32 的 ESP8266。
4. K210 本地 SD 卡数据很重要,删除或格式化 SD 卡会丢失本地人脸特征。
5. 如果重新录入人脸,原 face_id 可能变化,需要重新在 Qt 管理端设置人脸档案绑定关系。