유니티/IOS BLE

선수 파일 로딩 & 스윙 종류 분석

ZEROWIN.TECH 2020. 12. 26. 00:17
728x90

IOS에서 선수파일 저장 위치

바이너리 파일 Read

TextAsset bindata = Resources.Load("kimsangkyung") as TextAsset;
        Stream s = new MemoryStream(bindata.bytes);
        BinaryReader br = new BinaryReader(s);
        Debug.Log("br: " + bindata.bytes.Length + "," + br.ToString());

텍스트 파일 Read

TextAsset txtData;
        txtData = Resources.Load("kimyoungseong_left") as TextAsset;
        string fs = txtData.ToString();
        string[] fLines = Regex.Split(fs, "\n");

아이폰 로그파일

선수파일(바이너리파일)

BLE 스윙 데이터 수신

1. BLE subscribe FILE:GetBluetoothData.cs

2. 스윙 데이터 분석 FILE:GetBluetoothData.cs

private void readDataFromRacket(byte[] bytes)
    {
        //if (bytes[0] == 0x00)
        //    ButtonPositionText.text = "Not Pushed";
        //else
        //    ButtonPositionText.text = "Pushed";
        StatusText.text = ConvertByteToHexString(bytes) + "," + bytes.Length.ToString();

        int aX = 0;
        int aY = 0;
        int aZ = 0;
        int gX = 0;
        int gY = 0;
        int gZ = 0;

        int p = 0;

        float [] q = new float[4];

        aX = (((bytes[1] & 0xff) << 8 | (bytes[0] & 0xff))) - 32768;
        aY = (((bytes[1 + 2] & 0xff) << 8 | (bytes[2] & 0xff))) - 32768;
        aZ = (((bytes[1 + 4] & 0xff) << 8 | (bytes[4] & 0xff))) - 32768;
        gX = (((bytes[6 + 1] & 0xff) << 8 | (bytes[6] & 0xff))) - 32768;

        gY = 0; // gY = (((txValue[6 + 1 + 2] & 0xff) << 8 | (txValue[6 + 2] & 0xff))) - 32768;
        p = (((bytes[6 + 1 + 2] & 0xff) << 8 | (bytes[6 + 2] & 0xff))) - 32768;

        gZ = (((bytes[6 + 1 + 4] & 0xff) << 8 | (bytes[6 + 4] & 0xff))) - 32768;

        q[0] = (float)(((bytes[12 + 1] & 0xff) << 8 | (bytes[12] & 0xff)));
        q[1] = (float)(((bytes[12 + 1 + 2] & 0xff) << 8 | (bytes[12 + 2] & 0xff)));
        q[2] = (float)(((bytes[12 + 1 + 4] & 0xff) << 8 | (bytes[12 + 4] & 0xff)));
        q[3] = (float)(((bytes[19] & 0xff) << 8 | (bytes[18] & 0xff)));

        if (32767 < q[0]) q[0] -= 65535;
        if (32767 < q[1]) q[1] -= 65535;
        if (32767 < q[2]) q[2] -= 65535;
        if (32767 < q[3]) q[3] -= 65535;

        q[0] /= 100;
        q[1] /= 100;
        q[2] /= 100;
        q[3] /= 100;

        GameManager.g_Analysis.addData(aX,
            aY,
            aZ,
            gX,
            gY,
            gZ,
            q[0],
            q[1],
            q[2],
            q[3],
            p); // piezo
    }

3. 스윙 패킷을 버퍼에 저장합니다. FILE:DataAnalysis.cs

public void addData(int ax, int ay, int az, int gx, int gy, int gz, float q1, float q2, float q3, float q4, int p)
    {
        ac_x = ax;
        ac_y = ay;
        ac_z = az;
        gy_x = gx;
        gy_y = gy;
        gy_z = gz;

        Quat_W = q1;
        Quat_X = q2;
        Quat_Y = q3;
        Quat_Z = q4;

        //piezo = 1400 - p;
		piezo = p;

		Buffer.BlockCopy(mRecognitionHistory[0], 0 * INT_SIZE, mRecognitionHistory[0], 1 * INT_SIZE, (DATA_NUM - 1) * INT_SIZE);
        Buffer.BlockCopy(mRecognitionHistory[1], 0 * INT_SIZE, mRecognitionHistory[1], 1 * INT_SIZE, (DATA_NUM - 1) * INT_SIZE);
        Buffer.BlockCopy(mRecognitionHistory[2], 0 * INT_SIZE, mRecognitionHistory[2], 1 * INT_SIZE, (DATA_NUM - 1) * INT_SIZE);
        Buffer.BlockCopy(mRecognitionHistory[3], 0 * INT_SIZE, mRecognitionHistory[3], 1 * INT_SIZE, (DATA_NUM - 1) * INT_SIZE);
        Buffer.BlockCopy(mRecognitionHistory[4], 0 * INT_SIZE, mRecognitionHistory[4], 1 * INT_SIZE, (DATA_NUM - 1) * INT_SIZE);
        Buffer.BlockCopy(mRecognitionHistory[5], 0 * INT_SIZE, mRecognitionHistory[5], 1 * INT_SIZE, (DATA_NUM - 1) * INT_SIZE);

        mRecognitionHistory[0][0] = ac_x;
        mRecognitionHistory[1][0] = ac_y;
        mRecognitionHistory[2][0] = ac_z;
        mRecognitionHistory[3][0] = gy_x;
        mRecognitionHistory[4][0] = gy_y;
        mRecognitionHistory[5][0] = gy_z;

        Buffer.BlockCopy(quarternionHistory[0], 0 * sizeof(float), quarternionHistory[0], 1 * sizeof(float), (DATA_NUM - 1) * sizeof(float));
        Buffer.BlockCopy(quarternionHistory[1], 0 * sizeof(float), quarternionHistory[1], 1 * sizeof(float), (DATA_NUM - 1) * sizeof(float));
        Buffer.BlockCopy(quarternionHistory[2], 0 * sizeof(float), quarternionHistory[2], 1 * sizeof(float), (DATA_NUM - 1) * sizeof(float));
        Buffer.BlockCopy(quarternionHistory[3], 0 * sizeof(float), quarternionHistory[3], 1 * sizeof(float), (DATA_NUM - 1) * sizeof(float));

        quarternionHistory[0][0] = q1;
        quarternionHistory[1][0] = q2;
        quarternionHistory[2][0] = q3;
        quarternionHistory[3][0] = q4;

        Buffer.BlockCopy(racketAngle, 0 * sizeof(int), racketAngle, 1 * sizeof(int), (DATA_NUM - 1) * sizeof(int));
        racketAngle[0] = swing_degree;
		Buffer.BlockCopy(racketAnglez, 0 * sizeof(int), racketAnglez, 1 * sizeof(int), (DATA_NUM - 1) * sizeof(int));
		racketAnglez[0] = swing_degree_z;
		Buffer.BlockCopy(eulerAngleY, 0 * sizeof(float), eulerAngleY, 1 * sizeof(float), (DATA_NUM - 1) * sizeof(float));
        eulerAngleY[0] = euler_angle_y;
        Buffer.BlockCopy(racketSpeed, 0 * sizeof(int), racketSpeed, 1 * sizeof(int), (DATA_NUM - 1) * sizeof(int));
        racketSpeed[0] = acSpeed;

        Buffer.BlockCopy(racketPiezo, 0 * sizeof(int), racketPiezo, 1 * sizeof(int), (DATA_NUM - 1) * sizeof(int)); // piezo
        racketPiezo[0] = piezo;

        
        if (SwingInvaildCheck == true)
        {
#if UNITY_EDITOR
            if (checkSwing(gy_z) == true)
#else
            if (checkSwing(acSpeed) == true)
#endif

            {

                if (iDataTimeout < (validDuration - 10))
                {

                    iDataTrainValid += 1;
                    if (1 <= iDataTrainValid) // 스윙이라고 인식
                    {
                        iDataTimeout = validDuration;
                        bSwingData = true;
                        iDataTrainValid = 0;
                    }
                    else
                    if (bSwingData == true)
                    {
#if UNITY_EDITOR // test zwin
#else
                        SwingSaveDB();
#endif
                        Debug.Log("DATA VALID! iDataTimeout#1=" + iDataTimeout);
						SwingDataSave();
						
						bSwingData = false;
                        iDataTimeout = 0;
                    }
                }
            }
            else
            {
                iDataTrainValid = 0;
            }

            if (0 < iDataTimeout)
            {

                iDataTimeout -= 1;

                if (iDataTimeout == 0)
                {

                    if (bSwingData == true)
                    {

#if UNITY_EDITOR  // test zwin
#else
						// SwingSaveDB();
#endif
                        Debug.Log("DATA VALID! iDataTimeout#2=" + iDataTimeout);
						SwingSaveDB();
						SwingDataSave();
						
						bSwingData = false;
                    }
                }
            }
        }
    }

4. 스윙을 분석합니다. FILE:DataAnalysis.cs

 

int dataParsing()
    {
		//        Debug.Log("AX\tAY\tAZ\tGX\tGY\tGZ");

		//        for (int i = 0; i < DATA_NUM; i++)
		//        {
		//            Debug.Log(mRecognitionHistory[0][i] + "\t" + mRecognitionHistory[1][i] + "\t" + mRecognitionHistory[2][i] + "\t" 
		//                + mRecognitionHistory[3][i] + "\t" + mRecognitionHistory[4][i] + "\t" + mRecognitionHistory[5][i]);
		//        } 

		// You can add up the values in as many cells as you want.
		// 라켓 스윙 기울기

		// Debug.Log("스윙유효2");

        float min = 0, max = 0;

        for (int i = 0; i < DATA_NUM; i++)
        {
            if(mRecognitionHistory[5][i] < min) min = mRecognitionHistory[5][i]; // gz
            if (max < mRecognitionHistory[5][i]) max = mRecognitionHistory[5][i]; // gz
        }
        //Debug.Log("라켓기울기 max: " + max + " min: " + min + " = " + (max - min) );

        int PizeoPos = 0;
        int PiezoMax = 0;

        for (int i = 0; i < DATA_NUM; i++)
        {
            if (racketPiezo[i] < min) max = mRecognitionHistory[5][i];
            if (PiezoMax < racketPiezo[i])
            {
                PiezoMax = racketPiezo[i];
                PizeoPos = i;
            }
        }
       // Debug.Log("PiezoMax: " + PiezoMax + " PizeoPos: " + PizeoPos);
       // GameManager.g_Analysis.swing_accuracy = PizeoPos * 100 / 60;
       // GameManager.g_Analysis.swing_power = PiezoMax / 10;


#if UNITY_ANDROID
        GetJavaObject().Call("Debug_Log", "라켓기울기 max: " + max + " min: " + min + " = " + (max - min));

        for (int i = 0; i < DATA_NUM; i++)
        {
            //Debug.Log("Y값 : " + target.transform.GetChild(0).transform.localEulerAngles.y);

            GetJavaObject().Call("Debug_Log", "" +
                (quarternionHistory[0][i]*100) + "\t" +
                (quarternionHistory[1][i]*100) + "\t" +
                (quarternionHistory[2][i]*100) + "\t" +
                (quarternionHistory[2][i]*100) + "\t" +
                racketAngle[i] + "\t" +
                racketSpeed[i]);
        }
#endif


        double[] sum = new double[SWING_KINDS];
    
        double swing_low_value = 600000;
        int swing_match_first = 0;

        // dtw
        for (int i = 0; i < SWING_KINDS; i++)
        {
            

            for (int j = 0; j < SENSOR_NUM; j++)
            {
                double[] r = Array.ConvertAll(mRecognitionHistory[j], x => (double)x);
                double[] t = new double [DATA_NUM];
                
                switch(i)
                {
                    case TRAIN_FOREHAND_SMASH: t = Array.ConvertAll(forehand_smash[j], x => (double)x); break;
                    case TRAIN_FOREHAND_DRIVE: t = Array.ConvertAll(forehand_drive[j], x => (double)x); break;
                    case TRAIN_FOREHAND_SHORT: t = Array.ConvertAll(forehand_short[j], x => (double)x); break;
                    case TRAIN_FOREHAND_CUT: t = Array.ConvertAll(forehand_cut[j], x => (double)x); break;
                    case TRAIN_BACKHAND_SMASH: t = Array.ConvertAll(backhand_smash[j], x => (double)x); break;
                    case TRAIN_BACKHAND_DRIVE: t = Array.ConvertAll(backhand_drive[j], x => (double)x); break;
                    case TRAIN_BACKHAND_SHORT: t = Array.ConvertAll(backhand_short[j], x => (double)x); break;
                    case TRAIN_BACKHAND_CUT: t = Array.ConvertAll(backhand_cut[j], x => (double)x); break;

                    case TRAIN_FOREHAND_SMASH_2: t = Array.ConvertAll(forehand_smash_2[j], x => (double)x); break;
                    case TRAIN_FOREHAND_DRIVE_2: t = Array.ConvertAll(forehand_drive_2[j], x => (double)x); break;
                    case TRAIN_FOREHAND_SHORT_2: t = Array.ConvertAll(forehand_short_2[j], x => (double)x); break;
                    case TRAIN_FOREHAND_CUT_2: t = Array.ConvertAll(forehand_cut_2[j], x => (double)x); break;
                    case TRAIN_BACKHAND_SMASH_2: t = Array.ConvertAll(backhand_smash_2[j], x => (double)x); break;
                    case TRAIN_BACKHAND_DRIVE_2: t = Array.ConvertAll(backhand_drive_2[j], x => (double)x); break;
                    case TRAIN_BACKHAND_SHORT_2: t = Array.ConvertAll(backhand_short_2[j], x => (double)x); break;
                    case TRAIN_BACKHAND_CUT_2: t = Array.ConvertAll(backhand_cut_2[j], x => (double)x); break;
                }

                SimpleDTW dtw = new SimpleDTW(r, t);

                dtw.computeDTW();

                // Debug.Log("dtw " + i + "/" + j + " sum=" + dtw.getSum());
                sum[i] += dtw.getSum();

            }

            // Debug.Log("dtw " + i + " sum=" + sum);

            if(sum[i] < swing_low_value)
            {
                swing_match_first = i;
                swing_low_value = sum[i];
            }
        }
        GameManager.g_Analysis.swing = swing_match_first % 8; 
        Debug.Log("swing_match_first=" + swing_match_first);
        Debug.Log("" + sum[0] + " " + sum[1] + " " + sum[2] + " " + sum[3] + " " + sum[4] + " " + sum[5] + " " + sum[6] + " " + sum[7]);
        Debug.Log("" + sum[8+0] + " " + sum[8 + 1] + " " + sum[8 + 2] + " " + sum[8 + 3] + " " + sum[8 + 4] + " " + sum[8 + 5] + " " + sum[8 + 6] + " " + sum[8 + 7]);

// #if UNITY_EDITOR // test zwin
#if (UNITY_IOS || UNITY_STANDALONE_OSX || UNITY_IPHONE)

        double matching = 400000-swing_low_value;
        matching /= 10000;
        if (matching < 0) matching = 0;

        switch (GameManager.SWING_EXER_menu)
        {
            case GameManager.SWING_EXER_MENU.SWING_EXER_F_SMASH:
                {
                    switch (GameManager.g_Analysis.swing)
                    {
                        case 0: case 8 + 0: matching += 60; break; // Fsmash
                        case 1: case 8 + 1: matching += 40; break; // Fdrive
                        case 2: case 8 + 2: matching += 40; break; // Fshort
                        case 3: case 8 + 3: matching += 20; break; // Fcut
                        case 4: case 8 + 4: break; // Bsmash
                        case 5: case 8 + 5: break; // Bdrive
                        case 6: case 8 + 6: break; // Bshort
                        case 7: case 8 + 7: break; // Bcut
                    }
                    break;
                }
            case GameManager.SWING_EXER_MENU.SWING_EXER_F_DRIVE:
                {
                    switch (GameManager.g_Analysis.swing)
                    {
                        case 0: case 8 + 0: matching += 40; break; // Fsmash
                        case 1: case 8 + 1: matching += 60; break; // Fdrive
                        case 2: case 8 + 2: matching += 40; break; // Fshort
                        case 3: case 8 + 3: matching += 20; break; // Fcut
                        case 4: case 8 + 4: break; // Bsmash
                        case 5: case 8 + 5: break; // Bdrive
                        case 6: case 8 + 6: break; // Bshort
                        case 7: case 8 + 7: break; // Bcut
                    }
                    break;
                }
            case GameManager.SWING_EXER_MENU.SWING_EXER_F_SHORT:
                {
                    switch (GameManager.g_Analysis.swing)
                    {
                        case 0: case 8 + 0: matching += 40; break; // Fsmash
                        case 1: case 8 + 1: matching += 40; break; // Fdrive
                        case 2: case 8 + 2: matching += 60; break; // Fshort
                        case 3: case 8 + 3: matching += 20; break; // Fcut
                        case 4: case 8 + 4: break; // Bsmash
                        case 5: case 8 + 5: break; // Bdrive
                        case 6: case 8 + 6: break; // Bshort
                        case 7: case 8 + 7: break; // Bcut
                    }
                    break;
                }
            case GameManager.SWING_EXER_MENU.SWING_EXER_F_CUT:
                {
                    switch (GameManager.g_Analysis.swing)
                    {
                        case 0: case 8 + 0: matching += 20; break; // Fsmash
                        case 1: case 8 + 1: matching += 20; break; // Fdrive
                        case 2: case 8 + 2: matching += 20; break; // Fshort
                        case 3: case 8 + 3: matching += 60; break; // Fcut
                        case 4: case 8 + 4: break; // Bsmash
                        case 5: case 8 + 5: break; // Bdrive
                        case 6: case 8 + 6: break; // Bshort
                        case 7: case 8 + 7: break; // Bcut
                    }
                    break;
                }
            case GameManager.SWING_EXER_MENU.SWING_EXER_B_SMASH:
                switch (GameManager.g_Analysis.swing)
                {
                    case 0: case 8 + 0: break; // Fsmash
                    case 1: case 8 + 1: break; // Fdrive
                    case 2: case 8 + 2: break; // Fshort
                    case 3: case 8 + 3: break; // Fcut
                    case 4: case 8 + 4: matching += 60; break; // Bsmash
                    case 5: case 8 + 5: matching += 40; break; // Bdrive
                    case 6: case 8 + 6: matching += 40; break; // Bshort
                    case 7: case 8 + 7: matching += 20; break; // Bcut
                }
                break;
            case GameManager.SWING_EXER_MENU.SWING_EXER_B_DRIVE:
                switch (GameManager.g_Analysis.swing)
                {
                    case 0: case 8 + 0: break; // Fsmash
                    case 1: case 8 + 1: break; // Fdrive
                    case 2: case 8 + 2: break; // Fshort
                    case 3: case 8 + 3: break; // Fcut
                    case 4: case 8 + 4: matching += 40; break; // Bsmash
                    case 5: case 8 + 5: matching += 40; break; // Bdrive
                    case 6: case 8 + 6: matching += 60; break; // Bshort
                    case 7: case 8 + 7: matching += 20; break; // Bcut
                }
                break;
            case GameManager.SWING_EXER_MENU.SWING_EXER_B_SHORT:
                switch (GameManager.g_Analysis.swing)
                {
                    case 0: case 8 + 0: break; // Fsmash
                    case 1: case 8 + 1: break; // Fdrive
                    case 2: case 8 + 2: break; // Fshort
                    case 3: case 8 + 3: break; // Fcut
                    case 4: case 8 + 4: matching += 40; break; // Bsmash
                    case 5: case 8 + 5: matching += 40; break; // Bdrive
                    case 6: case 8 + 6: matching += 60; break; // Bshort
                    case 7: case 8 + 7: matching += 20; break; // Bcut
                }
                break;
            case GameManager.SWING_EXER_MENU.SWING_EXER_B_CUT:
                switch (GameManager.g_Analysis.swing)
                {
                    case 0: case 8 + 0: break; // Fsmash
                    case 1: case 8 + 1: break; // Fdrive
                    case 2: case 8 + 2: break; // Fshort
                    case 3: case 8 + 3: break; // Fcut
                    case 4: case 8 + 4: matching += 20; break; // Bsmash
                    case 5: case 8 + 5: matching += 20; break; // Bdrive
                    case 6: case 8 + 6: matching += 20; break; // Bshort
                    case 7: case 8 + 7: matching += 60; break; // Bcut
                }
                break;
            case GameManager.SWING_EXER_MENU.SWING_EXER_SERVE: break;
        }

        GameManager.g_Analysis.swing_matching = (int)matching;

        // int tempMathing = UnityEngine.Random.Range(0, 100);
        // random_i += 77;
        // GameManager.g_Analysis.swing_matching = random_i % 100;
        //swing = (random_i % 8);
        // GameManager.g_Analysis.swing_speed = (int)acSpeed / 100;
        //int tempSwing = UnityEngine.Random.Range(0, 7);
        doSwing("" + GameManager.g_Analysis.swing); //  swing); //  "" + tempSwing); // for test

#endif

        if (GameManager.SWING_EXER_MENU.SWING_RECORD_TIMER == GameManager.SWING_EXER_menu)
        {
            if (swing < 4)
                GameManager.g_Analysis.RECORD_hand[HAND_RIGHT] += 1;
            else
                GameManager.g_Analysis.RECORD_hand[HAND_LEFT] += 1;

            GameManager.g_Analysis.RECORD_swing[swing] += 1;

            Debug.Log("RECORD=" + " {" + GameManager.g_Analysis.RECORD_hand[HAND_RIGHT] + "," + GameManager.g_Analysis.RECORD_hand[HAND_LEFT] + " } {" +
                GameManager.g_Analysis.RECORD_swing[0] + "," +
                GameManager.g_Analysis.RECORD_swing[1] + "," +
                GameManager.g_Analysis.RECORD_swing[2] + "," +
                GameManager.g_Analysis.RECORD_swing[3] + "," +
                GameManager.g_Analysis.RECORD_swing[4] + "," +
                GameManager.g_Analysis.RECORD_swing[5] + "," +
                GameManager.g_Analysis.RECORD_swing[6] + "," +
                GameManager.g_Analysis.RECORD_swing[7] + "} ");
        }
		ArraySave();

		//Save(); // file to csv
          
        return 0;
    }

 

스윙인식

1. 포핸드 드라이브 인식

2. 스윙 종류

백핸드 드라이브 인식

포핸드 쇼트 인식

 

'유니티 > IOS BLE' 카테고리의 다른 글

Ble Racket Data  (0) 2020.12.22
Unity IOS BLE 컴파일 환경 구성  (0) 2020.12.08