diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index f62752ad4e8646e5392396fd545a35c60a250933..9d4fdd951af84a5fa39cfd0eef7e197a10a75ec7 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -469,6 +469,8 @@ HEADERS += \ src/MissionManager/RallyPointController.h \ src/MissionManager/RallyPointManager.h \ src/MissionManager/SimpleMissionItem.h \ + src/MissionManager/Section.h \ + src/MissionManager/SpeedSection.h \ src/MissionManager/SurveyMissionItem.h \ src/MissionManager/VisualMissionItem.h \ src/PositionManager/PositionManager.h \ @@ -648,6 +650,7 @@ SOURCES += \ src/MissionManager/RallyPointController.cc \ src/MissionManager/RallyPointManager.cc \ src/MissionManager/SimpleMissionItem.cc \ + src/MissionManager/SpeedSection.cc \ src/MissionManager/SurveyMissionItem.cc \ src/MissionManager/VisualMissionItem.cc \ src/PositionManager/PositionManager.cpp \ diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index 68d770f87b5563bfe3944c882a537da7ca9e0ceb..bfcbdcffb1f98e892eb6f909c950ead0fa70458e 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -197,6 +197,7 @@ src/MissionManager/FWLandingPattern.FactMetaData.json src/comm/USBBoardInfo.json src/MissionManager/CameraSection.FactMetaData.json + src/MissionManager/SpeedSection.FactMetaData.json src/MissionManager/MissionSettings.FactMetaData.json src/Vehicle/VehicleFact.json src/Vehicle/BatteryFact.json diff --git a/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.cc b/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.cc index 4f09a594b59d7b6c0ab6f341659a30a4bd925aac..99a6290cb846d804251b29fa931eded436e26b85 100644 --- a/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.cc +++ b/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.cc @@ -241,3 +241,17 @@ bool ArduCopterFirmwarePlugin::vehicleYawsToNextWaypointInMission(const Vehicle* } return false; } + +void ArduCopterFirmwarePlugin::missionFlightSpeedInfo(Vehicle* vehicle, double& hoverSpeed, double& cruiseSpeed) +{ + QString hoverSpeedParam("WPNAV_SPEED"); + + // First pull settings defaults + FirmwarePlugin::missionFlightSpeedInfo(vehicle, hoverSpeed, cruiseSpeed); + + cruiseSpeed = 0; + if (vehicle->parameterManager()->parameterExists(FactSystem::defaultComponentId, hoverSpeedParam)) { + Fact* speed = vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, hoverSpeedParam); + hoverSpeed = speed->rawValue().toDouble(); + } +} diff --git a/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.h b/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.h index 345fdb232e35d043fff0161d3b861e6203254ef7..5f35bfa15d53f2c92a040deeb2f510d4b923586b 100644 --- a/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.h +++ b/src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.h @@ -76,6 +76,7 @@ public: QString takeControlFlightMode(void) const override { return QString("Stablize"); } bool vehicleYawsToNextWaypointInMission(const Vehicle* vehicle) const final; QString autoDisarmParameter(Vehicle* vehicle) final { Q_UNUSED(vehicle); return QStringLiteral("DISARM_DELAY"); } + void missionFlightSpeedInfo(Vehicle* vehicle, double& hoverSpeed, double& cruiseSpeed) override; private: static bool _remapParamNameIntialized; diff --git a/src/FirmwarePlugin/FirmwarePlugin.cc b/src/FirmwarePlugin/FirmwarePlugin.cc index c89b9c947f039e002a8582498c518409a1492c57..c3e92e89fdb2000f229b0b2d0a2a09afbdfe1bdd 100644 --- a/src/FirmwarePlugin/FirmwarePlugin.cc +++ b/src/FirmwarePlugin/FirmwarePlugin.cc @@ -11,6 +11,8 @@ #include "QGCApplication.h" #include "Generic/GenericAutoPilotPlugin.h" #include "CameraMetaData.h" +#include "SettingsManager.h" +#include "AppSettings.h" #include @@ -452,3 +454,13 @@ QString FirmwarePlugin::autoDisarmParameter(Vehicle* vehicle) Q_UNUSED(vehicle); return QString(); } + +void FirmwarePlugin::missionFlightSpeedInfo(Vehicle* vehicle, double& hoverSpeed, double& cruiseSpeed) +{ + Q_UNUSED(vehicle); + + // Best we can do is use settings + AppSettings* appSettings = qgcApp()->toolbox()->settingsManager()->appSettings(); + hoverSpeed = appSettings->offlineEditingHoverSpeed()->rawValue().toDouble(); + cruiseSpeed = appSettings->offlineEditingCruiseSpeed()->rawValue().toDouble(); +} diff --git a/src/FirmwarePlugin/FirmwarePlugin.h b/src/FirmwarePlugin/FirmwarePlugin.h index 20ede07407c410d19018d5782120ebf7fa378097..5c6a6c6865847715668f167c55b6a2180306c124 100644 --- a/src/FirmwarePlugin/FirmwarePlugin.h +++ b/src/FirmwarePlugin/FirmwarePlugin.h @@ -282,6 +282,11 @@ public: /// @param[out] cruiseAmps Current draw in amps during cruise virtual void batteryConsumptionData(Vehicle* vehicle, int& mAhBattery, double& hoverAmps, double& cruiseAmps) const; + /// Returns the default mission flight speeds. + /// @param[out] hoverSpeed Flight speed for vehicle flying in multi-rotor mode. 0 for none, or not available. + /// @param[out] cruiseSpeed Flight speed for vehicle flying in fixed wing forward flight mode. 0 for none, or not available. + virtual void missionFlightSpeedInfo(Vehicle* vehicle, double& hoverSpeed, double& cruiseSpeed); + // Returns the parameter which control auto-dismar. Assume == 0 means no auto disarm virtual QString autoDisarmParameter(Vehicle* vehicle); diff --git a/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc b/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc index 762df402036d05e376cf1472b25aebf83ba43856..669fc01203c8f7cd1f8df64fe3be8185b67db1ba 100644 --- a/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc +++ b/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc @@ -518,9 +518,27 @@ void PX4FirmwarePlugin::_handleAutopilotVersion(Vehicle* vehicle, mavlink_messag bool PX4FirmwarePlugin::vehicleYawsToNextWaypointInMission(const Vehicle* vehicle) const { - if ( vehicle->parameterManager()->parameterExists(FactSystem::defaultComponentId, QStringLiteral("MIS_YAWMODE"))) { + if (vehicle->parameterManager()->parameterExists(FactSystem::defaultComponentId, QStringLiteral("MIS_YAWMODE"))) { Fact* yawMode = vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, QStringLiteral("MIS_YAWMODE")); return yawMode && yawMode->rawValue().toInt() == 1; } return false; } + +void PX4FirmwarePlugin::missionFlightSpeedInfo(Vehicle* vehicle, double& hoverSpeed, double& cruiseSpeed) +{ + QString hoverSpeedParam("MPC_XY_CRUISE"); + QString cruiseSpeedParam("FW_AIRSPD_TRIM"); + + // First pull settings defaults + FirmwarePlugin::missionFlightSpeedInfo(vehicle, hoverSpeed, cruiseSpeed); + + if (vehicle->parameterManager()->parameterExists(FactSystem::defaultComponentId, hoverSpeedParam)) { + Fact* speed = vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, hoverSpeedParam); + hoverSpeed = speed->rawValue().toDouble(); + } + if (vehicle->parameterManager()->parameterExists(FactSystem::defaultComponentId, cruiseSpeedParam)) { + Fact* speed = vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, cruiseSpeedParam); + cruiseSpeed = speed->rawValue().toDouble(); + } +} diff --git a/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h b/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h index 7778c2551209485222d2b2226d953b0557ad72dc..9e38ad582644c87b70994fb741321d6abe1aa502 100644 --- a/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h +++ b/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h @@ -68,6 +68,7 @@ public: QString brandImageOutdoor (const Vehicle* vehicle) const override { Q_UNUSED(vehicle); return QStringLiteral("/qmlimages/PX4/BrandImage"); } bool vehicleYawsToNextWaypointInMission(const Vehicle* vehicle) const override; QString autoDisarmParameter (Vehicle* vehicle) override { Q_UNUSED(vehicle); return QStringLiteral("COM_DISARM_LAND"); } + void missionFlightSpeedInfo (Vehicle* vehicle, double& hoverSpeed, double& cruiseSpeed) override; protected: typedef struct { diff --git a/src/MissionManager/CameraSection.cc b/src/MissionManager/CameraSection.cc index 3a2b349b226efda82ab3c4df0db3cc12797cbf2b..eea8c89f49b1f3d6c4b7cbba099b77652986e9da 100644 --- a/src/MissionManager/CameraSection.cc +++ b/src/MissionManager/CameraSection.cc @@ -20,8 +20,8 @@ const char* CameraSection::_cameraPhotoIntervalTimeName = "CameraPhotoInter QMap CameraSection::_metaDataMap; -CameraSection::CameraSection(QObject* parent) - : QObject(parent) +CameraSection::CameraSection(Vehicle* vehicle, QObject* parent) + : Section(vehicle, parent) , _available(false) , _settingsSpecified(false) , _specifyGimbal(false) @@ -48,8 +48,8 @@ CameraSection::CameraSection(QObject* parent) _cameraPhotoIntervalDistanceFact.setRawValue (_cameraPhotoIntervalDistanceFact.rawDefaultValue()); _cameraPhotoIntervalTimeFact.setRawValue (_cameraPhotoIntervalTimeFact.rawDefaultValue()); - connect(this, &CameraSection::specifyGimbalChanged, this, &CameraSection::_setDirtyAndUpdateMissionItemCount); - connect(&_cameraActionFact, &Fact::valueChanged, this, &CameraSection::_setDirtyAndUpdateMissionItemCount); + connect(this, &CameraSection::specifyGimbalChanged, this, &CameraSection::_setDirtyAndUpdateItemCount); + connect(&_cameraActionFact, &Fact::valueChanged, this, &CameraSection::_setDirtyAndUpdateItemCount); connect(&_gimbalPitchFact, &Fact::valueChanged, this, &CameraSection::_setDirty); connect(&_gimbalYawFact, &Fact::valueChanged, this, &CameraSection::_setDirty); @@ -67,7 +67,7 @@ void CameraSection::setSpecifyGimbal(bool specifyGimbal) } } -int CameraSection::missionItemCount(void) const +int CameraSection::itemCount(void) const { int itemCount = 0; @@ -89,9 +89,9 @@ void CameraSection::setDirty(bool dirty) } } -void CameraSection::appendMissionItems(QList& items, QObject* missionItemParent, int nextSequenceNumber) +void CameraSection::appendSectionItems(QList& items, QObject* missionItemParent, int& nextSequenceNumber) { - // IMPORTANT NOTE: If anything changes here you must also change CameraSection::scanForMissionSettings + // IMPORTANT NOTE: If anything changes here you must also change CameraSection::scanForSection if (_specifyGimbal) { MissionItem* item = new MissionItem(nextSequenceNumber++, @@ -188,7 +188,7 @@ void CameraSection::appendMissionItems(QList& items, QObject* miss } } -bool CameraSection::scanForCameraSection(QmlObjectListModel* visualItems, int scanIndex) +bool CameraSection::scanForSection(QmlObjectListModel* visualItems, int& scanIndex) { bool foundGimbal = false; bool foundCameraAction = false; @@ -196,6 +196,10 @@ bool CameraSection::scanForCameraSection(QmlObjectListModel* visualItems, int sc qCDebug(CameraSectionLog) << "CameraSection::scanForCameraSection" << visualItems->count() << scanIndex; + if (!_available || scanIndex >= visualItems->count()) { + return false; + } + // Scan through the initial mission items for possible mission settings while (!stopLooking && visualItems->count() > scanIndex) { @@ -214,6 +218,7 @@ bool CameraSection::scanForCameraSection(QmlObjectListModel* visualItems, int sc case MAV_CMD_DO_MOUNT_CONTROL: if (!foundGimbal && missionItem.param2() == 0 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == MAV_MOUNT_MODE_MAVLINK_TARGETING) { foundGimbal = true; + scanIndex++; setSpecifyGimbal(true); gimbalPitch()->setRawValue(missionItem.param1()); gimbalYaw()->setRawValue(missionItem.param3()); @@ -226,6 +231,7 @@ bool CameraSection::scanForCameraSection(QmlObjectListModel* visualItems, int sc case MAV_CMD_IMAGE_START_CAPTURE: if (!foundCameraAction && missionItem.param1() != 0 && missionItem.param2() == 0 && missionItem.param3() == -1 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) { foundCameraAction = true; + scanIndex++; cameraAction()->setRawValue(TakePhotosIntervalTime); cameraPhotoIntervalTime()->setRawValue(missionItem.param1()); visualItems->removeAt(scanIndex)->deleteLater(); @@ -245,6 +251,7 @@ bool CameraSection::scanForCameraSection(QmlObjectListModel* visualItems, int sc if (nextMissionItem.command() == MAV_CMD_IMAGE_STOP_CAPTURE && nextMissionItem.param1() == 0 && nextMissionItem.param2() == 0 && nextMissionItem.param3() == 0 && nextMissionItem.param4() == 0 && nextMissionItem.param5() == 0 && nextMissionItem.param6() == 0 && nextMissionItem.param7() == 0) { // We found a stop taking photos pair foundCameraAction = true; + scanIndex += 2; cameraAction()->setRawValue(StopTakingPhotos); visualItems->removeAt(scanIndex)->deleteLater(); visualItems->removeAt(scanIndex)->deleteLater(); @@ -257,6 +264,7 @@ bool CameraSection::scanForCameraSection(QmlObjectListModel* visualItems, int sc // We didn't find a stop taking photos pair, check for trigger distance if (missionItem.param1() > 0) { foundCameraAction = true; + scanIndex++; cameraAction()->setRawValue(TakePhotoIntervalDistance); cameraPhotoIntervalDistance()->setRawValue(missionItem.param1()); visualItems->removeAt(scanIndex)->deleteLater(); @@ -270,6 +278,7 @@ bool CameraSection::scanForCameraSection(QmlObjectListModel* visualItems, int sc case MAV_CMD_VIDEO_START_CAPTURE: if (!foundCameraAction && missionItem.param1() == 0 && missionItem.param2() == -1 && missionItem.param3() == -1 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) { foundCameraAction = true; + scanIndex++; cameraAction()->setRawValue(TakeVideo); visualItems->removeAt(scanIndex)->deleteLater(); } @@ -279,6 +288,7 @@ bool CameraSection::scanForCameraSection(QmlObjectListModel* visualItems, int sc case MAV_CMD_VIDEO_STOP_CAPTURE: if (!foundCameraAction && missionItem.param1() == 0 && missionItem.param2() == 0 && missionItem.param3() == 0 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) { foundCameraAction = true; + scanIndex++; cameraAction()->setRawValue(StopTakingVideo); visualItems->removeAt(scanIndex)->deleteLater(); } @@ -304,9 +314,9 @@ void CameraSection::_setDirty(void) setDirty(true); } -void CameraSection::_setDirtyAndUpdateMissionItemCount(void) +void CameraSection::_setDirtyAndUpdateItemCount(void) { - emit missionItemCountChanged(missionItemCount()); + emit itemCountChanged(itemCount()); setDirty(true); } diff --git a/src/MissionManager/CameraSection.h b/src/MissionManager/CameraSection.h index b5ad6f244e1ab441a4e6ed76d0ef89a86ef6960d..da2bf5a4d06755934a40d2bf328e5eb14d95dc82 100644 --- a/src/MissionManager/CameraSection.h +++ b/src/MissionManager/CameraSection.h @@ -7,21 +7,19 @@ * ****************************************************************************/ -#ifndef CameraSection_H -#define CameraSection_H +#pragma once +#include "Section.h" #include "ComplexMissionItem.h" #include "MissionItem.h" #include "Fact.h" -Q_DECLARE_LOGGING_CATEGORY(CameraSectionLog) - -class CameraSection : public QObject +class CameraSection : public Section { Q_OBJECT public: - CameraSection(QObject* parent = NULL); + CameraSection(Vehicle* vehicle, QObject* parent = NULL); // These nume values must match the json meta data enum CameraAction { @@ -34,8 +32,6 @@ public: }; Q_ENUMS(CameraAction) - Q_PROPERTY(bool available READ available WRITE setAvailable NOTIFY availableChanged) - Q_PROPERTY(bool settingsSpecified MEMBER _settingsSpecified NOTIFY settingsSpecifiedChanged) Q_PROPERTY(bool specifyGimbal READ specifyGimbal WRITE setSpecifyGimbal NOTIFY specifyGimbalChanged) Q_PROPERTY(Fact* gimbalPitch READ gimbalPitch CONSTANT) Q_PROPERTY(Fact* gimbalYaw READ gimbalYaw CONSTANT) @@ -43,8 +39,6 @@ public: Q_PROPERTY(Fact* cameraPhotoIntervalTime READ cameraPhotoIntervalTime CONSTANT) Q_PROPERTY(Fact* cameraPhotoIntervalDistance READ cameraPhotoIntervalDistance CONSTANT) - bool available (void) const { return _available; } - void setAvailable (bool available); bool specifyGimbal (void) const { return _specifyGimbal; } Fact* gimbalYaw (void) { return &_gimbalYawFact; } Fact* gimbalPitch (void) { return &_gimbalPitchFact; } @@ -52,40 +46,28 @@ public: Fact* cameraPhotoIntervalTime (void) { return &_cameraPhotoIntervalTimeFact; } Fact* cameraPhotoIntervalDistance (void) { return &_cameraPhotoIntervalDistanceFact; } + void setSpecifyGimbal (bool specifyGimbal); + ///< @return The gimbal yaw specified by this item, NaN if not specified double specifiedGimbalYaw(void) const; - /// Scans the loaded items for the section items - /// @param visualItems Item list - /// @param scanIndex Index to start scanning from - /// @return true: camera section found - bool scanForCameraSection(QmlObjectListModel* visualItems, int scanIndex); - - /// Appends the mission items associated with this section - /// @param items List to append to - /// @param missionItemParent QObject parent for created MissionItems - /// @param nextSequenceNumber Sequence number for first item - void appendMissionItems(QList& items, QObject* missionItemParent, int nextSequenceNumber); - - void setSpecifyGimbal (bool specifyGimbal); - bool dirty (void) const { return _dirty; } - void setDirty (bool dirty); - - /// Returns the number of mission items represented by this section. - /// Signals: missionItemCountChanged on change - int missionItemCount(void) const; + // Overrides from Section + bool available (void) const override { return _available; } + bool dirty (void) const override { return _dirty; } + void setAvailable (bool available) override; + void setDirty (bool dirty) override; + bool scanForSection (QmlObjectListModel* visualItems, int& scanIndex) override; + void appendSectionItems (QList& items, QObject* missionItemParent, int& seqNum) override; + int itemCount (void) const override; + bool settingsSpecified (void) const override {return _settingsSpecified; } signals: - void availableChanged (bool available); - void settingsSpecifiedChanged (bool settingsSpecified); - void dirtyChanged (bool dirty); bool specifyGimbalChanged (bool specifyGimbal); - void missionItemCountChanged (int missionItemCount); void specifiedGimbalYawChanged (double gimbalYaw); private slots: void _setDirty(void); - void _setDirtyAndUpdateMissionItemCount(void); + void _setDirtyAndUpdateItemCount(void); void _updateSpecifiedGimbalYaw(void); private: @@ -107,5 +89,3 @@ private: static const char* _cameraPhotoIntervalDistanceName; static const char* _cameraPhotoIntervalTimeName; }; - -#endif diff --git a/src/MissionManager/MavCmdInfoCommon.json b/src/MissionManager/MavCmdInfoCommon.json index b9c36568edae956ee41bacc9f31fcd00ee83d549..e9b135207e32902345965863504efff8a8c26cb9 100644 --- a/src/MissionManager/MavCmdInfoCommon.json +++ b/src/MissionManager/MavCmdInfoCommon.json @@ -32,7 +32,6 @@ "specifiesCoordinate": true, "friendlyEdit": true, "category": "Basic", - "cameraSection": true, "param1": { "label": "Hold", "units": "secs", diff --git a/src/MissionManager/MissionCommandUIInfo.cc b/src/MissionManager/MissionCommandUIInfo.cc index c29dbd000699ca507f82dc10b5b04f655aed3fc3..c9cd7933890b75004ec8d1d55d8e13a9f19a1018 100644 --- a/src/MissionManager/MissionCommandUIInfo.cc +++ b/src/MissionManager/MissionCommandUIInfo.cc @@ -39,7 +39,6 @@ const char* MissionCommandUIInfo::_specifiesCoordinateJsonKey = "specifiesCoor const char* MissionCommandUIInfo::_specifiesAltitudeOnlyJsonKey = "specifiesAltitudeOnly"; const char* MissionCommandUIInfo::_unitsJsonKey = "units"; const char* MissionCommandUIInfo::_commentJsonKey = "comment"; -const char* MissionCommandUIInfo::_cameraSectionJsonKey = "cameraSection"; const char* MissionCommandUIInfo::_advancedCategory = "Advanced"; MissionCmdParamInfo::MissionCmdParamInfo(QObject* parent) @@ -165,15 +164,6 @@ bool MissionCommandUIInfo::specifiesAltitudeOnly(void) const } } -bool MissionCommandUIInfo::cameraSection(void) const -{ - if (_infoMap.contains(_cameraSectionJsonKey)) { - return _infoMap[_cameraSectionJsonKey].toBool(); - } else { - return false; - } -} - void MissionCommandUIInfo::_overrideInfo(MissionCommandUIInfo* uiInfo) { // Override info values @@ -209,7 +199,7 @@ bool MissionCommandUIInfo::loadJsonInfo(const QJsonObject& jsonObject, bool requ QStringList allKeys; allKeys << _idJsonKey << _rawNameJsonKey << _friendlyNameJsonKey << _descriptionJsonKey << _standaloneCoordinateJsonKey << _specifiesCoordinateJsonKey <<_friendlyEditJsonKey << _param1JsonKey << _param2JsonKey << _param3JsonKey << _param4JsonKey << _param5JsonKey << _param6JsonKey << _param7JsonKey - << _paramRemoveJsonKey << _categoryJsonKey << _cameraSectionJsonKey<< _specifiesAltitudeOnlyJsonKey; + << _paramRemoveJsonKey << _categoryJsonKey << _specifiesAltitudeOnlyJsonKey; // Look for unknown keys in top level object foreach (const QString& key, jsonObject.keys()) { @@ -241,7 +231,7 @@ bool MissionCommandUIInfo::loadJsonInfo(const QJsonObject& jsonObject, bool requ QList types; types << QJsonValue::Double << QJsonValue::String << QJsonValue::String<< QJsonValue::String << QJsonValue::Bool << QJsonValue::Bool << QJsonValue::Bool << QJsonValue::Object << QJsonValue::Object << QJsonValue::Object << QJsonValue::Object << QJsonValue::Object << QJsonValue::Object << QJsonValue::Object - << QJsonValue::String << QJsonValue::String << QJsonValue::Bool << QJsonValue::Bool; + << QJsonValue::String << QJsonValue::String << QJsonValue::Bool; if (!JsonHelper::validateKeyTypes(jsonObject, allKeys, types, internalError)) { errorString = _loadErrorString(internalError); return false; @@ -275,9 +265,6 @@ bool MissionCommandUIInfo::loadJsonInfo(const QJsonObject& jsonObject, bool requ if (jsonObject.contains(_friendlyEditJsonKey)) { _infoMap[_friendlyEditJsonKey] = jsonObject.value(_friendlyEditJsonKey).toVariant(); } - if (jsonObject.contains(_cameraSectionJsonKey)) { - _infoMap[_cameraSectionJsonKey] = jsonObject.value(_cameraSectionJsonKey).toVariant(); - } if (jsonObject.contains(_paramRemoveJsonKey)) { QStringList indexList = jsonObject.value(_paramRemoveJsonKey).toString().split(QStringLiteral(",")); foreach (const QString& indexString, indexList) { diff --git a/src/MissionManager/MissionCommandUIInfo.h b/src/MissionManager/MissionCommandUIInfo.h index 17170c6c9f1375e310cb800f56e8febb23f8a8dc..5ec1915a0832a0a49d1688bdfeb4bbbe37afdaaf 100644 --- a/src/MissionManager/MissionCommandUIInfo.h +++ b/src/MissionManager/MissionCommandUIInfo.h @@ -97,7 +97,6 @@ private: /// specifiesAltitudeOnly bool false true: Command specifies an altitude only (no coordinate) /// standaloneCoordinate bool false true: Vehicle does not fly through coordinate associated with command (exampl: ROI) /// friendlyEdit bool false true: Command supports friendly editing dialog, false: Command supports 'Show all values" style editing only -/// cameraSection bool false true: Camera section of additional settings is added to editor /// category string Advanced Category which this command belongs to /// paramRemove string Used by an override to remove params, example: "1,3" will remove params 1 and 3 on the override /// param[1-7] object MissionCommandParamInfo object @@ -120,7 +119,6 @@ public: Q_PROPERTY(bool specifiesCoordinate READ specifiesCoordinate CONSTANT) Q_PROPERTY(bool specifiesAltitudeOnly READ specifiesAltitudeOnly CONSTANT) Q_PROPERTY(int command READ intCommand CONSTANT) - Q_PROPERTY(bool cameraSection READ cameraSection CONSTANT) MAV_CMD command(void) const { return _command; } int intCommand(void) const { return (int)_command; } @@ -133,7 +131,6 @@ public: bool isStandaloneCoordinate (void) const; bool specifiesCoordinate (void) const; bool specifiesAltitudeOnly (void) const; - bool cameraSection (void) const; /// Load the data in the object from the specified json /// @param jsonObject Json object to load from @@ -192,7 +189,6 @@ private: static const char* _specifiesAltitudeOnlyJsonKey; static const char* _unitsJsonKey; static const char* _commentJsonKey; - static const char* _cameraSectionJsonKey; static const char* _advancedCategory; friend class MissionCommandTree; diff --git a/src/MissionManager/MissionController.cc b/src/MissionManager/MissionController.cc index afa7e9a3b79628e0e865abcc8c1df1de4b38090e..730584c9cf49facd14177ccb046bfcec304e5bd9 100644 --- a/src/MissionManager/MissionController.cc +++ b/src/MissionManager/MissionController.cc @@ -1526,16 +1526,18 @@ void MissionController::_scanForAdditionalSettings(QmlObjectListModel* visualIte qCDebug(MissionControllerLog) << "MissionController::_scanForAdditionalSettings count:scanIndex" << visualItems->count() << scanIndex; MissionSettingsItem* settingsItem = qobject_cast(visualItem); - if (settingsItem && settingsItem->scanForMissionSettings(visualItems, scanIndex, vehicle)) { + if (settingsItem && settingsItem->scanForMissionSettings(visualItems, scanIndex)) { continue; } SimpleMissionItem* simpleItem = qobject_cast(visualItem); if (simpleItem) { - simpleItem->scanForSections(visualItems, scanIndex + 1, vehicle); + scanIndex++; + simpleItem->scanForSections(visualItems, scanIndex, vehicle); + } else { + // Complex item, can't have sections + scanIndex++; } - - scanIndex++; } } diff --git a/src/MissionManager/MissionSettings.FactMetaData.json b/src/MissionManager/MissionSettings.FactMetaData.json index 906947f05fcb006c05006ebde834a3b4b012ff95..e5ea2a5f038a797a57c3913f73a9319b551207fe 100644 --- a/src/MissionManager/MissionSettings.FactMetaData.json +++ b/src/MissionManager/MissionSettings.FactMetaData.json @@ -7,14 +7,6 @@ "decimalPlaces": 1, "defaultValue": 0 }, -{ - "name": "FlightSpeed", - "shortDescription": "Flight speed for mission.", - "type": "double", - "units": "m/s", - "min": 0, - "decimalPlaces": 1 -}, { "name": "MissionEndAction", "shortDescription": "The action to take when the mission completed.", diff --git a/src/MissionManager/MissionSettingsItem.cc b/src/MissionManager/MissionSettingsItem.cc index d28adc121c2e8f4f0900ab64a20309e1960cf212..e10d68950d6a499e4eb4fe923bb434ee12425dd8 100644 --- a/src/MissionManager/MissionSettingsItem.cc +++ b/src/MissionManager/MissionSettingsItem.cc @@ -24,17 +24,16 @@ QGC_LOGGING_CATEGORY(MissionSettingsComplexItemLog, "MissionSettingsComplexItemL const char* MissionSettingsItem::jsonComplexItemTypeValue = "MissionSettings"; const char* MissionSettingsItem::_plannedHomePositionAltitudeName = "PlannedHomePositionAltitude"; -const char* MissionSettingsItem::_missionFlightSpeedName = "FlightSpeed"; const char* MissionSettingsItem::_missionEndActionName = "MissionEndAction"; QMap MissionSettingsItem::_metaDataMap; MissionSettingsItem::MissionSettingsItem(Vehicle* vehicle, QObject* parent) : ComplexMissionItem(vehicle, parent) - , _specifyMissionFlightSpeed(false) , _plannedHomePositionAltitudeFact (0, _plannedHomePositionAltitudeName, FactMetaData::valueTypeDouble) - , _missionFlightSpeedFact (0, _missionFlightSpeedName, FactMetaData::valueTypeDouble) , _missionEndActionFact (0, _missionEndActionName, FactMetaData::valueTypeUint32) + , _cameraSection(vehicle) + , _speedSection(vehicle) , _sequenceNumber(0) , _dirty(false) { @@ -45,52 +44,36 @@ MissionSettingsItem::MissionSettingsItem(Vehicle* vehicle, QObject* parent) } _plannedHomePositionAltitudeFact.setMetaData (_metaDataMap[_plannedHomePositionAltitudeName]); - _missionFlightSpeedFact.setMetaData (_metaDataMap[_missionFlightSpeedName]); _missionEndActionFact.setMetaData (_metaDataMap[_missionEndActionName]); _plannedHomePositionAltitudeFact.setRawValue (_plannedHomePositionAltitudeFact.rawDefaultValue()); _missionEndActionFact.setRawValue (_missionEndActionFact.rawDefaultValue()); - // FIXME: Flight speed default value correctly based firmware parameter if online - AppSettings* appSettings = qgcApp()->toolbox()->settingsManager()->appSettings(); - Fact* speedFact = vehicle->multiRotor() ? appSettings->offlineEditingHoverSpeed() : appSettings->offlineEditingCruiseSpeed(); - _missionFlightSpeedFact.setRawValue(speedFact->rawValue().toDouble()); - setHomePositionSpecialCase(true); connect(this, &MissionSettingsItem::specifyMissionFlightSpeedChanged, this, &MissionSettingsItem::_setDirtyAndUpdateLastSequenceNumber); - connect(&_cameraSection, &CameraSection::missionItemCountChanged, this, &MissionSettingsItem::_setDirtyAndUpdateLastSequenceNumber); + connect(&_cameraSection, &CameraSection::itemCountChanged, this, &MissionSettingsItem::_setDirtyAndUpdateLastSequenceNumber); + connect(&_speedSection, &CameraSection::itemCountChanged, this, &MissionSettingsItem::_setDirtyAndUpdateLastSequenceNumber); connect(&_plannedHomePositionAltitudeFact, &Fact::valueChanged, this, &MissionSettingsItem::_setDirty); connect(&_plannedHomePositionAltitudeFact, &Fact::valueChanged, this, &MissionSettingsItem::_updateAltitudeInCoordinate); - connect(&_missionFlightSpeedFact, &Fact::valueChanged, this, &MissionSettingsItem::_setDirty); connect(&_missionEndActionFact, &Fact::valueChanged, this, &MissionSettingsItem::_setDirty); - connect(&_cameraSection, &CameraSection::dirtyChanged, this, &MissionSettingsItem::_cameraSectionDirtyChanged); + connect(&_cameraSection, &CameraSection::dirtyChanged, this, &MissionSettingsItem::_sectionDirtyChanged); + connect(&_speedSection, &SpeedSection::dirtyChanged, this, &MissionSettingsItem::_sectionDirtyChanged); - connect(&_missionFlightSpeedFact, &Fact::valueChanged, this, &MissionSettingsItem::specifiedFlightSpeedChanged); connect(&_cameraSection, &CameraSection::specifyGimbalChanged, this, &MissionSettingsItem::specifiedGimbalYawChanged); connect(&_cameraSection, &CameraSection::specifiedGimbalYawChanged, this, &MissionSettingsItem::specifiedGimbalYawChanged); } -void MissionSettingsItem::setSpecifyMissionFlightSpeed(bool specifyMissionFlightSpeed) -{ - if (specifyMissionFlightSpeed != _specifyMissionFlightSpeed) { - _specifyMissionFlightSpeed = specifyMissionFlightSpeed; - emit specifyMissionFlightSpeedChanged(specifyMissionFlightSpeed); - } -} - int MissionSettingsItem::lastSequenceNumber(void) const { int lastSequenceNumber = _sequenceNumber; - if (_specifyMissionFlightSpeed) { - lastSequenceNumber++; - } - lastSequenceNumber += _cameraSection.missionItemCount(); + lastSequenceNumber += _cameraSection.itemCount(); + lastSequenceNumber += _speedSection.itemCount(); return lastSequenceNumber; } @@ -171,23 +154,8 @@ void MissionSettingsItem::appendMissionItems(QList& items, QObject missionItemParent); items.append(item); - if (_specifyMissionFlightSpeed) { - qCDebug(MissionSettingsComplexItemLog) << "Appending MAV_CMD_DO_CHANGE_SPEED"; - MissionItem* item = new MissionItem(seqNum++, - MAV_CMD_DO_CHANGE_SPEED, - MAV_FRAME_MISSION, - _vehicle->multiRotor() ? 1 /* groundspeed */ : 0 /* airspeed */, // Change airspeed or groundspeed - _missionFlightSpeedFact.rawValue().toDouble(), - -1, // No throttle change - 0, // Absolute speed change - 0, 0, 0, // param 5-7 not used - true, // autoContinue - false, // isCurrentItem - missionItemParent); - items.append(item); - } - - _cameraSection.appendMissionItems(items, missionItemParent, seqNum); + _cameraSection.appendSectionItems(items, missionItemParent, seqNum); + _speedSection.appendSectionItems(items, missionItemParent, seqNum); } bool MissionSettingsItem::addMissionEndAction(QList& items, int seqNum, QObject* missionItemParent) @@ -254,11 +222,10 @@ bool MissionSettingsItem::addMissionEndAction(QList& items, int se } } -bool MissionSettingsItem::scanForMissionSettings(QmlObjectListModel* visualItems, int scanIndex, Vehicle* vehicle) +bool MissionSettingsItem::scanForMissionSettings(QmlObjectListModel* visualItems, int scanIndex) { - bool foundSpeed = false; + bool foundSpeedSection = false; bool foundCameraSection = false; - bool stopLooking = false; qCDebug(MissionSettingsComplexItemLog) << "MissionSettingsItem::scanForMissionSettings count:scanIndex" << visualItems->count() << scanIndex; @@ -271,54 +238,8 @@ bool MissionSettingsItem::scanForMissionSettings(QmlObjectListModel* visualItems // Scan through the initial mission items for possible mission settings scanIndex++; - while (!stopLooking && visualItems->count() > 1) { - SimpleMissionItem* item = visualItems->value(scanIndex); - if (!item) { - // We hit a complex item, there can be no more possible mission settings - break; - } - MissionItem& missionItem = item->missionItem(); - - qCDebug(MissionSettingsComplexItemLog) << item->command() << missionItem.param1() << missionItem.param2() << missionItem.param3() << missionItem.param4() << missionItem.param5() << missionItem.param6() << missionItem.param7() ; - - // See MissionSettingsItem::getMissionItems for specs on what compomises a known mission setting - - switch ((MAV_CMD)item->command()) { - case MAV_CMD_DO_CHANGE_SPEED: - if (!foundSpeed && missionItem.param3() == -1 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) { - if (vehicle->multiRotor()) { - if (missionItem.param1() != 1) { - stopLooking = true; - break; - } - } else { - if (missionItem.param1() != 0) { - stopLooking = true; - break; - } - } - foundSpeed = true; - settingsItem->setSpecifyMissionFlightSpeed(true); - settingsItem->missionFlightSpeed()->setRawValue(missionItem.param2()); - visualItems->removeAt(scanIndex)->deleteLater(); - qCDebug(MissionSettingsComplexItemLog) << "Scan: Found MAV_CMD_DO_CHANGE_SPEED"; - continue; - } - stopLooking = true; - break; - - default: - if (!foundCameraSection) { - if (settingsItem->_cameraSection.scanForCameraSection(visualItems, scanIndex)) { - foundCameraSection = true; - qCDebug(MissionSettingsComplexItemLog) << "Scan: Found Camera Section"; - continue; - } - } - stopLooking = true; - break; - } - } + foundCameraSection = settingsItem->_cameraSection.scanForSection(visualItems, scanIndex); + foundSpeedSection = settingsItem->_speedSection.scanForSection(visualItems, scanIndex); // Look at the end of the mission for end actions @@ -349,7 +270,7 @@ bool MissionSettingsItem::scanForMissionSettings(QmlObjectListModel* visualItems } } - return foundSpeed || foundCameraSection; + return foundSpeedSection || foundCameraSection; } double MissionSettingsItem::complexDistance(void) const @@ -378,18 +299,13 @@ void MissionSettingsItem::_setDirtyAndUpdateLastSequenceNumber(void) setDirty(true); } -void MissionSettingsItem::_cameraSectionDirtyChanged(bool dirty) +void MissionSettingsItem::_sectionDirtyChanged(bool dirty) { if (dirty) { setDirty(true); } } -double MissionSettingsItem::specifiedFlightSpeed(void) -{ - return _specifyMissionFlightSpeed ? _missionFlightSpeedFact.rawValue().toDouble() : std::numeric_limits::quiet_NaN(); -} - double MissionSettingsItem::specifiedGimbalYaw(void) { return _cameraSection.specifyGimbal() ? _cameraSection.gimbalYaw()->rawValue().toDouble() : std::numeric_limits::quiet_NaN(); @@ -406,3 +322,12 @@ void MissionSettingsItem::_updateAltitudeInCoordinate(QVariant value) emit exitCoordinateChanged(_plannedHomePositionCoordinate); } } + +double MissionSettingsItem::specifiedFlightSpeed(void) +{ + if (_speedSection.specifyFlightSpeed()) { + return _speedSection.flightSpeed()->rawValue().toDouble(); + } else { + return std::numeric_limits::quiet_NaN(); + } +} diff --git a/src/MissionManager/MissionSettingsItem.h b/src/MissionManager/MissionSettingsItem.h index b8f99189ce974ff34d01317e2ae6d22ce627df74..efafa87faf4fc9631b7cd8f5a1e83d3a70fbb652 100644 --- a/src/MissionManager/MissionSettingsItem.h +++ b/src/MissionManager/MissionSettingsItem.h @@ -15,6 +15,7 @@ #include "Fact.h" #include "QGCLoggingCategory.h" #include "CameraSection.h" +#include "SpeedSection.h" Q_DECLARE_LOGGING_CATEGORY(MissionSettingsComplexItemLog) @@ -32,22 +33,19 @@ public: }; Q_ENUMS(MissionEndAction) - Q_PROPERTY(bool specifyMissionFlightSpeed READ specifyMissionFlightSpeed WRITE setSpecifyMissionFlightSpeed NOTIFY specifyMissionFlightSpeedChanged) - Q_PROPERTY(Fact* missionFlightSpeed READ missionFlightSpeed CONSTANT) Q_PROPERTY(Fact* missionEndAction READ missionEndAction CONSTANT) Q_PROPERTY(Fact* plannedHomePositionAltitude READ plannedHomePositionAltitude CONSTANT) Q_PROPERTY(QObject* cameraSection READ cameraSection CONSTANT) + Q_PROPERTY(QObject* speedSection READ speedSection CONSTANT) Fact* plannedHomePositionAltitude (void) { return &_plannedHomePositionAltitudeFact; } - Fact* missionFlightSpeed (void) { return &_missionFlightSpeedFact; } Fact* missionEndAction (void) { return &_missionEndActionFact; } - bool specifyMissionFlightSpeed (void) const { return _specifyMissionFlightSpeed; } - void setSpecifyMissionFlightSpeed(bool specifyMissionFlightSpeed); QObject* cameraSection(void) { return &_cameraSection; } + QObject* speedSection(void) { return &_speedSection; } /// Scans the loaded items for settings items - static bool scanForMissionSettings(QmlObjectListModel* visualItems, int scanIndex, Vehicle* vehicle); + static bool scanForMissionSettings(QmlObjectListModel* visualItems, int scanIndex); /// Adds the optional mission end action to the list /// @param items Mission items list to append to @@ -77,10 +75,10 @@ public: QGeoCoordinate coordinate (void) const final { return _plannedHomePositionCoordinate; } QGeoCoordinate exitCoordinate (void) const final { return _plannedHomePositionCoordinate; } int sequenceNumber (void) const final { return _sequenceNumber; } - double specifiedFlightSpeed (void) final; double specifiedGimbalYaw (void) final; void appendMissionItems (QList& items, QObject* missionItemParent) final; void applyNewAltitude (double newAltitude) final { Q_UNUSED(newAltitude); /* no action */ } + double specifiedFlightSpeed (void) final; bool coordinateHasRelativeAltitude (void) const final { return true; } bool exitCoordinateHasRelativeAltitude (void) const final { return true; } @@ -99,16 +97,15 @@ signals: private slots: void _setDirtyAndUpdateLastSequenceNumber (void); void _setDirty (void); - void _cameraSectionDirtyChanged (bool dirty); + void _sectionDirtyChanged (bool dirty); void _updateAltitudeInCoordinate (QVariant value); private: - bool _specifyMissionFlightSpeed; QGeoCoordinate _plannedHomePositionCoordinate; // Does not include altitde Fact _plannedHomePositionAltitudeFact; - Fact _missionFlightSpeedFact; Fact _missionEndActionFact; CameraSection _cameraSection; + SpeedSection _speedSection; int _sequenceNumber; bool _dirty; @@ -116,7 +113,6 @@ private: static QMap _metaDataMap; static const char* _plannedHomePositionAltitudeName; - static const char* _missionFlightSpeedName; static const char* _missionEndActionName; }; diff --git a/src/MissionManager/Section.h b/src/MissionManager/Section.h new file mode 100644 index 0000000000000000000000000000000000000000..2bb049a160066e449edb599d6cd1e2e37ead2947 --- /dev/null +++ b/src/MissionManager/Section.h @@ -0,0 +1,66 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#pragma once + +#include "MissionItem.h" +#include "Vehicle.h" +#include "QmlObjectListModel.h" + +Q_DECLARE_LOGGING_CATEGORY(SectionLog) + +// A Section encapsulates a set of mission commands which can be associated with another simple mission item. +class Section : public QObject +{ + Q_OBJECT + +public: + Section(Vehicle* vehicle, QObject* parent = NULL) + : QObject(parent) + , _vehicle(vehicle) + { + + } + + Q_PROPERTY(bool available READ available WRITE setAvailable NOTIFY availableChanged) + Q_PROPERTY(bool settingsSpecified READ settingsSpecified NOTIFY settingsSpecifiedChanged) + Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY availableChanged) + + virtual bool available (void) const = 0; + virtual bool settingsSpecified (void) const = 0; + virtual bool dirty (void) const = 0; + + virtual void setAvailable (bool available) = 0; + virtual void setDirty (bool dirty) = 0; + + /// Scans the loaded items for the section items + /// @param visualItems Item list + /// @param scanIndex[in,out] Index to start scanning from + /// @return true: section found, items added, scanIndex updated + virtual bool scanForSection(QmlObjectListModel* visualItems, int& scanIndex) = 0; + + /// Appends the mission items associated with this section + /// @param items List to append to + /// @param missionItemParent QObject parent for created MissionItems + /// @param nextSequenceNumber[in,out] Sequence number for first item, updated as items are added + virtual void appendSectionItems(QList& items, QObject* missionItemParent, int& nextSequenceNumber) = 0; + + /// Returns the number of mission items represented by this section. + /// Signals: itemCountChanged + virtual int itemCount(void) const = 0; + +signals: + void availableChanged (bool available); + void settingsSpecifiedChanged (bool settingsSpecified); + void dirtyChanged (bool dirty); + void itemCountChanged (int itemCount); + +protected: + Vehicle* _vehicle; +}; diff --git a/src/MissionManager/SimpleMissionItem.cc b/src/MissionManager/SimpleMissionItem.cc index 8d5258bd5540eefb85bd2ef8ee9f6d3cbb62e08e..122912bcd38c8b12e1fdc157037d6257d8d89d6e 100644 --- a/src/MissionManager/SimpleMissionItem.cc +++ b/src/MissionManager/SimpleMissionItem.cc @@ -52,6 +52,7 @@ SimpleMissionItem::SimpleMissionItem(Vehicle* vehicle, QObject* parent) , _rawEdit(false) , _dirty(false) , _ignoreDirtyChangeSignals(false) + , _speedSection(NULL) , _cameraSection(NULL) , _commandTree(qgcApp()->toolbox()->missionCommandTree()) , _altitudeRelativeToHomeFact (0, "Altitude is relative to home", FactMetaData::valueTypeUint32) @@ -72,7 +73,7 @@ SimpleMissionItem::SimpleMissionItem(Vehicle* vehicle, QObject* parent) _setupMetaData(); _connectSignals(); - _updateCameraSection(); + _updateOptionalSections(); setDefaultsForCommand(); _rebuildFacts(); @@ -90,6 +91,7 @@ SimpleMissionItem::SimpleMissionItem(Vehicle* vehicle, const MissionItem& missio , _rawEdit(false) , _dirty(false) , _ignoreDirtyChangeSignals(false) + , _speedSection(NULL) , _cameraSection(NULL) , _commandTree(qgcApp()->toolbox()->missionCommandTree()) , _altitudeRelativeToHomeFact (0, "Altitude is relative to home", FactMetaData::valueTypeUint32) @@ -110,7 +112,7 @@ SimpleMissionItem::SimpleMissionItem(Vehicle* vehicle, const MissionItem& missio _setupMetaData(); _connectSignals(); - _updateCameraSection(); + _updateOptionalSections(); _syncFrameToAltitudeRelativeToHome(); _rebuildFacts(); } @@ -121,6 +123,7 @@ SimpleMissionItem::SimpleMissionItem(const SimpleMissionItem& other, QObject* pa , _rawEdit(false) , _dirty(false) , _ignoreDirtyChangeSignals(false) + , _speedSection(NULL) , _cameraSection(NULL) , _commandTree(qgcApp()->toolbox()->missionCommandTree()) , _altitudeRelativeToHomeFact (0, "Altitude is relative to home", FactMetaData::valueTypeUint32) @@ -136,7 +139,7 @@ SimpleMissionItem::SimpleMissionItem(const SimpleMissionItem& other, QObject* pa _setupMetaData(); _connectSignals(); - _updateCameraSection(); + _updateOptionalSections(); *this = other; @@ -651,7 +654,7 @@ void SimpleMissionItem::setCommand(MavlinkQmlSingleton::Qml_MAV_CMD command) { if ((MAV_CMD)command != _missionItem.command()) { _missionItem.setCommand((MAV_CMD)command); - _updateCameraSection(); + _updateOptionalSections(); } } @@ -674,7 +677,11 @@ void SimpleMissionItem::setSequenceNumber(int sequenceNumber) double SimpleMissionItem::specifiedFlightSpeed(void) { - return missionItem().specifiedFlightSpeed(); + if (_speedSection->specifyFlightSpeed()) { + return _speedSection->flightSpeed()->rawValue().toDouble(); + } else { + return missionItem().specifiedFlightSpeed(); + } } double SimpleMissionItem::specifiedGimbalYaw(void) @@ -682,47 +689,59 @@ double SimpleMissionItem::specifiedGimbalYaw(void) return _cameraSection->available() ? _cameraSection->specifiedGimbalYaw() : missionItem().specifiedGimbalYaw(); } -bool SimpleMissionItem::scanForSections(QmlObjectListModel* visualItems, int scanIndex, Vehicle* vehicle) +bool SimpleMissionItem::scanForSections(QmlObjectListModel* visualItems, int& scanIndex, Vehicle* vehicle) { bool sectionFound = false; Q_UNUSED(vehicle); if (_cameraSection->available()) { - sectionFound = _cameraSection->scanForCameraSection(visualItems, scanIndex); + sectionFound |= _cameraSection->scanForSection(visualItems, scanIndex); + } + if (_speedSection->available()) { + sectionFound |= _speedSection->scanForSection(visualItems, scanIndex); } return sectionFound; } -void SimpleMissionItem::_updateCameraSection(void) +void SimpleMissionItem::_updateOptionalSections(void) { + // Remove previous sections if (_cameraSection) { - // Remove previous section _cameraSection->deleteLater(); _cameraSection = NULL; } + if (_speedSection) { + _speedSection->deleteLater(); + _speedSection = NULL; + } - // Add new section - _cameraSection = new CameraSection(this); - const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command()); - if (uiInfo && uiInfo->cameraSection()) { + // Add new sections + + _cameraSection = new CameraSection(_vehicle, this); + _speedSection = new SpeedSection(_vehicle, this); + if ((MAV_CMD)command() == MAV_CMD_NAV_WAYPOINT) { _cameraSection->setAvailable(true); + _speedSection->setAvailable(true); } - connect(_cameraSection, &CameraSection::dirtyChanged, this, &SimpleMissionItem::_cameraSectionDirtyChanged); - connect(_cameraSection, &CameraSection::availableChanged, this, &SimpleMissionItem::_updateLastSequenceNumber); - connect(_cameraSection, &CameraSection::missionItemCountChanged, this, &SimpleMissionItem::_updateLastSequenceNumber); + connect(_cameraSection, &CameraSection::dirtyChanged, this, &SimpleMissionItem::_sectionDirtyChanged); + connect(_cameraSection, &CameraSection::itemCountChanged, this, &SimpleMissionItem::_updateLastSequenceNumber); connect(_cameraSection, &CameraSection::availableChanged, this, &SimpleMissionItem::specifiedGimbalYawChanged); connect(_cameraSection, &CameraSection::specifyGimbalChanged, this, &SimpleMissionItem::specifiedGimbalYawChanged); connect(_cameraSection, &CameraSection::specifiedGimbalYawChanged, this, &SimpleMissionItem::specifiedGimbalYawChanged); + connect(_speedSection, &CameraSection::dirtyChanged, this, &SimpleMissionItem::_sectionDirtyChanged); + connect(_speedSection, &CameraSection::itemCountChanged, this, &SimpleMissionItem::_updateLastSequenceNumber); + emit cameraSectionChanged(_cameraSection); + emit speedSectionChanged(_speedSection); } int SimpleMissionItem::lastSequenceNumber(void) const { - return sequenceNumber() + (_cameraSection ? _cameraSection->missionItemCount() : 0); + return sequenceNumber() + (_cameraSection ? _cameraSection->itemCount() : 0) + (_speedSection ? _speedSection->itemCount() : 0); } void SimpleMissionItem::_updateLastSequenceNumber(void) @@ -730,7 +749,7 @@ void SimpleMissionItem::_updateLastSequenceNumber(void) emit lastSequenceNumberChanged(lastSequenceNumber()); } -void SimpleMissionItem::_cameraSectionDirtyChanged(bool dirty) +void SimpleMissionItem::_sectionDirtyChanged(bool dirty) { if (dirty) { setDirty(true); @@ -744,7 +763,8 @@ void SimpleMissionItem::appendMissionItems(QList& items, QObject* items.append(new MissionItem(missionItem(), missionItemParent)); seqNum++; - _cameraSection->appendMissionItems(items, missionItemParent, seqNum); + _cameraSection->appendSectionItems(items, missionItemParent, seqNum); + _speedSection->appendSectionItems(items, missionItemParent, seqNum); } void SimpleMissionItem::applyNewAltitude(double newAltitude) diff --git a/src/MissionManager/SimpleMissionItem.h b/src/MissionManager/SimpleMissionItem.h index c1ee065fbbfaa1193998c18e44d1fa4096b59c30..14abcba2bb09c03a2a332d6a26c0ffd34341e277 100644 --- a/src/MissionManager/SimpleMissionItem.h +++ b/src/MissionManager/SimpleMissionItem.h @@ -15,6 +15,7 @@ #include "MissionItem.h" #include "MissionCommandTree.h" #include "CameraSection.h" +#include "SpeedSection.h" /// A SimpleMissionItem is used to represent a single MissionItem to the ui. class SimpleMissionItem : public VisualMissionItem @@ -31,12 +32,13 @@ public: const SimpleMissionItem& operator=(const SimpleMissionItem& other); Q_PROPERTY(QString category READ category NOTIFY commandChanged) - Q_PROPERTY(MavlinkQmlSingleton::Qml_MAV_CMD command READ command WRITE setCommand NOTIFY commandChanged) Q_PROPERTY(bool friendlyEditAllowed READ friendlyEditAllowed NOTIFY friendlyEditAllowedChanged) Q_PROPERTY(bool rawEdit READ rawEdit WRITE setRawEdit NOTIFY rawEditChanged) ///< true: raw item editing with all params Q_PROPERTY(bool relativeAltitude READ relativeAltitude NOTIFY frameChanged) + Q_PROPERTY(MavlinkQmlSingleton::Qml_MAV_CMD command READ command WRITE setCommand NOTIFY commandChanged) /// Optional sections + Q_PROPERTY(QObject* speedSection READ speedSection NOTIFY speedSectionChanged) Q_PROPERTY(QObject* cameraSection READ cameraSection NOTIFY cameraSectionChanged) // These properties are used to display the editing ui @@ -49,8 +51,8 @@ public: /// @param visualItems List of all visual items /// @param scanIndex Index to start scanning from /// @param vehicle Vehicle associated with this mission - /// @return true: section found - bool scanForSections(QmlObjectListModel* visualItems, int scanIndex, Vehicle* vehicle); + /// @return true: section found, scanIndex updated + bool scanForSections(QmlObjectListModel* visualItems, int& scanIndex, Vehicle* vehicle); // Property accesors @@ -59,6 +61,7 @@ public: bool friendlyEditAllowed (void) const; bool rawEdit (void) const; CameraSection* cameraSection (void) { return _cameraSection; } + SpeedSection* speedSection (void) { return _speedSection; } QmlObjectListModel* textFieldFacts (void) { return &_textFieldFacts; } QmlObjectListModel* nanFacts (void) { return &_nanFacts; } @@ -123,10 +126,11 @@ signals: void headingDegreesChanged (double heading); void rawEditChanged (bool rawEdit); void cameraSectionChanged (QObject* cameraSection); + void speedSectionChanged (QObject* cameraSection); private slots: - void _setDirtyFromSignal (void); - void _cameraSectionDirtyChanged (bool dirty); + void _setDirtyFromSignal (void); + void _sectionDirtyChanged (bool dirty); void _sendCommandChanged (void); void _sendCoordinateChanged (void); void _sendFrameChanged (void); @@ -139,7 +143,7 @@ private slots: private: void _connectSignals (void); void _setupMetaData (void); - void _updateCameraSection (void); + void _updateOptionalSections(void); void _rebuildTextFieldFacts (void); void _rebuildNaNFacts (void); void _rebuildCheckboxFacts (void); @@ -150,6 +154,7 @@ private: bool _dirty; bool _ignoreDirtyChangeSignals; + SpeedSection* _speedSection; CameraSection* _cameraSection; MissionCommandTree* _commandTree; diff --git a/src/MissionManager/SpeedSection.FactMetaData.json b/src/MissionManager/SpeedSection.FactMetaData.json new file mode 100644 index 0000000000000000000000000000000000000000..0a6f4368d3e431f68ff9948632da6c026ad0c6bb --- /dev/null +++ b/src/MissionManager/SpeedSection.FactMetaData.json @@ -0,0 +1,11 @@ +[ +{ + "name": "FlightSpeed", + "shortDescription": "Set the current flight speed", + "type": "double", + "units": "m/s", + "min": 0, + "decimalPlaces": 1, + "defaultValue": 0 +} +] diff --git a/src/MissionManager/SpeedSection.cc b/src/MissionManager/SpeedSection.cc new file mode 100644 index 0000000000000000000000000000000000000000..6ac99b8693c6fe848bb15f3d8d8498fe17fb37ca --- /dev/null +++ b/src/MissionManager/SpeedSection.cc @@ -0,0 +1,145 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#include "SpeedSection.h" +#include "JsonHelper.h" +#include "FirmwarePlugin.h" +#include "SimpleMissionItem.h" + +const char* SpeedSection::_flightSpeedName = "FlightSpeed"; + +QMap SpeedSection::_metaDataMap; + +SpeedSection::SpeedSection(Vehicle* vehicle, QObject* parent) + : Section (vehicle, parent) + , _available (false) + , _dirty (false) + , _specifyFlightSpeed (false) + , _flightSpeedFact (0, _flightSpeedName, FactMetaData::valueTypeDouble) +{ + if (_metaDataMap.isEmpty()) { + _metaDataMap = FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/SpeedSection.FactMetaData.json"), NULL /* metaDataParent */); + } + + double hoverSpeed, cruiseSpeed; + double flightSpeed = 0; + + _vehicle->firmwarePlugin()->missionFlightSpeedInfo(_vehicle, hoverSpeed, cruiseSpeed); + if (_vehicle->multiRotor()) { + flightSpeed = hoverSpeed; + } else if (_vehicle->fixedWing()) { + flightSpeed = cruiseSpeed; + } + + _metaDataMap[_flightSpeedName]->setRawDefaultValue(flightSpeed); + _flightSpeedFact.setMetaData(_metaDataMap[_flightSpeedName]); + _flightSpeedFact.setRawValue(flightSpeed); + + connect(this, &SpeedSection::specifyFlightSpeedChanged, this, &SpeedSection::_setDirtyAndUpdateItemCount); + connect(this, &SpeedSection::specifyFlightSpeedChanged, this, &SpeedSection::settingsSpecifiedChanged); + connect(&_flightSpeedFact, &Fact::valueChanged, this, &SpeedSection::_setDirty); +} + +bool SpeedSection::settingsSpecified(void) const +{ + return _specifyFlightSpeed; +} + +void SpeedSection::setAvailable(bool available) +{ + if (available != _available) { + if (available && (_vehicle->multiRotor() || _vehicle->fixedWing())) { + _available = available; + emit availableChanged(available); + } + } +} + +void SpeedSection::_setDirty(void) +{ + setDirty(true); +} + +void SpeedSection::_setDirtyAndUpdateItemCount(void) +{ + setDirty(true); + emit itemCountChanged(itemCount()); +} + +void SpeedSection::setDirty(bool dirty) +{ + if (_dirty != dirty) { + _dirty = dirty; + emit dirtyChanged(_dirty); + } +} + +void SpeedSection::setSpecifyFlightSpeed(bool specifyFlightSpeed) +{ + if (specifyFlightSpeed != _specifyFlightSpeed) { + _specifyFlightSpeed = specifyFlightSpeed; + emit specifyFlightSpeedChanged(specifyFlightSpeed); + } +} + +int SpeedSection::itemCount(void) const +{ + return _specifyFlightSpeed ? 1: 0; +} + +void SpeedSection::appendSectionItems(QList& items, QObject* missionItemParent, int& seqNum) +{ + // IMPORTANT NOTE: If anything changes here you must also change SpeedSection::scanForSettings + + if (_specifyFlightSpeed) { + MissionItem* item = new MissionItem(seqNum++, + MAV_CMD_DO_CHANGE_SPEED, + MAV_FRAME_MISSION, + _vehicle->multiRotor() ? 1 /* groundspeed */ : 0 /* airspeed */, // Change airspeed or groundspeed + _flightSpeedFact.rawValue().toDouble(), + -1, // No throttle change + 0, // Absolute speed change + 0, 0, 0, // param 5-7 not used + true, // autoContinue + false, // isCurrentItem + missionItemParent); + items.append(item); + } +} + +bool SpeedSection::scanForSection(QmlObjectListModel* visualItems, int& scanIndex) +{ + if (!_available || scanIndex >= visualItems->count()) { + return false; + } + + SimpleMissionItem* item = visualItems->value(scanIndex); + if (!item) { + // We hit a complex item, there can't be a speed setting + return false; + } + MissionItem& missionItem = item->missionItem(); + + // See SpeedSection::appendMissionItems for specs on what consitutes a known speed setting + + if (missionItem.command() == MAV_CMD_DO_CHANGE_SPEED && missionItem.param3() == -1 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) { + if (_vehicle->multiRotor() && missionItem.param1() != 1) { + return false; + } else if (_vehicle->fixedWing() && missionItem.param1() != 0) { + return false; + } + visualItems->removeAt(scanIndex)->deleteLater(); + _flightSpeedFact.setRawValue(missionItem.param2()); + setSpecifyFlightSpeed(true); + scanIndex++; + return true; + } + + return false; +} diff --git a/src/MissionManager/SpeedSection.h b/src/MissionManager/SpeedSection.h new file mode 100644 index 0000000000000000000000000000000000000000..dc85b07ab749b0503de8537444af8d3af5f14b38 --- /dev/null +++ b/src/MissionManager/SpeedSection.h @@ -0,0 +1,56 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#pragma once + +#include "Section.h" +#include "FactSystem.h" +#include "QmlObjectListModel.h" + +class SpeedSection : public Section +{ + Q_OBJECT + +public: + SpeedSection(Vehicle* vehicle, QObject* parent = NULL); + + Q_PROPERTY(bool specifyFlightSpeed READ specifyFlightSpeed WRITE setSpecifyFlightSpeed NOTIFY specifyFlightSpeedChanged) + Q_PROPERTY(Fact* flightSpeed READ flightSpeed CONSTANT) + + bool specifyFlightSpeed (void) const { return _specifyFlightSpeed; } + Fact* flightSpeed (void) { return &_flightSpeedFact; } + void setSpecifyFlightSpeed (bool specifyFlightSpeed); + + // Overrides from Section + bool available (void) const override { return _available; } + bool dirty (void) const override { return _dirty; } + void setAvailable (bool available) override; + void setDirty (bool dirty) override; + bool scanForSection (QmlObjectListModel* visualItems, int& scanIndex) override; + void appendSectionItems (QList& items, QObject* missionItemParent, int& seqNum) override; + int itemCount (void) const override; + bool settingsSpecified (void) const override; + +signals: + void specifyFlightSpeedChanged(bool specifyFlightSpeed); + +private slots: + void _setDirty(void); + void _setDirtyAndUpdateItemCount(void); + +private: + bool _available; + bool _dirty; + bool _specifyFlightSpeed; + Fact _flightSpeedFact; + + static QMap _metaDataMap; + + static const char* _flightSpeedName; +}; diff --git a/src/PlanView/MissionSettingsEditor.qml b/src/PlanView/MissionSettingsEditor.qml index db73936871fbb02defa27681c43bc4520ca65c65..590c028e67a72ec545b750a58b47abb33145627f 100644 --- a/src/PlanView/MissionSettingsEditor.qml +++ b/src/PlanView/MissionSettingsEditor.qml @@ -31,7 +31,8 @@ Rectangle { property bool _mobile: ScreenTools.isMobile property var _savePath: QGroundControl.settingsManager.appSettings.missionSavePath property var _fileExtension: QGroundControl.settingsManager.appSettings.missionFileExtension - property var _appSettings: QGroundControl.settingsManager.appSettings + property var _appSettings: QGroundControl.settingsManager.appSettings + property bool _waypointsOnlyMode: QGroundControl.corePlugin.options.missionWaypointsOnly readonly property string _firmwareLabel: qsTr("Firmware") readonly property string _vehicleLabel: qsTr("Vehicle") @@ -112,12 +113,12 @@ Rectangle { id: flightSpeedCheckBox text: qsTr("Flight speed") visible: !_missionVehicle.vtol - checked: missionItem.specifyMissionFlightSpeed - onClicked: missionItem.specifyMissionFlightSpeed = checked + checked: missionItem.speedSection.specifyFlightSpeed + onClicked: missionItem.speedSection.specifyFlightSpeed = checked } FactTextField { Layout.fillWidth: true - fact: missionItem.missionFlightSpeed + fact: missionItem.speedSection.flightSpeed visible: flightSpeedCheckBox.visible enabled: flightSpeedCheckBox.checked } @@ -138,7 +139,7 @@ Rectangle { SectionHeader { id: vehicleInfoSectionHeader text: qsTr("Vehicle Info") - visible: _offlineEditing + visible: _offlineEditing && !_waypointsOnlyMode checked: false } diff --git a/src/PlanView/SimpleItemEditor.qml b/src/PlanView/SimpleItemEditor.qml index aafad8bd324adbe2cf6c3aad0caad27d279e1a0b..06d9e62d7074dc016428a269ef82c47b73ddb0df 100644 --- a/src/PlanView/SimpleItemEditor.qml +++ b/src/PlanView/SimpleItemEditor.qml @@ -138,6 +138,26 @@ Rectangle { } } + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + spacing: ScreenTools.defaultFontPixelWidth + visible: missionItem.speedSection.available + + QGCCheckBox { + id: flightSpeedCheckbox + text: qsTr("Flight Speed") + checked: missionItem.speedSection.specifyFlightSpeed + onClicked: missionItem.speedSection.specifyFlightSpeed = checked + } + + FactTextField { + fact: missionItem.speedSection.flightSpeed + Layout.fillWidth: true + enabled: flightSpeedCheckbox.checked + } + } + Repeater { model: missionItem.checkboxFacts diff --git a/src/QmlControls/MissionItemIndexLabel.qml b/src/QmlControls/MissionItemIndexLabel.qml index ba859d2f7eafbe61fefc608f5395c2514f4771f6..d55b27a4c6e6ca4ae4b3d14bc5fa3009cf1d24d2 100644 --- a/src/QmlControls/MissionItemIndexLabel.qml +++ b/src/QmlControls/MissionItemIndexLabel.qml @@ -74,7 +74,7 @@ Canvas { color: "white" opacity: 0.5 radius: _labelRadius - visible: _label.length !== 0 + visible: _label.length !== 0 && !small } QGCLabel {