SensorsComponentController.cc 16.9 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.
 *
 ****************************************************************************/

Don Gagne's avatar
Don Gagne committed
10 11 12 13 14 15

/// @file
///     @author Don Gagne <don@thegagnes.com>

#include "SensorsComponentController.h"
#include "QGCMAVLink.h"
16
#include "UAS.h"
17
#include "QGCApplication.h"
Don Gagne's avatar
Don Gagne committed
18 19 20 21

#include <QVariant>
#include <QQmlProperty>

22 23
QGC_LOGGING_CATEGORY(SensorsComponentControllerLog, "SensorsComponentControllerLog")

Don Gagne's avatar
Don Gagne committed
24
SensorsComponentController::SensorsComponentController(void) :
25 26
    _statusLog(NULL),
    _progressBar(NULL),
Don Gagne's avatar
Don Gagne committed
27 28 29 30
    _compassButton(NULL),
    _gyroButton(NULL),
    _accelButton(NULL),
    _airspeedButton(NULL),
31
    _levelButton(NULL),
Don Gagne's avatar
Don Gagne committed
32
    _cancelButton(NULL),
Don Gagne's avatar
Don Gagne committed
33
    _showOrientationCalArea(false),
34
    _gyroCalInProgress(false),
Don Gagne's avatar
Don Gagne committed
35 36 37 38 39 40 41 42
    _magCalInProgress(false),
    _accelCalInProgress(false),
    _orientationCalDownSideDone(false),
    _orientationCalUpsideDownSideDone(false),
    _orientationCalLeftSideDone(false),
    _orientationCalRightSideDone(false),
    _orientationCalNoseDownSideDone(false),
    _orientationCalTailDownSideDone(false),
Don Gagne's avatar
Don Gagne committed
43 44 45 46 47 48
    _orientationCalDownSideVisible(false),
    _orientationCalUpsideDownSideVisible(false),
    _orientationCalLeftSideVisible(false),
    _orientationCalRightSideVisible(false),
    _orientationCalNoseDownSideVisible(false),
    _orientationCalTailDownSideVisible(false),
Don Gagne's avatar
Don Gagne committed
49 50 51 52 53 54
    _orientationCalDownSideInProgress(false),
    _orientationCalUpsideDownSideInProgress(false),
    _orientationCalLeftSideInProgress(false),
    _orientationCalRightSideInProgress(false),
    _orientationCalNoseDownSideInProgress(false),
    _orientationCalTailDownSideInProgress(false),
Don Gagne's avatar
Don Gagne committed
55
    _orientationCalDownSideRotate(false),
56
    _orientationCalUpsideDownSideRotate(false),
Don Gagne's avatar
Don Gagne committed
57
    _orientationCalLeftSideRotate(false),
58
    _orientationCalRightSideRotate(false),
Don Gagne's avatar
Don Gagne committed
59
    _orientationCalNoseDownSideRotate(false),
60
    _orientationCalTailDownSideRotate(false),
Don Gagne's avatar
Don Gagne committed
61
    _unknownFirmwareVersion(false),
Don Gagne's avatar
Don Gagne committed
62
    _waitingForCancel(false)
Don Gagne's avatar
Don Gagne committed
63
{
64
}
Don Gagne's avatar
Don Gagne committed
65

66 67 68
bool SensorsComponentController::usingUDPLink(void)
{
    return _vehicle->priorityLink()->getLinkConfiguration()->type() == LinkConfiguration::TypeUdp;
Don Gagne's avatar
Don Gagne committed
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
}

/// Appends the specified text to the status log area in the ui
void SensorsComponentController::_appendStatusLog(const QString& text)
{
    Q_ASSERT(_statusLog);
    
    QVariant returnedValue;
    QVariant varText = text;
    QMetaObject::invokeMethod(_statusLog,
                              "append",
                              Q_RETURN_ARG(QVariant, returnedValue),
                              Q_ARG(QVariant, varText));
}

Don Gagne's avatar
Don Gagne committed
84
void SensorsComponentController::_startLogCalibration(void)
Don Gagne's avatar
Don Gagne committed
85
{
Don Gagne's avatar
Don Gagne committed
86
    _unknownFirmwareVersion = false;
87 88
    _hideAllCalAreas();
    
Don Gagne's avatar
Don Gagne committed
89 90 91 92 93 94 95
    connect(_uas, &UASInterface::textMessageReceived, this, &SensorsComponentController::_handleUASTextMessage);
    
    _cancelButton->setEnabled(false);
}

void SensorsComponentController::_startVisualCalibration(void)
{
96 97 98 99
    _compassButton->setEnabled(false);
    _gyroButton->setEnabled(false);
    _accelButton->setEnabled(false);
    _airspeedButton->setEnabled(false);
100
    _levelButton->setEnabled(false);
Don Gagne's avatar
Don Gagne committed
101
    _cancelButton->setEnabled(true);
102 103

    _resetInternalState();
Don Gagne's avatar
Don Gagne committed
104 105
    
    _progressBar->setProperty("value", 0);
106 107
}

108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
void SensorsComponentController::_resetInternalState(void)
{
    _orientationCalDownSideDone = true;
    _orientationCalUpsideDownSideDone = true;
    _orientationCalLeftSideDone = true;
    _orientationCalRightSideDone = true;
    _orientationCalTailDownSideDone = true;
    _orientationCalNoseDownSideDone = true;
    _orientationCalDownSideInProgress = false;
    _orientationCalUpsideDownSideInProgress = false;
    _orientationCalLeftSideInProgress = false;
    _orientationCalRightSideInProgress = false;
    _orientationCalNoseDownSideInProgress = false;
    _orientationCalTailDownSideInProgress = false;
    _orientationCalDownSideRotate = false;
    _orientationCalUpsideDownSideRotate = false;
    _orientationCalLeftSideRotate = false;
    _orientationCalRightSideRotate = false;
    _orientationCalNoseDownSideRotate = false;
    _orientationCalTailDownSideRotate = false;

    emit orientationCalSidesRotateChanged();
    emit orientationCalSidesDoneChanged();
    emit orientationCalSidesInProgressChanged();
}

Don Gagne's avatar
Don Gagne committed
134
void SensorsComponentController::_stopCalibration(SensorsComponentController::StopCalibrationCode code)
135
{
Don Gagne's avatar
Don Gagne committed
136
    disconnect(_uas, &UASInterface::textMessageReceived, this, &SensorsComponentController::_handleUASTextMessage);
Don Gagne's avatar
Don Gagne committed
137
    
138 139 140 141
    _compassButton->setEnabled(true);
    _gyroButton->setEnabled(true);
    _accelButton->setEnabled(true);
    _airspeedButton->setEnabled(true);
142
    _levelButton->setEnabled(true);
Don Gagne's avatar
Don Gagne committed
143 144 145
    _cancelButton->setEnabled(false);
    
    if (code == StopCalibrationSuccess) {
146
        _resetInternalState();
Don Gagne's avatar
Don Gagne committed
147 148 149 150 151
        
        _progressBar->setProperty("value", 1);
    } else {
        _progressBar->setProperty("value", 0);
    }
152
    
Don Gagne's avatar
Don Gagne committed
153 154 155
    _waitingForCancel = false;
    emit waitingForCancelChanged();

156 157
    _refreshParams();
    
Don Gagne's avatar
Don Gagne committed
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    switch (code) {
        case StopCalibrationSuccess:
            _orientationCalAreaHelpText->setProperty("text", "Calibration complete");
            emit resetStatusTextArea();
            if (_magCalInProgress) {
                emit setCompassRotations();
            }
            break;
            
        case StopCalibrationCancelled:
            emit resetStatusTextArea();
            _hideAllCalAreas();
            break;
            
        default:
            // Assume failed
            _hideAllCalAreas();
175
            qgcApp()->showMessage("Calibration failed. Calibration log will be displayed.");
Don Gagne's avatar
Don Gagne committed
176
            break;
177
    }
Don Gagne's avatar
Don Gagne committed
178 179 180 181
    
    _magCalInProgress = false;
    _accelCalInProgress = false;
    _gyroCalInProgress = false;
182 183 184 185
}

void SensorsComponentController::calibrateGyro(void)
{
Don Gagne's avatar
Don Gagne committed
186 187
    _startLogCalibration();
    _uas->startCalibration(UASInterface::StartCalibrationGyro);
Don Gagne's avatar
Don Gagne committed
188 189 190 191
}

void SensorsComponentController::calibrateCompass(void)
{
Don Gagne's avatar
Don Gagne committed
192 193
    _startLogCalibration();
    _uas->startCalibration(UASInterface::StartCalibrationMag);
Don Gagne's avatar
Don Gagne committed
194 195 196 197
}

void SensorsComponentController::calibrateAccel(void)
{
Don Gagne's avatar
Don Gagne committed
198 199
    _startLogCalibration();
    _uas->startCalibration(UASInterface::StartCalibrationAccel);
Don Gagne's avatar
Don Gagne committed
200 201
}

202 203 204 205 206 207
void SensorsComponentController::calibrateLevel(void)
{
    _startLogCalibration();
    _uas->startCalibration(UASInterface::StartCalibrationLevel);
}

Don Gagne's avatar
Don Gagne committed
208 209
void SensorsComponentController::calibrateAirspeed(void)
{
Don Gagne's avatar
Don Gagne committed
210 211
    _startLogCalibration();
    _uas->startCalibration(UASInterface::StartCalibrationAirspeed);
Don Gagne's avatar
Don Gagne committed
212 213 214 215 216 217 218
}

void SensorsComponentController::_handleUASTextMessage(int uasId, int compId, int severity, QString text)
{
    Q_UNUSED(compId);
    Q_UNUSED(severity);
    
219
    UASInterface* uas = _autopilot->vehicle()->uas();
Don Gagne's avatar
Don Gagne committed
220 221 222 223 224
    Q_ASSERT(uas);
    if (uasId != uas->getUASID()) {
        return;
    }
    
225 226 227 228 229 230 231 232 233 234 235
    if (text.contains("progress <")) {
        QString percent = text.split("<").last().split(">").first();
        bool ok;
        int p = percent.toInt(&ok);
        if (ok) {
            Q_ASSERT(_progressBar);
            _progressBar->setProperty("value", (float)(p / 100.0));
        }
        return;
    }

Don Gagne's avatar
Don Gagne committed
236
    _appendStatusLog(text);
237
    qCDebug(SensorsComponentControllerLog) << text;
Don Gagne's avatar
Don Gagne committed
238 239 240 241 242 243 244 245 246 247 248 249
    
    if (_unknownFirmwareVersion) {
        // We don't know how to do visual cal with the version of firwmare
        return;
    }
    
    // All calibration messages start with [cal]
    QString calPrefix("[cal] ");
    if (!text.startsWith(calPrefix)) {
        return;
    }
    text = text.right(text.length() - calPrefix.length());
250

Don Gagne's avatar
Don Gagne committed
251 252 253 254 255 256
    QString calStartPrefix("calibration started: ");
    if (text.startsWith(calStartPrefix)) {
        text = text.right(text.length() - calStartPrefix.length());
        
        // Split version number and cal type
        QStringList parts = text.split(" ");
257
        if (parts.count() != 2 && parts[0].toInt() != _supportedFirmwareCalVersion) {
Don Gagne's avatar
Don Gagne committed
258
            _unknownFirmwareVersion = true;
259 260 261
            QString msg = "Unsupported calibration firmware version, using log";
            _appendStatusLog(msg);
            qDebug() << msg;
Don Gagne's avatar
Don Gagne committed
262
            return;
Don Gagne's avatar
Don Gagne committed
263
        }
Don Gagne's avatar
Don Gagne committed
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
        
        _startVisualCalibration();
        
        text = parts[1];
        if (text == "accel" || text == "mag" || text == "gyro") {
            // Reset all progress indication
            _orientationCalDownSideDone = false;
            _orientationCalUpsideDownSideDone = false;
            _orientationCalLeftSideDone = false;
            _orientationCalRightSideDone = false;
            _orientationCalTailDownSideDone = false;
            _orientationCalNoseDownSideDone = false;
            _orientationCalDownSideInProgress = false;
            _orientationCalUpsideDownSideInProgress = false;
            _orientationCalLeftSideInProgress = false;
            _orientationCalRightSideInProgress = false;
            _orientationCalNoseDownSideInProgress = false;
            _orientationCalTailDownSideInProgress = false;
            
            // Reset all visibility
            _orientationCalDownSideVisible = false;
            _orientationCalUpsideDownSideVisible = false;
            _orientationCalLeftSideVisible = false;
            _orientationCalRightSideVisible = false;
            _orientationCalTailDownSideVisible = false;
            _orientationCalNoseDownSideVisible = false;
            
            _orientationCalAreaHelpText->setProperty("text", "Place your vehicle into one of the Incomplete orientations shown below and hold it still");
            
            if (text == "accel") {
                _accelCalInProgress = true;
                _orientationCalDownSideVisible = true;
                _orientationCalUpsideDownSideVisible = true;
                _orientationCalLeftSideVisible = true;
                _orientationCalRightSideVisible = true;
                _orientationCalTailDownSideVisible = true;
                _orientationCalNoseDownSideVisible = true;
            } else if (text == "mag") {
302 303 304 305 306 307 308 309 310 311 312 313

                // Work out what the autopilot is configured to
                int sides = 0;

                if (_autopilot->parameterExists(FactSystem::defaultComponentId, "CAL_MAG_SIDES")) {
                    // Read the requested calibration directions off the system
                    sides = _autopilot->getParameterFact(FactSystem::defaultComponentId, "CAL_MAG_SIDES")->rawValue().toFloat();
                } else {
                    // There is no valid setting, default to all six sides
                    sides = (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0);
                }

Don Gagne's avatar
Don Gagne committed
314
                _magCalInProgress = true;
315 316 317 318 319 320
                _orientationCalTailDownSideVisible =   ((sides & (1 << 0)) > 0);
                _orientationCalNoseDownSideVisible =   ((sides & (1 << 1)) > 0);
                _orientationCalLeftSideVisible =       ((sides & (1 << 2)) > 0);
                _orientationCalRightSideVisible =      ((sides & (1 << 3)) > 0);
                _orientationCalUpsideDownSideVisible = ((sides & (1 << 4)) > 0);
                _orientationCalDownSideVisible =       ((sides & (1 << 5)) > 0);
Don Gagne's avatar
Don Gagne committed
321 322 323 324 325 326 327 328 329 330
            } else if (text == "gyro") {
                _gyroCalInProgress = true;
                _orientationCalDownSideVisible = true;
            } else {
                Q_ASSERT(false);
            }
            emit orientationCalSidesDoneChanged();
            emit orientationCalSidesVisibleChanged();
            emit orientationCalSidesInProgressChanged();
            _updateAndEmitShowOrientationCalArea(true);
Don Gagne's avatar
Don Gagne committed
331
        }
Don Gagne's avatar
Don Gagne committed
332 333 334 335
        return;
    }
    
    if (text.endsWith("orientation detected")) {
Don Gagne's avatar
Don Gagne committed
336 337
        QString side = text.section(" ", 0, 0);
        qDebug() << "Side started" << side;
Don Gagne's avatar
Don Gagne committed
338
        
Don Gagne's avatar
Don Gagne committed
339 340
        if (side == "down") {
            _orientationCalDownSideInProgress = true;
Don Gagne's avatar
Don Gagne committed
341 342 343
            if (_magCalInProgress) {
                _orientationCalDownSideRotate = true;
            }
344
        } else if (side == "up") {
Don Gagne's avatar
Don Gagne committed
345
            _orientationCalUpsideDownSideInProgress = true;
346 347 348
            if (_magCalInProgress) {
                _orientationCalUpsideDownSideRotate = true;
            }
349
        } else if (side == "left") {
Don Gagne's avatar
Don Gagne committed
350
            _orientationCalLeftSideInProgress = true;
Don Gagne's avatar
Don Gagne committed
351 352 353
            if (_magCalInProgress) {
                _orientationCalLeftSideRotate = true;
            }
354
        } else if (side == "right") {
Don Gagne's avatar
Don Gagne committed
355
            _orientationCalRightSideInProgress = true;
356 357 358
            if (_magCalInProgress) {
                _orientationCalRightSideRotate = true;
            }
359
        } else if (side == "front") {
Don Gagne's avatar
Don Gagne committed
360
            _orientationCalNoseDownSideInProgress = true;
Don Gagne's avatar
Don Gagne committed
361 362 363
            if (_magCalInProgress) {
                _orientationCalNoseDownSideRotate = true;
            }
364
        } else if (side == "back") {
Don Gagne's avatar
Don Gagne committed
365
            _orientationCalTailDownSideInProgress = true;
366 367 368
            if (_magCalInProgress) {
                _orientationCalTailDownSideRotate = true;
            }
369
        }
Don Gagne's avatar
Don Gagne committed
370 371 372 373 374 375 376
        
        if (_magCalInProgress) {
            _orientationCalAreaHelpText->setProperty("text", "Rotate the vehicle continuously as shown in the diagram until marked as Completed");
        } else {
            _orientationCalAreaHelpText->setProperty("text", "Hold still in the current orientation");
        }
        
Don Gagne's avatar
Don Gagne committed
377
        emit orientationCalSidesInProgressChanged();
Don Gagne's avatar
Don Gagne committed
378 379 380 381 382
        emit orientationCalSidesRotateChanged();
        return;
    }
    
    if (text.endsWith("side done, rotate to a different side")) {
383 384
        QString side = text.section(" ", 0, 0);
        qDebug() << "Side finished" << side;
Don Gagne's avatar
Don Gagne committed
385
        
386
        if (side == "down") {
Don Gagne's avatar
Don Gagne committed
387 388
            _orientationCalDownSideInProgress = false;
            _orientationCalDownSideDone = true;
Don Gagne's avatar
Don Gagne committed
389
            _orientationCalDownSideRotate = false;
390
        } else if (side == "up") {
Don Gagne's avatar
Don Gagne committed
391 392
            _orientationCalUpsideDownSideInProgress = false;
            _orientationCalUpsideDownSideDone = true;
393
            _orientationCalUpsideDownSideRotate = false;
394
        } else if (side == "left") {
Don Gagne's avatar
Don Gagne committed
395 396
            _orientationCalLeftSideInProgress = false;
            _orientationCalLeftSideDone = true;
Don Gagne's avatar
Don Gagne committed
397
            _orientationCalLeftSideRotate = false;
398
        } else if (side == "right") {
Don Gagne's avatar
Don Gagne committed
399 400
            _orientationCalRightSideInProgress = false;
            _orientationCalRightSideDone = true;
401
            _orientationCalRightSideRotate = false;
402
        } else if (side == "front") {
Don Gagne's avatar
Don Gagne committed
403 404
            _orientationCalNoseDownSideInProgress = false;
            _orientationCalNoseDownSideDone = true;
Don Gagne's avatar
Don Gagne committed
405
            _orientationCalNoseDownSideRotate = false;
406
        } else if (side == "back") {
Don Gagne's avatar
Don Gagne committed
407 408
            _orientationCalTailDownSideInProgress = false;
            _orientationCalTailDownSideDone = true;
409
            _orientationCalTailDownSideRotate = false;
410
        }
Don Gagne's avatar
Don Gagne committed
411 412 413
        
        _orientationCalAreaHelpText->setProperty("text", "Place you vehicle into one of the orientations shown below and hold it still");

Don Gagne's avatar
Don Gagne committed
414 415
        emit orientationCalSidesInProgressChanged();
        emit orientationCalSidesDoneChanged();
Don Gagne's avatar
Don Gagne committed
416 417
        emit orientationCalSidesRotateChanged();
        return;
418
    }
419 420 421 422 423

    if (text.endsWith("side already completed")) {
        _orientationCalAreaHelpText->setProperty("text", "Orientation already completed, place you vehicle into one of the incomplete orientations shown below and hold it still");
        return;
    }
Don Gagne's avatar
Don Gagne committed
424
    
Don Gagne's avatar
Don Gagne committed
425 426 427 428
    QString calCompletePrefix("calibration done:");
    if (text.startsWith(calCompletePrefix)) {
        _stopCalibration(StopCalibrationSuccess);
        return;
429
    }
Don Gagne's avatar
Don Gagne committed
430 431 432 433
    
    if (text.startsWith("calibration cancelled")) {
        _stopCalibration(_waitingForCancel ? StopCalibrationCancelled : StopCalibrationFailed);
        return;
434 435
    }
    
Don Gagne's avatar
Don Gagne committed
436 437 438 439 440 441 442 443
    if (text.startsWith("calibration failed")) {
        _stopCalibration(StopCalibrationFailed);
        return;
    }
}

void SensorsComponentController::_refreshParams(void)
{
Don Gagne's avatar
Don Gagne committed
444 445 446 447
    QStringList fastRefreshList;
    
    // We ask for a refresh on these first so that the rotation combo show up as fast as possible
    fastRefreshList << "CAL_MAG0_ID" << "CAL_MAG1_ID" << "CAL_MAG2_ID" << "CAL_MAG0_ROT" << "CAL_MAG1_ROT" << "CAL_MAG2_ROT";
448
    foreach (const QString &paramName, fastRefreshList) {
Don Gagne's avatar
Don Gagne committed
449 450 451 452
        _autopilot->refreshParameter(FactSystem::defaultComponentId, paramName);
    }
    
    // Now ask for all to refresh
453 454
    _autopilot->refreshParametersPrefix(FactSystem::defaultComponentId, "CAL_");
    _autopilot->refreshParametersPrefix(FactSystem::defaultComponentId, "SENS_");
Don Gagne's avatar
Don Gagne committed
455 456
}

Don Gagne's avatar
Don Gagne committed
457
void SensorsComponentController::_updateAndEmitShowOrientationCalArea(bool show)
458
{
Don Gagne's avatar
Don Gagne committed
459 460
    _showOrientationCalArea = show;
    emit showOrientationCalAreaChanged();
461 462 463 464
}

void SensorsComponentController::_hideAllCalAreas(void)
{
Don Gagne's avatar
Don Gagne committed
465 466 467
    _updateAndEmitShowOrientationCalArea(false);
}

Don Gagne's avatar
Don Gagne committed
468
void SensorsComponentController::cancelCalibration(void)
Don Gagne's avatar
Don Gagne committed
469
{
Don Gagne's avatar
Don Gagne committed
470 471 472 473 474 475
    // The firmware doesn't allow us to cancel calibration. The best we can do is wait
    // for it to timeout.
    _waitingForCancel = true;
    emit waitingForCancelChanged();
    _cancelButton->setEnabled(false);
    _uas->stopCalibration();
476
}