diff --git a/qgcresources.qrc b/qgcresources.qrc
index 5b6fa54..ff5c03e 100644
--- a/qgcresources.qrc
+++ b/qgcresources.qrc
@@ -171,6 +171,7 @@
src/FirmwarePlugin/APM/APMBrandImageSub.png
src/FirmwarePlugin/PX4/PX4BrandImage.png
src/FlightMap/Images/sub.png
+ resources/check.svg
resources/action.svg
diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index bf57edb..50ba35c 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -87,6 +87,7 @@
src/QmlControls/ParameterEditorDialog.qml
src/PlanView/PlanToolBar.qml
src/QmlControls/QGCButton.qml
+ src/QmlControls/QGCCheckListItem.qml
src/QmlControls/QGCCheckBox.qml
src/QmlControls/QGCColoredImage.qml
src/QmlControls/QGCComboBox.qml
diff --git a/resources/check.svg b/resources/check.svg
new file mode 100644
index 0000000..f5c4901
--- /dev/null
+++ b/resources/check.svg
@@ -0,0 +1,80 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/FlightDisplay/FlightDisplayView.qml b/src/FlightDisplay/FlightDisplayView.qml
index 85a4876..e9cdd56 100644
--- a/src/FlightDisplay/FlightDisplayView.qml
+++ b/src/FlightDisplay/FlightDisplayView.qml
@@ -504,8 +504,8 @@ QGCView {
z: _panel.z + 4
title: qsTr("Fly")
maxHeight: (_flightVideo.visible ? _flightVideo.y : parent.height) - toolStrip.y
- buttonVisible: [ _guidedController.showTakeoff || !_guidedController.showLand, _guidedController.showLand && !_guidedController.showTakeoff, true, true, true, _guidedController.smartShotsAvailable ]
- buttonEnabled: [ _guidedController.showTakeoff, _guidedController.showLand, _guidedController.showRTL, _guidedController.showPause, _anyActionAvailable, _anySmartShotAvailable ]
+ buttonVisible: [ QGroundControl.settingsManager.appSettings.useChecklist.rawValue, _guidedController.showTakeoff || !_guidedController.showLand, _guidedController.showLand && !_guidedController.showTakeoff, true, true, true, _guidedController.smartShotsAvailable ]
+ buttonEnabled: [ QGroundControl.settingsManager.appSettings.useChecklist.rawValue, _guidedController.showTakeoff, _guidedController.showLand, _guidedController.showRTL, _guidedController.showPause, _anyActionAvailable, _anySmartShotAvailable ]
property bool _anyActionAvailable: _guidedController.showStartMission || _guidedController.showResumeMission || _guidedController.showChangeAlt || _guidedController.showLandAbort
property bool _anySmartShotAvailable: _guidedController.showOrbit
@@ -552,6 +552,11 @@ QGCView {
model: [
{
+ name: "Checklist",
+ iconSource: "/qmlimages/check.svg",
+ dropPanelComponent: checklistDropPanel
+ },
+ {
name: _guidedController.takeoffTitle,
iconSource: "/res/takeoff.svg",
action: _guidedController.actionTakeoff
@@ -677,4 +682,292 @@ QGCView {
visible: false
}
}
-}
+
+ Component {
+ id: checklistDropPanel
+
+ Rectangle {
+ id: checklist
+ width: mainColumn.width + (ScreenTools.defaultFontPixelWidth * 4)
+ height: (headerColumn.height+mainColumn.height) * 1.07
+ color: qgcPal.windowShade
+ radius: 20
+ enabled: QGroundControl.multiVehicleManager.vehicles.count > 0;
+
+ onBatPercentRemainingChanged: {if(_initialized) buttonBattery.updateItem();}
+ onGpsLockChanged: {buttonSensors.updateItem();}
+
+ // Connections
+ Connections {
+ target: _activeVehicle
+ onUnhealthySensorsChanged: checklist.onUnhealthySensorsChanged();
+ }
+ Connections {
+ target: QGroundControl.multiVehicleManager
+ onActiveVehicleChanged: checklist.onActiveVehicleChanged();
+ onActiveVehicleAvailableChanged: {}
+ }
+ Connections {
+ target: QGroundControl.settingsManager.appSettings.audioMuted
+ onValueChanged: buttonSoundOutput.updateItem(); //TODO(philippoe): We are binding to a signal which is explicitly marked as "only for QT internal use" here.
+ }
+ Component.onCompleted: {
+ if(QGroundControl.multiVehicleManager.vehicles.count > 0) {
+ onActiveVehicleChanged();
+ _initialized=true;
+ }
+ }
+
+ function updateVehicleDependentItems() {
+ buttonSensors.updateItem();
+ buttonBattery.updateItem();
+ buttonRC.updateItem();
+ buttonEstimator.updateItem();
+ }
+ function onActiveVehicleChanged() {
+ buttonSoundOutput.updateItem(); // Just updated here for initialization once we connect to a vehicle
+ onUnhealthySensorsChanged(); // The health states could all have changed - need to update them.
+ }
+ function onUnhealthySensorsChanged() {
+ var unhealthySensorsStr = _activeVehicle.unhealthySensors;
+
+ // Set to healthy per default
+ for(var i=0;i<32;i++) _healthFlags[i]=true;
+
+ for(i=0;i 0;
+ opacity : 0.2+0.8*(QGroundControl.multiVehicleManager.vehicles.count > 0);
+
+ // Checklist items: Standard
+ QGCCheckListItem {
+ id: buttonHardware
+ name: "Hardware"
+ defaulttext: "Props mounted? Wings secured? Tail secured?"
+ }
+
+ QGCCheckListItem {
+ id: buttonBattery
+ name: "Battery"
+ pendingtext: "Healthy & charged > 40%. Battery connector firmly plugged?"
+ function updateItem() {
+ if (!_activeVehicle) {
+ _state = 0;
+ } else {
+ if (checklist._healthFlags[25] && batPercentRemaining>=40.0) _state = 1+3*(_nrClicked>0);
+ else {
+ if(!checklist._healthFlags[25]) buttonBattery.failuretext="Not healthy. Check console.";
+ else if(batPercentRemaining<40.0) buttonBattery.failuretext="Low (below 40%). Please recharge.";
+ buttonBattery._state = 3;
+ }
+ }
+ }
+ }
+
+ QGCCheckListItem {
+ id: buttonSensors
+ name: "Sensors"
+ function updateItem() {
+ if (!_activeVehicle) {
+ _state = 0;
+ } else {
+ if(checklist._healthFlags[0] &&
+ checklist._healthFlags[1] &&
+ checklist._healthFlags[2] &&
+ checklist._healthFlags[3] &&
+ checklist._healthFlags[4] &&
+ checklist._healthFlags[5]) {
+ if(!gpsLock) {
+ buttonSensors.pendingtext="Pending. Waiting for GPS lock.";
+ buttonSensors._state=1;
+ } else {
+ _state = 4; // All OK
+ }
+ } else {
+ if(!checklist._healthFlags[0]) failuretext="Failure. Gyroscope issues. Check console.";
+ else if(!checklist._healthFlags[1]) failuretext="Failure. Accelerometer issues. Check console.";
+ else if(!checklist._healthFlags[2]) failuretext="Failure. Magnetometer issues. Check console.";
+ else if(!checklist._healthFlags[3]) failuretext="Failure. Barometer issues. Check console.";
+ else if(!checklist._healthFlags[4]) failuretext="Failure. Airspeed sensor issues. Check console.";
+ else if(!checklist._healthFlags[5]) failuretext="Failure. No valid or low quality GPS signal. Check console.";
+ _state = 3;
+ }
+ }
+ }
+ }
+ QGCCheckListItem {
+ id: buttonRC
+ name: "Radio Control"
+ pendingtext: "Receiving signal. Perform range test & confirm."
+ failuretext: "No signal or invalid autopilot-RC config. Check RC and console."
+ function updateItem() {
+ if (!_activeVehicle) {
+ _state = 0;
+ } else {
+ if (_healthFlags[16]) {_state = 1+3*(_nrClicked>0);}
+ else {_state = 3;}
+ }
+ }
+ }
+
+ QGCCheckListItem {
+ id: buttonEstimator
+ name: "Global position estimate"
+ function updateItem() {
+ if (!_activeVehicle) {
+ _state = 0;
+ } else {
+ if (_healthFlags[21]) {_state = 4;}
+ else {_state = 3;}
+ }
+ }
+ }
+
+ // Arming header
+ //Rectangle {anchors.left:parent.left ; anchors.right:parent.right ; height:1 ; color:qgcPal.text}
+ QGCLabel {anchors.horizontalCenter:parent.horizontalCenter ; text:qsTr("Please arm the vehicle here.")}
+ //Rectangle {anchors.left:parent.left ; anchors.right:parent.right ; height:1 ; color:qgcPal.text}
+
+ QGCCheckListItem {
+ id: buttonActuators
+ name: "Actuators"
+ group: 1
+ defaulttext: "Move all control surfaces. Did they work properly?"
+ }
+
+ QGCCheckListItem {
+ id: buttonMotors
+ name: "Motors"
+ group: 1
+ defaulttext: "Propellers free? Then throttle up gently. Working properly?"
+ }
+
+ QGCCheckListItem {
+ id: buttonMission
+ name: "Mission"
+ group: 1
+ defaulttext: "Please confirm mission is valid (waypoints valid, no terrain collision)."
+ }
+
+ QGCCheckListItem {
+ id: buttonSoundOutput
+ name: "Sound output"
+ group: 1
+ pendingtext: "QGC audio output enabled. System audio output enabled, too?"
+ failuretext: "Failure, QGC audio output is disabled. Please enable it under application settings->general to hear audio warnings!"
+ function updateItem() {
+ if (!_activeVehicle) {
+ _state = 0;
+ } else {
+ if (QGroundControl.settingsManager.appSettings.audioMuted.rawValue) {_state = 3;_nrClicked=0;}
+ else {_state = 1+3*(_nrClicked>0);}
+ }
+ }
+ }
+
+ // Directly before launch header
+ //Rectangle {anchors.left:parent.left ; anchors.right:parent.right ; height:1 ; color:qgcPal.text}
+ QGCLabel {anchors.horizontalCenter:parent.horizontalCenter ; text:qsTr("Last preparations before launch") ; opacity : 0.2+0.8*(_checkState >= 2);}
+ //Rectangle {anchors.left:parent.left ; anchors.right:parent.right ; height:1 ; color:qgcPal.text}
+
+ QGCCheckListItem {
+ id: buttonPayload
+ name: "Payload"
+ group: 2
+ defaulttext: "Configured and started?"
+ pendingtext: "Payload lid closed?"
+ }
+
+ QGCCheckListItem {
+ id: buttonWeather
+ name: "Wind & weather"
+ group: 2
+ defaulttext: "OK for your platform?"
+ pendingtext: "Launching into the wind?"
+ }
+
+ QGCCheckListItem {
+ id: buttonFlightAreaFree
+ name: "Flight area"
+ group: 2
+ defaulttext: "Launch area and path free of obstacles/people?"
+ }
+
+ } // Column
+
+ property bool _initialized:false
+ property var _healthFlags: []
+ property int _checkState: _activeVehicle ? (_activeVehicle.armed ? 1 + (buttonActuators._state + buttonMotors._state + buttonMission._state + buttonSoundOutput._state) / 4 / 4 : 0) : 0 ; // Shows progress of checks inside the checklist - unlocks next check steps in groups
+ property bool gpsLock: _activeVehicle ? _activeVehicle.gps.lock.rawValue>=3 : 0
+ property var batPercentRemaining: _activeVehicle ? _activeVehicle.battery.getFact("percentRemaining").value : 0
+
+ // TODO: Having access to MAVLINK enums (or at least QML consts) would be much cleaner than the code below
+ property int subsystem_type_gyro : 1
+ property int subsystem_type_acc : 2
+ property int subsystem_type_mag : 4
+ property int subsystem_type_abspressure : 8
+ property int subsystem_type_diffpressure : 16
+ property int subsystem_type_gps : 32
+ property int subsystem_type_positioncontrol : 16384
+ property int subsystem_type_motorcontrol : 32768
+ property int subsystem_type_rcreceiver : 65536
+ property int subsystem_type_ahrs : 2097152
+ property int subsystem_type_terrain : 4194304
+ property int subsystem_type_reversemotor : 8388608
+ property int subsystem_type_logging : 16777216
+ property int subsystem_type_sensorbattery : 33554432
+ property int subsystem_type_rangefinder : 67108864
+ } //Rectangle
+ } //Component
+} //QGC View
diff --git a/src/QmlControls/DropPanel.qml b/src/QmlControls/DropPanel.qml
index 91fe3dc..1de3e1c 100644
--- a/src/QmlControls/DropPanel.qml
+++ b/src/QmlControls/DropPanel.qml
@@ -64,7 +64,7 @@ Item {
}
if (visible) {
visible = false
- _dropDownComponent = undefined
+ //_dropDownComponent = undefined //TODO (philippoe) such that drop down component state is not deleted - check with don gagne whether this is necessary
toolStrip.uncheckAll()
}
}
diff --git a/src/QmlControls/QGCCheckListItem.qml b/src/QmlControls/QGCCheckListItem.qml
new file mode 100644
index 0000000..cd1e82c
--- /dev/null
+++ b/src/QmlControls/QGCCheckListItem.qml
@@ -0,0 +1,76 @@
+import QtQuick 2.3
+import QtQuick.Controls 1.2
+import QtQuick.Controls.Styles 1.4
+
+import QGroundControl 1.0
+import QGroundControl.Palette 1.0
+import QGroundControl.ScreenTools 1.0
+
+QGCButton {
+ property string name: ""
+ property int _state: 0
+ property var _color: qgcPal.button;//qgcPal.windowShade;//qgcPal.windowShadeDark;//Qt.rgba(0.5,0.5,0.5,1) //qgcPal.window;//
+ property int _nrClicked: 0
+ property int group: 0
+ property string defaulttext: "Not checked yet"
+ property string pendingtext: ""
+ property string failuretext: "Failure. Check console."
+ property string _text: qsTr(name)+ ": " + qsTr(defaulttext)
+
+ enabled : (_activeVehicle==null || _activeVehicle.connectionLost) ? false : _checkState>=group
+ opacity : (_activeVehicle==null || _activeVehicle.connectionLost) ? 0.4 : 0.2+0.8*(_checkState >= group);
+
+ width: parent.width
+ style: ButtonStyle {
+ background: Rectangle {color:_color; border.color: qgcPal.button; radius:3}
+ label: Label {
+ text: _text
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ color: _state>0 ? qgcPal.mapWidgetBorderLight : qgcPal.buttonText
+ }
+ }
+
+ onClicked: {
+ if(_state<2) _nrClicked=_nrClicked+1; //Only allow click-counter to increase when not failed yet
+ updateItem();
+ }
+ onPendingtextChanged: { if(_state==1) {getTextFromState(); getColorFromState();} }
+ onFailuretextChanged: { if(_state==3) {getTextFromState(); getColorFromState();} }
+ on_StateChanged: { getTextFromState(); getColorFromState(); }
+// onEnabledChanged: { //Dont do this for now, because if we only accidentially lose connection, we don't want to delete the checklist state. Instead, we'd need to detect a re-connect, maybe based on the timesincesystemstart (i.e. when it decreases)?
+// if(enabled==false && group > 0) {
+// // Reset all check list items of group > 0 if it is disabled again (which e.g. happens after a vehicle reboot or disarm).
+// _nrClicked = 0;
+// _state = 0;
+// }
+// }
+
+ function updateItem() {
+ // This is the default updateFunction. It assumes the item is a MANUAL check list item, i.e. one that
+ // only requires user clicks (one click if pendingtext="", two clicks otherwise) for completion.
+ //if(_nrClicked>0) _state = 4;
+
+ if(_nrClicked===1) {
+ if(pendingtext.length === 0) _state = 4;
+ else _state = 1;
+ } else if(_nrClicked>1) _state = 4;
+
+ getTextFromState();
+ getColorFromState();
+ }
+ function getTextFromState() {
+ if(_state === 0) {_text= qsTr(name) + ": " + qsTr(defaulttext)} // Not checked yet
+ else if(_state === 1) {_text= ""+qsTr(name)+"" +": " + qsTr(pendingtext)} // Pending
+ else if(_state === 2) {_text= ""+qsTr(name)+"" +": " + qsTr("Minor problem")} // Small problem or need further user action to resolve
+ else if(_state === 3) {_text= ""+qsTr(name)+"" +": " + qsTr(failuretext)} // Big problem
+ else {_text= ""+qsTr(name)+"" +": " + qsTr("OK")} // All OK
+ }
+ function getColorFromState() {
+ if(_state === 0) {_color=qgcPal.button} // Not checked yet
+ else if(_state === 1) {_color=Qt.rgba(0.9,0.47,0.2,1)} // Pending
+ else if(_state === 2) {_color=Qt.rgba(1.0,0.6,0.2,1)} // Small problem or need further user action to resolve
+ else if(_state === 3) {_color=Qt.rgba(0.92,0.22,0.22,1)} // Big problem
+ else {_color=Qt.rgba(0.27,0.67,0.42,1)} // All OK
+ }
+}
diff --git a/src/QmlControls/QGroundControl.Controls.qmldir b/src/QmlControls/QGroundControl.Controls.qmldir
index 6bbe56f..22e8f16 100644
--- a/src/QmlControls/QGroundControl.Controls.qmldir
+++ b/src/QmlControls/QGroundControl.Controls.qmldir
@@ -34,6 +34,7 @@ ParameterEditor 1.0 ParameterEditor.qml
ParameterEditorDialog 1.0 ParameterEditorDialog.qml
PlanToolBar 1.0 PlanToolBar.qml
QGCButton 1.0 QGCButton.qml
+QGCCheckListItem 1.0 QGCCheckListItem.qml
QGCCheckBox 1.0 QGCCheckBox.qml
QGCColoredImage 1.0 QGCColoredImage.qml
QGCComboBox 1.0 QGCComboBox.qml
diff --git a/src/Settings/App.SettingsGroup.json b/src/Settings/App.SettingsGroup.json
index 8e60817..32d51f2 100644
--- a/src/Settings/App.SettingsGroup.json
+++ b/src/Settings/App.SettingsGroup.json
@@ -118,6 +118,13 @@
"defaultValue": false
},
{
+ "name": "UseChecklist",
+ "shortDescription": "Use preflight checklist",
+ "longDescription": "If this option is enabled the preflight checklist will be used.",
+ "type": "bool",
+ "defaultValue": false
+},
+{
"name": "BaseDeviceFontPointSize",
"shortDescription": "Application font size",
"longDescription": "The point size for the default font used.",
diff --git a/src/Settings/AppSettings.cc b/src/Settings/AppSettings.cc
index 56177c3..264181c 100644
--- a/src/Settings/AppSettings.cc
+++ b/src/Settings/AppSettings.cc
@@ -33,6 +33,7 @@ const char* AppSettings::indoorPaletteName = "StyleIs
const char* AppSettings::showLargeCompassName = "ShowLargeCompass";
const char* AppSettings::savePathName = "SavePath";
const char* AppSettings::autoLoadMissionsName = "AutoLoadMissions";
+const char* AppSettings::useChecklistName = "UseChecklist";
const char* AppSettings::mapboxTokenName = "MapboxToken";
const char* AppSettings::esriTokenName = "EsriToken";
const char* AppSettings::defaultFirmwareTypeName = "DefaultFirmwareType";
@@ -75,6 +76,7 @@ AppSettings::AppSettings(QObject* parent)
, _showLargeCompassFact (NULL)
, _savePathFact (NULL)
, _autoLoadMissionsFact (NULL)
+ , _useChecklistFact (NULL)
, _mapboxTokenFact (NULL)
, _esriTokenFact (NULL)
, _defaultFirmwareTypeFact (NULL)
@@ -220,6 +222,15 @@ Fact* AppSettings::audioMuted(void)
return _audioMutedFact;
}
+Fact* AppSettings::useChecklist(void)
+{
+ if (!_useChecklistFact) {
+ _useChecklistFact = _createSettingsFact(useChecklistName);
+ }
+
+ return _useChecklistFact;
+}
+
Fact* AppSettings::appFontPointSize(void)
{
if (!_appFontPointSizeFact) {
diff --git a/src/Settings/AppSettings.h b/src/Settings/AppSettings.h
index d1a7e2f..3b7b88f 100644
--- a/src/Settings/AppSettings.h
+++ b/src/Settings/AppSettings.h
@@ -37,6 +37,7 @@ public:
Q_PROPERTY(Fact* showLargeCompass READ showLargeCompass CONSTANT)
Q_PROPERTY(Fact* savePath READ savePath CONSTANT)
Q_PROPERTY(Fact* autoLoadMissions READ autoLoadMissions CONSTANT)
+ Q_PROPERTY(Fact* useChecklist READ useChecklist CONSTANT)
Q_PROPERTY(Fact* mapboxToken READ mapboxToken CONSTANT)
Q_PROPERTY(Fact* esriToken READ esriToken CONSTANT)
Q_PROPERTY(Fact* defaultFirmwareType READ defaultFirmwareType CONSTANT)
@@ -75,6 +76,7 @@ public:
Fact* showLargeCompass (void);
Fact* savePath (void);
Fact* autoLoadMissions (void);
+ Fact* useChecklist (void);
Fact* mapboxToken (void);
Fact* esriToken (void);
Fact* defaultFirmwareType (void);
@@ -110,6 +112,7 @@ public:
static const char* showLargeCompassName;
static const char* savePathName;
static const char* autoLoadMissionsName;
+ static const char* useChecklistName;
static const char* mapboxTokenName;
static const char* esriTokenName;
static const char* defaultFirmwareTypeName;
@@ -160,6 +163,7 @@ private:
SettingsFact* _showLargeCompassFact;
SettingsFact* _savePathFact;
SettingsFact* _autoLoadMissionsFact;
+ SettingsFact* _useChecklistFact;
SettingsFact* _mapboxTokenFact;
SettingsFact* _esriTokenFact;
SettingsFact* _defaultFirmwareTypeFact;
diff --git a/src/ui/preferences/GeneralSettings.qml b/src/ui/preferences/GeneralSettings.qml
index f302b34..70aa6cb 100644
--- a/src/ui/preferences/GeneralSettings.qml
+++ b/src/ui/preferences/GeneralSettings.qml
@@ -411,6 +411,16 @@ QGCView {
}
}
}
+
+ //-----------------------------------------------------------------
+ //-- Checklist Settings
+ FactCheckBox {
+ text: qsTr("Use preflight checklist")
+ fact: _useChecklist
+ visible: _useChecklist.visible
+
+ property Fact _useChecklist: QGroundControl.settingsManager.appSettings.useChecklist
+ }
}
}