void VtolLandFSM::run_at_descentrate(uint8_t flTimeout)
{
    VelocityStateData velocityState;

    VelocityStateGet(&velocityState);

    StabilizationDesiredData stabDesired;
    StabilizationDesiredGet(&stabDesired);

    mLandData->sum1 += velocityState.Down;
    mLandData->sum2 += stabDesired.Thrust;
    mLandData->observationCount++;
    if (flTimeout) {
        mLandData->fsmLandStatus.averageDescentRate   = boundf((mLandData->sum1 / (float)(mLandData->observationCount)), 0.5f * MIN_LANDRATE, 1.5f * MAX_LANDRATE);
        mLandData->fsmLandStatus.averageDescentThrust = boundf((mLandData->sum2 / (float)(mLandData->observationCount)), vtolPathFollowerSettings->ThrustLimits.Min, vtolPathFollowerSettings->ThrustLimits.Max);

        // We need to calculate a neutral limit to use later to constrain upper thrust range during states where we are close to the ground
        // As our battery gets flat, ThrustLimits.Neutral needs to constrain us too much and we get too fast a descent rate. We can
        // detect this by the fact that the descent rate will exceed the target and the required thrust will exceed the neutral value
        mLandData->fsmLandStatus.calculatedNeutralThrust = mLandData->fsmLandStatus.averageDescentRate / mLandData->fsmLandStatus.targetDescentRate * mLandData->fsmLandStatus.averageDescentThrust;
        mLandData->fsmLandStatus.calculatedNeutralThrust = boundf(mLandData->fsmLandStatus.calculatedNeutralThrust, vtolPathFollowerSettings->ThrustLimits.Neutral, vtolPathFollowerSettings->ThrustLimits.Max);


        setState(LAND_STATE_WTG_FOR_GROUNDEFFECT, STATUSVTOLLAND_STATEEXITREASON_DESCENTRATEOK);
    }
}
Exemplo n.º 2
0
static bool normalizeDeadband(float controlVector[4])
{
    bool moving = false;

    // roll, pitch, yaw between -1 and +1
    // thrust between 0 and 1 mapped to -1 to +1
    controlVector[3] = (2.0f * controlVector[3]) - 1.0f;
    int t;

    for (t = 0; t < 4; t++) {
        if (controlVector[t] < -DEADBAND) {
            moving = true;
            controlVector[t] += DEADBAND;
        } else if (controlVector[t] > DEADBAND) {
            moving = true;
            controlVector[t] -= DEADBAND;
        } else {
            controlVector[t] = 0.0f;
        }
        // deadband has been cut out, scale value back to [-1,+1]
        controlVector[t] *= (1.0f / (1.0f - DEADBAND));
        controlVector[t]  = boundf(controlVector[t], -1.0f, 1.0f);
    }

    return moving;
}
Exemplo n.º 3
0
static float applyExpo(float value, float expo)
{
    // note: fastPow makes a small error, therefore result needs to be bound
    float exp = boundf(fastPow(1.00695f, expo), 0.5f, 2.0f);

    // magic number scales expo
    // so that
    // expo=100 yields value**10
    // expo=0 yields value**1
    // expo=-100 yields value**(1/10)
    // (pow(2.0,1/100)~=1.00695)
    if (value > 0.0f) {
        return boundf(fastPow(value, exp), 0.0f, 1.0f);
    } else if (value < -0.0f) {
        return boundf(-fastPow(-value, exp), -1.0f, 0.0f);
    } else {
        return 0.0f;
    }
}
float VtolLandFSM::BoundVelocityDown(float velocity_down)
{
    velocity_down = boundf(velocity_down, MIN_LANDRATE, MAX_LANDRATE);
    if (mLandData->flLowAltitude) {
        velocity_down *= LOW_ALT_DESCENT_REDUCTION_FACTOR;
    }
    mLandData->fsmLandStatus.targetDescentRate = velocity_down;

    if (mLandData->flAltitudeHold) {
        return 0.0f;
    } else {
        return velocity_down;
    }
}
Exemplo n.º 5
0
/**
 * @brief Compute progress along path and deviation from it
 * @param[in] path PathDesired
 * @param[in] cur_point Current location
 * @param[out] status Structure containing progress along path and deviation
 * @param[in] mode3D set true to include altitude in distance and progress calculation
 */
static void path_vector(PathDesiredData *path, float *cur_point, struct path_status *status, bool mode3D)
{
    float diff[3];
    float dist_path;
    float dot;
    float velocity;
    float track_point[3];

    // Distance to go
    status->path_vector[0] = path->End.North - path->Start.North;
    status->path_vector[1] = path->End.East - path->Start.East;
    status->path_vector[2] = mode3D ? path->End.Down - path->Start.Down : 0.0f;

    // Current progress location relative to start
    diff[0]   = cur_point[0] - path->Start.North;
    diff[1]   = cur_point[1] - path->Start.East;
    diff[2]   = mode3D ? cur_point[2] - path->Start.Down : 0.0f;

    dot       = status->path_vector[0] * diff[0] + status->path_vector[1] * diff[1] + status->path_vector[2] * diff[2];
    dist_path = vector_lengthf(status->path_vector, 3);

    if (dist_path > 1e-6f) {
        // Compute direction to travel & progress
        status->fractional_progress = dot / (dist_path * dist_path);
    } else {
        // Fly towards the endpoint to prevent flying away,
        // but assume progress=1 either way.
        path_endpoint(path, cur_point, status, mode3D);
        status->fractional_progress = 1;
        return;
    }
    // Compute point on track that is closest to our current position.
    track_point[0] = status->fractional_progress * status->path_vector[0] + path->Start.North;
    track_point[1] = status->fractional_progress * status->path_vector[1] + path->Start.East;
    track_point[2] = status->fractional_progress * status->path_vector[2] + path->Start.Down;

    status->correction_vector[0] = track_point[0] - cur_point[0];
    status->correction_vector[1] = track_point[1] - cur_point[1];
    status->correction_vector[2] = track_point[2] - cur_point[2];

    status->error = vector_lengthf(status->correction_vector, 3);

    // correct movement vector to current velocity
    velocity = path->StartingVelocity + boundf(status->fractional_progress, 0.0f, 1.0f) * (path->EndingVelocity - path->StartingVelocity);
    status->path_vector[0] = velocity * status->path_vector[0] / dist_path;
    status->path_vector[1] = velocity * status->path_vector[1] / dist_path;
    status->path_vector[2] = velocity * status->path_vector[2] / dist_path;
}
Exemplo n.º 6
0
/**
 * Compute desired attitude for vtols - emergency fallback
 */
void VtolFlyController::UpdateDesiredAttitudeEmergencyFallback()
{
    VelocityDesiredData velocityDesired;
    VelocityStateData velocityState;
    StabilizationDesiredData stabDesired;

    float courseError;
    float courseCommand;

    VelocityStateGet(&velocityState);
    VelocityDesiredGet(&velocityDesired);

    ManualControlCommandData manualControlData;
    ManualControlCommandGet(&manualControlData);

    courseError = RAD2DEG(atan2f(velocityDesired.East, velocityDesired.North) - atan2f(velocityState.East, velocityState.North));

    if (courseError < -180.0f) {
        courseError += 360.0f;
    }
    if (courseError > 180.0f) {
        courseError -= 360.0f;
    }


    courseCommand   = (courseError * vtolPathFollowerSettings->EmergencyFallbackYawRate.kP);
    stabDesired.Yaw = boundf(courseCommand, -vtolPathFollowerSettings->EmergencyFallbackYawRate.Max, vtolPathFollowerSettings->EmergencyFallbackYawRate.Max);

    controlDown.UpdateVelocitySetpoint(velocityDesired.Down);
    controlDown.UpdateVelocityState(velocityState.Down);
    stabDesired.Thrust = controlDown.GetDownCommand();


    stabDesired.Roll   = vtolPathFollowerSettings->EmergencyFallbackAttitude.Roll;
    stabDesired.Pitch  = vtolPathFollowerSettings->EmergencyFallbackAttitude.Pitch;

    if (vtolPathFollowerSettings->ThrustControl == VTOLPATHFOLLOWERSETTINGS_THRUSTCONTROL_MANUAL) {
        stabDesired.Thrust = manualControlData.Thrust;
    }

    stabDesired.StabilizationMode.Roll   = STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE;
    stabDesired.StabilizationMode.Pitch  = STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE;
    stabDesired.StabilizationMode.Yaw    = STABILIZATIONDESIRED_STABILIZATIONMODE_RATE;
    stabDesired.StabilizationMode.Thrust = STABILIZATIONDESIRED_STABILIZATIONMODE_CRUISECONTROL;
    StabilizationDesiredSet(&stabDesired);
}
Exemplo n.º 7
0
/**
 * Update the PID computation
 * @param[in] pid The PID struture which stores temporary information
 * @param[in] err The error term
 * @param[in] dT  The time step
 * @returns Output the computed controller value
 */
float pid_apply(struct pid *pid, const float err, float dT)
{
    // Scale up accumulator by 1000 while computing to avoid losing precision
    pid->iAccumulator += err * (pid->i * dT * 1000.0f);
    pid->iAccumulator  = boundf(pid->iAccumulator, pid->iLim * -1000.0f, pid->iLim * 1000.0f);

    // Calculate DT1 term
    float diff  = (err - pid->lastErr);
    float dterm = 0;
    pid->lastErr = err;
    if (pid->d > 0.0f && dT > 0.0f) {
        dterm = pid->lastDer + dT / (dT + deriv_tau) * ((diff * pid->d / dT) - pid->lastDer);
        pid->lastDer = dterm; // ^ set constant to 1/(2*pi*f_cutoff)
    } // 7.9577e-3  means 20 Hz f_cutoff

    return (err * pid->p) + pid->iAccumulator / 1000.0f + dterm;
}
Exemplo n.º 8
0
/**
 * Update the PID computation with setpoint weighting on the derivative
 * @param[in] pid The PID struture which stores temporary information
 * @param[in] factor A dynamic factor to scale pid's by, to compensate nonlinearities
 * @param[in] setpoint The setpoint to use
 * @param[in] measured The measured value of output
 * @param[in] dT  The time step
 * @returns Output the computed controller value
 *
 * This version of apply uses setpoint weighting for the derivative component so the gain
 * on the gyro derivative can be different than the gain on the setpoint derivative
 */
float pid_apply_setpoint(struct pid *pid, const pid_scaler *scaler, const float setpoint, const float measured, float dT)
{
    float err = setpoint - measured;

    // Scale up accumulator by 1000 while computing to avoid losing precision
    pid->iAccumulator += err * (scaler->i * pid->i * dT * 1000.0f);
    pid->iAccumulator  = boundf(pid->iAccumulator, pid->iLim * -1000.0f, pid->iLim * 1000.0f);

    // Calculate DT1 term,
    float dterm = 0;
    float diff  = ((deriv_gamma * setpoint - measured) - pid->lastErr);
    pid->lastErr = (deriv_gamma * setpoint - measured);
    if (pid->d > 0.0f && dT > 0.0f) {
        // low pass filter derivative term. below formula is the same as
        // dterm = (1-alpha)*pid->lastDer + alpha * (...)/dT
        // with alpha = dT/(deriv_tau+dT)
        dterm = pid->lastDer + dT / (dT + deriv_tau) * ((scaler->d * diff * pid->d / dT) - pid->lastDer);
        pid->lastDer = dterm;
    }

    return (err * scaler->p * pid->p) + pid->iAccumulator / 1000.0f + dterm;
}
Exemplo n.º 9
0
int8_t VtolFlyController::UpdateStabilizationDesired(bool yaw_attitude, float yaw_direction)
{
    uint8_t result = 1;
    StabilizationDesiredData stabDesired;
    AttitudeStateData attitudeState;
    StabilizationBankData stabSettings;
    float northCommand;
    float eastCommand;

    StabilizationDesiredGet(&stabDesired);
    AttitudeStateGet(&attitudeState);
    StabilizationBankGet(&stabSettings);

    controlNE.GetNECommand(&northCommand, &eastCommand);

    float angle_radians = DEG2RAD(attitudeState.Yaw);
    float cos_angle     = cosf(angle_radians);
    float sine_angle    = sinf(angle_radians);
    float maxPitch = vtolPathFollowerSettings->MaxRollPitch;
    stabDesired.StabilizationMode.Pitch = STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE;
    stabDesired.Pitch = boundf(-northCommand * cos_angle - eastCommand * sine_angle, -maxPitch, maxPitch); // this should be in the controller
    stabDesired.StabilizationMode.Roll  = STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE;
    stabDesired.Roll = boundf(-northCommand * sine_angle + eastCommand * cos_angle, -maxPitch, maxPitch);

    ManualControlCommandData manualControl;
    ManualControlCommandGet(&manualControl);

    // TODO The below need to be rewritten because the PID implementation has changed.
#if 0
    // DEBUG HACK: allow user to skew compass on purpose to see if emergency failsafe kicks in
    if (vtolPathFollowerSettings->FlyawayEmergencyFallback == VTOLPATHFOLLOWERSETTINGS_FLYAWAYEMERGENCYFALLBACK_DEBUGTEST) {
        attitudeState.Yaw += 120.0f;
        if (attitudeState.Yaw > 180.0f) {
            attitudeState.Yaw -= 360.0f;
        }
    }


    if ( // emergency flyaway detection
        ( // integral already at its limit
            vtolPathFollowerSettings.HorizontalVelPID.ILimit - fabsf(global.PIDvel[0].iAccumulator) < 1e-6f ||
            vtolPathFollowerSettings.HorizontalVelPID.ILimit - fabsf(global.PIDvel[1].iAccumulator) < 1e-6f
        ) &&
        // angle between desired and actual velocity >90 degrees (by dot product)
        (velocityDesired.North * velocityState.North + velocityDesired.East * velocityState.East < 0.0f) &&
        // quad is moving at significant speed (during flyaway it would keep speeding up)
        squaref(velocityState.North) + squaref(velocityState.East) > 1.0f
        ) {
        vtolEmergencyFallback += dT;
        if (vtolEmergencyFallback >= vtolPathFollowerSettings->FlyawayEmergencyFallbackTriggerTime) {
            // after emergency timeout, trigger alarm - everything else is handled by callers
            // (switch to emergency algorithm, switch to emergency waypoint in pathplanner, alarms, ...)
            result = 0;
        }
    } else {
        vtolEmergencyFallback = 0.0f;
    }
#endif // if 0

    if (yaw_attitude) {
        stabDesired.StabilizationMode.Yaw = STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE;
        stabDesired.Yaw = yaw_direction;
    } else {
        stabDesired.StabilizationMode.Yaw = STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK;
        stabDesired.Yaw = stabSettings.MaximumRate.Yaw * manualControl.Yaw;
    }

    // default thrust mode to cruise control
    stabDesired.StabilizationMode.Thrust = STABILIZATIONDESIRED_STABILIZATIONMODE_CRUISECONTROL;

    if (mManualThrust) {
        stabDesired.Thrust = manualControl.Thrust;
    } else {
        stabDesired.Thrust = controlDown.GetDownCommand();
    }

    StabilizationDesiredSet(&stabDesired);

    return result;
}
Exemplo n.º 10
0
/**
 * @brief execute autocruise
 */
void plan_run_AutoCruise()
{
    PositionStateData positionState;

    PositionStateGet(&positionState);
    PathDesiredData pathDesired;
    PathDesiredGet(&pathDesired);
    FlightModeSettingsPositionHoldOffsetData offset;
    FlightModeSettingsPositionHoldOffsetGet(&offset);

    float controlVector[4];
    ManualControlCommandRollGet(&controlVector[0]);
    ManualControlCommandPitchGet(&controlVector[1]);
    ManualControlCommandYawGet(&controlVector[2]);
    controlVector[3] = 0.5f; // dummy, thrust is normalized separately
    normalizeDeadband(controlVector); // return value ignored
    ManualControlCommandThrustGet(&controlVector[3]); // no deadband as we are using thrust for velocity
    controlVector[3] = boundf(controlVector[3], 1e-6f, 1.0f); // bound to above zero, to prevent loss of vector direction

    // normalize old desired movement vector
    float vector[3] = { pathDesired.End.North - hold_position[0],
                        pathDesired.End.East - hold_position[1],
                        pathDesired.End.Down - hold_position[2] };
    float length    = sqrtf(vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2]);
    if (length < 1e-9f) {
        length = 1.0f; // should not happen since initialized properly in setup()
    }
    vector[0] /= length;
    vector[1] /= length;
    vector[2] /= length;

    // start position is advanced according to actual movement - in the direction of desired vector only
    // projection using scalar product
    float kp = (positionState.North - hold_position[0]) * vector[0]
               + (positionState.East - hold_position[1]) * vector[1]
               + (positionState.Down - hold_position[2]) * vector[2];
    if (kp > 0.0f) {
        hold_position[0] += kp * vector[0];
        hold_position[1] += kp * vector[1];
        hold_position[2] += kp * vector[2];
    }

    // new angle is equal to old angle plus offset depending on yaw input and time
    // (controlVector is normalized with a deadband, change is zero within deadband)
    float angle = RAD2DEG(atan2f(vector[1], vector[0]));
    float dT    = PIOS_DELTATIME_GetAverageSeconds(&actimeval);
    angle    += 10.0f * controlVector[2] * dT; // TODO magic value could eventually end up in a to be created settings

    // resulting movement vector is scaled by velocity demand in controlvector[3] [0.0-1.0]
    vector[0] = cosf(DEG2RAD(angle)) * offset.Horizontal * controlVector[3];
    vector[1] = sinf(DEG2RAD(angle)) * offset.Horizontal * controlVector[3];
    vector[2] = -controlVector[1] * offset.Vertical * controlVector[3];

    pathDesired.End.North   = hold_position[0] + vector[0];
    pathDesired.End.East    = hold_position[1] + vector[1];
    pathDesired.End.Down    = hold_position[2] + vector[2];
    // start position has the same offset as in position hold
    pathDesired.Start.North = pathDesired.End.North + offset.Horizontal; // in FlyEndPoint the direction of this vector does not matter
    pathDesired.Start.East  = pathDesired.End.East;
    pathDesired.Start.Down  = pathDesired.End.Down;
    PathDesiredSet(&pathDesired);
}
    StabilizationBankData stabSettings;
    float northCommand;
    float eastCommand;

    StabilizationDesiredGet(&stabDesired);
    AttitudeStateGet(&attitudeState);
    StabilizationBankGet(&stabSettings);

    controlNE.GetNECommand(&northCommand, &eastCommand);

    float angle_radians = DEG2RAD(attitudeState.Yaw);
    float cos_angle     = cosf(angle_radians);
    float sine_angle    = sinf(angle_radians);
    float maxPitch = vtolPathFollowerSettings->VelocityRoamMaxRollPitch;
    stabDesired.StabilizationMode.Pitch = STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE;
    stabDesired.Pitch = boundf(-northCommand * cos_angle - eastCommand * sine_angle, -maxPitch, maxPitch);
    stabDesired.StabilizationMode.Roll  = STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE;
    stabDesired.Roll = boundf(-northCommand * sine_angle + eastCommand * cos_angle, -maxPitch, maxPitch);

    ManualControlCommandData manualControl;
    ManualControlCommandGet(&manualControl);

    stabDesired.StabilizationMode.Yaw = STABILIZATIONDESIRED_STABILIZATIONMODE_RATE;
    stabDesired.Yaw = stabSettings.MaximumRate.Yaw * manualControl.Yaw;

    // default thrust mode to altvario
    stabDesired.StabilizationMode.Thrust = STABILIZATIONDESIRED_STABILIZATIONMODE_ALTITUDEVARIO;
    stabDesired.Thrust = manualControl.Thrust;

    StabilizationDesiredSet(&stabDesired);
/**
 * Compute desired attitude from the desired velocity for fixed wing craft
 */
uint8_t FixedWingFlyController::updateFixedDesiredAttitude()
{
    uint8_t result = 1;

    const float dT = fixedWingSettings->UpdatePeriod / 1000.0f;

    VelocityDesiredData velocityDesired;
    VelocityStateData velocityState;
    StabilizationDesiredData stabDesired;
    AttitudeStateData attitudeState;
    FixedWingPathFollowerStatusData fixedWingPathFollowerStatus;
    AirspeedStateData airspeedState;
    SystemSettingsData systemSettings;

    float groundspeedProjection;
    float indicatedAirspeedState;
    float indicatedAirspeedDesired;
    float airspeedError;

    float pitchCommand;

    float descentspeedDesired;
    float descentspeedError;
    float powerCommand;

    float airspeedVector[2];
    float fluidMovement[2];
    float courseComponent[2];
    float courseError;
    float courseCommand;

    FixedWingPathFollowerStatusGet(&fixedWingPathFollowerStatus);

    VelocityStateGet(&velocityState);
    StabilizationDesiredGet(&stabDesired);
    VelocityDesiredGet(&velocityDesired);
    AttitudeStateGet(&attitudeState);
    AirspeedStateGet(&airspeedState);
    SystemSettingsGet(&systemSettings);

    /**
     * Compute speed error and course
     */
    // missing sensors for airspeed-direction we have to assume within
    // reasonable error that measured airspeed is actually the airspeed
    // component in forward pointing direction
    // airspeedVector is normalized
    airspeedVector[0]     = cos_lookup_deg(attitudeState.Yaw);
    airspeedVector[1]     = sin_lookup_deg(attitudeState.Yaw);

    // current ground speed projected in forward direction
    groundspeedProjection = velocityState.North * airspeedVector[0] + velocityState.East * airspeedVector[1];

    // note that airspeedStateBias is ( calibratedAirspeed - groundspeedProjection ) at the time of measurement,
    // but thanks to accelerometers,  groundspeedProjection reacts faster to changes in direction
    // than airspeed and gps sensors alone
    indicatedAirspeedState = groundspeedProjection + indicatedAirspeedStateBias;

    // fluidMovement is a vector describing the aproximate movement vector of
    // the surrounding fluid in 2d space (aka wind vector)
    fluidMovement[0] = velocityState.North - (indicatedAirspeedState * airspeedVector[0]);
    fluidMovement[1] = velocityState.East - (indicatedAirspeedState * airspeedVector[1]);

    // calculate the movement vector we need to fly to reach velocityDesired -
    // taking fluidMovement into account
    courseComponent[0] = velocityDesired.North - fluidMovement[0];
    courseComponent[1] = velocityDesired.East - fluidMovement[1];

    indicatedAirspeedDesired = boundf(sqrtf(courseComponent[0] * courseComponent[0] + courseComponent[1] * courseComponent[1]),
                                      fixedWingSettings->HorizontalVelMin,
                                      fixedWingSettings->HorizontalVelMax);

    // if we could fly at arbitrary speeds, we'd just have to move towards the
    // courseComponent vector as previously calculated and we'd be fine
    // unfortunately however we are bound by min and max air speed limits, so
    // we need to recalculate the correct course to meet at least the
    // velocityDesired vector direction at our current speed
    // this overwrites courseComponent
    bool valid = correctCourse(courseComponent, (float *)&velocityDesired.North, fluidMovement, indicatedAirspeedDesired);

    // Error condition: wind speed too high, we can't go where we want anymore
    fixedWingPathFollowerStatus.Errors.Wind = 0;
    if ((!valid) &&
        fixedWingSettings->Safetymargins.Wind > 0.5f) { // alarm switched on
        fixedWingPathFollowerStatus.Errors.Wind = 1;
        result = 0;
    }

    // Airspeed error
    airspeedError = indicatedAirspeedDesired - indicatedAirspeedState;

    // Vertical speed error
    descentspeedDesired = boundf(
        velocityDesired.Down,
        -fixedWingSettings->VerticalVelMax,
        fixedWingSettings->VerticalVelMax);
    descentspeedError = descentspeedDesired - velocityState.Down;

    // Error condition: plane too slow or too fast
    fixedWingPathFollowerStatus.Errors.Highspeed = 0;
    fixedWingPathFollowerStatus.Errors.Lowspeed  = 0;
    if (indicatedAirspeedState > systemSettings.AirSpeedMax * fixedWingSettings->Safetymargins.Overspeed) {
        fixedWingPathFollowerStatus.Errors.Overspeed = 1;
        result = 0;
    }
    if (indicatedAirspeedState > fixedWingSettings->HorizontalVelMax * fixedWingSettings->Safetymargins.Highspeed) {
        fixedWingPathFollowerStatus.Errors.Highspeed = 1;
        result = 0;
    }
    if (indicatedAirspeedState < fixedWingSettings->HorizontalVelMin * fixedWingSettings->Safetymargins.Lowspeed) {
        fixedWingPathFollowerStatus.Errors.Lowspeed = 1;
        result = 0;
    }
    if (indicatedAirspeedState < systemSettings.AirSpeedMin * fixedWingSettings->Safetymargins.Stallspeed) {
        fixedWingPathFollowerStatus.Errors.Stallspeed = 1;
        result = 0;
    }

    /**
     * Compute desired thrust command
     */

    // Compute the cross feed from vertical speed to pitch, with saturation
    float speedErrorToPowerCommandComponent = boundf(
        (airspeedError / fixedWingSettings->HorizontalVelMin) * fixedWingSettings->AirspeedToPowerCrossFeed.Kp,
        -fixedWingSettings->AirspeedToPowerCrossFeed.Max,
        fixedWingSettings->AirspeedToPowerCrossFeed.Max
        );

    // Compute final thrust response
    powerCommand = pid_apply(&PIDpower, -descentspeedError, dT) +
                   speedErrorToPowerCommandComponent;

    // Output internal state to telemetry
    fixedWingPathFollowerStatus.Error.Power    = descentspeedError;
    fixedWingPathFollowerStatus.ErrorInt.Power = PIDpower.iAccumulator;
    fixedWingPathFollowerStatus.Command.Power  = powerCommand;

    // set thrust
    stabDesired.Thrust = boundf(fixedWingSettings->ThrustLimit.Neutral + powerCommand,
                                fixedWingSettings->ThrustLimit.Min,
                                fixedWingSettings->ThrustLimit.Max);

    // Error condition: plane cannot hold altitude at current speed.
    fixedWingPathFollowerStatus.Errors.Lowpower = 0;
    if (fixedWingSettings->ThrustLimit.Neutral + powerCommand >= fixedWingSettings->ThrustLimit.Max && // thrust at maximum
        velocityState.Down > 0.0f && // we ARE going down
        descentspeedDesired < 0.0f && // we WANT to go up
        airspeedError > 0.0f && // we are too slow already
        fixedWingSettings->Safetymargins.Lowpower > 0.5f) { // alarm switched on
        fixedWingPathFollowerStatus.Errors.Lowpower = 1;
        result = 0;
    }
    // Error condition: plane keeps climbing despite minimum thrust (opposite of above)
    fixedWingPathFollowerStatus.Errors.Highpower = 0;
    if (fixedWingSettings->ThrustLimit.Neutral + powerCommand <= fixedWingSettings->ThrustLimit.Min && // thrust at minimum
        velocityState.Down < 0.0f && // we ARE going up
        descentspeedDesired > 0.0f && // we WANT to go down
        airspeedError < 0.0f && // we are too fast already
        fixedWingSettings->Safetymargins.Highpower > 0.5f) { // alarm switched on
        fixedWingPathFollowerStatus.Errors.Highpower = 1;
        result = 0;
    }

    /**
     * Compute desired pitch command
     */
    // Compute the cross feed from vertical speed to pitch, with saturation
    float verticalSpeedToPitchCommandComponent = boundf(-descentspeedError * fixedWingSettings->VerticalToPitchCrossFeed.Kp,
                                                        -fixedWingSettings->VerticalToPitchCrossFeed.Max,
                                                        fixedWingSettings->VerticalToPitchCrossFeed.Max
                                                        );

    // Compute the pitch command as err*Kp + errInt*Ki + X_feed.
    pitchCommand = -pid_apply(&PIDspeed, airspeedError, dT) + verticalSpeedToPitchCommandComponent;

    fixedWingPathFollowerStatus.Error.Speed    = airspeedError;
    fixedWingPathFollowerStatus.ErrorInt.Speed = PIDspeed.iAccumulator;
    fixedWingPathFollowerStatus.Command.Speed  = pitchCommand;

    stabDesired.Pitch = boundf(fixedWingSettings->PitchLimit.Neutral + pitchCommand,
                               fixedWingSettings->PitchLimit.Min,
                               fixedWingSettings->PitchLimit.Max);

    // Error condition: high speed dive
    fixedWingPathFollowerStatus.Errors.Pitchcontrol = 0;
    if (fixedWingSettings->PitchLimit.Neutral + pitchCommand >= fixedWingSettings->PitchLimit.Max && // pitch demand is full up
        velocityState.Down > 0.0f && // we ARE going down
        descentspeedDesired < 0.0f && // we WANT to go up
        airspeedError < 0.0f && // we are too fast already
        fixedWingSettings->Safetymargins.Pitchcontrol > 0.5f) { // alarm switched on
        fixedWingPathFollowerStatus.Errors.Pitchcontrol = 1;
        result = 0;
    }

    /**
     * Compute desired roll command
     */
    courseError = RAD2DEG(atan2f(courseComponent[1], courseComponent[0])) - attitudeState.Yaw;

    if (courseError < -180.0f) {
        courseError += 360.0f;
    }
    if (courseError > 180.0f) {
        courseError -= 360.0f;
    }

    // overlap calculation. Theres a dead zone behind the craft where the
    // counter-yawing of some craft while rolling could render a desired right
    // turn into a desired left turn. Making the turn direction based on
    // current roll angle keeps the plane committed to a direction once chosen
    if (courseError < -180.0f + (fixedWingSettings->ReverseCourseOverlap * 0.5f)
        && attitudeState.Roll > 0.0f) {
        courseError += 360.0f;
    }
    if (courseError > 180.0f - (fixedWingSettings->ReverseCourseOverlap * 0.5f)
        && attitudeState.Roll < 0.0f) {
        courseError -= 360.0f;
    }

    courseCommand = pid_apply(&PIDcourse, courseError, dT);

    fixedWingPathFollowerStatus.Error.Course    = courseError;
    fixedWingPathFollowerStatus.ErrorInt.Course = PIDcourse.iAccumulator;
    fixedWingPathFollowerStatus.Command.Course  = courseCommand;

    stabDesired.Roll = boundf(fixedWingSettings->RollLimit.Neutral +
                              courseCommand,
                              fixedWingSettings->RollLimit.Min,
                              fixedWingSettings->RollLimit.Max);

    // TODO: find a check to determine loss of directional control. Likely needs some check of derivative


    /**
     * Compute desired yaw command
     */
    // TODO implement raw control mode for yaw and base on Accels.Y
    stabDesired.Yaw = 0.0f;


    stabDesired.StabilizationMode.Roll   = STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE;
    stabDesired.StabilizationMode.Pitch  = STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE;
    stabDesired.StabilizationMode.Yaw    = STABILIZATIONDESIRED_STABILIZATIONMODE_MANUAL;
    stabDesired.StabilizationMode.Thrust = STABILIZATIONDESIRED_STABILIZATIONMODE_MANUAL;

    StabilizationDesiredSet(&stabDesired);

    FixedWingPathFollowerStatusSet(&fixedWingPathFollowerStatus);

    return result;
}
Exemplo n.º 13
0
// #include"reaction.h"
int main(){

sky sky;

////////Input Parameters of the potential (fit parameters) /////
std::string parameters_filename="Input.inp";

//change this for neutron or proton
NuclearParameters Nu = read_nucleus_parameters( "Input/nca40.inp" );

double Ef=Nu.Ef;
//lmax can't be 6 for high r value
int lmax = 6;
double z0=20.0;
double zp0;
double A0=40.0;
// +1/2 for proton, -1/2 for neutron
double tz=-0.5;

int type=1;
int mvolume = 4;
int AsyVolume = 1;

double A = 40.0;

if (tz>0) { zp0=1;}
else {zp0=0;}

double ph_gap = Nu.ph_gap;
cout<<"ph_gap = "<<Nu.ph_gap<<endl;
double  rStart = .05;
double  rmax = 20.;
double  ham_pts = 300; 

double  rdelt = rmax / ham_pts;

        // Construct Parameters Object
        Parameters p = get_parameters( parameters_filename, Nu.A, Nu.Z, zp0 );

        // Construct Potential Object
        pot pottt = get_bobs_pot2( type, mvolume, AsyVolume, tz, Nu, p );
	pot * pott = &pottt;

        // store coulomb potential in order to compare with




 boundRspace initiate(rmax , ham_pts , Ef, ph_gap , lmax , Nu.Z , zp0 , Nu.A , pott);


  
 double Elower = -11.61818;
 double Eupper = -9.4;
 double jj = .5;
 int ll = 0;
 int Ifine = 1;
 initiate.searchNonLoc( Elower, Eupper, jj,  ll,  Ifine);
 initiate.exteriorWaveFunct(ll);
 initiate.normalizeWF();


double tol=.01;
double estart=Ef;

///// Making rmesh///

std::vector<double> rmesh_p= initiate.make_rmesh_point();
std::vector<double> rmesh= initiate.make_rmesh();
//std::vector<double> rmesh = initiate.make_rmesh_point();
double rdelt_p = rdelt * 39.0/40.0;

// Create momentum space grid
std::vector<double> kmesh;
std::vector<double> kweights;
double const kmax = 5.0;
int const kpts = rmesh.size();
kmesh.resize( kpts );
kweights.resize( kpts );
GausLeg( 0., kmax, kmesh, kweights );



////////////////////////////
//// s and d wave functions////
///////////////////////////
double J = 0.5;

double Emax=-0.005;
//double Emax = 2.0*Ef;
double Emin=-200.0;
//double Emin=-200.0 + Emax;

std::ofstream filee("waves/wave.out");
std::cout<<Elower<<std::endl;

//Generating the propagator

std::vector< lj_eigen_t > bound_levels = initiate.get_bound_levels( rmesh, tol );

cout<<"energy = "<<bound_levels[1][0].first<<endl;

ofstream boundf("waves/bound.txt");
for(int i=0;i<rmesh.size();i++){
	boundf<<rmesh[i]<<" "<<bound_levels[1][0].second[i]*rmesh[i]<<endl;
}

std::vector< mesh_t > emesh_vec =
        initiate.get_emeshes( rmesh, Emin, Emax, bound_levels );

cout<<"emesh_vec = "<<emesh_vec.size()<<endl;

std::vector< prop_t > prop_vec = initiate.get_propagators( rmesh, emesh_vec );

vector <double> pdist = initiate.point_distribution(rmesh,Emax,emesh_vec,prop_vec,bound_levels);

double occ[7];
double onum=0.0;
double num=0.0;

double part=0;
double kpart=0;
vector<double> p_dist;
p_dist.assign( rmesh.size(), 0 );
vector<double> k_dist;
k_dist.assign( kmesh.size(), 0 );

matrix_t d_mtx( rmesh.size(), rmesh.size() ); // density matrix
d_mtx.clear();


//Starting loop over L and J to go through all the orbitals
//THESE ARE CHANGED TO PRODUCE A SPECIFIC RESULT, CHANGE THEM BACK FOR GENERAL USE
lmax=3;
for(int L=3;L<lmax+1;L++){
	for(int s=0;s<2;s++){	
		J=L-0.5+s;
		if(J<0){
			J=0.5;
			s=1;
		}	
	
		cout<<"L = "<<L<<" J = "<<J<<endl;

		string jlab = sky.jlab(J);
		
		string llab = sky.llab(L);

		string dest = "waves/neutron/occ/";

		int index=initiate.index_from_LJ(L,J);

		const prop_t &propE = prop_vec.at(index);

		const mesh_t &emesh = emesh_vec.at(index);

		int Nmax = sky.Nmax(L,J);

		double socc[Nmax];

		string occlab =  dest + "sky" + llab + jlab + ".txt";
		ofstream focc(occlab.c_str());

// Create Bessel Function matrix in k and r
  /*  matrix_t bess_mtx( kmesh.size(), rmesh.size() );
		bess_mtx.clear();
		matrix_t bess_mtx_sky( kmesh.size(), rmesh.size() );
		bess_mtx_sky.clear();
    for( unsigned int nk = 0; nk < kmesh.size(); ++nk ) {
	    for( unsigned int nr = 0; nr < rmesh.size(); ++nr ) {
	      double rho = kmesh[nk] * rmesh[nr];
        bess_mtx( nk, nr ) = gsl_sf_bessel_jl( L, kmesh[nk] * rmesh_p[nr]);
				bess_mtx_sky( nk, nr ) = gsl_sf_bessel_jl( L, rho );
      }
    }	*/	

//Starting loop over N
		for(int N=0;N<Nmax;N++){
			d_mtx.clear();
			cout << "N = "<<N<<endl;
			string Nlab;
			ostringstream convert;
			convert << N;
			Nlab = convert.str();

			vector<double> wf = sky.read_q(N,L,J,rmesh.size());
			vector<double> skyrme = sky.read(N,L,J,rmesh.size());

			std::vector<double> spec;
			std::vector<double> spec0;

//Folding wave functions with S(r,r';E) to get S(E), does it for dom and skyrme wavefunctions
			double spf = 0;
			occ[N]=0;
			socc[N]=0;
			//cout<<"emesh size = "<<emesh.size()<<endl;
			for(unsigned int n=0;n<emesh.size();++n){
			  spf=0.0;
				double spf0=0;
				double Edelt=emesh[n].second;
			 for( unsigned int i = 0; i < rmesh.size(); ++i ) {
					for( unsigned int j = 0; j < rmesh.size(); ++j ) { 
						spf -= rdelt * skyrme[i] * skyrme[j] *imag( propE[n]( i, j ) ) / M_PI;
						d_mtx(i,j) -= imag(propE[n](i,j)) / M_PI / (rmesh[i] * rmesh[j] * rdelt) * Edelt;
					} 
				} 
			//WANT TO ADD A COUPLE MORE CATCHES IN HERE FOR VARIOUS OTHER ORBITALS!!!!!!!!!!!!!!!!
				if(L==0 && N==1 && emesh[n].first > -9){
					spf=0;
				}else if(L==2 && N==0 && J==1.5 && emesh[n].first > -10){
					spf=0;
				}else if(L==3 && N==0 && emesh[n].first > -9){
					spf=0;
				}
				
				spec.push_back(spf);
				spec0.push_back(spf0);
				occ[N] += spf0*Edelt;
				socc[N] += spf*Edelt;
			}

//creating the skyrme density
			for(int i=0;i<rmesh.size();i++){
				p_dist[i] += socc[N] * (2*J+1) * pow(skyrme[i]/rmesh[i],2) / (4*M_PI);
			//	k_dist[i] += socc[N] * (2*J+1) * pow(ksky[i],2) / (4*M_PI);
			}


//this adds the QP peaks to the particle number
			if(L==0 && N==1){
				const lj_eigen_t &levels = bound_levels.at(index);
        double QPE = levels[N].first;
        const std::vector<double> &QPF = levels[N].second;
        double S = initiate.sfactor( rmesh, QPE, L, J, QPF );
				onum += S*(2*J+1);
				occ[N] += S;
				for(int i=0;i<rmesh.size();i++){
					p_dist[i] += S * (2*J+1) * pow(QPF[i],2) / (4*M_PI);
				}
				//Transforming QPF to k-space
				/* vector <double> kqpf;
				kqpf.assign(kmesh.size(),0);
				for(int ik=0;ik<kmesh.size();ik++){
					double kq=0;
					for(int ir=0;ir<rmesh.size();ir++){
						kq += rdelt_p * sqrt(2.0/M_PI) * bess_mtx(ik,ir) * QPF[ir] * pow(rmesh_p[ir],2);
					}
					kqpf[ik] = kq;		
				}
				for(int i=0;i<rmesh.size();i++){
					k_dist[i] += S * (2*J+1) * pow(kqpf[i],2) / (4*M_PI);
				} */
			}else if(L==2 && J==1.5 && N==0){
				const lj_eigen_t &levels = bound_levels.at(index);
        double QPE = levels[N].first;
        const std::vector<double> &QPF = levels[N].second;
        double S = initiate.sfactor( rmesh, QPE, L, J, QPF );
				onum += S*(2*J+1);
				occ[N] += S;
				for(int i=0;i<rmesh.size();i++){
					p_dist[i] += S * (2*J+1) * pow(QPF[i],2) / (4*M_PI);
				}
			//see what happens if I find QPE using this self energy
				//Transforming QPF to k-space
				/* vector <double> kqpf;
				kqpf.assign(kmesh.size(),0);
				for(int ik=0;ik<kmesh.size();ik++){
					double kq=0;
					for(int ir=0;ir<rmesh.size();ir++){
						kq += rdelt_p * sqrt(2.0/M_PI) * bess_mtx(ik,ir) * QPF[ir] * pow(rmesh_p[ir],2);
					}
					kqpf[ik] = kq;		
				}
				for(int i=0;i<rmesh.size();i++){
					k_dist[i] += S * (2*J+1) * pow(kqpf[i],2) / (4*M_PI);
				} */
			}
			
			/* if(L ==3 && N == 0){
				//double QPEf = initiate.find_level(rmesh, -2.0, N, L, J, tol);
				eigen_t forbit = initiate.find_boundstate(rmesh, -2.0, N, L, J, tol);
				cout <<"QPE "<<llab<<jlab<<" = "<<forbit.first<<endl;
				double fs = initiate.sfactor(rmesh, forbit.first, L, J, forbit.second);
				cout <<"S "<<llab<<jlab<<" = "<<fs<<endl;
			}	*/	



			string speclab =   dest + "spec" + llab + jlab + Nlab + ".out";

			speclab = "waves/neutron/occ/new/spec" + llab + jlab + Nlab + ".out";

			ofstream fspec(speclab.c_str());
	
			for(int i=0;i<emesh.size();i++){
				fspec<<emesh[i].first<<" "<<emesh[i].second<<" "<<spec[i]<<endl;
				//fspec<<emesh[i].first<<" "<<spec[i]<<endl;
			}

//change this to occ if you want dom occupation numbers
			focc<<socc[N]<<endl;
			onum += socc[N]*(2*J+1);
			num += occ[N]*(2*J+1);		

		} //ending loop over N
	}		//ending loop over j
} 		//ending loop over L

ofstream sdenr("waves/skydenr.txt");
ofstream sdenk("waves/skydenk.txt");

for(int i=0;i<rmesh.size();i++){
	part += p_dist[i] * pow(rmesh_p[i],2) * rdelt_p * 4 * M_PI;
}

for(int i=0;i<rmesh.size();i++){
	sdenr<<rmesh_p[i]<<" "<<p_dist[i]/part<<endl;
}

cout<<"particle number from sky occ = "<<onum<<endl;
cout<<"particle number from sky density (r) = "<<part<<endl;
//out<<"particle number from sky density (k) = "<<kpart<<endl;

ofstream dfile("waves/background/wavedmtxt.txt");

for(int i=0;i<rmesh.size();i++){
	for(int j=0;j<rmesh.size();j++){
		dfile<<d_mtx(i,j)<<" ";
	}
	dfile<<endl;
}




}
Exemplo n.º 14
0
static inline float CruiseControlLimitThrust(float thrust)
{
    // limit to user specified absolute max thrust
    return boundf(thrust, stabSettings.cruiseControl.min_thrust, stabSettings.cruiseControl.max_thrust);
}
Exemplo n.º 15
0
/**
 * WARNING! This callback executes with critical flight control priority every
 * time a gyroscope update happens do NOT put any time consuming calculations
 * in this loop unless they really have to execute with every gyro update
 */
static void stabilizationInnerloopTask()
{
    // watchdog and error handling
    {
#ifdef PIOS_INCLUDE_WDG
        PIOS_WDG_UpdateFlag(PIOS_WDG_STABILIZATION);
#endif
        bool warn  = false;
        bool error = false;
        bool crit  = false;
        // check if outer loop keeps executing
        if (stabSettings.monitor.rateupdates > -64) {
            stabSettings.monitor.rateupdates--;
        }
        if (stabSettings.monitor.rateupdates < -(2 * OUTERLOOP_SKIPCOUNT)) {
            // warning if rate loop skipped more than 2 execution
            warn = true;
        }
        if (stabSettings.monitor.rateupdates < -(4 * OUTERLOOP_SKIPCOUNT)) {
            // critical if rate loop skipped more than 4 executions
            crit = true;
        }
        // check if gyro keeps updating
        if (stabSettings.monitor.gyroupdates < 1) {
            // error if gyro didn't update at all!
            error = true;
        }
        if (stabSettings.monitor.gyroupdates > 1) {
            // warning if we missed a gyro update
            warn = true;
        }
        if (stabSettings.monitor.gyroupdates > 3) {
            // critical if we missed 3 gyro updates
            crit = true;
        }
        stabSettings.monitor.gyroupdates = 0;

        if (crit) {
            AlarmsSet(SYSTEMALARMS_ALARM_STABILIZATION, SYSTEMALARMS_ALARM_CRITICAL);
        } else if (error) {
            AlarmsSet(SYSTEMALARMS_ALARM_STABILIZATION, SYSTEMALARMS_ALARM_ERROR);
        } else if (warn) {
            AlarmsSet(SYSTEMALARMS_ALARM_STABILIZATION, SYSTEMALARMS_ALARM_WARNING);
        } else {
            AlarmsClear(SYSTEMALARMS_ALARM_STABILIZATION);
        }
    }


    RateDesiredData rateDesired;
    ActuatorDesiredData actuator;
    StabilizationStatusInnerLoopData enabled;
    FlightStatusControlChainData cchain;

    RateDesiredGet(&rateDesired);
    ActuatorDesiredGet(&actuator);
    StabilizationStatusInnerLoopGet(&enabled);
    FlightStatusControlChainGet(&cchain);
    float *rate = &rateDesired.Roll;
    float *actuatorDesiredAxis = &actuator.Roll;
    int t;
    float dT;
    dT = PIOS_DELTATIME_GetAverageSeconds(&timeval);

    for (t = 0; t < AXES; t++) {
        bool reinit = (cast_struct_to_array(enabled, enabled.Roll)[t] != previous_mode[t]);
        previous_mode[t] = cast_struct_to_array(enabled, enabled.Roll)[t];

        if (t < STABILIZATIONSTATUS_INNERLOOP_THRUST) {
            if (reinit) {
                stabSettings.innerPids[t].iAccumulator = 0;
            }
            switch (cast_struct_to_array(enabled, enabled.Roll)[t]) {
            case STABILIZATIONSTATUS_INNERLOOP_VIRTUALFLYBAR:
                stabilization_virtual_flybar(gyro_filtered[t], rate[t], &actuatorDesiredAxis[t], dT, reinit, t, &stabSettings.settings);
                break;
            case STABILIZATIONSTATUS_INNERLOOP_RELAYTUNING:
                rate[t] = boundf(rate[t],
                                 -cast_struct_to_array(stabSettings.stabBank.MaximumRate, stabSettings.stabBank.MaximumRate.Roll)[t],
                                 cast_struct_to_array(stabSettings.stabBank.MaximumRate, stabSettings.stabBank.MaximumRate.Roll)[t]
                                 );
                stabilization_relay_rate(rate[t] - gyro_filtered[t], &actuatorDesiredAxis[t], t, reinit);
                break;
            case STABILIZATIONSTATUS_INNERLOOP_AXISLOCK:
                if (fabsf(rate[t]) > stabSettings.settings.MaxAxisLockRate) {
                    // While getting strong commands act like rate mode
                    axis_lock_accum[t] = 0;
                } else {
                    // For weaker commands or no command simply attitude lock (almost) on no gyro change
                    axis_lock_accum[t] += (rate[t] - gyro_filtered[t]) * dT;
                    axis_lock_accum[t]  = boundf(axis_lock_accum[t], -stabSettings.settings.MaxAxisLock, stabSettings.settings.MaxAxisLock);
                    rate[t] = axis_lock_accum[t] * stabSettings.settings.AxisLockKp;
                }
            // IMPORTANT: deliberately no "break;" here, execution continues with regular RATE control loop to avoid code duplication!
            // keep order as it is, RATE must follow!
            case STABILIZATIONSTATUS_INNERLOOP_RATE:
                // limit rate to maximum configured limits (once here instead of 5 times in outer loop)
                rate[t] = boundf(rate[t],
                                 -cast_struct_to_array(stabSettings.stabBank.MaximumRate, stabSettings.stabBank.MaximumRate.Roll)[t],
                                 cast_struct_to_array(stabSettings.stabBank.MaximumRate, stabSettings.stabBank.MaximumRate.Roll)[t]
                                 );
                actuatorDesiredAxis[t] = pid_apply_setpoint(&stabSettings.innerPids[t], speedScaleFactor, rate[t], gyro_filtered[t], dT);
                break;
            case STABILIZATIONSTATUS_INNERLOOP_DIRECT:
            default:
                actuatorDesiredAxis[t] = rate[t];
                break;
            }
        } else {
            switch (cast_struct_to_array(enabled, enabled.Roll)[t]) {
            case STABILIZATIONSTATUS_INNERLOOP_CRUISECONTROL:
                actuatorDesiredAxis[t] = cruisecontrol_apply_factor(rate[t]);
                break;
            case STABILIZATIONSTATUS_INNERLOOP_DIRECT:
            default:
                actuatorDesiredAxis[t] = rate[t];
                break;
            }
        }

        actuatorDesiredAxis[t] = boundf(actuatorDesiredAxis[t], -1.0f, 1.0f);
    }

    actuator.UpdateTime = dT * 1000;

    if (cchain.Stabilization == FLIGHTSTATUS_CONTROLCHAIN_TRUE) {
        ActuatorDesiredSet(&actuator);
    } else {
        // Force all axes to reinitialize when engaged
        for (t = 0; t < AXES; t++) {
            previous_mode[t] = 255;
        }
    }
    {
        uint8_t armed;
        FlightStatusArmedGet(&armed);
        float throttleDesired;
        ManualControlCommandThrottleGet(&throttleDesired);
        if (armed != FLIGHTSTATUS_ARMED_ARMED ||
            ((stabSettings.settings.LowThrottleZeroIntegral == STABILIZATIONSETTINGS_LOWTHROTTLEZEROINTEGRAL_TRUE) && throttleDesired < 0)) {
            // Force all axes to reinitialize when engaged
            for (t = 0; t < AXES; t++) {
                previous_mode[t] = 255;
            }
        }
    }
    PIOS_CALLBACKSCHEDULER_Schedule(callbackHandle, FAILSAFE_TIMEOUT_MS, CALLBACK_UPDATEMODE_LATER);
}