3.7 KiB
3.7 KiB
Day 15: 性能优化 - 解决导航模式帧率问题
问题描述
导航模式下 FPS 从 10.0 降到 0.5-1.5,画面严重卡顿。
已完成优化
1. YOLO 帧间隔修复 ✅
将 yolo_process_interval 从 1 帧改为 5 帧。
2. 性能诊断日志 ✅
添加了 [NAVIGATION DEBUG] 日志用于监控状态。
3. 线程池化帧处理 ✅
使用 ThreadPoolExecutor 将 CPU 密集型处理移至后台线程。
4. 修复模型重复加载 BUG ✅
根因:audio_stream.py 中的 import app_main 触发模块顶层代码再次执行。
修复:改为 sys.modules['app_main'] 获取已加载的模块。
5. 跳帧机制 ✅
根因:虽然用了 run_in_executor,但 await 仍同步等待处理完成。
修复:实现非阻塞式帧处理:
- 后台任务处理帧,主循环不等待
- 使用最后一次成功的结果广播
- 新帧覆盖待处理队列(跳过中间帧)
6. 导航语音频率优化 ✅
问题:FPS 恢复后,导航指令触发过于频繁(每1秒一次),造成干扰。
修复:将 audio_player.py 中的 _voice_cooldown 从 1.0秒 调整为 3.0秒。
代码修改
audio_stream.py
get_tts_websocket(): 改用sys.modules避免触发模块重载
app_main.py
- 添加跳帧机制全局变量:
_nav_processing_task,_nav_last_result_image,_nav_pending_frame - 修改
ws_camera_esp中的帧处理为非阻塞式
audio_player.py
- 调整
_voice_cooldown= 3.0 (原 1.0)
预期效果
| 场景 | 修改前 | 修改后 |
|---|---|---|
| CHAT 模式 | 10 FPS | 10 FPS |
| 导航模式 | 0.5-1.5 FPS | 8-10 FPS |
| Omni 对话 | 0.5 FPS | 8-10 FPS |
真正的根因:
- 同步帧处理阻塞事件循环 -
orchestrator.process_frame()在主 async 循环中同步执行 - Omni 对话阻塞 - TTS 音频流发送与帧处理串行竞争时间片
- 双重 JPEG 编解码 - 每帧都解码+重编码
4. 线程池化帧处理 ✅
方案:将 CPU 密集型的帧处理移至 ThreadPoolExecutor 后台线程执行。
修改:
- 添加
concurrent.futures.ThreadPoolExecutor导入 - 创建全局
frame_processing_executor(2 个 worker 线程) - 使用
await loop.run_in_executor()执行orchestrator.process_frame() - 使用
await loop.run_in_executor()执行trafficlight_detection.process_single_frame() - 在 lifespan 关闭时调用
executor.shutdown(wait=False)
📝 代码变更汇总
| 文件 | 变更 |
|---|---|
workflow_blindpath.py |
YOLO 帧间隔检查 + 性能诊断计时 |
app_main.py |
添加线程池 + run_in_executor 异步帧处理 |
audio_player.py |
增加语音冷却时间至 3秒 |
⏭️ 下一步 (Day 16 计划)
1. 户外测试全流程配置
- 公网连接支持:修改代码支持命令行指定 IP (避免硬编码) 或配置公网服务器地址。
- 开机自启动:配置
/etc/rc.local实现通电即运行。 - 程序固化:将
avaota_client部署到/usr/bin等非易失存储。
3. 程序部署与自启动 (已验证)
- 解决存储空间不足问题:
/overlay空间不足 (316KB),改用/mnt/UDISK(17MB)。 - 部署命令:
adb push avaota_client /mnt/UDISK/ - 自启动配置:
/etc/rc.local添加启动脚本sleep 15 /mnt/UDISK/avaota_client & - 连通性验证:通过串口日志确认 WiFi 连接成功,程序成功收发数据。
2. 网络自动连接
- 配置
wpa_supplicant.conf预存户外热点信息。 - 验证断电重启后的自动重连能力。