BetaFlight模块设计之二十六:接收机任务分析
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接口:
- static uint8_t nullFrameStatus(rxRuntimeState_t *rxRuntimeState)
- static float nullReadRawRC(const rxRuntimeState_t *rxRuntimeState, uint8_t channel)
- typedef void (*serialReceiveCallbackPtr)(uint16_t data, void *rxCallbackData);
- static bool nullProcessFrame(const rxRuntimeState_t *rxRuntimeState)
Kakute F7 AIO使用的是sbus协议,所以这里驱动相关主要函数如下:
- sbusFrameStatus
- sbusChannelsReadRawRC
- 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模块设计之二十六:接收机任务分析相关推荐
- BetaFlight模块设计之二十四:transponder任务分析
BetaFlight模块设计之二十四:transponder任务分析 transponder任务 配置情况 硬件配置 驱动配置 业务配置 初始化 MSP协议 三种IR transponder type ...
- PX4模块设计之二十六:BatteryStatus模块
PX4模块设计之二十六:BatteryStatus模块 1. BatteryStatus模块简介 2. 模块入口函数 2.1 主入口battery_status_main 2.2 自定义子命令cust ...
- BetaFlight模块设计之二十:CMS菜单模块分析
BetaFlight模块设计之二十:CMS菜单模块分析 CMS菜单模块 CMS菜单按键控制 CMS菜单Elements CMS_Menu OSD_Etnry Element类型 可调Element类型 ...
- BetaFlight模块设计之二十九:滤波模块分析
BetaFlight模块设计之二十九:滤波模块分析 滤波模块 滤波类型 1. slewFilter 2. simpleLowpassFilter 3. laggedMovingAverage 4. p ...
- BetaFlight模块设计之二:SERIAL任务分析
BetaFlight模块设计之二:SERIAL任务分析 SERIAL任务 1.总体情况 2.主要函数分析 2.1 taskHandleSerial任务 2.2 命令行处理函数cliProcess 2. ...
- BetaFlight模块设计之三十三:Pid模块分析
BetaFlight模块设计之三十三:Pid模块分析 Pid模块 1. Pid_audio子模块 2. Pid_init子模块 3. Pid算法子模块 3.1 TPA模式 3.2 飞行模式 3.3 L ...
- BetaFlight模块设计之三十五:RSSI信号强度链路稳定性分析
BetaFlight模块设计之三十五:RSSI信号强度&链路稳定性分析 1. RSSI信号强度 1.1 RSSI Value 1.2 RSSI dBm Value 2. 链路稳定性 3. RS ...
- BetaFlight模块设计之三十:Cli模块分析
BetaFlight模块设计之三十:Cli模块分析 Cli模块 Cli接口 Cli框架 Cli命令结构 主要函数分析 cliProcess函数 processCharacterInteractive函 ...
- BetaFlight模块设计之三十二:MSP协议模块分析
BetaFlight模块设计之三十二:MSP协议模块分析 1. MSP协议模块 1.1 MSP描述 1.2 MSP版本优缺点 1.3 MSP代码资源 2. MSP报文解析 2.1 MSP收包状态机 2 ...
最新文章
- [Linux] PHP程序员玩转Linux系列-腾讯云硬盘扩容挂载
- Linux两个进程交换信息,如何在Linux中的进程之间交换二进制数据
- Linux内核tracepoints
- 5.jQueryAjax
- 前端学习(1712):前端系列javascript之创建uni-app创建下
- java - 水仙花数
- 小白学HarmonyOS,HarmonyOS 2.0正式发布 分布式能力获得全面升级
- 剑指offer——11.旋转数组的最小数字
- 使用Jackson解析JSON
- Linux 下安装JDK1.8
- C# System.Drawing.SystemColors 系统颜色
- 剑盾神秘礼物正在维护服务器,宝可梦剑盾神秘礼物获取途径一览
- Foxmail是否可以隐藏文件夹?【网易企业邮箱申请】
- 项目经理面试问题整理与技巧分析
- 酰肼PEG酰肼,HZ-PEG-HZ
- 【科技知识】世界量子计算发展史
- 金蝶K3开发-工业单据自定义控件
- 七天玩转Redis 第七天打卡 Redis常见面试题及课程总结
- 杯子倒水问题 -python
- 精神心理科医生教您如何摆脱精神科药物带来的副作用