利用Myo臂環採集肌電信號(EMG)和角速度(來自陀螺儀)來實現實時手勢識別

一、系統概述與工作原理

Myo臂環是一款可穿戴設備,它包含:

  1. 8個EMG傳感器:測量前臂肌肉產生的電信號。不同的手勢會激活不同的肌肉羣,產生獨特的肌電模式。
  2. 9軸IMU:包含陀螺儀(角速度)、加速度計和磁力計,用於捕捉手部的運動和朝向。

核心思想:將EMG和角速度等多模態數據融合,通過機器學習算法訓練一個分類模型,從而實時識別出執行的手勢。


二、技術流程詳解

1. 數據採集與預處理
  • 連接Myo:使用Myo的SDK(MATLAB支持通過Myo SDK的MEX包裝器)建立連接。
  • 數據流:同時訂閲EMG和IMU(陀螺儀)數據流。
  • 預處理
  • EMG:通常應用一個帶通濾波器(如20-450 Hz)來去除直流偏移和高頻噪聲。
  • 陀螺儀:數據通常已經比較平滑,有時需要進行校準以去除零偏。
2. 數據分割(用於訓練)

實時識別需要處理連續的數據流。通常採用滑動窗口方法:

  • 窗口長度:200-300 ms(平衡實時性和信息量)。
  • 窗口重疊:50%的重疊率很常見,這能提高響應速度,確保不會在窗口邊緣錯過手勢。
3. 特徵提取

這是最關鍵的一步。從每個數據窗口中提取特徵,以降低維度並捕獲模式。

對於EMG信號(每個通道提取特徵,共8通道):

  • 時域特徵(計算速度快,適合實時系統):
  • 平均值:信號的平均能量。
  • 標準差:信號的幅度變化。
  • 積分肌電值:信號的絕對值的和或積分。
  • 過零率:信號穿過零點的次數。
  • 威爾遜振幅:信號一階差分絕對值的平均值。
  • 頻域特徵(計算量稍大):
  • 中值頻率平均頻率(需對信號進行FFT)。

對於陀螺儀信號(每個軸X, Y, Z提取特徵):

  • 均值:平均角速度。
  • 標準差:角速度的變化量。
  • 峯值:窗口內的最大角速度。
  • 信號幅度面積:角速度絕對值的積分。

最終,對於一個數據窗口,你會得到一個長長的特徵向量(例如,8個EMG通道 * 4個特徵 + 3個陀螺儀軸 * 3個特徵 = 41個特徵)。

4. 模型訓練(離線階段)
  1. 數據收集:錄製每個手勢(例如,握拳、張開、手腕左旋、手腕右旋、休息)的多組數據。
  2. 標註:為錄製的每一段數據打上標籤(如 1=握拳, 2=張開…)。
  3. 特徵提取:對每個窗口的數據進行上述特徵提取,形成特徵矩陣和標籤向量。
  4. 訓練分類器:使用特徵矩陣和標籤來訓練一個機器學習模型。常用且高效的算法有:
  • 支持向量機:在小數據集上表現優異,非常受歡迎。
  • 隨機森林:抗過擬合能力強,性能穩定。
  • LDA:計算量小,速度快,適合實時系統。
5. 實時識別(在線階段)
  1. 實時獲取數據並放入滑動窗口。
  2. 對窗口內的最新數據提取相同的特徵
  3. 將特徵向量輸入到已訓練好的模型中。
  4. 模型輸出一個預測的手勢標籤。
  5. 根據識別出的手勢執行相應操作(如控制機器人、虛擬鼠標等)。

三、MATLAB 實現代碼

步驟 1: 離線訓練模型
% 假設你已經錄製並加載了數據
% load('training_data.mat'); 
% trainingData: N x Features 矩陣
% trainingLabels: N x 1 標籤向量
% 使用隨機森林訓練分類模型
rng(1); % 控制可重複性
model = TreeBagger(100, trainingData, trainingLabels, ...
'Method', 'classification', ...
'OOBPrediction', 'on', ...
'MinLeafSize', 5);
% 或者使用SVM
% model = fitcecoc(trainingData, trainingLabels);
% 評估模型(使用留出法或交叉驗證)
[predictions, scores] = model.predict(trainingData);
accuracy = sum(predictions == trainingLabels) / numel(trainingLabels);
fprintf('Training Accuracy: %.2f%%\n', accuracy * 100);
% 保存模型
save('my_gesture_model.mat', 'model');
步驟 2: 實時識別循環
function realTimeRecognition()
% 加載預訓練模型
load('my_gesture_model.mat', 'model');
% 初始化Myo連接
mm = MyoMex();
myo = mm.myoData;
% 參數設置
windowLength = 200; % 200ms 窗口
sampleRate = 200; % Myo EMG採樣率約為200Hz
windowSize = round(windowLength / 1000 * sampleRate); % 計算窗口點數
overlap = round(windowSize * 0.5); % 50% 重疊
bufferEMG = zeros(windowSize, 8); % 環形緩衝區存儲EMG
bufferGyro = zeros(windowSize, 3); % 環形緩衝區存儲Gyro
index = 1;
h = figure;
stop = false;
disp('Starting real-time recognition. Press any key to stop.');
% 主循環
while ishghandle(h) && ~stop
% 獲取最新數據
latestEMG = myo.emg_log;
latestGyro = myo.rotational_velocity_log;
if ~isempty(latestEMG)
% 將新數據填入緩衝區(模擬實時流)
for i = 1:size(latestEMG, 1)
bufferEMG(index, :) = latestEMG(i, :);
bufferGyro(index, :) = latestGyro(i, :);
index = mod(index, windowSize) + 1; % 環形索引
% 每當緩衝區填滿一個“步長”後就進行一次預測
if index == overlap
% 1. 獲取當前窗口數據(需要處理環形緩衝區的索引)
windowEMG = [bufferEMG(index:end, :); bufferEMG(1:index-1, :)];
windowGyro = [bufferGyro(index:end, :); bufferGyro(1:index-1, :)];
% 2. 特徵提取 (這裏簡化了,實際需要為每個通道計算)
features = [];
for ch = 1:8 % EMG特徵
sig = windowEMG(:, ch);
features = [features, mean(sig), std(sig), mean(abs(sig))];
end
for ax = 1:3 % Gyro特徵
sig = windowGyro(:, ax);
features = [features, mean(sig), std(sig)];
end
% 3. 進行預測
[gestureLabel, scores] = predict(model, features);
gestureStr = string(gestureLabel);
confidence = max(scores);
% 4. 顯示結果
clf;
text(0.5, 0.7, gestureStr, 'FontSize', 30, 'HorizontalAlignment', 'center');
text(0.5, 0.3, sprintf('Conf: %.2f', confidence), 'FontSize', 20, 'HorizontalAlignment', 'center');
drawnow;
% 5. 這裏可以添加控制邏輯: 
% if gestureStr == "fist", ... end
end
end
end
pause(0.01); % 短暫暫停,避免佔用100% CPU
stop = ~isempty(get(h,'CurrentCharacter'));
end
delete(mm); % 斷開Myo連接
close(h);
end

參考代碼 利用myo採集肌電信號和角速度信息,實現實時的手勢識別 www.youwenfan.com/contentcsj/53663.html

四、挑戰與改進建議

  1. 個性化與校準:不同用户的肌肉信號差異很大。最好為每個用户單獨收集數據並訓練模型,或使用遷移學習來適配新用户。
  2. 手勢設計:選擇在EMG和運動模式上差異明顯的手勢,以提高識別率。例如,“握拳” vs. “張開” vs. “手腕左旋”是很好的選擇。
  3. 疲勞和位移:長時間使用後,肌肉疲勞或臂環稍微轉動都會導致信號漂移。可以考慮加入在線自適應機制,定期更新模型。
  4. 數據同步:確保EMG和陀螺儀數據的時間戳對齊。
  5. 延遲優化:在MATLAB中實現真正的低延遲實時處理具有挑戰性。對於性能要求極高的應用,可以考慮用C++實現核心算法。