QGC ground station teaches you how to change-how to add a follow panel to display key parameters


All love must spare no effort. If you really like it, give it a higher priority and more time!

For other articles about QGC ground station, please click here:     QGC ground station


1. Goals to be achieved

When the plane is flying on the map, the plane icon will follow a small parameter panel in real time, so that the user can see the key information at a glance. The small panel of this parameter is set to translucent and can follow the aircraft icon in real time. The display content includes the remaining battery percentage, battery voltage, flight mode, ground speed, air speed, climb speed, relative altitude, flight distance and other key parameters. The following gif:

Insert picture description here

2. Code analysis and modification

1. Analysis and modification of flight map files

The code is as follows: (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
}

Reference : Search "MapItemView", MapQuickItem in the QT Creator Help

● Mark 1 : MapItemView is used to form part of Map. Its data is mainly derived from models (ListModel, RouteModel, etc.). Similar to ListView, it is also a mode-delegate model. Only the delegate delegate different from MapItemView needs to be a map control, that is, the location is set to the latitude and longitude coordinates. The Delegate control of ListView is a desktop control, and the position is set to the screen position. The MapItemView type is meaningful only when it is included in the Map, it cannot exist independently.

● Mark 2 : model: Provide data to the mapItem (VehicleMapItem) defined by the delegate, and the information provided by it (flight mode, ground speed, air speed, climb speed, relative altitude, flight distance) is used as the input of Map ItemView, and the following details explain. Remember that model only supports the base model "QAbstractItemModel".

Obviously "QGroundControl.multiVehicleManager.vehicles" is of type QAbstractItemModel, as follows:

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

● Mark 3 : delegate: defines how to display each item in the model. It is required that the delegate must be a component and contain a map item, mostly of type "MapQuickItem".

● Mark 4 : coordinate: positioning coordinate. Why can it follow dynamically? This is the most critical attribute. It will be updated in real time in the C++ vehiclel class. (NOTIFY modified attributes will be discussed below)

Coordinate is an attribute of "MapQuickItem". This property holds the anchor point coordinates of the MapQuickItem. When the map is displayed, the point on the sourceItem specified by anchorPoint will be consistent with this coordinate.

In this MapItemView. Object corresponds to vehicles, which is implemented by VehicleMapItem, which is of type MapQuickItem. The sourceItem of MapQuickItem specifies how to display an Item. This Item is the display information of the key parameters in 9 rows and 3 columns.

● Modification 1: Only one "z" attribute is modified in this file to display the panel on the top level. Remember to put it under the attribute of "MapItemView", otherwise it will not take effect, this is very important

Next, let me look at the files in the agent again!

2. Data source in proxy file

The model mentioned above is the flight mode, ground speed, air speed, climb speed, relative altitude, and flight distance provided by it.

flightMode, roll, and groundSpeed ​​are all variables defined in "VehicleMapItem". object.flightMode, object.roll.rawValue, object.groundSpeed.rawValue come from "vehicles". Then look at Vehicle in C++

● Modification 2: Add the following attributes in the file header:

//总修改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;

object = vehicle = QGroundControl.multiVehicleManager.vehicles, let’s take a look at the vehicle class...

● Analysis of Vehicle class in C++.
To display in QML in real time, it must be a signal modified by "NOTIFY", which associates a signal with the attribute, which will be triggered when the value of the attribute changes. Compare the flightMode property,

  Q_PROPERTY(QString              flightMode              READ flightMode             WRITE setFlightMode             NOTIFY flightModeChanged)

If you don’t know how to interact between C++ and QML, you can click here: Qt Quick Qml QML and C++ mixed programming learning

When we change the value of this parameter in C++, we emit the flightModeChanged signal to notify the qml related properties of the change, and then realize the related state change. Without "NOTIFY" modification, it will not be triggered in real time, nor will it be dynamically updated.

But did you find that in the Vehicle class, some key attributes did not use NOTIFY?

as follows:

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; }

Carefully analyze the Fact class:

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)
}

It is found that "rawValue" is also modified with "NOTIFY". So the problem is very simple, just go to "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;
...

3. Display form in proxy file

● Modification 3: Add a rectangular box at the end of "sourceItem: Item" in MapQuickItem:

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
                }
            }
        }
    }
}

For a detailed explanation of the nested layout of Column and Row, please refer to my QT Quick QML layout-fixed position layout (Row, Column, Grid, Flow and Repeater) summary. No more introduction here.

The following green box:
Insert picture description here

If you have other ideas, you can add a control in the flight view to configure whether the rectangular box is displayed; you can also add a timer to highlight the changed data; you can also make a cool skin with UI art support. Why has to be this way?

There is no other reason, everything is crazy and cool, haha! I won’t introduce the details one by one, just start my little head and melon seeds~


For other articles about QGC ground station, please click here:     QGC ground station

Guess you like

Origin blog.csdn.net/qq_16504163/article/details/110779071