Sunday, August 18, 2013

Troubleshooting the SDK: Accessing the Head Tracker Data

For myself, people on the Oculus Developer forums who report issues and request help boil down into two main categories: people with display issues, people with tracker issues.  Display issue people are having problems with display splitters, monitor cloning, or getting the output to the correct window, or even getting the rift display to show any output at all.   Tracker issue people are having issues getting the tracker to properly represent the orientation of the Rift and convey that information to the application.  Today we're going to focus on tracker issues.


Display problems are tough because there's so many possible issues to work through, but tracker issues are pretty easy to troubleshoot, at least to the extent of proving to yourself your hardware is being detected and sending data.

The head tracker is simply a solid state accelerometer, gyroscope and magnetometer.  This is now common hardware, having also been driven by the mobile computing market, as well as  have been driven by the same mobile market as well as the game controller market.

Applications tend to get data out of a sensor fusion object, which adds features like turning a continuous stream of tracker messages into a cohesive orientation in the form of a quaternion.  Sensor fusion also adds magnetic calibration for yaw correction and prediction based on the current speed of movement.  These things can be enabled and disabled, so it's sometimes not clear whether you have a problem with your sensor fusion setup, or the connection to the SDK, or the hardware itself.

The easiest way to troubleshoot these issues is to make a minimal application that will read the tracker messages and output something to the console, bypassing sensor fusion completely.  Once you're assured that's working you can start building up from there.

using namespace std;
using namespace OVR;

class TrackerHandler : public MessageHandler {
public:
    virtual void OnMessage(const Message& msg) {
        const MessageBodyFrame & trackerMessage = *(MessageBodyFrame*) &msg;
        const Vector3f & accel = trackerMessage.Acceleration;
        cout << accel.x << " " << accel.y << " " << accel.z << " " << accel.Length() << endl;
    }

    virtual bool SupportsMessageType(MessageType type) const {
        return Message_BodyFrame == type;
    }
};

class Example2 {
public:
    Ptr pSensor;
    Ptr pManager;

    Example2() {
        System::Init();
        pManager = *DeviceManager::Create();
        if (!pManager) {
            throw std::exception();
        }
        pSensor = *pManager->EnumerateDevices().CreateDevice();
        if (!pSensor) {
            throw std::exception();
        }
    }

    virtual ~Example2() {
        if (pSensor) {
            pSensor->SetMessageHandler(0);
            pSensor.Clear();
        }
        if (pManager) {
            pManager.Clear();
        }
        System::Destroy();
    }
};

int main(int argc, char ** argv) {
   Example2 example;
   TrackerHandler handler;
   example.pSensor->SetMessageHandler(&handler);
   // Sleep and let the tracker handler receive messages, which will
   // be processed in another thread
   usleep(1000 * 1000 * 10);
   return 0;
}

If that gives you output, you can follow it up by trying sensor fusion instead, as shown here:

int main(int argc, char ** argv) {
   Example2 example;
   SensorFusion fusion;
   if (!fusion.AttachToSensor(example.pSensor)) {
       throw std::exception();
   }

   for (int i = 0; i < 10; ++i) {
       Quatf orientation = fusion.GetOrientation();
       cout << orientation.x << " " << orientation.y << " " << orientation.z << " " << orientation.w << endl;
       usleep(1000 * 1000);
   }
   return;
}

You may need to replace the declaration of usleep with something from your platform if you're not working in Linux. Remember to change the value from microseconds to seconds or milliseconds if appropriate.

1 comment:

  1. Could this be used to record from the accelerometer, magnetometer, and gyroscope?

    ReplyDelete

Note: Only a member of this blog may post a comment.