# 呼吸綁帶 (或是任何要接藍芽的碗糕) 修正 ###### tags: `lab` :::success 兼容原本 (PC) 版本,請安心服用 ::: :::info 對於實驗室在開發新專案的同學:請使用 [LabFrame2023](https://hackmd.io/@jcxyisncu1102/labframe2023) ::: ## 操作說明 - 先在 pico 裡面設定把設備跟 pico 配對 (藍芽) - 如果有 PIN,請看 [底下](#Pico-VR-不支援配對有-PIN-碼的裝置) - (設備名稱要叫做 `HC-05` 或 `HC-06`,不然要改下面的 `SensorController.cs` (見第 56 行)) - 然後就可以開始改了 ## 匯入外掛包 - [下載這個 jar 檔](https://drive.google.com/file/d/1P-x8JDkoeCKMrd_1cu59VzHtF6frzvtR/view?usp=sharing) - 放在 `Plugins/Android/libs` 底下 ## 更改 AndroidManifest.xml 檢查有沒有以下三行 (善用 `ctrl+F`) ```xml <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" /> ``` ## 新增 BluetoothService.cs - **新寫的腳本** - 負責與外掛包呼叫 ```csharp= // from https://github.com/bentalebahmed/BlueUnity // Modded by JCxYIS 20220331 using System; using UnityEngine; public class BluetoothService { private static bool isInited = false; private static AndroidJavaClass unityPlayer; private static AndroidJavaObject activity; private static AndroidJavaObject context; private static AndroidJavaClass unity3dbluetoothplugin; private static AndroidJavaObject BluetoothConnector; // creating an instance of the bluetooth class from the plugin public static void CreateBluetoothObject() { if (Application.platform == RuntimePlatform.Android && !isInited) { unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); context = activity.Call<AndroidJavaObject>("getApplicationContext"); unity3dbluetoothplugin = new AndroidJavaClass("com.example.unity3dbluetoothplugin.BluetoothConnector"); BluetoothConnector = unity3dbluetoothplugin.CallStatic<AndroidJavaObject>("getInstance"); isInited = true; } } // starting bluetooth connection with device named "DeviceName" // print the status on the screen using native android Toast public static bool StartBluetoothConnection(string DeviceName) { if (Application.platform == RuntimePlatform.Android) { string connectionStatus = "non"; try { connectionStatus = BluetoothConnector.Call<string>("StartBluetoothConnection", DeviceName); Toast(connectionStatus); if (connectionStatus == "Connected") return true; else return false; } catch (Exception e) { Toast(connectionStatus); return false; } } else return false; } // should be called inside OnApplicationQuit // stop connection with the bluetooth device public static void StopBluetoothConnection() { if (Application.platform == RuntimePlatform.Android) { try { BluetoothConnector.Call("StopBluetoothConnection"); Toast("connction stoped"); } catch (Exception e) { Toast("stop connction error"); } } } // write data as a string to the bluetooth device public static void WritetoBluetooth(string data) { if (Application.platform == RuntimePlatform.Android) { try { BluetoothConnector.Call("WriteData", data); } catch (Exception e) { Toast("write data error"); } } } //read data from the bluetooth device // if there is an error or there is no data coming, this method will return "" as an output public static string ReadFromBluetooth() { string data = ""; if (Application.platform == RuntimePlatform.Android) { try { data = BluetoothConnector.Call<string>("ReadData"); return data; } catch (Exception e) { // Toast("read data error"); return ""; } } else return ""; } public static void Toast(object log) { BluetoothConnector.Call("PrintOnScreen", context, log.ToString()); } } ``` ## 改實驗室框架/模組 ### SensorController.cs - 我覺得我拿到的這個 script 已經有被改過了 - 請自己複製關鍵的 code 去用ㄅ ```csharp= /// Mooded by JCxYIS /// 20220331 using UnityEngine; using System.Collections; using System.Collections.Generic; using System; using System.Threading; using UnityEngine.SceneManagement; using LabData; using System.Globalization; #if UNITY_STANDALONE_WIN using System.IO.Ports; #endif // 掛在場景中的GameObject(我取名叫BreathSensor)身上 public class SensorController : MonoBehaviour, IDisposable { #if UNITY_STANDALONE_WIN private SerialPort stream = null; #endif private string val = null; private string sArray = ""; private string sArr = ""; private Thread myThread; private float currentPressure; private float breathVal = 0.0f; private float breathTotal = 0.0f; private int numOfVal = 0; // Use this for initialization public IEnumerator ConnectionInit (string ComNum) { //if (LabTools.GetConfig<ApplicationConfig>().BlueTooth) //{ //} Debug.Log("連接初始化"); bool isConnected = false; while(!isConnected) //重複開啟serial port接口直到連線成功為止 { try { Debug.Log("連接中... com="+ComNum); #if UNITY_STANDALONE_WIN stream = new SerialPort("COM" + ComNum, 9600);//呼吸 9600 舌壓 12800 stream.Open(); //開啟serial port接口,才能收資料 isConnected = true; #elif UNITY_ANDROID && !UNITY_EDITOR BluetoothService.CreateBluetoothObject(); if( BluetoothService.StartBluetoothConnection("HC-05") || BluetoothService.StartBluetoothConnection("HC-06")) { isConnected = true; } #else Debug.LogError("I can't breathe"); yield break; #endif } catch (Exception e) { Debug.Log("Reconnect... Reason="+e); } yield return 0; } Debug.Log("已連接! Sensor Connected"); myThread = new Thread(new ThreadStart(GetArduino)); //物件宣告及呼叫GetArduino myThread.Start(); //這邊用thread } void Update(){ //float.TryParse (val, out m); if(val != null) { sArray = val; //舌壓 //Debug.Log(sArray); if (sArray != "Pressure:") { sArr = sArray; Debug.LogError("呼吸綁帶數值: " + sArr); if(TestGameFrame.Test_EnemyTask._isCalBreathStart) { if(float.TryParse(sArr, out float f)) { // boundry check if(f < 900 || f > 1100) break; // 取得呼吸綁帶數值 給breathVal, 儲存在breathArr裡 breathVal = f; breathTotal += breathVal; numOfVal++; } else { Debug.LogWarning("[Sensor] 無法解析呼吸綁帶數值="+sArr); } } } } // Get Arduino ANDROID ver :P #if UNITY_ANDROID && !UNITY_EDITOR try { string inVal = BluetoothService.ReadFromBluetooth(); if(inVal.Length > 0) { val = inVal; // Debug.Log("[Sensor_Android] "+val); } } catch(Exception e) { Debug.LogWarning("[Sensor_Android] "+e); } #endif } public string getBreathStr() { return sArr; } public float getBreathVal() { return breathVal; } public double getBaseline() { double baseline = 0.0f; baseline = breathTotal / numOfVal; return baseline; } public double getThreshold() { double baseline = 0.0f; double threshold = 0.0f; // 算這些值的平均 baseline = breathTotal / numOfVal; // 平均加一個數值等於門檻值 threshold = baseline + 5; return threshold; } private void GetArduino() { #if UNITY_STANDALONE //Debug.Log(stream.IsOpen); while(myThread.IsAlive && stream.IsOpen) { //Debug.Log("進入完成"); val = stream.ReadLine(); //Debug.Log(val); } #elif UNITY_ANDROID // fetch data in Update() #endif } //關閉thread&serial port,否則會死當 void OnDisable() { Dispose(); } void OnApplicationQuit() { Dispose(); } public void Dispose() { #if UNITY_STANDALONE if (stream != null) { stream.Close(); myThread.Abort(); } #elif UNITY_ANDROID BluetoothService.StopBluetoothConnection(); #endif } } ``` ### 呼吸綁帶 Init 的地方 (我的在 Test_EnemyTask.cs) ```csharp=222 #region 呼吸綁帶 if(string.IsNullOrEmpty(GameDataManager.FlowData.BreathCOM)) { Debug.LogWarning("略過呼吸綁帶綁定"); } else { sensorObject = GameObject.Find("BreathSensor"); print("呼吸綁帶 GO => "+sensorObject); // #if UNITY_STANDALONE yield return sensorObject.GetComponent<SensorController>().ConnectionInit(GameDataManager.FlowData.BreathCOM); // #endif } #endregion ``` ## Troubleshoot ### Pico VR 不支援配對有 PIN 碼的裝置 先使用這個 app 來連接吧 https://github.com/JCxYIS/PicoXR-BluetoothConnector/releases  - 安裝 app - 進入 app,按 Scan Devices - 找到想連接的裝置 *(e.g. 呼吸綁帶是 HC-05 or HC-06)* - **先**輸入右下角的 PIN 碼 *(e.g. 呼吸綁帶是 1234)* - 再按裝置旁邊的 Connect - You're done! 裝置只需綁定一次,之後可直接連線不需要再綁。 如果設備不支援配對也可以嘗試使用這專案的程式碼來連。 ### 呼吸綁帶功能無法使用時的防錯方案 在取用呼吸數值 (我的放在 Test_EnemyTask 的`IEnumerator BreathCtrlBalloon(GameObject balloon)` ) 函式中如果不傳入 sensorObject 會炸掉,所以要加 ```csharp=1850 ... while (!_isBreathFinish && !_isRebreathButtonClick) { if(!sensorObject) { Debug.LogWarning("不使用呼吸綁帶無法計算呼吸"); yield return 0; continue; } ... ``` ###### References https://github.com/bentalebahmed/BlueUnity
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up