How to export VR headset position and rotation

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.

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)

1 Like

This is for a JSON, feel free to use

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 Matrix4x4 headToWorld;
    }

    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.headToWorld = vrcam.transform.localToWorldMatrix;

      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();
    }
  }
1 Like

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…

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 :slight_smile:

using general matrix math…

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

public Vector3 position;
public Quaternion orientation;

and then replace frame.headToWorld = vrcam.transform.localToWorldMatrix; with

frame.position = vrcam.transform.position;
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.

1 Like

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! :slight_smile: 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:

8059376--1040867--Data 1.PNG

But I would like the data to output like this:

8059376--1040870--Data 2.PNG

Can you please show me how I can do this?

Maybe MS can give you some guidance for importing data to Excel, and how they expect the data to be formatted?

1 Like

THANK YOU! IT WORKS! (see below) :slight_smile:

8059547--1040894--Data 3.PNG

If you want Euler angles rather than a quaternion, replace public Quaternion orientation; with public Vector3 eulerAngles; and then do

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.

1 Like

Perfect! Thank you again :slight_smile:

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

8525528--1137410--Error.JPG

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();
}
}

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

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

1 Like

using System;
using System.IO;
using UnityEngine;

I use this to generate Excel into my folder straightway; each participant /session won’t overwrite, and will have a new data set.

public class DataCollector : MonoBehaviour {
[SerializeField]private float dataCollectionRate = 0.5f; // seconds between data collections
private float nextTimeToCollect = 0f;
private string dataPath;
private Vector3 previousPosition;
private float previousTime;

void Start() {
StartNewSession();
previousPosition = transform.position;
previousTime = Time.time;
}

void Update() {
if (Time.time >= nextTimeToCollect) {
nextTimeToCollect = Time.time + dataCollectionRate;
RecordData();
}
}

void StartNewSession() {
string directoryPath = @“D:\Cathy\DataPLayer”; // Updated path of your folder to store the data
string fileName = “PlayerDataLog_” + DateTime.UtcNow.ToString(“yyyyMMdd_HHmmss”) + “.csv”;

if (!Directory.Exists(directoryPath)) {
Directory.CreateDirectory(directoryPath);
}

dataPath = Path.Combine(directoryPath, fileName);
File.WriteAllText(dataPath, “Timestamp,X,Y,Z,Speed\n”); // Include speed in header
}

void RecordData() {
Vector3 currentPosition = transform.position;
float currentTime = Time.time;

// Calculate speed
float speed = Vector3.Distance(currentPosition, previousPosition) / (currentTime - previousTime);

string dataLine = DateTime.UtcNow.ToString(“o”) + “,” +
currentPosition.x + “,” +
currentPosition.y + “,” +
currentPosition.z + “,” +
speed.ToString(“F2”) + “\n”; // F2 format for floating-point precision

File.AppendAllText(dataPath, dataLine);

// Update previous position and time for the next calculation
previousPosition = currentPosition;
previousTime = currentTime;
}
}