From e3fb75b356c86ae190f54db7b9fdb43a2e9b31d6 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Wed, 29 May 2013 23:10:58 +0200 Subject: [PATCH 01/44] OP-979 additional fixes in Settings dialog: - Make Environment/General node auto expandable (i.e. always expanded when the dialog is opened) - Reorganize persistent settings (move to own node in XML file + renaming) - Simplify persistent splitter position handling (persist location instead of 2 sizes) --- .../default_configurations/OpenPilotGCS.xml | 11 +++-- .../coreplugin/dialogs/settingsdialog.cpp | 44 +++++++++---------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml index bee98b3e0..1a6e84f42 100644 --- a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml +++ b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml @@ -5,13 +5,16 @@ Default configuration
Default configuration built to work on all screen sizes
false - - true - 600 - 800 default false + + Environment + General + 600 + 800 + 150 + diff --git a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp index d5581ff75..4df71dd76 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp @@ -102,6 +102,7 @@ SettingsDialog::SettingsDialog(QWidget *parent, const QString &categoryId, const QSettings *settings = ICore::instance()->settings(); settings->beginGroup("General"); + settings->beginGroup("Settings"); // restore last displayed category and page // this is done only if no category or page was provided through the constructor @@ -115,31 +116,26 @@ SettingsDialog::SettingsDialog(QWidget *parent, const QString &categoryId, const } // restore window size - int windowWidth = settings->value("SettingsWindowWidth", 0).toInt(); - int windowHeight = settings->value("SettingsWindowHeight", 0).toInt(); + int windowWidth = settings->value("WindowWidth", 0).toInt(); + int windowHeight = settings->value("WindowHeight", 0).toInt(); qDebug() << "SettingsDialog window width :" << windowWidth << ", height:" << windowHeight; if (windowWidth > 0 && windowHeight > 0) { resize(windowWidth, windowHeight); } // restore splitter size - int size0 = settings->value("SettingsSplitterSize0", 0).toInt(); - int size1 = settings->value("SettingsSplitterSize1", 0).toInt(); - qDebug() << "SettingsDialog splitter size0:" << size0 << ", size1:" << size1; + int splitterPosition = settings->value("SplitterPosition", 350).toInt(); + qDebug() << "SettingsDialog splitter position:" << splitterPosition; QList sizes; - if (size0 > 0 && size1 > 0) { - sizes << size0 << size1; - } - else { - sizes << 150 << 300; - } + sizes << splitterPosition << 400; splitter->setSizes(sizes); + settings->endGroup(); settings->endGroup(); // all extra space must go to the option page and none to the tree - splitter->setStretchFactor(splitter->indexOf(pageTree), 0); - splitter->setStretchFactor(splitter->indexOf(layoutWidget), 1); + splitter->setStretchFactor(0, 0); + splitter->setStretchFactor(1, 1); buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); @@ -172,10 +168,11 @@ SettingsDialog::SettingsDialog(QWidget *parent, const QString &categoryId, const } } - // the plugin options page list sorted by untranslated names to facilitate access to the language settings when GCS - // is not running in a language understood by the user. + // the plugin options page list is sorted by untranslated category and names + // this is done to facilitate access to the language settings when GCS is not running in a language understood by the user. qStableSort(pluginPages.begin(), pluginPages.end(), compareOptionsPageByCategoryAndId); - // the plugin options page list sorted is sorted by translated names + + // the plugin options page list is sorted by translated names qStableSort(gadgetPages.begin(), gadgetPages.end(), compareOptionsPageByCategoryAndNameTr); // will hold the initially selected item if any @@ -184,14 +181,14 @@ SettingsDialog::SettingsDialog(QWidget *parent, const QString &categoryId, const // add plugin pages foreach(IOptionsPage *page, pluginPages) { QTreeWidgetItem *item = addPage(page); - // to automatically expand all plugin categories, uncomment next line - //item->parent()->setExpanded(true); + // automatically expand all plugin categories + item->parent()->setExpanded(true); if (page->id() == initialPage && page->category() == initialCategory) { initialItem = item; } } - // insert separator bewteen plugin and gadget pages + // insert separator between plugin and gadget pages QTreeWidgetItem *separator = new QTreeWidgetItem(pageTree); separator->setFlags(separator->flags() & ~Qt::ItemIsSelectable & ~Qt::ItemIsEnabled); separator->setText(0, QString(30, 0xB7)); @@ -453,16 +450,17 @@ void SettingsDialog::done(int val) { QSettings *settings = ICore::instance()->settings(); settings->beginGroup("General"); + settings->beginGroup("Settings"); settings->setValue("LastPreferenceCategory", m_currentCategory); settings->setValue("LastPreferencePage", m_currentPage); - settings->setValue("SettingsWindowWidth", this->width()); - settings->setValue("SettingsWindowHeight", this->height()); + settings->setValue("WindowWidth", this->width()); + settings->setValue("WindowHeight", this->height()); QList sizes = splitter->sizes(); qDebug() << "SettingsDialog splitter saving size0:" << sizes[0] << ", size1:" << sizes[1]; - settings->setValue("SettingsSplitterSize0", sizes[0]); - settings->setValue("SettingsSplitterSize1", sizes[1]); + settings->setValue("SplitterPosition", sizes[0]); + settings->endGroup(); settings->endGroup(); QDialog::done(val); From 64c1c4cda4b2bbc57c6264e30e999a8994db3ac4 Mon Sep 17 00:00:00 2001 From: Kevin Vertucio Date: Thu, 13 Jun 2013 09:09:43 -0400 Subject: [PATCH 02/44] OP-910 updated CREDITS.txt --- CREDITS.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CREDITS.txt b/CREDITS.txt index 8abc0d029..677550577 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -16,6 +16,7 @@ Ed Faulkner Darren Furniss Frederic Goddeeris Daniel Godin +Anthony Gomez Bani Greyling Nuno Guedes Erik Gustavsson @@ -27,6 +28,7 @@ Ryan Hunt Mark James Sami Korhonen Thorsten Klose +Ricky King Hallvard Kristiansen Edouard Lafargue Mike Labranche @@ -36,12 +38,14 @@ David Llama Matt Lipski Les Newell Ken Northup +Ben Matthews Greg Matthews Guy McCaldin Gary Mortimer Alessio Morale Cathy Moss Angus Peart +John Pike Dmytro Poplavskiy Eric Price Richard Querin @@ -58,6 +62,7 @@ Oleg Semyonov Stacey Sheldon Troy Schultz Dr. Erhard Siegl +Dusty Anne Smith Mike Smith Alex Sowa Pete Stapley @@ -69,9 +74,10 @@ Jasper van Loenen Vassilis Varveropoulos Kevin Vertucio Alex Vrubel +Mike Walters Brian Webb Justin Welander Mat Wellington Kendal Wells David Willis -Dmitriy Zaitsev +Dmitriy Zaitsev \ No newline at end of file From 6da421dfa24918e47ae62486219b1dc1d1af7d1d Mon Sep 17 00:00:00 2001 From: Oleg Semyonov Date: Thu, 13 Jun 2013 22:23:56 +0300 Subject: [PATCH 03/44] Update WHATSNEW.txt (magnetometers are not used by default yet) --- WHATSNEW.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index 7cf724ff4..72ccc015c 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -127,6 +127,12 @@ KNOWN ISSUES: - Sensor calibration is not final. It will be reworked completely to increase its accuracy and make it easier to use. +- Until the calibration is reworked, default attitude estimation algorithm + used by Revo is a complimentary filter with magnetometers disabled. Hence + Revo does not use them yet to correct yaw drift. Magnetometers can be + enabled, but you should properly calibrate them first. That's the reason + why they are disabled by default. + - AltitudeHold mode is enabled, but it is not officially supported. Do not expect it to work perfectly and be considered production quality. You may play with it and report your issues and suggestions at your own From 599a5c1bfd0d33c12d77bc297b3e261cf0ee8eb8 Mon Sep 17 00:00:00 2001 From: Oleg Semyonov Date: Thu, 13 Jun 2013 22:33:57 +0300 Subject: [PATCH 04/44] Fix lost last line EOL --- CREDITS.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CREDITS.txt b/CREDITS.txt index 677550577..c39940316 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -80,4 +80,4 @@ Justin Welander Mat Wellington Kendal Wells David Willis -Dmitriy Zaitsev \ No newline at end of file +Dmitriy Zaitsev From 9cd368bd11fa432092b47f79907fa00a2292ab4d Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Thu, 13 Jun 2013 22:48:45 +0200 Subject: [PATCH 05/44] OP-1000 Adds GUI to set Altitude Hold filter parameters. --- .../src/plugins/config/stabilization.ui | 2747 ++++++++++++++++- 1 file changed, 2743 insertions(+), 4 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/config/stabilization.ui b/ground/openpilotgcs/src/plugins/config/stabilization.ui index f45f7888c..7a3216385 100644 --- a/ground/openpilotgcs/src/plugins/config/stabilization.ui +++ b/ground/openpilotgcs/src/plugins/config/stabilization.ui @@ -6,7 +6,7 @@ 0 0 - 983 + 820 736 @@ -461,6 +461,9 @@ + + true + 0 @@ -606,7 +609,7 @@ 0 0 - 953 + 790 653 @@ -8802,7 +8805,7 @@ border-radius: 5; 0 0 - 936 + 773 702 @@ -18805,7 +18808,7 @@ border-radius: 5; 0 0 - 953 + 790 653 @@ -26852,6 +26855,2742 @@ border-radius: 5; + + + Miscellaneous + + + + 0 + + + + + QFrame::NoFrame + + + true + + + + + 0 + 0 + 790 + 653 + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + + + + + 0 + 0 + 0 + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + 255 + 255 + 255 + + + + + + + 251 + 251 + 251 + + + + + + + 124 + 124 + 124 + + + + + + + 165 + 165 + 165 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + 0 + 0 + 0 + + + + + + + 251 + 251 + 251 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + 255 + 255 + 255 + + + + + + + 251 + 251 + 251 + + + + + + + 124 + 124 + 124 + + + + + + + 165 + 165 + 165 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + 0 + 0 + 0 + + + + + + + 251 + 251 + 251 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 124 + 124 + 124 + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + 255 + 255 + 255 + + + + + + + 251 + 251 + 251 + + + + + + + 124 + 124 + 124 + + + + + + + 165 + 165 + 165 + + + + + + + 124 + 124 + 124 + + + + + + + 255 + 255 + 255 + + + + + + + 124 + 124 + 124 + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + 0 + 0 + 0 + + + + + + + 248 + 248 + 248 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + Altitude Hold Stabilization + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + 12 + + + 6 + + + + + + 0 + 0 + + + + + 0 + 140 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 251 + 251 + 251 + + + + + + + 124 + 124 + 124 + + + + + + + 165 + 165 + 165 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 251 + 251 + 251 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 251 + 251 + 251 + + + + + + + 124 + 124 + 124 + + + + + + + 165 + 165 + 165 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 251 + 251 + 251 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 124 + 124 + 124 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 251 + 251 + 251 + + + + + + + 124 + 124 + 124 + + + + + + + 165 + 165 + 165 + + + + + + + 124 + 124 + 124 + + + + + + + 255 + 255 + 255 + + + + + + + 124 + 124 + 124 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 248 + 248 + 248 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + false + + + QGroupBox{border: 0px;} + + + + + + true + + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + Integral + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 69 + 16 + + + + + + + Proportional + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 58 + 0 + + + + + 16777215 + 16777215 + + + + + + + Derivative + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 20 + + + 10 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + + objname:AltitudeHoldSettings + fieldname:ThrottleRate + haslimits:no + scale:1 + buttongroup:99 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 10 + + + + + + + + + 0 + 0 + + + + + 69 + 16 + + + + + + + Exponential + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 100 + + + 50 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + + objname:AltitudeHoldSettings + fieldname:Kp + scale:0.001 + haslimits:yes + buttongroup:99 + + + + + + + + 100 + + + 50 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + + objname:AltitudeHoldSettings + fieldname:Ki + scale:0.001 + haslimits:yes + buttongroup:99 + + + + + + + + + 0 + 0 + + + + + 50 + 22 + + + + + 50 + 22 + + + + Qt::StrongFocus + + + <html><head/><body><p>This adjusts how much leveling stability is set into Rate mode (inner loop). Too much will make your vehicle oscillate in Rate mode.</p></body></html> + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 0 + + + 256.000000000000000 + + + 1.000000000000000 + + + 128.000000000000000 + + + + objname:AltitudeHoldSettings + fieldname:ThrottleExp + haslimits:no + scale:1 + buttongroup:99 + + + + + + + + + 0 + 0 + + + + + + + Rate + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 100 + + + 50 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + + objname:AltitudeHoldSettings + fieldname:Kd + scale:0.001 + haslimits:yes + buttongroup:99 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 10 + + + + + + + + + 0 + 0 + + + + + 50 + 22 + + + + + 50 + 22 + + + + Qt::StrongFocus + + + <html><head/><body><p>This adjusts how much stabilty your vehicle will have when flying tilted (ie forward flight) in Rate Mode. A good starting point for Integral is the same as Proportional.</p></body></html> + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 1 + + + 20.000000000000000 + + + 0.100000000000000 + + + 10.000000000000000 + + + + objname:AltitudeHoldSettings + fieldname:ThrottleRate + haslimits:no + scale:1 + buttongroup:99 + + + + + + + + 256 + + + 128 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + + objname:AltitudeHoldSettings + fieldname:ThrottleExp + haslimits:no + scale:1 + buttongroup:99 + + + + + + + + + 0 + 0 + + + + + 0 + 16 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 58 + 58 + 58 + + + + + + + 48 + 48 + 48 + + + + + + + 19 + 19 + 19 + + + + + + + 26 + 26 + 26 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 0 + 0 + 0 + + + + + + + 19 + 19 + 19 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 58 + 58 + 58 + + + + + + + 48 + 48 + 48 + + + + + + + 19 + 19 + 19 + + + + + + + 26 + 26 + 26 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 0 + 0 + 0 + + + + + + + 19 + 19 + 19 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 58 + 58 + 58 + + + + + + + 48 + 48 + 48 + + + + + + + 19 + 19 + 19 + + + + + + + 26 + 26 + 26 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 0 + 0 + 0 + + + + + + + 39 + 39 + 39 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 75 + true + + + + false + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; + + + Throttle + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 16 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 58 + 58 + 58 + + + + + + + 48 + 48 + 48 + + + + + + + 19 + 19 + 19 + + + + + + + 26 + 26 + 26 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 0 + 0 + 0 + + + + + + + 19 + 19 + 19 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 58 + 58 + 58 + + + + + + + 48 + 48 + 48 + + + + + + + 19 + 19 + 19 + + + + + + + 26 + 26 + 26 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 0 + 0 + 0 + + + + + + + 19 + 19 + 19 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 58 + 58 + 58 + + + + + + + 48 + 48 + 48 + + + + + + + 19 + 19 + 19 + + + + + + + 26 + 26 + 26 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 0 + 0 + 0 + + + + + + + 39 + 39 + 39 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 75 + true + + + + false + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; + + + Altitude + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 50 + 22 + + + + + 50 + 22 + + + + Qt::StrongFocus + + + <html><head/><body><p>This adjusts how much leveling stability is set into Rate mode (inner loop). Too much will make your vehicle oscillate in Rate mode.</p></body></html> + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 100 + + + 51 + + + + objname:AltitudeHoldSettings + fieldname:Kp + scale:0.001 + haslimits:yes + buttongroup:99 + + + + + + + + + 0 + 0 + + + + + 50 + 22 + + + + + 50 + 22 + + + + Qt::StrongFocus + + + <html><head/><body><p>This adjusts how much stabilty your vehicle will have when flying tilted (ie forward flight) in Rate Mode. A good starting point for Integral is the same as Proportional.</p></body></html> + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 100 + + + 51 + + + + objname:AltitudeHoldSettings + fieldname:Ki + scale:0.001 + haslimits:yes + buttongroup:99 + + + + + + + + + 0 + 0 + + + + + 50 + 22 + + + + + 50 + 22 + + + + Qt::StrongFocus + + + <html><head/><body><p>This makes the control output respond faster due to fast stick movements or external disturbance like wind gusts.It also acts like a dampener, thus allowing higher KP settings. Only effects Rate Mode.</p></body></html> + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 100 + + + 51 + + + + objname:AltitudeHoldSettings + fieldname:Kd + scale:0.001 + haslimits:yes + buttongroup:99 + + + + + + + + + + + Qt::Horizontal + + + + 497 + 20 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Reset all values to GCS defaults + + + + + + Default + + + + objname:AltitudeHoldSettings + button:default + buttongroup:99 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + From 00737925611448d1523ca45155720d892590d455 Mon Sep 17 00:00:00 2001 From: Mathieu Rondonneau Date: Fri, 14 Jun 2013 19:24:42 -0700 Subject: [PATCH 06/44] OP-1011: Remove deprecated powerlog --- .../translations/openpilotgcs_de.ts | 18 - .../translations/openpilotgcs_es.ts | 18 - .../translations/openpilotgcs_fr.ts | 18 - .../translations/openpilotgcs_ru.ts | 18 - .../translations/openpilotgcs_zh_CN.ts | 18 - ground/openpilotgcs/src/plugins/plugins.pro | 5 - .../src/plugins/powerlog/PowerLog.pluginspec | 11 - .../src/plugins/powerlog/powerlog.pro | 11 - .../powerlog/powerlog_dependencies.pri | 2 - .../src/plugins/powerlog/powerlogplugin.cpp | 369 ------------------ .../src/plugins/powerlog/powerlogplugin.h | 135 ------- 11 files changed, 623 deletions(-) delete mode 100644 ground/openpilotgcs/src/plugins/powerlog/PowerLog.pluginspec delete mode 100644 ground/openpilotgcs/src/plugins/powerlog/powerlog.pro delete mode 100644 ground/openpilotgcs/src/plugins/powerlog/powerlog_dependencies.pri delete mode 100644 ground/openpilotgcs/src/plugins/powerlog/powerlogplugin.cpp delete mode 100644 ground/openpilotgcs/src/plugins/powerlog/powerlogplugin.h diff --git a/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_de.ts b/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_de.ts index fad9557a4..106433d33 100644 --- a/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_de.ts +++ b/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_de.ts @@ -13562,24 +13562,6 @@ Move the %1 stick. - - PowerlogPlugin - - - Log filename - - - - - PowerLog-%0.csv - - - - - Comma Separated Values (*.csv) - - - QmlViewGadgetFactory diff --git a/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_es.ts b/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_es.ts index 5f29e13a0..1a9d98543 100644 --- a/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_es.ts +++ b/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_es.ts @@ -13563,24 +13563,6 @@ Move the %1 stick. - - PowerlogPlugin - - - Log filename - - - - - PowerLog-%0.csv - - - - - Comma Separated Values (*.csv) - - - QmlViewGadgetFactory diff --git a/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_fr.ts b/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_fr.ts index d7414840c..165057d2f 100644 --- a/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_fr.ts +++ b/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_fr.ts @@ -14000,24 +14000,6 @@ Bougez le manche %1. - - PowerlogPlugin - - - Log filename - Fichier de journal - - - - PowerLog-%0.csv - - - - - Comma Separated Values (*.csv) - - - QmlViewGadgetFactory diff --git a/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_ru.ts b/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_ru.ts index 842ad65d1..5d625d8a2 100644 --- a/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_ru.ts +++ b/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_ru.ts @@ -13585,24 +13585,6 @@ Move the %1 stick. - - PowerlogPlugin - - - Log filename - - - - - PowerLog-%0.csv - - - - - Comma Separated Values (*.csv) - - - QmlViewGadgetFactory diff --git a/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_zh_CN.ts b/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_zh_CN.ts index 6c3652305..c1c16f9ed 100644 --- a/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_zh_CN.ts +++ b/ground/openpilotgcs/share/openpilotgcs/translations/openpilotgcs_zh_CN.ts @@ -13565,24 +13565,6 @@ Move the %1 stick. - - PowerlogPlugin - - - Log filename - - - - - PowerLog-%0.csv - - - - - Comma Separated Values (*.csv) - - - QmlViewGadgetFactory diff --git a/ground/openpilotgcs/src/plugins/plugins.pro b/ground/openpilotgcs/src/plugins/plugins.pro index 20b402704..3f371b722 100644 --- a/ground/openpilotgcs/src/plugins/plugins.pro +++ b/ground/openpilotgcs/src/plugins/plugins.pro @@ -244,8 +244,3 @@ plugin_setupwizard.depends += plugin_config plugin_setupwizard.depends += plugin_uploader SUBDIRS += plugin_setupwizard -# Junsi Powerlog plugin -#plugin_powerlog.subdir = powerlog -#plugin_powerlog.depends = plugin_coreplugin -#plugin_powerlog.depends += plugin_rawhid -#SUBDIRS += plugin_powerlog diff --git a/ground/openpilotgcs/src/plugins/powerlog/PowerLog.pluginspec b/ground/openpilotgcs/src/plugins/powerlog/PowerLog.pluginspec deleted file mode 100644 index 24ac39811..000000000 --- a/ground/openpilotgcs/src/plugins/powerlog/PowerLog.pluginspec +++ /dev/null @@ -1,11 +0,0 @@ - - The OpenPilot Project - (C) 2010 OpenPilot - The GNU Public License (GPL) Version 3 - A plugin that downloads the log from a Junsi PowerLog6S to a file - http://www.openpilot.org - - - - - diff --git a/ground/openpilotgcs/src/plugins/powerlog/powerlog.pro b/ground/openpilotgcs/src/plugins/powerlog/powerlog.pro deleted file mode 100644 index e521ad17c..000000000 --- a/ground/openpilotgcs/src/plugins/powerlog/powerlog.pro +++ /dev/null @@ -1,11 +0,0 @@ -TEMPLATE = lib -TARGET = PowerLog -DEFINES += POWERLOG_LIBRARY -include(../../openpilotgcsplugin.pri) -include(powerlog_dependencies.pri) -HEADERS += powerlogplugin.h - -SOURCES += powerlogplugin.cpp - -OTHER_FILES += PowerLog.pluginspec - diff --git a/ground/openpilotgcs/src/plugins/powerlog/powerlog_dependencies.pri b/ground/openpilotgcs/src/plugins/powerlog/powerlog_dependencies.pri deleted file mode 100644 index f77ee6b96..000000000 --- a/ground/openpilotgcs/src/plugins/powerlog/powerlog_dependencies.pri +++ /dev/null @@ -1,2 +0,0 @@ -include(../../plugins/coreplugin/coreplugin.pri) -include(../../plugins/rawhid/opHID.pri) diff --git a/ground/openpilotgcs/src/plugins/powerlog/powerlogplugin.cpp b/ground/openpilotgcs/src/plugins/powerlog/powerlogplugin.cpp deleted file mode 100644 index 5f0b9c820..000000000 --- a/ground/openpilotgcs/src/plugins/powerlog/powerlogplugin.cpp +++ /dev/null @@ -1,369 +0,0 @@ -/** - ****************************************************************************** - * - * @file powerlogplugin.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @see The GNU Public License (GPL) Version 3 - * @brief Junsi Powerlog utility Plugin - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup PowerLog - * @{ - * - *****************************************************************************/ -/* - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "powerlogplugin.h" -#include "rawhid/usbmonitor.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -/** - * Sets the file to use for logging and takes the parent plugin - * to connect to stop logging signal - * @param[in] file File name to write to - * @param[in] parent plugin - */ -bool PowerlogThread::openFile(QString file, PowerlogPlugin *parent) -{ - logFile.setFileName(file); - logFile.open(QIODevice::WriteOnly); - fileStream.setDevice(&logFile); - - connect(parent, SIGNAL(stopLoggingSignal()), this, SLOT(stopLogging())); - - return true; -}; - -/** - * Get all logs from Powerlog - */ -void PowerlogThread::run() -{ - // TODO: pop up a dialog here! - - qDebug() << "Connect a Junsi PowerLog 6S and watch the logging output"; - opHID_hidapi hidHandle; - int numDevices = hidHandle.open(1, 0x0483, 0x5750, 0, 0); // 0xff9c,0x0001); - if (numDevices == 0) { - numDevices = hidHandle.open(1, 0x0483, 0, 0, 0); - } - - qDebug() << numDevices << " device(s) opened"; - if (numDevices == 0) { - return; - } - - // hidHandle.mytest(0); - - char buf[BUF_LEN]; - buf[0] = 2; - buf[1] = 0; - - fileStream << "Interval,Current,Volt,Cap,Cell1,Cell2,Cell3,Cell4,Cell5,Cell6,RPM,Temp0,Temp1,Temp2,Temp3,Period,Pulse\n"; - - while (int received = hidHandle.receive(0, buf, BUF_LEN, 3500)) { - ShowInf(buf); - fileStream.flush(); // Just to be sure... - } - - stopLogging(); -} - -/** - * Pass this command to the correct thread then close the file - */ -void PowerlogThread::stopLogging() -{ - QWriteLocker locker(&lock); - - fileStream.flush(); - logFile.close(); - quit(); -} - -/** - * Formats the content of the buffer we just read and write - * to the logfile - */ -void PowerlogThread::ShowInf(char *pBuf) -{ - POWERLOG_HID_PACK Inf; - int i; - int Count; - - Count = 0; - Inf.Len = pBuf[Count]; - Count += sizeof(Inf.Len); - - Inf.Type = pBuf[Count]; - Count += sizeof(Inf.Type); - - Inf.Interval = *((DWORD *)&pBuf[Count]); - fileStream << QString::number(Inf.Interval) << ","; - - Count += sizeof(Inf.Interval); - - Inf.LogState = pBuf[Count]; - Count += sizeof(Inf.LogState); - - if (((Inf.Type == TYPE_DATA_ONLINE) || (Inf.Type == TYPE_DATA_OFFLINE)) && (Inf.Len == 0x29)) { // 0x27 - Inf.Current = *((SHORT *)&pBuf[Count]); - Count += sizeof(Inf.Current); - GetShowValue(QString("Current"), Inf.Current, 5, 2); - - Inf.Volt = *((USHORT *)&pBuf[Count]); - Count += sizeof(Inf.Volt); - GetShowValue(QString("Voltage"), Inf.Volt, 5, 2); - - Inf.Cap = *((DWORD *)&pBuf[Count]); - Count += sizeof(Inf.Cap); - GetShowValue(QString("Cap"), Inf.Cap, 6, 0); - - for (i = 0; i < 6; i++) { - Inf.Cell[i] = *((SHORT *)&pBuf[Count]); - Count += sizeof(Inf.Cell[i]); - } - GetShowValue(QString("Cell 1"), Inf.Cell[0], 5, 3); - GetShowValue(QString("Cell 2"), Inf.Cell[1], 5, 3); - GetShowValue(QString("Cell 3"), Inf.Cell[2], 5, 3); - GetShowValue(QString("Cell 4"), Inf.Cell[3], 5, 3); - GetShowValue(QString("Cell 5"), Inf.Cell[4], 5, 3); - GetShowValue(QString("Cell 6"), Inf.Cell[5], 5, 3); - - Inf.RPM = *((USHORT *)&pBuf[Count]); - Count += sizeof(Inf.RPM); - GetShowValue(QString("RPM"), Inf.RPM, 6, 0); - - for (i = 0; i < 4; i++) { - Inf.Temp[i] = *((SHORT *)&pBuf[Count]); - Count += sizeof(Inf.Temp[i]); - } - GetShowValue(QString("Int Temp0"), Inf.Temp[0], 4, 1); - - if (Inf.Temp[1] == 0x7fff) { - fileStream << "0.0,"; - } else { - GetShowValue(QString("Ext temp1"), Inf.Temp[1], 4, 1); - } - - if (Inf.Temp[2] == 0x7fff) { - fileStream << "0.0,"; - } else { - GetShowValue(QString("Ext temp2"), Inf.Temp[2], 4, 1); - } - - if (Inf.Temp[3] == 0x7fff) { - fileStream << "0.0,"; - } else { - GetShowValue(QString("Ext temp3"), Inf.Temp[3], 4, 1); - } - - Inf.Period = *((USHORT *)&pBuf[Count]); - Count += sizeof(Inf.Period); - GetShowValue(QString("Period:"), Inf.Period, 6, 0); - - Inf.Pulse = *((USHORT *)&pBuf[Count]); - Count += sizeof(Inf.Pulse); - GetShowValue(QString("Pulse:"), Inf.Pulse, 6, 0); - - fileStream << "\n"; - } -} - -/** - * Formats a numeric value - */ -void PowerlogThread::GetShowValue(QString label, DWORD Value, WORD Len, WORD Dot) -{ - QString out; - - if (Value < 0) { - fileStream << "-"; - Value = -Value; - } - - if (Dot == 1) { - fileStream << Value / 10 << "." << Value % 10; // printf("%ld.%01lu",Value/10,Value%10); - } else if (Dot == 2) { - fileStream << Value / 100 << "." << Value % 100; // printf("%ld.%02lu",Value/100,Value%100); - } else if (Dot == 3) { - fileStream << Value / 1000 << "." << Value % 1000; // printf("%ld.%03lu",Value/1000,Value%1000); - } else if (Dot == 4) { - fileStream << Value / 10000 << "." << Value % 10000; // printf("%ld.%04lu",Value/10000,Value%10000); - } else { - fileStream << Value; // printf("%ld",Value); - } - fileStream << out << ","; -} - - -/**************************************************************** - Logging plugin - ********************************/ - - -PowerlogPlugin::PowerlogPlugin() : - devSerialNumber(""), - logging(false), - loggingThread(NULL) -{} - -PowerlogPlugin::~PowerlogPlugin() -{} - -/** - * Add Powerlog plugin entry to File menu - */ -bool PowerlogPlugin::initialize(const QStringList & args, QString *errMsg) -{ - Q_UNUSED(args); - Q_UNUSED(errMsg); - - - // Add Menu entry - Core::ActionManager *am = Core::ICore::instance()->actionManager(); - Core::ActionContainer *ac = am->actionContainer(Core::Constants::M_TOOLS); - - // Command to start logging - cmd = am->registerAction(new QAction(this), - "PowerlogPlugin.Transfer", - QList() << - Core::Constants::C_GLOBAL_ID); - cmd->action()->setText("Receive from PowerLog6S..."); - - ac->menu()->addSeparator(); - ac->appendGroup("Utilities"); - ac->addAction(cmd, "Utilities"); - - connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(receiveLog())); - - // At this stage we know that other plugins we depend upon are - // initialized, in prticular the USB Monitor is now running: - USBMonitor *mon = USBMonitor::instance(); - connect(mon, SIGNAL(deviceDiscovered(USBPortInfo)), this, SLOT(devConnected(USBPortInfo))); - connect(mon, SIGNAL(deviceRemoved(USBPortInfo)), this, SLOT(devRemoved(USBPortInfo))); - - return true; -} - -/** - * The action that is triggered by the menu item which opens the - * file and begins log reception if successful - */ -void PowerlogPlugin::receiveLog() -{ - if (logging) { - loggingThread->stopLogging(); - logging = false; - cmd->action()->setText("Receive from PowerLog6S..."); - } else { - QString fileName = QFileDialog::getSaveFileName(NULL, tr("Log filename"), - tr("PowerLog-%0.csv").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss")), - tr("Comma Separated Values (*.csv)")); - if (fileName.isEmpty()) { - return; - } - - loggingThread = new PowerlogThread(); - if (loggingThread->openFile(fileName, this)) { - loggingThread->start(); - cmd->action()->setText("Stop PowerLog6S reception"); - logging = true; - } - } -} - -/** - Device connected, check whether it is a powerlog & act accordingly - */ -void PowerlogPlugin::devConnected(USBPortInfo port) -{ - if (devSerialNumber.length() > 0) { - return; - } - if ((port.vendorID == 0x0483) && (port.productID == 0x5750)) { - devSerialNumber = port.serialNumber; - cmd->action()->setEnabled(true); - } -} - - -/** - Device Removed, check whether it is a powerlog & act accordingly. - As when the device is removed, we don't get the info on the device, - we have to list all available remaining devices and check if the serial - number of our device is missing... - */ -void PowerlogPlugin::devRemoved(USBPortInfo port) -{ - bool foundDevice; - - QList ports = USBMonitor::instance()->availableDevices(); - foreach(USBPortInfo port, ports) { - if ((port.vendorID == 0x0483) && (port.productID == 0x5750) && - (devSerialNumber == port.serialNumber)) { - foundDevice = true; - break; - } - } - if (!foundDevice) { - devSerialNumber = QString(""); - cmd->action()->setEnabled(false); - // Also stop logging in case we were logging: - if (loggingThread) { - loggingThread->stopLogging(); - } - } -} - - -void PowerlogPlugin::extensionsInitialized() -{ - cmd->action()->setEnabled(false); - QList ports = USBMonitor::instance()->availableDevices(); - foreach(USBPortInfo port, ports) { - if ((port.vendorID == 0x0483) && (port.productID == 0x5750)) { - devSerialNumber = port.serialNumber; - cmd->action()->setEnabled(true); - break; - } - } -} - -void PowerlogPlugin::shutdown() -{ - // Do nothing -} -Q_EXPORT_PLUGIN(PowerlogPlugin) - -/** - * @} - * @} - */ diff --git a/ground/openpilotgcs/src/plugins/powerlog/powerlogplugin.h b/ground/openpilotgcs/src/plugins/powerlog/powerlogplugin.h deleted file mode 100644 index 70054cfab..000000000 --- a/ground/openpilotgcs/src/plugins/powerlog/powerlogplugin.h +++ /dev/null @@ -1,135 +0,0 @@ -/** - ****************************************************************************** - * @file powerlogplugin.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @see The GNU Public License (GPL) Version 3 - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup powerlogplugin - * @{ - *****************************************************************************/ -/* - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef POWERLOGPLUGIN_H_ -#define POWERLOGPLUGIN_H_ - -#include -#include -#include -#include -#include -#include "opHID/inc/opHID_usbmon.h" -#include "opHID/inc/opHID_hidapi.h" - -#include -#include -#include - -using namespace std; - -typedef unsigned long ULONG; // 4 Bytes -typedef short SHORT; -typedef unsigned short USHORT; // 2 Bytes -typedef unsigned char BYTE; // 1 Byte -typedef unsigned short WORD; // 2 Bytes -typedef unsigned long DWORD; // 4 Bytes - - -#define BUF_LEN 64 -struct POWERLOG_HID_PACK { - BYTE Len; - BYTE Type; - DWORD Interval; - BYTE LogState; - SHORT Current; - USHORT Volt; - DWORD Cap; - SHORT Cell[6]; - USHORT RPM; - SHORT Temp[4]; - USHORT Period; - USHORT Pulse; -}; - -enum { - TYPE_DATA_ONLINE = 0x10, - TYPE_DATA_OFFLINE = 0x11, - TYPE_ORDER = 0x20, -}; - - -class PowerlogPlugin; - -class PowerlogThread : public QThread { - Q_OBJECT - -public: - bool openFile(QString file, PowerlogPlugin *parent); - -private slots: - -public slots: - void stopLogging(); - -protected: - void run(); - QReadWriteLock lock; - QFile logFile; - QTextStream fileStream; - -private: - void ShowInf(char *pBuf); - void GetShowValue(QString label, DWORD Value, WORD Len, WORD Dot); -}; - - -class PowerlogPlugin : public ExtensionSystem::IPlugin { - Q_OBJECT - - -public: - PowerlogPlugin(); - ~PowerlogPlugin(); - - void extensionsInitialized(); - bool initialize(const QStringList & arguments, QString *errorString); - void shutdown(); - - void setPowerlogMenuTitle(QString str); - - -signals: - void stopLoggingSignal(void); - -protected: - -private slots: - void receiveLog(); - void devConnected(USBPortInfo); - void devRemoved(USBPortInfo); - -private: - Core::Command *cmd; - QString devSerialNumber; - PowerlogThread *loggingThread; - bool logging; -}; -#endif /* POWERLOGPLUGIN_H_ */ -/** - * @} - * @} - */ From 02562902a9adb66686b771ccb4fd7539da3caff5 Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Sat, 15 Jun 2013 13:00:54 +0200 Subject: [PATCH 07/44] OP-1000 Adds disabling of AH settings tab if board is not Revolution. --- .../plugins/config/configstabilizationwidget.cpp | 13 ++++++++++++- .../src/plugins/config/configstabilizationwidget.h | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp index 896801f16..b4033d101 100644 --- a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp @@ -90,6 +90,8 @@ ConfigStabilizationWidget::ConfigStabilizationWidget(QWidget *parent) : ConfigTa connect(this, SIGNAL(widgetContentsChanged(QWidget *)), this, SLOT(processLinkedWidgets(QWidget *))); + connect(this, SIGNAL(autoPilotConnected()), this, SLOT(onBoardConnected())); + // Link by default ui->checkBox_7->setChecked(true); ui->checkBox_8->setChecked(true); @@ -103,7 +105,6 @@ ConfigStabilizationWidget::~ConfigStabilizationWidget() // Do nothing } - void ConfigStabilizationWidget::refreshWidgetsValues(UAVObject *o) { ConfigTaskWidget::refreshWidgetsValues(o); @@ -194,3 +195,13 @@ void ConfigStabilizationWidget::processLinkedWidgets(QWidget *widget) } } } + +void ConfigStabilizationWidget::onBoardConnected() +{ + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectUtilManager *utilMngr = pm->getObject(); + Q_ASSERT(utilMngr); + + // If Revolution board enable misc tab, otherwise disable it + ui->Miscellaneous->setEnabled((utilMngr->getBoardModel() & 0xff00) == 0x0900); +} diff --git a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.h b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.h index 7f6324779..0a783f4c5 100644 --- a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.h +++ b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.h @@ -58,6 +58,7 @@ private slots: void realtimeUpdatesSlot(bool value); void linkCheckBoxes(bool value); void processLinkedWidgets(QWidget *); + void onBoardConnected(); }; #endif // ConfigStabilizationWidget_H From 1a1b1b1e4ee34c7e0df9b0bf71d55a77404987b2 Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Sat, 15 Jun 2013 13:40:46 +0200 Subject: [PATCH 08/44] OP-1010 Removes some default check-box settings. --- .../src/plugins/config/configstabilizationwidget.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp index b4033d101..92d1b6dfb 100644 --- a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp @@ -92,10 +92,6 @@ ConfigStabilizationWidget::ConfigStabilizationWidget(QWidget *parent) : ConfigTa connect(this, SIGNAL(autoPilotConnected()), this, SLOT(onBoardConnected())); - // Link by default - ui->checkBox_7->setChecked(true); - ui->checkBox_8->setChecked(true); - disableMouseWheelEvents(); updateEnableControls(); } From cb3ba339fe0480b1d5e223251c6938efc25f7286 Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Sat, 15 Jun 2013 14:02:43 +0200 Subject: [PATCH 09/44] OP-1000 Changes some ranges. Removed faulty tool-tips. --- .../src/plugins/config/stabilization.ui | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/config/stabilization.ui b/ground/openpilotgcs/src/plugins/config/stabilization.ui index 7a3216385..79d0b8c46 100644 --- a/ground/openpilotgcs/src/plugins/config/stabilization.ui +++ b/ground/openpilotgcs/src/plugins/config/stabilization.ui @@ -27960,10 +27960,16 @@ border-radius: 5; - 20 + 10 + + + 1 + + + 1 - 10 + 5 Qt::Horizontal @@ -27971,12 +27977,15 @@ border-radius: 5; QSlider::TicksBelow + + 0 + objname:AltitudeHoldSettings fieldname:ThrottleRate haslimits:no - scale:1 + scale:0.5 buttongroup:99 @@ -28096,9 +28105,6 @@ border-radius: 5; Qt::StrongFocus - - <html><head/><body><p>This adjusts how much leveling stability is set into Rate mode (inner loop). Too much will make your vehicle oscillate in Rate mode.</p></body></html> - @@ -28211,9 +28217,6 @@ border-radius: 5; Qt::StrongFocus - - <html><head/><body><p>This adjusts how much stabilty your vehicle will have when flying tilted (ie forward flight) in Rate Mode. A good starting point for Integral is the same as Proportional.</p></body></html> - @@ -28224,13 +28227,13 @@ border-radius: 5; 1 - 20.000000000000000 + 5.000000000000000 0.100000000000000 - 10.000000000000000 + 2.500000000000000 @@ -29391,9 +29394,6 @@ border-radius: 5; Qt::StrongFocus - - <html><head/><body><p>This adjusts how much leveling stability is set into Rate mode (inner loop). Too much will make your vehicle oscillate in Rate mode.</p></body></html> - @@ -29440,9 +29440,6 @@ border-radius: 5; Qt::StrongFocus - - <html><head/><body><p>This adjusts how much stabilty your vehicle will have when flying tilted (ie forward flight) in Rate Mode. A good starting point for Integral is the same as Proportional.</p></body></html> - @@ -29489,9 +29486,6 @@ border-radius: 5; Qt::StrongFocus - - <html><head/><body><p>This makes the control output respond faster due to fast stick movements or external disturbance like wind gusts.It also acts like a dampener, thus allowing higher KP settings. Only effects Rate Mode.</p></body></html> - From 49da1aca865a7ce4a1a1015d882b4f5612e0e687 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Sat, 15 Jun 2013 16:22:24 +0200 Subject: [PATCH 10/44] OP-1009 Redo gyro zero in Complementary after calibration parameters changes --- flight/modules/Attitude/revolution/attitude.c | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/flight/modules/Attitude/revolution/attitude.c b/flight/modules/Attitude/revolution/attitude.c index 452ba4ba2..ac4317466 100644 --- a/flight/modules/Attitude/revolution/attitude.c +++ b/flight/modules/Attitude/revolution/attitude.c @@ -75,10 +75,12 @@ #include "CoordinateConversions.h" // Private constants -#define STACK_SIZE_BYTES 2048 -#define TASK_PRIORITY (tskIDLE_PRIORITY + 3) -#define FAILSAFE_TIMEOUT_MS 10 +#define STACK_SIZE_BYTES 2048 +#define TASK_PRIORITY (tskIDLE_PRIORITY + 3) +#define FAILSAFE_TIMEOUT_MS 10 +#define CALIBRATION_DELAY 4000 +#define CALIBRATION_DURATION 6000 // low pass filter configuration to calculate offset // of barometric altitude sensor // reasoning: updates at: 10 Hz, tau= 300 s settle time @@ -319,6 +321,7 @@ static int32_t updateAttitudeComplementary(bool first_run) float dT; static uint8_t init = 0; static bool magCalibrated = true; + static uint32_t initStartupTime = 0; // Wait until the AttitudeRaw object is updated, if a timeout then go to failsafe if (xQueueReceive(gyroQueue, &ev, FAILSAFE_TIMEOUT_MS / portTICK_RATE_MS) != pdTRUE || @@ -389,10 +392,26 @@ static int32_t updateAttitudeComplementary(bool first_run) timeval = PIOS_DELAY_GetRaw(); + // wait calibration_delay only at powerup + if (xTaskGetTickCount() < 3000) { + initStartupTime = 0; + } else { + initStartupTime = xTaskGetTickCount() - CALIBRATION_DELAY; + } + + // Zero gyro bias + // This is really needed after updating calibration settings. + GyrosBiasData zeroGyrosBias; + GyrosBiasGet(&zeroGyrosBias); + zeroGyrosBias.x = 0; + zeroGyrosBias.y = 0; + zeroGyrosBias.z = 0; + GyrosBiasSet(&zeroGyrosBias); return 0; } - if ((xTaskGetTickCount() < 10000) && (xTaskGetTickCount() > 4000)) { + if ((xTaskGetTickCount() - initStartupTime < CALIBRATION_DURATION + CALIBRATION_DELAY) && + (xTaskGetTickCount() - initStartupTime > CALIBRATION_DELAY)) { // For first 7 seconds use accels to get gyro bias attitudeSettings.AccelKp = 1.0f; attitudeSettings.AccelKi = 0.0f; @@ -619,8 +638,9 @@ static int32_t updateAttitudeComplementary(bool first_run) } } - - if (variance_error) { + if (!init) { + AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE, SYSTEMALARMS_ALARM_ERROR); + } else if (variance_error) { AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE, SYSTEMALARMS_ALARM_CRITICAL); } else { AlarmsClear(SYSTEMALARMS_ALARM_ATTITUDE); From 354fdf4bdfadecdf6ee1686cc7f1149f0a5556b3 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Sat, 15 Jun 2013 16:38:53 +0200 Subject: [PATCH 11/44] OP-1012 implement several messages for alarm led --- flight/modules/System/systemmod.c | 32 +++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/flight/modules/System/systemmod.c b/flight/modules/System/systemmod.c index b218876be..c2f8b660a 100644 --- a/flight/modules/System/systemmod.c +++ b/flight/modules/System/systemmod.c @@ -167,7 +167,7 @@ static void systemTask(__attribute__((unused)) void *parameters) { /* start the delayed callback scheduler */ CallbackSchedulerStart(); - + static uint8_t cycleCount; /* create all modules thread */ MODULE_TASKCREATE_ALL; @@ -204,6 +204,7 @@ static void systemTask(__attribute__((unused)) void *parameters) while (1) { // Update the system statistics updateStats(); + cycleCount = cycleCount > 0 ? cycleCount - 1 : 3; // Update the system alarms updateSystemAlarms(); @@ -220,26 +221,33 @@ static void systemTask(__attribute__((unused)) void *parameters) // Flash the heartbeat LED #if defined(PIOS_LED_HEARTBEAT) - PIOS_LED_Toggle(PIOS_LED_HEARTBEAT); + uint8_t armingStatus; + FlightStatusArmedGet(&armingStatus); + if ((armingStatus == FLIGHTSTATUS_ARMED_ARMED && (cycleCount & 0x1)) || + (armingStatus != FLIGHTSTATUS_ARMED_ARMED && (cycleCount & 0x2))) { + PIOS_LED_On(PIOS_LED_HEARTBEAT); + } else { + PIOS_LED_Off(PIOS_LED_HEARTBEAT); + } + DEBUG_MSG("+ 0x%08x\r\n", 0xDEADBEEF); #endif /* PIOS_LED_HEARTBEAT */ // Turn on the error LED if an alarm is set #if defined(PIOS_LED_ALARM) - if (AlarmsHasWarnings()) { + if (AlarmsHasCritical()) { + PIOS_LED_On(PIOS_LED_ALARM); + } else if( (AlarmsHasErrors() && (cycleCount & 0x1)) || + (!AlarmsHasErrors() && AlarmsHasWarnings() && (cycleCount & 0x2))){ PIOS_LED_On(PIOS_LED_ALARM); } else { PIOS_LED_Off(PIOS_LED_ALARM); } #endif /* PIOS_LED_ALARM */ - FlightStatusData flightStatus; - FlightStatusGet(&flightStatus); UAVObjEvent ev; - int delayTime = flightStatus.Armed == FLIGHTSTATUS_ARMED_ARMED ? - SYSTEM_UPDATE_PERIOD_MS / portTICK_RATE_MS / (LED_BLINK_RATE_HZ * 2) : - SYSTEM_UPDATE_PERIOD_MS / portTICK_RATE_MS; + int delayTime = SYSTEM_UPDATE_PERIOD_MS / portTICK_RATE_MS / (LED_BLINK_RATE_HZ); if (xQueueReceive(objectPersistenceQueue, &ev, delayTime) == pdTRUE) { // If object persistence is updated call the callback @@ -468,14 +476,14 @@ static void updateStats() idleCounter = 0; } #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) - if(pios_uavo_settings_fs_id){ + if (pios_uavo_settings_fs_id) { PIOS_FLASHFS_GetStats(pios_uavo_settings_fs_id, &fsStats); - stats.SysSlotsFree = fsStats.num_free_slots; + stats.SysSlotsFree = fsStats.num_free_slots; stats.SysSlotsActive = fsStats.num_active_slots; } - if(pios_user_fs_id){ + if (pios_user_fs_id) { PIOS_FLASHFS_GetStats(pios_user_fs_id, &fsStats); - stats.UsrSlotsFree = fsStats.num_free_slots; + stats.UsrSlotsFree = fsStats.num_free_slots; stats.UsrSlotsActive = fsStats.num_active_slots; } #endif From f2431b2868feae569d8a9e910ab3f10da0b538c8 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Sat, 15 Jun 2013 16:39:29 +0200 Subject: [PATCH 12/44] GPS module is builtin so there is no way to shut the gps alarm when gps is not used. This change does remove any alarm when no port is configured for gps. Things depending on GPS will continue to raise their own alarm when no gps data are feed. --- flight/modules/GPS/GPS.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/flight/modules/GPS/GPS.c b/flight/modules/GPS/GPS.c index 4158a4b3b..caa61260f 100644 --- a/flight/modules/GPS/GPS.c +++ b/flight/modules/GPS/GPS.c @@ -112,8 +112,6 @@ int32_t GPSStart(void) PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_GPS, gpsTaskHandle); return 0; } - - AlarmsSet(SYSTEMALARMS_ALARM_GPS, SYSTEMALARMS_ALARM_ERROR); } return -1; } From 517c331dd4dcb68c74d458ee4eaecc175b00e907 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Sat, 15 Jun 2013 17:27:48 +0200 Subject: [PATCH 13/44] OP-1012 fixed speeds to make easy to distinguish flash rates --- flight/modules/System/systemmod.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flight/modules/System/systemmod.c b/flight/modules/System/systemmod.c index c2f8b660a..4873a7877 100644 --- a/flight/modules/System/systemmod.c +++ b/flight/modules/System/systemmod.c @@ -204,7 +204,7 @@ static void systemTask(__attribute__((unused)) void *parameters) while (1) { // Update the system statistics updateStats(); - cycleCount = cycleCount > 0 ? cycleCount - 1 : 3; + cycleCount = cycleCount > 0 ? cycleCount - 1 : 7; // Update the system alarms updateSystemAlarms(); @@ -224,7 +224,7 @@ static void systemTask(__attribute__((unused)) void *parameters) uint8_t armingStatus; FlightStatusArmedGet(&armingStatus); if ((armingStatus == FLIGHTSTATUS_ARMED_ARMED && (cycleCount & 0x1)) || - (armingStatus != FLIGHTSTATUS_ARMED_ARMED && (cycleCount & 0x2))) { + (armingStatus != FLIGHTSTATUS_ARMED_ARMED && (cycleCount & 0x4))) { PIOS_LED_On(PIOS_LED_HEARTBEAT); } else { PIOS_LED_Off(PIOS_LED_HEARTBEAT); @@ -238,7 +238,7 @@ static void systemTask(__attribute__((unused)) void *parameters) if (AlarmsHasCritical()) { PIOS_LED_On(PIOS_LED_ALARM); } else if( (AlarmsHasErrors() && (cycleCount & 0x1)) || - (!AlarmsHasErrors() && AlarmsHasWarnings() && (cycleCount & 0x2))){ + (!AlarmsHasErrors() && AlarmsHasWarnings() && (cycleCount & 0x4))){ PIOS_LED_On(PIOS_LED_ALARM); } else { PIOS_LED_Off(PIOS_LED_ALARM); @@ -247,7 +247,7 @@ static void systemTask(__attribute__((unused)) void *parameters) UAVObjEvent ev; - int delayTime = SYSTEM_UPDATE_PERIOD_MS / portTICK_RATE_MS / (LED_BLINK_RATE_HZ); + int delayTime = SYSTEM_UPDATE_PERIOD_MS / portTICK_RATE_MS / (LED_BLINK_RATE_HZ * 2); if (xQueueReceive(objectPersistenceQueue, &ev, delayTime) == pdTRUE) { // If object persistence is updated call the callback From d5a77fb5258295c3319954340ff53cc7e2765dbe Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Sat, 15 Jun 2013 17:28:30 +0200 Subject: [PATCH 14/44] OP-1009 prevent gyro zeroing from raise an alarm when arming --- flight/modules/Attitude/revolution/attitude.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/modules/Attitude/revolution/attitude.c b/flight/modules/Attitude/revolution/attitude.c index ac4317466..f608ce442 100644 --- a/flight/modules/Attitude/revolution/attitude.c +++ b/flight/modules/Attitude/revolution/attitude.c @@ -638,7 +638,7 @@ static int32_t updateAttitudeComplementary(bool first_run) } } - if (!init) { + if (!init && flightStatus.Armed == FLIGHTSTATUS_ARMED_DISARMED) { AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE, SYSTEMALARMS_ALARM_ERROR); } else if (variance_error) { AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE, SYSTEMALARMS_ALARM_CRITICAL); From 15c6e625b2a38097af6e18931b3f1b949d0cf6bc Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Sun, 16 Jun 2013 17:40:25 +0200 Subject: [PATCH 15/44] OP-1000 Changes a label. --- ground/openpilotgcs/src/plugins/config/stabilization.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ground/openpilotgcs/src/plugins/config/stabilization.ui b/ground/openpilotgcs/src/plugins/config/stabilization.ui index 79d0b8c46..b99e232fd 100644 --- a/ground/openpilotgcs/src/plugins/config/stabilization.ui +++ b/ground/openpilotgcs/src/plugins/config/stabilization.ui @@ -28146,7 +28146,7 @@ border-radius: 5; - Rate + Max Vertical Speed Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter From b221c7bfea3ae3c46365ab63d44bcb8a8c6717eb Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Sun, 16 Jun 2013 17:53:15 +0200 Subject: [PATCH 16/44] OP-1000 Changes a label again. --- ground/openpilotgcs/src/plugins/config/stabilization.ui | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ground/openpilotgcs/src/plugins/config/stabilization.ui b/ground/openpilotgcs/src/plugins/config/stabilization.ui index b99e232fd..d0d31dd03 100644 --- a/ground/openpilotgcs/src/plugins/config/stabilization.ui +++ b/ground/openpilotgcs/src/plugins/config/stabilization.ui @@ -28105,6 +28105,9 @@ border-radius: 5; Qt::StrongFocus + + <html><head/><body><p>Throttle exponential value.</p></body></html> + @@ -28146,7 +28149,7 @@ border-radius: 5; - Max Vertical Speed + Max Vertical Velocity Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -28217,6 +28220,9 @@ border-radius: 5; Qt::StrongFocus + + <html><head/><body><p>Maximum allowed vertical velocity in m/s.</p></body></html> + From d28609349f4eb5941a8b408eff8f4e246510efb5 Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Mon, 17 Jun 2013 07:43:56 +0200 Subject: [PATCH 17/44] OP-1005 Fixes velocity units in PFD and PFDQml widgets. --- .../openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml | 2 +- ground/openpilotgcs/src/plugins/pfd/pfdgadgetwidget.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml index 1340b9cdb..804319181 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml @@ -3,7 +3,7 @@ import Qt 4.7 Item { id: sceneItem property variant sceneSize - property real groundSpeed : 3.6 * Math.sqrt(Math.pow(VelocityActual.North,2)+ + property real groundSpeed : Math.sqrt(Math.pow(VelocityActual.North,2)+ Math.pow(VelocityActual.East,2)) SvgElementImage { diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetwidget.cpp index bbd034193..ce22b4e94 100644 --- a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetwidget.cpp @@ -328,7 +328,7 @@ void PFDGadgetWidget::updateGroundspeed(UAVObject *object) if (northField && eastField) { double val = floor(sqrt(pow(northField->getDouble(), 2) + pow(eastField->getDouble(), 2)) * 10) / 10; - groundspeedTarget = 3.6 * val * speedScaleHeight / 30; + groundspeedTarget = val * speedScaleHeight / 30; if (!dialTimer.isActive()) { dialTimer.start(); // Rearm the dial Timer which might be stopped. From 2b232ae155a72fe5bcde49b1b40ac228984ff1c5 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Mon, 17 Jun 2013 20:22:17 +0200 Subject: [PATCH 18/44] Fix bootloader usb issues caused by USB reconnection fixes. Issues were related to missing usb detection and broken communication while updloading fw. They are now skipped in NON FreeRTOS mode (aka bootloader). +review OPReview --- flight/pios/stm32f4xx/pios_usb.c | 33 +++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/flight/pios/stm32f4xx/pios_usb.c b/flight/pios/stm32f4xx/pios_usb.c index 5ef3ca3b2..6578785e6 100644 --- a/flight/pios/stm32f4xx/pios_usb.c +++ b/flight/pios/stm32f4xx/pios_usb.c @@ -53,9 +53,9 @@ struct pios_usb_dev { xSemaphoreHandle statusCheckSemaphore; #endif }; - +#ifdef PIOS_INCLUDE_FREERTOS static void raiseDisconnectionCallbacks(void); - +#endif /** * @brief Validate the usb device structure * @returns true if valid device or false otherwise @@ -170,30 +170,33 @@ uint32_t usb_found; bool PIOS_USB_CheckAvailable(__attribute__((unused)) uint32_t id) { struct pios_usb_dev *usb_dev = (struct pios_usb_dev *)pios_usb_id; - static bool lastStatus = false; if (!PIOS_USB_validate(usb_dev)) { return false; } usb_found = ((usb_dev->cfg->vsense.gpio->IDR & usb_dev->cfg->vsense.init.GPIO_Pin) != 0) ^ usb_dev->cfg->vsense_active_low; - +// Please note that checks of transfer_possible and the reconnection handling is +// suppressed for non freertos mode (aka bootloader) as this is causing problems detecting connection and +// broken communications. +#ifdef PIOS_INCLUDE_FREERTOS + static bool lastStatus = false; bool status = usb_found != 0 && transfer_possible ? 1 : 0; bool reconnect = false; -#ifdef PIOS_INCLUDE_FREERTOS if (xSemaphoreTakeFromISR(usb_dev->statusCheckSemaphore, NULL) == pdTRUE) { -#endif - reconnect = (lastStatus && !status); - lastStatus = status; -#ifdef PIOS_INCLUDE_FREERTOS - xSemaphoreGiveFromISR(usb_dev->statusCheckSemaphore, NULL); -} -#endif + reconnect = (lastStatus && !status); + lastStatus = status; + xSemaphoreGiveFromISR(usb_dev->statusCheckSemaphore, NULL); + } if (reconnect) { raiseDisconnectionCallbacks(); } - return status; + +#else + return usb_found; + +#endif } /* @@ -212,7 +215,7 @@ void PIOS_USB_RegisterDisconnectionCallback(void (*disconnectionCB)(void)) } PIOS_Assert(0); } - +#ifdef PIOS_INCLUDE_FREERTOS static void raiseDisconnectionCallbacks(void) { uint32_t i = 0; @@ -221,7 +224,7 @@ static void raiseDisconnectionCallbacks(void) (disconnection_cb_list[i++])(); } } - +#endif /* * * Provide STM32 USB OTG BSP layer API From b012d55f268b3697a3cd526ee3ba7ec20cd553ee Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Mon, 17 Jun 2013 21:01:24 +0200 Subject: [PATCH 19/44] OP-1009 fix comments and fixes review +review OPReview-516 --- flight/modules/Attitude/revolution/attitude.c | 3 ++- flight/modules/System/systemmod.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/flight/modules/Attitude/revolution/attitude.c b/flight/modules/Attitude/revolution/attitude.c index f608ce442..c955e25ed 100644 --- a/flight/modules/Attitude/revolution/attitude.c +++ b/flight/modules/Attitude/revolution/attitude.c @@ -412,7 +412,8 @@ static int32_t updateAttitudeComplementary(bool first_run) if ((xTaskGetTickCount() - initStartupTime < CALIBRATION_DURATION + CALIBRATION_DELAY) && (xTaskGetTickCount() - initStartupTime > CALIBRATION_DELAY)) { - // For first 7 seconds use accels to get gyro bias + // For first CALIBRATION_DURATION seconds after CALIBRATION_DELAY from startup + // Zero gyro bias assuming it is steady, smoothing the gyro input value applying rollPitchBiasRate. attitudeSettings.AccelKp = 1.0f; attitudeSettings.AccelKi = 0.0f; attitudeSettings.YawBiasRate = 0.23f; diff --git a/flight/modules/System/systemmod.c b/flight/modules/System/systemmod.c index 4873a7877..42664128d 100644 --- a/flight/modules/System/systemmod.c +++ b/flight/modules/System/systemmod.c @@ -167,7 +167,7 @@ static void systemTask(__attribute__((unused)) void *parameters) { /* start the delayed callback scheduler */ CallbackSchedulerStart(); - static uint8_t cycleCount; + uint8_t cycleCount; /* create all modules thread */ MODULE_TASKCREATE_ALL; @@ -237,8 +237,8 @@ static void systemTask(__attribute__((unused)) void *parameters) #if defined(PIOS_LED_ALARM) if (AlarmsHasCritical()) { PIOS_LED_On(PIOS_LED_ALARM); - } else if( (AlarmsHasErrors() && (cycleCount & 0x1)) || - (!AlarmsHasErrors() && AlarmsHasWarnings() && (cycleCount & 0x4))){ + } else if ((AlarmsHasErrors() && (cycleCount & 0x1)) || + (!AlarmsHasErrors() && AlarmsHasWarnings() && (cycleCount & 0x4))) { PIOS_LED_On(PIOS_LED_ALARM); } else { PIOS_LED_Off(PIOS_LED_ALARM); From 7c3dafbfde6ea5715d71c986db460b8a4cbf9c3c Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 17 Jun 2013 21:16:47 +0200 Subject: [PATCH 20/44] OP-1008 fixed issue in GCS Options dialog where selected item was not always highlighted --- .../coreplugin/dialogs/settingsdialog.cpp | 43 ++++++++++++------- .../coreplugin/dialogs/settingsdialog.h | 4 +- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp index 4df71dd76..28503d0a8 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp @@ -48,7 +48,6 @@ namespace { int index; QString category; QString id; - }; // helper to sort by translated category and name @@ -146,14 +145,15 @@ SettingsDialog::SettingsDialog(QWidget *parent, const QString &categoryId, const connect(this, SIGNAL(settingsDialogShown(Core::Internal::SettingsDialog *)), m_instanceManager, SLOT(settingsDialogShown(Core::Internal::SettingsDialog *))); connect(this, SIGNAL(settingsDialogRemoved()), m_instanceManager, SLOT(settingsDialogRemoved())); - connect(this, SIGNAL(categoryItemSelected()), this, SLOT(categoryItemSelectedShowChildInstead()), - Qt::QueuedConnection); + + // needs to be queued to be able to change the selection from the selection change signal call + connect(this, SIGNAL(categoryItemSelected()), this, SLOT(onCategorySelected()), Qt::QueuedConnection); splitter->setCollapsible(0, false); splitter->setCollapsible(1, false); pageTree->header()->setVisible(false); - connect(pageTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(pageSelected())); + connect(pageTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(onItemSelected())); QList pluginPages; QList gadgetPages; @@ -286,18 +286,31 @@ QTreeWidgetItem *SettingsDialog::addPage(IOptionsPage *page) { return item; } -void SettingsDialog::pageSelected() +void SettingsDialog::onItemSelected() { QTreeWidgetItem *item = pageTree->currentItem(); - if (!item) { return; } + if (pageTree->indexOfTopLevelItem(item) >= 0) { + if (item->childCount() == 1) { + // single child : category will not be expanded + item = item->child(0); + } + else if (item->childCount() > 1) { + // multiple children : expand category and select 1st child + emit categoryItemSelected(); + return; + } + } + + // get user data PageData data = item->data(0, Qt::UserRole).value(); int index = data.index; m_currentCategory = data.category; m_currentPage = data.id; + // check if we are looking at a place holder or not QWidget *widget = dynamic_cast(stackedPages->widget(index)); if (widget) { @@ -308,25 +321,23 @@ void SettingsDialog::pageSelected() IOptionsPage *page = m_pages.at(index); stackedPages->insertWidget(index, page->createPage(stackedPages)); } + stackedPages->setCurrentIndex(index); - // If user selects a toplevel item, select the first child for them - // I.e. Top level items are not really selectable - if ((pageTree->indexOfTopLevelItem(item) >= 0) && (item->childCount() > 0)) { - emit categoryItemSelected(); - } } -void SettingsDialog::categoryItemSelectedShowChildInstead() +void SettingsDialog::onCategorySelected() { QTreeWidgetItem *item = pageTree->currentItem(); - - item->setExpanded(true); - pageTree->setCurrentItem(item->child(0), 0, QItemSelectionModel::SelectCurrent); + if (item->childCount() > 1) { + item->setExpanded(true); + pageTree->setCurrentItem(item->child(0), 0, QItemSelectionModel::SelectCurrent); + } } void SettingsDialog::deletePage() { QTreeWidgetItem *item = pageTree->currentItem(); + PageData data = item->data(0, Qt::UserRole).value(); QString category = data.category; @@ -337,9 +348,9 @@ void SettingsDialog::deletePage() parentItem->removeChild(item); if (parentItem->childCount() == 1) { parentItem->child(0)->setHidden(true); + pageTree->setCurrentItem(parentItem, 0, QItemSelectionModel::SelectCurrent); } } - pageSelected(); } // TODO duplicates a lot of the addPage code... diff --git a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.h b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.h index 7333844a4..0157ec840 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.h @@ -64,11 +64,11 @@ public slots: void done(int); private slots: - void pageSelected(); + void onItemSelected(); + void onCategorySelected(); void accept(); void reject(); void apply(); - void categoryItemSelectedShowChildInstead(); private: QList m_pages; From 54af41765e6b8d960666ce4c0b4f62849b82df23 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Mon, 17 Jun 2013 21:41:54 +0200 Subject: [PATCH 21/44] OP-1009 missing initialization on a previously static variable. +review OPReview-516 --- flight/modules/System/systemmod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/modules/System/systemmod.c b/flight/modules/System/systemmod.c index 42664128d..9ff5dd7e0 100644 --- a/flight/modules/System/systemmod.c +++ b/flight/modules/System/systemmod.c @@ -167,7 +167,7 @@ static void systemTask(__attribute__((unused)) void *parameters) { /* start the delayed callback scheduler */ CallbackSchedulerStart(); - uint8_t cycleCount; + uint8_t cycleCount = 0; /* create all modules thread */ MODULE_TASKCREATE_ALL; From a6ac95612748dbac7f3ca043d61ca17140aa9069 Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Tue, 18 Jun 2013 00:52:27 +0200 Subject: [PATCH 22/44] OP-1005 Adds configurable units for velocity/speed and altitude in QML PFD. Units are configured in settings panel. OP-1015 Reduces precision of the PDOP value in the PFD display to 3 decimals. --- .../pfd/default/AltitudeScale.qml | 29 ++++++- .../pfd/default/PfdIndicators.qml | 2 +- .../openpilotgcs/pfd/default/SpeedScale.qml | 24 +++++- .../share/openpilotgcs/pfd/default/pfd.svg | 84 +++++++++---------- .../src/plugins/pfdqml/pfdqmlgadget.cpp | 4 + .../pfdqml/pfdqmlgadgetconfiguration.cpp | 19 ++++- .../pfdqml/pfdqmlgadgetconfiguration.h | 41 +++++++++ .../pfdqml/pfdqmlgadgetoptionspage.cpp | 20 +++++ .../plugins/pfdqml/pfdqmlgadgetoptionspage.ui | 60 ++++++++++--- .../src/plugins/pfdqml/pfdqmlgadgetwidget.cpp | 38 ++++++++- .../src/plugins/pfdqml/pfdqmlgadgetwidget.h | 38 +++++++++ 11 files changed, 293 insertions(+), 66 deletions(-) diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/AltitudeScale.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/AltitudeScale.qml index a8f4d66b2..4d0ef2c89 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/AltitudeScale.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/AltitudeScale.qml @@ -24,10 +24,10 @@ Item { anchors.verticalCenter: parent.verticalCenter // The altitude scale represents 30 meters, // move it in 0..5m range - anchors.verticalCenterOffset: -height/30 * (PositionActual.Down-Math.floor(PositionActual.Down/5)*5) + anchors.verticalCenterOffset: -height/30 * (PositionActual.Down-Math.floor(PositionActual.Down/5*qmlWidget.altitudeFactor)*5) anchors.left: parent.left - property int topNumber: 15-Math.floor(PositionActual.Down/5)*5 + property int topNumber: 15-Math.floor(PositionActual.Down/5*qmlWidget.altitudeFactor)*5 // Altitude numbers Column { @@ -52,7 +52,6 @@ Item { } } - SvgElementImage { id: altitude_window clip: true @@ -69,7 +68,7 @@ Item { Text { id: altitude_text - text: Math.floor(-PositionActual.Down).toFixed() + text: Math.floor(-PositionActual.Down * qmlWidget.altitudeFactor).toFixed() color: "white" font { family: "Arial" @@ -78,4 +77,26 @@ Item { anchors.centerIn: parent } } + + SvgElementImage { + id: altitude_unit + elementName: "altitude-unit" + sceneSize: sceneItem.sceneSize + clip: true + + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) + + Text { + id: altitude_unit_text + text: qmlWidget.altitudeUnit + color: "white" + font { + family: "Arial" + pixelSize: parent.height + } + anchors.right: parent.right + } + } + } diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml index 8d821e7c3..6824d5a7c 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml @@ -31,7 +31,7 @@ Item { Text { id: gps_text - text: "GPS: " + GPSPosition.Satellites + "\nPDP: " + GPSPosition.PDOP + text: "GPS: " + GPSPosition.Satellites + "\nPDP: " + Math.round(GPSPosition.PDOP*1000)/1000 color: "white" font.family: "Arial" font.pixelSize: telemetry_status.height * 0.75 diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml index 804319181..6d8643e66 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml @@ -3,7 +3,7 @@ import Qt 4.7 Item { id: sceneItem property variant sceneSize - property real groundSpeed : Math.sqrt(Math.pow(VelocityActual.North,2)+ + property real groundSpeed : qmlWidget.speedFactor * Math.sqrt(Math.pow(VelocityActual.North,2)+ Math.pow(VelocityActual.East,2)) SvgElementImage { @@ -58,7 +58,6 @@ Item { } } - SvgElementImage { id: speed_window clip: true @@ -82,4 +81,25 @@ Item { anchors.centerIn: parent } } + + SvgElementImage { + id: speed_unit + elementName: "speed-unit" + sceneSize: sceneItem.sceneSize + clip: true + + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) + + Text { + id: speed_unit_text + text: qmlWidget.speedUnit + color: "white" + font { + family: "Arial" + pixelSize: parent.height + } + anchors.right: parent.right + } + } } diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg b/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg index abdc4f8c5..2b7ff19bd 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg @@ -14,8 +14,8 @@ height="707.56323" id="svg2" version="1.1" - inkscape:version="0.48.3.1 r9886" - sodipodi:docname="pfd-11.svg" + inkscape:version="0.48.4 r9939" + sodipodi:docname="pfd.svg" style="display:inline" inkscape:export-filename="C:\Users\Nuno\Desktop\OpenPilot\PFD\PFD-4.png" inkscape:export-xdpi="71.993568" @@ -1616,15 +1616,15 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1.1617336" - inkscape:cx="415.72223" - inkscape:cy="353.78162" + inkscape:cx="613.40088" + inkscape:cy="388.21292" inkscape:document-units="px" - inkscape:current-layer="svg2" + inkscape:current-layer="foreground" showgrid="false" inkscape:window-width="1920" inkscape:window-height="1017" - inkscape:window-x="-4" - inkscape:window-y="-4" + inkscape:window-x="-8" + inkscape:window-y="-8" inkscape:window-maximized="1" showguides="false" inkscape:guide-bbox="true" @@ -1953,8 +1953,7 @@ id="layer3" inkscape:label="foreground" style="display:inline" - transform="translate(230.4171,-2.5493479)" - sodipodi:insensitive="true"> + transform="translate(230.4171,-2.5493479)"> @@ -1980,7 +1979,7 @@ + transform="translate(19.192898,0)"> + transform="translate(184.16754,0)"> + + + - ALT - m/s - m + inkscape:label="rect2816" + style="display:inline"> setLatitude(m->latitude()); m_widget->setLongitude(m->longitude()); m_widget->setAltitude(m->altitude()); + m_widget->setSpeedFactor(m->speedFactor()); + m_widget->setSpeedUnit(m->speedUnit()); + m_widget->setAltitudeFactor(m->altitudeFactor()); + m_widget->setAltitudeUnit(m->altitudeUnit()); // setting OSGEARTH_CACHE_ONLY seems to work the most reliably // between osgEarth versions I tried diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.cpp b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.cpp index e00e52a1d..d3efb6a42 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.cpp +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.cpp @@ -31,8 +31,19 @@ PfdQmlGadgetConfiguration::PfdQmlGadgetConfiguration(QString classId, QSettings m_latitude(0), m_longitude(0), m_altitude(0), - m_cacheOnly(false) + m_cacheOnly(false), + m_speedFactor(1.0), + m_altitudeFactor(1.0) { + + m_speedMap[1.0] = "m/s"; + m_speedMap[3.6] = "km/h"; + m_speedMap[2.2369] = "mph"; + m_speedMap[1.9438] = "knots"; + + m_altitudeMap[1.0] = "m"; + m_altitudeMap[3.2808] = "ft"; + // if a saved configuration exists load it if (qSettings != 0) { m_qmlFile = qSettings->value("qmlFile").toString(); @@ -48,6 +59,8 @@ PfdQmlGadgetConfiguration::PfdQmlGadgetConfiguration(QString classId, QSettings m_longitude = qSettings->value("longitude").toDouble(); m_altitude = qSettings->value("altitude").toDouble(); m_cacheOnly = qSettings->value("cacheOnly").toBool(); + m_speedFactor = qSettings->value("speedFactor").toDouble(); + m_altitudeFactor = qSettings->value("altitudeFactor").toDouble(); } } @@ -68,6 +81,8 @@ IUAVGadgetConfiguration *PfdQmlGadgetConfiguration::clone() m->m_longitude = m_longitude; m->m_altitude = m_altitude; m->m_cacheOnly = m_cacheOnly; + m->m_speedFactor = m_speedFactor; + m->m_altitudeFactor = m_altitudeFactor; return m; } @@ -91,4 +106,6 @@ void PfdQmlGadgetConfiguration::saveConfig(QSettings *qSettings) const qSettings->setValue("longitude", m_longitude); qSettings->setValue("altitude", m_altitude); qSettings->setValue("cacheOnly", m_cacheOnly); + qSettings->setValue("speedFactor", m_speedFactor); + qSettings->setValue("altitudeFactor", m_altitudeFactor); } diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.h b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.h index f09e4a0ad..7171c3bd9 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.h +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.h @@ -18,6 +18,7 @@ #define PFDQMLGADGETCONFIGURATION_H #include +#include using namespace Core; @@ -62,6 +63,14 @@ public: { m_cacheOnly = flag; } + void setSpeedFactor(double factor) + { + m_speedFactor = factor; + } + void setAltitudeFactor(double factor) + { + m_altitudeFactor = factor; + } QString qmlFile() const { @@ -99,6 +108,34 @@ public: { return m_cacheOnly; } + double speedFactor() const + { + return m_speedFactor; + } + double altitudeFactor() const + { + return m_altitudeFactor; + } + + QString speedUnit() const + { + return m_speedMap[m_speedFactor]; + } + + QString altitudeUnit() const + { + return m_altitudeMap[m_altitudeFactor]; + } + + QMapIterator speedMapIterator() + { + return QMapIterator(m_speedMap); + } + + QMapIterator altitudeMapIterator() + { + return QMapIterator(m_altitudeMap); + } void saveConfig(QSettings *settings) const; IUAVGadgetConfiguration *clone(); @@ -113,6 +150,10 @@ private: double m_longitude; double m_altitude; bool m_cacheOnly; + double m_speedFactor; + double m_altitudeFactor; + QMap m_speedMap; + QMap m_altitudeMap; }; #endif // PfdQmlGADGETCONFIGURATION_H diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.cpp b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.cpp index 0b20b8480..99fb40501 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.cpp +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.cpp @@ -62,6 +62,23 @@ QWidget *PfdQmlGadgetOptionsPage::createPage(QWidget *parent) options_page->altitude->setText(QString::number(m_config->altitude())); options_page->useOnlyCache->setChecked(m_config->cacheOnly()); + //Setup units combos + QMapIterator iter = m_config->speedMapIterator(); + while(iter.hasNext()) + { + iter.next(); + options_page->speedUnitCombo->addItem(iter.value(), iter.key()); + } + options_page->speedUnitCombo->setCurrentIndex(options_page->speedUnitCombo->findData(m_config->speedFactor())); + + iter = m_config->altitudeMapIterator(); + while(iter.hasNext()) + { + iter.next(); + options_page->altUnitCombo->addItem(iter.value(), iter.key()); + } + options_page->altUnitCombo->setCurrentIndex(options_page->altUnitCombo->findData(m_config->altitudeFactor())); + #ifndef USE_OSG options_page->showTerrain->setChecked(false); options_page->showTerrain->setVisible(false); @@ -93,6 +110,9 @@ void PfdQmlGadgetOptionsPage::apply() m_config->setLongitude(options_page->longitude->text().toDouble()); m_config->setAltitude(options_page->altitude->text().toDouble()); m_config->setCacheOnly(options_page->useOnlyCache->isChecked()); + + m_config->setSpeedFactor(options_page->speedUnitCombo->itemData(options_page->speedUnitCombo->currentIndex()).toDouble()); + m_config->setAltitudeFactor(options_page->altUnitCombo->itemData(options_page->altUnitCombo->currentIndex()).toDouble()); } void PfdQmlGadgetOptionsPage::finish() diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.ui b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.ui index 20d617e9b..bb136c6e1 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.ui +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.ui @@ -6,8 +6,8 @@ 0 0 - 457 - 436 + 636 + 558 @@ -19,11 +19,11 @@ Form - + 0 - + QFrame::NoFrame @@ -39,15 +39,15 @@ 0 0 - 457 - 436 + 636 + 558 - + 0 - + 10 @@ -77,7 +77,7 @@ - + Use OpenGL @@ -87,7 +87,45 @@ - + + + + + + Speed Unit: + + + + + + + Altitude Unit: + + + + + + + + 150 + 16777215 + + + + + + + + + 150 + 16777215 + + + + + + + Show Terrain: @@ -223,7 +261,7 @@ - + Qt::Vertical diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.cpp index 60fe0539c..b28e1e418 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.cpp @@ -39,7 +39,11 @@ PfdQmlGadgetWidget::PfdQmlGadgetWidget(QWidget *parent) : m_actualPositionUsed(false), m_latitude(46.671478), m_longitude(10.158932), - m_altitude(2000) + m_altitude(2000), + m_speedUnit("m/s"), + m_speedFactor(1.0), + m_altitudeUnit("m"), + m_altitudeFactor(1.0) { setMinimumSize(64, 64); setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); @@ -121,6 +125,38 @@ void PfdQmlGadgetWidget::setTerrainEnabled(bool arg) } } +void PfdQmlGadgetWidget::setSpeedUnit(QString unit) +{ + if (m_speedUnit != unit) { + m_speedUnit = unit; + emit speedUnitChanged(unit); + } +} + +void PfdQmlGadgetWidget::setSpeedFactor(double factor) +{ + if (m_speedFactor != factor) { + m_speedFactor = factor; + emit speedFactorChanged(factor); + } +} + +void PfdQmlGadgetWidget::setAltitudeUnit(QString unit) +{ + if (m_altitudeUnit != unit) { + m_altitudeUnit = unit; + emit altitudeUnitChanged(unit); + } +} + +void PfdQmlGadgetWidget::setAltitudeFactor(double factor) +{ + if (m_altitudeFactor != factor) { + m_altitudeFactor = factor; + emit altitudeFactorChanged(factor); + } +} + void PfdQmlGadgetWidget::setOpenGLEnabled(bool arg) { if (m_openGLEnabled != arg) { diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.h b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.h index 77ab49f9d..46d540345 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.h +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.h @@ -26,6 +26,11 @@ class PfdQmlGadgetWidget : public QDeclarativeView { Q_PROPERTY(bool actualPositionUsed READ actualPositionUsed WRITE setActualPositionUsed NOTIFY actualPositionUsedChanged) + Q_PROPERTY(QString speedUnit READ speedUnit WRITE setSpeedUnit NOTIFY speedUnitChanged) + Q_PROPERTY(double speedFactor READ speedFactor WRITE setSpeedFactor NOTIFY speedFactorChanged) + Q_PROPERTY(QString altitudeUnit READ altitudeUnit WRITE setAltitudeUnit NOTIFY altitudeUnitChanged) + Q_PROPERTY(double altitudeFactor READ altitudeFactor WRITE setAltitudeFactor NOTIFY altitudeFactorChanged) + // pre-defined fallback position Q_PROPERTY(double latitude READ latitude WRITE setLatitude NOTIFY latitudeChanged) Q_PROPERTY(double longitude READ longitude WRITE setLongitude NOTIFY longitudeChanged) @@ -45,6 +50,23 @@ public: return m_terrainEnabled && m_openGLEnabled; } + QString speedUnit() const + { + return m_speedUnit; + } + double speedFactor() const + { + return m_speedFactor; + } + QString altitudeUnit() const + { + return m_altitudeUnit; + } + double altitudeFactor() const + { + return m_altitudeFactor; + } + bool actualPositionUsed() const { return m_actualPositionUsed; @@ -65,6 +87,12 @@ public: public slots: void setEarthFile(QString arg); void setTerrainEnabled(bool arg); + + void setSpeedUnit(QString unit); + void setSpeedFactor(double factor); + void setAltitudeUnit(QString unit); + void setAltitudeFactor(double factor); + void setOpenGLEnabled(bool arg); void setLatitude(double arg); @@ -82,6 +110,11 @@ signals: void longitudeChanged(double arg); void altitudeChanged(double arg); + void speedUnitChanged(QString arg); + void speedFactorChanged(double arg); + void altitudeUnitChanged(QString arg); + void altitudeFactorChanged(double arg); + private: QString m_qmlFileName; QString m_earthFile; @@ -92,6 +125,11 @@ private: double m_latitude; double m_longitude; double m_altitude; + + QString m_speedUnit; + double m_speedFactor; + QString m_altitudeUnit; + double m_altitudeFactor; }; #endif /* PFDQMLGADGETWIDGET_H_ */ From 68b2b285941a327d44ea2bae04dcdce9e0f41349 Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Tue, 18 Jun 2013 07:45:44 +0200 Subject: [PATCH 23/44] OP-1005 Removes 'old' PFD (non qml based one). --- .../src/plugins/pfd/PFDGadget.pluginspec | 11 - .../src/plugins/pfd/images/pfd-default.svg | 394 ------ ground/openpilotgcs/src/plugins/pfd/pfd.pro | 22 - ground/openpilotgcs/src/plugins/pfd/pfd.qrc | 5 - .../src/plugins/pfd/pfd_dependencies.pri | 1 - .../src/plugins/pfd/pfdgadget.cpp | 57 - .../openpilotgcs/src/plugins/pfd/pfdgadget.h | 58 - .../plugins/pfd/pfdgadgetconfiguration.cpp | 77 -- .../src/plugins/pfd/pfdgadgetconfiguration.h | 86 -- .../src/plugins/pfd/pfdgadgetfactory.cpp | 58 - .../src/plugins/pfd/pfdgadgetfactory.h | 51 - .../src/plugins/pfd/pfdgadgetoptionspage.cpp | 85 -- .../src/plugins/pfd/pfdgadgetoptionspage.h | 64 - .../src/plugins/pfd/pfdgadgetoptionspage.ui | 150 --- .../src/plugins/pfd/pfdgadgetwidget.cpp | 1133 ----------------- .../src/plugins/pfd/pfdgadgetwidget.h | 160 --- .../src/plugins/pfd/pfdplugin.cpp | 65 - .../openpilotgcs/src/plugins/pfd/pfdplugin.h | 46 - .../plugins/pfdqml/pfdqmlgadgetfactory.cpp | 2 +- ground/openpilotgcs/src/plugins/plugins.pro | 8 +- 20 files changed, 2 insertions(+), 2531 deletions(-) delete mode 100644 ground/openpilotgcs/src/plugins/pfd/PFDGadget.pluginspec delete mode 100644 ground/openpilotgcs/src/plugins/pfd/images/pfd-default.svg delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfd.pro delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfd.qrc delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfd_dependencies.pri delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfdgadget.cpp delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfdgadget.h delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfdgadgetconfiguration.cpp delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfdgadgetconfiguration.h delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfdgadgetfactory.cpp delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfdgadgetfactory.h delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.cpp delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.h delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.ui delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfdgadgetwidget.cpp delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfdgadgetwidget.h delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfdplugin.cpp delete mode 100644 ground/openpilotgcs/src/plugins/pfd/pfdplugin.h diff --git a/ground/openpilotgcs/src/plugins/pfd/PFDGadget.pluginspec b/ground/openpilotgcs/src/plugins/pfd/PFDGadget.pluginspec deleted file mode 100644 index 0a4f70bc0..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/PFDGadget.pluginspec +++ /dev/null @@ -1,11 +0,0 @@ - - The OpenPilot Project - (C) 2010 Edouard Lafargue - The GNU Public License (GPL) Version 3 - The Primary Flight Display gadget - http://www.openpilot.org - - - - - diff --git a/ground/openpilotgcs/src/plugins/pfd/images/pfd-default.svg b/ground/openpilotgcs/src/plugins/pfd/images/pfd-default.svg deleted file mode 100644 index 0fdc3669b..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/images/pfd-default.svg +++ /dev/null @@ -1,394 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ground/openpilotgcs/src/plugins/pfd/pfd.pro b/ground/openpilotgcs/src/plugins/pfd/pfd.pro deleted file mode 100644 index 961d89c19..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfd.pro +++ /dev/null @@ -1,22 +0,0 @@ -TEMPLATE = lib -TARGET = PFDGadget -QT += svg -QT += opengl -include(../../openpilotgcsplugin.pri) -include(../../plugins/coreplugin/coreplugin.pri) -include(pfd_dependencies.pri) -HEADERS += pfdplugin.h -HEADERS += pfdgadget.h -HEADERS += pfdgadgetwidget.h -HEADERS += pfdgadgetfactory.h -HEADERS += pfdgadgetconfiguration.h -HEADERS += pfdgadgetoptionspage.h -SOURCES += pfdplugin.cpp -SOURCES += pfdgadget.cpp -SOURCES += pfdgadgetfactory.cpp -SOURCES += pfdgadgetwidget.cpp -SOURCES += pfdgadgetconfiguration.cpp -SOURCES += pfdgadgetoptionspage.cpp -OTHER_FILES += PFDGadget.pluginspec -FORMS += pfdgadgetoptionspage.ui -RESOURCES += pfd.qrc diff --git a/ground/openpilotgcs/src/plugins/pfd/pfd.qrc b/ground/openpilotgcs/src/plugins/pfd/pfd.qrc deleted file mode 100644 index 278dd281e..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfd.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - images/pfd-default.svg - - diff --git a/ground/openpilotgcs/src/plugins/pfd/pfd_dependencies.pri b/ground/openpilotgcs/src/plugins/pfd/pfd_dependencies.pri deleted file mode 100644 index 9aae5fbc0..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfd_dependencies.pri +++ /dev/null @@ -1 +0,0 @@ -include(../../plugins/uavobjects/uavobjects.pri) diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdgadget.cpp b/ground/openpilotgcs/src/plugins/pfd/pfdgadget.cpp deleted file mode 100644 index 6d91e3c88..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfdgadget.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/** - ****************************************************************************** - * - * @file pfdgadget.cpp - * @author Edouard Lafargue Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin Primary Flight Display Plugin - * @{ - * @brief The Primary Flight Display Gadget - *****************************************************************************/ -/* - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "pfdgadget.h" -#include "pfdgadgetwidget.h" -#include "pfdgadgetconfiguration.h" - -PFDGadget::PFDGadget(QString classId, PFDGadgetWidget *widget, QWidget *parent) : - IUAVGadget(classId, parent), - m_widget(widget) -{} - -PFDGadget::~PFDGadget() -{ - delete m_widget; -} - -/* - This is called when a configuration is loaded, and updates the plugin's settings. - Careful: the plugin is already drawn before the loadConfiguration method is called the - first time, so you have to be careful not to assume all the plugin values are initialized - the first time you use them - */ -void PFDGadget::loadConfiguration(IUAVGadgetConfiguration *config) -{ - PFDGadgetConfiguration *m = qobject_cast(config); - - m_widget->setHqFonts(m->getHqFonts()); - m_widget->setDialFile(m->dialFile()); - m_widget->enableOpenGL(m->useOpenGL()); - m_widget->enableSmoothUpdates(m->getBeSmooth()); - m_widget->connectNeedles(); -} diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdgadget.h b/ground/openpilotgcs/src/plugins/pfd/pfdgadget.h deleted file mode 100644 index c161aa97f..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfdgadget.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - ****************************************************************************** - * - * @file pfdgadget.h - * @author Edouard Lafargue Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin Primary Flight Display Plugin - * @{ - * @brief The Primary Flight Display Gadget - *****************************************************************************/ -/* - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef PFDGADGET_H_ -#define PFDGADGET_H_ - -#include -#include "pfdgadgetwidget.h" - -class IUAVGadget; -class QWidget; -class QString; -class PFDGadgetWidget; - -using namespace Core; - -class PFDGadget : public Core::IUAVGadget { - Q_OBJECT -public: - PFDGadget(QString classId, PFDGadgetWidget *widget, QWidget *parent = 0); - ~PFDGadget(); - - QWidget *widget() - { - return m_widget; - } - void loadConfiguration(IUAVGadgetConfiguration *config); - -private: - PFDGadgetWidget *m_widget; -}; - - -#endif // PFDGADGET_H_ diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetconfiguration.cpp b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetconfiguration.cpp deleted file mode 100644 index f05235409..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetconfiguration.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/** - ****************************************************************************** - * - * @file pfdgadgetconfiguration.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin Primary Flight Display Plugin - * @{ - * @brief The Primary Flight Display Gadget - *****************************************************************************/ -/* - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "pfdgadgetconfiguration.h" -#include "utils/pathutils.h" - -/** - * Loads a saved configuration or defaults if non exist. - * - */ -PFDGadgetConfiguration::PFDGadgetConfiguration(QString classId, QSettings *qSettings, QObject *parent) : - IUAVGadgetConfiguration(classId, parent), - m_defaultDial("Unknown"), - beSmooth(true) -{ - // if a saved configuration exists load it - if (qSettings != 0) { - QString dialFile = qSettings->value("dialFile").toString(); - useOpenGLFlag = qSettings->value("useOpenGLFlag").toBool(); - hqFonts = qSettings->value("hqFonts").toBool(); - beSmooth = qSettings->value("beSmooth").toBool(); - m_defaultDial = Utils::PathUtils().InsertDataPath(dialFile); - } -} - -/** - * Clones a configuration. - * - */ -IUAVGadgetConfiguration *PFDGadgetConfiguration::clone() -{ - PFDGadgetConfiguration *m = new PFDGadgetConfiguration(this->classId()); - - m->m_defaultDial = m_defaultDial; - m->useOpenGLFlag = useOpenGLFlag; - m->hqFonts = hqFonts; - m->beSmooth = beSmooth; - return m; -} - -/** - * Saves a configuration. - * - */ -void PFDGadgetConfiguration::saveConfig(QSettings *qSettings) const -{ - QString dialFile = Utils::PathUtils().RemoveDataPath(m_defaultDial); - - qSettings->setValue("dialFile", dialFile); - qSettings->setValue("useOpenGLFlag", useOpenGLFlag); - qSettings->setValue("hqFonts", hqFonts); - qSettings->setValue("beSmooth", beSmooth); -} diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetconfiguration.h b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetconfiguration.h deleted file mode 100644 index 9f3152c63..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetconfiguration.h +++ /dev/null @@ -1,86 +0,0 @@ -/** - ****************************************************************************** - * - * @file pfdgadgetconfiguration.h - * @author Edouard Lafargue Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin Primary Flight Display Plugin - * @{ - * @brief The Primary Flight Display Gadget - *****************************************************************************/ -/* - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef PFDGADGETCONFIGURATION_H -#define PFDGADGETCONFIGURATION_H - -#include - -using namespace Core; - -class PFDGadgetConfiguration : public IUAVGadgetConfiguration { - Q_OBJECT -public: - explicit PFDGadgetConfiguration(QString classId, QSettings *qSettings = 0, QObject *parent = 0); - - // set dial configuration functions - void setDialFile(QString dialFile) - { - m_defaultDial = dialFile; - } - void setUseOpenGL(bool flag) - { - useOpenGLFlag = flag; - } - void setHqFonts(bool flag) - { - hqFonts = flag; - } - void setBeSmooth(bool flag) - { - beSmooth = flag; - } - - // get dial configuration functions - QString dialFile() - { - return m_defaultDial; - } - bool useOpenGL() - { - return useOpenGLFlag; - } - bool getHqFonts() - { - return hqFonts; - } - bool getBeSmooth() - { - return beSmooth; - } - - void saveConfig(QSettings *settings) const; - IUAVGadgetConfiguration *clone(); - -private: - QString m_defaultDial; // The name of the dial's SVG source file - bool useOpenGLFlag; - bool hqFonts; - bool beSmooth; -}; - -#endif // PFDGADGETCONFIGURATION_H diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetfactory.cpp b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetfactory.cpp deleted file mode 100644 index 1e3725189..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetfactory.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/** - ****************************************************************************** - * - * @file pfdgadgetfactory.cpp - * @author Edouard Lafargue Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin Primary Flight Display Plugin - * @{ - * @brief The Primary Flight Display Gadget - *****************************************************************************/ -/* - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "pfdgadgetfactory.h" -#include "pfdgadgetwidget.h" -#include "pfdgadget.h" -#include "pfdgadgetconfiguration.h" -#include "pfdgadgetoptionspage.h" -#include - -PFDGadgetFactory::PFDGadgetFactory(QObject *parent) : - IUAVGadgetFactory(QString("PFDGadget"), - tr("Primary Flight Display"), - parent) -{} - -PFDGadgetFactory::~PFDGadgetFactory() -{} - -Core::IUAVGadget *PFDGadgetFactory::createGadget(QWidget *parent) -{ - PFDGadgetWidget *gadgetWidget = new PFDGadgetWidget(parent); - - return new PFDGadget(QString("PFDGadget"), gadgetWidget, parent); -} - -IUAVGadgetConfiguration *PFDGadgetFactory::createConfiguration(QSettings *qSettings) -{ - return new PFDGadgetConfiguration(QString("PFDGadget"), qSettings); -} - -IOptionsPage *PFDGadgetFactory::createOptionsPage(IUAVGadgetConfiguration *config) -{ - return new PFDGadgetOptionsPage(qobject_cast(config)); -} diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetfactory.h b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetfactory.h deleted file mode 100644 index be7867494..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetfactory.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - ****************************************************************************** - * - * @file pfdgadgetfactory.h - * @author Edouard Lafargue Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin Primary Flight Display Plugin - * @{ - * @brief The Primary Flight Display Gadget - *****************************************************************************/ -/* - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef PFDGADGETFACTORY_H_ -#define PFDGADGETFACTORY_H_ - -#include - -namespace Core { -class IUAVGadget; -class IUAVGadgetFactory; -} - -using namespace Core; - -class PFDGadgetFactory : public IUAVGadgetFactory { - Q_OBJECT -public: - PFDGadgetFactory(QObject *parent = 0); - ~PFDGadgetFactory(); - - Core::IUAVGadget *createGadget(QWidget *parent); - IUAVGadgetConfiguration *createConfiguration(QSettings *qSettings); - IOptionsPage *createOptionsPage(IUAVGadgetConfiguration *config); -}; - -#endif // PFDGADGETFACTORY_H_ diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.cpp b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.cpp deleted file mode 100644 index 3af712dd4..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/** - ****************************************************************************** - * - * @file pfdgadgetoptionspage.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin Primary Flight Display Plugin - * @{ - * @brief The Primary Flight Display Gadget - *****************************************************************************/ -/* - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "pfdgadgetoptionspage.h" -#include "pfdgadgetconfiguration.h" -#include "ui_pfdgadgetoptionspage.h" -#include "extensionsystem/pluginmanager.h" -#include "uavobjectmanager.h" -#include "uavdataobject.h" - - -#include -#include -#include - -PFDGadgetOptionsPage::PFDGadgetOptionsPage(PFDGadgetConfiguration *config, QObject *parent) : - IOptionsPage(parent), - m_config(config) -{} - -// creates options page widget (uses the UI file) -QWidget *PFDGadgetOptionsPage::createPage(QWidget *parent) -{ - Q_UNUSED(parent); - - options_page = new Ui::PFDGadgetOptionsPage(); - // main widget - QWidget *optionsPageWidget = new QWidget; - // main layout - options_page->setupUi(optionsPageWidget); - - - // Restore the contents from the settings: - options_page->svgSourceFile->setExpectedKind(Utils::PathChooser::File); - options_page->svgSourceFile->setPromptDialogFilter(tr("SVG image (*.svg)")); - options_page->svgSourceFile->setPromptDialogTitle(tr("Choose SVG image")); - options_page->svgSourceFile->setPath(m_config->dialFile()); - options_page->useOpenGL->setChecked(m_config->useOpenGL()); - options_page->hqText->setChecked(m_config->getHqFonts()); - options_page->smoothUpdates->setChecked(m_config->getBeSmooth()); - - return optionsPageWidget; -} - -/** - * Called when the user presses apply or OK. - * - * Saves the current values - * - */ -void PFDGadgetOptionsPage::apply() -{ - m_config->setDialFile(options_page->svgSourceFile->path()); - m_config->setUseOpenGL(options_page->useOpenGL->checkState()); - m_config->setHqFonts(options_page->hqText->checkState()); - m_config->setBeSmooth(options_page->smoothUpdates->checkState()); -} - - -void PFDGadgetOptionsPage::finish() -{} diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.h b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.h deleted file mode 100644 index 83ea51ded..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.h +++ /dev/null @@ -1,64 +0,0 @@ -/** - ****************************************************************************** - * - * @file pfdgadgetoptionspage.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin Primary Flight Display Plugin - * @{ - * @brief The Primary Flight Display Gadget - *****************************************************************************/ -/* - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef PFDGADGETOPTIONSPAGE_H -#define PFDGADGETOPTIONSPAGE_H - -#include "coreplugin/dialogs/ioptionspage.h" -#include "QString" -#include -#include - -namespace Core { -class IUAVGadgetConfiguration; -} - -class PFDGadgetConfiguration; - -namespace Ui { -class PFDGadgetOptionsPage; -} - -using namespace Core; - -class PFDGadgetOptionsPage : public IOptionsPage { - Q_OBJECT -public: - explicit PFDGadgetOptionsPage(PFDGadgetConfiguration *config, QObject *parent = 0); - - QWidget *createPage(QWidget *parent); - void apply(); - void finish(); - -private: - Ui::PFDGadgetOptionsPage *options_page; - PFDGadgetConfiguration *m_config; - -private slots: -}; - -#endif // PFDGADGETOPTIONSPAGE_H diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.ui b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.ui deleted file mode 100644 index 1373d2d3c..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.ui +++ /dev/null @@ -1,150 +0,0 @@ - - - PFDGadgetOptionsPage - - - - 0 - 0 - 430 - 306 - - - - - 0 - 0 - - - - Form - - - - 0 - - - - - QFrame::NoFrame - - - QFrame::Plain - - - true - - - - - 0 - 0 - 430 - 306 - - - - - 0 - - - - - 10 - - - QLayout::SetMaximumSize - - - 10 - - - - - PFD SVG: - - - - - - - - 0 - 0 - - - - - - - - - - - - true - - - Use OpenGL for rendering - - - true - - - - - - - High Quality text (OpenGL) - - - - - - - - - - - Smooth updates - - - true - - - - - - - - - Qt::Vertical - - - QSizePolicy::MinimumExpanding - - - - 20 - 40 - - - - - - - - - - - - - Utils::PathChooser - QWidget -
utils/pathchooser.h
- 1 -
-
- - -
diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetwidget.cpp deleted file mode 100644 index ce22b4e94..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetwidget.cpp +++ /dev/null @@ -1,1133 +0,0 @@ -/** - ****************************************************************************** - * - * @file pfdgadgetwidget.cpp - * @author Edouard Lafargue Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin Primary Flight Display Plugin - * @{ - * @brief The Primary Flight Display Gadget - *****************************************************************************/ -/* - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "pfdgadgetwidget.h" -#include -#include -#include -#include -#include -#include -#include - -PFDGadgetWidget::PFDGadgetWidget(QWidget *parent) : QGraphicsView(parent) -{ - setMinimumSize(64, 64); - setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - setScene(new QGraphicsScene(this)); -// setRenderHint(QPainter::SmoothPixmapTransform); - - setViewportUpdateMode(QGraphicsView::FullViewportUpdate); - // setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); - // setRenderHints(QPainter::TextAntialiasing); - // setRenderHints(QPainter::HighQualityAntialiasing); - - m_renderer = new QSvgRenderer(); - - attitudeObj = NULL; - headingObj = NULL; - gcsBatteryObj = NULL; - gpsObj = NULL; - compassBandWidth = 0; - pfdError = true; - hqFonts = false; - rollTarget = 0; - rollValue = 0; - pitchTarget = 0; - pitchValue = 0; - headingTarget = 0; - headingValue = 0; - groundspeedTarget = 0; - groundspeedValue = 0; - altitudeTarget = 0; - altitudeValue = 0; - - // This timer mechanism makes needles rotate smoothly - connect(&dialTimer, SIGNAL(timeout()), this, SLOT(moveNeedles())); - dialTimer.start(30); - - connect(&skyDialTimer, SIGNAL(timeout()), this, SLOT(moveSky())); - skyDialTimer.start(30); -} - -PFDGadgetWidget::~PFDGadgetWidget() -{ - skyDialTimer.stop(); - dialTimer.stop(); -} - -void PFDGadgetWidget::setToolTipPrivate() -{ - static qint32 updateRate = 0; - UAVObject::Metadata mdata = attitudeObj->getMetadata(); - - if (mdata.flightTelemetryUpdatePeriod != updateRate) { - this->setToolTip("Current refresh rate:" + QString::number(mdata.flightTelemetryUpdatePeriod) + " miliseconds" + "\nIf you want to change it please edit the AttitudeActual metadata on the object browser."); - } -} - -/*! - \brief Enables/Disables OpenGL - */ -void PFDGadgetWidget::enableOpenGL(bool flag) -{ - if (flag) { - setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); - } else { - setViewport(new QWidget); - } -} - -/*! - \brief Connects the widget to the relevant UAVObjects - - Should only be called after the PFD artwork is loaded. - We want: AttitudeActual, FlightBattery, Location. - - */ -void PFDGadgetWidget::connectNeedles() -{ - if (attitudeObj != NULL) { - disconnect(attitudeObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateAttitude(UAVObject *))); - } - - if (headingObj != NULL) { - disconnect(headingObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateHeading(UAVObject *))); - } - - if (gcsBatteryObj != NULL) { - disconnect(gcsBatteryObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateBattery(UAVObject *))); - } - - if (gpsObj != NULL) { - disconnect(gpsObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateGPS(UAVObject *))); - } - - // Safeguard: if artwork did not load properly, don't go further - if (pfdError) { - return; - } - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - - airspeedObj = dynamic_cast(objManager->getObject("AirspeedActual")); - if (airspeedObj != NULL) { - connect(airspeedObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateAirspeed(UAVObject *))); - } else { - qDebug() << "Error: Object is unknown (AirspeedActual)."; - } - - groundspeedObj = dynamic_cast(objManager->getObject("VelocityActual")); - if (groundspeedObj != NULL) { - connect(groundspeedObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateGroundspeed(UAVObject *))); - } else { - qDebug() << "Error: Object is unknown (VelocityActual)."; - } - - altitudeObj = dynamic_cast(objManager->getObject("PositionActual")); - if (altitudeObj != NULL) { - connect(altitudeObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateAltitude(UAVObject *))); - } else { - qDebug() << "Error: Object is unknown (PositionActual)."; - } - - attitudeObj = dynamic_cast(objManager->getObject("AttitudeActual")); - if (attitudeObj != NULL) { - connect(attitudeObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateAttitude(UAVObject *))); - } else { - qDebug() << "Error: Object is unknown (AttitudeActual)."; - } - - headingObj = dynamic_cast(objManager->getObject("PositionActual")); - if (headingObj != NULL) { - connect(headingObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateHeading(UAVObject *))); - } else { - qDebug() << "Error: Object is unknown (PositionActual)."; - } - - if (gcsGPSStats) { - gpsObj = dynamic_cast(objManager->getObject("GPSPosition")); - if (gpsObj != NULL) { - connect(gpsObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateGPS(UAVObject *))); - } else { - qDebug() << "Error: Object is unknown (GPSPosition)."; - } - } - - if (gcsTelemetryArrow || gcsTelemetryStats) { - // Only register if the PFD wants link stats/status - gcsTelemetryObj = dynamic_cast(objManager->getObject("GCSTelemetryStats")); - if (gcsTelemetryObj != NULL) { - connect(gcsTelemetryObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateLinkStatus(UAVObject *))); - } else { - qDebug() << "Error: Object is unknown (GCSTelemetryStats)."; - } - } - - if (gcsBatteryStats) { // Only register if the PFD wants battery display - gcsBatteryObj = dynamic_cast(objManager->getObject("FlightBatteryState")); - if (gcsBatteryObj != NULL) { - connect(gcsBatteryObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateBattery(UAVObject *))); - } else { - qDebug() << "Error: Object is unknown (FlightBatteryState)."; - } - } -} - - -/*! - \brief Updates the GPS stats - */ -void PFDGadgetWidget::updateGPS(UAVObject *object1) -{ - UAVObjectField *field = object1->getField(QString("Satellites")); - UAVObjectField *field1 = object1->getField(QString("PDOP")); - - if (field && field1) { - QString s = QString("GPS: ") + field->getValue().toString() + "\nPDP: " - + field1->getValue().toString(); - if (s != satString) { - gcsGPSStats->setPlainText(s); - satString = s; - } - } -} - -/*! - \brief Updates the link stats - */ -void PFDGadgetWidget::updateLinkStatus(UAVObject *object1) -{ - // TODO: find a way to avoid updating the graphics if the value - // has not changed since the last update - // Double check that the field exists: - QString st = QString("Status"); - QString tdr = QString("TxDataRate"); - QString rdr = QString("RxDataRate"); - UAVObjectField *field = object1->getField(st); - UAVObjectField *field2 = object1->getField(tdr); - UAVObjectField *field3 = object1->getField(rdr); - - if (field && field2 && field3) { - QString s = field->getValue().toString(); - if (m_renderer->elementExists("gcstelemetry-" + s) && gcsTelemetryArrow) { - gcsTelemetryArrow->setElementId("gcstelemetry-" + s); - } else { // Safeguard - gcsTelemetryArrow->setElementId("gcstelemetry-Disconnected"); - } - double v1 = field2->getDouble(); - double v2 = field3->getDouble(); - s.sprintf("%.0f/%.0f", v1, v2); - if (gcsTelemetryStats) { - gcsTelemetryStats->setPlainText(s); - } - } else { - qDebug() << "UpdateLinkStatus: Wrong field, maybe an issue with object disconnection ?"; - } -} - -/*! - \brief Reads the updated attitude and computes the new display position - - Resolution is 1 degree roll & 1/7.5 degree pitch. - */ -void PFDGadgetWidget::updateAttitude(UAVObject *object1) -{ - setToolTipPrivate(); - UAVObjectField *rollField = object1->getField(QString("Roll")); - UAVObjectField *yawField = object1->getField(QString("Yaw")); - UAVObjectField *pitchField = object1->getField(QString("Pitch")); - if (rollField && yawField && pitchField) { - // These factors assume some things about the PFD SVG, namely: - // - Roll, Pitch and Heading value in degrees - // - Pitch lines are 300px high for a +20/-20 range, which means - // 7.5 pixels per pitch degree. - // TODO: loosen this constraint and only require a +/- 20 deg range, - // and compute the height from the SVG element. - // Also: keep the integer value only, to avoid unnecessary redraws - rollTarget = -floor(rollField->getDouble() * 10) / 10; - if ((rollTarget - rollValue) > 180) { - rollValue += 360; - } else if (((rollTarget - rollValue) < -180)) { - rollValue -= 360; - } - pitchTarget = floor(pitchField->getDouble() * 7.5); - - // These factors assume some things about the PFD SVG, namely: - // - Heading value in degrees - // - "Scale" element is 540 degrees wide - - // Corvus Corax: "If you want a smooth transition between two angles, It is usually solved that by substracting - // one from another, and if the result is >180 or <-180 I substract (respectively add) 360 degrees - // to it. That way you always get the "shorter difference" to turn in." - double fac = compassBandWidth / 540; - headingTarget = yawField->getDouble() * (-fac); - if (headingTarget != headingTarget) { - headingTarget = headingValue; // NaN checking. - } - if ((headingValue - headingTarget) / fac > 180) { - headingTarget += 360 * fac; - } else if (((headingValue - headingTarget) / fac < -180)) { - headingTarget -= 360 * fac; - } - headingTarget = floor(headingTarget * 10) / 10; // Avoid stupid redraws - - if (!dialTimer.isActive()) { - dialTimer.start(); // Rearm the dial Timer which might be stopped. - } - } else { - qDebug() << "Unable to get one of the fields for attitude update"; - } -} - -/*! - \brief Updates the compass reading and speed dial. - - This also updates speed & altitude according to PositionActual data. - - Note: the speed dial shows the ground speed at the moment, because - there is no airspeed by default. Should become configurable in a future - gadget release (TODO) - */ -void PFDGadgetWidget::updateHeading(UAVObject *object) -{ - Q_UNUSED(object); -} - -/*! - \brief Called by updates to @PositionActual to compute groundspeed from velocity - */ -void PFDGadgetWidget::updateGroundspeed(UAVObject *object) -{ - UAVObjectField *northField = object->getField("North"); - UAVObjectField *eastField = object->getField("East"); - - if (northField && eastField) { - double val = floor(sqrt(pow(northField->getDouble(), 2) + pow(eastField->getDouble(), 2)) * 10) / 10; - groundspeedTarget = val * speedScaleHeight / 30; - - if (!dialTimer.isActive()) { - dialTimer.start(); // Rearm the dial Timer which might be stopped. - } - } else { - qDebug() << "UpdateHeading: Wrong field, maybe an issue with object disconnection ?"; - } -} - - -/*! - \brief Called by updates to @AirspeedActual - */ -void PFDGadgetWidget::updateAirspeed(UAVObject *object) -{ - UAVObjectField *airspeedField = object->getField("CalibratedAirspeed"); - - if (airspeedField) { - airspeedTarget = airspeedField->getDouble(); - - if (!dialTimer.isActive()) { - dialTimer.start(); // Rearm the dial Timer which might be stopped. - } - } else { - qDebug() << "UpdateHeading: Wrong field, maybe an issue with object disconnection ?"; - } -} - -/*! - \brief Called by the @ref PositionActual updates to show altitude - */ -void PFDGadgetWidget::updateAltitude(UAVObject *object) -{ - UAVObjectField *downField = object->getField("Down"); - - if (downField) { - altitudeTarget = -downField->getDouble(); - - if (!dialTimer.isActive()) { - dialTimer.start(); // Rearm the dial Timer which might be stopped. - } - } else { - qDebug() << "Unable to get field for altitude update. Obj: " << object->getName(); - } -} - - -/*! - \brief Called by the UAVObject which got updated - */ -void PFDGadgetWidget::updateBattery(UAVObject *object1) -{ - // Double check that the field exists: - QString voltage = QString("Voltage"); - QString current = QString("Current"); - QString energy = QString("ConsumedEnergy"); - UAVObjectField *field = object1->getField(voltage); - UAVObjectField *field2 = object1->getField(current); - UAVObjectField *field3 = object1->getField(energy); - - if (field && field2 && field3) { - QString s = QString(); - double v0 = field->getDouble(); - double v1 = field2->getDouble(); - double v2 = field3->getDouble(); - s.sprintf("%.2fV\n%.2fA\n%.0fmAh", v0, v1, v2); - if (s != batString) { - gcsBatteryStats->setPlainText(s); - batString = s; - } - } else { - qDebug() << "UpdateBattery: Wrong field, maybe an issue with object disconnection ?"; - } -} - - -/*! - \brief Sets up the PFD from the SVG master file. - - Initializes the display, and does all the one-time calculations. - */ -void PFDGadgetWidget::setDialFile(QString dfn) -{ - QGraphicsScene *l_scene = scene(); - - setBackgroundBrush(QBrush(Utils::StyleHelper::baseColor())); - if (QFile::exists(dfn) && m_renderer->load(dfn) && m_renderer->isValid()) { -/* The PFD element IDs are fixed, not like with the analog dial. - - Background: background - - Foreground: foreground (contains all fixed elements, including plane) - - earth/sky : world - - Roll scale: rollscale - - compass frame: compass (part of the foreground) - - compass band : compass-band - - Home point: homewaypoint - - Next point: nextwaypoint - - Home point bearing: homewaypoint-bearing - - Next point bearing: nextwaypoint-bearing - - Speed rectangle (left side): speed-bg - - Speed scale: speed-scale. - - Black speed window: speed-window. - - Altitude rectangle (right site): altitude-bg. - - Altitude scale: altitude-scale. - - Black altitude window: altitude-window. - - GCS Telemetry status arrow: gcstelemetry-XXXX - - Telemetry link rate: linkrate - - GPS status text: gps-txt - - Battery stats: battery-txt - */ - l_scene->clear(); // Deletes all items contained in the scene as well. - m_background = new CachedSvgItem(); - // All other items will be clipped to the shape of the background - m_background->setFlags(QGraphicsItem::ItemClipsChildrenToShape | - QGraphicsItem::ItemClipsToShape); - m_background->setSharedRenderer(m_renderer); - m_background->setElementId("background"); - l_scene->addItem(m_background); - - m_world = new CachedSvgItem(); - m_world->setParentItem(m_background); - m_world->setSharedRenderer(m_renderer); - m_world->setElementId("world"); - l_scene->addItem(m_world); - - // red Roll scale: rollscale - m_rollscale = new CachedSvgItem(); - m_rollscale->setSharedRenderer(m_renderer); - m_rollscale->setElementId("rollscale"); - l_scene->addItem(m_rollscale); - - // Home point: - m_homewaypoint = new CachedSvgItem(); - // Next point: - m_nextwaypoint = new CachedSvgItem(); - // Home point bearing: - m_homepointbearing = new CachedSvgItem(); - // Next point bearing: - m_nextpointbearing = new CachedSvgItem(); - - QGraphicsSvgItem *m_foreground = new CachedSvgItem(); - m_foreground->setParentItem(m_background); - m_foreground->setSharedRenderer(m_renderer); - m_foreground->setElementId("foreground"); - l_scene->addItem(m_foreground); - - //////////////////// - // Compass - //////////////////// - // Get the default location of the Compass: - QMatrix compassMatrix = m_renderer->matrixForElement("compass"); - qreal startX = compassMatrix.mapRect(m_renderer->boundsOnElement("compass")).x(); - qreal startY = compassMatrix.mapRect(m_renderer->boundsOnElement("compass")).y(); - // Then once we have the initial location, we can put it - // into a QGraphicsSvgItem which we will display at the same - // place: we do this so that the heading scale can be clipped to - // the compass dial region. - m_compass = new CachedSvgItem(); - m_compass->setSharedRenderer(m_renderer); - m_compass->setElementId("compass"); - m_compass->setFlags(QGraphicsItem::ItemClipsChildrenToShape | - QGraphicsItem::ItemClipsToShape); - l_scene->addItem(m_compass); - QTransform matrix; - matrix.translate(startX, startY); - m_compass->setTransform(matrix, false); - - // Now place the compass scale inside: - m_compassband = new CachedSvgItem(); - m_compassband->setSharedRenderer(m_renderer); - m_compassband->setElementId("compass-band"); - m_compassband->setParentItem(m_compass); - l_scene->addItem(m_compassband); - matrix.reset(); - // Note: the compass band has to be a path, which means all text elements have to be - // converted, ortherwise boundsOnElement does not compute the height correctly - // if the highest element is a text element. This is a Qt Bug as far as I can tell. - - // compass-scale is the while bottom line inside the band: using the band's width - // includes half the width of the letters, which causes errors: - compassBandWidth = m_renderer->boundsOnElement("compass-scale").width(); - - //////////////////// - // Speed - //////////////////// - // Speedometer on the left hand: - // - compassMatrix = m_renderer->matrixForElement("speed-bg"); - startX = compassMatrix.mapRect(m_renderer->boundsOnElement("speed-bg")).x(); - startY = compassMatrix.mapRect(m_renderer->boundsOnElement("speed-bg")).y(); - QGraphicsSvgItem *verticalbg = new CachedSvgItem(); - verticalbg->setSharedRenderer(m_renderer); - verticalbg->setElementId("speed-bg"); - verticalbg->setFlags(QGraphicsItem::ItemClipsChildrenToShape | - QGraphicsItem::ItemClipsToShape); - l_scene->addItem(verticalbg); - matrix.reset(); - matrix.translate(startX, startY); - verticalbg->setTransform(matrix, false); - - // Note: speed-scale should contain exactly 6 major ticks - // for 30km/h - m_speedscale = new QGraphicsItemGroup(); - m_speedscale->setParentItem(verticalbg); - - QGraphicsSvgItem *speedscalelines = new CachedSvgItem(); - speedscalelines->setSharedRenderer(m_renderer); - speedscalelines->setElementId("speed-scale"); - speedScaleHeight = m_renderer->matrixForElement("speed-scale").mapRect( - m_renderer->boundsOnElement("speed-scale")).height(); - startX = compassMatrix.mapRect(m_renderer->boundsOnElement("speed-bg")).width(); - startX -= m_renderer->matrixForElement("speed-scale").mapRect( - m_renderer->boundsOnElement("speed-scale")).width(); - matrix.reset(); - matrix.translate(startX, 0); - speedscalelines->setTransform(matrix, false); - // Quick way to reposition the item before putting it in the group: - speedscalelines->setParentItem(verticalbg); - m_speedscale->addToGroup(speedscalelines); // (reparents the item) - - // Add the scale text elements: - QGraphicsTextItem *speed0 = new QGraphicsTextItem("0"); - speed0->setDefaultTextColor(QColor("White")); - speed0->setFont(QFont("Arial", (int)speedScaleHeight / 30)); - if (hqFonts) { - speed0->setCacheMode(QGraphicsItem::DeviceCoordinateCache); - } - matrix.reset(); - matrix.translate(compassMatrix.mapRect(m_renderer->boundsOnElement("speed-bg")).width() / 10, -speedScaleHeight / 30); - speed0->setTransform(matrix, false); - speed0->setParentItem(verticalbg); - m_speedscale->addToGroup(speed0); - for (int i = 0; i < 6; i++) { - speed0 = new QGraphicsTextItem(""); - speed0->setDefaultTextColor(QColor("White")); - speed0->setFont(QFont("Arial", (int)speedScaleHeight / 30)); - speed0->setPlainText(QString().setNum(i * 5 + 1)); - if (hqFonts) { - speed0->setCacheMode(QGraphicsItem::DeviceCoordinateCache); - } - matrix.translate(0, speedScaleHeight / 6); - speed0->setTransform(matrix, false); - speed0->setParentItem(verticalbg); - m_speedscale->addToGroup(speed0); - } - // Now vertically center the speed scale on the speed background - QRectF rectB = verticalbg->boundingRect(); - QRectF rectN = speedscalelines->boundingRect(); - m_speedscale->setPos(0, rectB.height() / 2 - rectN.height() / 2 - rectN.height() / 6); - - // Isolate the speed window and put it above the speed scale - compassMatrix = m_renderer->matrixForElement("speed-window"); - startX = compassMatrix.mapRect(m_renderer->boundsOnElement("speed-window")).x(); - startY = compassMatrix.mapRect(m_renderer->boundsOnElement("speed-window")).y(); - qreal speedWindowHeight = compassMatrix.mapRect(m_renderer->boundsOnElement("speed-window")).height(); - QGraphicsSvgItem *speedwindow = new CachedSvgItem(); - speedwindow->setSharedRenderer(m_renderer); - speedwindow->setElementId("speed-window"); - speedwindow->setFlags(QGraphicsItem::ItemClipsChildrenToShape | - QGraphicsItem::ItemClipsToShape); - l_scene->addItem(speedwindow); - matrix.reset(); - matrix.translate(startX, startY); - speedwindow->setTransform(matrix, false); - - // Last create a Text Item at the location of the speed window - // and save it for future updates: - m_speedtext = new QGraphicsTextItem("0000"); - m_speedtext->setDefaultTextColor(QColor("White")); - m_speedtext->setFont(QFont("Arial", (int)speedWindowHeight / 2)); - if (hqFonts) { - m_speedtext->setCacheMode(QGraphicsItem::DeviceCoordinateCache); - } - m_speedtext->setParentItem(speedwindow); - - //////////////////// - // Altitude - //////////////////// - // Right hand, very similar to speed - compassMatrix = m_renderer->matrixForElement("altitude-bg"); - startX = compassMatrix.mapRect(m_renderer->boundsOnElement("altitude-bg")).x(); - startY = compassMatrix.mapRect(m_renderer->boundsOnElement("altitude-bg")).y(); - verticalbg = new CachedSvgItem(); - verticalbg->setSharedRenderer(m_renderer); - verticalbg->setElementId("altitude-bg"); - verticalbg->setFlags(QGraphicsItem::ItemClipsChildrenToShape | - QGraphicsItem::ItemClipsToShape); - l_scene->addItem(verticalbg); - matrix.reset(); - matrix.translate(startX, startY); - verticalbg->setTransform(matrix, false); - - // Note: altitude-scale should contain exactly 6 major ticks - // for 30 meters - m_altitudescale = new QGraphicsItemGroup(); - m_altitudescale->setParentItem(verticalbg); - - QGraphicsSvgItem *altitudescalelines = new CachedSvgItem(); - altitudescalelines->setSharedRenderer(m_renderer); - altitudescalelines->setElementId("altitude-scale"); - altitudeScaleHeight = m_renderer->matrixForElement("altitude-scale").mapRect( - m_renderer->boundsOnElement("altitude-scale")).height(); - // Quick way to reposition the item before putting it in the group: - altitudescalelines->setParentItem(verticalbg); - m_altitudescale->addToGroup(altitudescalelines); // (reparents the item) - - // Add the scale text elements: - speed0 = new QGraphicsTextItem("XXXX"); - speed0->setDefaultTextColor(QColor("White")); - speed0->setFont(QFont("Arial", (int)altitudeScaleHeight / 30)); - if (hqFonts) { - speed0->setCacheMode(QGraphicsItem::DeviceCoordinateCache); - } - matrix.reset(); - matrix.translate(m_renderer->matrixForElement("altitude-scale").mapRect(m_renderer->boundsOnElement("altitude-scale")).width() - + m_renderer->matrixForElement("altitude-bg").mapRect(m_renderer->boundsOnElement("altitude-bg")).width() / 10, -altitudeScaleHeight / 30); - speed0->setTransform(matrix, false); - speed0->setParentItem(verticalbg); - m_altitudescale->addToGroup(speed0); - for (int i = 0; i < 6; i++) { - speed0 = new QGraphicsTextItem("XXXX"); - speed0->setDefaultTextColor(QColor("White")); - speed0->setFont(QFont("Arial", (int)altitudeScaleHeight / 30)); - speed0->setPlainText(QString().setNum(i * 5 + 1)); - if (hqFonts) { - speed0->setCacheMode(QGraphicsItem::DeviceCoordinateCache); - } - matrix.translate(0, altitudeScaleHeight / 6); - speed0->setTransform(matrix, false); - speed0->setParentItem(verticalbg); - m_altitudescale->addToGroup(speed0); - } - // Now vertically center the speed scale on the speed background - rectB = verticalbg->boundingRect(); - rectN = altitudescalelines->boundingRect(); - m_altitudescale->setPos(0, rectB.height() / 2 - rectN.height() / 2 - rectN.height() / 6); - - // Isolate the Altitude window and put it above the altitude scale - compassMatrix = m_renderer->matrixForElement("altitude-window"); - startX = compassMatrix.mapRect(m_renderer->boundsOnElement("altitude-window")).x(); - startY = compassMatrix.mapRect(m_renderer->boundsOnElement("altitude-window")).y(); - qreal altitudeWindowHeight = compassMatrix.mapRect(m_renderer->boundsOnElement("altitude-window")).height(); - QGraphicsSvgItem *altitudewindow = new CachedSvgItem(); - altitudewindow->setSharedRenderer(m_renderer); - altitudewindow->setElementId("altitude-window"); - altitudewindow->setFlags(QGraphicsItem::ItemClipsChildrenToShape | - QGraphicsItem::ItemClipsToShape); - l_scene->addItem(altitudewindow); - matrix.reset(); - matrix.translate(startX, startY); - altitudewindow->setTransform(matrix, false); - - // Last create a Text Item at the location of the speed window - // and save it for future updates: - m_altitudetext = new QGraphicsTextItem("0000"); - m_altitudetext->setDefaultTextColor(QColor("White")); - m_altitudetext->setFont(QFont("Arial", (int)altitudeWindowHeight / 2)); - if (hqFonts) { - m_altitudetext->setCacheMode(QGraphicsItem::DeviceCoordinateCache); - } - m_altitudetext->setParentItem(altitudewindow); - startX = compassMatrix.mapRect(m_renderer->boundsOnElement("altitude-window")).width() / 10; - matrix.reset(); - matrix.translate(startX, 0); - m_altitudetext->setTransform(matrix, false); - - //////////////// - // GCS Telemetry Indicator - //////////////// - if (m_renderer->elementExists("gcstelemetry-Disconnected")) { - compassMatrix = m_renderer->matrixForElement("gcstelemetry-Disconnected"); - startX = compassMatrix.mapRect(m_renderer->boundsOnElement("gcstelemetry-Disconnected")).x(); - startY = compassMatrix.mapRect(m_renderer->boundsOnElement("gcstelemetry-Disconnected")).y(); - gcsTelemetryArrow = new CachedSvgItem(); - gcsTelemetryArrow->setSharedRenderer(m_renderer); - gcsTelemetryArrow->setElementId("gcstelemetry-Disconnected"); - l_scene->addItem(gcsTelemetryArrow); - matrix.reset(); - matrix.translate(startX, startY); - gcsTelemetryArrow->setTransform(matrix, false); - } else { - gcsTelemetryArrow = NULL; - } - - if (m_renderer->elementExists("linkrate")) { - compassMatrix = m_renderer->matrixForElement("linkrate"); - startX = compassMatrix.mapRect(m_renderer->boundsOnElement("linkrate")).x(); - startY = compassMatrix.mapRect(m_renderer->boundsOnElement("linkrate")).y(); - qreal linkRateHeight = compassMatrix.mapRect(m_renderer->boundsOnElement("linkrate")).height(); - gcsTelemetryStats = new QGraphicsTextItem(); - gcsTelemetryStats->setDefaultTextColor(QColor("White")); - gcsTelemetryStats->setFont(QFont("Arial", (int)linkRateHeight)); - if (hqFonts) { - gcsTelemetryStats->setCacheMode(QGraphicsItem::DeviceCoordinateCache); - } - l_scene->addItem(gcsTelemetryStats); - matrix.reset(); - matrix.translate(startX, startY - linkRateHeight / 2); - gcsTelemetryStats->setTransform(matrix, false); - } else { - gcsTelemetryStats = NULL; - } - - - //////////////// - // GCS Battery Indicator - //////////////// - /* (to be used the day I add a green/yellow/red indicator) - compassMatrix = m_renderer->matrixForElement("gcstelemetry-Disconnected"); - startX = compassMatrix.mapRect(m_renderer->boundsOnElement("gcstelemetry-Disconnected")).x(); - startY = compassMatrix.mapRect(m_renderer->boundsOnElement("gcstelemetry-Disconnected")).y(); - gcsTelemetryArrow = new CachedSvgItem(); - gcsTelemetryArrow->setSharedRenderer(m_renderer); - gcsTelemetryArrow->setElementId("gcstelemetry-Disconnected"); - l_scene->addItem(gcsTelemetryArrow); - matrix.reset(); - matrix.translate(startX,startY); - gcsTelemetryArrow->setTransform(matrix,false); - */ - - if (m_renderer->elementExists("battery-txt")) { - compassMatrix = m_renderer->matrixForElement("battery-txt"); - startX = compassMatrix.mapRect(m_renderer->boundsOnElement("battery-txt")).x(); - startY = compassMatrix.mapRect(m_renderer->boundsOnElement("battery-txt")).y(); - qreal batStatHeight = compassMatrix.mapRect(m_renderer->boundsOnElement("battery-txt")).height(); - gcsBatteryStats = new QGraphicsTextItem("Battery"); - gcsBatteryStats->setDefaultTextColor(QColor("White")); - gcsBatteryStats->setFont(QFont("Arial", (int)batStatHeight)); - if (hqFonts) { - gcsBatteryStats->setCacheMode(QGraphicsItem::DeviceCoordinateCache); - } - l_scene->addItem(gcsBatteryStats); - matrix.reset(); - matrix.translate(startX, startY - batStatHeight / 2); - gcsBatteryStats->setTransform(matrix, false); - } else { - gcsBatteryStats = NULL; - } - - //////////////// - // GCS GPS Indicator - //////////////// - /* (to be used the day I add a green/yellow/red indicator) - compassMatrix = m_renderer->matrixForElement("gcstelemetry-Disconnected"); - startX = compassMatrix.mapRect(m_renderer->boundsOnElement("gcstelemetry-Disconnected")).x(); - startY = compassMatrix.mapRect(m_renderer->boundsOnElement("gcstelemetry-Disconnected")).y(); - gcsTelemetryArrow = new CachedSvgItem(); - gcsTelemetryArrow->setSharedRenderer(m_renderer); - gcsTelemetryArrow->setElementId("gcstelemetry-Disconnected"); - l_scene->addItem(gcsTelemetryArrow); - matrix.reset(); - matrix.translate(startX,startY); - gcsTelemetryArrow->setTransform(matrix,false); - */ - - if (m_renderer->elementExists("gps-txt")) { - compassMatrix = m_renderer->matrixForElement("gps-txt"); - startX = compassMatrix.mapRect(m_renderer->boundsOnElement("gps-txt")).x(); - startY = compassMatrix.mapRect(m_renderer->boundsOnElement("gps-txt")).y(); - qreal gpsStatHeight = compassMatrix.mapRect(m_renderer->boundsOnElement("gps-txt")).height(); - gcsGPSStats = new QGraphicsTextItem("GPS"); - gcsGPSStats->setDefaultTextColor(QColor("White")); - gcsGPSStats->setFont(QFont("Arial", (int)gpsStatHeight)); - if (hqFonts) { - gcsGPSStats->setCacheMode(QGraphicsItem::DeviceCoordinateCache); - } - l_scene->addItem(gcsGPSStats); - matrix.reset(); - matrix.translate(startX, startY - gpsStatHeight / 2); - gcsGPSStats->setTransform(matrix, false); - } else { - gcsGPSStats = NULL; - } - - l_scene->setSceneRect(m_background->boundingRect()); - - ///////////////// - // Item placement - ///////////////// - - // Now Initialize the center for all transforms of the relevant elements to the - // center of the background: - - // 1) Move the center of the needle to the center of the background. - rectB = m_background->boundingRect(); - rectN = m_world->boundingRect(); - m_world->setPos(rectB.width() / 2 - rectN.width() / 2, rectB.height() / 2 - rectN.height() / 2); - // 2) Put the transform origin point of the needle at its center. - m_world->setTransformOriginPoint(rectN.width() / 2, rectN.height() / 2); - - rectN = m_rollscale->boundingRect(); - m_rollscale->setPos(rectB.width() / 2 - rectN.width() / 2, rectB.height() / 2 - rectN.height() / 2); - m_rollscale->setTransformOriginPoint(rectN.width() / 2, rectN.height() / 2); - - // Also to the same init for the compass: - rectB = m_compass->boundingRect(); - rectN = m_compassband->boundingRect(); - m_compassband->setPos(rectB.width() / 2 - rectN.width() / 2, rectB.height() / 2 - rectN.height() / 2); - m_compassband->setTransformOriginPoint(rectN.width() / 2, rectN.height() / 2); - - // Last: we just loaded the dial file which is by default valid for a "zero" value - // of the needles, so we have to reset the needles too upon dial file loading, otherwise - // we would end up with an offset when we change a dial file and the needle value - // is not zero at that time. - rollValue = 0; - pitchValue = 0; - headingValue = 0; - groundspeedValue = 0; - altitudeValue = 0; - pfdError = false; - if (!dialTimer.isActive()) { - dialTimer.start(); // Rearm the dial Timer which might be stopped. - } - } else { qDebug() << "Error on PFD artwork file."; - m_renderer->load(QString(":/pfd/images/pfd-default.svg")); - l_scene->clear(); // This also deletes all items contained in the scene. - m_background = new CachedSvgItem(); - m_background->setSharedRenderer(m_renderer); - l_scene->addItem(m_background); - pfdError = true; } -} - -void PFDGadgetWidget::paint() -{ - // update(); -} - -void PFDGadgetWidget::paintEvent(QPaintEvent *event) -{ - // Skip painting until the dial file is loaded - if (!m_renderer->isValid()) { - qDebug() << "Dial file not loaded, not rendering"; - return; - } - QGraphicsView::paintEvent(event); -} - -// This event enables the dial to be dynamically resized -// whenever the gadget is resized, taking advantage of the vector -// nature of SVG dials. -void PFDGadgetWidget::resizeEvent(QResizeEvent *event) -{ - Q_UNUSED(event); - fitInView(m_background, Qt::KeepAspectRatio); -} - - -/*! - \brief Update method for the vertical scales - */ -void PFDGadgetWidget::moveVerticalScales() {} - -void PFDGadgetWidget::moveSky() -{ - int dialCount = 2; // Gets decreased by one for each element - - // which has finished moving -// qDebug() << "MoveSky"; - /// TODO: optimize!!! - if (pfdError) { - // skyDialTimer.stop(); - return; - } - - // In some instances, it can happen that the rollValue & target are - // invalid inside the UAVObjects, and become a "nan" value, which freezes - // the PFD and the whole GCS: for this reason, we check this here. - // The strange check below works, it is a workaround because "isnan(double)" - // is not supported on every compiler. - if (rollTarget != rollTarget || pitchTarget != pitchTarget) { - return; - } - ////// - // Roll - ////// - if (rollValue != rollTarget) { - double rollDiff; - if ((abs((rollValue - rollTarget) * 10) > 5) && beSmooth) { - rollDiff = (rollTarget - rollValue) / 2; - } else { - rollDiff = rollTarget - rollValue; - dialCount--; - } - m_world->setRotation(m_world->rotation() + rollDiff); - m_rollscale->setRotation(m_rollscale->rotation() + rollDiff); - rollValue += rollDiff; - } else { - dialCount--; - } - - ////// - // Pitch - ////// - if (pitchValue != pitchTarget) { - double pitchDiff; - if ((abs((pitchValue - pitchTarget) * 10) > 5) && beSmooth) { - // if (0) { - pitchDiff = (pitchTarget - pitchValue) / 2; - } else { - pitchDiff = pitchTarget - pitchValue; - dialCount--; - } - QPointF opd = QPointF(0, pitchDiff); - m_world->setTransform(QTransform::fromTranslate(opd.x(), opd.y()), true); - QPointF oop = m_world->transformOriginPoint(); - m_world->setTransformOriginPoint((oop.x() - opd.x()), (oop.y() - opd.y())); - pitchValue += pitchDiff; - } else { - dialCount--; - } - - if (dialCount) { - scene()->update(sceneRect()); - } - // if (!dialCount) - // skyDialTimer.stop(); -} - - -// Take an input value and move the elements accordingly. -// Movement is smooth, starts fast and slows down when -// approaching the target. -// -void PFDGadgetWidget::moveNeedles() -{ - int dialCount = 3; // Gets decreased by one for each element - - // which has finished moving - -// qDebug() << "MoveNeedles"; - /// TODO: optimize!!! - - if (pfdError) { - dialTimer.stop(); - return; - } - - ////// - // Heading - // - // If you want a smooth transition between two angles, It is usually solved that by substracting - // one from another, and if the result is >180 or <-180 I substract (respectively add) 360 degrees - // to it. That way you always get the "shorter difference" to turn in. - ////// - if (headingValue != headingTarget) { - double headingDiff; - if ((abs((headingValue - headingTarget) * 10) > 5) && beSmooth) { - headingDiff = (headingTarget - headingValue) / 5; - } else { - headingDiff = headingTarget - headingValue; - dialCount--; - } - double threshold = 180 * compassBandWidth / 540; - // Note: rendering can jump oh so very slightly when crossing the 180 degree - // boundary, should not impact actual useability of the display. - if ((headingValue + headingDiff) >= threshold) { - // We went over 180°: activate a -360 degree offset - headingDiff -= 2 * threshold; - headingTarget -= 2 * threshold; - } else if ((headingValue + headingDiff) < -threshold) { - // We went under -180°: remove the -360 degree offset - headingDiff += 2 * threshold; - headingTarget += 2 * threshold; - } - QPointF opd = QPointF(headingDiff, 0); - m_compassband->setTransform(QTransform::fromTranslate(opd.x(), opd.y()), true); - headingValue += headingDiff; - } else { - dialCount--; - } - - ////// - // Airspeed - ////// - if (airspeedValue != airspeedTarget) { - if ((abs(airspeedValue - airspeedTarget) > speedScaleHeight / 100) && beSmooth) { - airspeedValue += (airspeedTarget - airspeedValue) / 2; - } else { - airspeedValue = airspeedTarget; - dialCount--; - } - - float airspeed_kph = airspeedValue * 3.6; - float airspeed_kph_scale = airspeed_kph * speedScaleHeight / 30; - - qreal x = m_speedscale->transform().dx(); - // opd = QPointF(x,fmod(airspeed_kph,speedScaleHeight/6)); - // fmod does rounding errors!! the formula below works better: - QPointF opd = QPointF(x, airspeed_kph_scale - floor(airspeed_kph_scale / speedScaleHeight * 6) * speedScaleHeight / 6); - m_speedscale->setTransform(QTransform::fromTranslate(opd.x(), opd.y()), false); - - double speedText = airspeed_kph; - QString s = QString().sprintf("%.0f", speedText); - m_speedtext->setPlainText(s); - - // Now update the text elements inside the scale: - // (Qt documentation states that the list has the same order - // as the item add order in the QGraphicsItemGroup) - QList textList = m_speedscale->childItems(); - qreal val = 5 * floor(airspeed_kph_scale / speedScaleHeight * 6) + 20; - foreach(QGraphicsItem * item, textList) { - if (QGraphicsTextItem * text = qgraphicsitem_cast(item)) { - QString s = (val < 0) ? QString() : QString().sprintf("%.0f", val); - if (text->toPlainText() == s) { - break; // This should happen at element one if is has not changed, indicating - } - // that it's not necessary to do the rest of the list - text->setPlainText(s); - val -= 5; - } - } - } else { - dialCount--; - } - - ////// - // Groundspeed - ////// - if (groundspeedValue != groundspeedTarget) { - groundspeedValue = groundspeedTarget; - qreal x = m_speedscale->transform().dx(); - // opd = QPointF(x,fmod(groundspeedValue,speedScaleHeight/6)); - // fmod does rounding errors!! the formula below works better: - QPointF opd = QPointF(x, groundspeedValue - floor(groundspeedValue / speedScaleHeight * 6) * speedScaleHeight / 6); - m_speedscale->setTransform(QTransform::fromTranslate(opd.x(), opd.y()), false); - - double speedText = groundspeedValue / speedScaleHeight * 30; - QString s = QString().sprintf("%.0f", speedText); - m_speedtext->setPlainText(s); - - // Now update the text elements inside the scale: - // (Qt documentation states that the list has the same order - // as the item add order in the QGraphicsItemGroup) - QList textList = m_speedscale->childItems(); - qreal val = 5 * floor(groundspeedValue / speedScaleHeight * 6) + 20; - foreach(QGraphicsItem * item, textList) { - if (QGraphicsTextItem * text = qgraphicsitem_cast(item)) { - QString s = (val < 0) ? QString() : QString().sprintf("%.0f", val); - if (text->toPlainText() == s) { - break; // This should happen at element one if is has not changed, indicating - } - // that it's not necessary to do the rest of the list - text->setPlainText(s); - val -= 5; - } - } - } - - ////// - // Altitude - ////// - if (altitudeValue != altitudeTarget) { - if ((abs(altitudeValue - altitudeTarget) > altitudeScaleHeight / 100) && beSmooth) { - altitudeValue += (altitudeTarget - altitudeValue) / 2; - } else { - altitudeValue = altitudeTarget; - dialCount--; - } - - // The altitude scale represents 30 meters - float altitudeValue_scale = floor(altitudeValue * 10) / 10 * altitudeScaleHeight / 30; - - qreal x = m_altitudescale->transform().dx(); - // opd = QPointF(x,fmod(altitudeValue,altitudeScaleHeight/6)); - // fmod does rounding errors!! the formula below works better: - QPointF opd = QPointF(x, altitudeValue_scale - floor(altitudeValue_scale / altitudeScaleHeight * 6) * altitudeScaleHeight / 6); - m_altitudescale->setTransform(QTransform::fromTranslate(opd.x(), opd.y()), false); - - double altitudeText = altitudeValue; - QString s = QString().sprintf("%.0f", altitudeText); - m_altitudetext->setPlainText(s); - - // Now update the text elements inside the scale: - // (Qt documentation states that the list has the same order - // as the item add order in the QGraphicsItemGroup) - QList textList = m_altitudescale->childItems(); - qreal val = 5 * floor(altitudeValue_scale / altitudeScaleHeight * 6) + 20; - foreach(QGraphicsItem * item, textList) { - if (QGraphicsTextItem * text = qgraphicsitem_cast(item)) { - QString s = (val < 0) ? QString() : QString().sprintf("%.0f", val); - if (text->toPlainText() == s) { - break; // This should happen at element one if is has not changed, indicating - } - // that it's not necessary to do the rest of the list - text->setPlainText(s); - val -= 5; - } - } - } else { - dialCount--; - } - - if (!dialCount) { - dialTimer.stop(); - } else { - scene()->update(sceneRect()); - } -} - -/** - @} - @} - */ diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetwidget.h b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetwidget.h deleted file mode 100644 index d80b73432..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetwidget.h +++ /dev/null @@ -1,160 +0,0 @@ -/** - ****************************************************************************** - * - * @file pfdgadgetwidget.h - * @author Edouard Lafargue Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin Primary Flight Display Plugin - * @{ - * @brief The Primary Flight Display Gadget - *****************************************************************************/ -/* - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef PFDGADGETWIDGET_H_ -#define PFDGADGETWIDGET_H_ - -#include "pfdgadgetconfiguration.h" -#include "extensionsystem/pluginmanager.h" -#include "uavobjectmanager.h" -#include "uavobject.h" -#include -#include -#include - -#include -#include - -class PFDGadgetWidget : public QGraphicsView { - Q_OBJECT - -public: - PFDGadgetWidget(QWidget *parent = 0); - ~PFDGadgetWidget(); - void setDialFile(QString dfn); - void paint(); - // Sets up needle/UAVObject connections: - void connectNeedles(); - void enableOpenGL(bool flag); - void setHqFonts(bool flag) - { - hqFonts = flag; - } - void enableSmoothUpdates(bool flag) - { - beSmooth = flag; - } - - -public slots: - void updateAttitude(UAVObject *object1); - void updateHeading(UAVObject *object1); - void updateGPS(UAVObject *object1); - void updateGroundspeed(UAVObject *object1); - void updateAirspeed(UAVObject *object1); - void updateAltitude(UAVObject *object1); - void updateBattery(UAVObject *object1); - void updateLinkStatus(UAVObject *object1); - -protected: - void paintEvent(QPaintEvent *event); - void resizeEvent(QResizeEvent *event); - - -private slots: - void moveNeedles(); - void moveVerticalScales(); - void moveSky(); - void setToolTipPrivate(); -private: - QSvgRenderer *m_renderer; - - // Background: background - QGraphicsSvgItem *m_background; - // earth/sky : world - QGraphicsSvgItem *m_world; - // Roll scale: rollscale - QGraphicsSvgItem *m_rollscale; - // Compass dial: - QGraphicsSvgItem *m_compass; - // Compass band: - QGraphicsSvgItem *m_compassband; - // Home point: - QGraphicsSvgItem *m_homewaypoint; - // Next point: - QGraphicsSvgItem *m_nextwaypoint; - // Home point bearing: - QGraphicsSvgItem *m_homepointbearing; - // Next point bearing: - QGraphicsSvgItem *m_nextpointbearing; - // Speed scale: - QGraphicsItemGroup *m_speedscale; - // Speed indicator text: - QGraphicsTextItem *m_speedtext; - // Vertical altitude scale: - QGraphicsItemGroup *m_altitudescale; - // Altitude indicator text: - QGraphicsTextItem *m_altitudetext; - // GCS link status Arrow - QGraphicsSvgItem *gcsTelemetryArrow; - QGraphicsTextItem *gcsTelemetryStats; - QGraphicsTextItem *gcsBatteryStats; - QGraphicsTextItem *gcsGPSStats; - - // The Value and target variables - // are expressed in degrees - double rollTarget; - double rollValue; - double pitchTarget; - double pitchValue; - double headingTarget; - double headingValue; - double groundspeedTarget; - double groundspeedValue; - double airspeedTarget; - double airspeedValue; - double altitudeTarget; - double altitudeValue; - - qreal compassBandWidth; - qreal speedScaleHeight; - qreal altitudeScaleHeight; - - // Name of the fields to read when an update is received: - UAVDataObject *airspeedObj; - UAVDataObject *altitudeObj; - UAVDataObject *attitudeObj; - UAVDataObject *groundspeedObj; - UAVDataObject *headingObj; - UAVDataObject *gpsObj; - UAVDataObject *gcsTelemetryObj; - UAVDataObject *gcsBatteryObj; - - // Rotation timer - QTimer dialTimer; - QTimer skyDialTimer; - - QString satString; - QString batString; - - // Flag to check for pfd Error - bool pfdError; - // Flag to enable better rendering of fonts in OpenGL - bool hqFonts; - bool beSmooth; -}; -#endif /* PFDGADGETWIDGET_H_ */ diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdplugin.cpp b/ground/openpilotgcs/src/plugins/pfd/pfdplugin.cpp deleted file mode 100644 index fce87ea88..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfdplugin.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/** - ****************************************************************************** - * - * @file pfdplugin.h - * @author Edouard Lafargue Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin Primary Flight Display Plugin - * @{ - * @brief The Primary Flight Display Gadget - *****************************************************************************/ -/* - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "pfdplugin.h" -#include "pfdgadgetfactory.h" -#include -#include -#include -#include - - -PFDPlugin::PFDPlugin() -{ - // Do nothing -} - -PFDPlugin::~PFDPlugin() -{ - // Do nothing -} - -bool PFDPlugin::initialize(const QStringList & args, QString *errMsg) -{ - Q_UNUSED(args); - Q_UNUSED(errMsg); - mf = new PFDGadgetFactory(this); - addAutoReleasedObject(mf); - - return true; -} - -void PFDPlugin::extensionsInitialized() -{ - // Do nothing -} - -void PFDPlugin::shutdown() -{ - // Do nothing -} -Q_EXPORT_PLUGIN(PFDPlugin) diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdplugin.h b/ground/openpilotgcs/src/plugins/pfd/pfdplugin.h deleted file mode 100644 index 067384793..000000000 --- a/ground/openpilotgcs/src/plugins/pfd/pfdplugin.h +++ /dev/null @@ -1,46 +0,0 @@ -/** - ****************************************************************************** - * - * @file pfdplugin.h - * @author Edouard Lafargue Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin Primary Flight Display Plugin - * @{ - * @brief The Primary Flight Display Gadget - *****************************************************************************/ -/* - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef PFDPLUGIN_H_ -#define PFDPLUGIN_H_ - -#include - -class PFDGadgetFactory; - -class PFDPlugin : public ExtensionSystem::IPlugin { -public: - PFDPlugin(); - ~PFDPlugin(); - - void extensionsInitialized(); - bool initialize(const QStringList & arguments, QString *errorString); - void shutdown(); -private: - PFDGadgetFactory *mf; -}; -#endif /* PFDPLUGIN_H_ */ diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetfactory.cpp b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetfactory.cpp index 0fa0503aa..f7d6b1f66 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetfactory.cpp +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetfactory.cpp @@ -22,7 +22,7 @@ PfdQmlGadgetFactory::PfdQmlGadgetFactory(QObject *parent) : IUAVGadgetFactory(QString("PfdQmlGadget"), - tr("PFD (qml)"), + tr("PFD"), parent) {} diff --git a/ground/openpilotgcs/src/plugins/plugins.pro b/ground/openpilotgcs/src/plugins/plugins.pro index 20b402704..99597fc59 100644 --- a/ground/openpilotgcs/src/plugins/plugins.pro +++ b/ground/openpilotgcs/src/plugins/plugins.pro @@ -132,12 +132,6 @@ plugin_gpsdisplay.depends = plugin_coreplugin plugin_gpsdisplay.depends += plugin_uavobjects SUBDIRS += plugin_gpsdisplay -# Primary Flight Display (PFD) gadget -plugin_pfd.subdir = pfd -plugin_pfd.depends = plugin_coreplugin -plugin_pfd.depends += plugin_uavobjects -SUBDIRS += plugin_pfd - # QML viewer gadget plugin_qmlview.subdir = qmlview plugin_qmlview.depends = plugin_coreplugin @@ -150,7 +144,7 @@ plugin_pathactioneditor.depends = plugin_coreplugin plugin_pathactioneditor.depends += plugin_uavobjects SUBDIRS += plugin_pathactioneditor -# Primary Flight Display (PFD) gadget, QML version +# Primary Flight Display (PFD) gadget plugin_pfdqml.subdir = pfdqml plugin_pfdqml.depends = plugin_coreplugin plugin_pfdqml.depends += plugin_uavobjects From 095d71b5748b8f592c7662c7c84c6352409636f5 Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Tue, 18 Jun 2013 18:35:13 +0200 Subject: [PATCH 24/44] OP-1005 Reduced the number of decimals for the GPS PDP value to 1. --- .../share/openpilotgcs/pfd/default/PfdIndicators.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml index 6824d5a7c..fd6f175d4 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml @@ -31,7 +31,7 @@ Item { Text { id: gps_text - text: "GPS: " + GPSPosition.Satellites + "\nPDP: " + Math.round(GPSPosition.PDOP*1000)/1000 + text: "GPS: " + GPSPosition.Satellites + "\nPDP: " + Math.round(GPSPosition.PDOP*10)/10 color: "white" font.family: "Arial" font.pixelSize: telemetry_status.height * 0.75 From 5cc3645b961d1fbab1e2e8f4648af433b982f9de Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Tue, 18 Jun 2013 20:23:46 +0200 Subject: [PATCH 25/44] Uncrustify --- flight/modules/System/systemmod.c | 8 ++++---- flight/pios/common/pios_flashfs_logfs.c | 5 +++-- flight/pios/inc/pios_flashfs.h | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/flight/modules/System/systemmod.c b/flight/modules/System/systemmod.c index b218876be..ce8ae698a 100644 --- a/flight/modules/System/systemmod.c +++ b/flight/modules/System/systemmod.c @@ -468,14 +468,14 @@ static void updateStats() idleCounter = 0; } #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) - if(pios_uavo_settings_fs_id){ + if (pios_uavo_settings_fs_id) { PIOS_FLASHFS_GetStats(pios_uavo_settings_fs_id, &fsStats); - stats.SysSlotsFree = fsStats.num_free_slots; + stats.SysSlotsFree = fsStats.num_free_slots; stats.SysSlotsActive = fsStats.num_active_slots; } - if(pios_user_fs_id){ + if (pios_user_fs_id) { PIOS_FLASHFS_GetStats(pios_user_fs_id, &fsStats); - stats.UsrSlotsFree = fsStats.num_free_slots; + stats.UsrSlotsFree = fsStats.num_free_slots; stats.UsrSlotsActive = fsStats.num_active_slots; } #endif diff --git a/flight/pios/common/pios_flashfs_logfs.c b/flight/pios/common/pios_flashfs_logfs.c index 6dfea60b6..81b103de7 100644 --- a/flight/pios/common/pios_flashfs_logfs.c +++ b/flight/pios/common/pios_flashfs_logfs.c @@ -1164,7 +1164,8 @@ out_exit: * @return 0 if success or error code * @retval -1 if fs_id is not a valid filesystem instance */ -int32_t PIOS_FLASHFS_GetStats(uintptr_t fs_id, struct PIOS_FLASHFS_Stats *stats){ +int32_t PIOS_FLASHFS_GetStats(uintptr_t fs_id, struct PIOS_FLASHFS_Stats *stats) +{ PIOS_Assert(stats); struct logfs_state *logfs = (struct logfs_state *)fs_id; @@ -1172,7 +1173,7 @@ int32_t PIOS_FLASHFS_GetStats(uintptr_t fs_id, struct PIOS_FLASHFS_Stats *stats) return -1; } stats->num_active_slots = logfs->num_active_slots; - stats->num_free_slots = logfs->num_free_slots; + stats->num_free_slots = logfs->num_free_slots; return 0; } #endif /* PIOS_INCLUDE_FLASH */ diff --git a/flight/pios/inc/pios_flashfs.h b/flight/pios/inc/pios_flashfs.h index a37a5333c..ebfa030db 100644 --- a/flight/pios/inc/pios_flashfs.h +++ b/flight/pios/inc/pios_flashfs.h @@ -29,9 +29,9 @@ #include -struct PIOS_FLASHFS_Stats{ - uint16_t num_free_slots; /* slots in free state */ - uint16_t num_active_slots; /* slots in active state */ +struct PIOS_FLASHFS_Stats { + uint16_t num_free_slots; /* slots in free state */ + uint16_t num_active_slots; /* slots in active state */ }; int32_t PIOS_FLASHFS_Format(uintptr_t fs_id); From e1851b48333e6fcac2844f727209c36e2cc0f9a5 Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Tue, 18 Jun 2013 20:58:43 +0200 Subject: [PATCH 26/44] OP-1005 Fixes default configuration files to set altitude and speed factor. --- .../default_configurations/Developer.xml | 28 ++--------------- .../default_configurations/OpenPilotGCS.xml | 30 ++----------------- .../OpenPilotGCS_wide.xml | 30 ++----------------- 3 files changed, 8 insertions(+), 80 deletions(-) diff --git a/ground/openpilotgcs/share/openpilotgcs/default_configurations/Developer.xml b/ground/openpilotgcs/share/openpilotgcs/default_configurations/Developer.xml index d04c74168..126696f0d 100644 --- a/ground/openpilotgcs/share/openpilotgcs/default_configurations/Developer.xml +++ b/ground/openpilotgcs/share/openpilotgcs/default_configurations/Developer.xml @@ -1781,32 +1781,6 @@ - - - - false - 0.0.0 - - - false - %%DATAPATH%%pfd/default/pfd.svg - false - false - - - - - false - 0.0.0 - - - true - %%DATAPATH%%pfd/default/pfd.svg - false - false - - - @@ -1816,12 +1790,14 @@ false 2000 + 1 false %%DATAPATH%%pfd/default/readymap.earth 46.6715 10.1589 true %%DATAPATH%%pfd/default/Pfd.qml + 1 false diff --git a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml index bee98b3e0..4f4666e0c 100644 --- a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml +++ b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml @@ -1819,33 +1819,7 @@ true - - - - - false - 0.0.0 - - - false - %%DATAPATH%%pfd/default/pfd.svg - false - false - - - - - false - 0.0.0 - - - true - %%DATAPATH%%pfd/default/pfd.svg - false - false - - - + @@ -1855,12 +1829,14 @@ false 2000 + 1 false %%DATAPATH%%pfd/default/readymap.earth 46.6715 10.1589 true %%DATAPATH%%pfd/default/Pfd.qml + 1 false diff --git a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS_wide.xml b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS_wide.xml index bd99b9685..eaabdd8e5 100644 --- a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS_wide.xml +++ b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS_wide.xml @@ -1797,33 +1797,7 @@ true - - - - - false - 0.0.0 - - - false - %%DATAPATH%%pfd/default/pfd.svg - false - false - - - - - false - 0.0.0 - - - true - %%DATAPATH%%pfd/default/pfd.svg - false - false - - - + @@ -1833,12 +1807,14 @@ false 2000 + 1 false %%DATAPATH%%pfd/default/readymap.earth 46.6715 10.1589 true %%DATAPATH%%pfd/default/Pfd.qml + 1 false From 78b4a61a10ceab506db29eff6471dd59165733b9 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Tue, 18 Jun 2013 23:10:35 +0200 Subject: [PATCH 27/44] OP-910: update WHATSNEW.txt --- WHATSNEW.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index 72ccc015c..f91e9be4a 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -184,7 +184,8 @@ OP-899, OP-900, OP-903, OP-905, OP-906, OP-907, OP-910, OP-912, OP-917, OP-920, OP-925, OP-926, OP-928, OP-935, OP-936, OP-939, OP-952, OP-955, OP-957, OP-958, OP-965, OP-968, OP-969, OP-970, OP-976, OP-977, OP-980, OP-981, OP-982, OP-983, OP-987, OP-988, OP-989, OP-990, OP-991, OP-993 -OP-997, OP-998, OP-999 +OP-997, OP-998, OP-999, OP-1000, OP-1005, OP-1009, OP-1011, OP-1012, OP-1013, + Short summary of changes. For a complete list see the git log. @@ -234,6 +235,10 @@ Flight code changes: - Cyr's attitude patch is ported from CC3D to Revo; - added magnetometer options (mags are disabled by default for Revo complimenary filter); - advance camera stabilisation is now officially released; +- Revo alarm led now distinguish between Critical(lit led), Error(blink fast), Warning(blink slowly) Alarm condition +- Revo alarm led flash fast(like in Error Alarm) during calibration using complementary attitude estimation. +- Redo gyro bias zero after calibration parameters changes +- Do not raise GPS alarm if a gps port is not configured. - fixed numerous internal firmware bugs (too many to list here). GCS code changes: @@ -261,6 +266,10 @@ GCS code changes: - anti-aliased scope plugin; - numerous code fixes and cleanups (too many to list here); - USB HID code is replaced by new cross-platform hidapi library to fix old Linux/OSX problems. +- Adds GUI to set Altitude Hold filter parameters. +- Adds configurable units for velocity/speed and altitude in QML PFD. Units are configured in settings panel. +- Reduces precision of the PDOP value in the PFD display to 1 decimal. +- Remove deprecated powerlog Common parts: - added simple toolchain install make targets; From 11e0a26ebd9052efb4b9f3a4c812424ec7718a8e Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Tue, 18 Jun 2013 23:34:47 +0200 Subject: [PATCH 28/44] OP-1005 Fixes ugliness in attitude dial and replaces PFD in default configuration with some analog dials on Firmware workspace. --- .../default_configurations/Developer.xml | 46 +++++++++++++++++-- .../default_configurations/OpenPilotGCS.xml | 46 +++++++++++++++++-- .../OpenPilotGCS_wide.xml | 46 +++++++++++++++++-- .../openpilotgcs/dials/deluxe/attitude.svg | 37 ++++++++------- 4 files changed, 144 insertions(+), 31 deletions(-) diff --git a/ground/openpilotgcs/share/openpilotgcs/default_configurations/Developer.xml b/ground/openpilotgcs/share/openpilotgcs/default_configurations/Developer.xml index 126696f0d..824f123b0 100644 --- a/ground/openpilotgcs/share/openpilotgcs/default_configurations/Developer.xml +++ b/ground/openpilotgcs/share/openpilotgcs/default_configurations/Developer.xml @@ -2778,11 +2778,47 @@ splitter - PFDGadget - - raw - - uavGadget + + + DialGadget + + Deluxe Attitude + + uavGadget + + + DialGadget + + Deluxe Baro Altimeter + + uavGadget + + 2 + @Variant(AAAACQAAAAA=) + splitter + + + + DialGadget + + Deluxe Compass + + uavGadget + + + DialGadget + + Deluxe Climbrate + + uavGadget + + 2 + @Variant(AAAACQAAAAA=) + splitter + + 1 + @Variant(AAAACQAAAAA=) + splitter 2 @Variant(AAAACQAAAAIAAAACAAABLwAAAAIAAAHf) diff --git a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml index 4f4666e0c..89254f8d9 100644 --- a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml +++ b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml @@ -2759,11 +2759,47 @@ splitter - PFDGadget - - raw - - uavGadget + + + DialGadget + + Deluxe Attitude + + uavGadget + + + DialGadget + + Deluxe Baro Altimeter + + uavGadget + + 2 + @Variant(AAAACQAAAAA=) + splitter + + + + DialGadget + + Deluxe Compass + + uavGadget + + + DialGadget + + Deluxe Climbrate + + uavGadget + + 2 + @Variant(AAAACQAAAAA=) + splitter + + 1 + @Variant(AAAACQAAAAA=) + splitter 2 @Variant(AAAACQAAAAIAAAACAAABLwAAAAIAAAHf) diff --git a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS_wide.xml b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS_wide.xml index eaabdd8e5..a73874fef 100644 --- a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS_wide.xml +++ b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS_wide.xml @@ -2761,11 +2761,47 @@ splitter - PFDGadget - - raw - - uavGadget + + + DialGadget + + Deluxe Attitude + + uavGadget + + + DialGadget + + Deluxe Baro Altimeter + + uavGadget + + 2 + @Variant(AAAACQAAAAA=) + splitter + + + + DialGadget + + Deluxe Compass + + uavGadget + + + DialGadget + + Deluxe Climbrate + + uavGadget + + 2 + @Variant(AAAACQAAAAA=) + splitter + + 1 + @Variant(AAAACQAAAAA=) + splitter 2 @Variant(AAAACQAAAAIAAAACAAABLwAAAAIAAAHf) diff --git a/ground/openpilotgcs/share/openpilotgcs/dials/deluxe/attitude.svg b/ground/openpilotgcs/share/openpilotgcs/dials/deluxe/attitude.svg index 9a1de6638..0740be27f 100644 --- a/ground/openpilotgcs/share/openpilotgcs/dials/deluxe/attitude.svg +++ b/ground/openpilotgcs/share/openpilotgcs/dials/deluxe/attitude.svg @@ -12,7 +12,7 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" id="svg4745" - inkscape:version="0.48.0 r9654" + inkscape:version="0.48.4 r9939" sodipodi:docname="attitude.svg" x="0px" y="0px" @@ -1205,17 +1205,17 @@ guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" - inkscape:window-width="1366" - inkscape:window-height="691" + inkscape:window-width="1920" + inkscape:window-height="1017" id="namedview2585" showgrid="false" inkscape:zoom="1.3107546" - inkscape:cx="78.320852" + inkscape:cx="-40.694561" inkscape:cy="152.84311" - inkscape:window-x="0" - inkscape:window-y="24" + inkscape:window-x="-8" + inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="layer5" /> + inkscape:current-layer="background-7" /> @@ -7558,7 +7558,12 @@ Date: Wed, 19 Jun 2013 23:53:39 +0200 Subject: [PATCH 29/44] OP-1016 GCS Options dialog - fixed issue that allowed a user to delete all configurations of a given category and would lead to a GCS crash --- .../plugins/coreplugin/dialogs/ioptionspage.h | 14 ++++++ .../coreplugin/dialogs/settingsdialog.cpp | 6 ++- .../coreplugin/uavgadgetinstancemanager.cpp | 48 +++++++++++++++---- .../coreplugin/uavgadgetinstancemanager.h | 30 +++++++++--- .../uavgadgetoptionspagedecorator.cpp | 41 ++++++++++++---- .../uavgadgetoptionspagedecorator.h | 1 + 6 files changed, 114 insertions(+), 26 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/ioptionspage.h b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/ioptionspage.h index 1060d072d..fa24f7c94 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -39,8 +39,10 @@ class QWidget; QT_END_NAMESPACE namespace Core { + class CORE_EXPORT IOptionsPage : public QObject { Q_OBJECT + public: IOptionsPage(QObject *parent = 0) : QObject(parent), @@ -51,6 +53,7 @@ public: { m_icon = icon; } + QIcon icon() { return m_icon; @@ -63,25 +66,36 @@ public: { return ""; }; + virtual QString trName() const { return ""; }; + virtual QString category() const { return "DefaultCategory"; }; + virtual QString trCategory() const { return "DefaultCategory"; }; virtual QWidget *createPage(QWidget *parent) = 0; + virtual void apply() = 0; virtual void finish() = 0; + +public slots: + virtual void updateState() + { + }; + private: QIcon m_icon; }; + } // namespace Core #endif // IOPTIONSPAGE_H diff --git a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp index 28503d0a8..47ab0858d 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp @@ -322,6 +322,9 @@ void SettingsDialog::onItemSelected() stackedPages->insertWidget(index, page->createPage(stackedPages)); } + IOptionsPage *page = m_pages.at(index); + page->updateState(); + stackedPages->setCurrentIndex(index); } @@ -465,10 +468,11 @@ void SettingsDialog::done(int val) settings->setValue("LastPreferenceCategory", m_currentCategory); settings->setValue("LastPreferencePage", m_currentPage); + settings->setValue("WindowWidth", this->width()); settings->setValue("WindowHeight", this->height()); + QList sizes = splitter->sizes(); - qDebug() << "SettingsDialog splitter saving size0:" << sizes[0] << ", size1:" << sizes[1]; settings->setValue("SplitterPosition", sizes[0]); settings->endGroup(); diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.cpp index 1aa28d890..751531ddf 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.cpp @@ -303,23 +303,31 @@ void UAVGadgetInstanceManager::removeAllGadgets() } -bool UAVGadgetInstanceManager::canDeleteConfiguration(IUAVGadgetConfiguration *config) +bool UAVGadgetInstanceManager::isConfigurationActive(IUAVGadgetConfiguration *config) { - // to be able to delete a configuration, no instance must be using it + // check if there is gadget currently using the configuration foreach(IUAVGadget * gadget, m_gadgetInstances) { if (gadget->activeConfiguration() == config) { - return false; - } - } - // and it cannot be the only configuration - foreach(IUAVGadgetConfiguration * c, m_configurations) { - if (c != config && c->classId() == config->classId()) { return true; } } return false; } +UAVGadgetInstanceManager::DeleteStatus UAVGadgetInstanceManager::canDeleteConfiguration(IUAVGadgetConfiguration *config) +{ + // to be able to delete a configuration, no instance must be using it + if (isConfigurationActive(config)) { + return UAVGadgetInstanceManager::KO_ACTIVE; + } + // and it cannot be the only configuration + QList *configs = provisionalConfigurations(config->classId()); + if (configs->count() <= 1) { + return UAVGadgetInstanceManager::KO_LONE; + } + return UAVGadgetInstanceManager::OK; +} + void UAVGadgetInstanceManager::deleteConfiguration(IUAVGadgetConfiguration *config) { m_provisionalDeletes.append(config); @@ -504,6 +512,30 @@ QList *UAVGadgetInstanceManager::configurations(QStri return configs; } +QList *UAVGadgetInstanceManager::provisionalConfigurations(QString classId) const +{ + QList *configs = new QList; + // add current configurations + foreach(IUAVGadgetConfiguration * config, m_configurations) { + if (config->classId() == classId) { + configs->append(config); + } + } + // add provisional configurations + foreach(IUAVGadgetConfiguration * config, m_provisionalConfigs) { + if (config->classId() == classId) { + configs->append(config); + } + } + // remove provisional configurations + foreach(IUAVGadgetConfiguration * config, m_provisionalDeletes) { + if (config->classId() == classId) { + configs->removeOne(config); + } + } + return configs; +} + int UAVGadgetInstanceManager::indexForConfig(QList configurations, QString classId, QString configName) { diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.h b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.h index 23ee1075a..6190e1525 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.h @@ -41,6 +41,7 @@ class PluginManager; } namespace Core { + namespace Internal { class SettingsDialog; } @@ -53,22 +54,30 @@ class IUAVGadgetFactory; class CORE_EXPORT UAVGadgetInstanceManager : public QObject { Q_OBJECT public: + enum DeleteStatus { OK, KO_ACTIVE, KO_LONE }; + explicit UAVGadgetInstanceManager(QObject *parent = 0); ~UAVGadgetInstanceManager(); + void readSettings(QSettings *qs); void saveSettings(QSettings *qs); + IUAVGadget *createGadget(QString classId, QWidget *parent, bool loadDefaultConfiguration = true); void removeGadget(IUAVGadget *gadget); void removeAllGadgets(); - bool canDeleteConfiguration(IUAVGadgetConfiguration *config); + + bool isConfigurationActive(IUAVGadgetConfiguration *config); + DeleteStatus canDeleteConfiguration(IUAVGadgetConfiguration *config); void deleteConfiguration(IUAVGadgetConfiguration *config); void cloneConfiguration(IUAVGadgetConfiguration *config); void applyChanges(IUAVGadgetConfiguration *config); void configurationNameEdited(QString text, bool hasText = true); + QStringList classIds() const { return m_classIdNameMap.keys(); } + QStringList configurationNames(QString classId) const; QString gadgetName(QString classId) const; QIcon gadgetIcon(QString classId) const; @@ -84,10 +93,6 @@ public slots: void settingsDialogRemoved(); private: - IUAVGadgetFactory *factory(QString classId) const; - void createOptionsPages(); - QList *configurations(QString classId) const; - QString suggestName(QString classId, QString name); QList m_gadgetInstances; QList m_factories; QList m_configurations; @@ -100,11 +105,22 @@ private: QList m_provisionalOptionsPages; Core::Internal::SettingsDialog *m_settingsDialog; ExtensionSystem::PluginManager *m_pm; - int indexForConfig(QList configurations, - QString classId, QString configName); + + IUAVGadgetFactory *factory(QString classId) const; + + void createOptionsPages(); + + QList *configurations(QString classId) const; + QList *provisionalConfigurations(QString classId) const; + + QString suggestName(QString classId, QString name); + + int indexForConfig(QList configurations, QString classId, QString configName); + void readConfigs_1_1_0(QSettings *qs); void readConfigs_1_2_0(QSettings *qs); }; + } // namespace Core #endif // UAVGADGETINSTANCEMANAGER_H diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp index a2a956c99..12f28defc 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp @@ -53,16 +53,6 @@ QWidget *UAVGadgetOptionsPageDecorator::createPage(QWidget *parent) m_page = new Ui_TopOptionsPage(); QWidget *w = new QWidget(parent); m_page->setupUi(w); - if (m_config->locked()) { - m_page->deleteButton->hide(); - m_page->lockCheckBox->hide(); - m_page->nameLineEdit->setDisabled(true); - } - if (!m_instanceManager->canDeleteConfiguration(m_config)) { - m_page->deleteButton->setDisabled(true); - } - m_page->lockCheckBox->hide(); // - m_page->nameLineEdit->setText(m_id); QWidget *wi = m_optionsPage->createPage(w); wi->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); @@ -73,6 +63,8 @@ QWidget *UAVGadgetOptionsPageDecorator::createPage(QWidget *parent) m_page->configurationBox->hide(); } + updateState(); + connect(m_page->cloneButton, SIGNAL(clicked()), this, SLOT(cloneConfiguration())); connect(m_page->deleteButton, SIGNAL(clicked()), this, SLOT(deleteConfiguration())); connect(m_page->nameLineEdit, SIGNAL(textEdited(QString)), this, SLOT(textEdited(QString))); @@ -92,6 +84,35 @@ void UAVGadgetOptionsPageDecorator::finish() m_optionsPage->finish(); } +void UAVGadgetOptionsPageDecorator::updateState() +{ + if (m_config->locked()) { + m_page->deleteButton->hide(); + m_page->lockCheckBox->hide(); + m_page->nameLineEdit->setDisabled(true); + } + switch(m_instanceManager->canDeleteConfiguration(m_config)) { + case UAVGadgetInstanceManager::OK: + m_page->deleteButton->setEnabled(true); + m_page->deleteButton->setToolTip(tr("Delete this configuration")); + break; + case UAVGadgetInstanceManager::KO_ACTIVE: + m_page->deleteButton->setEnabled(false); + m_page->deleteButton->setToolTip(tr("Cannot delete a currently in use configuration")); + break; + case UAVGadgetInstanceManager::KO_LONE: + m_page->deleteButton->setEnabled(false); + m_page->deleteButton->setToolTip(tr("Cannot delete the last configuration")); + break; + default: + m_page->deleteButton->setEnabled(false); + m_page->deleteButton->setToolTip(tr("DON'T KNOW !")); + break; + } + m_page->lockCheckBox->hide(); + m_page->nameLineEdit->setText(m_id); +} + void UAVGadgetOptionsPageDecorator::cloneConfiguration() { m_instanceManager->cloneConfiguration(m_config); diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.h b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.h index f82244a0d..00145387d 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.h @@ -67,6 +67,7 @@ public: signals: public slots: + void updateState(); private slots: void cloneConfiguration(); From 5318c20de6b336a9c197f8c9f4c051001c741147 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Thu, 20 Jun 2013 10:04:46 +0200 Subject: [PATCH 30/44] OP-1019 add a simple altitude hold --- flight/modules/AltitudeHold/altitudehold.c | 24 +++++++++-------- flight/modules/ManualControl/manualcontrol.c | 19 ++++++++++---- shared/uavobjectdefinition/flightstatus.xml | 2 +- .../manualcontrolsettings.xml | 26 +++++++++---------- 4 files changed, 41 insertions(+), 30 deletions(-) diff --git a/flight/modules/AltitudeHold/altitudehold.c b/flight/modules/AltitudeHold/altitudehold.c index b92e00f88..3f2fe7909 100644 --- a/flight/modules/AltitudeHold/altitudehold.c +++ b/flight/modules/AltitudeHold/altitudehold.c @@ -139,11 +139,15 @@ static void altitudeHoldTask(__attribute__((unused)) void *parameters) BaroAltitudeConnectQueue(queue); FlightStatusConnectQueue(queue); AccelsConnectQueue(queue); - + bool altitudeHoldFlightMode = false; BaroAltitudeAltitudeGet(&smoothed_altitude); running = false; enum init_state { WAITING_BARO, WAITIING_INIT, INITED } init = WAITING_BARO; + uint8_t flightMode; + FlightStatusFlightModeGet(&flightMode); + // initialize enable flag + altitudeHoldFlightMode = flightMode == FLIGHTSTATUS_FLIGHTMODE_ALTITUDEHOLD || flightMode == FLIGHTSTATUS_FLIGHTMODE_ALTITUDEVARIO; // Main task loop bool baro_updated = false; while (1) { @@ -161,10 +165,9 @@ static void altitudeHoldTask(__attribute__((unused)) void *parameters) init = (init == WAITING_BARO) ? WAITIING_INIT : init; } else if (ev.obj == FlightStatusHandle()) { - FlightStatusData flightStatus; - FlightStatusGet(&flightStatus); - - if (flightStatus.FlightMode == FLIGHTSTATUS_FLIGHTMODE_ALTITUDEHOLD && !running) { + FlightStatusFlightModeGet(&flightMode); + altitudeHoldFlightMode = flightMode == FLIGHTSTATUS_FLIGHTMODE_ALTITUDEHOLD || flightMode == FLIGHTSTATUS_FLIGHTMODE_ALTITUDEVARIO; + if (altitudeHoldFlightMode && !running) { // Copy the current throttle as a starting point for integral StabilizationDesiredThrottleGet(&throttleIntegral); switchThrottle = throttleIntegral; @@ -175,7 +178,7 @@ static void altitudeHoldTask(__attribute__((unused)) void *parameters) AltHoldSmoothedData altHold; AltHoldSmoothedGet(&altHold); starting_altitude = altHold.Altitude; - } else if (flightStatus.FlightMode != FLIGHTSTATUS_FLIGHTMODE_ALTITUDEHOLD) { + } else if (!altitudeHoldFlightMode) { running = false; lastAltitudeHoldDesiredUpdate = PIOS_DELAY_GetRaw(); } @@ -348,11 +351,10 @@ static void altitudeHoldTask(__attribute__((unused)) void *parameters) AltHoldSmoothedGet(&altHold); - // Verify that we are in altitude hold mode - FlightStatusData flightStatus; - FlightStatusGet(&flightStatus); - if (flightStatus.FlightMode != FLIGHTSTATUS_FLIGHTMODE_ALTITUDEHOLD || - flightStatus.Armed != FLIGHTSTATUS_ARMED_ARMED) { + // Verify that we are in altitude hold mode + uint8_t armed; + FlightStatusArmedGet(&armed); + if (!altitudeHoldFlightMode || armed != FLIGHTSTATUS_ARMED_ARMED) { running = false; } diff --git a/flight/modules/ManualControl/manualcontrol.c b/flight/modules/ManualControl/manualcontrol.c index a11e3eab8..9dc1c5850 100644 --- a/flight/modules/ManualControl/manualcontrol.c +++ b/flight/modules/ManualControl/manualcontrol.c @@ -460,6 +460,7 @@ static void manualControlTask(__attribute__((unused)) void *parameters) case FLIGHTMODE_GUIDANCE: switch (flightStatus.FlightMode) { case FLIGHTSTATUS_FLIGHTMODE_ALTITUDEHOLD: + case FLIGHTSTATUS_FLIGHTMODE_ALTITUDEVARIO: altitudeHoldDesired(&cmd, lastFlightMode != flightStatus.FlightMode); break; case FLIGHTSTATUS_FLIGHTMODE_POSITIONHOLD: @@ -820,17 +821,24 @@ static void altitudeHoldDesired(ManualControlCommandData *cmd, bool changed) uint8_t throttleRate; uint8_t throttleExp; + static uint8_t flightMode; static portTickType lastSysTimeAH; static bool zeroed = false; portTickType thisSysTime; float dT; - AltitudeHoldDesiredData altitudeHoldDesiredData; + FlightStatusFlightModeGet(&flightMode); + AltitudeHoldDesiredData altitudeHoldDesiredData; AltitudeHoldDesiredGet(&altitudeHoldDesiredData); - AltitudeHoldSettingsThrottleExpGet(&throttleExp); - AltitudeHoldSettingsThrottleRateGet(&throttleRate); + if (flightMode == FLIGHTSTATUS_FLIGHTMODE_ALTITUDEHOLD) { + throttleExp = 128; + throttleRate = 0; + } else { + AltitudeHoldSettingsThrottleExpGet(&throttleExp); + AltitudeHoldSettingsThrottleRateGet(&throttleRate); + } StabilizationSettingsData stabSettings; StabilizationSettingsGet(&stabSettings); @@ -851,12 +859,13 @@ static void altitudeHoldDesired(ManualControlCommandData *cmd, bool changed) zeroed = false; } else if (cmd->Throttle > DEADBAND_HIGH && zeroed) { // being the two band symmetrical I can divide by DEADBAND_LOW to scale it to a value betweeon 0 and 1 - // then apply an "exp" f(x,k) = (k∙x∙x∙x + x∙(256−k)) / 256 + // then apply an "exp" f(x,k) = (k*x*x*x + x*(256−k)) / 256 altitudeHoldDesiredData.Altitude += (throttleExp * powf((cmd->Throttle - DEADBAND_HIGH) / (DEADBAND_LOW), 3) + (256 - throttleExp)) / 256 * throttleRate * dT; } else if (cmd->Throttle < DEADBAND_LOW && zeroed) { altitudeHoldDesiredData.Altitude -= (throttleExp * powf((DEADBAND_LOW - (cmd->Throttle < 0 ? 0 : cmd->Throttle)) / DEADBAND_LOW, 3) + (256 - throttleExp)) / 256 * throttleRate * dT; - } else if (cmd->Throttle >= DEADBAND_LOW && cmd->Throttle <= DEADBAND_HIGH) { + } else if (cmd->Throttle >= DEADBAND_LOW && cmd->Throttle <= DEADBAND_HIGH && (throttleRate != 0)) { // Require the stick to enter the dead band before they can move height + // Vario is not "engaged" when throttleRate == 0 zeroed = true; } diff --git a/shared/uavobjectdefinition/flightstatus.xml b/shared/uavobjectdefinition/flightstatus.xml index 765e15d66..24befac63 100644 --- a/shared/uavobjectdefinition/flightstatus.xml +++ b/shared/uavobjectdefinition/flightstatus.xml @@ -4,7 +4,7 @@ - + diff --git a/shared/uavobjectdefinition/manualcontrolsettings.xml b/shared/uavobjectdefinition/manualcontrolsettings.xml index 0c627d92e..99c89e5bb 100644 --- a/shared/uavobjectdefinition/manualcontrolsettings.xml +++ b/shared/uavobjectdefinition/manualcontrolsettings.xml @@ -43,31 +43,31 @@ units="" type="enum" elements="6" - options="Manual,Stabilized1,Stabilized2,Stabilized3,Autotune,AltitudeHold,VelocityControl,PositionHold,ReturnToBase,Land,PathPlanner,POI" + options="Manual,Stabilized1,Stabilized2,Stabilized3,Autotune,AltitudeHold,AltitudeVario,VelocityControl,PositionHold,ReturnToBase,Land,PathPlanner,POI" defaultvalue="Stabilized1,Stabilized2,Stabilized3,AltitudeHold,PositionHold,Manual" limits="\ - %0401NE:Autotune:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ - %0402NE:Autotune:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ + %0401NE:Autotune:AltitudeVario:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ + %0402NE:Autotune:AltitudeVario:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ %0903NE:Autotune:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI;\ \ - %0401NE:Autotune:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ - %0402NE:Autotune:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ + %0401NE:Autotune:AltitudeVario:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ + %0402NE:Autotune:AltitudeVario:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ %0903NE:Autotune:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI;\ \ - %0401NE:Autotune:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ - %0402NE:Autotune:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ + %0401NE:Autotune:AltitudeVario:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ + %0402NE:Autotune:AltitudeVario:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ %0903NE:Autotune:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI;\ \ - %0401NE:Autotune:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ - %0402NE:Autotune:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ + %0401NE:Autotune:AltitudeVario:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ + %0402NE:Autotune:AltitudeVario:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ %0903NE:Autotune:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI;\ \ - %0401NE:Autotune:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ - %0402NE:Autotune:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ + %0401NE:Autotune:AltitudeVario:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ + %0402NE:Autotune:AltitudeVario:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ %0903NE:Autotune:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI;\ \ - %0401NE:Autotune:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ - %0402NE:Autotune:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ + %0401NE:Autotune:AltitudeVario:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ + %0402NE:Autotune:AltitudeVario:AltitudeHold:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI,\ %0903NE:Autotune:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner:POI"/> From 0f5e354f993a5ccb8d44fc1b32a8f5bd3355e606 Mon Sep 17 00:00:00 2001 From: Werner Backes Date: Thu, 20 Jun 2013 12:42:22 +0200 Subject: [PATCH 31/44] Removed first occurance of accel_err scaling. We don't want to do this twice. --- flight/modules/Attitude/revolution/attitude.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/flight/modules/Attitude/revolution/attitude.c b/flight/modules/Attitude/revolution/attitude.c index c955e25ed..f1cd7a714 100644 --- a/flight/modules/Attitude/revolution/attitude.c +++ b/flight/modules/Attitude/revolution/attitude.c @@ -472,12 +472,6 @@ static int32_t updateAttitudeComplementary(bool first_run) accel_mag = accels_filtered[0] * accels_filtered[0] + accels_filtered[1] * accels_filtered[1] + accels_filtered[2] * accels_filtered[2]; accel_mag = sqrtf(accel_mag); - // TODO! check accel vector magnitude value for correctness - - accel_err[0] /= accel_mag; - accel_err[1] /= accel_mag; - accel_err[2] /= accel_mag; - float grot_mag; if (accel_filter_enabled) { grot_mag = sqrtf(grot_filtered[0] * grot_filtered[0] + grot_filtered[1] * grot_filtered[1] + grot_filtered[2] * grot_filtered[2]); From e5b68382e0a1570e1d9e75c98453a87d6aaddf47 Mon Sep 17 00:00:00 2001 From: Werner Backes Date: Thu, 20 Jun 2013 14:35:40 +0200 Subject: [PATCH 32/44] Keep TODO comment. --- flight/modules/Attitude/revolution/attitude.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/modules/Attitude/revolution/attitude.c b/flight/modules/Attitude/revolution/attitude.c index f1cd7a714..65d193610 100644 --- a/flight/modules/Attitude/revolution/attitude.c +++ b/flight/modules/Attitude/revolution/attitude.c @@ -479,7 +479,7 @@ static int32_t updateAttitudeComplementary(bool first_run) grot_mag = 1.0f; } - // TODO! check grot_mag value for correctness. + // TODO! check grot_mag & accel vector magnitude values for correctness. accel_err[0] /= (accel_mag * grot_mag); accel_err[1] /= (accel_mag * grot_mag); From d2893fd32b4d5bb8fa8b0bb8beab2f77da9131dc Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Thu, 20 Jun 2013 19:39:19 +0200 Subject: [PATCH 33/44] OP-1019 fix sanitychecks and other uavo definition sanity checks for the newly defined altitudevario mode --- flight/libraries/sanitycheck.c | 1 + flight/modules/ManualControl/inc/manualcontrol.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/flight/libraries/sanitycheck.c b/flight/libraries/sanitycheck.c index dfc7b2c31..c1bb65eb3 100644 --- a/flight/libraries/sanitycheck.c +++ b/flight/libraries/sanitycheck.c @@ -110,6 +110,7 @@ int32_t configuration_check() } break; case MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_ALTITUDEHOLD: + case MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_ALTITUDEVARIO: if (coptercontrol) { severity = SYSTEMALARMS_ALARM_ERROR; } else if (!PIOS_TASK_MONITOR_IsRunning(TASKINFO_RUNNING_ALTITUDEHOLD)) { // Revo supports altitude hold diff --git a/flight/modules/ManualControl/inc/manualcontrol.h b/flight/modules/ManualControl/inc/manualcontrol.h index 6278daa45..7b989fb5e 100644 --- a/flight/modules/ManualControl/inc/manualcontrol.h +++ b/flight/modules/ManualControl/inc/manualcontrol.h @@ -41,6 +41,7 @@ typedef enum { FLIGHTMODE_UNDEFINED = 0, FLIGHTMODE_MANUAL = 1, FLIGHTMODE_STABI (x == FLIGHTSTATUS_FLIGHTMODE_STABILIZED2) ? FLIGHTMODE_STABILIZED : \ (x == FLIGHTSTATUS_FLIGHTMODE_STABILIZED3) ? FLIGHTMODE_STABILIZED : \ (x == FLIGHTSTATUS_FLIGHTMODE_ALTITUDEHOLD) ? FLIGHTMODE_GUIDANCE : \ + (x == FLIGHTSTATUS_FLIGHTMODE_ALTITUDEVARIO) ? FLIGHTMODE_GUIDANCE : \ (x == FLIGHTSTATUS_FLIGHTMODE_VELOCITYCONTROL) ? FLIGHTMODE_GUIDANCE : \ (x == FLIGHTSTATUS_FLIGHTMODE_POSITIONHOLD) ? FLIGHTMODE_GUIDANCE : \ (x == FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER) ? FLIGHTMODE_GUIDANCE : \ @@ -116,6 +117,7 @@ int32_t ManualControlInitialize(); ((int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_STABILIZED2 == (int)FLIGHTSTATUS_FLIGHTMODE_STABILIZED2) && \ ((int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_STABILIZED3 == (int)FLIGHTSTATUS_FLIGHTMODE_STABILIZED3) && \ ((int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_ALTITUDEHOLD == (int)FLIGHTSTATUS_FLIGHTMODE_ALTITUDEHOLD) && \ + ((int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_ALTITUDEVARIO == (int)FLIGHTSTATUS_FLIGHTMODE_ALTITUDEVARIO) && \ ((int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_VELOCITYCONTROL == (int)FLIGHTSTATUS_FLIGHTMODE_VELOCITYCONTROL) && \ ((int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_POSITIONHOLD == (int)FLIGHTSTATUS_FLIGHTMODE_POSITIONHOLD) && \ ((int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_PATHPLANNER == (int)FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER) && \ From 0cf3ef1e52a7a332f01a15039be85470bdb47bc0 Mon Sep 17 00:00:00 2001 From: dankers Date: Thu, 20 Jun 2013 19:42:12 +0200 Subject: [PATCH 34/44] OP-1019 fixed UI for AltitudeHold/Vario settings --- .../config/configstabilizationwidget.cpp | 2 +- .../src/plugins/config/stabilization.ui | 2903 ++++++++++++----- 2 files changed, 2087 insertions(+), 818 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp index 92d1b6dfb..b344c890d 100644 --- a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp @@ -199,5 +199,5 @@ void ConfigStabilizationWidget::onBoardConnected() Q_ASSERT(utilMngr); // If Revolution board enable misc tab, otherwise disable it - ui->Miscellaneous->setEnabled((utilMngr->getBoardModel() & 0xff00) == 0x0900); + ui->AltitudeHold->setEnabled((utilMngr->getBoardModel() & 0xff00) == 0x0900); } diff --git a/ground/openpilotgcs/src/plugins/config/stabilization.ui b/ground/openpilotgcs/src/plugins/config/stabilization.ui index d0d31dd03..55d02d7d4 100644 --- a/ground/openpilotgcs/src/plugins/config/stabilization.ui +++ b/ground/openpilotgcs/src/plugins/config/stabilization.ui @@ -456,7 +456,16 @@ 6 - + + 12 + + + 12 + + + 12 + + 12 @@ -498,7 +507,7 @@ QTabWidget::Rounded - 0 + 3 false @@ -511,7 +520,16 @@ Basic - + + 0 + + + 0 + + + 0 + + 0 @@ -609,8 +627,8 @@ 0 0 - 790 - 653 + 778 + 659 @@ -647,7 +665,16 @@ true - + + 12 + + + 12 + + + 12 + + 12 @@ -2687,7 +2714,16 @@ border-radius: 5; false - + + 12 + + + 12 + + + 12 + + 12 @@ -6063,7 +6099,16 @@ border-radius: 5; Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + + 12 + + + 12 + + + 12 + + 12 @@ -8613,7 +8658,16 @@ border-radius: 5; Integral - + + 12 + + + 12 + + + 12 + + 12 @@ -8722,7 +8776,16 @@ border-radius: 5; Advanced - + + 0 + + + 0 + + + 0 + + 0 @@ -8804,9 +8867,9 @@ border-radius: 5; 0 - 0 - 773 - 702 + -117 + 778 + 762 @@ -9360,7 +9423,16 @@ border-radius: 5; false - + + 12 + + + 12 + + + 12 + + 12 @@ -12709,7 +12781,16 @@ border-radius: 5; false - + + 12 + + + 12 + + + 12 + + 12 @@ -16035,12 +16116,21 @@ border-radius: 5; false + + 12 + + + 12 + + + 12 + + + 12 + 4 - - 12 - @@ -18722,7 +18812,16 @@ border-radius: 5; Expert - + + 0 + + + 0 + + + 0 + + 0 @@ -18808,15 +18907,24 @@ border-radius: 5; 0 0 - 790 - 653 + 792 + 645 9 - + + 9 + + + 9 + + + 9 + + 9 @@ -18840,7 +18948,16 @@ border-radius: 5; Weak Leveling / Axis Lock - + + 12 + + + 12 + + + 12 + + 12 @@ -21454,7 +21571,16 @@ border-radius: 5; Integral Limits - + + 12 + + + 12 + + + 12 + + 12 @@ -24406,7 +24532,16 @@ border-radius: 5; Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + + 12 + + + 12 + + + 12 + + 12 @@ -26855,12 +26990,21 @@ border-radius: 5; - + - Miscellaneous + Altitude Hold - + + 0 + + + 0 + + + 0 + + 0 @@ -26876,12 +27020,12 @@ border-radius: 5; 0 0 - 790 - 653 + 792 + 645 - - + + @@ -27416,7 +27560,7 @@ border-radius: 5; - Altitude Hold Stabilization + Tuning Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -27425,12 +27569,72 @@ border-radius: 5; false - + + 12 + + + 12 + + + 12 + + 12 6 + + + + Qt::Horizontal + + + + 497 + 20 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Reset all values to GCS defaults + + + + + + Default + + + + objname:AltitudeHoldSettings + button:default + buttongroup:99 + + + + @@ -27872,7 +28076,7 @@ border-radius: 5; true - + 0 @@ -27957,81 +28161,6 @@ border-radius: 5; - - - - 10 - - - 1 - - - 1 - - - 5 - - - Qt::Horizontal - - - QSlider::TicksBelow - - - 0 - - - - objname:AltitudeHoldSettings - fieldname:ThrottleRate - haslimits:no - scale:0.5 - buttongroup:99 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 10 - 10 - - - - - - - - - 0 - 0 - - - - - 69 - 16 - - - - - - - Exponential - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - @@ -28082,80 +28211,6 @@ border-radius: 5; - - - - - 0 - 0 - - - - - 50 - 22 - - - - - 50 - 22 - - - - Qt::StrongFocus - - - <html><head/><body><p>Throttle exponential value.</p></body></html> - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 0 - - - 256.000000000000000 - - - 1.000000000000000 - - - 128.000000000000000 - - - - objname:AltitudeHoldSettings - fieldname:ThrottleExp - haslimits:no - scale:1 - buttongroup:99 - - - - - - - - - 0 - 0 - - - - - - - Max Vertical Velocity - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - @@ -28197,636 +28252,6 @@ border-radius: 5;
- - - - - 0 - 0 - - - - - 50 - 22 - - - - - 50 - 22 - - - - Qt::StrongFocus - - - <html><head/><body><p>Maximum allowed vertical velocity in m/s.</p></body></html> - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1 - - - 5.000000000000000 - - - 0.100000000000000 - - - 2.500000000000000 - - - - objname:AltitudeHoldSettings - fieldname:ThrottleRate - haslimits:no - scale:1 - buttongroup:99 - - - - - - - - 256 - - - 128 - - - Qt::Horizontal - - - QSlider::TicksBelow - - - - objname:AltitudeHoldSettings - fieldname:ThrottleExp - haslimits:no - scale:1 - buttongroup:99 - - - - - - - - - 0 - 0 - - - - - 0 - 16 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 74 - 74 - 74 - - - - - 36 - 36 - 36 - - - - - - - - - 58 - 58 - 58 - - - - - - - 48 - 48 - 48 - - - - - - - 19 - 19 - 19 - - - - - - - 26 - 26 - 26 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 74 - 74 - 74 - - - - - 36 - 36 - 36 - - - - - - - - - - - 74 - 74 - 74 - - - - - 36 - 36 - 36 - - - - - - - - - 0 - 0 - 0 - - - - - - - 19 - 19 - 19 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 74 - 74 - 74 - - - - - 36 - 36 - 36 - - - - - - - - - 58 - 58 - 58 - - - - - - - 48 - 48 - 48 - - - - - - - 19 - 19 - 19 - - - - - - - 26 - 26 - 26 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 74 - 74 - 74 - - - - - 36 - 36 - 36 - - - - - - - - - - - 74 - 74 - 74 - - - - - 36 - 36 - 36 - - - - - - - - - 0 - 0 - 0 - - - - - - - 19 - 19 - 19 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 74 - 74 - 74 - - - - - 36 - 36 - 36 - - - - - - - - - 58 - 58 - 58 - - - - - - - 48 - 48 - 48 - - - - - - - 19 - 19 - 19 - - - - - - - 26 - 26 - 26 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 74 - 74 - 74 - - - - - 36 - 36 - 36 - - - - - - - - - - - 74 - 74 - 74 - - - - - 36 - 36 - 36 - - - - - - - - - 0 - 0 - 0 - - - - - - - 39 - 39 - 39 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 75 - true - - - - false - - - background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); -color: rgb(255, 255, 255); -border-radius: 5; - - - Throttle - - - Qt::AlignCenter - - - @@ -29518,8 +28943,1803 @@ border-radius: 5; + + +
+ + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + + + + + 0 + 0 + 0 + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + 255 + 255 + 255 + + + + + + + 251 + 251 + 251 + + + + + + + 124 + 124 + 124 + + + + + + + 165 + 165 + 165 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + 0 + 0 + 0 + + + + + + + 251 + 251 + 251 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + 255 + 255 + 255 + + + + + + + 251 + 251 + 251 + + + + + + + 124 + 124 + 124 + + + + + + + 165 + 165 + 165 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + 0 + 0 + 0 + + + + + + + 251 + 251 + 251 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 124 + 124 + 124 + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + 255 + 255 + 255 + + + + + + + 251 + 251 + 251 + + + + + + + 124 + 124 + 124 + + + + + + + 165 + 165 + 165 + + + + + + + 124 + 124 + 124 + + + + + + + 255 + 255 + 255 + + + + + + + 124 + 124 + 124 + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + + + 243 + 243 + 243 + + + + + 250 + 250 + 250 + + + + + + + + + 0 + 0 + 0 + + + + + + + 248 + 248 + 248 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + Vario Altitude + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + 12 + + + 12 + + + 12 + + + 12 + + + 6 + + + + + + 0 + 0 + + + + + 0 + 140 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 251 + 251 + 251 + + + + + + + 124 + 124 + 124 + + + + + + + 165 + 165 + 165 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 251 + 251 + 251 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 251 + 251 + 251 + + + + + + + 124 + 124 + 124 + + + + + + + 165 + 165 + 165 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 251 + 251 + 251 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 124 + 124 + 124 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 251 + 251 + 251 + + + + + + + 124 + 124 + 124 + + + + + + + 165 + 165 + 165 + + + + + + + 124 + 124 + 124 + + + + + + + 255 + 255 + 255 + + + + + + + 124 + 124 + 124 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 248 + 248 + 248 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + false + + + QGroupBox{border: 0px;} + + + + + + true + + + + 0 + + + 0 + + + 0 + + + + + 10 + + + 1 + + + 1 + + + 5 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 0 + + + + objname:AltitudeHoldSettings + fieldname:ThrottleRate + haslimits:no + scale:0.5 + buttongroup:99 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 10 + + + + + + + + + 0 + 0 + + + + + 69 + 16 + + + + + + + Exponential + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 50 + 22 + + + + + 50 + 22 + + + + Qt::StrongFocus + + + <html><head/><body><p>Throttle exponential value.</p></body></html> + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 0 + + + 256.000000000000000 + + + 1.000000000000000 + + + 128.000000000000000 + + + + objname:AltitudeHoldSettings + fieldname:ThrottleExp + haslimits:no + scale:1 + buttongroup:99 + + + + + + + + + 0 + 0 + + + + + + + Max Vertical Velocity + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 50 + 22 + + + + + 50 + 22 + + + + Qt::StrongFocus + + + <html><head/><body><p>Maximum allowed vertical velocity in m/s.</p></body></html> + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 1 + + + 5.000000000000000 + + + 0.100000000000000 + + + 2.500000000000000 + + + + objname:AltitudeHoldSettings + fieldname:ThrottleRate + haslimits:no + scale:1 + buttongroup:99 + + + + + + + + 256 + + + 128 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + + objname:AltitudeHoldSettings + fieldname:ThrottleExp + haslimits:no + scale:1 + buttongroup:99 + + + + + + + + + 0 + 0 + + + + + 0 + 16 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 58 + 58 + 58 + + + + + + + 48 + 48 + 48 + + + + + + + 19 + 19 + 19 + + + + + + + 26 + 26 + 26 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 0 + 0 + 0 + + + + + + + 19 + 19 + 19 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 58 + 58 + 58 + + + + + + + 48 + 48 + 48 + + + + + + + 19 + 19 + 19 + + + + + + + 26 + 26 + 26 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 0 + 0 + 0 + + + + + + + 19 + 19 + 19 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 58 + 58 + 58 + + + + + + + 48 + 48 + 48 + + + + + + + 19 + 19 + 19 + + + + + + + 26 + 26 + 26 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + + + 74 + 74 + 74 + + + + + 36 + 36 + 36 + + + + + + + + + 0 + 0 + 0 + + + + + + + 39 + 39 + 39 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 75 + true + + + + false + + + background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255)); +color: rgb(255, 255, 255); +border-radius: 5; + + + Throttle Stick Responce + + + Qt::AlignCenter + + + + + + - + Qt::Horizontal @@ -29532,7 +30752,7 @@ border-radius: 5; - + 0 @@ -29572,11 +30792,60 @@ border-radius: 5; - + + + + + 0 + 0 + + + + + 0 + 60 + + + + Instant Update + + + + + + + 0 + 0 + + + + + 136 + 20 + + + + <html><head/><body><p>Enabling this feature mean that any changes made to the sliders will be instantly sent and used by the Flight Controller, useful for two person tuning where one normally flies and ones changes the GCS.</p></body></html> + + + + + + Update flight controller in real time + + + + + + + Qt::Vertical + + QSizePolicy::Expanding + 20 From dc4e3f220f7a8ebf374875fbd359eb4ba65a515f Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 20 Jun 2013 21:51:18 +0200 Subject: [PATCH 35/44] OP-1016 GCS Options dialog : improved delete button tooltip text as per review --- .../src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp index 12f28defc..88ac5a2bc 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp @@ -98,7 +98,7 @@ void UAVGadgetOptionsPageDecorator::updateState() break; case UAVGadgetInstanceManager::KO_ACTIVE: m_page->deleteButton->setEnabled(false); - m_page->deleteButton->setToolTip(tr("Cannot delete a currently in use configuration")); + m_page->deleteButton->setToolTip(tr("Cannot delete a configuration currently in use")); break; case UAVGadgetInstanceManager::KO_LONE: m_page->deleteButton->setEnabled(false); From 2ece9ef3daf720bd796234d5e62c557af537b414 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Fri, 21 Jun 2013 09:39:06 +0200 Subject: [PATCH 36/44] OP-1007 fixed issue in output config gadget where the unsaved changes warning was displayed although no changes were made --- .../src/plugins/config/configoutputwidget.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp index 65a9851af..d0db17f9b 100644 --- a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp @@ -110,6 +110,11 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren updateEnableControls(); } +ConfigOutputWidget::~ConfigOutputWidget() +{ + // Do nothing +} + void ConfigOutputWidget::enableControls(bool enable) { ConfigTaskWidget::enableControls(enable); @@ -120,11 +125,6 @@ void ConfigOutputWidget::enableControls(bool enable) ui->channelOutTest->setEnabled(enable); } -ConfigOutputWidget::~ConfigOutputWidget() -{ - // Do nothing -} - /** Toggles the channel testing mode by making the GCS take over the ActuatorCommand objects @@ -242,6 +242,8 @@ void ConfigOutputWidget::refreshWidgetsValues(UAVObject *obj) { Q_UNUSED(obj); + bool dirty = isDirty(); + // Get Actuator Settings ActuatorSettings *actuatorSettings = ActuatorSettings::GetInstance(getObjectManager()); Q_ASSERT(actuatorSettings); @@ -353,6 +355,8 @@ void ConfigOutputWidget::refreshWidgetsValues(UAVObject *obj) int neutral = actuatorSettingsData.ChannelNeutral[outputChannelForm->index()]; outputChannelForm->neutral(neutral); } + + setDirty(dirty); } /** From 1e4e8af1650e58e84af348ec274372e467e79d59 Mon Sep 17 00:00:00 2001 From: a*morale Date: Fri, 21 Jun 2013 10:55:35 +0200 Subject: [PATCH 37/44] Fix template for dmg not opening with correct size/options --- package/osx/OpenPilot.dmg | Bin 4149671 -> 4161363 bytes package/osx/package | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/package/osx/OpenPilot.dmg b/package/osx/OpenPilot.dmg index 66a3b882f461d4e1af0c4945ec29fb8058f799aa..d53bf09b50f3fecac4de2e71d49f88ac90b8f0fc 100644 GIT binary patch delta 43117 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 QduZ;9Z-US>9f1130F_PQssI20 delta 30895 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 diff --git a/package/osx/package b/package/osx/package index 758038386..276e74f84 100755 --- a/package/osx/package +++ b/package/osx/package @@ -13,7 +13,7 @@ VOL_NAME="OpenPilot" rm -f "${TEMP_FILE}" rm -f "${OUT_FILE}" -# if the file doesn't exist, try to create folder +# if an OpenPilot volume is already mounted, unmount it if [ ! -f "/Volumes/${VOL_NAME}" ] then hdiutil unmount "/Volumes/${VOL_NAME}" From 259c1393b0dc070d41fa4a04ee26a5d1f7281d05 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Fri, 21 Jun 2013 14:16:41 +0200 Subject: [PATCH 38/44] OP-1019 fix UI margins for AltitudeHold/Vario settings +review OPReview-521 --- .../src/plugins/config/stabilization.ui | 106 +++++++++--------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/config/stabilization.ui b/ground/openpilotgcs/src/plugins/config/stabilization.ui index 55d02d7d4..78e69f45f 100644 --- a/ground/openpilotgcs/src/plugins/config/stabilization.ui +++ b/ground/openpilotgcs/src/plugins/config/stabilization.ui @@ -457,16 +457,16 @@ 6 - 12 + 9 - 12 + 9 - 12 + 9 - 12 + 9 @@ -507,7 +507,7 @@ QTabWidget::Rounded - 3 + 0 false @@ -666,16 +666,16 @@ - 12 + 9 - 12 + 9 - 12 + 9 - 12 + 9 @@ -2715,16 +2715,16 @@ border-radius: 5; - 12 + 9 - 12 + 9 - 12 + 9 - 12 + 9 6 @@ -6100,16 +6100,16 @@ border-radius: 5; - 12 + 9 - 12 + 9 - 12 + 9 - 12 + 9 6 @@ -8659,16 +8659,16 @@ border-radius: 5; - 12 + 9 - 12 + 9 - 12 + 9 - 12 + 9 @@ -9424,16 +9424,16 @@ border-radius: 5; - 12 + 9 - 12 + 9 - 12 + 9 - 12 + 9 6 @@ -12782,16 +12782,16 @@ border-radius: 5; - 12 + 9 - 12 + 9 - 12 + 9 - 12 + 9 6 @@ -16117,16 +16117,16 @@ border-radius: 5; - 12 + 9 - 12 + 9 - 12 + 9 - 12 + 9 4 @@ -18949,16 +18949,16 @@ border-radius: 5; - 12 + 9 - 12 + 9 - 12 + 9 - 12 + 9 @@ -21572,16 +21572,16 @@ border-radius: 5; - 12 + 9 - 12 + 9 - 12 + 9 - 12 + 9 6 @@ -24533,16 +24533,16 @@ border-radius: 5; - 12 + 9 - 12 + 9 - 12 + 9 - 12 + 9 @@ -27570,16 +27570,16 @@ border-radius: 5; - 12 + 9 - 12 + 9 - 12 + 9 - 12 + 9 6 @@ -29491,16 +29491,16 @@ border-radius: 5; - 12 + 9 - 12 + 9 - 12 + 9 - 12 + 9 6 From a1388e203c7f04212967d5d5a28d86c4c66c5330 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Fri, 21 Jun 2013 17:08:29 +0200 Subject: [PATCH 39/44] OP-1019 fix UI typo +review OPReview-521 --- ground/openpilotgcs/src/plugins/config/stabilization.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ground/openpilotgcs/src/plugins/config/stabilization.ui b/ground/openpilotgcs/src/plugins/config/stabilization.ui index 78e69f45f..040f2c046 100644 --- a/ground/openpilotgcs/src/plugins/config/stabilization.ui +++ b/ground/openpilotgcs/src/plugins/config/stabilization.ui @@ -30728,7 +30728,7 @@ color: rgb(255, 255, 255); border-radius: 5; - Throttle Stick Responce + Throttle Stick Response Qt::AlignCenter From 4a793c47ad332766ff96567ee1fdefa697e09dce Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Fri, 21 Jun 2013 18:42:46 +0200 Subject: [PATCH 40/44] Changed default AH parameters --- shared/uavobjectdefinition/altitudeholdsettings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/uavobjectdefinition/altitudeholdsettings.xml b/shared/uavobjectdefinition/altitudeholdsettings.xml index 25c75aca3..61f36d37f 100644 --- a/shared/uavobjectdefinition/altitudeholdsettings.xml +++ b/shared/uavobjectdefinition/altitudeholdsettings.xml @@ -1,9 +1,9 @@ Settings for the @ref AltitudeHold module - - - + + + From 1b1bb04305a0cb0ed8f87aaf39ff60f6c436e801 Mon Sep 17 00:00:00 2001 From: Oleg Semyonov Date: Sat, 22 Jun 2013 04:14:23 +0200 Subject: [PATCH 41/44] OP-1002: Windows Installer: update branding images --- package/winx86/openpilotgcs.nsi | 24 +++++++++++++++++++++--- package/winx86/resources/header.bmp | Bin 25820 -> 25818 bytes package/winx86/resources/welcome.bmp | Bin 154544 -> 154542 bytes 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/package/winx86/openpilotgcs.nsi b/package/winx86/openpilotgcs.nsi index 0dc1f21b6..df5d34152 100644 --- a/package/winx86/openpilotgcs.nsi +++ b/package/winx86/openpilotgcs.nsi @@ -98,11 +98,25 @@ !define MUI_ICON "${NSIS_DATA_TREE}\resources\openpilot.ico" !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_BITMAP "${NSIS_DATA_TREE}\resources\header.bmp" - !define MUI_HEADERIMAGE_BITMAP_NOSTRETCH !define MUI_WELCOMEFINISHPAGE_BITMAP "${NSIS_DATA_TREE}\resources\welcome.bmp" - !define MUI_WELCOMEFINISHPAGE_BITMAP_NOSTRETCH !define MUI_UNWELCOMEFINISHPAGE_BITMAP "${NSIS_DATA_TREE}\resources\welcome.bmp" - !define MUI_UNWELCOMEFINISHPAGE_BITMAP_NOSTRETCH + + !define HEADER_BGCOLOR "0x8C8C8C" + !define HEADER_FGCOLOR "0x343434" + + !macro SetHeaderColors un + Function ${un}SetHeaderColors + GetDlgItem $r3 $HWNDPARENT 1034 + SetCtlColors $r3 ${HEADER_BGCOLOR} ${HEADER_FGCOLOR} + GetDlgItem $r3 $HWNDPARENT 1037 + SetCtlColors $r3 ${HEADER_BGCOLOR} ${HEADER_FGCOLOR} + GetDlgItem $r3 $HWNDPARENT 1038 + SetCtlColors $r3 ${HEADER_BGCOLOR} ${HEADER_FGCOLOR} + FunctionEnd + !macroend + + !insertmacro SetHeaderColors "" + !insertmacro SetHeaderColors "un." ;-------------------------------- ; Language selection dialog settings @@ -122,6 +136,8 @@ ;-------------------------------- ; Pages + !define MUI_PAGE_CUSTOMFUNCTION_PRE "SetHeaderColors" + !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "$(LicenseFile)" !insertmacro MUI_PAGE_COMPONENTS @@ -129,6 +145,8 @@ !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH + !define MUI_PAGE_CUSTOMFUNCTION_PRE "un.SetHeaderColors" + !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_COMPONENTS diff --git a/package/winx86/resources/header.bmp b/package/winx86/resources/header.bmp index 1c0f7dd1d2e2a505e79a3de894a54266e5a4362a..8f09ec6f3e993887570e07e69ba1dd13435398a4 100644 GIT binary patch literal 25818 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 Lqp2dCGv|K*J$AWw literal 25820 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 M41mQCPdn}Z088p7JOBUy diff --git a/package/winx86/resources/welcome.bmp b/package/winx86/resources/welcome.bmp index 71247106063bb2f64621d63e335d64d18fd83cd6..b6384c6fd6945044eda087b606ec8cb073633174 100644 GIT binary patch literal 154542 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 literal 154544 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 Date: Sat, 22 Jun 2013 12:51:05 +0200 Subject: [PATCH 42/44] OP-1018: Fix ETASv3 Airspeed sensor autocalibration --- flight/modules/Airspeed/revolution/baro_airspeed_etasv3.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/flight/modules/Airspeed/revolution/baro_airspeed_etasv3.c b/flight/modules/Airspeed/revolution/baro_airspeed_etasv3.c index e26262ec2..50c5d78fb 100644 --- a/flight/modules/Airspeed/revolution/baro_airspeed_etasv3.c +++ b/flight/modules/Airspeed/revolution/baro_airspeed_etasv3.c @@ -72,7 +72,8 @@ void baro_airspeedGetETASV3(AirspeedSensorData *airspeedSensor, AirspeedSettings // Calibrate sensor by averaging zero point value if (calibrationCount <= CALIBRATION_IDLE_MS / airspeedSettings->SamplePeriod) { calibrationCount++; - calibrationCount2++; + calibrationSum = 0; + calibrationCount2 = 0; return; } else if (calibrationCount <= (CALIBRATION_IDLE_MS + CALIBRATION_COUNT_MS) / airspeedSettings->SamplePeriod) { calibrationCount++; @@ -81,6 +82,9 @@ void baro_airspeedGetETASV3(AirspeedSensorData *airspeedSensor, AirspeedSettings if (calibrationCount > (CALIBRATION_IDLE_MS + CALIBRATION_COUNT_MS) / airspeedSettings->SamplePeriod) { airspeedSettings->ZeroPoint = (int16_t)(((float)calibrationSum) / calibrationCount2); AirspeedSettingsZeroPointSet(&airspeedSettings->ZeroPoint); + calibrationCount = 0; + calibrationSum = 0; + calibrationCount2 = 0; } return; } From 54eb5d8894b849add603aaca377d0021cb14440b Mon Sep 17 00:00:00 2001 From: Oleg Semyonov Date: Sat, 22 Jun 2013 14:17:30 +0300 Subject: [PATCH 43/44] Update release notes --- WHATSNEW.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index f91e9be4a..2b0d7e7c2 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -175,17 +175,17 @@ Due to major rework of all code and integration of Revo code into mainline list above. Some of them can be found using this link: http://progress.openpilot.org/issues/?filter=10860 -OP-678, OP-693, OP-719, OP-726, OP-727, OP-747, OP-761, OP-769, OP-770, -OP-772, OP-784, OP-792, OP-804, OP-807, OP-812, OP-816, OP-817, OP-820, -OP-821, OP-843, OP-846, OP-854, OP-855, OP-856, OP-861, OP-864, OP-867, -OP-871, OP-873, OP-874, OP-875, OP-879, OP-885, OP-886, OP-888, OP-889, -OP-890, OP-891, OP-892, OP-893, OP-894, OP-895, OP-896, OP-897, OP-898, -OP-899, OP-900, OP-903, OP-905, OP-906, OP-907, OP-910, OP-912, OP-917, -OP-920, OP-925, OP-926, OP-928, OP-935, OP-936, OP-939, OP-952, OP-955, -OP-957, OP-958, OP-965, OP-968, OP-969, OP-970, OP-976, OP-977, OP-980, -OP-981, OP-982, OP-983, OP-987, OP-988, OP-989, OP-990, OP-991, OP-993 -OP-997, OP-998, OP-999, OP-1000, OP-1005, OP-1009, OP-1011, OP-1012, OP-1013, - +OP-678, OP-693, OP-719, OP-726, OP-727, OP-747, OP-761, OP-769, OP-770, +OP-772, OP-784, OP-792, OP-804, OP-807, OP-812, OP-816, OP-817, OP-820, +OP-821, OP-843, OP-846, OP-854, OP-855, OP-856, OP-861, OP-864, OP-867, +OP-871, OP-873, OP-874, OP-875, OP-879, OP-885, OP-886, OP-888, OP-889, +OP-890, OP-891, OP-892, OP-893, OP-894, OP-895, OP-896, OP-897, OP-898, +OP-899, OP-900, OP-903, OP-905, OP-906, OP-907, OP-910, OP-912, OP-917, +OP-920, OP-925, OP-926, OP-928, OP-935, OP-936, OP-939, OP-952, OP-955, +OP-957, OP-958, OP-965, OP-968, OP-969, OP-970, OP-977, OP-979, OP-980, +OP-981, OP-982, OP-983, OP-988, OP-989, OP-990, OP-991, OP-993, OP-997, +OP-998, OP-999, OP-1000, OP-1002, OP-1005, OP-1007, OP-1008, OP-1009, OP-1010, +OP-1011, OP-1012, OP-1013, OP-1015, OP-1016, OP-1021 Short summary of changes. For a complete list see the git log. From 8325cc3be75fd5523ec25edbaa95ec1592e40b4a Mon Sep 17 00:00:00 2001 From: Oleg Semyonov Date: Sat, 22 Jun 2013 14:24:47 +0300 Subject: [PATCH 44/44] Uncrustify --- .../plugins/config/configstabilizationwidget.cpp | 3 ++- .../plugins/coreplugin/dialogs/ioptionspage.h | 5 +---- .../coreplugin/dialogs/settingsdialog.cpp | 8 +++++--- .../coreplugin/uavgadgetinstancemanager.h | 2 -- .../coreplugin/uavgadgetoptionspagedecorator.cpp | 4 ++-- .../plugins/pfdqml/pfdqmlgadgetconfiguration.cpp | 11 +++++------ .../plugins/pfdqml/pfdqmlgadgetconfiguration.h | 2 +- .../plugins/pfdqml/pfdqmlgadgetoptionspage.cpp | 16 +++++++--------- 8 files changed, 23 insertions(+), 28 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp index b344c890d..013f82666 100644 --- a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp @@ -195,7 +195,8 @@ void ConfigStabilizationWidget::processLinkedWidgets(QWidget *widget) void ConfigStabilizationWidget::onBoardConnected() { ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectUtilManager *utilMngr = pm->getObject(); + UAVObjectUtilManager *utilMngr = pm->getObject(); + Q_ASSERT(utilMngr); // If Revolution board enable misc tab, otherwise disable it diff --git a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/ioptionspage.h b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/ioptionspage.h index fa24f7c94..a8ee2a8f9 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -39,7 +39,6 @@ class QWidget; QT_END_NAMESPACE namespace Core { - class CORE_EXPORT IOptionsPage : public QObject { Q_OBJECT @@ -89,13 +88,11 @@ public: public slots: virtual void updateState() - { - }; + {}; private: QIcon m_icon; }; - } // namespace Core #endif // IOPTIONSPAGE_H diff --git a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp index e32e5f060..ea545a82c 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp @@ -177,8 +177,9 @@ Q_DECLARE_METATYPE(::PageData) SettingsDialog::SettingsDialog(QWidget *parent, c QTreeWidgetItem *initialItem = 0; // add plugin pages - foreach(IOptionsPage *page, pluginPages) { + foreach(IOptionsPage * page, pluginPages) { QTreeWidgetItem *item = addPage(page); + // automatically expand all plugin categories item->parent()->setExpanded(true); if (page->id() == initialPage && page->category() == initialCategory) { @@ -289,6 +290,7 @@ QTreeWidgetItem *SettingsDialog::addPage(IOptionsPage *page) void SettingsDialog::onItemSelected() { QTreeWidgetItem *item = pageTree->currentItem(); + if (!item) { return; } @@ -297,8 +299,7 @@ void SettingsDialog::onItemSelected() if (item->childCount() == 1) { // single child : category will not be expanded item = item->child(0); - } - else if (item->childCount() > 1) { + } else if (item->childCount() > 1) { // multiple children : expand category and select 1st child emit categoryItemSelected(); return; @@ -331,6 +332,7 @@ void SettingsDialog::onItemSelected() void SettingsDialog::onCategorySelected() { QTreeWidgetItem *item = pageTree->currentItem(); + if (item->childCount() > 1) { item->setExpanded(true); pageTree->setCurrentItem(item->child(0), 0, QItemSelectionModel::SelectCurrent); diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.h b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.h index 6190e1525..bab32efb2 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.h @@ -41,7 +41,6 @@ class PluginManager; } namespace Core { - namespace Internal { class SettingsDialog; } @@ -120,7 +119,6 @@ private: void readConfigs_1_1_0(QSettings *qs); void readConfigs_1_2_0(QSettings *qs); }; - } // namespace Core #endif // UAVGADGETINSTANCEMANAGER_H diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp index 88ac5a2bc..dc76ae08d 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp @@ -51,7 +51,7 @@ UAVGadgetOptionsPageDecorator::UAVGadgetOptionsPageDecorator(IOptionsPage *page, QWidget *UAVGadgetOptionsPageDecorator::createPage(QWidget *parent) { m_page = new Ui_TopOptionsPage(); - QWidget *w = new QWidget(parent); + QWidget *w = new QWidget(parent); m_page->setupUi(w); QWidget *wi = m_optionsPage->createPage(w); @@ -91,7 +91,7 @@ void UAVGadgetOptionsPageDecorator::updateState() m_page->lockCheckBox->hide(); m_page->nameLineEdit->setDisabled(true); } - switch(m_instanceManager->canDeleteConfiguration(m_config)) { + switch (m_instanceManager->canDeleteConfiguration(m_config)) { case UAVGadgetInstanceManager::OK: m_page->deleteButton->setEnabled(true); m_page->deleteButton->setToolTip(tr("Delete this configuration")); diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.cpp b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.cpp index d3efb6a42..614441daf 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.cpp +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.cpp @@ -35,13 +35,12 @@ PfdQmlGadgetConfiguration::PfdQmlGadgetConfiguration(QString classId, QSettings m_speedFactor(1.0), m_altitudeFactor(1.0) { + m_speedMap[1.0] = "m/s"; + m_speedMap[3.6] = "km/h"; + m_speedMap[2.2369] = "mph"; + m_speedMap[1.9438] = "knots"; - m_speedMap[1.0] = "m/s"; - m_speedMap[3.6] = "km/h"; - m_speedMap[2.2369] = "mph"; - m_speedMap[1.9438] = "knots"; - - m_altitudeMap[1.0] = "m"; + m_altitudeMap[1.0] = "m"; m_altitudeMap[3.2808] = "ft"; // if a saved configuration exists load it diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.h b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.h index 7171c3bd9..b3f8e9b34 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.h +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.h @@ -119,7 +119,7 @@ public: QString speedUnit() const { - return m_speedMap[m_speedFactor]; + return m_speedMap[m_speedFactor]; } QString altitudeUnit() const diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.cpp b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.cpp index 99fb40501..b7f2aab5e 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.cpp +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.cpp @@ -62,20 +62,18 @@ QWidget *PfdQmlGadgetOptionsPage::createPage(QWidget *parent) options_page->altitude->setText(QString::number(m_config->altitude())); options_page->useOnlyCache->setChecked(m_config->cacheOnly()); - //Setup units combos + // Setup units combos QMapIterator iter = m_config->speedMapIterator(); - while(iter.hasNext()) - { - iter.next(); - options_page->speedUnitCombo->addItem(iter.value(), iter.key()); + while (iter.hasNext()) { + iter.next(); + options_page->speedUnitCombo->addItem(iter.value(), iter.key()); } options_page->speedUnitCombo->setCurrentIndex(options_page->speedUnitCombo->findData(m_config->speedFactor())); iter = m_config->altitudeMapIterator(); - while(iter.hasNext()) - { - iter.next(); - options_page->altUnitCombo->addItem(iter.value(), iter.key()); + while (iter.hasNext()) { + iter.next(); + options_page->altUnitCombo->addItem(iter.value(), iter.key()); } options_page->altUnitCombo->setCurrentIndex(options_page->altUnitCombo->findData(m_config->altitudeFactor()));