Commit d115de8a authored by Don Gagne's avatar Don Gagne

Merge pull request #1716 from DonLakeFlyer/FlightModeConfig

Flight Mode config redesign
parents 415e1642 8c82e9b0
......@@ -93,6 +93,7 @@
<file alias="QGroundControl/Controls/QGCViewMessage.qml">src/QmlControls/QGCViewMessage.qml</file>
<file alias="QGroundControl/Controls/ParameterEditor.qml">src/QmlControls/ParameterEditor.qml</file>
<file alias="QGroundControl/Controls/ParameterEditorDialog.qml">src/QmlControls/ParameterEditorDialog.qml</file>
<file alias="QGroundControl/Controls/ModeSwitchDisplay.qml">src/QmlControls/ModeSwitchDisplay.qml</file>
<file alias="ParameterEditorWidget.qml">src/ViewWidgets/ParameterEditorWidget.qml</file>
<file alias="CustomCommandWidget.qml">src/ViewWidgets/CustomCommandWidget.qml</file>
<file alias="SetupView.qml">src/VehicleSetup/SetupView.qml</file>
......
......@@ -21,974 +21,377 @@
======================================================================*/
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
import QGroundControl.ScreenTools 1.0
Item {
Loader {
id: loader
anchors.fill: parent
sourceComponent: controller.validConfiguration ? validComponent : invalidComponent
property FlightModesComponentController controller: FlightModesComponentController { factPanel: loader.item }
property QGCPalette qgcPal: QGCPalette { colorGroupEnabled: true }
property bool loading: true
onLoaded: loading = false
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
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
import QGroundControl.ScreenTools 1.0
QGCView {
id: rootQGCView
viewPanel: panel
readonly property int monitorThresholdCharWidth: 8 // Character width of Monitor and Threshold labels
// User visible strings
readonly property string topHelpText: "Assign Flight Modes to radio control channels and adjust the thresholds for triggering them. " +
"You can assign multiple flight modes to a single channel. " +
"Turn your radio control on to test switch settings."
readonly property string fwManualModeName: "Manual/Main"
readonly property string mrManualModeName: "Stabilized/Main"
readonly property string fwManualModeDescription: "The pilot has full control of the aircraft, no assistance is provided. " +
"The Main mode switch must always be assigned to a channel in order to fly"
readonly property string mrManualModeDescription: "Centering roll/pitch stick will return the multirotor to a level attitude, but it will continue drifting in the direction it was previously sent. " +
"Altitude is controlled fully by pilot using the Throttle stick. " +
"The Main mode switch must always be assigned to a channel in order to fly"
readonly property string assistModeName: "Assist"
readonly property string assistModeDescription: "If Position Control is placed on a seperate channel from the Main mode channel, an additional 'Assist' mode is added to the Main switch. " +
"In order for the Attitude Control/Position Control switch to be active, the Main switch must be in Assist mode."
readonly property string autoModeName: "Auto"
readonly property string autoModeDescription: "If Loiter is placed on a seperate channel from the Main mode channel, an additional 'Auto' mode is added to the Main switch. " +
"In order for the Mission/Loiter switch to be active, the Main switch must be in Auto mode."
readonly property string fwAcroModeName: "Stabilized"
readonly property string mrAcroModeName: "Acro"
readonly property string fwAcroModeDescription: "Need Stablized description"
readonly property string mrAcroModeDescription: "Need Acro mode description"
readonly property string fwAltCtlModeName: "Attitude Control"
readonly property string mrAltCtlModeName: "Altitude Control"
readonly property string fwAltCtlModeDescription: "Aileron and Elevator sticks affect roll and pitch according to the Attitude Control settings. " +
"Altitude is not maintained automatically. " +
"Rudder is controlled fully by the pilot."
readonly property string mrAltCtlModeDescription: "Same as Stablized mode except that Throttle controls climb/sink rate. Centered throttle holds altitude steady."
readonly property string posCtlModeName: "Position Control"
readonly property string fwPosCtlModeDescription: "Throttle controls speed, pitch controls climb/sink rate, roll controls yaw rate. " +
"Roll and Pitch centered gives level, straight-line flight. " +
"Position Control and Attitude Control must always be on the same channel."
readonly property string mrPosCtlModeDescription: "Roll and Pitch control left-right and front-back speed over ground respectively. " +
"When roll and pitch are centered, the multirotor will hold position. " +
"Yaw controls yaw rate as in Stablized mode. " +
"Throttle controls climb/sink rate. Centered throttle holds altitude steady. " +
"Position Control and Attitude Control must always be on the same channel."
readonly property string missionModeName: "Mission"
readonly property string missionModeDescription: "The aircraft obeys the programmed mission sent by QGroundControl. " +
"If no mission was sent, aircraft will loiter at current position instead."
readonly property string loiterModeName: "Loiter"
readonly property string fwLoiterModeDescription: "The aircraft flies in a circle around the current position at the current altitude. " +
"Loiter and Mission must always be on the same channel."
readonly property string mrLoiterModeDescription: "The multirotor hovers in a fixed position at the current position and altitude. " +
"Loiter and Mission must always be on the same channel."
readonly property string returnModeName: "Return"
readonly property string fwReturnModeDescription: "The aircraft returns to the home position and loiters above it." +
"The settings which control this sequence can be found under Setup - Safety."
readonly property string mrReturnModeDescription: "The multirotor returns to the home position, loiters and then lands. " +
"The settings which control this sequence can be found under Setup - Safety."
readonly property string offboardModeName: "Offboard"
readonly property string offboardModeDescription: "Offboard description"
readonly property real modeSpacing: ScreenTools.defaultFontPixelHeight / 3
QGCPalette { id: qgcPal; colorGroupEnabled: panel.enabled }
FlightModesComponentController {
id: controller
factPanel: panel
onModeRowsChanged: recalcModePositions()
}
Component {
id: validComponent
Timer {
interval: 200
running: true
FactPanel {
property Fact rc_map_throttle: controller.getParameterFact(-1, "RC_MAP_THROTTLE")
property Fact rc_map_yaw: controller.getParameterFact(-1, "RC_MAP_YAW")
property Fact rc_map_pitch: controller.getParameterFact(-1, "RC_MAP_PITCH")
property Fact rc_map_roll: controller.getParameterFact(-1, "RC_MAP_ROLL")
property Fact rc_map_flaps: controller.getParameterFact(-1, "RC_MAP_FLAPS")
property Fact rc_map_aux1: controller.getParameterFact(-1, "RC_MAP_AUX1")
property Fact rc_map_aux2: controller.getParameterFact(-1, "RC_MAP_AUX2")
property Fact rc_map_mode_sw: controller.getParameterFact(-1, "RC_MAP_MODE_SW")
property Fact rc_map_posctl_sw: controller.getParameterFact(-1, "RC_MAP_POSCTL_SW")
property Fact rc_map_return_sw: controller.getParameterFact(-1, "RC_MAP_RETURN_SW")
property Fact rc_map_offboard_sw: controller.getParameterFact(-1, "RC_MAP_OFFB_SW")
property Fact rc_map_loiter_sw: controller.getParameterFact(-1, "RC_MAP_LOITER_SW")
property Fact rc_map_acro_sw: controller.getParameterFact(-1, "RC_MAP_ACRO_SW")
property Fact rc_assist_th: controller.getParameterFact(-1, "RC_ASSIST_TH")
property Fact rc_posctl_th: controller.getParameterFact(-1, "RC_POSCTL_TH")
property Fact rc_auto_th: controller.getParameterFact(-1, "RC_AUTO_TH")
property Fact rc_loiter_th: controller.getParameterFact(-1, "RC_LOITER_TH")
property Fact rc_return_th: controller.getParameterFact(-1, "RC_RETURN_TH")
property Fact rc_offboard_th: controller.getParameterFact(-1, "RC_OFFB_TH")
property Fact rc_acro_th: controller.getParameterFact(-1, "RC_ACRO_TH")
property Fact rc_th_user: controller.getParameterFact(-1, "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 offboardChannel: rc_map_offboard_sw.value
property int loiterChannel: rc_map_loiter_sw.value
property int acroChannel: rc_map_acro_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
onTriggered: recalcModePositions()
}
Component {
id: dragHandle
function recalcModePositions() {
var spacing = ScreenTools.defaultFontPixelHeight / 2
var nextY = manualMode.y + manualMode.height + spacing
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
}
}
}
for (var index = 0; index < 9; index++) {
if (controller.assistModeRow == index) {
if (controller.assistModeVisible) {
assistMode.y = nextY
assistMode.z = 9 - index
nextY += assistMode.height + spacing
}
}
// 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 {
property Fact fact: controller.getParameterFact(-1, 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) {
if (!singleSwitchRequired || parent.Drag.target.unassignedChannel) {
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
property bool unassignedChannel: 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: nullFact }
property Fact fact: tileDragEnabled ? controller.getParameterFact(-1, tileParam) : nullFact
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) {
if (!singleSwitchRequired || parent.Drag.target.unassignedChannel) {
fact.value = parent.Drag.target.channel
}
}
}
}
} else if (controller.autoModeRow == index) {
if (controller.autoModeVisible) {
autoMode.y = nextY
autoMode.z = 9 - index
nextY += autoMode.height + spacing
}
} else if (controller.acroModeRow == index) {
acroMode.y = nextY
acroMode.z = 9 - index
nextY += acroMode.height + spacing
} else if (controller.altCtlModeRow == index) {
altCtlMode.y = nextY
altCtlMode.z = 9 - index
nextY += altCtlMode.height + spacing
} else if (controller.posCtlModeRow == index) {
posCtlMode.y = nextY
posCtlMode.z = 9 - index
nextY += posCtlMode.height + spacing
} else if (controller.loiterModeRow == index) {
loiterMode.y = nextY
loiterMode.z = 9 - index
nextY += loiterMode.height + spacing
} else if (controller.missionModeRow == index) {
missionMode.y = nextY
missionMode.z = 9 - index
nextY += missionMode.height + spacing
} else if (controller.returnModeRow == index) {
returnMode.y = nextY
returnMode.z = 9 - index
nextY += returnMode.height + spacing
} else if (controller.offboardModeRow == index) {
offboardMode.y = nextY
offboardMode.z = 9 - index
nextY += offboardMode.height + spacing
}
}
onModeChannelChanged: if (!inRedistribution) redistributeThresholds()
onReturnChannelChanged: if (!inRedistribution) redistributeThresholds()
onOffboardChannelChanged: if (!inRedistribution) redistributeThresholds()
onLoiterChannelChanged: if (!inRedistribution) redistributeThresholds()
onPosCtlChannelChanged: if (!inRedistribution) redistributeThresholds()
onAcroChannelChanged: 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 loiterOnModeSwitch = modeChannel == loiterChannel
var posCtlOnModeSwitch = modeChannel == posCtlChannel
var acroOnModeSwitch = modeChannel == acroChannel
positions += loiterOnModeSwitch ? 1 : 0
positions += posCtlOnModeSwitch ? 1 : 0
positions += acroOnModeSwitch ? 1 : 0
var increment = 1.0 / positions
var currentThreshold = 0.0
// Make sure we don't re-enter
inRedistribution = true
scrollItem.height = nextY
}
if (acroOnModeSwitch) {
currentThreshold += increment
rc_acro_th.value = currentThreshold
}
QGCViewPanel {
id: panel
anchors.fill: parent
currentThreshold += increment
rc_assist_th.value = currentThreshold
if (posCtlOnModeSwitch) {
currentThreshold += increment
rc_posctl_th.value = currentThreshold
}
ScrollView {
id: scroll
anchors.fill: parent
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
currentThreshold += increment
rc_auto_th.value = currentThreshold
if (loiterOnModeSwitch) {
currentThreshold += increment
rc_loiter_th.value = currentThreshold
}
Item {
id: scrollItem
width: scroll.viewport.width
inRedistribution = false
QGCLabel {
id: header
width: parent.width
font.pixelSize: ScreenTools.largeFontPixelSize
text: "FLIGHT MODES CONFIG"
}
if (returnChannel != 0) {
inRedistribution = true
// 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
rc_return_th.value = 0.25
inRedistribution = false
Item {
id: headingSpacer
anchors.top: header.bottom
height: 20
width: 20
}
if (offboardChannel != 0) {
inRedistribution = true
// 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
rc_offboard_th.value = 0.25
inRedistribution = false
QGCLabel {
anchors.top: headingSpacer.bottom
anchors.left: parent.left
anchors.rightMargin: ScreenTools.defaultFontPixelWidth
anchors.right: applyButton.left
text: topHelpText
wrapMode: Text.WordWrap
}
if (loiterChannel != 0 && loiterChannel != modeChannel) {
inRedistribution = true
QGCButton {
id: applyButton
anchors.top: headingSpacer.bottom
anchors.rightMargin: ScreenTools.defaultFontPixelWidth
anchors.right: parent.right
text: "Generate Thresholds"
// 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
rc_loiter_th.value = 0.25
inRedistribution = false
onClicked: controller.generateThresholds()
}
if (posCtlChannel != 0 & posCtlChannel != modeChannel) {
inRedistribution = true
// 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
rc_posctl_th.value = 0.25
inRedistribution = false
Item {
id: lastSpacer
anchors.top: applyButton.bottom
height: 20
width: 10
}
if (acroChannel != 0 & acroChannel != modeChannel) {
inRedistribution = true
// 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
rc_acro_th.value = 0.25
inRedistribution = false
ModeSwitchDisplay {
id: manualMode
anchors.top: lastSpacer.bottom
flightModeName: controller.fixedWing ? fwManualModeName : mrManualModeName
flightModeDescription: controller.fixedWing ? fwManualModeDescription : mrManualModeDescription
rcValue: controller.manualModeRcValue
modeChannelIndex: controller.manualModeChannelIndex
modeChannelEnabled: true
modeSelected: controller.manualModeSelected
thresholdValue: controller.manualModeThreshold
thresholdDragEnabled: false
onModeChannelIndexChanged: controller.manualModeChannelIndex = modeChannelIndex
}
}
Column {
anchors.fill: parent
QGCLabel {
text: "FLIGHT MODES CONFIG"
font.pixelSize: ScreenTools.largeFontPixelSize
ModeSwitchDisplay {
id: assistMode
visible: controller.assistModeVisible
flightModeName: assistModeName
flightModeDescription: assistModeDescription
rcValue: controller.assistModeRcValue
modeChannelIndex: controller.assistModeChannelIndex
modeChannelEnabled: false
modeSelected: controller.assistModeSelected
thresholdValue: controller.assistModeThreshold
thresholdDragEnabled: true
onThresholdValueChanged: controller.assistModeThreshold = thresholdValue
Behavior on y { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 1000 } }
}
Item { height: 20; width: 10 } // spacer
QGCLabel {
width: parent.width
text: "The Main Mode, Loiter, PostCtl and Acro switches can be assigned to any channel which is not currently being used for attitude control. The Return and Offboard switches must be assigned to their seperate channel. " +
"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
ModeSwitchDisplay {
id: autoMode
visible: controller.autoModeVisible
flightModeName: autoModeName
flightModeDescription: autoModeDescription
rcValue: controller.autoModeRcValue
modeChannelIndex: controller.autoModeChannelIndex
modeChannelEnabled: false
modeSelected: controller.autoModeSelected
thresholdValue: controller.autoModeThreshold
thresholdDragEnabled: true
onThresholdValueChanged: controller.autoModeThreshold = thresholdValue
Behavior on y { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 1000 } }
}
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 offboardMapped: channel == offboardChannel
property bool loiterMapped: channel == loiterChannel
property bool acroMapped: channel == acroChannel
property bool nonFlightModeMapping: throttleMapped | yawMapped | pitchMapped | rollMapped | flapsMapped | aux1Mapped | aux2Mapped
property bool unassignedMapping: !(nonFlightModeMapping | modeMapped | posCtlMapped | returnMapped | offboardMapped | loiterMapped | acroMapped)
property bool singleSwitchMapping: returnMapped | offboardMapped
id: channelTarget
width: tileWidth
height: channelCol.implicitHeight
color: qgcPal.windowShadeDark
states: [
State {
when: dropArea.containsDrag && dropArea.dropAllowed && (!dropArea.drag.source.singleSwitchRequired || dropArea.unassignedChannel)
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"
property bool singleSwitchRequired: false
visible: modeMapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "Return"
property bool tileVisible: visible
property bool tileDragEnabled: true
property string tileParam: "RC_MAP_RETURN_SW"
property bool singleSwitchRequired: true
visible: returnMapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "Offboard"
property bool tileVisible: visible
property bool tileDragEnabled: true
property string tileParam: "RC_MAP_OFFB_SW"
property bool singleSwitchRequired: true
visible: offboardMapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "Loiter"
property bool tileVisible: visible
property bool tileDragEnabled: true
property string tileParam: "RC_MAP_LOITER_SW"
property bool singleSwitchRequired: false
visible: loiterMapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "PosCtl"
property bool tileVisible: visible
property bool tileDragEnabled: true
property string tileParam: "RC_MAP_POSCTL_SW"
property bool singleSwitchRequired: false
visible: posCtlMapped
sourceComponent: assignedModeTileComponent
}
Loader {
property string tileLabel: "Acro/Stabilize"
property bool tileVisible: visible
property bool tileDragEnabled: true
property string tileParam: "RC_MAP_ACRO_SW"
property bool singleSwitchRequired: false
visible: acroMapped
sourceComponent: assignedModeTileComponent
}
}
DropArea {
// Drops are not allowed on channels which are mapped to non-flight mode switches
property bool dropAllowed: !nonFlightModeMapping && !singleSwitchMapping
property bool unassignedChannel: unassignedMapping
property int channel: parent.channel
id: dropArea
width: parent.width
height: parent.height
keys: [ "unassigned", "assigned" ]
}
}
}
ModeSwitchDisplay {
id: acroMode
flightModeName: controller.fixedWing ? fwAcroModeName : mrAcroModeName
flightModeDescription: controller.fixedWing ? fwAcroModeDescription : mrAcroModeDescription
rcValue: controller.acroModeRcValue
modeChannelIndex: controller.acroModeChannelIndex
modeChannelEnabled: true
modeSelected: controller.acroModeSelected
thresholdValue: controller.acroModeThreshold
thresholdDragEnabled: true
onModeChannelIndexChanged: controller.acroModeChannelIndex = modeChannelIndex
onThresholdValueChanged: controller.acroModeThreshold = thresholdValue
Behavior on y { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 1000 } }
}
Item { height: 20; width: 10 } // spacer
ModeSwitchDisplay {
id: altCtlMode
flightModeName: controller.fixedWing ? fwAltCtlModeName : mrAltCtlModeName
flightModeDescription: controller.fixedWing ? fwAltCtlModeDescription : mrAltCtlModeDescription
rcValue: controller.altCtlModeRcValue
modeChannelIndex: controller.altCtlModeChannelIndex
modeChannelEnabled: false
modeSelected: controller.altCtlModeSelected
thresholdValue: controller.altCtlModeThreshold
thresholdDragEnabled: !controller.assistModeVisible
Row {
spacing: 5
onThresholdValueChanged: controller.altCtlModeThreshold = thresholdValue
QGCLabel {
text: "Flight Modes"
}
QGCLabel {
text: "(Mode Switch must be assigned to channel before flight is allowed)"
visible: rc_map_mode_sw.value == 0
}
Behavior on y { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 1000 } }
}
Flow {
width: parent.width
spacing: 5
Loader {
property string tileLabel: "Main Mode"
property string tileParam: "RC_MAP_MODE_SW"
property bool singleSwitchRequired: false
sourceComponent: unassignedModeTileComponent
}
Loader {
property string tileLabel: "Loiter"
property string tileParam: "RC_MAP_LOITER_SW"
property bool singleSwitchRequired: false
sourceComponent: unassignedModeTileComponent
}
Loader {
property string tileLabel: "PosCtl"
property string tileParam: "RC_MAP_POSCTL_SW"
property bool singleSwitchRequired: false
sourceComponent: unassignedModeTileComponent
}
Loader {
property string tileLabel: "Acro/Stabilize"
property string tileParam: "RC_MAP_ACRO_SW"
property bool singleSwitchRequired: false
sourceComponent: unassignedModeTileComponent
}
Loader {
property string tileLabel: "Return"
property string tileParam: "RC_MAP_RETURN_SW"
property bool singleSwitchRequired: true
sourceComponent: unassignedModeTileComponent
}
Loader {
property string tileLabel: "Offboard"
property string tileParam: "RC_MAP_OFFB_SW"
property bool singleSwitchRequired: true
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)"
ModeSwitchDisplay {
id: posCtlMode
flightModeName: posCtlModeName
flightModeDescription: controller.fixedWing ? fwPosCtlModeDescription : mrPosCtlModeDescription
rcValue: controller.posCtlModeRcValue
modeChannelIndex: controller.posCtlModeChannelIndex
modeChannelEnabled: true
modeSelected: controller.posCtlModeSelected
thresholdValue: controller.posCtlModeThreshold
thresholdDragEnabled: true
onModeChannelIndexChanged: controller.posCtlModeChannelIndex = modeChannelIndex
onThresholdValueChanged: controller.posCtlModeThreshold = thresholdValue
Behavior on y { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 1000 } }
}
Item { height: 20; width: 10 } // spacer
ModeSwitchDisplay {
id: missionMode
flightModeName: missionModeName
flightModeDescription: missionModeDescription
rcValue: controller.missionModeRcValue
modeChannelIndex: controller.missionModeChannelIndex
modeChannelEnabled: false
modeSelected: controller.missionModeSelected
thresholdValue: controller.missionModeThreshold
thresholdDragEnabled: !controller.autoModeVisible
Row {
spacing: 20
onThresholdValueChanged: controller.missionModeThreshold = thresholdValue
QGCLabel {
text: "Switch Display"
}
QGCCheckBox {
checked: controller.sendLiveRCSwitchRanges
text: "Show live RC display"
onClicked: {
controller.sendLiveRCSwitchRanges = checked
}
}
Behavior on y { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 1000 } }
}
Item { height: 20; width: 10 } // spacer
Row {
property bool modeSwitchVisible: modeChannel != 0
property bool loiterSwitchVisible: loiterChannel != 0 && loiterChannel != modeChannel && loiterChannel != returnChannel
property bool posCtlSwitchVisible: posCtlChannel != 0 && posCtlChannel != modeChannel
property bool acroSwitchVisible: acroChannel != 0 && acroChannel != modeChannel
property bool returnSwitchVisible: returnChannel != 0
property bool offboardSwitchVisible: offboardChannel != 0
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_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 * (1.0 - rc_acro_th.value)) - (implicitHeight / 2)
visible: modeChannel == acroChannel
horizontalAlignment: Text.AlignRight
text: "Acro/Stabilize"
}
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.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
}
}
}
Column {
visible: parent.acroSwitchVisible
QGCLabel { text: "Acro/Stabilize Switch" }
Row {
Item {
height: progressBarHeight
width: 150
QGCLabel {
width: parent.width
y: (parent.height * (1.0 - rc_acro_th.value)) - (implicitHeight / 2)
horizontalAlignment: Text.AlignRight
text: "Acro/Stabilize"
}
QGCLabel {
width: parent.width
y: parent.height - (implicitHeight / 2)
horizontalAlignment: Text.AlignRight
text: "Manual"
}
}
ProgressBar {
height: progressBarHeight
orientation: Qt.Vertical
value: controller.acroSwitchLiveRange
}
}
}
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: "Return"
}
QGCLabel {
width: parent.width
y: parent.height - (implicitHeight / 2)
horizontalAlignment: Text.AlignRight
text: "Return Off"
}
}
ProgressBar {
height: progressBarHeight
orientation: Qt.Vertical
value: controller.returnSwitchLiveRange
}
}
}
Column {
visible: parent.offboardSwitchVisible
QGCLabel { text: "Offboard 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: "Offboard"
}
QGCLabel {
width: parent.width
y: parent.height - (implicitHeight / 2)
visible: returnChannel != loiterChannel
horizontalAlignment: Text.AlignRight
text: "Offboard Off"
}
}
ProgressBar {
height: progressBarHeight
orientation: Qt.Vertical
value: controller.offboardSwitchLiveRange
}
}
}
ModeSwitchDisplay {
id: loiterMode
flightModeName: loiterModeName
flightModeDescription: controller.fixedWing ? fwLoiterModeDescription : mrLoiterModeDescription
rcValue: controller.loiterModeRcValue
modeChannelIndex: controller.loiterModeChannelIndex
modeChannelEnabled: true
modeSelected: controller.loiterModeSelected
thresholdValue: controller.loiterModeThreshold
thresholdDragEnabled: true
onModeChannelIndexChanged: controller.loiterModeChannelIndex = modeChannelIndex
onThresholdValueChanged: controller.loiterModeThreshold = thresholdValue
Behavior on y { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 1000 } }
}
}
}
}
Component {
id: invalidComponent
FactPanel {
anchors.fill: parent
color: qgcPal.window
Column {
width: parent.width
spacing: 20
QGCLabel {
text: "FLIGHT MODES CONFIG"
font.pixelSize: ScreenTools.largeFontPixelSize
}
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."
ModeSwitchDisplay {
id: returnMode
flightModeName: returnModeName
flightModeDescription: controller.fixedWing ? fwReturnModeDescription : mrReturnModeDescription
rcValue: controller.returnModeRcValue
modeChannelIndex: controller.returnModeChannelIndex
modeChannelEnabled: true
modeSelected: controller.returnModeSelected
thresholdValue: controller.returnModeThreshold
thresholdDragEnabled: true
onModeChannelIndexChanged: controller.returnModeChannelIndex = modeChannelIndex
onThresholdValueChanged: controller.returnModeThreshold = thresholdValue
Behavior on y { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 1000 } }
}
QGCLabel {
width: parent.width
wrapMode: Text.WordWrap
text: controller.configurationErrors
ModeSwitchDisplay {
id: offboardMode
flightModeName: offboardModeName
flightModeDescription: offboardModeDescription
rcValue: controller.offboardModeRcValue
modeChannelIndex: controller.offboardModeChannelIndex
modeChannelEnabled: true
modeSelected: controller.offboardModeSelected
thresholdValue: controller.offboardModeThreshold
thresholdDragEnabled: true
onModeChannelIndexChanged: controller.offboardModeChannelIndex = modeChannelIndex
onThresholdValueChanged: controller.offboardModeThreshold = thresholdValue
Behavior on y { PropertyAnimation { easing.type: Easing.InOutQuad; duration: 1000 } }
}
}
}
}
}
} // Item
} // Scroll View
} // QGCViewPanel
} // QGCView
......@@ -33,31 +33,115 @@
#include <QQmlProperty>
FlightModesComponentController::FlightModesComponentController(void) :
_liveRCValues(false),
_validConfiguration(false),
_channelCount(18)
_channelCount(18),
_manualModeSelected(false),
_assistModeSelected(false),
_autoModeSelected(false),
_acroModeSelected(false),
_altCtlModeSelected(false),
_posCtlModeSelected(false),
_missionModeSelected(false),
_loiterModeSelected(false),
_returnModeSelected(false),
_offboardModeSelected(false)
{
QStringList usedParams;
usedParams << "RC_MAP_THROTTLE" << "RC_MAP_YAW" << "RC_MAP_PITCH" << "RC_MAP_ROLL" << "RC_MAP_FLAPS" << "RC_MAP_AUX1" << "RC_MAP_AUX2" << "RC_MAP_ACRO_SW";
usedParams << "RC_MAP_THROTTLE" << "RC_MAP_YAW" << "RC_MAP_PITCH" << "RC_MAP_ROLL" << "RC_MAP_FLAPS" << "RC_MAP_AUX1" << "RC_MAP_AUX2" <<
"RC_MAP_MODE_SW" << "RC_MAP_RETURN_SW" << "RC_MAP_LOITER_SW" << "RC_MAP_POSCTL_SW" << "RC_MAP_OFFB_SW" << "RC_MAP_ACRO_SW";
if (!_allParametersExists(FactSystem::defaultComponentId, usedParams)) {
return;
}
_initRcValues();
_init();
_validateConfiguration();
connect(_uas, &UASInterface::remoteControlChannelRawChanged, this, &FlightModesComponentController::_remoteControlChannelRawChanged);
}
FlightModesComponentController::~FlightModesComponentController()
{
setSendLiveRCSwitchRanges(false);
disconnect(_uas, &UASInterface::remoteControlChannelRawChanged, this, &FlightModesComponentController::_remoteControlChannelRawChanged);
}
void FlightModesComponentController::_initRcValues(void)
void FlightModesComponentController::_init(void)
{
for (int i=0; i<_chanMax; i++) {
_rcValues << 1.0;
// FIXME: What about VTOL? That confuses the whole Flight Mode naming scheme
_fixedWing = _uas->getSystemType() == MAV_TYPE_FIXED_WING;
// We need to know min and max for channel in order to calculate percentage range
for (int channel=0; channel<_chanMax; channel++) {
QString rcMinParam, rcMaxParam, rcRevParam;
rcMinParam = QString("RC%1_MIN").arg(channel+1);
rcMaxParam = QString("RC%1_MAX").arg(channel+1);
rcRevParam = QString("RC%1_REV").arg(channel+1);
QVariant value;
_rgRCMin[channel] = getParameterFact(FactSystem::defaultComponentId, rcMinParam)->value().toInt();
_rgRCMax[channel] = getParameterFact(FactSystem::defaultComponentId, rcMaxParam)->value().toInt();
float floatReversed = getParameterFact(-1, rcRevParam)->value().toFloat();
_rgRCReversed[channel] = floatReversed == -1.0f;
_rcValues[channel] = 0.0;
}
// RC_CHAN_CNT parameter is set by Radio Cal to specify the number of radio channels.
if (parameterExists(FactSystem::defaultComponentId, "RC_CHAN_CNT")) {
_channelCount = getParameterFact(FactSystem::defaultComponentId, "RC_CHAN_CNT")->value().toInt();
} else {
_channelCount =_chanMax;
}
if (_channelCount <= 0 || _channelCount > _chanMax) {
// Parameter exists, but has not yet been set or is invalid. Use default
_channelCount = _chanMax;
}
int modeChannel = getParameterFact(-1, "RC_MAP_MODE_SW")->value().toInt();
int posCtlChannel = getParameterFact(-1, "RC_MAP_POSCTL_SW")->value().toInt();
int loiterChannel = getParameterFact(-1, "RC_MAP_LOITER_SW")->value().toInt();
if (posCtlChannel == 0) {
// PosCtl disabled so AltCtl must move back to main Mode switch
_assistModeVisible = false;
} else {
// Assist mode is visible if AltCtl/PosCtl are on seperate channel from main Mode switch
_assistModeVisible = posCtlChannel != modeChannel;
}
if (loiterChannel == 0) {
// Loiter disabled so Mission must move back to main Mode switch
_autoModeVisible = false;
} else {
// Auto mode is visible if Mission/Loiter are on seperate channel from main Mode switch
_autoModeVisible = loiterChannel != modeChannel;
}
// Setup the channel combobox model
QList<int> usedChannels;
QStringList attitudeParams;
attitudeParams << "RC_MAP_THROTTLE" << "RC_MAP_YAW" << "RC_MAP_PITCH" << "RC_MAP_ROLL" << "RC_MAP_FLAPS" << "RC_MAP_AUX1" << "RC_MAP_AUX2";
foreach(QString attitudeParam, attitudeParams) {
int channel = getParameterFact(-1, attitudeParam)->value().toInt();
if (channel != 0) {
usedChannels << channel;
}
}
_channelListModel << "Disabled";
_channelListModelChannel << 0;
for (int channel=1; channel<_channelCount; channel++) {
if (!usedChannels.contains(channel)) {
_channelListModel << QString("Channel %1").arg(channel);
_channelListModelChannel << channel;
}
}
_recalcModeRows();
}
/// This will look for parameter settings which would cause the config to not run correctly.
......@@ -66,19 +150,12 @@ void FlightModesComponentController::_validateConfiguration(void)
{
_validConfiguration = true;
_channelCount = parameterExists(FactSystem::defaultComponentId, "RC_CHAN_CNT") ? getParameterFact(FactSystem::defaultComponentId, "RC_CHAN_CNT")->value().toInt() : _chanMax;
if (_channelCount <= 0 || _channelCount > _chanMax) {
// Parameter exists, but has not yet been set or is invalid. Use default
_channelCount = _chanMax;
}
// Make sure switches are valid and within channel range
QStringList switchParams, switchNames;
QStringList switchParams;
QList<int> switchMappings;
switchParams << "RC_MAP_MODE_SW" << "RC_MAP_RETURN_SW" << "RC_MAP_LOITER_SW" << "RC_MAP_POSCTL_SW" << "RC_MAP_OFFB_SW" << "RC_MAP_ACRO_SW";
switchNames << "Mode Switch" << "Return Switch" << "Loiter Switch" << "PosCtl Switch" << "Offboard Switch" << "Acro Switch";
switchParams << "RC_MAP_MODE_SW" << "RC_MAP_ACRO_SW" << "RC_MAP_POSCTL_SW" << "RC_MAP_LOITER_SW" << "RC_MAP_RETURN_SW" << "RC_MAP_OFFB_SW";
for(int i=0; i<switchParams.count(); i++) {
int map = getParameterFact(FactSystem::defaultComponentId, switchParams[i])->value().toInt();
......@@ -86,16 +163,15 @@ void FlightModesComponentController::_validateConfiguration(void)
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);
_configurationErrors += QString("%1 is set to %2. Mapping must between 0 and %3 (inclusive).\n").arg(switchParams[i]).arg(map).arg(_channelCount);
}
}
// Make sure switches are not double-mapped
// Make sure mode switches are not double-mapped
QStringList attitudeParams, attitudeNames;
QStringList attitudeParams;
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 = getParameterFact(FactSystem::defaultComponentId, attitudeParams[i])->value().toInt();
......@@ -103,58 +179,23 @@ void FlightModesComponentController::_validateConfiguration(void)
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]);
_configurationErrors += QString("%1 is set to same channel as %2.\n").arg(switchParams[j]).arg(attitudeParams[i]);
}
}
}
// Check for switches that must be on their own channel
// Validate thresholds within range
QStringList singleSwitchParams, singleSwitchNames;
QStringList thresholdParams;
singleSwitchParams << "RC_MAP_RETURN_SW" << "RC_MAP_OFFB_SW";
singleSwitchNames << "Return Switch" << "Offboard Switch";
thresholdParams << "RC_ASSIST_TH" << "RC_AUTO_TH" << "RC_ACRO_TH" << "RC_POSCTL_TH" << "RC_LOITER_TH" << "RC_RETURN_TH" << "RC_OFFB_TH";
for (int i=0; i<singleSwitchParams.count(); i++) {
int map = getParameterFact(FactSystem::defaultComponentId, singleSwitchParams[i])->value().toInt();
for (int j=0; j<switchParams.count(); j++) {
if (map != 0 && singleSwitchParams[i] != switchParams[j] && map == switchMappings[j]) {
_validConfiguration = false;
_configurationErrors += QString("%1 must be on seperate channel, but is set to same channel as %2.\n").arg(singleSwitchNames[i]).arg(switchParams[j]);
}
}
}
}
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] = getParameterFact(FactSystem::defaultComponentId, rcMinParam)->value().toInt();
_rgRCMax[i] = getParameterFact(FactSystem::defaultComponentId, rcMaxParam)->value().toInt();
float floatReversed = getParameterFact(-1, rcRevParam)->value().toFloat();
_rgRCReversed[i] = floatReversed == -1.0f;
foreach(QString thresholdParam, thresholdParams) {
float threshold = getParameterFact(-1, thresholdParam)->value().toFloat();
if (threshold < 0.0f || threshold > 1.0f) {
_validConfiguration = false;
_configurationErrors += QString("%1 is set to %2. Threshold must between 0.0 and 1.0 (inclusive).\n").arg(thresholdParam).arg(threshold);
}
_uas->startCalibration(UASInterface::StartCalibrationRadio);
connect(_uas, &UASInterface::remoteControlChannelRawChanged, this, &FlightModesComponentController::_remoteControlChannelRawChanged);
} else {
disconnect(_uas, &UASInterface::remoteControlChannelRawChanged, this, &FlightModesComponentController::_remoteControlChannelRawChanged);
_uas->stopCalibration();
_initRcValues();
emit switchLiveRangeChanged();
}
}
......@@ -178,6 +219,9 @@ void FlightModesComponentController::_remoteControlChannelRawChanged(int chan, f
}
_rcValues[chan] = percentRange;
_recalcModeSelections();
emit switchLiveRangeChanged();
}
......@@ -187,38 +231,582 @@ double FlightModesComponentController::_switchLiveRange(const QString& param)
int channel = getParameterFact(-1, param)->value().toInt();
if (channel == 0) {
return 1.0;
return 0.0;
} else {
return _rcValues[channel - 1];
}
}
double FlightModesComponentController::modeSwitchLiveRange(void)
double FlightModesComponentController::manualModeRcValue(void)
{
return _switchLiveRange("RC_MAP_MODE_SW");
}
double FlightModesComponentController::returnSwitchLiveRange(void)
double FlightModesComponentController::assistModeRcValue(void)
{
return manualModeRcValue();
}
double FlightModesComponentController::autoModeRcValue(void)
{
return manualModeRcValue();
}
double FlightModesComponentController::acroModeRcValue(void)
{
return _switchLiveRange("RC_MAP_ACRO_SW");
}
double FlightModesComponentController::altCtlModeRcValue(void)
{
int posCtlSwitchChannel = getParameterFact(-1, "RC_MAP_POSCTL_SW")->value().toInt();
if (posCtlSwitchChannel == 0) {
return _switchLiveRange("RC_MAP_MODE_SW");
} else {
return _switchLiveRange("RC_MAP_POSCTL_SW");
}
}
double FlightModesComponentController::posCtlModeRcValue(void)
{
return _switchLiveRange("RC_MAP_POSCTL_SW");
}
double FlightModesComponentController::missionModeRcValue(void)
{
int returnSwitchChannel = getParameterFact(-1, "RC_MAP_RETURN_SW")->value().toInt();
int loiterSwitchChannel = getParameterFact(-1, "RC_MAP_LOITER_SW")->value().toInt();
const char* switchChannelParam = "RC_MAP_MODE_SW";
if (returnSwitchChannel == 0) {
if (loiterSwitchChannel != 0) {
switchChannelParam = "RC_MAP_LOITER_SW";
}
} else {
if (loiterSwitchChannel == 0) {
switchChannelParam = "RC_MAP_RETURN_SW";
} else {
switchChannelParam = "RC_MAP_LOITER_SW";
}
}
return _switchLiveRange(switchChannelParam);
}
double FlightModesComponentController::loiterModeRcValue(void)
{
return _switchLiveRange("RC_MAP_LOITER_SW");
}
double FlightModesComponentController::returnModeRcValue(void)
{
return _switchLiveRange("RC_MAP_RETURN_SW");
}
double FlightModesComponentController::offboardSwitchLiveRange(void)
double FlightModesComponentController::offboardModeRcValue(void)
{
return _switchLiveRange("RC_MAP_OFFB_SW");
}
double FlightModesComponentController::loiterSwitchLiveRange(void)
void FlightModesComponentController::_recalcModeSelections(void)
{
return _switchLiveRange("RC_MAP_LOITER_SW");
_manualModeSelected = false;
_assistModeSelected = false;
_autoModeSelected = false;
_acroModeSelected = false;
_altCtlModeSelected = false;
_posCtlModeSelected = false;
_missionModeSelected = false;
_loiterModeSelected = false;
_returnModeSelected = false;
_offboardModeSelected = false;
// Convert channels to 0-based, -1 signals not mapped
int modeSwitchChannel = getParameterFact(-1, "RC_MAP_MODE_SW")->value().toInt() - 1;
int acroSwitchChannel = getParameterFact(-1, "RC_MAP_ACRO_SW")->value().toInt() - 1;
int posCtlSwitchChannel = getParameterFact(-1, "RC_MAP_POSCTL_SW")->value().toInt() - 1;
int loiterSwitchChannel = getParameterFact(-1, "RC_MAP_LOITER_SW")->value().toInt() - 1;
int returnSwitchChannel = getParameterFact(-1, "RC_MAP_RETURN_SW")->value().toInt() - 1;
int offboardSwitchChannel = getParameterFact(-1, "RC_MAP_OFFB_SW")->value().toInt() - 1;
double autoThreshold = getParameterFact(-1, "RC_AUTO_TH")->value().toDouble();
double assistThreshold = getParameterFact(-1, "RC_ASSIST_TH")->value().toDouble();
double acroThreshold = getParameterFact(-1, "RC_ACRO_TH")->value().toDouble();
double posCtlThreshold = getParameterFact(-1, "RC_POSCTL_TH")->value().toDouble();
double loiterThreshold = getParameterFact(-1, "RC_LOITER_TH")->value().toDouble();
double returnThreshold = getParameterFact(-1, "RC_RETURN_TH")->value().toDouble();
double offboardThreshold = getParameterFact(-1, "RC_OFFB_TH")->value().toDouble();
if (modeSwitchChannel >= 0) {
if (offboardSwitchChannel >= 0 && _rcValues[offboardSwitchChannel] >= offboardThreshold) {
_offboardModeSelected = true;
} else if (returnSwitchChannel >= 0 && _rcValues[returnSwitchChannel] >= returnThreshold) {
_returnModeSelected = true;
} else {
if (_rcValues[modeSwitchChannel] >= autoThreshold) {
_autoModeSelected = true;
if (loiterSwitchChannel >= 0 && _rcValues[loiterSwitchChannel] >= loiterThreshold) {
_loiterModeSelected = true;
} else {
_missionModeSelected = true;
}
} else if (_rcValues[modeSwitchChannel] >= assistThreshold) {
_assistModeSelected = true;
if (posCtlSwitchChannel >= 0 && _rcValues[posCtlSwitchChannel] >= posCtlThreshold) {
_posCtlModeSelected = true;
} else {
_altCtlModeSelected = true;
}
} else if (acroSwitchChannel >= 0 && _rcValues[acroSwitchChannel] >= acroThreshold) {
_acroModeSelected = true;
} else {
_manualModeSelected = true;
}
}
}
emit modesSelectedChanged();
}
double FlightModesComponentController::posCtlSwitchLiveRange(void)
void FlightModesComponentController::_recalcModeRows(void)
{
return _switchLiveRange("RC_MAP_POSCTL_SW");
int modeSwitchChannel = getParameterFact(-1, "RC_MAP_MODE_SW")->value().toInt();
int acroSwitchChannel = getParameterFact(-1, "RC_MAP_ACRO_SW")->value().toInt();
int posCtlSwitchChannel = getParameterFact(-1, "RC_MAP_POSCTL_SW")->value().toInt();
int loiterSwitchChannel = getParameterFact(-1, "RC_MAP_LOITER_SW")->value().toInt();
int returnSwitchChannel = getParameterFact(-1, "RC_MAP_RETURN_SW")->value().toInt();
int offboardSwitchChannel = getParameterFact(-1, "RC_MAP_OFFB_SW")->value().toInt();
if (modeSwitchChannel == 0) {
_acroModeRow = 0;
_assistModeRow = 1;
_autoModeRow = 2;
_altCtlModeRow = 3;
_posCtlModeRow = 4;
_loiterModeRow = 5;
_missionModeRow = 6;
_returnModeRow = 7;
_offboardModeRow = 8;
} else {
int row = 0;
// First set is all switches on main mode channel
if (acroSwitchChannel == modeSwitchChannel) {
_acroModeRow = row++;
}
_assistModeRow = row++;
if (posCtlSwitchChannel == modeSwitchChannel) {
_altCtlModeRow = row++;
_posCtlModeRow = row++;
} else if (posCtlSwitchChannel == 0) {
_altCtlModeRow = row++;
}
_autoModeRow = row++;
if (loiterSwitchChannel == modeSwitchChannel) {
_missionModeRow = row++;
_loiterModeRow = row++;
} else if (loiterSwitchChannel == 0) {
_missionModeRow = row++;
}
if (returnSwitchChannel == modeSwitchChannel) {
_returnModeRow = row++;
}
if (offboardSwitchChannel == modeSwitchChannel) {
_offboardModeRow = row++;
}
// Now individual enabled switches not on main mode channel
if (acroSwitchChannel != 0 && acroSwitchChannel != modeSwitchChannel) {
_acroModeRow = row++;
}
if (posCtlSwitchChannel != 0 && posCtlSwitchChannel != modeSwitchChannel) {
_altCtlModeRow = row++;
_posCtlModeRow = row++;
}
if (loiterSwitchChannel != 0 && loiterSwitchChannel != modeSwitchChannel) {
_missionModeRow = row++;
_loiterModeRow = row++;
}
if (returnSwitchChannel != 0 && returnSwitchChannel != modeSwitchChannel) {
_returnModeRow = row++;
}
if (offboardSwitchChannel != 0 && offboardSwitchChannel != modeSwitchChannel) {
_offboardModeRow = row++;
}
// Now disabled switches
if (acroSwitchChannel == 0) {
_acroModeRow = row++;
}
if (posCtlSwitchChannel == 0) {
_posCtlModeRow = row++;
}
if (loiterSwitchChannel == 0) {
_loiterModeRow = row++;
}
if (returnSwitchChannel == 0) {
_returnModeRow = row++;
}
if (offboardSwitchChannel == 0) {
_offboardModeRow = row++;
}
}
emit modeRowsChanged();
}
double FlightModesComponentController::acroSwitchLiveRange(void)
double FlightModesComponentController::manualModeThreshold(void)
{
return _switchLiveRange("RC_MAP_ACRO_SW");
return 0.0;
}
double FlightModesComponentController::assistModeThreshold(void)
{
return getParameterFact(-1, "RC_ASSIST_TH")->value().toDouble();
}
double FlightModesComponentController::autoModeThreshold(void)
{
return getParameterFact(-1, "RC_AUTO_TH")->value().toDouble();
}
double FlightModesComponentController::acroModeThreshold(void)
{
return getParameterFact(-1, "RC_ACRO_TH")->value().toDouble();
}
double FlightModesComponentController::altCtlModeThreshold(void)
{
return _assistModeVisible ? 0.0 : getParameterFact(-1, "RC_ASSIST_TH")->value().toDouble();
}
double FlightModesComponentController::posCtlModeThreshold(void)
{
return getParameterFact(-1, "RC_POSCTL_TH")->value().toDouble();
}
double FlightModesComponentController::missionModeThreshold(void)
{
return _autoModeVisible ? 0.0 : getParameterFact(-1, "RC_AUTO_TH")->value().toDouble();
}
double FlightModesComponentController::loiterModeThreshold(void)
{
return getParameterFact(-1, "RC_LOITER_TH")->value().toDouble();
}
double FlightModesComponentController::returnModeThreshold(void)
{
return getParameterFact(-1, "RC_RETURN_TH")->value().toDouble();
}
double FlightModesComponentController::offboardModeThreshold(void)
{
return getParameterFact(-1, "RC_OFFB_TH")->value().toDouble();
}
void FlightModesComponentController::setAssistModeThreshold(double threshold)
{
getParameterFact(-1, "RC_ASSIST_TH")->setValue(threshold);
_recalcModeSelections();
}
void FlightModesComponentController::setAutoModeThreshold(double threshold)
{
getParameterFact(-1, "RC_AUTO_TH")->setValue(threshold);
_recalcModeSelections();
}
void FlightModesComponentController::setAcroModeThreshold(double threshold)
{
getParameterFact(-1, "RC_ACRO_TH")->setValue(threshold);
_recalcModeSelections();
}
void FlightModesComponentController::setAltCtlModeThreshold(double threshold)
{
setAssistModeThreshold(threshold);
}
void FlightModesComponentController::setPosCtlModeThreshold(double threshold)
{
getParameterFact(-1, "RC_POSCTL_TH")->setValue(threshold);
_recalcModeSelections();
}
void FlightModesComponentController::setMissionModeThreshold(double threshold)
{
setAutoModeThreshold(threshold);
}
void FlightModesComponentController::setLoiterModeThreshold(double threshold)
{
getParameterFact(-1, "RC_LOITER_TH")->setValue(threshold);
_recalcModeSelections();
}
void FlightModesComponentController::setReturnModeThreshold(double threshold)
{
getParameterFact(-1, "RC_RETURN_TH")->setValue(threshold);
_recalcModeSelections();
}
void FlightModesComponentController::setOffboardModeThreshold(double threshold)
{
getParameterFact(-1, "RC_OFFB_TH")->setValue(threshold);
_recalcModeSelections();
}
int FlightModesComponentController::_channelToChannelIndex(int channel)
{
return _channelListModelChannel.lastIndexOf(channel);
}
int FlightModesComponentController::_channelToChannelIndex(const QString& channelParam)
{
return _channelToChannelIndex(getParameterFact(-1, channelParam)->value().toInt());
}
int FlightModesComponentController::manualModeChannelIndex(void)
{
return _channelToChannelIndex("RC_MAP_MODE_SW");
}
int FlightModesComponentController::assistModeChannelIndex(void)
{
return _channelToChannelIndex("RC_MAP_MODE_SW");
}
int FlightModesComponentController::autoModeChannelIndex(void)
{
return _channelToChannelIndex("RC_MAP_MODE_SW");
}
int FlightModesComponentController::acroModeChannelIndex(void)
{
return _channelToChannelIndex("RC_MAP_ACRO_SW");
}
int FlightModesComponentController::altCtlModeChannelIndex(void)
{
int posCtlSwitchChannel = getParameterFact(-1, "RC_MAP_POSCTL_SW")->value().toInt();
if (posCtlSwitchChannel == 0) {
return _channelToChannelIndex("RC_MAP_MODE_SW");
} else {
return _channelToChannelIndex(posCtlSwitchChannel);
}
}
int FlightModesComponentController::posCtlModeChannelIndex(void)
{
return _channelToChannelIndex("RC_MAP_POSCTL_SW");
}
int FlightModesComponentController::loiterModeChannelIndex(void)
{
return _channelToChannelIndex("RC_MAP_LOITER_SW");
}
int FlightModesComponentController::missionModeChannelIndex(void)
{
int loiterSwitchChannel = getParameterFact(-1, "RC_MAP_LOITER_SW")->value().toInt();
if (loiterSwitchChannel == 0) {
return _channelToChannelIndex("RC_MAP_MODE_SW");
} else {
return _channelToChannelIndex(loiterSwitchChannel);
}
}
int FlightModesComponentController::returnModeChannelIndex(void)
{
return _channelToChannelIndex("RC_MAP_RETURN_SW");
}
int FlightModesComponentController::offboardModeChannelIndex(void)
{
return _channelToChannelIndex("RC_MAP_OFFB_SW");
}
int FlightModesComponentController::_channelIndexToChannel(int index)
{
return _channelListModelChannel[index];
}
void FlightModesComponentController::setManualModeChannelIndex(int index)
{
getParameterFact(-1, "RC_MAP_MODE_SW")->setValue(_channelIndexToChannel(index));
_recalcModeSelections();
_recalcModeRows();
}
void FlightModesComponentController::setAcroModeChannelIndex(int index)
{
getParameterFact(-1, "RC_MAP_ACRO_SW")->setValue(_channelIndexToChannel(index));
_recalcModeSelections();
_recalcModeRows();
}
void FlightModesComponentController::setPosCtlModeChannelIndex(int index)
{
int channel = _channelIndexToChannel(index);
getParameterFact(-1, "RC_MAP_POSCTL_SW")->setValue(channel);
if (channel == 0) {
// PosCtl disabled so AltCtl must move back to main Mode switch
_assistModeVisible = false;
} else {
// Assist mode is visible if AltCtl/PosCtl are on seperate channel from main Mode switch
_assistModeVisible = channel != getParameterFact(-1, "RC_MAP_MODE_SW")->value().toInt();
}
emit altCtlModeChannelIndexChanged(index);
emit modesVisibleChanged();
_recalcModeSelections();
_recalcModeRows();
}
void FlightModesComponentController::setLoiterModeChannelIndex(int index)
{
int channel = _channelIndexToChannel(index);
getParameterFact(-1, "RC_MAP_LOITER_SW")->setValue(channel);
if (channel == 0) {
// Loiter disabled so Mission must move back to main Mode switch
_autoModeVisible = false;
} else {
// Auto mode is visible if Mission/Loiter are on seperate channel from main Mode switch
_autoModeVisible = channel != getParameterFact(-1, "RC_MAP_MODE_SW")->value().toInt();
}
emit missionModeChannelIndexChanged(index);
emit modesVisibleChanged();
_recalcModeSelections();
_recalcModeRows();
}
void FlightModesComponentController::setReturnModeChannelIndex(int index)
{
getParameterFact(-1, "RC_MAP_RETURN_SW")->setValue(_channelIndexToChannel(index));
_recalcModeSelections();
_recalcModeRows();
}
void FlightModesComponentController::setOffboardModeChannelIndex(int index)
{
getParameterFact(-1, "RC_MAP_OFFB_SW")->setValue(_channelIndexToChannel(index));
_recalcModeSelections();
_recalcModeRows();
}
void FlightModesComponentController::generateThresholds(void)
{
// Reset all thresholds to 0.0
QStringList thresholdParams;
thresholdParams << "RC_ASSIST_TH" << "RC_AUTO_TH" << "RC_ACRO_TH" << "RC_POSCTL_TH" << "RC_LOITER_TH" << "RC_RETURN_TH" << "RC_OFFB_TH";
foreach(QString thresholdParam, thresholdParams) {
getParameterFact(-1, thresholdParam)->setValue(0.0f);
}
// Redistribute
int modeChannel = getParameterFact(-1, "RC_MAP_MODE_SW")->value().toInt();
int acroChannel = getParameterFact(-1, "RC_MAP_ACRO_SW")->value().toInt();
int posCtlChannel = getParameterFact(-1, "RC_MAP_POSCTL_SW")->value().toInt();
int loiterChannel = getParameterFact(-1, "RC_MAP_LOITER_SW")->value().toInt();
int returnChannel = getParameterFact(-1, "RC_MAP_RETURN_SW")->value().toInt();
int offboardChannel = getParameterFact(-1, "RC_MAP_OFFB_SW")->value().toInt();
if (modeChannel != 0) {
int positions = 3; // Manual/Assist/Auto always exist
bool acroOnModeSwitch = modeChannel == acroChannel;
bool posCtlOnModeSwitch = modeChannel == posCtlChannel;
bool loiterOnModeSwitch = modeChannel == loiterChannel;
bool returnOnModeSwitch = modeChannel == returnChannel;
bool offboardOnModeSwitch = modeChannel == offboardChannel;
positions += acroOnModeSwitch ? 1 : 0;
positions += posCtlOnModeSwitch ? 1 : 0;
positions += loiterOnModeSwitch ? 1 : 0;
positions += returnOnModeSwitch ? 1 : 0;
positions += offboardOnModeSwitch ? 1 : 0;
float increment = 1.0f / positions;
float currentThreshold = 0.0f;
if (acroOnModeSwitch) {
currentThreshold += increment;
getParameterFact(-1, "RC_ACRO_TH")->setValue(currentThreshold);
acroChannel = 0;
}
currentThreshold += increment;
getParameterFact(-1, "RC_ASSIST_TH")->setValue(currentThreshold);
if (posCtlOnModeSwitch) {
currentThreshold += increment;
getParameterFact(-1, "RC_POSCTL_TH")->setValue(currentThreshold);
posCtlChannel = 0;
}
currentThreshold += increment;
getParameterFact(-1, "RC_AUTO_TH")->setValue(currentThreshold);
if (loiterOnModeSwitch) {
currentThreshold += increment;
getParameterFact(-1, "RC_LOITER_TH")->setValue(currentThreshold);
loiterChannel = 0;
}
if (returnOnModeSwitch) {
currentThreshold += increment;
getParameterFact(-1, "RC_RETURN_TH")->setValue(currentThreshold);
returnChannel = 0;
}
if (offboardOnModeSwitch) {
currentThreshold += increment;
getParameterFact(-1, "RC_OFFB_TH")->setValue(currentThreshold);
offboardChannel = 0;
}
}
if (acroChannel != 0) {
// If only two positions don't set threshold at midrange. Setting to 0.25
// allows for this channel to work with either a two or three position switch
getParameterFact(-1, "RC_ACRO_TH")->setValue(0.25f);
}
if (posCtlChannel != 0) {
getParameterFact(-1, "RC_POSCTL_TH")->setValue(0.25f);
}
if (loiterChannel != 0) {
getParameterFact(-1, "RC_LOITER_TH")->setValue(0.25f);
}
if (returnChannel != 0) {
getParameterFact(-1, "RC_RETURN_TH")->setValue(0.25f);
}
if (offboardChannel != 0) {
getParameterFact(-1, "RC_OFFB_TH")->setValue(0.25f);
}
emit thresholdsChanged();
}
......@@ -30,6 +30,7 @@
#include <QObject>
#include <QQuickItem>
#include <QList>
#include <QStringList>
#include "UASInterface.h"
#include "AutoPilotPlugin.h"
......@@ -48,49 +49,198 @@ public:
Q_PROPERTY(QString configurationErrors MEMBER _configurationErrors CONSTANT)
Q_PROPERTY(int channelCount MEMBER _channelCount CONSTANT)
Q_PROPERTY(bool fixedWing MEMBER _fixedWing CONSTANT)
Q_PROPERTY(double modeSwitchLiveRange READ modeSwitchLiveRange NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double loiterSwitchLiveRange READ loiterSwitchLiveRange NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double posCtlSwitchLiveRange READ posCtlSwitchLiveRange NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double returnSwitchLiveRange READ returnSwitchLiveRange NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double offboardSwitchLiveRange READ offboardSwitchLiveRange NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double acroSwitchLiveRange READ acroSwitchLiveRange NOTIFY switchLiveRangeChanged)
Q_PROPERTY(int assistModeRow MEMBER _assistModeRow NOTIFY modeRowsChanged)
Q_PROPERTY(int autoModeRow MEMBER _autoModeRow NOTIFY modeRowsChanged)
Q_PROPERTY(int acroModeRow MEMBER _acroModeRow NOTIFY modeRowsChanged)
Q_PROPERTY(int altCtlModeRow MEMBER _altCtlModeRow NOTIFY modeRowsChanged)
Q_PROPERTY(int posCtlModeRow MEMBER _posCtlModeRow NOTIFY modeRowsChanged)
Q_PROPERTY(int loiterModeRow MEMBER _loiterModeRow NOTIFY modeRowsChanged)
Q_PROPERTY(int missionModeRow MEMBER _missionModeRow NOTIFY modeRowsChanged)
Q_PROPERTY(int returnModeRow MEMBER _returnModeRow NOTIFY modeRowsChanged)
Q_PROPERTY(int offboardModeRow MEMBER _offboardModeRow NOTIFY modeRowsChanged)
Q_PROPERTY(bool sendLiveRCSwitchRanges READ sendLiveRCSwitchRanges WRITE setSendLiveRCSwitchRanges NOTIFY liveRCSwitchRangesChanged)
Q_PROPERTY(int manualModeChannelIndex READ manualModeChannelIndex WRITE setManualModeChannelIndex NOTIFY manualModeChannelIndexChanged)
Q_PROPERTY(int assistModeChannelIndex READ assistModeChannelIndex NOTIFY assistModeChannelIndexChanged)
Q_PROPERTY(int autoModeChannelIndex READ autoModeChannelIndex NOTIFY autoModeChannelIndexChanged)
Q_PROPERTY(int acroModeChannelIndex READ acroModeChannelIndex WRITE setAcroModeChannelIndex NOTIFY acroModeChannelIndexChanged)
Q_PROPERTY(int altCtlModeChannelIndex READ altCtlModeChannelIndex NOTIFY altCtlModeChannelIndexChanged)
Q_PROPERTY(int posCtlModeChannelIndex READ posCtlModeChannelIndex WRITE setPosCtlModeChannelIndex NOTIFY posCtlModeChannelIndexChanged)
Q_PROPERTY(int loiterModeChannelIndex READ loiterModeChannelIndex WRITE setLoiterModeChannelIndex NOTIFY loiterModeChannelIndexChanged)
Q_PROPERTY(int missionModeChannelIndex READ missionModeChannelIndex NOTIFY missionModeChannelIndexChanged)
Q_PROPERTY(int returnModeChannelIndex READ returnModeChannelIndex WRITE setReturnModeChannelIndex NOTIFY returnModeChannelIndexChanged)
Q_PROPERTY(int offboardModeChannelIndex READ offboardModeChannelIndex WRITE setOffboardModeChannelIndex NOTIFY offboardModeChannelIndexChanged)
double modeSwitchLiveRange(void);
double loiterSwitchLiveRange(void);
double posCtlSwitchLiveRange(void);
double returnSwitchLiveRange(void);
double offboardSwitchLiveRange(void);
double acroSwitchLiveRange(void);
Q_PROPERTY(double manualModeRcValue READ manualModeRcValue NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double assistModeRcValue READ assistModeRcValue NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double autoModeRcValue READ autoModeRcValue NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double acroModeRcValue READ acroModeRcValue NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double altCtlModeRcValue READ altCtlModeRcValue NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double posCtlModeRcValue READ posCtlModeRcValue NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double loiterModeRcValue READ loiterModeRcValue NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double missionModeRcValue READ missionModeRcValue NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double returnModeRcValue READ returnModeRcValue NOTIFY switchLiveRangeChanged)
Q_PROPERTY(double offboardModeRcValue READ offboardModeRcValue NOTIFY switchLiveRangeChanged)
bool sendLiveRCSwitchRanges(void) { return _liveRCValues; }
void setSendLiveRCSwitchRanges(bool start);
Q_PROPERTY(double manualModeThreshold READ manualModeThreshold NOTIFY thresholdsChanged)
Q_PROPERTY(double assistModeThreshold READ assistModeThreshold WRITE setAssistModeThreshold NOTIFY thresholdsChanged)
Q_PROPERTY(double autoModeThreshold READ autoModeThreshold WRITE setAutoModeThreshold NOTIFY thresholdsChanged)
Q_PROPERTY(double acroModeThreshold READ acroModeThreshold WRITE setAcroModeThreshold NOTIFY thresholdsChanged)
Q_PROPERTY(double altCtlModeThreshold READ altCtlModeThreshold WRITE setAltCtlModeThreshold NOTIFY thresholdsChanged)
Q_PROPERTY(double posCtlModeThreshold READ posCtlModeThreshold WRITE setPosCtlModeThreshold NOTIFY thresholdsChanged)
Q_PROPERTY(double loiterModeThreshold READ loiterModeThreshold WRITE setLoiterModeThreshold NOTIFY thresholdsChanged)
Q_PROPERTY(double missionModeThreshold READ missionModeThreshold WRITE setMissionModeThreshold NOTIFY thresholdsChanged)
Q_PROPERTY(double returnModeThreshold READ returnModeThreshold WRITE setReturnModeThreshold NOTIFY thresholdsChanged)
Q_PROPERTY(double offboardModeThreshold READ offboardModeThreshold WRITE setOffboardModeThreshold NOTIFY thresholdsChanged)
Q_PROPERTY(bool assistModeVisible MEMBER _assistModeVisible NOTIFY modesVisibleChanged)
Q_PROPERTY(bool autoModeVisible MEMBER _autoModeVisible NOTIFY modesVisibleChanged)
Q_PROPERTY(bool manualModeSelected MEMBER _manualModeSelected NOTIFY modesSelectedChanged)
Q_PROPERTY(bool assistModeSelected MEMBER _assistModeSelected NOTIFY modesSelectedChanged)
Q_PROPERTY(bool autoModeSelected MEMBER _autoModeSelected NOTIFY modesSelectedChanged)
Q_PROPERTY(bool acroModeSelected MEMBER _acroModeSelected NOTIFY modesSelectedChanged)
Q_PROPERTY(bool altCtlModeSelected MEMBER _altCtlModeSelected NOTIFY modesSelectedChanged)
Q_PROPERTY(bool posCtlModeSelected MEMBER _posCtlModeSelected NOTIFY modesSelectedChanged)
Q_PROPERTY(bool missionModeSelected MEMBER _missionModeSelected NOTIFY modesSelectedChanged)
Q_PROPERTY(bool loiterModeSelected MEMBER _loiterModeSelected NOTIFY modesSelectedChanged)
Q_PROPERTY(bool returnModeSelected MEMBER _returnModeSelected NOTIFY modesSelectedChanged)
Q_PROPERTY(bool offboardModeSelected MEMBER _offboardModeSelected NOTIFY modesSelectedChanged)
Q_PROPERTY(QStringList channelListModel MEMBER _channelListModel CONSTANT)
Q_INVOKABLE void generateThresholds(void);
int assistModeRow(void);
int autoModeRow(void);
int acroModeRow(void);
int altCtlModeRow(void);
int posCtlModeRow(void);
int loiterModeRow(void);
int missionModeRow(void);
int returnModeRow(void);
int offboardModeRow(void);
int manualModeChannelIndex(void);
int assistModeChannelIndex(void);
int autoModeChannelIndex(void);
int acroModeChannelIndex(void);
int altCtlModeChannelIndex(void);
int posCtlModeChannelIndex(void);
int loiterModeChannelIndex(void);
int missionModeChannelIndex(void);
int returnModeChannelIndex(void);
int offboardModeChannelIndex(void);
void setManualModeChannelIndex(int index);
void setAcroModeChannelIndex(int index);
void setPosCtlModeChannelIndex(int index);
void setLoiterModeChannelIndex(int index);
void setReturnModeChannelIndex(int index);
void setOffboardModeChannelIndex(int index);
double manualModeRcValue(void);
double assistModeRcValue(void);
double autoModeRcValue(void);
double acroModeRcValue(void);
double altCtlModeRcValue(void);
double posCtlModeRcValue(void);
double missionModeRcValue(void);
double loiterModeRcValue(void);
double returnModeRcValue(void);
double offboardModeRcValue(void);
double manualModeThreshold(void);
double assistModeThreshold(void);
double autoModeThreshold(void);
double acroModeThreshold(void);
double altCtlModeThreshold(void);
double posCtlModeThreshold(void);
double missionModeThreshold(void);
double loiterModeThreshold(void);
double returnModeThreshold(void);
double offboardModeThreshold(void);
void setAssistModeThreshold(double threshold);
void setAutoModeThreshold(double threshold);
void setAcroModeThreshold(double threshold);
void setAltCtlModeThreshold(double threshold);
void setPosCtlModeThreshold(double threshold);
void setMissionModeThreshold(double threshold);
void setLoiterModeThreshold(double threshold);
void setReturnModeThreshold(double threshold);
void setOffboardModeThreshold(double threshold);
signals:
void switchLiveRangeChanged(void);
void liveRCSwitchRangesChanged(void);
void thresholdsChanged(void);
void modesSelectedChanged(void);
void modesVisibleChanged(void);
void manualModeChannelIndexChanged(int index);
void assistModeChannelIndexChanged(int index);
void autoModeChannelIndexChanged(int index);
void acroModeChannelIndexChanged(int index);
void altCtlModeChannelIndexChanged(int index);
void posCtlModeChannelIndexChanged(int index);
void loiterModeChannelIndexChanged(int index);
void missionModeChannelIndexChanged(int index);
void returnModeChannelIndexChanged(int index);
void offboardModeChannelIndexChanged(int index);
void modeRowsChanged(void);
private slots:
void _remoteControlChannelRawChanged(int chan, float fval);
private:
double _switchLiveRange(const QString& param);
void _initRcValues(void);
void _init(void);
void _validateConfiguration(void);
void _recalcModeSelections(void);
void _recalcModeRows(void);
int _channelToChannelIndex(int channel);
int _channelToChannelIndex(const QString& channelParam);
int _channelIndexToChannel(int index);
static const int _chanMax = 18;
QList<double> _rcValues;
bool _liveRCValues;
int _rgRCMin[_chanMax];
int _rgRCMax[_chanMax];
bool _rgRCReversed[_chanMax];
bool _fixedWing;
double _rcValues[_chanMax];
int _rgRCMin[_chanMax];
int _rgRCMax[_chanMax];
bool _rgRCReversed[_chanMax];
bool _validConfiguration;
QString _configurationErrors;
int _channelCount;
int _assistModeRow;
int _autoModeRow;
int _acroModeRow;
int _altCtlModeRow;
int _posCtlModeRow;
int _loiterModeRow;
int _missionModeRow;
int _returnModeRow;
int _offboardModeRow;
bool _manualModeSelected;
bool _assistModeSelected;
bool _autoModeSelected;
bool _acroModeSelected;
bool _altCtlModeSelected;
bool _posCtlModeSelected;
bool _missionModeSelected;
bool _loiterModeSelected;
bool _returnModeSelected;
bool _offboardModeSelected;
bool _assistModeVisible;
bool _autoModeVisible;
QStringList _channelListModel;
QList<int> _channelListModelChannel;
};
#endif
/*=====================================================================
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/>.
======================================================================*/
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.Palette 1.0
import QGroundControl.ScreenTools 1.0
Rectangle {
property string flightModeName ///< User visible name for this flight mode
property string flightModeDescription
property real rcValue ///< Current rcValue to show in Monitor display, range: 0.0 - 1.0
property int modeChannelIndex ///< Index into channel list for this mode
property bool modeChannelEnabled ///< true: Channel combo box is enabled
property bool modeSelected ///< true: This mode is currently selected
property real thresholdValue ///< Treshold setting for this mode, show in Threshold display, range 0.0 - 1.0
property bool thresholdDragEnabled ///< true: Threshold value indicator can be dragged to modify value
anchors.leftMargin: ScreenTools.defaultFontPixelWidth
anchors.rightMargin: ScreenTools.defaultFontPixelWidth
anchors.left: parent.left
anchors.right: parent.right
height: column.height + (ScreenTools.defaultFontPixelWidth * 2)
color: _qgcPal.windowShade
QGCPalette { id: _qgcPal; colorGroupEnabled: enabled }
Item {
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.fill: parent
Column {
id: column
width: parent.width
spacing: ScreenTools.defaultFontPixelHeight / 4
Row {
width: parent.width
spacing: ScreenTools.defaultFontPixelWidth
Rectangle {
width: modeLabel.width
height: modeLabel.contentHeight
color: modeSelected ? _qgcPal.buttonHighlight : _qgcPal.windowShade
QGCLabel {
id: modeLabel
width: ScreenTools.defaultFontPixelWidth * 18
color: modeSelected ? _qgcPal.buttonHighlightText : _qgcPal.text
horizontalAlignment: Text.AlignHCenter
font.pixelSize: ScreenTools.mediumFontPixelSize
text: flightModeName
}
}
QGCComboBox {
id: channelCombo
width: ScreenTools.defaultFontPixelWidth * 15
model: controller.channelListModel
currentIndex: modeChannelIndex
enabled: modeChannelEnabled
onActivated: modeChannelIndex = index
}
QGCLabel {
width: parent.width - x
wrapMode: Text.WordWrap
text: flightModeDescription
}
}
Row {
width: parent.width
spacing: ScreenTools.defaultFontPixelWidth * 2
QGCLabel {
width: ScreenTools.defaultFontPixelWidth * monitorThresholdCharWidth
height: ScreenTools.defaultFontPixelHeight
verticalAlignment: Text.AlignVCenter
text: "Monitor:"
}
Item {
height: ScreenTools.defaultFontPixelHeight
width: parent.width - x
// Won't be able to pull these properties, need to reference parent.
property int __lastRcValue: 1500
readonly property int __rcValueMaxJitter: 2
// Bar
Rectangle {
id: bar
anchors.verticalCenter: parent.verticalCenter
width: parent.width
height: parent.height / 2
color: _qgcPal.windowShadeDark
}
// RC Indicator
Rectangle {
anchors.verticalCenter: parent.verticalCenter
width: parent.height * 0.75
height: width
x: (parent.width * rcValue) - (width / 2)
radius: width / 2
color: _qgcPal.text
}
} // Item
}
Row {
width: parent.width
spacing: ScreenTools.defaultFontPixelWidth * 2
QGCLabel {
width: ScreenTools.defaultFontPixelWidth * monitorThresholdCharWidth
height: ScreenTools.defaultFontPixelHeight
verticalAlignment: Text.AlignVCenter
text: "Threshold:"
}
Item {
id: thresholdContainer
height: ScreenTools.defaultFontPixelHeight
width: parent.width - x
// Bar
Rectangle {
anchors.verticalCenter: parent.verticalCenter
width: parent.width
height: parent.height / 2
color: _qgcPal.windowShadeDark
}
// Threshold Indicator
Rectangle {
id: thresholdIndicator
anchors.verticalCenter: parent.verticalCenter
width: parent.height * 0.75
height: width
x: (parent.width * thresholdValue) - (width / 2)
radius: width / 2
color: thresholdDragEnabled ? _qgcPal.buttonHighlight : _qgcPal.text
Drag.active: thresholdDrag.drag.active
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
MouseArea {
id: thresholdDrag
anchors.fill: parent
cursorShape: Qt.SizeHorCursor
drag.target: thresholdDragEnabled ? parent : null
drag.minimumX: - (width / 2)
drag.maximumX: thresholdContainer.width - (width / 2)
drag.axis: Drag.XAxis
property bool dragActive: drag.active
onDragActiveChanged: {
if (!drag.active) {
thresholdValue = (thresholdIndicator.x + (thresholdIndicator.width / 2)) / thresholdContainer.width
}
}
}
}
} // Item
} // Row
} // Column
} // Item
} // Rectangle
......@@ -19,6 +19,8 @@ ViewWidget 1.0 ViewWidget.qml
ParameterEditor 1.0 ParameterEditor.qml
ParameterEditorDialog 1.0 ParameterEditorDialog.qml
ModeSwitchDisplay 1.0 ModeSwitchDisplay.qml
QGCView 1.0 QGCView.qml
QGCViewPanel 1.0 QGCViewPanel.qml
QGCViewDialog 1.0 QGCViewDialog.qml
......
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