BetaFlight模块设计之三十五:RSSI信号强度&链路稳定性分析

本文详细探讨了BetaFlight开源飞控中RSSI信号强度和链路稳定性的设计与实现,包括RSSIValue、RSSIdBmValue的获取与过滤处理,以及链路质量的计算。通过分析不同数据源如ADC、RX_CHANNEL、MSP和RX_PROTOCOL_CRSF,展示了如何利用这些信息来评估遥控器通信链路的可靠性和稳定性。此外,还提到了OSD上显示的LinkQuality信息及其多种显示模式。
摘要由CSDN通过智能技术生成

基于BetaFlight开源代码框架简介的框架设计,逐步分析内部模块功能设计。这里主要针对四轴飞控DIY集成FPV功能第七章节调试遇到的问题,进一步深入分析和理解。

航模主要通过遥控器或者数传两个通道进行控制,而BetaFlight这种穿越机最主要的方式还是通过遥控器。

遥控器控制飞控这个通道的可靠性、稳定性需要通过这个通信链路的一些指标量化体现,从BetaFlight代码上看,主要有以下几个指标:

  1. RSSI信号强度
  • Value
  • dBm
  1. 链路质量(Link Quality)

1. RSSI信号强度

定时更新RSSI信号强度,并将强度值范围线性映射到0-100之间。值越大表示信号强度越大,值为0表示信号丢失(飞控进入failsafe模式)。

1.1 RSSI Value

RSSI Value设置的几种方式:

  1. 直接设置:主要取决于数据发送端对数据的处理和定义
  2. 过滤处理:PT1低频滤波或者算术平均滤波
  3. MSP设置:根据MSP协议,对MSP对端RSSI值乘以2^2
void setRssiDirect(uint16_t newRssi, rssiSource_e source)
{
    if (source != rssiSource) {
        return;
    }

    rssi = newRssi;
}

void setRssi(uint16_t rssiValue, rssiSource_e source)
{
    if (source != rssiSource) {
        return;
    }

    // Filter RSSI value
    if (source == RSSI_SOURCE_FRAME_ERRORS) {
        rssi = pt1FilterApply(&frameErrFilter, rssiValue);
    } else {
        // calculate new sample mean
        rssi = updateRssiSamples(rssiValue);
    }
}

void setRssiMsp(uint8_t newMspRssi)
{
    if (rssiSource == RSSI_SOURCE_NONE) {
        rssiSource = RSSI_SOURCE_MSP;
    }

    if (rssiSource == RSSI_SOURCE_MSP) {
        rssi = ((uint16_t)newMspRssi) << 2;
        lastMspRssiUpdateUs = micros();
    }
}

1.2 RSSI dBm Value

RSSI dBm Value设置的几种方式:

  1. 直接设置:主要取决于数据发送端对数据的处理和定义
  2. 过滤处理:算术平均滤波
void setRssiDbmDirect(int16_t newRssiDbm, rssiSource_e source)
{
    if (source != rssiSource) {
        return;
    }

    rssiDbm = newRssiDbm;
}

void setRssiDbm(int16_t rssiDbmValue, rssiSource_e source)
{
    if (source != rssiSource) {
        return;
    }

    rssiDbm = updateRssiDbmSamples(rssiDbmValue);
}

2. 链路稳定性

  1. 直接设置:主要取决于数据发送端对数据的处理和定义
  2. 丢包率计算:计算最近16个报文的丢包率
void setLinkQualityDirect(uint16_t linkqualityValue)
{
#ifdef USE_RX_LINK_QUALITY_INFO
    linkQuality = linkqualityValue;
#else
    UNUSED(linkqualityValue);
#endif
}

static void setLinkQuality(bool validFrame, timeDelta_t currentDeltaTimeUs)
{
    static uint16_t rssiSum = 0;
    static uint16_t rssiCount = 0;
    static timeDelta_t resampleTimeUs = 0;

#ifdef USE_RX_LINK_QUALITY_INFO
    if (linkQualitySource == LQ_SOURCE_NONE) {
        // calculate new sample mean
        linkQuality = updateLinkQualitySamples(validFrame ? LINK_QUALITY_MAX_VALUE : 0);
    }
#endif

    if (rssiSource == RSSI_SOURCE_FRAME_ERRORS) {
        resampleTimeUs += currentDeltaTimeUs;
        rssiSum += validFrame ? RSSI_MAX_VALUE : 0;
        rssiCount++;

        if (resampleTimeUs >= FRAME_ERR_RESAMPLE_US) {
            setRssi(rssiSum / rssiCount, rssiSource);
            rssiSum = 0;
            rssiCount = 0;
            resampleTimeUs -= FRAME_ERR_RESAMPLE_US;
        }
    }
}

STATIC_UNIT_TESTED uint16_t updateLinkQualitySamples(uint16_t value)
{
    static uint16_t samples[LINK_QUALITY_SAMPLE_COUNT];
    static uint8_t sampleIndex = 0;
    static uint16_t sum = 0;

    sum += value - samples[sampleIndex];
    samples[sampleIndex] = value;
    sampleIndex = (sampleIndex + 1) % LINK_QUALITY_SAMPLE_COUNT;
    return sum / LINK_QUALITY_SAMPLE_COUNT;
}

3. RSSI & LinkQuality来源

3.1 RSSI_SOURCE_ADC

  1. 【RSSI Value】数据源来自ADC模拟采样,通过过滤处理进行数据保存。
  2. 【LinkQuality】此时没有LinkQuality来源。
static void updateRSSIADC(timeUs_t currentTimeUs)
{
#ifndef USE_ADC
    UNUSED(currentTimeUs);
#else
    static uint32_t rssiUpdateAt = 0;

    if ((int32_t)(currentTimeUs - rssiUpdateAt) < 0) {
        return;
    }
    rssiUpdateAt = currentTimeUs + DELAY_20_MS;

    const uint16_t adcRssiSample = adcGetChannel(ADC_RSSI);
    uint16_t rssiValue = adcRssiSample / RSSI_ADC_DIVISOR;

    setRssi(rssiValue, RSSI_SOURCE_ADC);
#endif
}

3.2 RSSI_SOURCE_RX_CHANNEL

  1. 【RSSI Value】数据源来自AUX Channel[1000;2000],直接scaleRange进行0-100的百分比线性映射。
  2. 【LinkQuality】rxFrameCheck通过setLinkQuality进行丢包率计算。
static void updateRSSIPWM(void)
{
    // Read value of AUX channel as rssi
    int16_t pwmRssi = rcData[rxConfig()->rssi_channel - 1];

    // Range of rawPwmRssi is [1000;2000]. rssi should be in [0;1023];
    setRssiDirect(scaleRange(constrain(pwmRssi, PWM_RANGE_MIN, PWM_RANGE_MAX), PWM_RANGE_MIN, PWM_RANGE_MAX, 0, RSSI_MAX_VALUE), RSSI_SOURCE_RX_CHANNEL);
}

3.3 RSSI_SOURCE_MSP

  1. 【RSSI Value】根据MSP协议调用专用函数setRssiMsp设置信号强度;当DELAY_1500_MS超时,信号强度强制赋值零。
  2. 【LinkQuality】rxFrameCheck通过setLinkQuality进行丢包率计算。
\src\main\msp\msp.c
    case MSP_SET_TX_INFO:
        setRssiMsp(sbufReadU8(src));

        break;
\src\main\rx\rx.c
    case RSSI_SOURCE_MSP:
        if (cmpTimeUs(micros(), lastMspRssiUpdateUs) > DELAY_1500_MS) {  // 1.5s
            rssi = 0;
        }

3.4 RSSI_SOURCE_RX_PROTOCOL_CRSF

  1. 【RSSI Value】来自于CRSF_FRAMETYPE_LINK_STATISTICS或者CRSF_FRAMETYPE_LINK_STATISTICS_TX报文
  2. 【RSSI dBm】来自于CRSF_FRAMETYPE_LINK_STATISTICS或者CRSF_FRAMETYPE_LINK_STATISTICS_TX报文
  3. 【LinkQuality】来自于CRSF_FRAMETYPE_LINK_STATISTICS或者CRSF_FRAMETYPE_LINK_STATISTICS_TX报文

注:CRSF具有双向通信功能以及协商速率的功能,BetaFlight模块设计之二十三:CRSF V3串口速率协商任务分析

3.4.1 CRSF_FRAMETYPE_LINK_STATISTICS

该报文使用链路统计数据:

  1. SNR映射:-10dB of SNR mapped to 0; 0dB of SNR mapped to 20; 41dB of SNR mapped to 99
  2. CRSF_RSSI_MIN(-130)-0线性映射
  3. 算术平均AUX Channel的rssiDbm
static void handleCrsfLinkStatisticsFrame(const crsfLinkStatistics_t* statsPtr, timeUs_t currentTimeUs)
{
    const crsfLinkStatistics_t stats = *statsPtr;
    lastLinkStatisticsFrameUs = currentTimeUs;
    int16_t rssiDbm = -1 * (stats.active_antenna ? stats.uplink_RSSI_2 : stats.uplink_RSSI_1);
    if (rssiSource == RSSI_SOURCE_RX_PROTOCOL_CRSF) {
        if (rxConfig()->crsf_use_rx_snr) {
            // -10dB of SNR mapped to 0 RSSI (fail safe is likely to happen at this measure)
            //   0dB of SNR mapped to 20 RSSI (default alarm)
            //  41dB of SNR mapped to 99 RSSI (SNR can climb to around 60, but showing that is not very meaningful)
            const uint16_t rsnrPercentScaled = constrain((stats.uplink_SNR + 10) * 20, 0, RSSI_MAX_VALUE);
            setRssi(rsnrPercentScaled, RSSI_SOURCE_RX_PROTOCOL_CRSF);
#ifdef USE_RX_RSSI_DBM
            rssiDbm = stats.uplink_SNR;
#endif
        } else {
            const uint16_t rssiPercentScaled = scaleRange(rssiDbm, CRSF_RSSI_MIN, 0, 0, RSSI_MAX_VALUE);
            setRssi(rssiPercentScaled, RSSI_SOURCE_RX_PROTOCOL_CRSF);
        }
    }
#ifdef USE_RX_RSSI_DBM
    setRssiDbm(rssiDbm, RSSI_SOURCE_RX_PROTOCOL_CRSF);
#endif

#ifdef USE_RX_LINK_QUALITY_INFO
    if (linkQualitySource == LQ_SOURCE_RX_PROTOCOL_CRSF) {
        setLinkQualityDirect(stats.uplink_Link_quality);
        rxSetRfMode(stats.rf_Mode);
    }
#endif

#ifdef USE_RX_LINK_UPLINK_POWER
    const uint8_t crsfUplinkPowerStatesItemIndex = (stats.uplink_TX_Power < CRSF_UPLINK_POWER_LEVEL_MW_ITEMS_COUNT) ? stats.uplink_TX_Power : 0;
    rxSetUplinkTxPwrMw(uplinkTXPowerStatesMw[crsfUplinkPowerStatesItemIndex]);
#endif

    DEBUG_SET(DEBUG_CRSF_LINK_STATISTICS_UPLINK, 0, stats.uplink_RSSI_1);
    DEBUG_SET(DEBUG_CRSF_LINK_STATISTICS_UPLINK, 1, stats.uplink_RSSI_2);
    DEBUG_SET(DEBUG_CRSF_LINK_STATISTICS_UPLINK, 2, stats.uplink_Link_quality);
    DEBUG_SET(DEBUG_CRSF_LINK_STATISTICS_UPLINK, 3, stats.rf_Mode);

    DEBUG_SET(DEBUG_CRSF_LINK_STATISTICS_PWR, 0, stats.active_antenna);
    DEBUG_SET(DEBUG_CRSF_LINK_STATISTICS_PWR, 1, stats.uplink_SNR);
    DEBUG_SET(DEBUG_CRSF_LINK_STATISTICS_PWR, 2, stats.uplink_TX_Power);

    DEBUG_SET(DEBUG_CRSF_LINK_STATISTICS_DOWN, 0, stats.downlink_RSSI);
    DEBUG_SET(DEBUG_CRSF_LINK_STATISTICS_DOWN, 1, stats.downlink_Link_quality);
    DEBUG_SET(DEBUG_CRSF_LINK_STATISTICS_DOWN, 2, stats.downlink_SNR);
}

3.4.2 CRSF_FRAMETYPE_LINK_STATISTICS_TX

该报文CRSF_V3使用,链路统计数据:

  1. 线性映射AUX Channel的uplink_RSSI_percentage
  2. 算术平均(-1 * stats.uplink_RSSI)
  3. 算术平均(stats.uplink_SNR)
static void handleCrsfLinkStatisticsTxFrame(const crsfLinkStatisticsTx_t* statsPtr, timeUs_t currentTimeUs)
{
    const crsfLinkStatisticsTx_t stats = *statsPtr;
    lastLinkStatisticsFrameUs = currentTimeUs;
    if (rssiSource == RSSI_SOURCE_RX_PROTOCOL_CRSF) {
        const uint16_t rssiPercentScaled = scaleRange(stats.uplink_RSSI_percentage, 0, 100, 0, RSSI_MAX_VALUE);
        setRssi(rssiPercentScaled, RSSI_SOURCE_RX_PROTOCOL_CRSF);
    }
#ifdef USE_RX_RSSI_DBM
    int16_t rssiDbm = -1 * stats.uplink_RSSI;
    if (rxConfig()->crsf_use_rx_snr) {
        rssiDbm = stats.uplink_SNR;
    }
    setRssiDbm(rssiDbm, RSSI_SOURCE_RX_PROTOCOL_CRSF);
#endif

#ifdef USE_RX_LINK_QUALITY_INFO
    if (linkQualitySource == LQ_SOURCE_RX_PROTOCOL_CRSF) {
        setLinkQualityDirect(stats.uplink_Link_quality);
    }
#endif

    DEBUG_SET(DEBUG_CRSF_LINK_STATISTICS_UPLINK, 0, stats.uplink_RSSI);
    DEBUG_SET(DEBUG_CRSF_LINK_STATISTICS_UPLINK, 1, stats.uplink_SNR);
    DEBUG_SET(DEBUG_CRSF_LINK_STATISTICS_UPLINK, 2, stats.uplink_Link_quality);
    DEBUG_SET(DEBUG_CRSF_LINK_STATISTICS_UPLINK, 3, stats.uplink_RSSI_percentage);
}

3.4.3 rxFrameCheck

超时场景下直接将RSSI Value & RSSI dBm以及链路质量清零。

static void crsfCheckRssi(uint32_t currentTimeUs) {

    if (cmpTimeUs(currentTimeUs, lastLinkStatisticsFrameUs) > CRSF_LINK_STATUS_UPDATE_TIMEOUT_US) {
        if (rssiSource == RSSI_SOURCE_RX_PROTOCOL_CRSF) {
            setRssiDirect(0, RSSI_SOURCE_RX_PROTOCOL_CRSF);
#ifdef USE_RX_RSSI_DBM
            if (rxConfig()->crsf_use_rx_snr) {
                setRssiDbmDirect(CRSF_SNR_MIN, RSSI_SOURCE_RX_PROTOCOL_CRSF);
            } else {
                setRssiDbmDirect(CRSF_RSSI_MIN, RSSI_SOURCE_RX_PROTOCOL_CRSF);
            }
#endif
        }
#ifdef USE_RX_LINK_QUALITY_INFO
        if (linkQualitySource == LQ_SOURCE_RX_PROTOCOL_CRSF) {
            setLinkQualityDirect(0);
        }
#endif
    }
}

4. 其他协议

TBD,比如:SRXL2, 代码链接

注:后续再做更新,分析方法类似。

5. 补充:OSD显示LQ

LinkQuality在OSD显示的时候,支持三种模式:

1. LQ_SOURCE_RX_PROTOCOL_CRSF:“%c%1d:%2d”

1)可参考:下面第一第二张图
2)%c:LQ图标
3)%1d:包速率,范围(0 - 7),与elrsRfRate_e定义相反;表达式:RATE_4HZ(7) - 设定速率;
第一张图3表示7-4=3,实际设定速率RATE_100HZ(4)
第二张图5表示7-2=5,实际设定速率RATE_200HZ(2)
4)%2d:信号质量,范围(0 - 100)

2. LQ_SOURCE_RX_PROTOCOL_GHST:“%c%2d”

1)笔者没有这个协议的设备,所以暂时没有这个图
2)%c:LQ图标
3)%2d:信号质量,范围(0 - 100)

3. 其他:“%c%1d”

1)可参考:下面第三张图
2)%1d:信号质量,范围(0 - 9)

5. 1 BetaFlight Kakute F7 AIO F450 + NorthCityPark

BetaFlight Kakute F7 AIO F450 + 城北公园

LQ 3:100

5. 2 BetaFlight Kakute F7 RX Signal Lost (ELRS 50mW+Dynamic)

BetaFlight Kakute F7 RX Signal Lost (ELRS 50mW+Dynamic)

LQ 5:100

5. 3 BetaFlight Kakute F7 AIO F450 + AT9SPro + R12DSM可视通信测距

BetaFlight Kakute F7 AIO F450 + AT9SPro + R12DSM可视通信测距

LQ 9

5. 4 相关代码

#ifdef USE_RX_LINK_QUALITY_INFO
static void osdElementLinkQuality(osdElementParms_t *element)
{
    uint16_t osdLinkQuality = 0;
    if (linkQualitySource == LQ_SOURCE_RX_PROTOCOL_CRSF) { // 0-99
        osdLinkQuality = rxGetLinkQuality();
        const uint8_t osdRfMode = rxGetRfMode();
        tfp_sprintf(element->buff, "%c%1d:%2d", SYM_LINK_QUALITY, osdRfMode, osdLinkQuality);
    } else if (linkQualitySource == LQ_SOURCE_RX_PROTOCOL_GHST) { // 0-100
        osdLinkQuality = rxGetLinkQuality();
        tfp_sprintf(element->buff, "%c%2d", SYM_LINK_QUALITY, osdLinkQuality);
    } else { // 0-9
        osdLinkQuality = rxGetLinkQuality() * 10 / LINK_QUALITY_MAX_VALUE;
        if (osdLinkQuality >= 10) {
            osdLinkQuality = 9;
        }
        tfp_sprintf(element->buff, "%c%1d", SYM_LINK_QUALITY, osdLinkQuality);
    }
}
#endif // USE_RX_LINK_QUALITY_INFO
typedef enum {
    RATE_500HZ = 0,
    RATE_250HZ = 1,
    RATE_200HZ = 2,
    RATE_150HZ = 3,
    RATE_100HZ = 4,
    RATE_50HZ = 5,
    RATE_25HZ = 6,
    RATE_4HZ = 7,
} elrsRfRate_e; // Max value of 16 since only 4 bits have been assigned in the sync package.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值