BetaFlight模块设计之十五:RunCam设备任务分析

Posted lida2003

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BetaFlight模块设计之十五:RunCam设备任务分析相关的知识,希望对你有一定的参考价值。

BetaFlight模块设计之十五:RunCam设备任务分析

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

RunCam设备任务

描述:主要用于处理遥控器、飞控、摄像头之间的事务处理(此过程中也形成了RunCam设备标准协议)。

 ├──> 初始化
 │   ├──> [v]硬件初始化runcamDeviceInit
 │   └──> [v]业务初始化rcdeviceInit
 ├──> 任务
 │   ├──> [x]实时任务
 │   ├──> [x]事件任务
 │   └──> [v]时间任务[TASK_RCDEVICE] = DEFINE_TASK("RCDEVICE", NULL, NULL, rcdeviceUpdate, TASK_PERIOD_HZ(20), TASK_PRIORITY_MEDIUM),
 ├──> 驱动
 │   ├──> [v]查询runcamDeviceGetDeviceInfo/rcdeviceReceive/runcamDeviceParseV1DeviceInfo/runcamDeviceParseV2DeviceInfo
 │   └──> [x]中断
 └──> 接口
     ├──> Support RunCam Device Protocol (FW v1.1.0/FW above v1.1.0)
     └──> OMNIBUSF4 机型支持该协议

注:RunCam Device Protocol is the serial communication protocol (Latest V1.1.0) initially developed for the RunCam Split and analog cameras.

机型配置

从代码角度分析,目前官网上4.3代码,只有OMNIBUSF4机型是配置了这个串口(也许配置工具也能调整),不过总体来说现在摄像头的VideoOut接FC_VideoIn,然后FC_VideoOut接图传VideoIn,更多OSDlayer上的内容在飞控上完成,这个协议的作用后续可能会越来越淡出视线。

/src/main/target/OMNIBUSF4/config.c
 SERIAL_PORT_UART4,  FUNCTION_RCDEVICE ,

rcdeviceUpdate任务分析

任务总体上表述四部分:1)从设备端接受串口数据;2)摄像头控制过程;3)遥控器5按键模拟;4)设备请求数据处理

rcdeviceUpdate
 ├──> rcdeviceReceive
 ├──> rcdeviceCameraControlProcess
 ├──> rcdevice5KeySimulationProcess
 └──> <isFeatureSupported(RCDEVICE_PROTOCOL_FEATURE_FC_ATTITUDE)>
     ├──> runcamDeviceRequest_t *request = rcdeviceGetRequest();
     └──> <request>
         └──> rcdeviceProcessDeviceRequest(request);

1. rcdeviceReceive函数分析

这个rcdeviceReceive函数主要分为两部分:1)处理FC发出,且需要反馈的串口报文事务;2)接受设备端主动发起的事务请求。

rcdeviceReceive
 ├──> <(respCtx = getWaitingResponse(millis())) != NULL>  //判断存在需要反馈的事务,发送事务报文;失败尝试三次
 │   ├──> <!serialRxBytesWaiting(respCtx->device->serialPort> //等待设备端事务反馈
 │   │   └──> break //等待超时
 │   ├──> const uint8_t c = serialRead(respCtx->device->serialPort);
 │   ├──> <判断报文满足协议格式>
 │   │   └──> break //不满足协议头定义
 │   ├──> respCtx->recvBuf[respCtx->recvRespLen] = c;
 │   ├──> respCtx->recvRespLen += 1;
 │   ├──> <respCtx->recvRespLen == respCtx->expectedRespLen>
 │   ├──> [不同协议报文格式解析] ==> RCDEVICE_RESP_INCORRECT_CRC or RCDEVICE_RESP_SUCCESS
 │   ├──> <respCtx->parserFunc != NULL>
 │   │   └──> respCtx->parserFunc(respCtx);  //执行事务反馈函数
 │   └──> <respCtx->result == RCDEVICE_RESP_SUCCESS>
 │       └──> rcdeviceRespCtxQueueShift(&waitingResponseQueue); //移除已经获得反馈的事务
 └──> <currentDevice != NULL> //处理设备端请求事务
     ├──> <!serialRxBytesWaiting(currentDevice->serialPort)>
     │   └──> break //没有设备请求
     ├──> <requestParserContext.isParseDone>
     │   └──> break //最近一次设备请求尚未处理,已经有后续事务,先放在缓存中
     ├──> <requestParserContext.state != RCDEVICE_STATE_WAITING_HEADER && millis() - requestParserContext.lastRecvDataTimestamp > 200> // 200ms超时检查
     │   └──> requestParserContext.state = RCDEVICE_STATE_WAITING_COMMAND; // reset state to waiting header,这里代码有问题,逻辑和批注都描述状态机恢复到判断SOF状态(RCDEVICE_STATE_WAITING_HEADER)
     ├──> [RCDEVICE_STATE_WAITING_HEADER/RCDEVICE_STATE_WAITING_COMMAND/RCDEVICE_STATE_WAITING_DATA_LENGTH/RCDEVICE_STATE_WAITING_DATA/RCDEVICE_STATE_WAITING_CRC过程收包]
     └──> requestParserContext.lastRecvDataTimestamp = millis();

2. rcdeviceCameraControlProcess函数分析

这里主要摄像头的可用功能Enable/Disable控制。

rcdeviceCameraControlProcess
 └──> 遍历BOXCAMERA1/BOXCAMERA2/BOXCAMERA3模式
     ├──> <IS_RC_MODE_ACTIVE(i)> //模式激活
     │   ├──> <switchStates[switchIndex].isActivated> //已经激活的模式,无需重复激活
     │   │   └──> continue
     │   ├──> uint8_t behavior = RCDEVICE_PROTOCOL_CAM_CTRL_UNKNOWN_CAMERA_OPERATION;
     │   ├──> <isFeatureSupported(RCDEVICE_PROTOCOL_FEATURE_SIMULATE_WIFI_BUTTON)><!ARMING_FLAG(ARMED) && !(getArmingDisableFlags() & (ARMING_DISABLED_RUNAWAY_TAKEOFF | ARMING_DISABLED_CRASH_DETECTED))>
     │   │   └──> behavior = RCDEVICE_PROTOCOL_CAM_CTRL_SIMULATE_WIFI_BTN;
     │   ├──> <isFeatureSupported(RCDEVICE_PROTOCOL_FEATURE_SIMULATE_POWER_BUTTON)>
     │   │   └──> behavior = RCDEVICE_PROTOCOL_CAM_CTRL_SIMULATE_POWER_BTN;
     │   ├──> <isFeatureSupported(RCDEVICE_PROTOCOL_FEATURE_CHANGE_MODE)><!ARMING_FLAG(ARMED) && !(getArmingDisableFlags() & (ARMING_DISABLED_RUNAWAY_TAKEOFF | ARMING_DISABLED_CRASH_DETECTED))>
     │   │   └──> behavior = RCDEVICE_PROTOCOL_CAM_CTRL_CHANGE_MODE;
     │   └──> <behavior != RCDEVICE_PROTOCOL_CAM_CTRL_UNKNOWN_CAMERA_OPERATION>
     │       ├──> runcamDeviceSimulateCameraButton(camDevice, behavior);  //直接串口命令下发
     │       └──> switchStates[switchIndex].isActivated = true;
     └──> <IS_RC_MODE_ACTIVE(i)>//模式不激活
         └──> switchStates[switchIndex].isActivated = false;

3. rcdevice5KeySimulationProcess函数分析

这里是一个遥控器的模拟5按键操作:

  1. IS_MID(THROTTLE) && IS_MID(ROLL) && IS_MID(PITCH) && IS_LO(YAW): 退出Cam菜单
  2. IS_MID(THROTTLE) && IS_MID(ROLL) && IS_MID(PITCH) && IS_HI(YAW):进入Cam菜单
  3. IS_LO(ROLL) :KEY_LEFT
  4. IS_HI(PITCH):KEY_UP
  5. IS_HI(ROLL) :KEY_RIGHT
  6. IS_LO(PITCH):KEY_DOWN
  7. IS_MID(THROTTLE) && IS_MID(ROLL) && IS_MID(PITCH) && IS_HI(YAW):KEY_ENTER
rcdevice5KeySimulationProcess
 ├──> <USE_CMS><cmsInMenu>
 │   └──> return
 ├──> <ARMING_FLAG(ARMED) || IS_RC_MODE_ACTIVE(BOXSTICKCOMMANDDISABLE) || (getArmingDisableFlags() & (ARMING_DISABLED_RUNAWAY_TAKEOFF | ARMING_DISABLED_CRASH_DETECTED))>
 │   └──> return
 ├──> <isButtonPressed>
 │   └──> <IS_MID(YAW) && IS_MID(PITCH) && IS_MID(ROLL)>
 │       ├──> rcdeviceSend5KeyOSDCableSimualtionEvent(RCDEVICE_CAM_KEY_RELEASE);
 │       └──> waitingDeviceResponse = true;
 └──> <!isButtonPressed>
     ├──> <waitingDeviceResponse>
     │   └──> return
     ├──> <IS_MID(THROTTLE) && IS_MID(ROLL) && IS_MID(PITCH) && IS_LO(YAW)> // Disconnect Lo YAW
     │   └──> <rcdeviceInMenu>
     │       └──> key = RCDEVICE_CAM_KEY_CONNECTION_CLOSE;
     ├──> <!(IS_MID(THROTTLE) && IS_MID(ROLL) && IS_MID(PITCH) && IS_LO(YAW))> 
     │   ├──> <!rcdeviceInMenu>
     │   │   └──> <IS_MID(THROTTLE) && IS_MID(ROLL) && IS_MID(PITCH) && IS_HI(YAW)> // Enter HI YAW
     │   │       └──> key = RCDEVICE_CAM_KEY_CONNECTION_OPEN;
     │   └──> <rcdeviceInMenu>
     │       ├──> <IS_LO(ROLL)> // Left LO ROLL
     │       │   └──> key = RCDEVICE_CAM_KEY_LEFT;
     │       ├──> <IS_HI(PITCH)> // Up HI PITCH
     │       │   └──> key = RCDEVICE_CAM_KEY_UP;
     │       ├──> <IS_HI(ROLL)> // Right HI ROLL
     │       │   └──> key = RCDEVICE_CAM_KEY_RIGHT;
     │       ├──> <IS_LO(PITCH)> // Down LO PITCH
     │       │   └──> key = RCDEVICE_CAM_KEY_DOWN;
     │       └──> <IS_MID(THROTTLE) && IS_MID(ROLL) && IS_MID(PITCH) && IS_HI(YAW)> // Enter HI YAW
     │           └──> key = RCDEVICE_CAM_KEY_ENTER;
     └──> <key != RCDEVICE_CAM_KEY_NONE>
         ├──> rcdeviceSend5KeyOSDCableSimualtionEvent(key);
         ├──> isButtonPressed = true;
         └──> waitingDeviceResponse = true;

4. rcdeviceProcessDeviceRequest函数分析

这里是设备从FC出请求获取yaw,roll,pitch方面的信息,以便显示在OSD layer上。

rcdeviceProcessDeviceRequest
 └──> <request->command == RCDEVICE_PROTOCOL_COMMAND_REQUEST_FC_ATTITUDE>
     └──> runcamDeviceSendAttitude(camDevice);  // send yaw, roll, pitch info to device for OSD layer display

以上是关于BetaFlight模块设计之十五:RunCam设备任务分析的主要内容,如果未能解决你的问题,请参考以下文章

BetaFlight模块设计之十四:高度计算任务分析

BetaFlight模块设计之十三:Gyro过滤任务分析

BetaFlight模块设计之十七:pinioBox任务分析

BetaFlight模块设计之十八:图传模块同步任务分析

BetaFlight模块设计之十:磁力计任务分析

BetaFlight模块设计之十六:OSD更新任务分析