mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-15 20:35:33 +03:00
Failsafe - Add rxfail auto
mode. Allow rxfail to be used for all
channels, not just aux channel.
This commit is contained in:
parent
5142ff032a
commit
a030d4dd9e
6 changed files with 105 additions and 61 deletions
38
docs/Rx.md
38
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.
|
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:
|
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.
|
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`.
|
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 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,...)
|
* Index of aux channel (AUX1 = 0, AUX2 = 1,...)
|
||||||
* A mode ('h' = HOLD, 's' = SET)
|
* Mode ('a' = AUTOMATIC, 'h' = HOLD, 's' = SET)
|
||||||
* A value to use when in SET mode. (always required, even if using HOLD mode).
|
* 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:
|
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:
|
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:
|
To make AUX8 hold it's value when RX loss is detected:
|
||||||
|
|
||||||
`rxfail 7 h 1500`
|
`rxfail 11 h`
|
||||||
|
|
||||||
In the above example the '1500' will be ignored.
|
|
||||||
|
|
||||||
|
WARNING: Always make sure you test the behavior is as expected after configuring rxfail settings!
|
||||||
|
|
||||||
#### `rx_min_usec`
|
#### `rx_min_usec`
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ static uint32_t activeFeaturesLatch = 0;
|
||||||
static uint8_t currentControlRateProfileIndex = 0;
|
static uint8_t currentControlRateProfileIndex = 0;
|
||||||
controlRateConfig_t *currentControlRateProfile;
|
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)
|
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_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
|
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++) {
|
for (i = 0; i < MAX_SUPPORTED_RC_CHANNEL_COUNT; i++) {
|
||||||
rxFailsafeChannelConfiguration_t *channelFailsafeConfiguration = &masterConfig.rxConfig.failsafe_aux_channel_configurations[i];
|
rxFailsafeChannelConfiguration_t *channelFailsafeConfiguration = &masterConfig.rxConfig.failsafe_channel_configurations[i];
|
||||||
|
channelFailsafeConfiguration->mode = RX_FAILSAFE_MODE_AUTO;
|
||||||
channelFailsafeConfiguration->mode = RX_FAILSAFE_MODE_HOLD;
|
|
||||||
channelFailsafeConfiguration->step = CHANNEL_VALUE_TO_RXFAIL_STEP(masterConfig.rxConfig.midrc);
|
channelFailsafeConfiguration->step = CHANNEL_VALUE_TO_RXFAIL_STEP(masterConfig.rxConfig.midrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -169,6 +169,9 @@ static const char * const featureNames[] = {
|
||||||
"BLACKBOX", "CHANNEL_FORWARDING", NULL
|
"BLACKBOX", "CHANNEL_FORWARDING", NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// sync this with rxFailsafeChannelMode_e
|
||||||
|
static char rxFailsafeModes[RX_FAILSAFE_MODE_COUNT] = { 'a', 'h', 's'};
|
||||||
|
|
||||||
#ifndef CJMCU
|
#ifndef CJMCU
|
||||||
// sync this with sensors_e
|
// sync this with sensors_e
|
||||||
static const char * const sensorTypeNames[] = {
|
static const char * const sensorTypeNames[] = {
|
||||||
|
@ -573,23 +576,28 @@ static void cliRxFail(char *cmdline)
|
||||||
|
|
||||||
if (isEmpty(cmdline)) {
|
if (isEmpty(cmdline)) {
|
||||||
// print out rxConfig failsafe settings
|
// 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));
|
cliRxFail(itoa(channel, buf, 10));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
char *ptr = cmdline;
|
char *ptr = cmdline;
|
||||||
|
|
||||||
channel = atoi(ptr++);
|
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;
|
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, ' ');
|
ptr = strchr(ptr, ' ');
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
switch (*(++ptr)) {
|
switch (*(++ptr)) {
|
||||||
|
case 'a':
|
||||||
|
mode = RX_FAILSAFE_MODE_AUTO;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
mode = RX_FAILSAFE_MODE_HOLD;
|
mode = RX_FAILSAFE_MODE_HOLD;
|
||||||
break;
|
break;
|
||||||
|
@ -601,34 +609,49 @@ static void cliRxFail(char *cmdline)
|
||||||
cliShowParseError();
|
cliShowParseError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ptr = strchr(ptr, ' ');
|
requireValue = mode == RX_FAILSAFE_MODE_SET;
|
||||||
if (ptr) {
|
|
||||||
value = atoi(++ptr);
|
ptr = strchr(ptr, ' ');
|
||||||
value = CHANNEL_VALUE_TO_RXFAIL_STEP(value);
|
if (ptr) {
|
||||||
if (value > MAX_RXFAIL_RANGE_STEP) {
|
if (!requireValue) {
|
||||||
cliPrint("Value out of range\r\n");
|
cliShowParseError();
|
||||||
return;
|
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->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
|
// triple use of printf below
|
||||||
// 1. acknowledge interpretation on command,
|
// 1. acknowledge interpretation on command,
|
||||||
// 2. query current setting on single item,
|
// 2. query current setting on single item,
|
||||||
// 3. recursive use for full list.
|
// 3. recursive use for full list.
|
||||||
|
|
||||||
printf("rxfail %u %c %d\r\n",
|
if (requireValue) {
|
||||||
channel,
|
printf("rxfail %u %c %d\r\n",
|
||||||
modeCharacter,
|
channel,
|
||||||
RXFAIL_STEP_TO_CHANNEL_VALUE(channelFailsafeConfiguration->step)
|
modeCharacter,
|
||||||
);
|
RXFAIL_STEP_TO_CHANNEL_VALUE(channelFailsafeConfiguration->step)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
printf("rxfail %u %c\r\n",
|
||||||
|
channel,
|
||||||
|
modeCharacter
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
printf("channel must be < %u\r\n", MAX_AUX_CHANNEL_COUNT);
|
cliShowArgumentRangeError("channel", 0, MAX_SUPPORTED_RC_CHANNEL_COUNT - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1171,10 +1171,10 @@ static bool processOutCommand(uint8_t cmdMSP)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSP_RXFAIL_CONFIG:
|
case MSP_RXFAIL_CONFIG:
|
||||||
headSerialReply(3 * (rxRuntimeConfig.channelCount - NON_AUX_CHANNEL_COUNT));
|
headSerialReply(3 * (rxRuntimeConfig.channelCount));
|
||||||
for (i = NON_AUX_CHANNEL_COUNT; i < rxRuntimeConfig.channelCount; i++) {
|
for (i = 0; i < rxRuntimeConfig.channelCount; i++) {
|
||||||
serialize8(masterConfig.rxConfig.failsafe_aux_channel_configurations[i - NON_AUX_CHANNEL_COUNT].mode);
|
serialize8(masterConfig.rxConfig.failsafe_channel_configurations[i].mode);
|
||||||
serialize16(RXFAIL_STEP_TO_CHANNEL_VALUE(masterConfig.rxConfig.failsafe_aux_channel_configurations[i - NON_AUX_CHANNEL_COUNT].step));
|
serialize16(RXFAIL_STEP_TO_CHANNEL_VALUE(masterConfig.rxConfig.failsafe_channel_configurations[i].step));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1606,12 +1606,12 @@ static bool processInCommand(void)
|
||||||
case MSP_SET_RXFAIL_CONFIG:
|
case MSP_SET_RXFAIL_CONFIG:
|
||||||
{
|
{
|
||||||
uint8_t channelCount = currentPort->dataSize / 3;
|
uint8_t channelCount = currentPort->dataSize / 3;
|
||||||
if (channelCount > MAX_AUX_CHANNEL_COUNT) {
|
if (channelCount > MAX_SUPPORTED_RC_CHANNEL_COUNT) {
|
||||||
headSerialError(0);
|
headSerialError(0);
|
||||||
} else {
|
} else {
|
||||||
for (i = NON_AUX_CHANNEL_COUNT; i < channelCount; i++) {
|
for (i = 0; i < channelCount; i++) {
|
||||||
masterConfig.rxConfig.failsafe_aux_channel_configurations[i - NON_AUX_CHANNEL_COUNT].mode = read8();
|
masterConfig.rxConfig.failsafe_channel_configurations[i].mode = read8();
|
||||||
masterConfig.rxConfig.failsafe_aux_channel_configurations[i - NON_AUX_CHANNEL_COUNT].step = CHANNEL_VALUE_TO_RXFAIL_STEP(read16());
|
masterConfig.rxConfig.failsafe_channel_configurations[i].step = CHANNEL_VALUE_TO_RXFAIL_STEP(read16());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -326,22 +326,23 @@ static uint16_t calculateNonDataDrivenChannel(uint8_t chan, uint16_t sample)
|
||||||
|
|
||||||
static uint16_t getRxfailValue(uint8_t channel)
|
static uint16_t getRxfailValue(uint8_t channel)
|
||||||
{
|
{
|
||||||
switch (channel) {
|
rxFailsafeChannelConfiguration_t *channelFailsafeConfiguration = &rxConfig->failsafe_channel_configurations[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];
|
|
||||||
|
|
||||||
switch(channelFailsafeConfiguration->mode) {
|
switch(channelFailsafeConfiguration->mode) {
|
||||||
default:
|
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:
|
case RX_FAILSAFE_MODE_HOLD:
|
||||||
return rcData[channel];
|
return rcData[channel];
|
||||||
|
|
||||||
|
|
|
@ -82,10 +82,13 @@ extern int16_t rcData[MAX_SUPPORTED_RC_CHANNEL_COUNT]; // interval [1000;2
|
||||||
#define RSSI_SCALE_DEFAULT 30
|
#define RSSI_SCALE_DEFAULT 30
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RX_FAILSAFE_MODE_HOLD = 0,
|
RX_FAILSAFE_MODE_AUTO = 0,
|
||||||
RX_FAILSAFE_MODE_SET
|
RX_FAILSAFE_MODE_HOLD,
|
||||||
|
RX_FAILSAFE_MODE_SET,
|
||||||
} rxFailsafeChannelMode_e;
|
} rxFailsafeChannelMode_e;
|
||||||
|
|
||||||
|
#define RX_FAILSAFE_MODE_COUNT 3
|
||||||
|
|
||||||
typedef struct rxFailsafeChannelConfiguration_s {
|
typedef struct rxFailsafeChannelConfiguration_s {
|
||||||
uint8_t mode; // See rxFailsafeChannelMode_e
|
uint8_t mode; // See rxFailsafeChannelMode_e
|
||||||
uint8_t step;
|
uint8_t step;
|
||||||
|
@ -109,7 +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;
|
||||||
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];
|
rxChannelRangeConfiguration_t channelRanges[NON_AUX_CHANNEL_COUNT];
|
||||||
} rxConfig_t;
|
} rxConfig_t;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue