Delete 'src/GUI/PANEL_MAP_UPDATE.md'
This commit is contained in:
@@ -1,189 +0,0 @@
|
||||
# Panel 和 Map 10Hz 更新機制
|
||||
|
||||
## 概述
|
||||
|
||||
Panel(DronePanel)和 Map(DroneMap)的更新率已優化為 **10Hz(每 100ms 更新一次)**,同時其他 UI 元素保持更快的更新速率。這確保了地圖和面板在資訊流量大時不會過度刷新,同時保持流暢的用戶體驗。
|
||||
|
||||
## 架構
|
||||
|
||||
### 資料流
|
||||
|
||||
```
|
||||
接收執行緒 (高頻)
|
||||
↓
|
||||
monitor.latest_data
|
||||
↓
|
||||
spin_ros() [10ms] - 發送信號
|
||||
↓
|
||||
update_ui() [快速更新]
|
||||
├─ State, Battery, Altitude, etc. → 直接更新 (快速)
|
||||
└─ GPS, HUD → 快取到 _message_cache
|
||||
↓
|
||||
_update_panel_and_map() [100ms / 10Hz]
|
||||
├─ 讀取 _message_cache 的 GPS 資料
|
||||
│ └─ 更新經緯度表格
|
||||
├─ 讀取 _message_cache 的 HUD 資料
|
||||
│ ├─ 更新標題、速度、高度等
|
||||
│ └─ 更新 Panel 顯示
|
||||
└─ 更新地圖位置和無人機方向
|
||||
```
|
||||
|
||||
### 關鍵特性
|
||||
|
||||
1. **消息快取 (`_message_cache`)**
|
||||
- GPS 和 HUD 消息被快取而不是立即處理
|
||||
- 如果在 10Hz 更新週期內沒有收到新消息,使用上一次的值
|
||||
- 避免因快速連續的消息導致過度刷新
|
||||
|
||||
2. **分層更新**
|
||||
- **快速更新** (on-demand): State, Battery, Altitude, Loss Rate, Ping 等
|
||||
- **10Hz 更新**: GPS 位置, HUD(標題、速度、高度、爬升率), Panel 和 Map
|
||||
|
||||
3. **定時器機制**
|
||||
```python
|
||||
# 10Hz 定時器
|
||||
self.panel_map_timer = QTimer()
|
||||
self.panel_map_timer.timeout.connect(self._update_panel_and_map)
|
||||
self.panel_map_timer.start(100) # 100ms = 10Hz
|
||||
```
|
||||
|
||||
## 實現細節
|
||||
|
||||
### 步驟 1: 快取消息
|
||||
|
||||
在 `update_ui()` 中,GPS 和 HUD 消息被快取:
|
||||
|
||||
```python
|
||||
# 快取 GPS 和 HUD 資料用於 panel/map 的 10Hz 更新
|
||||
if msg_type in ('gps', 'hud'):
|
||||
if drone_id not in self._message_cache:
|
||||
self._message_cache[drone_id] = {}
|
||||
self._message_cache[drone_id][msg_type] = data
|
||||
# 不在這裡更新,等待 _update_panel_and_map 在 10Hz 執行
|
||||
return
|
||||
```
|
||||
|
||||
### 步驟 2: 10Hz 批次更新
|
||||
|
||||
每 100ms,`_update_panel_and_map()` 被調用:
|
||||
|
||||
```python
|
||||
def _update_panel_and_map(self):
|
||||
"""10Hz 定時更新 panel 和 map,使用快取的 GPS 和 HUD 消息"""
|
||||
for drone_id in list(self._message_cache.keys()):
|
||||
cache = self._message_cache[drone_id]
|
||||
|
||||
# 使用快取的 GPS 資料
|
||||
if 'gps' in cache:
|
||||
gps_data = cache['gps']
|
||||
lat, lon = gps_data.get('lat', 0), gps_data.get('lon', 0)
|
||||
self.drone_positions[drone_id] = (lat, lon)
|
||||
# ... 更新表格
|
||||
|
||||
# 使用快取的 HUD 資料
|
||||
if 'hud' in cache:
|
||||
hud_data = cache['hud']
|
||||
heading = hud_data.get('heading', 0)
|
||||
# ... 更新 panel 和 map
|
||||
self.drone_map.update_drone_position(drone_id, lat, lon, heading)
|
||||
```
|
||||
|
||||
### 步驟 3: 持久化數據
|
||||
|
||||
即使沒有新消息,先前快取的值仍然存在於 `_message_cache` 中,所以 `_update_panel_and_map()` 將在下一個 10Hz 周期使用它:
|
||||
|
||||
```python
|
||||
# 第一個週期:GPS 消息到達
|
||||
_message_cache = {
|
||||
'drone_0': {'gps': {'lat': 23.123, 'lon': 120.456, ...}}
|
||||
}
|
||||
|
||||
# 第二個週期:沒有新 GPS 消息,但仍使用前一個值
|
||||
_update_panel_and_map() 會使用 'drone_0' 的上一個 GPS 位置
|
||||
```
|
||||
|
||||
## 性能影響
|
||||
|
||||
### 優點
|
||||
- **降低 Map 更新頻率**: 避免過度繪製導致 CPU 負荷
|
||||
- **更流暢的 UI**: 批次更新減少了視覺閃爍
|
||||
- **減少同步開銷**: 地圖位置和面板資訊一起批次更新
|
||||
|
||||
### 更新頻率對比
|
||||
|
||||
| 組件 | 舊速率 | 新速率 | 說明 |
|
||||
|------|--------|--------|------|
|
||||
| State/Battery/Altitude | 即時 | 即時 | 保持快速響應 |
|
||||
| GPS/HUD 消息 | 即時 | 10Hz | 快取並批次更新 |
|
||||
| Map 更新 | 即時 | 10Hz | 隨 HUD 更新 |
|
||||
| Panel 顯示 | 即時 | 10Hz | 隨 HUD 更新 |
|
||||
|
||||
## 故障排除
|
||||
|
||||
### Panel 或 Map 沒有更新
|
||||
1. 檢查 `panel_map_timer` 是否啟動
|
||||
```python
|
||||
print(self.panel_map_timer.isActive()) # 應該是 True
|
||||
```
|
||||
|
||||
2. 驗證 `_update_panel_and_map()` 是否被調用
|
||||
- 在方法開始添加 `print(f"Panel/Map update: {len(self._message_cache)} drones")`
|
||||
|
||||
3. 檢查快取是否有數據
|
||||
```python
|
||||
print(self._message_cache) # 應該看到 drone_id 和消息
|
||||
```
|
||||
|
||||
### 數據延遲或重複
|
||||
|
||||
如果看到數據延遲(最多 100ms),這是正常的。這就是為什麼我們使用快取 - 確保最新值始終可用。
|
||||
|
||||
如果看到重複更新,檢查是否有多個地方在調用 `update_drone_position()`。
|
||||
|
||||
## 初始化
|
||||
|
||||
在 `__init__` 中添加:
|
||||
|
||||
```python
|
||||
# 初始化 panel 和 map 更新(10Hz)
|
||||
self.panel_map_timer = QTimer()
|
||||
self.panel_map_timer.timeout.connect(self._update_panel_and_map)
|
||||
self.panel_map_timer.start(100) # 10Hz
|
||||
|
||||
# 快取消息數據,以便在沒有新消息時使用上一次的值
|
||||
self._message_cache = {}
|
||||
```
|
||||
|
||||
## 監控與調試
|
||||
|
||||
### 列印更新頻率
|
||||
|
||||
添加到 `_update_panel_and_map()`:
|
||||
|
||||
```python
|
||||
def _update_panel_and_map(self):
|
||||
if not hasattr(self, '_map_update_count'):
|
||||
self._map_update_count = 0
|
||||
self._map_update_time = time.time()
|
||||
|
||||
self._map_update_count += 1
|
||||
if time.time() - self._map_update_time >= 1.0:
|
||||
print(f"Panel/Map update frequency: {self._map_update_count} Hz")
|
||||
self._map_update_count = 0
|
||||
self._map_update_time = time.time()
|
||||
|
||||
# ... 其餘代碼
|
||||
```
|
||||
|
||||
### 快取大小監控
|
||||
|
||||
```python
|
||||
print(f"Cache size: {len(self._message_cache)} drones")
|
||||
for drone_id, cache in self._message_cache.items():
|
||||
print(f" {drone_id}: {list(cache.keys())}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**更新日期**: 2025-03-25
|
||||
**版本**: Panel/Map 10Hz 優化 v1.0
|
||||
Reference in New Issue
Block a user