LP-311 Remove basic/advanced stabilization tab auto-switch (autotune/txpid lock issues)
[librepilot.git] / ground / gcs / src / share / qml / pfd / Info.qml
blob827d2e039d6558b0b0c62a255355b5d3f2f3c2f6
1 /*
2  * Copyright (C) 2016 The LibrePilot Project
3  * Contact: http://www.librepilot.org
4  *
5  * This file is part of LibrePilot GCS.
6  *
7  * LibrePilot GCS is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * LibrePilot GCS is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with LibrePilot GCS.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 import QtQuick 2.4
22 import "../js/common.js" as Utils
23 import "../js/uav.js" as UAV
25 Item {
26     id: info
27     property variant sceneSize
29     //
30     // Waypoint functions
31     //
33     property real posEast_old
34     property real posNorth_old
35     property real total_distance
36     property real total_distance_km
38     property bool init_dist: false
40     function reset_distance() {
41         total_distance = 0;
42     }
44     function compute_distance(posEast,posNorth) {
45         if (total_distance == 0 && !init_dist) { init_dist = "true"; posEast_old = posEast; posNorth_old = posNorth; }
46         if (posEast > posEast_old+3 || posEast < posEast_old - 3 || posNorth > posNorth_old + 3 || posNorth < posNorth_old - 3) {
47            total_distance += Math.sqrt(Math.pow((posEast - posEast_old ), 2) + Math.pow((posNorth - posNorth_old), 2));
48            total_distance_km = total_distance / 1000;
50            posEast_old = posEast;
51            posNorth_old = posNorth;
52            return total_distance;
53         }
54     }
56     // End Functions
57     //
58     // Start Drawing
60     SvgElementImage {
61         id: info_bg
62         sceneSize: info.sceneSize
63         elementName: "info-bg"
64         width: parent.width
65         opacity: opaque ? 1 : 0.3
66     }
68     //
69     // GPS Info (Top)
70     //
72     property real bar_width: (info_bg.height + info_bg.width) / 110
74     property variant gps_tooltip: "Altitude : " + UAV.gpsAltitude() + "m\n" +
75                                   "H/V/P DOP : " + UAV.gpsHdopInfo() +
76                                   [UAV.gpsSensorType() == "DJI" ? "" :  "\n" + UAV.gpsSatsInView() + " Sats in view"]
78     Repeater {
79         id: satNumberBar
81         model: 13
82         Rectangle {
83             property int minSatNumber : index
84             width: Math.round(bar_width)
85             radius: width / 4
87             TooltipArea {
88                text: gps_tooltip
89             }
91             x: Math.round((bar_width * 4.5) + (bar_width * 1.6 * index))
92             height: bar_width * index * 0.6
93             y: (bar_width * 8) - height
94             color: "green"
95             opacity: UAV.gpsNumSat() >= minSatNumber ? 1 : 0.4
96         }
97     }
99     SvgElementPositionItem {
100         sceneSize: info.sceneSize
101         elementName: "gps-mode-text"
103         TooltipArea {
104             text: gps_tooltip
105         }
107         Text {
108             text: [UAV.gpsNumSat() > 5 ? " " + UAV.gpsNumSat().toString() + " sats - " : ""] + UAV.gpsStatus()
109             anchors.centerIn: parent
110             font.pixelSize: parent.height*1.3
111             font.family: pt_bold.name
112             font.weight: Font.DemiBold
113             color: "white"
114         }
115     }
117     SvgElementImage {
118         sceneSize: info.sceneSize
119         elementName: "gps-icon"
120         width: scaledBounds.width * sceneItem.width
121         height: scaledBounds.height * sceneItem.height
123         TooltipArea {
124             text: gps_tooltip
125         }
126     }
128     // Waypoint Info (Top)
129     // Only visible when PathPlan is active (WP loaded)
131     SvgElementImage {
132         sceneSize: info.sceneSize
133         elementName: "waypoint-labels"
134         width: scaledBounds.width * sceneItem.width
135         height: scaledBounds.height * sceneItem.height
136         y: Math.floor(scaledBounds.y * sceneItem.height)
137         visible: UAV.isPathPlanValid()
138     }
140     SvgElementPositionItem {
141         sceneSize: info.sceneSize
142         elementName: "waypoint-heading-text"
143         width: scaledBounds.width * sceneItem.width
144         height: scaledBounds.height * sceneItem.height
145         y: Math.floor(scaledBounds.y * sceneItem.height)
146         visible: UAV.isPathPlanValid()
148         Text {
149             text: UAV.isPathPlanValid() ? "   " + UAV.waypointHeading().toFixed(1) + "°" : "   0°"
150             anchors.centerIn: parent
151             color: "cyan"
153             font {
154                 family: pt_bold.name
155                 pixelSize: Math.floor(parent.height * 1.5)
156                 weight: Font.DemiBold
157             }
158         }
159     }
161     SvgElementPositionItem {
162         sceneSize: info.sceneSize
163         elementName: "waypoint-distance-text"
164         width: scaledBounds.width * sceneItem.width
165         height: scaledBounds.height * sceneItem.height
166         y: Math.floor(scaledBounds.y * sceneItem.height)
167         visible: UAV.isPathPlanValid()
169         Text {
170             text: UAV.isPathPlanValid() ? "  " + UAV.waypointDistance().toFixed(0) + " m" : "  0 m"
171             anchors.centerIn: parent
172             color: "cyan"
174             font {
175                 family: pt_bold.name
176                 pixelSize: Math.floor(parent.height * 1.5)
177                 weight: Font.DemiBold
178             }
179         }
180     }
182     SvgElementPositionItem {
183         sceneSize: info.sceneSize
184         elementName: "waypoint-total-distance-text"
185         width: scaledBounds.width * sceneItem.width
186         height: scaledBounds.height * sceneItem.height
187         y: Math.floor(scaledBounds.y * sceneItem.height)
188         visible: UAV.isPathPlanValid()
190         MouseArea { id: total_dist_mouseArea; anchors.fill: parent; cursorShape: Qt.PointingHandCursor; onClicked: reset_distance()}
192         Text {
193             text: "  "+total_distance.toFixed(0)+" m"
194             anchors.centerIn: parent
195             color: "cyan"
197             font {
198                 family: pt_bold.name
199                 pixelSize: Math.floor(parent.height * 1.5)
200                 weight: Font.DemiBold
201             }
202         }
204         Timer {
205             interval: 1000; running: true; repeat: true;
206             onTriggered: { if (UAV.isGpsStatusFix3D()) compute_distance(positionState.east, positionState.north) }
207         }
208     }
210     SvgElementPositionItem {
211         sceneSize: info.sceneSize
212         elementName: "waypoint-eta-text"
213         width: scaledBounds.width * sceneItem.width
214         height: scaledBounds.height * sceneItem.height
215         y: Math.floor(scaledBounds.y * sceneItem.height)
216         visible: UAV.isPathPlanValid()
218         Text {
219             text: UAV.isPathPlanValid() ? Utils.estimatedTimeOfArrival(UAV.waypointDistance(), UAV.currentVelocity()) : "00:00:00"
220             anchors.centerIn: parent
221             color: "cyan"
223             font {
224                 family: pt_bold.name
225                 pixelSize: Math.floor(parent.height * 1.5)
226                 weight: Font.DemiBold
227             }
228         }
229     }
231     SvgElementPositionItem {
232         sceneSize: info.sceneSize
233         elementName: "waypoint-number-text"
234         width: scaledBounds.width * sceneItem.width
235         height: scaledBounds.height * sceneItem.height
236         y: Math.floor(scaledBounds.y * sceneItem.height)
237         visible: UAV.isPathPlanValid()
239         Text {
240             text: UAV.isPathPlanValid() ? UAV.currentWaypointActive() + " / " + UAV.waypointCount() : "0 / 0"
241             anchors.centerIn: parent
242             color: "cyan"
244             font {
245                 family: pt_bold.name
246                 pixelSize: Math.floor(parent.height * 1.5)
247                 weight: Font.DemiBold
248             }
249         }
250     }
252     SvgElementPositionItem {
253         sceneSize: info.sceneSize
254         elementName: "waypoint-mode-text"
255         width: scaledBounds.width * sceneItem.width
256         height: scaledBounds.height * sceneItem.height
257         y: Math.floor(scaledBounds.y * sceneItem.height)
258         visible: UAV.isPathPlanValid()
260         Text {
261             text: UAV.isPathPlanValid() ? UAV.pathModeDesired() : ""
262             anchors.centerIn: parent
263             color: "cyan"
265             font {
266                 family: pt_bold.name
267                 pixelSize: Math.floor(parent.height * 1.5)
268                 weight: Font.DemiBold
269             }
270         }
271     }
273     // Battery Info (Top)
274     // Only visible when PathPlan not active and Battery module enabled
276     SvgElementPositionItem {
277         id: topbattery_voltamp_bg
278         sceneSize: info.sceneSize
279         elementName: "topbattery-label-voltamp-bg"
281         width: scaledBounds.width * sceneItem.width
282         height: scaledBounds.height * sceneItem.height
283         y: scaledBounds.y * sceneItem.height
284         visible: (!UAV.isPathPlanValid() && UAV.batteryModuleEnabled())
286         Rectangle {
287             anchors.fill: parent
288             color: (UAV.batteryNbCells() > 0) ? UAV.batteryAlarmColor() : "black"
290         }
291     }
293     SvgElementImage {
294         sceneSize: info.sceneSize
295         elementName: "topbattery-labels"
296         width: scaledBounds.width * sceneItem.width
297         height: scaledBounds.height * sceneItem.height
298         y: Math.floor(scaledBounds.y * sceneItem.height)
299         visible: (!UAV.isPathPlanValid() && UAV.batteryModuleEnabled())
300     }
302     SvgElementPositionItem {
303         id: topbattery_volt
304         sceneSize: info.sceneSize
305         elementName: "topbattery-volt-text"
307         width: scaledBounds.width * sceneItem.width
308         height: scaledBounds.height * sceneItem.height
309         y: scaledBounds.y * sceneItem.height
310         visible: (!UAV.isPathPlanValid() && UAV.batteryModuleEnabled())
312         Rectangle {
313             anchors.fill: parent
314             color: "transparent"
316             Text {
317                text: UAV.batteryVoltage()
318                anchors.centerIn: parent
319                color: "white"
320                font {
321                    family: pt_bold.name
322                    pixelSize: Math.floor(parent.height * 0.6)
323                    weight: Font.DemiBold
324                }
325             }
326         }
327     }
329     SvgElementPositionItem {
330         id: topbattery_amp
331         sceneSize: info.sceneSize
332         elementName: "topbattery-amp-text"
334         width: scaledBounds.width * sceneItem.width
335         height: scaledBounds.height * sceneItem.height
336         y: scaledBounds.y * sceneItem.height
337         visible: (!UAV.isPathPlanValid() && UAV.batteryModuleEnabled())
339         Rectangle {
340             anchors.fill: parent
341             color: "transparent"
343             Text {
344                text: UAV.batteryCurrent()
345                anchors.centerIn: parent
346                color: "white"
347                font {
348                    family: pt_bold.name
349                    pixelSize: Math.floor(parent.height * 0.6)
350                    weight: Font.DemiBold
351                }
352             }
353         }
354     }
356     SvgElementPositionItem {
357         id: topbattery_milliamp
358         sceneSize: info.sceneSize
359         elementName: "topbattery-milliamp-text"
361         width: scaledBounds.width * sceneItem.width
362         height: scaledBounds.height * sceneItem.height
363         y: scaledBounds.y * sceneItem.height
364         visible: (!UAV.isPathPlanValid() && UAV.batteryModuleEnabled())
366         Rectangle {
367             anchors.fill: parent
369             TooltipArea {
370                   text: "Reset consumed energy"
371             }
373             MouseArea {
374                id: reset_consumed_energy_mouseArea;
375                anchors.fill: parent;
376                cursorShape: Qt.PointingHandCursor;
377                onClicked: pfdContext.resetConsumedEnergy();
378             }
380             // Alarm based on estimatedFlightTime < 120s orange, < 60s red
381             color: UAV.estimatedTimeAlarmColor()
383             border.color: "white"
384             border.width: topbattery_volt.width * 0.01
385             radius: border.width * 4
387             Text {
388                text: UAV.batteryConsumedEnergy()
389                anchors.centerIn: parent
390                color: "white"
391                font {
392                    family: pt_bold.name
393                    pixelSize: Math.floor(parent.height * 0.6)
394                    weight: Font.DemiBold
395                }
396             }
397         }
398     }
400     // Default counter
401     // Only visible when PathPlan not active
403     SvgElementImage {
404         sceneSize: info.sceneSize
405         elementName: "topbattery-total-distance-label"
406         width: scaledBounds.width * sceneItem.width
407         height: scaledBounds.height * sceneItem.height
408         y: Math.floor(scaledBounds.y * sceneItem.height)
409         visible: !UAV.isPathPlanValid()
410     }
412     SvgElementPositionItem {
413         sceneSize: info.sceneSize
414         elementName: "topbattery-total-distance-text"
415         width: scaledBounds.width * sceneItem.width
416         height: scaledBounds.height * sceneItem.height
417         y: Math.floor(scaledBounds.y * sceneItem.height)
418         visible: !UAV.isPathPlanValid()
420         TooltipArea {
421             text: "Reset distance counter"
422         }
424         MouseArea { id: total_dist_mouseArea2; anchors.fill: parent; cursorShape: Qt.PointingHandCursor; onClicked: reset_distance()}
426         Text {
427             text:  total_distance > 1000 ? total_distance_km.toFixed(2) +" Km" : total_distance.toFixed(0)+" m"
428             anchors.right: parent.right
429             color: "cyan"
431             font {
432                 family: pt_bold.name
433                 pixelSize: Math.floor(parent.height * 1)
434                 weight: Font.DemiBold
435             }
436         }
438         Timer {
439             interval: 1000; running: true; repeat: true;
440             onTriggered: { if (UAV.isGpsStatusFix3D()) compute_distance(positionState.east, positionState.north) }
441         }
442     }
444     //
445     // Home info (visible after arming)
446     //
448     SvgElementImage {
449         id: home_bg
450         elementName: "home-bg"
451         sceneSize: info.sceneSize
452         x: Math.floor(scaledBounds.x * sceneItem.width)
453         y: Math.floor(scaledBounds.y * sceneItem.height)
455         opacity: opaque ? 1 : 0.6
457         states: State {
458              name: "fading"
459              when: UAV.isTakeOffLocationValid()
460              PropertyChanges { target: home_bg; x: Math.floor(scaledBounds.x * sceneItem.width) - home_bg.width; }
461         }
463         transitions: Transition {
464             SequentialAnimation {
465                 PropertyAnimation { property: "x"; duration: 800 }
466             }
467         }
468     }
470     SvgElementPositionItem {
471         sceneSize: info.sceneSize
472         id: home_heading_text
473         elementName: "home-heading-text"
474         width: scaledBounds.width * sceneItem.width
475         height: scaledBounds.height * sceneItem.height
476         y: Math.floor(scaledBounds.y * sceneItem.height)
478         states: State {
479              name: "fading_heading"
480              when: UAV.isTakeOffLocationValid()
481              PropertyChanges { target: home_heading_text; x: Math.floor(scaledBounds.x * sceneItem.width) - home_bg.width; }
482         }
484         transitions: Transition {
485             SequentialAnimation {
486                 PropertyAnimation { property: "x"; duration: 800 }
487             }
488         }
490         Text {
491             text: "  " + UAV.homeHeading().toFixed(1) + "°"
492             anchors.centerIn: parent
493             color: "cyan"
494             font {
495                 family: pt_bold.name
496                 pixelSize: parent.height * 1.2
497             }
498         }
499     }
501     SvgElementPositionItem {
502         sceneSize: info.sceneSize
503         id: home_distance_text
504         elementName: "home-distance-text"
505         width: scaledBounds.width * sceneItem.width
506         height: scaledBounds.height * sceneItem.height
507         y: Math.floor(scaledBounds.y * sceneItem.height)
509         states: State {
510              name: "fading_distance"
511              when: UAV.isTakeOffLocationValid()
512              PropertyChanges { target: home_distance_text; x: Math.floor(scaledBounds.x * sceneItem.width) - home_bg.width; }
513         }
515         transitions: Transition {
516             SequentialAnimation {
517                 PropertyAnimation { property: "x"; duration: 800 }
518             }
519         }
521         Text {
522             text: UAV.homeDistance().toFixed(0) + " m"
523             anchors.centerIn: parent
524             color: "cyan"
525             font {
526                 family: pt_bold.name
527                 pixelSize: parent.height * 1.2
528             }
529         }
530     }
532     SvgElementPositionItem {
533         sceneSize: info.sceneSize
534         id: home_eta_text
535         elementName: "home-eta-text"
536         width: scaledBounds.width * sceneItem.width
537         height: scaledBounds.height * sceneItem.height
538         y: Math.floor(scaledBounds.y * sceneItem.height)
540         states: State {
541              name: "fading_distance"
542              when: UAV.isTakeOffLocationValid()
543              PropertyChanges { target: home_eta_text; x: Math.floor(scaledBounds.x * sceneItem.width) - home_bg.width; }
544         }
546         transitions: Transition {
547             SequentialAnimation {
548                 PropertyAnimation { property: "x"; duration: 800 }
549             }
550         }
552         Text {
553             text: Utils.estimatedTimeOfArrival(UAV.homeDistance(), UAV.currentVelocity())
554             anchors.centerIn: parent
555             color: "cyan"
556             font {
557                 family: pt_bold.name
558                 pixelSize: parent.height * 1.2
559             }
560         }
561     }
563     SvgElementImage {
564         id: info_border
565         elementName: "info-border"
566         sceneSize: info.sceneSize
567         width: Math.floor(parent.width * 1.009)
568     }