Browse Source

Merge pull request #8954 from DonLakeFlyer/VTOLCommandEditors

Plan: Show correct item editor based on current VTOL state in mission
QGC4.4
Don Gagne 5 years ago committed by GitHub
parent
commit
4c872ca4ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.cc
  2. 1
      src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.h
  3. 5
      src/FirmwarePlugin/FirmwarePlugin.cc
  4. 3
      src/FirmwarePlugin/FirmwarePlugin.h
  5. 4
      src/MissionManager/CameraSectionTest.cc
  6. 2
      src/MissionManager/KMLPlanDomDocument.cc
  7. 2
      src/MissionManager/MavCmdInfoFixedWing.json
  8. 5
      src/MissionManager/MavCmdInfoMultiRotor.json
  9. 23
      src/MissionManager/MissionCommandTree.cc
  10. 6
      src/MissionManager/MissionCommandTree.h
  11. 6
      src/MissionManager/MissionCommandTreeTest.cc
  12. 8
      src/MissionManager/MissionController.cc
  13. 4
      src/MissionManager/MissionManager.cc
  14. 50
      src/MissionManager/SimpleMissionItem.cc
  15. 29
      src/MissionManager/SimpleMissionItem.h
  16. 145
      src/MissionManager/SimpleMissionItemTest.cc
  17. 67
      src/MissionManager/SimpleMissionItemTest.h
  18. 2
      src/MissionManager/TakeoffMissionItem.cc
  19. 11
      src/MissionManager/VisualMissionItem.cc
  20. 50
      src/MissionManager/VisualMissionItem.h
  21. 16
      src/QGC.cc
  22. 11
      src/QGC.h
  23. 5
      src/Vehicle/Vehicle.cc
  24. 3
      src/Vehicle/Vehicle.h

13
src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.cc

@ -134,19 +134,6 @@ bool ArduCopterFirmwarePlugin::multiRotorXConfig(Vehicle* vehicle)
return vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, "FRAME")->rawValue().toInt() != 0; return vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, "FRAME")->rawValue().toInt() != 0;
} }
bool ArduCopterFirmwarePlugin::vehicleYawsToNextWaypointInMission(const Vehicle* vehicle) const
{
if (vehicle->isOfflineEditingVehicle()) {
return FirmwarePlugin::vehicleYawsToNextWaypointInMission(vehicle);
} else {
if (vehicle->multiRotor() && vehicle->parameterManager()->parameterExists(FactSystem::defaultComponentId, QStringLiteral("WP_YAW_BEHAVIOR"))) {
Fact* yawMode = vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, QStringLiteral("WP_YAW_BEHAVIOR"));
return yawMode && yawMode->rawValue().toInt() != 0;
}
}
return true;
}
#if 0 #if 0
// Follow me not ready for Stable // Follow me not ready for Stable
void ArduCopterFirmwarePlugin::sendGCSMotionReport(Vehicle* vehicle, FollowMe::GCSMotionReport& motionReport, uint8_t estimatationCapabilities) void ArduCopterFirmwarePlugin::sendGCSMotionReport(Vehicle* vehicle, FollowMe::GCSMotionReport& motionReport, uint8_t estimatationCapabilities)

1
src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.h

@ -71,7 +71,6 @@ public:
QString landFlightMode (void) const override { return QStringLiteral("Land"); } QString landFlightMode (void) const override { return QStringLiteral("Land"); }
QString takeControlFlightMode (void) const override { return QStringLiteral("Loiter"); } QString takeControlFlightMode (void) const override { return QStringLiteral("Loiter"); }
QString followFlightMode (void) const override { return QStringLiteral("Follow"); } QString followFlightMode (void) const override { return QStringLiteral("Follow"); }
bool vehicleYawsToNextWaypointInMission (const Vehicle* vehicle) const override;
QString autoDisarmParameter (Vehicle* vehicle) override { Q_UNUSED(vehicle); return QStringLiteral("DISARM_DELAY"); } QString autoDisarmParameter (Vehicle* vehicle) override { Q_UNUSED(vehicle); return QStringLiteral("DISARM_DELAY"); }
bool supportsSmartRTL (void) const override { return true; } bool supportsSmartRTL (void) const override { return true; }
#if 0 #if 0

5
src/FirmwarePlugin/FirmwarePlugin.cc

@ -698,11 +698,6 @@ QMap<QString, FactGroup*>* FirmwarePlugin::factGroups(void) {
return nullptr; return nullptr;
} }
bool FirmwarePlugin::vehicleYawsToNextWaypointInMission(const Vehicle* vehicle) const
{
return vehicle->multiRotor() ? false : true;
}
bool FirmwarePlugin::_armVehicleAndValidate(Vehicle* vehicle) bool FirmwarePlugin::_armVehicleAndValidate(Vehicle* vehicle)
{ {
if (vehicle->armed()) { if (vehicle->armed()) {

3
src/FirmwarePlugin/FirmwarePlugin.h

@ -297,9 +297,6 @@ public:
/// Returns a pointer to a dictionary of firmware-specific FactGroups /// Returns a pointer to a dictionary of firmware-specific FactGroups
virtual QMap<QString, FactGroup*>* factGroups(void); virtual QMap<QString, FactGroup*>* factGroups(void);
/// @true: When flying a mission the vehicle is always facing towards the next waypoint
virtual bool vehicleYawsToNextWaypointInMission(const Vehicle* vehicle) const;
/// Returns the data needed to do battery consumption calculations /// Returns the data needed to do battery consumption calculations
/// @param[out] mAhBattery Battery milliamp-hours rating (0 for no battery data available) /// @param[out] mAhBattery Battery milliamp-hours rating (0 for no battery data available)
/// @param[out] hoverAmps Current draw in amps during hover /// @param[out] hoverAmps Current draw in amps during hover

4
src/MissionManager/CameraSectionTest.cc

@ -1057,7 +1057,7 @@ void CameraSectionTest::_testScanForMultipleItems(void)
item2->missionItem() = cameraItem->missionItem(); item2->missionItem() = cameraItem->missionItem();
visualItems.append(item1); visualItems.append(item1);
visualItems.append(item2); visualItems.append(item2);
qDebug() << commandTree->getUIInfo(_controllerVehicle, (MAV_CMD)item1->command())->rawName() << commandTree->getUIInfo(_controllerVehicle, (MAV_CMD)item2->command())->rawName();; qDebug() << commandTree->getUIInfo(_controllerVehicle, QGCMAVLink::VehicleClassGeneric, (MAV_CMD)item1->command())->rawName() << commandTree->getUIInfo(_controllerVehicle, QGCMAVLink::VehicleClassGeneric, (MAV_CMD)item2->command())->rawName();;
scanIndex = 0; scanIndex = 0;
QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), true); QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), true);
@ -1078,7 +1078,7 @@ void CameraSectionTest::_testScanForMultipleItems(void)
item2->missionItem() = cameraItem->missionItem(); item2->missionItem() = cameraItem->missionItem();
visualItems.append(item1); visualItems.append(item1);
visualItems.append(item2); visualItems.append(item2);
qDebug() << commandTree->getUIInfo(_controllerVehicle, (MAV_CMD)item1->command())->rawName() << commandTree->getUIInfo(_controllerVehicle, (MAV_CMD)item2->command())->rawName();; qDebug() << commandTree->getUIInfo(_controllerVehicle, QGCMAVLink::VehicleClassGeneric, (MAV_CMD)item1->command())->rawName() << commandTree->getUIInfo(_controllerVehicle, QGCMAVLink::VehicleClassGeneric, (MAV_CMD)item2->command())->rawName();;
scanIndex = 0; scanIndex = 0;
QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), true); QCOMPARE(_cameraSection->scanForSection(&visualItems, scanIndex), true);

2
src/MissionManager/KMLPlanDomDocument.cc

@ -51,7 +51,7 @@ void KMLPlanDomDocument::_addFlightPath(Vehicle* vehicle, QList<MissionItem*> rg
QList<QGeoCoordinate> rgFlightCoords; QList<QGeoCoordinate> rgFlightCoords;
QGeoCoordinate homeCoord = rgMissionItems[0]->coordinate(); QGeoCoordinate homeCoord = rgMissionItems[0]->coordinate();
for (const MissionItem* item : rgMissionItems) { for (const MissionItem* item : rgMissionItems) {
const MissionCommandUIInfo* uiInfo = qgcApp()->toolbox()->missionCommandTree()->getUIInfo(vehicle, item->command()); const MissionCommandUIInfo* uiInfo = qgcApp()->toolbox()->missionCommandTree()->getUIInfo(vehicle, QGCMAVLink::VehicleClassGeneric, item->command());
if (uiInfo) { if (uiInfo) {
double altAdjustment = item->frame() == MAV_FRAME_GLOBAL ? 0 : homeCoord.altitude(); // Used to convert to amsl double altAdjustment = item->frame() == MAV_FRAME_GLOBAL ? 0 : homeCoord.altitude(); // Used to convert to amsl
if (uiInfo->isTakeoffCommand() && !vehicle->fixedWing()) { if (uiInfo->isTakeoffCommand() && !vehicle->fixedWing()) {

2
src/MissionManager/MavCmdInfoFixedWing.json

@ -7,7 +7,7 @@
{ {
"id": 16, "id": 16,
"comment": "MAV_CMD_NAV_WAYPOINT", "comment": "MAV_CMD_NAV_WAYPOINT",
"paramRemove": "4" "paramRemove": "1,4"
}, },
{ {
"id": 17, "id": 17,

5
src/MissionManager/MavCmdInfoMultiRotor.json

@ -10,6 +10,11 @@
"paramRemove": "3" "paramRemove": "3"
}, },
{ {
"id": 18,
"comment": "MAV_CMD_NAV_LOITER_TURNS",
"paramRemove": "1,2,3,4"
},
{
"id": 19, "id": 19,
"comment": "MAV_CMD_NAV_LOITER_TIME", "comment": "MAV_CMD_NAV_LOITER_TIME",
"paramRemove": "2,3,4" "paramRemove": "2,3,4"

23
src/MissionManager/MissionCommandTree.cc

@ -81,12 +81,12 @@ void MissionCommandTree::_collapseHierarchy(const MissionCommandList*
} }
} }
void MissionCommandTree::_buildAllCommands(Vehicle* vehicle) void MissionCommandTree::_buildAllCommands(Vehicle* vehicle, QGCMAVLink::VehicleClass_t vtolMode)
{ {
QGCMAVLink::FirmwareClass_t firmwareClass; QGCMAVLink::FirmwareClass_t firmwareClass;
QGCMAVLink::VehicleClass_t vehicleClass; QGCMAVLink::VehicleClass_t vehicleClass;
_firmwareAndVehicleClassInfo(vehicle, firmwareClass, vehicleClass); _firmwareAndVehicleClassInfo(vehicle, vtolMode, firmwareClass, vehicleClass);
if (_allCommands.contains(firmwareClass) && _allCommands[firmwareClass].contains(vehicleClass)) { if (_allCommands.contains(firmwareClass) && _allCommands[firmwareClass].contains(vehicleClass)) {
// Already built // Already built
@ -131,8 +131,8 @@ QStringList MissionCommandTree::_availableCategoriesForVehicle(Vehicle* vehicle)
QGCMAVLink::FirmwareClass_t firmwareClass; QGCMAVLink::FirmwareClass_t firmwareClass;
QGCMAVLink::VehicleClass_t vehicleClass; QGCMAVLink::VehicleClass_t vehicleClass;
_firmwareAndVehicleClassInfo(vehicle, firmwareClass, vehicleClass); _firmwareAndVehicleClassInfo(vehicle, QGCMAVLink::VehicleClassGeneric, firmwareClass, vehicleClass);
_buildAllCommands(vehicle); _buildAllCommands(vehicle, QGCMAVLink::VehicleClassGeneric);
return _supportedCategories[firmwareClass][vehicleClass]; return _supportedCategories[firmwareClass][vehicleClass];
} }
@ -166,13 +166,13 @@ const QList<MAV_CMD>& MissionCommandTree::allCommandIds(void) const
return _staticCommandTree[QGCMAVLink::FirmwareClassGeneric][QGCMAVLink::VehicleClassGeneric]->commandIds(); return _staticCommandTree[QGCMAVLink::FirmwareClassGeneric][QGCMAVLink::VehicleClassGeneric]->commandIds();
} }
const MissionCommandUIInfo* MissionCommandTree::getUIInfo(Vehicle* vehicle, MAV_CMD command) const MissionCommandUIInfo* MissionCommandTree::getUIInfo(Vehicle* vehicle, QGCMAVLink::VehicleClass_t vtolMode, MAV_CMD command)
{ {
QGCMAVLink::FirmwareClass_t firmwareClass; QGCMAVLink::FirmwareClass_t firmwareClass;
QGCMAVLink::VehicleClass_t vehicleClass; QGCMAVLink::VehicleClass_t vehicleClass;
_firmwareAndVehicleClassInfo(vehicle, firmwareClass, vehicleClass); _firmwareAndVehicleClassInfo(vehicle, vtolMode, firmwareClass, vehicleClass);
_buildAllCommands(vehicle); _buildAllCommands(vehicle, vtolMode);
const QMap<MAV_CMD, MissionCommandUIInfo*>& infoMap = _allCommands[firmwareClass][vehicleClass]; const QMap<MAV_CMD, MissionCommandUIInfo*>& infoMap = _allCommands[firmwareClass][vehicleClass];
if (infoMap.contains(command)) { if (infoMap.contains(command)) {
@ -187,8 +187,8 @@ QVariantList MissionCommandTree::getCommandsForCategory(Vehicle* vehicle, const
QGCMAVLink::FirmwareClass_t firmwareClass; QGCMAVLink::FirmwareClass_t firmwareClass;
QGCMAVLink::VehicleClass_t vehicleClass; QGCMAVLink::VehicleClass_t vehicleClass;
_firmwareAndVehicleClassInfo(vehicle, firmwareClass, vehicleClass); _firmwareAndVehicleClassInfo(vehicle, QGCMAVLink::VehicleClassGeneric, firmwareClass, vehicleClass);
_buildAllCommands(vehicle); _buildAllCommands(vehicle, QGCMAVLink::VehicleClassGeneric);
// vehicle can be null in which case _firmwareAndVehicleClassInfo will tell of the firmware/vehicle type for the offline editing vehicle. // vehicle can be null in which case _firmwareAndVehicleClassInfo will tell of the firmware/vehicle type for the offline editing vehicle.
// We then use that to get a firmware plugin so we can get the list of supported commands. // We then use that to get a firmware plugin so we can get the list of supported commands.
@ -210,8 +210,11 @@ QVariantList MissionCommandTree::getCommandsForCategory(Vehicle* vehicle, const
return list; return list;
} }
void MissionCommandTree::_firmwareAndVehicleClassInfo(Vehicle* vehicle, QGCMAVLink::FirmwareClass_t& firmwareClass, QGCMAVLink::VehicleClass_t& vehicleClass) const void MissionCommandTree::_firmwareAndVehicleClassInfo(Vehicle* vehicle, QGCMAVLink::VehicleClass_t vtolMode, QGCMAVLink::FirmwareClass_t& firmwareClass, QGCMAVLink::VehicleClass_t& vehicleClass) const
{ {
firmwareClass = QGCMAVLink::firmwareClass(vehicle->firmwareType()); firmwareClass = QGCMAVLink::firmwareClass(vehicle->firmwareType());
vehicleClass = QGCMAVLink::vehicleClass(vehicle->vehicleType()); vehicleClass = QGCMAVLink::vehicleClass(vehicle->vehicleType());
if (vehicleClass == QGCMAVLink::VehicleClassVTOL && vtolMode != QGCMAVLink::VehicleClassGeneric) {
vehicleClass = vtolMode;
}
} }

6
src/MissionManager/MissionCommandTree.h

@ -59,7 +59,7 @@ public:
Q_INVOKABLE QStringList categoriesForVehicle(Vehicle* vehicle) { return _availableCategoriesForVehicle(vehicle); } Q_INVOKABLE QStringList categoriesForVehicle(Vehicle* vehicle) { return _availableCategoriesForVehicle(vehicle); }
const MissionCommandUIInfo* getUIInfo(Vehicle* vehicle, MAV_CMD command); const MissionCommandUIInfo* getUIInfo(Vehicle* vehicle, QGCMAVLink::VehicleClass_t vtolMode, MAV_CMD command);
/// @param showFlyThroughCommands - true: all commands shows, false: filter out commands which the vehicle flies through (specifiedCoordinate=true, standaloneCoordinate=false) /// @param showFlyThroughCommands - true: all commands shows, false: filter out commands which the vehicle flies through (specifiedCoordinate=true, standaloneCoordinate=false)
Q_INVOKABLE QVariantList getCommandsForCategory(Vehicle* vehicle, const QString& category, bool showFlyThroughCommands); Q_INVOKABLE QVariantList getCommandsForCategory(Vehicle* vehicle, const QString& category, bool showFlyThroughCommands);
@ -69,9 +69,9 @@ public:
private: private:
void _collapseHierarchy (const MissionCommandList* cmdList, QMap<MAV_CMD, MissionCommandUIInfo*>& collapsedTree); void _collapseHierarchy (const MissionCommandList* cmdList, QMap<MAV_CMD, MissionCommandUIInfo*>& collapsedTree);
void _buildAllCommands (Vehicle* vehicle); void _buildAllCommands (Vehicle* vehicle, QGCMAVLink::VehicleClass_t vtolMode);
QStringList _availableCategoriesForVehicle (Vehicle* vehicle); QStringList _availableCategoriesForVehicle (Vehicle* vehicle);
void _firmwareAndVehicleClassInfo (Vehicle* vehicle, QGCMAVLink::FirmwareClass_t& firmwareClass, QGCMAVLink::VehicleClass_t& vehicleClass) const; void _firmwareAndVehicleClassInfo (Vehicle* vehicle, QGCMAVLink::VehicleClass_t vtolMode, QGCMAVLink::FirmwareClass_t& firmwareClass, QGCMAVLink::VehicleClass_t& vehicleClass) const;
private: private:
QString _allCommandsCategory; ///< Category which contains all available commands QString _allCommandsCategory; ///< Category which contains all available commands

6
src/MissionManager/MissionCommandTreeTest.cc

@ -188,12 +188,12 @@ void MissionCommandTreeTest::testOverride(void)
{ {
// Generic/Generic should not have any overrides // Generic/Generic should not have any overrides
Vehicle* vehicle = new Vehicle(MAV_AUTOPILOT_GENERIC, MAV_TYPE_GENERIC, qgcApp()->toolbox()->firmwarePluginManager()); Vehicle* vehicle = new Vehicle(MAV_AUTOPILOT_GENERIC, MAV_TYPE_GENERIC, qgcApp()->toolbox()->firmwarePluginManager());
_checkBaseValues(_commandTree->getUIInfo(vehicle, (MAV_CMD)4), 4); _checkBaseValues(_commandTree->getUIInfo(vehicle, QGCMAVLink::VehicleClassGeneric, (MAV_CMD)4), 4);
delete vehicle; delete vehicle;
// Generic/FixedWing should have overrides // Generic/FixedWing should have overrides
vehicle = new Vehicle(MAV_AUTOPILOT_GENERIC, MAV_TYPE_FIXED_WING, qgcApp()->toolbox()->firmwarePluginManager()); vehicle = new Vehicle(MAV_AUTOPILOT_GENERIC, MAV_TYPE_FIXED_WING, qgcApp()->toolbox()->firmwarePluginManager());
_checkOverrideValues(_commandTree->getUIInfo(vehicle, (MAV_CMD)4), 4); _checkOverrideValues(_commandTree->getUIInfo(vehicle, QGCMAVLink::VehicleClassGeneric, (MAV_CMD)4), 4);
delete vehicle; delete vehicle;
} }
@ -214,7 +214,7 @@ void MissionCommandTreeTest::testAllTrees(void)
} }
qDebug() << firmwareType << vehicleType; qDebug() << firmwareType << vehicleType;
Vehicle* vehicle = new Vehicle(firmwareType, vehicleType, qgcApp()->toolbox()->firmwarePluginManager()); Vehicle* vehicle = new Vehicle(firmwareType, vehicleType, qgcApp()->toolbox()->firmwarePluginManager());
QVERIFY(qgcApp()->toolbox()->missionCommandTree()->getUIInfo(vehicle, MAV_CMD_NAV_WAYPOINT) != nullptr); QVERIFY(qgcApp()->toolbox()->missionCommandTree()->getUIInfo(vehicle, QGCMAVLink::VehicleClassMultiRotor, MAV_CMD_NAV_WAYPOINT) != nullptr);
delete vehicle; delete vehicle;
} }
} }

8
src/MissionManager/MissionController.cc

@ -318,7 +318,7 @@ VisualMissionItem* MissionController::_insertSimpleMissionItemWorker(QGeoCoordin
_initVisualItem(newItem); _initVisualItem(newItem);
if (newItem->specifiesAltitude()) { if (newItem->specifiesAltitude()) {
const MissionCommandUIInfo* uiInfo = qgcApp()->toolbox()->missionCommandTree()->getUIInfo(_controllerVehicle, command); const MissionCommandUIInfo* uiInfo = qgcApp()->toolbox()->missionCommandTree()->getUIInfo(_controllerVehicle, QGCMAVLink::VehicleClassGeneric, command);
if (!uiInfo->isLandCommand()) { if (!uiInfo->isLandCommand()) {
double prevAltitude; double prevAltitude;
int prevAltitudeMode; int prevAltitudeMode;
@ -1672,9 +1672,9 @@ void MissionController::_recalcMissionFlightStatus()
case MAV_CMD_DO_VTOL_TRANSITION: case MAV_CMD_DO_VTOL_TRANSITION:
{ {
int transitionState = simpleItem->missionItem().param1(); int transitionState = simpleItem->missionItem().param1();
if (transitionState == MAV_VTOL_STATE_TRANSITION_TO_MC) { if (transitionState == MAV_VTOL_STATE_MC) {
_missionFlightStatus.vtolMode = QGCMAVLink::VehicleClassMultiRotor; _missionFlightStatus.vtolMode = QGCMAVLink::VehicleClassMultiRotor;
} else if (transitionState == MAV_VTOL_STATE_TRANSITION_TO_FW) { } else if (transitionState == MAV_VTOL_STATE_FW) {
_missionFlightStatus.vtolMode = QGCMAVLink::VehicleClassFixedWing; _missionFlightStatus.vtolMode = QGCMAVLink::VehicleClassFixedWing;
} }
} }
@ -1901,7 +1901,7 @@ void MissionController::_initVisualItem(VisualMissionItem* visualItem)
connect(visualItem, &VisualMissionItem::specifiedVehicleYawChanged, this, &MissionController::_recalcMissionFlightStatusSignal, Qt::QueuedConnection); connect(visualItem, &VisualMissionItem::specifiedVehicleYawChanged, this, &MissionController::_recalcMissionFlightStatusSignal, Qt::QueuedConnection);
connect(visualItem, &VisualMissionItem::terrainAltitudeChanged, this, &MissionController::_recalcMissionFlightStatusSignal, Qt::QueuedConnection); connect(visualItem, &VisualMissionItem::terrainAltitudeChanged, this, &MissionController::_recalcMissionFlightStatusSignal, Qt::QueuedConnection);
connect(visualItem, &VisualMissionItem::additionalTimeDelayChanged, this, &MissionController::_recalcMissionFlightStatusSignal, Qt::QueuedConnection); connect(visualItem, &VisualMissionItem::additionalTimeDelayChanged, this, &MissionController::_recalcMissionFlightStatusSignal, Qt::QueuedConnection);
connect(visualItem, &VisualMissionItem::currentVTOLModeChanged, this, &MissionController::_recalcMissionFlightStatusSignal, Qt::QueuedConnection);
connect(visualItem, &VisualMissionItem::lastSequenceNumberChanged, this, &MissionController::_recalcSequence); connect(visualItem, &VisualMissionItem::lastSequenceNumberChanged, this, &MissionController::_recalcSequence);
if (visualItem->isSimpleItem()) { if (visualItem->isSimpleItem()) {

4
src/MissionManager/MissionManager.cc

@ -97,11 +97,11 @@ void MissionManager::generateResumeMission(int resumeIndex)
resumeIndex = qMax(0, qMin(resumeIndex, _missionItems.count() - 1)); resumeIndex = qMax(0, qMin(resumeIndex, _missionItems.count() - 1));
// Adjust resume index to be a location based command // Adjust resume index to be a location based command
const MissionCommandUIInfo* uiInfo = qgcApp()->toolbox()->missionCommandTree()->getUIInfo(_vehicle, _missionItems[resumeIndex]->command()); const MissionCommandUIInfo* uiInfo = qgcApp()->toolbox()->missionCommandTree()->getUIInfo(_vehicle, QGCMAVLink::VehicleClassGeneric, _missionItems[resumeIndex]->command());
if (!uiInfo || uiInfo->isStandaloneCoordinate() || !uiInfo->specifiesCoordinate()) { if (!uiInfo || uiInfo->isStandaloneCoordinate() || !uiInfo->specifiesCoordinate()) {
// We have to back up to the last command which the vehicle flies through // We have to back up to the last command which the vehicle flies through
while (--resumeIndex > 0) { while (--resumeIndex > 0) {
uiInfo = qgcApp()->toolbox()->missionCommandTree()->getUIInfo(_vehicle, _missionItems[resumeIndex]->command()); uiInfo = qgcApp()->toolbox()->missionCommandTree()->getUIInfo(_vehicle, QGCMAVLink::VehicleClassGeneric, _missionItems[resumeIndex]->command());
if (uiInfo && (uiInfo->specifiesCoordinate() && !uiInfo->isStandaloneCoordinate())) { if (uiInfo && (uiInfo->specifiesCoordinate() && !uiInfo->isStandaloneCoordinate())) {
// Found it // Found it
break; break;

50
src/MissionManager/SimpleMissionItem.cc

@ -191,13 +191,18 @@ void SimpleMissionItem::_connectSignals(void)
// Whenever these properties change the ui model changes as well // Whenever these properties change the ui model changes as well
connect(this, &SimpleMissionItem::commandChanged, this, &SimpleMissionItem::_rebuildFacts); connect(this, &SimpleMissionItem::commandChanged, this, &SimpleMissionItem::_rebuildFacts);
connect(this, &SimpleMissionItem::rawEditChanged, this, &SimpleMissionItem::_rebuildFacts); connect(this, &SimpleMissionItem::rawEditChanged, this, &SimpleMissionItem::_rebuildFacts);
connect(this, &SimpleMissionItem::previousVTOLModeChanged,this, &SimpleMissionItem::_rebuildFacts);
// The following changes must signal currentVTOLModeChanged to cause a MissionController recalc
connect(this, &SimpleMissionItem::commandChanged, this, &SimpleMissionItem::_signalIfVTOLTransitionCommand);
connect(&_missionItem._param1Fact, &Fact::valueChanged, this, &SimpleMissionItem::_signalIfVTOLTransitionCommand);
// These fact signals must alway signal out through SimpleMissionItem signals // These fact signals must alway signal out through SimpleMissionItem signals
connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::_sendCommandChanged); connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::_sendCommandChanged);
// Propogate signals from MissionItem up to SimpleMissionItem // Propogate signals from MissionItem up to SimpleMissionItem
connect(&_missionItem, &MissionItem::sequenceNumberChanged, this, &SimpleMissionItem::sequenceNumberChanged); connect(&_missionItem, &MissionItem::sequenceNumberChanged, this, &SimpleMissionItem::sequenceNumberChanged);
connect(&_missionItem, &MissionItem::specifiedFlightSpeedChanged, this, &SimpleMissionItem::specifiedFlightSpeedChanged); connect(&_missionItem, &MissionItem::specifiedFlightSpeedChanged, this, &SimpleMissionItem::specifiedFlightSpeedChanged);
} }
void SimpleMissionItem::_setupMetaData(void) void SimpleMissionItem::_setupMetaData(void)
@ -333,7 +338,7 @@ bool SimpleMissionItem::load(const QJsonObject& json, int sequenceNumber, QStrin
bool SimpleMissionItem::isStandaloneCoordinate(void) const bool SimpleMissionItem::isStandaloneCoordinate(void) const
{ {
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, (MAV_CMD)command()); const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, _previousVTOLMode, (MAV_CMD)command());
if (uiInfo) { if (uiInfo) {
return uiInfo->isStandaloneCoordinate(); return uiInfo->isStandaloneCoordinate();
} else { } else {
@ -343,7 +348,7 @@ bool SimpleMissionItem::isStandaloneCoordinate(void) const
bool SimpleMissionItem::specifiesCoordinate(void) const bool SimpleMissionItem::specifiesCoordinate(void) const
{ {
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, (MAV_CMD)command()); const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, _previousVTOLMode, (MAV_CMD)command());
if (uiInfo) { if (uiInfo) {
return uiInfo->specifiesCoordinate(); return uiInfo->specifiesCoordinate();
} else { } else {
@ -353,7 +358,7 @@ bool SimpleMissionItem::specifiesCoordinate(void) const
bool SimpleMissionItem::specifiesAltitudeOnly(void) const bool SimpleMissionItem::specifiesAltitudeOnly(void) const
{ {
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, (MAV_CMD)command()); const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, _previousVTOLMode, (MAV_CMD)command());
if (uiInfo) { if (uiInfo) {
return uiInfo->specifiesAltitudeOnly(); return uiInfo->specifiesAltitudeOnly();
} else { } else {
@ -363,7 +368,7 @@ bool SimpleMissionItem::specifiesAltitudeOnly(void) const
QString SimpleMissionItem::commandDescription(void) const QString SimpleMissionItem::commandDescription(void) const
{ {
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, (MAV_CMD)command()); const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, _previousVTOLMode, (MAV_CMD)command());
if (uiInfo) { if (uiInfo) {
return uiInfo->description(); return uiInfo->description();
} else { } else {
@ -374,7 +379,7 @@ QString SimpleMissionItem::commandDescription(void) const
QString SimpleMissionItem::commandName(void) const QString SimpleMissionItem::commandName(void) const
{ {
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, (MAV_CMD)command()); const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, _previousVTOLMode, (MAV_CMD)command());
if (uiInfo) { if (uiInfo) {
return uiInfo->friendlyName(); return uiInfo->friendlyName();
} else { } else {
@ -444,7 +449,7 @@ void SimpleMissionItem::_rebuildTextFieldFacts(void)
Fact* rgParamFacts[7] = { &_missionItem._param1Fact, &_missionItem._param2Fact, &_missionItem._param3Fact, &_missionItem._param4Fact, &_missionItem._param5Fact, &_missionItem._param6Fact, &_missionItem._param7Fact }; Fact* rgParamFacts[7] = { &_missionItem._param1Fact, &_missionItem._param2Fact, &_missionItem._param3Fact, &_missionItem._param4Fact, &_missionItem._param5Fact, &_missionItem._param6Fact, &_missionItem._param7Fact };
FactMetaData* rgParamMetaData[7] = { &_param1MetaData, &_param2MetaData, &_param3MetaData, &_param4MetaData, &_param5MetaData, &_param6MetaData, &_param7MetaData }; FactMetaData* rgParamMetaData[7] = { &_param1MetaData, &_param2MetaData, &_param3MetaData, &_param4MetaData, &_param5MetaData, &_param6MetaData, &_param7MetaData };
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, command); const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, _previousVTOLMode, command);
for (int i=1; i<=7; i++) { for (int i=1; i<=7; i++) {
bool showUI; bool showUI;
@ -483,7 +488,7 @@ void SimpleMissionItem::_rebuildNaNFacts(void)
Fact* rgParamFacts[7] = { &_missionItem._param1Fact, &_missionItem._param2Fact, &_missionItem._param3Fact, &_missionItem._param4Fact, &_missionItem._param5Fact, &_missionItem._param6Fact, &_missionItem._param7Fact }; Fact* rgParamFacts[7] = { &_missionItem._param1Fact, &_missionItem._param2Fact, &_missionItem._param3Fact, &_missionItem._param4Fact, &_missionItem._param5Fact, &_missionItem._param6Fact, &_missionItem._param7Fact };
FactMetaData* rgParamMetaData[7] = { &_param1MetaData, &_param2MetaData, &_param3MetaData, &_param4MetaData, &_param5MetaData, &_param6MetaData, &_param7MetaData }; FactMetaData* rgParamMetaData[7] = { &_param1MetaData, &_param2MetaData, &_param3MetaData, &_param4MetaData, &_param5MetaData, &_param6MetaData, &_param7MetaData };
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, command); const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, _previousVTOLMode, command);
for (int i=1; i<=7; i++) { for (int i=1; i<=7; i++) {
bool showUI; bool showUI;
@ -496,10 +501,6 @@ void SimpleMissionItem::_rebuildNaNFacts(void)
if (!firmwareVehicle) { if (!firmwareVehicle) {
firmwareVehicle = _controllerVehicle; firmwareVehicle = _controllerVehicle;
} }
bool hideWaypointHeading = (command == MAV_CMD_NAV_WAYPOINT || command == MAV_CMD_NAV_TAKEOFF) && (i == 4) && firmwareVehicle->firmwarePlugin()->vehicleYawsToNextWaypointInMission(firmwareVehicle);
if (hideWaypointHeading) {
continue;
}
Fact* paramFact = rgParamFacts[i-1]; Fact* paramFact = rgParamFacts[i-1];
FactMetaData* paramMetaData = rgParamMetaData[i-1]; FactMetaData* paramMetaData = rgParamMetaData[i-1];
@ -541,7 +542,7 @@ void SimpleMissionItem::_rebuildComboBoxFacts(void)
for (int i=1; i<=7; i++) { for (int i=1; i<=7; i++) {
bool showUI; bool showUI;
const MissionCmdParamInfo* paramInfo = _commandTree->getUIInfo(_controllerVehicle, command)->getParamInfo(i, showUI); const MissionCmdParamInfo* paramInfo = _commandTree->getUIInfo(_controllerVehicle, _previousVTOLMode, command)->getParamInfo(i, showUI);
if (showUI && paramInfo && paramInfo->enumStrings().count() != 0) { if (showUI && paramInfo && paramInfo->enumStrings().count() != 0) {
Fact* paramFact = rgParamFacts[i-1]; Fact* paramFact = rgParamFacts[i-1];
@ -567,7 +568,7 @@ void SimpleMissionItem::_rebuildFacts(void)
bool SimpleMissionItem::friendlyEditAllowed(void) const bool SimpleMissionItem::friendlyEditAllowed(void) const
{ {
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, static_cast<MAV_CMD>(command())); const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, _previousVTOLMode, static_cast<MAV_CMD>(command()));
if (uiInfo && uiInfo->friendlyEdit()) { if (uiInfo && uiInfo->friendlyEdit()) {
if (!_missionItem.autoContinue()) { if (!_missionItem.autoContinue()) {
return false; return false;
@ -740,7 +741,7 @@ void SimpleMissionItem::_setDefaultsForCommand(void)
} }
MAV_CMD command = static_cast<MAV_CMD>(this->command()); MAV_CMD command = static_cast<MAV_CMD>(this->command());
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, command); const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, _previousVTOLMode, command);
if (uiInfo) { if (uiInfo) {
for (int i=1; i<=7; i++) { for (int i=1; i<=7; i++) {
bool showUI; bool showUI;
@ -777,7 +778,7 @@ void SimpleMissionItem::_sendFriendlyEditAllowedChanged(void)
QString SimpleMissionItem::category(void) const QString SimpleMissionItem::category(void) const
{ {
return _commandTree->getUIInfo(_controllerVehicle, static_cast<MAV_CMD>(command()))->category(); return _commandTree->getUIInfo(_controllerVehicle, _previousVTOLMode, static_cast<MAV_CMD>(command()))->category();
} }
void SimpleMissionItem::setCommand(int command) void SimpleMissionItem::setCommand(int command)
@ -920,7 +921,7 @@ void SimpleMissionItem::appendMissionItems(QList<MissionItem*>& items, QObject*
void SimpleMissionItem::applyNewAltitude(double newAltitude) void SimpleMissionItem::applyNewAltitude(double newAltitude)
{ {
MAV_CMD command = static_cast<MAV_CMD>(this->command()); MAV_CMD command = static_cast<MAV_CMD>(this->command());
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, command); const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, _previousVTOLMode, command);
if (uiInfo->specifiesCoordinate() || uiInfo->specifiesAltitudeOnly()) { if (uiInfo->specifiesCoordinate() || uiInfo->specifiesAltitudeOnly()) {
switch (static_cast<MAV_CMD>(this->command())) { switch (static_cast<MAV_CMD>(this->command())) {
@ -937,8 +938,9 @@ void SimpleMissionItem::applyNewAltitude(double newAltitude)
void SimpleMissionItem::setMissionFlightStatus(MissionController::MissionFlightStatus_t& missionFlightStatus) void SimpleMissionItem::setMissionFlightStatus(MissionController::MissionFlightStatus_t& missionFlightStatus)
{ {
// If speed and/or gimbal are not specifically set on this item. Then use the flight status values as initial defaults should a user turn them on.
VisualMissionItem::setMissionFlightStatus(missionFlightStatus); VisualMissionItem::setMissionFlightStatus(missionFlightStatus);
// If speed and/or gimbal are not specifically set on this item. Then use the flight status values as initial defaults should a user turn them on.
if (_speedSection->available() && !_speedSection->specifyFlightSpeed() && !qFuzzyCompare(_speedSection->flightSpeed()->rawValue().toDouble(), missionFlightStatus.vehicleSpeed)) { if (_speedSection->available() && !_speedSection->specifyFlightSpeed() && !qFuzzyCompare(_speedSection->flightSpeed()->rawValue().toDouble(), missionFlightStatus.vehicleSpeed)) {
_speedSection->flightSpeed()->setRawValue(missionFlightStatus.vehicleSpeed); _speedSection->flightSpeed()->setRawValue(missionFlightStatus.vehicleSpeed);
} }
@ -988,7 +990,7 @@ void SimpleMissionItem::_possibleAdditionalTimeDelayChanged(void)
bool SimpleMissionItem::isLandCommand(void) const bool SimpleMissionItem::isLandCommand(void) const
{ {
MAV_CMD command = static_cast<MAV_CMD>(this->command()); MAV_CMD command = static_cast<MAV_CMD>(this->command());
const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, command); const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_controllerVehicle, _previousVTOLMode, command);
return uiInfo->isLandCommand(); return uiInfo->isLandCommand();
} }
@ -1019,3 +1021,11 @@ double SimpleMissionItem::amslEntryAlt(void) const
qWarning() << "Internal Error SimpleMissionItem::amslEntryAlt: Invalid altitudeMode:" << _altitudeMode; qWarning() << "Internal Error SimpleMissionItem::amslEntryAlt: Invalid altitudeMode:" << _altitudeMode;
return qQNaN(); return qQNaN();
} }
void SimpleMissionItem::_signalIfVTOLTransitionCommand(void)
{
if (mavCommand() == MAV_CMD_DO_VTOL_TRANSITION) {
// This will cause a MissionController recalc
emit currentVTOLModeChanged();
}
}

29
src/MissionManager/SimpleMissionItem.h

@ -139,20 +139,21 @@ signals:
void altitudeModeChanged (void); void altitudeModeChanged (void);
private slots: private slots:
void _setDirty (void); void _setDirty (void);
void _sectionDirtyChanged (bool dirty); void _sectionDirtyChanged (bool dirty);
void _sendCommandChanged (void); void _sendCommandChanged (void);
void _sendCoordinateChanged (void); void _sendCoordinateChanged (void);
void _sendFriendlyEditAllowedChanged (void); void _sendFriendlyEditAllowedChanged (void);
void _altitudeChanged (void); void _altitudeChanged (void);
void _altitudeModeChanged (void); void _altitudeModeChanged (void);
void _terrainAltChanged (void); void _terrainAltChanged (void);
void _updateLastSequenceNumber (void); void _updateLastSequenceNumber (void);
void _rebuildFacts (void); void _rebuildFacts (void);
void _rebuildTextFieldFacts (void); void _rebuildTextFieldFacts (void);
void _possibleAdditionalTimeDelayChanged(void); void _possibleAdditionalTimeDelayChanged (void);
void _setDefaultsForCommand (void); void _setDefaultsForCommand (void);
void _possibleVehicleYawChanged (void); void _possibleVehicleYawChanged (void);
void _signalIfVTOLTransitionCommand (void);
private: private:
void _connectSignals (void); void _connectSignals (void);

145
src/MissionManager/SimpleMissionItemTest.cc

@ -7,14 +7,13 @@
* *
****************************************************************************/ ****************************************************************************/
#include "SimpleMissionItemTest.h" #include "SimpleMissionItemTest.h"
#include "QGCApplication.h" #include "QGCApplication.h"
#include "QGroundControlQmlGlobal.h" #include "QGroundControlQmlGlobal.h"
#include "SettingsManager.h" #include "SettingsManager.h"
#include "PlanMasterController.h" #include "PlanMasterController.h"
const SimpleMissionItemTest::ItemInfo_t SimpleMissionItemTest::_rgItemInfo[] = { static const ItemInfo_t _rgItemInfo[] = {
{ MAV_CMD_NAV_WAYPOINT, MAV_FRAME_GLOBAL_RELATIVE_ALT }, { MAV_CMD_NAV_WAYPOINT, MAV_FRAME_GLOBAL_RELATIVE_ALT },
{ MAV_CMD_NAV_LOITER_UNLIM, MAV_FRAME_GLOBAL }, { MAV_CMD_NAV_LOITER_UNLIM, MAV_FRAME_GLOBAL },
{ MAV_CMD_NAV_LOITER_TURNS, MAV_FRAME_GLOBAL_RELATIVE_ALT }, { MAV_CMD_NAV_LOITER_TURNS, MAV_FRAME_GLOBAL_RELATIVE_ALT },
@ -24,42 +23,48 @@ const SimpleMissionItemTest::ItemInfo_t SimpleMissionItemTest::_rgItemInfo[] = {
{ MAV_CMD_DO_JUMP, MAV_FRAME_MISSION }, { MAV_CMD_DO_JUMP, MAV_FRAME_MISSION },
}; };
const SimpleMissionItemTest::FactValue_t SimpleMissionItemTest::_rgFactValuesWaypoint[] = { static const FactValue_t _rgFactValuesWaypoint[] = {
{ "Hold", 10.1234567 }, { "Hold", QGCMAVLink::VehicleClassMultiRotor, false, 1 },
{ "Yaw", QGCMAVLink::VehicleClassMultiRotor, true, 4 },
};
static const FactValue_t _rgFactValuesLoiterUnlim[] = {
{ "Radius", QGCMAVLink::VehicleClassFixedWing, false, 3 },
{ "Yaw", QGCMAVLink::VehicleClassMultiRotor, true, 4 },
}; };
const SimpleMissionItemTest::FactValue_t SimpleMissionItemTest::_rgFactValuesLoiterUnlim[] = { static const FactValue_t _rgFactValuesLoiterTurns[] = {
{ "Radius", 30.1234567 }, { "Turns", QGCMAVLink::VehicleClassFixedWing, false, 1 },
{ "Radius", QGCMAVLink::VehicleClassFixedWing, false, 3 },
}; };
const SimpleMissionItemTest::FactValue_t SimpleMissionItemTest::_rgFactValuesLoiterTurns[] = { static const FactValue_t _rgFactValuesLoiterTime[] = {
{ "Radius", 30.1234567 }, { "Loiter Time", QGCMAVLink::VehicleClassGeneric, false, 1 },
{ "Turns", 10.1234567 }, { "Radius", QGCMAVLink::VehicleClassFixedWing, false, 3 },
}; };
const SimpleMissionItemTest::FactValue_t SimpleMissionItemTest::_rgFactValuesLoiterTime[] = { static const FactValue_t _rgFactValuesLand[] = {
{ "Radius", 30.1234567 }, { "Yaw", QGCMAVLink::VehicleClassMultiRotor, true, 4 },
{ "Loiter Time", 10.1234567 },
}; };
const SimpleMissionItemTest::FactValue_t SimpleMissionItemTest::_rgFactValuesTakeoff[] = { static const FactValue_t _rgFactValuesTakeoff[] = {
{ "Pitch", 10.1234567 }, { "Pitch", QGCMAVLink::VehicleClassFixedWing, false, 1 },
{ "Yaw", QGCMAVLink::VehicleClassMultiRotor, true, 4 },
}; };
const SimpleMissionItemTest::FactValue_t SimpleMissionItemTest::_rgFactValuesDoJump[] = { static const FactValue_t _rgFactValuesDoJump[] = {
{ "Item #", 10.1234567 }, { "Item #", QGCMAVLink::VehicleClassGeneric, false, 1 },
{ "Repeat", 20.1234567 }, { "Repeat", QGCMAVLink::VehicleClassGeneric, false, 2 },
}; };
const SimpleMissionItemTest::ItemExpected_t SimpleMissionItemTest::_rgItemExpected[] = { const ItemExpected_t _rgItemExpected[] = {
// Text field facts count Fact Values Altitude Altitude Mode { sizeof(_rgFactValuesWaypoint)/sizeof(_rgFactValuesWaypoint[0]), _rgFactValuesWaypoint, 70.1234567, QGroundControlQmlGlobal::AltitudeModeRelative },
{ sizeof(SimpleMissionItemTest::_rgFactValuesWaypoint)/sizeof(SimpleMissionItemTest::_rgFactValuesWaypoint[0]), SimpleMissionItemTest::_rgFactValuesWaypoint, 70.1234567, QGroundControlQmlGlobal::AltitudeModeRelative }, { sizeof(_rgFactValuesLoiterUnlim)/sizeof(_rgFactValuesLoiterUnlim[0]), _rgFactValuesLoiterUnlim, 70.1234567, QGroundControlQmlGlobal::AltitudeModeAbsolute },
{ sizeof(SimpleMissionItemTest::_rgFactValuesLoiterUnlim)/sizeof(SimpleMissionItemTest::_rgFactValuesLoiterUnlim[0]), SimpleMissionItemTest::_rgFactValuesLoiterUnlim, 70.1234567, QGroundControlQmlGlobal::AltitudeModeAbsolute }, { sizeof(_rgFactValuesLoiterTurns)/sizeof(_rgFactValuesLoiterTurns[0]), _rgFactValuesLoiterTurns, 70.1234567, QGroundControlQmlGlobal::AltitudeModeRelative },
{ sizeof(SimpleMissionItemTest::_rgFactValuesLoiterTurns)/sizeof(SimpleMissionItemTest::_rgFactValuesLoiterTurns[0]), SimpleMissionItemTest::_rgFactValuesLoiterTurns, 70.1234567, QGroundControlQmlGlobal::AltitudeModeRelative }, { sizeof(_rgFactValuesLoiterTime)/sizeof(_rgFactValuesLoiterTime[0]), _rgFactValuesLoiterTime, 70.1234567, QGroundControlQmlGlobal::AltitudeModeAbsolute },
{ sizeof(SimpleMissionItemTest::_rgFactValuesLoiterTime)/sizeof(SimpleMissionItemTest::_rgFactValuesLoiterTime[0]), SimpleMissionItemTest::_rgFactValuesLoiterTime, 70.1234567, QGroundControlQmlGlobal::AltitudeModeAbsolute }, { sizeof(_rgFactValuesLand)/sizeof(_rgFactValuesLand[0]), _rgFactValuesLand, 70.1234567, QGroundControlQmlGlobal::AltitudeModeRelative },
{ 0, nullptr, 70.1234567, QGroundControlQmlGlobal::AltitudeModeRelative }, { sizeof(_rgFactValuesTakeoff)/sizeof(_rgFactValuesTakeoff[0]), _rgFactValuesTakeoff, 70.1234567, QGroundControlQmlGlobal::AltitudeModeAbsolute },
{ sizeof(SimpleMissionItemTest::_rgFactValuesTakeoff)/sizeof(SimpleMissionItemTest::_rgFactValuesTakeoff[0]), SimpleMissionItemTest::_rgFactValuesTakeoff, 70.1234567, QGroundControlQmlGlobal::AltitudeModeAbsolute }, { sizeof(_rgFactValuesDoJump)/sizeof(_rgFactValuesDoJump[0]), _rgFactValuesDoJump, qQNaN(), QGroundControlQmlGlobal::AltitudeModeRelative },
{ sizeof(SimpleMissionItemTest::_rgFactValuesDoJump)/sizeof(SimpleMissionItemTest::_rgFactValuesDoJump[0]), SimpleMissionItemTest::_rgFactValuesDoJump, qQNaN(), QGroundControlQmlGlobal::AltitudeModeRelative },
}; };
SimpleMissionItemTest::SimpleMissionItemTest(void) SimpleMissionItemTest::SimpleMissionItemTest(void)
@ -109,16 +114,42 @@ void SimpleMissionItemTest::cleanup(void)
VisualMissionItemTest::cleanup(); VisualMissionItemTest::cleanup();
} }
void SimpleMissionItemTest::_testEditorFacts(void) bool SimpleMissionItemTest::_classMatch(QGCMAVLink::VehicleClass_t vehicleClass, QGCMAVLink::VehicleClass_t testClass)
{
return vehicleClass == QGCMAVLink::VehicleClassGeneric || vehicleClass == testClass;
}
void SimpleMissionItemTest::_testEditorFactsWorker(QGCMAVLink::VehicleClass_t vehicleClass, QGCMAVLink::VehicleClass_t vtolMode, const ItemExpected_t* rgExpected)
{ {
PlanMasterController fwMasterController(MAV_AUTOPILOT_PX4, MAV_TYPE_FIXED_WING); qDebug() << "vehicleClass:vtolMode" << QGCMAVLink::vehicleClassToString(vehicleClass) << QGCMAVLink::vehicleClassToString(vtolMode);
PlanMasterController planController(MAV_AUTOPILOT_PX4, QGCMAVLink::vehicleClassToMavType(vehicleClass));
QGCMAVLink::VehicleClass_t commandVehicleClass = vtolMode == QGCMAVLink::VehicleClassGeneric ? vehicleClass : vtolMode;
for (size_t i=0; i<sizeof(_rgItemInfo)/sizeof(_rgItemInfo[0]); i++) { for (size_t i=0; i<sizeof(_rgItemInfo)/sizeof(_rgItemInfo[0]); i++) {
const ItemInfo_t* info = &_rgItemInfo[i]; const ItemInfo_t* info = &_rgItemInfo[i];
const ItemExpected_t* expected = &_rgItemExpected[i]; const ItemExpected_t* expected = &rgExpected[i];
qDebug() << "Command" << info->command; qDebug() << "Command" << info->command;
// Determine how many fact values we should get back
int cExpectedTextFieldFacts = 0;
int cExpectedNaNFieldFacts = 0;
for (size_t j=0; j<expected->cFactValues; j++) {
const FactValue_t* factValue = &expected->rgFactValues[j];
if (!_classMatch(factValue->vehicleClass, commandVehicleClass)) {
continue;
}
if (factValue->nanValue) {
cExpectedNaNFieldFacts++;
} else {
cExpectedTextFieldFacts++;
}
}
MissionItem missionItem(1, // sequence number MissionItem missionItem(1, // sequence number
info->command, info->command,
info->frame, info->frame,
@ -131,11 +162,18 @@ void SimpleMissionItemTest::_testEditorFacts(void)
70.1234567, 70.1234567,
true, // autoContinue true, // autoContinue
false); // isCurrentItem false); // isCurrentItem
SimpleMissionItem simpleMissionItem(&fwMasterController, false /* flyView */, missionItem, nullptr); SimpleMissionItem simpleMissionItem(&planController, false /* flyView */, missionItem, nullptr);
MissionController::MissionFlightStatus_t missionFlightStatus;
missionFlightStatus.vtolMode = vtolMode;
missionFlightStatus.vehicleSpeed = 10;
missionFlightStatus.gimbalYaw = qQNaN();
missionFlightStatus.gimbalPitch = qQNaN();
simpleMissionItem.setMissionFlightStatus(missionFlightStatus);
// Validate that the fact values are correctly returned // Validate that the fact values are correctly returned
size_t factCount = 0; int foundTextFieldCount = 0;
for (int i=0; i<simpleMissionItem.textFieldFacts()->count(); i++) { for (int i=0; i<simpleMissionItem.textFieldFacts()->count(); i++) {
Fact* fact = qobject_cast<Fact*>(simpleMissionItem.textFieldFacts()->get(i)); Fact* fact = qobject_cast<Fact*>(simpleMissionItem.textFieldFacts()->get(i));
@ -143,9 +181,13 @@ void SimpleMissionItemTest::_testEditorFacts(void)
for (size_t j=0; j<expected->cFactValues; j++) { for (size_t j=0; j<expected->cFactValues; j++) {
const FactValue_t* factValue = &expected->rgFactValues[j]; const FactValue_t* factValue = &expected->rgFactValues[j];
if (!_classMatch(factValue->vehicleClass, commandVehicleClass)) {
continue;
}
if (factValue->name == fact->name()) { if (factValue->name == fact->name()) {
QCOMPARE(fact->rawValue().toDouble(), factValue->value); QCOMPARE(fact->rawValue().toDouble(), (factValue->paramIndex * 10.0) + 0.1234567);
factCount ++; foundTextFieldCount ++;
found = true; found = true;
break; break;
} }
@ -154,7 +196,32 @@ void SimpleMissionItemTest::_testEditorFacts(void)
qDebug() << "textFieldFact" << fact->name(); qDebug() << "textFieldFact" << fact->name();
QVERIFY(found); QVERIFY(found);
} }
QCOMPARE(factCount, expected->cFactValues); QCOMPARE(foundTextFieldCount, cExpectedTextFieldFacts);
int foundNaNFieldCount = 0;
for (int i=0; i<simpleMissionItem.nanFacts()->count(); i++) {
Fact* fact = qobject_cast<Fact*>(simpleMissionItem.nanFacts()->get(i));
bool found = false;
for (size_t j=0; j<expected->cFactValues; j++) {
const FactValue_t* factValue = &expected->rgFactValues[j];
if (!_classMatch(factValue->vehicleClass, commandVehicleClass)) {
continue;
}
if (factValue->name == fact->name()) {
QCOMPARE(fact->rawValue().toDouble(), (factValue->paramIndex * 10.0) + 0.1234567);
foundNaNFieldCount ++;
found = true;
break;
}
}
qDebug() << "nanFieldFact" << fact->name();
QVERIFY(found);
}
QCOMPARE(foundNaNFieldCount, cExpectedNaNFieldFacts);
if (!qIsNaN(expected->altValue)) { if (!qIsNaN(expected->altValue)) {
QCOMPARE(simpleMissionItem.altitudeMode(), expected->altMode); QCOMPARE(simpleMissionItem.altitudeMode(), expected->altMode);
@ -163,6 +230,14 @@ void SimpleMissionItemTest::_testEditorFacts(void)
} }
} }
void SimpleMissionItemTest::_testEditorFacts(void)
{
_testEditorFactsWorker(QGCMAVLink::VehicleClassMultiRotor, QGCMAVLink::VehicleClassGeneric, _rgItemExpected);
_testEditorFactsWorker(QGCMAVLink::VehicleClassFixedWing, QGCMAVLink::VehicleClassGeneric, _rgItemExpected);
_testEditorFactsWorker(QGCMAVLink::VehicleClassVTOL, QGCMAVLink::VehicleClassMultiRotor, _rgItemExpected);
_testEditorFactsWorker(QGCMAVLink::VehicleClassVTOL, QGCMAVLink::VehicleClassFixedWing, _rgItemExpected);
}
void SimpleMissionItemTest::_testDefaultValues(void) void SimpleMissionItemTest::_testDefaultValues(void)
{ {
SimpleMissionItem item(_masterController, false /* flyView */, false /* forLoad */, nullptr); SimpleMissionItem item(_masterController, false /* flyView */, false /* forLoad */, nullptr);

67
src/MissionManager/SimpleMissionItemTest.h

@ -13,6 +13,26 @@
#include "SimpleMissionItem.h" #include "SimpleMissionItem.h"
/// Unit test for SimpleMissionItem /// Unit test for SimpleMissionItem
typedef struct {
MAV_CMD command;
MAV_FRAME frame;
} ItemInfo_t;
typedef struct {
const char* name;
QGCMAVLink::VehicleClass_t vehicleClass;
bool nanValue;
int paramIndex;
} FactValue_t;
typedef struct {
size_t cFactValues;
const FactValue_t* rgFactValues;
double altValue;
QGroundControlQmlGlobal::AltitudeMode altMode;
} ItemExpected_t;
class SimpleMissionItemTest : public VisualMissionItemTest class SimpleMissionItemTest : public VisualMissionItemTest
{ {
Q_OBJECT Q_OBJECT
@ -20,18 +40,18 @@ class SimpleMissionItemTest : public VisualMissionItemTest
public: public:
SimpleMissionItemTest(void); SimpleMissionItemTest(void);
void init(void) override; void init (void) override;
void cleanup(void) override; void cleanup(void) override;
private slots: private slots:
void _testSignals(void); void _testSignals (void);
void _testEditorFacts(void); void _testEditorFacts (void);
void _testDefaultValues(void); void _testDefaultValues (void);
void _testCameraSectionDirty(void); void _testCameraSectionDirty (void);
void _testSpeedSectionDirty(void); void _testSpeedSectionDirty (void);
void _testCameraSection(void); void _testCameraSection (void);
void _testSpeedSection(void); void _testSpeedSection (void);
void _testAltitudePropogation(void); void _testAltitudePropogation (void);
private: private:
enum { enum {
@ -58,35 +78,10 @@ private:
static const size_t cSimpleItemSignals = maxSignalIndex; static const size_t cSimpleItemSignals = maxSignalIndex;
const char* rgSimpleItemSignals[cSimpleItemSignals]; const char* rgSimpleItemSignals[cSimpleItemSignals];
typedef struct { void _testEditorFactsWorker (QGCMAVLink::VehicleClass_t vehicleClass, QGCMAVLink::VehicleClass_t vtolMode, const ItemExpected_t* rgExpected);
MAV_CMD command; bool _classMatch (QGCMAVLink::VehicleClass_t vehicleClass, QGCMAVLink::VehicleClass_t testClass);
MAV_FRAME frame;
} ItemInfo_t;
typedef struct {
const char* name;
double value;
} FactValue_t;
typedef struct {
size_t cFactValues;
const FactValue_t* rgFactValues;
double altValue;
QGroundControlQmlGlobal::AltitudeMode altMode;
} ItemExpected_t;
SimpleMissionItem* _simpleItem; SimpleMissionItem* _simpleItem;
MultiSignalSpy* _spySimpleItem; MultiSignalSpy* _spySimpleItem;
MultiSignalSpy* _spyVisualItem; MultiSignalSpy* _spyVisualItem;
static const ItemInfo_t _rgItemInfo[];
static const ItemExpected_t _rgItemExpected[];
static const FactValue_t _rgFactValuesWaypoint[];
static const FactValue_t _rgFactValuesLoiterUnlim[];
static const FactValue_t _rgFactValuesLoiterTurns[];
static const FactValue_t _rgFactValuesLoiterTime[];
static const FactValue_t _rgFactValuesLand[];
static const FactValue_t _rgFactValuesTakeoff[];
static const FactValue_t _rgFactValuesConditionDelay[];
static const FactValue_t _rgFactValuesDoJump[];
}; };

2
src/MissionManager/TakeoffMissionItem.cc

@ -116,7 +116,7 @@ void TakeoffMissionItem::setCoordinate(const QGeoCoordinate& coordinate)
bool TakeoffMissionItem::isTakeoffCommand(MAV_CMD command) bool TakeoffMissionItem::isTakeoffCommand(MAV_CMD command)
{ {
const MissionCommandUIInfo* uiInfo = qgcApp()->toolbox()->missionCommandTree()->getUIInfo(qgcApp()->toolbox()->multiVehicleManager()->offlineEditingVehicle(), command); const MissionCommandUIInfo* uiInfo = qgcApp()->toolbox()->missionCommandTree()->getUIInfo(qgcApp()->toolbox()->multiVehicleManager()->offlineEditingVehicle(), QGCMAVLink::VehicleClassGeneric, command);
return uiInfo ? uiInfo->isTakeoffCommand() : false; return uiInfo ? uiInfo->isTakeoffCommand() : false;
} }

11
src/MissionManager/VisualMissionItem.cc

@ -7,7 +7,6 @@
* *
****************************************************************************/ ****************************************************************************/
#include <QStringList> #include <QStringList>
#include <QDebug> #include <QDebug>
@ -18,6 +17,7 @@
#include "TerrainQuery.h" #include "TerrainQuery.h"
#include "TakeoffMissionItem.h" #include "TakeoffMissionItem.h"
#include "PlanMasterController.h" #include "PlanMasterController.h"
#include "QGC.h"
const char* VisualMissionItem::jsonTypeKey = "type"; const char* VisualMissionItem::jsonTypeKey = "type";
const char* VisualMissionItem::jsonTypeSimpleItemValue = "SimpleItem"; const char* VisualMissionItem::jsonTypeSimpleItemValue = "SimpleItem";
@ -152,13 +152,14 @@ void VisualMissionItem::setAzimuth(double azimuth)
void VisualMissionItem::setMissionFlightStatus(MissionController::MissionFlightStatus_t& missionFlightStatus) void VisualMissionItem::setMissionFlightStatus(MissionController::MissionFlightStatus_t& missionFlightStatus)
{ {
if (qIsNaN(missionFlightStatus.gimbalYaw) && qIsNaN(_missionGimbalYaw)) { if (!QGC::fuzzyCompare(missionFlightStatus.gimbalYaw, _missionGimbalYaw)) {
return;
}
if (!qFuzzyCompare(missionFlightStatus.gimbalYaw, _missionGimbalYaw)) {
_missionGimbalYaw = missionFlightStatus.gimbalYaw; _missionGimbalYaw = missionFlightStatus.gimbalYaw;
emit missionGimbalYawChanged(_missionGimbalYaw); emit missionGimbalYawChanged(_missionGimbalYaw);
} }
if (missionFlightStatus.vtolMode != _previousVTOLMode) {
_previousVTOLMode = missionFlightStatus.vtolMode;
emit previousVTOLModeChanged();
}
} }
void VisualMissionItem::setMissionVehicleYaw(double vehicleYaw) void VisualMissionItem::setMissionVehicleYaw(double vehicleYaw)

50
src/MissionManager/VisualMissionItem.h

@ -81,6 +81,7 @@ public:
Q_PROPERTY(double missionVehicleYaw READ missionVehicleYaw NOTIFY missionVehicleYawChanged) ///< Expected vehicle yaw at this point in mission Q_PROPERTY(double missionVehicleYaw READ missionVehicleYaw NOTIFY missionVehicleYawChanged) ///< Expected vehicle yaw at this point in mission
Q_PROPERTY(bool flyView READ flyView CONSTANT) Q_PROPERTY(bool flyView READ flyView CONSTANT)
Q_PROPERTY(bool wizardMode READ wizardMode WRITE setWizardMode NOTIFY wizardModeChanged) Q_PROPERTY(bool wizardMode READ wizardMode WRITE setWizardMode NOTIFY wizardModeChanged)
Q_PROPERTY(int previousVTOLMode MEMBER _previousVTOLMode NOTIFY previousVTOLModeChanged) ///< Current VTOL mode (VehicleClass_t) prior to executing this item
Q_PROPERTY(PlanMasterController* masterController READ masterController CONSTANT) Q_PROPERTY(PlanMasterController* masterController READ masterController CONSTANT)
Q_PROPERTY(ReadyForSaveState readyForSaveState READ readyForSaveState NOTIFY readyForSaveStateChanged) Q_PROPERTY(ReadyForSaveState readyForSaveState READ readyForSaveState NOTIFY readyForSaveStateChanged)
@ -238,6 +239,8 @@ signals:
void parentItemChanged (VisualMissionItem* parentItem); void parentItemChanged (VisualMissionItem* parentItem);
void amslEntryAltChanged (double alt); void amslEntryAltChanged (double alt);
void amslExitAltChanged (double alt); void amslExitAltChanged (double alt);
void previousVTOLModeChanged (void);
void currentVTOLModeChanged (void); ///< Signals that this item has changed the VTOL mode (MAV_CMD_DO_VTOL_TRANSITION)
void exitCoordinateSameAsEntryChanged (bool exitCoordinateSameAsEntry); void exitCoordinateSameAsEntryChanged (bool exitCoordinateSameAsEntry);
@ -246,29 +249,30 @@ protected slots:
void _amslExitAltChanged(void); // signals new amslExitAlt value void _amslExitAltChanged(void); // signals new amslExitAlt value
protected: protected:
bool _flyView = false; bool _flyView = false;
bool _isCurrentItem = false; bool _isCurrentItem = false;
bool _hasCurrentChildItem = false; bool _hasCurrentChildItem = false;
bool _dirty = false; bool _dirty = false;
bool _homePositionSpecialCase = false; ///< true: This item is being used as a ui home position indicator bool _homePositionSpecialCase = false; ///< true: This item is being used as a ui home position indicator
bool _wizardMode = false; ///< true: Item editor is showing wizard completion panel bool _wizardMode = false; ///< true: Item editor is showing wizard completion panel
double _terrainAltitude = qQNaN(); ///< Altitude of terrain at coordinate position, NaN for not known double _terrainAltitude = qQNaN(); ///< Altitude of terrain at coordinate position, NaN for not known
double _altDifference = 0; ///< Difference in altitude from previous waypoint double _altDifference = 0; ///< Difference in altitude from previous waypoint
double _altPercent = 0; ///< Percent of total altitude change in mission double _altPercent = 0; ///< Percent of total altitude change in mission
double _terrainPercent = qQNaN(); ///< Percent of terrain altitude for coordinate double _terrainPercent = qQNaN(); ///< Percent of terrain altitude for coordinate
bool _terrainCollision = false; ///< true: item collides with terrain bool _terrainCollision = false; ///< true: item collides with terrain
double _azimuth = 0; ///< Azimuth to previous waypoint double _azimuth = 0; ///< Azimuth to previous waypoint
double _distance = 0; ///< Distance to previous waypoint double _distance = 0; ///< Distance to previous waypoint
double _distanceFromStart = 0; ///< Flight path cumalative horizontal distance from home point to this item double _distanceFromStart = 0; ///< Flight path cumalative horizontal distance from home point to this item
QString _editorQml; ///< Qml resource for editing item QString _editorQml; ///< Qml resource for editing item
double _missionGimbalYaw = qQNaN(); double _missionGimbalYaw = qQNaN();
double _missionVehicleYaw = qQNaN(); double _missionVehicleYaw = qQNaN();
QGCMAVLink::VehicleClass_t _previousVTOLMode = QGCMAVLink::VehicleClassGeneric; ///< Generic == unknown
PlanMasterController* _masterController = nullptr;
MissionController* _missionController = nullptr; PlanMasterController* _masterController = nullptr;
Vehicle* _controllerVehicle = nullptr; MissionController* _missionController = nullptr;
FlightPathSegment * _simpleFlightPathSegment = nullptr; ///< The simple item flight segment (if any) which starts with this visual item. Vehicle* _controllerVehicle = nullptr;
VisualMissionItem* _parentItem = nullptr; FlightPathSegment * _simpleFlightPathSegment = nullptr; ///< The simple item flight segment (if any) which starts with this visual item.
VisualMissionItem* _parentItem = nullptr;
QGCGeoBoundingCube _boundingCube; ///< The bounding "cube" of this element. QGCGeoBoundingCube _boundingCube; ///< The bounding "cube" of this element.
/// This is used to reference any subsequent mission items which do not specify a coordinate. /// This is used to reference any subsequent mission items which do not specify a coordinate.

16
src/QGC.cc

@ -9,9 +9,12 @@
#include "QGC.h" #include "QGC.h"
#include <qmath.h> #include <qmath.h>
#include <float.h> #include <float.h>
#include <QtGlobal>
namespace QGC namespace QGC
{ {
@ -137,4 +140,17 @@ quint32 crc32(const quint8 *src, unsigned len, unsigned state)
return state; return state;
} }
bool fuzzyCompare(double value1, double value2)
{
if (qIsNaN(value1) && qIsNaN(value2)) {
return true;
} else if (qIsNaN(value1) || qIsNaN(value2)) {
return false;
} else if (value1 == value2) {
return true;
} else {
return qFuzzyCompare(value1, value2);
}
}
} }

11
src/QGC.h

@ -7,9 +7,7 @@
* *
****************************************************************************/ ****************************************************************************/
#pragma once
#ifndef QGC_H
#define QGC_H
#include <QDateTime> #include <QDateTime>
#include <QColor> #include <QColor>
@ -42,7 +40,8 @@ void initTimer();
/** @brief Get the ground time since boot in milliseconds */ /** @brief Get the ground time since boot in milliseconds */
quint64 bootTimeMilliseconds(); quint64 bootTimeMilliseconds();
const static int MAX_FLIGHT_TIME = 60 * 60 * 24 * 21; /// Returns true if the two values are equal or close. Correctly handles 0 and NaN values.
bool fuzzyCompare(double value1, double value2);
class SLEEP : public QThread class SLEEP : public QThread
{ {
@ -56,7 +55,3 @@ public:
quint32 crc32(const quint8 *src, unsigned len, unsigned state); quint32 crc32(const quint8 *src, unsigned len, unsigned state);
} }
#define QGC_EVENTLOOP_DEBUG 0
#endif // QGC_H

5
src/Vehicle/Vehicle.cc

@ -3835,11 +3835,6 @@ const QVariantList& Vehicle::staticCameraList() const
return emptyList; return emptyList;
} }
bool Vehicle::vehicleYawsToNextWaypointInMission() const
{
return _firmwarePlugin->vehicleYawsToNextWaypointInMission(this);
}
void Vehicle::_setupAutoDisarmSignalling() void Vehicle::_setupAutoDisarmSignalling()
{ {
QString param = _firmwarePlugin->autoDisarmParameter(this); QString param = _firmwarePlugin->autoDisarmParameter(this);

3
src/Vehicle/Vehicle.h

@ -1125,9 +1125,6 @@ public:
QGCCameraManager* dynamicCameras () { return _cameras; } QGCCameraManager* dynamicCameras () { return _cameras; }
QString hobbsMeter (); QString hobbsMeter ();
/// @true: When flying a mission the vehicle is always facing towards the next waypoint
bool vehicleYawsToNextWaypointInMission() const;
/// The vehicle is responsible for making the initial request for the Plan. /// The vehicle is responsible for making the initial request for the Plan.
/// @return: true: initial request is complete, false: initial request is still in progress; /// @return: true: initial request is complete, false: initial request is still in progress;
bool initialPlanRequestComplete() const { return _initialPlanRequestComplete; } bool initialPlanRequestComplete() const { return _initialPlanRequestComplete; }

Loading…
Cancel
Save