How to add 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:
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:
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