MissionSettingsItem.cc 11.5 KB
Newer Older
1 2 3 4 5 6 7 8 9
/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

10
#include "MissionSettingsItem.h"
11 12 13 14 15 16 17
#include "JsonHelper.h"
#include "MissionController.h"
#include "QGCGeo.h"
#include "QGroundControlQmlGlobal.h"
#include "SimpleMissionItem.h"
#include "SettingsManager.h"
#include "AppSettings.h"
18
#include "MissionCommandUIInfo.h"
19 20 21 22 23

#include <QPolygonF>

QGC_LOGGING_CATEGORY(MissionSettingsComplexItemLog, "MissionSettingsComplexItemLog")

24
const char* MissionSettingsItem::jsonComplexItemTypeValue = "MissionSettings";
25

DonLakeFlyer's avatar
DonLakeFlyer committed
26
const char* MissionSettingsItem::_plannedHomePositionAltitudeName = "PlannedHomePositionAltitude";
27

28
QMap<QString, FactMetaData*> MissionSettingsItem::_metaDataMap;
29

30
MissionSettingsItem::MissionSettingsItem(Vehicle* vehicle, bool planView, QObject* parent)
31
    : ComplexMissionItem                (vehicle, parent)
32
    , _planView                         (planView)
33
    , _plannedHomePositionAltitudeFact  (0, _plannedHomePositionAltitudeName,   FactMetaData::valueTypeDouble)
34
    , _plannedHomePositionFromVehicle   (false)
35 36 37 38 39
    , _missionEndRTL                    (false)
    , _cameraSection                    (vehicle)
    , _speedSection                     (vehicle)
    , _sequenceNumber                   (0)
    , _dirty                            (false)
40 41 42 43 44 45 46 47 48 49 50
{
    _editorQml = "qrc:/qml/MissionSettingsEditor.qml";

    if (_metaDataMap.isEmpty()) {
        _metaDataMap = FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/MissionSettings.FactMetaData.json"), NULL /* metaDataParent */);
    }

    _plannedHomePositionAltitudeFact.setMetaData    (_metaDataMap[_plannedHomePositionAltitudeName]);
    _plannedHomePositionAltitudeFact.setRawValue    (_plannedHomePositionAltitudeFact.rawDefaultValue());
    setHomePositionSpecialCase(true);

51 52 53
    _cameraSection.setAvailable(true);
    _speedSection.setAvailable(true);

54
    connect(this,               &MissionSettingsItem::specifyMissionFlightSpeedChanged, this, &MissionSettingsItem::_setDirtyAndUpdateLastSequenceNumber);
55
    connect(this,               &MissionSettingsItem::missionEndRTLChanged,             this, &MissionSettingsItem::_setDirtyAndUpdateLastSequenceNumber);
56 57
    connect(&_cameraSection,    &CameraSection::itemCountChanged,                       this, &MissionSettingsItem::_setDirtyAndUpdateLastSequenceNumber);
    connect(&_speedSection,     &CameraSection::itemCountChanged,                       this, &MissionSettingsItem::_setDirtyAndUpdateLastSequenceNumber);
58

59
    connect(this,               &MissionSettingsItem::terrainAltitudeChanged,           this, &MissionSettingsItem::_setHomeAltFromTerrain);
60

61
    connect(&_plannedHomePositionAltitudeFact,  &Fact::rawValueChanged,                 this, &MissionSettingsItem::_updateAltitudeInCoordinate);
62

63 64
    connect(&_cameraSection,    &CameraSection::dirtyChanged,   this, &MissionSettingsItem::_sectionDirtyChanged);
    connect(&_speedSection,     &SpeedSection::dirtyChanged,    this, &MissionSettingsItem::_sectionDirtyChanged);
DonLakeFlyer's avatar
DonLakeFlyer committed
65

66 67 68
    connect(&_cameraSection,    &CameraSection::specifiedGimbalYawChanged,      this, &MissionSettingsItem::specifiedGimbalYawChanged);
    connect(&_cameraSection,    &CameraSection::specifiedGimbalPitchChanged,    this, &MissionSettingsItem::specifiedGimbalPitchChanged);
    connect(&_speedSection,     &SpeedSection::specifiedFlightSpeedChanged,     this, &MissionSettingsItem::specifiedFlightSpeedChanged);
69 70
}

71
int MissionSettingsItem::lastSequenceNumber(void) const
72
{
73
    int lastSequenceNumber = _sequenceNumber;
74

75 76
    lastSequenceNumber += _cameraSection.itemCount();
    lastSequenceNumber += _speedSection.itemCount();
77 78 79 80

    return lastSequenceNumber;
}

81
void MissionSettingsItem::setDirty(bool dirty)
82 83 84
{
    if (_dirty != dirty) {
        _dirty = dirty;
85 86 87 88
        if (!dirty) {
            _cameraSection.setDirty(false);
            _speedSection.setDirty(false);
        }
89 90 91 92
        emit dirtyChanged(_dirty);
    }
}

93
void MissionSettingsItem::save(QJsonArray&  missionItems)
94
{
95 96 97
    QList<MissionItem*> items;

    appendMissionItems(items, this);
98

Patrick José Pereira's avatar
Patrick José Pereira committed
99
    // First item show be planned home position, we are not responsible for save/load
100
    // Remaining items we just output as is
101 102
    for (int i=1; i<items.count(); i++) {
        MissionItem* item = items[i];
103 104 105
        QJsonObject saveObject;
        item->save(saveObject);
        missionItems.append(saveObject);
106
        item->deleteLater();
107 108 109
    }
}

110
void MissionSettingsItem::setSequenceNumber(int sequenceNumber)
111 112 113 114 115 116 117 118
{
    if (_sequenceNumber != sequenceNumber) {
        _sequenceNumber = sequenceNumber;
        emit sequenceNumberChanged(sequenceNumber);
        emit lastSequenceNumberChanged(lastSequenceNumber());
    }
}

119
bool MissionSettingsItem::load(const QJsonObject& complexObject, int sequenceNumber, QString& errorString)
120 121 122 123 124 125 126 127
{
    Q_UNUSED(complexObject);
    Q_UNUSED(sequenceNumber);
    Q_UNUSED(errorString);

    return true;
}

128
double MissionSettingsItem::greatestDistanceTo(const QGeoCoordinate &other) const
129 130 131 132 133
{
    Q_UNUSED(other);
    return 0;
}

134
bool MissionSettingsItem::specifiesCoordinate(void) const
135
{
DonLakeFlyer's avatar
DonLakeFlyer committed
136
    return true;
137 138
}

139
void MissionSettingsItem::appendMissionItems(QList<MissionItem*>& items, QObject* missionItemParent)
140 141 142
{
    int seqNum = _sequenceNumber;

143
    // IMPORTANT NOTE: If anything changes here you must also change MissionSettingsItem::scanForMissionSettings
144 145 146 147 148 149 150 151 152

    // Planned home position
    MissionItem* item = new MissionItem(seqNum++,
                                        MAV_CMD_NAV_WAYPOINT,
                                        MAV_FRAME_GLOBAL,
                                        0,                      // Hold time
                                        0,                      // Acceptance radius
                                        0,                      // Not sure?
                                        0,                      // Yaw
153 154
                                        coordinate().latitude(),
                                        coordinate().longitude(),
155 156 157
                                        _plannedHomePositionAltitudeFact.rawValue().toDouble(),
                                        true,                   // autoContinue
                                        false,                  // isCurrentItem
158 159
                                        missionItemParent);
    items.append(item);
160

161 162
    _cameraSection.appendSectionItems(items, missionItemParent, seqNum);
    _speedSection.appendSectionItems(items, missionItemParent, seqNum);
163 164
}

165
bool MissionSettingsItem::addMissionEndAction(QList<MissionItem*>& items, int seqNum, QObject* missionItemParent)
166 167 168
{
    MissionItem* item = NULL;

169
    // IMPORTANT NOTE: If anything changes here you must also change MissionSettingsItem::scanForMissionSettings
170

171
    if (_missionEndRTL) {
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
        qCDebug(MissionSettingsComplexItemLog) << "Appending end action RTL seqNum" << seqNum;
        item = new MissionItem(seqNum,
                               MAV_CMD_NAV_RETURN_TO_LAUNCH,
                               MAV_FRAME_MISSION,
                               0, 0, 0, 0, 0, 0, 0,        // param 1-7 not used
                               true,                       // autoContinue
                               false,                      // isCurrentItem
                               missionItemParent);
        items.append(item);
        return true;
    } else {
        return false;
    }
}

187
bool MissionSettingsItem::scanForMissionSettings(QmlObjectListModel* visualItems, int scanIndex)
188
{
189
    bool foundSpeedSection = false;
190 191
    bool foundCameraSection = false;

192
    qCDebug(MissionSettingsComplexItemLog) << "MissionSettingsItem::scanForMissionSettings count:scanIndex" << visualItems->count() << scanIndex;
193 194

    // Scan through the initial mission items for possible mission settings
195 196
    foundCameraSection = _cameraSection.scanForSection(visualItems, scanIndex);
    foundSpeedSection = _speedSection.scanForSection(visualItems, scanIndex);
197

198 199 200 201 202 203 204
    // Look at the end of the mission for end actions

    int lastIndex = visualItems->count() - 1;
    SimpleMissionItem* item = visualItems->value<SimpleMissionItem*>(lastIndex);
    if (item) {
        MissionItem& missionItem = item->missionItem();

Don Gagne's avatar
Don Gagne committed
205
        if (missionItem.command() == MAV_CMD_NAV_RETURN_TO_LAUNCH &&
206 207
                missionItem.param1() == 0 && missionItem.param2() == 0 && missionItem.param3() == 0 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) {
            qCDebug(MissionSettingsComplexItemLog) << "Scan: Found end action RTL";
208
            _missionEndRTL = true;
209
            visualItems->removeAt(lastIndex)->deleteLater();
210 211 212
        }
    }

213
    return foundSpeedSection || foundCameraSection;
214 215
}

216
double MissionSettingsItem::complexDistance(void) const
217 218 219 220
{
    return 0;
}

221
void MissionSettingsItem::_setDirty(void)
222 223 224 225
{
    setDirty(true);
}

226 227 228 229 230 231
void MissionSettingsItem::setHomePositionFromVehicle(const QGeoCoordinate& coordinate)
{
    _plannedHomePositionFromVehicle = true;
    setCoordinate(coordinate);
}

232
void MissionSettingsItem::setCoordinate(const QGeoCoordinate& coordinate)
233
{
234
    if (_plannedHomePositionCoordinate != coordinate) {
235
        // ArduPilot tends to send crap home positions at initial vehicel boot, discard them
Don Gagne's avatar
Don Gagne committed
236
        if (coordinate.isValid() && (coordinate.latitude() != 0 || coordinate.longitude() != 0)) {
237 238 239 240 241
            _plannedHomePositionCoordinate = coordinate;
            emit coordinateChanged(coordinate);
            emit exitCoordinateChanged(coordinate);
            _plannedHomePositionAltitudeFact.setRawValue(coordinate.altitude());
        }
242 243 244
    }
}

245
void MissionSettingsItem::_setDirtyAndUpdateLastSequenceNumber(void)
246 247 248 249 250
{
    emit lastSequenceNumberChanged(lastSequenceNumber());
    setDirty(true);
}

251
void MissionSettingsItem::_sectionDirtyChanged(bool dirty)
252 253 254 255 256
{
    if (dirty) {
        setDirty(true);
    }
}
DonLakeFlyer's avatar
DonLakeFlyer committed
257

258
double MissionSettingsItem::specifiedGimbalYaw(void)
DonLakeFlyer's avatar
DonLakeFlyer committed
259 260 261
{
    return _cameraSection.specifyGimbal() ? _cameraSection.gimbalYaw()->rawValue().toDouble() : std::numeric_limits<double>::quiet_NaN();
}
262

263 264 265 266 267
double MissionSettingsItem::specifiedGimbalPitch(void)
{
    return _cameraSection.specifyGimbal() ? _cameraSection.gimbalPitch()->rawValue().toDouble() : std::numeric_limits<double>::quiet_NaN();
}

268 269 270 271 272 273 274 275 276 277 278
void MissionSettingsItem::_updateAltitudeInCoordinate(QVariant value)
{
    double newAltitude = value.toDouble();

    if (!qFuzzyCompare(_plannedHomePositionCoordinate.altitude(), newAltitude)) {

        _plannedHomePositionCoordinate.setAltitude(newAltitude);
        emit coordinateChanged(_plannedHomePositionCoordinate);
        emit exitCoordinateChanged(_plannedHomePositionCoordinate);
    }
}
279 280 281 282 283 284 285 286 287

double MissionSettingsItem::specifiedFlightSpeed(void)
{
    if (_speedSection.specifyFlightSpeed()) {
        return _speedSection.flightSpeed()->rawValue().toDouble();
    } else {
        return std::numeric_limits<double>::quiet_NaN();
    }
}
288 289 290 291 292 293 294 295

void MissionSettingsItem::setMissionEndRTL(bool missionEndRTL)
{
    if (missionEndRTL != _missionEndRTL) {
        _missionEndRTL = missionEndRTL;
        emit missionEndRTLChanged(missionEndRTL);
    }
}
296 297 298 299 300 301 302

void MissionSettingsItem::_setHomeAltFromTerrain(double terrainAltitude)
{
    if (!_plannedHomePositionFromVehicle) {
        _plannedHomePositionAltitudeFact.setRawValue(terrainAltitude);
    }
}
303 304 305 306 307

QString MissionSettingsItem::abbreviation(void) const
{
    return _planView ? tr("Planned Home") : tr("H");
}