Betaflight - 领先的开源飞行控制器固件

5 阅读6分钟

Betaflight 飞行控制器固件

Betaflight 是一款为多旋翼和固定翼飞行器设计的高性能飞行控制器软件(固件)。它源自Cleanflight,专注于提供顶级的飞行性能、前沿的功能特性以及对广泛硬件平台的支持。

功能特性

  • 极致飞行性能:专为竞速和花式飞行优化的核心算法,提供流畅、响应迅速的操控体验。
  • 黑匣子日志(Blackbox):记录飞行数据,支持SD卡、Flash和串口等多种存储设备,方便事后分析飞行姿态、PID响应和电机输出。
  • 板载设置菜单(CMS/OSD):通过遥控器和图传屏幕即可配置PID、速率、VTX、LED灯带等几乎所有参数,无需连接地面站。
  • 全面的GPS支持:支持GPS定位,具备GPS救援模式,在失控时自动返航,并支持GPS圈速计时功能。
  • 丰富的调试工具:内置多种调试模式,可实时监控循环时间、电池数据、滤波器状态、PID输出等关键指标。
  • 多平台硬件支持:支持STM32F4、F7、H7、G4、APM32、AT32、RP2350等多种MCU,适配各类飞控硬件。
  • 灵活的通信协议:支持DShot、ProShot、MultiShot等多种电调协议,并兼容CRSF、SBUS、FPORT、GHST等主流接收机协议。
  • 可配置的LED灯带:支持可编程的RGB LED灯带,用于状态指示、视觉报时和竞速效果。

安装指南

系统要求

  • 支持的目标飞控板(如MATEK、Holybro、iFlight等品牌的F7/H7系列飞控)
  • Windows/Linux/macOS操作系统
  • Betaflight Configurator地面站(用于固件烧录和基础配置)

烧录步骤

  1. 下载并安装 Betaflight Configurator
  2. 通过USB将飞控连接到电脑。
  3. 打开Configurator,选择正确的串口并连接。
  4. 进入“固件烧录”选项卡,选择您的飞控目标(Target)和固件版本。
  5. 点击“烧录固件”,等待烧录完成。
# 也可以使用命令行工具通过STM32CubeProgrammer烧录
STM32_Programmer_CLI -c port=USB1 -d betaflight_4.5.0_MATEKF722SE.hex -hardRst

从源码构建

# 克隆仓库
git clone https://github.com/betaflight/betaflight.git
cd betaflight

# 构建特定目标(例如MATEKF722SE)
make MATEKF722SE

使用说明

基础配置

  1. 连接地面站:通过Betaflight Configurator连接到飞控。
  2. 校准传感器:在“设置”页面校准加速度计,在“电源”页面校准电压和电流计。
  3. 配置接收机:在“接收机”页面选择协议(如SBUS、CRSF),并检查通道映射。
  4. 设置电机和电调:在“电机”页面选择DShot协议,测试电机转向。
  5. 调整PID和滤波器:使用默认PID通常可获得良好飞行效果,高级用户可进一步微调。

使用板载CMS菜单(通过OSD)

  1. 进入菜单:解锁后,将油门摇杆推到中间(Yaw Left)+ 俯仰摇杆向上(Pitch Up)。
  2. 导航:使用摇杆在菜单中移动、选择和退出。
  3. 快速调整:在“QUICK”菜单中可快速调整限幅、电机输出限制等常用参数。
  4. PID和速率调参:进入“PID TUNING”和“RATE PROFILE”菜单实时调整飞行手感。
  5. VTX设置:进入“VTX”菜单修改图传频段、信道和功率(需VTX支持SmartAudio或Tramp协议)。

黑匣子日志分析

// 黑匣子配置示例(通过CLI)
set blackbox_device = SDCARD    // 设置存储设备为SD卡
set blackbox_sample_rate = 1/2  // 设置采样率为1/2
set blackbox_mode = NORMAL      // 设置记录模式
save

日志文件(.BFL)可使用 Betaflight Blackbox Explorer 打开,分析Gyro轨迹、RC指令和PID响应。

核心代码

主程序入口 - 系统初始化与调度循环

这是飞控的主入口点,负责系统初始化、USB配置、多核支持以及启动主调度器。

// 来自 src/main/main.c
int main(int argc, char * argv[])
{
#ifdef USE_MAIN_ARGS
    targetParseArgs(argc, argv);
#else
    UNUSED(argc);
    UNUSED(argv);
#endif

    // 基本系统初始化
    systemInit();

#ifdef USE_MULTICORE
    // 多核支持的阶段初始化
    multicoreExecuteBlocking(initPhase1);
    multicoreExecuteBlocking(initPhase2);
#else
    initPhase1();
    initPhase2();
#endif

#ifdef USE_USB_MSC
    // USB大容量存储模式(用于读取SD卡)
    if (checkMsc()) {
        initMsc();
        return 0;
    }
#endif

#ifdef USE_VCP
    // 初始化USB虚拟串口
    usbVcpInit();
#endif

#ifdef USE_MULTICORE
    multicoreExecuteBlocking(initPhase3);
#else
    initPhase3();
#endif

    // 启动主调度器
    run();

    return 0;
}

// 主调度循环
void FAST_CODE run(void)
{
    while (true) {
        scheduler();  // 执行所有调度任务(PID循环、传感器读取等)
    }
}

黑匣子日志 - 数据编码与写入

黑匣子模块负责将飞行数据(姿态、PID输出、电机值等)编码并写入存储设备。以下代码展示了如何将浮点数编码为字节流。

// 来自 src/main/blackbox/blackbox_encoding.c
int blackboxPrintf(const char *fmt, ...)
{
    va_list va;
    va_start(va, fmt);
    const int written = blackboxPrintfv(fmt, va);
    va_end(va);
    return written;
}

void blackboxWriteUnsignedVB(uint32_t value)
{
    // 可变字节编码:每个字节的最高位表示是否还有后续字节
    do {
        uint8_t b = value & 0x7F;
        value >>= 7;
        if (value) {
            b |= 0x80;  // 设置延续标志
        }
        blackboxWrite(b);
    } while (value);
}

void blackboxWriteFloat(float value)
{
    // 将浮点数作为32位整数写入
    uint32_t *ptr = (uint32_t *)&value;
    blackboxWriteU32(*ptr);
}

CMS菜单系统 - 动态配置界面

CMS(板载设置菜单)允许用户通过遥控器和图传屏幕直接修改飞控参数,无需连接地面站。以下代码定义了一个简单的菜单项。

// 来自 src/main/cms/cms_menu_main.c
// 主菜单入口定义
static const OSD_Entry cmsx_menuMainEntries[] =
{
    {"--- MAIN MENU ---", OME_Label, NULL, NULL},
    {"SETUP & CAL",      OME_Submenu, cmsMenuChange_Calibration, &cmsx_menuSetupPopup},
    {"POWER & BATTERY",  OME_Submenu, cmsMenuChange, &cmsx_menuPower},
    {"FAILSAFE",         OME_Submenu, cmsMenuChange, &cmsx_menuFailsafe},
    {"LED STRIP",        OME_Submenu, cmsMenuChange, &cmsx_menuLedstrip},
    {"VTX",              OME_Funcall, cmsSelectVtx, NULL},
    {"MOTORS",           OME_Submenu, cmsMenuChange, &cmsx_menuMotors},
    {"BLACKBOX",         OME_Submenu, cmsMenuChange, &cmsx_menuBlackbox},
    {"SAVE & EXIT",      OME_Submenu, cmsMenuChange, getSaveExitMenu()},
    {"BACK", OME_Back, NULL, NULL},
    {NULL, OME_END, NULL, NULL}
};

// 菜单切换函数
const void *cmsMenuChange(displayPort_t *pPort, const void *ptr)
{
    pCurrentDisplay = pPort;
    return ptr;  // 返回要跳转到的菜单指针
}

ADC驱动 - 电池电压和电流采集

ADC模块负责采集电池电压、电流和RSSI等模拟信号,并进行校准和滤波。

// 来自 src/main/drivers/adc.c
uint16_t adcGetValue(adcSource_e source)
{
    // 根据不同的ADC源返回对应的采样值
    switch (source) {
        case ADC_BATTERY:
            return adcValues[ADC_BATTERY];
        case ADC_CURRENT:
            return adcValues[ADC_CURRENT];
        case ADC_RSSI:
            return adcValues[ADC_RSSI];
        default:
            return 0;
    }
}

// 内部Vref补偿,用于提高电压测量精度
uint16_t adcInternalCompensateVref(uint16_t intVRefAdcValue)
{
    // 使用出厂校准值和当前测量值计算实际Vref+
    return (uint16_t)((uint32_t)(adcVREFINTCAL * VREFINT_CAL_VREF) / intVRefAdcValue);
}

90F3fWfiJGCEIQVeneEqA3GIOQ5aPW66IMRMuWjhQ7g=