5 changed files with 501 additions and 453 deletions
@ -0,0 +1,429 @@
@@ -0,0 +1,429 @@
|
||||
/**************************************************************************** |
||||
* |
||||
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org> |
||||
* |
||||
* QGroundControl is licensed according to the terms in the file |
||||
* COPYING.md in the root of the source code directory. |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
import QtQuick 2.3 |
||||
import QtQuick.Controls 1.2 |
||||
import QtCharts 2.2 |
||||
import QtQuick.Layouts 1.2 |
||||
|
||||
import QGroundControl 1.0 |
||||
import QGroundControl.Controls 1.0 |
||||
import QGroundControl.FactSystem 1.0 |
||||
import QGroundControl.FactControls 1.0 |
||||
import QGroundControl.ScreenTools 1.0 |
||||
|
||||
RowLayout { |
||||
layoutDirection: Qt.RightToLeft |
||||
|
||||
property var tuneList |
||||
property var params |
||||
|
||||
property real _chartHeight: ScreenTools.defaultFontPixelHeight * 20 |
||||
property real _margins: ScreenTools.defaultFontPixelHeight / 2 |
||||
property string _currentTuneType: tuneList[0] |
||||
property real _roll: _activeVehicle.roll.value |
||||
property real _rollSetpoint: _activeVehicle.setpoint.roll.value |
||||
property real _rollRate: _activeVehicle.rollRate.value |
||||
property real _rollRateSetpoint: _activeVehicle.setpoint.rollRate.value |
||||
property real _pitch: _activeVehicle.pitch.value |
||||
property real _pitchSetpoint: _activeVehicle.setpoint.pitch.value |
||||
property real _pitchRate: _activeVehicle.pitchRate.value |
||||
property real _pitchRateSetpoint: _activeVehicle.setpoint.pitchRate.value |
||||
property real _yaw: _activeVehicle.heading.value |
||||
property real _yawSetpoint: _activeVehicle.setpoint.yaw.value |
||||
property real _yawRate: _activeVehicle.yawRate.value |
||||
property real _yawRateSetpoint: _activeVehicle.setpoint.yawRate.value |
||||
property var _valueXAxis: valueXAxis |
||||
property var _valueRateXAxis: valueRateXAxis |
||||
property var _valueYAxis: valueYAxis |
||||
property var _valueRateYAxis: valueRateYAxis |
||||
property int _msecs: 0 |
||||
property var _savedTuningParamValues: [ ] |
||||
|
||||
// The following are set when getValues is called |
||||
property real _value |
||||
property real _valueSetpoint |
||||
property real _valueRate |
||||
property real _valueRateSetpoint |
||||
|
||||
readonly property int _tickSeparation: 5 |
||||
readonly property int _maxTickSections: 10 |
||||
readonly property int _tuneListRollIndex: 0 |
||||
readonly property int _tuneListPitchIndex: 1 |
||||
readonly property int _tuneListYawIndex: 2 |
||||
|
||||
function adjustYAxisMin(yAxis, newValue) { |
||||
var newMin = Math.min(yAxis.min, newValue) |
||||
if (newMin % 5 != 0) { |
||||
newMin -= 5 |
||||
newMin = Math.floor(newMin / _tickSeparation) * _tickSeparation |
||||
} |
||||
yAxis.min = newMin |
||||
} |
||||
|
||||
function adjustYAxisMax(yAxis, newValue) { |
||||
var newMax = Math.max(yAxis.max, newValue) |
||||
if (newMax % 5 != 0) { |
||||
newMax += 5 |
||||
newMax = Math.floor(newMax / _tickSeparation) * _tickSeparation |
||||
} |
||||
yAxis.max = newMax |
||||
} |
||||
|
||||
function getValues() { |
||||
if (_currentTuneType === tuneList[_tuneListRollIndex]) { |
||||
_value = _roll |
||||
_valueSetpoint = _rollSetpoint |
||||
_valueRate = _rollRate |
||||
_valueRateSetpoint = _rollRateSetpoint |
||||
} else if (_currentTuneType === tuneList[_tuneListPitchIndex]) { |
||||
_value = _pitch |
||||
_valueSetpoint = _pitchSetpoint |
||||
_valueRate = _pitchRate |
||||
_valueRateSetpoint = _pitchRateSetpoint |
||||
} else if (_currentTuneType === tuneList[_tuneListYawIndex]) { |
||||
_value = _yaw |
||||
_valueSetpoint = _yawSetpoint |
||||
_valueRate = _yawRate |
||||
_valueRateSetpoint = _yawRateSetpoint |
||||
} |
||||
} |
||||
|
||||
function resetGraphs() { |
||||
valueSeries.removePoints(0, valueSeries.count) |
||||
valueSetpointSeries.removePoints(0, valueSetpointSeries.count) |
||||
valueRateSeries.removePoints(0, valueRateSeries.count) |
||||
valueRateSetpointSeries.removePoints(0, valueRateSetpointSeries.count) |
||||
_valueXAxis.min = 0 |
||||
_valueXAxis.max = 0 |
||||
_valueRateXAxis.min = 0 |
||||
_valueRateXAxis.max = 0 |
||||
_valueYAxis.min = 0 |
||||
_valueYAxis.max = 10 |
||||
_valueRateYAxis.min = 0 |
||||
_valueRateYAxis.max = 10 |
||||
_msecs = 0 |
||||
} |
||||
|
||||
function currentTuneTypeIndex() { |
||||
if (_currentTuneType === tuneList[_tuneListRollIndex]) { |
||||
return _tuneListRollIndex |
||||
} else if (_currentTuneType === tuneList[_tuneListPitchIndex]) { |
||||
return _tuneListPitchIndex |
||||
} else if (_currentTuneType === tuneList[_tuneListYawIndex]) { |
||||
return _tuneListYawIndex |
||||
} |
||||
} |
||||
|
||||
// Save the current set of tuning values so we can reset to them |
||||
function saveTuningParamValues() { |
||||
var tuneTypeIndex = currentTuneTypeIndex() |
||||
|
||||
_savedTuningParamValues = [ ] |
||||
var currentTuneParams = params[tuneTypeIndex] |
||||
for (var i=0; i<currentTuneParams.length; i++) { |
||||
_savedTuningParamValues.push(currentTuneParams[i].valueString) |
||||
} |
||||
savedRepeater.model = _savedTuningParamValues |
||||
} |
||||
|
||||
function resetToSavedTuningParamValues() { |
||||
var tuneTypeIndex = currentTuneTypeIndex() |
||||
|
||||
for (var i=0; i<_savedTuningParamValues.length; i++) { |
||||
params[tuneTypeIndex][i].value = _savedTuningParamValues[i] |
||||
} |
||||
} |
||||
|
||||
Component.onCompleted: { |
||||
saveTuningParamValues() |
||||
} |
||||
|
||||
on_CurrentTuneTypeChanged: { |
||||
saveTuningParamValues() |
||||
resetGraphs() |
||||
} |
||||
|
||||
ExclusiveGroup { |
||||
id: tuneTypeRadios |
||||
} |
||||
|
||||
ValueAxis { |
||||
id: valueXAxis |
||||
min: 0 |
||||
max: 0 |
||||
labelFormat: "%d" |
||||
titleText: "sec" |
||||
} |
||||
|
||||
ValueAxis { |
||||
id: valueRateXAxis |
||||
min: 0 |
||||
max: 0 |
||||
labelFormat: "%d" |
||||
titleText: "sec" |
||||
} |
||||
|
||||
ValueAxis { |
||||
id: valueYAxis |
||||
min: 0 |
||||
max: 10 |
||||
titleText: "deg" |
||||
tickCount: Math.min(((max - min) / _tickSeparation), _maxTickSections) + 1 |
||||
} |
||||
|
||||
ValueAxis { |
||||
id: valueRateYAxis |
||||
min: 0 |
||||
max: 10 |
||||
titleText: "deg/s" |
||||
tickCount: Math.min(((max - min) / _tickSeparation), _maxTickSections) + 1 |
||||
} |
||||
|
||||
Timer { |
||||
id: dataTimer |
||||
interval: 10 |
||||
running: false |
||||
repeat: true |
||||
|
||||
onTriggered: { |
||||
var seconds = _msecs / 1000 |
||||
_valueXAxis.max = seconds |
||||
_valueRateXAxis.max = seconds |
||||
|
||||
getValues() |
||||
|
||||
valueSeries.append(seconds, _value) |
||||
adjustYAxisMin(_valueYAxis, _value) |
||||
adjustYAxisMax(_valueYAxis, _value) |
||||
|
||||
valueSetpointSeries.append(seconds, _valueSetpoint) |
||||
adjustYAxisMin(_valueYAxis, _valueSetpoint) |
||||
adjustYAxisMax(_valueYAxis, _valueSetpoint) |
||||
|
||||
valueRateSeries.append(seconds, _valueRate) |
||||
adjustYAxisMin(_valueRateYAxis, _valueRate) |
||||
adjustYAxisMax(_valueRateYAxis, _valueRate) |
||||
|
||||
valueRateSetpointSeries.append(seconds, _valueRateSetpoint) |
||||
adjustYAxisMin(_valueRateYAxis, _valueRateSetpoint) |
||||
adjustYAxisMax(_valueRateYAxis, _valueRateSetpoint) |
||||
|
||||
_msecs += interval |
||||
/* |
||||
Testing with just start/stop for now. No time limit. |
||||
if (valueSeries.count > _maxPointCount) { |
||||
valueSeries.remove(0) |
||||
valueSetpointSeries.remove(0) |
||||
valueRateSeries.remove(0) |
||||
valueRateSetpointSeries.remove(0) |
||||
valueXAxis.min = valueSeries.at(0).x |
||||
valueRateXAxis.min = valueSeries.at(0).x |
||||
} |
||||
*/ |
||||
} |
||||
|
||||
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle |
||||
property int _maxPointCount: 10000 / interval |
||||
} |
||||
|
||||
Column { |
||||
spacing: _margins |
||||
Layout.alignment: Qt.AlignTop |
||||
|
||||
QGCLabel { text: qsTr("Tuning Axis:") } |
||||
|
||||
RowLayout { |
||||
spacing: _margins |
||||
|
||||
Repeater { |
||||
model: tuneList |
||||
QGCRadioButton { |
||||
text: modelData |
||||
checked: _currentTuneType === modelData |
||||
exclusiveGroup: tuneTypeRadios |
||||
|
||||
onClicked: _currentTuneType = modelData |
||||
} |
||||
} |
||||
} |
||||
|
||||
Item { width: 1; height: 1 } |
||||
|
||||
QGCLabel { text: qsTr("Tuning Values:") } |
||||
|
||||
GridLayout { |
||||
rows: factList.length |
||||
flow: GridLayout.TopToBottom |
||||
rowSpacing: _margins |
||||
columnSpacing: _margins |
||||
|
||||
property var factList: params[tuneList.indexOf(_currentTuneType)] |
||||
|
||||
Repeater { |
||||
model: parent.factList |
||||
|
||||
QGCLabel { text: modelData.name } |
||||
} |
||||
|
||||
Repeater { |
||||
model: parent.factList |
||||
|
||||
QGCButton { |
||||
text: "-" |
||||
onClicked: { |
||||
var value = modelData.value |
||||
modelData.value -= value * adjustPercentModel.get(adjustPercentCombo.currentIndex).value |
||||
} |
||||
} |
||||
} |
||||
|
||||
Repeater { |
||||
model: parent.factList |
||||
|
||||
FactTextField { |
||||
Layout.fillWidth: true |
||||
fact: modelData |
||||
showUnits: false |
||||
} |
||||
} |
||||
|
||||
Repeater { |
||||
model: parent.factList |
||||
|
||||
QGCButton { |
||||
text: "+" |
||||
onClicked: { |
||||
var value = modelData.value |
||||
modelData.value += value * adjustPercentModel.get(adjustPercentCombo.currentIndex).value |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
RowLayout { |
||||
QGCLabel { text: qsTr("Increment/Decrement %") } |
||||
|
||||
QGCComboBox { |
||||
id: adjustPercentCombo |
||||
model: ListModel { |
||||
id: adjustPercentModel |
||||
ListElement { text: "5"; value: 0.05 } |
||||
ListElement { text: "10"; value: 0.10 } |
||||
ListElement { text: "15"; value: 0.15 } |
||||
ListElement { text: "20"; value: 0.20 } |
||||
} |
||||
} |
||||
} |
||||
Item { width: 1; height: 1 } |
||||
|
||||
QGCLabel { text: qsTr("Saved Tuning Values:") } |
||||
|
||||
GridLayout { |
||||
rows: savedRepeater.model.length |
||||
flow: GridLayout.TopToBottom |
||||
rowSpacing: _margins |
||||
columnSpacing: _margins |
||||
|
||||
Repeater { |
||||
model: params[tuneList.indexOf(_currentTuneType)] |
||||
|
||||
QGCLabel { text: modelData.name } |
||||
} |
||||
|
||||
Repeater { |
||||
id: savedRepeater |
||||
|
||||
QGCLabel { text: modelData } |
||||
} |
||||
} |
||||
|
||||
RowLayout { |
||||
spacing: _margins |
||||
|
||||
QGCButton { |
||||
text: qsTr("Save Values") |
||||
onClicked: saveTuningParamValues() |
||||
} |
||||
|
||||
QGCButton { |
||||
text: qsTr("Reset To Saved Values") |
||||
onClicked: resetToSavedTuningParamValues() |
||||
} |
||||
} |
||||
|
||||
Item { width: 1; height: 1 } |
||||
|
||||
QGCLabel { text: qsTr("Chart:") } |
||||
|
||||
RowLayout { |
||||
spacing: _margins |
||||
|
||||
QGCButton { |
||||
text: qsTr("Clear") |
||||
onClicked: resetGraphs() |
||||
} |
||||
|
||||
QGCButton { |
||||
text: dataTimer.running ? qsTr("Stop") : qsTr("Start") |
||||
onClicked: dataTimer.running = !dataTimer.running |
||||
} |
||||
} |
||||
} |
||||
|
||||
Column { |
||||
Layout.fillWidth: true |
||||
|
||||
ChartView { |
||||
anchors.left: parent.left |
||||
anchors.right: parent.right |
||||
height: availableHeight / 2 |
||||
title: _currentTuneType |
||||
antialiasing: true |
||||
legend.alignment: Qt.AlignRight |
||||
|
||||
LineSeries { |
||||
id: valueSeries |
||||
name: "Response" |
||||
axisY: valueYAxis |
||||
axisX: valueXAxis |
||||
} |
||||
|
||||
LineSeries { |
||||
id: valueSetpointSeries |
||||
name: "Command" |
||||
axisY: valueYAxis |
||||
axisX: valueXAxis |
||||
} |
||||
} |
||||
|
||||
ChartView { |
||||
anchors.left: parent.left |
||||
anchors.right: parent.right |
||||
height: availableHeight / 2 |
||||
title: _currentTuneType + qsTr(" Rate") |
||||
antialiasing: true |
||||
legend.alignment: Qt.AlignRight |
||||
|
||||
LineSeries { |
||||
id: valueRateSeries |
||||
name: "Response" |
||||
axisY: valueRateYAxis |
||||
axisX: valueRateXAxis |
||||
} |
||||
|
||||
LineSeries { |
||||
id: valueRateSetpointSeries |
||||
name: "Command" |
||||
axisY: valueRateYAxis |
||||
axisX: valueRateXAxis |
||||
} |
||||
} |
||||
} |
||||
} // RowLayout |
Loading…
Reference in new issue