
QGC二次开发入门教程(一):课程大纲
QGC版本:4.2.4稳定版需要的基础:少量的C++、QT基础飞控固件:PX4、Ardupilot课程答疑微(18362086993)课程所用虚拟机(已配置好开发环境)链接:https://pan.baidu.com/s/12zes9Jk2OB_c2ghNsAKv1w?pwd=7o4u提取码:7o4u–来自百度网盘超级会员V6的分享独家汉化版QGC下载地址:链接:https://pan.baidu
文章目录
前言
可加文章底部作者微信进交流群
QGC版本:4.2.4稳定版
需要的基础:少量的C++、QT基础
飞控固件:PX4、Ardupilot
修改后的QGC源码:
通过百度网盘分享的文件:QGC二次开发入门
链接:https://pan.baidu.com/s/1xOb3nVFcFdgcZN6RYBohUQ?pwd=cwkj
提取码:cwkj
–来自百度网盘超级会员V7的分享
课程所用虚拟机(已配置好开发环境)
链接:https://pan.baidu.com/s/12zes9Jk2OB_c2ghNsAKv1w?pwd=7o4u
提取码:7o4u
–来自百度网盘超级会员V6的分享
VMware下载(使用VM17)
链接:https://pan.baidu.com/s/1lBCMX1O3U-T64gzM5c0IYg?pwd=ylf6
提取码:ylf6
–来自百度网盘超级会员V6的分享
虚拟机的安装和打开:
https://cwkj-tech.yuque.com/bsge84/uav-m1/cuut9sq5sci8c5wr#rdB9k
独家汉化版QGC下载地址:
链接:https://pan.baidu.com/s/16G97kfid-tDQq2kZCEYjnQ?pwd=es97
提取码:es97
–来自百度网盘超级会员V6的分享
QGC二次开发入门教程(一):课程大纲
编译环境安装可以参考:
6.1、QGC编译环境安装(ubuntu)
课程目录(暂时想到这么多,后续会不断更新)
一、课程大纲
二、修改软件名称
改一行代码就行
修改
QGCApplication.cc
setApplicationName("cwkj");
修改后效果如下:
三、修改软件图标
添加图片资源
新建一个文件夹img_add,放入需要添加的图片资源
然后在qgcimages.qrc中点击添加->添加文件,选择上面添加的图片,然后填写别名,回车然后ctrl+s保存qgcimages.qrc
然后就可以在程序中使用添加的图片了,注意程序中填写的是图片的别名。
修改主工具栏图标:
修改MainToolBar.qml,在下图位置修改图片资源的路径为自己添加的资源(以软件设置按钮为例):
icon.source: "/qmlimages/软件图标.png"
效果如下:
修改软件设置图标:
修改MainRootWindow.qml
需要修改两个地方:
showTool(qsTr("Application Settings"), "AppSettings.qml", "/qmlimages/软件图标.png")
imageResource: "/qmlimages/软件图标.png"
四、官方QGC中文版BUG修复
QGC中文bug解决教程
五、汉化
打开QGC源码工程,点击工具->外部->Linguist->Update Translations(lupdate),弹窗选全是
然后打开Qt Linguist
在Qt Linguist中点击file->open,打开汉化脚本
打开后,在左侧会显示总个数和已汉化的个数,点击没有全部汉化的Context,在右侧对有问号的进行汉化,在简体中文下面的输入框写入对应的汉化结果,然后点击上方的勾号,勾完后对应的问号就变成了勾号,然后点击上方的保存按钮。
保存后打开QGC工程源码,如果出现下面的提示,选全是,然后编译
编译后效果如下:
六、修改商标
修改PX4FirmwarePlugin.h下图位置,将图片改成自己想显示的图片:
QString brandImageIndoor (const Vehicle* vehicle) const override { Q_UNUSED(vehicle); return QStringLiteral("/qmlimages/软件图标.png"); }
QString brandImageOutdoor (const Vehicle* vehicle) const override { Q_UNUSED(vehicle); return QStringLiteral("/qmlimages/软件图标.png"); }
修改后效果如下:
七、添加信号-槽
1、添加文件到QGC工程
在qgroundcontrol/src目录下创建SimpleTest文件夹
在文件夹中创建SimpleTest.cpp
、SimpleTest.h
和SimpleTest.qml
三个文件
在qgroundcontrol.pro
中添加下图位置添加src/SimpleTest/SimpleTest.h\
下图位置添加src/SimpleTest/SimpleTest.cpp\
然后即可将添加的test.cpp和test.h编译到QGC中。
SimpleTest.cpp
填入内容如下:
#include "SimpleTest.h"
#include <QtCharts/QLineSeries>
#include<qdebug.h>
SimpleTest::SimpleTest()
{
connect(this,&SimpleTest::valueChanged,this,&SimpleTest::_test);
}
SimpleTest::~SimpleTest()
{
}
void SimpleTest::setTest1(QString test)
{
_test1=test;
qDebug()<<test;
emit valueChanged();
}
void SimpleTest::setTest2(QString test)
{
_test2=test;
qDebug()<<test;
emit valueChanged2();
}
void SimpleTest::_test()
{
qDebug()<<"in C++ slot";
emit _testChanged();
}
SimpleTest.h
填入内容如下:
#pragma once
#include <QObject>
#include <QString>
#include <QMetaObject>
#include <QStringListModel>
// Fordward decls
class Vehicle;
class SimpleTest : public QObject
{
Q_OBJECT
public:
SimpleTest();
virtual ~SimpleTest();
Q_PROPERTY(QString test1 READ test1 WRITE setTest1 NOTIFY valueChanged)
Q_PROPERTY(QString test2 READ test2 WRITE setTest2 NOTIFY valueChanged2)
QString test1 ()
{
return _test1;
}
QString test2 ()
{
return _test2;
}
void setTest1(QString test1);
void setTest2(QString test2);
signals:
void valueChanged();
void valueChanged2();
void _testChanged();
private slots:
void _test(void);
private:
QString _test1="A";
QString _test2="a";
};
SimpleTest.qml
填入内容如下:
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QGroundControl 1.0
import QGroundControl.Palette 1.0
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Controllers 1.0
import SimpleTest 1.0
AnalyzePage {
id: mavlinkConsolePage
pageComponent: pageComponent
pageName: qsTr("SimpleTest")
SimpleTest {
id: _SimpleTest
}
Connections
{
target: _SimpleTest
function on_testChanged()
{
_SimpleTest.test2="c"
}
}
TextEdit {
id: textEdit
x: 285
y: 189
width: 81
height: 25
color: "#f5f3f3"
text: qsTr(_SimpleTest.test1)
font.family: "Times New Roman"
font.pixelSize: 12
}
TextEdit {
id: textEdit1
x: 285
y: 229
width: 81
height: 25
color: "#f5f3f3"
text: qsTr(_SimpleTest.test2)
font.family: "Times New Roman"
font.pixelSize: 12
}
Button {
id: button
x: 372
y: 189
text: qsTr("发送")
onClicked: {
_SimpleTest.test1="C"
}
}
}
2、添加界面
在qgroundcontrol.qrc中将上面创建的QML资源添加进去,点击Add Files选择上面创建的QML文件。取别名叫SimpleTest.qml。注意添加完后一定不要忘了把下面别名那个输入框填上别名,注意别名不要写错,不要忘了加上后缀.qml。否则如果后面QGCCorePlugin.cc引用的时候和别名不一样,会导致页面里是空的
然后修改QGCCorePlugin.cc文件
添加一行
_p->analyzeList.append(QVariant::fromValue(new QmlComponentInfo(tr("SimpleTest"), QUrl::fromUserInput("qrc:/qml/SimpleTest.qml"), QUrl::fromUserInput("qrc:/qmlimages/MavlinkConsoleIcon"))));
3、QML和C++交互
1.C++类如果想被QML访问,需要满足两个条件:
(1)继承自QObject类
(2)添加Q_OBJECT宏
对应本例如下:
2.C++实例注册到qml
QT可以通过qmlRegisterUncreatableType或者qmlRegisterType将 C++的类声明为 qml 中可以访问的类型:
首先在QGCApplication.cc
中添加头文件:
#include "SimpleTest/SimpleTest.h"
(1)qmlRegisterType
qmlRegisterType 声明的 C++类型可以在 qml 文件中直接构造,在 qml 中通过 id来访问属性和方法。
qmlRegisterType里总共4个参数:第一个参数指的是QML中import后的内容,相当于头文件名;第二个第三个参数分别是主次版本号;第四个指的是QML中类的名字。
在本例中,在QGCApplication.cc
中下图位置添加:
qmlRegisterType<SimpleTest> ("SimpleTest", 1, 0, "SimpleTest");
然后先在SimpleTest.qml
中import SimpleTest 1.0
,再
SimpleTest {
id: _SimpleTest
}
就可以通过_SimpleTest
访问SimpleTest
类中的属性和方法。
注册属性或者方法
通过上面的方式将 C++类注册入 Qt 的元对象系统中后 ,可以通过 Q_PROPERTY 注册qml 可以调用的属性,同时可以通过在函数声明前添加Q_INVOKABLE 来声明 qml 可以调用的方法。
属性声明
主要存在以下几种形式:
Q_PROPERTY(int
test
READ
test
CONSTANT)
当该属性的值一旦被赋值,在整个程序运行期间 C++中不会修改该属性。
Q_PROPERTY(int
test
READ
test
NOTIFY valueChanged)
这种方法声明的属性只有在C++中会更改,当更改时,发射 valueChanged 信号来通知 qml 。
Q_PROPERTY(int
test
READ
test
WRITE
settest
NOTIFY valueChanged)
这种方法声明的属性在C++和QML中都可能被更改,当在 C++中改变该参数值时,发射 valueChanged 信号来通知 qml 。在 qml 中也可以对test进行赋值,触发 C++中的 settest 函数,来实现相关属性的更改。
方法声明
方法声明只需要我们在函数定义前面添加 Q_INVOKABLE 即可。
如:Q_INVOKABLE void test(void);
本例声明了下面两个属性,test1和test2在C++和QML中都可能被更改,当值更改时,触发valueChanged信号
在QML中将输入框textEdit显示的内容设置为
_SimpleTest.test1
,_SimpleTest.test1
对应C++中的:
QString test1 ()
{
return _test1;
}
_test1定义如下,默认值为“A”,所以框中默认显示A
QString _test1="A";
在QML中通过_SimpleTest.test1
对属性进行赋值,点击按钮后将test1赋值为“C”
_SimpleTest.test1
调用了C++的setTest1
方法,在该方法中将形参(也就是“C”)赋值给_test1,同时触发valueChanged()信号,通知QML相关的属性已发生改变,来更新相关的显示。
void SimpleTest::setTest1(QString test)
{
_test1=test;
qDebug()<<test;
emit valueChanged();
}
所以本例中在点击按钮后,输入框textEdit显示的值将从“A”变为“C”
4、信号与槽
信号(Signal)就是在特定情况下被发射的事件(如上一节的valueChanged()),槽函数相当于回调函数,在触发特定的信号后执行。
槽函数的声明:
C++中连接信号与槽
一般在构造函数中连接。
connect的参数的含义如下:
connect(
const QObject *sender, //信号发送者
const char *signal, //发送的信号
const QObject *receiver, //信号接收者
const char *method, //表示与信号连接的方式的字符串,可以是槽或信号
Qt::ConnectionType type = Qt::AutoConnection //连接方式,默认自动连接
)
本例中信号是valueChanged(),槽函数是_test()。
槽函数的实现如下:
void SimpleTest::_test()
{
qDebug()<<"in C++ slot";
emit _testChanged();
}
在槽函数中发射了_testChanged()信号。
QML中连接信号与槽
QML通过Connections类型连接信号与槽函数。本例如下:
Connections分为两部分:一个是target属性,表示发出信号的对象。另一个是对应信号的槽函数。
使用示例如下:
Connections {
target: targetA;
function onAsignal1() {
// 信号处理槽函数
}
}
本例中信号发出的对象来自_SimpleTest,具体的信号为_testChanged(),在槽函数中将
_SimpleTest.test2设置为“c”
也就是说,点击按钮后,会触发valueChanged()信号,进入到C++的_test()槽函数中,发射_testChanged()信号,进入到QML的on_testChanged,将test2设置为“c”。
5、测试
编译QGC,进入下面的页面。
点击“发送”按钮,原来的A和a会变成C和c。
八、添加QML和C++交互
1、添加文件
在src目录下添加文件夹SingletonTest,在里面新建SingletonTest.cc和SingletonTest.h
SingletonTest.cc
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#include "SingletonTest.h"
#include "QGCLoggingCategory.h"
#include "QGCToolbox.h"
#include "QGCApplication.h"
#include "SettingsManager.h"
#include "PositionManager.h"
#include <QTime>
#include <QDateTime>
#include <QLocale>
#include <QQuaternion>
#include <Eigen/Eigen>
#include <QDebug>
SingletonTest::SingletonTest():_toolbox (qgcApp()->toolbox())
{
connect(&timer, &QTimer::timeout, this, &SingletonTest::send_mavlink);
timer.setInterval(500);
timer.start();
_mavlink = _toolbox->mavlinkProtocol();
connect(_mavlink, &MAVLinkProtocol::messageReceived, this, &SingletonTest::_mavlinkMessageReceived);
}
SingletonTest::~SingletonTest()
{
}
void SingletonTest::send_mavlink()
{
auto *manager = qgcApp()->toolbox()->multiVehicleManager();
_vehiclelist=manager->vehicles();
if(_vehiclelist && _vehiclelist->objectList()->count()>0)
{
for(int i=0;i<_vehiclelist->objectList()->count();i++)
{
QObject* obj = _vehiclelist->get(i);
Vehicle* vehicle0=static_cast<Vehicle*> (obj);
// if (vehicle0->id()==1)
// {
WeakLinkInterfacePtr weakLink = vehicle0->vehicleLinkManager()->primaryLink();
if (!weakLink.expired()) {
SharedLinkInterfacePtr sharedLink = weakLink.lock();
if (!sharedLink) {
qCDebug(VehicleLog) << "_handlePing: primary link gone!";
return;
}
// auto protocol = qgcApp()->toolbox()->mavlinkProtocol();
auto priority_link =sharedLink;
mavlink_message_t msg;
mavlink_msg_gps_raw_int_pack(vehicle0->id(),
vehicle0->id(),
&msg,
1,
1,
_test1.toLong(),
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1);
// mavlink_msg_adsb_vehicle_pack(vehicle0->id(),
// vehicle0->id(),
// &msg,
// 12345,
// _test1.toLong(),
// 1,
// 1,
// 1,
// 1,
// 1,
// 1,
// "1",
// 1,
// 1,
// 1,
// 1);
vehicle0->sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
}
// }
}
}
}
void SingletonTest::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t message)
{
switch (message.msgid) {
case MAVLINK_MSG_ID_GPS_RAW_INT:
_handleGpsRawInt(message);
break;
case MAVLINK_MSG_ID_ADSB_VEHICLE:
_handleADSBVehicle(message);
break;
}
}
void SingletonTest::_handleGpsRawInt(mavlink_message_t& message)
{
mavlink_gps_raw_int_t gpsRawInt;
mavlink_msg_gps_raw_int_decode(&message, &gpsRawInt);
_test1=QString::number(gpsRawInt.lat/ (double)1E7);
emit test1Changed();
}
void SingletonTest::_handleADSBVehicle(mavlink_message_t& message)
{
mavlink_adsb_vehicle_t adsbVehicleMsg;
mavlink_msg_adsb_vehicle_decode(&message, &adsbVehicleMsg);
if(adsbVehicleMsg.ICAO_address==12345)
{
_isboat=true;
}
else
{
_isboat=false;
}
emit test1Changed();
}
void SingletonTest::setTest1(QString test1)
{
_test1=test1;
emit test1Changed();
}
void SingletonTest::setIsboat(bool isboat)
{
_isboat=isboat;
emit isboatChanged();
}
SingletonTest.h
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#pragma once
#include <QThread>
#include <QTcpSocket>
#include <QGeoCoordinate>
#include <QUrl>
#include "Vehicle.h"
#include "Drivers/src/rtcm.h"
#include "RTCM/RTCMMavlink.h"
#include "QGCApplication.h"
#include "MAVLinkInspectorController.h"
#include "MultiVehicleManager.h"
class SingletonTest : public QObject{
Q_OBJECT
public:
SingletonTest();
virtual ~SingletonTest();
Q_PROPERTY(QString test1 READ test1 WRITE setTest1 NOTIFY test1Changed)
Q_PROPERTY(bool isboat READ isboat WRITE setIsboat NOTIFY isboatChanged)
// QGCTool overrides
QString test1 ()
{
return _test1;
}
bool isboat ()
{
return _isboat;
}
void setTest1(QString test1);
void setIsboat(bool isboat);
signals:
void test1Changed();
void isboatChanged();
public slots:
private slots:
void _mavlinkMessageReceived (LinkInterface* link, mavlink_message_t message);
void send_mavlink();
private:
void _handleGpsRawInt (mavlink_message_t& message);
void _handleADSBVehicle (mavlink_message_t& message);
QTimer timer;
//Vehicle* _vehicle;
QmlObjectListModel* _vehiclelist;
QGCToolbox* _toolbox = nullptr;
MAVLinkProtocol* _mavlink = nullptr;
QString _test1="A";
bool _isboat="true";
};
2、修改qgroundcontrol.pro
添加
src/SingletonTest/SingletonTest.h \
添加
src/SingletonTest/SingletonTest.cc \
3、修改QGroundControlQmlGlobal.h
添加头文件
#include "SingletonTest/SingletonTest.h"
添加
Q_PROPERTY(SingletonTest* singletontest READ singletontest CONSTANT)
添加
SingletonTest* singletontest () { return _singletontest; }
添加
SingletonTest* _singletontest = nullptr;
4、修改QGroundControlQmlGlobal.cc
添加
_singletontest = new SingletonTest();
5、测试
修改GPSIndicator.qml
修改
QGCLabel { text: QGroundControl.singletontest.test1}
修改完编译
编译出的界面显示如下,正常的话会显示lat的值
九、MAVLINK的解析与发送
MAVLINK官网
https://mavlink.io/en/
SingletonTest.cc
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#include "SingletonTest.h"
#include "QGCLoggingCategory.h"
#include "QGCToolbox.h"
#include "QGCApplication.h"
#include "SettingsManager.h"
#include "PositionManager.h"
#include <QTime>
#include <QDateTime>
#include <QLocale>
#include <QQuaternion>
#include <Eigen/Eigen>
#include <QDebug>
SingletonTest::SingletonTest():_toolbox (qgcApp()->toolbox())
{
connect(&timer, &QTimer::timeout, this, &SingletonTest::send_mavlink);
timer.setInterval(500);
timer.start();
_mavlink = _toolbox->mavlinkProtocol();
connect(_mavlink, &MAVLinkProtocol::messageReceived, this, &SingletonTest::_mavlinkMessageReceived);
}
SingletonTest::~SingletonTest()
{
}
void SingletonTest::send_mavlink()
{
auto *manager = qgcApp()->toolbox()->multiVehicleManager();
_vehiclelist=manager->vehicles();
if(_vehiclelist && _vehiclelist->objectList()->count()>0)
{
for(int i=0;i<_vehiclelist->objectList()->count();i++)
{
QObject* obj = _vehiclelist->get(i);
Vehicle* vehicle0=static_cast<Vehicle*> (obj);
// if (vehicle0->id()==1)
// {
WeakLinkInterfacePtr weakLink = vehicle0->vehicleLinkManager()->primaryLink();
if (!weakLink.expired()) {
SharedLinkInterfacePtr sharedLink = weakLink.lock();
if (!sharedLink) {
qCDebug(VehicleLog) << "_handlePing: primary link gone!";
return;
}
// auto protocol = qgcApp()->toolbox()->mavlinkProtocol();
auto priority_link =sharedLink;
mavlink_message_t msg;
// qDebug()<<i;
if(j%3==0)
{
mavlink_msg_gps_raw_int_pack(vehicle0->id(),
vehicle0->id(),
&msg,
1,
1,
321399000-j*100,
1185291000,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1);
vehicle0->sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
}
else if(j%3==1)
{
mavlink_msg_set_gps_global_origin_pack(vehicle0->id(),
vehicle0->id(),
&msg,
1,
321399400,
1185291000,
1,
10222);
vehicle0->sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
}
else
{
mavlink_msg_set_gps_global_origin_pack(vehicle0->id(),
vehicle0->id(),
&msg,
1,
321399800,
1185291000,
2,
10222);
vehicle0->sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
}
mavlink_msg_adsb_vehicle_pack(vehicle0->id(),
vehicle0->id(),
&msg,
1,
-353632921,
1491652874,
1,
1,
1,
1,
1,
"1",
1,
1,
1,
1);
vehicle0->sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
j++;
}
// }
}
}
}
void SingletonTest::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t message)
{
switch (message.msgid) {
case MAVLINK_MSG_ID_GPS_RAW_INT:
_handleGpsRawInt(message);
break;
case MAVLINK_MSG_ID_ADSB_VEHICLE:
_handleADSBVehicle(message);
break;
}
}
void SingletonTest::_handleGpsRawInt(mavlink_message_t& message)
{
mavlink_gps_raw_int_t gpsRawInt;
mavlink_msg_gps_raw_int_decode(&message, &gpsRawInt);
_test1=QString::number(gpsRawInt.lat/ (double)1E7);
emit test1Changed();
}
void SingletonTest::_handleADSBVehicle(mavlink_message_t& message)
{
mavlink_adsb_vehicle_t adsbVehicleMsg;
mavlink_msg_adsb_vehicle_decode(&message, &adsbVehicleMsg);
if(adsbVehicleMsg.ICAO_address==12345)
{
_isboat=true;
}
else
{
_isboat=false;
}
if(adsbVehicleMsg.ICAO_address>=100&&adsbVehicleMsg.ICAO_address<11000)
{
_isright=false;
}
else
{
_isright=true;
}
qDebug()<<"_isright"<<_isright;
qDebug()<<"_isboat"<<_isboat;
qDebug()<<"adsbVehicleMsg.ICAO_address"<<adsbVehicleMsg.ICAO_address;
emit test1Changed();
//emit isboatChanged();
//emit isrightChanged();
}
void SingletonTest::setTest1(QString test1)
{
_test1=test1;
emit test1Changed();
}
void SingletonTest::setIsboat(bool isboat)
{
_isboat=isboat;
emit isboatChanged();
}
void SingletonTest::setIsright(bool isright)
{
_isright=isright;
emit isrightChanged();
}
SingletonTest.h
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#pragma once
#include <QThread>
#include <QTcpSocket>
#include <QGeoCoordinate>
#include <QUrl>
#include "Vehicle.h"
#include "Drivers/src/rtcm.h"
#include "RTCM/RTCMMavlink.h"
#include "QGCApplication.h"
#include "MAVLinkInspectorController.h"
#include "MultiVehicleManager.h"
class SingletonTest : public QObject{
Q_OBJECT
public:
SingletonTest();
virtual ~SingletonTest();
Q_PROPERTY(QString test1 READ test1 WRITE setTest1 NOTIFY test1Changed)
Q_PROPERTY(bool isboat READ isboat WRITE setIsboat NOTIFY isboatChanged)
Q_PROPERTY(bool isright READ isright WRITE setIsright NOTIFY isrightChanged)
// QGCTool overrides
QString test1 ()
{
return _test1;
}
bool isboat ()
{
return _isboat;
}
bool isright ()
{
return _isright;
}
void setTest1(QString test1);
void setIsboat(bool isboat);
void setIsright(bool isright);
signals:
void test1Changed();
void isboatChanged();
void isrightChanged();
public slots:
private slots:
void _mavlinkMessageReceived (LinkInterface* link, mavlink_message_t message);
void send_mavlink();
private:
void _handleGpsRawInt (mavlink_message_t& message);
void _handleADSBVehicle (mavlink_message_t& message);
QTimer timer;
int j=0;
//Vehicle* _vehicle;
QmlObjectListModel* _vehiclelist;
QGCToolbox* _toolbox = nullptr;
MAVLinkProtocol* _mavlink = nullptr;
QString _test1="A";
bool _isboat="true";
bool _isright="false";
};
十、换地图
修改GenericMapProvider.cpp
添加地图url接口
static const QString maptest = QStringLiteral("https://mapz.oss-cn-beijing.aliyuncs.com/%1/%2/%3.png");
QString SeamapImgSatMapProvider::_getURL(const int x, const int y, const int zoom, QNetworkAccessManager* networkManager) {
Q_UNUSED(networkManager)
return maptest.arg(zoom).arg(x).arg(y);
}
修改GenericMapProvider.h
添加:
//hai图
class SeamapImgSatMapProvider : public MapProvider {
Q_OBJECT
public:
SeamapImgSatMapProvider(QObject* parent = nullptr)
: MapProvider(QStringLiteral("www.tiandi.com"), QStringLiteral("jpg"),
AVERAGE_TILE_SIZE, QGeoMapType::SatelliteMapDay, parent) {}
QString _getURL(const int x, const int y, const int zoom, QNetworkAccessManager* networkManager) override;
private:
const QString _versionBingMaps = QStringLiteral("563");
};
修改QGCMapUrlEngine.cpp
添加:
_providersTable["Seamap Satellite Map"] = new SeamapImgSatMapProvider(this);
然后在地面站上选择地图提供商为添加进去的海图
就可以加载出来添加的地图
十一、添加自定义mavlink消息
十二、在主工具栏添加一个自定义图标
在上面singletest的基础上继续修改,添加SingletonTest.qml
SingletonTest.qml内容如下:
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
import QtQuick 2.11
import QtQuick.Layouts 1.11
import QGroundControl 1.0
import QGroundControl.Controls 1.0
import QGroundControl.MultiVehicleManager 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Palette 1.0
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controllers 1.0
//-------------------------------------------------------------------------
//-- Battery Indicator
Item {
id: _root
anchors.top: parent.top
anchors.bottom: parent.bottom
width: batteryIndicatorRow1.width
property bool showIndicator: true
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
Row {
id: batteryIndicatorRow1
anchors.top: parent.top
anchors.bottom: parent.bottom
Repeater {
model: _activeVehicle ? _activeVehicle.batteries : 0
Loader {
anchors.top: parent.top
anchors.bottom: parent.bottom
sourceComponent: batteryVisual
property var battery: object
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
mainWindow.showIndicatorPopup(_root, batteryPopup)
}
}
Component {
id: batteryVisual
Row {
anchors.top: parent.top
anchors.bottom: parent.bottom
function getBatteryColor() {
switch (battery.chargeState.rawValue) {
case MAVLink.MAV_BATTERY_CHARGE_STATE_OK:
return qgcPal.text
case MAVLink.MAV_BATTERY_CHARGE_STATE_LOW:
return qgcPal.colorOrange
case MAVLink.MAV_BATTERY_CHARGE_STATE_CRITICAL:
case MAVLink.MAV_BATTERY_CHARGE_STATE_EMERGENCY:
case MAVLink.MAV_BATTERY_CHARGE_STATE_FAILED:
case MAVLink.MAV_BATTERY_CHARGE_STATE_UNHEALTHY:
return qgcPal.colorRed
default:
return qgcPal.text
}
}
function getBatteryPercentageText() {
if (!isNaN(battery.percentRemaining.rawValue)) {
if (battery.percentRemaining.rawValue > 98.9) {
return qsTr("100%")
} else {
return battery.percentRemaining.valueString + battery.percentRemaining.units
}
} else if (!isNaN(battery.voltage.rawValue)) {
return battery.voltage.valueString + battery.voltage.units
} else if (battery.chargeState.rawValue !== MAVLink.MAV_BATTERY_CHARGE_STATE_UNDEFINED) {
return battery.chargeState.enumStringValue
}
return ""
}
QGCColoredImage {
anchors.top: parent.top
anchors.bottom: parent.bottom
width: height
sourceSize.width: width
source: "/qmlimages/软件图标.png"
fillMode: Image.PreserveAspectFit
color: getBatteryColor()
}
Column {
id: battery1ValuesColumn
anchors.verticalCenter: parent.verticalCenter
QGCLabel {
anchors.horizontalCenter: hdopValue1.horizontalCenter
visible: true
color: getBatteryColor()
text: " "+QGroundControl.singletontest.test1
}
QGCLabel {
id: hdopValue1
visible: true
color: qgcPal.buttonText
text: QGroundControl.singletontest.test1
}
}
// QGCLabel {
// text: getBatteryPercentageText()
// font.pointSize: ScreenTools.mediumFontPointSize
// color: getBatteryColor()
// anchors.verticalCenter: parent.verticalCenter
// }
}
}
Component {
id: batteryValuesAvailableComponent
QtObject {
property bool functionAvailable: battery.function.rawValue !== MAVLink.MAV_BATTERY_FUNCTION_UNKNOWN
property bool temperatureAvailable: !isNaN(battery.temperature.rawValue)
property bool currentAvailable: !isNaN(battery.current.rawValue)
property bool mahConsumedAvailable: !isNaN(battery.mahConsumed.rawValue)
property bool timeRemainingAvailable: !isNaN(battery.timeRemaining.rawValue)
property bool chargeStateAvailable: battery.chargeState.rawValue !== MAVLink.MAV_BATTERY_CHARGE_STATE_UNDEFINED
}
}
Component {
id: batteryPopup
Rectangle {
width: mainLayout.width + mainLayout.anchors.margins * 2
height: mainLayout.height + mainLayout.anchors.margins * 2
radius: ScreenTools.defaultFontPixelHeight / 2
color: qgcPal.window
border.color: qgcPal.text
ColumnLayout {
id: mainLayout
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.top: parent.top
anchors.right: parent.right
spacing: ScreenTools.defaultFontPixelHeight
QGCLabel {
Layout.alignment: Qt.AlignCenter
text: qsTr("test")
font.family: ScreenTools.demiboldFontFamily
}
RowLayout {
spacing: ScreenTools.defaultFontPixelWidth
ColumnLayout {
Repeater {
model: _activeVehicle ? _activeVehicle.batteries : 0
ColumnLayout {
spacing: 0
property var batteryValuesAvailable: nameAvailableLoader.item
Loader {
id: nameAvailableLoader
sourceComponent: batteryValuesAvailableComponent
property var battery: object
}
// QGCLabel { text: qsTr("Battery %1").arg(object.id.rawValue) }
QGCLabel { text: qsTr("lat")}
// QGCLabel { text: qsTr("Consumed"); visible: batteryValuesAvailable.mahConsumedAvailable }
// QGCLabel { text: qsTr("Temperature"); visible: batteryValuesAvailable.temperatureAvailable }
// QGCLabel { text: qsTr("Function"); visible: batteryValuesAvailable.functionAvailable }
}
}
}
ColumnLayout {
Repeater {
model: _activeVehicle ? _activeVehicle.batteries : 0
ColumnLayout {
spacing: 0
property var batteryValuesAvailable: valueAvailableLoader.item
Loader {
id: valueAvailableLoader
sourceComponent: batteryValuesAvailableComponent
property var battery: object
}
// QGCLabel { text: "" }
QGCLabel { text: QGroundControl.singletontest.test1}
// QGCLabel { text: object.mahConsumed.valueString + " " + object.mahConsumed.units; visible: batteryValuesAvailable.mahConsumedAvailable }
// QGCLabel { text: object.temperature.valueString + " " + object.temperature.units; visible: batteryValuesAvailable.temperatureAvailable }
// QGCLabel { text: object.function.enumStringValue; visible: batteryValuesAvailable.functionAvailable }
}
}
}
}
}
}
}
}
将QML资源添加到QGC
修改FirmwarePlugin.cc
添加如下
QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/SingletonTest.qml")),
添加后的效果如下:
十三、解析自定义mavlink数据并在自定义图标上显示
在上一节的基础上修改,添加自定义消息的解析
修改后的完整源码如下:
SingletonTest.cc
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#include "SingletonTest.h"
#include "QGCLoggingCategory.h"
#include "QGCToolbox.h"
#include "QGCApplication.h"
#include "SettingsManager.h"
#include "PositionManager.h"
#include <QTime>
#include <QDateTime>
#include <QLocale>
#include <QQuaternion>
#include <Eigen/Eigen>
#include <QDebug>
SingletonTest::SingletonTest():_toolbox (qgcApp()->toolbox())
{
connect(&timer, &QTimer::timeout, this, &SingletonTest::send_mavlink);
timer.setInterval(500);
timer.start();
_mavlink = _toolbox->mavlinkProtocol();
connect(_mavlink, &MAVLinkProtocol::messageReceived, this, &SingletonTest::_mavlinkMessageReceived);
}
SingletonTest::~SingletonTest()
{
}
void SingletonTest::send_mavlink()
{
auto *manager = qgcApp()->toolbox()->multiVehicleManager();
_vehiclelist=manager->vehicles();
if(_vehiclelist && _vehiclelist->objectList()->count()>0)
{
for(int i=0;i<_vehiclelist->objectList()->count();i++)
{
QObject* obj = _vehiclelist->get(i);
Vehicle* vehicle0=static_cast<Vehicle*> (obj);
// if (vehicle0->id()==1)
// {
WeakLinkInterfacePtr weakLink = vehicle0->vehicleLinkManager()->primaryLink();
if (!weakLink.expired()) {
SharedLinkInterfacePtr sharedLink = weakLink.lock();
if (!sharedLink) {
qCDebug(VehicleLog) << "_handlePing: primary link gone!";
return;
}
// auto protocol = qgcApp()->toolbox()->mavlinkProtocol();
auto priority_link =sharedLink;
mavlink_message_t msg;
mavlink_msg_gps_raw_int_pack(vehicle0->id(),
vehicle0->id(),
&msg,
1,
1,
_test1.toLong(),
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1);
// mavlink_msg_adsb_vehicle_pack(vehicle0->id(),
// vehicle0->id(),
// &msg,
// 12345,
// _test1.toLong(),
// 1,
// 1,
// 1,
// 1,
// 1,
// 1,
// "1",
// 1,
// 1,
// 1,
// 1);
vehicle0->sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
}
// }
}
}
}
void SingletonTest::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t message)
{
switch (message.msgid) {
case MAVLINK_MSG_ID_GPS_RAW_INT:
_handleGpsRawInt(message);
break;
case MAVLINK_MSG_ID_ADSB_VEHICLE:
_handleADSBVehicle(message);
break;
case MAVLINK_MSG_ID_SENSOR_MESSAGE:
_handlesensor(message);
break;
}
}
void SingletonTest::_handlesensor(mavlink_message_t& message)
{
mavlink_sensor_message_t sensor;
mavlink_msg_sensor_message_decode(&message, &sensor);
_test1=QString::number(sensor.unuse1);
emit test1Changed();
}
void SingletonTest::_handleGpsRawInt(mavlink_message_t& message)
{
mavlink_gps_raw_int_t gpsRawInt;
mavlink_msg_gps_raw_int_decode(&message, &gpsRawInt);
//_test1=QString::number(gpsRawInt.lat/ (double)1E7);
//emit test1Changed();
}
void SingletonTest::_handleADSBVehicle(mavlink_message_t& message)
{
mavlink_adsb_vehicle_t adsbVehicleMsg;
mavlink_msg_adsb_vehicle_decode(&message, &adsbVehicleMsg);
if(adsbVehicleMsg.ICAO_address==12345)
{
_isboat=true;
}
else
{
_isboat=false;
}
emit test1Changed();
}
void SingletonTest::setTest1(QString test1)
{
_test1=test1;
emit test1Changed();
}
void SingletonTest::setIsboat(bool isboat)
{
_isboat=isboat;
emit isboatChanged();
}
SingletonTest.h
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#pragma once
#include <QThread>
#include <QTcpSocket>
#include <QGeoCoordinate>
#include <QUrl>
#include "Vehicle.h"
#include "Drivers/src/rtcm.h"
#include "RTCM/RTCMMavlink.h"
#include "QGCApplication.h"
#include "MAVLinkInspectorController.h"
#include "MultiVehicleManager.h"
class SingletonTest : public QObject{
Q_OBJECT
public:
SingletonTest();
virtual ~SingletonTest();
Q_PROPERTY(QString test1 READ test1 WRITE setTest1 NOTIFY test1Changed)
Q_PROPERTY(bool isboat READ isboat WRITE setIsboat NOTIFY isboatChanged)
// QGCTool overrides
QString test1 ()
{
return _test1;
}
bool isboat ()
{
return _isboat;
}
void setTest1(QString test1);
void setIsboat(bool isboat);
signals:
void test1Changed();
void isboatChanged();
public slots:
private slots:
void _mavlinkMessageReceived (LinkInterface* link, mavlink_message_t message);
void send_mavlink();
private:
void _handleGpsRawInt (mavlink_message_t& message);
void _handleADSBVehicle (mavlink_message_t& message);
void _handlesensor (mavlink_message_t& message);
QTimer timer;
//Vehicle* _vehicle;
QmlObjectListModel* _vehiclelist;
QGCToolbox* _toolbox = nullptr;
MAVLinkProtocol* _mavlink = nullptr;
QString _test1="A";
bool _isboat="true";
};
修改后可在图标上显示自定义mavlink数据
十四、同时显示多机轨迹
修改FlyViewMap.qml
将
MapPolyline {
id: trajectoryPolyline
line.width: 3
line.color: "red"
z: QGroundControl.zOrderTrajectoryLines
visible: !pipMode
Connections {
target: QGroundControl.multiVehicleManager
function onActiveVehicleChanged(activeVehicle) {
trajectoryPolyline.path = _activeVehicle ? _activeVehicle.trajectoryPoints.list() : []
}
}
Connections {
target: _activeVehicle ? _activeVehicle.trajectoryPoints : null
onPointAdded: trajectoryPolyline.addCoordinate(coordinate)
onUpdateLastPoint: trajectoryPolyline.replaceCoordinate(trajectoryPolyline.pathLength() - 1, coordinate)
onPointsCleared: trajectoryPolyline.path = []
}
}
替换为
MapItemView {
model: QGroundControl.multiVehicleManager.vehicles
delegate:
MapPolyline {
id: trajectoryPolyline
line.width: 3
line.color: "red"
z: QGroundControl.zOrderTrajectoryLines
visible: !pipMode
Connections {
target: object ? object.trajectoryPoints : null
onPointAdded: trajectoryPolyline.addCoordinate(coordinate)
onUpdateLastPoint: trajectoryPolyline.replaceCoordinate(trajectoryPolyline.pathLength() - 1, coordinate)
onPointsCleared: trajectoryPolyline.path = []
}
}
}
如下:
修改后效果如下:
十五、在地图上画一个点
如果在飞行视图显示,修改FlyViewMap.qml
如果在规划视图显示,修改PlanView.qml
使用MapCircle 控件就可以在地图上画圆圈
MapCircle {
center {
latitude: 47.39785
longitude: 8.5456074
}
radius: 5
color: 'green'
border.width: 1
}
画多个点
MapItemView {
model: ListModel {
id: myModel
ListElement { lat1: -35.3631580; long1: 149.1651190;rad1:10;color1:"green" }
ListElement { lat1: -35.3631680; long1: 149.1651190;rad1:10;color1:"red" }
}
delegate: MapCircle {
z: QGroundControl.zOrderWaypointLines + 1
center {
latitude: lat1
longitude: long1
}
radius: rad1
color: color1
border.width: 1
opacity: 0.3
}
}
添加如下:
效果如下:
更多推荐
所有评论(0)