From a030d4dd9e9996e715987fc88d38500505c4ced0 Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Thu, 20 Aug 2015 01:25:32 +0100 Subject: [PATCH] Failsafe - Add rxfail `auto` mode. Allow rxfail to be used for all channels, not just aux channel. --- docs/Rx.md | 38 +++++++++++++++++------ src/main/config/config.c | 9 +++--- src/main/io/serial_cli.c | 67 +++++++++++++++++++++++++++------------- src/main/io/serial_msp.c | 16 +++++----- src/main/rx/rx.c | 27 ++++++++-------- src/main/rx/rx.h | 9 ++++-- 6 files changed, 105 insertions(+), 61 deletions(-) diff --git a/docs/Rx.md b/docs/Rx.md index 2baf944f00..863df54407 100644 --- a/docs/Rx.md +++ b/docs/Rx.md @@ -133,7 +133,7 @@ The software has signal loss detection which is always enabled. Signal loss det The `rx_min_usec` and `rx_max_usec` settings helps detect when your RX stops sending any data, enters failsafe mode or when the RX looses signal. -By default, when the signal loss is detected the FC will set pitch/roll/yaw to the value configured for `mid_rc`. The throttle will be set to the value configured for `rx_min_usec`. +By default, when the signal loss is detected the FC will set pitch/roll/yaw to the value configured for `mid_rc`. The throttle will be set to the value configured for `rx_min_usec` or `mid_rc` if using 3D feature. Signal loss can be detected when: @@ -141,29 +141,47 @@ Signal loss can be detected when: 2. using Serial RX and receiver indicates failsafe condition. 3. using any of the first 4 stick channels do not have a value in the range specified by `rx_min_usec` and `rx_max_usec`. -#### `rxfail` +### RX loss configuration -The `rxfail` command is used to configure per-aux-channel rx-loss behaviour. Unless otherwise configured all AUX channels will HOLD the last value received. You can use the `rxfail` cli command to change this behaviour, a channel can either HOLD it's last value or be SET to a specific value. +The `rxfail` cli command is used to configure per-channel rx-loss behaviour. +You can use the `rxfail` command to change this behaviour, a channel can either be AUTOMATIC, HOLD or SET. + +* AUTOMATIC - Flight channels are set to safe values (low throttle, mid position for yaw/pitch/roll), all AUX channels HOLD last value. +* HOLD - Channel holds the last value. +* SET - Channel is set to a specific configured value. + +The default mode for all channels is AUTOMATIC. The rxfail command can be used in conjunction with mode ranges to trigger various actions. -The `rxfail` command takes 3 arguments. +The `rxfail` command takes 2 or 3 arguments. * Index of aux channel (AUX1 = 0, AUX2 = 1,...) -* A mode ('h' = HOLD, 's' = SET) -* A value to use when in SET mode. (always required, even if using HOLD mode). +* Mode ('a' = AUTOMATIC, 'h' = HOLD, 's' = SET) +* A value to use when in SET mode. + +Channels are always specified in the same order, regardless of your channel mapping. + +* Roll is 0 +* Pitch is 1 +* Yaw is 2 +* Throttle is 3. +* Aux channels are 4 onwards. Examples: +To make Throttle channel have an automatic value when RX loss is detected: + +`rxfail 3 a` + To make AUX4 have a value of 2000 when RX loss is detected: -`rxfail 3 s 2000` +`rxfail 7 s 2000` To make AUX8 hold it's value when RX loss is detected: -`rxfail 7 h 1500` - -In the above example the '1500' will be ignored. +`rxfail 11 h` +WARNING: Always make sure you test the behavior is as expected after configuring rxfail settings! #### `rx_min_usec` diff --git a/src/main/config/config.c b/src/main/config/config.c index afdf373164..91f1ad9498 100644 --- a/src/main/config/config.c +++ b/src/main/config/config.c @@ -128,7 +128,7 @@ static uint32_t activeFeaturesLatch = 0; static uint8_t currentControlRateProfileIndex = 0; controlRateConfig_t *currentControlRateProfile; -static const uint8_t EEPROM_CONF_VERSION = 103; +static const uint8_t EEPROM_CONF_VERSION = 104; static void resetAccelerometerTrims(flightDynamicsTrims_t *accelerometerTrims) { @@ -405,10 +405,9 @@ static void resetConf(void) masterConfig.rxConfig.rx_min_usec = 885; // any of first 4 channels below this value will trigger rx loss detection masterConfig.rxConfig.rx_max_usec = 2115; // any of first 4 channels above this value will trigger rx loss detection - for (i = 0; i < MAX_AUX_CHANNEL_COUNT; i++) { - rxFailsafeChannelConfiguration_t *channelFailsafeConfiguration = &masterConfig.rxConfig.failsafe_aux_channel_configurations[i]; - - channelFailsafeConfiguration->mode = RX_FAILSAFE_MODE_HOLD; + for (i = 0; i < MAX_SUPPORTED_RC_CHANNEL_COUNT; i++) { + rxFailsafeChannelConfiguration_t *channelFailsafeConfiguration = &masterConfig.rxConfig.failsafe_channel_configurations[i]; + channelFailsafeConfiguration->mode = RX_FAILSAFE_MODE_AUTO; channelFailsafeConfiguration->step = CHANNEL_VALUE_TO_RXFAIL_STEP(masterConfig.rxConfig.midrc); } diff --git a/src/main/io/serial_cli.c b/src/main/io/serial_cli.c index fc37589f7b..0250e1d8bd 100644 --- a/src/main/io/serial_cli.c +++ b/src/main/io/serial_cli.c @@ -169,6 +169,9 @@ static const char * const featureNames[] = { "BLACKBOX", "CHANNEL_FORWARDING", NULL }; +// sync this with rxFailsafeChannelMode_e +static char rxFailsafeModes[RX_FAILSAFE_MODE_COUNT] = { 'a', 'h', 's'}; + #ifndef CJMCU // sync this with sensors_e static const char * const sensorTypeNames[] = { @@ -573,23 +576,28 @@ static void cliRxFail(char *cmdline) if (isEmpty(cmdline)) { // print out rxConfig failsafe settings - for (channel = 0; channel < MAX_AUX_CHANNEL_COUNT; channel++) { + for (channel = 0; channel < MAX_SUPPORTED_RC_CHANNEL_COUNT; channel++) { cliRxFail(itoa(channel, buf, 10)); } } else { char *ptr = cmdline; - channel = atoi(ptr++); - if ((channel < MAX_AUX_CHANNEL_COUNT)) { + if ((channel < MAX_SUPPORTED_RC_CHANNEL_COUNT)) { - rxFailsafeChannelConfiguration_t *channelFailsafeConfiguration = &masterConfig.rxConfig.failsafe_aux_channel_configurations[channel]; + rxFailsafeChannelConfiguration_t *channelFailsafeConfiguration = &masterConfig.rxConfig.failsafe_channel_configurations[channel]; uint16_t value; - rxFailsafeChannelMode_e mode; + rxFailsafeChannelMode_e mode = channelFailsafeConfiguration->mode; + bool requireValue = channelFailsafeConfiguration->mode == RX_FAILSAFE_MODE_SET; + // TODO optimize to use rxFailsafeModes - less logic. ptr = strchr(ptr, ' '); if (ptr) { switch (*(++ptr)) { + case 'a': + mode = RX_FAILSAFE_MODE_AUTO; + break; + case 'h': mode = RX_FAILSAFE_MODE_HOLD; break; @@ -601,34 +609,49 @@ static void cliRxFail(char *cmdline) cliShowParseError(); return; } - } - ptr = strchr(ptr, ' '); - if (ptr) { - value = atoi(++ptr); - value = CHANNEL_VALUE_TO_RXFAIL_STEP(value); - if (value > MAX_RXFAIL_RANGE_STEP) { - cliPrint("Value out of range\r\n"); - return; + requireValue = mode == RX_FAILSAFE_MODE_SET; + + ptr = strchr(ptr, ' '); + if (ptr) { + if (!requireValue) { + cliShowParseError(); + return; + } + value = atoi(++ptr); + value = CHANNEL_VALUE_TO_RXFAIL_STEP(value); + if (value > MAX_RXFAIL_RANGE_STEP) { + cliPrint("Value out of range\r\n"); + return; + } + + channelFailsafeConfiguration->step = value; } - channelFailsafeConfiguration->mode = mode; - channelFailsafeConfiguration->step = value; + } - char modeCharacter = channelFailsafeConfiguration->mode == RX_FAILSAFE_MODE_SET ? 's' : 'h'; + char modeCharacter = rxFailsafeModes[channelFailsafeConfiguration->mode]; + // triple use of printf below // 1. acknowledge interpretation on command, // 2. query current setting on single item, // 3. recursive use for full list. - printf("rxfail %u %c %d\r\n", - channel, - modeCharacter, - RXFAIL_STEP_TO_CHANNEL_VALUE(channelFailsafeConfiguration->step) - ); + if (requireValue) { + printf("rxfail %u %c %d\r\n", + channel, + modeCharacter, + RXFAIL_STEP_TO_CHANNEL_VALUE(channelFailsafeConfiguration->step) + ); + } else { + printf("rxfail %u %c\r\n", + channel, + modeCharacter + ); + } } else { - printf("channel must be < %u\r\n", MAX_AUX_CHANNEL_COUNT); + cliShowArgumentRangeError("channel", 0, MAX_SUPPORTED_RC_CHANNEL_COUNT - 1); } } } diff --git a/src/main/io/serial_msp.c b/src/main/io/serial_msp.c index 4fd0a9dfa1..66b0b5ec1b 100644 --- a/src/main/io/serial_msp.c +++ b/src/main/io/serial_msp.c @@ -1171,10 +1171,10 @@ static bool processOutCommand(uint8_t cmdMSP) break; case MSP_RXFAIL_CONFIG: - headSerialReply(3 * (rxRuntimeConfig.channelCount - NON_AUX_CHANNEL_COUNT)); - for (i = NON_AUX_CHANNEL_COUNT; i < rxRuntimeConfig.channelCount; i++) { - serialize8(masterConfig.rxConfig.failsafe_aux_channel_configurations[i - NON_AUX_CHANNEL_COUNT].mode); - serialize16(RXFAIL_STEP_TO_CHANNEL_VALUE(masterConfig.rxConfig.failsafe_aux_channel_configurations[i - NON_AUX_CHANNEL_COUNT].step)); + headSerialReply(3 * (rxRuntimeConfig.channelCount)); + for (i = 0; i < rxRuntimeConfig.channelCount; i++) { + serialize8(masterConfig.rxConfig.failsafe_channel_configurations[i].mode); + serialize16(RXFAIL_STEP_TO_CHANNEL_VALUE(masterConfig.rxConfig.failsafe_channel_configurations[i].step)); } break; @@ -1606,12 +1606,12 @@ static bool processInCommand(void) case MSP_SET_RXFAIL_CONFIG: { uint8_t channelCount = currentPort->dataSize / 3; - if (channelCount > MAX_AUX_CHANNEL_COUNT) { + if (channelCount > MAX_SUPPORTED_RC_CHANNEL_COUNT) { headSerialError(0); } else { - for (i = NON_AUX_CHANNEL_COUNT; i < channelCount; i++) { - masterConfig.rxConfig.failsafe_aux_channel_configurations[i - NON_AUX_CHANNEL_COUNT].mode = read8(); - masterConfig.rxConfig.failsafe_aux_channel_configurations[i - NON_AUX_CHANNEL_COUNT].step = CHANNEL_VALUE_TO_RXFAIL_STEP(read16()); + for (i = 0; i < channelCount; i++) { + masterConfig.rxConfig.failsafe_channel_configurations[i].mode = read8(); + masterConfig.rxConfig.failsafe_channel_configurations[i].step = CHANNEL_VALUE_TO_RXFAIL_STEP(read16()); } } } diff --git a/src/main/rx/rx.c b/src/main/rx/rx.c index ae91db6ee8..888b96a546 100644 --- a/src/main/rx/rx.c +++ b/src/main/rx/rx.c @@ -326,22 +326,23 @@ static uint16_t calculateNonDataDrivenChannel(uint8_t chan, uint16_t sample) static uint16_t getRxfailValue(uint8_t channel) { - switch (channel) { - case ROLL: - case PITCH: - case YAW: - return rxConfig->midrc; - case THROTTLE: - if (feature(FEATURE_3D)) - return rxConfig->midrc; - else - return rxConfig->rx_min_usec; - } - - rxFailsafeChannelConfiguration_t *channelFailsafeConfiguration = &rxConfig->failsafe_aux_channel_configurations[channel - NON_AUX_CHANNEL_COUNT]; + rxFailsafeChannelConfiguration_t *channelFailsafeConfiguration = &rxConfig->failsafe_channel_configurations[channel]; switch(channelFailsafeConfiguration->mode) { default: + case RX_FAILSAFE_MODE_AUTO: + switch (channel) { + case ROLL: + case PITCH: + case YAW: + return rxConfig->midrc; + case THROTTLE: + if (feature(FEATURE_3D)) + return rxConfig->midrc; + else + return rxConfig->rx_min_usec; + } + // fall though to HOLD if there's nothing specific to do. case RX_FAILSAFE_MODE_HOLD: return rcData[channel]; diff --git a/src/main/rx/rx.h b/src/main/rx/rx.h index 099f596efb..e6538cc12c 100644 --- a/src/main/rx/rx.h +++ b/src/main/rx/rx.h @@ -82,10 +82,13 @@ extern int16_t rcData[MAX_SUPPORTED_RC_CHANNEL_COUNT]; // interval [1000;2 #define RSSI_SCALE_DEFAULT 30 typedef enum { - RX_FAILSAFE_MODE_HOLD = 0, - RX_FAILSAFE_MODE_SET + RX_FAILSAFE_MODE_AUTO = 0, + RX_FAILSAFE_MODE_HOLD, + RX_FAILSAFE_MODE_SET, } rxFailsafeChannelMode_e; +#define RX_FAILSAFE_MODE_COUNT 3 + typedef struct rxFailsafeChannelConfiguration_s { uint8_t mode; // See rxFailsafeChannelMode_e uint8_t step; @@ -109,7 +112,7 @@ typedef struct rxConfig_s { uint16_t rx_min_usec; uint16_t rx_max_usec; - rxFailsafeChannelConfiguration_t failsafe_aux_channel_configurations[MAX_AUX_CHANNEL_COUNT]; + rxFailsafeChannelConfiguration_t failsafe_channel_configurations[MAX_SUPPORTED_RC_CHANNEL_COUNT]; rxChannelRangeConfiguration_t channelRanges[NON_AUX_CHANNEL_COUNT]; } rxConfig_t;