Beispiel #1
0
Datei: pid.c Projekt: dan557/inav
/*
 * TURN ASSISTANT mode is an assisted mode to do a Yaw rotation on a ground plane, allowing one-stick turn in RATE more
 * and keeping ROLL and PITCH attitude though the turn.
 */
static void pidTurnAssistant(pidState_t *pidState)
{
    t_fp_vector targetRates;

    targetRates.V.X = 0.0f;
    targetRates.V.Y = 0.0f;
    targetRates.V.Z = pidState[YAW].rateTarget;

    imuTransformVectorEarthToBody(&targetRates);

    // Add in roll and pitch, replace yaw completery
    pidState[ROLL].rateTarget += targetRates.V.X;
    pidState[PITCH].rateTarget += targetRates.V.Y;
    pidState[YAW].rateTarget = targetRates.V.Z;
}
/**
 * Calculate next estimate using IMU and apply corrections from reference sensors (GPS, BARO etc)
 *  Function is called at main loop rate
 */
static void updateEstimatedTopic(uint32_t currentTime)
{
    t_fp_vector accelBiasCorr;
    float dt = US2S(currentTime - posEstimator.est.lastUpdateTime);
    posEstimator.est.lastUpdateTime = currentTime;

    /* If IMU is not ready we can't estimate anything */
    if (!isImuReady()) {
        posEstimator.est.eph = posControl.navConfig->inav.max_eph_epv + 0.001f;
        posEstimator.est.epv = posControl.navConfig->inav.max_eph_epv + 0.001f;
        return;
    }

    /* increase EPH/EPV on each iteration */
    if (posEstimator.est.eph <= posControl.navConfig->inav.max_eph_epv) {
        posEstimator.est.eph *= 1.0f + dt;
    }

    if (posEstimator.est.epv <= posControl.navConfig->inav.max_eph_epv) {
        posEstimator.est.epv *= 1.0f + dt;
    }

    /* Figure out if we have valid position data from our data sources */
    bool isGPSValid = sensors(SENSOR_GPS) && posControl.gpsOrigin.valid && ((currentTime - posEstimator.gps.lastUpdateTime) <= MS2US(INAV_GPS_TIMEOUT_MS));
    bool isBaroValid = sensors(SENSOR_BARO) && ((currentTime - posEstimator.baro.lastUpdateTime) <= MS2US(INAV_BARO_TIMEOUT_MS));
    bool isSonarValid = sensors(SENSOR_SONAR) && ((currentTime - posEstimator.sonar.lastUpdateTime) <= MS2US(INAV_SONAR_TIMEOUT_MS));

    /* Do some preparations to data */
    if (isBaroValid) {
        if (!ARMING_FLAG(ARMED)) {
            posEstimator.state.baroGroundAlt = posEstimator.est.pos.V.Z;
            posEstimator.state.isBaroGroundValid = true;
            posEstimator.state.baroGroundTimeout = currentTime + 250000;   // 0.25 sec
        }
        else {
            if (posEstimator.est.vel.V.Z > 15) {
                if (currentTime > posEstimator.state.baroGroundTimeout) {
                    posEstimator.state.isBaroGroundValid = false;
                }
            }
            else {
                posEstimator.state.baroGroundTimeout = currentTime + 250000;   // 0.25 sec
            }
        }
    }
    else {
        posEstimator.state.isBaroGroundValid = false;
    }

    /* We might be experiencing air cushion effect - use sonar or baro groung altitude to detect it */
    bool isAirCushionEffectDetected = ARMING_FLAG(ARMED) &&
                                        ((isSonarValid && posEstimator.sonar.alt < 20.0f && posEstimator.state.isBaroGroundValid) ||
                                         (isBaroValid && posEstimator.state.isBaroGroundValid && posEstimator.baro.alt < posEstimator.state.baroGroundAlt));

#if defined(NAV_GPS_GLITCH_DETECTION)
    //isGPSValid = isGPSValid && !posEstimator.gps.glitchDetected;
#endif

    /* Apply GPS altitude corrections only on fixed wing aircrafts */
    bool useGpsZ = STATE(FIXED_WING) && isGPSValid;

    /* Pre-calculate history index for GPS delay compensation */
    int gpsHistoryIndex = (posEstimator.history.index - 1) - constrain(((int)posControl.navConfig->inav.gps_delay_ms / (1000 / INAV_POSITION_PUBLISH_RATE_HZ)), 0, INAV_HISTORY_BUF_SIZE - 1);
    if (gpsHistoryIndex < 0) {
        gpsHistoryIndex += INAV_HISTORY_BUF_SIZE;
    }

    /* Correct accelerometer bias */
    if (posControl.navConfig->inav.w_acc_bias > 0) {
        accelBiasCorr.V.X = 0;
        accelBiasCorr.V.Y = 0;
        accelBiasCorr.V.Z = 0;

        /* accelerometer bias correction for GPS */
        if (isGPSValid) {
            accelBiasCorr.V.X -= (posEstimator.gps.pos.V.X - posEstimator.history.pos[gpsHistoryIndex].V.X) * sq(posControl.navConfig->inav.w_xy_gps_p);
            accelBiasCorr.V.X -= (posEstimator.gps.vel.V.X - posEstimator.history.vel[gpsHistoryIndex].V.X) * posControl.navConfig->inav.w_xy_gps_v;
            accelBiasCorr.V.Y -= (posEstimator.gps.pos.V.Y - posEstimator.history.pos[gpsHistoryIndex].V.Y) * sq(posControl.navConfig->inav.w_xy_gps_p);
            accelBiasCorr.V.Y -= (posEstimator.gps.vel.V.Y - posEstimator.history.vel[gpsHistoryIndex].V.Y) * posControl.navConfig->inav.w_xy_gps_v;

            if (useGpsZ) {
                accelBiasCorr.V.Z -= (posEstimator.gps.pos.V.Z - posEstimator.history.pos[gpsHistoryIndex].V.Z) * sq(posControl.navConfig->inav.w_z_gps_p);
                accelBiasCorr.V.Z -= (posEstimator.gps.vel.V.Z - posEstimator.history.vel[gpsHistoryIndex].V.Z) * posControl.navConfig->inav.w_z_gps_v;
            }
        }

        /* accelerometer bias correction for baro */
        if (isBaroValid && !isAirCushionEffectDetected) {
            accelBiasCorr.V.Z -= (posEstimator.baro.alt - posEstimator.est.pos.V.Z) * sq(posControl.navConfig->inav.w_z_baro_p);
        }

        /* transform error vector from NEU frame to body frame */
        imuTransformVectorEarthToBody(&accelBiasCorr);

        /* Correct accel bias */
        posEstimator.imu.accelBias.V.X += accelBiasCorr.V.X * posControl.navConfig->inav.w_acc_bias * dt;
        posEstimator.imu.accelBias.V.Y += accelBiasCorr.V.Y * posControl.navConfig->inav.w_acc_bias * dt;
        posEstimator.imu.accelBias.V.Z += accelBiasCorr.V.Z * posControl.navConfig->inav.w_acc_bias * dt;
    }

    /* Estimate Z-axis */
    if ((posEstimator.est.epv < posControl.navConfig->inav.max_eph_epv) || useGpsZ || isBaroValid) {
        /* Predict position/velocity based on acceleration */
        inavFilterPredict(Z, dt, posEstimator.imu.accelNEU.V.Z);

#if defined(BARO)
        if (isBaroValid) {
            float baroError = (isAirCushionEffectDetected ? posEstimator.state.baroGroundAlt : posEstimator.baro.alt) - posEstimator.est.pos.V.Z;

            /* Apply only baro correction, no sonar */
            inavFilterCorrectPos(Z, dt, baroError, posControl.navConfig->inav.w_z_baro_p);

            /* Adjust EPV */
            posEstimator.est.epv = MIN(posEstimator.est.epv, posEstimator.baro.epv);
        }
#endif

        /* Apply GPS correction to altitude */
        if (useGpsZ) {
            inavFilterCorrectPos(Z, dt, posEstimator.gps.pos.V.Z - posEstimator.history.pos[gpsHistoryIndex].V.Z, posControl.navConfig->inav.w_z_gps_p);
            inavFilterCorrectVel(Z, dt, posEstimator.gps.vel.V.Z - posEstimator.history.vel[gpsHistoryIndex].V.Z, posControl.navConfig->inav.w_z_gps_v);

            /* Adjust EPV */
            posEstimator.est.epv = MIN(posEstimator.est.epv, posEstimator.gps.epv);
        }
    }
    else {
        inavFilterCorrectVel(Z, dt, 0.0f - posEstimator.est.vel.V.Z, posControl.navConfig->inav.w_z_res_v);
    }

    /* Estimate XY-axis only if heading is valid (X-Y acceleration is North-East)*/
    if ((posEstimator.est.eph < posControl.navConfig->inav.max_eph_epv) || isGPSValid) {
        if (isImuHeadingValid()) {
            inavFilterPredict(X, dt, posEstimator.imu.accelNEU.V.X);
            inavFilterPredict(Y, dt, posEstimator.imu.accelNEU.V.Y);
        }

        /* Correct position from GPS - always if GPS is valid */
        if (isGPSValid) {
            inavFilterCorrectPos(X, dt, posEstimator.gps.pos.V.X - posEstimator.history.pos[gpsHistoryIndex].V.X, posControl.navConfig->inav.w_xy_gps_p);
            inavFilterCorrectPos(Y, dt, posEstimator.gps.pos.V.Y - posEstimator.history.pos[gpsHistoryIndex].V.Y, posControl.navConfig->inav.w_xy_gps_p);

            inavFilterCorrectVel(X, dt, posEstimator.gps.vel.V.X - posEstimator.history.vel[gpsHistoryIndex].V.X, posControl.navConfig->inav.w_xy_gps_v);
            inavFilterCorrectVel(Y, dt, posEstimator.gps.vel.V.Y - posEstimator.history.vel[gpsHistoryIndex].V.Y, posControl.navConfig->inav.w_xy_gps_v);

            /* Adjust EPH */
            posEstimator.est.eph = MIN(posEstimator.est.eph, posEstimator.gps.eph);
        }
    }
    else {
        inavFilterCorrectVel(X, dt, 0.0f - posEstimator.est.vel.V.X, posControl.navConfig->inav.w_xy_res_v);
        inavFilterCorrectVel(Y, dt, 0.0f - posEstimator.est.vel.V.Y, posControl.navConfig->inav.w_xy_res_v);
    }

    /* Surface offset */
#if defined(SONAR)
    if (isSonarValid) {
        posEstimator.est.surface = posEstimator.sonar.alt;
        posEstimator.est.surfaceVel = posEstimator.sonar.vel;
    }
    else {
        posEstimator.est.surface = -1;
        posEstimator.est.surfaceVel = 0;
    }
#else
    posEstimator.est.surface = -1;
    posEstimator.est.surfaceVel = 0;
#endif
}