From b5b1d616d9c33d98195ac6639c7ef2b04be223a5 Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Fri, 25 Dec 2015 17:26:32 -0800 Subject: [PATCH] APM Stack Camera Config --- qgcresources.qrc | 2 + qgroundcontrol.pro | 2 + qgroundcontrol.qrc | 2 + src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc | 6 + src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h | 5 +- src/AutoPilotPlugins/APM/APMCameraComponent.cc | 88 ++++ src/AutoPilotPlugins/APM/APMCameraComponent.h | 53 +++ src/AutoPilotPlugins/APM/APMCameraComponent.qml | 490 +++++++++++++++++++++ .../APM/APMCameraComponentSummary.qml | 46 ++ src/AutoPilotPlugins/APM/APMTuningComponent.cc | 2 +- .../PX4/Images/CameraComponentIcon.png | Bin 0 -> 2038 bytes .../PX4/Images/PowerComponentIcon.png | Bin 19189 -> 684 bytes .../PX4/Images/TuningComponentIcon.png | Bin 0 -> 15426 bytes 13 files changed, 694 insertions(+), 2 deletions(-) create mode 100644 src/AutoPilotPlugins/APM/APMCameraComponent.cc create mode 100644 src/AutoPilotPlugins/APM/APMCameraComponent.h create mode 100644 src/AutoPilotPlugins/APM/APMCameraComponent.qml create mode 100644 src/AutoPilotPlugins/APM/APMCameraComponentSummary.qml create mode 100644 src/AutoPilotPlugins/PX4/Images/CameraComponentIcon.png create mode 100644 src/AutoPilotPlugins/PX4/Images/TuningComponentIcon.png diff --git a/qgcresources.qrc b/qgcresources.qrc index 72b12dc..ad1f6b5 100644 --- a/qgcresources.qrc +++ b/qgcresources.qrc @@ -14,6 +14,7 @@ src/QmlControls/arrow-down.png src/VehicleSetup/FirmwareUpgradeIcon.png src/AutoPilotPlugins/PX4/Images/FlightModesComponentIcon.png + src/AutoPilotPlugins/PX4/Images/CameraComponentIcon.png src/AutoPilotPlugins/PX4/Images/PowerComponentBattery_01cell.svg src/AutoPilotPlugins/PX4/Images/PowerComponentBattery_02cell.svg src/AutoPilotPlugins/PX4/Images/PowerComponentBattery_03cell.svg @@ -25,6 +26,7 @@ src/AutoPilotPlugins/PX4/Images/ReturnToHomeAltitude.svg src/AutoPilotPlugins/PX4/Images/SafetyComponentIcon.png src/AutoPilotPlugins/PX4/Images/SensorsComponentIcon.png + src/AutoPilotPlugins/PX4/Images/TuningComponentIcon.png resources/CogWheels.png src/AutoPilotPlugins/PX4/Images/VehicleDown.png src/AutoPilotPlugins/PX4/Images/VehicleDownRotate.png diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 15c1ba3..76b97c5 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -560,6 +560,7 @@ HEADERS+= \ src/AutoPilotPlugins/APM/APMAirframeComponent.h \ src/AutoPilotPlugins/APM/APMAirframeComponentController.h \ src/AutoPilotPlugins/APM/APMAirframeComponentAirframes.h \ + src/AutoPilotPlugins/APM/APMCameraComponent.h \ src/AutoPilotPlugins/APM/APMCompassCal.h \ src/AutoPilotPlugins/APM/APMComponent.h \ src/AutoPilotPlugins/APM/APMFlightModesComponent.h \ @@ -614,6 +615,7 @@ SOURCES += \ src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc \ src/AutoPilotPlugins/APM/APMAirframeComponent.cc \ src/AutoPilotPlugins/APM/APMAirframeComponentController.cc \ + src/AutoPilotPlugins/APM/APMCameraComponent.cc \ src/AutoPilotPlugins/APM/APMCompassCal.cc \ src/AutoPilotPlugins/APM/APMComponent.cc \ src/AutoPilotPlugins/APM/APMFlightModesComponent.cc \ diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index ae36d21..07ac0d0 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -106,6 +106,8 @@ src/AutoPilotPlugins/Common/RadioComponent.qml src/AutoPilotPlugins/PX4/PX4RadioComponentSummary.qml src/AutoPilotPlugins/APM/APMNotSupported.qml + src/AutoPilotPlugins/APM/APMCameraComponent.qml + src/AutoPilotPlugins/APM/APMCameraComponentSummary.qml src/AutoPilotPlugins/APM/APMPowerComponent.qml src/AutoPilotPlugins/APM/APMPowerComponentSummary.qml src/AutoPilotPlugins/APM/APMRadioComponentSummary.qml diff --git a/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc b/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc index e0bdf16..418edb2 100644 --- a/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc +++ b/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc @@ -39,12 +39,14 @@ #include "APMTuningComponent.h" #include "APMSensorsComponent.h" #include "APMPowerComponent.h" +#include "APMCameraComponent.h" /// This is the AutoPilotPlugin implementatin for the MAV_AUTOPILOT_ARDUPILOT type. APMAutoPilotPlugin::APMAutoPilotPlugin(Vehicle* vehicle, QObject* parent) : AutoPilotPlugin(vehicle, parent) , _incorrectParameterVersion(false) , _airframeComponent(NULL) + , _cameraComponent(NULL) , _flightModesComponent(NULL) , _powerComponent(NULL) , _radioComponent(NULL) @@ -75,6 +77,10 @@ const QVariantList& APMAutoPilotPlugin::vehicleComponents(void) qWarning() << "new APMAirframeComponent failed"; } + _cameraComponent = new APMCameraComponent(_vehicle, this); + _cameraComponent->setupTriggerSignals(); + _components.append(QVariant::fromValue((VehicleComponent*)_cameraComponent)); + _flightModesComponent = new APMFlightModesComponent(_vehicle, this); if (_flightModesComponent) { _flightModesComponent->setupTriggerSignals(); diff --git a/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h b/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h index 9eedfe9..67dd583 100644 --- a/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h +++ b/src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h @@ -35,6 +35,7 @@ class APMTuningComponent; class APMSafetyComponent; class APMSensorsComponent; class APMPowerComponent; +class APMCameraComponent; /// This is the APM specific implementation of the AutoPilot class. class APMAutoPilotPlugin : public AutoPilotPlugin @@ -49,6 +50,7 @@ public: virtual const QVariantList& vehicleComponents(void); APMAirframeComponent* airframeComponent (void) { return _airframeComponent; } + APMCameraComponent* cameraComponent (void) { return _cameraComponent; } APMFlightModesComponent* flightModesComponent(void) { return _flightModesComponent; } APMPowerComponent* powerComponent (void) { return _powerComponent; } APMRadioComponent* radioComponent (void) { return _radioComponent; } @@ -65,13 +67,14 @@ private: QVariantList _components; APMAirframeComponent* _airframeComponent; + APMCameraComponent* _cameraComponent; APMFlightModesComponent* _flightModesComponent; APMPowerComponent* _powerComponent; APMRadioComponent* _radioComponent; APMSafetyComponent* _safetyComponent; APMSensorsComponent* _sensorsComponent; APMTuningComponent* _tuningComponent; - APMAirframeLoader* _airframeFacts; + APMAirframeLoader* _airframeFacts; }; #endif diff --git a/src/AutoPilotPlugins/APM/APMCameraComponent.cc b/src/AutoPilotPlugins/APM/APMCameraComponent.cc new file mode 100644 index 0000000..d4613e4 --- /dev/null +++ b/src/AutoPilotPlugins/APM/APMCameraComponent.cc @@ -0,0 +1,88 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +/// @file +/// @author Don Gagne + +#include "APMCameraComponent.h" +#include "QGCQmlWidgetHolder.h" +#include "APMAutoPilotPlugin.h" +#include "APMAirframeComponent.h" + +APMCameraComponent::APMCameraComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent) + : APMComponent(vehicle, autopilot, parent) + , _name(tr("Camera")) +{ +} + +QString APMCameraComponent::name(void) const +{ + return _name; +} + +QString APMCameraComponent::description(void) const +{ + return tr("The Camera Component is used to setup camera and gimbal settings."); +} + +QString APMCameraComponent::iconResource(void) const +{ + return "/qmlimages/CameraComponentIcon.png"; +} + +bool APMCameraComponent::requiresSetup(void) const +{ + return false; +} + +bool APMCameraComponent::setupComplete(void) const +{ + return true; +} + +QStringList APMCameraComponent::setupCompleteChangedTriggerList(void) const +{ + return QStringList(); +} + +QUrl APMCameraComponent::setupSource(void) const +{ + return QUrl::fromUserInput("qrc:/qml/APMCameraComponent.qml"); +} + +QUrl APMCameraComponent::summaryQmlSource(void) const +{ + return QUrl::fromUserInput("qrc:/qml/APMCameraComponentSummary.qml"); +} + +QString APMCameraComponent::prerequisiteSetup(void) const +{ + APMAutoPilotPlugin* plugin = dynamic_cast(_autopilot); + Q_ASSERT(plugin); + + if (!plugin->airframeComponent()->setupComplete()) { + return plugin->airframeComponent()->name(); + } + + return QString(); +} diff --git a/src/AutoPilotPlugins/APM/APMCameraComponent.h b/src/AutoPilotPlugins/APM/APMCameraComponent.h new file mode 100644 index 0000000..354c802 --- /dev/null +++ b/src/AutoPilotPlugins/APM/APMCameraComponent.h @@ -0,0 +1,53 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#ifndef APMCameraComponent_H +#define APMCameraComponent_H + +#include "APMComponent.h" + +class APMCameraComponent : public APMComponent +{ + Q_OBJECT + +public: + APMCameraComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent = NULL); + + // Virtuals from PX4Component + virtual QStringList setupCompleteChangedTriggerList(void) const; + + // Virtuals from VehicleComponent + virtual QString name(void) const; + virtual QString description(void) const; + virtual QString iconResource(void) const; + virtual bool requiresSetup(void) const; + virtual bool setupComplete(void) const; + virtual QUrl setupSource(void) const; + virtual QUrl summaryQmlSource(void) const; + virtual QString prerequisiteSetup(void) const; + +private: + const QString _name; +}; + +#endif diff --git a/src/AutoPilotPlugins/APM/APMCameraComponent.qml b/src/AutoPilotPlugins/APM/APMCameraComponent.qml new file mode 100644 index 0000000..479990f --- /dev/null +++ b/src/AutoPilotPlugins/APM/APMCameraComponent.qml @@ -0,0 +1,490 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2015 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +import QtQuick 2.5 +import QtQuick.Controls 1.2 + +import QGroundControl.FactSystem 1.0 +import QGroundControl.FactControls 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.ScreenTools 1.0 + +QGCView { + id: _cameraView + viewPanel: panel + anchors.fill: parent + + FactPanelController { id: controller; factPanel: panel } + + QGCPalette { id: palette; colorGroupEnabled: enabled } + + property Fact _mountRetractX: controller.getParameterFact(-1, "MNT_RETRACT_X") + property Fact _mountRetractY: controller.getParameterFact(-1, "MNT_RETRACT_Y") + property Fact _mountRetractZ: controller.getParameterFact(-1, "MNT_RETRACT_Z") + + property Fact _mountNeutralX: controller.getParameterFact(-1, "MNT_NEUTRAL_X") + property Fact _mountNeutralY: controller.getParameterFact(-1, "MNT_NEUTRAL_Y") + property Fact _mountNeutralZ: controller.getParameterFact(-1, "MNT_NEUTRAL_Z") + + /* + property Fact _mountControlX: controller.getParameterFact(-1, "MNT_CONTROL_X") + property Fact _mountControlY: controller.getParameterFact(-1, "MNT_CONTROL_Y") + property Fact _mountControlZ: controller.getParameterFact(-1, "MNT_CONTROL_Z") + */ + + property Fact _mountRCInTilt: controller.getParameterFact(-1, "MNT_RC_IN_TILT") + property Fact _mountStabTilt: controller.getParameterFact(-1, "MNT_STAB_TILT") + property Fact _mountAngMinTilt: controller.getParameterFact(-1, "MNT_ANGMIN_TIL") + property Fact _mountAngMaxTilt: controller.getParameterFact(-1, "MNT_ANGMAX_TIL") + + property Fact _mountRCInRoll: controller.getParameterFact(-1, "MNT_RC_IN_ROLL") + property Fact _mountStabRoll: controller.getParameterFact(-1, "MNT_STAB_ROLL") + property Fact _mountAngMinRoll: controller.getParameterFact(-1, "MNT_ANGMIN_ROL") + property Fact _mountAngMaxRoll: controller.getParameterFact(-1, "MNT_ANGMAX_ROL") + + property Fact _mountRCInPan: controller.getParameterFact(-1, "MNT_RC_IN_PAN") + property Fact _mountStabPan: controller.getParameterFact(-1, "MNT_STAB_PAN") + property Fact _mountAngMinPan: controller.getParameterFact(-1, "MNT_ANGMIN_PAN") + property Fact _mountAngMaxPan: controller.getParameterFact(-1, "MNT_ANGMAX_PAN") + + // FIXME: WHat do we set this to? APM Planner sets to RC Tracking whenever a value is changed. + // Check default iris settings. + property Fact _mountDefaultMode: controller.getParameterFact(-1, "MNT_DEFLT_MODE") + property Fact _mountType: controller.getParameterFact(-1, "MNT_TYPE") + + property Fact _rc5Function: controller.getParameterFact(-1, "RC5_FUNCTION") + property Fact _rc6Function: controller.getParameterFact(-1, "RC6_FUNCTION") + property Fact _rc7Function: controller.getParameterFact(-1, "RC7_FUNCTION") + property Fact _rc8Function: controller.getParameterFact(-1, "RC8_FUNCTION") + property Fact _rc9Function: controller.getParameterFact(-1, "RC9_FUNCTION") + property Fact _rc10Function: controller.getParameterFact(-1, "RC10_FUNCTION") + property Fact _rc11Function: controller.getParameterFact(-1, "RC11_FUNCTION") + property Fact _rc12Function: controller.getParameterFact(-1, "RC12_FUNCTION") + property Fact _rc13Function: controller.getParameterFact(-1, "RC13_FUNCTION") + property Fact _rc14Function: controller.getParameterFact(-1, "RC14_FUNCTION") + + property bool _tiltEnabled: false + property bool _panEnabled: false + property bool _rollEnabled: false + + readonly property real _margins: ScreenTools.defaultFontPixelHeight + readonly property int _rcFunctionDisabled: 0 + readonly property int _rcFunctionMountPan: 6 + readonly property int _rcFunctionMountTilt: 7 + readonly property int _rcFunctionMountRoll: 8 + readonly property int _firstGimbalOutChannel: 5 + readonly property int _lastGimbalOutChannel: 14 + readonly property int _mountDefaultModeRCTargetting: 3 + + function setGimbalSettingsServoInfo(loader, channel) { + var rcPrefix = "RC" + channel + "_" + + loader.gimbalOutIndex = channel - 4 + loader.servoPWMMinFact = controller.getParameterFact(-1, rcPrefix + "MIN") + loader.servoPWMMaxFact = controller.getParameterFact(-1, rcPrefix + "MAX") + loader.servoReverseFact = controller.getParameterFact(-1, rcPrefix + "REV") + } + + /// Gimbal output channels are stored in RC#_FUNCTION parameters. We need to loop through those + /// to find them and setup the ui accordindly. + function calcGimbalOutValues() { + gimbalDirectionTiltLoader.gimbalOutIndex = 0 + gimbalDirectionPanLoader.gimbalOutIndex = 0 + gimbalDirectionRollLoader.gimbalOutIndex = 0 + _tiltEnabled = false + _panEnabled = false + _rollEnabled = false + for (var channel=_firstGimbalOutChannel; channel<=_lastGimbalOutChannel; channel++) { + var functionFact = controller.getParameterFact(-1, "RC" + channel + "_FUNCTION") + if (functionFact.value == _rcFunctionMountTilt) { + _tiltEnabled = true + setGimbalSettingsServoInfo(gimbalDirectionTiltLoader, channel) + } else if (functionFact.value == _rcFunctionMountPan) { + _panEnabled = true + setGimbalSettingsServoInfo(gimbalDirectionPanLoader, channel) + } else if (functionFact.value == _rcFunctionMountRoll) { + _rollEnabled = true + setGimbalSettingsServoInfo(gimbalDirectionRollLoader, channel) + } + } + } + + function setRCFunction(channel, rcFunction) { + // First clear any previous settings for this function + for (var index=_firstGimbalOutChannel; index<=_lastGimbalOutChannel; index++) { + var functionFact = controller.getParameterFact(-1, "RC" + index + "_FUNCTION") + if (functionFact.value != _rcFunctionDisabled && functionFact.value == rcFunction) { + functionFact.value = _rcFunctionDisabled + } + } + + // Now set the function into the new channel + if (channel != 0) { + var functionFact = controller.getParameterFact(-1, "RC" + channel + "_FUNCTION") + functionFact.value = rcFunction + } + } + + Component.onCompleted: calcGimbalOutValues() + + // Whenever any RC#_FUNCTION parameters chagnes we need to go looking for gimbal output channels again + Connections { target: _rc5Function; onValueChanged: calcGimbalOutValues() } + Connections { target: _rc6Function; onValueChanged: calcGimbalOutValues() } + Connections { target: _rc7Function; onValueChanged: calcGimbalOutValues() } + Connections { target: _rc8Function; onValueChanged: calcGimbalOutValues() } + Connections { target: _rc9Function; onValueChanged: calcGimbalOutValues() } + Connections { target: _rc10Function; onValueChanged: calcGimbalOutValues() } + Connections { target: _rc11Function; onValueChanged: calcGimbalOutValues() } + Connections { target: _rc12Function; onValueChanged: calcGimbalOutValues() } + Connections { target: _rc13Function; onValueChanged: calcGimbalOutValues() } + Connections { target: _rc14Function; onValueChanged: calcGimbalOutValues() } + + // Whenever an MNT_RC_IN_* setting is changed make sure to turn on RC targetting + Connections { + target: _mountRCInPan + onValueChanged: _mountDefaultMode.value = _mountDefaultModeRCTargetting + } + + Connections { + target: _mountRCInRoll + onValueChanged: _mountDefaultMode.value = _mountDefaultModeRCTargetting + } + + Connections { + target: _mountRCInTilt + onValueChanged: _mountDefaultMode.value = _mountDefaultModeRCTargetting + } + + ListModel { + id: gimbalOutModel + ListElement { text: "Disabled"; value: 0 } + ListElement { text: "Channel 5"; value: 5 } + ListElement { text: "Channel 6"; value: 6 } + ListElement { text: "Channel 7"; value: 7 } + ListElement { text: "Channel 8"; value: 8 } + ListElement { text: "Channel 9"; value: 9 } + ListElement { text: "Channel 10"; value: 10 } + ListElement { text: "Channel 11"; value: 11 } + ListElement { text: "Channel 12"; value: 12 } + ListElement { text: "Channel 13"; value: 13 } + ListElement { text: "Channel 14"; value: 14 } + } + + Component { + id: gimbalDirectionSettings + + // The following properties must be set in the Loader + // property string directionTitle + // property bool directionEnabled + // property int gimbalOutIndex + // property Fact mountRcInFact + // property Fact mountStabFact + // property Fact mountAngMinFact + // property Fact mountAngMaxFact + // property Fact servoPWMMinFact + // property Fact servoPWMMaxFact + // property Fact servoReverseFact + // property int rcFunction + + Item { + width: rectangle.x + rectangle.width + height: rectangle.y + rectangle.height + + QGCLabel { + id: directionLabel + text: "Gimbal " + directionTitle + font.weight: Font.DemiBold + } + + Rectangle { + id: rectangle + anchors.topMargin: _margins / 2 + anchors.left: parent.left + anchors.top: directionLabel.bottom + width: mountAngMaxField.x + mountAngMaxField.width + _margins + height: servoPWMMaxField.y + servoPWMMaxField.height + _margins + color: palette.windowShade + + FactCheckBox { + id: mountStabCheckBox + anchors.topMargin: _margins + anchors.left: servoReverseCheckBox.left + anchors.top: parent.top + text: "Stabilize" + fact: mountStabFact + checkedValue: 1 + uncheckedValue: 0 + enabled: directionEnabled + } + + FactCheckBox { + id: servoReverseCheckBox + anchors.margins: _margins + anchors.top: mountStabCheckBox.bottom + anchors.right: parent.right + text: "Servo reverse" + checkedValue: 1 + uncheckedValue: 0 + fact: servoReverseFact + enabled: directionEnabled + } + + QGCLabel { + id: gimbalOutLabel + anchors.margins: _margins + anchors.left: parent.left + anchors.baseline: gimbalOutCombo.baseline + text: "Output channel:" + } + + QGCComboBox { + id: gimbalOutCombo + anchors.margins: _margins + anchors.top: parent.top + anchors.left: gimbalOutLabel.right + width: mountAngMinField.width + model: gimbalOutModel + currentIndex: gimbalOutIndex + + onActivated: setRCFunction(gimbalOutModel.get(index).value, rcFunction) + } + + QGCLabel { + id: mountRcInLabel + anchors.margins: _margins + anchors.left: parent.left + anchors.baseline: mountRcInCombo.baseline + text: "Input channel:" + enabled: directionEnabled + } + + FactComboBox { + id: mountRcInCombo + anchors.topMargin: _margins / 2 + anchors.top: gimbalOutCombo.bottom + anchors.left: gimbalOutCombo.left + width: mountAngMinField.width + fact: mountRcInFact + indexModel: false + enabled: directionEnabled + } + + QGCLabel { + id: mountAngLabel + anchors.margins: _margins + anchors.left: parent.left + anchors.baseline: mountAngMinField.baseline + text: "Gimbal angle limits:" + enabled: directionEnabled + } + + QGCLabel { + id: mountAngMinLabel + anchors.margins: _margins + anchors.left: mountAngLabel.right + anchors.baseline: mountAngMinField.baseline + text: "min" + enabled: directionEnabled + } + + FactTextField { + id: mountAngMinField + anchors.margins: _margins + anchors.top: mountRcInCombo.bottom + anchors.left: mountAngMinLabel.right + fact: mountAngMinFact + enabled: directionEnabled + } + + QGCLabel { + id: mountAngMaxLabel + anchors.margins: _margins + anchors.left: mountAngMinField.right + anchors.baseline: mountAngMinField.baseline + text: "max" + enabled: directionEnabled + } + + FactTextField { + id: mountAngMaxField + anchors.leftMargin: _margins + anchors.top: mountAngMinField.top + anchors.left: mountAngMaxLabel.right + fact: mountAngMaxFact + enabled: directionEnabled + } + + QGCLabel { + id: servoPWMLabel + anchors.margins: _margins + anchors.left: parent.left + anchors.baseline: servoPWMMinField.baseline + text: "Servo PWM limits:" + enabled: directionEnabled + } + + QGCLabel { + id: servoPWMMinLabel + anchors.left: mountAngMinLabel.left + anchors.baseline: servoPWMMinField.baseline + text: "min" + enabled: directionEnabled + } + + FactTextField { + id: servoPWMMinField + anchors.topMargin: _margins / 2 + anchors.leftMargin: _margins + anchors.top: mountAngMaxField.bottom + anchors.left: servoPWMMinLabel.right + fact: servoPWMMinFact + enabled: directionEnabled + } + + QGCLabel { + id: servoPWMMaxLabel + anchors.margins: _margins + anchors.left: servoPWMMinField.right + anchors.baseline: servoPWMMinField.baseline + text: "max" + enabled: directionEnabled + } + + FactTextField { + id: servoPWMMaxField + anchors.leftMargin: _margins + anchors.top: servoPWMMinField.top + anchors.left: servoPWMMaxLabel.right + fact: servoPWMMaxFact + enabled: directionEnabled + } + } // Rectangle + } // Item + } // Component - gimbalDirectionSettings + + QGCViewPanel { + id: panel + anchors.fill: parent + + Flickable { + clip: true + anchors.fill: parent + contentHeight: gimbalDirectionPanLoader.y + gimbalDirectionPanLoader.height + contentWidth: gimbalTypeRectangle.x + gimbalTypeRectangle.width + + Loader { + id: gimbalDirectionTiltLoader + sourceComponent: gimbalDirectionSettings + + property string directionTitle: "Tilt" + property bool directionEnabled: _tiltEnabled + property int gimbalOutIndex: 0 + property Fact mountRcInFact: _mountRCInTilt + property Fact mountStabFact: _mountStabTilt + property Fact mountAngMinFact: _mountAngMinTilt + property Fact mountAngMaxFact: _mountAngMaxTilt + property Fact servoPWMMinFact: Fact { } + property Fact servoPWMMaxFact: Fact { } + property Fact servoReverseFact: Fact { } + property int rcFunction: _rcFunctionMountTilt + } + + Loader { + id: gimbalDirectionRollLoader + anchors.margins: _margins + anchors.top: gimbalDirectionTiltLoader.bottom + sourceComponent: gimbalDirectionSettings + + property string directionTitle: "Roll" + property bool directionEnabled: _rollEnabled + property int gimbalOutIndex: 0 + property Fact mountRcInFact: _mountRCInRoll + property Fact mountStabFact: _mountStabRoll + property Fact mountAngMinFact: _mountAngMinRoll + property Fact mountAngMaxFact: _mountAngMaxRoll + property Fact servoPWMMinFact: Fact { } + property Fact servoPWMMaxFact: Fact { } + property Fact servoReverseFact: Fact { } + property int rcFunction: _rcFunctionMountRoll + } + + Loader { + id: gimbalDirectionPanLoader + anchors.margins: _margins + anchors.top: gimbalDirectionRollLoader.bottom + sourceComponent: gimbalDirectionSettings + + property string directionTitle: "Pan" + property bool directionEnabled: _panEnabled + property int gimbalOutIndex: 0 + property Fact mountRcInFact: _mountRCInPan + property Fact mountStabFact: _mountStabPan + property Fact mountAngMinFact: _mountAngMinPan + property Fact mountAngMaxFact: _mountAngMaxPan + property Fact servoPWMMinFact: Fact { } + property Fact servoPWMMaxFact: Fact { } + property Fact servoReverseFact: Fact { } + property int rcFunction: _rcFunctionMountPan + } + + QGCLabel { + id: typeLabel + anchors.leftMargin: _margins + anchors.left: gimbalDirectionTiltLoader.right + text: "Gimbal Type" + font.weight: Font.DemiBold + } + + Rectangle { + id: gimbalTypeRectangle + anchors.topMargin: _margins / 2 + anchors.left: typeLabel.left + anchors.top: typeLabel.bottom + width: rebootLabel.x + rebootLabel.width + _margins + height: rebootLabel.y + rebootLabel.height + _margins + color: palette.windowShade + + FactComboBox { + id: gimbalTypeCombo + anchors.margins: _margins + anchors.top: parent.top + anchors.left: parent.left + width: ScreenTools.defaultFontPixelWidth * 15 + fact: _mountType + indexModel: false + } + + QGCLabel { + id: rebootLabel + anchors.topMargin: _margins / 2 + anchors.left: gimbalTypeCombo.left + anchors.top: gimbalTypeCombo.bottom + width: ScreenTools.defaultFontPixelWidth * 25 + wrapMode: Text.WordWrap + text: "Gimbal Type changes takes affect next reboot of autopilot" + } + } + } // Flickable + } // QGCViewPanel +} // QGCView diff --git a/src/AutoPilotPlugins/APM/APMCameraComponentSummary.qml b/src/AutoPilotPlugins/APM/APMCameraComponentSummary.qml new file mode 100644 index 0000000..62ebfae --- /dev/null +++ b/src/AutoPilotPlugins/APM/APMCameraComponentSummary.qml @@ -0,0 +1,46 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.2 + +import QGroundControl.FactSystem 1.0 +import QGroundControl.FactControls 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.Palette 1.0 + +FactPanel { + id: panel + anchors.fill: parent + color: qgcPal.windowShadeDark + + QGCPalette { id: qgcPal; colorGroupEnabled: enabled } + FactPanelController { id: controller; factPanel: panel } + + property Fact _mountRCInTilt: controller.getParameterFact(-1, "MNT_RC_IN_TILT") + property Fact _mountRCInRoll: controller.getParameterFact(-1, "MNT_RC_IN_ROLL") + property Fact _mountRCInPan: controller.getParameterFact(-1, "MNT_RC_IN_PAN") + property Fact _mountType: controller.getParameterFact(-1, "MNT_TYPE") + + Column { + anchors.fill: parent + anchors.margins: 8 + + VehicleSummaryRow { + labelText: "Gimbal type:" + valueText: _mountType.enumStringValue + } + + VehicleSummaryRow { + labelText: "Tilt input channel:" + valueText: _mountRCInTilt.enumStringValue + } + + VehicleSummaryRow { + labelText: "Pan input channel:" + valueText: _mountRCInPan.enumStringValue + } + + VehicleSummaryRow { + labelText: "Roll input channel:" + valueText: _mountRCInRoll.enumStringValue + } + } +} diff --git a/src/AutoPilotPlugins/APM/APMTuningComponent.cc b/src/AutoPilotPlugins/APM/APMTuningComponent.cc index 7275d98..e8dfdcd 100644 --- a/src/AutoPilotPlugins/APM/APMTuningComponent.cc +++ b/src/AutoPilotPlugins/APM/APMTuningComponent.cc @@ -43,7 +43,7 @@ QString APMTuningComponent::description(void) const QString APMTuningComponent::iconResource(void) const { - return "/qmlimages/subMenuButtonImage.png"; + return "/qmlimages/TuningComponentIcon.png"; } bool APMTuningComponent::requiresSetup(void) const diff --git a/src/AutoPilotPlugins/PX4/Images/CameraComponentIcon.png b/src/AutoPilotPlugins/PX4/Images/CameraComponentIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..cc784b2e028b0e6ebf13c1679c807672fa1fca15 GIT binary patch literal 2038 zcmbtVc~Fzr77t;`1|&v644^|4wepFz#6XoL1dvb^mrDFVmP93_C4vhIaRCxT*cWZV zhZGP5#E`^*&;WsgMoX0RHbzrQ>T z@*T}>AR{8qe~&L>#FPMoBe>1Cc#!3izmM0!gu(Yip0O*VY!N4Rml>9?woNASi@hqK(sbs9xuoXj4J6$B1h-`V z!mpyVJWXP^{#%NdHRG0=n@Pv9%zu!?~xmq%iQ=o`5_Sr8xdc=`HQKk|})* zngo!(%Es_gWcW~5Ji6wwV+K*ai(tjyyg4YSs}9gchrlts*9mFuR1mers6a+#qX0pE z&ynJm@2rEt{7CK*2Q`cYaDY8uKthlJGo|OPb+-(TtvTpfVVi+1MKyb|K{oxG6+8g6 zuQ#%~hc0uF;pkKh&q0iX;2{S*7)qdb%D0)CTzXFTW9wpvQ&p$Hi?bfr?=nst27gep zL6g$_YVEnD52MPh53G5|Yl4Qv#VMakDVH%Z^1=-rb=`_|Mg`nIf?&@_)<4pD6C|9;Y6Zq@87-SkQ)%s*`Pd>HQuM=%tajq zusH$>>1O3F!)Ox0{ZwID>si&u%M*hm(QngtTNf$a#2rDUhb7t_B)fAtg3!&~(-LgN z4BdI&jVzBN46 zq`vLfSIkYFQ|qfJxKPp>P(Lv=|L96;?VSGO#}YOl*pjrG^P#`(;nuN2pZOy9hRIu6 z=Z1{vw?WkUD<*C7@=a6H@aI~SvmD-SW|QGYIk&UUZD45V;yc3aq`hSK2zVzh+Rm}6q1;9vQjKdOIVv)GiEAnRRbex2+@gL zJmbwc83xgnLxzZzMum{Tk)7-6!GZ13Q<>cS-%T)=o3f%dYzHnG*J{$zXm|X_Zvl6oed^l3R_^ zst>#b*@@eM_RBa5!|M;XSko8Cx2q}g5(9?tXi0<_M89?R$?b3>D`;8Q4_}S!HldX#&lu1 zA`y#Dv>kRO3>xb;9B{!+i@Jy9FQ+iz8+uQ3Y2!hI!|6gSdrn|u?U+8-z z+wsBV@ox%S@N|Mz`kR?^t*?I%EIYZyD)T{tTO!%kytKL5?%L6Y)}pH3H&2$9mh?G^ zq555$WMC1*+q3cUYvtd@vHTb)pxl-+eI(o?C3Rw9d#d&>ORB)esM~(oF89&J2 z3XOfd83tc+_fG;P`}bQkIUqa^y<8hNGq#_$iPCb?0!r=*xg*b*4Z{45=p~xN1$MLI zqimaqzZ_HYC>J7<3F^+?`X%RS1B(f$hWtEw~Z*vQgP4X-GqN@Dfdb@dd`cO}Tj2!i5x4vmz3 zVXs)@n11cdx#b48jXyKl&=X;l`N^_bsZ>7cSo%Dqh?i#*!?r`uSrEyslgstTp#CP2!H_%5)W$^z8sdH}8 literal 0 HcmV?d00001 diff --git a/src/AutoPilotPlugins/PX4/Images/PowerComponentIcon.png b/src/AutoPilotPlugins/PX4/Images/PowerComponentIcon.png index cba13b67525fa2e315ea53d7ac3e0eb3474cb834..83f6caf8f85a2652bad7cf78668177a14c8f40cf 100644 GIT binary patch literal 684 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 B&hh{N diff --git a/src/AutoPilotPlugins/PX4/Images/TuningComponentIcon.png b/src/AutoPilotPlugins/PX4/Images/TuningComponentIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..059b5868af30b75b18a3d3d0503d1a5e02c0fe67 GIT binary patch literal 15426 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