Newer
Older
const char* WimaController::wimaFileExtension = "wima";
const char* WimaController::areaItemsName = "AreaItems";
const char* WimaController::missionItemsName = "MissionItems";
const char* WimaController::settingsGroup = "WimaController";
const char* WimaController::enableWimaControllerName = "EnableWimaController";
const char* WimaController::overlapWaypointsName = "OverlapWaypoints";
const char* WimaController::maxWaypointsPerPhaseName = "MaxWaypointsPerPhase";
const char* WimaController::startWaypointIndexName = "StartWaypointIndex";
const char* WimaController::showAllMissionItemsName = "ShowAllMissionItems";
const char* WimaController::showCurrentMissionItemsName = "ShowCurrentMissionItems";
const char* WimaController::flightSpeedName = "FlightSpeed";
const char* WimaController::altitudeName = "Altitude";
WimaController::WimaController(QObject *parent)
: QObject (parent)
, _container (nullptr)
, _joinedArea (this)
, _measurementArea (this)
, _serviceArea (this)
, _corridor (this)
, _localPlanDataValid (false)
, _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/WimaController.SettingsGroup.json"), this))
, _enableWimaController (settingsGroup, _metaDataMap[enableWimaControllerName])
, _overlapWaypoints (settingsGroup, _metaDataMap[overlapWaypointsName])
, _maxWaypointsPerPhase (settingsGroup, _metaDataMap[maxWaypointsPerPhaseName])
, _nextPhaseStartWaypointIndex (settingsGroup, _metaDataMap[startWaypointIndexName])
, _showAllMissionItems (settingsGroup, _metaDataMap[showAllMissionItemsName])
, _showCurrentMissionItems (settingsGroup, _metaDataMap[showCurrentMissionItemsName])
, _flightSpeed (settingsGroup, _metaDataMap[flightSpeedName])
, _altitude (settingsGroup, _metaDataMap[altitudeName])
Valentin Platzgummer
committed
, _startWaypointIndex (0)
Valentin Platzgummer
committed
, _uploadOverrideRequired (false)
, _phaseDistance(-1)
, _phaseDuration(-1)
, _vehicleHasLowBattery(false)
, _lowBatteryHandlingTriggered(false)
Valentin Platzgummer
committed
_nextPhaseStartWaypointIndex.setRawValue(int(1));
_showAllMissionItems.setRawValue(true);
_showCurrentMissionItems.setRawValue(true);
connect(&_overlapWaypoints, &Fact::rawValueChanged, this, &WimaController::updateNextWaypoint);
connect(&_maxWaypointsPerPhase, &Fact::rawValueChanged, this, &WimaController::recalcCurrentPhase);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
connect(&_flightSpeed, &Fact::rawValueChanged, this, &WimaController::updateSpeed);
connect(&_altitude, &Fact::rawValueChanged, this, &WimaController::updateAltitude);
// battery timer
connect(&_checkBatteryTimer, &QTimer::timeout, this, &WimaController::checkBatteryLevel);
_checkBatteryTimer.setInterval(500);
_checkBatteryTimer.start();
Valentin Platzgummer
committed
QmlObjectListModel* WimaController::visualItems()
{
}
QStringList WimaController::loadNameFilters() const
{
QStringList filters;
filters << tr("Supported types (*.%1 *.%2)").arg(wimaFileExtension).arg(AppSettings::planFileExtension) <<
}
QStringList WimaController::saveNameFilters() const
{
QStringList filters;
filters << tr("Supported types (*.%1 *.%2)").arg(wimaFileExtension).arg(AppSettings::planFileExtension);
return filters;
WimaDataContainer *WimaController::dataContainer()
{
Valentin Platzgummer
committed
return _container;
}
QmlObjectListModel *WimaController::missionItems()
{
return &_missionItems;
}
QmlObjectListModel *WimaController::currentMissionItems()
{
return &_currentMissionItems;
}
QVariantList WimaController::waypointPath()
{
return _waypointPath;
}
QVariantList WimaController::currentWaypointPath()
{
return _currentWaypointPath;
}
Fact *WimaController::enableWimaController()
{
return &_enableWimaController;
}
Fact *WimaController::overlapWaypoints()
{
return &_overlapWaypoints;
}
Fact *WimaController::maxWaypointsPerPhase()
{
return &_maxWaypointsPerPhase;
}
Fact *WimaController::showAllMissionItems()
{
return &_showAllMissionItems;
}
Fact *WimaController::showCurrentMissionItems()
{
return &_showCurrentMissionItems;
}
Fact *WimaController::flightSpeed()
{
return &_flightSpeed;
}
Fact *WimaController::altitude()
{
return &_altitude;
}
Valentin Platzgummer
committed
bool WimaController::uploadOverrideRequired() const
{
return _uploadOverrideRequired;
}
double WimaController::phaseDistance() const
{
return _phaseDistance;
}
double WimaController::phaseDuration() const
{
return _phaseDuration;
}
bool WimaController::vehicleHasLowBattery() const
{
return _vehicleHasLowBattery;
}
Fact *WimaController::startWaypointIndex()
{
void WimaController::setMasterController(PlanMasterController *masterC)
{
_masterController = masterC;
emit masterControllerChanged();
}
void WimaController::setMissionController(MissionController *missionC)
{
_missionController = missionC;
emit missionControllerChanged();
}
Valentin Platzgummer
committed
/*!
* \fn void WimaController::setDataContainer(WimaDataContainer *container)
* Sets the pointer to the \c WimaDataContainer, which is meant to exchange data between the \c WimaController and the \c WimaPlaner.
*
* \sa WimaPlaner, WimaDataContainer, WimaPlanData
*/
void WimaController::setDataContainer(WimaDataContainer *container)
{
Valentin Platzgummer
committed
if (container != nullptr) {
if (_container != nullptr) {
disconnect(_container, &WimaDataContainer::newDataAvailable, this, &WimaController::fetchContainerData);
Valentin Platzgummer
committed
}
connect(_container, &WimaDataContainer::newDataAvailable, this, &WimaController::fetchContainerData);
emit dataContainerChanged();
}
}
Valentin Platzgummer
committed
void WimaController::setUploadOverrideRequired(bool overrideRequired)
{
if (_uploadOverrideRequired != overrideRequired) {
_uploadOverrideRequired = overrideRequired;
emit uploadOverrideRequiredChanged();
}
}
void WimaController::nextPhase()
{
Valentin Platzgummer
committed
void WimaController::previousPhase()
{
if (_nextPhaseStartWaypointIndex.rawValue().toInt() > 0) {
_lastMissionPhaseReached = false;
Valentin Platzgummer
committed
_nextPhaseStartWaypointIndex.setRawValue(std::max(_startWaypointIndex
- _maxWaypointsPerPhase.rawValue().toInt()
+ _overlapWaypoints.rawValue().toInt(), 1));
Valentin Platzgummer
committed
}
void WimaController::resetPhase()
{
_lastMissionPhaseReached = false;
_nextPhaseStartWaypointIndex.setRawValue(int(1));
Valentin Platzgummer
committed
}
Valentin Platzgummer
committed
{
Valentin Platzgummer
committed
if ( !_serviceArea.containsCoordinate(_masterController->managerVehicle()->coordinate())
&& _currentMissionItems.count() > 0) {
Valentin Platzgummer
committed
setUploadOverrideRequired(true);
return false;
}
return forceUploadToVehicle();
}
bool WimaController::forceUploadToVehicle()
{
setUploadOverrideRequired(false);
if (_currentMissionItems.count() < 1)
_missionController->removeAll();
// set homeposition of settingsItem
QmlObjectListModel* visuals = _missionController->visualItems();
MissionSettingsItem* settingsItem = visuals->value<MissionSettingsItem *>(0);
if (settingsItem == nullptr) {
qWarning("WimaController::updateCurrentMissionItems(): nullptr");
}
settingsItem->setCoordinate(_takeoffLandPostion);
// copy mission items from _currentMissionItems to _missionController
for (int i = 0; i < _currentMissionItems.count(); i++){
SimpleMissionItem *item = _currentMissionItems.value<SimpleMissionItem *>(i);
_missionController->insertSimpleMissionItem(*item, visuals->count());
}
Valentin Platzgummer
committed
void WimaController::removeFromVehicle()
{
_masterController->removeAllFromVehicle();
_missionController->removeAll();
}
bool WimaController::checkSmartRTLPreCondition()
{
QString errorString;
bool retValue = _checkSmartRTLPreCondition(errorString);
if (retValue == false) {
qgcApp()->showMessage(errorString);
return false;
}
return true;
}
bool WimaController::calcReturnPath()
{
QString errorString;
bool retValue = _calcReturnPath(errorString);
if (retValue == false) {
qgcApp()->showMessage(errorString);
return false;
}
return true;
Valentin Platzgummer
committed
}
void WimaController::saveToFile(const QString& filename)
{
}
bool WimaController::loadFromFile(const QString &filename)
{
QJsonDocument WimaController::saveToJson(FileType fileType)
Valentin Platzgummer
committed
return QJsonDocument();
bool WimaController::calcShortestPath(const QGeoCoordinate &start, const QGeoCoordinate &destination, QList<QGeoCoordinate> &path)
{
using namespace GeoUtilities;
using namespace PolygonCalculus;
QList<QPointF> path2D;
bool retVal = PolygonCalculus::shortestPath(
toQPolygonF(toCartesian2D(_joinedArea.coordinateList(), /*origin*/ start)),
/*start point*/ QPointF(0,0),
/*destination*/ toCartesian2D(destination, start),
/*shortest path*/ path2D);
path.append(toGeo(path2D, /*origin*/ start));
return retVal;
}
bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QList<QGeoCoordinate> &coordinateList)
{
return extractCoordinateList(missionItems, coordinateList, 0, missionItems.count()-1);
}
bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QList<QGeoCoordinate> &coordinateList, int startIndex, int endIndex)
{
if ( startIndex >= 0
&& startIndex < missionItems.count()
&& endIndex >= 0
&& endIndex < missionItems.count()) {
if (startIndex > endIndex) {
if (!extractCoordinateList(missionItems, coordinateList, startIndex, missionItems.count()-1))
return false;
if (!extractCoordinateList(missionItems, coordinateList, 0, endIndex))
return false;
} else {
for (int i = startIndex; i <= endIndex; i++) {
SimpleMissionItem *mItem = missionItems.value<SimpleMissionItem *>(i);
if (mItem == nullptr) {
coordinateList.clear();
return false;
}
coordinateList.append(mItem->coordinate());
}
}
} else
return false;
return true;
}
bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QVariantList &coordinateList)
{
return extractCoordinateList(missionItems, coordinateList, 0 , missionItems.count()-1);
}
bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QVariantList &coordinateList, int startIndex, int endIndex)
{
QList<QGeoCoordinate> geoCoordintateList;
bool retValue = extractCoordinateList(missionItems, geoCoordintateList, startIndex, endIndex);
if (!retValue)
return false;
for (int i = 0; i < geoCoordintateList.size(); i++) {
QGeoCoordinate vertex = geoCoordintateList[i];
if (qFuzzyIsNull(vertex.latitude()) && qFuzzyIsNull(vertex.longitude()))
geoCoordintateList.removeAt(i);
}
for (auto coordinate : geoCoordintateList)
coordinateList.append(QVariant::fromValue(coordinate));
return true;
}
Valentin Platzgummer
committed
/*!
* \fn void WimaController::containerDataValidChanged(bool valid)
* Pulls plan data generated by \c WimaPlaner from the \c _container if the data is valid (\a valid equals true).
* Is connected to the dataValidChanged() signal of the \c WimaDataContainer.
*
* \sa WimaDataContainer, WimaPlaner, WimaPlanData
*/
Valentin Platzgummer
committed
// reset visual items
_visualItems.clear();
_missionItems.clearAndDeleteContents();
_currentMissionItems.clearAndDeleteContents();
_waypointPath.clear();
_currentWaypointPath.clear();
Valentin Platzgummer
committed
emit visualItemsChanged();
emit missionItemsChanged();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
Valentin Platzgummer
committed
_localPlanDataValid = false;
_lastMissionPhaseReached = false;
Valentin Platzgummer
committed
if (_container == nullptr) {
qWarning("WimaController::fetchContainerData(): No container assigned!");
return false;
}
Valentin Platzgummer
committed
Valentin Platzgummer
committed
// extract list with WimaAreas
QList<const WimaAreaData*> areaList = planData.areaList();
Valentin Platzgummer
committed
int areaCounter = 0;
int numAreas = 4; // extract only numAreas Areas, if there are more they are invalid and ignored
for (int i = 0; i < areaList.size(); i++) {
const WimaAreaData *areaData = areaList[i];
Valentin Platzgummer
committed
if (areaData->type() == WimaServiceAreaData::typeString) { // is it a service area?
_serviceArea = *qobject_cast<const WimaServiceAreaData*>(areaData);
areaCounter++;
_visualItems.append(&_serviceArea);
Valentin Platzgummer
committed
Valentin Platzgummer
committed
if (areaData->type() == WimaMeasurementAreaData::typeString) { // is it a measurement area?
_measurementArea = *qobject_cast<const WimaMeasurementAreaData*>(areaData);
areaCounter++;
_visualItems.append(&_measurementArea);
Valentin Platzgummer
committed
Valentin Platzgummer
committed
}
if (areaData->type() == WimaCorridorData::typeString) { // is it a corridor?
_corridor = *qobject_cast<const WimaCorridorData*>(areaData);
areaCounter++;
//_visualItems.append(&_corridor); // not needed
Valentin Platzgummer
committed
Valentin Platzgummer
committed
if (areaData->type() == WimaJoinedAreaData::typeString) { // is it a corridor?
_joinedArea = *qobject_cast<const WimaJoinedAreaData*>(areaData);
areaCounter++;
_visualItems.append(&_joinedArea);
Valentin Platzgummer
committed
Valentin Platzgummer
committed
Valentin Platzgummer
committed
QList<MissionItem> tempMissionItems = planData.missionItems();
if (tempMissionItems.size() < 1)
return false;
Valentin Platzgummer
committed
// create mission items
_missionController->removeAll();
QmlObjectListModel* missionControllerVisualItems = _missionController->visualItems();
// create SimpleMissionItem by using _missionController
for ( int i = 0; i < tempMissionItems.size(); i++) {
_missionController->insertSimpleMissionItem(tempMissionItems[i], missionControllerVisualItems->count());
}
// copy mission items from _missionController to _missionItems
for ( int i = 1; i < missionControllerVisualItems->count(); i++) {
SimpleMissionItem *visualItem = qobject_cast<SimpleMissionItem *>((*missionControllerVisualItems)[i]);
if (visualItem == nullptr) {
qWarning("WimaController::fetchContainerData(): Nullptr at SimpleMissionItem!");
return false;
Valentin Platzgummer
committed
}
SimpleMissionItem *visualItemCopy = new SimpleMissionItem(*visualItem, true, this);
_missionItems.append(visualItemCopy);
}
if (areaCounter != numAreas)
return false;
Valentin Platzgummer
committed
if (!setTakeoffLandPosition())
return false;
// set _nextPhaseStartWaypointIndex to 1
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
_nextPhaseStartWaypointIndex.setRawValue(int(1));
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
_localPlanDataValid = true;
return true;
if (_missionItems.count() < 1 || _lastMissionPhaseReached)
return false;
_currentMissionItems.clearAndDeleteContents();
_currentWaypointPath.clear();
emit currentMissionItemsChanged();
emit currentWaypointPathChanged();
_startWaypointIndex = _nextPhaseStartWaypointIndex.rawValue().toInt()-1;
if (_startWaypointIndex > _missionItems.count()-1)
return false;
Valentin Platzgummer
committed
int maxWaypointsPerPhaseInt = _maxWaypointsPerPhase.rawValue().toInt();
// determine end waypoint index
_endWaypointIndex = std::min(_startWaypointIndex + maxWaypointsPerPhaseInt - 1, _missionItems.count()-1);
if (_endWaypointIndex == _missionItems.count() - 1)
_lastMissionPhaseReached = true;
QList<QGeoCoordinate> geoCoordinateList; // list with potential waypoints (from _missionItems), for _currentMissionItems
if (!extractCoordinateList(_missionItems, geoCoordinateList, _startWaypointIndex, _endWaypointIndex)) {
qWarning("WimaController::calcNextPhase(): error on waypoint extraction.");
return false;
// set start waypoint index for next phase
if (!_lastMissionPhaseReached) {
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
int untruncated = std::max(_endWaypointIndex + 1 - _overlapWaypoints.rawValue().toInt(), 0);
int truncated = std::min(untruncated , _missionItems.count()-1);
_nextPhaseStartWaypointIndex.setRawValue(truncated + 1);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
// calculate path from home to first waypoint
QList<QGeoCoordinate> path;
if (!_takeoffLandPostion.isValid()){
qWarning("WimaController::calcNextPhase(): _takeoffLandPostion not valid.");
return false;
}
Valentin Platzgummer
committed
if ( !calcShortestPath(_takeoffLandPostion, geoCoordinateList[0], path) ) {
qWarning("WimaController::calcNextPhase(): Not able to calc path from home to first waypoint.");
return false;
}
// prepend to geoCoordinateList
for (int i = path.size()-2; i >= 0; i--) // i = path.size()-2 : last coordinate already in geoCoordinateList
geoCoordinateList.prepend(path[i]);
// calculate path from last waypoint to home
path.clear();
Valentin Platzgummer
committed
if ( !calcShortestPath(geoCoordinateList.last(), _takeoffLandPostion, path) ) {
qWarning("WimaController::calcNextPhase(): Not able to calc path from home to first waypoint.");
return false;
}
path.removeFirst(); // first coordinate already in geoCoordinateList
geoCoordinateList.append(path);
Valentin Platzgummer
committed
// create Mission Items
_missionController->removeAll();
QmlObjectListModel* missionControllerVisuals = _missionController->visualItems();
Valentin Platzgummer
committed
// set homeposition of settingsItem
MissionSettingsItem* settingsItem = missionControllerVisuals->value<MissionSettingsItem *>(0);
if (settingsItem == nullptr) {
qWarning("WimaController::calcNextPhase(): nullptr");
return false;
Valentin Platzgummer
committed
}
settingsItem->setCoordinate(_takeoffLandPostion);
for (auto coordinate : geoCoordinateList) {
_missionController->insertSimpleMissionItem(coordinate, missionControllerVisuals->count());
Valentin Platzgummer
committed
}
// set takeoff position for first mission item (bug)
SimpleMissionItem *takeoffItem = missionControllerVisuals->value<SimpleMissionItem*>(1);
if (takeoffItem == nullptr) {
qWarning("WimaController::calcNextPhase(): nullptr");
return false;
Valentin Platzgummer
committed
}
takeoffItem->setCoordinate(_takeoffLandPostion);
Valentin Platzgummer
committed
// create change speed item
_missionController->insertSimpleMissionItem(_takeoffLandPostion, 2);
SimpleMissionItem *speedItem = missionControllerVisuals->value<SimpleMissionItem*>(2);
if (speedItem == nullptr) {
qWarning("WimaController::calcNextPhase(): nullptr");
return false;
}
speedItem->setCoordinate(_takeoffLandPostion);
speedItem->setCommand(MAV_CMD_DO_CHANGE_SPEED);
speedItem->missionItem().setParam2(_flightSpeed.rawValue().toDouble());
// set land command for last mission item
SimpleMissionItem *landItem = missionControllerVisuals->value<SimpleMissionItem*>(missionControllerVisuals->count()-1);
if (landItem == nullptr) {
qWarning("WimaController::calcNextPhase(): nullptr");
return false;
_missionController->setLandCommand(*landItem);
Valentin Platzgummer
committed
// copy to _currentMissionItems
for ( int i = 1; i < missionControllerVisuals->count(); i++) {
SimpleMissionItem *visualItem = missionControllerVisuals->value<SimpleMissionItem*>(i);
if (visualItem == nullptr) {
qWarning("WimaController::calcNextPhase(): Nullptr at SimpleMissionItem!");
Valentin Platzgummer
committed
Valentin Platzgummer
committed
SimpleMissionItem *visualItemCopy = new SimpleMissionItem(*visualItem, true, this);
_currentMissionItems.append(visualItemCopy);
}
_setPhaseDistance(_missionController->missionDistance());
_setPhaseDuration(_missionController->missionDistance()/_flightSpeed.rawValue().toDouble());
_missionController->removeAll(); // remove items from _missionController, will be added on upload
updateAltitude();
void WimaController::updateWaypointPath()
{
_waypointPath.clear();
Valentin Platzgummer
committed
extractCoordinateList(_missionItems, _waypointPath, 0, _missionItems.count()-1);
emit waypointPathChanged();
}
void WimaController::updateCurrentPath()
{
_currentWaypointPath.clear();
Valentin Platzgummer
committed
extractCoordinateList(_currentMissionItems, _currentWaypointPath, 0, _currentMissionItems.count()-1);
emit currentWaypointPathChanged();
}
void WimaController::updateNextWaypoint()
{
if (_endWaypointIndex < _missionItems.count()-2) {
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
_nextPhaseStartWaypointIndex.setRawValue(1 + std::max(_endWaypointIndex + 1 - _overlapWaypoints.rawValue().toInt(), 0));
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
void WimaController::recalcCurrentPhase()
{
Valentin Platzgummer
committed
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
_nextPhaseStartWaypointIndex.setRawValue(_startWaypointIndex + 1);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
calcNextPhase();
}
bool WimaController::setTakeoffLandPosition()
{
_takeoffLandPostion.setAltitude(0);
_takeoffLandPostion.setLongitude(_serviceArea.center().longitude());
_takeoffLandPostion.setLatitude(_serviceArea.center().latitude());
return true;
void WimaController::updateSpeed()
{
SimpleMissionItem *item = _currentMissionItems.value<SimpleMissionItem *>(1); // speed item
if (item != nullptr && item->command() == MAV_CMD_DO_CHANGE_SPEED) {
item->missionItem().setParam2(_flightSpeed.rawValue().toDouble());
_setPhaseDuration(_phaseDistance/_flightSpeed.rawValue().toDouble());
}
else {
qWarning("WimaController::updateSpeed(): internal error.");
}
}
void WimaController::updateAltitude()
{
for (int i = 0; i < _currentMissionItems.count(); i++) {
SimpleMissionItem *item = _currentMissionItems.value<SimpleMissionItem *>(i);
if (item == nullptr) {
qWarning("WimaController::updateAltitude(): nullptr");
return;
}
item->altitude()->setRawValue(_altitude.rawValue().toDouble());
}
}
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
void WimaController::checkBatteryLevel()
{
Vehicle *managerVehicle = masterController()->managerVehicle();
int batteryThreshold = 94; // percent
if (managerVehicle != nullptr) {
Fact *battery1percentRemaining = managerVehicle->battery1FactGroup()->getFact(VehicleBatteryFactGroup::_percentRemainingFactName);
Fact *battery2percentRemaining = managerVehicle->battery2FactGroup()->getFact(VehicleBatteryFactGroup::_percentRemainingFactName);
if (battery1percentRemaining->rawValue().toDouble() < batteryThreshold
&& battery2percentRemaining->rawValue().toDouble() < batteryThreshold) {
_setVehicleHasLowBattery(true);
if (!_lowBatteryHandlingTriggered) {
QString errorString;
if (_checkSmartRTLPreCondition(errorString) == true) {
managerVehicle->pauseVehicle();
if (_calcReturnPath(errorString)) {
emit returnBatteryLowConfirmRequired();
} else {
qgcApp()->showMessage(tr("Battery level is low. Smart RTL not possible."));
qgcApp()->showMessage(errorString);
}
}
_lowBatteryHandlingTriggered = true;
}
}
else {
_setVehicleHasLowBattery(false);
_lowBatteryHandlingTriggered = false;
}
}
}
void WimaController::_setPhaseDistance(double distance)
{
if (!qFuzzyCompare(distance, _phaseDistance)) {
_phaseDistance = distance;
emit phaseDistanceChanged();
}
}
void WimaController::_setPhaseDuration(double duration)
{
if (!qFuzzyCompare(duration, _phaseDuration)) {
_phaseDuration = duration;
emit phaseDurationChanged();
}
}
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
bool WimaController::_checkSmartRTLPreCondition(QString &errorString)
{
if (!_localPlanDataValid) {
errorString.append(tr("No WiMA data available. Please define at least a measurement and a service area."));
return false;
}
Vehicle *managerVehicle = masterController()->managerVehicle();
if (!managerVehicle->flying()) {
errorString.append(tr("Vehicle is not flying. Smart RTL not available."));
return false;
}
}
bool WimaController::_calcReturnPath(QString &errorSring)
{
// it is assumed that checkSmartRTLPreCondition() was called first and true was returned
Vehicle *managerVehicle = masterController()->managerVehicle();
QGeoCoordinate currentVehiclePosition = managerVehicle->coordinate();
// check if vehicle inside _joinedArea, this statement is not inside checkSmartRTLPreCondition() because during checkSmartRTLPreCondition() vehicle is not paused yet
if (!_joinedArea.containsCoordinate(currentVehiclePosition)) {
errorSring.append(tr("Vehicle not inside joined area. Action not supported."));
return false;
}
// calculate return path
QList<QGeoCoordinate> returnPath;
calcShortestPath(currentVehiclePosition, _takeoffLandPostion, returnPath);
// successful?
if (returnPath.isEmpty()) {
errorSring.append(tr("Not able to calculate return path."));
return false;
}
// qWarning() << "returnPath.size()" << returnPath.size();
// buffer _currentMissionItems
//qWarning() << "_currentMissionItems.count()" << _currentMissionItems.count();
//qWarning() << "_missionItemsBuffer.count()" << _missionItemsBuffer.count();
_missionItemsBuffer.clear();
int numCurrentMissionItems = _currentMissionItems.count();
for (int i = 0; i < numCurrentMissionItems; i++)
_missionItemsBuffer.append(_currentMissionItems.removeAt(0));
//qWarning() << "_currentMissionItems.count()" << _currentMissionItems.count();
//qWarning() << "_missionItemsBuffer.count()" << _missionItemsBuffer.count();
// create Mission Items
removeFromVehicle();
QmlObjectListModel* missionControllerVisuals = _missionController->visualItems();
// set homeposition of settingsItem
MissionSettingsItem* settingsItem = missionControllerVisuals->value<MissionSettingsItem *>(0);
if (settingsItem == nullptr) {
qWarning("WimaController: nullptr");
return false;
}
settingsItem->setCoordinate(_takeoffLandPostion);
// copy from returnPath to _missionController
QGeoCoordinate speedItemCoordinate = returnPath.first();
for (auto coordinate : returnPath) {
_missionController->insertSimpleMissionItem(coordinate, missionControllerVisuals->count());
}
//qWarning() << "missionControllerVisuals->count()" << missionControllerVisuals->count();
// create speed item
int speedItemIndex = 1;
_missionController->insertSimpleMissionItem(speedItemCoordinate, speedItemIndex);
SimpleMissionItem *speedItem = missionControllerVisuals->value<SimpleMissionItem*>(speedItemIndex);
if (speedItem == nullptr) {
qWarning("WimaController: nullptr");
return false;
}
speedItem->setCoordinate(speedItemCoordinate);
speedItem->setCommand(MAV_CMD_DO_CHANGE_SPEED);
speedItem->missionItem().setParam2(_flightSpeed.rawValue().toDouble());
// set second item command to ordinary waypoint (is takeoff)
SimpleMissionItem *secondItem = missionControllerVisuals->value<SimpleMissionItem*>(2);
if (secondItem == nullptr) {
qWarning("WimaController: nullptr");
return false;
}
secondItem->setCoordinate(speedItemCoordinate);
secondItem->setCommand(MAV_CMD_NAV_WAYPOINT);
// set land command for last mission item
SimpleMissionItem *landItem = missionControllerVisuals->value<SimpleMissionItem*>(missionControllerVisuals->count()-1);
if (landItem == nullptr) {
qWarning("WimaController: nullptr");
return false;
}
_missionController->setLandCommand(*landItem);
// copy to _currentMissionItems
//qWarning() << "_currentMissionItems.count()" << _currentMissionItems.count();
for ( int i = 1; i < missionControllerVisuals->count(); i++) {
SimpleMissionItem *visualItem = missionControllerVisuals->value<SimpleMissionItem*>(i);
if (visualItem == nullptr) {
qWarning("WimaController: Nullptr at SimpleMissionItem!");
_currentMissionItems.clear();
return false;
}
SimpleMissionItem *visualItemCopy = new SimpleMissionItem(*visualItem, true, this);
_currentMissionItems.append(visualItemCopy);
}
//qWarning() << "_currentMissionItems.count()" << _currentMissionItems.count();
_setPhaseDistance(_missionController->missionDistance());
_setPhaseDuration(_missionController->missionDistance()/_flightSpeed.rawValue().toDouble());
_missionController->removeAll(); // remove items from _missionController, will be added on upload
updateAltitude();
updateCurrentPath();
emit currentMissionItemsChanged();
//qWarning() << "_currentMissionItems.count()" << _currentMissionItems.count();
_showAllMissionItems.setRawValue(false);
managerVehicle->trajectoryPoints()->clear();
emit uploadAndExecuteConfirmRequired();
return true;
}
void WimaController::_setVehicleHasLowBattery(bool batteryLow)
{
if (_vehicleHasLowBattery != batteryLow) {
_vehicleHasLowBattery = batteryLow;
emit vehicleHasLowBatteryChanged();
qWarning() << "WimaController::_setVehicleHasLowBattery(bool batteryLow)" << _vehicleHasLowBattery;
}
}