Search Unity

Resolved How to export VR headset position and rotation

Discussion in 'VR' started by qttsc2021, Apr 13, 2022.

  1. qttsc2021

    qttsc2021

    Joined:
    Mar 29, 2022
    Posts:
    24
    Hello!

    I am developing a VR experiment for my research on improving pedestrian safety at midblock crosswalks. The device I am using for the experiment is HTC Vive Pro Eye. I am very new to coding and Unity and I hope someone can help. So far, I built the environment for the experiment (i.e. crosswalk, road, buildings, vehicles), however, I am struggling on how I can collect data when after I run my experiment.

    Can anyone please advise me on how I can export the headset position & rotation (with respect to time) to a csv or xml file format? Hope to hear from someone soon. Thank you.
     
  2. arfish

    arfish

    Joined:
    Jan 28, 2017
    Posts:
    782
    Hi,

    Maybe you could run the app in debug mode and log the positions with Debug.Log lines. Just prefix them with something to make them easier to pull from the log.

    Or setting up a server to send the data to, like this: (Haven't tested it myself)
     
    Last edited: Apr 14, 2022
    qttsc2021 likes this.
  3. mabulous

    mabulous

    Joined:
    Jan 4, 2013
    Posts:
    198
    This is for a JSON, feel free to use

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using System.IO;
    6.  
    7.   public class MotionRecorder : MonoBehaviour
    8.   {
    9.     [System.Serializable]
    10.     private struct MotionFrame
    11.     {
    12.       public int frameIndex;
    13.       public float timeStamp;
    14.       public Matrix4x4 headToWorld;
    15.     }
    16.  
    17.     public GameObject vrcam;
    18.  
    19.     private StreamWriter writer;
    20.     private bool firstFrameWritten;
    21.  
    22.     // Start is called before the first frame update
    23.     void Start()
    24.     {
    25.       string path = Application.persistentDataPath + "/" + "motion_" + System.DateTime.Now.ToString("s") + ".json";
    26.       writer = new StreamWriter(path, false);
    27.       writer.AutoFlush = false;
    28.       writer.WriteLine("{");
    29.       writer.WriteLine("\"frames\":[");
    30.     }
    31.  
    32.     // Update is called once per frame
    33.     void LateUpdate()
    34.     {
    35.       MotionFrame frame;
    36.       frame.frameIndex = Time.frameCount;
    37.       frame.timeStamp = Time.time;
    38.       frame.headToWorld = vrcam.transform.localToWorldMatrix;
    39.  
    40.       string jsonFrame = JsonUtility.ToJson(frame, true);
    41.       if(firstFrameWritten)
    42.       {
    43.         writer.WriteLine(",");
    44.       }
    45.       writer.Write(jsonFrame);
    46.       writer.FlushAsync();
    47.       firstFrameWritten = true;
    48.     }
    49.  
    50.     void OnApplicationQuit() {
    51.       writer.WriteLine("]");
    52.       writer.WriteLine("}");
    53.       writer.Close();
    54.     }
    55.   }
     
    qttsc2021 likes this.
  4. qttsc2021

    qttsc2021

    Joined:
    Mar 29, 2022
    Posts:
    24
    Thank you for your response. I tested your code and received a set of data in the form of a 4x4 matrix. One example with the frame index of 214 is shown below:

    "frameIndex": 214,
    "timeStamp": 2.7564923763275148,
    "headToWorld": {
    "e00": 0.996915876865387,
    "e01": 0.06917691975831986,
    "e02": -0.03705805167555809,
    "e03": 0.13320612907409669,
    "e10": -0.0695580318570137,
    "e11": 0.9975364804267883,
    "e12": -0.00909413117915392,
    "e13": 1.0398576259613038,
    "e20": 0.036337655037641528,
    "e21": 0.011643768288195134,
    "e22": 0.9992717504501343,
    "e23": -2.7802181243896486,
    "e30": 0.0,
    "e31": 0.0,
    "e32": 0.0,
    "e33": 1.0

    Does (e03,e13,e23) represent (Tx, Ty, Tz)? Also how do I get the rotation from this data? It looks very confusing...
     
  5. qttsc2021

    qttsc2021

    Joined:
    Mar 29, 2022
    Posts:
    24
    Also, is there a way to convert the data collected into an excel file? If so, how do I do it with the given data? Looking forward to your response :)
     
  6. mabulous

    mabulous

    Joined:
    Jan 4, 2013
    Posts:
    198
    using general matrix math...

    But if you prefer vector position plus quaternion orientation output, you can also simply replace
    public Matrix4x4 headToWorld;
    with

    Code (CSharp):
    1. public Vector3 position;
    2. public Quaternion orientation;
    and then replace
    frame.headToWorld = vrcam.transform.localToWorldMatrix;
    with

    Code (CSharp):
    1. frame.position = vrcam.transform.position;
    2. frame.orientation = vrcam.transform.rotation;
    If you don't want JSON, it should be trivial to adapt to code to output CSV textfile that you can load into excel.
     
    qttsc2021 likes this.
  7. qttsc2021

    qttsc2021

    Joined:
    Mar 29, 2022
    Posts:
    24
    Thank you so much for your reply, you have really helped me a lot in my research and I highly appreciate it. The data looks great! :) I managed to code it to output CSV as well. But I would like to organize the data differently...

    Right now, the data output looks like this on excel:

    Data 1.PNG

    But I would like the data to output like this:

    Data 2.PNG

    Can you please show me how I can do this?
     
  8. arfish

    arfish

    Joined:
    Jan 28, 2017
    Posts:
    782
    qttsc2021 likes this.
  9. qttsc2021

    qttsc2021

    Joined:
    Mar 29, 2022
    Posts:
    24
  10. mabulous

    mabulous

    Joined:
    Jan 4, 2013
    Posts:
    198
    If you want Euler angles rather than a quaternion, replace
    public Quaternion orientation;
    with
    public Vector3 eulerAngles;
    and then do

    Code (CSharp):
    1. frame.eulerAngles = vrcam.transform.eulerAngles;
    This will give you the orientation as Euler Angles in degrees and of course all the problems associated with Euler Angles.
     
    qttsc2021 likes this.
  11. qttsc2021

    qttsc2021

    Joined:
    Mar 29, 2022
    Posts:
    24
    Perfect! Thank you again :)
     
  12. mm2758

    mm2758

    Joined:
    Oct 18, 2022
    Posts:
    3
    hi, Hope you are doing well.
    I tried to use your code for access the gyro data of unity rift s, I'm completely new in programing.
    I got two error in my unity console :
    1)
    DirectoryNotFoundException: Could not find a part of the path "C:\Users\mm2758\AppData\LocalLow\DefaultCompany\My project 1\motion_2022-10-19T11:23:37.json".
    System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.Boolean anonymous, System.IO.FileOptions options) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
    System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.IO.FileOptions options) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
    (wrapper remoting-invoke-with-check) System.IO.FileStream..ctor(string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare,int,System.IO.FileOptions)
    System.IO.StreamWriter..ctor (System.String path, System.Boolean append, System.Text.Encoding encoding, System.Int32 bufferSize) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
    System.IO.StreamWriter..ctor (System.String path, System.Boolean append) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
    (wrapper remoting-invoke-with-check) System.IO.StreamWriter..ctor(string,bool)
    MotionRecorder.Start () (at Assets/Scripts/MotionRecorder.cs:27)
    2)
    NullReferenceException: Object reference not set to an instance of an object
    MotionRecorder.LateUpdate () (at Assets/Scripts/MotionRecorder.cs:47)

    and its the code :

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.IO;

    public class MotionRecorder : MonoBehaviour
    {
    [System.Serializable]
    private struct MotionFrame
    {
    public int frameIndex;
    public float timeStamp;
    public Vector3 position;
    public Quaternion orientation;
    }

    public GameObject vrcam;

    private StreamWriter writer;
    private bool firstFrameWritten;

    // Start is called before the first frame update
    void Start()
    {
    string path = Application.persistentDataPath + "/" + "motion_" + System.DateTime.Now.ToString("s") + ".json";
    writer = new StreamWriter(path, false);
    writer.AutoFlush = false;
    writer.WriteLine("{");
    writer.WriteLine("\"frames\":[");
    }

    // Update is called once per frame
    void LateUpdate()
    {
    MotionFrame frame;
    frame.frameIndex = Time.frameCount;
    frame.timeStamp = Time.time;
    frame.position = vrcam.transform.position;
    frame.orientation = vrcam.transform.rotation;

    string jsonFrame = JsonUtility.ToJson(frame, true);
    if (firstFrameWritten)
    {
    writer.WriteLine(",");
    }
    writer.Write(jsonFrame);
    writer.FlushAsync();
    firstFrameWritten = true;
    }

    void OnApplicationQuit()
    {
    writer.WriteLine("]");
    writer.WriteLine("}");
    writer.Close();
    }
    }
    cloud you please help me. I really appreciate for any help.
    Thanks
     

    Attached Files:

    Last edited: Oct 19, 2022
  13. mm2758

    mm2758

    Joined:
    Oct 18, 2022
    Posts:
    3
    Hi, I'm trying to use your code to extract the gyro data of my oculus rift s through unity; I got these errors; I would appreciate it if anyone could help me.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.IO;

    public class MotionRecorder : MonoBehaviour
    {
    [System.Serializable]
    private struct MotionFrame
    {
    public int frameIndex;
    public float timeStamp;
    public Vector3 position;
    public Quaternion orientation;
    }

    public GameObject vrcam;

    private StreamWriter writer;
    private bool firstFrameWritten;

    // Start is called before the first frame update
    void Start()
    {
    string path = Application.persistentDataPath + "/" + "motion_" + System.DateTime.Now.ToString("s") + ".json";
    writer = new StreamWriter(path, false);
    writer.AutoFlush = false;
    writer.WriteLine("{");
    writer.WriteLine("\"frames\":[");
    }

    // Update is called once per frame
    void LateUpdate()
    {
    MotionFrame frame;
    frame.frameIndex = Time.frameCount;
    frame.timeStamp = Time.time;
    frame.position = vrcam.transform.position;
    frame.orientation = vrcam.transform.rotation;

    string jsonFrame = JsonUtility.ToJson(frame, true);
    if (firstFrameWritten)
    {
    writer.WriteLine(",");
    }
    writer.Write(jsonFrame);
    writer.FlushAsync();
    firstFrameWritten = true;
    }

    void OnApplicationQuit()
    {
    writer.WriteLine("]");
    writer.WriteLine("}");
    writer.Close();
    }
    }
     

    Attached Files:

  14. mm2758

    mm2758

    Joined:
    Oct 18, 2022
    Posts:
    3
    Hi, Hope you are doing well.
    I tried to use your code to access the gyro data of unity rift s, but I'm completely new to programming.
    I got this error in my unity console :
    1.
    InvalidOperationException: The stream is currently in use by a previous operation on the stream.
    System.IO.StreamWriter.ThrowAsyncIOInProgress () (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
    System.IO.StreamWriter.CheckAsyncTaskInProgress () (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
    System.IO.StreamWriter.WriteLine (System.String value) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
    VRCamera.LateUpdate () (at Assets/Scripts/VRCamera.cs:46)

    and its the code :

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.IO;

    public class MotionRecorder : MonoBehaviour
    {
    [System.Serializable]
    private struct MotionFrame
    {
    public int frameIndex;
    public float timeStamp;
    public Vector3 position;
    public Quaternion orientation;
    }

    public GameObject vrcam;

    private StreamWriter writer;
    private bool firstFrameWritten;

    // Start is called before the first frame update
    void Start()
    {
    string path = Application.persistentDataPath + "/" + "motion_" + System.DateTime.Now.ToString("s") + ".json";
    writer = new StreamWriter(path, false);
    writer.AutoFlush = false;
    writer.WriteLine("{");
    writer.WriteLine("\"frames\":[");
    }

    // Update is called once per frame
    void LateUpdate()
    {
    MotionFrame frame;
    frame.frameIndex = Time.frameCount;
    frame.timeStamp = Time.time;
    frame.position = vrcam.transform.position;
    frame.orientation = vrcam.transform.rotation;

    string jsonFrame = JsonUtility.ToJson(frame, true);
    if (firstFrameWritten)
    {
    writer.WriteLine(",");
    }
    writer.Write(jsonFrame);
    writer.FlushAsync();
    firstFrameWritten = true;
    }

    void OnApplicationQuit()
    {
    writer.WriteLine("]");
    writer.WriteLine("}");
    writer.Close();
    }
    }
    cloud you please help me. I really appreciate for any help.
    Thanks
     

    Attached Files:

  15. andonegr

    andonegr

    Joined:
    Jan 20, 2013
    Posts:
    7
    Hey people,

    @qttsc2021 , could you share the code that gave you this formating of the csv file?

    @mabulous
    Thanks for sharing this code, very helpful!

    Cheers
     
    JoyceBosmans likes this.