com.xrlab.labframe_brainbit
v1.1.2
Published
BrainBit Support for LabFrame2023. Note: Currently only supports BrainBit in lab!!
Readme
LabFrame BrainBit Package
LabFrame BrainBit Package 是給 LabFrame 2023 專案使用的 BrainBit 腦波儀套件。它負責搜尋與連接 BrainBit、讀取 EEG 腦波與阻抗資料,並可把資料自動寫入 LabFrame 的資料系統。套件也整合 NeuroSDK 的情緒與頻譜分析,讓實驗或互動專案可以直接取得專注、放鬆與五頻段腦波比例。
這份文件面向使用者與實驗操作人員,重點是怎麼安裝、怎麼戴、怎麼開始錄資料,以及錄出來的資料代表什麼。
支援功能
- 搜尋並連接 BrainBit 藍牙低功耗裝置。
- 讀取 4 通道 EEG:
T3、T4、O1、O2。 - 檢查 4 通道阻抗,協助確認電極與頭皮接觸狀態。
- 依實驗階段用不同 tag 自動寫入 LabFrame 資料。
- 即時取得專注、放鬆與
Delta、Theta、Alpha、Beta、Gamma五頻段百分比。 - 提供阻抗檢查 UI 控制器與範例場景。
設備說明
本套件主要支援實驗室使用的 BrainBit Headband。BrainBit 是 4 通道乾式 EEG 頭帶,透過 Bluetooth LE 連線。官方文件標示 BrainBit 有 O1、O2、T3、T4 四個資料通道,每個通道取樣頻率為 250 Hz。
| 通道 | 位置 | 常見用途 |
|---|---|---|
| T3 | 左側顳葉區 | 常用於注意、專注相關節律觀察 |
| T4 | 右側顳葉區 | 常用於注意、專注相關節律觀察 |
| O1 | 左側枕葉區 | 常用於 alpha、放鬆相關節律觀察 |
| O2 | 右側枕葉區 | 常用於 alpha、放鬆相關節律觀察 |
配戴時,前額的參考/共用電極要貼在額頭,T3、T4 靠近左右顳側,O1、O2 靠近後腦枕側。頭帶要貼合但不需要勒緊;如果阻抗過高,通常代表接觸不穩、頭髮擋住電極、頭帶位置偏移,或裝置電極沒有確實貼到皮膚。
本套件不是醫療診斷工具。EEG、專注、放鬆與頻譜資料適合用於研究、教育、互動體驗與實驗紀錄,不應直接解讀為醫療結論。
安裝
1. Unity 與 LabFrame
- 建議 Unity 版本:
2022.3.62f2,或同系列2022.3LTS。 - 需要 LabFrame package:
com.xrlab.labframe。 - 本 package 的
package.json已依賴 BrainBitNeuroSDK2。
2. 安裝情緒/頻譜分析套件
此 package 的情緒與頻譜功能會使用 SignalMath,請在 Unity Package Manager 加入下列 Git URL:
https://github.com/BrainbitLLC/unity_em_st_artifacts.git#a04238a934b3da0494dd9120a489005277063a1f目前建議使用上面的固定 commit。開發時曾遇過較新的 Android 版本套件相容性問題,因此不要任意升級到最新版,除非你已經重新測試 Android build。
3. 平台權限
Android 權限已放在:
Packages/LabFrame_Brainbit/Runtime/Plugins/Android/AndroidManifest.xml它包含定位、Bluetooth scan、Bluetooth connect 等權限。實機第一次啟動時仍可能需要使用者允許權限。
iOS build 後處理會自動加入藍牙用途文字:
NSBluetoothAlwaysUsageDescription
NSBluetoothPeripheralUsageDescription建議使用流程
- 開啟 BrainBit,確認電量足夠。
- 在手機、平板或電腦開啟藍牙,並允許 App 使用藍牙與定位權限。
- 戴上 BrainBit,調整前額與左右/後方電極位置。
- 呼叫
ManualConnect()或使用範例 UI 連線。 - 先開啟阻抗檢查,確認 4 個通道接觸穩定。
- 停止阻抗檢查。
- 開始 EEG 錄製,並用 tag 標示實驗階段。
- 若需要專注、放鬆或頻譜資料,啟動情緒處理並等待校正完成。
- 實驗階段切換時,用
SetEEGTag()、SetMindTag()、SetSpectralTag()切換資料 tag。 - 結束時停止情緒處理、EEG 與阻抗串流,必要時斷線。
快速開始
連接設備
預設不會在遊戲啟動時自動連線。請在開始畫面、準備階段或使用者按下按鈕時呼叫:
BrainBitManager.Instance.ManualConnect();斷線:
BrainBitManager.Instance.ManualDisconnect();常用狀態:
bool connected = BrainBitManager.Instance.IsConnected;
bool scanning = BrainBitManager.Instance.IsScanning;
string deviceName = BrainBitManager.Instance.ConnectedDeviceName;
string deviceAddress = BrainBitManager.Instance.ConnectedDeviceAddress;阻抗檢查
阻抗資料用來確認電極接觸品質。建議在正式錄 EEG 前先檢查阻抗,確認通道穩定後再開始實驗。
BrainBitManager.Instance.StartImpedanceStream(
autoWriteToLabData: false,
tag: "precheck_impedance");讀取目前阻抗:
var impedance = BrainBitManager.Instance.GetLatestImpedanceData();
if (impedance != null)
{
Debug.Log(impedance.ToString());
if (impedance.IsImpedanceGood)
{
Debug.Log("All channels are ready.");
}
else
{
Debug.LogWarning(impedance.GetImpedanceStatus());
}
}停止阻抗檢查:
BrainBitManager.Instance.StopImpedanceStream();本套件目前用 200000 ohm 作為預設警示門檻。若任何通道高於此值,IsImpedanceGood 會是 false。
EEG 錄製
開始 EEG:
BrainBitManager.Instance.StartEEGStream(
autoWriteToLabData: true,
tag: "baseline_eeg");取得最新 EEG:
var eeg = BrainBitManager.Instance.GetLatestEEGData();
if (eeg != null)
{
Debug.Log($"T3:{eeg.T3} T4:{eeg.T4} O1:{eeg.O1} O2:{eeg.O2}");
}切換實驗階段時,不需要停止 EEG,可以直接改 tag:
BrainBitManager.Instance.SetEEGTag("task1_eeg");停止 EEG:
BrainBitManager.Instance.StopEEGStream();專注、放鬆與五頻段資料
情緒處理會使用 EEG 訊號計算 MindData 與 SpectralData。啟動後需要先校正,預設校正時間為 6 秒。校正完成前 GetLatestMindData() 與 GetLatestSpectralData() 可能回傳 null。
啟動:
BrainBitManager.Instance.StartEmotionsProcessing(
autoWriteToLabData: true,
mindTag: "baseline_mind",
spectralTag: "baseline_spectral");監聽校正:
BrainBitManager.Instance.OnCalibrationProgress += progress =>
{
Debug.Log($"Calibration: {progress}%");
};
BrainBitManager.Instance.OnCalibrationFinished += () =>
{
Debug.Log("Calibration finished.");
};讀取專注與放鬆:
if (BrainBitManager.Instance.IsEmotionsCalibrated)
{
var mind = BrainBitManager.Instance.GetLatestMindData();
if (mind != null)
{
Debug.Log($"Attention:{mind.Attention:F1} Relaxation:{mind.Relaxation:F1}");
}
}讀取五頻段百分比:
var spectral = BrainBitManager.Instance.GetLatestSpectralData();
if (spectral != null)
{
Debug.Log(
$"Delta:{spectral.Delta:F1} " +
$"Theta:{spectral.Theta:F1} " +
$"Alpha:{spectral.Alpha:F1} " +
$"Beta:{spectral.Beta:F1} " +
$"Gamma:{spectral.Gamma:F1}");
}切換 tag:
BrainBitManager.Instance.SetMindTag("task1_mind");
BrainBitManager.Instance.SetSpectralTag("task1_spectral");停止:
BrainBitManager.Instance.StopEmotionsProcessing();若中途換受測者、頭帶取下後重新戴上,或資料明顯不穩,可以重新校正:
BrainBitManager.Instance.RestartCalibration();完整範例程式
以下範例示範一個常見實驗流程:連線、檢查阻抗、開始錄 EEG 與情緒資料、切換階段、結束錄製。
using UnityEngine;
public class BrainBitSessionExample : MonoBehaviour
{
private void OnEnable()
{
BrainBitManager.Instance.OnConnectionStatusChanged += HandleConnectionChanged;
BrainBitManager.Instance.OnCalibrationProgress += HandleCalibrationProgress;
BrainBitManager.Instance.OnCalibrationFinished += HandleCalibrationFinished;
BrainBitManager.Instance.OnError += HandleError;
}
private void OnDisable()
{
if (BrainBitManager.Instance == null) return;
BrainBitManager.Instance.OnConnectionStatusChanged -= HandleConnectionChanged;
BrainBitManager.Instance.OnCalibrationProgress -= HandleCalibrationProgress;
BrainBitManager.Instance.OnCalibrationFinished -= HandleCalibrationFinished;
BrainBitManager.Instance.OnError -= HandleError;
}
public void ConnectBrainBit()
{
BrainBitManager.Instance.ManualConnect();
}
private void HandleConnectionChanged(bool connected)
{
if (!connected) return;
Debug.Log($"Connected: {BrainBitManager.Instance.ConnectedDeviceName}");
BrainBitManager.Instance.StartImpedanceStream(
autoWriteToLabData: false,
tag: "precheck_impedance");
}
public void StartRecordingIfReady()
{
var impedance = BrainBitManager.Instance.GetLatestImpedanceData();
if (impedance == null || !impedance.IsImpedanceGood)
{
Debug.LogWarning("BrainBit impedance is not ready. Adjust the headband first.");
return;
}
BrainBitManager.Instance.StopImpedanceStream();
BrainBitManager.Instance.StartEEGStream(
autoWriteToLabData: true,
tag: "baseline_eeg");
BrainBitManager.Instance.StartEmotionsProcessing(
autoWriteToLabData: true,
mindTag: "baseline_mind",
spectralTag: "baseline_spectral");
}
public void SetExperimentPhase(string phaseName)
{
BrainBitManager.Instance.SetEEGTag($"{phaseName}_eeg");
BrainBitManager.Instance.SetMindTag($"{phaseName}_mind");
BrainBitManager.Instance.SetSpectralTag($"{phaseName}_spectral");
}
private void Update()
{
if (!BrainBitManager.Instance.IsEmotionsCalibrated) return;
var mind = BrainBitManager.Instance.GetLatestMindData();
var spectral = BrainBitManager.Instance.GetLatestSpectralData();
if (mind != null)
{
Debug.Log($"Attention:{mind.Attention:F1} Relaxation:{mind.Relaxation:F1}");
}
if (spectral != null)
{
Debug.Log($"Alpha:{spectral.Alpha:F1} Beta:{spectral.Beta:F1}");
}
}
public void StopRecording()
{
BrainBitManager.Instance.StopEmotionsProcessing();
BrainBitManager.Instance.StopEEGStream();
BrainBitManager.Instance.StopImpedanceStream();
}
private void HandleCalibrationProgress(int progress)
{
Debug.Log($"Calibration progress: {progress}%");
}
private void HandleCalibrationFinished()
{
Debug.Log("BrainBit emotion calibration finished.");
}
private void HandleError(string message)
{
Debug.LogError($"BrainBit error: {message}");
}
}範例場景
本 repo 內有一個範例場景:
Packages/LabFrame_Brainbit/Sample/SampleScene.unity範例場景使用 BrainBitCheckController 顯示連線狀態、阻抗數值與阻抗警示。它適合拿來做實驗前的配戴檢查畫面,也可以直接參考按鈕如何呼叫 BrainBitManager。
資料格式
當 autoWriteToLabData 設為 true 且 LabDataManager 已初始化時,套件會把資料物件寫入 LabFrame。實際檔案位置與檔案格式由 LabFrame 專案設定決定;下面列的是本套件交給 LabFrame 的資料欄位。
EEG:BrainBit_EEGData
| 欄位 | 型別 | 單位 | 說明 |
|---|---|---|---|
| T3 | double | V | 左側顳葉通道 EEG |
| T4 | double | V | 右側顳葉通道 EEG |
| O1 | double | V | 左側枕葉通道 EEG |
| O2 | double | V | 右側枕葉通道 EEG |
| EEGValues | List<double> | V | 順序為 T3、T4、O1、O2 |
BrainBit 官方資料流每通道為 250 samples/sec。本套件保留最新一筆 EEG,可用 GetLatestEEGData() 取得。
阻抗:BrainBit_ImpedanceData
| 欄位 | 型別 | 單位 | 說明 |
|---|---|---|---|
| T3 | double | ohm | 左側顳葉通道阻抗 |
| T4 | double | ohm | 右側顳葉通道阻抗 |
| O1 | double | ohm | 左側枕葉通道阻抗 |
| O2 | double | ohm | 右側枕葉通道阻抗 |
| ImpedanceValues | List<double> | ohm | 順序為 T3、T4、O1、O2 |
| IsImpedanceGood | bool | 無 | 4 通道都低於 200000 ohm 時為 true |
輔助方法:
string status = impedance.GetImpedanceStatus();
var values = impedance.GetImpedanceValues();專注與放鬆:BrainBit_MindData
| 欄位 | 型別 | 範圍 | 說明 |
|---|---|---|---|
| Attention | double | 約 0-100 | 相對專注度,較平滑,建議顯示給使用者 |
| Relaxation | double | 約 0-100 | 相對放鬆度,較平滑,建議顯示給使用者 |
| InstAttention | double | 約 0-100 | 瞬時專注度,波動較大 |
| InstRelaxation | double | 約 0-100 | 瞬時放鬆度,波動較大 |
MindData 必須等 IsEmotionsCalibrated == true 後才有穩定意義。
五頻段百分比:BrainBit_SpectralData
| 欄位 | 型別 | 單位 | 說明 |
|---|---|---|---|
| Delta | double | percent | Delta 波百分比 |
| Theta | double | percent | Theta 波百分比 |
| Alpha | double | percent | Alpha 波百分比 |
| Beta | double | percent | Beta 波百分比 |
| Gamma | double | percent | Gamma 波百分比 |
連線事件:BrainBit_ConnectionData
| 欄位 | 型別 | 說明 |
|---|---|---|
| IsConnected | bool | 連線狀態 |
| DeviceName | string | BrainBit 裝置名稱 |
| DeviceAddress | string | BrainBit 裝置位址 |
| EventType | string | Connected、Disconnected、EEG_Stream_Started 等事件 |
Tag 與資料分段
tag 是寫入 LabFrame 時用來區分資料階段的名稱。建議使用清楚且穩定的命名,例如:
baseline_eeg
baseline_mind
baseline_spectral
task1_eeg
task1_mind
task1_spectral
rest_impedanceEEG、MindData、SpectralData 都可以在不中斷串流的情況下切換 tag:
BrainBitManager.Instance.SetEEGTag("task2_eeg");
BrainBitManager.Instance.SetMindTag("task2_mind");
BrainBitManager.Instance.SetSpectralTag("task2_spectral");下一筆寫入的資料會使用新的 tag。
事件 API
若你不想在 Update() 裡輪詢,可以訂閱事件:
BrainBitManager.Instance.OnEEGDataReceived += data =>
{
Debug.Log(data.ToString());
};
BrainBitManager.Instance.OnImpedanceDataReceived += data =>
{
Debug.Log(data.GetImpedanceStatus());
};
BrainBitManager.Instance.OnMindDataReceived += data =>
{
Debug.Log($"Attention:{data.Attention:F1}");
};
BrainBitManager.Instance.OnSpectralDataReceived += data =>
{
Debug.Log($"Alpha:{data.Alpha:F1}");
};
BrainBitManager.Instance.OnEmotionsArtifact += hasArtifact =>
{
if (hasArtifact)
{
Debug.LogWarning("BrainBit signal artifact detected.");
}
};設定項目
BrainBitConfig 可控制掃描、重連與情緒校正行為。
| 欄位 | 預設 | 說明 |
|---|---:|---|
| AutoConnectOnInit | false | Manager 初始化後是否自動掃描連線 |
| DisconnectNotification | true | 斷線時是否顯示提示 |
| ScanTimeoutSeconds | 10.0 | 掃描逾時秒數 |
| ImpedanceWarningThreshold | 200000.0 | 阻抗警示參考門檻,單位 ohm |
| AutoReconnectAttempts | 3 | 斷線後自動重連嘗試次數 |
| ReconnectIntervalSeconds | 2.0 | 重連間隔秒數 |
| AutoSelectBestSignal | false | 多台 BrainBit 時是否選 RSSI 最強者 |
| TargetDeviceAddress | "" | 優先連線的 BrainBit MAC;留空時維持原本選台行為 |
| ConnectDelaySeconds | 1.0 | 停止掃描後等待多久才建立連線 |
| EmotionsCalibrationLength | 6 | 情緒處理校正秒數 |
| EmotionsMentalEstimation | false | 是否啟用 Mental Estimation |
| EmotionsPrioritySide | SideType.NONE | 情緒分析優先腦側:NONE、LEFT、RIGHT |
如果現場同時有多台 BrainBit,建議用 TargetDeviceAddress 優先指定 MAC。設定後,掃描會先尋找該 MAC;如果連續 3 次、每次間隔 2 秒的掃描結果都沒有看到目標,系統會改用原本的選台策略尋找其他 BrainBit。AutoSelectBestSignal 只建議在沒有指定 MAC、或目標 MAC 找不到後可接受用 RSSI 選台時使用。
Android 實機若要每台頭顯綁定不同 BrainBit,請在各裝置的 Application.persistentDataPath/Config/BrainBitConfig.json 放完整設定檔,例如:
{
"AutoConnectOnInit": false,
"DisconnectNotification": true,
"ScanTimeoutSeconds": 20.0,
"ImpedanceWarningThreshold": 200000.0,
"AutoReconnectAttempts": 3,
"ReconnectIntervalSeconds": 2.0,
"AutoSelectBestSignal": false,
"ConnectDelaySeconds": 1.0,
"EmotionsCalibrationLength": 6,
"EmotionsMentalEstimation": false,
"EmotionsPrioritySide": 0,
"TargetDeviceAddress": "E0:39:7A:68:75:58"
}若裝置上已有舊版 BrainBitConfig.json,請整檔覆蓋成最新欄位;磁碟上的設定會優先於內建範本。
目前 BrainBit_ImpedanceData.IsImpedanceGood 使用 200000 ohm 作為判斷門檻;若你的實驗需要不同標準,請在 UI 或檢查流程中使用自訂門檻判斷。
設備資訊查詢
需要查看電量、韌體版本、硬體版本、取樣頻率等資訊時,可使用 SensorInfoProvider:
using NeuroSDK;
using System.Collections.Generic;
void ShowDeviceInfo(BrainBitSensor sensor)
{
Dictionary<string, string> parameters =
SensorInfoProvider.GetBrainBitSensorParameters(sensor);
foreach (var item in parameters)
{
Debug.Log($"{item.Key}: {item.Value}");
}
}一般使用者不一定需要呼叫這段。它比較適合現場除錯、確認電量與確認裝置版本。
常見問題
掃不到設備
- 確認 BrainBit 已開機且有電。
- 確認 App 已允許藍牙、定位與附近裝置權限。
- 確認 BrainBit 沒有被其他 App 或其他手機連線。
- 把 BrainBit 靠近執行 App 的裝置後再掃描。
- 如果現場有多台 BrainBit,優先在
TargetDeviceAddress填入指定 MAC;若目標連續 3 次、每次間隔 2 秒的掃描都找不到,Manager 會改找其他設備。
阻抗一直太高
- 調整頭帶位置,讓
T3、T4、O1、O2更貼近頭皮。 - 撥開頭髮,避免頭髮卡在電極與頭皮之間。
- 確認前額參考電極有貼住皮膚。
- 讓受測者先保持不動,再觀察數值是否下降。
- 若只有單一通道高,優先調整該通道所在的位置。
MindData 或 SpectralData 一直是空的
- 確認已呼叫
StartEmotionsProcessing()。 - 確認 EEG 正在輸入。
- 等待
OnCalibrationFinished或IsEmotionsCalibrated == true。 - 校正期間請受測者保持安靜、少眨眼、少咬牙、少說話。
- 若中途重新配戴,呼叫
RestartCalibration()。
資料沒有寫入 LabFrame
- 確認呼叫串流時
autoWriteToLabData是true。 - 確認
LabDataManager.Instance.IsInited為true。 - 確認 tag 不為空字串。
- 確認有呼叫
StartEEGStream()或StartEmotionsProcessing()。
Android build 或執行出錯
- 確認已安裝
unity_em_st_artifacts固定 commit。 - 確認 Android 權限已在實機上允許。
- 若使用較新的 Android 版本,請特別檢查
BLUETOOTH_SCAN與BLUETOOTH_CONNECT權限。
官方參考
- BrainBit SDK - Receiving data: https://sdk.brainbit.com/sdk2_bb/
- BrainBit SDK - Device recommendation: https://sdk.brainbit.com/device-recommendation/
- BrainBit SDK - Emotions library: https://sdk.brainbit.com/lib-emotions/
- BrainBit SDK - Overview and supported platforms: https://sdk.brainbit.com/sdk2_overview/
