/** * @brief Handler to interprete Command inputs in regards to arming/disarming * @input: ManualControlCommand, AccessoryDesired * @output: FlightStatus.Arming */ void armHandler(bool newinit) { static ArmState_t armState; if (newinit) { AccessoryDesiredInitialize(); setArmedIfChanged(FLIGHTSTATUS_ARMED_DISARMED); armState = ARM_STATE_DISARMED; } portTickType sysTime = xTaskGetTickCount(); FlightModeSettingsData settings; FlightModeSettingsGet(&settings); ManualControlCommandData cmd; ManualControlCommandGet(&cmd); AccessoryDesiredData acc; bool lowThrottle = cmd.Throttle < 0; bool armSwitch = false; switch (settings.Arming) { case FLIGHTMODESETTINGS_ARMING_ACCESSORY0: AccessoryDesiredInstGet(0, &acc); armSwitch = true; break; case FLIGHTMODESETTINGS_ARMING_ACCESSORY1: AccessoryDesiredInstGet(1, &acc); armSwitch = true; break; case FLIGHTMODESETTINGS_ARMING_ACCESSORY2: AccessoryDesiredInstGet(2, &acc); armSwitch = true; break; default: break; } // immediate disarm on switch if (armSwitch && acc.AccessoryVal <= -ARMED_THRESHOLD) { lowThrottle = true; } if (forcedDisArm()) { // PathPlanner forces explicit disarming due to error condition (crash, impact, fire, ...) setArmedIfChanged(FLIGHTSTATUS_ARMED_DISARMED); return; } if (settings.Arming == FLIGHTMODESETTINGS_ARMING_ALWAYSDISARMED) { // In this configuration we always disarm setArmedIfChanged(FLIGHTSTATUS_ARMED_DISARMED); return; } // The throttle is not low, in case we where arming or disarming, abort if (!lowThrottle) { switch (armState) { case ARM_STATE_DISARMING_MANUAL: case ARM_STATE_DISARMING_TIMEOUT: armState = ARM_STATE_ARMED; break; case ARM_STATE_ARMING_MANUAL: armState = ARM_STATE_DISARMED; break; default: // Nothing needs to be done in the other states break; } return; } // The rest of these cases throttle is low if (settings.Arming == FLIGHTMODESETTINGS_ARMING_ALWAYSARMED) { // In this configuration, we go into armed state as soon as the throttle is low, never disarm setArmedIfChanged(FLIGHTSTATUS_ARMED_ARMED); return; } // When the configuration is not "Always armed" and no "Always disarmed", // the state will not be changed when the throttle is not low static portTickType armedDisarmStart; float armingInputLevel = 0; // Calc channel see assumptions7 switch (settings.Arming) { case FLIGHTMODESETTINGS_ARMING_ROLLLEFT: armingInputLevel = 1.0f * cmd.Roll; break; case FLIGHTMODESETTINGS_ARMING_ROLLRIGHT: armingInputLevel = -1.0f * cmd.Roll; break; case FLIGHTMODESETTINGS_ARMING_PITCHFORWARD: armingInputLevel = 1.0f * cmd.Pitch; break; case FLIGHTMODESETTINGS_ARMING_PITCHAFT: armingInputLevel = -1.0f * cmd.Pitch; break; case FLIGHTMODESETTINGS_ARMING_YAWLEFT: armingInputLevel = 1.0f * cmd.Yaw; break; case FLIGHTMODESETTINGS_ARMING_YAWRIGHT: armingInputLevel = -1.0f * cmd.Yaw; break; case FLIGHTMODESETTINGS_ARMING_ACCESSORY0: case FLIGHTMODESETTINGS_ARMING_ACCESSORY1: case FLIGHTMODESETTINGS_ARMING_ACCESSORY2: armingInputLevel = -1.0f * acc.AccessoryVal; break; } bool manualArm = false; bool manualDisarm = false; if (armingInputLevel <= -ARMED_THRESHOLD) { manualArm = true; } else if (armingInputLevel >= +ARMED_THRESHOLD) { manualDisarm = true; } switch (armState) { case ARM_STATE_DISARMED: setArmedIfChanged(FLIGHTSTATUS_ARMED_DISARMED); // only allow arming if it's OK too if (manualArm && okToArm()) { armedDisarmStart = sysTime; armState = ARM_STATE_ARMING_MANUAL; } break; case ARM_STATE_ARMING_MANUAL: setArmedIfChanged(FLIGHTSTATUS_ARMED_ARMING); if (manualArm && (timeDifferenceMs(armedDisarmStart, sysTime) > settings.ArmingSequenceTime)) { armState = ARM_STATE_ARMED; } else if (!manualArm) { armState = ARM_STATE_DISARMED; } break; case ARM_STATE_ARMED: // When we get here, the throttle is low, // we go immediately to disarming due to timeout, also when the disarming mechanism is not enabled armedDisarmStart = sysTime; armState = ARM_STATE_DISARMING_TIMEOUT; setArmedIfChanged(FLIGHTSTATUS_ARMED_ARMED); break; case ARM_STATE_DISARMING_TIMEOUT: { // we should never reach the disarming timeout if the pathfollower is engaged - reset timeout FlightStatusControlChainData cc; FlightStatusControlChainGet(&cc); if (cc.PathFollower == FLIGHTSTATUS_CONTROLCHAIN_TRUE) { armedDisarmStart = sysTime; } } // We get here when armed while throttle low, even when the arming timeout is not enabled if ((settings.ArmedTimeout != 0) && (timeDifferenceMs(armedDisarmStart, sysTime) > settings.ArmedTimeout)) { armState = ARM_STATE_DISARMED; } // Switch to disarming due to manual control when needed if (manualDisarm) { armedDisarmStart = sysTime; armState = ARM_STATE_DISARMING_MANUAL; } break; case ARM_STATE_DISARMING_MANUAL: // arming switch disarms immediately, if (manualDisarm && (timeDifferenceMs(armedDisarmStart, sysTime) > settings.DisarmingSequenceTime)) { armState = ARM_STATE_DISARMED; } else if (!manualDisarm) { armState = ARM_STATE_ARMED; } break; } // End Switch }
/** * 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); }