216 lines
6.1 KiB
Markdown
216 lines
6.1 KiB
Markdown
# Day 23 - 移动端优化 + PM2 部署 + 红绿灯检测修复
|
||
|
||
**日期**: 2025-12-29
|
||
**主题**: 可视化界面移动端适配与服务器部署优化
|
||
|
||
---
|
||
|
||
## 🔧 移动端可视化界面优化 (12:44)
|
||
|
||
**问题**:手机访问可视化界面时看不到视频画面
|
||
**根因**:
|
||
1. `.stage` 容器在移动端 `height: auto` 时高度坍塌为 0
|
||
2. IMU 浮窗占满全宽,遮挡视频区域
|
||
3. `fitCanvas()` 函数只用宽度计算高度,忽略容器实际高度
|
||
4. 移动端 IMU 浮窗无法折叠
|
||
|
||
### 修复内容
|
||
|
||
#### 1. CSS 布局修复 (`index.html`)
|
||
```css
|
||
/* 1100px 以下屏幕 */
|
||
@media (max-width:1100px) {
|
||
.stage {
|
||
min-height: 50vh; /* 确保视频区域有高度 */
|
||
height: 50vh;
|
||
}
|
||
.imu-float {
|
||
width: 160px;
|
||
right: 8px; bottom: 8px; /* 移到右下角 */
|
||
}
|
||
.imu-float:not(.expanded) {
|
||
height: 40px; /* 默认折叠 */
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 2. Canvas 尺寸计算修复 (`main.js`)
|
||
```javascript
|
||
function fitCanvas() {
|
||
const rect = canvas.getBoundingClientRect();
|
||
const w = Math.max(320, Math.floor(rect.width) || 320);
|
||
let h = Math.floor(rect.height) || 0;
|
||
if (h < 100) h = Math.floor(w * 3 / 4); // 回退 4:3
|
||
...
|
||
}
|
||
```
|
||
|
||
#### 3. 移动端默认折叠 IMU (`main.js`)
|
||
```javascript
|
||
const isMobile = window.innerWidth < 1100;
|
||
if (isMobile) {
|
||
imuFloat.classList.add('collapsed');
|
||
imuToggle.textContent = '+';
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 PM2 服务器部署配置 (14:12)
|
||
|
||
**需求**:使用 PM2 管理 NaviGlass 后端服务
|
||
|
||
### 最简启动命令
|
||
```bash
|
||
pm2 start ~/ProgramFiles/OpenAIglasses_for_Navigation/venv/bin/python \
|
||
--name naviglass \
|
||
--cwd ~/ProgramFiles/OpenAIglasses_for_Navigation \
|
||
-- app_main.py
|
||
|
||
pm2 save
|
||
pm2 startup
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 VAD 模型加载优化 (14:25)
|
||
|
||
**问题**:PM2 启动时 VAD 模型加载卡住(尝试从 GitHub 检查更新超时)
|
||
**原因**:`torch.hub.load()` 默认每次检查远程更新,网络慢则超时
|
||
**修复**:优先使用本地缓存 (`source='local'`)
|
||
|
||
### 代码变更 (`server_vad.py`)
|
||
```python
|
||
# 优先使用缓存,避免每次检查 GitHub 更新
|
||
cache_dir = os.path.expanduser("~/.cache/torch/hub/snakers4_silero-vad_master")
|
||
if os.path.exists(cache_dir):
|
||
print(f"[VAD] 使用 torch hub 缓存: {cache_dir}")
|
||
_vad_model, _ = torch.hub.load(
|
||
repo_or_dir=cache_dir,
|
||
source="local",
|
||
model="silero_vad",
|
||
force_reload=False,
|
||
)
|
||
```
|
||
|
||
**效果**:启动从 ~30s 降至 ~3s
|
||
|
||
---
|
||
|
||
## 🔧 红绿灯检测画面卡住修复 (17:36)
|
||
|
||
**问题**:户外测试时,启动红绿灯检测后视频画面卡住
|
||
**日志表现**:
|
||
```
|
||
[PERF] 导航:147.2ms | state=TRAFFIC_LIGHT_DETECTION (第一帧)
|
||
[PERF] 导航:0.0ms | state=TRAFFIC_LIGHT_DETECTION (后续帧无处理)
|
||
```
|
||
|
||
**根因分析**:
|
||
1. 红绿灯检测使用 `await loop.run_in_executor(...)` **同步等待**,阻塞主循环
|
||
2. 广播时错误使用盲道导航的缓存 `_nav_last_result_jpeg`,而非红绿灯检测结果
|
||
3. 如果之前运行过盲道导航,会一直广播旧的盲道检测图
|
||
|
||
### 修复方案
|
||
|
||
#### 1. 添加红绿灯检测独立缓存 (`app_main.py` 第 550 行)
|
||
```python
|
||
# ============== 红绿灯检测跳帧机制 =================
|
||
_traffic_light_task = None
|
||
_traffic_light_result_jpeg = None
|
||
_traffic_light_pending_frame = None
|
||
```
|
||
|
||
#### 2. 实现非阻塞跳帧机制 (`app_main.py` 第 1503-1541 行)
|
||
```python
|
||
if current_state == "TRAFFIC_LIGHT_DETECTION":
|
||
# 更新待处理帧
|
||
_traffic_light_pending_frame = bgr
|
||
|
||
# 如果任务完成,获取结果并启动新任务
|
||
if _traffic_light_task is None or _traffic_light_task.done():
|
||
if _traffic_light_task is not None and _traffic_light_task.done():
|
||
result = _traffic_light_task.result()
|
||
if result and result.get('vis_image') is not None:
|
||
_traffic_light_result_jpeg = turbo_encode(result['vis_image'])
|
||
|
||
# 启动新任务(不等待)
|
||
_traffic_light_task = loop.run_in_executor(...)
|
||
|
||
# 独立广播红绿灯检测结果
|
||
if _traffic_light_result_jpeg is not None:
|
||
await _broadcast_to_viewers(_traffic_light_result_jpeg)
|
||
else:
|
||
await _broadcast_to_viewers(data) # 首帧回退
|
||
continue # 跳过盲道导航逻辑
|
||
```
|
||
|
||
#### 3. 停止时清除缓存
|
||
```python
|
||
if "停止检测" in user_text:
|
||
global _traffic_light_result_jpeg
|
||
_traffic_light_result_jpeg = None # 清除缓存
|
||
```
|
||
|
||
**修复效果**:
|
||
- ✅ 红绿灯检测不再阻塞主循环
|
||
- ✅ 独立缓存,不干扰盲道导航
|
||
- ✅ 跳帧机制与盲道导航一致
|
||
|
||
---
|
||
|
||
## 🔧 Nginx 域名配置 (14:06)
|
||
|
||
**需求**:为可视化界面配置域名 `naviglass.hbyrkj.top`
|
||
|
||
### Nginx 配置
|
||
```nginx
|
||
server {
|
||
listen 80;
|
||
server_name naviglass.hbyrkj.top;
|
||
|
||
location /ws {
|
||
proxy_pass http://127.0.0.1:8081;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade $http_upgrade;
|
||
proxy_set_header Connection "upgrade";
|
||
proxy_read_timeout 86400;
|
||
}
|
||
|
||
location / {
|
||
proxy_pass http://127.0.0.1:8081;
|
||
proxy_set_header Host $host;
|
||
proxy_buffering off;
|
||
}
|
||
}
|
||
```
|
||
|
||
### SSL 证书
|
||
```bash
|
||
sudo certbot --nginx -d naviglass.hbyrkj.top
|
||
```
|
||
|
||
---
|
||
|
||
## 📁 修改文件汇总
|
||
|
||
| 文件 | 修改内容 |
|
||
|------|----------|
|
||
| `templates/index.html` | 移动端 CSS 布局修复 |
|
||
| `static/main.js` | fitCanvas() 优化、移动端 IMU 折叠 |
|
||
| `server_vad.py` | VAD 模型本地缓存优先 |
|
||
| `app_main.py` | 红绿灯检测跳帧机制 + 独立缓存 |
|
||
|
||
---
|
||
|
||
## 📝 Day 23 总结
|
||
|
||
| 类别 | 状态 | 说明 |
|
||
|------|------|------|
|
||
| 移动端视频显示 | ✅ | 布局修复 + Canvas 适配 |
|
||
| 移动端 IMU 折叠 | ✅ | 默认折叠 + 移到右下角 |
|
||
| PM2 部署 | ✅ | 一行命令启动 |
|
||
| VAD 加载优化 | ✅ | 本地缓存优先,启动快 30s→3s |
|
||
| 红绿灯检测卡顿 | ✅ | 跳帧机制 + 独立缓存 |
|
||
| Nginx 域名 | ✅ | naviglass.hbyrkj.top |
|