Oculus Rift: Extracting Roll, Pitch, and Yaw from a Quaternian

I’m using the ofxOculusDK2 addon to extract some basic head orientation data from the rift — my goal is essentially to make a pan/tilt(/roll) camera rig that matches up with somebody’s head movement.

The addon has a getOrientationQuat() function that obviously returns a Quaternian, and by using ofQuaternian’s getEuler(), I can extract angles from that. When I turn the 90 degrees to the right, however, the angle jumps from -179 to 179, which makes mapping rotations to servo positions a pain.

At the moment, I’m just remapping the circle so the angles go from 90 to -270, instead of the desired 180 to -180 (and on top of that, 0 isn’t facing the tracking camera, which is kind of annoying), making the jump happen at the back of the head.

Here’s the gist of it:

Is there a way to get around this jumping at all? Is there a way to make 0 face the camera? I’m completely unfamiliar with Quaternians, so I’m not sure how I’d go about any math involving them.

And on top of that, it seems like the 0 point isn’t the same every day. Three days ago it was West, two days ago it was East, and today it’s Southwest. What the heck is up with that?

I’m just speculating here, so I haven’t tested if this is true on the oculus, but usually with gyroscopes/IMUs (except magnetometers), the readouts are relative to where the device was facing at the moment it was powered on. Are you sure that getOrientationQuat() is returning values from the tracking camera, and not the internal sensors on the headset? Try running your app with the tracking camera disconnected (it should still work). What values are you getting then?

I did a project with a bunch of IMUs for inertial motion tracking of people. I had to build-in a calibration pose that people cold hold and then I’d manually zero-out the readings. You will probably have to do the same…create a function that you can call once at the beginning when you are facing the direction you’d like zero to be, store those sensor values and do all your transformations relative to them.

Again, purely speculating, but there might be a way to automatically do that calibration using the DK2 tracking camera, even if the quaternion is coming from the internal sensors.

Disconnecting the camera does nothing (as far as I can tell) to the tracking. Although I don’t know if that’s because getOrientationQuat() never used the camera, or because it uses it as a supplement. My guess is the former (I kind of remember a forum post where the addon author said head position wasn’t supported yet, and head position is from the camera).

So, with the camera unplugged, I tried a series of tests with turning on and plugging in the Rift while facing different directions. I think this is how it works: the angle is the same on power-on as it was on power-off, regardless of the actual physical orientation of the headset. So, if I turn the Rift off while facing 0°, when I turn it back on, whatever direction the Rift is now facing is the new 0°. If I turn it off at -142°, the Rift will be facing -142° on startup, etc.

Now the tricky part is re-implementing my anti-jumping mechanism to take into account calibration transforms.

I’m curious about this now and I will try to play around with it over the holidays. Unfortunately I won’t have physical access to my Dk2 again until then.

Meanwhile, I did get a chance to peek at the Oculus Developer Guide (You can download it from https://developer.oculus.com/documentation/). Not sure if this is helpful, or easily modifiable in the the Dk2 addon, but heres what the docs say (p.21):

The simplest way to extract yaw-pitch-roll from ovrPose is to use the C++ OVR Math helper classes that are included with the library. The following example uses direct conversion to assign ovrPosef to the equivalent C++ Posef class. You can then use the Quatf::GetEulerAngles<> to extract the Euler angles in the desired axis rotation order.

Posef pose = trackingState.HeadPose.ThePose; float yaw, float eyePitch, float eyeRoll; pose.Orientation.GetEulerAngles<Axis_Y, Axis_X, Axis_Z>(&yaw, &eyePitch, &eyeRoll);

All simple C math types provided by OVR such as ovrVector3f and ovrQuatf have corresponding C++ types that provide constructors and operators for convenience. These types can be used interchangeably.

1 Like