WimaController.cc 25.1 KB
Newer Older
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1
#include "WimaController.h"
2

Valentin Platzgummer's avatar
Valentin Platzgummer committed
3
#include "utilities.h"
4

5
#include "Snake/QNemoHeartbeat.h"
6
#include "Snake/QNemoProgress.h"
7

8
#include "QVector3D"
9
#include <QScopedPointer>
10
#include <QtConcurrentRun>
11

12 13
#include <memory>

14
#define SMART_RTL_MAX_ATTEMPTS 3       // times
15
#define SMART_RTL_ATTEMPT_INTERVAL 200 // ms
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
#define EVENT_TIMER_INTERVAL 50        // ms

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::arrivalReturnSpeedName = "ArrivalReturnSpeed";
const char *WimaController::altitudeName = "Altitude";
const char *WimaController::snakeTileWidthName = "SnakeTileWidth";
const char *WimaController::snakeTileHeightName = "SnakeTileHeight";
const char *WimaController::snakeMinTileAreaName = "SnakeMinTileArea";
const char *WimaController::snakeLineDistanceName = "SnakeLineDistance";
const char *WimaController::snakeMinTransectLengthName =
    "SnakeMinTransectLength";
Valentin Platzgummer's avatar
Valentin Platzgummer committed
37

Valentin Platzgummer's avatar
Valentin Platzgummer committed
38 39 40
WimaController::StatusMap WimaController::_nemoStatusMap{
    std::make_pair<int, QString>(0, "No Heartbeat"),
    std::make_pair<int, QString>(1, "Connected"),
41 42
    std::make_pair<int, QString>(-1, "Timeout"),
    std::make_pair<int, QString>(-2, "Error")};
43

44
WimaController::WimaController(QObject *parent)
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
    : QObject(parent), _joinedArea(), _measurementArea(), _serviceArea(),
      _corridor(), _localPlanDataValid(false),
      _areaInterface(&_measurementArea, &_serviceArea, &_corridor,
                     &_joinedArea),
      _WMSettings(), _defaultWM(_WMSettings, _areaInterface),
      _snakeWM(_WMSettings, _areaInterface),
      _rtlWM(_WMSettings, _areaInterface),
      _currentWM(&_defaultWM), _WMList{&_defaultWM, &_snakeWM, &_rtlWM},
      _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]),
      _arrivalReturnSpeed(settingsGroup, _metaDataMap[arrivalReturnSpeedName]),
      _altitude(settingsGroup, _metaDataMap[altitudeName]),
      _snakeTileWidth(settingsGroup, _metaDataMap[snakeTileWidthName]),
      _snakeTileHeight(settingsGroup, _metaDataMap[snakeTileHeightName]),
      _snakeMinTileArea(settingsGroup, _metaDataMap[snakeMinTileAreaName]),
      _snakeLineDistance(settingsGroup, _metaDataMap[snakeLineDistanceName]),
      _snakeMinTransectLength(settingsGroup,
                              _metaDataMap[snakeMinTransectLengthName]),
      _lowBatteryHandlingTriggered(false), _measurementPathLength(-1),
      _currentDM(&_emptyDM),
      _batteryLevelTicker(EVENT_TIMER_INTERVAL, 1000 /*ms*/) {

  // Set up facts.
  _showAllMissionItems.setRawValue(true);
  _showCurrentMissionItems.setRawValue(true);
  connect(&_overlapWaypoints, &Fact::rawValueChanged, this,
          &WimaController::_updateOverlap);
  connect(&_maxWaypointsPerPhase, &Fact::rawValueChanged, this,
          &WimaController::_updateMaxWaypoints);
  connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this,
          &WimaController::_setStartIndex);
  connect(&_flightSpeed, &Fact::rawValueChanged, this,
          &WimaController::_updateflightSpeed);
  connect(&_arrivalReturnSpeed, &Fact::rawValueChanged, this,
          &WimaController::_updateArrivalReturnSpeed);
  connect(&_altitude, &Fact::rawValueChanged, this,
          &WimaController::_updateAltitude);

  // Init waypoint managers.
  bool value;
  size_t overlap = _overlapWaypoints.rawValue().toUInt(&value);
  Q_ASSERT(value);
  size_t N = _maxWaypointsPerPhase.rawValue().toUInt(&value);
  Q_ASSERT(value);
  size_t startIdx = _nextPhaseStartWaypointIndex.rawValue().toUInt(&value);
  Q_ASSERT(value);
  (void)value;
  for (auto manager : _WMList) {
    manager->setOverlap(overlap);
    manager->setN(N);
    manager->setStartIndex(startIdx);
  }

  // Periodic.
  connect(&_eventTimer, &QTimer::timeout, this,
          &WimaController::_eventTimerHandler);
  _eventTimer.start(EVENT_TIMER_INTERVAL);

  // Snake Data Manager.
  connect(_currentDM, &SnakeDataManager::finished, this,
          &WimaController::_DMFinishedHandler);
  connect(_currentDM, &SnakeDataManager::nemoProgressChanged, this,
          &WimaController::_progressChangedHandler);
  connect(_currentDM, &SnakeDataManager::nemoStatusChanged, this,
          &WimaController::nemoStatusChanged);
  connect(_currentDM, &SnakeDataManager::nemoStatusChanged, this,
          &WimaController::nemoStatusStringChanged);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
124 125
  connect(_currentDM, &SnakeDataManager::calcInProgressChanged, this,
          &WimaController::snakeCalcInProgressChanged);
126 127 128 129 130 131 132 133 134 135 136 137

  connect(this, &QObject::destroyed, &this->_snakeDM, &SnakeDataManager::quit);
  connect(this, &QObject::destroyed, &this->_emptyDM, &SnakeDataManager::quit);

  connect(&_enableSnake, &Fact::rawValueChanged, this,
          &WimaController::_enableSnakeChangedHandler);
  _enableSnakeChangedHandler();

  // Snake Waypoint Manager.
  connect(&_enableSnake, &Fact::rawValueChanged, this,
          &WimaController::_switchToSnakeWaypointManager);
  _switchToSnakeWaypointManager(_enableSnake.rawValue());
138 139
}

140
PlanMasterController *WimaController::masterController() {
141
  return _masterController;
142 143 144
}

MissionController *WimaController::missionController() {
145
  return _missionController;
146 147
}

148
QmlObjectListModel *WimaController::visualItems() { return &_areas; }
149 150

QmlObjectListModel *WimaController::missionItems() {
151
  return const_cast<QmlObjectListModel *>(&_currentWM->missionItems());
152 153 154
}

QmlObjectListModel *WimaController::currentMissionItems() {
155
  return const_cast<QmlObjectListModel *>(&_currentWM->currentMissionItems());
156 157
}

158 159
QVariantList WimaController::waypointPath() {
  return const_cast<QVariantList &>(_currentWM->waypointsVariant());
160 161
}

162 163
QVariantList WimaController::currentWaypointPath() {
  return const_cast<QVariantList &>(_currentWM->currentWaypointsVariant());
164 165
}

166
Fact *WimaController::enableWimaController() { return &_enableWimaController; }
167

168
Fact *WimaController::overlapWaypoints() { return &_overlapWaypoints; }
169

170
Fact *WimaController::maxWaypointsPerPhase() { return &_maxWaypointsPerPhase; }
171 172

Fact *WimaController::startWaypointIndex() {
173
  return &_nextPhaseStartWaypointIndex;
174 175
}

176
Fact *WimaController::showAllMissionItems() { return &_showAllMissionItems; }
177 178

Fact *WimaController::showCurrentMissionItems() {
179
  return &_showCurrentMissionItems;
180 181
}

182
Fact *WimaController::flightSpeed() { return &_flightSpeed; }
183

184
Fact *WimaController::arrivalReturnSpeed() { return &_arrivalReturnSpeed; }
185

186
Fact *WimaController::altitude() { return &_altitude; }
187

188
QmlObjectListModel *WimaController::snakeTiles() {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
189
  return const_cast<QmlObjectListModel *>(this->_currentDM->tiles());
Valentin Platzgummer's avatar
Valentin Platzgummer committed
190 191
}

192 193
QVariantList WimaController::snakeTileCenterPoints() {
  return _currentDM->tileCenterPoints();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
194 195
}

196 197
QVector<int> WimaController::nemoProgress() {
  return _currentDM->nemoProgress().progress();
198 199
}

200 201 202
double WimaController::phaseDistance() const {
  qWarning() << "using phaseDistance dummy";
  return 0.0;
203 204
}

205 206 207
double WimaController::phaseDuration() const {
  qWarning() << "using phaseDuration dummy";
  return 0.0;
208 209
}

210
int WimaController::nemoStatus() const { return _currentDM->nemoStatus(); }
211

212 213
QString WimaController::nemoStatusString() const {
  return _nemoStatusMap.at(nemoStatus());
Valentin Platzgummer's avatar
Valentin Platzgummer committed
214 215
}

216 217
bool WimaController::snakeCalcInProgress() const {
  return _currentDM->calcInProgress();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
218 219
}

220 221 222 223
void WimaController::setMasterController(PlanMasterController *masterC) {
  _masterController = masterC;
  _WMSettings.setMasterController(masterC);
  emit masterControllerChanged();
224 225
}

226 227 228 229
void WimaController::setMissionController(MissionController *missionC) {
  _missionController = missionC;
  _WMSettings.setMissionController(missionC);
  emit missionControllerChanged();
230 231
}

232
void WimaController::nextPhase() { _calcNextPhase(); }
233

234 235 236 237
void WimaController::previousPhase() {
  if (!_currentWM->previous()) {
    Q_ASSERT(false);
  }
238

239 240 241 242
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
243 244
}

245 246 247 248
void WimaController::resetPhase() {
  if (!_currentWM->reset()) {
    Q_ASSERT(false);
  }
249

250 251 252 253
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
254 255
}

256 257 258 259 260 261 262
void WimaController::requestSmartRTL() {
  QString errorString("Smart RTL requested. ");
  if (!_checkSmartRTLPreCondition(errorString)) {
    qgcApp()->showMessage(errorString);
    return;
  }
  emit smartRTLRequestConfirm();
263 264
}

265 266 267 268 269 270 271 272
bool WimaController::upload() {
  auto &currentMissionItems = _defaultWM.currentMissionItems();
  if (!_serviceArea.containsCoordinate(
          _masterController->managerVehicle()->coordinate()) &&
      currentMissionItems.count() > 0) {
    emit forceUploadConfirm();
    return false;
  }
273

274
  return forceUpload();
275 276
}

277 278 279 280
bool WimaController::forceUpload() {
  auto &currentMissionItems = _defaultWM.currentMissionItems();
  if (currentMissionItems.count() < 1)
    return false;
281

282 283 284 285 286 287 288 289 290 291
  _missionController->removeAll();
  // Set homeposition of settingsItem.
  QmlObjectListModel *visuals = _missionController->visualItems();
  MissionSettingsItem *settingsItem = visuals->value<MissionSettingsItem *>(0);
  if (settingsItem == nullptr) {
    Q_ASSERT(false);
    qWarning("WimaController::updateCurrentMissionItems(): nullptr");
    return false;
  }
  settingsItem->setCoordinate(_WMSettings.homePosition());
292

293 294 295 296 297
  // Copy mission items to _missionController.
  for (int i = 1; i < currentMissionItems.count(); i++) {
    auto *item = currentMissionItems.value<const SimpleMissionItem *>(i);
    _missionController->insertSimpleMissionItem(*item, visuals->count());
  }
298

299
  _masterController->sendToVehicle();
300

301
  return true;
302
}
303

304 305 306
void WimaController::removeFromVehicle() {
  _masterController->removeAllFromVehicle();
  _missionController->removeAll();
307 308
}

309 310 311
void WimaController::executeSmartRTL() {
  forceUpload();
  masterController()->managerVehicle()->startMission();
312 313
}

314
void WimaController::initSmartRTL() { _initSmartRTL(); }
315

316 317 318
void WimaController::removeVehicleTrajectoryHistory() {
  Vehicle *managerVehicle = masterController()->managerVehicle();
  managerVehicle->trajectoryPoints()->clear();
319 320
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
321 322
bool WimaController::_calcShortestPath(const QGeoCoordinate &start,
                                       const QGeoCoordinate &destination,
323 324 325 326 327 328 329 330 331
                                       QVector<QGeoCoordinate> &path) {
  using namespace GeoUtilities;
  using namespace PolygonCalculus;
  QPolygonF polygon2D;
  toCartesianList(_joinedArea.coordinateList(), /*origin*/ start, polygon2D);
  QPointF start2D(0, 0);
  QPointF end2D;
  toCartesian(destination, start, end2D);
  QVector<QPointF> path2D;
332

333 334 335
  bool retVal =
      PolygonCalculus::shortestPath(polygon2D, start2D, end2D, path2D);
  toGeoList(path2D, /*origin*/ start, path);
336

337 338
  return retVal;
}
339

340 341 342 343 344
bool WimaController::setWimaPlanData(const WimaPlanData &planData) {
  // reset visual items
  _areas.clear();
  _defaultWM.clear();
  _snakeWM.clear();
345

346 347 348 349 350
  emit visualItemsChanged();
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit waypointPathChanged();
  emit currentWaypointPathChanged();
351

352
  _localPlanDataValid = false;
353

354 355
  // extract list with WimaAreas
  QList<const WimaAreaData *> areaList = planData.areaList();
356

357 358 359 360 361
  int areaCounter = 0;
  const 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];
362

363 364 365 366 367
    if (areaData->type() ==
        WimaServiceAreaData::typeString) { // is it a service area?
      _serviceArea = *qobject_cast<const WimaServiceAreaData *>(areaData);
      areaCounter++;
      _areas.append(&_serviceArea);
368

369
      continue;
370
    }
371

372 373 374 375 376 377
    if (areaData->type() ==
        WimaMeasurementAreaData::typeString) { // is it a measurement area?
      _measurementArea =
          *qobject_cast<const WimaMeasurementAreaData *>(areaData);
      areaCounter++;
      _areas.append(&_measurementArea);
378

379
      continue;
380
    }
381

382 383 384 385
    if (areaData->type() == WimaCorridorData::typeString) { // is it a corridor?
      _corridor = *qobject_cast<const WimaCorridorData *>(areaData);
      areaCounter++;
      //_visualItems.append(&_corridor); // not needed
386

387
      continue;
388
    }
389

390 391 392 393 394
    if (areaData->type() ==
        WimaJoinedAreaData::typeString) { // is it a corridor?
      _joinedArea = *qobject_cast<const WimaJoinedAreaData *>(areaData);
      areaCounter++;
      _areas.append(&_joinedArea);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
395

396
      continue;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
397 398
    }

399 400 401
    if (areaCounter >= numAreas)
      break;
  }
402

403 404 405 406
  if (areaCounter != numAreas) {
    Q_ASSERT(false);
    return false;
  }
407

408
  emit visualItemsChanged();
409

410 411 412 413 414 415
  // extract mission items
  QList<MissionItem> tempMissionItems = planData.missionItems();
  if (tempMissionItems.size() < 1) {
    qWarning("WimaController: Mission items from WimaPlaner empty!");
    return false;
  }
416

417 418 419
  for (auto item : tempMissionItems) {
    _defaultWM.push_back(item.coordinate());
  }
420

421 422
  _WMSettings.setHomePosition(QGeoCoordinate(
      _serviceArea.center().latitude(), _serviceArea.center().longitude(), 0));
423

424 425 426 427
  if (!_defaultWM.reset()) {
    Q_ASSERT(false);
    return false;
  }
428

429 430 431 432
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit waypointPathChanged();
  emit currentWaypointPathChanged();
433

434 435 436 437 438
  // Update Snake Data Manager
  _snakeDM.setMeasurementArea(_measurementArea.coordinateList());
  _snakeDM.setServiceArea(_serviceArea.coordinateList());
  _snakeDM.setCorridor(_corridor.coordinateList());
  _currentDM->start();
439

440 441
  _localPlanDataValid = true;
  return true;
442
}
443

444
WimaController *WimaController::thisPointer() { return this; }
445

446 447 448 449 450
bool WimaController::_calcNextPhase() {
  if (!_currentWM->next()) {
    Q_ASSERT(false);
    return false;
  }
451

452 453 454 455
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
456

457
  return true;
458 459
}

460 461 462 463 464 465
bool WimaController::_setStartIndex() {
  bool value;
  _currentWM->setStartIndex(
      _nextPhaseStartWaypointIndex.rawValue().toUInt(&value) - 1);
  Q_ASSERT(value);
  (void)value;
466

467 468 469 470
  if (!_currentWM->update()) {
    Q_ASSERT(false);
    return false;
  }
471

472 473 474 475
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
476

477
  return true;
478 479
}

480 481 482 483
void WimaController::_recalcCurrentPhase() {
  if (!_currentWM->update()) {
    Q_ASSERT(false);
  }
484

485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
}

void WimaController::_updateOverlap() {
  bool value;
  _currentWM->setOverlap(_overlapWaypoints.rawValue().toUInt(&value));
  Q_ASSERT(value);
  (void)value;

  if (!_currentWM->update()) {
    assert(false);
  }

  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
}

void WimaController::_updateMaxWaypoints() {
  bool value;
  _currentWM->setN(_maxWaypointsPerPhase.rawValue().toUInt(&value));
  Q_ASSERT(value);
  (void)value;

  if (!_currentWM->update()) {
    Q_ASSERT(false);
  }

  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
}

void WimaController::_updateflightSpeed() {
  bool value;
  _WMSettings.setFlightSpeed(_flightSpeed.rawValue().toDouble(&value));
  Q_ASSERT(value);
  (void)value;

  if (!_currentWM->update()) {
    Q_ASSERT(false);
  }

  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
}

void WimaController::_updateArrivalReturnSpeed() {
  bool value;
  _WMSettings.setArrivalReturnSpeed(
      _arrivalReturnSpeed.rawValue().toDouble(&value));
  Q_ASSERT(value);
  (void)value;

  if (!_currentWM->update()) {
    Q_ASSERT(false);
  }

  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
}

void WimaController::_updateAltitude() {
  bool value;
  _WMSettings.setAltitude(_altitude.rawValue().toDouble(&value));
  Q_ASSERT(value);
  (void)value;

  if (!_currentWM->update()) {
    Q_ASSERT(false);
  }

  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
}

void WimaController::_checkBatteryLevel() {
  Vehicle *managerVehicle = masterController()->managerVehicle();
  WimaSettings *wimaSettings =
      qgcApp()->toolbox()->settingsManager()->wimaSettings();
  int batteryThreshold =
      wimaSettings->lowBatteryThreshold()->rawValue().toInt();
  bool enabled = _enableWimaController.rawValue().toBool();
  unsigned int minTime =
      wimaSettings->minimalRemainingMissionTime()->rawValue().toUInt();

  if (managerVehicle != nullptr && enabled == true) {
    Fact *battery1percentRemaining =
        managerVehicle->battery1FactGroup()->getFact(
            VehicleBatteryFactGroup::_percentRemainingFactName);
    Fact *battery2percentRemaining =
        managerVehicle->battery2FactGroup()->getFact(
            VehicleBatteryFactGroup::_percentRemainingFactName);

    if (battery1percentRemaining->rawValue().toDouble() < batteryThreshold &&
        battery2percentRemaining->rawValue().toDouble() < batteryThreshold) {
      if (!_lowBatteryHandlingTriggered) {
        _lowBatteryHandlingTriggered = true;
        if (!(_missionController->remainingTime() <= minTime)) {
          requestSmartRTL();
596
        }
597 598 599
      }
    } else {
      _lowBatteryHandlingTriggered = false;
600
    }
601
  }
602 603
}

604 605 606 607 608 609 610 611 612 613
void WimaController::_eventTimerHandler() {
  // Battery level check necessary?
  Fact *enableLowBatteryHandling = qgcApp()
                                       ->toolbox()
                                       ->settingsManager()
                                       ->wimaSettings()
                                       ->enableLowBatteryHandling();
  if (enableLowBatteryHandling->rawValue().toBool() &&
      _batteryLevelTicker.ready())
    _checkBatteryLevel();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
614 615
}

616 617 618 619 620 621 622 623
void WimaController::_smartRTLCleanUp(bool flying) {
  if (!flying) { // vehicle has landed
    _switchWaypointManager(_defaultWM);
    _missionController->removeAllFromVehicle();
    _missionController->removeAll();
    disconnect(masterController()->managerVehicle(), &Vehicle::flyingChanged,
               this, &WimaController::_smartRTLCleanUp);
  }
624 625
}

626 627 628 629
void WimaController::_setPhaseDistance(double distance) {
  (void)distance;
  //    if (!qFuzzyCompare(distance, _phaseDistance)) {
  //        _phaseDistance = distance;
630

631 632
  //        emit phaseDistanceChanged();
  //    }
633 634
}

635 636 637 638
void WimaController::_setPhaseDuration(double duration) {
  (void)duration;
  //    if (!qFuzzyCompare(duration, _phaseDuration)) {
  //        _phaseDuration = duration;
639

640 641
  //        emit phaseDurationChanged();
  //    }
642 643
}

644 645 646 647 648 649
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;
  }
650

651
  return _rtlWM.checkPrecondition(errorString);
652 653
}

654 655 656 657
void WimaController::_switchWaypointManager(
    WaypointManager::ManagerBase &manager) {
  if (_currentWM != &manager) {
    _currentWM = &manager;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
658

659 660 661 662 663 664
    disconnect(&_overlapWaypoints, &Fact::rawValueChanged, this,
               &WimaController::_updateOverlap);
    disconnect(&_maxWaypointsPerPhase, &Fact::rawValueChanged, this,
               &WimaController::_updateMaxWaypoints);
    disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this,
               &WimaController::_setStartIndex);
665

666 667 668
    _maxWaypointsPerPhase.setRawValue(_currentWM->N());
    _overlapWaypoints.setRawValue(_currentWM->overlap());
    _nextPhaseStartWaypointIndex.setRawValue(_currentWM->startIndex());
Valentin Platzgummer's avatar
Valentin Platzgummer committed
669

670 671 672 673 674 675
    connect(&_overlapWaypoints, &Fact::rawValueChanged, this,
            &WimaController::_updateOverlap);
    connect(&_maxWaypointsPerPhase, &Fact::rawValueChanged, this,
            &WimaController::_updateMaxWaypoints);
    connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this,
            &WimaController::_setStartIndex);
676

677
    emit missionItemsChanged();
678 679
    emit currentMissionItemsChanged();
    emit waypointPathChanged();
680
    emit currentWaypointPathChanged();
681

682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
    qWarning()
        << "WimaController::_switchWaypointManager: statistics update missing.";
  }
}

void WimaController::_initSmartRTL() {
  QString errorString;
  static int attemptCounter = 0;
  attemptCounter++;

  if (_checkSmartRTLPreCondition(errorString)) {
    _masterController->managerVehicle()->pauseVehicle();
    connect(masterController()->managerVehicle(), &Vehicle::flyingChanged, this,
            &WimaController::_smartRTLCleanUp);
    if (_rtlWM.update()) { // Calculate return path.
      _switchWaypointManager(_rtlWM);
      attemptCounter = 0;
      emit smartRTLPathConfirm();
      return;
    }
  } else if (attemptCounter > SMART_RTL_MAX_ATTEMPTS) {
    errorString.append(
        tr("Smart RTL: No success after maximum number of attempts."));
    qgcApp()->showMessage(errorString);
    attemptCounter = 0;
  } else {
    _smartRTLTimer.singleShot(SMART_RTL_ATTEMPT_INTERVAL, this,
                              &WimaController::_initSmartRTL);
  }
}

void WimaController::_DMFinishedHandler() {
  if (!_snakeDM.success()) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
715 716
    qDebug() << _snakeDM.errorMessage();
    // qgcApp()->showMessage(_snakeDM.errorMessage());
717 718 719 720 721 722 723 724 725 726 727 728 729 730
    return;
  }

  // Copy waypoints to waypoint manager.
  _snakeWM.clear();
  auto waypoints = _snakeDM.waypoints();
  if (waypoints.size() < 1) {
    return;
  }
  for (auto &vertex : waypoints) {
    _snakeWM.push_back(vertex);
  }

  // Do update.
Valentin Platzgummer's avatar
Valentin Platzgummer committed
731
  this->_snakeWM.update(); // this can take a while (ca. 200ms)
732

Valentin Platzgummer's avatar
Valentin Platzgummer committed
733 734 735 736 737 738 739
  emit snakeTilesChanged();
  emit snakeTileCenterPointsChanged();
  emit nemoProgressChanged();
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
}

void WimaController::_switchToSnakeWaypointManager(QVariant variant) {
  if (variant.value<bool>()) {
    _switchWaypointManager(_snakeWM);
  } else {
    _switchWaypointManager(_defaultWM);
  }
}

void WimaController::_switchDataManager(SnakeDataManager &dataManager) {
  if (_currentDM != &dataManager) {

    disconnect(_currentDM, &SnakeDataManager::finished, this,
               &WimaController::_DMFinishedHandler);
    disconnect(_currentDM, &SnakeDataManager::nemoProgressChanged, this,
               &WimaController::_progressChangedHandler);
    disconnect(_currentDM, &SnakeDataManager::nemoStatusChanged, this,
               &WimaController::nemoStatusChanged);
    disconnect(_currentDM, &SnakeDataManager::nemoStatusChanged, this,
               &WimaController::nemoStatusStringChanged);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
761 762
    disconnect(_currentDM, &SnakeDataManager::calcInProgressChanged, this,
               &WimaController::snakeCalcInProgressChanged);
763 764 765 766 767 768 769 770 771 772 773

    _currentDM = &dataManager;

    connect(_currentDM, &SnakeDataManager::finished, this,
            &WimaController::_DMFinishedHandler);
    connect(_currentDM, &SnakeDataManager::nemoProgressChanged, this,
            &WimaController::_progressChangedHandler);
    connect(_currentDM, &SnakeDataManager::nemoStatusChanged, this,
            &WimaController::nemoStatusChanged);
    connect(_currentDM, &SnakeDataManager::nemoStatusChanged, this,
            &WimaController::nemoStatusStringChanged);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
774 775
    connect(_currentDM, &SnakeDataManager::calcInProgressChanged, this,
            &WimaController::snakeCalcInProgressChanged);
776 777 778 779 780 781 782 783

    emit snakeCalcInProgressChanged();
    emit snakeTilesChanged();
    emit snakeTileCenterPointsChanged();
    emit nemoProgressChanged();
    emit nemoStatusChanged();
    emit nemoStatusStringChanged();
  }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
784 785
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
786
void WimaController::_progressChangedHandler() { _snakeDM.start(); }
787

788 789
void WimaController::_enableSnakeChangedHandler() {
  if (this->_enableSnake.rawValue().toBool()) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
790
    qDebug() << "WimaController: enabling snake.";
Valentin Platzgummer's avatar
Valentin Platzgummer committed
791
    _switchDataManager(this->_snakeDM);
792 793 794
    this->_snakeDM.enableRosBridge();
    _currentDM->start();
  } else {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
795
    qDebug() << "WimaController: disabling snake.";
796 797 798 799
    this->_snakeDM.disableRosBride();
    _switchDataManager(_emptyDM);
  }
}