当前位置: 首页 > news >正文

PH47代码框架软件二次开发极简教程

 1. 教程说明

本教程适用于对飞控及Stm32程序设计比较熟悉的二次开发者快速掌握PH47框架的使用要点。本教程仅对PH47框架中最主要的二次开发特性进行简要说明,建议与框架中\DevStudio\Algorithms\Controller_Demo.cpp(.h)示例代码配合学习。关于二次开发特性中的详细或高级内容,请参见《PH47框架二次开发教程》。

对于飞控或是Stm32编程不是太熟练的开发者,建议先了解学习Stm32程序设计相关内容,以及《PH47框架二次开发教程》。

1.1 基本概念

  • 时间相关、循环控制、调试功能大部分基本功能由框架层全局函数实现。
  • 整个PH47框架内,数据读取、写入、交换等操作均依托框架层的数据总线系统(frm.bus),以frm.bus.Function()方式使用。
  • 机载调参参数(控制参数)的读取、写入存储均通过框架层的参数系统core.para实现,以core.para.Function()方式使用。
  • 用户代码一般位于应用层Application当中实现。应用层为用户提供了初始化、快速循环,普通循环、慢速循环函数,以及GCS上行指令响应函数、控制台指令响应函数等重要函数框架供用户扩充使用。

2. 基本全局功能函数使用

2.1 常用全局时间函数

函  数

功 能 描 述

HAL_Delay()

用于ms 级延时,执行时独占系统资源

osDelay()

用于ms 级延时。osDelay() 依赖于 FreeRTOS 启动完成,延时期间可以将系统资源轮换给其他线程使用

gDelay_us()

用于 us 级别延时。延时时间不要超过 1000us

gGetMills()

获取调用时刻距离 mcu 加电启动时刻的ms时间间隔, 获取数据范围为 4294967296ms,即1193 hour

gGetMills_f()

获取精确到小数点后3位的ms时间, 即精确到us。

gGetMills_f()在运行时间超过4800s后会溢出重置为 0 后重新开始计时

gGetMicros() 

获取mcu加电以来的us时间。

注意: us计时器溢出时间为600s

2.2 调试功能使用

函  数

功 能 描 述

TRACE()

使用邮件队列方式显示格式化字符串。

具有线程安全性,且连续调用能够确保顺序正确。依赖于 PH47 框架的启动完成, 框架启动前不能正常工作。显示时刻会晚于函数调用时刻(滞后不高于 10ms 级别)   。

TRACE("\r\ndemo> 1. TRACE at %.3fms", gGetMills_f());   

gPrintf()

使用中断方式显示格式化字符串。

不依赖于框架的启动完成。连续密集调用时显示的先后顺序可能会发生改变

gPrintf("\r\ndemo> 2. gPrintf at %.3fms", gGetMills_f());  

ASSERT(f)

表达式f真值确认。

若表示式f为false,则核心板状态指示LED连续快速闪烁,当前线程执行停止在ASSERT()语句处,同时在调试串口输出ASSERT语句所在的文件名及代码行号。

bus.arDbg_1[10]

bus.arDbg_2[10]

调试专用总线数据项。只需将调试数据赋值给总线数据项即可。

PH47框架已经预置了调试数据的下行发送机制,用户无需自己实现。

调试数据默认下行发送频率为25hz,运行过程中可调整。

3 使用CFreqDiv类进行循环频率控制

  • 1/3: 在.h文件中定义一个CFreqDiv类对象_FreqDemo_1Hz
CFreqDiv _FreqDemo_1Hz;
  • 2/3: 适当位置对_FreqDemo_1Hz对象进行初始化,如在.cpp文件初始化函数中,设定循环间隔。
_FreqDemo_1Hz.SetRunInv_ms(1000);  // 循环控制间隔为 1000ms, 即 1Hz
  • 3/3: 在需要进行循环频率控制的位置通过IsSetRunInv_ms()函数判断是否达到循环控制条件。此处注意:_FreqDemo_1Hz对象的IsSetRunInv_ms()函数调用在同一循环中只能在一个位置出现一次,不能在多个不同位置多次调用。
if(_FreqDemo_1Hz.IsSetRunInv_ms())
{// do something…
}

4. 数据总线基本操作

数据总线系统为整个PH47代码框架提供了设置、获取、交换数据的方法和途径。以及获取诸如设置获取数据时间戳,数据设置时间间隔,数据权限控制等功能。

数据总线系统由一系列总线数据项(Bus item)构成,总线数据项既可以是包含了一个数据简单类型(如 uint8_t,int32,float等)的数据项,也可以是多个具有相关性的数据构成的复杂类型数据项,如结构变量。

4.1 数据总线系统文件包含

用户要在自己的代码文件中使用数据总线功能,只需在自己的.cpp文件开始出加入如下文件包含:

#include"../../Frame/UseGlobalObject.h"   //文件包含路径根据实际情况确定

数据总线中数据项的声明位于如下文件中:

\DevStudio\BoardConfig\Board_BBDB\DataBus_BBDB.h

数据总线中复杂类型数据项(框架内置)的结构声明位于如下文件中:

\DevStudio\Frame\Core\BusItemFormatDef.h

4.2 数据总线功能函数使用

函  数

功 能 描 述

Get()

读取数据总线数值

Vector3f vAcc = bus.sImu.AccRaw.Get();  // 获取总线数据项数值

TRACE("\r\n> Acc %.2f %.2f %.2f", vAcc.x, vAcc.y, vAcc.z);

Set()

设置数据总线数值。

本函数在设置总线数值的同时,对当前总线数据的时间戳进行了设置。

// demo 1

bus.arDbg_2[0].Set(2.234);

// demo 2

MICOLINK_PAYLOAD_RANGE_SENSOR_t payload;

payload.distance = 10.5f;

payload.strength = 1.0f;

bus.OptiFlowTof_MTF01.Set(&payload)// 设置总线数据项数值

GetTimeStamp_ms()

获取 AccRaw 以 ms 为单位时间戳的整数部分,示例见下。

GetTmStampDec_us()

获取 AccRaw 以 ms 为单位时间戳的 3 位小数部分(即精确到 us),示例见下。

GetDt2Prev_us()

获取总线数据项最近两次被设置(Set)之间的时间间隔(us)

// 上述三个函数综合示例

TRACE("\r\n> AccRaw timeTag:%d.%dms dt:%dus",

bus.sImu.AccRaw.GetTimeStamp_ms(),  // 时间戳整数部分(ms)

bus.sImu.AccRaw.GetTmStampDec_us(), // 时间戳小数部分(us)

bus.sImu.AccRaw.GetDt2Prev_us());   // 最近两次设置时间间隔(us)

4.3 全局变量

全局变量变量是一种特殊的总线数据,用于在整个PH47代码框架内表示系统状态,分为bool型和uint8_t型两种类型。整个框架共有48个bool型,8个uint8_t类型全局变量。

PH47代码框架以及CSS插件已经预置了全局变量的发送及解析机制,以5Hz频率下行发送更新。用户在PH47框架中只需对其进行设置或读取即可。

函  数

功 能 描 述

gGetStatus()

GetStatus()

读取全局变量数值。

gGetStatus()等同于GetStatus(),只是前者为全局函数形式,后者需要通过core对象进行引用。

gGetStatus(S_IMU_STILL);    // bool 类型

core.GetStatus(S_RC_ALIVE);

uint8_t uTmp = gGetStatus(S_SYSTEM_STATUS_TAG);   // uint8_t 类型

gSetStatus()

SetStatus()

设置全局状态变量。

参数blForceUpdate为true表示无论当前全局状态变量数值如何都进行设置。

false表示若待设置数值与当前数值相同就不进行设置

gSetStatus(S_WATCH_DOG_MODE, true, true);

4.4 自定义简单类型总线数据项

\DevStudio\BoardConfig\Board_BBDB\DataBus_BBDB.h文件中注释为"用户自定义设置区域"内加入自有总线数据的定义(注意!不要对该区域以外的总线数据声明进行任何修改或删除!):

// <=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>
// 用户自定义参数设置区域, 不得对该区域之外的任何内容进行修改
CBusItem<float> fAspdDiffPress;    // float类型的bus item
// <=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>

之后就可以使用总线相关函数实现各种功能了

4.5 自定义复杂类型总线数据项目

  • 1/3:在需要使用总线的.cpp文件头部加入对数据总线的文件包含:
#include"../../Frame/UseGlobalObject.h"
  • 2/3:在如下文件中加入对复杂类型的结构声明(用户自定义):

\DevStudio\BoardConfig\Board_BBDB\BusItemDef4User.h

struct BUS_ITEM_DEMO
{CBusItem<uint8_t>    Item_A;CBusItem<float>      Item_B;
};
  • 3/3:在\DevStudio\BoardConfig\Board_BBDB\DataBus_BBDB.h文件的“用户自定义参数设置区域”加入总线数据的定义:
// <=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>
// 用户自定义参数设置区域, 不得对该区域之外的任何内容进行修改
BUS_ITEM_DEMO sBusItemDemo;
// <=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>

4.6 自定义全局状态变量

文件DevStudio\BoardConfig\Board_BBP\StateVarDef_BBP.h对全局状态变量的ID进行了定义,此文件中的enum STATUS_BOOLenumSTATUS_UINT枚举分别定义了bool及uint8_t类型的全局状态变量ID。

与自定义总线数据类似,自定义全局状态变量必须位于标注“用户自定义参数设置区域”的区域内。二次开发者不能对该区域意外的任何内容进行删除或修改。

  • 1/2:在DevStudio\BoardConfig\Board_BBDB\StateVarDef_BBDB.h文件的enum STATUS_BOOL声明的用户自定义部分加入S_STATUS_VAR_DEMO声明
// <=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>
// 用户自定义 全局状态变量 设置区域, 不得对该区域之外的任何内容进行修改
S_STATUS_VAR_DEMO,          // 直接定义 id 即可
// <=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>
  • 2/2:之后在程序中需要的地方就可以通过下述函数设置或是获取状态;
gSetStatus(S_STATUS_VAR_DEMO, true);
bool blStatus = gGetStatus(S_STATUS_VAR_DEMO);

5. 机载参数系统基本操作

机载控制参数系统为整个PH47代码框架提供了控制参数的读取、写入、空地间传输等功能的全套使用解决方案。

机载参数数据存储于控制板外置 flash 或 eeprom 存储器中。可通过 CSS控制站以单个或批量的方式下载及上传设定。

5.1 参数系统文件包含

用户要在自己的代码文件中使用参数系统功能,只需在自己的.cpp文件开始处加入如下文件包含:

#include"../../Frame/UseGlobalObject.h"   //文件包含路径根据实际情况确定

参数系统的参数id定义,以及参数默认属性设置(参数字典),分别位于如下文件中:

\DevStudio\BoardConfig\Firmware_BBDB\ParamDict_BBDB.h

\DevStudio\BoardConfig\Firmware_BBDB\ParamDict_BBDB.cpp

5.2 参数系统功能使用

函  数

功 能 描 述

Get()

读取记载参数数值。

Get() 函数获取的参数存储于RAM中,若存储器(flash/e2prom)中参数被CSS上传设定所更新,或被程序中其他参数设定函数所改变,则RAM中参数数值也自动更新,用户无需手动刷新。

// 获取当前设定的遥测通讯波特率

uint32_t uBaudRate = (uint32_t)(core.para.Get(P_BAUD_RATE));

// 获取加速度计x轴偏移量

float fVal = frm.para.Get(P_SENSOR_ACC_OFST_X);

Set()

设置机载调参参数数值。

blForcesave决定是否对存储介质(Flash或EEprom)存储数据进行强制更新。

为 ture时不能进行高速率(>50hz)密集调用,否则有可能造成存储器密集写入超时而导致数据存储失败

// 设置参数数值强制更新存储

core.para.Set(P_SENSOR_ACC_OFST_X, _cal_acc_offset.x, true);

// 仅对RAM当中的参数数值进行更新,控制板重启后丢失

frm.para.Set(P_SENSOR_ACC_OFST_X, blSave)

5.3 自定义参数的实现

  • 1/3:在ParaDict_BBDB.h文件enum PARAID枚举定义的用户区域当中加入新参数P_TEST_USER_1的 id 的定义,无需为id指定特定数值,顺序排列即可。在 CSS 参数下载列表中的顺序以enum PARAID当中的顺序为准。
    // <=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>// 用户自定义参数设置区域, 不得对该区域之外的任何内容进行修改P_TEST_USER_1,       // 自定义参数 id// <=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>
  • 2/3:在ParaDict_BBDB.cpp文件全局数组g_arParaDictMCU[]参数字典的用户区域中加入新参数的属性数据。enum PARAID中参数id的数值及顺序与g_arParaDictMCU[]各元素均无关系,可根据实际需要组织。
    // <=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>// 用户自定义参数设置区域, 不得对该区域之外的任何内容进行修改// 自定义参数 P_TEST_USER_1 的默认属性进行设置//{"TestUser_1", P_TEST_USER_1, 0x0000, 256.0f, 0.0f, 500.0f},   // <=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>=<=>
  • 3/3;修改参数字典并编译下载至控制板后,必须通过控制板的调试串口运行一次 "initfstrun;"命令以初始化存储器数据。

6. 遥测通讯系统使用

PH7 代码框架通过 mavlink plus 协议与地面控制站 GCS,或其他无人控制目标进行双向通讯。mavlink plus 协议在mavlink 1.0基础上增加修改了message 设置,并对 GCS 上行控制命令实施真伪性动态甄别。

6.1 遥测通讯系统文件包含

若在用户二次开发代码中使用mavlink通讯功能,那么就需要在自己的代码中加入如下文件包含:

    #include "/DevStudio/Frame/Core/MavlinkInterface.h"#include "/DevStudio/Frame/Core/MavlinkWrap.h"

6.2 遥测通讯系统功能使用

在整个 PH7 代码框架内对 GCS 的数据通讯以core.mavlink.FunName()的形式来使用 mavlink 协议相关功能函数。

对其他控制目标的数据通讯以core.consolelink.FunName()的形式来使用 mavlink 通讯相关功能函数。

PH47代码框架已对Message的下行发送进行了完善的封装,为不同类型的Message设定了不同的发送速率,发送速率在运行过程中可重新设定调整。整个Message的下行发送机制为全自动执行,用户在仅需在发送message时以core.mavlink.AddMsg_xxx()形式调用对应函数,即可将待发送消息加入下行消息发送队列随即自动发送。二次开发用户常用消息发送函数如下:

函  数

功 能 描 述

AddMsg_Ctrl_Base()

下行发送飞控控制器相关数据

AddMsg_Atms_Data()

下行发送大气相关数据

AddMsg_GpsRawInt()

下行发送GPS相关数据

AddMsg_Raw_Imu()

下行发送IMU相关数据

AddMsg_Attitude()

下行发送姿态相关数据

AddMsg_Debug_1()

下行发送调试数据 1

AddMsg_Debug_2()

下行发送调试数据 2

AddMsg_StatusText()

下行发送状态信息

mavlink message 发送示例:

// demo 1: 下行发送心跳包
mavlink_heartbeat_t packet;
memset(&packet, 0x00, sizeof(packet));packet.base_mode     = (uint8_t) 6;         
packet.system_status  = 0xA5;               
packet.autopilot         = BOARD_PH7;
packet.custom_mode      = 0xEE;
packet.mavlink_version = MAVLINK_VERSION;uRet = core.mavlink.AddMsg_HeartBeat(&packet);   // 加入发送队列,随后自动发送

demo 2: 下行发送状态信息

char szTmp[32] = {""};
gFormat(szTmp, "Log %d HIL sim start.", uFlightNum);
core.mavlink.AddMsg_StatusText(szTmp, MAV_SEVERITY_WARNING);// 更多Message发送使用方法可见文件:\DevStudio\Frame\Frame.cpp 当中的
// void MavMsgSnd2GCS_Slow() 函数

7. 应用层框架预制功能函数的使用

PH47框架在应用层\DevStudio\Application\App_BBP.cpp.h文件,即应用层类CAppBBDB中预置了多个供二次开发用户使用的功能函数,用户根据上述函数的功能特性,有针对性的在其中加入自己的代码即可方便的进行二次开发。

函数名称

CAppBBDB类成员函数

功 能 描 述

Init()

PH47框架完全启动后调用该初始化函数

在本函数中可安全使用 ASSERT, TRACE 等依赖于框架启动的函数

FastThread_1000Hz()

快速线程函数,调用频率在400—500hz之间波动。

NormalThread_250Hz()

普通线程函数,调用频率固定为250hz

SlowThread_50Hz()

慢速线程函数,调用频率固定为50hz

HandleRevMavlinkMsg()

mavlink 用户自定义上行控制指令处理函数

HandleConsoleCmd()

调试控制台用户自定义命令处理函数

7.1 程序示例:

普通线程函数示例

void CAppBBDB::NormalThread_250Hz()
{// 获取循环间隔时间float fDt = 0.0f;if(_NormalLoopDt.GetLocalDt_ms(fDt) == false)return;// Controller_Common 示例代码algo._pController_Common->Update(fDt);      
}

接收 mavlink message 用户自定义上行指令处理示例

void CAppBBDB::HandleRevMavlinkMsg(mavlink_command_long_sa_t *pPacket)
{//解析及响应 GCS 上行控制命令if(pRevMsg ->msgid == MAVLINK_MSG_ID_COMMAND_LONG_SA ){mavlink_command_long_sa_t packet;mavlink_msg_command_long_sa_decode(pRevMsg, &packet);if(packet.command == MAV_CMD_USER_DEFINE){  if(packet.param1 == fValue){// User code ...}}}
}

用户自定义调试控制台命令处理函数示例

void CAppBBDB::HandleConsoleCmd(uint8_t *pBuff)
{// pBuff 为用户命令字符串,命令字符串最长不能超过 32 byteif(strcmp((char *) pBuff, "User CMD") == 0){// User code ...}
}

 


更多内容见CSDN博客专栏:无人机飞控icon-default.png?t=O83Ahttps://blog.csdn.net/ss15/category_9690939.html?spm=1001.2014.3001.5482相关资源:PH47: PH47运动控制代码框架.icon-default.png?t=O83Ahttps://gitee.com/ss15/ph47


http://www.mrgr.cn/news/55561.html

相关文章:

  • 【exceljs】纯前端如何实现Excel导出下载和上传解析?
  • 【JS】如何识别一个变量是不是数组对象
  • 控制Stable Diffusion生成质量的多种方法
  • Linux工具的使用-【git的理解和使用】【调试器gdb的使用】
  • TCP/UDP 通用通信代码库(C语言实现)
  • 基于Multisim的汽车尾灯控制电路设计与仿真
  • HarmonyOS开发 - ohpm环境变量配置
  • JAVA课设-图书指引系统(前后端分离)
  • 期权懂|股票下跌时可以使用期权止损吗?
  • 绝对差值的和
  • 【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-1
  • 高级java每日一道面试题-2024年10月19日-消息队列[RabbitMQ]-RabbitMQ中积压了大量的消息,如何处理?
  • Saprk:数据插入的优化(forachPartition)
  • 电能表预付费系统-标准传输规范(STS)(15)
  • Hadoop---HDFS(2)
  • A Graph-Transformer for Whole SlideImage Classification文献笔记
  • arm_acle.h找不到
  • 基于递推式最小二乘法的PMSM参数辨识MATLAB仿真模型
  • 六、栈————相关概念详解
  • ChatGPT4o、o1 谁才是最佳大模型?
  • DDD话语批评之一:评“状态和事件本质相同”[全文]
  • 稀疏表示的图像修复、图像退化、白噪声
  • Linux conda activate报错:CondaError: Run ‘conda init‘ before ‘conda activate‘
  • 算法|牛客网华为机试1-10C++
  • 拥抱云开发的未来:腾讯云数据库、云模板与AI智能化的应用场景探索
  • 大数据新视界 --大数据大厂之区块链技术:为大数据安全保驾护航