2025年4月29日 星期二

PyTorch LSTM 模型可用的標準化處理

 針對這些 DataFrame(df、df_type0/1/2)進行 PyTorch LSTM 模型可用的標準化處理

下面我會依據 LSTM 模型需求幫你設計這個流程,包括:

  1. 資料標準化(Zero-mean, Unit-std)

  2. 轉為 NumPy 陣列(每個 sample 為一筆時間序列的特徵向量)

  3. 可選:轉為 PyTorch Dataset


✅ Step 1:標準化全體 df(再套用到各類別)

✅ 假設每筆資料是獨立時間點(如 IMU frame)

python
from sklearn.preprocessing import StandardScaler # 取出特徵欄位 b1 ~ b9(排除 type) feature_cols = ['b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9'] # 建立標準化器 scaler = StandardScaler() # 對全體資料 df 做 fit(避免只 fit 某一類產生偏差) scaler.fit(df[feature_cols])

✅ Step 2:對每個資料集標準化(df / df_type0 / df_type1 / df_type2)

python
# 標準化後存回 DataFrame(保留其他欄位如 type) df_scaled = df.copy() df_scaled[feature_cols] = scaler.transform(df[feature_cols]) df_type0_scaled = df_type0.copy() df_type0_scaled[feature_cols] = scaler.transform(df_type0[feature_cols]) df_type1_scaled = df_type1.copy() df_type1_scaled[feature_cols] = scaler.transform(df_type1[feature_cols]) df_type2_scaled = df_type2.copy() df_type2_scaled[feature_cols] = scaler.transform(df_type2[feature_cols])

✅ Step 3:轉成 NumPy 陣列(準備餵給 LSTM)

📌 LSTM 輸入格式為 (batch_size, seq_len, feature_dim)

如果每筆資料都是單點(沒有序列),你可以手動 reshape 加 seq_len=1

python
import numpy as np # 提取資料 X_all = df_scaled[feature_cols].to_numpy().reshape(-1, 1, len(feature_cols)) # [N, 1, 9] y_all = df_scaled['type'].to_numpy().astype(int)

對於各類別:

python
X0 = df_type0_scaled[feature_cols].to_numpy().reshape(-1, 1, len(feature_cols)) y0 = df_type0_scaled['type'].to_numpy().astype(int) X1 = df_type1_scaled[feature_cols].to_numpy().reshape(-1, 1, len(feature_cols)) y1 = df_type1_scaled['type'].to_numpy().astype(int) X2 = df_type2_scaled[feature_cols].to_numpy().reshape(-1, 1, len(feature_cols)) y2 = df_type2_scaled['type'].to_numpy().astype(int)

✅ Step 4:轉為 PyTorch Dataset(LSTM 可用格式)

python
import torch from torch.utils.data import TensorDataset, DataLoader # 將全體轉為 tensor dataset X_tensor = torch.tensor(X_all, dtype=torch.float32) y_tensor = torch.tensor(y_all, dtype=torch.long) dataset_all = TensorDataset(X_tensor, y_tensor) # 分類別也可建立獨立資料集 dataset0 = TensorDataset(torch.tensor(X0, dtype=torch.float32), torch.tensor(y0, dtype=torch.long)) dataset1 = TensorDataset(torch.tensor(X1, dtype=torch.float32), torch.tensor(y1, dtype=torch.long)) dataset2 = TensorDataset(torch.tensor(X2, dtype=torch.float32), torch.tensor(y2, dtype=torch.long))

📦 DataLoader 建立(批次訓練)

python
loader_all = DataLoader(dataset_all, batch_size=32, shuffle=True) loader0 = DataLoader(dataset0, batch_size=32, shuffle=True)

✅ LSTM 輸入範例格式(模型)

python
class LSTMClassifier(torch.nn.Module): def __init__(self, input_dim, hidden_dim, output_dim): super().__init__() self.lstm = torch.nn.LSTM(input_dim, hidden_dim, batch_first=True) self.fc = torch.nn.Linear(hidden_dim, output_dim) def forward(self, x): _, (hn, _) = self.lstm(x) # hn: [1, batch, hidden] out = self.fc(hn.squeeze(0)) return out model = LSTMClassifier(input_dim=9, hidden_dim=32, output_dim=3)

🔍 小提醒:

  • 如果你要處理 時間序列(多筆一組),需先將 DataFrame 按時間組成「序列視窗」,這邊是以每筆為單點(seq_len=1)做範例。

  • 若你有 IMU 連續資料想轉為每 20 筆一個序列,也可用 sliding window 處理。


是否要我再補上「每 type 資料切成 seq_len=100 的滑動視窗」的處理邏輯?

這樣才真正符合 LSTM 使用場景。


2025年4月28日 星期一

機器學習 (分類演算法&聚類演算法)

 介紹這些常見的機器學習分類演算法&聚類演算法

Common Machine Learning Algorithms

Naïve Bayes Classifiers

Support Vector Machines

Logistic Regression

Artificial Neural Networks

Random Forests

Decision Trees

k-Nearest Neighbors

• K-Means Clustering

• Apriori Algorithm

• Linear Regression

#分類演算法 (Classification Algorithms):

  • Naïve Bayes Classifiers (樸素貝氏分類器):

    • 原理: 基於貝氏定理和特徵條件獨立的假設。它假設每個特徵對於分類結果的影響是獨立的,即使這些特徵在現實世界中可能並非如此。
    • 優點: 簡單易懂,訓練速度快,在小數據集和特徵獨立性較強的情況下表現良好。
    • 缺點: 對特徵獨立性的假設在現實中往往不成立,可能導致預測準確度下降。如果訓練集中某個特徵的某個取值從未出現,預測結果可能會出現問題(零概率問題)。
    • 應用場景: 垃圾郵件過濾、文本分類、情感分析等。
  • Support Vector Machines (SVMs, 支持向量機):

    • 原理: 尋找一個能夠將不同類別的數據點最大程度分隔開來的最佳超平面。對於非線性可分的數據,SVM 可以通過核函數將數據映射到高維空間,使其在高維空間中線性可分。
    • 優點: 在高維空間中有效,對於線性不可分的數據也能處理,泛化能力強(在未見過的數據上表現良好),可以使用不同的核函數來適應不同的數據分佈。
    • 缺點: 對於大型數據集訓練時間較長,參數調整(例如核函數的選擇和超參數的設定)比較複雜,模型解釋性較差。
    • 應用場景: 圖像分類、文本分類、生物資訊學、人臉識別等。
  • Logistic Regression (邏輯迴歸):

    • 原理: 雖然名字帶有「迴歸」,但它實際上是一種分類演算法,主要用於二元分類問題。它使用 Sigmoid 函數將線性迴歸的輸出映射到 0 和 1 之間的概率值,從而進行分類。對於多元分類,可以使用 One-vs-Rest (OvR) 或 One-vs-One (OvO) 等策略。
    • 優點: 簡單高效,易於實現和解釋,可以直接輸出概率預測。
    • 缺點: 對於複雜的非線性關係建模能力較弱,容易欠擬合。
    • 應用場景: 廣告點擊預測、疾病風險預測、信用評估等。
  • Artificial Neural Networks (ANNs, 人工神經網路):

    • 原理: 模擬人腦神經元的結構和功能,通過多層相互連接的節點(神經元)進行信息處理。通過調整連接權重和偏置項來學習數據中的複雜模式。深度學習是 ANN 的一個重要分支,包含更多層次的網路結構。
    • 優點: 能夠學習非常複雜的非線性關係,在圖像、語音、自然語言處理等領域取得了巨大成功。
    • 缺點: 模型結構複雜,訓練需要大量的數據和計算資源,模型解釋性差,容易過擬合,參數調整困難。
    • 應用場景: 圖像識別、語音識別、自然語言處理、機器翻譯、推薦系統等。
  • Random Forests (隨機森林):

    • 原理: 一種集成學習方法,通過構建多個決策樹並將它們的預測結果進行組合(例如,對於分類問題採用多數投票,對於迴歸問題取平均)來做出最終決策。在構建每棵樹時,會隨機選擇一部分特徵和一部分數據樣本。
    • 優點: 準確率高,泛化能力強,不容易過擬合,能夠處理高維數據,可以評估特徵的重要性。
    • 缺點: 模型解釋性不如單個決策樹,訓練和預測速度可能比單個決策樹慢。
    • 應用場景: 圖像分類、目標檢測、金融風險評估、疾病診斷等。
  • Decision Trees (決策樹):

    • 原理: 一種基於樹狀結構的分類和迴歸方法。通過一系列的判斷節點,將數據逐步劃分到不同的葉子節點,每個葉子節點代表一個類別(分類)或一個預測值(迴歸)。
    • 優點: 易於理解和解釋,可以處理離散型和連續型特徵,對數據的預處理要求不高。
    • 缺點: 容易過擬合,對於複雜的非線性關係建模能力有限,樹的結構可能不穩定(數據的微小變化可能導致樹的結構發生很大變化)。
    • 應用場景: 風險評估、客戶流失預測、醫學診斷等。
  • k-Nearest Neighbors (k-NN, k 近鄰):

    • 原理: 一種基於實例的學習方法。對於一個新的數據點,它會找到訓練集中與該點最接近的 k 個鄰居,然後根據這 k 個鄰居的類別進行投票(分類)或取平均值(迴歸)來預測新數據點的類別或值。
    • 優點: 簡單易懂,無需顯式的訓練過程,可以用於分類和迴歸。
    • 缺點: 對於大型數據集計算成本高,對特徵的尺度敏感,需要選擇合適的 k 值,對於不平衡的數據集表現可能不佳。
    • 應用場景: 推薦系統、圖像識別、模式識別等。

#聚類演算法 (Clustering Algorithm):

  • K-Means Clustering (K-均值聚類):
    • 原理: 一種迭代的聚類演算法,旨在將數據集劃分為 k 個不同的簇,使得每個數據點都屬於離它最近的均值(簇中心)所代表的簇。算法通過不斷迭代調整簇中心和重新分配數據點來實現聚類。
    • 優點: 簡單高效,容易實現,對於球狀簇結構的數據效果較好。
    • 缺點: 需要預先指定簇的數量 k,對初始簇中心的選擇敏感,對非球狀簇結構和大小差異較大的簇效果不佳,對離群點敏感。
    • 應用場景: 客戶分群、圖像分割、文件聚類、異常檢測等。

#關聯規則學習演算法 (Association Rule Learning Algorithm):

  • Apriori Algorithm:
    • 原理: 一種用於發現數據集中項集之間有趣關聯的演算法。它通過識別頻繁項集(出現頻率超過給定閾值的項集),然後從這些頻繁項集中生成關聯規則。Apriori 算法的核心思想是「如果一個項集是頻繁的,那麼它的所有子集也必須是頻繁的」。
    • 優點: 原理簡單,易於實現,可以發現數據集中潛在的關聯規則。
    • 缺點: 對於大型數據集和大量的候選項集,計算成本可能很高,需要多次掃描數據集。
    • 應用場景: 購物籃分析(例如,哪些商品經常被一起購買)、推薦系統、網頁點擊流分析等。

#迴歸演算法 (Regression Algorithms):

  • Linear Regression (線性迴歸):
    • 原理: 假設自變數和因變數之間存在線性關係,通過擬合一條最佳直線(或在高維空間中的超平面)來預測因變數的值。目標是最小化預測值和實際值之間的誤差平方和。
    • 優點: 簡單直觀,易於理解和解釋,計算效率高。
    • 缺點: 只能建模線性關係,對於非線性關係效果不佳,對異常值敏感。
    • 應用場景: 房價預測、股票價格預測、銷售額預測等。

希望這個詳細的說明能夠幫助你更好地理解這些常見的機器學習演算法!



nohup and /dev/null for python

 介紹在 Ubuntu 環境下使用 nohup 命令將 Python 程式放到背景執行的用法。這在需要長時間運行,且不希望因為終端機關閉而中斷程式的情況下非常實用。

nohup 命令的基本概念

nohup 是 "no hang up" 的縮寫,它的主要作用是讓程式在使用者登出終端機後,仍然能夠繼續執行。當你使用 nohup 啟動一個程式時,它會忽略 SIGHUP (hangup) 訊號。這個訊號通常在終端機連線中斷時發送給所有與該終端機相關的程序。

使用 nohup 執行 Python 程式於背景

以下是基本的用法和步驟:

  1. 確保你的 Python 程式可以正常執行: 首先,請確認你的 Python 程式 (your_script.py) 在前台可以正確地執行。你可以使用以下命令測試:

    Bash
    python your_script.py
    
  2. 使用 nohup 執行 Python 程式並放到背景: 要使用 nohup 將你的 Python 程式放到背景執行,你可以使用以下命令:

    Bash
    nohup python your_script.py &
    
    • nohup: 這個命令會讓後面的程式忽略 SIGHUP 訊號。
    • python your_script.py: 這是你要執行的 Python 命令。
    • &: 這個符號放在命令的最後面,表示將該命令放到背景執行。執行後,終端機會立即返回提示符號,你可以繼續輸入其他命令。
  3. 查看輸出: nohup 會將程式的標準輸出 (stdout) 和標準錯誤輸出 (stderr) 預設重新導向到目前目錄下一個名為 nohup.out 的檔案中。你可以使用 catlesstail 等命令來查看這個檔案的內容,以了解程式的執行情況。

    Bash
    cat nohup.out
    less nohup.out
    tail -f nohup.out  # 實時追蹤輸出
    
  4. 指定輸出檔案: 如果你想要將輸出導向到特定的檔案,可以使用重新導向符號 >>>

    • 覆蓋寫入:
      Bash
      nohup python your_script.py > my_output.log &
      
    • 追加寫入:
      Bash
      nohup python your_script.py >> my_output.log &
      
    • 同時導向標準輸出和標準錯誤輸出到同一個檔案:
      Bash
      nohup python your_script.py > output.log 2>&1 &
      
      或者更簡潔的寫法:
      Bash
      nohup python your_script.py &> output.log &
      
  5. 查看背景執行的程序: 你可以使用 jobsps 命令來查看目前在背景執行的程序。

    • jobs: 這個命令會列出目前終端機會話中放到背景執行的任務。但如果你關閉了終端機,jobs 就無法顯示這些程序了。

    • ps: 這個命令可以列出目前系統中正在執行的程序。你可以搭配 grep 來過濾出你的 Python 程序。

      Bash
      ps aux | grep "python your_script.py"
      

      這個命令會顯示包含 "python your_script.py" 的所有程序資訊。

  6. 終止背景執行的程序: 要終止一個在背景執行的程序,你需要先找到它的程序 ID (PID)。你可以使用 ps aux | grep "python your_script.py" 命令找到 PID,通常是輸出的第二欄的數字。然後使用 kill 命令加上 PID 來終止程序。

    Bash
    kill <PID>
    

    如果程序沒有正常終止,你可以嘗試使用 kill -9 強制終止它。

    Bash
    kill -9 <PID>
    

總結用法範例:

假設你的 Python 程式是 my_long_task.py,你想要在背景執行它,並將輸出寫入到 task.log 檔案中,你可以使用以下命令:

Bash
nohup python my_long_task.py > task.log 2>&1 &

執行後,你可以關閉你的終端機,這個 Python 程式仍然會在伺服器上繼續執行,並且所有的輸出都會被記錄在 task.log 檔案中。

[use  /dev/null ]

如果你不希望 nohup 產生預設的 nohup.out 檔案,或者你指定了其他的輸出檔案,但現在想避免這些檔案的寫入以減少對硬碟讀寫壽命的影響,你可以將標準輸出 (stdout) 和標準錯誤輸出 (stderr) 重新導向到一個特殊的「空設備」檔案,即 /dev/null

/dev/null 是一個特殊的檔案,所有寫入到這個檔案的資料都會被丟棄,而從這個檔案讀取資料則會立即得到檔案結束 (EOF)。將輸出導向到 /dev/null 實際上就是將輸出「丟掉」,不會有任何資料被寫入到硬碟。

以下是如何修改你的 nohup 命令來避免寫入 log 檔案:

1. 丟棄標準輸出 (stdout):

如果你只想丟棄程式的標準輸出,可以使用 > 將其導向到 /dev/null

Bash
nohup python your_script.py > /dev/null &

2. 丟棄標準錯誤輸出 (stderr):

如果你只想丟棄程式的標準錯誤輸出,可以使用 2> 將其導向到 /dev/null

Bash
nohup python your_script.py 2> /dev/null &

3. 同時丟棄標準輸出和標準錯誤輸出:

如果你想同時丟棄標準輸出和標準錯誤輸出,可以將它們都導向到 /dev/null。有幾種寫法:

  • 分別導向:

    Bash
    nohup python your_script.py > /dev/null 2> /dev/null &
    
  • 先導向 stdout 到 /dev/null,然後將 stderr 導向到與 stdout 相同的位置(即 /dev/null):

    Bash
    nohup python your_script.py > /dev/null 2>&1 &
    
  • 使用 &> (bash 4 及更新版本):

    Bash
    nohup python your_script.py &> /dev/null &
    

    這個語法會將標準輸出和標準錯誤輸出都導向到 /dev/null

選擇哪種方式取決於你的需求:

  • 如果你完全不關心程式的任何輸出(包括正常的資訊和錯誤訊息),那麼同時導向標準輸出和標準錯誤輸出到 /dev/null 是最直接的方法。
  • 如果你希望偶爾能夠檢查程式是否出錯(即使沒有詳細的 log),你可能需要考慮其他記錄錯誤的方式,或者在開發和測試階段開啟 log 記錄,在正式長時間運行時再禁用。

注意事項:

  • 將輸出導向到 /dev/null 後,你將無法看到程式運行的任何資訊或錯誤訊息。這可能會在程式出現問題時增加除錯的難度。
  • 如果你的 Python 程式本身有其他的檔案寫入操作,這些操作仍然會發生,並且不受你使用 /dev/null 重新導向 nohup 輸出的影響。

總之,使用 /dev/null 是一個有效避免 nohup 產生 log 檔案的方法,但你需要權衡這樣做可能帶來的除錯不便。在決定是否使用這種方法時,請仔細考慮你的應用場景和對程式輸出的需求。




2025年4月27日 星期日

IMU HAR 簡報大綱


 1#IMU 功能和應用介紹

2#HAR 資料分析

3#IMU 測試工具建立

4#流程概述:IMU 姿勢分類(RNN-LSTM)

5#Pytorch ML 訓練操作

6#模型驗證圖表

7#問題與討論   



1️⃣ IMU 功能和應用介紹


什麼是 IMU(Inertial Measurement Unit)?

  • 加速度計(Accelerometer):測量線性加速度

  • 陀螺儀(Gyroscope):測量角速度

  • 磁力計(Magnetometer,選配):測量地磁方向

常見應用領域

  • 自駕車與機器人導航

  • 穿戴式裝置(智慧手錶、健康監測)

  • 運動科學與復健追蹤

  • 遊戲控制器與 VR 設備


2️⃣ HAR 資料分析(Human Activity Recognition)


Human Activity Recognition(人體活動辨識)簡介

  • 利用 IMU 資料分析使用者的活動狀態

  • 常見活動類別:靜止、行走、跑步、上下樓梯、騎車

HAR 資料分析流程

  • IMU 原始數據(6軸/9軸)蒐集

  • 訊號處理(濾波、標準化)

  • 資料標註(Activity Labels)

  • 特徵提取(Raw Data or Features)

  • 建立分類模型


3️⃣ IMU 測試工具建立


開發 IMU 測試平台

  • 目標:即時收集與顯示 IMU 資料

  • 技術堆疊:Flask + PyQt5 + pyqtgraph

功能需求

  • Wi-Fi 透過 API 接收即時資料

  • 資料緩衝與流暢播放(100Hz)

  • 支援 CSV 載入 / API 即時讀取

  • 支援資料組選擇、分類疊加顯示


4️⃣ 流程概述:IMU 姿勢分類(RNN-LSTM)


IMU 姿勢分類整體流程

  1. 收集 IMU 連續時間序列資料

  2. 資料標準化與滑動視窗切割

  3. 訓練 Recurrent Neural Network (RNN)

  4. 使用 LSTM(Long Short-Term Memory)擷取時間特徵

  5. 分類輸出:靜止 / 站立 / 行走 / 坐下

資料處理重點

  • 每 0.01 秒一筆資料

  • 滑動窗格:100筆(1秒)、200筆(2秒)

  • 標籤依活動切分


5️⃣ PyTorch ML 訓練操作


PyTorch 訓練主要步驟

  • 定義 LSTM 類別模型

  • 建立訓練與驗證集

  • 設置 Loss function (CrossEntropyLoss)

  • 設置 Optimizer (Adam)

  • 訓練迴圈(Epochs)

  • 儲存最佳化模型 (model.pth)

範例超參數

  • Hidden units:64

  • Layers:2

  • Batch size:64

  • Learning rate:0.001

  • 訓練次數:20 epochs


6️⃣ 模型驗證圖表


訓練結果驗證

  • Loss 曲線(Training loss vs Validation loss)

  • Accuracy 曲線(Training accuracy vs Validation accuracy)

  • 混淆矩陣(Confusion Matrix)

    • 靜止、站立、行走、坐下辨識率

  • Precision / Recall / F1-Score

典型圖表類型

  • Line Chart:損失與正確率

  • Heatmap:混淆矩陣


7️⃣ 問題與討論


潛在問題

  • 資料不均(靜止樣本數遠大於行走)

  • 感測器雜訊影響分類精度

  • 延遲與時間同步問題

  • 小樣本訓練過擬合

未來改進方向

  • 引入更多傳感器數據(如心率)

  • 增加資料增強(Data Augmentation)

  • 測試不同神經網絡架構(GRU, Transformer)




2025年4月24日 星期四

imulog Server API 功能擴充(/imulogload)

 

imulog Server API 功能擴充

✅ 功能擴充目標

API 路徑功能說明
/imulog接收 log 陣列資料(每筆為 [b1..b6, time]),以 .append() 加入全域變數 log_data。若總長度超過 500 筆,則自動移除最舊資料
/imulogloadlog_data 內容作為 JSON 回傳,並在回傳後立即清空(即一次性讀取)


✅ 更新後程式碼內容

🔧 全域 log_data 改為固定容量佇列(可用 collections.deque

python
from flask import Flask, request, jsonify import os import csv import re import json from collections import deque app = Flask(__name__) # 最大容量為 500 筆(約 5 秒) log_data = deque(maxlen=500)

✅ 更新 /imulog:改為 append 模式

python
@app.route('/imulog', methods=['POST']) def post_imu_log(): """接收 IMU log 資料並追加到 log_data(自動裁剪至 500 筆)。""" print("POST IMU log data!") if not request.is_json: return jsonify({"error": "Request must be JSON"}), 400 data = request.get_json() if 'time' not in data or 'log' not in data: return jsonify({"error": "JSON must contain 'time' and 'log' keys"}), 400 try: log_items = data['log'] if isinstance(log_items, str): log_items = json.loads(log_items) if not isinstance(log_items, list): raise ValueError("log must be a list") added = 0 for item in log_items: if isinstance(item, list) and len(item) == 7: log_data.append(item) added += 1 else: print(f"忽略格式錯誤項目:{item}") print(f"Appended {added} items to log_data (total: {len(log_data)})") return jsonify({"message": f"Appended {added} items", "length": len(log_data)}), 201 except Exception as e: print(f"Error appending log: {str(e)}") return jsonify({"error": f"Failed to append: {str(e)}"}), 400

✅ 新增 /imulogload:讀取後清空

python
@app.route('/imulogload', methods=['GET']) def load_and_clear_log_data(): """一次性取得 log_data 中的內容,並清空。""" print("GET /imulogload called") # 將 deque 轉成 list 回傳 data = list(log_data) log_data.clear() print(f"Returned {len(data)} items and cleared log_data") return jsonify({"log": data, "count": len(data)})

🔁 測試流程建議

  1. 傳送 log 資料

    bash
    curl -X POST http://localhost:8081/imulog \ -H "Content-Type: application/json" \ -d '{"time":"t1", "log":[[0.1,0.2,0.3,0.4,0.5,0.6,0.01]]}'
  2. 取得並清空 log 資料

    bash
    curl http://localhost:8081/imulogload


✅ 新增功能 + 調整重點

項目說明
🔁 新增 GET /imulogpeek API只讀取 log 資料內容,但不清除
🔁 log_data buffer 容量提升至 1000 筆對應 100Hz 取樣率 ≈ 10 秒緩衝

🔧 修改程式碼說明

1️⃣ 將 log_data 變更為 1000 筆上限:

python
from collections import deque log_data = deque(maxlen=1000) # 緩衝 10 秒的資料(100Hz)

2️⃣ 新增 /imulogpeek API

python
@app.route('/imulogpeek', methods=['GET']) def peek_log_data(): """僅查看 log_data 內容(不清除)。""" print("GET /imulogpeek called") data = list(log_data) return jsonify({ "log": data, "count": len(data) }), 200

✅ 完整 API 結構總結(目前為止)

Method路徑功能
POST/imulog接收 IMU log,追加至 log_data,保留最多 1000 筆
GET/imulogload讀取 + 清空 log_data
GET/imulogpeek只讀取 log_data,不清空
POST/imulogsave接收 log 並儲存成 CSV(由 client 主動上傳 log)

🧪 測試指令建議

✅ peek(只查看)

bash
curl http://localhost:8081/imulogpeek

✅ load(取出 + 清空)

bash
curl http://localhost:8081/imulogload