diff --git a/README b/README index dfd742424d211fdacc8ebc481af703e2c70e1ff4..09bae4c61322521d1a14c370d26e72509299c9bb 100644 --- a/README +++ b/README @@ -46,11 +46,12 @@ To build on Linux: Windows ======= -********************************************************************************************** -* PLEASE NOTE: YOU NEED TO DOWNLOAD THE MAVLINK LIBRARY IN ORDER TO COMPILE THIS APPLICATION * -********************************************************************************************** +Windows XP: +1) Download and install the QT SDK for Windows from http://qt.nokia.com/downloads/. + +2) Open qgroundcontrol.pro with QT to open the project. + +3) Once the indexing is complete, you may build the project, which will compile and run the debug build. -To build on Windows: - diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index a6d82a27550e2f9fbebeec9f2d94591daa8ed824..85d707fe5a96e79407b16a31ed72fc4c39120914 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -83,7 +83,6 @@ HEADERS += src/MG.h \ src/ui/uas/UASInfoWidget.h \ src/ui/HUD.h \ src/ui/linechart/LinechartWidget.h \ - src/ui/linechart/LinechartContainer.h \ src/ui/linechart/LinechartPlot.h \ src/ui/linechart/Scrollbar.h \ src/ui/linechart/ScrollZoomer.h \ @@ -115,7 +114,8 @@ HEADERS += src/MG.h \ src/ui/param/ParamTreeItem.h \ src/ui/param/ParamTreeModel.h \ src/ui/QGCParamWidget.h \ - src/ui/QGCSensorSettingsWidget.h + src/ui/QGCSensorSettingsWidget.h \ + src/ui/linechart/Linecharts.h SOURCES += src/main.cc \ src/Core.cc \ src/uas/UASManager.cc \ @@ -133,7 +133,6 @@ SOURCES += src/main.cc \ src/ui/uas/UASInfoWidget.cc \ src/ui/HUD.cc \ src/ui/linechart/LinechartWidget.cc \ - src/ui/linechart/LinechartContainer.cc \ src/ui/linechart/LinechartPlot.cc \ src/ui/linechart/Scrollbar.cc \ src/ui/linechart/ScrollZoomer.cc \ @@ -164,5 +163,6 @@ SOURCES += src/main.cc \ src/ui/param/ParamTreeItem.cc \ src/ui/param/ParamTreeModel.cc \ src/ui/QGCParamWidget.cc \ - src/ui/QGCSensorSettingsWidget.cc + src/ui/QGCSensorSettingsWidget.cc \ + src/ui/linechart/Linecharts.cc RESOURCES = mavground.qrc diff --git a/src/comm/MAVLinkProtocol.cc b/src/comm/MAVLinkProtocol.cc index 83853345a82b7e9b21fb1736430904684532fe8c..daff4a870b9c8ae51ae60763e14f5cdae6890d7b 100644 --- a/src/comm/MAVLinkProtocol.cc +++ b/src/comm/MAVLinkProtocol.cc @@ -122,6 +122,13 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link) // of its existence, as it only then can send and receive // it's first messages. + // FIXME Current debugging + // check if the UAS has the same id like this system + if (message.sysid == getSystemId()) + { + qDebug() << "WARNING\nWARNING\nWARNING\nWARNING\nWARNING\nWARNING\nWARNING\n\n RECEIVED MESSAGE FROM THIS SYSTEM WITH ID" << message.msgid << "FROM COMPONENT" << message.compid; + } + // First create new UAS object uas = new UAS(this, message.sysid); // Make UAS aware that this link can be used to communicate with the actual robot diff --git a/src/comm/SerialLink.cc b/src/comm/SerialLink.cc index 514cf26e1f4591f3d570c3c93cd1f1bfb7bbb687..55751cc2820372a333f8cc30bdb5a07a09ce6911 100644 --- a/src/comm/SerialLink.cc +++ b/src/comm/SerialLink.cc @@ -152,16 +152,18 @@ void SerialLink::checkForBytes() { void SerialLink::writeBytes(const char* data, qint64 size) { - if(port->isOpen()) { + if(port->isOpen()) + { int b = port->write(data, size); qDebug() << "Transmitted " << b << "bytes:"; - /* Increase write counter */ + // Increase write counter bitsSentTotal += size * 8; int i; - for (i=0; igetUASID()); QString stateAudio = ""; QString modeAudio = ""; @@ -158,13 +161,13 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) stateAudio = " changed status to " + uasState; } - if (static_cast(this->mode) != static_cast(state.mode)) + if (static_cast(this->mode) != static_cast(state.mode)) { modechanged = true; this->mode = state.mode; QString mode; - switch (state.mode) + switch ((unsigned int)(state.mode)) { case MAV_MODE_LOCKED: mode = "LOCKED MODE"; @@ -449,8 +452,9 @@ void UAS::setMode(int mode) { this->mode = mode; mavlink_message_t msg; - mavlink_msg_set_mode_pack(MG::SYSTEM::ID, MG::SYSTEM::COMPID, &msg, getUASID(), (unsigned char)mode); + mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, uasId, (unsigned char)mode); sendMessage(msg); + qDebug() << "SENDING REQUEST TO SET MODE TO SYSTEM" << uasId << ", REQUEST TO SET MODE " << mode; } } diff --git a/src/uas/UASManager.cc b/src/uas/UASManager.cc index 0a4ce829fddfb575050bcf8b9bcc979a184d93dc..ea14116817b361cc10fe700262d1c9e2b93566fd 100644 --- a/src/uas/UASManager.cc +++ b/src/uas/UASManager.cc @@ -83,6 +83,7 @@ void UASManager::addUAS(UASInterface* uas) { activeUAS = uas; emit activeUASSet(uas); + emit activeUASSet(uas->getUASID()); } } @@ -170,6 +171,7 @@ void UASManager::setActiveUAS(UASInterface* uas) qDebug() << __FILE__ << ":" << __LINE__ << " ACTIVE UAS SET TO: " << uas->getUASName(); emit activeUASSet(uas); + emit activeUASSet(uas->getUASID()); } } diff --git a/src/uas/UASManager.h b/src/uas/UASManager.h index 1aecb277fb128cedcc5497785e7a0fb034c1182e..6698897529f7dfcfea71b03a75bfbc97ef5f28d4 100644 --- a/src/uas/UASManager.h +++ b/src/uas/UASManager.h @@ -166,6 +166,7 @@ protected: signals: void UASCreated(UASInterface* UAS); void activeUASSet(UASInterface* UAS); + void activeUASSet(int systemId); }; diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc index 8a79d146366fa31bfd3c7334f18192e89ddc17eb..dfedb4fb12eb5bd4e0152e694e79768c205681ad 100644 --- a/src/ui/MainWindow.cc +++ b/src/ui/MainWindow.cc @@ -71,9 +71,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), // Initialize views, NOT show them yet, only initialize model and controller centerStack = new QStackedWidget(this); - linechart = new LinechartWidget(this); + linechart = new Linecharts(this); linechart->setActive(false); - connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), linechart, SLOT(setActivePlot(UASInterface*))); + connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), linechart, SLOT(addSystem(UASInterface*))); + connect(UASManager::instance(), SIGNAL(activeUASSet(int)), linechart, SLOT(selectSystem(int))); centerStack->addWidget(linechart); control = new UASControlWidget(this); //controlDock = new QDockWidget(this); @@ -312,7 +313,7 @@ void MainWindow::addLink(LinkInterface *link) MAVLinkSimulationLink* sim = dynamic_cast(link); if (sim) { - connect(sim, SIGNAL(valueChanged(int,QString,double,quint64)), linechart, SLOT(appendData(int,QString,double,quint64))); + //connect(sim, SIGNAL(valueChanged(int,QString,double,quint64)), linechart, SLOT(appendData(int,QString,double,quint64))); connect(ui.actionSimulate, SIGNAL(triggered(bool)), sim, SLOT(connectLink(bool))); } } @@ -322,15 +323,6 @@ void MainWindow::UASCreated(UASInterface* uas) // Connect the UAS to the full user interface //ui.menuConnected_Systems->addAction(QIcon(":/images/mavs/generic.svg"), tr("View ") + uas->getUASName(), uas, SLOT(setSelected())); - // Line chart - // FIXME DO THIS ONLY FOR THE FIRST CONNECTED SYSTEM - static bool sysPresent = false; - if (!sysPresent) - { - connect(uas, SIGNAL(valueChanged(int,QString,double,quint64)), linechart, SLOT(appendData(int,QString,double,quint64)), Qt::QueuedConnection); - sysPresent = true; - } - // FIXME Should be not inside the mainwindow connect(uas, SIGNAL(textMessageReceived(int,int,QString)), debugConsole, SLOT(receiveTextMessage(int,int,QString))); diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h index 9e0a43e696a04e03ec12f679cc0f394872900ad7..9cb2f23a7f38a1e364d9abd1f0d7997e1ff94b99 100644 --- a/src/ui/MainWindow.h +++ b/src/ui/MainWindow.h @@ -42,7 +42,7 @@ This file is part of the PIXHAWK project #include "UASInterface.h" #include "UASManager.h" #include "UASControlWidget.h" -#include "LinechartWidget.h" +#include "Linecharts.h" #include "UASInfoWidget.h" #include "WaypointList.h" #include "CameraView.h" @@ -132,7 +132,7 @@ protected: QSettings settings; UASControlWidget* control; - LinechartWidget* linechart; + Linecharts* linechart; UASInfoWidget* info; CameraView* camera; UASListWidget* list; diff --git a/src/ui/QGCParamWidget.cc b/src/ui/QGCParamWidget.cc index f9170925b8325d6c3ff1633b78012c53ebe5beed..6d29661d0f037ac6399622da90026f29df3b2034 100644 --- a/src/ui/QGCParamWidget.cc +++ b/src/ui/QGCParamWidget.cc @@ -130,7 +130,15 @@ void QGCParamWidget::addParameter(int uas, int component, QString parameterName, { Q_UNUSED(uas); // Insert parameter into map - //tree->appendParam(component, parameterName, value); + + QString splitToken = "_"; + // Check if auto-grouping can work + /* + if (parameterName.contains(splitToken)) + { + QString parent = parameterName.section(splitToken, 0, 0, QString::SectionSkipEmpty); + QString children = parameterName.section(splitToken, 1, -1, QString::SectionSkipEmpty); + }*/ QStringList plist; plist.append(parameterName); plist.append(QString::number(value)); diff --git a/src/ui/XMLCommProtocolWidget.cc b/src/ui/XMLCommProtocolWidget.cc index 797deed3ae22d82faad9d620b0d057a555bd2629..be3004e79b42bd63f77afeb64dd49f9ff7355e38 100644 --- a/src/ui/XMLCommProtocolWidget.cc +++ b/src/ui/XMLCommProtocolWidget.cc @@ -1,6 +1,7 @@ #include #include #include +#include #include "XMLCommProtocolWidget.h" #include "ui_XMLCommProtocolWidget.h" @@ -23,10 +24,12 @@ XMLCommProtocolWidget::XMLCommProtocolWidget(QWidget *parent) : void XMLCommProtocolWidget::selectXMLFile() { - qDebug() << "OPENING XML FILE"; - //QString fileName = QFileDialog::getOpenFileName(this, tr("Load Protocol Definition File"), ".", "*.xml"); + QSettings settings; + const QString mavlinkXML = "MAVLINK_XML_FILE"; + QString dirPath = settings.value(mavlinkXML, QCoreApplication::applicationDirPath() + "../").toString(); QFileDialog dialog; + dialog.setDirectory(dirPath); dialog.setFileMode(QFileDialog::AnyFile); dialog.setFilter(tr("MAVLink XML (*.xml)")); dialog.setViewMode(QFileDialog::Detail); @@ -40,6 +43,8 @@ void XMLCommProtocolWidget::selectXMLFile() { m_ui->fileNameLabel->setText(fileNames.first()); QFile file(fileNames.first()); + // Store filename for next time + settings.setValue(mavlinkXML, fileNames.first()); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { const QString instanceText(QString::fromUtf8(file.readAll())); @@ -80,7 +85,11 @@ void XMLCommProtocolWidget::setXML(const QString& xml) void XMLCommProtocolWidget::selectOutputDirectory() { + QSettings settings; + const QString mavlinkOutputDir = "MAVLINK_OUTPUT_DIR"; + QString dirPath = settings.value(mavlinkOutputDir, QCoreApplication::applicationDirPath() + "../").toString(); QFileDialog dialog; + dialog.setDirectory(dirPath); dialog.setFileMode(QFileDialog::Directory); dialog.setFilter(tr("MAVLink XML (*.xml)")); dialog.setViewMode(QFileDialog::Detail); @@ -93,6 +102,8 @@ void XMLCommProtocolWidget::selectOutputDirectory() if (fileNames.size() > 0) { m_ui->outputDirNameLabel->setText(fileNames.first()); + // Store directory for next time + settings.setValue(mavlinkOutputDir, fileNames.first()); //QFile file(fileName); } } diff --git a/src/ui/linechart/LinechartContainer.cc b/src/ui/linechart/LinechartContainer.cc deleted file mode 100644 index 58c60017f4128fb6b0d2e939155299ad22fc5ca1..0000000000000000000000000000000000000000 --- a/src/ui/linechart/LinechartContainer.cc +++ /dev/null @@ -1,59 +0,0 @@ -/*===================================================================== - -PIXHAWK Micro Air Vehicle Flying Robotics Toolkit - -(c) 2009, 2010 PIXHAWK PROJECT - -This file is part of the PIXHAWK project - - PIXHAWK is free software: you can redistribute it and/or modify - 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. - - PIXHAWK is distributed in the hope that it will be useful, - 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 - along with PIXHAWK. If not, see . - -======================================================================*/ - -/** - * @file - * @brief Brief Description - * - * @author Lorenz Meier - * - */ - -#include -#include - -LinechartContainer::LinechartContainer(QWidget* parent) : QWidget(parent) -{ -// setMinimumHeight(300); -// setMinimumWidth(450); - setContentsMargins(0, 0, 0, 0); // No margin around container content -} - -LinechartContainer::~LinechartContainer() -{ - -} - -LinechartPlot* LinechartContainer::getPlot() -{ - return plot; -} - -void LinechartContainer::setPlot(LinechartPlot* plot) -{ - this->plot = plot; - delete layout(); - QHBoxLayout* currentLayout = new QHBoxLayout(this); - currentLayout->addWidget(plot); - setLayout(currentLayout); -} diff --git a/src/ui/linechart/LinechartContainer.h b/src/ui/linechart/LinechartContainer.h deleted file mode 100644 index dbd2c5f063c91b35b3b37a49c9cc3b0639ebc757..0000000000000000000000000000000000000000 --- a/src/ui/linechart/LinechartContainer.h +++ /dev/null @@ -1,59 +0,0 @@ -/*===================================================================== - -PIXHAWK Micro Air Vehicle Flying Robotics Toolkit - -(c) 2009 PIXHAWK PROJECT - -This file is part of the PIXHAWK project - - PIXHAWK is free software: you can redistribute it and/or modify - 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. - - PIXHAWK is distributed in the hope that it will be useful, - 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 - along with PIXHAWK. If not, see . - -======================================================================*/ - -/** - * @file - * @brief Brief Description - * - * @author Lorenz Meier - * - */ - -#ifndef _LINECHARTCONTAINER_H_ -#define _LINECHARTCONTAINER_H_ - -#include -#include - -/** - * @brief Container for line chart plots - * - * @see LinechartPlot - * @see LinechartWidget - */ -class LinechartContainer : public QWidget { - Q_OBJECT -public: - LinechartContainer(QWidget *parent = NULL); - ~LinechartContainer(); - - LinechartPlot* getPlot(); - -public slots: - void setPlot(LinechartPlot* plot); - -private: - LinechartPlot* plot; -}; - -#endif /* _LINECHARTCONTAINER_H_ */ diff --git a/src/ui/linechart/LinechartPlot.cc b/src/ui/linechart/LinechartPlot.cc index 9d1eecbb19cf9641c0a345dbf1d4a39220513332..4dd452401541fd3af02f41757411a4bfcc0c9a01 100644 --- a/src/ui/linechart/LinechartPlot.cc +++ b/src/ui/linechart/LinechartPlot.cc @@ -55,9 +55,9 @@ maxTime(QUINT64_MIN), maxInterval(MAX_STORAGE_INTERVAL), timeScaleStep(DEFAULT_SCALE_INTERVAL), // 10 seconds automaticScrollActive(false), +m_active(true), d_data(NULL), -d_curve(NULL), -m_active(true) +d_curve(NULL) { this->plotid = plotid; this->plotInterval = interval; @@ -158,6 +158,14 @@ int LinechartPlot::getPlotId() return this->plotid; } +/** + * @param id curve identifier + */ +double LinechartPlot::getCurrentValue(QString id) +{ + return data.value(id)->getCurrentValue(); +} + /** * @param id curve identifier */ @@ -280,7 +288,7 @@ void LinechartPlot::addCurve(QString id) data.insert(id, dataset); // Notify connected components about new curve - emit curveAdded(plotid, id); + emit curveAdded(id); } QColor LinechartPlot::getNextColor() @@ -337,7 +345,7 @@ void LinechartPlot::setCurveColor(QString id, QColor color) QwtPlotCurve* curve = curves.value(id); curve->setPen(color); - emit colorSet(plotid, id, color); + emit colorSet(id, color); } /** @@ -635,7 +643,7 @@ void LinechartPlot::removeAllData() curve = NULL; // Notify connected components about the removal - emit curveRemoved(plotid, i.key()); + emit curveRemoved(i.key()); } // Delete data @@ -814,6 +822,11 @@ double TimeSeriesData::getMedian() return median; } +double TimeSeriesData::getCurrentValue() +{ + return ms.last(); +} + /** * @brief Get the zero (center) value in the data set * The zero value is not a statistical value, but instead manually defined diff --git a/src/ui/linechart/LinechartPlot.h b/src/ui/linechart/LinechartPlot.h index e255e21842c31fe9da30a3bad0b5dfd70d8992f9..d415f71e31a846ccff1398486728bd5fdf7e6d2b 100644 --- a/src/ui/linechart/LinechartPlot.h +++ b/src/ui/linechart/LinechartPlot.h @@ -132,6 +132,8 @@ public: double getMean(); /** @brief Get the short-term median */ double getMedian(); + /** @brief Get the current value */ + double getCurrentValue(); void setZeroValue(double zeroValue); void setInterval(quint64 ms); void setAverageWindowSize(int windowSize); @@ -203,6 +205,8 @@ public: double getMean(QString id); /** @brief Get the short-term median of a curve */ double getMedian(QString id); + /** @brief Get the last inserted value */ + double getCurrentValue(QString id); static const int SCALE_ABSOLUTE = 0; static const int SCALE_BEST_FIT = 1; @@ -303,20 +307,20 @@ signals: * * @param color The curve color in the diagram **/ - void curveAdded(int uasid, QString idstring); + void curveAdded(QString idstring); /** * @brief This signal is emitted when a curve gets assigned a color * * @param idstring The id-string of the curve * @param color The curve color in the diagram **/ - void colorSet(int uasid, QString idstring, QColor color); + void colorSet(QString idstring, QColor color); /** * @brief This signal is emitted when a curve is removed * * @param name The id-string of the curve **/ - void curveRemoved(int uasid, QString name); + void curveRemoved(QString name); /** * @brief This signal is emitted when the plot window position changes * diff --git a/src/ui/linechart/LinechartWidget.cc b/src/ui/linechart/LinechartWidget.cc index 5775fbd3e5bf4bceb58a780ba3b0fdaf68519cd0..5ed9ce98640ea9e11cb2a10cd421f79146dab26b 100644 --- a/src/ui/linechart/LinechartWidget.cc +++ b/src/ui/linechart/LinechartWidget.cc @@ -49,19 +49,22 @@ This file is part of the PIXHAWK project #include "MG.h" -LinechartWidget::LinechartWidget(QWidget *parent) : QWidget(parent), +LinechartWidget::LinechartWidget(int systemid, QWidget *parent) : QWidget(parent), +sysid(systemid), +activePlot(NULL), curvesLock(new QReadWriteLock()), +plotWindowLock(), curveListIndex(0), curveListCounter(0), -activePlot(NULL), -curveMenu(new QMenu(this)), listedCurves(new QList()), curveLabels(new QMap()), curveMeans(new QMap()), curveMedians(new QMap()), +curveMenu(new QMenu(this)), logFile(new QFile()), logindex(1), -logging(false) +logging(false), +updateTimer(new QTimer()) { // Add elements defined in Qt Designer ui.setupUi(this); @@ -78,15 +81,16 @@ logging(false) // Add and customize plot elements (right side) - // Instantiate the actual plot for multiple vehicles - plots = QMap(); - // Create the layout createLayout(); // Add the last actions connect(this, SIGNAL(plotWindowPositionUpdated(int)), scrollbar, SLOT(setValue(int))); connect(scrollbar, SIGNAL(sliderMoved(int)), this, SLOT(setPlotWindowPosition(int))); + + updateTimer->setInterval(100); + connect(updateTimer, SIGNAL(timeout()), this, SLOT(refresh())); + updateTimer->start(); } LinechartWidget::~LinechartWidget() { @@ -95,11 +99,6 @@ LinechartWidget::~LinechartWidget() { listedCurves = NULL; } -void LinechartWidget::setPlot(int uasId) -{ - setActivePlot(uasId); -} - void LinechartWidget::createLayout() { // Create actions @@ -112,13 +111,15 @@ void LinechartWidget::createLayout() layout->setMargin(2); // Create plot container widget - plotContainer = new LinechartContainer(ui.diagramGroupBox); + activePlot = new LinechartPlot(this, sysid); + // Activate automatic scrolling + activePlot->setAutoScroll(true); // TODO Proper Initialization needed // activePlot = getPlot(0); // plotContainer->setPlot(activePlot); - layout->addWidget(plotContainer, 0, 0, 1, 5); + layout->addWidget(activePlot, 0, 0, 1, 5); layout->setRowStretch(0, 10); layout->setRowStretch(1, 0); @@ -167,35 +168,47 @@ void LinechartWidget::createLayout() layout->setColumnStretch(4, 10); ui.diagramGroupBox->setLayout(layout); + + // Add actions + averageSpinBox->setValue(activePlot->getAverageWindow()); + + // Connect notifications from the user interface to the plot + connect(this, SIGNAL(curveRemoved(QString)), activePlot, SLOT(hideCurve(QString))); + connect(this, SIGNAL(curveSet(QString, int)), activePlot, SLOT(showCurve(QString, int))); + + // Connect notifications from the plot to the user interface + connect(activePlot, SIGNAL(curveAdded(QString)), this, SLOT(addCurve(QString))); + connect(activePlot, SIGNAL(curveRemoved(QString)), this, SLOT(removeCurve(QString))); + + // Scrollbar + + // Update scrollbar when plot window changes (via translator method setPlotWindowPosition() + connect(activePlot, SIGNAL(windowPositionChanged(quint64)), this, SLOT(setPlotWindowPosition(quint64))); + + // Update plot when scrollbar is moved (via translator method setPlotWindowPosition() + connect(this, SIGNAL(plotWindowPositionUpdated(quint64)), activePlot, SLOT(setWindowPosition(quint64))); + + // Set scaling + connect(scalingLinearButton, SIGNAL(clicked()), activePlot, SLOT(setLinearScaling())); + connect(scalingLogButton, SIGNAL(clicked()), activePlot, SLOT(setLogarithmicScaling())); } void LinechartWidget::appendData(int uasId, QString curve, double value, quint64 usec) { // Order matters here, first append to plot, then update curve list - LinechartPlot* currPlot = getPlot(uasId); - currPlot->appendData(curve, usec, value); - if(activePlot == NULL) setActivePlot(uasId); - QString str; - str.sprintf("%+.2f", value); + activePlot->appendData(curve, usec, value); + // Store data QLabel* label = curveLabels->value(curve, NULL); // Make sure the curve will be created if it does not yet exist if(!label) { - addCurve(uasId, curve); + addCurve(curve); } - // Value - curveLabels->value(curve)->setText(str); - // Mean - str.sprintf("%+.2f", currPlot->getMean(curve)); - curveMeans->value(curve)->setText(str); - // Median - str.sprintf("%+.2f", currPlot->getMedian(curve)); - curveMedians->value(curve)->setText(str); // Log data if (logging) { - if (currPlot->isVisible(curve)) + if (activePlot->isVisible(curve)) { logFile->write(QString(QString::number(usec) + "\t" + QString::number(uasId) + "\t" + curve + "\t" + QString::number(value) + "\n").toLatin1()); logFile->flush(); @@ -203,6 +216,33 @@ void LinechartWidget::appendData(int uasId, QString curve, double value, quint64 } } +void LinechartWidget::refresh() +{ + QString str; + + QMap::iterator i; + for (i = curveLabels->begin(); i != curveLabels->end(); ++i) + { + str.sprintf("%+.2f", activePlot->getCurrentValue(i.key())); + // Value + i.value()->setText(str); + } + // Mean + QMap::iterator j; + for (j = curveMeans->begin(); j != curveMeans->end(); ++j) + { + str.sprintf("%+.2f", activePlot->getMean(j.key())); + j.value()->setText(str); + } + QMap::iterator k; + for (k = curveMedians->begin(); k != curveMedians->end(); ++k) + { + // Median + str.sprintf("%+.2f", activePlot->getMedian(k.key())); + k.value()->setText(str); + } +} + void LinechartWidget::startLogging() { @@ -219,10 +259,6 @@ void LinechartWidget::startLogging() logButton->setText(tr("Stop logging")); disconnect(logButton, SIGNAL(clicked()), this, SLOT(startLogging())); connect(logButton, SIGNAL(clicked()), this, SLOT(stopLogging())); - - // Write file header - //logFile->write(QString("MILLISECONDS\tID\t\"NAME\"\tVALUE\n").toLatin1()); - //logFile->flush(); } else { @@ -268,13 +304,14 @@ void LinechartWidget::createActions() * @param curve The id-string of the curve * @see removeCurve() **/ -void LinechartWidget::addCurve(int uasid, QString curve) +void LinechartWidget::addCurve(QString curve) { - curvesWidgetLayout->addWidget(createCurveItem(getPlot(uasid), curve)); + curvesWidgetLayout->addWidget(createCurveItem(curve)); } -QWidget* LinechartWidget::createCurveItem(LinechartPlot* plot, QString curve) +QWidget* LinechartWidget::createCurveItem(QString curve) { + LinechartPlot* plot = activePlot; QWidget* form = new QWidget(this); QHBoxLayout *horizontalLayout; QCheckBox *checkBox; @@ -366,22 +403,10 @@ QWidget* LinechartWidget::createCurveItem(LinechartPlot* plot, QString curve) * @param curve The curve to remove * @see addCurve() **/ -void LinechartWidget::removeCurve(int uasid, QString curve) +void LinechartWidget::removeCurve(QString curve) { //TODO @todo Ensure that the button for a curve gets deleted when the original curve is deleted -} - -/** - * @brief Get the plot widget. - * - * @return The plot widget - **/ -LinechartPlot* LinechartWidget::getPlot(int plotid) { - if(!plots.contains(plotid)) - { - plots.insert(plotid, new LinechartPlot(ui.diagramGroupBox, plotid)); - } - return plots.value(plotid); + // Remove name } void LinechartWidget::setActive(bool active) @@ -390,67 +415,13 @@ void LinechartWidget::setActive(bool active) { activePlot->setActive(active); } -} - -void LinechartWidget::setActivePlot(UASInterface* uas) -{ - setActivePlot(uas->getUASID()); -} - -void LinechartWidget::setActivePlot(int uasId) -{ - if (!activePlot || uasId != activePlot->getPlotId()) + if (active) { - // Make sure there is an active plot, else the next - // if clause will access a null pointer - if (!activePlot) - { - // Get plot, if it does not exist yet it will be automatically created - activePlot = getPlot(uasId); - } - - // Remove current plot - disconnect(this, SIGNAL(curveRemoved(QString)), activePlot, SLOT(hideCurve(QString))); - disconnect(this, SIGNAL(curveSet(QString, int)), activePlot, SLOT(showCurve(QString, int))); - disconnect(activePlot, SIGNAL(curveAdded(int, QString)), this, SLOT(addCurve(int, QString))); - disconnect(activePlot, SIGNAL(curveRemoved(int, QString)), this, SLOT(removeCurve(int, QString))); - disconnect(activePlot, SIGNAL(windowPositionChanged(quint64)), this, SLOT(setPlotWindowPosition(quint64))); - disconnect(this, SIGNAL(plotWindowPositionUpdated(quint64)), activePlot, SLOT(setWindowPosition(quint64))); - disconnect(scalingLinearButton, SIGNAL(clicked()), activePlot, SLOT(setLinearScaling())); - disconnect(scalingLogButton, SIGNAL(clicked()), activePlot, SLOT(setLogarithmicScaling())); - - // Get plot, if it does not exist yet it will be automatically created - activePlot = getPlot(uasId); - - plotContainer->setPlot(activePlot); - - qDebug() << "LinechartWidget::setPlot(): Setting plot to UAS ID:" << uasId; - - // Activate automatic scrolling - activePlot->setAutoScroll(true); - - // Add actions - averageSpinBox->setValue(activePlot->getAverageWindow()); - - // Connect notifications from the user interface to the plot - connect(this, SIGNAL(curveRemoved(QString)), activePlot, SLOT(hideCurve(QString))); - connect(this, SIGNAL(curveSet(QString, int)), activePlot, SLOT(showCurve(QString, int))); - - // Connect notifications from the plot to the user interface - connect(activePlot, SIGNAL(curveAdded(int, QString)), this, SLOT(addCurve(int, QString))); - connect(activePlot, SIGNAL(curveRemoved(int, QString)), this, SLOT(removeCurve(int, QString))); - - // Scrollbar - - // Update scrollbar when plot window changes (via translator method setPlotWindowPosition() - connect(activePlot, SIGNAL(windowPositionChanged(quint64)), this, SLOT(setPlotWindowPosition(quint64))); - - // Update plot when scrollbar is moved (via translator method setPlotWindowPosition() - connect(this, SIGNAL(plotWindowPositionUpdated(quint64)), activePlot, SLOT(setWindowPosition(quint64))); - - // Set scaling - connect(scalingLinearButton, SIGNAL(clicked()), activePlot, SLOT(setLinearScaling())); - connect(scalingLogButton, SIGNAL(clicked()), activePlot, SLOT(setLogarithmicScaling())); + updateTimer->start(); + } + else + { + updateTimer->stop(); } } diff --git a/src/ui/linechart/LinechartWidget.h b/src/ui/linechart/LinechartWidget.h index 4307ddf5641c465971f1ff9bee3bc76f45f06afd..cd97c1a6d6e9508c11df6629b606e04f1e6f7fcf 100644 --- a/src/ui/linechart/LinechartWidget.h +++ b/src/ui/linechart/LinechartWidget.h @@ -46,9 +46,9 @@ This file is part of the PIXHAWK project #include #include #include +#include #include -#include "LinechartContainer.h" #include "LinechartPlot.h" #include "UASInterface.h" #include "ui_Linechart.h" @@ -63,81 +63,62 @@ class LinechartWidget : public QWidget { Q_OBJECT public: - LinechartWidget(QWidget *parent = 0); + LinechartWidget(int systemid, QWidget *parent = 0); ~LinechartWidget(); - LinechartPlot* getPlot(int uasId); - static const int MIN_TIME_SCROLLBAR_VALUE = 0; ///< The minimum scrollbar value static const int MAX_TIME_SCROLLBAR_VALUE = 16383; ///< The maximum scrollbar value public slots: - void addCurve(int uasid, QString curve); - void removeCurve(int uasid, QString curve); - void appendData(int uasid, QString curve, double data, quint64 usec); + void addCurve(QString curve); + void removeCurve(QString curve); + void appendData(int sysId, QString curve, double data, quint64 usec); void takeButtonClick(bool checked); void setPlotWindowPosition(int scrollBarValue); void setPlotWindowPosition(quint64 position); void setPlotInterval(quint64 interval); - void setActivePlot(int uasid); - void setActivePlot(UASInterface* uas); void setActive(bool active); /** @brief Set the number of values to average over */ void setAverageWindow(int windowSize); - /** @brief Start logging to file */ void startLogging(); /** @brief Stop logging to file */ void stopLogging(); + /** @brief Refresh the view */ + void refresh(); protected: - // The plot part (right side) - - /** The widget which contains all or the single plot **/ - QMap plots; - LinechartPlot* activePlot; - /** A lock (mutex) for the concurrent access on the curves **/ - QReadWriteLock* curvesLock; - /** A lock (mutex) for the concurrent access on the window position **/ - QReadWriteLock plotWindowLock; - - QMap* curveLabels; ///< References to the curve labels - QMap* curveMeans; ///< References to the curve means - QMap* curveMedians; ///< References to the curve medians - - // The combo box curve selection part (left side) - - QWidget* curvesWidget; ///< The QWidget containing the curve selection button - QVBoxLayout* curvesWidgetLayout; ///< The layout for the curvesWidget QWidget - QScrollBar* scrollbar; ///< The plot window scroll bar - QSpinBox* averageSpinBox; ///< Spin box to setup average window filter size - void addCurveToList(QString curve); void removeCurveFromList(QString curve); - QWidget* createCurveItem(LinechartPlot* plot, QString curve); + QToolButton* createButton(QWidget* parent); + QWidget* createCurveItem(QString curve); + void createLayout(); - QAction* setScalingLogarithmic; ///< Set logarithmic scaling - QAction* setScalingLinear; ///< Set linear scaling - QAction* addNewCurve; ///< Add curve candidate to the active curves + int sysid; ///< ID of the unmanned system this plot belongs to + LinechartPlot* activePlot; ///< Plot for this system + QReadWriteLock* curvesLock; ///< A lock (mutex) for the concurrent access on the curves + QReadWriteLock plotWindowLock; ///< A lock (mutex) for the concurrent access on the window position - /** Order index of curves **/ int curveListIndex; + int curveListCounter; ///< Counter of curves in curve list + QList* listedCurves; ///< Curves listed + QMap* curveLabels; ///< References to the curve labels + QMap* curveMeans; ///< References to the curve means + QMap* curveMedians; ///< References to the curve medians + + QWidget* curvesWidget; ///< The QWidget containing the curve selection button + QVBoxLayout* curvesWidgetLayout; ///< The layout for the curvesWidget QWidget + QScrollBar* scrollbar; ///< The plot window scroll bar + QSpinBox* averageSpinBox; ///< Spin box to setup average window filter size - /** Counter of curves in curve list **/ - int curveListCounter; + QAction* setScalingLogarithmic; ///< Set logarithmic scaling + QAction* setScalingLinear; ///< Set linear scaling + QAction* addNewCurve; ///< Add curve candidate to the active curves QMenu* curveMenu; - QList* listedCurves; QGridLayout* mainLayout; - void createLayout(); - void setPlot(int uasId); - - /* Factory methods */ - - LinechartContainer* plotContainer; - QToolButton* createButton(QWidget* parent); QToolButton* scalingLinearButton; QToolButton* scalingLogButton; QToolButton* logButton; @@ -145,6 +126,7 @@ protected: QFile* logFile; unsigned int logindex; bool logging; + QTimer* updateTimer; LogCompressor* compressor; static const int MAX_CURVE_MENUITEM_NUMBER = 8; diff --git a/src/ui/linechart/Linecharts.cc b/src/ui/linechart/Linecharts.cc new file mode 100644 index 0000000000000000000000000000000000000000..fa88d9d2f4ec45680f96038f27214aa93f89b43e --- /dev/null +++ b/src/ui/linechart/Linecharts.cc @@ -0,0 +1,66 @@ +#include "Linecharts.h" + +Linecharts::Linecharts(QWidget *parent) : + QStackedWidget(parent), + plots(), + active(true) +{ +} + + +void Linecharts::setActive(bool active) +{ + this->active = active; + QWidget* prevWidget = currentWidget(); + if (prevWidget) + { + LinechartWidget* chart = dynamic_cast(prevWidget); + if (chart) + { + chart->setActive(active); + } + } +} + + +void Linecharts::selectSystem(int systemid) +{ + QWidget* prevWidget = currentWidget(); + if (prevWidget) + { + LinechartWidget* chart = dynamic_cast(prevWidget); + if (chart) + { + chart->setActive(false); + } + } + QWidget* widget = plots.value(systemid, NULL); + if (widget) + { + setCurrentWidget(widget); + LinechartWidget* chart = dynamic_cast(widget); + if (chart) + { + chart->setActive(true); + } + } +} + +void Linecharts::addSystem(UASInterface* uas) +{ + if (!plots.contains(uas->getUASID())) + { + LinechartWidget* widget = new LinechartWidget(uas->getUASID(), this); + addWidget(widget); + plots.insert(uas->getUASID(), widget); + connect(uas, SIGNAL(valueChanged(int,QString,double,quint64)), widget, SLOT(appendData(int,QString,double,quint64))); + // Set system active if this is the only system + if (active) + { + if (plots.size() == 1) + { + selectSystem(uas->getUASID()); + } + } + } +} diff --git a/src/ui/linechart/Linecharts.h b/src/ui/linechart/Linecharts.h new file mode 100644 index 0000000000000000000000000000000000000000..a7342046240ddb99051cfbffd2cd405a0324655a --- /dev/null +++ b/src/ui/linechart/Linecharts.h @@ -0,0 +1,31 @@ +#ifndef LINECHARTS_H +#define LINECHARTS_H + +#include +#include + +#include "LinechartWidget.h" +#include "UASInterface.h" + +class Linecharts : public QStackedWidget +{ +Q_OBJECT +public: + explicit Linecharts(QWidget *parent = 0); + +signals: + +public slots: + /** @brief Set all plots active/inactive */ + void setActive(bool active); + /** @brief Select plot for one system */ + void selectSystem(int systemid); + /** @brief Add a new system to the list of plots */ + void addSystem(UASInterface* uas); + +protected: + QMap plots; + bool active; +}; + +#endif // LINECHARTS_H diff --git a/src/ui/uas/UASListWidget.cc b/src/ui/uas/UASListWidget.cc index 2a4275ec529b85da378fc89a24eb02934460d3ef..7369341e2b6cdf3c2a08d63708a95c7d387feae6 100644 --- a/src/ui/uas/UASListWidget.cc +++ b/src/ui/uas/UASListWidget.cc @@ -87,7 +87,11 @@ void UASListWidget::addUAS(UASInterface* uas) void UASListWidget::activeUAS(UASInterface* uas) { - //uasViews.value(uas)->setUASasActive(true); + UASView* view = uasViews.value(uas, NULL); + if (view) + { + view->setUASasActive(true); + } } void UASListWidget::removeUAS(UASInterface* uas) diff --git a/src/ui/uas/UASView.cc b/src/ui/uas/UASView.cc index af575a430e0e9e69668a87e5d91252841cc75d30..6741bd8f5e47020380cf6ddfb19fef53e6daa7ae 100644 --- a/src/ui/uas/UASView.cc +++ b/src/ui/uas/UASView.cc @@ -225,23 +225,31 @@ void UASView::updateLocalPosition(UASInterface* uas, double x, double y, double } } -void UASView::updateGlobalPosition(UASInterface*, double lon, double lat, double alt, quint64 usec) +void UASView::updateGlobalPosition(UASInterface* uas, double lon, double lat, double alt, quint64 usec) { + Q_UNUSED(uas); + Q_UNUSED(usec); + QString position; + position = position.sprintf("%02.2f %02.2f %02.2f m", lon, lat, alt); + m_ui->positionLabel->setText(position); } void UASView::updateSpeed(UASInterface*, double x, double y, double z, quint64 usec) { - // double totalSpeed = sqrt((pow(x, 2) + pow(y, 2) + pow(z, 2))); - // m_ui->speedBar->setValue(totalSpeed); -} - -void UASView::receiveValue(int uasid, QString id, double value, quint64 time) -{ - + Q_UNUSED(usec); + double totalSpeed = sqrt((pow(x, 2) + pow(y, 2) + pow(z, 2))); + QString speed; + speed = speed.sprintf("%02.2f m/s", totalSpeed); + m_ui->speedLabel->setText(speed); } void UASView::setWaypoint(int uasId, int id, double x, double y, double z, double yaw, bool autocontinue, bool current) { + Q_UNUSED(x); + Q_UNUSED(y); + Q_UNUSED(z); + Q_UNUSED(yaw); + Q_UNUSED(autocontinue); if (uasId == this->uas->getUASID()) { if (current) @@ -269,6 +277,7 @@ void UASView::updateThrust(UASInterface* uas, double thrust) void UASView::updateBattery(UASInterface* uas, double voltage, double percent, int seconds) { + Q_UNUSED(voltage); if (this->uas == uas) { timeRemaining = seconds; diff --git a/src/ui/uas/UASView.h b/src/ui/uas/UASView.h index dd6c3d47a2d39019c4705a4b9b5ad37112ca1b59..6329cdbc70727f426449de569036d428d746a47e 100644 --- a/src/ui/uas/UASView.h +++ b/src/ui/uas/UASView.h @@ -23,7 +23,7 @@ This file is part of the PIXHAWK project /** * @file - * @brief Definition of one airstrip + * @brief Definition of class UASView * * @author Lorenz Meier * @@ -59,7 +59,7 @@ public slots: /** @brief Update the MAV mode */ void updateMode(int sysId, QString status, QString description); void updateLoad(UASInterface* uas, double load); - void receiveValue(int uasid, QString id, double value, quint64 time); + //void receiveValue(int uasid, QString id, double value, quint64 time); void refresh(); /** @brief Receive new waypoint information */ void setWaypoint(int uasId, int id, double x, double y, double z, double yaw, bool autocontinue, bool current);