当前位置:   article > 正文

QGC地面站手把手教你改——如何添加跟随面板显示关键参数_/home/gua_ji/soft/develop/qgroundcontrol/src/fligh

/home/gua_ji/soft/develop/qgroundcontrol/src/flightdisplay/flightdisplayview


所有的热爱都要不遗余力,真正喜欢它便给它更高的优先级,和更多的时间吧!

关于QGC地面站其它文章请点击这里:     QGC地面站


QGroundControl(QGC)是一款开源的跨平台地面站软件,用于控制和监控各种类型的无人机、无人船、无人车等载具。它提供了丰富的功能,包括飞行计划、实时地图、传感器数据显示、飞行状态监测、遥控器控制、实时视频显示等,可以支持多种硬件设备和自定义设置。

一. 要实现的目标

无人机在地图上飞行时,实现飞机图标实时跟随一个参数小面板,让用户对关键信息一目了然。 此参数小面板设置为半透明,可实时跟随飞机图标移动,显示内容包括电池剩余百分比、电池电压、飞行模式、地速、空速、爬升速度、相对高度、飞行距离等关键参数。如下gif:

在这里插入图片描述

二. 代码分析与修改

1. 飞行地图文件的分析与修改

代码如下:(FlightDisplayViewMap.qml):

// Add the vehicles to the map  244行
MapItemView {  											//标记1
    model: QGroundControl.multiVehicleManager.vehicles  //标记2
    delegate: VehicleMapItem { 							//标记3
        vehicle:        		object
        coordinate:     		object.coordinate 		//标记4
        map:            		flightMap
		size:           		mainIsMap ? ScreenTools.defaultFontPixelHeight * 3 : ScreenTools.defaultFontPixelHeight
        //z:              QGroundControl.zOrderVehicles  //总修改1-1
    }
    z:              QGroundControl.zOrderTopMost         //总修改1-2
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

参考:QT Creator 帮助中搜 “MapItemView”,MapQuickItem

● 标记1:MapItemView是用来构成Map的一部分的。它数据主要是源自model(ListModel、RouteModel等)。和ListView 相似 ,也是mode-delegate模型。 仅仅不同于MapItemView的代理Delegate需要为地图控件,即位置设置为经纬度坐标。ListView的Delegate控件为桌面控件,位置设置为屏幕位置。 MapItemView类型只有在包含在Map中时才有意义,它不能独立存在。

● 标记2:model:提供数据给委托定义的mapItem(VehicleMapItem),由它提供的信息(飞行模式、地速、空速、爬升速度、相对高度、飞行距离)作为Map ItemView的输入,下面再具体讲解。记住model 仅支持 “QAbstractItemModel” 的基础模型。

显然 “QGroundControl.multiVehicleManager.vehicles” 是 QAbstractItemModel 类型的,如下:

// src\Vehicle\MultiVehicleManager.h:100
QmlObjectListModel* vehicles(void) { return &_vehicles; }
  • 1
  • 2

● 标记3:delegate:定义了模型中的每个项改如何显示。 要求 delegate 必须为组件,且包含一个map Item, “MapQuickItem”类型的居多。

● 标记4:coordinate:定位坐标。为什么能动态跟随,此为最关键的属性,它在C++ vehiclel 类中会实时更新。(NOTIFY修饰的属性,下文会讲到)

coordinate是“MapQuickItem”的一个属性。 此属性保存MapQuickItem的锚点坐标。在地图显示时,由anchorPoint指定的sourceItem上的点与此坐标保持会一致。

在此MapItemView中。object 对应的就是 vehicles ,委托了VehicleMapItem来实现,VehicleMapItem为MapQuickItem类型的。MapQuickItem的sourceItem指定了一个Item来如何显示。该Item就是9行3列的关键参数的显示信息。

● 修改1: 此文件中仅修改一处“z” 属性,是为了让面板在顶层显示。记得放在“MapItemView”的属性下,不然不会生效,这很关键

接下来让我再看看代理中的文件吧!

2. 代理文件中数据源

上文提到 model,由它提供的飞行模式、地速、空速、爬升速度、相对高度、飞行距离的。

flightMode、roll、groundSpeed都是在“VehicleMapItem”中定义的变量。 object.flightMode、object.roll.rawValue、 object.groundSpeed.rawValue来自于“vehicles”。那么再看下 C++中的Vehicle吧

● 修改2: 在文件头增加如下属性:

//总修改2: (object = vehicle = QGroundControl.multiVehicleManager.vehicles)
property string flightMode:           vehicle.flightMode;
property real   roll:                 vehicle.roll.rawValue;
property real   groundSpeed:          vehicle.groundSpeed.rawValue;
property real   airSpeed:             vehicle.airSpeed.rawValue;
property real   climbRate:            vehicle.climbRate.rawValue;
property real   altitudeRelative:     vehicle.altitudeRelative.rawValue;
property real   flightDistance:       vehicle.flightDistance.rawValue;
property real   distanceToHome:       object.distanceToHome.rawValue;
property real   batteryPercentRemain: object.battery.percentRemaining.value
property real   batteryVoltage:       object.battery.voltage.value;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

object = vehicle = QGroundControl.multiVehicleManager.vehicles ,让我们在看看vehicle类…

● C++中的Vehicle类的分析。
要在QML实时显示,那么必须是“NOTIFY”修饰的信号,它给属性关联一个信号,当属性的值发生变化时就会触发该信号。比下flightMode属性,

  Q_PROPERTY(QString              flightMode              READ flightMode             WRITE setFlightMode             NOTIFY flightModeChanged)
  • 1

C++和QML之间不懂如何交互的可以点击这里:Qt Quick Qml 之QML与C++ 混合编程学习

当我们在 C++中改变该参数值时,发射 flightModeChanged 信号, 来通知 qml 相关的属性有更改,进而实现相关的状态更改。没有“NOTIFY”修饰的,不会实时触发,也不会动态更新了。

但是是不是发现在Vehicle类中,一些关键的属性并没有使用NOTIFY ?

如下:

Fact* roll                              () { return &_rollFact; }
Fact* rollRate                          () { return &_rollRateFact; }
Fact* pitchRate                         () { return &_pitchRateFact; }
Fact* yawRate                           () { return &_yawRateFact; }
Fact* airSpeed                          () { return &_airSpeedFact; }
Fact* groundSpeed                       () { return &_groundSpeedFact; }
Fact* climbRate                         () { return &_climbRateFact; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

仔细分析Fact类:

class Fact : public QObject
{
    Q_OBJECT
...
    Q_PROPERTY(QString      shortDescription        READ shortDescription                                   CONSTANT)
    Q_PROPERTY(QString      units                   READ cookedUnits                                        CONSTANT)
    Q_PROPERTY(QVariant     value                   READ cookedValue            WRITE setCookedValue        NOTIFY valueChanged)
    Q_PROPERTY(QVariant     rawValue                READ rawValue               WRITE setRawValue           NOTIFY rawValueChanged)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

发现“rawValue ”也用“NOTIFY”修饰了。所以问题就很简单了,直接去到 “rawValue” 就好

...
property string flightMode:           vehicle.flightMode;
property real   roll:                 vehicle.roll.rawValue;
property real   groundSpeed:          vehicle.groundSpeed.rawValue;
property real   airSpeed:             vehicle.airSpeed.rawValue;
property real   climbRate:            vehicle.climbRate.rawValue;
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

3. 代理文件中显示形式

● 修改3: 在MapQuickItem中的“ sourceItem: Item "中最后增加矩形框:

Rectangle {
    id:                         cchVehicleStatusView;
    anchors.bottom:             vehicleIcon.top;
    anchors.bottomMargin:  4
    anchors.horizontalCenter:   vehicleIcon.horizontalCenter;
    color:                      "#DDDDFF"
    radius:                     10
    width:                      buttonColumn.implicitWidth * 1.1
    height:                     buttonColumn.implicitHeight * 1.1
    opacity :                   0.8;
    border.color:               "black"
    border.width:               2

    Column {
        id:                 buttonColumn
        width:              statusNameRepeater.implicitWidth
        height:             statusNameRepeater.implicitHeight
        anchors.top:        parent.top
        anchors.topMargin:  6
        anchors.left:       parent.left
        anchors.leftMargin: 6
        spacing:            ScreenTools.defaultFontPixelHeight / 2

        Repeater {
            id:     statusNameRepeater
            model:  9
            property var statusNames:  [ "电池剩余百分比: ", "电池电压: ", qsTr("飞行模式:"), qsTr("地速: "), qsTr("空速: "), qsTr("爬升速度: "), qsTr("相对高度: "), qsTr("飞行距离: "),"到home点距离: "]
            property var statusValues: [batteryPercentRemain, batteryVoltage, flightMode, groundSpeed.toFixed(2), airSpeed.toFixed(2), climbRate.toFixed(2), altitudeRelative.toFixed(2), flightDistance.toFixed(2), distanceToHome.toFixed(2)]
            property var statusUnits: ["%", "v", "", "(m/s)", "(m/s)", "(m/s)", "(m)", "(m)", "(m)"]

            Row{
                id: _row
                QGCLabel {
                    color:                            "#424200"
                    horizontalAlignment:              Text.AlignHCenter
                    font.pointSize:                   ScreenTools.mediumFontPointSize * 1.0
                    text:                             statusNameRepeater.statusNames[index]
                    font.bold:                        true
                }
                QGCLabel {
                    color:                            "#336666"
                    horizontalAlignment:              Text.AlignHCenter
                    font.pointSize:                   ScreenTools.mediumFontPointSize *1.0
                    text:                             statusNameRepeater.statusValues[index] + statusNameRepeater.statusUnits[index]
                    font.bold:                        true
                }
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

这个Column和Row的嵌套布局的详细解释,可以看我的 QT Quick QML 布局——定位置布局(Row、Column、Grid、Flow和Repeater) 总结。 这里不再介绍。

如下绿色框中:
在这里插入图片描述

有其他想法的,可以在飞行视图中,增加一个控件,来配置矩形框是否显示;还可以增加一个定时器让变化的数据高亮显示;有UI美工支持的还可以弄个炫酷的皮肤。


关于QGC地面站其它文章请点击这里:     QGC地面站

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/428944
推荐阅读
相关标签
  

闽ICP备14008679号