ProWaveDAQ 即時資料可視化系統是一個基於 Python 的振動數據採集與可視化平台,用於從 PW-RVT-2-4(Modbus RTU)設備取得振動數據,並在瀏覽器中即時顯示所有資料點的連續曲線,同時自動進行 CSV 儲存和 SQL 資料庫上傳。
本系統提供完整的 Web 介面,讓使用者可以透過瀏覽器操作,不需進入終端機,即可:
- 修改設定檔(
ProWaveDAQ.ini、csv.ini、sql.ini) - 輸入資料標籤(Label)
- 設定 SQL 伺服器上傳(可選)
- 按下「開始讀取」即啟動採集與即時顯示
- 系統同時自動分檔儲存資料(根據
csv.ini的秒數) - 按下「停止」即可安全結束,並自動上傳剩餘資料
- 即時資料採集:透過 Modbus RTU 協議從 ProWaveDAQ 設備讀取振動數據
- 即時資料可視化:使用 Chart.js 在瀏覽器中顯示多通道連續曲線圖
- 自動 CSV 儲存:根據設定檔自動分檔儲存資料
- SQL 資料庫上傳:可選的 SQL 伺服器上傳功能,支援 MySQL/MariaDB
- Web 介面控制:完整的瀏覽器操作介面,無需終端機
- 設定檔管理:透過 Web 介面使用固定輸入框編輯設定檔(防止誤刪參數)
- 降頻佇列架構:使用
web_data_queue存儲降頻後的資料(50:1 降頻),大幅減少前端資料傳輸量和繪圖負擔 - 增量更新機制:前端使用增量更新方式,只處理新資料,維持固定視窗大小(500 點)
- 原廠手冊規範:ProWaveDAQ 模組嚴格遵循原廠手冊 Page 5 規範,使用 FC04 讀取完整封包
- 多執行緒架構:5 個獨立執行緒(Flask、DAQ Reading、Collection、CSV Writer、SQL Writer),確保各組件不互相干擾
- 執行緒安全通訊:使用
queue.Queue進行執行緒間通訊,確保資料一致性 - 即時資料可視化:使用 Chart.js 實現即時圖表(每 100ms 更新),關閉動畫以提升效能
- 自動分檔儲存:根據設定檔自動分檔儲存 CSV 檔案,確保樣本邊界正確
- SQL 批次上傳:使用暫存檔案機制,批次上傳資料到 SQL 伺服器,提升效能
- 資料保護機制:重試機制、失敗保留,確保資料不遺失
- 統一日誌系統:自動時間戳記和日誌級別管理
- 通道錯位保護:確保資料順序正確,避免通道錯位
- 時間戳記精確計算:根據取樣率自動計算每個樣本的時間
- ProWaveDAQ 設備(透過 Modbus RTU 連接)
- 串列埠(USB 轉串列埠或直接串列埠)
- 支援 Python 3.10+ 的系統(建議 DietPi 或其他 Debian-based 系統)
- (可選)SQL 伺服器(MySQL/MariaDB)用於資料上傳
- Python 3.10 或更高版本
- 支援的作業系統:
- DietPi(建議)
- Debian-based Linux 發行版
- Ubuntu
- Raspberry Pi OS
請參考 requirements.txt 檔案,主要依賴包括:
pymodbus>=3.11.3- Modbus 通訊pyserial>=3.5- 串列埠通訊Flask>=3.1.2- Web 伺服器pymysql>=1.0.2- SQL 資料庫連線(MySQL/MariaDB)
cd /path/to/ProWaveDAQ_Python_Visualization_Unit./deploy.sh注意:deploy.sh 腳本在以下情況需要 sudo 權限:
- 系統未安裝 Python 3、pip3 或 venv 模組時(需要安裝系統套件)
- 需要將用戶加入
dialout群組以存取串列埠時
如果系統已安裝 Python 環境且用戶已在 dialout 群組中,則不需要 sudo。
若需要 sudo,請執行:
sudo ./deploy.shpip install -r requirements.txt或使用 pip3:
pip3 install -r requirements.txt確保 Python 腳本有執行權限:
chmod +x src/main.py
chmod +x src/prowavedaq.py
chmod +x src/csv_writer.py
chmod +x src/sql_uploader.py如果使用 USB 轉串列埠設備,可能需要將使用者加入 dialout 群組:
sudo usermod -a -G dialout $USER然後重新登入或執行:
newgrp dialout檢查 API/ 目錄下的設定檔:
API/ProWaveDAQ.ini- ProWaveDAQ 設備設定API/csv.ini- CSV 分檔間隔設定API/sql.ini- SQL 伺服器連線設定和上傳間隔設定
如果啟用 SQL 上傳功能,需要在 MariaDB/MySQL 中建立資料表:
CREATE TABLE IF NOT EXISTS vibration_data (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
timestamp DATETIME NOT NULL,
label VARCHAR(255) NOT NULL,
channel_1 DOUBLE NOT NULL,
channel_2 DOUBLE NOT NULL,
channel_3 DOUBLE NOT NULL,
INDEX idx_timestamp (timestamp),
INDEX idx_label (label)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;注意:如果資料表不存在,程式會在首次連線時自動建立。
背景說明: 由於逢甲大學防火牆政策,如需連線至 IMSL 實驗室的 MariaDB 伺服器,需要透過 OpenVPN 建立 VPN 連線。
安裝 OpenVPN(如果尚未安裝):
sudo apt-get update
sudo apt-get install openvpn設定 OpenVPN 連線:
-
首次設定連線資訊:
./connection.sh --setup
腳本會提示輸入:
- 私鑰密碼(Private Key Password)
- OVPN 帳號(Username)
- OVPN 密碼(Password)
- OVPN 伺服器位址(可選)
-
確認 OVPN 設定檔存在:
- 確保
API/imCloud.ovpn檔案存在 - 如果不存在,腳本會建立基本設定檔,需要手動編輯以添加完整設定
- 確保
-
建立 OpenVPN 連線:
./connection.sh
或使用 sudo 權限:
sudo ./connection.sh
-
檢查連線狀態:
# 檢查 OpenVPN 程序是否運行 pgrep -x openvpn # 查看連線狀態 ip addr show tun0
-
中斷連線:
./connection.sh --disconnect
或:
sudo killall openvpn
重要提示:
- 連線資訊會儲存在
API/connection_config.txt(權限 600,僅擁有者可讀寫) - 請勿將
API/connection_config.txt和API/imCloud.ovpn提交到版本控制系統 - 建議將這些檔案加入
.gitignore - 連線成功後,即可正常使用 SQL 上傳功能連線至 IMSL 實驗室的 MariaDB 伺服器
使用預設 port 8080:
./run.sh指定自訂 port:
./run.sh 3000 # 使用 port 3000
./run.sh 9000 # 使用 port 9000使用日誌記錄功能:
./run_with_logs.sh # 使用預設 port 8080,並保存日誌
./run_with_logs.sh 3000 # 使用 port 3000,並保存日誌使用預設 port 8080:
cd src
python3 main.py指定自訂 port:
cd src
python3 main.py --port 3000 # 使用 port 3000
python3 main.py -p 9000 # 使用 port 9000(簡短形式)查看所有可用選項:
python3 src/main.py --help啟動成功後,您會看到類似以下的訊息:
============================================================
ProWaveDAQ Real-time Data Visualization System
============================================================
Web interface will be available at http://0.0.0.0:8080/
Press Ctrl+C to stop the server
============================================================
-
開啟瀏覽器
- 在本地機器:開啟
http://localhost:<port>/(預設為 8080) - 在遠端機器:開啟
http://<設備IP>:<port>/(預設為 8080)
範例:
- 使用預設 port:
http://localhost:8080/ - 使用自訂 port 3000:
http://localhost:3000/
- 在本地機器:開啟
-
輸入資料標籤
- 在「資料標籤 (Label)」欄位輸入本次測量的標籤名稱
- 例如:
test_001、vibration_20240101等
-
設定 SQL 上傳(可選)
- 勾選「啟用 SQL 伺服器上傳」
- 選擇「使用 INI 檔案設定」或「手動輸入設定」
- 如果選擇使用 INI 設定,系統會自動讀取
sql.ini中的設定 - 如果選擇手動輸入,可以覆蓋 INI 設定
-
開始資料收集
- 點擊「開始讀取」按鈕
- 系統會自動:
- 連接 ProWaveDAQ 設備
- 開始讀取資料
- 即時顯示資料曲線
- 自動儲存 CSV 檔案
- (如果啟用)自動上傳資料至 SQL 伺服器
-
查看即時資料
- 即時曲線圖會自動更新(每 200ms)
- 可以同時查看三個通道的資料
- 顯示最近 10 秒的資料(每個通道約 78,120 個資料點)
- 資料點數會即時顯示
-
停止資料收集
- 點擊「停止讀取」按鈕
- 系統會安全地停止採集並關閉連線
- 自動上傳剩餘資料至 SQL 伺服器(如果啟用)
-
管理設定檔
- 點擊「設定檔管理」連結
- 使用固定輸入框編輯設定檔(防止誤刪參數)
- 可以編輯
ProWaveDAQ.ini、csv.ini和sql.ini - 修改後點擊「儲存設定檔」
-
瀏覽和下載檔案
- 點擊「檔案瀏覽」連結
- 可以瀏覽
output/ProWaveDAQ/目錄中的所有資料夾和檔案 - 點擊資料夾名稱或「進入」按鈕可以進入資料夾
- 點擊「下載」按鈕可以下載 CSV 檔案
- 使用麵包屑導航可以返回上層目錄
[ProWaveDAQ]
serialPort = /dev/ttyUSB0 # 串列埠路徑
baudRate = 3000000 # 鮑率
sampleRate = 7812 # 取樣率(Hz)
slaveID = 1 # Modbus 從站 ID[CSVServer]
enabled = false
[DumpUnit]
second = 60 # 每個 CSV 檔案的資料時間長度(秒)分檔邏輯說明:
- 系統會根據
sampleRate × channels × second計算每個 CSV 檔案應包含的資料點數 - 當累積的資料點數達到目標值時,自動建立新檔案
- 例如:取樣率 7812 Hz,3 通道,60 秒 → 每個檔案約 1,406,160 個資料點
[SQLServer]
enabled = false # 是否啟用 SQL 上傳(true/false)
host = 192.168.9.13 # SQL 伺服器位置
port = 3306 # 連接埠
user = raspberrypi # 使用者名稱
password = Raspberry@Pi # 密碼
database = daq-data # 資料庫名稱
[DumpUnit]
second = 5 # SQL 上傳間隔(秒),運作方式與 CSV 的 second 相同SQL 設定說明:
enabled:控制是否啟用 SQL 上傳功能- 如果
enabled = true,前端會自動勾選「啟用 SQL 伺服器上傳」 - 前端可以選擇使用 INI 設定或手動輸入(覆蓋 INI 設定)
- 重要:如果連線至 IMSL 實驗室的 MariaDB 伺服器,由於逢甲大學防火牆政策,需要先透過
connection.sh建立 OpenVPN 連線(詳見「設定 OpenVPN 連線」章節)
SQL 上傳邏輯說明:
- SQL 上傳採用暫存檔案機制,資料先寫入暫存 CSV 檔案
- 系統會建立暫存檔案目錄(
.sql_temp),檔案命名格式:{timestamp}_sql_temp.csv - 每
second秒定時檢查並上傳暫存檔案 - 上傳成功後自動刪除暫存檔案,並立即建立新暫存檔案(避免資料溢出)
- 停止時會檢查並上傳所有剩餘暫存檔案
- 例如:取樣率 7812 Hz,3 通道,5 秒 → 每 5 秒上傳一次暫存檔案
CSV 檔案會儲存在 output/ProWaveDAQ/ 目錄下,檔案命名格式:
YYYYMMDDHHMMSS_<Label>_001.csv
YYYYMMDDHHMMSS_<Label>_002.csv
...
每個 CSV 檔案包含:
Timestamp- 時間戳記(根據取樣率精確計算)Channel_1(X)- 通道 1 資料(對應 X 軸)Channel_2(Y)- 通道 2 資料(對應 Y 軸)Channel_3(Z)- 通道 3 資料(對應 Z 軸)
資料格式說明:
- 資料格式:
[長度, X, Y, Z, X, Y, Z, ...] - 從設備讀取時,第0格為長度,之後依序為 X, Y, Z 循環
- 時間戳記根據取樣率自動計算,確保每個樣本的時間間隔正確
如果啟用 SQL 上傳,資料會儲存在 vibration_data 資料表中,包含:
id- 自動遞增主鍵timestamp- 資料時間戳記label- 資料標籤channel_1- 通道 1 資料channel_2- 通道 2 資料channel_3- 通道 3 資料
ProWaveDAQ_Python_Visualization_Unit/
│
├── API/
│ ├── ProWaveDAQ.ini # ProWaveDAQ 設備設定檔
│ ├── csv.ini # CSV 分檔間隔設定檔
│ ├── sql.ini # SQL 伺服器連線設定檔和上傳間隔設定檔
│ ├── imCloud.ovpn # OpenVPN 連線設定檔(用於連線至 IMSL 實驗室)
│ └── connection_config.txt # OpenVPN 連線資訊設定檔(自動產生,請勿提交到版本控制)
│
├── connection.sh # OpenVPN 連線腳本(用於連線至 IMSL 實驗室 MariaDB 伺服器)
│
├── output/
│ └── ProWaveDAQ/ # CSV 輸出目錄
│ └── YYYYMMDDHHMMSS_<Label>/
│ ├── YYYYMMDDHHMMSS_<Label>_*.csv
│ └── .sql_temp/ # SQL 暫存檔案目錄(如果啟用 SQL)
│ └── YYYYMMDDHHMMSS_sql_temp.csv
│
├── src/
│ ├── prowavedaq.py # ProWaveDAQ 核心模組(Modbus 通訊)
│ ├── csv_writer.py # CSV 寫入器模組
│ ├── sql_uploader.py # SQL 上傳器模組
│ ├── logger.py # 統一日誌系統模組
│ ├── main.py # 主控制程式(Web 介面)
│ ├── requirements.txt # Python 依賴套件列表
│ └── templates/ # HTML 模板目錄
│ ├── index.html # 主頁模板
│ ├── config.html # 設定檔管理頁面模板
│ └── files.html # 檔案瀏覽頁面模板
│
├── README.md # 本文件
├── deploy.sh # 部署腳本
└── run.sh # 啟動腳本(進入虛擬環境並啟動程式)
| 路由 | 方法 | 功能說明 |
|---|---|---|
/ |
GET | 主頁,顯示設定表單、Label 輸入、SQL 設定、開始/停止按鈕與折線圖 |
/data |
GET | 回傳目前最新資料 JSON 給前端 |
/status |
GET | 檢查資料收集狀態 |
/sql_config |
GET | 取得 SQL 設定(從 sql.ini) |
/config |
GET | 顯示設定檔編輯頁面(固定輸入框,包含 ProWaveDAQ.ini、csv.ini、sql.ini) |
/config |
POST | 儲存修改後的設定檔 |
/start |
POST | 啟動 DAQ、CSVWriter、SQLUploader 與即時顯示 |
/stop |
POST | 停止所有執行緒、安全關閉,並上傳剩餘資料 |
/files_page |
GET | 檔案瀏覽頁面 |
/files |
GET | 列出 output 目錄中的檔案和資料夾(查詢參數:path) |
/download |
GET | 下載檔案(查詢參數:path) |
{
"success": true,
"data": [0.123, 0.456, 0.789, ...],
"counter": 12345
}{
"success": true,
"sql_config": {
"enabled": false,
"host": "localhost",
"port": "3306",
"user": "root",
"password": "",
"database": "prowavedaq"
}
}請求:
{
"label": "test_001",
"sql_enabled": true,
"sql_host": "192.168.9.13",
"sql_port": "3306",
"sql_user": "raspberrypi",
"sql_password": "Raspberry@Pi",
"sql_database": "daq-data"
}回應:
{
"success": true,
"message": "資料收集已啟動 (取樣率: 7812 Hz, 分檔間隔: 600 秒, SQL 上傳間隔: 600 秒)"
}注意:
- 如果選擇「使用 INI 檔案設定」,只需傳送
sql_enabled: true - 如果選擇「手動輸入設定」,需要傳送所有 SQL 設定參數
回應:
{
"success": true,
"message": "資料收集已停止"
}回應:
{
"success": true,
"is_collecting": true,
"counter": 12345
}查詢參數:
path(可選):要瀏覽的子目錄路徑
回應:
{
"success": true,
"items": [
{
"name": "20240101120000_test_001",
"type": "directory",
"path": "20240101120000_test_001"
},
{
"name": "data.csv",
"type": "file",
"path": "data.csv",
"size": 1024
}
],
"current_path": ""
}查詢參數:
path(必需):要下載的檔案路徑
回應:直接下載檔案
ProWaveDAQ 設備 (Modbus RTU)
↓
資料格式:[長度, X, Y, Z, X, Y, Z, ...]
↓
ProWaveDAQ._read_loop() [背景執行緒]
├─→ 讀取資料長度(第0格)
├─→ 讀取完整資料(包含長度)
├─→ 處理長度不是3的倍數的情況(remaining_data 機制)
├─→ 確保只處理完整的樣本(X, Y, Z 組合)
└─→ 資料轉換(16位元整數 → 浮點數)
↓ (放入佇列)
data_queue (queue.Queue, 最大 1000 筆)
↓
collection_loop() [背景執行緒]
├─→ update_realtime_data()
│ ↓
│ realtime_data_buffer (np.ndarray, 固定 234,360 點)
│ realtime_time_buffer (np.ndarray, 固定 10 個時間點)
│ ↓
│ Flask /data API (HTTP GET, 每 200ms)
│ ↓
│ 前端 Chart.js (templates/index.html)
│
├─→ CSV Writer
│ ├─→ 根據取樣率計算時間戳記
│ ├─→ 確保分檔時時間戳記連續
│ └─→ CSV 檔案 (分檔儲存,確保樣本邊界)
│
└─→ SQL Uploader(如果啟用)
├─→ 寫入暫存 CSV 檔案
│ └─→ .sql_temp/{timestamp}_sql_temp.csv
│
└─→ 定時上傳執行緒(每 sql_upload_interval 秒)
├─→ 讀取暫存檔案
├─→ 批次上傳至 SQL
├─→ 刪除暫存檔案
└─→ 建立新暫存檔案
↓
MariaDB/MySQL 資料庫
機制:HTTP 輪詢(Polling)+ 降頻佇列
- 請求頻率:每 100 毫秒(0.1 秒)請求一次
- 資料傳輸:JSON 格式(降頻後的增量資料)
- 降頻架構:降頻佇列(Downsampling Queue)
- 降頻比例:50(每 50 點取 1 點)
- 原始採樣率:7812 Hz → 降頻後約 156 Hz
- 前端資料傳輸量減少約 98%
- 前端繪圖負擔大幅降低
- 佇列架構:
web_data_queue:存儲降頻後的資料供前端使用(最大 10,000 筆)csv_data_queue:存儲原始資料供 CSV 寫入(最大 1,000 筆)sql_data_queue:存儲原始資料供 SQL 上傳(最大 1,000 筆)
- 顯示限制:前端顯示最多 500 個點(約 5-10 秒的降頻資料)
- 增量更新:前端只處理新資料,使用
push()和splice()維持固定視窗大小
前端處理:
// 每 200ms 執行一次
setInterval(updateChart, 200);
function updateChart() {
fetch('/data')
.then(response => response.json())
.then(data => {
// 將資料按通道分組(每3個為一組)
// 更新 Chart.js 圖表
// 限制顯示最近 10 秒的資料(78,120 個資料點/通道)
});
}觸發方式:基於資料量
-
計算目標大小:
target_size = second × sampleRate × channels -
累積計數器:
current_data_size += len(data)
-
分檔邏輯:
- 如果
current_data_size < target_size:直接寫入當前檔案 - 如果
current_data_size >= target_size:分批處理,建立新檔案 - 重要:確保切斷位置在樣本邊界(3的倍數),避免通道錯位
- 如果
-
時間戳記計算:
- 每個樣本的時間間隔 = 1 / sample_rate 秒
- 時間戳記 = 全局起始時間 + (樣本計數 × 樣本間隔)
- 確保分檔時時間戳記連續
觸發方式:基於時間間隔(定時上傳)
-
暫存檔案機制:
- 資料收集開始時,在輸出目錄下建立
.sql_temp暫存目錄 - 建立第一個暫存檔案(檔名格式:
{timestamp}_sql_temp.csv) - 所有 SQL 資料直接寫入當前暫存檔案
- 資料收集開始時,在輸出目錄下建立
-
定時上傳執行緒:
- 啟動獨立的背景執行緒(
sql_upload_timer_loop) - 每
sql_upload_interval秒檢查一次 - 時間到達時:
- 上傳當前暫存檔案到 SQL 伺服器
- 上傳成功後刪除暫存檔案
- 立即建立新的暫存檔案(避免資料溢出)
- 啟動獨立的背景執行緒(
-
資料保護機制:
- 重試機制:上傳失敗時最多重試 3 次,遞增延遲(0.1s, 0.2s, 0.3s)
- 失敗保留:上傳失敗時暫存檔案保留,等待下次重試
- 成功確認:只有上傳成功後才刪除暫存檔案
- 自動重連:連線中斷時自動重連
-
批次插入:
- 從暫存 CSV 檔案讀取所有資料
- 使用
executemany()批次插入,提升效能 - 自動建立對應的 SQL 資料表(表名與 CSV 檔名對應)
-
停止時處理:
- 停止時上傳當前暫存檔案
- 檢查並上傳所有剩餘暫存檔案(確保資料不遺失)
- 上傳成功後刪除所有暫存檔案
暫存檔案結構:
output/ProWaveDAQ/{timestamp}_{label}/
├── {timestamp}_{label}_001.csv
├── {timestamp}_{label}_002.csv
└── .sql_temp/ # 暫存檔案目錄
├── 20250106120000_sql_temp.csv
├── 20250106120600_sql_temp.csv
└── ...
優勢:
- 降低記憶體使用:資料直接寫入檔案,不佔用記憶體緩衝區
- 資料持久化:即使程式異常終止,暫存檔案仍保留
- 定時上傳:避免頻繁的 SQL 連線,提升效能
- 自動清理:上傳成功後自動刪除暫存檔案
症狀:啟動後無法讀取資料
解決方法:
- 檢查串列埠路徑是否正確(
/dev/ttyUSB0或其他) - 確認設備已正確連接
- 檢查使用者是否有串列埠存取權限
- 嘗試使用
ls -l /dev/ttyUSB*確認設備存在
症狀:無法在瀏覽器中開啟網頁
解決方法:
- 確認防火牆允許使用的埠號(預設為 8080)
- 檢查是否有其他程式佔用該埠號
- 如果使用自訂 port,請確認瀏覽器中的 URL 使用正確的埠號
- 確認 Python 程式正在執行
- 檢查系統日誌是否有錯誤訊息
症狀:圖表顯示異常或資料點不正確
解決方法:
- 檢查設定檔中的取樣率是否正確
- 確認通道數設定(預設為 3)
- 檢查瀏覽器控制台是否有 JavaScript 錯誤
症狀:資料收集正常但沒有 CSV 檔案
解決方法:
- 檢查
output/ProWaveDAQ/目錄是否有寫入權限 - 確認 Label 已正確輸入
- 檢查磁碟空間是否充足
症狀:SQL 上傳功能無法正常運作
解決方法:
- 檢查
sql.ini中的連線設定是否正確 - 如果連線至 IMSL 實驗室 MariaDB 伺服器:
- 確認 OpenVPN 連線已建立(執行
./connection.sh) - 檢查 OpenVPN 連線狀態:
pgrep -x openvpn - 確認 VPN 連線正常:
ip addr show tun0 - 如果連線失敗,檢查:
API/imCloud.ovpn檔案是否存在且正確API/connection_config.txt中的連線資訊是否正確- 執行
./connection.sh --setup重新設定連線資訊
- 確認 OpenVPN 連線已建立(執行
- 一般連線問題:
- 確認 SQL 伺服器是否可連線(測試:
mysql -h <host> -P <port> -u <user> -p) - 檢查資料庫是否存在
- 確認使用者權限是否足夠(CREATE TABLE、INSERT)
- 查看終端機的錯誤訊息
- 檢查網路連線(特別是跨網段時)
- 確認 SQL 伺服器是否可連線(測試:
症狀:資料採集中途停止
解決方法:
- 檢查 Modbus 連線是否中斷
- 查看終端機的錯誤訊息
- 確認設備是否正常運作
- 檢查 SQL 連線是否正常(如果啟用 SQL 上傳)
症狀:系統記憶體使用過高
解決方法:
- 檢查
sql_upload_interval設定是否過大 - 系統會自動限制緩衝區大小(最多 10,000,000 個資料點)
- 如果持續出現記憶體問題,可以降低
sql_upload_interval值
症狀:CSV 檔案或圖表中的通道順序不正確
解決方法:
- 系統已自動處理此問題(使用
remaining_data機制) - 如果仍有問題,檢查:
- 資料格式是否正確:
[長度, X, Y, Z, X, Y, Z, ...] - 檢查日誌中是否有「Remaining data points」警告
- 查看
通道錯誤可能性分析.md文件了解詳細情況
- 資料格式是否正確:
系統使用統一的日誌系統(logger.py),提供以下日誌級別:
[INFO]- 一般資訊訊息[Debug]- 調試訊息(可透過Logger.set_debug_enabled(False)關閉)[Error]- 錯誤訊息[Warning]- 警告訊息
所有日誌訊息自動包含時間戳記,格式為:
[YYYY-MM-DD HH:MM:SS] [LEVEL] 訊息內容
注意:Flask 的 HTTP 請求日誌已預設隱藏,只顯示應用程式的日誌訊息。
如需查看詳細的除錯資訊,可以:
- 查看終端機的日誌輸出
- 使用
Logger.set_debug_enabled(True)啟用 Debug 訊息 - 檢查
通道錯誤可能性分析.md文件了解可能的問題
| 執行緒 | 功能 | 備註 |
|---|---|---|
| 主執行緒 | 控制流程、等待使用者中斷 | 同步主控核心 |
| Flask Thread | 提供 HTTP 介面與 API | daemon=True |
| Collection Thread | 資料收集迴圈(處理 CSV 和 SQL) | 在 /start 時啟動 |
| DAQ Reading Thread | 從 Modbus 設備讀取資料 | 在 start_reading() 時啟動,執行 _read_loop() |
公開 API(供外部使用):
scan_devices()- 掃描可用的 Modbus 設備init_devices(filename)- 從 INI 檔案初始化設備並建立連線start_reading()- 啟動資料讀取(背景執行緒)stop_reading()- 停止資料讀取並關閉連線get_data()- 非阻塞取得最新一批資料get_data_blocking(timeout)- 阻塞取得最新一批資料get_counter()- 取得讀取批次計數get_sample_rate()- 取得取樣率
內部方法(模組內部使用):
_connect()- 建立 Modbus RTU 連線_disconnect()- 關閉 Modbus 連線_ensure_connected()- 確保連線存在(自動重連)_read_chip_id()- 讀取晶片 ID(初始化時)_set_sample_rate()- 設定取樣率(初始化時)_read_registers_with_header()- 讀取寄存器(包含 Header)_read_normal_data()- Normal Mode 讀取(Address 0x02)_read_bulk_data()- Bulk Mode 讀取(Address 0x15)_get_buffer_status()- 讀取緩衝區狀態_convert_raw_to_float_samples()- 轉換為浮點數(確保 XYZ 不錯位)_read_loop()- 主要讀取迴圈(背景執行緒)
讀取模式:
- Normal Mode:當緩衝區資料量 ≤ 123 時使用,從 Address 0x02 讀取
- Bulk Mode:當緩衝區資料量 > 123 時使用,從 Address 0x15 讀取,最多讀取 9 個樣本
- 自動根據緩衝區狀態切換模式,優化讀取效率
設計原則:
- 每次讀取只處理完整的 XYZ 三軸組,避免通道錯位
- FIFO buffer size(0x02) 連同資料一起讀出,確保一致性
- 自動重連機制,確保連線穩定性
- 模組化設計,方便未來擴展和維護
ProWaveDAQ 設備
↓ (Modbus RTU)
ProWaveDAQ._read_loop() [背景執行緒]
├─ _get_buffer_status() # 讀取緩衝區狀態(寄存器 0x02)
├─ 模式判斷
│ ├─ buffer_count ≤ 123 → Normal Mode
│ │ └─ _read_normal_data() # 從 Address 0x02 讀取
│ └─ buffer_count > 123 → Bulk Mode
│ └─ _read_bulk_data() # 從 Address 0x15 讀取(最多 9 個樣本)
├─ _read_registers_with_header() # 讀取 Header + 資料
└─ _convert_raw_to_float_samples() # 轉換為浮點數(確保 XYZ 不錯位)
↓ (放入佇列)
data_queue (queue.Queue, 最大 10000 筆)
↓
collection_loop() [背景執行緒]
│
├─→ update_realtime_data()
│ │
│ ▼
│ realtime_data (List[float], 最多 234,360 個點)
│ │ - 智慧緩衝區:僅在有活躍連線時更新
│ │ - 限制為 10 秒的資料量(7812 Hz × 3 通道 × 10 秒)
│ │
│ ▼
│ Flask /data API (HTTP GET, 每 200ms)
│ │
│ ▼
│ 前端 Chart.js (templates/index.html)
│ - 每 200ms 更新一次
│ - 限制顯示最近 10 秒的資料(78,120 個資料點/通道)
│
├─→ CSV 資料佇列 (csv_data_queue)
│ │
│ ▼
│ CSV Writer Thread (獨立執行緒)
│ │
│ ▼
│ 分檔邏輯判斷
│ │
│ ├─→ current_data_size < target_size
│ │ └─→ 直接寫入當前檔案
│ │
│ └─→ current_data_size >= target_size
│ ├─→ 寫入完整批次
│ ├─→ update_filename() (建立新檔案)
│ └─→ 處理剩餘資料
│ │
│ ▼
│ CSV 檔案
│ output/ProWaveDAQ/{timestamp}_{label}/{timestamp}_{label}_{001-999}.csv
│
└─→ SQL 資料佇列 (sql_data_queue)
│
▼
SQL Writer Thread (獨立執行緒)
│
▼
SQL 暫存檔案寫入
│
├─→ sql_current_data_size < sql_target_size
│ └─→ 累積資料,不上傳
│
└─→ sql_current_data_size >= sql_target_size
├─→ 定時上傳 (executemany)
├─→ 重試機制 (最多 3 次)
├─→ 失敗保留 (資料不遺失)
└─→ 成功後刪除暫存檔案
│
▼
MariaDB/MySQL 資料庫
vibration_data 資料表
- 不使用
asyncio或WebSocket - 不使用檔案中介資料交換
- 所有資料傳遞均在記憶體中完成
- 使用 Python 變數或全域狀態保存資料
- SQL 上傳使用 HTTP 連線,不支援 WebSocket
-
即時資料緩衝區:
- 最多保留 234,360 個資料點(約 1.87 MB,10 秒的資料量)
- 計算:7812 Hz × 3 通道 × 10 秒 = 234,360 個資料點
- 僅在有活躍前端連線時更新
- 前端顯示限制:最近 10 秒的資料(每個通道 78,120 個資料點)
-
SQL 資料緩衝區:
- 上限:
min(sql_target_size × 2, 10,000,000)個資料點 - 超過上限時強制上傳
- 上限:
-
DAQ 資料佇列:
- 最多 1000 筆(每筆約 123 個點,約 1 MB)
如需擴展系統功能,可以:
- 修改前端介面:編輯
src/templates/index.html和src/templates/config.html模板 - 調整圖表設定:在
src/templates/index.html中修改 Chart.js 的配置選項 - 新增 API 路由:在
src/main.py中新增路由處理函數 - 自訂 CSV 格式:修改
src/csv_writer.py中的寫入邏輯 - 自訂 SQL 格式:修改
src/sql_uploader.py中的資料表結構和插入邏輯
src/prowavedaq.py:負責 Modbus RTU 通訊與資料讀取- 處理資料格式:
[長度, X, Y, Z, X, Y, Z, ...] - 自動處理長度不是3的倍數的情況(使用
remaining_data機制) - 多執行緒安全保護(使用鎖定機制)
- 資料完整性檢查
- 處理資料格式:
src/csv_writer.py:負責 CSV 檔案的建立與寫入- 根據取樣率自動計算時間戳記
- 確保分檔時時間戳記連續
- 通道標示:Channel_1(X), Channel_2(Y), Channel_3(Z)
src/sql_uploader.py:負責 SQL 資料庫連線與資料上傳- 支援 MySQL/MariaDB
- 重試機制和資料保護
src/logger.py:統一日誌系統- 提供統一的日誌格式
- 支援多種日誌級別
- 自動時間戳記
src/main.py:整合所有功能,提供 Web 介面(使用 Flask + templates)- 分檔邏輯確保樣本邊界(3的倍數)
- SQL 上傳確保樣本邊界
- 智慧緩衝區管理
src/templates/index.html:主頁 HTML 模板(包含 Chart.js 圖表、SQL 設定)src/templates/config.html:設定檔管理頁面模板(固定輸入框)src/templates/files.html:檔案瀏覽頁面模板
-
資料保護:
- SQL 上傳失敗時保留資料在緩衝區
- 只有上傳成功後才從緩衝區移除
- 最多重試 3 次,遞增延遲
-
記憶體保護:
- SQL 緩衝區設定上限,防止記憶體溢出
- 超過上限時強制上傳
-
設定檔管理:
- 使用固定輸入框,防止使用者誤刪參數
- SQL 設定獨立為
sql.ini檔案
-
智慧緩衝區:
- 僅在有活躍前端連線時更新即時資料緩衝區
- 節省 CPU 和記憶體資源
本專案為內部使用專案,請遵循相關使用規範。
如有問題或建議,請聯絡專案維護者。
最後更新:2025年12月22日
作者:王建葦
當前版本:8.1.0
詳細的版本更新記錄請參考 CHANGELOG.md