Skip to main content
Up and Coming
February 10, 2015

Using Oculus on motion platform impair head tracking

I am trying to use the Rift on an motion platform (a 6-dof Stewart platform). The trouble I am having is that the accelerations from the motion platform gets picked up but the accelerometers in the Rift. This results in the sensor fusion thinks there is movement even though the user is keeping his head completely still inside the cockpit. The Oculus camera detects this aggressive drift and corrects for it, but this is done in a much slower rate that the drift occurs, which result in extreme "judder". Especially rotational drift correction becomes very apparent. One user described it as if the frame rate was reduced to ~2 Hz.

So how can this be solved? Well since the motion platform is already fitted with its own accelerometers, we know the acceleration (both linear and rotational) of the platform. If somehow this information could be feed to the sensor fusion of the Oculus, the accelerations from the platform could be subtracted from the accelerations from the HMD. Thus eliminating this drift.

Is there a way to supply the sensor fusion with this type of corrections?

    13 replies

    VrallyAuthor
    Up and Coming
    March 2, 2015
    Ok, since I have implemented this in a custom engine I think pseudo code will be best:

    Quat lastFilteredOrientation;
    Vec lastHmdOrientationAsEuler;
    Vec integratedOrientationAsEuler;
    Vec errorVec;
    double lastTime;

    // Begin Magic numbers
    double angleThreashold = 5.0; // Angular speed, when HMD camera resets view
    double errorThreshold = 0.02; // Angular differences that will require low pass filtering
    double smoothing = 0.02; // Smoothing factor used to fade out error
    double slerpFactor = 0.95; // Use 95% of new signal when doing standard SLERP
    double slerpFactorLowPass = 0.20; // SLERP factor when error is above threshold
    // End Magic numbers

    // Render loop
    while (!rendering.done()) {
    // Calculate time delta
    double currentTime = getCurrentTime(); // Get current high precision time
    double deltaTime = currentTime - lastTime;
    lastTime = currentTime;

    // Get tracking state from Oculus
    ovrTrackingState state = ovrHmd_GetTrackingState(hmdDevice, 0.0); // Get tracking state
    Vec3 gyroRaw = state.RawSensorData.Gyro;
    Vec3 position = state.HeadPose.Position;
    Quat orientation = state.HeadPose.Position.Orientation;

    // Calculate derivative of reported orientation
    Vec3 hmdOrientationAsEuler = getEulerFromQuat(hmdOrientation);
    Vec3 rotationDiff = (hmdOrientationAsEuler - lastHmdOrientationAsEuler) / deltaTime;
    lastHmdOrientationAsEuler = hmdOrientationAsEuler;

    // Calculate difference between derivative of orientation and raw gyro
    Vec3 angleDiff = rotationDiff - gyroRaw;

    // If angle derivative is above threshold, then Oculus camera has reset orientation
    if (angleDiff.length() > angleThreshold) {
    errorVec += integratedOrientationAsEuler; // Add current integrator value to error vector
    integratedOrientationAsEuler.set(Vec3(0.0, 0.0, 0.0)); // Reset integrator
    }

    // Get data from external inertial sensor
    Vec3 externalGyro = getExternalGyroAsEuler();

    // Integrate external gyro signal to get orientation
    integratedOrientationAsEuler += Vec3(externalGyro.x(), externalGyro.y(), externalGyro.z()) * deltaTime;

    // If accumulated error is above threshold, then add part of error vector to gyro signal
    Quat errorCompensation;
    if (errorVec.length() > errorThreshold) {
    errorCompensation = makeQuatFromEuler(errorVec);
    errorVec = errorVec * (1 - smoothing); // Fade out error
    slerpFactor = slerpFactorLowPass; // Set low pass slerp factor
    }

    // Make quaternion from integrated external gyro signal
    Quat orientationFromExternalGyro = makeQuatFromEuler(integratedOrientationAsEuler);

    // Subtract orientation from external gyro from HMD orientation
    Quat computedOrientation = orientation / (orientationFromExternalGyro * errorCompensation);

    // Spherical linear interpolation from lastFilteredOrientation to computedOrientation (0..1)
    Quat filteredOrientation = slerp(slerpFactor, lastFilteredOrientation, computedOrientation);
    lastFilteredOrientation = filteredOrientation;

    // Set render camera orientation
    setCameraOrientation(filteredOrientation);

    // Render frame
    renderFrame();
    }


    This code only handles orientations, but I guess positions could be handled using the same principles.

    Note: Time Warp has to be disabled, since it does its computations without any information from this algorithm.
    New Participant
    November 25, 2015
    Sorry for brnging up an old thread.

    I am no programmer and have no idea how to modify the SDK
    Is it possible to make the software ignore the headset internal IMU and only use data from optical tracking of the camera for 6dof headtracking??
    VrallyAuthor
    Up and Coming
    November 25, 2015
    "clyevo" wrote:
    Sorry for brnging up an old thread.

    I am no programmer and have no idea how to modify the SDK
    Is it possible to make the software ignore the headset internal IMU and only use data from optical tracking of the camera for 6dof headtracking??


    Well, Yes and No.

    You can forgo the Oculus tracking data in your engine and use the data from your own tracking system. BUT then you must disable all prediction inside the warping engine. Otherwise the SDK will use its internal tracking data to do "time warp" on the rendered image and this internal tracking data may conflict with the tracking data from your own tracking system (as it does in my case).

    There have been some hacks to remedy this, but as of lately this hack seem to be disabled by Oculus:
    viewtopic.php?t=26610#p297758