da11
一、xml文件修改
文件位置:F:\QGC\mavlink\mavlink\message_definitions\v1.0\ardupilotmega.xml
修改内容:仿照原有格式,自定义ID236号 添加在226号之后,如下:
<message id="226" name="RPM">
<description>RPM sensor output.</description>
<field type="float" name="rpm1">RPM Sensor1.</field>
<field type="float" name="rpm2">RPM Sensor2.</field>
<!--标记:参考CSDN文章-->
</message><!--示例文件CSDN TEXT-->
<!--定义消息id为236,名称为“CSDN TEXT"-->
<message id="236" name="CSDN_TEST">
<!--对消息的描述,表明它是 CSDN TEXT。-->
<description>CSDN TEXT.</description>
<!--定义名为 "byte1" 的字段,类型为无符号8位整数(uint8_t),并提供了描述FRIST BYTE.-->
<field type="uint8_t" name="byte1">FRIST BYTE.</field>
<!--定义名为 "byte2" 的字段,类型为无符号8位整数(uint8_t),并提供了描述SECOND BYTE.-->
<field type="uint8_t" name="byte2">SECOND BYTE.</field>
<!--定义了消息的结束标签。-->
</message>
定义了byte1、byte2两个字节的数据,数据内容为所需传递的信息
二、MavLink文件夹内进行的操作与操作目的讲解
1.MavLink源码来源:https://github.com/mavlink/mavlink.git
2.MavLink作用:在QGC二次开发过程中调用MavLink生成器
使用方法:
进入下载的MavLink的根文件夹内 F:\QGC\mavlink\mavlink,win+R输入CMD打开终端并输入 python mavgenerate.py启动MavLink生成器。(注意python 3.0版本)
注:XML:F:/QGC/mavlink/mavlink/message_definitions/v1.0/ardupilotmega.xml
Out:新建文件夹 用于存储新生成的MavLink文件 不建议直接覆盖MavLink文件夹中的原有MavLink文件
Language:选择 C
Protocol : 选择 2.0
最后点击generate生成新的MavLink文件,存储在Out所选位置。
所生成的MavLink文件如下:F:\QGC\mavlink\OUT1
到此为止,需要在MavLink文件夹中进行的操作已全部结束,其目的就是利用mavgenerate.py更方便的生成我们所需要的MavLink文件,即上图内容。
三、复制生成的MavLink文件到QGC的mavlink文件夹进行添加自定义
在上一步生成的MavLink文件中(路径:F:\QGC\mavlink\OUT1\ardupilotmega\mavlink_msg_csdn_test.h)
复制mavlink_msg_csdn_test.h到qgc源码文件夹的对应位置(路径:F:\QGC\qgroundcontrol\qgroundcontrol\libs\mavlink\include\mavlink\v2.0\ardupilotmega)
之后修改qgc源码中mavlink的ardupilotmega.h文件中的三个地方,目的是通过mavlink通讯校验。
1、修改qgc源码中mavlink的ardupilotmege.h中的#define MAVLINK_MESSAGE_CRCS校验处,增加了236号的ID,如下图所示。
(从mavlink文件夹中的ardupilotmege.h中的#define MAVLINK_MESSAGE_CRCS校验处复制生成的236号ID校验码,粘贴到qgc源码中mavlink的ardupilotmege.h中的#define MAVLINK_MESSAGE_CRCS校验处)
2.include mavlink_msg_csdn_test.h文件
在qgc源码中mavlink的ardupilotmege.h中#include mavlink_msg_csdn_test.h文件
3.在qgc源码中mavlink的ardupilotmege.h中修改MAVLINK_MESSAGE_INFO:添加了MAVLINK_MESSAGE_INFO_CSDN_TEST
4.在qgc源码中mavlink的ardupilotmege.h中修改MAVLINK_MESSAGE_NAMES:添加了{ "CSDN_TEST", 236 }
四、认识相关类以及理清功能逻辑
4.1QGC页面发送显示
文件:FlightDisplayView.qml
发送功能关键函数: activeVehicle.testSendToVehicle(protectTextField1.text,protectTextField2.text)
//QML 中矩形对象 sendRect 的属性设置;发送部分设置
Rectangle{
//指定矩形对象的唯一标识符
id: sendRect
//将矩形对象的顶部边缘与其父级元素的顶部边缘对齐
anchors.top: parent.top
//设置矩形对象与其父级元素顶部的间距为 20 像素
anchors.topMargin: 20
//将矩形对象的水平中心与其父级元素的水平中心对齐
anchors.horizontalCenter: parent.horizontalCenter
//设置矩形对象的高度为 col 元素的高度的 1.1 倍
height: col.height*1.2
//设置矩形对象的宽度为 col 元素的宽度的 1.1 倍
width: col.width*1.2
//设置矩形对象的圆角半径为 2
radius: 2
//设置矩形对象的颜色为黑色
color: "black"
//定义了一个垂直布局的 Column 容器,用于包含多个子元素
Column{
id: col
//设置子元素之间的垂直间距为 4 像素
spacing: 4
//将 Column 容器居中放置在其父级元素中心位置
anchors.centerIn: parent
//QGCLabel 组件,用于显示文本内容
QGCLabel {
//将 QGCLabel 组件水平居中放置在 Column 容器中
anchors.horizontalCenter: parent.horizontalCenter
//设置 QGCLabel 组件显示的文本内容为 "Mavlink 发送测试!"
text: "Mavlink 发送测试!"
//设置字体大小为 12
font.pointSize: 12
//设置文字为粗体显示
font.bold: true
//设置文字颜色为红色
color: "red"
}
//定义了一个水平布局的 Row 容器:Row容器是一种布局容器,用于将多个子元素水平排列在一行上
Row{
//将 Row 容器的左边缘与其父级元素的左边缘对齐
anchors.left: parent.left
//将 Row 容器的右边缘与其父级元素的右边缘对齐
anchors.right: parent.right
//QGCLabel组件是一个用于显示文本标签的控件
QGCLabel {
id: tipsLabel
//将 QGCLabel 组件的垂直中心与 protectTextField1 组件的垂直中心对齐
anchors.verticalCenter: protectTextField1.verticalCenter
//设置 QGCLabel 组件显示的文本内容为 "第一个字节:"
text: qsTr("第一个字节:")
//设置字体大小为 11
font.pointSize: 11
//设置文字为粗体显示
font.bold: true
//设置文字颜色为 "#B7FF4A":亮绿色
color: "#B7FF4A"
}
//QGCTextField组件是一个用于接收用户输入的文本框控件。它具有各种属性和事件,用于设置文本框的外观和行为。
QGCTextField {
id: protectTextField1
//设置宽度为父组件的宽度(parent.width)减去父组件的间距(parent.spacing)和tipsLabel的宽度(tipsLabel.width)
width: parent.width - parent.spacing - tipsLabel.width
//高度为tipsLabel高度的1.5倍
height: tipsLabel.implicitHeight*1.5
//置文本框中显示的默认文本为 "1"
text: "1"
//设置输入法提示,使用 Qt.ImhFormattedNumbersOnly 表示只允许格式化的数字输入
//InputMethodHints: Qt.ImhFormattedNumbersOnly
//设置文本框初始化时是否获取焦点,默认为true,即初始化后自动获得焦点
focus: true
//事件处理程序:当编辑完成时触发此事件处理程序。在此处,如果输入的文本大于256,则将文本设置为256,并弹出一个警告对话框显示消息"输入必须小于等于256";如果文本小于0,则将文本设置为0,并弹出一个警告对话框显示消息"输入必须大于等于0"
onEditingFinished:{
if(text>256){
text = 256
mainWindow.showMessageDialog(qsTr("警告"),qsTr("输入必须小于等于256"))
}
else if(text < 0 ){
text = 0
mainWindow.showMessageDialog(qsTr("警告"),qsTr("输入必须大于等于0"))
}
}
}
}
//Row容器是一种布局容器,用于将多个子元素水平排列在一行上
Row{
anchors.left: parent.left
anchors.right: parent.right
//QGCTextField组件是一个用于接收用户输入的文本框控件。它具有各种属性和事件,用于设置文本框的外观和行为。
QGCLabel {
id: tipsLabel2
//将 QGCLabel 组件的垂直中心与 protectTextField1 组件的垂直中心对齐
anchors.verticalCenter: protectTextField2.verticalCenter
//设置 QGCLabel 组件显示的文本内容为 "第二个字节:"
text: qsTr("第二个字节:")
//设置字体大小为 11
font.pointSize: 11
//设置文字为粗体显示
font.bold: true
//设置文字颜色为 "#B7FF4A":亮绿色
color: "#B7FF4A"
}
//QGCTextField组件是一个用于接收用户输入的文本框控件。它具有各种属性和事件,用于设置文本框的外观和行为。:用于保护距离的输入
QGCTextField {
id: protectTextField2
//设置宽度为父组件的宽度(parent.width)减去父组件的间距(parent.spacing)和tipsLabel的宽度(tipsLabel.width)
width: parent.width - parent.spacing - tipsLabel2.width
//高度为tipsLabel高度的1.5倍
height: tipsLabel2.implicitHeight*1.5
//置文本框中显示的默认文本为 "1"
text: "1"
//设置输入法提示,使用 Qt.ImhFormattedNumbersOnly 表示只允许格式化的数字输入(用不了)
//InputMethodHints: Qt.ImhFormattedNumbersOnly
//设置文本框初始化时是否获取焦点,默认为true,即初始化后自动获得焦点
focus: true
//事件处理程序:当编辑完成时触发此事件处理程序。在此处,如果输入的文本大于256,则将文本设置为256,并弹出一个警告对话框显示消息"输入必须小于等于256";如果文本小于0,则将文本设置为0,并弹出一个警告对话框显示消息"输入必须大于等于0"
onEditingFinished:{
if(text>256){
text = 256
mainWindow.showMessageDialog(qsTr("警告"),qsTr("输入必须小于等于256"))
}
else if(text < 0 ){
text = 0
mainWindow.showMessageDialog(qsTr("警告"),qsTr("输入必须大于等于0"))
}
}
}
}
//QGCButton一种按钮控件,用于触发操作、提交表单、触发事件等
QGCButton {
id: mavTestButton
//设置按钮的背景圆角半径为高度的一半,使按钮呈现圆形的外观。
backRadius: height/2
//置按钮显示的文本内容为 "MAVLINK消息发送测试",这是按钮上显示的文字。
text: qsTr("MAVLINK消息发送测试")
//设置按钮是否可用的状态为 activeVehicle 的值,即只有当 activeVehicle 为 true 时按钮才可用。
enabled: activeVehicle
//当按钮被点击时触发的事件处理函数。在函数内部,首先检查 activeVehicle 是否为真,如果是,则调用 activeVehicle 的 testSendToVehicle 方法,传递 protectTextField1.text 和 protectTextField2.text 作为参数。
onClicked:{
if(activeVehicle)
activeVehicle.testSendToVehicle(protectTextField1.text,protectTextField2.text)
}
}
}
}
4.2QGC接收页面显示
接收关键: text: activeVehicle ? activeVehicle.rcvByte1:""
text: activeVehicle ? activeVehicle.rcvByte2:""
//接收显示
Rectangle{
//将矩形对象的顶部边缘与其父级元素的顶部边缘对齐
anchors.top: sendRect.bottom
//设置矩形对象与其父级元素顶部的间距为 20 像素
anchors.topMargin: 20
//将矩形对象的水平中心与其父级元素的水平中心对齐
anchors.horizontalCenter: parent.horizontalCenter
//设置矩形对象的高度为 col 元素的高度的 1.2 倍
height: colSendRect.height*1.4
//设置矩形对象的宽度为 col 元素的宽度的 1.2 倍
width: colSendRect.width*1.4
//设置矩形对象的圆角半径为 2
radius: 2
//设置矩形对象的颜色为黑色
color: "black"
Column{
id: colSendRect
spacing: 4
anchors.centerIn: parent
//QGCTextField组件是一个用于接收用户输入的文本框控件。它具有各种属性和事件,用于设置文本框的外观和行为。
QGCLabel{
anchors.horizontalCenter: parent.horizontalCenter
text: "MAVLink 接收测试!"
font.pointSize: 12
font.bold: true
color: "red"
}
//Row容器是一种布局容器,用于将多个子元素水平排列在一行上
Row {
id: row1
anchors.horizontalCenter: parent.horizontalCenter
height: label1.height
//QGCTextField组件是一个用于接收用户输入的文本框控件。它具有各种属性和事件,用于设置文本框的外观和行为。
QGCLabel{
id: label1
anchors.verticalCenter: parent.verticalCenter
text: qsTr("接收到的第一个字节 :")
font.pointSize: 11
font.bold: true
color: "#B7FF4A"
//设置层级
//z: _panel.z + 4
}
//QGCTextField组件是一个用于接收用户输入的文本框控件。它具有各种属性和事件,用于设置文本框的外观和行为。
QGCLabel{
anchors.verticalCenter: parent.verticalCenter
//设置文本内容为 activeVehicle.rcvByte1 的值。如果 activeVehicle 存在且 rcvByte1 有值,文本内容将设置为 activeVehicle.rcvByte1;否则,文本内容将为空字符串。
text: activeVehicle ? activeVehicle.rcvByte1:" "
font.pointSize: 11
font.bold: true
color: "#B7FF4A"
}
}
Row{
anchors.left: row1.left
height: label2.hight
QGCLabel{
id: label2
anchors.verticalCenter: parent.verticalCenter
text: qsTr("接收到的第二个字节 : ")
font.pointSize: 11
font.bold: true
color: "#B7FF4A"
}
QGCLabel{
anchors.verticalCenter: parent.verticalCenter
//设置文本内容为 activeVehicle.rcvByte1 的值。如果 activeVehicle 存在且 rcvByte1 有值,文本内容将设置为 activeVehicle.rcvByte1;否则,文本内容将为空字符串。
text: activeVehicle ? activeVehicle.rcvByte2:" "
font.pointSize: 11
font.bold: true
color: "#B7FF4A"
}
}
}
}
五、C++后端
5.1QGC发送
关键函数: activeVehicle.testSendToVehicle(protectTextField1.text,protectTextField2.text)
5.1.1 Vehicle.h头文件声明
找到class Vehicle : public FactGroup,在public:类中添加一下内容:Q_INVOKABLE void testSendToVehicle(quint8 byte1,quint8 byte2);
class Vehicle : public FactGroup
{
Q_OBJECT
public:
...
Q_INVOKABLE void testSendToVehicle(quint8 byte1,quint8 byte2);
5.1.2 Vehicle.cc文件
QGC发送函数:void Vehicle::testSendToVehicle(quint8 byte1,quint8 byte2)
//QGC开发测试内容
//范围解析运算符:: 类::成员函数 用于在类的外部定义类的成员函数
//定义了一个成员函数,用于QGC发送数据
void Vehicle::testSendToVehicle(quint8 byte1,quint8 byte2)
{
// 定义一个 MAVLink 消息变量
mavlink_message_t msg;
// 定义一个 CSDN 测试消息变量
mavlink_csdn_test_t csdn_test_t;
// 将用户传入的数据填充到结构体中
csdn_test_t.byte1 = byte1;
csdn_test_t.byte2 = byte2;
// 输出填充后的 byte1和byte2 数据,用于调试和确认
qDebug() << "csdn_test_t.byte1 :" << csdn_test_t.byte1;
qDebug() << "csdn_test_t.byte2 :" << csdn_test_t.byte2;
// 使用 MAVLink 库中的函数将数据编码进消息中
mavlink_msg_csdn_test_encode_chan(_mavlink->getSystemId(),
_mavlink->getComponentId(),
priorityLink()->mavlinkChannel(),
&msg,
&csdn_test_t);
sendMessageOnLink(priorityLink(),msg);
}
5.2 MockLink接收
5.2.1 //MockLink.cc
MockLink定义接受函数:void MockLink::_handleCSDNTest(const mavlink_message_t& msg)
//MockLink接收函数
void MockLink::_handleCSDNTest(const mavlink_message_t& msg)
{
mavlink_csdn_test_t csdn_test_t;
mavlink_msg_csdn_test_decode(&msg, &csdn_test_t);
qDebug() << "[MOCKLINK] Rcv byte1 : " <<csdn_test_t.byte1;
qDebug() << "[MOCKLINK] Rcv byte2 : " <<csdn_test_t.byte2;
}
5.2.2 //MockLink.cc
调用MockLink接收函数:
在void MockLink::_handleIncomingMavlinkBytes(const uint8_t* bytes, int cBytes)函数中添加一下内容:
//QGC二次开发:调用MockLink接收函数
case MAVLINK_MSG_ID_CSDN_TEST:
_handleCSDNTest(msg);
break;
void MockLink::_handleIncomingMavlinkBytes(const uint8_t* bytes, int cBytes)
{
...
//参照格式添加
//QGC二次开发:调用MockLink接收函数
case MAVLINK_MSG_ID_CSDN_TEST:
_handleCSDNTest(msg);
break;
...
5.2.3 MockLink接收函数声明
//MockLink.h
在class MockLink : public LinkInterface的public类中添加一下内容:
//MockLinke接收函数声明
void _handleCSDNTest(const mavlink_message_t& msg);
class MockLink : public LinkInterface
{
Q_OBJECT
public:
...
//MockLinke接收函数声明
void _handleCSDNTest(const mavlink_message_t& msg);
...
5.3 MockLink发送部分
5.3.1 //MockLink.h
MockLink发送声明
在class MockLink : public LinkInterface的公共类public中添加一下内容:
//MockLink发送两字节数据的声明
void _sendCSDNTest(void);
uint8_t _testByte1;
uint8_t _testByte2;
class MockLink : public LinkInterface
{
Q_OBJECT
public:
...
//MockLink发送两字节数据的声明
void _sendCSDNTest(void);
uint8_t _testByte1;
uint8_t _testByte2;
...
5.3.2 //MockLink.cc
MockLink数据初始化
在MockLink::MockLink(SharedLinkConfigurationPointer& config)中添加一下内容:
//MockLink发送数据函数 数据初始化
, _testByte1 (0)
, _testByte2 (0)
MockLink::MockLink(SharedLinkConfigurationPointer& config){
...
//MockLink发送数据函数 数据初始化
, _testByte1 (0)
, _testByte2 (0)
...
}
5.3.3 //MockLink.cc
MockLink定义发送函数:
void MockLink::_sendCSDNTest(void)
{
mavlink_message_t msg;
_testByte1++;
_testByte2--;
mavlink_msg_csdn_test_pack_chan(_vehicleSystemId, //车辆系统ID
_vehicleComponentId, //车辆组件ID
_mavlinkChannel, //Mavlink通道
&msg,
_testByte1,
_testByte2
);
respondWithMavlinkMessage(msg);
}
5.3.4 模拟发送所需定时器设置
在void MockLink::_run1HzTasks(void)中添加:
//借助定时器模拟发送,频率1Hz
_sendCSDNTest();
void MockLink::_run1HzTasks(void)
{
...
//借助定时器模拟发送,频率1Hz
_sendCSDNTest();
...
}
5.4 QGC接收
5.4.1 //Vehicle.h
QGC接收函数声明:分为三部分,分别在public、signals、private中添加对应部分
在class Vehicle : public FactGroup中:
public:
//QGC二次开发 :新增QGC接收变量和函数声明
Q_PROPERTY(quint8 rcvByte1 READ rcvByte1 NOTIFY rcvByte1Changed)
Q_PROPERTY(quint8 rcvByte2 READ rcvByte2 NOTIFY rcvByte2Changed)
quint8 rcvByte1 () {return _rcvByte1;}
quint8 rcvByte2 () {return _rcvByte2;}
signals:
void rcvByte1Changed (quint8 rcvByte1);
void rcvByte2Changed (quint8 rcvByte2);
privates:
//QGC二次开发 :新增QGC接收变量和函数声明
void _handleCSDNTestRcv(mavlink_message_t& message);
quint8 _rcvByte1;
quint8 _rcvByte2;
class Vehicle : public FactGroup
{
Q_OBJECT
public:
...
//QGC二次开发 :新增QGC接收变量和函数声明
Q_PROPERTY(quint8 rcvByte1 READ rcvByte1 NOTIFY rcvByte1Changed)
Q_PROPERTY(quint8 rcvByte2 READ rcvByte2 NOTIFY rcvByte2Changed)
quint8 rcvByte1 () {return _rcvByte1;}
quint8 rcvByte2 () {return _rcvByte2;}
...
signals:
...
void rcvByte1Changed (quint8 rcvByte1);
void rcvByte2Changed (quint8 rcvByte2);
...
private:
...
//QGC二次开发 :新增QGC接收变量和函数声明
void _handleCSDNTestRcv(mavlink_message_t& message);
quint8 _rcvByte1;
quint8 _rcvByte2;
...
}
5.4.2 QGC接收函数定义
//QGC接收
void Vehicle::_handleCSDNTestRcv(mavlink_message_t& message)
{
mavlink_csdn_test_t csdn_test_t;
mavlink_msg_csdn_test_decode(&message, &csdn_test_t);
_rcvByte1 = csdn_test_t.byte1;
_rcvByte2 = csdn_test_t.byte2;
//触发信号,在QML前端中接收
emit rcvByte1Changed(_rcvByte1);
emit rcvByte2Changed(_rcvByte2);
}
5.4.3 调用QGC接收函数
在void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t message)
中的switch (message.msgid)中添加以下内容:
//QGC二次开发 修改 调用QGC接收函数
case MAVLINK_MSG_ID_CSDN_TEST:
_handleCSDNTestRcv(message);
break;
void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t message)
{
...
switch (message.msgid) {
...
//QGC二次开发 修改 调用QGC接收函数
case MAVLINK_MSG_ID_CSDN_TEST:
_handleCSDNTestRcv(message);
break;
...
}
5.4.4 QGC接收函数的变量初始化
在Vehicle::Vehicle(LinkInterface* link,
...
JoystickManager* joystickManager)
: FactGroup(...)中添加以下内容:
//QGC接收变量初始化
, _rcvByte1(0)
, _rcvByte2(0)
Vehicle::Vehicle(LinkInterface* link,
int vehicleId,
int defaultComponentId,
MAV_AUTOPILOT firmwareType,
MAV_TYPE vehicleType,
FirmwarePluginManager* firmwarePluginManager,
JoystickManager* joystickManager)
: FactGroup(_vehicleUIUpdateRateMSecs, ":/json/Vehicle/VehicleFact.json")
...
//QGC接收变量初始化
, _rcvByte1(0)
, _rcvByte2(0)
...