[Betaflight] 電能與電池監視設定


在Betaflight 4.2.x的電能與電池 (Power & Battery) 設定項目中,你可以設定電池的電壓、電流與電量監控的一些參數。涵蓋「電池 Battery」、「電壓計 Voltage Meter」、「電流計 Amperage Meter」跟 「電能狀態」這幾個項目。

Omnibus F4 採用的 MCU  STM32F405 本身有內建類比數位轉換器 (ADC, Analog to Digital Converter),可以從 Vbat 腳位,讀取電池的電壓,然轉成數位值顯示出來,不需要第三方零件,你也可以選擇從有內建電池監測的高階ESC電調讀取。Betaflight 透過電壓、電流測量,對應時間積分,就能知道電池的消耗量,並顯示在右邊的【電能狀態Power State】欄位。

若你要用F4內建的ADC監控電池的電壓,你必須從 ESC 電調板的電池電壓 Vbat+  連接到 Vbat 上,才能讀值 (Vbat- 基本上不需要接到 F4飛控的 GND,因為排線裡面就有接了)。至於電流,如果你不想外接電流計到CRNT電流偵測針腳的話,Betaflight有提供虛擬電流計的功能,用馬達輸出大略估一下消耗的電流。

以內建ADC測量電壓

STM32F405 MPU 內建的類比-數位轉換器,解析度是 12位元,可以將測量範圍內的電壓,切割成 2^12 = 4096 等分。以標準 3.3V參考電壓的範圍來說,等同於 3.3V / 4096 = 0.000806V,也就是 0.8mV左右的精度。

根據 Betaflight 原始碼,main/sensors/voltage.c 中換算ADC值到實際電壓的計算函式內容:

STATIC_UNIT_TESTED uint16_t voltageAdcToVoltage(const uint16_t src, const voltageSensorADCConfig_t *config)
{
    // calculate battery voltage based on ADC reading
    // result is Vbatt in 0.01V steps. 3.3V = ADC Vref, 0xFFF = 12bit adc, 110 = 10:1 voltage divider (10k:1k) * 100 for 0.01V
    return ((((uint32_t)src * config->vbatscale * getVrefMv() / 10 + (0xFFF * 5)) / (0xFFF * config->vbatresdivval)) / config->vbatresdivmultiplier);
}

公式是這麼算的:

((MCU的ADC值 * 放大倍率(Scale, 110) * 參考電壓[3.3V] / 10 [把mV變成10mV步階] + 4096 * 5) / (4096 * 電阻分壓比例 [Divider Value,10])) / 放大倍率[Multiplier Value, 1, 正常沒放大]

getVrefMv() 這個函數,會傳回參考電壓值,除非有另外定義參考電壓,否則預設是 3300mV,也就是 3.3V:

uint16_t getVrefMv(void)
{
#ifdef ADC_VOLTAGE_REFERENCE_MV
    return ADC_VOLTAGE_REFERENCE_MV;
#else
    return 3300;
#endif
}

每次 Betaflight 韌體要更新電池電壓的時候,會呼叫 main/sensors/battery.c 裡面的這個batteryUpdateVoltage 函數,選擇Omnibus內建的 ADC就會執行 VOLTAGE_METER_ADC下面那段程式:

void batteryUpdateVoltage(timeUs_t currentTimeUs)
{
    UNUSED(currentTimeUs);
    switch (batteryConfig()->voltageMeterSource) {
#ifdef USE_ESC_SENSOR
        case VOLTAGE_METER_ESC:
            if (featureIsEnabled(FEATURE_ESC_SENSOR)) {
                voltageMeterESCRefresh();
                voltageMeterESCReadCombined(&voltageMeter);
            }
            break;
#endif
        case VOLTAGE_METER_ADC:
            voltageMeterADCRefresh();
            voltageMeterADCRead(VOLTAGE_SENSOR_ADC_VBAT, &voltageMeter);
            break;
        default:
        case VOLTAGE_METER_NONE:
            voltageMeterReset(&voltageMeter);
            break;
    }
    DEBUG_SET(DEBUG_BATTERY, 0, voltageMeter.unfiltered);
    DEBUG_SET(DEBUG_BATTERY, 1, voltageMeter.displayFiltered);
}

(本文未完成,待續)

沒有留言:

張貼留言