Browse Source

Merge pull request #7407 from DonLakeFlyer/PIDTuning

Pid Tuning: Stream rate adjustment, Automatic flight mode switching
QGC4.4
Don Gagne 6 years ago committed by GitHub
parent
commit
2d8ae58293
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 20
      src/AutoPilotPlugins/PX4/PX4TuningComponentCopter.qml
  2. 22
      src/QmlControls/FactSliderPanel.qml
  3. 95
      src/QmlControls/PIDTuning.qml
  4. 78
      src/Vehicle/Vehicle.cc
  5. 10
      src/Vehicle/Vehicle.h

20
src/AutoPilotPlugins/PX4/PX4TuningComponentCopter.qml

@ -61,26 +61,6 @@ SetupPage {
max: 15 max: 15
step: 1 step: 1
} }
/*
These seem to have disappeared from PX4 firmware!
ListElement {
title: qsTr("Roll sensitivity")
description: qsTr("Slide to the left to make roll control faster and more accurate. Slide to the right if roll oscillates or is too twitchy.")
param: "MC_ROLL_TC"
min: 0.15
max: 0.25
step: 0.01
}
ListElement {
title: qsTr("Pitch sensitivity")
description: qsTr("Slide to the left to make pitch control faster and more accurate. Slide to the right if pitch oscillates or is too twitchy.")
param: "MC_PITCH_TC"
min: 0.15
max: 0.25
step: 0.01
}
*/
} }
} }

22
src/QmlControls/FactSliderPanel.qml

@ -34,6 +34,8 @@ Column {
property real _margins: ScreenTools.defaultFontPixelHeight property real _margins: ScreenTools.defaultFontPixelHeight
property bool _loadComplete: false property bool _loadComplete: false
Component.onCompleted: _loadComplete = true
FactPanelController { FactPanelController {
id: controller id: controller
factPanel: qgcViewPanel factPanel: qgcViewPanel
@ -71,10 +73,22 @@ Column {
font.family: ScreenTools.demiboldFontFamily font.family: ScreenTools.demiboldFontFamily
} }
FactValueSlider { Slider {
digitCount: fact.maxString.length anchors.left: parent.left
incrementSlots: 3 anchors.right: parent.right
fact: controller.getParameterFact(-1, param) minimumValue: min
maximumValue: max
stepSize: step
tickmarksEnabled: true
value: _fact.value
property Fact _fact: controller.getParameterFact(-1, param)
onValueChanged: {
if (_loadComplete) {
_fact.value = value
}
}
} }
QGCLabel { QGCLabel {

95
src/QmlControls/PIDTuning.qml

@ -142,16 +142,11 @@ RowLayout {
} }
Component.onCompleted: { Component.onCompleted: {
// Stop deferring updates to vehicle values. We need them as fast as we can for charting. _activeVehicle.setPIDTuningTelemetryMode(true)
_activeVehicle.setLiveUpdates(true)
_activeVehicle.setpoint.setLiveUpdates(true)
saveTuningParamValues() saveTuningParamValues()
} }
Component.onDestruction: { Component.onDestruction: _activeVehicle.setPIDTuningTelemetryMode(false)
_activeVehicle.setLiveUpdates(false)
_activeVehicle.setpoint.setLiveUpdates(true)
}
on_CurrentTuneTypeChanged: { on_CurrentTuneTypeChanged: {
saveTuningParamValues() saveTuningParamValues()
@ -202,14 +197,6 @@ RowLayout {
running: false running: false
repeat: true repeat: true
function startOrStop() {
if (dataTimer.running) {
dataTimer.stop()
} else {
dataTimer.start()
}
}
onTriggered: { onTriggered: {
_valueXAxis.max = _msecs _valueXAxis.max = _msecs
_valueRateXAxis.max = _msecs _valueRateXAxis.max = _msecs
@ -243,25 +230,25 @@ RowLayout {
spacing: _margins spacing: _margins
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
QGCLabel { text: qsTr("Tuning Axis:") } Column {
QGCLabel { text: qsTr("Tuning Axis:") }
RowLayout { RowLayout {
spacing: _margins spacing: _margins
Repeater { Repeater {
model: tuneList model: tuneList
QGCRadioButton { QGCRadioButton {
text: modelData text: modelData
checked: _currentTuneType === modelData checked: _currentTuneType === modelData
exclusiveGroup: tuneTypeRadios exclusiveGroup: tuneTypeRadios
onClicked: _currentTuneType = modelData onClicked: _currentTuneType = modelData
}
} }
} }
} }
Item { width: 1; height: 1 }
QGCLabel { text: qsTr("Tuning Values:") } QGCLabel { text: qsTr("Tuning Values:") }
GridLayout { GridLayout {
@ -333,26 +320,27 @@ RowLayout {
} }
} }
} }
Item { width: 1; height: 1 }
QGCLabel { text: qsTr("Clipboard Values:") } Column {
QGCLabel { text: qsTr("Clipboard Values:") }
GridLayout { GridLayout {
rows: savedRepeater.model.length rows: savedRepeater.model.length
flow: GridLayout.TopToBottom flow: GridLayout.TopToBottom
rowSpacing: _margins rowSpacing: 0
columnSpacing: _margins columnSpacing: _margins
Repeater { Repeater {
model: params[tuneList.indexOf(_currentTuneType)] model: params[tuneList.indexOf(_currentTuneType)]
QGCLabel { text: modelData.name } QGCLabel { text: modelData.name }
} }
Repeater { Repeater {
id: savedRepeater id: savedRepeater
QGCLabel { text: modelData } QGCLabel { text: modelData }
}
} }
} }
@ -384,7 +372,30 @@ RowLayout {
QGCButton { QGCButton {
text: dataTimer.running ? qsTr("Stop") : qsTr("Start") text: dataTimer.running ? qsTr("Stop") : qsTr("Start")
onClicked: dataTimer.startOrStop() onClicked: {
dataTimer.running = !dataTimer.running
if (autoModeChange.checked) {
_activeVehicle.flightMode = dataTimer.running ? "Stabilized" : _activeVehicle.pauseFlightMode
}
}
}
}
QGCCheckBox {
id: autoModeChange
text: qsTr("Automatic Flight Mode Switching")
}
Column {
visible: autoModeChange.checked
QGCLabel {
text: qsTr("Switches to 'Stabilized' when you click Start.")
font.pointSize: ScreenTools.smallFontPointSize
}
QGCLabel {
text: qsTr("Switches to '%1' when you click Stop.").arg(_activeVehicle.pauseFlightMode)
font.pointSize: ScreenTools.smallFontPointSize
} }
} }
} }

78
src/Vehicle/Vehicle.cc

@ -185,6 +185,8 @@ Vehicle::Vehicle(LinkInterface* link,
, _lastAnnouncedLowBatteryPercent(100) , _lastAnnouncedLowBatteryPercent(100)
, _priorityLinkCommanded(false) , _priorityLinkCommanded(false)
, _orbitActive(false) , _orbitActive(false)
, _pidTuningTelemetryMode(false)
, _pidTuningWaitingForRates(false)
, _rollFact (0, _rollFactName, FactMetaData::valueTypeDouble) , _rollFact (0, _rollFactName, FactMetaData::valueTypeDouble)
, _pitchFact (0, _pitchFactName, FactMetaData::valueTypeDouble) , _pitchFact (0, _pitchFactName, FactMetaData::valueTypeDouble)
, _headingFact (0, _headingFactName, FactMetaData::valueTypeDouble) , _headingFact (0, _headingFactName, FactMetaData::valueTypeDouble)
@ -386,6 +388,8 @@ Vehicle::Vehicle(MAV_AUTOPILOT firmwareType,
, _uid(0) , _uid(0)
, _lastAnnouncedLowBatteryPercent(100) , _lastAnnouncedLowBatteryPercent(100)
, _orbitActive(false) , _orbitActive(false)
, _pidTuningTelemetryMode(false)
, _pidTuningWaitingForRates(false)
, _rollFact (0, _rollFactName, FactMetaData::valueTypeDouble) , _rollFact (0, _rollFactName, FactMetaData::valueTypeDouble)
, _pitchFact (0, _pitchFactName, FactMetaData::valueTypeDouble) , _pitchFact (0, _pitchFactName, FactMetaData::valueTypeDouble)
, _headingFact (0, _headingFactName, FactMetaData::valueTypeDouble) , _headingFact (0, _headingFactName, FactMetaData::valueTypeDouble)
@ -519,6 +523,8 @@ void Vehicle::_commonInit(void)
} }
} }
#endif #endif
_pidTuningMessages << MAVLINK_MSG_ID_ATTITUDE << MAVLINK_MSG_ID_ATTITUDE_TARGET;
} }
Vehicle::~Vehicle() Vehicle::~Vehicle()
@ -794,7 +800,9 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes
case MAVLINK_MSG_ID_ORBIT_EXECUTION_STATUS: case MAVLINK_MSG_ID_ORBIT_EXECUTION_STATUS:
_handleOrbitExecutionStatus(message); _handleOrbitExecutionStatus(message);
break; break;
case MAVLINK_MSG_ID_MESSAGE_INTERVAL:
_handleMessageInterval(message);
break;
case MAVLINK_MSG_ID_PING: case MAVLINK_MSG_ID_PING:
_handlePing(link, message); _handlePing(link, message);
break; break;
@ -3859,6 +3867,74 @@ int Vehicle::versionCompare(int major, int minor, int patch)
return _firmwarePlugin->versionCompare(this, major, minor, patch); return _firmwarePlugin->versionCompare(this, major, minor, patch);
} }
void Vehicle::_handleMessageInterval(const mavlink_message_t& message)
{
if (_pidTuningWaitingForRates) {
mavlink_message_interval_t messageInterval;
mavlink_msg_message_interval_decode(&message, &messageInterval);
int msgId = messageInterval.message_id;
if (_pidTuningMessages.contains(msgId)) {
_pidTuningMessageRatesUsecs[msgId] = messageInterval.interval_us;
}
if (_pidTuningMessageRatesUsecs.count() == _pidTuningMessages.count()) {
// We have back all the rates we requested
_pidTuningWaitingForRates = false;
_pidTuningAdjustRates(true);
}
}
}
void Vehicle::setPIDTuningTelemetryMode(bool pidTuning)
{
if (pidTuning) {
if (!_pidTuningTelemetryMode) {
// First step is to get the current message rates before we adjust them
_pidTuningTelemetryMode = true;
_pidTuningWaitingForRates = true;
_pidTuningMessageRatesUsecs.clear();
for (int telemetry: _pidTuningMessages) {
sendMavCommand(defaultComponentId(),
MAV_CMD_GET_MESSAGE_INTERVAL,
true, // show error
telemetry);
}
}
} else {
if (_pidTuningTelemetryMode) {
_pidTuningTelemetryMode = false;
if (_pidTuningWaitingForRates) {
// We never finished waiting for previous rates
_pidTuningWaitingForRates = false;
} else {
_pidTuningAdjustRates(false);
}
}
}
}
void Vehicle::_pidTuningAdjustRates(bool setRatesForTuning)
{
int requestedRate = (int)(1000000.0 / 30.0); // 30 Hz in usecs
for (int telemetry: _pidTuningMessages) {
if (requestedRate < _pidTuningMessageRatesUsecs[telemetry]) {
sendMavCommand(defaultComponentId(),
MAV_CMD_SET_MESSAGE_INTERVAL,
true, // show error
telemetry,
setRatesForTuning ? requestedRate : _pidTuningMessageRatesUsecs[telemetry]);
}
}
setLiveUpdates(setRatesForTuning);
_setpointFactGroup.setLiveUpdates(setRatesForTuning);
}
#if !defined(NO_ARDUPILOT_DIALECT) #if !defined(NO_ARDUPILOT_DIALECT)
void Vehicle::flashBootloader(void) void Vehicle::flashBootloader(void)
{ {

10
src/Vehicle/Vehicle.h

@ -758,6 +758,8 @@ public:
/// @param percent 0-no power, 100-full power /// @param percent 0-no power, 100-full power
Q_INVOKABLE void motorTest(int motor, int percent); Q_INVOKABLE void motorTest(int motor, int percent);
Q_INVOKABLE void setPIDTuningTelemetryMode(bool pidTuning);
#if !defined(NO_ARDUPILOT_DIALECT) #if !defined(NO_ARDUPILOT_DIALECT)
Q_INVOKABLE void flashBootloader(void); Q_INVOKABLE void flashBootloader(void);
#endif #endif
@ -1265,6 +1267,7 @@ private:
void _handleEstimatorStatus(mavlink_message_t& message); void _handleEstimatorStatus(mavlink_message_t& message);
void _handleStatusText(mavlink_message_t& message, bool longVersion); void _handleStatusText(mavlink_message_t& message, bool longVersion);
void _handleOrbitExecutionStatus(const mavlink_message_t& message); void _handleOrbitExecutionStatus(const mavlink_message_t& message);
void _handleMessageInterval(const mavlink_message_t& message);
// ArduPilot dialect messages // ArduPilot dialect messages
#if !defined(NO_ARDUPILOT_DIALECT) #if !defined(NO_ARDUPILOT_DIALECT)
void _handleCameraFeedback(const mavlink_message_t& message); void _handleCameraFeedback(const mavlink_message_t& message);
@ -1291,6 +1294,7 @@ private:
void _setCapabilities(uint64_t capabilityBits); void _setCapabilities(uint64_t capabilityBits);
void _updateArmed(bool armed); void _updateArmed(bool armed);
bool _apmArmingNotRequired(void); bool _apmArmingNotRequired(void);
void _pidTuningAdjustRates(bool setRatesForTuning);
int _id; ///< Mavlink system id int _id; ///< Mavlink system id
int _defaultComponentId; int _defaultComponentId;
@ -1473,6 +1477,12 @@ private:
QTimer _orbitTelemetryTimer; QTimer _orbitTelemetryTimer;
static const int _orbitTelemetryTimeoutMsecs = 3000; // No telemetry for this amount and orbit will go inactive static const int _orbitTelemetryTimeoutMsecs = 3000; // No telemetry for this amount and orbit will go inactive
// PID Tuning telemetry mode
bool _pidTuningTelemetryMode;
bool _pidTuningWaitingForRates;
QList<int> _pidTuningMessages;
QMap<int, int> _pidTuningMessageRatesUsecs;
// FactGroup facts // FactGroup facts
Fact _rollFact; Fact _rollFact;

Loading…
Cancel
Save