Unverified Commit 4b15d5bc authored by Gus Grubba's avatar Gus Grubba Committed by GitHub

Merge pull request #7641 from mavlink/customGimbalControl

Custom Gimbal Control
parents 0adaa167 d7b10093
......@@ -24,6 +24,9 @@
<file alias="compass_needle.svg">res/Images/compass_needle.svg</file>
<file alias="compass_pointer.svg">res/Images/compass_pointer.svg</file>
<file alias="distance.svg">res/Images/distance.svg</file>
<file alias="gimbal_icon.svg">res/Images/gimbal_icon.svg</file>
<file alias="gimbal_pitch.svg">res/Images/gimbal_pitch.svg</file>
<file alias="gimbal_position.svg">res/Images/gimbal_position.svg</file>
<file alias="horizontal_speed.svg">res/Images/horizontal_speed.svg</file>
<file alias="microSD.svg">res/Images/microSD.svg</file>
<file alias="odometer.svg">res/Images/odometer.svg</file>
......@@ -40,6 +43,7 @@
<file alias="Custom/Widgets/CustomComboBox.qml">res/Custom/Widgets/CustomComboBox.qml</file>
<file alias="Custom/Widgets/CustomIconButton.qml">res/Custom/Widgets/CustomIconButton.qml</file>
<file alias="Custom/Widgets/CustomOnOffSwitch.qml">res/Custom/Widgets/CustomOnOffSwitch.qml</file>
<file alias="Custom/Widgets/CustomQuickButton.qml">res/Custom/Widgets/CustomQuickButton.qml</file>
<file alias="Custom/Widgets/CustomSignalStrength.qml">res/Custom/Widgets/CustomSignalStrength.qml</file>
<file alias="Custom/Widgets/CustomToolBarButton.qml">res/Custom/Widgets/CustomToolBarButton.qml</file>
<file alias="Custom/Widgets/CustomVehicleButton.qml">res/Custom/Widgets/CustomVehicleButton.qml</file>
......
/****************************************************************************
*
* (c) 2009-2019 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.
*
* @file
* @author Gus Grubba <gus@auterion.com>
*/
import QtQuick 2.11
import QtQuick.Controls 2.4
import QGroundControl 1.0
import QGroundControl.Controls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.ScreenTools 1.0
Button {
id: control
autoExclusive: true
checkable: true
property string iconSource: ""
property real iconRatio: 0.5
property real buttonRadius: ScreenTools.defaultFontPixelWidth * 0.5
background: Rectangle {
width: control.width
height: width
anchors.centerIn: parent
color: (mouseArea.pressed || control.checked) ? qgcPal.buttonHighlight : (qgcPal.globalTheme === QGCPalette.Light ? Qt.rgba(1,1,1,0.5) : Qt.rgba(0,0,0,0.5))
radius: control.buttonRadius
}
contentItem: Item {
anchors.fill: control
QGCColoredImage {
source: iconSource
color: (mouseArea.pressed || control.checked) ? qgcPal.buttonHighlightText : qgcPal.buttonText
width: control.width * iconRatio
height: width
anchors.centerIn: parent
sourceSize.height: height
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: {
if(checkable)
checked = true
control.clicked()
}
}
}
......@@ -5,6 +5,7 @@ CustomAttitudeWidget 1.0 CustomAttitudeWidget.qml
CustomComboBox 1.0 CustomComboBox.qml
CustomIconButton 1.0 CustomIconButton.qml
CustomOnOffSwitch 1.0 CustomOnOffSwitch.qml
CustomQuickButton 1.0 CustomQuickButton.qml
CustomSignalStrength 1.0 CustomSignalStrength.qml
CustomToolBarButton 1.0 CustomToolBarButton.qml
CustomVehicleButton 1.0 CustomVehicleButton.qml
This diff is collapsed.
......@@ -50,6 +50,7 @@ Item {
property var _camera: _isCamera ? _dynamicCameras.cameras.get(_curCameraIndex) : null
property bool _cameraPresent: _camera && _camera.cameraMode !== QGCCameraControl.CAM_MODE_UNDEFINED
property var _flightPermit: QGroundControl.airmapSupported ? QGroundControl.airspaceManager.flightPlan.flightPermitStatus : null
property bool _hasGimbal: activeVehicle && activeVehicle.gimbalData
property bool _airspaceIndicatorVisible: QGroundControl.airmapSupported && mainIsMap && _flightPermit && _flightPermit !== AirspaceFlightPlanProvider.PermitNone
......@@ -143,7 +144,7 @@ Item {
connectionLostDisarmedDialog.close()
}
}
//-------------------------------------------------------------------------
MessageDialog {
id: connectionLostDisarmedDialog
title: qsTr("Communication Lost")
......@@ -153,7 +154,7 @@ Item {
connectionLostDisarmedDialog.close()
}
}
//-------------------------------------------------------------------------
//-- Heading Indicator
Rectangle {
id: compassBar
......@@ -163,7 +164,7 @@ Item {
radius: 2
clip: true
anchors.top: parent.top
anchors.topMargin: ScreenTools.defaultFontPixelHeight * (_airspaceIndicatorVisible ? 3 : 2)
anchors.topMargin: ScreenTools.defaultFontPixelHeight * (_airspaceIndicatorVisible ? 3 : 1)
anchors.horizontalCenter: parent.horizontalCenter
visible: !mainIsMap
Repeater {
......@@ -225,7 +226,7 @@ Item {
anchors.topMargin: ScreenTools.defaultFontPixelHeight * -0.5
anchors.horizontalCenter: parent.horizontalCenter
}
//-------------------------------------------------------------------------
//-- Camera Control
Loader {
id: camControlLoader
......@@ -234,9 +235,9 @@ Item {
anchors.right: parent.right
anchors.rightMargin: ScreenTools.defaultFontPixelWidth
anchors.top: parent.top
anchors.topMargin: ScreenTools.defaultFontPixelHeight * 4
anchors.topMargin: ScreenTools.defaultFontPixelHeight
}
//-------------------------------------------------------------------------
//-- Map Scale
MapScale {
id: mapScale
......@@ -247,7 +248,7 @@ Item {
mapControl: mainWindow.flightDisplayMap
visible: rootBackground.visible && mainIsMap
}
//-------------------------------------------------------------------------
//-- Vehicle Indicator
Rectangle {
id: vehicleIndicator
......@@ -457,7 +458,7 @@ Item {
onDoubleClicked: _showAttitude = !_showAttitude
}
}
//-------------------------------------------------------------------------
//-- Attitude Indicator
Rectangle {
color: qgcPal.window
......@@ -485,7 +486,7 @@ Item {
anchors.centerIn: parent
}
}
//-------------------------------------------------------------------------
//-- Multi Vehicle Selector
Row {
id: multiVehicleSelector
......@@ -507,42 +508,99 @@ Item {
}
}
}
//-------------------------------------------------------------------------
//-- Gimbal Control
Item {
Rectangle {
id: gimbalControl
visible: camControlLoader.visible && CustomQuickInterface.showGimbalControl
visible: camControlLoader.visible && CustomQuickInterface.showGimbalControl && _hasGimbal
anchors.bottom: camControlLoader.bottom
anchors.right: camControlLoader.left
anchors.rightMargin: ScreenTools.defaultFontPixelWidth * (QGroundControl.videoManager.hasThermal ? -4 : 2)
anchors.rightMargin: ScreenTools.defaultFontPixelWidth * (QGroundControl.videoManager.hasThermal ? -1 : 1)
height: parent.width * 0.125
width: height
property real curPitch: 0
property real curYaw: 0
color: Qt.rgba(1,1,1,0.25)
radius: width * 0.5
property real _currentPitch: 0
property real _currentYaw: 0
property real time_last_seconds:0
property real _lastHackedYaw: 0
property real speedMultiplier: 5
property real maxRate: 20
property real exponentialFactor:0.6
property real kPFactor: 3
property real reportedYawDeg: activeVehicle ? activeVehicle.gimbalYaw : NaN
property real reportedPitchDeg: activeVehicle ? activeVehicle.gimbalPitch : NaN
Timer {
interval: 100 //-- 10Hz
running: gimbalControl.visible && activeVehicle
repeat: true
onTriggered: {
if (activeVehicle) {
var p = Math.round(stick.yAxis * -90)
var y = Math.round(stick.xAxis * 180)
if(p !== gimbalControl.curPitch || y !== gimbalControl.curYaw) {
gimbalControl.curPitch = p
gimbalControl.curYaw = y
activeVehicle.gimbalControlValue(p, y)
var yaw = gimbalControl._currentYaw
var oldYaw = yaw;
var pitch = gimbalControl._currentPitch
var oldPitch = pitch;
var pitch_stick = (stick.yAxis * 2.0 - 1.0)
if(_camera && _camera.vendor === "NextVision") {
var time_current_seconds = ((new Date()).getTime())/1000.0
if(gimbalControl.time_last_seconds === 0.0)
gimbalControl.time_last_seconds = time_current_seconds
var pitch_angle = gimbalControl._currentPitch
// Preparing stick input with exponential curve and maximum rate
var pitch_expo = (1 - gimbalControl.exponentialFactor) * pitch_stick + gimbalControl.exponentialFactor * pitch_stick * pitch_stick * pitch_stick
var pitch_rate = pitch_stick * gimbalControl.maxRate
var pitch_angle_reported = gimbalControl.reportedPitchDeg
// Integrate the angular rate to an angle time abstracted
pitch_angle += pitch_rate * (time_current_seconds - gimbalControl.time_last_seconds)
// Control the angle quicker by driving the gimbal internal angle controller into saturation
var pitch_angle_error = pitch_angle - pitch_angle_reported
pitch_angle_error = Math.round(pitch_angle_error)
var pitch_setpoint = pitch_angle + pitch_angle_error * gimbalControl.kPFactor
//console.info("error: " + pitch_angle_error + "; angle_state: " + pitch_angle)
pitch = pitch_setpoint
yaw += stick.xAxis * gimbalControl.speedMultiplier
yaw = clamp(yaw, -180, 180)
pitch = clamp(pitch, -45, 45)
//console.info("P: " + pitch + "; Y: " + yaw)
activeVehicle.gimbalControlValue(pitch, yaw);
gimbalControl._currentYaw = yaw
gimbalControl._currentPitch = pitch_angle
gimbalControl.time_last_seconds = time_current_seconds
} else {
yaw += stick.xAxis * gimbalControl.speedMultiplier
var hackedYaw = yaw + (stick.xAxis * gimbalControl.speedMultiplier * 25)
pitch += pitch_stick * gimbalControl.speedMultiplier
hackedYaw = clamp(hackedYaw, -180, 180)
yaw = clamp(yaw, -180, 180)
pitch = clamp(pitch, -90, 90)
if(gimbalControl._lastHackedYaw !== hackedYaw || gimbalControl.hackedYaw !== oldYaw || pitch !== oldPitch) {
activeVehicle.gimbalControlValue(pitch, hackedYaw)
gimbalControl._lastHackedYaw = hackedYaw
gimbalControl._currentPitch = pitch
gimbalControl._currentYaw = yaw
}
}
}
}
function clamp(num, min, max) {
return Math.min(Math.max(num, min), max);
}
}
JoystickThumbPad {
id: stick
anchors.fill: parent
lightColors: true
lightColors: qgcPal.globalTheme === QGCPalette.Light
yAxisThrottle: true
yAxisThrottleCentered: true
springYToCenter: false
xAxis: 0
yAxis: 0.5
}
}
//-------------------------------------------------------------------------
//-- Connection Lost While Armed
Popup {
id: connectionLostArmed
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 72 72" style="enable-background:new 0 0 72 72;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
</style>
<title>670134</title>
<desc>Created with Sketch.</desc>
<path class="st0" d="M19.589,25.301L19.589,25.301c1.113-0.307,2.259,0.344,2.57,1.453c0.307,1.109-0.345,2.258-1.453,2.565
c-7.701,2.139-13.367,9.206-13.359,17.587c0,3.427,0.996,6.588,2.637,9.322l0.775-4.4c0.198-1.135,1.281-1.895,2.416-1.693
c1.135,0.198,1.895,1.281,1.693,2.416L13.26,61.67l-0.378,0.595c-0.09,0.157-0.067,0.352-0.202,0.487
c-0.041,0.041-0.101,0.022-0.146,0.06l-0.131,0.206l-0.79,0.176c-0.191,0.037-0.341,0.127-0.532,0.116l-0.236,0.052l-9.119-1.607
c-1.135-0.198-1.895-1.281-1.693-2.416c0.198-1.135,1.281-1.895,2.416-1.693l3.959,0.697c-2.007-3.36-3.232-7.247-3.232-11.438
C3.178,36.604,10.118,27.927,19.589,25.301z M69.549,57.648L69.549,57.648c1.135-0.202,2.218,0.554,2.42,1.689
c0.199,1.135-0.558,2.213-1.693,2.416l-9.119,1.607l-0.236-0.052c-0.191,0.015-0.345-0.075-0.532-0.116l-0.79-0.176l-0.131-0.206
c-0.041-0.037-0.105-0.019-0.146-0.06c-0.135-0.135-0.112-0.33-0.202-0.487l-0.378-0.595l-1.607-9.119
c-0.199-1.135,0.558-2.213,1.693-2.416c1.135-0.199,2.213,0.558,2.416,1.693l0.775,4.404c1.64-2.734,2.64-5.895,2.64-9.322
c0.003-8.385-5.663-15.453-13.363-17.587c-1.112-0.307-1.76-1.457-1.453-2.565c0.307-1.112,1.457-1.76,2.565-1.453
c9.471,2.625,16.411,11.303,16.415,21.605c0,4.191-1.225,8.079-3.232,11.438L69.549,57.648z M41.772,20.352l-4.565-4.566
l0.004,28.939l4.565-4.565c0.813-0.813,2.135-0.813,2.947,0c0.813,0.813,0.813,2.131,0,2.947L36.6,51.23
c-0.378,0.378-0.899,0.61-1.476,0.61c-0.577,0-1.097-0.232-1.476-0.61l-8.157-8.157c-0.813-0.813-0.813-2.135,0-2.947
c0.813-0.813,2.131-0.813,2.947,0l4.599,4.599V15.719l-4.599,4.599c-0.813,0.813-2.135,0.813-2.947,0
c-0.813-0.813-0.813-2.135,0-2.947l8.123-8.123c0.412-0.412,0.951-0.607,1.491-0.603c0.004,0,0.007-0.007,0.015-0.007
c0.599,0,1.12,0.262,1.498,0.667l8.101,8.101c0.813,0.813,0.813,2.135,0,2.947C43.907,21.164,42.585,21.164,41.772,20.352z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 72 756" style="enable-background:new 0 0 72 756;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#9F0B10;stroke-width:3;stroke-miterlimit:10;}
.st1{fill:none;stroke:#FFFFFF;stroke-width:3;stroke-miterlimit:10;}
.st2{fill:none;stroke:#FFFFFF;stroke-width:6;stroke-miterlimit:10;}
.st3{fill:none;stroke:#9F0B10;stroke-width:6;stroke-miterlimit:10;}
</style>
<line class="st0" x1="36" y1="0" x2="36" y2="108"/>
<line class="st1" x1="36" y1="108" x2="36" y2="756"/>
<line class="st2" x1="18" y1="108" x2="54" y2="108"/>
<line class="st2" x1="18" y1="324" x2="54" y2="324"/>
<line class="st2" x1="18" y1="540" x2="54" y2="540"/>
<line class="st2" x1="18" y1="753" x2="54" y2="753"/>
<line class="st3" x1="18" y1="3" x2="54" y2="3"/>
<line class="st1" x1="23.4" y1="216" x2="48.6" y2="216"/>
<line class="st1" x1="23.4" y1="432" x2="48.6" y2="432"/>
<line class="st1" x1="23.4" y1="648" x2="48.6" y2="648"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 72 72" style="enable-background:new 0 0 72 72;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#48D6FF;}
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:url(#Rectangle_1_);}
</style>
<title>gimbal position</title>
<desc>Created with Sketch.</desc>
<g id="Camera-focused">
<g transform="translate(-972.000000, -253.000000)">
<g id="middle" transform="translate(29.000000, 162.000000)">
<g id="right" transform="translate(841.000000, 0.000000)">
<g id="gimbal" transform="translate(102.000000, 53.000000)">
<g id="gimbal-position" transform="translate(0.000000, 38.000000)">
<ellipse id="Oval" class="st0" cx="36" cy="35.24" rx="9.683" ry="9.36"/>
<linearGradient id="Rectangle_1_" gradientUnits="userSpaceOnUse" x1="-295.5833" y1="277.1371" x2="-295.5833" y2="278.9163" gradientTransform="matrix(24 0 0 20.082 7130 -5563.6465)">
<stop offset="0" style="stop-color:#48D6FF;stop-opacity:0"/>
<stop offset="1" style="stop-color:#48D6FF"/>
</linearGradient>
<polygon id="Rectangle" class="st1" points="14.4,1.4 57.6,1.4 45.387,37.548 26.585,37.434 "/>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
......@@ -45,6 +45,8 @@ Item {
Component.onCompleted: {
flyButton.checked = true
sectionTitle = flyButton.text
//-- Show full screen
mainWindow.showFullScreen()
}
//-------------------------------------------------------------------------
//-- Fly/Plan state toggle
......
......@@ -218,7 +218,7 @@ CustomPlugin::adjustSettingMetaData(const QString& settingsGroup, FactMetaData&
{
if (settingsGroup == AppSettings::settingsGroup) {
if (metaData.name() == AppSettings::appFontPointSizeName) {
#if defined(WIN32)
#if defined(Q_OS_LINUX)
int defaultFontPointSize = 11;
metaData.setRawDefaultValue(defaultFontPointSize);
#endif
......@@ -231,7 +231,6 @@ CustomPlugin::adjustSettingMetaData(const QString& settingsGroup, FactMetaData&
return true;
}
const QColor CustomPlugin::_windowShadeEnabledLightColor("#FFFFFF");
const QColor CustomPlugin::_windowShadeEnabledDarkColor("#212529");
......
......@@ -42,6 +42,9 @@ class CustomOptions : public QGCOptions
public:
CustomOptions(CustomPlugin*, QObject* parent = nullptr);
bool wifiReliableForCalibration () const final { return true; }
#if defined(Q_OS_LINUX)
double toolbarHeightMultiplier () final { return 1.25; }
#endif
QUrl flyViewOverlay () const final { return QUrl::fromUserInput("qrc:/custom/CustomFlyView.qml"); }
QUrl preFlightChecklistUrl () const final { return QUrl::fromUserInput("qrc:/custom/PreFlightCheckList.qml"); }
//-- We have our own toolbar
......
......@@ -18,6 +18,7 @@ QGC_LOGGING_CATEGORY(CustomCameraLog, "CustomCameraLog")
QGC_LOGGING_CATEGORY(CustomCameraVerboseLog, "CustomCameraVerboseLog")
static const char* kCAM_IRPALETTE = "CAM_IRPALETTE";
static const char* kCAM_NEXTVISION_IRPALETTE = "IR_SENS_POL";
//-----------------------------------------------------------------------------
CustomCameraControl::CustomCameraControl(const mavlink_camera_information_t *info, Vehicle* vehicle, int compID, QObject* parent)
......@@ -104,6 +105,30 @@ CustomCameraControl::handleCaptureStatus(const mavlink_camera_capture_status_t&
Fact*
CustomCameraControl::irPalette()
{
return (_paramComplete && _activeSettings.contains(kCAM_IRPALETTE)) ? getFact(kCAM_IRPALETTE) : nullptr;
if(_paramComplete) {
if(_activeSettings.contains(kCAM_IRPALETTE)) {
return getFact(kCAM_IRPALETTE);
}
else if(_activeSettings.contains(kCAM_NEXTVISION_IRPALETTE)) {
return getFact(kCAM_NEXTVISION_IRPALETTE);
}
}
return nullptr;
}
//-----------------------------------------------------------------------------
void
CustomCameraControl::setThermalMode(ThermalViewMode mode)
{
if(_paramComplete) {
if(vendor() == "NextVision" && _activeSettings.contains("CAM_SENSOR")) {
if(mode == THERMAL_FULL) {
getFact("CAM_SENSOR")->setRawValue(1);
}
else if(mode == THERMAL_OFF) {
getFact("CAM_SENSOR")->setRawValue(0);
}
}
}
QGCCameraControl::setThermalMode(mode);
}
......@@ -38,6 +38,7 @@ public:
void setVideoMode () override;
void setPhotoMode () override;
void handleCaptureStatus (const mavlink_camera_capture_status_t& capStatus) override;
void setThermalMode (ThermalViewMode mode) override;
protected:
void _setVideoStatus (VideoStatus status) override;
......
......@@ -98,8 +98,16 @@ Rectangle {
Component.onCompleted: showSummaryPanel()
Connections {
target: QGroundControl.multiVehicleManager
target: QGroundControl.corePlugin
onShowAdvancedUIChanged: {
if(!QGroundControl.corePlugin.showAdvancedUI) {
showSummaryPanel()
}
}
}
Connections {
target: QGroundControl.multiVehicleManager
onParameterReadyVehicleAvailableChanged: {
if(!QGroundControl.skipSetupPage) {
if (QGroundControl.multiVehicleManager.parameterReadyVehicleAvailable || summaryButton.checked || setupButtonGroup.current != firmwareButton) {
......@@ -116,10 +124,8 @@ Rectangle {
Component {
id: noComponentsVehicleSummaryComponent
Rectangle {
color: qgcPal.windowShade
QGCLabel {
anchors.margins: _defaultTextWidth * 2
anchors.fill: parent
......@@ -129,7 +135,6 @@ Rectangle {
font.pointSize: ScreenTools.mediumFontPointSize
text: qsTr("%1 does not currently support setup of your vehicle type. ").arg(QGroundControl.appName) +
"If your vehicle is already configured you can still Fly."
onLinkActivated: Qt.openUrlExternally(link)
}
}
......@@ -137,10 +142,8 @@ Rectangle {
Component {
id: disconnectedVehicleSummaryComponent
Rectangle {
color: qgcPal.windowShade
QGCLabel {
anchors.margins: _defaultTextWidth * 2
anchors.fill: parent
......
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