Commit 94e718b6 authored by Lorenz Meier's avatar Lorenz Meier

Merge pull request #1337 from DonLakeFlyer/FMConfig

New Flight Mode config
parents dd078544 b69a146e
......@@ -676,7 +676,6 @@ HEADERS += \
src/qgcunittest/PX4RCCalibrationTest.h \
src/qgcunittest/LinkManagerTest.h \
src/qgcunittest/MainWindowTest.h \
src/AutoPilotPlugins/PX4/Tests/FlightModeConfigTest.h \
src/qgcunittest/MavlinkLogTest.h \
src/FactSystem/FactSystemTestBase.h \
src/FactSystem/FactSystemTestPX4.h \
......@@ -702,7 +701,6 @@ SOURCES += \
src/qgcunittest/PX4RCCalibrationTest.cc \
src/qgcunittest/LinkManagerTest.cc \
src/qgcunittest/MainWindowTest.cc \
src/AutoPilotPlugins/PX4/Tests/FlightModeConfigTest.cc \
src/qgcunittest/MavlinkLogTest.cc \
src/FactSystem/FactSystemTestBase.cc \
src/FactSystem/FactSystemTestPX4.cc \
......@@ -722,7 +720,6 @@ INCLUDEPATH += \
FORMS += \
src/VehicleSetup/ParameterEditor.ui \
src/ui/QGCPX4VehicleConfig.ui \
src/AutoPilotPlugins/PX4/FlightModeConfig.ui \
src/VehicleSetup/SetupView.ui \
HEADERS+= \
......@@ -740,7 +737,7 @@ HEADERS+= \
src/AutoPilotPlugins/PX4/PX4Component.h \
src/AutoPilotPlugins/PX4/RadioComponent.h \
src/AutoPilotPlugins/PX4/FlightModesComponent.h \
src/AutoPilotPlugins/PX4/FlightModeConfig.h \
src/AutoPilotPlugins/PX4/FlightModesComponentController.h \
src/AutoPilotPlugins/PX4/AirframeComponent.h \
src/AutoPilotPlugins/PX4/SensorsComponent.h \
src/AutoPilotPlugins/PX4/SensorsComponentController.h \
......@@ -762,7 +759,7 @@ SOURCES += \
src/AutoPilotPlugins/PX4/PX4Component.cc \
src/AutoPilotPlugins/PX4/RadioComponent.cc \
src/AutoPilotPlugins/PX4/FlightModesComponent.cc \
src/AutoPilotPlugins/PX4/FlightModeConfig.cc \
src/AutoPilotPlugins/PX4/FlightModesComponentController.cc \
src/AutoPilotPlugins/PX4/AirframeComponent.cc \
src/AutoPilotPlugins/PX4/SensorsComponent.cc \
src/AutoPilotPlugins/PX4/SensorsComponentController.cc \
......
......@@ -247,15 +247,14 @@
<qresource prefix="/qml">
<file alias="test.qml">src/test.qml</file>
<file alias="QmlTest.qml">src/QmlControls/QmlTest.qml</file>
<file alias="QGroundControl/FactControls/qmldir">src/FactSystem/FactControls/qmldir</file>
<file alias="QGroundControl/FactControls/FactLabel.qml">src/FactSystem/FactControls/FactLabel.qml</file>
<file alias="QGroundControl/FactControls/FactTextField.qml">src/FactSystem/FactControls/FactTextField.qml</file>
<file alias="QGroundControl/FactControls/FactCheckBox.qml">src/FactSystem/FactControls/FactCheckBox.qml</file>
<file alias="QGroundControl/FactControls/FactComboBox.qml">src/FactSystem/FactControls/FactComboBox.qml</file>
<file alias="QGroundControl/Controls/qmldir">src/QmlControls/qmldir</file>
<file alias="QGroundControl/Controls/SubMenuButton.qml">src/QmlControls/SubMenuButton.qml</file>
<file alias="QGroundControl/Controls/IndicatorButton.qml">src/QmlControls/IndicatorButton.qml</file>
<file alias="QGroundControl/Controls/VehicleRotationCal.qml">src/QmlControls/VehicleRotationCal.qml</file>
<file alias="QGroundControl/Controls/QGCButton.qml">src/QmlControls/QGCButton.qml</file>
<file alias="QGroundControl/Controls/QGCRadioButton.qml">src/QmlControls/QGCRadioButton.qml</file>
<file alias="QGroundControl/Controls/QGCCheckBox.qml">src/QmlControls/QGCCheckBox.qml</file>
......@@ -263,21 +262,31 @@
<file alias="QGroundControl/Controls/QGCTextField.qml">src/QmlControls/QGCTextField.qml</file>
<file alias="QGroundControl/Controls/QGCComboBox.qml">src/QmlControls/QGCComboBox.qml</file>
<file alias="QGroundControl/Controls/QGCColoredImage.qml">src/QmlControls/QGCColoredImage.qml</file>
<file alias="QGroundControl/Controls/arrow-down.png">src/QmlControls/arrow-down.png</file>
<file alias="QGroundControl/Controls/QGCToolBarButton.qml">src/QmlControls/QGCToolBarButton.qml</file>
<file alias="QGroundControl/Controls/SubMenuButton.qml">src/QmlControls/SubMenuButton.qml</file>
<file alias="QGroundControl/Controls/IndicatorButton.qml">src/QmlControls/IndicatorButton.qml</file>
<file alias="QGroundControl/Controls/VehicleRotationCal.qml">src/QmlControls/VehicleRotationCal.qml</file>
<file alias="QGroundControl/Controls/arrow-down.png">src/QmlControls/arrow-down.png</file>
<file alias="octo_x.png">files/images/px4/airframes/octo_x.png</file>
<file alias="px4fmu_2.x.png">files/images/px4/boards/px4fmu_2.x.png</file>
<file alias="SetupViewButtons.qml">src/VehicleSetup/SetupViewButtons.qml</file>
<file alias="VehicleSummary.qml">src/VehicleSetup/VehicleSummary.qml</file>
<file alias="FirmwareUpgrade.qml">src/VehicleSetup/FirmwareUpgrade.qml</file>
<file alias="SafetyComponent.qml">src/AutoPilotPlugins/PX4/SafetyComponent.qml</file>
<file alias="SensorsComponent.qml">src/AutoPilotPlugins/PX4/SensorsComponent.qml</file>
<file alias="FlightModesComponent.qml">src/AutoPilotPlugins/PX4/FlightModesComponent.qml</file>
<file alias="SafetyComponentSummary.qml">src/AutoPilotPlugins/PX4/SafetyComponentSummary.qml</file>
<file alias="SensorsComponentSummary.qml">src/AutoPilotPlugins/PX4/SensorsComponentSummary.qml</file>
<file alias="SensorsComponentSummaryFixedWing.qml">src/AutoPilotPlugins/PX4/SensorsComponentSummaryFixedWing.qml</file>
<file alias="RadioComponentSummary.qml">src/AutoPilotPlugins/PX4/RadioComponentSummary.qml</file>
<file alias="FlightModesComponentSummary.qml">src/AutoPilotPlugins/PX4/FlightModesComponentSummary.qml</file>
<file alias="AirframeComponentSummary.qml">src/AutoPilotPlugins/PX4/AirframeComponentSummary.qml</file>
<file alias="SafetyComponentTree.png">src/AutoPilotPlugins/PX4/Images/SafetyComponentTree.png</file>
<file alias="SafetyComponentHome.png">src/AutoPilotPlugins/PX4/Images/SafetyComponentHome.png</file>
<file alias="SafetyComponentArrowDown.png">src/AutoPilotPlugins/PX4/Images/SafetyComponentArrowDown.png</file>
......@@ -288,6 +297,7 @@
<file alias="VehicleRight.png">src/AutoPilotPlugins/PX4/Images/VehicleRight.png</file>
<file alias="VehicleNoseDown.png">src/AutoPilotPlugins/PX4/Images/VehicleNoseDown.png</file>
<file alias="VehicleTailDown.png">src/AutoPilotPlugins/PX4/Images/VehicleTailDown.png</file>
<file alias="QGroundControl/Controls/subMenuButtonImage.png">files/Setup/cogwheels.png</file>
<file alias="QGroundControl/Controls/SensorsComponentIcon.png">src/AutoPilotPlugins/PX4/Images/SensorsComponentIcon.png</file>
<file alias="QGroundControl/Controls/RadioComponentIcon.png">src/AutoPilotPlugins/PX4/Images/RadioComponentIcon.png</file>
......@@ -296,6 +306,7 @@
<file alias="QGroundControl/Controls/SafetyComponentIcon.png">src/AutoPilotPlugins/PX4/Images/SafetyComponentIcon.png</file>
<file alias="QGroundControl/Controls/FirmwareUpgradeIcon.png">src/VehicleSetup/FirmwareUpgradeIcon.png</file>
<file alias="QGroundControl/Controls/VehicleSummaryIcon.png">src/VehicleSetup/VehicleSummaryIcon.png</file>
<file alias="MainToolBar.qml">src/ui/toolbar/MainToolBar.qml</file>
</qresource>
<qresource prefix="/AutoPilotPlugins/PX4">
......
......@@ -25,8 +25,8 @@
/// @author Don Gagne <don@thegagnes.com>
#include "FlightModesComponent.h"
#include "FlightModeConfig.h"
#include "PX4AutoPilotPlugin.h"
#include "QGCQmlWidgetHolder.h"
struct SwitchListItem {
const char* param;
......@@ -111,7 +111,14 @@ QStringList FlightModesComponent::paramFilterList(void) const
QWidget* FlightModesComponent::setupWidget(void) const
{
return new FlightModeConfig();
QGCQmlWidgetHolder* holder = new QGCQmlWidgetHolder();
Q_CHECK_PTR(holder);
holder->setAutoPilot(_autopilot);
holder->setSource(QUrl::fromUserInput("qrc:/qml/FlightModesComponent.qml"));
return holder;
}
QUrl FlightModesComponent::summaryQmlSource(void) const
......
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.Controls 1.0
import QGroundControl.Controllers 1.0
Item {
Loader {
property FlightModesComponentController controller: FlightModesComponentController { }
property QGCPalette qgcPal: QGCPalette { colorGroupEnabled: true }
property bool loading: true
anchors.fill: parent
sourceComponent: controller.validConfiguration ? validComponent : invalidComponent
onLoaded: loading = false
}
Component {
id: validComponent
Rectangle {
Fact { id: rc_map_throttle; name: "RC_MAP_THROTTLE" }
Fact { id: rc_map_yaw; name: "RC_MAP_YAW" }
Fact { id: rc_map_pitch; name: "RC_MAP_PITCH" }
Fact { id: rc_map_roll; name: "RC_MAP_ROLL" }
Fact { id: rc_map_flaps; name: "RC_MAP_FLAPS" }
Fact { id: rc_map_aux1; name: "RC_MAP_AUX1" }
Fact { id: rc_map_aux2; name: "RC_MAP_AUX2" }
Fact { id: rc_map_mode_sw; name: "RC_MAP_MODE_SW" }
Fact { id: rc_map_posctl_sw; name: "RC_MAP_POSCTL_SW" }
Fact { id: rc_map_return_sw; name: "RC_MAP_RETURN_SW" }
Fact { id: rc_map_loiter_sw; name: "RC_MAP_LOITER_SW" }
Fact { id: rc_assist_th; name: "RC_ASSIST_TH" }
Fact { id: rc_posctl_th; name: "RC_POSCTL_TH" }
Fact { id: rc_auto_th; name: "RC_AUTO_TH" }
Fact { id: rc_loiter_th; name: "RC_LOITER_TH" }
Fact { id: rc_return_th; name: "RC_RETURN_TH" }
Fact { id: rc_chan_cnt; name: "RC_CHAN_CNT" }
Fact { id: rc_th_user; name: "RC_TH_USER" }
property int throttleChannel: rc_map_throttle.value
property int yawChannel: rc_map_yaw.value
property int pitchChannel: rc_map_pitch.value
property int rollChannel: rc_map_roll.value
property int flapsChannel: rc_map_flaps.value
property int aux1Channel: rc_map_aux1.value
property int aux2Channel: rc_map_aux2.value
property int modeChannel: rc_map_mode_sw.value
property int posCtlChannel: rc_map_posctl_sw.value
property int returnChannel: rc_map_return_sw.value
property int loiterChannel: rc_map_loiter_sw.value
property real rcThUserValue: rc_th_user.value
readonly property int channelCount: controller.channelCount
property bool inRedistribution: false
readonly property int tileWidth: 150
readonly property int tileHeight: 30
readonly property int progressBarHeight: 200
anchors.fill: parent
color: qgcPal.window
Component {
id: dragHandle
Item {
id: outerItem
width: parent.width
height: parent.height
Column {
x: 4
y: 4
spacing: 3
Repeater {
model: (outerItem.height - 8) / 4
Rectangle {
color: qgcPal.text
width: 15
height: 1
}
}
}
}
}
// This component is used to create draggable tiles for unassigned mode switches. It also
// creates the drop area for dragging an assigned mode switch tile back to an unassigned state.
// The following properties must be set in the Loader:
// tileLabel - label for tile
// tileParam - parameter to load from
// tileDragEnabled - true: this tile can be dragged
Component {
id: unassignedModeTileComponent
Rectangle {
Fact { id: fact; name: tileParam }
property bool dragEnabled: fact.value == 0
id: outerRect
width: tileWidth
height: tileHeight
color: qgcPal.windowShadeDark
border.width: dragEnabled ? 1 : 0
border.color: qgcPal.text
Drag.active: mouseArea.drag.active
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
Drag.keys: [ "unassigned"]
states: [
State {
when: dropArea.containsDrag
PropertyChanges {
target: outerRect
color: "red"
}
}
]
Loader {
width: parent.width
height: parent.height
visible: dragEnabled
sourceComponent: dragHandle
}
QGCLabel {
width: parent.width
height: parent.height
text: tileLabel
enabled: dragEnabled
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
MouseArea {
id: mouseArea
width: parent.width
height: parent.height
drag.target: dragEnabled ? parent : null
onReleased: {
// Move tile back to original position
parent.x = 0; parent.y = 0;
// If dropped over a channel target remap switch
if (parent.Drag.target && parent.Drag.target.dropAllowed) {
fact.value = parent.Drag.target.channel
}
}
}
DropArea {
// This will cause to tile to go back to unassigned if dropped here
readonly property int channel: 0
property bool dropAllowed: true
id: dropArea
width: parent.width
height: parent.height
keys: [ "assigned" ]
}
}
}
// This component is used to create draggable tiles for currently assigned mode switches. The following
// properties must be set in the Loader:
// tileLabel - label for tile
// tileVisible - visibility for tile
// tileDragEnabled - true: this tile can be dragged
// tileParam - parameter to load from
Component {
id: assignedModeTileComponent
Rectangle {
Fact { id: fact; name: tileDragEnabled ? tileParam : "" }
width: tileWidth
height: tileHeight
color: qgcPal.windowShadeDark
border.width: tileDragEnabled ? 1 : 0
border.color: qgcPal.text
visible: tileVisible
Drag.active: mouseArea.drag.active
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
Drag.keys: [ "assigned" ]
Loader {
width: parent.width
height: parent.height
visible: tileDragEnabled
sourceComponent: dragHandle
}
QGCLabel {
width: parent.width
height: parent.height
enabled: tileDragEnabled
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: tileLabel
}
MouseArea {
id: mouseArea
width: parent.width
height: parent.height
drag.target: tileDragEnabled ? parent : null
onReleased: {
// Move tile back to original position
parent.x = 0; parent.y = 0;
// If dropped over a channel target remap switch
if (parent.Drag.target && parent.Drag.target.dropAllowed) {
fact.value = parent.Drag.target.channel
}
}
}
}
}
onModeChannelChanged: if (!inRedistribution) redistributeThresholds()
onReturnChannelChanged: if (!inRedistribution) redistributeThresholds()
onLoiterChannelChanged: if (!inRedistribution) redistributeThresholds()
onPosCtlChannelChanged: if (!inRedistribution) redistributeThresholds()
onRcThUserValue: if (!inRedistribution) redistributeThresholds()
function redistributeThresholds() {
if (loading || rcThUserValue != 0) {
// User is specifying thresholds, do not auto-calculate
return
}
if (modeChannel != 0) {
var positions = 3 // Manual/Assist/Auto always exist
var returnOnModeSwitch = modeChannel == returnChannel
var loiterOnModeSwitch = modeChannel == loiterChannel
var posCtlOnModeSwitch = modeChannel == posCtlChannel
positions += returnOnModeSwitch ? 1 : 0
positions += loiterOnModeSwitch ? 1 : 0
positions += posCtlOnModeSwitch ? 1 : 0
var increment = 1.0 / positions
var currentThreshold = 0.0
// Make sure we don't re-enter
inRedistribution = true
currentThreshold += increment
rc_assist_th.value = currentThreshold
if (posCtlOnModeSwitch) {
currentThreshold += increment
rc_posctl_th.value = currentThreshold
}
currentThreshold += increment
rc_auto_th.value = currentThreshold
if (loiterOnModeSwitch) {
currentThreshold += increment
rc_loiter_th.value = currentThreshold
}
if (returnOnModeSwitch) {
currentThreshold += increment
rc_return_th.value = currentThreshold
}
inRedistribution = false
}
if (returnChannel != 0 && returnChannel != modeChannel) {
var positions = 2 // On/off always exist
var loiterOnReturnSwitch = returnChannel == loiterChannel
positions += loiterOnReturnSwitch ? 1 : 0
var increment = 1.0 / positions
var currentThreshold = 0.0
if (positions == 2) {
// If only two positions don't set threshold at midrange. Setting to 0.25
// allows for this channel to work with either two or three position switch
increment = 0.25
}
// Make sure we don't re-enter
inRedistribution = true
if (loiterOnReturnSwitch) {
currentThreshold += increment
rc_loiter_th.value = currentThreshold
}
currentThreshold += increment
rc_return_th.value = currentThreshold
inRedistribution = false
}
if (loiterChannel != 0 && loiterChannel != modeChannel && loiterChannel != returnChannel) {
// If only two positions don't set threshold at midrange. Setting to 0.25
// allows for this channel to work with either two or three position switch
var increment = 0.25
var currentThreshold = 0.0
// Make sure we don't re-enter
inRedistribution = true
currentThreshold += increment
rc_loiter_th.value = currentThreshold
inRedistribution = false
}
if (posCtlChannel != 0 & posCtlChannel != modeChannel) {
// If only two positions don't set threshold at midrange. Setting to 0.25
// allows for this channel to work with either two or three position switch
var increment = 0.25
var currentThreshold = 0.0
// Make sure we don't re-enter
inRedistribution = true
currentThreshold += increment
rc_posctl_th.value = currentThreshold
inRedistribution = false
}
}
Column {
anchors.fill: parent
QGCLabel {
text: "FLIGHT MODES CONFIG"
font.pointSize: 20
}
Item { height: 20; width: 10 } // spacer
QGCLabel {
width: parent.width
text: "Flight Mode switches can be assigned to any channel which is not currently being used for attitude control. All channels are displayed below. " +
"You can drag Flight Modes from the Flight Modes section below to a channel and drop it there. You can also drag switches assigned to a channel " +
"to another channel or back to the Unassigned Switches section. The Switch Display section at the very bottom will show you the results of your Flight Mode setup."
wrapMode: Text.WordWrap
}
Item { height: 20; width: 10 } // spacer
QGCLabel {
text: "Channel Assignments"
}
Flow {
width: parent.width
spacing: 5
Repeater {
model: channelCount
Rectangle {
property int channel: modelData + 1
property bool throttleMapped: channel == throttleChannel
property bool yawMapped: channel == yawChannel
property bool pitchMapped: channel == pitchChannel
property bool rollMapped: channel == rollChannel
property bool flapsMapped: channel == flapsChannel
property bool aux1Mapped: channel == aux1Channel
property bool aux2Mapped: channel == aux2Channel
property bool modeMapped: channel == modeChannel
property bool posCtlMapped: channel == posCtlChannel
property bool returnMapped: channel == returnChannel
property bool loiterMapped: channel == loiterChannel
property bool nonFlightModeMapping: throttleMapped | yawMapped | pitchMapped | rollMapped | flapsMapped | aux1Mapped | aux2Mapped
property bool unassignedMapping: !(nonFlightModeMapping | modeMapped | posCtlMapped | returnMapped | loiterMapped)
id: channelTarget
width: tileWidth
height: channelCol.implicitHeight
color: qgcPal.windowShadeDark
states: [
State {
when: dropArea.containsDrag && dropArea.dropAllowed
PropertyChanges {
target: channelHeader
color: "red"
}
}
]
Column {
id: channelCol
spacing: 3
Rectangle {
id: channelHeader
width: tileWidth
height: tileHeight
color: qgcPal.windowShade
QGCLabel {
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: "Channel " + (modelData + 1) + (nonFlightModeMapping ? ": Unavailable" : "")
}
}
Loader {
property string tileLabel: "Available"
property bool tileVisible: visible
property bool tileDragEnabled: false
visible: unassignedMapping
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "Throttle"
property bool tileVisible: visible
property bool tileDragEnabled: false
visible: throttleMapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "Yaw"
property bool tileVisible: visible
property bool tileDragEnabled: false
visible: yawMapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "Pitch"
property bool tileVisible: visible
property bool tileDragEnabled: false
visible: pitchMapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "Roll"
property bool tileVisible: visible
property bool tileDragEnabled: false
visible: rollMapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "Flaps Switch"
property bool tileVisible: visible
property bool tileDragEnabled: false
visible: flapsMapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "Aux1 Switch"
property bool tileVisible: visible
property bool tileDragEnabled: false
visible: aux1Mapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "Aux2 Switch"
property bool tileVisible: visible
property bool tileDragEnabled: false
visible: aux2Mapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "Main Mode"
property bool tileVisible: visible
property bool tileDragEnabled: true
property string tileParam: "RC_MAP_MODE_SW"
visible: modeMapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "Return"
property bool tileVisible: visible
property bool tileDragEnabled: true
property string tileParam: "RC_MAP_RETURN_SW"
visible: returnMapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "Loiter"
property bool tileVisible: visible
property bool tileDragEnabled: true
property string tileParam: "RC_MAP_LOITER_SW"
visible: loiterMapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "PosCtl"
property bool tileVisible: visible
property bool tileDragEnabled: true
property string tileParam: "RC_MAP_POSCTL_SW"
visible: posCtlMapped
sourceComponent: assignedModeTileComponent
}
}
DropArea {
// Drops are not allowed on channels which are mapped to non-flight mode switches
property bool dropAllowed: !nonFlightModeMapping
property int channel: parent.channel
id: dropArea
width: parent.width
height: parent.height
keys: [ "unassigned", "assigned" ]
}
}
}
}
Item { height: 20; width: 10 } // spacer
Row {
spacing: 5
QGCLabel {
text: "Flight Modes"
}
QGCLabel {
text: "(Mode Switch must be assigned to channel before flight is allowed)"
visible: rc_map_mode_sw.value == 0
}
}
Flow {
width: parent.width
spacing: 5
Loader {
property string tileLabel: "Main Mode"
property string tileParam: "RC_MAP_MODE_SW"
sourceComponent: unassignedModeTileComponent
}
Loader {
property string tileLabel: "Return"
property string tileParam: "RC_MAP_RETURN_SW"
sourceComponent: unassignedModeTileComponent
}
Loader {
property string tileLabel: "Loiter"
property string tileParam: "RC_MAP_LOITER_SW"
sourceComponent: unassignedModeTileComponent
}
Loader {
property string tileLabel: "PosCtl"
property string tileParam: "RC_MAP_POSCTL_SW"
sourceComponent: unassignedModeTileComponent
}
}
Item { height: 20; width: 10 } // spacer
FactCheckBox {
checkedValue: 0
uncheckedValue: 1
fact: rc_th_user
text: "Allow setup to generate the thresholds for the flight mode positions within a switch (recommended)"
}
Item { height: 20; width: 10 } // spacer
Row {
spacing: 20
QGCLabel {
text: "Switch Display"
}
QGCCheckBox {
checked: controller.sendLiveRCSwitchRanges
text: "Show live RC display"
onClicked: {
controller.sendLiveRCSwitchRanges = checked
}
}
}
Item { height: 20; width: 10 } // spacer
Row {
property bool modeSwitchVisible: modeChannel != 0
property bool returnSwitchVisible: returnChannel != 0 && returnChannel != modeChannel
property bool loiterSwitchVisible: loiterChannel != 0 && loiterChannel != modeChannel && loiterChannel != returnChannel
property bool posCtlSwitchVisible: posCtlChannel != 0 && posCtlChannel != modeChannel
width: parent.width
spacing: 20
Column {
visible: parent.modeSwitchVisible
QGCLabel { text: "Mode Switch" }
Row {
Item {
height: progressBarHeight
width: 150
QGCLabel {
width: parent.width
y: (parent.height * (1.0 - rc_auto_th.value)) - (implicitHeight / 2)
visible: modeChannel != returnChannel && modeChannel != loiterChannel
horizontalAlignment: Text.AlignRight
text: "Auto"
}
QGCLabel {
width: parent.width
y: (parent.height * (1.0 - rc_return_th.value)) - (implicitHeight / 2)
visible: modeChannel == returnChannel
horizontalAlignment: Text.AlignRight
text: "Auto: Return"
}
QGCLabel {
width: parent.width
y: (parent.height * (1.0 - rc_loiter_th.value)) - (implicitHeight / 2)
visible: modeChannel == loiterChannel
horizontalAlignment: Text.AlignRight
text: "Auto: Loiter"
}
QGCLabel {
width: parent.width
y: (parent.height * (1.0 - rc_auto_th.value)) - (implicitHeight / 2)
visible: modeChannel == loiterChannel
horizontalAlignment: Text.AlignRight
text: "Auto: Mission"
}
QGCLabel {
width: parent.width
y: (parent.height * (1.0 - rc_auto_th.value)) - (implicitHeight / 2)
visible: modeChannel == returnChannel && modeChannel != loiterChannel
horizontalAlignment: Text.AlignRight
text: "Auto: Loiter/Mission"
}
QGCLabel {
width: parent.width
y: (parent.height * (1.0 - rc_assist_th.value)) - (implicitHeight / 2)
visible: modeChannel != posCtlChannel
horizontalAlignment: Text.AlignRight
text: "Assist"
}
QGCLabel {
width: parent.width
y: (parent.height * (1.0 - rc_posctl_th.value)) - (implicitHeight / 2)
visible: modeChannel == posCtlChannel
horizontalAlignment: Text.AlignRight
text: "Assist: PosCtl"
}
QGCLabel {
width: parent.width
y: (parent.height * (1.0 - rc_assist_th.value)) - (implicitHeight / 2)
visible: modeChannel == posCtlChannel
horizontalAlignment: Text.AlignRight
text: "Assist: AltCtl"
}
QGCLabel {
width: parent.width
y: parent.height - (implicitHeight / 2)
text: "Manual"
horizontalAlignment: Text.AlignRight
}
}
ProgressBar {
height: progressBarHeight
orientation: Qt.Vertical
value: controller.modeSwitchLiveRange
}
}
}
Column {
visible: parent.returnSwitchVisible
QGCLabel { text: "Return Switch" }
Row {
Item {
height: progressBarHeight
width: 150
QGCLabel {
width: parent.width
y: (parent.height * (1.0 - rc_return_th.value)) - (implicitHeight / 2)
horizontalAlignment: Text.AlignRight
text: "Auto: Return"
}
QGCLabel {
width: parent.width
y: (parent.height * (1.0 - rc_loiter_th.value)) - (implicitHeight / 2)
visible: returnChannel == loiterChannel
horizontalAlignment: Text.AlignRight
text: "Auto: Loiter"
}
QGCLabel {
width: parent.width
y: parent.height - (implicitHeight / 2)
visible: returnChannel == loiterChannel
horizontalAlignment: Text.AlignRight
text: "Auto: Mission"
}
QGCLabel {
width: parent.width
y: parent.height - (implicitHeight / 2)
visible: returnChannel != loiterChannel
horizontalAlignment: Text.AlignRight
text: "Auto: Return Off"
}
}
ProgressBar {
height: progressBarHeight
orientation: Qt.Vertical
value: controller.returnSwitchLiveRange
}
}
}
Column {
visible: parent.loiterSwitchVisible
QGCLabel { text: "Loiter Switch" }
Row {
Item {
height: progressBarHeight
width: 150
QGCLabel {
width: parent.width
y: (parent.height * (1.0 - rc_loiter_th.value)) - (implicitHeight / 2)
horizontalAlignment: Text.AlignRight
text: "Auto: Loiter"
}
QGCLabel {
width: parent.width
y: parent.height - (implicitHeight / 2)
horizontalAlignment: Text.AlignRight
text: "Auto: Mission"
}
}
ProgressBar {
height: progressBarHeight
orientation: Qt.Vertical
value: controller.loiterSwitchLiveRange
}
}
}
Column {
visible: parent.posCtlSwitchVisible
QGCLabel { text: "PosCtl Switch" }
Row {
Item {
height: progressBarHeight
width: 150
QGCLabel {
width: parent.width
y: (parent.height * (1.0 - rc_posctl_th.value)) - (implicitHeight / 2)
horizontalAlignment: Text.AlignRight
text: "Assist: PosCtl"
}
QGCLabel {
width: parent.width
y: parent.height - (implicitHeight / 2)
horizontalAlignment: Text.AlignRight
text: "Assist: AltCtl"
}
}
ProgressBar {
height: progressBarHeight
orientation: Qt.Vertical
value: controller.posCtlSwitchLiveRange
}
}
}
}
}
}
}
Component {
id: invalidComponent
Rectangle {
anchors.fill: parent
color: qgcPal.window
Column {
width: parent.width
spacing: 20
QGCLabel {
text: "FLIGHT MODES CONFIG"
font.pointSize: 20
}
QGCLabel {
width: parent.width
wrapMode: Text.WordWrap
text: "There are errors in your current configuration which will need to be fixed before you can used Flight Config setup. " +
"You will need to change Parameters directly using Parameters Setup to remove these errors."
}
QGCLabel {
width: parent.width
wrapMode: Text.WordWrap
text: controller.configurationErrors
}
}
}
}
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include "FlightModesComponentController.h"
#include "QGCMAVLink.h"
#include "UASManager.h"
#include "AutoPilotPluginManager.h"
#include <QVariant>
#include <QQmlProperty>
FlightModesComponentController::FlightModesComponentController(QObject* parent) :
QObject(parent),
_liveRCValues(false),
_validConfiguration(false),
_channelCount(18),
_autoPilotPlugin(NULL)
{
_uas = UASManager::instance()->getActiveUAS();
Q_ASSERT(_uas);
_autoPilotPlugin = AutoPilotPluginManager::instance()->getInstanceForAutoPilotPlugin(_uas);
Q_ASSERT(_autoPilotPlugin);
Q_ASSERT(_autoPilotPlugin->pluginIsReady());
_initRcValues();
_validateConfiguration();
}
FlightModesComponentController::~FlightModesComponentController()
{
setSendLiveRCSwitchRanges(false);
}
void FlightModesComponentController::_initRcValues(void)
{
for (int i=0; i<_chanMax; i++) {
_rcValues << 1.0;
}
}
/// This will look for parameter settings which would cause the config to not run correctly.
/// It will set _validConfiguration and _configurationErrors as needed.
void FlightModesComponentController::_validateConfiguration(void)
{
_validConfiguration = true;
_channelCount = _autoPilotPlugin->factExists("RC_CHAN_CNT") ? _autoPilotPlugin->getFact("RC_CHAN_CNT")->value().toInt() : 18;
// Make sure switches are valid and within channel range
QStringList switchParams, switchNames;
QList<int> switchMappings;
switchParams << "RC_MAP_MODE_SW" << "RC_MAP_RETURN_SW" << "RC_MAP_LOITER_SW" << "RC_MAP_POSCTL_SW";
switchNames << "Mode Switch" << "Return Switch" << "Loiter Switch" << "PosCtl Switch";
for(int i=0; i<switchParams.count(); i++) {
int map = _autoPilotPlugin->getFact(switchParams[i])->value().toInt();
switchMappings << map;
if (map < 0 || map > _channelCount) {
_validConfiguration = false;
_configurationErrors += QString("%1 is set to %2. Mapping must between 0 and %3 (inclusive).\n").arg(switchNames[i]).arg(map).arg(_channelCount);
}
}
// Make sure switches are not mapped to attitude control channels
QStringList attitudeParams, attitudeNames;
attitudeParams << "RC_MAP_THROTTLE" << "RC_MAP_YAW" << "RC_MAP_PITCH" << "RC_MAP_ROLL" << "RC_MAP_FLAPS" << "RC_MAP_AUX1" << "RC_MAP_AUX2";
attitudeNames << "Throttle" << "Yaw" << "Pitch" << "Roll" << "Flaps" << "Aux1" << "Aux2";
for (int i=0; i<attitudeParams.count(); i++) {
int map = _autoPilotPlugin->getFact(attitudeParams[i])->value().toInt();
for (int j=0; j<switchParams.count(); j++) {
if (map != 0 && map == switchMappings[j]) {
_validConfiguration = false;
_configurationErrors += QString("%1 is set to same channel as %2.\n").arg(switchNames[j]).arg(attitudeNames[i]);
}
}
}
}
void FlightModesComponentController::setSendLiveRCSwitchRanges(bool start)
{
if (start) {
// We need to know min and max for channel in order to calculate percentage range
for (int i=0; i<_chanMax; i++) {
QString rcMinParam, rcMaxParam, rcRevParam;
rcMinParam = QString("RC%1_MIN").arg(i+1);
rcMaxParam = QString("RC%1_MAX").arg(i+1);
rcRevParam = QString("RC%1_REV").arg(i+1);
QVariant value;
_rgRCMin[i] = _autoPilotPlugin->getFact(rcMinParam)->value().toInt();
_rgRCMax[i] = _autoPilotPlugin->getFact(rcMaxParam)->value().toInt();
float floatReversed = _autoPilotPlugin->getFact(rcRevParam)->value().toFloat();
_rgRCReversed[i] = floatReversed == -1.0f;
}
_uas->startRadioControlCalibration();
connect(_uas, &UASInterface::remoteControlChannelRawChanged, this, &FlightModesComponentController::_remoteControlChannelRawChanged);
} else {
disconnect(_uas, &UASInterface::remoteControlChannelRawChanged, this, &FlightModesComponentController::_remoteControlChannelRawChanged);
_uas->endRadioControlCalibration();
_initRcValues();
emit switchLiveRangeChanged();
}
}
/// @brief This routine is called whenever a raw value for an RC channel changes.
/// @param chan RC channel on which signal is coming from (0-based)
/// @param fval Current value for channel
void FlightModesComponentController::_remoteControlChannelRawChanged(int chan, float fval)
{
Q_ASSERT(chan >= 0 && chan <= _chanMax);
if (fval < _rgRCMin[chan]) {
fval= _rgRCMin[chan];
}
if (fval > _rgRCMax[chan]) {
fval= _rgRCMax[chan];
}
float percentRange = (fval - _rgRCMin[chan]) / (float)(_rgRCMax[chan] - _rgRCMin[chan]);
if (_rgRCReversed[chan]) {
percentRange = 1.0 - percentRange;
}
_rcValues[chan] = percentRange;
emit switchLiveRangeChanged();
}
double FlightModesComponentController::_switchLiveRange(const QString& param)
{
QVariant value;
int channel = _autoPilotPlugin->getFact(param)->value().toInt();
if (channel == 0) {
return 1.0;
} else {
return _rcValues[channel - 1];
}
}
double FlightModesComponentController::modeSwitchLiveRange(void)
{
return _switchLiveRange("RC_MAP_MODE_SW");
}
double FlightModesComponentController::returnSwitchLiveRange(void)
{
return _switchLiveRange("RC_MAP_RETURN_SW");
}
double FlightModesComponentController::loiterSwitchLiveRange(void)
{
return _switchLiveRange("RC_MAP_LOITER_SW");
}
double FlightModesComponentController::posCtlSwitchLiveRange(void)
{
return _switchLiveRange("RC_MAP_POSCTL_SW");
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#ifndef FLIGHTMODESCOMPONENTCONTROLLER_H
#define FLIGHTMODESCOMPONENTCONTROLLER_H
#include <QObject>
#include <QQuickItem>
#include <QList>
#include "UASInterface.h"
#include "AutoPilotPlugin.h"
/// MVC Controller for FlightModesComponent.qml.
class FlightModesComponentController : public QObject
{
Q_OBJECT
public:
FlightModesComponentController(QObject* parent = NULL);
~FlightModesComponentController();
Q_PROPERTY(bool validConfiguration MEMBER _validConfiguration CONSTANT)
Q_PROPERTY(QString configurationErrors MEMBER _configurationErrors CONSTANT)
Q_PROPERTY(int channelCount MEMBER _channelCount CONSTANT)
Q_PROPERTY(double modeSwitchLiveRange READ modeSwitchLiveRange NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double returnSwitchLiveRange READ returnSwitchLiveRange NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double loiterSwitchLiveRange READ loiterSwitchLiveRange NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double posCtlSwitchLiveRange READ posCtlSwitchLiveRange NOTIFY switchLiveRangeChanged)
Q_PROPERTY(bool sendLiveRCSwitchRanges READ sendLiveRCSwitchRanges WRITE setSendLiveRCSwitchRanges NOTIFY liveRCSwitchRangesChanged)
double modeSwitchLiveRange(void);
double returnSwitchLiveRange(void);
double loiterSwitchLiveRange(void);
double posCtlSwitchLiveRange(void);
bool sendLiveRCSwitchRanges(void) { return _liveRCValues; }
void setSendLiveRCSwitchRanges(bool start);
signals:
void switchLiveRangeChanged(void);
void liveRCSwitchRangesChanged(void);
private slots:
void _remoteControlChannelRawChanged(int chan, float fval);
private:
double _switchLiveRange(const QString& param);
void _initRcValues(void);
void _validateConfiguration(void);
static const int _chanMax = 18;
UASInterface* _uas;
QList<double> _rcValues;
bool _liveRCValues;
int _rgRCMin[_chanMax];
int _rgRCMax[_chanMax];
bool _rgRCReversed[_chanMax];
bool _validConfiguration;
QString _configurationErrors;
int _channelCount;
AutoPilotPlugin* _autoPilotPlugin;
};
#endif
......@@ -26,7 +26,7 @@
#include "UASManager.h"
#include "QGCUASParamManagerInterface.h"
#include "PX4ParameterFacts.h"
#include "SensorsComponentController.h"
#include "FlightModesComponentController.h"
#include "QGCMessageBox.h"
/// @file
......@@ -74,6 +74,8 @@ PX4AutoPilotPlugin::PX4AutoPilotPlugin(UASInterface* uas, QObject* parent) :
{
Q_ASSERT(uas);
qmlRegisterType<FlightModesComponentController>("QGroundControl.Controllers", 1, 0, "FlightModesComponentController");
_parameterFacts = new PX4ParameterFacts(uas, this);
Q_CHECK_PTR(_parameterFacts);
......
......@@ -108,7 +108,7 @@ signals:
/// Signalled when property has been changed by a call to the property write accessor
///
/// This signal is meant for use by Fact container implementations.
void _containerValueChanged(QVariant& value);
void _containerValueChanged(const QVariant& value);
private:
QString _name;
......
......@@ -57,11 +57,7 @@ FactLoader::FactLoader(UASInterface* uas, QObject* parent) :
FactLoader::~FactLoader()
{
foreach(Fact* fact, _mapFact2ParameterName.keys()) {
delete fact;
}
_mapParameterName2Variant.clear();
_mapFact2ParameterName.clear();
}
/// Called whenever a parameter is updated or first seen.
......@@ -141,7 +137,7 @@ void FactLoader::_parameterUpdate(int uas, int component, QString parameterName,
/// Connected to Fact::valueUpdated
///
/// Sets the new value into the Parameter Manager. Parameter is persisted after send.
void FactLoader::_valueUpdated(QVariant value)
void FactLoader::_valueUpdated(const QVariant& value)
{
Fact* fact = qobject_cast<Fact*>(sender());
Q_ASSERT(fact);
......
......@@ -65,7 +65,7 @@ protected:
private slots:
void _parameterUpdate(int uas, int component, QString parameterName, int mavType, QVariant value);
void _valueUpdated(QVariant value);
void _valueUpdated(const QVariant& value);
void _paramMgrParameterListUpToDate(void);
private:
......
......@@ -389,22 +389,22 @@
1 50 RC1_MAX 2000 9
1 50 RC1_MIN 1000 9
1 50 RC1_REV 1 9
1 50 RC1_TRIM 1500 9
1 50 RC1_TRIM 1501 9
1 50 RC2_DZ 10 9
1 50 RC2_MAX 2000 9
1 50 RC2_MIN 1000 9
1 50 RC2_REV 1 9
1 50 RC2_TRIM 1500 9
1 50 RC2_TRIM 1501 9
1 50 RC3_DZ 10 9
1 50 RC3_MAX 2000 9
1 50 RC3_MIN 1000 9
1 50 RC3_REV 1 9
1 50 RC3_TRIM 1500 9
1 50 RC3_TRIM 1501 9
1 50 RC4_DZ 10 9
1 50 RC4_MAX 2000 9
1 50 RC4_MIN 1000 9
1 50 RC4_REV 1 9
1 50 RC4_TRIM 1500 9
1 50 RC4_TRIM 1501 9
1 50 RC5_DZ 10 9
1 50 RC5_MAX 2000 9
1 50 RC5_MIN 1000 9
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment