Jump to content
 
ScottHerz

Getting VerboseData at the fastest rate possible.

Recommended Posts

sample_getdatathread will abort the producer thread on disable/stop. That's not great for other reasons, but it shouldn't lock up Unity. Although in my experience it does cause instability and crashing if you happen to ahort it in the middle of the GetEyeData call (the one meaty call in that function).

Share this post


Link to post
Share on other sites

FWIW, here's what I ended up doing (to avoid aborting the thread and the reach-in for EyeData on who-knows-what-thread).

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Threading;
using System.IO;
using ViveSR.anipal.Eye;

public class ViveProEyeProducerThread : MonoBehaviour
{
    public Action<EyeData> NewOffThreadEyeDataAction;

    private EyeData EyeData = new EyeData();
    private Thread Thread;
    private const int FrequencyControl = 1;
    private bool Abort = false;

    void Start()
    {
        Abort = false;
        Thread = new Thread(QueryEyeData);
        Thread.Start();
    }

    private void OnApplicationQuit()
    {
        Abort = true;
    }

    private void OnDisable()
    {
        Abort = true;
    }

    void QueryEyeData()
    {
        int PrevFrameSequence = 0, CurrFrameSequence = 0;

        while (Abort == false) {
            ViveSR.Error error = SRanipal_Eye.GetEyeData(ref EyeData);
            if (error == ViveSR.Error.WORK) {
                CurrFrameSequence = EyeData.frame_sequence;
                if (CurrFrameSequence != PrevFrameSequence) {
                    PrevFrameSequence = CurrFrameSequence;

                    if (Abort == false && NewOffThreadEyeDataAction != null) {
                        NewOffThreadEyeDataAction(EyeData);
                    }
                }
            }
            Thread.Sleep(FrequencyControl);
        }
    }
}

 

Edited by ScottHerz
Fixed a typeo

Share this post


Link to post
Share on other sites
On 10/8/2019 at 11:23 PM, ScottHerz said:

FWIW, here's what I ended up doing (to avoid aborting the thread and the reach-in for EyeData on who-knows-what-thread).


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Threading;
using System.IO;
using ViveSR.anipal.Eye;

public class ViveProEyeProducerThread : MonoBehaviour
{
    public Action<EyeData> NewOffThreadEyeDataAction;

    private EyeData EyeData = new EyeData();
    private Thread Thread;
    private const int FrequencyControl = 1;
    private bool Abort = false;

    void Start()
    {
        Abort = false;
        Thread = new Thread(QueryEyeData);
        Thread.Start();
    }

    private void OnApplicationQuit()
    {
        Abort = true;
    }

    private void OnDisable()
    {
        Abort = true;
    }

    void QueryEyeData()
    {
        int PrevFrameSequence = 0, CurrFrameSequence = 0;

        while (Abort == false) {
            ViveSR.Error error = SRanipal_Eye.GetEyeData(ref EyeData);
            if (error == ViveSR.Error.WORK) {
                CurrFrameSequence = EyeData.frame_sequence;
                if (CurrFrameSequence != PrevFrameSequence) {
                    PrevFrameSequence = CurrFrameSequence;

                    if (Abort == false && NewOffThreadEyeDataAction != null) {
                        NewOffThreadEyeDataAction(EyeData);
                    }
                }
            }
            Thread.Sleep(FrequencyControl);
        }
    }
}

 

Is this the alternative "Sample_GetDataThread.cs", could you please add the "Sample_MainThread.cs".  I don't understand " public Action<EyeData> NewOffThreadEyeDataAction;  private EyeData EyeData = new EyeData();  ", which are different to the version before. Could you explain a little bit, thank you very much.

Share this post


Link to post
Share on other sites
On 6/19/2019 at 3:25 PM, jason_lu said:

 Hi kadakadakScott:

 

You can follow these step to get 120 frame data per second.

- Create an empty scene and add SRanipal_Framework into the scene. (The framework GameObject will be in Prefab folder)

- Create an empty GameObject and attach below two script on it.

- Start the scene preview then you can check the EyeData's frame sequence and timestamp in DataRecord.txt

 

Notice, If you use this method to get EyeData or VerboseData, you should not use other function in SRanipal_Eye simultaneously since the function in SRanipal_Eye are implement within Unity's main thread. 

 

Best Regards

Jason

 

 


// Sample_MainThread.csusing System.Collections;using System.Collections.Generic;using UnityEngine;using ViveSR.anipal.Eye;namespace Test120FPS{    public class Sample_MainThread : MonoBehaviour    {        private Sample_GetDataThread DataThread = null;        private EyeData data = new EyeData();        // Use this for initialization        void Start()        {            DataThread = FindObjectOfType<Sample_GetDataThread>();            if (DataThread == null) return;        }        // You can get data from another thread and use MonoBehaviour's method here.        // But in Unity's Update function, you can only have 90 FPS.        void Update()        {            data = DataThread.data;            Debug.Log("Left eye openness: " + data.verbose_data.left.eye_openness);            Debug.Log("Right eye openness: " + data.verbose_data.right.eye_openness);        }    }}

// Sample_GetDataThread.csusing System.Collections;using System.Collections.Generic;using UnityEngine;using System;using System.Threading;using System.IO;using ViveSR.anipal.Eye;namespace Test120FPS{    public class Sample_GetDataThread : MonoBehaviour    {        public EyeData data = new EyeData();        private Thread thread;        private const int FrequencyControl = 1;        private const int MaxFrameCount = 3600;		        void Start()        {            thread = new Thread(QueryEyeData);            thread.Start();        }        private void OnApplicationQuit()        {            thread.Abort();        }        private void OnDisable()        {            thread.Abort();        }        // You can only use C# native function in Unity's thread.        // Use EyeData's frame_sequence to calculate frame numbers and record data in file.        void QueryEyeData()        {            int FrameCount = 0;            int PrevFrameSequence = 0, CurrFrameSequence = 0;            bool StartRecord = false;            while (FrameCount < MaxFrameCount)            {                ViveSR.Error error = SRanipal_Eye.GetEyeData(ref data);                if (error == ViveSR.Error.WORK)                {                    CurrFrameSequence = data.frame_sequence;                    if (CurrFrameSequence != PrevFrameSequence)                    {                        FrameCount ++;                        PrevFrameSequence = CurrFrameSequence;                        StartRecord = true;                    }                }                // Record time stamp every 120 frame.                if (FrameCount % 120 == 0 && StartRecord)                {                    long ms = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;                    string text = "CurrentFrameSequence: " + CurrFrameSequence +                        " CurrentSystemTime(ms): " + ms.ToString() + Environment.NewLine;                    File.AppendAllText("DataRecord.txt", text);                    FrameCount = 0;                }                Thread.Sleep(FrequencyControl);            }        }    }}

 

 

I used this code, but I cannot close my application when it should be closed. Could you please give me a hand?

 

@Daniel_Y @VIVE_Jason_Lu

Share this post


Link to post
Share on other sites
On 2/10/2020 at 9:37 AM, alwyuyang said:

Is this the alternative "Sample_GetDataThread.cs", could you please add the "Sample_MainThread.cs".  I don't understand " public Action<EyeData> NewOffThreadEyeDataAction;  private EyeData EyeData = new EyeData();  ", which are different to the version before. Could you explain a little bit, thank you very much.

This is just something I (not an HTC employee) did. I think they've updated the API since. I used Action's instead of callbacks, as I prefer them. Here's the C# documentation on them: https://docs.microsoft.com/en-us/dotnet/api/system.action-1?view=netframework-4.8

Share this post


Link to post
Share on other sites

Thank you @ScottHerz and @jason_lu for sharing your code. I ended up with a similar version but Unity keeps freezing and crashing after running the code, both my version and your versions. Did you experience similar issues? Everything works fine though when I access the eye data in the main thread, so I thought that this might be caused by race conditions or the thread not being closed correctly, but I can't figure out a workaround.

Share this post


Link to post
Share on other sites

@imarin18 @VIVE_Jason_Lu @jason_lu

What change did you make to the while loop in sample_getdatathread.cs to get it to work? Unity keeps crashing for me. I'd like to track where the user is looking (x, y) over time - will these scripts help me do that?

I appreciate all help.

Share this post


Link to post
Share on other sites

Make sure any code in your action is threadsafe. I think I just added the record to a threadsafe queue and pulled from it on the main thread. 

That said, have you all tried the newer API? I've moved on from this tracker, but my understanding is they've reworked how you grab events.

@Daniel_Y

Share this post


Link to post
Share on other sites

@wdrake @fayre If anyone is experiencing crashes with Unity and threads feel free to use the callback method in the SDK. The thread crashes may be due to aborting a thread during an eye data update. The callback method has been reliable in my testing.

 

using UnityEngine;
using ViveSR.anipal.Eye;
using System.Runtime.InteropServices;

public class CallbackExample : MonoBehaviour
{

    private EyeData eyeData = new EyeData();
    private bool eye_callback_registered = false;

    private void Update()
    {
        if (SRanipal_Eye_Framework.Status != SRanipal_Eye_Framework.FrameworkStatus.WORKING) return;

        if (SRanipal_Eye_Framework.Instance.EnableEyeDataCallback == true && eye_callback_registered == false)
        {
            SRanipal_Eye.WrapperRegisterEyeDataCallback(Marshal.GetFunctionPointerForDelegate((SRanipal_Eye.CallbackBasic)EyeCallback));
            eye_callback_registered = true;
        }
        else if (SRanipal_Eye_Framework.Instance.EnableEyeDataCallback == false && eye_callback_registered == true)
        {
            SRanipal_Eye.WrapperUnRegisterEyeDataCallback(Marshal.GetFunctionPointerForDelegate((SRanipal_Eye.CallbackBasic)EyeCallback));
            eye_callback_registered = false;
        }
    }

    private void OnDisable()
    {
        Release();
    }

    void OnApplicationQuit()
    {
        Release();
    }

    private void Release()
    {
        if (eye_callback_registered == true)
        {
            SRanipal_Eye.WrapperUnRegisterEyeDataCallback(Marshal.GetFunctionPointerForDelegate((SRanipal_Eye.CallbackBasic)EyeCallback));
            eye_callback_registered = false;
        }
    }

    private void EyeCallback(ref EyeData eye_data)
    {
        eyeData = eye_data;
        
        // do stuff with eyeData..
    }
}

 

Share this post


Link to post
Share on other sites
On 6/23/2020 at 5:15 PM, Corvus said:

@wdrake @fayre If anyone is experiencing crashes with Unity and threads feel free to use the callback method in the SDK. The thread crashes may be due to aborting a thread during an eye data update. The callback method has been reliable in my testing.

 


using UnityEngine;
using ViveSR.anipal.Eye;
using System.Runtime.InteropServices;

public class CallbackExample : MonoBehaviour
{

    private EyeData eyeData = new EyeData();
    private bool eye_callback_registered = false;

    private void Update()
    {
        if (SRanipal_Eye_Framework.Status != SRanipal_Eye_Framework.FrameworkStatus.WORKING) return;

        if (SRanipal_Eye_Framework.Instance.EnableEyeDataCallback == true && eye_callback_registered == false)
        {
            SRanipal_Eye.WrapperRegisterEyeDataCallback(Marshal.GetFunctionPointerForDelegate((SRanipal_Eye.CallbackBasic)EyeCallback));
            eye_callback_registered = true;
        }
        else if (SRanipal_Eye_Framework.Instance.EnableEyeDataCallback == false && eye_callback_registered == true)
        {
            SRanipal_Eye.WrapperUnRegisterEyeDataCallback(Marshal.GetFunctionPointerForDelegate((SRanipal_Eye.CallbackBasic)EyeCallback));
            eye_callback_registered = false;
        }
    }

    private void OnDisable()
    {
        Release();
    }

    void OnApplicationQuit()
    {
        Release();
    }

    private void Release()
    {
        if (eye_callback_registered == true)
        {
            SRanipal_Eye.WrapperUnRegisterEyeDataCallback(Marshal.GetFunctionPointerForDelegate((SRanipal_Eye.CallbackBasic)EyeCallback));
            eye_callback_registered = false;
        }
    }

    private void EyeCallback(ref EyeData eye_data)
    {
        eyeData = eye_data;
        
        // do stuff with eyeData..
    }
}

 

 

Hi @Corvus,

I've tried your callback method solution, unfortunately it is still crashing the Unity when I stop the game. Moreover it pretty soon throws a NullReferenceException, usually after a second or so. I attached the image with the exception.

Výstřižek.PNG

Share this post


Link to post
Share on other sites

Please sign in to comment

You need to be a member in order to leave a comment

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...