Skip to content

ESC Status Toolbar #13191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 17 commits into
base: master
Choose a base branch
from
Draft
1 change: 1 addition & 0 deletions qgcimages.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
<file alias="MAVLinkInspector.svg">src/AnalyzeView/MAVLinkInspector.svg</file>
<file alias="Megaphone.svg">src/UI/toolbar/Images/Megaphone.svg</file>
<file alias="MotorComponentIcon.svg">src/AutoPilotPlugins/Common/Images/MotorComponentIcon.svg</file>
<file alias="PropellerComponentIcon.svg">src/AutoPilotPlugins/Common/Images/PropellerComponentIcon.svg</file>
<file alias="no-logging-light.svg">src/AutoPilotPlugins/PX4/Images/no-logging-light.svg</file>
<file alias="no-logging.svg">src/AutoPilotPlugins/PX4/Images/no-logging.svg</file>
<file alias="ObjectAvoidance.svg">src/AutoPilotPlugins/PX4/Images/ObjectAvoidance.svg</file>
Expand Down
21 changes: 21 additions & 0 deletions src/AutoPilotPlugins/Common/Images/PropellerComponentIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
88 changes: 85 additions & 3 deletions src/AutoPilotPlugins/PX4/ActuatorComponent.qml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ SetupPage {
showAdvanced: true

property var actuators: globals.activeVehicle.actuators
property var _escStatus: globals.activeVehicle ? globals.activeVehicle.escStatus : null

property var _showAdvanced: advanced
readonly property real _margins: ScreenTools.defaultFontPixelHeight
Expand All @@ -27,6 +28,85 @@ SetupPage {
spacing: ScreenTools.defaultFontPixelWidth * 4
property var _leftColumnWidth: Math.max(actuatorTesting.implicitWidth, mixerUi.implicitWidth) + (_margins * 2)

// ESC data properties
property bool _escDataAvailable: _escStatus ? _escStatus.telemetryAvailable : false
property int _motorCount: _escStatus ? _escStatus.count.rawValue : 0
property int _infoBitmask: _escStatus ? _escStatus.info.rawValue : 0

function _isMotorOnline(motorIndex) {
return (_infoBitmask & (1 << motorIndex)) !== 0
}

function _isMotorHealthy(motorIndex) {
if (!_escDataAvailable || !_isMotorOnline(motorIndex)) return false
var failureFlags = _getMotorFailureFlags(motorIndex)
return failureFlags === 0
}

function _getMotorFailureFlags(motorIndex) {
if (!_escStatus) return 0

switch (motorIndex) {
case 0: return _escStatus.failureFlagsFirst.rawValue
case 1: return _escStatus.failureFlagsSecond.rawValue
case 2: return _escStatus.failureFlagsThird.rawValue
case 3: return _escStatus.failureFlagsFourth.rawValue
case 4: return _escStatus.failureFlagsFifth.rawValue
case 5: return _escStatus.failureFlagsSixth.rawValue
case 6: return _escStatus.failureFlagsSeventh.rawValue
case 7: return _escStatus.failureFlagsEighth.rawValue
default: return 0
}
}

function _getMotorRPM(motorIndex) {
if (!_escStatus) return 0

switch (motorIndex) {
case 0: return _escStatus.rpmFirst.rawValue
case 1: return _escStatus.rpmSecond.rawValue
case 2: return _escStatus.rpmThird.rawValue
case 3: return _escStatus.rpmFourth.rawValue
case 4: return _escStatus.rpmFifth.rawValue
case 5: return _escStatus.rpmSixth.rawValue
case 6: return _escStatus.rpmSeventh.rawValue
case 7: return _escStatus.rpmEighth.rawValue
default: return 0
}
}

function _getMotorVoltage(motorIndex) {
if (!_escStatus) return 0

switch (motorIndex) {
case 0: return _escStatus.voltageFirst.rawValue
case 1: return _escStatus.voltageSecond.rawValue
case 2: return _escStatus.voltageThird.rawValue
case 3: return _escStatus.voltageFourth.rawValue
case 4: return _escStatus.voltageFifth.rawValue
case 5: return _escStatus.voltageSixth.rawValue
case 6: return _escStatus.voltageSeventh.rawValue
case 7: return _escStatus.voltageEighth.rawValue
default: return 0
}
}

function _getMotorCurrent(motorIndex) {
if (!_escStatus) return 0

switch (motorIndex) {
case 0: return _escStatus.currentFirst.rawValue
case 1: return _escStatus.currentSecond.rawValue
case 2: return _escStatus.currentThird.rawValue
case 3: return _escStatus.currentFourth.rawValue
case 4: return _escStatus.currentFifth.rawValue
case 5: return _escStatus.currentSixth.rawValue
case 6: return _escStatus.currentSeventh.rawValue
case 7: return _escStatus.currentEighth.rawValue
default: return 0
}
}

ColumnLayout {
spacing: ScreenTools.defaultFontPixelHeight
implicitWidth: _leftColumnWidth
Expand Down Expand Up @@ -252,7 +332,8 @@ SetupPage {
id: allMotorsComponent
ActuatorSlider {
channel: actuators.actuatorTest.allMotorsActuator
rightPadding: ScreenTools.defaultFontPixelWidth * 3
motorIndex: -1 // Special value for "all" slider
escStatus: _escStatus
onActuatorValueChanged: {
stopTimer();
for (var channelIdx=0; channelIdx<sliderRepeater.count; channelIdx++) {
Expand All @@ -272,6 +353,8 @@ SetupPage {

ActuatorSlider {
channel: object
motorIndex: (object && object.isMotor) ? index : -1
escStatus: _escStatus
onActuatorValueChanged: (value) =>{
if (isNaN(value)) {
actuators.actuatorTest.stopControl(index);
Expand All @@ -281,7 +364,7 @@ SetupPage {
}
}
}
} // Repeater
}
} // Row

// actuator actions
Expand Down Expand Up @@ -334,7 +417,6 @@ SetupPage {
bottomPadding: ScreenTools.defaultFontPixelHeight
}


// actuator output selection tabs
QGCTabBar {
Repeater {
Expand Down
85 changes: 73 additions & 12 deletions src/AutoPilotPlugins/PX4/ActuatorSlider.qml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import QGroundControl
import QGroundControl.Controls
import QGroundControl.ScreenTools

Column {
Item {
property var channel
property alias value: channelSlider.value
property int motorIndex: -1 // Motor index for telemetry, -1 for non-motors
property var escStatus: null // ESC status object

// If the default value is NaN, we add a small range
// below, which snaps into place
Expand All @@ -19,10 +21,52 @@ Column {
property var blockUpdates: true // avoid slider changes on startup

id: root
width: 60 // Fixed width for proper spacing
height: ScreenTools.defaultFontPixelHeight * 6

Layout.alignment: Qt.AlignTop

readonly property int _sliderHeight: 6
// ESC telemetry helper functions
function _isMotorHealthy() {
if (!escStatus || motorIndex < 0 || !escStatus.telemetryAvailable) return false
var infoBitmask = escStatus.info.rawValue
var isOnline = (infoBitmask & (1 << motorIndex)) !== 0
if (!isOnline) return false
var failureFlags = _getMotorFailureFlags()
return failureFlags === 0
}

function _getMotorFailureFlags() {
if (!escStatus || motorIndex < 0) return 0
switch (motorIndex) {
case 0: return escStatus.failureFlagsFirst.rawValue
case 1: return escStatus.failureFlagsSecond.rawValue
case 2: return escStatus.failureFlagsThird.rawValue
case 3: return escStatus.failureFlagsFourth.rawValue
case 4: return escStatus.failureFlagsFifth.rawValue
case 5: return escStatus.failureFlagsSixth.rawValue
case 6: return escStatus.failureFlagsSeventh.rawValue
case 7: return escStatus.failureFlagsEighth.rawValue
default: return 0
}
}

function _getMotorRPM() {
if (!escStatus || motorIndex < 0) return 0
switch (motorIndex) {
case 0: return escStatus.rpmFirst.rawValue
case 1: return escStatus.rpmSecond.rawValue
case 2: return escStatus.rpmThird.rawValue
case 3: return escStatus.rpmFourth.rawValue
case 4: return escStatus.rpmFifth.rawValue
case 5: return escStatus.rpmSixth.rawValue
case 6: return escStatus.rpmSeventh.rawValue
case 7: return escStatus.rpmEighth.rawValue
default: return 0
}
}

readonly property int _sliderHeight: 5

function stopTimer() {
sendTimer.stop();
Expand All @@ -35,15 +79,30 @@ Column {

signal actuatorValueChanged(real value, real sliderValue)

// RPM value positioned above the slider
QGCLabel {
id: rpmLabel
visible: motorIndex >= 0 && channel.isMotor && escStatus && escStatus.telemetryAvailable
text: _isMotorHealthy() ? _getMotorRPM().toString() : qsTr("ERR")
color: _isMotorHealthy() ? qgcPal.text : qgcPal.colorRed

// Center horizontally and position above slider
anchors.horizontalCenter: channelSlider.horizontalCenter
anchors.bottom: channelSlider.top
anchors.bottomMargin: 2
}

QGCSlider {
id: channelSlider
orientation: Qt.Vertical
from: snap ? channel.min - snapRange : channel.min
to: channel.max
from: snap ? channel.min - snapRange : channel.min
to: channel.max
stepSize: (channel.max-channel.min)/100
value: defaultVal
live: true
live: true
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 20 // Leave space for RPM label above
height: ScreenTools.defaultFontPixelHeight * _sliderHeight
indicatorBarVisible: sendTimer.running

Expand Down Expand Up @@ -84,13 +143,15 @@ Column {

QGCLabel {
id: channelLabel
anchors.horizontalCenter: parent.horizontalCenter
text: channel.label
width: contentHeight
height: contentWidth
text: channel.label
font.pointSize: ScreenTools.defaultFontPointSize
width: contentHeight
height: contentWidth
anchors.bottom: parent.bottom
anchors.bottomMargin: 6
transform: [
Rotation { origin.x: 0; origin.y: 0; angle: -90 },
Rotation { origin.x: -5; origin.y: 0; angle: -90 },
Translate { y: channelLabel.height + 5 }
]
]
}
} // Column
} // Item
1 change: 1 addition & 0 deletions src/FirmwarePlugin/FirmwarePlugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ const QVariantList &FirmwarePlugin::toolIndicators(const Vehicle*)
QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Controls/BatteryIndicator.qml")),
QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/RemoteIDIndicator.qml")),
QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/GimbalIndicator.qml")),
QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Controls/EscIndicator.qml")),
// ControlIndicator is only available in debug builds for the moment
#ifdef QT_DEBUG
QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/GCSControlIndicator.qml")),
Expand Down
2 changes: 2 additions & 0 deletions src/QmlControls/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ qt_add_qml_module(QGroundControlControlsModule
DropButton.qml
DropPanel.qml
EditPositionDialog.qml
EscIndicator.qml
EscIndicatorPage.qml
ExclusiveGroupItem.qml
FactSlider.qml
FactSliderPanel.qml
Expand Down
Loading
Loading