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

  • 接收机任务
  • 配置情况
    • 硬件配置
    • 软件配置
    • 驱动配置
  • sbus驱动函数分析
    • sbusDataReceive函数
    • sbusFrameStatus函数
    • sbusChannelsDecode函数
    • sbusChannelsReadRawRC函数
  • 主要任务相关函数分析
    • rxUpdateCheck函数
    • taskUpdateRxMain函数

基于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└──> 接口├──> 支持SRXL2、SPEKTRUM、SBUS、SUMD、SUMH、XBUS、IBUS、JETIEXBUS、CRSF、GHST、FPORT协议└──> 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_TAERparseRcChannels("TAER1234", rxConfig);
#elseparseRcChannels("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,链接详见。

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

  1. BetaFlight模块设计之二十四:transponder任务分析

    BetaFlight模块设计之二十四:transponder任务分析 transponder任务 配置情况 硬件配置 驱动配置 业务配置 初始化 MSP协议 三种IR transponder type ...

  2. PX4模块设计之二十六:BatteryStatus模块

    PX4模块设计之二十六:BatteryStatus模块 1. BatteryStatus模块简介 2. 模块入口函数 2.1 主入口battery_status_main 2.2 自定义子命令cust ...

  3. BetaFlight模块设计之二十:CMS菜单模块分析

    BetaFlight模块设计之二十:CMS菜单模块分析 CMS菜单模块 CMS菜单按键控制 CMS菜单Elements CMS_Menu OSD_Etnry Element类型 可调Element类型 ...

  4. BetaFlight模块设计之二十九:滤波模块分析

    BetaFlight模块设计之二十九:滤波模块分析 滤波模块 滤波类型 1. slewFilter 2. simpleLowpassFilter 3. laggedMovingAverage 4. p ...

  5. BetaFlight模块设计之二:SERIAL任务分析

    BetaFlight模块设计之二:SERIAL任务分析 SERIAL任务 1.总体情况 2.主要函数分析 2.1 taskHandleSerial任务 2.2 命令行处理函数cliProcess 2. ...

  6. BetaFlight模块设计之三十三:Pid模块分析

    BetaFlight模块设计之三十三:Pid模块分析 Pid模块 1. Pid_audio子模块 2. Pid_init子模块 3. Pid算法子模块 3.1 TPA模式 3.2 飞行模式 3.3 L ...

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

    BetaFlight模块设计之三十五:RSSI信号强度&链路稳定性分析 1. RSSI信号强度 1.1 RSSI Value 1.2 RSSI dBm Value 2. 链路稳定性 3. RS ...

  8. BetaFlight模块设计之三十:Cli模块分析

    BetaFlight模块设计之三十:Cli模块分析 Cli模块 Cli接口 Cli框架 Cli命令结构 主要函数分析 cliProcess函数 processCharacterInteractive函 ...

  9. BetaFlight模块设计之三十二:MSP协议模块分析

    BetaFlight模块设计之三十二:MSP协议模块分析 1. MSP协议模块 1.1 MSP描述 1.2 MSP版本优缺点 1.3 MSP代码资源 2. MSP报文解析 2.1 MSP收包状态机 2 ...

最新文章

  1. [Linux] PHP程序员玩转Linux系列-腾讯云硬盘扩容挂载
  2. Linux两个进程交换信息,如何在Linux中的进程之间交换二进制数据
  3. Linux内核tracepoints
  4. 5.jQueryAjax
  5. 前端学习(1712):前端系列javascript之创建uni-app创建下
  6. java - 水仙花数
  7. 小白学HarmonyOS,HarmonyOS 2.0正式发布 分布式能力获得全面升级
  8. 剑指offer——11.旋转数组的最小数字
  9. 使用Jackson解析JSON
  10. Linux 下安装JDK1.8
  11. C# System.Drawing.SystemColors 系统颜色
  12. 剑盾神秘礼物正在维护服务器,宝可梦剑盾神秘礼物获取途径一览
  13. Foxmail是否可以隐藏文件夹?【网易企业邮箱申请】
  14. 项目经理面试问题整理与技巧分析
  15. 酰肼PEG酰肼,HZ-PEG-HZ
  16. 【科技知识】世界量子计算发展史
  17. 金蝶K3开发-工业单据自定义控件
  18. 七天玩转Redis 第七天打卡 Redis常见面试题及课程总结
  19. 杯子倒水问题 -python
  20. 精神心理科医生教您如何摆脱精神科药物带来的副作用

热门文章

  1. 2017智慧医疗与安防产业发展研讨会圆满落幕
  2. kali破解pdf密码
  3. 嵩天老师Python面向对象-28,文本清洗及统计案例
  4. CMOS Sensor介绍
  5. 郭盛华:黑客破坏Okta的GitHub存储库,窃取源代码
  6. 2022建筑电工(建筑特殊工种)考试题库及答案
  7. 区块链上市公司半年报: 41家进入实际应用及研究 5家瞄准供应链金融
  8. Unity3D 入门:安装 Unity3D 并配置与 Visual Studio 的协作开发环境
  9. 自动控制理论(1):一般概念及数学模型
  10. 服务器压力测试工具1——压力端模块设计