BetaFlight模块设计之二十六:接收机任务分析

基于BetaFlight开源代码框架简介的框架设计,逐步分析内部模块功能设计。

接收机任务

描述:主要用于处理接受遥控指令的任务。

 ├──> 初始化
 │   ├──> [v]硬件初始化openSerialPort
 │   └──> [v]业务初始化rxInit(serialRxInit/sbusInit/sbusFrameStatus/sbusDataReceive/sbusChannelsReadRawRC)
 ├──> 任务
 │   ├──> [x]实时任务
 │   ├──> [v]事件任务[TASK_RX] = DEFINE_TASK("RX", NULL, rxUpdateCheck, taskUpdateRxMain, TASK_PERIOD_HZ(33), TASK_PRIORITY_HIGH),
 │   └──> [x]时间任务
 ├──> 驱动
 │   ├──> [x]查询
 │   └──> [v]中断sbusDataReceive
 └──> 接口
     ├──> 支持SRXL2SPEKTRUMSBUSSUMDSUMHXBUSIBUSJETIEXBUSCRSFGHSTFPORT协议
     └──> bool getRxRateValid(void)

配置情况

硬件配置

在配置文件\src\main\target\KAKUTEF7\target.h定义。

#define SERIALRX_UART           SERIAL_PORT_USART6
#define SERIALRX_PROVIDER       SERIALRX_SBUS

软件配置

\src\main\pg\rx.c
PG_REGISTER_WITH_RESET_FN(rxConfig_t, rxConfig, PG_RX_CONFIG, 3);
void pgResetFn_rxConfig(rxConfig_t *rxConfig)
{
    RESET_CONFIG_2(rxConfig_t, rxConfig,
        .halfDuplex = 0,
        .serialrx_provider = SERIALRX_PROVIDER,
        .serialrx_inverted = 0,
        .spektrum_bind_pin_override_ioTag = IO_TAG(SPEKTRUM_BIND_PIN),
        .spektrum_bind_plug_ioTag = IO_TAG(BINDPLUG_PIN),
        .spektrum_sat_bind = 0,
        .spektrum_sat_bind_autoreset = 1,
        .midrc = RX_MID_USEC,
        .mincheck = 1050,
        .maxcheck = 1900,
        .rx_min_usec = RX_MIN_USEC,          // any of first 4 channels below this value will trigger rx loss detection
        .rx_max_usec = RX_MAX_USEC,         // any of first 4 channels above this value will trigger rx loss detection
        .rssi_src_frame_errors = false,
        .rssi_channel = 0,
        .rssi_scale = RSSI_SCALE_DEFAULT,
        .rssi_offset = 0,
        .rssi_invert = 0,
        .rssi_src_frame_lpf_period = 30,
        .fpvCamAngleDegrees = 0,
        .airModeActivateThreshold = 25,
        .max_aux_channel = DEFAULT_AUX_CHANNEL_COUNT,
        .rc_smoothing_mode = 1,
        .rc_smoothing_setpoint_cutoff = 0,
        .rc_smoothing_feedforward_cutoff = 0,
        .rc_smoothing_throttle_cutoff = 0,
        .rc_smoothing_debug_axis = ROLL,
        .rc_smoothing_auto_factor_rpy = 30,
        .rc_smoothing_auto_factor_throttle = 30,
        .srxl2_unit_id = 1,
        .srxl2_baud_fast = true,
        .sbus_baud_fast = false,
        .crsf_use_rx_snr = false,
        .msp_override_channels_mask = 0,
        .crsf_use_negotiated_baud = false,
    );

#ifdef RX_CHANNELS_TAER
    parseRcChannels("TAER1234", rxConfig);
#else
    parseRcChannels("AETR1234", rxConfig);
#endif
}

驱动配置

从驱动框架设计的角度,需要实现以下几个API接口:

  1. static uint8_t nullFrameStatus(rxRuntimeState_t *rxRuntimeState)
  2. static float nullReadRawRC(const rxRuntimeState_t *rxRuntimeState, uint8_t channel)
  3. typedef void (*serialReceiveCallbackPtr)(uint16_t data, void *rxCallbackData);
  4. static bool nullProcessFrame(const rxRuntimeState_t *rxRuntimeState)

Kakute F7 AIO使用的是sbus协议,所以这里驱动相关主要函数如下:

  1. sbusFrameStatus
  2. sbusChannelsReadRawRC
  3. sbusDataReceive

注:这里sbus不需要auxiliaryProcessing,所以nullProcessFrame接口不需要实现。

sbus驱动函数分析

sbusDataReceive函数

这里Kakute F7 AIO采用的是sbus协议,所以这里以这个为例,其他协议请根据配置查找对应的协议代码

sbusDataReceive
 ├──> nowUs = microsISR();
 ├──> sbusFrameTime = cmpTimeUs(nowUs, sbusFrameData->startAtUs);
 ├──> <sbusFrameTime > (long)(SBUS_TIME_NEEDED_PER_FRAME + 500)> //一帧数据接收超时
 │   └──> sbusFrameData->position = 0;  //重置起始位
 ├──> <sbusFrameData->position == 0>
 │   ├──> <c != SBUS_FRAME_BEGIN_BYTE>
 │   │   └──> return  //不是有效SOF,直接跳过
 │   └──> sbusFrameData->startAtUs = nowUs; //有效SOF,记录起始接收时间,以便后续判断帧接收超时
 └──> <sbusFrameData->position < SBUS_FRAME_SIZE>
     ├──> sbusFrameData->frame.bytes[sbusFrameData->position++] = (uint8_t)c;  //记录数据
     ├──> <sbusFrameData->position < SBUS_FRAME_SIZE>
     │   └──> sbusFrameData->done = false;  //一帧数据尚未传输完
     └──> <!(sbusFrameData->position < SBUS_FRAME_SIZE)>
         └──> sbusFrameData->done = true;   //一帧数据传输完成

sbusFrameStatus函数

sbusFrameStatus
 ├──> <!sbusFrameData->done>
 │   └──> return RX_FRAME_PENDING;  //一帧数据报文尚未传输完成
 ├──> sbusFrameData->done = false;
 ├──> frameStatus = sbusChannelsDecode(rxRuntimeState, &sbusFrameData->frame.frame.channels);  //报文解码
 ├──> <!(frameStatus & (RX_FRAME_FAILSAFE | RX_FRAME_DROPPED))>
 │   └──> rxRuntimeState->lastRcFrameTimeUs = sbusFrameData->startAtUs; //正确报文,记录最近一次收到报文的时间,以便后续判断接收机失联
 └──> return frameStatus;

sbusChannelsDecode函数

对一帧数据进行译码,判断帧数据是否存在问题。

sbusChannelsDecode
 ├──> 赋值rxRuntimeState->channelData[chan], chan=0..15
 ├──> 数据最大最小值赋值rxRuntimeState->channelData[chan], chan=16..17
 ├──> <channels->flags & SBUS_FLAG_FAILSAFE_ACTIVE>
 │   └──> return RX_FRAME_COMPLETE | RX_FRAME_FAILSAFE;
 ├──> <channels->flags & SBUS_FLAG_SIGNAL_LOSS>
 │   └──> return RX_FRAME_COMPLETE | RX_FRAME_DROPPED;
 └──> return RX_FRAME_COMPLETE;

注:一帧SBUS总长度是24字节。

typedef struct sbusChannels_s {
    // 176 bits of data (11 bits per channel * 16 channels) = 22 bytes.
    unsigned int chan0 : 11;
    unsigned int chan1 : 11;
    unsigned int chan2 : 11;
    unsigned int chan3 : 11;
    unsigned int chan4 : 11;
    unsigned int chan5 : 11;
    unsigned int chan6 : 11;
    unsigned int chan7 : 11;
    unsigned int chan8 : 11;
    unsigned int chan9 : 11;
    unsigned int chan10 : 11;
    unsigned int chan11 : 11;
    unsigned int chan12 : 11;
    unsigned int chan13 : 11;
    unsigned int chan14 : 11;
    unsigned int chan15 : 11;
    uint8_t flags;
} __attribute__((__packed__)) sbusChannels_t;

#define SBUS_CHANNEL_DATA_LENGTH sizeof(sbusChannels_t)
#define SBUS_FRAME_SIZE (SBUS_CHANNEL_DATA_LENGTH + 2)

sbusChannelsReadRawRC函数

函数注释上有关于这个公式的来源,详见链接

sbusChannelsReadRawRC // Linear fitting values read from OpenTX-ppmus and comparing with values received by X4R
 └──> return (5 * (float)rxRuntimeState->channelData[chan] / 8) + 880;

主要任务相关函数分析

rxUpdateCheck函数

以下3种直接场景+1钟隐含场景,需要提升该任务优先级:
1.【直接场景】taskUpdateRxMainInProgress //函数正处在数据处理过程中,需要尽快得到调度以处理后续报文中的数据
2.【直接场景】rxDataProcessingRequired //rxFrameCheck检查过程中发现有接收数据或者有新报文需要处理,提升优先级应对后续数据或者报文
3.【直接场景】auxiliaryProcessingRequired //根据报文状态标志,还有帧数据需要处理
4.【隐含场景】上述三种场景已经满足情况下,时间轮询时发现任然未得到调度,继续提升优先级(以便尽快得到处理)

rxUpdateCheck //主要用于增加动态调度优先级,详见[Schedule调度框架](https://blog.csdn.net/lida2003/article/details/124876862)
 └──> taskUpdateRxMainInProgress() || rxDataProcessingRequired || auxiliaryProcessingRequired

taskUpdateRxMain函数

遥控器通过RC接收机发送给飞控,如果定义USE_USB_CDC_HID,正好截断发给PC,作为一个模拟器使用。

taskUpdateRxMain
 ├──> <rxState != RX_STATE_UPDATE> //非update状态,无需更新任务的anticipatedExecutionTime(内部更新)
 │   └──> schedulerIgnoreTaskExecRate
 ├──> <rxState> //正常情况三个状态机依次时间片轮询
 │   ├──> <RX_STATE_CHECK>
 │   │   ├──> <!processRx(currentTimeUs)>
 │   │   │   ├──> rxState = RX_STATE_CHECK;
 │   │   │   └──> break
 │   │   └──> rxState = RX_STATE_MODES;
 │   ├──> <RX_STATE_MODES>
 │   │   ├──> processRxModes(currentTimeUs);
 │   │   └──> rxState = RX_STATE_UPDATE;
 │   └──> <RX_STATE_UPDATE>
 │       ├──> updateRcCommands
 │       ├──> updateArmingStatus
 │       ├──> <USE_USB_CDC_HID><!ARMING_FLAG(ARMED)>  //PC模拟器,非常好的idea,可以作为模拟stick玩游戏了。
 │       │   └──> sendRcDataToHid
 │       └──> rxState = RX_STATE_CHECK;
 ├──> <!schedulerGetIgnoreTaskExecTime()>
 │   ├──> <anticipatedExecutionTime != (rxStateDurationFractionUs[oldRxState] >> RX_TASK_DECAY_SHIFT> //期望时间与上次更新执行时间不一致
 │   │   └──> rxStateDurationFractionUs[oldRxState] = anticipatedExecutionTime << RX_TASK_DECAY_SHIFT; //更新为实际执行时间
 │   ├──> <executeTimeUs > (rxStateDurationFractionUs[oldRxState] >> RX_TASK_DECAY_SHIFT> //实际执行时间大于上次更新执行时间
 │   │   └──> rxStateDurationFractionUs[oldRxState] = executeTimeUs << RX_TASK_DECAY_SHIFT; //更新上次执行时间
 │   └──> <executeTimeUs <= (rxStateDurationFractionUs[oldRxState] >> RX_TASK_DECAY_SHIFT> //实际执行时间小于等于上次更新执行时间
 │       └──> rxStateDurationFractionUs[oldRxState]--; //慢慢减少上次执行时间
 └──> schedulerSetNextStateTime //提示schedulerExecuteTask更新期望任务执行时间

注:这里作为穿越机手动模拟器有一个非常好的FPV FreeRider,链接详见

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Betaflight 10.8.0是一款开源的多轴飞行控制软件。它专为无人机设计,具有强大的飞行控制能力和丰富的功能。如果您想下载Betaflight 10.8.0,您可以通过以下步骤获得它。 首先,您可以在Betaflight官方网站上获得最新版本的下载链接。访问官方网站后,找到下载页面并点击进入。在下载页面上,您将看到各种不同的版本可供选择。您需要找到10.8.0版本,并点击下载链接。 下载完成后,您可以将文件保存到您的计算机上的任意位置。请确保选择一个方便访问的位置,以便稍后安装软件。 然后,解压下载的文件。您可以使用常见的解压软件,例如WinRAR或7-Zip。右键点击文件并选择“解压缩到当前文件夹”或类似选项。解压完成后,您将在目标文件夹中看到Betaflight 10.8.0的文件和文件夹。 最后,您可以通过连接无人机到计算机上,使用飞行控制器如F4或F7,然后通过Betaflight Configurator来加载Betaflight 10.8.0。您只需打开Betaflight Configurator并选择正确的端口,然后将固件升级为Betaflight 10.8.0即可。 总之,下载Betaflight 10.8.0只需几个简单的步骤。请记住,使用Betaflight控制软件可能需要一定的技术知识和理解。在操作过程中,务必仔细阅读官方文档和教程,以确保您正确且安全地使用Betaflight 10.8.0。 ### 回答2: Betaflight是一款十分受欢迎的开源飞控固件,用于控制无人机的飞行和飞控功能。Betaflight 10.8.0是Betaflight团队开发的最新版本。 要下载Betaflight 10.8.0,首先需要访问Betaflight官方网站。在网站上,你可以找到下载页面。你可以在导航栏中找到“固件下载”或类似的选项。点击进入下载页面。 在下载页面,你会看到不同版本的Betaflight固件列在一起。现在你需要找到Betaflight 10.8.0的下载链接。可能有一些列如“最新稳定版”、“测试版”、“老版本”等的选项,你需要选择适合你的选择。找到Betaflight 10.8.0的选项并点击。 点击后,将会有一个提示框显示文件将要保存在电脑中的位置。选择一个你想保存固件文件的位置,并点击“保存”按钮。 下载过程可能需要一些时间,具体取决于你的网络连接和文件大小。一旦下载完成,你就可以在你选择的位置找到下载好的Betaflight 10.8.0固件文件。 下载好Betaflight 10.8.0后,你可以将固件文件烧录到你的飞控硬件中。具体的烧录步骤因不同的飞控硬件而异,你可以在Betaflight官方网站上找到详细的步骤和教程。 总之,要下载Betaflight 10.8.0,可以通过访问Betaflight官方网站,在下载页面中找到Betaflight 10.8.0的下载链接,然后保存到你的电脑中。下载完成后,可以将固件烧录到你的飞控硬件中,并开始享受最新版本的Betaflight带来的功能和飞行体验。 ### 回答3: Betaflight 10.8.0是一款开源的飞控固件,适用于无人机的飞行控制。要下载Betaflight 10.8.0版本,可以按照以下步骤进行操作: 第一步,打开Betaflight官方网站,网址为"https://betaflight.com/"。在网站首页的顶部导航栏中,可以找到一个名为"Downloads"的选项,点击进入。 第二步,进入Downloads页面后,会看到各个版本的Betaflight固件列表。向下滚动页面,直到找到Betaflight 10.8.0版本。点击版本号旁边的下载按钮。 第三步,选择适用于你的机型的固件下载链接。根据你的无人机型号和硬件配置,选择对应的下载链接,比如选择适用于F3飞控的固件。 第四步,点击下载链接后,会开始下载Betaflight 10.8.0的固件文件。下载完成后,将文件保存到你的计算机本地或指定的文件夹中。 第五步,将下载的Betaflight 10.8.0固件文件导入到你的飞控设备中。具体方法可以参考Betaflight官方网站提供的相关教程或使用说明。 总结,要下载Betaflight 10.8.0固件,首先前往Betaflight官方网站的Downloads页面,找到对应版本的固件文件,下载并导入到你的飞控设备中,然后按照相关教程进行设置和使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值