Commit 0aea0088 authored by Don Gagne's avatar Don Gagne

Motor Setup/Testing support

parent 6920c117
......@@ -63,6 +63,7 @@
<file alias="LandModeCopter.svg">src/AutoPilotPlugins/PX4/Images/LandModeCopter.svg</file>
<file alias="LowBattery.svg">src/AutoPilotPlugins/PX4/Images/LowBattery.svg</file>
<file alias="LowBatteryLight.svg">src/AutoPilotPlugins/PX4/Images/LowBatteryLight.svg</file>
<file alias="MotorComponentIcon.png">src/AutoPilotPlugins/Common/MotorComponentIcon.png</file>
<file alias="PowerComponentBattery_01cell.svg">src/AutoPilotPlugins/PX4/Images/PowerComponentBattery_01cell.svg</file>
<file alias="PowerComponentBattery_02cell.svg">src/AutoPilotPlugins/PX4/Images/PowerComponentBattery_02cell.svg</file>
<file alias="PowerComponentBattery_03cell.svg">src/AutoPilotPlugins/PX4/Images/PowerComponentBattery_03cell.svg</file>
......
......@@ -638,6 +638,7 @@ HEADERS+= \
src/AutoPilotPlugins/APM/APMSensorsComponent.h \
src/AutoPilotPlugins/APM/APMSensorsComponentController.h \
src/AutoPilotPlugins/APM/APMTuningComponent.h \
src/AutoPilotPlugins/Common/MotorComponent.h \
src/AutoPilotPlugins/Common/RadioComponentController.h \
src/AutoPilotPlugins/Common/ESP8266ComponentController.h \
src/AutoPilotPlugins/Common/ESP8266Component.h \
......@@ -696,6 +697,7 @@ SOURCES += \
src/AutoPilotPlugins/APM/APMSensorsComponent.cc \
src/AutoPilotPlugins/APM/APMSensorsComponentController.cc \
src/AutoPilotPlugins/APM/APMTuningComponent.cc \
src/AutoPilotPlugins/Common/MotorComponent.cc \
src/AutoPilotPlugins/Common/RadioComponentController.cc \
src/AutoPilotPlugins/Common/ESP8266ComponentController.cc \
src/AutoPilotPlugins/Common/ESP8266Component.cc \
......
......@@ -39,6 +39,7 @@
<file alias="MainWindowNative.qml">src/ui/MainWindowNative.qml</file>
<file alias="MainWindowLeftPanel.qml">src/ui/MainWindowLeftPanel.qml</file>
<file alias="MissionEditor.qml">src/MissionEditor/MissionEditor.qml</file>
<file alias="MotorComponent.qml">src/AutoPilotPlugins/Common/MotorComponent.qml</file>
<file alias="PowerComponent.qml">src/AutoPilotPlugins/PX4/PowerComponent.qml</file>
<file alias="PowerComponentSummary.qml">src/AutoPilotPlugins/PX4/PowerComponentSummary.qml</file>
<file alias="PX4FlowSensor.qml">src/VehicleSetup/PX4FlowSensor.qml</file>
......@@ -55,6 +56,8 @@
<file alias="QGroundControl/Controls/MissionItemIndexLabel.qml">src/QmlControls/MissionItemIndexLabel.qml</file>
<file alias="QGroundControl/Controls/MissionItemStatus.qml">src/MissionEditor/MissionItemStatus.qml</file>
<file alias="QGroundControl/Controls/MissionCommandDialog.qml">src/QmlControls/MissionCommandDialog.qml</file>
<file alias="QGroundControl/Controls/MultiRotorMotorDisplay.qml">src/QmlControls/MultiRotorMotorDisplay.qml</file>
<file alias="QGroundControl/Controls/MultiRotorMotorDisplayLegend.qml">src/QmlControls/MultiRotorMotorDisplayLegend.qml</file>
<file alias="QGroundControl/Controls/ModeSwitchDisplay.qml">src/QmlControls/ModeSwitchDisplay.qml</file>
<file alias="QGroundControl/Controls/ParameterEditor.qml">src/QmlControls/ParameterEditor.qml</file>
<file alias="QGroundControl/Controls/ParameterEditorDialog.qml">src/QmlControls/ParameterEditorDialog.qml</file>
......@@ -71,6 +74,7 @@
<file alias="QGroundControl/Controls/QGCMovableItem.qml">src/QmlControls/QGCMovableItem.qml</file>
<file alias="QGroundControl/Controls/QGCPipable.qml">src/QmlControls/QGCPipable.qml</file>
<file alias="QGroundControl/Controls/QGCRadioButton.qml">src/QmlControls/QGCRadioButton.qml</file>
<file alias="QGroundControl/Controls/QGCSlider.qml">src/QmlControls/QGCSlider.qml</file>
<file alias="QGroundControl/Controls/QGCTextField.qml">src/QmlControls/QGCTextField.qml</file>
<file alias="QGroundControl/Controls/QGCToolBarButton.qml">src/QmlControls/QGCToolBarButton.qml</file>
<file alias="QGroundControl/Controls/QGCView.qml">src/QmlControls/QGCView.qml</file>
......@@ -78,6 +82,7 @@
<file alias="QGroundControl/Controls/QGCViewMessage.qml">src/QmlControls/QGCViewMessage.qml</file>
<file alias="QGroundControl/Controls/QGCViewPanel.qml">src/QmlControls/QGCViewPanel.qml</file>
<file alias="QGroundControl/Controls/RoundButton.qml">src/QmlControls/RoundButton.qml</file>
<file alias="QGroundControl/Controls/SetupPage.qml">src/AutoPilotPlugins/Common/SetupPage.qml</file>
<file alias="QGroundControl/Controls/SignalStrength.qml">src/ui/toolbar/SignalStrength.qml</file>
<file alias="QGroundControl/Controls/SliderSwitch.qml">src/QmlControls/SliderSwitch.qml</file>
<file alias="QGroundControl/Controls/SubMenuButton.qml">src/QmlControls/SubMenuButton.qml</file>
......@@ -113,7 +118,6 @@
<file alias="QGroundControl/FlightMap/QGCInstrumentWidget.qml">src/FlightMap/Widgets/QGCInstrumentWidget.qml</file>
<file alias="QGroundControl/FlightMap/QGCInstrumentWidgetAlternate.qml">src/FlightMap/Widgets/QGCInstrumentWidgetAlternate.qml</file>
<file alias="QGroundControl/FlightMap/QGCPitchIndicator.qml">src/FlightMap/Widgets/QGCPitchIndicator.qml</file>
<file alias="QGroundControl/FlightMap/QGCSlider.qml">src/FlightMap/Widgets/QGCSlider.qml</file>
<file alias="QGroundControl/FlightMap/QGCVideoBackground.qml">src/FlightMap/QGCVideoBackground.qml</file>
<file alias="QGroundControl/FlightMap/ValuesWidget.qml">src/FlightMap/Widgets/ValuesWidget.qml</file>
<file alias="QGroundControl/FlightMap/VibrationWidget.qml">src/FlightMap/Widgets/VibrationWidget.qml</file>
......
......@@ -25,6 +25,7 @@
#include "APMTuningComponent.h"
#include "APMSensorsComponent.h"
#include "APMPowerComponent.h"
#include "MotorComponent.h"
#include "APMCameraComponent.h"
#include "ESP8266Component.h"
......@@ -36,6 +37,7 @@ APMAutoPilotPlugin::APMAutoPilotPlugin(Vehicle* vehicle, QObject* parent)
, _cameraComponent(NULL)
, _flightModesComponent(NULL)
, _powerComponent(NULL)
, _motorComponent(NULL)
, _radioComponent(NULL)
, _safetyComponent(NULL)
, _sensorsComponent(NULL)
......@@ -77,6 +79,12 @@ const QVariantList& APMAutoPilotPlugin::vehicleComponents(void)
_powerComponent->setupTriggerSignals();
_components.append(QVariant::fromValue((VehicleComponent*)_powerComponent));
if (_vehicle->multiRotor() || _vehicle->vtol()) {
_motorComponent = new MotorComponent(_vehicle, this);
_motorComponent->setupTriggerSignals();
_components.append(QVariant::fromValue((VehicleComponent*)_motorComponent));
}
_safetyComponent = new APMSafetyComponent(_vehicle, this);
_safetyComponent->setupTriggerSignals();
_components.append(QVariant::fromValue((VehicleComponent*)_safetyComponent));
......
......@@ -22,6 +22,7 @@ class APMTuningComponent;
class APMSafetyComponent;
class APMSensorsComponent;
class APMPowerComponent;
class MotorComponent;
class APMCameraComponent;
class ESP8266Component;
......@@ -41,6 +42,7 @@ public:
APMCameraComponent* cameraComponent (void) const { return _cameraComponent; }
APMFlightModesComponent* flightModesComponent(void) const { return _flightModesComponent; }
APMPowerComponent* powerComponent (void) const { return _powerComponent; }
MotorComponent* motorComponent (void) const { return _motorComponent; }
APMRadioComponent* radioComponent (void) const { return _radioComponent; }
APMSafetyComponent* safetyComponent (void) const { return _safetyComponent; }
APMSensorsComponent* sensorsComponent (void) const { return _sensorsComponent; }
......@@ -59,6 +61,7 @@ private:
APMCameraComponent* _cameraComponent;
APMFlightModesComponent* _flightModesComponent;
APMPowerComponent* _powerComponent;
MotorComponent* _motorComponent;
APMRadioComponent* _radioComponent;
APMSafetyComponent* _safetyComponent;
APMSensorsComponent* _sensorsComponent;
......
/****************************************************************************
*
* (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.
*
****************************************************************************/
#include "MotorComponent.h"
#include "APMAutoPilotPlugin.h"
#include "APMAirframeComponent.h"
MotorComponent::MotorComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent) :
VehicleComponent(vehicle, autopilot, parent),
_name(tr("Motors"))
{
}
QString MotorComponent::name(void) const
{
return _name;
}
QString MotorComponent::description(void) const
{
return tr("Motors Setup is used to manually test motor control and direction.");
}
QString MotorComponent::iconResource(void) const
{
return QStringLiteral("/qmlimages/MotorComponentIcon.png");
}
bool MotorComponent::requiresSetup(void) const
{
return false;
}
bool MotorComponent::setupComplete(void) const
{
return true;
}
QStringList MotorComponent::setupCompleteChangedTriggerList(void) const
{
return QStringList();
}
QUrl MotorComponent::setupSource(void) const
{
return QUrl::fromUserInput(QStringLiteral("qrc:/qml/MotorComponent.qml"));
}
QUrl MotorComponent::summaryQmlSource(void) const
{
return QUrl();
}
QString MotorComponent::prerequisiteSetup(void) const
{
return QString();
}
/****************************************************************************
*
* (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.
*
****************************************************************************/
#ifndef MotorComponent_H
#define MotorComponent_H
#include "VehicleComponent.h"
#include "Fact.h"
class MotorComponent : public VehicleComponent
{
Q_OBJECT
public:
MotorComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent = NULL);
// Virtuals from VehicleComponent
QStringList setupCompleteChangedTriggerList(void) const final;
// Virtuals from VehicleComponent
QString name(void) const final;
QString description(void) const final;
QString iconResource(void) const final;
bool requiresSetup(void) const final;
bool setupComplete(void) const final;
QUrl setupSource(void) const final;
QUrl summaryQmlSource(void) const final;
QString prerequisiteSetup(void) const final;
private:
const QString _name;
};
#endif
/****************************************************************************
*
* (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.5
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import QGroundControl 1.0
import QGroundControl.Controls 1.0
import QGroundControl.FactSystem 1.0
import QGroundControl.ScreenTools 1.0
SetupPage {
id: motorPage
pageComponent: pageComponent
readonly property int _barHeight: 10
readonly property int _barWidth: 5
readonly property int _sliderHeight: 10
FactPanelController {
id: controller
factPanel: motorPage.viewPanel
}
Component {
id: pageComponent
Column {
spacing: 10
Row {
id: motorSliders
enabled: safetySwitch.checked
spacing: ScreenTools.defaultFontPixelWidth * 4
Repeater {
id: sliderRepeater
model: controller.vehicle.motorCount == -1 ? 8 : controller.vehicle.motorCount
Column {
property alias motorSlider: slider
Timer {
interval: 250
running: true
repeat: true
property real _lastValue: 0
onTriggered: {
if (_lastValue != slider.value) {
controller.vehicle.motorTest(index + 1, slider.value, 1)
}
}
}
QGCLabel {
anchors.horizontalCenter: parent.horizontalCenter
text: index + 1
}
QGCSlider {
id: slider
height: ScreenTools.defaultFontPixelHeight * _sliderHeight
orientation: Qt.Vertical
maximumValue: 100
value: 0
}
} // Column
} // Repeater
Column {
QGCLabel {
anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("All")
}
QGCSlider {
id: allSlider
height: ScreenTools.defaultFontPixelHeight * _sliderHeight
orientation: Qt.Vertical
maximumValue: 100
value: 0
onValueChanged: {
for (var sliderIndex=0; sliderIndex<sliderRepeater.count; sliderIndex++) {
sliderRepeater.itemAt(sliderIndex).motorSlider.value = allSlider.value
}
}
}
} // Column
MultiRotorMotorDisplay {
anchors.top: parent.top
anchors.bottom: parent.bottom
width: height
motorCount: controller.vehicle.motorCount
xConfig: controller.vehicle.xConfigMotors
coaxial: controller.vehicle.coaxialMotors
}
MultiRotorMotorDisplayLegend {
anchors.top: parent.top
anchors.bottom: parent.bottom
width: height
}
} // Row
QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: qsTr("Moving the sliders will causes the motors to spin. Make sure you remove all props.")
}
Row {
spacing: ScreenTools.defaultFontPixelWidth
Switch {
id: safetySwitch
onClicked: {
if (!checked) {
for (var sliderIndex=0; sliderIndex<sliderRepeater.count; sliderIndex++) {
sliderRepeater.itemAt(sliderIndex).motorSlider.value = 0
}
allSlider.value = 0
}
}
}
QGCLabel {
color: qgcPal.warningText
text: qsTr("Propellors are removed - Enable motor sliders")
}
} // Row
} // Column
} // Component
} // SetupPahe
/****************************************************************************
*
* (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.5
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import QGroundControl 1.0
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.Controls 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Controllers 1.0
/// Base view control for all Setup pages
QGCView {
id: setupView
viewPanel: setupPanel
property alias pageComponent: pageLoader.sourceComponent
property real _margins: ScreenTools.defaultFontPixelHeight / 2
QGCPalette { id: qgcPal; colorGroupEnabled: setupPanel.enabled }
QGCViewPanel {
id: setupPanel
anchors.fill: parent
QGCFlickable {
anchors.fill: parent
contentWidth: pageLoader.item.x + pageLoader.item.width
contentHeight: pageLoader.item.y + pageLoader.item.height
clip: true
Column {
id: headingColumn
anchors.left: parent.left
anchors.right: parent.right
spacing: _margins
QGCLabel {
font.pointSize: ScreenTools.largeFontPointSize
text: vehicleComponent.name + " " + qsTr("Setup")
visible: !ScreenTools.isShortScreen
}
QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: vehicleComponent.description
visible: !ScreenTools.isShortScreen
}
}
Loader {
anchors.topMargin: _margins
anchors.top: headingColumn.bottom
id: pageLoader
}
}
}
}
......@@ -22,16 +22,17 @@
/// @brief This is the AutoPilotPlugin implementatin for the MAV_AUTOPILOT_PX4 type.
/// @author Don Gagne <don@thegagnes.com>
PX4AutoPilotPlugin::PX4AutoPilotPlugin(Vehicle* vehicle, QObject* parent) :
AutoPilotPlugin(vehicle, parent),
_airframeComponent(NULL),
_radioComponent(NULL),
_esp8266Component(NULL),
_flightModesComponent(NULL),
_sensorsComponent(NULL),
_safetyComponent(NULL),
_powerComponent(NULL),
_incorrectParameterVersion(false)
PX4AutoPilotPlugin::PX4AutoPilotPlugin(Vehicle* vehicle, QObject* parent)
: AutoPilotPlugin(vehicle, parent)
, _airframeComponent(NULL)
, _radioComponent(NULL)
, _esp8266Component(NULL)
, _flightModesComponent(NULL)
, _sensorsComponent(NULL)
, _safetyComponent(NULL)
, _powerComponent(NULL)
, _motorComponent(NULL)
, _incorrectParameterVersion(false)
{
Q_ASSERT(vehicle);
......@@ -74,6 +75,13 @@ const QVariantList& PX4AutoPilotPlugin::vehicleComponents(void)
_powerComponent->setupTriggerSignals();
_components.append(QVariant::fromValue((VehicleComponent*)_powerComponent));
#if 0
// Coming soon
_motorComponent = new MotorComponent(_vehicle, this);
_motorComponent->setupTriggerSignals();
_components.append(QVariant::fromValue((VehicleComponent*)_motorComponent));
#endif
_safetyComponent = new SafetyComponent(_vehicle, this);
_safetyComponent->setupTriggerSignals();
_components.append(QVariant::fromValue((VehicleComponent*)_safetyComponent));
......
......@@ -21,6 +21,7 @@
#include "SafetyComponent.h"
#include "CameraComponent.h"
#include "PowerComponent.h"
#include "MotorComponent.h"
#include "PX4TuningComponent.h"
#include "Vehicle.h"
......@@ -50,6 +51,7 @@ public:
SafetyComponent* safetyComponent(void) { return _safetyComponent; }
CameraComponent* cameraComponent(void) { return _cameraComponent; }
PowerComponent* powerComponent(void) { return _powerComponent; }
MotorComponent* motorComponent(void) { return _motorComponent; }
PX4TuningComponent* tuningComponent(void) { return _tuningComponent; }
public slots:
......@@ -67,6 +69,7 @@ private:
SafetyComponent* _safetyComponent;
CameraComponent* _cameraComponent;
PowerComponent* _powerComponent;
MotorComponent* _motorComponent;
PX4TuningComponent* _tuningComponent;
bool _incorrectParameterVersion; ///< true: parameter version incorrect, setup not allowed
};
......
......@@ -122,7 +122,6 @@ APMCustomMode::APMCustomMode(uint32_t mode, bool settable) :
{
}
void APMCustomMode::setEnumToStringMapping(const QMap<uint32_t, QString>& enumToString)
{
_enumToString = enumToString;
......@@ -138,8 +137,10 @@ QString APMCustomMode::modeString() const
}
APMFirmwarePlugin::APMFirmwarePlugin(void)
: _coaxialMotors(false)
, _textSeverityAdjustmentNeeded(false)
{
_textSeverityAdjustmentNeeded = false;
}
bool APMFirmwarePlugin::isCapable(FirmwareCapabilities capabilities)
......@@ -380,6 +381,15 @@ bool APMFirmwarePlugin::_handleStatusText(Vehicle* vehicle, mavlink_message_t* m
// Start TCP video handshake with ARTOO
_soloVideoHandshake(vehicle);
} else if (messageText.contains(APM_FRAME_REXP)) {
// We need to parse the Frame: message in order to determine whether the motors are coaxial or not
QRegExp frameTypeRegex("^Frame: (\\S*)");
if (frameTypeRegex.indexIn(messageText) != -1) {
QString frameType = frameTypeRegex.cap(1);
if (!frameType.isEmpty() && (frameType == QStringLiteral("Y6") || frameType == QStringLiteral("OCTA_QUAD") || frameType == QStringLiteral("COAX"))) {
_coaxialMotors = true;
}
}
}
if (messageText.startsWith("PreArm")) {
......
......@@ -99,6 +99,8 @@ protected:
APMFirmwarePlugin(void);
void setSupportedModes(QList<APMCustomMode> supportedModes);
bool _coaxialMotors;
private slots:
void _artooSocketError(QAbstractSocket::SocketError socketError);
......
......@@ -197,3 +197,14 @@ void ArduCopterFirmwarePlugin::setGuidedMode(Vehicle* vehicle, bool guidedMode)
pauseVehicle(vehicle);
}
}
bool ArduCopterFirmwarePlugin::multiRotorCoaxialMotors(Vehicle* vehicle)
{
Q_UNUSED(vehicle);
return _coaxialMotors;
}
bool ArduCopterFirmwarePlugin::multiRotorXConfig(Vehicle* vehicle)
{
return vehicle->autopilotPlugin()->getParameterFact(FactSystem::defaultComponentId, "FRAME")->rawValue().toInt() != 0;
}
......@@ -64,6 +64,8 @@ public:
void guidedModeChangeAltitude(Vehicle* vehicle, double altitudeRel) final;
const FirmwarePlugin::remapParamNameMajorVersionMap_t& paramNameRemapMajorVersionMap(void) const final { return _remapParamName; }
virtual int remapParamNameHigestMinorVersionNumber(int majorVersionNumber) const final;
virtual bool multiRotorCoaxialMotors(Vehicle* vehicle) final;
virtual bool multiRotorXConfig(Vehicle* vehicle) final;
private:
static bool _remapParamNameIntialized;
......
......@@ -181,6 +181,12 @@ public:
/// Returns the highest major version number that is known to the remap for this specified major version.
virtual int remapParamNameHigestMinorVersionNumber(int majorVersionNumber) const;
/// @return true: Motors are coaxial like an X8 config, false: Quadcopter for example
virtual bool multiRotorCoaxialMotors(Vehicle* vehicle) { Q_UNUSED(vehicle); return false; }
/// @return true: X confiuration, false: Plus configuration
virtual bool multiRotorXConfig(Vehicle* vehicle) { Q_UNUSED(vehicle); return false; }
};
#endif
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.1
import QGroundControl.Controls 1.0
import QGroundControl.ScreenTools 1.0
Item {
id: slider;
height: 12
property real value // value is read/write.
property real minimum: 0
property real maximum: 1
property int length: width - handle.width
Rectangle {
anchors.fill: parent
radius: ScreenTools.defaultFontPixelHeight * (0.5)
color: Qt.rgba(0,0,0,0.65);
}
Rectangle {
anchors.left: parent.left
anchors.leftMargin: ScreenTools.defaultFontPixelHeight * (0.33)
radius: ScreenTools.defaultFontPixelHeight * (0.33)
height: ScreenTools.defaultFontPixelHeight * (0.33)
width: handle.x - x
color: "#69bb17"
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
id: labelRect
width: label.width
height: label.height + ScreenTools.defaultFontPixelHeight * (0.33)
radius: ScreenTools.defaultFontPixelHeight * (0.33)
smooth: true
color: Qt.rgba(1,1,1,0.75);
border.width: ScreenTools.defaultFontPixelHeight * (0.083)
border.color: Qt.rgba(0,0,0,0.45);
anchors.bottom: handle.top
anchors.bottomMargin: ScreenTools.defaultFontPixelHeight * (0.33)
visible: mouseRegion.pressed
x: Math.max(Math.min(handle.x + (handle.width - width ) / 2, slider.width - width), 0)
QGCLabel{
id: label
color: "black"
text: slider.value.toFixed(2)
width: font.pointSize * 3.5
anchors.horizontalCenter: labelRect.horizontalCenter
horizontalAlignment: Text.AlignHCenter
anchors.verticalCenter: labelRect.verticalCenter
}
}
Rectangle {
id: handle;
smooth: true
width: ScreenTools.defaultFontPixelHeight * (2.16);
y: (slider.height - height) / 2;
x: (slider.value - slider.minimum) * slider.length / (slider.maximum - slider.minimum)
height: width
radius: width / 2
gradient: normalGradient
border.width: 2
border.color: "white"
Gradient {
id: normalGradient
GradientStop { position: 0.0; color: "#b0b0b0" }
GradientStop { position: 0.66; color: "#909090" }
GradientStop { position: 1.0; color: "#545454" }
}
MouseArea {
id: mouseRegion
hoverEnabled: false
anchors.fill: parent; drag.target: parent
drag.axis: Drag.XAxis; drag.minimumX: 0; drag.maximumX: slider.length
preventStealing: true
onPositionChanged: { slider.value = (slider.maximum - slider.minimum) * handle.x / slider.length + slider.minimum; }
}
}
}
import QtQuick 2.2
import QGroundControl.Palette 1.0
import QGroundControl.ScreenTools 1.0
Item {
id: motorRoot
property int motorCount: 4 // Number of motors on vehicle
property bool xConfig: true // true: X configuration, false: Plus configuration
property bool coaxial: true // true: motors on top bottom of same arm, false: motors only on top of arm
property bool _unsupportedConfig: motorCount == 3 || (motorCount == 6 && coaxial) // Tricopters NYI
property var _qgcPal: QGCPalette { colorGroupEnabled: enabled }
property real _rotorRadius: motorRoot.height / 8
property int _motorsPerSide: motorCount / (coaxial ? 2 : 1)
readonly property string _cwColor: "green"
readonly property string _ccwColor: "blue"
readonly property var _motorColors4Plus: [ _ccwColor, _cwColor ]
readonly property var _motorColors4X: [ _cwColor, _ccwColor ]
readonly property var _motorColors6: [ _cwColor, _ccwColor ]
readonly property var _motorColors8: [ _cwColor, _ccwColor ]
readonly property var _motorColors4Top: [ _cwColor, _ccwColor ]
readonly property var _motorColors4Bottom: [ _ccwColor, _cwColor ]
readonly property var _motorNumbers4Plus: [ 1, 4, 2, 3 ]
readonly property var _motorNumbers4X: [ 4, 2, 3, 1 ]
readonly property var _motorNumbers6Plus: [ 6, 2, 3, 5, 1, 4 ]
readonly property var _motorNumbers6X: [ 1, 4, 6, 2, 3, 5 ]
readonly property var _motorNumbers8: [ 8, 4, 2, 6, 7, 5, 1, 3 ]
readonly property var _motorNumbers4Top: [ 4, 3, 2, 1 ]
readonly property var _motorNumbers4Bottom: [ 7, 8, 5, 6 ]
Component.onCompleted: {
if (coaxial) {
topMotors.motorNumbers = _motorNumbers4Top
bottomMotors.motorNumbers = _motorNumbers4Bottom
} else {
switch (motorCount) {
case 4:
topMotors.motorNumbers = xConfig ? _motorNumbers4X : _motorNumbers4Plus
topMotors.motorColors = xConfig ? _motorColors4X : _motorColors4Plus
break
case 6:
topMotors.motorNumbers = xConfig ? _motorNumbers6X : _motorNumbers6Plus
topMotors.motorColors = _motorColors6
break
default:
case 8:
topMotors.motorNumbers = _motorNumbers8
topMotors.motorColors = _motorColors8
break
}
bottomMotors.motorNumbers = _motorNumbers8
}
}
Component {
id: motorDisplayComponent
Repeater {
id: motorRepeater
model: _motorsPerSide
Item {
x: motorRepeater.width / 2 + _armXCenter - rotor.radius
y: motorRepeater.height / 2 + _armYCenter - rotor.radius
width: _rotorRadius * 2
height: _rotorRadius * 2
property real _armOffsetRadians: ((2 * Math.PI) / _motorsPerSide)
property real _armOffsetIndexRadians: (_armOffsetRadians * index) + ((xConfig && _motorsPerSide != 6) || (!xConfig && _motorsPerSide == 6) ? _armOffsetRadians / 2 : 0)
property real _armLength: (motorRepeater.height / 2) - (_rotorRadius * (xConfig && _motorsPerSide == 4 ? 0 : 1))
property real _armXCenter: Math.cos(_armOffsetIndexRadians) * _armLength // adjacent = cos * hypotenuse
property real _armYCenter: Math.sin(_armOffsetIndexRadians) * _armLength // opposite = sin * hypotenuse
Rectangle {id: rotor
anchors.fill: parent
radius: _rotorRadius
color: motorColors[index & 1]
opacity: topCoaxial ? 0.65 : 1.0
border.color: topCoaxial ? "black" : color
readonly property bool topCoaxial: topMotors && coaxial
}
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
width: radius *2
height: radius *2
radius: ScreenTools.defaultFontPixelHeight / 2
color: "white"
border.color: "black"
QGCLabel {
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: motorNumbers[index]
color: parent.border.color
}
}
} // Item
} // Repeater
} // Component - MotorDisplayComponent
Item {
anchors.fill: parent
visible: !_unsupportedConfig
Loader {
id: bottomMotors
anchors.topMargin: ScreenTools.defaultFontPixelHeight
anchors.fill: parent
sourceComponent: motorDisplayComponent
visible: coaxial
property bool topMotors: false
property var motorNumbers: _motorNumbers8
property var motorColors: _motorColors4Bottom
}
Loader {
id: topMotors
anchors.fill: parent
anchors.bottomMargin: coaxial ? ScreenTools.defaultFontPixelHeight : 0
sourceComponent: motorDisplayComponent
property bool topMotors: true
property var motorNumbers: _motorNumbers8
property var motorColors: _motorColors4Top
}
// Body direction
Canvas {
anchors.fill: parent
property real _centerX : width / 2
property real _centerY : height / 2
onPaint: {
var ctx = getContext("2d");
ctx.lineWidth = 3
ctx.strokeStyle = _qgcPal.text
ctx.translate(_centerX, _centerY)
ctx.moveTo(0, -_rotorRadius / 2);
ctx.lineTo(_rotorRadius / 2, _rotorRadius);
ctx.lineTo(-_rotorRadius / 2, _rotorRadius);
ctx.lineTo(0, -_rotorRadius / 2);
ctx.stroke();
}
}
} // Item
} // Item
import QtQuick 2.2
import QGroundControl.Palette 1.0
import QGroundControl.ScreenTools 1.0
Item {
id: legendRoot
property var _qgcPal: QGCPalette { colorGroupEnabled: enabled }
property real _rotorRadius: legendRoot.height / 16
readonly property string _cwColor: "green"
readonly property string _ccwColor: "blue"
Item {
id: cwItem
anchors.left: parent.left
anchors.right: parent.right
height: legendRoot.height / 2
Rectangle {
id: cwRotor
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: _rotorRadius * 2
height: _rotorRadius * 2
radius: _rotorRadius
color: _cwColor
}
QGCLabel {
anchors.leftMargin: ScreenTools.defaultFontPixelWidth
anchors.left: cwRotor.right
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
text: qsTr("Clockwise rotation, use pusher propellor")
}
}
Item {
id: ccwItem
anchors.top: cwItem.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
Rectangle {
id: ccwRotor
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: _rotorRadius * 2
height: _rotorRadius * 2
radius: _rotorRadius
color: _ccwColor
}
QGCLabel {
anchors.leftMargin: ScreenTools.defaultFontPixelWidth
anchors.left: ccwRotor.right
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
text: qsTr("Counter-Clockwise rotation, use normal propellor")
}
}
} // Item
/****************************************************************************
*
* (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.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QtQuick.Controls.Private 1.0
import QGroundControl.Palette 1.0
import QGroundControl.ScreenTools 1.0
Slider {
property var _qgcPal: QGCPalette { colorGroupEnabled: enabled }
style: SliderStyle {
groove: Item {
property color fillColor: "#49d"
anchors.verticalCenter: parent.verticalCenter
implicitWidth: Math.round(TextSingleton.implicitHeight * 4.5)
implicitHeight: Math.max(6, Math.round(TextSingleton.implicitHeight * 0.3))
Rectangle {
radius: height/2
anchors.fill: parent
border.width: 1
border.color: "#888"
gradient: Gradient {
GradientStop { color: "#bbb" ; position: 0 }
GradientStop { color: "#ccc" ; position: 0.6 }
GradientStop { color: "#ccc" ; position: 1 }
}
}
Item {
clip: true
width: styleData.handlePosition
height: parent.height
Rectangle {
anchors.fill: parent
border.color: Qt.darker(fillColor, 1.2)
radius: height/2
gradient: Gradient {
GradientStop {color: Qt.lighter(fillColor, 1.3) ; position: 0}
GradientStop {color: fillColor ; position: 1.4}
}
}
}
}
}
}
......@@ -13,6 +13,8 @@ MissionItemEditor 1.0 MissionItemEditor.qml
MissionItemIndexLabel 1.0 MissionItemIndexLabel.qml
MissionItemStatus 1.0 MissionItemStatus.qml
ModeSwitchDisplay 1.0 ModeSwitchDisplay.qml
MultiRotorMotorDisplay 1.0 MultiRotorMotorDisplay.qml
MultiRotorMotorDisplayLegend 1.0 MultiRotorMotorDisplayLegend.qml
ParameterEditor 1.0 ParameterEditor.qml
ParameterEditorDialog 1.0 ParameterEditorDialog.qml
RCChannelMonitor 1.0 RCChannelMonitor.qml
......@@ -26,6 +28,7 @@ QGCMobileFileDialog 1.0 QGCMobileFileDialog.qml
QGCMovableItem 1.0 QGCMovableItem.qml
QGCPipable 1.0 QGCPipable.qml
QGCRadioButton 1.0 QGCRadioButton.qml
QGCSlider 1.0 QGCSlider.qml
QGCTextField 1.0 QGCTextField.qml
QGCToolBarButton 1.0 QGCToolBarButton.qml
QGCView 1.0 QGCView.qml
......@@ -33,6 +36,7 @@ QGCViewDialog 1.0 QGCViewDialog.qml
QGCViewMessage 1.0 QGCViewMessage.qml
QGCViewPanel 1.0 QGCViewPanel.qml
RoundButton 1.0 RoundButton.qml
SetupPage 1.0 SetupPage.qml
SignalStrength 1.0 SignalStrength.qml
SliderSwitch 1.0 SliderSwitch.qml
SubMenuButton 1.0 SubMenuButton.qml
......
......@@ -916,6 +916,37 @@ void Vehicle::_updateNavigationControllerData(UASInterface *uas, float, float, f
}
}
int Vehicle::motorCount(void)
{
switch (_vehicleType) {
case MAV_TYPE_HELICOPTER:
return 1;
case MAV_TYPE_VTOL_DUOROTOR:
return 2;
case MAV_TYPE_TRICOPTER:
return 3;
case MAV_TYPE_QUADROTOR:
case MAV_TYPE_VTOL_QUADROTOR:
return 4;
case MAV_TYPE_HEXAROTOR:
return 6;
case MAV_TYPE_OCTOROTOR:
return 8;
default:
return -1;
}
}
bool Vehicle::coaxialMotors(void)
{
return _firmwarePlugin->multiRotorCoaxialMotors(this);
}
bool Vehicle::xConfigMotors(void)
{
return _firmwarePlugin->multiRotorXConfig(this);
}
/*
* Internal
*/
......@@ -1738,6 +1769,11 @@ void Vehicle::setSoloFirmware(bool soloFirmware)
}
}
void Vehicle::motorTest(int motor, int percent, int timeoutSecs)
{
doCommandLong(defaultComponentId(), MAV_CMD_DO_MOTOR_TEST, motor, MOTOR_TEST_THROTTLE_PERCENT, percent, timeoutSecs);
}
const char* VehicleGPSFactGroup::_hdopFactName = "hdop";
const char* VehicleGPSFactGroup::_vdopFactName = "vdop";
const char* VehicleGPSFactGroup::_courseOverGroundFactName = "courseOverGround";
......
......@@ -277,6 +277,9 @@ public:
Q_PROPERTY(bool rover READ rover CONSTANT)
Q_PROPERTY(bool autoDisconnect MEMBER _autoDisconnect NOTIFY autoDisconnectChanged)
Q_PROPERTY(QString prearmError READ prearmError WRITE setPrearmError NOTIFY prearmErrorChanged)
Q_PROPERTY(int motorCount READ motorCount CONSTANT)
Q_PROPERTY(bool coaxialMotors READ coaxialMotors CONSTANT)
Q_PROPERTY(bool xConfigMotors READ xConfigMotors CONSTANT)
/// true: Vehicle is flying, false: Vehicle is on ground
Q_PROPERTY(bool flying READ flying WRITE setFlying NOTIFY flyingChanged)
......@@ -362,6 +365,12 @@ public:
/// Clear Messages
Q_INVOKABLE void clearMessages();
/// Test motor
/// @param motor Motor number, 1-based
/// @param percent 0-no power, 100-full power
/// @param timeoutSecs Number of seconds for motor to run
Q_INVOKABLE void motorTest(int motor, int percent, int timeoutSecs);
bool guidedModeSupported(void) const;
bool pauseVehicleSupported(void) const;
......@@ -438,7 +447,6 @@ public:
QString flightMode(void) const;
void setFlightMode(const QString& flightMode);
bool hilMode(void);
void setHilMode(bool hilMode);
......@@ -535,6 +543,15 @@ public:
int defaultComponentId(void);
/// @return -1 = Unknown, Number of motors on vehicle
int motorCount(void);
/// @return true: Motors are coaxial like an X8 config, false: Quadcopter for example
bool coaxialMotors(void);
/// @return true: X confiuration, false: Plus configuration
bool xConfigMotors(void);
public slots:
void setLatitude(double latitude);
void setLongitude(double longitude);
......
......@@ -97,6 +97,7 @@ Rectangle {
_messagePanelText = vehicleComponent.prerequisiteSetup + " setup must be completed prior to " + vehicleComponent.name + " setup."
panelLoader.sourceComponent = messagePanelComponent
} else {
panelLoader.vehicleComponent = vehicleComponent
panelLoader.source = vehicleComponent.setupSource
for(var i = 0; i < componentRepeater.count; i++) {
var obj = componentRepeater.itemAt(i);
......@@ -324,5 +325,7 @@ Rectangle {
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
property var vehicleComponent
}
}
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