1
0
Fork 0
mirror of https://github.com/iNavFlight/inav.git synced 2025-07-26 01:35:35 +03:00

Merge pull request #1196 from iNavFlight/failsafe-phase2-mods

Failsafe refactoring - phase 2
This commit is contained in:
Konstantin Sharlaimov 2017-02-01 00:12:30 +10:00 committed by GitHub
commit ae3b4fb8f8
6 changed files with 174 additions and 75 deletions

View file

@ -320,6 +320,10 @@ static const char * const lookupTableDebug[DEBUG_COUNT] = {
"NOTCH" "NOTCH"
}; };
static const char * const lookupTableNoSignalThrottle[] = {
"HOLD", "DROP"
};
typedef struct lookupTableEntry_s { typedef struct lookupTableEntry_s {
const char * const *values; const char * const *values;
const uint8_t valueCount; const uint8_t valueCount;
@ -375,6 +379,7 @@ typedef enum {
TABLE_OSD, TABLE_OSD,
#endif #endif
TABLE_DEBUG, TABLE_DEBUG,
TABLE_RX_NOSIGNAL_THROTTLE,
LOOKUP_TABLE_COUNT LOOKUP_TABLE_COUNT
} lookupTableIndex_e; } lookupTableIndex_e;
@ -428,6 +433,7 @@ static const lookupTableEntry_t lookupTables[] = {
{ lookupTableOsdType, sizeof(lookupTableOsdType) / sizeof(char *) }, { lookupTableOsdType, sizeof(lookupTableOsdType) / sizeof(char *) },
#endif #endif
{ lookupTableDebug, sizeof(lookupTableDebug) / sizeof(char *) }, { lookupTableDebug, sizeof(lookupTableDebug) / sizeof(char *) },
{ lookupTableNoSignalThrottle, sizeof(lookupTableNoSignalThrottle) / sizeof(char *) },
}; };
#define VALUE_TYPE_OFFSET 0 #define VALUE_TYPE_OFFSET 0
@ -567,6 +573,7 @@ static const clivalue_t valueTable[] = {
#endif #endif
{ "rx_min_usec", VAR_UINT16 | MASTER_VALUE, .config.minmax = { PWM_PULSE_MIN, PWM_PULSE_MAX }, PG_RX_CONFIG, offsetof(rxConfig_t, rx_min_usec) }, { "rx_min_usec", VAR_UINT16 | MASTER_VALUE, .config.minmax = { PWM_PULSE_MIN, PWM_PULSE_MAX }, PG_RX_CONFIG, offsetof(rxConfig_t, rx_min_usec) },
{ "rx_max_usec", VAR_UINT16 | MASTER_VALUE, .config.minmax = { PWM_PULSE_MIN, PWM_PULSE_MAX }, PG_RX_CONFIG, offsetof(rxConfig_t, rx_max_usec) }, { "rx_max_usec", VAR_UINT16 | MASTER_VALUE, .config.minmax = { PWM_PULSE_MIN, PWM_PULSE_MAX }, PG_RX_CONFIG, offsetof(rxConfig_t, rx_max_usec) },
{ "rx_nosignal_throttle", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_RX_NOSIGNAL_THROTTLE }, PG_RX_CONFIG, offsetof(rxConfig_t, rxNoSignalThrottleBehavior) },
// PG_BLACKBOX_CONFIG // PG_BLACKBOX_CONFIG
#ifdef BLACKBOX #ifdef BLACKBOX
@ -589,6 +596,7 @@ static const clivalue_t valueTable[] = {
{ "failsafe_kill_switch", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_FAILSAFE_CONFIG, offsetof(failsafeConfig_t, failsafe_kill_switch) }, { "failsafe_kill_switch", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_FAILSAFE_CONFIG, offsetof(failsafeConfig_t, failsafe_kill_switch) },
{ "failsafe_throttle_low_delay",VAR_UINT16 | MASTER_VALUE, .config.minmax = { 0, 300 }, PG_FAILSAFE_CONFIG, offsetof(failsafeConfig_t, failsafe_throttle_low_delay) }, { "failsafe_throttle_low_delay",VAR_UINT16 | MASTER_VALUE, .config.minmax = { 0, 300 }, PG_FAILSAFE_CONFIG, offsetof(failsafeConfig_t, failsafe_throttle_low_delay) },
{ "failsafe_procedure", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_FAILSAFE_PROCEDURE }, PG_FAILSAFE_CONFIG, offsetof(failsafeConfig_t, failsafe_procedure) }, { "failsafe_procedure", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_FAILSAFE_PROCEDURE }, PG_FAILSAFE_CONFIG, offsetof(failsafeConfig_t, failsafe_procedure) },
{ "failsafe_stick_threshold", VAR_UINT16 | MASTER_VALUE, .config.minmax = { 0, 500 }, PG_FAILSAFE_CONFIG, offsetof(failsafeConfig_t, failsafe_stick_motion_threshold) },
{ "failsafe_fw_roll_angle", VAR_INT16 | MASTER_VALUE, .config.minmax = { -800, 800 }, PG_FAILSAFE_CONFIG, offsetof(failsafeConfig_t, failsafe_fw_roll_angle) }, { "failsafe_fw_roll_angle", VAR_INT16 | MASTER_VALUE, .config.minmax = { -800, 800 }, PG_FAILSAFE_CONFIG, offsetof(failsafeConfig_t, failsafe_fw_roll_angle) },
{ "failsafe_fw_pitch_angle", VAR_INT16 | MASTER_VALUE, .config.minmax = { -800, 800 }, PG_FAILSAFE_CONFIG, offsetof(failsafeConfig_t, failsafe_fw_pitch_angle) }, { "failsafe_fw_pitch_angle", VAR_INT16 | MASTER_VALUE, .config.minmax = { -800, 800 }, PG_FAILSAFE_CONFIG, offsetof(failsafeConfig_t, failsafe_fw_pitch_angle) },
{ "failsafe_fw_yaw_rate", VAR_INT16 | MASTER_VALUE, .config.minmax = { -1000, 1000 }, PG_FAILSAFE_CONFIG, offsetof(failsafeConfig_t, failsafe_fw_yaw_rate) }, { "failsafe_fw_yaw_rate", VAR_INT16 | MASTER_VALUE, .config.minmax = { -1000, 1000 }, PG_FAILSAFE_CONFIG, offsetof(failsafeConfig_t, failsafe_fw_yaw_rate) },

View file

@ -173,28 +173,26 @@ static void updatePreArmingChecks(void)
void annexCode(void) void annexCode(void)
{ {
bool needRPY = true;
bool needThrottle = true;
int32_t throttleValue; int32_t throttleValue;
if (failsafeIsActive()) { if (failsafeIsActive()) {
const failsafeControlChannels_e failsafeControlInput = failsafeShouldApplyControlInput(); // Failsafe will apply rcCommand for us
failsafeApplyControlInput();
// In some cases our failsafe logic will still allow values from RX to be used
if (failsafeControlInput != FAILSAFE_CONTROL_NONE) {
failsafeApplyControlInput();
needRPY = !(failsafeControlInput & FAILSAFE_CONTROL_RPY);
needThrottle = !(failsafeControlInput & FAILSAFE_CONTROL_THROTTLE);
}
} }
else {
if (needRPY) {
// Compute ROLL PITCH and YAW command // Compute ROLL PITCH and YAW command
rcCommand[ROLL] = getAxisRcCommand(rcData[ROLL], currentControlRateProfile->rcExpo8, rcControlsConfig()->deadband); rcCommand[ROLL] = getAxisRcCommand(rcData[ROLL], currentControlRateProfile->rcExpo8, rcControlsConfig()->deadband);
rcCommand[PITCH] = getAxisRcCommand(rcData[PITCH], currentControlRateProfile->rcExpo8, rcControlsConfig()->deadband); rcCommand[PITCH] = getAxisRcCommand(rcData[PITCH], currentControlRateProfile->rcExpo8, rcControlsConfig()->deadband);
rcCommand[YAW] = -getAxisRcCommand(rcData[YAW], currentControlRateProfile->rcYawExpo8, rcControlsConfig()->yaw_deadband); rcCommand[YAW] = -getAxisRcCommand(rcData[YAW], currentControlRateProfile->rcYawExpo8, rcControlsConfig()->yaw_deadband);
//Compute THROTTLE command
throttleValue = constrain(rcData[THROTTLE], rxConfig()->mincheck, PWM_RANGE_MAX);
throttleValue = (uint32_t)(throttleValue - rxConfig()->mincheck) * PWM_RANGE_MIN / (PWM_RANGE_MAX - rxConfig()->mincheck); // [MINCHECK;2000] -> [0;1000]
rcCommand[THROTTLE] = rcLookupThrottle(throttleValue);
// Signal updated rcCommand values to Failsafe system
failsafeUpdateRcCommandValues();
if (FLIGHT_MODE(HEADFREE_MODE)) { if (FLIGHT_MODE(HEADFREE_MODE)) {
const float radDiff = degreesToRadians(DECIDEGREES_TO_DEGREES(attitude.values.yaw) - headFreeModeHold); const float radDiff = degreesToRadians(DECIDEGREES_TO_DEGREES(attitude.values.yaw) - headFreeModeHold);
const float cosDiff = cos_approx(radDiff); const float cosDiff = cos_approx(radDiff);
@ -205,13 +203,6 @@ void annexCode(void)
} }
} }
if (needThrottle) {
//Compute THROTTLE command
throttleValue = constrain(rcData[THROTTLE], rxConfig()->mincheck, PWM_RANGE_MAX);
throttleValue = (uint32_t)(throttleValue - rxConfig()->mincheck) * PWM_RANGE_MIN / (PWM_RANGE_MAX - rxConfig()->mincheck); // [MINCHECK;2000] -> [0;1000]
rcCommand[THROTTLE] = rcLookupThrottle(throttleValue);
}
if (ARMING_FLAG(ARMED)) { if (ARMING_FLAG(ARMED)) {
LED0_ON; LED0_ON;
} else { } else {
@ -385,7 +376,7 @@ void processRx(timeUs_t currentTimeUs)
bool canUseHorizonMode = true; bool canUseHorizonMode = true;
if ((IS_RC_MODE_ACTIVE(BOXANGLE) || failsafeIsActive() || naivationRequiresAngleMode()) && sensors(SENSOR_ACC)) { if ((IS_RC_MODE_ACTIVE(BOXANGLE) || failsafeRequiresAngleMode() || naivationRequiresAngleMode()) && sensors(SENSOR_ACC)) {
// bumpless transfer to Level mode // bumpless transfer to Level mode
canUseHorizonMode = false; canUseHorizonMode = false;

View file

@ -26,6 +26,7 @@
#include "common/axis.h" #include "common/axis.h"
#include "config/feature.h"
#include "config/parameter_group.h" #include "config/parameter_group.h"
#include "config/parameter_group_ids.h" #include "config/parameter_group_ids.h"
@ -39,6 +40,7 @@
#include "fc/controlrate_profile.h" #include "fc/controlrate_profile.h"
#include "flight/failsafe.h" #include "flight/failsafe.h"
#include "flight/mixer.h"
#include "flight/pid.h" #include "flight/pid.h"
#include "navigation/navigation.h" #include "navigation/navigation.h"
@ -73,8 +75,62 @@ PG_RESET_TEMPLATE(failsafeConfig_t, failsafeConfig,
.failsafe_fw_roll_angle = -200, // 20 deg left .failsafe_fw_roll_angle = -200, // 20 deg left
.failsafe_fw_pitch_angle = 100, // 10 deg dive (yes, positive means dive) .failsafe_fw_pitch_angle = 100, // 10 deg dive (yes, positive means dive)
.failsafe_fw_yaw_rate = -45, // 45 deg/s left yaw (4s for full turn) .failsafe_fw_yaw_rate = -45, // 45 deg/s left yaw (4s for full turn)
.failsafe_stick_motion_threshold = 0,
); );
typedef enum {
FAILSAFE_CHANNEL_HOLD, // Hold last known good value
FAILFAFE_CHANNEL_NEUTRAL, // RPY = zero, THR = zero
FAILSAFE_CHANNEL_AUTO, // Defined by failsafe configured values
} failsafeChannelBehavior_e;
typedef struct {
bool forceAngleMode;
failsafeChannelBehavior_e channelBehavior[4];
} failsafeProcedureLogic_t;
static const failsafeProcedureLogic_t failsafeProcedureLogic[] = {
[FAILSAFE_PROCEDURE_AUTO_LANDING] = {
.forceAngleMode = true,
.channelBehavior = {
FAILSAFE_CHANNEL_AUTO, // ROLL
FAILSAFE_CHANNEL_AUTO, // PITCH
FAILSAFE_CHANNEL_AUTO, // YAW
FAILSAFE_CHANNEL_AUTO // THROTTLE
}
},
[FAILSAFE_PROCEDURE_DROP_IT] = {
.forceAngleMode = true,
.channelBehavior = {
FAILFAFE_CHANNEL_NEUTRAL, // ROLL
FAILFAFE_CHANNEL_NEUTRAL, // PITCH
FAILFAFE_CHANNEL_NEUTRAL, // YAW
FAILFAFE_CHANNEL_NEUTRAL // THROTTLE
}
},
[FAILSAFE_PROCEDURE_RTH] = {
.forceAngleMode = true,
.channelBehavior = {
FAILFAFE_CHANNEL_NEUTRAL, // ROLL
FAILFAFE_CHANNEL_NEUTRAL, // PITCH
FAILFAFE_CHANNEL_NEUTRAL, // YAW
FAILSAFE_CHANNEL_HOLD // THROTTLE
}
},
[FAILSAFE_PROCEDURE_NONE] = {
.forceAngleMode = false,
.channelBehavior = {
FAILSAFE_CHANNEL_HOLD, // ROLL
FAILSAFE_CHANNEL_HOLD, // PITCH
FAILSAFE_CHANNEL_HOLD, // YAW
FAILSAFE_CHANNEL_HOLD // THROTTLE
}
}
};
/* /*
* Should called when the failsafe config needs to be changed - e.g. a different profile has been selected. * Should called when the failsafe config needs to be changed - e.g. a different profile has been selected.
*/ */
@ -90,7 +146,6 @@ void failsafeReset(void)
failsafeState.receivingRxDataPeriodPreset = 0; failsafeState.receivingRxDataPeriodPreset = 0;
failsafeState.phase = FAILSAFE_IDLE; failsafeState.phase = FAILSAFE_IDLE;
failsafeState.rxLinkState = FAILSAFE_RXLINK_DOWN; failsafeState.rxLinkState = FAILSAFE_RXLINK_DOWN;
failsafeState.shouldApplyControlInput = FAILSAFE_CONTROL_NONE;
} }
void failsafeInit(uint16_t deadband3d_throttle) void failsafeInit(uint16_t deadband3d_throttle)
@ -124,56 +179,82 @@ bool failsafeIsActive(void)
return failsafeState.active; return failsafeState.active;
} }
bool failsafeRequiresAngleMode(void)
{
return failsafeState.active && failsafeProcedureLogic[failsafeConfig()->failsafe_procedure].forceAngleMode;
}
void failsafeStartMonitoring(void) void failsafeStartMonitoring(void)
{ {
failsafeState.monitoring = true; failsafeState.monitoring = true;
} }
failsafeControlChannels_e failsafeShouldApplyControlInput(void)
{
return failsafeState.shouldApplyControlInput;
}
static bool failsafeShouldHaveCausedLandingByNow(void) static bool failsafeShouldHaveCausedLandingByNow(void)
{ {
return (millis() > failsafeState.landingShouldBeFinishedAt); return (millis() > failsafeState.landingShouldBeFinishedAt);
} }
static void failsafeActivate(failsafePhase_e newPhase, failsafeControlChannels_e applyControlInput) static void failsafeActivate(failsafePhase_e newPhase)
{ {
failsafeState.active = true; failsafeState.active = true;
failsafeState.phase = newPhase; failsafeState.phase = newPhase;
ENABLE_FLIGHT_MODE(FAILSAFE_MODE); ENABLE_FLIGHT_MODE(FAILSAFE_MODE);
failsafeState.landingShouldBeFinishedAt = millis() + failsafeConfig()->failsafe_off_delay * MILLIS_PER_TENTH_SECOND; failsafeState.landingShouldBeFinishedAt = millis() + failsafeConfig()->failsafe_off_delay * MILLIS_PER_TENTH_SECOND;
failsafeState.shouldApplyControlInput = applyControlInput;
failsafeState.events++; failsafeState.events++;
} }
void failsafeApplyControlInput(void) void failsafeUpdateRcCommandValues(void)
{ {
if (failsafeState.shouldApplyControlInput & FAILSAFE_CONTROL_RPY) { if (!failsafeState.active) {
if (STATE(FIXED_WING)) { for (int idx = 0; idx < 4; idx++) {
if (failsafeConfig()->failsafe_procedure == FAILSAFE_PROCEDURE_RTH) { failsafeState.lastGoodRcCommand[idx] = rcCommand[idx];
for (int i = 0; i < 3; i++) {
rcCommand[i] = 0;
}
}
else {
rcCommand[ROLL] = pidAngleToRcCommand(failsafeConfig()->failsafe_fw_roll_angle, pidProfile()->max_angle_inclination[FD_ROLL]);
rcCommand[PITCH] = pidAngleToRcCommand(failsafeConfig()->failsafe_fw_pitch_angle, pidProfile()->max_angle_inclination[FD_PITCH]);
rcCommand[YAW] = pidRateToRcCommand(failsafeConfig()->failsafe_fw_yaw_rate, currentControlRateProfile->rates[FD_YAW]);
}
}
else {
for (int i = 0; i < 3; i++) {
rcCommand[i] = 0;
}
} }
} }
}
if (failsafeState.shouldApplyControlInput & FAILSAFE_CONTROL_THROTTLE) { void failsafeApplyControlInput(void)
rcCommand[THROTTLE] = failsafeConfig()->failsafe_throttle; {
// Prepare FAILSAFE_CHANNEL_AUTO values for rcCommand
int16_t autoRcCommand[4];
if (STATE(FIXED_WING)) {
autoRcCommand[ROLL] = pidAngleToRcCommand(failsafeConfig()->failsafe_fw_roll_angle, pidProfile()->max_angle_inclination[FD_ROLL]);
autoRcCommand[PITCH] = pidAngleToRcCommand(failsafeConfig()->failsafe_fw_pitch_angle, pidProfile()->max_angle_inclination[FD_PITCH]);
autoRcCommand[YAW] = pidRateToRcCommand(failsafeConfig()->failsafe_fw_yaw_rate, currentControlRateProfile->rates[FD_YAW]);
autoRcCommand[THROTTLE] = failsafeConfig()->failsafe_throttle;
}
else {
for (int i = 0; i < 3; i++) {
autoRcCommand[i] = 0;
}
autoRcCommand[THROTTLE] = failsafeConfig()->failsafe_throttle;
}
// Apply channel values
for (int idx = 0; idx < 4; idx++) {
switch (failsafeProcedureLogic[failsafeConfig()->failsafe_procedure].channelBehavior[idx]) {
case FAILSAFE_CHANNEL_HOLD:
rcCommand[idx] = failsafeState.lastGoodRcCommand[idx];
break;
case FAILFAFE_CHANNEL_NEUTRAL:
switch (idx) {
case ROLL:
case PITCH:
case YAW:
rcCommand[idx] = 0;
break;
case THROTTLE:
rcCommand[idx] = feature(FEATURE_3D) ? rxConfig()->midrc : motorConfig()->minthrottle;
break;
}
break;
case FAILSAFE_CHANNEL_AUTO:
rcCommand[idx] = autoRcCommand[idx];
break;
}
} }
} }
@ -209,15 +290,32 @@ void failsafeOnValidDataFailed(void)
} }
} }
static bool failsafeCheckStickMotion(void)
{
if (failsafeConfig()->failsafe_stick_motion_threshold > 0) {
uint32_t totalRcDelta = 0;
totalRcDelta += ABS(rcData[ROLL] - rxConfig()->midrc);
totalRcDelta += ABS(rcData[PITCH] - rxConfig()->midrc);
totalRcDelta += ABS(rcData[YAW] - rxConfig()->midrc);
return totalRcDelta >= failsafeConfig()->failsafe_stick_motion_threshold;
}
else {
return true;
}
}
void failsafeUpdateState(void) void failsafeUpdateState(void)
{ {
if (!failsafeIsMonitoring()) { if (!failsafeIsMonitoring()) {
return; return;
} }
bool receivingRxData = failsafeIsReceivingRxData(); const bool receivingRxData = failsafeIsReceivingRxData();
bool armed = ARMING_FLAG(ARMED); const bool armed = ARMING_FLAG(ARMED);
bool failsafeSwitchIsOn = IS_RC_MODE_ACTIVE(BOXFAILSAFE); const bool failsafeSwitchIsOn = IS_RC_MODE_ACTIVE(BOXFAILSAFE);
const bool sticksAreMoving = failsafeCheckStickMotion();
beeperMode_e beeperMode = BEEPER_SILENCE; beeperMode_e beeperMode = BEEPER_SILENCE;
// Beep RX lost only if we are not seeing data and we have been armed earlier // Beep RX lost only if we are not seeing data and we have been armed earlier
@ -240,14 +338,14 @@ void failsafeUpdateState(void)
// Kill switch logic (must be independent of receivingRxData to skip PERIOD_RXDATA_FAILURE delay before disarming) // Kill switch logic (must be independent of receivingRxData to skip PERIOD_RXDATA_FAILURE delay before disarming)
if (failsafeSwitchIsOn && failsafeConfig()->failsafe_kill_switch) { if (failsafeSwitchIsOn && failsafeConfig()->failsafe_kill_switch) {
// KillswitchEvent: failsafe switch is configured as KILL switch and is switched ON // KillswitchEvent: failsafe switch is configured as KILL switch and is switched ON
failsafeActivate(FAILSAFE_LANDED, FAILSAFE_CONTROL_ALL); // skip auto-landing procedure failsafeActivate(FAILSAFE_LANDED); // skip auto-landing procedure
failsafeState.receivingRxDataPeriodPreset = PERIOD_OF_1_SECONDS; // require 1 seconds of valid rxData failsafeState.receivingRxDataPeriodPreset = PERIOD_OF_1_SECONDS; // require 1 seconds of valid rxData
reprocessState = true; reprocessState = true;
} else if (!receivingRxData) { } else if (!receivingRxData) {
if ((failsafeConfig()->failsafe_throttle_low_delay && (millis() > failsafeState.throttleLowPeriod)) || STATE(NAV_MOTOR_STOP_OR_IDLE)) { if ((failsafeConfig()->failsafe_throttle_low_delay && (millis() > failsafeState.throttleLowPeriod)) || STATE(NAV_MOTOR_STOP_OR_IDLE)) {
// JustDisarm: throttle was LOW for at least 'failsafe_throttle_low_delay' seconds or waiting for launch // JustDisarm: throttle was LOW for at least 'failsafe_throttle_low_delay' seconds or waiting for launch
// Don't disarm at all if `failsafe_throttle_low_delay` is set to zero // Don't disarm at all if `failsafe_throttle_low_delay` is set to zero
failsafeActivate(FAILSAFE_LANDED, FAILSAFE_CONTROL_ALL); // skip auto-landing procedure failsafeActivate(FAILSAFE_LANDED); // skip auto-landing procedure
failsafeState.receivingRxDataPeriodPreset = PERIOD_OF_3_SECONDS; // require 3 seconds of valid rxData failsafeState.receivingRxDataPeriodPreset = PERIOD_OF_3_SECONDS; // require 3 seconds of valid rxData
} else { } else {
failsafeState.phase = FAILSAFE_RX_LOSS_DETECTED; failsafeState.phase = FAILSAFE_RX_LOSS_DETECTED;
@ -273,26 +371,26 @@ void failsafeUpdateState(void)
switch (failsafeConfig()->failsafe_procedure) { switch (failsafeConfig()->failsafe_procedure) {
case FAILSAFE_PROCEDURE_AUTO_LANDING: case FAILSAFE_PROCEDURE_AUTO_LANDING:
// Stabilize, and set Throttle to specified level // Stabilize, and set Throttle to specified level
failsafeActivate(FAILSAFE_LANDING, FAILSAFE_CONTROL_ALL); failsafeActivate(FAILSAFE_LANDING);
break; break;
case FAILSAFE_PROCEDURE_DROP_IT: case FAILSAFE_PROCEDURE_DROP_IT:
// Drop the craft // Drop the craft
failsafeActivate(FAILSAFE_LANDED, FAILSAFE_CONTROL_ALL); // skip auto-landing procedure failsafeActivate(FAILSAFE_LANDED); // skip auto-landing procedure
failsafeState.receivingRxDataPeriodPreset = PERIOD_OF_3_SECONDS; // require 3 seconds of valid rxData failsafeState.receivingRxDataPeriodPreset = PERIOD_OF_3_SECONDS; // require 3 seconds of valid rxData
break; break;
#if defined(NAV) #if defined(NAV)
case FAILSAFE_PROCEDURE_RTH: case FAILSAFE_PROCEDURE_RTH:
// Proceed to handling & monitoring RTH navigation // Proceed to handling & monitoring RTH navigation
failsafeActivate(FAILSAFE_RETURN_TO_HOME, FAILSAFE_CONTROL_RPY); failsafeActivate(FAILSAFE_RETURN_TO_HOME);
activateForcedRTH(); activateForcedRTH();
break; break;
#endif #endif
case FAILSAFE_PROCEDURE_NONE: case FAILSAFE_PROCEDURE_NONE:
default: default:
// Do nothing procedure // Do nothing procedure
failsafeActivate(FAILSAFE_RX_LOSS_IDLE, FAILSAFE_CONTROL_NONE); failsafeActivate(FAILSAFE_RX_LOSS_IDLE);
break; break;
} }
} }
@ -301,7 +399,7 @@ void failsafeUpdateState(void)
/* A very simple do-nothing failsafe procedure. The only thing it will do is monitor the receiver state and switch out of FAILSAFE condition */ /* A very simple do-nothing failsafe procedure. The only thing it will do is monitor the receiver state and switch out of FAILSAFE condition */
case FAILSAFE_RX_LOSS_IDLE: case FAILSAFE_RX_LOSS_IDLE:
if (receivingRxData) { if (receivingRxData && sticksAreMoving) {
failsafeState.phase = FAILSAFE_RX_LOSS_RECOVERED; failsafeState.phase = FAILSAFE_RX_LOSS_RECOVERED;
reprocessState = true; reprocessState = true;
} }
@ -309,7 +407,7 @@ void failsafeUpdateState(void)
#if defined(NAV) #if defined(NAV)
case FAILSAFE_RETURN_TO_HOME: case FAILSAFE_RETURN_TO_HOME:
if (receivingRxData) { if (receivingRxData && sticksAreMoving) {
abortForcedRTH(); abortForcedRTH();
failsafeState.phase = FAILSAFE_RX_LOSS_RECOVERED; failsafeState.phase = FAILSAFE_RX_LOSS_RECOVERED;
reprocessState = true; reprocessState = true;
@ -340,7 +438,7 @@ void failsafeUpdateState(void)
#endif #endif
case FAILSAFE_LANDING: case FAILSAFE_LANDING:
if (receivingRxData) { if (receivingRxData && sticksAreMoving) {
failsafeState.phase = FAILSAFE_RX_LOSS_RECOVERED; failsafeState.phase = FAILSAFE_RX_LOSS_RECOVERED;
reprocessState = true; reprocessState = true;
} }

View file

@ -41,6 +41,8 @@ typedef struct failsafeConfig_s {
int16_t failsafe_fw_roll_angle; // Settings to be applies during "LAND" procedure on a fixed-wing int16_t failsafe_fw_roll_angle; // Settings to be applies during "LAND" procedure on a fixed-wing
int16_t failsafe_fw_pitch_angle; int16_t failsafe_fw_pitch_angle;
int16_t failsafe_fw_yaw_rate; int16_t failsafe_fw_yaw_rate;
uint16_t failsafe_stick_motion_threshold;
} failsafeConfig_t; } failsafeConfig_t;
PG_DECLARE(failsafeConfig_t, failsafeConfig); PG_DECLARE(failsafeConfig_t, failsafeConfig);
@ -76,13 +78,6 @@ typedef enum {
RTH_HAS_LANDED // RTH is active and has landed. RTH_HAS_LANDED // RTH is active and has landed.
} rthState_e; } rthState_e;
typedef enum {
FAILSAFE_CONTROL_NONE = 0,
FAILSAFE_CONTROL_RPY = 1 << 0,
FAILSAFE_CONTROL_THROTTLE = 1 << 1,
FAILSAFE_CONTROL_ALL = (FAILSAFE_CONTROL_RPY | FAILSAFE_CONTROL_THROTTLE)
} failsafeControlChannels_e;
typedef struct failsafeState_s { typedef struct failsafeState_s {
int16_t events; int16_t events;
bool monitoring; bool monitoring;
@ -97,7 +92,7 @@ typedef struct failsafeState_s {
timeMs_t receivingRxDataPeriodPreset; // preset for the required period of valid rxData timeMs_t receivingRxDataPeriodPreset; // preset for the required period of valid rxData
failsafePhase_e phase; failsafePhase_e phase;
failsafeRxLinkState_e rxLinkState; failsafeRxLinkState_e rxLinkState;
failsafeControlChannels_e shouldApplyControlInput; int16_t lastGoodRcCommand[4];
} failsafeState_t; } failsafeState_t;
void failsafeInit(uint16_t deadband3d_throttle); void failsafeInit(uint16_t deadband3d_throttle);
@ -114,7 +109,8 @@ void failsafeOnRxSuspend(uint32_t suspendPeriod);
void failsafeOnRxResume(void); void failsafeOnRxResume(void);
bool failsafeMayRequireNavigationMode(void); bool failsafeMayRequireNavigationMode(void);
void failsafeApplyControlInput(void); void failsafeApplyControlInput(void);
failsafeControlChannels_e failsafeShouldApplyControlInput(void); bool failsafeRequiresAngleMode(void);
void failsafeUpdateRcCommandValues(void);
void failsafeOnValidDataReceived(void); void failsafeOnValidDataReceived(void);
void failsafeOnValidDataFailed(void); void failsafeOnValidDataFailed(void);

View file

@ -120,7 +120,8 @@ PG_RESET_TEMPLATE(rxConfig_t, rxConfig,
.rssi_channel = 0, .rssi_channel = 0,
.rssi_scale = RSSI_SCALE_DEFAULT, .rssi_scale = RSSI_SCALE_DEFAULT,
.rssi_ppm_invert = 0, .rssi_ppm_invert = 0,
.rcSmoothing = 1 .rcSmoothing = 1,
.rxNoSignalThrottleBehavior = RX_NOSIGNAL_THROTTLE_HOLD,
); );
void resetAllRxChannelRangeConfigurations(void) void resetAllRxChannelRangeConfigurations(void)
@ -417,11 +418,12 @@ static uint16_t getRxNosignalValue(uint8_t channel)
return rxConfig()->midrc; return rxConfig()->midrc;
case THROTTLE: case THROTTLE:
if (feature(FEATURE_3D)) if (rxConfig()->rxNoSignalThrottleBehavior == RX_NOSIGNAL_THROTTLE_DROP) {
return rxConfig()->midrc; return feature(FEATURE_3D) ? rxConfig()->midrc : rxConfig()->rx_min_usec;
else }
//return rxConfig()->rx_min_usec; else {
return rcData[channel]; return rcData[channel];
}
default: default:
return rcData[channel]; return rcData[channel];

View file

@ -91,6 +91,9 @@ typedef struct rxChannelRangeConfig_s {
} rxChannelRangeConfig_t; } rxChannelRangeConfig_t;
PG_DECLARE_ARRAY(rxChannelRangeConfig_t, NON_AUX_CHANNEL_COUNT, rxChannelRangeConfigs); PG_DECLARE_ARRAY(rxChannelRangeConfig_t, NON_AUX_CHANNEL_COUNT, rxChannelRangeConfigs);
#define RX_NOSIGNAL_THROTTLE_HOLD 0
#define RX_NOSIGNAL_THROTTLE_DROP 1
typedef struct rxConfig_s { typedef struct rxConfig_s {
uint8_t rcmap[MAX_MAPPABLE_RX_INPUTS]; // mapping of radio channels to internal RPYTA+ order uint8_t rcmap[MAX_MAPPABLE_RX_INPUTS]; // mapping of radio channels to internal RPYTA+ order
uint8_t serialrx_provider; // type of UART-based receiver (0 = spek 10, 1 = spek 11, 2 = sbus). Must be enabled by FEATURE_RX_SERIAL first. uint8_t serialrx_provider; // type of UART-based receiver (0 = spek 10, 1 = spek 11, 2 = sbus). Must be enabled by FEATURE_RX_SERIAL first.
@ -109,6 +112,7 @@ typedef struct rxConfig_s {
uint16_t rx_min_usec; uint16_t rx_min_usec;
uint16_t rx_max_usec; uint16_t rx_max_usec;
uint8_t rcSmoothing; // Enable/Disable RC filtering uint8_t rcSmoothing; // Enable/Disable RC filtering
uint8_t rxNoSignalThrottleBehavior;
} rxConfig_t; } rxConfig_t;
PG_DECLARE(rxConfig_t, rxConfig); PG_DECLARE(rxConfig_t, rxConfig);