using ArduinoBluetoothAPI; using System; using UnityEngine; public class o06DOF { /////////////////////g degree/ms //void Update(Vector3 Acc, Vector3 Gyr, Vector3 Mag, long TimeGap) //{ // if (TimeGap <= 0) // return; //} public class SixAxisFusion { Vector3 acceleratorOffset; Vector3 gyroscopeOffset; float gForce; float gyroscopeToDegree; //float acceleratorRateAsOffset; float overallGVectorCredibility = 0; Vector3 previousAccelerator; public Vector3 acceleratorGlobal; public Quaternion quaternion = new Quaternion(0, 0, 0, 1); public Vector3 accelerationNG//with No G force { get { var newQuat = new Quaternion(quaternion.x, quaternion.y, quaternion.z, -quaternion.w); return previousAccelerator - newQuat * new Vector3(0, -gForce, 0); } } public Vector3 speed = Vector3.zero; public Vector3 locus = Vector3.zero; public Vector3 rotation = Vector3.zero; public SixAxisFusion(Vector3 acceleratorOffset, Vector3 gyroscopeOffset, float gForce, float gyroscopeToDegree) { this.acceleratorOffset = acceleratorOffset;// 反向校正 this.gyroscopeOffset = gyroscopeOffset;// 反向校正 this.gForce = gForce; this.gyroscopeToDegree = gyroscopeToDegree; //this.acceleratorRateAsOffset = acceleratorRateAsOffset; previousAccelerator = new Vector3(0, -gForce, 0); acceleratorGlobal = new Vector3(0, -gForce, 0); } Quaternion update(Vector3 accelerator, Vector3 gyroscope) { accelerator += acceleratorOffset; gyroscope += gyroscopeOffset; gyroscope *= gyroscopeToDegree; var newQua = new Quaternion(); newQua.eulerAngles = gyroscope; // 根据陀螺仪计算新的四元数旋转 //var newQua = Quaternion.Euler(gyroscope); // 使用 Euler 角度来生成四元数 quaternion = quaternion * newQua;//一定要这样乘 float gForceCredibility = 1 / (1 + Mathf.Pow((Mathf.Abs(Mathf.Sqrt(accelerator.sqrMagnitude) - gForce) / gForce * 16), 1.0f)); float gDegreeCredibility = 1 / (1 + Mathf.Pow(Vector3.Angle(accelerator, newQua * previousAccelerator), 1.0f)); overallGVectorCredibility = overallGVectorCredibility * 0.3f + gForceCredibility * gDegreeCredibility * 0.7f; //Debug.Log(Mathf.Pow(overallGVectorCredibility, 0.1f)); float rotationUnCredibility = Mathf.Pow(1 - 1 / (1 + gyroscope.magnitude), 5); //Debug.Log(rotationUnCredibility); acceleratorGlobal = quaternion * accelerator; Vector3 downVector = new Vector3(0, -1, 0); float angle = Vector3.Angle(acceleratorGlobal, downVector); //Vector3 gVector = Vector3.RotateTowards(acceleratorGlobal, downVector, angle / 180 * Mathf.PI * Mathf.Pow(overallGVectorCredibility, 1f) * rotationUnCredibility, 1);//偏移量,从陀螺仪数据往加速计数据的偏移量 Vector3 gVector = Vector3.RotateTowards(acceleratorGlobal, downVector, angle / 180 * Mathf.PI * Mathf.Pow(overallGVectorCredibility, 1f) * 0.1f, 1);//偏移量,从陀螺仪数据往加速计数据的偏移量 //Vector3 gVector = Vector3.RotateTowards(acceleratorGlobal, downVector, angle / 180 * Mathf.PI * 1, 1);//偏移量,从陀螺仪数据往加速计数据的偏移量 newQua = new Quaternion(); newQua.SetFromToRotation(quaternion * accelerator, gVector); // 使用 SetFromToRotation 进行四元数校正 // newQua = Quaternion.FromToRotation(quaternion * accelerator, gVector); quaternion = newQua * quaternion;//一定要反过来乘 previousAccelerator = accelerator; rotation = gyroscope; speed = speed * 0.95f + accelerationNG; locus = locus * 0.95f + speed; return quaternion; } public void ResetToInitialRotation() { quaternion = Quaternion.identity; speed = Vector3.zero; locus = Vector3.zero; rotation = Vector3.zero; previousAccelerator = new Vector3(0, -gForce, 0); acceleratorGlobal = new Vector3(0, -gForce, 0); Debug.Log("重置到初始状态"); } /// /// 转换成四元数 /// /// /// /// public Quaternion tranUpdateData(SixData sixData) { return update(sixData.Acc, sixData.Gryo); } protected double LastMS; /// /// 解析处理一个6轴数据 /// /// /// public SixData getSixAxisByBytes(byte[] bytes) { // 获取时间信息 int min = bytes[16]; int sec = bytes[17]; float millis = SNum(bytes[1], bytes[2]); var CurrentMS = (((double)min) * 60 + sec) * 1000 + millis; if (LastMS == default) { LastMS = CurrentMS; } // 计算时间差,以秒为单位 var GapMS = CurrentMS - LastMS; LastMS = CurrentMS; double deltaTime = GapMS / 1000.0; // 转换为秒 string handle = bytes[3].ToString(); float ax = (SNum(bytes[4], bytes[5]) / 32768 * 16); float ay = (SNum(bytes[6], bytes[7]) / 32768 * 16); float az = (SNum(bytes[8], bytes[9]) / 32768 * 16); float gx = (SNum(bytes[10], bytes[11]) / 32768 * 2000); // 度/秒 float gy = (SNum(bytes[12], bytes[13]) / 32768 * 2000); // 度/秒 float gz = (SNum(bytes[14], bytes[15]) / 32768 * 2000); // 度/秒 string[] parseDataAcc = { ax.ToString("#0.000"), ay.ToString("#0.000"), az.ToString("#0.000") }; string[] parseDataGro = { gx.ToString("#0.000"), gy.ToString("#0.000"), gz.ToString("#0.000") }; string[] parseDataTime = { min.ToString(), sec.ToString(), millis.ToString() }; // 计算每帧旋转的角度(角速度 * 时间) float rotationX = gx * (float)deltaTime; // X轴转动的度数 float rotationY = gy * (float)deltaTime; // Y轴转动的度数 float rotationZ = gz * (float)deltaTime; // Z轴转动的度数 //Quaternion quaternion = update(new Vector3(ax, ay, az), new Vector3(rotationX, rotationY, rotationZ)); //+ ":Quat:" + quaternion // Debug.Log("数据:Acc[" + string.Join(", ", parseDataAcc) + "] Gryo:" + string.Join(", ", parseDataGro) + "]. Time:" + string.Join(", ", parseDataTime) + ",Euler:" + quaternion.eulerAngles); return new SixData(new Vector3(ax, ay, az), new Vector3(rotationX, rotationY, rotationZ), min, sec, millis); } float SNum(byte b1, byte b2) { ushort twoByte = (ushort)(b1 * 256 + b2); short shortNum = (short)twoByte; return (float)shortNum; } } /// /// 解析转换的6轴格式 /// public class SixData { public Vector3 Acc; public Vector3 Gryo; public int Min; public int Sec; public float Millis; public SixData(Vector3 acc, Vector3 gyro, int min, int sec, float millis) { Acc = acc; Gryo = gyro; Min = min; Sec = sec; Millis = millis; } } }