MSmithDev / AirAPI_Windows

MIT License
115 stars 20 forks source link

Fixed roll data getting flipped after few seconds when Xreal glasses are tilted #12

Closed iVideoGameBoss closed 4 months ago

iVideoGameBoss commented 4 months ago

PhoenixHeadTracker uses AirAPI_Windows.dll to capture Yaw, Pitch and Roll data from Xreal Air glasses and passes info via UDP to OpenTrack. I found if you tilt your glasses the roll data was flipping after few seconds by AirAPI_Windows.dll when glasses were titled. After much testing I was able to pin down the issue to these two functions below.

The issue is that the function seems to be reordering and inverting some of the angular velocity components:

The X-axis (index 0) is inverted. The Y-axis (index 1) is mapped to the Z-axis output. The Z-axis (index 2) is mapped to the Y-axis output.

This reordering and inversion was leading to incorrect roll calculations later in the process. The Euler angles are derived from the quaternion, which in turn is calculated using this potentially misaligned angular velocity data.

static void
process_ang_vel(const int32_t in_ang_vel[3], float out_vec[])
{

    // these scale and bias corrections are all rough guesses
    out_vec[0] = (float)(in_ang_vel[0]) * -1.0f * GYRO_SCALAR;
    out_vec[1] = (float)(in_ang_vel[2]) * GYRO_SCALAR;
    out_vec[2] = (float)(in_ang_vel[1]) * GYRO_SCALAR;
}

static void
process_accel(const int32_t in_accel[3], float out_vec[])
{
    // these scale and bias corrections are all rough guesses
    out_vec[0] = (float)(in_accel[0]) * ACCEL_SCALAR;
    out_vec[1] = (float)(in_accel[2]) * ACCEL_SCALAR;
    out_vec[2] = (float)(in_accel[1]) * ACCEL_SCALAR;

}

To fix the potential issues with the roll data handling, we need to make adjustments to the process_ang_vel function and process_accel function. Here's a proposed fix:

static void
process_ang_vel(const int32_t in_ang_vel[3], float out_vec[])
{

    // these scale and bias corrections are all rough guesses
    out_vec[0] = (float)(in_ang_vel[0]) * GYRO_SCALAR;
    out_vec[1] = (float)(in_ang_vel[1]) * GYRO_SCALAR;
    out_vec[2] = (float)(in_ang_vel[2]) * GYRO_SCALAR;
}

static void
process_accel(const int32_t in_accel[3], float out_vec[])
{
    // these scale and bias corrections are all rough guesses
    out_vec[0] = (float)(in_accel[0]) * ACCEL_SCALAR;
    out_vec[1] = (float)(in_accel[1]) * ACCEL_SCALAR;
    out_vec[2] = (float)(in_accel[2]) * ACCEL_SCALAR;

}

This solution worked for PhoenixHeadTracker so I am sharing it. I'm not sure what the original reason was for the reordering. This was my custom solution which I used.