dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
outputcalibrationpage.cpp
Go to the documentation of this file.
1 
13 /*
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  * for more details.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, see <http://www.gnu.org/licenses/>
26  */
27 
28 #include "outputcalibrationpage.h"
29 #include "ui_outputcalibrationpage.h"
30 #include "systemalarms.h"
32 
34  : AbstractWizardPage(wizard, parent)
35  , ui(new Ui::OutputCalibrationPage)
36  , m_vehicleBoundsItem(nullptr)
37  , m_currentWizardIndex(-1)
38  , m_calibrationUtil(nullptr)
39 {
40  ui->setupUi(this);
41 
42  m_vehicleRenderer = new QSvgRenderer();
43  if (QFile::exists(QString(":/setupwizard/resources/multirotor-shapes.svg"))
44  && m_vehicleRenderer->load(QString(":/setupwizard/resources/multirotor-shapes.svg"))
45  && m_vehicleRenderer->isValid()) {
46  m_vehicleScene = new QGraphicsScene(this);
47  ui->vehicleView->setScene(m_vehicleScene);
48  }
49 }
50 
52 {
53  if (m_calibrationUtil) {
54  delete m_calibrationUtil;
55  m_calibrationUtil = nullptr;
56  }
57  delete ui;
58 }
59 
60 void OutputCalibrationPage::setupVehicle()
61 {
62  m_actuatorSettings = getWizard()->getActuatorSettings();
63  m_wizardIndexes.clear();
64  m_vehicleElementIds.clear();
65  m_vehicleHighlightElementIndexes.clear();
66  m_channelIndex.clear();
67  m_currentWizardIndex = 0;
68  m_vehicleScene->clear();
69  switch (getWizard()->getVehicleSubType()) {
71  m_wizardIndexes << 0 << 1 << 1 << 1 << 2 << 3 << 4;
72  m_vehicleElementIds << "tri"
73  << "tri-frame"
74  << "tri-m1"
75  << "tri-m2"
76  << "tri-m3"
77  << "tri-s1";
78  m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3 << 4 << 4 << 4;
79  m_channelIndex << 0 << 0 << 1 << 2 << 3 << 3 << 3;
80  m_actuatorSettings[3].channelMin = 1500;
81  m_actuatorSettings[3].channelNeutral = 1500;
82  m_actuatorSettings[3].channelMax = 1500;
83  getWizard()->setActuatorSettings(m_actuatorSettings);
84  break;
86  m_wizardIndexes << 0 << 1 << 1 << 1 << 1;
87  m_vehicleElementIds << "quad-x"
88  << "quad-x-frame"
89  << "quad-x-m1"
90  << "quad-x-m2"
91  << "quad-x-m3"
92  << "quad-x-m4";
93  m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3 << 4;
94  m_channelIndex << 0 << 0 << 1 << 2 << 3;
95  break;
97  m_wizardIndexes << 0 << 1 << 1 << 1 << 1;
98  m_vehicleElementIds << "quad-p"
99  << "quad-p-frame"
100  << "quad-p-m1"
101  << "quad-p-m2"
102  << "quad-p-m3"
103  << "quad-p-m4";
104  m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3 << 4;
105  m_channelIndex << 0 << 0 << 1 << 2 << 3;
106  break;
108  m_wizardIndexes << 0 << 1 << 1 << 1 << 1 << 1 << 1;
109  m_vehicleElementIds << "hexa"
110  << "hexa-frame"
111  << "hexa-m1"
112  << "hexa-m2"
113  << "hexa-m3"
114  << "hexa-m4"
115  << "hexa-m5"
116  << "hexa-m6";
117  m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3 << 4 << 5 << 6;
118  m_channelIndex << 0 << 0 << 1 << 2 << 3 << 4 << 5;
119  break;
121  m_wizardIndexes << 0 << 1 << 1 << 1 << 1 << 1 << 1;
122  m_vehicleElementIds << "hexa-y6"
123  << "hexa-y6-frame"
124  << "hexa-y6-m2"
125  << "hexa-y6-m1"
126  << "hexa-y6-m4"
127  << "hexa-y6-m3"
128  << "hexa-y6-m6"
129  << "hexa-y6-m5";
130  m_vehicleHighlightElementIndexes << 0 << 2 << 1 << 4 << 3 << 6 << 5;
131  m_channelIndex << 0 << 0 << 1 << 2 << 3 << 4 << 5;
132  break;
134  m_wizardIndexes << 0 << 1 << 1 << 1 << 1 << 1 << 1;
135  m_vehicleElementIds << "hexa-h"
136  << "hexa-h-frame"
137  << "hexa-h-m1"
138  << "hexa-h-m2"
139  << "hexa-h-m3"
140  << "hexa-h-m4"
141  << "hexa-h-m5"
142  << "hexa-h-m6";
143  m_vehicleHighlightElementIndexes << 0 << 1 << 2 << 3 << 4 << 5 << 6;
144  m_channelIndex << 0 << 0 << 1 << 2 << 3 << 4 << 5;
145  break;
146  default:
147  break;
148  }
149 
151  helper.setupVehicle(false);
152 
153  if (m_calibrationUtil) {
154  delete m_calibrationUtil;
155  m_calibrationUtil = nullptr;
156  }
157  m_calibrationUtil = new OutputCalibrationUtil();
158 
159  setupVehicleItems();
160 }
161 
162 void OutputCalibrationPage::setupVehicleItems()
163 {
164  m_vehicleItems.clear();
165  m_vehicleBoundsItem = new QGraphicsSvgItem();
166  m_vehicleBoundsItem->setSharedRenderer(m_vehicleRenderer);
167  m_vehicleBoundsItem->setElementId(m_vehicleElementIds[0]);
168  m_vehicleBoundsItem->setZValue(-1);
169  m_vehicleBoundsItem->setOpacity(0);
170  m_vehicleScene->addItem(m_vehicleBoundsItem);
171 
172  QRectF parentBounds = m_vehicleRenderer->boundsOnElement(m_vehicleElementIds[0]);
173 
174  for (int i = 1; i < m_vehicleElementIds.size(); i++) {
175  QGraphicsSvgItem *item = new QGraphicsSvgItem();
176  item->setSharedRenderer(m_vehicleRenderer);
177  item->setElementId(m_vehicleElementIds[i]);
178  item->setZValue(i);
179  item->setOpacity(1.0);
180 
181  QRectF itemBounds = m_vehicleRenderer->boundsOnElement(m_vehicleElementIds[i]);
182  item->setPos(itemBounds.x() - parentBounds.x(), itemBounds.y() - parentBounds.y());
183 
184  m_vehicleScene->addItem(item);
185  m_vehicleItems << item;
186  }
187 }
188 
189 void OutputCalibrationPage::startWizard()
190 {
191  ui->calibrationStack->setCurrentIndex(m_wizardIndexes[0]);
192  setupVehicleHighlightedPart();
193 
194  QPointer<SetupWizard> wizard = getWizard();
195 
196  switch (wizard->getESCType()) {
198  ui->motorNeutralSlider->setRange(125, 152);
199  ui->motorNeutralSlider->setPageStep(1);
200  ui->motorNeutralSlider->setSingleStep(1);
201  break;
203  ui->motorNeutralSlider->setRange(125 / 3, 152 / 3);
204  ui->motorNeutralSlider->setPageStep(1);
205  ui->motorNeutralSlider->setSingleStep(1);
206  break;
210  // 1-47 reserved for special commands, max = 2047
211  ui->motorNeutralSlider->setRange(48, 400);
212  ui->motorNeutralSlider->setPageStep(1);
213  ui->motorNeutralSlider->setSingleStep(1);
214  break;
215  default:
216  break;
217  }
218 }
219 
220 void OutputCalibrationPage::setupVehicleHighlightedPart()
221 {
222  qreal dimOpaque = m_currentWizardIndex == 0 ? 1.0 : 0.3;
223  qreal highlightOpaque = 1.0;
224  int highlightedIndex = m_vehicleHighlightElementIndexes[m_currentWizardIndex];
225 
226  for (int i = 0; i < m_vehicleItems.size(); i++) {
227  QGraphicsSvgItem *item = m_vehicleItems[i];
228  item->setOpacity((highlightedIndex == i) ? highlightOpaque : dimOpaque);
229  }
230 }
231 
232 void OutputCalibrationPage::setWizardPage()
233 {
234  qDebug() << "Wizard index: " << m_currentWizardIndex;
235  m_calibrationUtil->stopChannelOutput();
236 
237  QApplication::processEvents();
238 
239  int currentPageIndex = m_wizardIndexes[m_currentWizardIndex];
240  qDebug() << "Current page: " << currentPageIndex;
241  ui->calibrationStack->setCurrentIndex(currentPageIndex);
242 
243  int currentChannel = getCurrentChannel();
244  qDebug() << "Current channel: " << currentChannel;
245  if (currentChannel >= 0) {
246  if (currentPageIndex == 1) {
247  ui->motorNeutralSlider->setValue(m_actuatorSettings[currentChannel].channelNeutral);
248  } else if (currentPageIndex == 2) {
249  ui->servoCenterSlider->setValue(m_actuatorSettings[currentChannel].channelNeutral);
250  } else if (currentPageIndex == 3) {
251  ui->servoMinAngleSlider->setMaximum(m_actuatorSettings[currentChannel].channelNeutral);
252  ui->servoMinAngleSlider->setValue(m_actuatorSettings[currentChannel].channelMin);
253  } else if (currentPageIndex == 4) {
254  ui->servoMaxAngleSlider->setMinimum(m_actuatorSettings[currentChannel].channelNeutral);
255  ui->servoMaxAngleSlider->setValue(m_actuatorSettings[currentChannel].channelMax);
256  }
257  }
258  setupVehicleHighlightedPart();
259 }
260 
262 {
263  if (m_vehicleScene) {
264  setupVehicle();
265  startWizard();
266  }
267 }
268 
270 {
271  if (isFinished()) {
272  getWizard()->setActuatorSettings(m_actuatorSettings);
273  return true;
274  } else {
275  m_currentWizardIndex++;
276  setWizardPage();
277  return false;
278  }
279 }
280 
281 void OutputCalibrationPage::showEvent(QShowEvent *event)
282 {
283  Q_UNUSED(event);
284  if (m_vehicleBoundsItem) {
285  ui->vehicleView->setSceneRect(m_vehicleBoundsItem->boundingRect());
286  ui->vehicleView->fitInView(m_vehicleBoundsItem, Qt::KeepAspectRatio);
287  }
288 }
289 
290 void OutputCalibrationPage::resizeEvent(QResizeEvent *event)
291 {
292  Q_UNUSED(event);
293  if (m_vehicleBoundsItem) {
294  ui->vehicleView->setSceneRect(m_vehicleBoundsItem->boundingRect());
295  ui->vehicleView->fitInView(m_vehicleBoundsItem, Qt::KeepAspectRatio);
296  }
297 }
298 
300 {
301  if (m_currentWizardIndex > 0) {
302  m_currentWizardIndex--;
303  setWizardPage();
304  } else {
305  getWizard()->back();
306  }
307 }
308 
309 quint16 OutputCalibrationPage::getCurrentChannel()
310 {
311  return m_channelIndex[m_currentWizardIndex];
312 }
313 
314 void OutputCalibrationPage::enableButtons(bool enable)
315 {
316  getWizard()->button(QWizard::NextButton)->setEnabled(enable);
317  getWizard()->button(QWizard::CustomButton1)->setEnabled(enable);
318  getWizard()->button(QWizard::CancelButton)->setEnabled(enable);
319  getWizard()->button(QWizard::BackButton)->setEnabled(enable);
320  QApplication::processEvents();
321 }
322 
323 void OutputCalibrationPage::on_motorNeutralButton_toggled(bool checked)
324 {
325  ui->motorNeutralButton->setText(checked ? tr("Stop") : tr("Start"));
326  quint16 channel = getCurrentChannel();
327  onStartButtonToggle(ui->motorNeutralButton, channel, m_actuatorSettings[channel].channelNeutral,
328  m_actuatorSettings[channel].channelMin, ui->motorNeutralSlider);
329 }
330 
331 void OutputCalibrationPage::onStartButtonToggle(QAbstractButton *button, quint16 channel,
332  quint16 value, quint16 safeValue, QSlider *slider)
333 {
334  if (button->isChecked()) {
335  if (checkAlarms()) {
336  enableButtons(false);
337  m_calibrationUtil->startChannelOutput(channel, safeValue);
338  slider->setValue(value);
339  m_calibrationUtil->setChannelOutputValue(value);
340  } else {
341  button->setChecked(false);
342  }
343  } else {
344  m_calibrationUtil->stopChannelOutput();
345  enableButtons(true);
346  }
347  debugLogChannelValues();
348 }
349 
350 bool OutputCalibrationPage::checkAlarms()
351 {
352  ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
353  UAVObjectManager *uavObjectManager = pm->getObject<UAVObjectManager>();
354 
355  Q_ASSERT(uavObjectManager);
356  SystemAlarms *systemAlarms = SystemAlarms::GetInstance(uavObjectManager);
357  Q_ASSERT(systemAlarms);
358  SystemAlarms::DataFields data = systemAlarms->getData();
359 
360  if (data.Alarm[SystemAlarms::ALARM_ACTUATOR] != SystemAlarms::ALARM_OK) {
361  QMessageBox mbox(this);
362  mbox.setText(QString(tr("The actuator module is in an error state.\n\n"
363  "Please make sure the correct firmware version is used then "
364  "restart the wizard and try again. If the problem persists please "
365  "consult the openpilot.org support forum.")));
366  mbox.setStandardButtons(QMessageBox::Ok);
367  mbox.setIcon(QMessageBox::Critical);
368 
369  getWizard()->setWindowFlags(getWizard()->windowFlags() & ~Qt::WindowStaysOnTopHint);
370 
371  mbox.exec();
372 
373  getWizard()->setWindowFlags(getWizard()->windowFlags() | Qt::WindowStaysOnTopHint);
374  getWizard()->setWindowIcon(qApp->windowIcon());
375  getWizard()->show();
376  return false;
377  }
378  return true;
379 }
380 
381 void OutputCalibrationPage::debugLogChannelValues()
382 {
383  quint16 channel = getCurrentChannel();
384 
385  qDebug() << "ChannelMin : " << m_actuatorSettings[channel].channelMin;
386  qDebug() << "ChannelNeutral: " << m_actuatorSettings[channel].channelNeutral;
387  qDebug() << "ChannelMax : " << m_actuatorSettings[channel].channelMax;
388 }
389 
390 void OutputCalibrationPage::on_motorNeutralSlider_valueChanged(int value)
391 {
392  Q_UNUSED(value);
393  if (ui->motorNeutralButton->isChecked()) {
394  quint16 value = ui->motorNeutralSlider->value();
395  m_calibrationUtil->setChannelOutputValue(value);
396  m_actuatorSettings[getCurrentChannel()].channelNeutral = value;
397  debugLogChannelValues();
398  }
399 }
400 
401 void OutputCalibrationPage::on_servoCenterButton_toggled(bool checked)
402 {
403  ui->servoCenterButton->setText(checked ? tr("Stop") : tr("Start"));
404  quint16 channel = getCurrentChannel();
405  quint16 safeValue = m_actuatorSettings[channel].channelNeutral;
406  onStartButtonToggle(ui->servoCenterButton, channel, safeValue, safeValue,
407  ui->servoCenterSlider);
408 }
409 
410 void OutputCalibrationPage::on_servoCenterSlider_valueChanged(int position)
411 {
412  Q_UNUSED(position);
413  if (ui->servoCenterButton->isChecked()) {
414  quint16 value = ui->servoCenterSlider->value();
415  m_calibrationUtil->setChannelOutputValue(value);
416  quint16 channel = getCurrentChannel();
417  m_actuatorSettings[channel].channelNeutral = value;
418 
419  // Adjust min and max
420  if (value < m_actuatorSettings[channel].channelMin) {
421  m_actuatorSettings[channel].channelMin = value;
422  }
423  if (value > m_actuatorSettings[channel].channelMax) {
424  m_actuatorSettings[channel].channelMax = value;
425  }
426  debugLogChannelValues();
427  }
428 }
429 
430 void OutputCalibrationPage::on_servoMinAngleButton_toggled(bool checked)
431 {
432  ui->servoMinAngleButton->setText(checked ? tr("Stop") : tr("Start"));
433  quint16 channel = getCurrentChannel();
434  quint16 safeValue = m_actuatorSettings[channel].channelNeutral;
435  onStartButtonToggle(ui->servoMinAngleButton, channel, m_actuatorSettings[channel].channelMin,
436  safeValue, ui->servoMinAngleSlider);
437 }
438 
439 void OutputCalibrationPage::on_servoMinAngleSlider_valueChanged(int position)
440 {
441  Q_UNUSED(position);
442  if (ui->servoMinAngleButton->isChecked()) {
443  quint16 value = ui->servoMinAngleSlider->value();
444  m_calibrationUtil->setChannelOutputValue(value);
445  m_actuatorSettings[getCurrentChannel()].channelMin = value;
446  debugLogChannelValues();
447  }
448 }
449 
450 void OutputCalibrationPage::on_servoMaxAngleButton_toggled(bool checked)
451 {
452  ui->servoMaxAngleButton->setText(checked ? tr("Stop") : tr("Start"));
453  quint16 channel = getCurrentChannel();
454  quint16 safeValue = m_actuatorSettings[channel].channelNeutral;
455  onStartButtonToggle(ui->servoMaxAngleButton, channel, m_actuatorSettings[channel].channelMax,
456  safeValue, ui->servoMaxAngleSlider);
457 }
458 
459 void OutputCalibrationPage::on_servoMaxAngleSlider_valueChanged(int position)
460 {
461  Q_UNUSED(position);
462  if (ui->servoMaxAngleButton->isChecked()) {
463  quint16 value = ui->servoMaxAngleSlider->value();
464  m_calibrationUtil->setChannelOutputValue(value);
465  m_actuatorSettings[getCurrentChannel()].channelMax = value;
466  debugLogChannelValues();
467  }
468 }
OutputCalibrationPage(SetupWizard *wizard, QWidget *parent=nullptr)
void showEvent(QShowEvent *event)
The SetupWizard class is the main interface to the setup wizard. It provides selects the sequence of ...
Definition: setupwizard.h:47
SetupWizard * getWizard() const
Core plugin system that manages the plugins, their life cycle and their registered objects...
Definition: pluginmanager.h:53
for i
Definition: OPPlots.m:140
void resizeEvent(QResizeEvent *event)
DataFields data
void setActuatorSettings(QList< actuatorChannelSettings > actuatorSettings)
Definition: setupwizard.h:84
void setChannelOutputValue(quint16 value)
QList< actuatorChannelSettings > getActuatorSettings() const
Definition: setupwizard.h:89
void startChannelOutput(quint16 channel, quint16 safeValue)
The VehicleConfigurationHelper class provides an interface between the settings selected in the wizar...