Bosch Sensortec Community

    cancel
    Showing results for 
    Search instead for 
    Did you mean: 

    Heading Calculation

    Heading Calculation

    Error_Code
    New Poster

    Hi,

    Im using bno055 sensor for one of my project, where i need to find compensated heading. I have used sensor fusion in bno055 which gives very good result.Some how i have tried to make a filter algorithm (madgwick ) where i have observed heading with not compensated as in sensor fusion algorithm.im attaching my code below , could some one suggest any solution for the same.

    Thanks in advance. 

    float calculateHeading(struct mag_float_t *mag_xyz_data)
    {
    float mx = mag_xyz_data -> x;
    float my = mag_xyz_data -> y;
    float mz = mag_xyz_data -> z;
     
    // axis swapped in 9dof breakout
    float roll_rad = roll / 57.29578f; //in radians/s
    float pitch_rad = pitch / 57.29578f; //in radians/s
     
    float mx_compensated = (mx * cosf(pitch_rad)) + (mz * sinf(pitch_rad));
    float my_compensated = (mx * sinf(roll_rad) * sinf(pitch_rad)) + (my * cosf(roll_rad)) - (mz * sinf(roll_rad) * cosf(pitch_rad));
     
    float magX = mx_compensated;
    float magY = my_compensated;
     
    float heading = 0;
     
    if(magX == 0)
    {
    if(magY < 0)
    {
      heading = 90;
    }
    else if(magY >= 0)
    {
      heading = 0;
    }
    }
    else if(magX != 0)
    {
    heading = atan2(magY, magX);
    heading += DEC_ANGLE; // subtraction works not adding
    heading *= (180.0f / M_PIf);
    }
     
    if(heading > 360.0f)
    {
    heading -= 360.0f;
    }
    if(heading < 0.0f)
    {
    heading += 360.0f;
    }
    return heading;
    }
     
     
    void CK_IMU_MadwickUpdate2(struct accel_float_t *acc_xyz_data,struct mag_float_t *mag_xyz_data,struct gyro_float_t *gyro_xyz_data)
    {
    imuSyncCounter++;
     
    if(imuSyncCounter >= 0)
    {
     
    imuSyncCounter = 0;
     
    float recipNorm;
    float s0, s1, s2, s3;
    float qDot1, qDot2, qDot3, qDot4;
    float hx, hy;
    float _2q0mx, _2q0my, _2q0mz, _2q1mx, _2bx, _2bz, _4bx, _4bz, _2q0, _2q1, _2q2, _2q3, _2q0q2, _2q2q3, q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3;
     
    float gx = gyro_xyz_data -> x;
    float gy = gyro_xyz_data -> y;
    float gz = gyro_xyz_data -> z;
     
    float ax = acc_xyz_data -> x;
    float ay = acc_xyz_data -> y;
    float az = acc_xyz_data -> z;
     
    float mx = mag_xyz_data -> x;
    float my = mag_xyz_data -> y;
    float mz = mag_xyz_data -> z;
     
    // Convert gyroscope degrees/sec to radians/sec
    gx *= 0.0174533f;
    gy *= 0.0174533f;
    gz *= 0.0174533f;
     
    // Rate of change of quaternion from gyroscope
    qDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz);
    qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy);
    qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx);
    qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx);
     
    // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
    if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f)))
    {
     
    // Normalise accelerometer measurement
    recipNorm = CK_MATH_invSqrt(ax * ax + ay * ay + az * az);
    ax *= recipNorm;
    ay *= recipNorm;
    az *= recipNorm;
     
    // Normalise magnetometer measurement
    recipNorm = CK_MATH_invSqrt(mx * mx + my * my + mz * mz);
    mx *= recipNorm;
    my *= recipNorm;
    mz *= recipNorm;
     
    // Auxiliary variables to avoid repeated arithmetic
    _2q0mx = 2.0f * q0 * mx;
    _2q0my = 2.0f * q0 * my;
    _2q0mz = 2.0f * q0 * mz;
    _2q1mx = 2.0f * q1 * mx;
    _2q0 = 2.0f * q0;
    _2q1 = 2.0f * q1;
    _2q2 = 2.0f * q2;
    _2q3 = 2.0f * q3;
    _2q0q2 = 2.0f * q0 * q2;
    _2q2q3 = 2.0f * q2 * q3;
    q0q0 = q0 * q0;
    q0q1 = q0 * q1;
    q0q2 = q0 * q2;
    q0q3 = q0 * q3;
    q1q1 = q1 * q1;
    q1q2 = q1 * q2;
    q1q3 = q1 * q3;
    q2q2 = q2 * q2;
    q2q3 = q2 * q3;
    q3q3 = q3 * q3;
     
    // Reference direction of Earth's magnetic field
    hx = mx * q0q0 - _2q0my * q3 + _2q0mz * q2 + mx * q1q1 + _2q1 * my * q2 + _2q1 * mz * q3 - mx * q2q2 - mx * q3q3;
    hy = _2q0mx * q3 + my * q0q0 - _2q0mz * q1 + _2q1mx * q2 - my * q1q1 + my * q2q2 + _2q2 * mz * q3 - my * q3q3;
    _2bx = sqrtf(hx * hx + hy * hy);
    _2bz = -_2q0mx * q2 + _2q0my * q1 + mz * q0q0 + _2q1mx * q3 - mz * q1q1 + _2q2 * my * q3 - mz * q2q2 + mz * q3q3;
    _4bx = 2.0f * _2bx;
    _4bz = 2.0f * _2bz;
     
    // Gradient decent algorithm corrective step
    s0 = -_2q2 * (2.0f * q1q3 - _2q0q2 - ax) + _2q1 * (2.0f * q0q1 + _2q2q3 - ay) - _2bz * q2 * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (-_2bx * q3 + _2bz * q1) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + _2bx * q2 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);
    s1 = _2q3 * (2.0f * q1q3 - _2q0q2 - ax) + _2q0 * (2.0f * q0q1 + _2q2q3 - ay) - 4.0f * q1 * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az) + _2bz * q3 * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (_2bx * q2 + _2bz * q0) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + (_2bx * q3 - _4bz * q1) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);
    s2 = -_2q0 * (2.0f * q1q3 - _2q0q2 - ax) + _2q3 * (2.0f * q0q1 + _2q2q3 - ay) - 4.0f * q2 * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az) + (-_4bx * q2 - _2bz * q0) * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (_2bx * q1 + _2bz * q3) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + (_2bx * q0 - _4bz * q2) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);
    s3 = _2q1 * (2.0f * q1q3 - _2q0q2 - ax) + _2q2 * (2.0f * q0q1 + _2q2q3 - ay) + (-_4bx * q3 + _2bz * q1) * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (-_2bx * q0 + _2bz * q2) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + _2bx * q1 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);
    recipNorm = CK_MATH_invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude
    s0 *= recipNorm;
    s1 *= recipNorm;
    s2 *= recipNorm;
    s3 *= recipNorm;
     
    // Apply feedback step
    qDot1 -= beta * s0;
    qDot2 -= beta * s1;
    qDot3 -= beta * s2;
    qDot4 -= beta * s3;
    }
     
    // Integrate rate of change of quaternion to yield quaternion
    q0 += qDot1 * imu_dT;
    q1 += qDot2 * imu_dT;
    q2 += qDot3 * imu_dT;
    q3 += qDot4 * imu_dT;
     
    // Normalise quaternion
    recipNorm = CK_MATH_invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
    q0 *= recipNorm;
    q1 *= recipNorm;
    q2 *= recipNorm;
    q3 *= recipNorm;
     
    CK_IMU_ComputeEulerAngles();
    }
    }
    5 REPLIES 5

    BSTRobin
    Community Moderator
    Community Moderator

    Hi Error_Code,

    Do you mean you would like to compensate heading value which output by the BNO055 fusion algorithm?

    BNO055 is not recommended for use in new designs. You can use BHI360 + BMM350 in new design as their combination has better performance.

    Thank you for your response,

    I didn't mean to compensate bno055 heading value. I want to know how can i implement this compensated heading just like bno055 provides.

    As you suggested , if i take  BHI360 + BMM350 for estimate  compensated heading.How can i implement it?Is there any libraries or any reference documents available for the same?If so could you please provide.

    Which filter algorithm will be good for estimate compensated headinng?

     

    BSTRobin
    Community Moderator
    Community Moderator

    Hi Error_Code,

    We have not publicly disclosed the implementation of the fusion algorithm, and there are no plans to make it public.

    So how can i implement the compensated  algorithm using these two sensors?

    Icon--AD-black-48x48Icon--address-consumer-data-black-48x48Icon--appointment-black-48x48Icon--back-left-black-48x48Icon--calendar-black-48x48Icon--center-alignedIcon--Checkbox-checkIcon--clock-black-48x48Icon--close-black-48x48Icon--compare-black-48x48Icon--confirmation-black-48x48Icon--dealer-details-black-48x48Icon--delete-black-48x48Icon--delivery-black-48x48Icon--down-black-48x48Icon--download-black-48x48Ic-OverlayAlertIcon--externallink-black-48x48Icon-Filledforward-right_adjustedIcon--grid-view-black-48x48IC_gd_Check-Circle170821_Icons_Community170823_Bosch_Icons170823_Bosch_Icons170821_Icons_CommunityIC-logout170821_Icons_Community170825_Bosch_Icons170821_Icons_CommunityIC-shopping-cart2170821_Icons_CommunityIC-upIC_UserIcon--imageIcon--info-i-black-48x48Icon--left-alignedIcon--Less-minimize-black-48x48Icon-FilledIcon--List-Check-grennIcon--List-Check-blackIcon--List-Cross-blackIcon--list-view-mobile-black-48x48Icon--list-view-black-48x48Icon--More-Maximize-black-48x48Icon--my-product-black-48x48Icon--newsletter-black-48x48Icon--payment-black-48x48Icon--print-black-48x48Icon--promotion-black-48x48Icon--registration-black-48x48Icon--Reset-black-48x48Icon--right-alignedshare-circle1Icon--share-black-48x48Icon--shopping-bag-black-48x48Icon-shopping-cartIcon--start-play-black-48x48Icon--store-locator-black-48x48Ic-OverlayAlertIcon--summary-black-48x48tumblrIcon-FilledvineIc-OverlayAlertwhishlist