dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
configattitudewidget.cpp
Go to the documentation of this file.
1 
14 /*
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful, but
21  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23  * for more details.
24  *
25  * You should have received a copy of the GNU General Public License along
26  * with this program; if not, see <http://www.gnu.org/licenses/>
27  */
28 #include "configattitudewidget.h"
29 #include "physical_constants.h"
30 
31 #include "math.h"
32 #include <QDebug>
33 #include <QTimer>
34 #include <QStringList>
35 #include <QWidget>
36 #include <QTextEdit>
37 #include <QVBoxLayout>
38 #include <QPushButton>
39 #include <QMessageBox>
40 #include <QThread>
41 #include <QErrorMessage>
42 #include <iostream>
43 #include <QDesktopServices>
44 #include <QUrl>
45 #include <coreplugin/iboardtype.h>
46 #include <attitudesettings.h>
47 #include <sensorsettings.h>
48 #include <inssettings.h>
49 #include <homelocation.h>
50 #include <accels.h>
51 #include <gyros.h>
52 #include <magnetometer.h>
53 #include <baroaltitude.h>
54 
55 #include "assertions.h"
56 #include "calibration.h"
57 
58 #define sign(x) ((x < 0) ? -1 : 1)
59 
60 // Uncomment this to enable 6 point calibration on the accels
61 #define SIX_POINT_CAL_ACCEL
62 
63 const double ConfigAttitudeWidget::maxVarValue = 0.1;
64 
65 // *****************
66 
67 class Thread : public QThread
68 {
69 public:
70  static void usleep(unsigned long usecs) { QThread::usleep(usecs); }
71 };
72 
73 // *****************
74 
76  : ConfigTaskWidget(parent)
77  , m_ui(new Ui_AttitudeWidget())
78 {
79  m_ui->setupUi(this);
80 
81  // Initialization of the Paper plane widget
82  m_ui->sixPointHelp->setScene(new QGraphicsScene(this));
83 
84  paperplane = new QGraphicsSvgItem();
85  paperplane->setSharedRenderer(new QSvgRenderer());
86  paperplane->renderer()->load(QString(":/configgadget/images/paper-plane.svg"));
87  paperplane->setElementId("plane-horizontal");
88  m_ui->sixPointHelp->scene()->addItem(paperplane);
89  m_ui->sixPointHelp->setSceneRect(paperplane->boundingRect());
90 
91  // keep calibration selection in sync with board
93  this, &ConfigAttitudeWidget::updateCalibrationEnabled);
94  if (Q_LIKELY(utilMngr)) {
95  auto uavoMan = utilMngr->getObjectManager();
96  if (Q_LIKELY(uavoMan)) {
97  auto mag = uavoMan->getObject(QStringLiteral("Magnetometer"));
98  if (mag) {
99  connect(mag, &UAVObject::objectUnpacked,
100  this, &ConfigAttitudeWidget::updateCalibrationEnabled);
101  }
102  }
103  }
104  updateCalibrationEnabled();
105 
106  // Must set up the UI (above) before setting up the UAVO mappings or refreshWidgetValues
107  // will be dealing with some null pointers
108  addUAVObject("AttitudeSettings");
109  addUAVObject("SensorSettings");
110  addUAVObject("INSSettings");
111  setNotMandatory("INSSettings");
112  autoLoadWidgets();
113 
114  // Configure the calibration object
115  calibration.initialize(false, false);
116 
117  // Configure the calibration selection
118  updateCalibrationEnabled();
119 
120  // Must connect the graphs to the calibration object to see the calibration results
121  calibration.configureTempCurves(m_ui->xGyroTemp, m_ui->yGyroTemp, m_ui->zGyroTemp);
122 
123  // Connect the signals
124  connect(m_ui->yawOrientationStart, &QAbstractButton::clicked, &calibration,
126  connect(m_ui->levelingStart, &QAbstractButton::clicked, &calibration,
128  connect(m_ui->levelingAndBiasStart, &QAbstractButton::clicked, &calibration,
130  connect(m_ui->sixPointStart, &QAbstractButton::clicked, &calibration,
132  connect(m_ui->sixPointSave, &QAbstractButton::clicked, &calibration,
134  connect(m_ui->sixPointCancel, &QAbstractButton::clicked, &calibration,
136  connect(m_ui->cbCalibrateAccels, &QAbstractButton::clicked, this,
137  &ConfigAttitudeWidget::configureSixPoint);
138  connect(m_ui->cbCalibrateMags, &QAbstractButton::clicked, this,
139  &ConfigAttitudeWidget::configureSixPoint);
140  connect(m_ui->startTempCal, &QAbstractButton::clicked, &calibration,
142  connect(m_ui->acceptTempCal, &QAbstractButton::clicked, &calibration,
144  connect(m_ui->cancelTempCal, &QAbstractButton::clicked, &calibration,
146  connect(m_ui->tempCalRange, QOverload<int>::of(&QSpinBox::valueChanged), &calibration,
148  // only allow the calibration to be accepted after min temperature change
149  m_ui->acceptTempCal->setEnabled(false);
150  connect(&calibration, &Calibration::tempCalProgressChanged, this, [this](int progress) {
151  if (!m_ui->acceptTempCal)
152  return;
153  if (progress >= 100)
154  m_ui->acceptTempCal->setEnabled(true);
155  else if (m_ui->acceptTempCal->isEnabled())
156  m_ui->acceptTempCal->setEnabled(false);
157  });
158  calibration.setTempCalRange(m_ui->tempCalRange->value());
159 
160  // Let calibration update the UI
161  connect(&calibration, &Calibration::yawOrientationProgressChanged, m_ui->pb_yawCalibration,
162  &QProgressBar::setValue);
163  connect(&calibration, &Calibration::levelingProgressChanged, m_ui->accelBiasProgress,
164  &QProgressBar::setValue);
165  connect(&calibration, &Calibration::tempCalProgressChanged, m_ui->tempCalProgress,
166  &QProgressBar::setValue);
167  connect(&calibration, &Calibration::showTempCalMessage, m_ui->tempCalMessage, &QLabel::setText);
168  connect(&calibration, &Calibration::sixPointProgressChanged, m_ui->sixPointProgress,
169  &QProgressBar::setValue);
170  connect(&calibration, &Calibration::showSixPointMessage, m_ui->sixPointCalibInstructions,
171  &QTextEdit::setText);
172  connect(&calibration, &Calibration::updatePlane, this, &ConfigAttitudeWidget::displayPlane);
173 
174  // Let the calibration gadget control some control enables
175  connect(&calibration, &Calibration::toggleSavePosition, m_ui->sixPointSave,
176  &QWidget::setEnabled);
177  connect(&calibration, &Calibration::toggleControls, m_ui->sixPointStart, &QWidget::setEnabled);
178  connect(&calibration, &Calibration::toggleControls, m_ui->sixPointCancel,
179  &QWidget::setDisabled);
180  connect(&calibration, &Calibration::toggleControls, m_ui->yawOrientationStart,
181  &QWidget::setEnabled);
182  connect(&calibration, &Calibration::toggleControls, m_ui->levelingStart, &QWidget::setEnabled);
183  connect(&calibration, &Calibration::toggleControls, m_ui->levelingAndBiasStart,
184  &QWidget::setEnabled);
185  connect(&calibration, &Calibration::toggleControls, m_ui->startTempCal, &QWidget::setEnabled);
186  connect(&calibration, &Calibration::toggleControls, m_ui->acceptTempCal, &QWidget::setDisabled);
187  connect(&calibration, &Calibration::toggleControls, m_ui->cancelTempCal, &QWidget::setDisabled);
188 
189  // Let the calibration gadget mark the tab as dirty, i.e. having unsaved data.
191  &ConfigAttitudeWidget::do_SetDirty);
192 
193  // Let the calibration class mark the widget as busy
194  connect(&calibration, &Calibration::calibrationBusy, this,
195  &ConfigAttitudeWidget::onCalibrationBusy);
196 
197  m_ui->sixPointStart->setEnabled(true);
198  m_ui->yawOrientationStart->setEnabled(true);
199  m_ui->levelingStart->setEnabled(true);
200  m_ui->levelingAndBiasStart->setEnabled(true);
201 
202  refreshWidgetsValues();
203 }
204 
206 {
207  // Do nothing
208 }
209 
210 void ConfigAttitudeWidget::showEvent(QShowEvent *event)
211 {
212  Q_UNUSED(event)
213  m_ui->sixPointHelp->fitInView(paperplane, Qt::KeepAspectRatio);
214 }
215 
216 void ConfigAttitudeWidget::resizeEvent(QResizeEvent *event)
217 {
218  Q_UNUSED(event)
219  m_ui->sixPointHelp->fitInView(paperplane, Qt::KeepAspectRatio);
220 }
221 
225 void ConfigAttitudeWidget::displayPlane(int position)
226 {
227  QString displayElement;
228  switch (position) {
229  case 1:
230  displayElement = "plane-horizontal";
231  break;
232  case 2:
233  displayElement = "plane-left";
234  break;
235  case 3:
236  displayElement = "plane-flip";
237  break;
238  case 4:
239  displayElement = "plane-right";
240  break;
241  case 5:
242  displayElement = "plane-up";
243  break;
244  case 6:
245  displayElement = "plane-down";
246  break;
247  default:
248  return;
249  }
250 
251  paperplane->setElementId(displayElement);
252  m_ui->sixPointHelp->setSceneRect(paperplane->boundingRect());
253  m_ui->sixPointHelp->fitInView(paperplane, Qt::KeepAspectRatio);
254 }
255 
256 /********** UI Functions *************/
257 
262 void ConfigAttitudeWidget::refreshWidgetsValues(UAVObject *)
263 {
265 }
266 
270 void ConfigAttitudeWidget::do_SetDirty()
271 {
272  setDirty(true);
273 }
274 
275 void ConfigAttitudeWidget::configureSixPoint()
276 {
277  if (!m_ui->cbCalibrateAccels->isChecked() && !m_ui->cbCalibrateMags->isChecked()) {
278  QMessageBox::information(this, "No sensors chosen", "At least one of the sensors must be "
279  "chosen. \n\nResetting six-point "
280  "sensor calibration selection.");
281  // set checkboxes to default state
282  updateCalibrationEnabled();
283  } else {
284  calibration.initialize(m_ui->cbCalibrateAccels->isChecked(),
285  m_ui->cbCalibrateMags->isChecked());
286  }
287 }
288 
289 void ConfigAttitudeWidget::onCalibrationBusy(bool busy)
290 {
291  // Show the UI is blocking
292  if (busy)
293  QApplication::setOverrideCursor(Qt::WaitCursor);
294  else
295  QApplication::restoreOverrideCursor();
296 }
297 
298 void ConfigAttitudeWidget::updateCalibrationEnabled()
299 {
300  bool have_mag = false, have_accel = false;
301 
302  if (Q_LIKELY(utilMngr)) {
304  if (board) {
306  // some boards don't have this capability, but can still have an external mag
308  }
309 
310  auto uavoMan = utilMngr->getObjectManager();
311  if (Q_LIKELY(uavoMan)) {
312  auto mag = qobject_cast<UAVDataObject *>(
313  uavoMan->getObject(QStringLiteral("Magnetometer")));
314  if (mag && mag->getIsPresentOnHardware()) {
315  // if any of the fields have data, the mag must be present
316  const auto fields = mag->getFields();
317  for (const auto f : fields) {
318  if (f->getValue() != f->getDefaultValue())
319  have_mag = true;
320  }
321  }
322  }
323  }
324 
325  m_ui->cbCalibrateAccels->setEnabled(have_accel);
326  m_ui->cbCalibrateMags->setEnabled(have_mag);
327  if (!have_accel)
328  m_ui->cbCalibrateAccels->setChecked(false);
329  if (!have_mag)
330  m_ui->cbCalibrateMags->setChecked(false);
331  if (!m_ui->cbCalibrateAccels->isChecked() && !m_ui->cbCalibrateMags->isChecked()) {
332  m_ui->cbCalibrateAccels->setChecked(have_accel);
333  m_ui->cbCalibrateMags->setChecked(have_mag);
334  }
335 
336  if (have_accel || have_mag) {
337  configureSixPoint();
338  }
339 }
340 
void updatePlane(int position)
Change the UAV visualization.
void setDirty(bool value)
UAVObjectUtilManager * utilMngr
void showEvent(QShowEvent *event)
void setNotMandatory(QString object)
void doSaveSixPointPosition()
Indicates UAV is in a position to collect data during 6pt calibration.
void calibrationCompleted()
Indicate that a calibration process has successfully completed and the results saved to UAVO...
void autoPilotConnected()
void doStartSixPoint()
Start the six point calibration routine.
void setTempCalRange(int r)
Set temperature calibration range.
ConfigAttitudeWidget(QWidget *parent=nullptr)
void objectUnpacked(UAVObject *obj)
objectUnpacked: triggered whenever an object is unpacked (i.e. arrives from the telemetry link) ...
void resizeEvent(QResizeEvent *event)
void tempCalProgressChanged(int)
Indicate what the progress is for temperature calibration.
void levelingProgressChanged(int)
Indicate what the progress is for leveling.
void initialize(bool calibrateAccels, bool calibrateMags)
Calibration::initialize Configure whether to calibrate the magnetometer and/or accelerometer during 6...
Definition: calibration.cpp:85
void doStartOrientation()
Start collecting data while vehicle is in pure pitch.
virtual bool queryCapabilities(BoardCapabilities capability)=0
Query capabilities of the board.
void doStartNoBiasLeveling()
Start collecting data while vehicle is level.
void showTempCalMessage(QString message)
Show an instruction or message from temperature calibration.
UAVObjectManager * getObjectManager()
void sixPointProgressChanged(int)
Indicate what the progress is for six point collection.
void doCancelSixPoint()
Cancels the six point calibration routine.
void showSixPointMessage(QString message)
Show an instruction to the user for six point calibration.
void doCancelTempCalPoint()
Cancels the temperature calibration routine.
QList< UAVObjectField * > getFields()
Definition: uavobject.cpp:196
void yawOrientationProgressChanged(int)
Indicate what the progress is for yaw orientation.
void addUAVObject(QString objectName, QList< int > *reloadGroups=NULL)
static void usleep(unsigned long usecs)
Gui-less support class for calibration.
void doStartBiasAndLeveling()
Start collecting data while vehicle is level.
virtual void refreshWidgetsValues(UAVObject *obj=NULL)
void toggleSavePosition(bool enable)
Indicate whether to enable or disable controls.
void calibrationBusy(bool busy)
Indicate whether the calibration is busy.
void doAcceptTempCal()
Accept gyro temp calibration data.
void toggleControls(bool enable)
Indicate whether to enable or disable controls.
UAVObject * getObject(const QString &name, quint32 instId=0)
Core::IBoardType * getBoardType()
Get the IBoardType corresponding to the connected board.
void configureTempCurves(TempCompCurve *x, TempCompCurve *y, TempCompCurve *z)
Set up the curves.
void doStartTempCal()
Start collecting gyro temp calibration data.