HSIDisplay.cc 54.9 KB
Newer Older
1
2
/*=====================================================================

3
QGroundControl Open Source Ground Control Station
4

5
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
6

7
This file is part of the QGROUNDCONTROL project
8

9
    QGROUNDCONTROL is free software: you can redistribute it and/or modify
10
11
12
13
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

14
    QGROUNDCONTROL is distributed in the hope that it will be useful,
15
16
17
18
19
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
20
    along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
21
22
23
24
25
26
27
28
29
30
31
32
33

======================================================================*/

/**
 * @file
 *   @brief Implementation of Horizontal Situation Indicator class
 *
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QFile>
#include <QStringList>
34
#include <QPainter>
35
36
37
#include <QGraphicsScene>
#include <QHBoxLayout>
#include <QDoubleSpinBox>
38
39
#include <QDebug>

40
41
#include "UASManager.h"
#include "HSIDisplay.h"
42
#include "QGC.h"
pixhawk's avatar
pixhawk committed
43
#include "Waypoint.h"
44
#include "UASWaypointManager.h"
45
#include <qmath.h>
46
#include "MAV2DIcon.h"
47
#include "QGCApplication.h"
48

49
HSIDisplay::HSIDisplay(QWidget *parent) :
50
    HDDisplay(QStringList(), "HSI", parent),
51
52
53
54
55
56
57
    dragStarted(false),
    leftDragStarted(false),
    mouseHasMoved(false),
    startX(0.0f),
    startY(0.0f),
    actionPending(false),
    directSending(false),
58
59
60
61
62
63
64
65
66
    gpsSatellites(),
    satellitesUsed(0),
    attXSet(0.0f),
    attYSet(0.0f),
    attYawSet(0.0f),
    altitudeSet(1.0f),
    posXSet(0.0f),
    posYSet(0.0f),
    posZSet(0.0f),
pixhawk's avatar
pixhawk committed
67
68
    attXSaturation(0.2f),
    attYSaturation(0.2f),
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
    attYawSaturation(0.5f),
    posXSaturation(0.05f),
    posYSaturation(0.05f),
    altitudeSaturation(1.0f),
    lat(0.0f),
    lon(0.0f),
    alt(0.0f),
    globalAvailable(0),
    x(0.0f),
    y(0.0f),
    z(0.0f),
    vx(0.0f),
    vy(0.0f),
    vz(0.0f),
    speed(0.0f),
    localAvailable(0),
    roll(0.0f),
    pitch(0.0f),
    yaw(0.0f),
    bodyXSetCoordinate(0.0f),
    bodyYSetCoordinate(0.0f),
    bodyZSetCoordinate(0.0f),
    bodyYawSet(0.0f),
    uiXSetCoordinate(0.0f),
    uiYSetCoordinate(0.0f),
LM's avatar
LM committed
94
    uiZSetCoordinate(0.0f),
95
96
    uiYawSet(0.0f),
    metricWidth(4.0),
97
    crosstrackError(std::numeric_limits<double>::quiet_NaN()),
98
99
    xCenterPos(0),
    yCenterPos(0),
100
101
102
103
104
105
106
107
108
    positionLock(false),
    attControlEnabled(false),
    xyControlEnabled(false),
    zControlEnabled(false),
    yawControlEnabled(false),
    positionFix(0),
    gpsFix(0),
    visionFix(0),
    laserFix(0),
109
    iruFix(0),
110
    mavInitialized(false),
111
112
    topMargin(20.0f),
    bottomMargin(14.0f),
113
114
115
116
117
118
119
120
    attControlKnown(false),
    xyControlKnown(false),
    zControlKnown(false),
    yawControlKnown(false),
    positionFixKnown(false),
    visionFixKnown(false),
    gpsFixKnown(false),
    iruFixKnown(false),
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
    gyroKnown(false),
    gyroON(false),
    gyroOK(false),
    accelKnown(false),
    accelON(false),
    accelOK(false),
    magKnown(false),
    magON(false),
    magOK(false),
    pressureKnown(false),
    pressureON(false),
    pressureOK(false),
    diffPressureKnown(false),
    diffPressureON(false),
    diffPressureOK(false),
    flowKnown(false),
    flowON(false),
    flowOK(false),
    laserKnown(false),
    laserON(false),
    laserOK(false),
    viconKnown(false),
    viconON(false),
    viconOK(false),
    actuatorsKnown(false),
    actuatorsON(false),
147
148
149
150
151
152
153
    actuatorsOK(false),
    setPointKnown(false),
    positionSetPointKnown(false),
    userSetPointSet(false),
    userXYSetPointSet(false),
    userZSetPointSet(false),
    userYawSetPointSet(false)
154
{
155
    refreshTimer->setInterval(updateInterval);
156

pixhawk's avatar
pixhawk committed
157
    columns = 1;
158
    this->setAutoFillBackground(true);
159
160
161
    QPalette pal = palette();
    pal.setColor(backgroundRole(), QGC::colorBlack);
    setPalette(pal);
162

163
    vwidth = 80.0f;
164
    vheight = 100.0f;
pixhawk's avatar
pixhawk committed
165

166
    xCenterPos = vwidth/2.0f;
pixhawk's avatar
pixhawk committed
167
    yCenterPos = vheight/2.0f + topMargin - bottomMargin;
168

169
170
171
    uas = NULL;
    resetMAVState();

172
173
    // Do first update
    setMetricWidth(metricWidth);
174
175
176
    // Set tooltip
    setToolTip(tr("View from top in body frame. Scroll with mouse wheel to change the horizontal field of view of the widget."));
    setStatusTip(tr("View from top in body frame. Scroll with mouse wheel to change the horizontal field of view of the widget."));
177

178
179
    // XXX this looks a potential recursive issue
    //connect(&statusClearTimer, SIGNAL(timeout()), this, SLOT(clearStatusMessage()));
180

181
182
183
184
    if (UASManager::instance()->getActiveUAS())
    {
        setActiveUAS(UASManager::instance()->getActiveUAS());
    }
185

186
187
    connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
            this, SLOT(setActiveUAS(UASInterface*)));
188

189
190
    connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
            this, SLOT(setActiveUAS(UASInterface*)));
191

192
    setFocusPolicy(Qt::StrongFocus);
193
194
}

195
196
197
198
199
HSIDisplay::~HSIDisplay()
{

}

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
void HSIDisplay::resetMAVState()
{
    mavInitialized = false;
    attControlKnown = false;
    attControlEnabled = false;
    xyControlKnown = false;
    xyControlEnabled = false;
    zControlKnown = false;
    zControlEnabled = false;
    yawControlKnown = false;
    yawControlEnabled = false;

    // Draw position lock indicators
    positionFixKnown = false;
    positionFix = 0;
    visionFixKnown = false;
    visionFix = 0;
    gpsFixKnown = false;
    gpsFix = 0;
    iruFixKnown = false;
    iruFix = 0;

    // Data
    setPointKnown = false;
    localAvailable = 0;
    globalAvailable = 0;
226
227
228
229

    // Setpoints
    positionSetPointKnown = false;
    setPointKnown = false;
230
231
}

lm's avatar
lm committed
232
233
234
235
void HSIDisplay::paintEvent(QPaintEvent * event)
{
    Q_UNUSED(event);
    //paintGL();
236
237
238
    //    static quint64 interval = 0;
    //    //qDebug() << "INTERVAL:" << MG::TIME::getGroundTimeNow() - interval << __FILE__ << __LINE__;
    //    interval = MG::TIME::getGroundTimeNow();
239
    renderOverlay();
lm's avatar
lm committed
240
241
}

242
void HSIDisplay::renderOverlay()
243
{
244
    if (!isVisible() || !uas) return;
245
246
247
#if (QGC_EVENTLOOP_DEBUG)
    qDebug() << "EVENTLOOP:" << __FILE__ << __LINE__;
#endif
lm's avatar
lm committed
248
249
    // Center location of the HSI gauge items

250
    //float bottomMargin = 3.0f;
lm's avatar
lm committed
251
252

    // Size of the ring instrument
pixhawk's avatar
pixhawk committed
253
    //const float margin = 0.1f;  // 10% margin of total width on each side
254
    float baseRadius = (vheight - topMargin - bottomMargin) / 2.0f - (topMargin + bottomMargin) / 2.8f;
255

256
257
258
259
260
261
262
263
    // Draw instruments
    // TESTING THIS SHOULD BE MOVED INTO A QGRAPHICSVIEW
    // Update scaling factor
    // adjust scaling to fit both horizontally and vertically
    scalingFactor = this->width()/vwidth;
    double scalingFactorH = this->height()/vheight;
    if (scalingFactorH < scalingFactor) scalingFactor = scalingFactorH;

264
    QPainter painter(viewport());
265
266
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
267

lm's avatar
lm committed
268
269
    // Draw base instrument
    // ----------------------
lm's avatar
lm committed
270
    painter.setBrush(Qt::NoBrush);
271
272
273
274
275
276
277
278
279
280

    // Set the color scheme depending on the light/dark theme employed.
    QColor ringColor;
    QColor positionColor;
    QColor setpointColor;
    QColor labelColor;
    QColor valueColor;
    QColor statusColor;
    QColor waypointLineColor;
    QColor attitudeColor;
281
    if (qgcApp()->styleIsDark())
282
    {
283
        ringColor = QColor(255, 255, 255);
284
285
        positionColor = QColor(20, 20, 200);
        setpointColor = QColor(150, 250, 150);
286
287
        labelColor = QGC::colorCyan;
        valueColor = QColor(255, 255, 255);
288
        statusColor = QGC::colorOrange;
289
        waypointLineColor = QGC::colorYellow;
290
291
292
293
        attitudeColor = QColor(200, 20, 20);
    }
    else
    {
294
        ringColor = QGC::colorBlack;
295
296
        positionColor = QColor(20, 20, 200);
        setpointColor = QColor(150, 250, 150);
297
298
        labelColor = QColor(26, 75, 95);
        valueColor = QColor(40, 40, 40);
299
        statusColor = QGC::colorOrange;
300
        waypointLineColor = QGC::colorDarkYellow;
301
302
303
        attitudeColor = QColor(200, 20, 20);
    }

lm's avatar
lm committed
304
305
    QPen pen;
    pen.setColor(ringColor);
306
    pen.setWidth(refLineWidthToPen(1.0f));
lm's avatar
lm committed
307
    painter.setPen(pen);
lm's avatar
lm committed
308
    const int ringCount = 2;
309
310
    for (int i = 0; i < ringCount; i++)
    {
311
        float radius = (vwidth - (topMargin + bottomMargin)*0.3f) / (1.35f * i+1) / 2.0f - bottomMargin / 2.0f;
312
        drawCircle(xCenterPos, yCenterPos, radius, 1.0f, ringColor, &painter);
313
        paintText(tr("%1 m").arg(refToMetric(radius), 5, 'f', 1, ' '), valueColor, 1.6f, vwidth/2-4, vheight/2+radius+7, &painter);
lm's avatar
lm committed
314
315
    }

316
317
318
    // Draw orientation labels
    // Translate and rotate coordinate frame
    painter.translate((xCenterPos)*scalingFactor, (yCenterPos)*scalingFactor);
319
320
321
    const float yawDeg = ((yaw/M_PI)*180.0f);
    int yawRotate = static_cast<int>(yawDeg) % 360;
    painter.rotate(-yawRotate);
322
323
    paintText(tr("N"), ringColor, 3.5f, - 1.0f, - baseRadius - 5.5f, &painter);
    paintText(tr("S"), ringColor, 3.5f, - 1.0f, + baseRadius + 1.5f, &painter);
324
    paintText(tr("E"), ringColor, 3.5f, + baseRadius + 3.0f, - 1.25f, &painter);
325
    paintText(tr("W"), ringColor, 3.5f, - baseRadius - 5.5f, - 1.75f, &painter);
326
    painter.rotate(+yawRotate);
327
328
    painter.translate(-(xCenterPos)*scalingFactor, -(yCenterPos)*scalingFactor);

329
    // Draw trail
330
331
332
333
334
335
    //    QPointF m(bodyXSetCoordinate, bodyYSetCoordinate);
    //    // Transform from body to world coordinates
    //    m = metricWorldToBody(m);
    //    // Scale from metric body to screen reference units
    //    QPointF s = metricBodyToRef(m);
    //    drawLine(s.x(), s.y(), xCenterPos, yCenterPos, 1.5f, uas->getColor(), &painter);
336
337


lm's avatar
lm committed
338
    // Draw center indicator
339
340
341
342
343
    //    QPolygonF p(3);
    //    p.replace(0, QPointF(xCenterPos, yCenterPos-4.0f));
    //    p.replace(1, QPointF(xCenterPos-4.0f, yCenterPos+3.5f));
    //    p.replace(2, QPointF(xCenterPos+4.0f, yCenterPos+3.5f));
    //    drawPolygon(p, &painter);
344

345
346
    if (uas)
    {
347
348
349
        // Translate to center
        painter.translate((xCenterPos)*scalingFactor, (yCenterPos)*scalingFactor);
        QColor uasColor = uas->getColor();
350
        MAV2DIcon::drawAirframePolygon(uas->getAirframe(), painter, static_cast<int>((vwidth/4.0f)*scalingFactor*1.1f), uasColor, 0.0f);
lm's avatar
lm committed
351
        //MAV2DIcon::drawAirframePolygon(uas->getAirframe(), painter, static_cast<int>((vwidth/4.0f)*scalingFactor*1.1f), uasColor, 0.0f);
352
353
354
        // Translate back
        painter.translate(-(xCenterPos)*scalingFactor, -(yCenterPos)*scalingFactor);
    }
lm's avatar
lm committed
355
356

    // ----------------------
pixhawk's avatar
pixhawk committed
357

358
359
360
    // Draw satellites
    drawGPS(painter);

pixhawk's avatar
pixhawk committed
361
362
363
    // Draw state indicator

    // Draw position
364
    drawPositionDirection(xCenterPos, yCenterPos, baseRadius, positionColor, &painter);
lm's avatar
lm committed
365
366

    // Draw attitude
367
    drawAttitudeDirection(xCenterPos, yCenterPos, baseRadius, attitudeColor, &painter);
pixhawk's avatar
pixhawk committed
368
369


370
    // Draw position setpoints in body coordinates
lm's avatar
lm committed
371

372
373
374
375
376
377
    float xSpDiff = uiXSetCoordinate - bodyXSetCoordinate;
    float ySpDiff = uiYSetCoordinate - bodyYSetCoordinate;
    float zSpDiff = uiZSetCoordinate - bodyZSetCoordinate;

    float setPointDist = sqrt(xSpDiff*xSpDiff + ySpDiff*ySpDiff + zSpDiff*zSpDiff);

378
379
380
381
    float angleDiff = uiYawSet - bodyYawSet;

    float normAngleDiff = fabs(atan2(sin(angleDiff), cos(angleDiff)));

382
383
384
385
386
    // Labels on outer part and bottom

    // Draw waypoints
    drawWaypoints(painter);

387
    // Draw status flags
388
389
390
391
392
    drawStatusFlag(1,  1, tr("RAT"), rateControlEnabled, rateControlKnown, painter);
    drawStatusFlag(17, 1, tr("ATT"), attControlEnabled, attControlKnown, painter);
    drawStatusFlag(33, 1, tr("PXY"), xyControlEnabled,  xyControlKnown,  painter);
    drawStatusFlag(49, 1, tr("PZ"),  zControlEnabled,   zControlKnown,   painter);
    drawStatusFlag(65, 1, tr("YAW"), yawControlEnabled, yawControlKnown, painter);
393

394
    // Draw position lock indicators
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
    drawPositionLock(1,  6, tr("POS"), positionFix, positionFixKnown, painter);
    drawPositionLock(17, 6, tr("GPS"), gpsFix,      gpsFixKnown,      painter);
    drawStatusFlag(33,   6, tr("FLO"), flowON, flowKnown, flowOK, painter);
    drawPositionLock(49, 6, tr("VIS"), visionFix,   visionFixKnown,   painter);
    drawPositionLock(65, 6, tr("IRU"), iruFix,      iruFixKnown,      painter);

    drawStatusFlag(1,   11, tr("GYR"), gyroON, gyroKnown, gyroOK, painter);
    drawStatusFlag(17,  11, tr("ACC"), accelON, accelKnown, accelOK, painter);
    drawStatusFlag(33,  11, tr("MAG"), magON, magKnown, magOK, painter);
    drawStatusFlag(49,  11, tr("BAR"), pressureON, pressureKnown, pressureOK, painter);
    drawStatusFlag(65,  11, tr("PIT"), diffPressureON, diffPressureKnown, diffPressureOK, painter);

    drawStatusFlag(1, 16, tr("ACT"), actuatorsON, actuatorsKnown, actuatorsOK, painter);
    drawStatusFlag(17, 16, tr("LAS"), laserON, laserKnown, laserOK, painter);
    drawStatusFlag(33, 16, tr("VCN"), viconON, viconKnown, viconOK, painter);
410
411

    // Draw speed to top left
412
413
    paintText(tr("SPEED"), labelColor, 2.2f, 2, topMargin+2, &painter);
    paintText(tr("%1 m/s").arg(speed, 5, 'f', 2, '0'), valueColor, 2.2f, 12, topMargin+2, &painter);
414
415

    // Draw crosstrack error to top right
416
    paintText(tr("XTRACK"), labelColor, 2.2f, 54, topMargin+2, &painter);
417
418
419
420
421
422
    if (!isnan(crosstrackError)) {
        paintText(tr("%1 m").arg(crosstrackError, 5, 'f', 2, '0'), valueColor, 2.2f, 67, topMargin+2, &painter);
    } else {
        paintText(tr("-- m"), valueColor, 2.2f, 67, topMargin+2, &painter);
    }

423
424

    // Draw position to bottom left
425
426
    if (localAvailable > 0)
    {
427
428
        // Position
        QString str;
429
        float offset = (globalAvailable > 0) ? -3.0f : 0.0f;
430
        str.sprintf("%05.2f %05.2f %05.2f m", x, y, z);
431
432
        paintText(tr("POS"), labelColor, 2.6f, 2, vheight - offset - 4.0f, &painter);
        paintText(str, valueColor, 2.6f, 10, vheight - offset - 4.0f, &painter);
433
434
    }

435
436
    if (globalAvailable > 0)
    {
437
438
        // Position
        QString str;
439
        str.sprintf("lat: %05.2f lon: %06.2f alt: %06.2f", lat, lon, alt);
440
441
        paintText(tr("GPS"), labelColor, 2.6f, 2, vheight- 4.0f, &painter);
        paintText(str, valueColor, 2.6f, 10, vheight - 4.0f, &painter);
442
443
    }

444
445
446
    // Draw Safety
    double x1, y1, z1, x2, y2, z2;
    UASManager::instance()->getLocalNEDSafetyLimits(&x1, &y1, &z1, &x2, &y2, &z2);
447
    //    drawSafetyArea(QPointF(x1, y1), QPointF(x2, y2), QGC::colorYellow, painter);
448
449

    // Draw status message
450
    paintText(statusMessage, statusColor, 2.8f, 8, 15, &painter);
451
452
453
454
455

    // Draw setpoint over waypoints
    if (positionSetPointKnown || setPointKnown)
    {
        // Draw setpoint
456
        drawSetpointXYZYaw(bodyXSetCoordinate, bodyYSetCoordinate, bodyZSetCoordinate, bodyYawSet, setpointColor, painter);
457
458
459
460
461
462
        // Draw travel direction line
        QPointF m(bodyXSetCoordinate, bodyYSetCoordinate);
        // Transform from body to world coordinates
        m = metricWorldToBody(m);
        // Scale from metric body to screen reference units
        QPointF s = metricBodyToRef(m);
463
        drawLine(s.x(), s.y(), xCenterPos, yCenterPos, 1.5f, setpointColor, &painter);
464
465
466
467
    }

    if ((userSetPointSet || dragStarted) && ((normAngleDiff > 0.05f) || !(setPointDist < 0.08f && mavInitialized)))
    {
468
        drawSetpointXYZYaw(uiXSetCoordinate, uiYSetCoordinate, uiZSetCoordinate, uiYawSet, setpointColor, painter);
469
    }
470
}
lm's avatar
lm committed
471

472
void HSIDisplay::drawStatusFlag(float x, float y, QString label, bool status, bool known, QPainter& painter)
473
474
475
476
477
{
    drawStatusFlag(x, y, label, status, known, true, painter);
}

void HSIDisplay::drawStatusFlag(float x, float y, QString label, bool status, bool known, bool ok, QPainter& painter)
478
{
479
    QColor statusColor;
480
    QColor labelColor;
481
    if (qgcApp()->styleIsDark())
482
    {
483
484
        statusColor = QColor(250, 250, 250);
        labelColor = QGC::colorCyan;
485
486
487
    }
    else
    {
488
489
        statusColor = QColor(40, 40, 40);
        labelColor = QColor(26, 75, 95);
490
    }
491

492
493
494
495
    // Draw the label.
    paintText(label, labelColor, 2.6f, x, y+0.8f, &painter);

    // Determine color of status rectangle.
496
    if (!ok) {
497
        painter.setBrush(QGC::colorDarkYellow);
498
499
500
501
502
503
    } else {
        if(status) {
            painter.setBrush(QGC::colorGreen);
        } else {
            painter.setBrush(Qt::darkGray);
        }
504
505
    }
    painter.setPen(Qt::NoPen);
506

507
    // Draw the status rectangle.
508
509
510
    float indicatorWidth = refToScreenX(7.0f);
    float indicatorHeight = refToScreenY(4.0f);
    painter.drawRect(QRect(refToScreenX(x+7.3f), refToScreenY(y+0.05), indicatorWidth, indicatorHeight));
511
    paintText((status) ? tr("ON") : tr("OFF"), statusColor, 2.6f, x+7.9f, y+0.8f, &painter);
512

513
    // Cross out instrument if state unknown
514
515
    if (!known)
    {
516
        QPen pen(Qt::yellow);
517
        pen.setWidth(3);
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
        painter.setPen(pen);
        // Top left to bottom right
        QPointF p1, p2, p3, p4;
        p1.setX(refToScreenX(x));
        p1.setY(refToScreenX(y));
        p2.setX(p1.x()+indicatorWidth+refToScreenX(7.3f));
        p2.setY(p1.y()+indicatorHeight);
        painter.drawLine(p1, p2);
        // Bottom left to top right
        p3.setX(refToScreenX(x));
        p3.setY(refToScreenX(y)+indicatorHeight);
        p4.setX(p1.x()+indicatorWidth+refToScreenX(7.3f));
        p4.setY(p1.y());
        painter.drawLine(p3, p4);
    }
533
534
}

535
void HSIDisplay::drawPositionLock(float x, float y, QString label, int status, bool known, QPainter& painter)
536
{
537
538
    // Select color scheme based on light or dark window theme.
    QColor labelColor;
539
540
541
    QColor negStatusColor(200, 20, 20);
    QColor intermediateStatusColor (Qt::yellow);
    QColor posStatusColor(20, 200, 20);
542
    QColor statusColor;
543
    if (qgcApp()->styleIsDark())
544
    {
545
546
        statusColor = QColor(250, 250, 250);
        labelColor = QGC::colorCyan;
547
548
549
    }
    else
    {
550
551
        statusColor = QColor(40, 40, 40);
        labelColor = QColor(26, 75, 95);
552
    }
553

554
555
556
557
    // Draw the label.
    paintText(label, labelColor, 2.6f, x, y+0.8f, &painter);

    // based on the status, choose both the coloring and lock text.
558
559
560
    QString lockText;
    switch (status) {
    case 1:
561
        painter.setBrush(intermediateStatusColor.dark(150));
562
563
564
        lockText = tr("LOC");
        break;
    case 2:
565
        painter.setBrush(intermediateStatusColor.dark(150));
566
567
568
        lockText = tr("2D");
        break;
    case 3:
569
        painter.setBrush(posStatusColor);
570
571
572
        lockText = tr("3D");
        break;
    default:
573
        painter.setBrush(negStatusColor);
574
575
576
        lockText = tr("NO");
        break;
    }
577

578
579
580
581
582
583
    float indicatorWidth = refToScreenX(7.0f);
    float indicatorHeight = refToScreenY(4.0f);

    painter.setPen(Qt::NoPen);
    painter.drawRect(QRect(refToScreenX(x+7.3f), refToScreenY(y+0.05), refToScreenX(7.0f), refToScreenY(4.0f)));
    paintText(lockText, statusColor, 2.6f, x+7.9f, y+0.8f, &painter);
584

585
586
587
    // Cross out instrument if state unknown
    if (!known) {
        QPen pen(Qt::yellow);
588
        pen.setWidth(3);
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
        painter.setPen(pen);
        // Top left to bottom right
        QPointF p1, p2, p3, p4;
        p1.setX(refToScreenX(x));
        p1.setY(refToScreenX(y));
        p2.setX(p1.x()+indicatorWidth+refToScreenX(7.3f));
        p2.setY(p1.y()+indicatorHeight);
        painter.drawLine(p1, p2);
        // Bottom left to top right
        p3.setX(refToScreenX(x));
        p3.setY(refToScreenX(y)+indicatorHeight);
        p4.setX(p1.x()+indicatorWidth+refToScreenX(7.3f));
        p4.setY(p1.y());
        painter.drawLine(p3, p4);
    }
604
605
}

lm's avatar
lm committed
606
607
void HSIDisplay::updatePositionLock(UASInterface* uas, bool lock)
{
pixhawk's avatar
pixhawk committed
608
    Q_UNUSED(uas);
609
    bool changed = positionLock != lock;
lm's avatar
lm committed
610
    positionLock = lock;
611
612
613
614
    if (changed)
    {
        update();
    }
lm's avatar
lm committed
615
616
}

pixhawk's avatar
pixhawk committed
617
void HSIDisplay::updateAttitudeControllerEnabled(bool enabled)
lm's avatar
lm committed
618
{
619
    bool changed = attControlEnabled != enabled;
lm's avatar
lm committed
620
    attControlEnabled = enabled;
621
    attControlKnown = true;
622
623
624
625
    if (changed)
    {
        update();
    }
lm's avatar
lm committed
626
627
}

pixhawk's avatar
pixhawk committed
628
void HSIDisplay::updatePositionXYControllerEnabled(bool enabled)
lm's avatar
lm committed
629
{
630
    bool changed = xyControlEnabled != enabled;
lm's avatar
lm committed
631
    xyControlEnabled = enabled;
632
    xyControlKnown = true;
633
634
635
636
    if (changed)
    {
        update();
    }
lm's avatar
lm committed
637
638
}

pixhawk's avatar
pixhawk committed
639
void HSIDisplay::updatePositionZControllerEnabled(bool enabled)
lm's avatar
lm committed
640
{
641
    bool changed = zControlEnabled != enabled;
lm's avatar
lm committed
642
    zControlEnabled = enabled;
643
    zControlKnown = true;
644
645
646
647
    if (changed)
    {
        update();
    }
lm's avatar
lm committed
648
649
}

LM's avatar
LM committed
650
651
void HSIDisplay::updateObjectPosition(unsigned int time, int id, int type, const QString& name, int quality, float bearing, float distance)
{
652
653
654
655
656
    Q_UNUSED(quality);
    Q_UNUSED(name);
    Q_UNUSED(type);
    Q_UNUSED(id);
    Q_UNUSED(time);
LM's avatar
LM committed
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
    // FIXME add multi-object support
    QPainter painter(this);
    QColor color(Qt::yellow);
    float radius = vwidth / 20.0f;
    QPen pen(color);
    pen.setWidthF(refLineWidthToPen(0.4f));
    pen.setColor(color);
    painter.setPen(pen);
    painter.setBrush(Qt::NoBrush);
    QPointF in(cos(bearing)-sin(bearing)*distance, sin(bearing)+cos(bearing)*distance);
    // Scale from metric to screen reference coordinates
    QPointF p = metricBodyToRef(in);
    drawCircle(p.x(), p.y(), radius, 0.4f, color, &painter);
}

pixhawk's avatar
pixhawk committed
672
673
674
675
QPointF HSIDisplay::metricWorldToBody(QPointF world)
{
    // First translate to body-centered coordinates
    // Rotate around -yaw
pixhawk's avatar
pixhawk committed
676
    float angle = -yaw - M_PI;
677
    QPointF result(cos(angle) * (x - world.x()) - sin(angle) * (y - world.y()), sin(angle) * (x - world.x()) + cos(angle) * (y - world.y()));
pixhawk's avatar
pixhawk committed
678
679
680
681
682
683
684
    return result;
}

QPointF HSIDisplay::metricBodyToWorld(QPointF body)
{
    // First rotate into world coordinates
    // then translate to world position
685
    QPointF result((cos(-yaw) * body.x()) + (sin(-yaw) * body.y()) + x, (-sin(-yaw) * body.x()) + (cos(-yaw) * body.y()) + y);
pixhawk's avatar
pixhawk committed
686
    return result;
687
}
lm's avatar
lm committed
688

689
690
QPointF HSIDisplay::screenToMetricBody(QPointF ref)
{
691
    return QPointF(-((screenToRefY(ref.y()) - yCenterPos)/ vwidth) * metricWidth, ((screenToRefX(ref.x()) - xCenterPos) / vwidth) * metricWidth);
692
693
694
695
}

QPointF HSIDisplay::refToMetricBody(QPointF &ref)
{
lm's avatar
Changes    
lm committed
696
    return QPointF(-((ref.y() - yCenterPos)/ vwidth) * metricWidth - x, ((ref.x() - xCenterPos) / vwidth) * metricWidth - y);
697
698
699
700
701
}

/**
 * @see refToScreenX()
 */
pixhawk's avatar
pixhawk committed
702
QPointF HSIDisplay::metricBodyToRef(QPointF &metric)
703
704
705
706
{
    return QPointF(((metric.y())/ metricWidth) * vwidth + xCenterPos, ((-metric.x()) / metricWidth) * vwidth + yCenterPos);
}

707
708
709
710
711
712
713
714
715
716
double HSIDisplay::metricToRef(double metric)
{
    return (metric / metricWidth) * vwidth;
}

double HSIDisplay::refToMetric(double ref)
{
    return (ref/vwidth) * metricWidth;
}

pixhawk's avatar
pixhawk committed
717
718
719
720
721
722
723
724
QPointF HSIDisplay::metricBodyToScreen(QPointF metric)
{
    QPointF ref = metricBodyToRef(metric);
    ref.setX(refToScreenX(ref.x()));
    ref.setY(refToScreenY(ref.y()));
    return ref;
}

725
726
void HSIDisplay::mouseDoubleClickEvent(QMouseEvent * event)
{
727
728
    if (event->type() == QMouseEvent::MouseButtonDblClick)
    {
729
        QPointF p = screenToMetricBody(event->localPos());
pixhawk's avatar
pixhawk committed
730
731
732
733
734
        if (!directSending)
        {
            setBodySetpointCoordinateXY(p.x(), p.y());
            if (!userZSetPointSet) setBodySetpointCoordinateZ(0.0);
        }
735
        //        qDebug() << "Double click at x: " << screenToRefX(event->x()) - xCenterPos << "y:" << screenToRefY(event->y()) - yCenterPos;
736
737
738
739
740
    }
}

void HSIDisplay::mouseReleaseEvent(QMouseEvent * event)
{
LM's avatar
LM committed
741
    // FIXME hardcode yaw to current value
pixhawk's avatar
pixhawk committed
742
    //setBodySetpointCoordinateYaw(0);
743
    if (mouseHasMoved)
744
    {
745
746
747
748
        if (event->type() == QMouseEvent::MouseButtonRelease && event->button() == Qt::RightButton)
        {
            if (dragStarted)
            {
LM's avatar
LM committed
749
                if (!directSending) setBodySetpointCoordinateYaw(uiYawSet);
750
751
752
753
754
755
756
                dragStarted = false;
            }
        }
        if (event->type() == QMouseEvent::MouseButtonRelease && event->button() == Qt::LeftButton)
        {
            if (leftDragStarted)
            {
LM's avatar
LM committed
757
                if (!directSending) setBodySetpointCoordinateZ(uiZSetCoordinate);
758
                leftDragStarted = false;
759
760
            }
        }
761
    }
762
    mouseHasMoved = false;
763
764
765
766
767
768
769
770
771
}

void HSIDisplay::mousePressEvent(QMouseEvent * event)
{
    if (event->type() == QMouseEvent::MouseButtonPress)
    {
        if (event->button() == Qt::RightButton)
        {
            startX = event->x();
772
773
            // Start tracking mouse move
            dragStarted = true;
774
775
776
        }
        else if (event->button() == Qt::LeftButton)
        {
777
778
            startY = event->y();
            leftDragStarted = true;
779
        }
pixhawk's avatar
pixhawk committed
780
    }
781
    mouseHasMoved = false;
782
}
783

784
785
786
787
void HSIDisplay::mouseMoveEvent(QMouseEvent * event)
{
    if (event->type() == QMouseEvent::MouseMove)
    {
788
        if (dragStarted) uiYawSet -= 0.06f*(startX - event->x()) / this->frameSize().width();
789
790
791

        if (leftDragStarted)
        {
792
793
            //            uiZSetCoordinate -= 0.06f*(startY - event->y()) / this->frameSize().height();
            //            setBodySetpointCoordinateZ(uiZSetCoordinate);
794
        }
795
796

        if (leftDragStarted || dragStarted) mouseHasMoved = true;
pixhawk's avatar
pixhawk committed
797
    }
798
799
}

pixhawk's avatar
pixhawk committed
800
801
void HSIDisplay::keyPressEvent(QKeyEvent* event)
{
802
803
    QPointF bodySP = metricWorldToBody(QPointF(uiXSetCoordinate, uiYSetCoordinate));

804
    if ((event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) && actionPending)
pixhawk's avatar
pixhawk committed
805
806
807
808
809
810
    {
        actionPending = false;
        statusMessage = "SETPOINT SENT";
        statusClearTimer.start();
        sendBodySetPointCoordinates();
    }
LM's avatar
LM committed
811
    else
812
    {
LM's avatar
LM committed
813
814
815
816
817
818
819
        // FIXME hardcode yaw to current value
        setBodySetpointCoordinateYaw(0);


        // Reset setpoints to current position / orientation
        // if not initialized
        if (!userYawSetPointSet)
820
        {
LM's avatar
LM committed
821
            setBodySetpointCoordinateYaw(0);
822
        }
LM's avatar
LM committed
823
824

        if (!userZSetPointSet)
825
        {
LM's avatar
LM committed
826
            setBodySetpointCoordinateZ(0);
827
828
        }

LM's avatar
LM committed
829
        if (!userXYSetPointSet)
830
        {
LM's avatar
LM committed
831
            setBodySetpointCoordinateXY(0, 0);
832
        }
LM's avatar
LM committed
833
834

        if ((event->key() ==  Qt::Key_W))
835
        {
LM's avatar
LM committed
836
            setBodySetpointCoordinateXY(qBound(-1.5, bodySP.x()+0.2, +1.5), bodySP.y());
837
838
        }

LM's avatar
LM committed
839
        if ((event->key() ==  Qt::Key_S))
840
        {
LM's avatar
LM committed
841
            setBodySetpointCoordinateXY(qBound(-1.5, bodySP.x()-0.2, +1.5), bodySP.y());
842
        }
LM's avatar
LM committed
843
844

        if ((event->key() ==  Qt::Key_A))
845
846
847
848
        {
            setBodySetpointCoordinateXY(bodySP.x(), qBound(-1.5, bodySP.y()-0.2, +1.5));
        }

LM's avatar
LM committed
849
        if ((event->key() ==  Qt::Key_D))
850
851
852
853
        {
            setBodySetpointCoordinateXY(bodySP.x(), qBound(-1.5, bodySP.y()+0.2, +1.5));
        }

LM's avatar
LM committed
854
        if ((event->key() ==  Qt::Key_Up))
855
        {
pixhawk's avatar
pixhawk committed
856
            setBodySetpointCoordinateZ(-0.2);
857
858
        }

LM's avatar
LM committed
859
        if ((event->key() ==  Qt::Key_Down))
860
        {
pixhawk's avatar
pixhawk committed
861
            setBodySetpointCoordinateZ(+0.2);
862
863
        }

LM's avatar
LM committed
864
        if ((event->key() ==  Qt::Key_Left))
865
        {
LM's avatar
LM committed
866
            setBodySetpointCoordinateYaw(-0.2);
867
868
        }

LM's avatar
LM committed
869
        if ((event->key() ==  Qt::Key_Right))
870
        {
LM's avatar
LM committed
871
            setBodySetpointCoordinateYaw(0.2);
872
        }
PIXHAWK Team's avatar
PIXHAWK Team committed
873
    }
874
875


LM's avatar
LM committed
876
877
878
    // Overwrite any existing non-zero body setpoints
    // for escape
    if ((event->key() == Qt::Key_Escape) || (event->key() == Qt::Key_R))
PIXHAWK Team's avatar
PIXHAWK Team committed
879
    {
LM's avatar
LM committed
880
        setBodySetpointCoordinateXY(0, 0);
881
882
883
        setBodySetpointCoordinateZ(0);
        setBodySetpointCoordinateYaw(0);
        statusMessage = "CANCELLED, PRESS <ENTER> TO SEND";
PIXHAWK Team's avatar
PIXHAWK Team committed
884
    }
885
886

    if ((event->key() == Qt::Key_T))
PIXHAWK Team's avatar
PIXHAWK Team committed
887
    {
888
889
890
        directSending = !directSending;
        statusMessage = (directSending) ? "DIRECT SEND ON" : "DIRECT SEND OFF";
        statusClearTimer.start();
PIXHAWK Team's avatar
PIXHAWK Team committed
891
    }
892
893

    if (actionPending && (directSending || (event->key() == Qt::Key_Escape)))
PIXHAWK Team's avatar
PIXHAWK Team committed
894
    {
895
896
897
898
        actionPending = false;
        statusMessage = "SETPOINT SENT";
        statusClearTimer.start();
        sendBodySetPointCoordinates();
PIXHAWK Team's avatar
PIXHAWK Team committed
899
    }
900
901

    HDDisplay::keyPressEvent(event);
pixhawk's avatar
pixhawk committed
902
903
}

904
905
906
907
908
void HSIDisplay::contextMenuEvent (QContextMenuEvent* event)
{
    event->ignore();
}

909
910
void HSIDisplay::setMetricWidth(double width)
{
911
    if (width != metricWidth) {
912
913
914
915
916
        metricWidth = width;
        emit metricWidthChanged(metricWidth);
    }
}

917
918
919
920
921
922
/**
 *
 * @param uas the UAS/MAV to monitor/display with the HUD
 */
void HSIDisplay::setActiveUAS(UASInterface* uas)
{
923
924
925
    if (this->uas != NULL) {
        disconnect(this->uas, SIGNAL(gpsSatelliteStatusChanged(int,int,float,float,float,bool)), this, SLOT(updateSatellite(int,int,float,float,float,bool)));
        disconnect(this->uas, SIGNAL(localPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateLocalPosition(UASInterface*,double,double,double,quint64)));
926
        disconnect(this->uas, SIGNAL(globalPositionChanged(UASInterface*,double,double,double,double,quint64)), this, SLOT(updateGlobalPosition(UASInterface*,double,double,double,double,quint64)));
927
        disconnect(this->uas, SIGNAL(attitudeThrustSetPointChanged(UASInterface*,float,float,float,float,quint64)), this, SLOT(updateAttitudeSetpoints(UASInterface*,float,float,float,float,quint64)));
928
        disconnect(this->uas, SIGNAL(positionSetPointsChanged(int,float,float,float,float,quint64)), this, SLOT(updatePositionSetpoints(int,float,float,float,float,quint64)));
929
        disconnect(uas, SIGNAL(userPositionSetPointsChanged(int,float,float,float,float)), this, SLOT(updateUserPositionSetpoints(int,float,float,float,float)));
930
        disconnect(this->uas, SIGNAL(velocityChanged_NED(UASInterface*,double,double,double,quint64)), this, SLOT(updateSpeed(UASInterface*,double,double,double,quint64)));
931
932
933
934
935
936
937
938
939
940
941
        disconnect(this->uas, SIGNAL(attitudeChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateAttitude(UASInterface*,double,double,double,quint64)));

        disconnect(this->uas, SIGNAL(attitudeControlEnabled(bool)), this, SLOT(updateAttitudeControllerEnabled(bool)));
        disconnect(this->uas, SIGNAL(positionXYControlEnabled(bool)), this, SLOT(updatePositionXYControllerEnabled(bool)));
        disconnect(this->uas, SIGNAL(positionZControlEnabled(bool)), this, SLOT(updatePositionZControllerEnabled(bool)));
        disconnect(this->uas, SIGNAL(positionYawControlEnabled(bool)), this, SLOT(updatePositionYawControllerEnabled(bool)));

        disconnect(this->uas, SIGNAL(localizationChanged(UASInterface*,int)), this, SLOT(updateLocalization(UASInterface*,int)));
        disconnect(this->uas, SIGNAL(visionLocalizationChanged(UASInterface*,int)), this, SLOT(updateVisionLocalization(UASInterface*,int)));
        disconnect(this->uas, SIGNAL(gpsLocalizationChanged(UASInterface*,int)), this, SLOT(updateGpsLocalization(UASInterface*,int)));
        disconnect(this->uas, SIGNAL(irUltraSoundLocalizationChanged(UASInterface*,int)), this, SLOT(updateInfraredUltrasoundLocalization(UASInterface*,int)));
LM's avatar
LM committed
942
        disconnect(this->uas, SIGNAL(objectDetected(uint,int,int,QString,int,float,float)), this, SLOT(updateObjectPosition(uint,int,int,QString,int,float,float)));
943
944
945
946
947
948
949
950
951
952

        disconnect(this->uas, SIGNAL(gyroStatusChanged(bool,bool,bool)), this, SLOT(updateGyroStatus(bool,bool,bool)));
        disconnect(this->uas, SIGNAL(accelStatusChanged(bool,bool,bool)), this, SLOT(updateAccelStatus(bool,bool,bool)));
        disconnect(this->uas, SIGNAL(magSensorStatusChanged(bool,bool,bool)), this, SLOT(updateMagSensorStatus(bool,bool,bool)));
        disconnect(this->uas, SIGNAL(baroStatusChanged(bool,bool,bool)), this, SLOT(updateBaroStatus(bool,bool,bool)));
        disconnect(this->uas, SIGNAL(airspeedStatusChanged(bool,bool,bool)), this, SLOT(updateAirspeedStatus(bool,bool,bool)));
        disconnect(this->uas, SIGNAL(opticalFlowStatusChanged(bool,bool,bool)), this, SLOT(updateOpticalFlowStatus(bool,bool,bool)));
        disconnect(this->uas, SIGNAL(laserStatusChanged(bool,bool,bool)), this, SLOT(updateLaserStatus(bool,bool,bool)));
        disconnect(this->uas, SIGNAL(groundTruthSensorStatusChanged(bool,bool,bool)), this, SLOT(updateGroundTruthSensorStatus(bool,bool,bool)));
        disconnect(this->uas, SIGNAL(actuatorStatusChanged(bool,bool,bool)), this, SLOT(updateActuatorStatus(bool,bool,bool)));
953
954
        disconnect(this->uas, &UASInterface::navigationControllerErrorsChanged,
                   this, &HSIDisplay::UpdateNavErrors);
955
    }
956

957
958
    if (uas)
    {
959
960
961
962
        connect(uas, SIGNAL(gpsSatelliteStatusChanged(int,int,float,float,float,bool)),
                this, SLOT(updateSatellite(int,int,float,float,float,bool)));
        connect(uas, SIGNAL(localPositionChanged(UASInterface*,double,double,double,quint64)),
                this, SLOT(updateLocalPosition(UASInterface*,double,double,double,quint64)));
963
964
        connect(uas, SIGNAL(globalPositionChanged(UASInterface*,double,double,double,double,quint64)),
                this, SLOT(updateGlobalPosition(UASInterface*,double,double,double,double,quint64)));
965
966
        connect(uas, SIGNAL(attitudeThrustSetPointChanged(UASInterface*,float,float,float,float,quint64)),
                this, SLOT(updateAttitudeSetpoints(UASInterface*,float,float,float,float,quint64)));
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
        connect(uas, SIGNAL(positionSetPointsChanged(int,float,float,float,float,quint64)),
                this, SLOT(updatePositionSetpoints(int,float,float,float,float,quint64)));
        connect(uas, SIGNAL(userPositionSetPointsChanged(int,float,float,float,float)),
                this, SLOT(updateUserPositionSetpoints(int,float,float,float,float)));
        connect(uas, SIGNAL(velocityChanged_NED(UASInterface*,double,double,double,quint64)),
                this, SLOT(updateSpeed(UASInterface*,double,double,double,quint64)));
        connect(uas, SIGNAL(attitudeChanged(UASInterface*,double,double,double,quint64)),
                this, SLOT(updateAttitude(UASInterface*,double,double,double,quint64)));
        connect(uas, SIGNAL(attitudeControlEnabled(bool)),
                this, SLOT(updateAttitudeControllerEnabled(bool)));
        connect(uas, SIGNAL(positionXYControlEnabled(bool)),
                this, SLOT(updatePositionXYControllerEnabled(bool)));
        connect(uas, SIGNAL(positionZControlEnabled(bool)),
                this, SLOT(updatePositionZControllerEnabled(bool)));
        connect(uas, SIGNAL(positionYawControlEnabled(bool)),
                this, SLOT(updatePositionYawControllerEnabled(bool)));

        connect(uas, SIGNAL(localizationChanged(UASInterface*,int)),
                this, SLOT(updateLocalization(UASInterface*,int)));
        connect(uas, SIGNAL(visionLocalizationChanged(UASInterface*,int)),
                this, SLOT(updateVisionLocalization(UASInterface*,int)));
        connect(uas, SIGNAL(gpsLocalizationChanged(UASInterface*,int)),
                this, SLOT(updateGpsLocalization(UASInterface*,int)));
        connect(uas, SIGNAL(irUltraSoundLocalizationChanged(UASInterface*,int)),
                this, SLOT(updateInfraredUltrasoundLocalization(UASInterface*,int)));
        connect(uas, SIGNAL(objectDetected(uint,int,int,QString,int,float,float)),
                this, SLOT(updateObjectPosition(uint,int,int,QString,int,float,float)));

        connect(uas, SIGNAL(gyroStatusChanged(bool,bool,bool)),
                this, SLOT(updateGyroStatus(bool,bool,bool)));
        connect(uas, SIGNAL(accelStatusChanged(bool,bool,bool)),
                this, SLOT(updateAccelStatus(bool,bool,bool)));
        connect(uas, SIGNAL(magSensorStatusChanged(bool,bool,bool)),
                this, SLOT(updateMagSensorStatus(bool,bool,bool)));
For faster browsing, not all history is shown. View entire blame