28 #define _USE_MATH_DEFINES
41 #include "altitudeholdsettings.h"
42 #include "manualcontrolsettings.h"
43 #include "mixersettings.h"
44 #include "modulesettings.h"
45 #include "sensorsettings.h"
46 #include "stabilizationsettings.h"
47 #include "systemident.h"
48 #include "systemsettings.h"
53 #include "physical_constants.h"
55 #include <QtAlgorithms>
58 #include <QCryptographicHash>
60 #include <QDesktopServices>
61 #include <QFileDialog>
63 #include <QPushButton>
64 #include <QStringList>
68 #include <QVBoxLayout>
72 #include <QtNetwork/QNetworkAccessManager>
73 #include <QtNetwork/QNetworkRequest>
76 #ifdef CONF_ATUNE_DEBUG
77 #define CONF_ATUNE_QXTLOG_DEBUG(...) qDebug() << __VA_ARGS__
78 #else // CONF_ATUNE_DEBUG
79 #define CONF_ATUNE_QXTLOG_DEBUG(...)
80 #endif // CONF_ATUNE_DEBUG
82 const QString ConfigAutotuneWidget::databaseUrl =
83 QString(
"http://dronin-autotown.appspot.com/storeTune");
88 parentConfigWidget = parent;
89 m_autotune =
new Ui_AutotuneWidget();
90 m_autotune->setupUi(
this);
102 Qt::QueuedConnection);
104 &ConfigAutotuneWidget::atDisconnected, Qt::QueuedConnection);
105 connect(m_autotune->adjustTune, &QPushButton::pressed,
this,
106 QOverload<>::of(&ConfigAutotuneWidget::openAutotuneDialog));
107 connect(m_autotune->fromDataFileBtn, &QPushButton::pressed,
this,
108 &ConfigAutotuneWidget::openAutotuneFile);
113 void ConfigAutotuneWidget::atConnected()
115 m_autotune->adjustTune->setEnabled(
true);
119 void ConfigAutotuneWidget::atDisconnected()
121 m_autotune->adjustTune->setEnabled(
false);
124 void ConfigAutotuneWidget::checkNewAutotune()
128 SystemIdent::DataFields systemIdentData = systemIdent->getData();
130 if (systemIdentData.NewTune) {
134 systemIdentData.NewTune =
false;
136 systemIdent->setData(systemIdentData);
138 systemIdent->updated();
144 openAutotuneDialog(
true);
152 QJsonDocument ConfigAutotuneWidget::getResultsJson(
AutotuneFinalPage *autotuneShareForm,
158 QJsonObject rawSettings;
161 json[
"dataVersion"] = 3;
163 QString(QCryptographicHash::hash(utilMngr->
getBoardCPUSerial(), QCryptographicHash::Sha256)
166 QJsonObject vehicle, fw;
172 fw[
"tag"] = firmware.
gitTag;
173 fw[
"commit"] = firmware.
gitHash;
174 QDateTime fwDate = QDateTime::fromString(firmware.
gitDate,
"yyyyMMdd hh:mm");
175 fwDate.setTimeSpec(Qt::UTC);
176 fw[
"date"] = fwDate.toString(Qt::ISODate);
177 vehicle[
"firmware"] = fw;
179 SystemSettings *sysSettings = SystemSettings::GetInstance(
getObjectManager());
181 rawSettings[sysSettings->getName()] = sysSettings->getJsonRepresentation();
183 ActuatorSettings *actSettings = ActuatorSettings::GetInstance(
getObjectManager());
184 rawSettings[actSettings->getName()] = actSettings->getJsonRepresentation();
186 StabilizationSettings *stabSettings = StabilizationSettings::GetInstance(
getObjectManager());
187 rawSettings[stabSettings->getName()] = stabSettings->getJsonRepresentation();
190 rawSettings[systemIdent->getName()] = systemIdent->getJsonRepresentation();
192 SensorSettings *senSettings = SensorSettings::GetInstance(
getObjectManager());
193 rawSettings[senSettings->getName()] = senSettings->getJsonRepresentation();
195 ManualControlSettings *manSettings = ManualControlSettings::GetInstance(
getObjectManager());
196 rawSettings[manSettings->getName()] = manSettings->getJsonRepresentation();
198 MixerSettings *mixSettings = MixerSettings::GetInstance(
getObjectManager());
199 rawSettings[mixSettings->getName()] = mixSettings->getJsonRepresentation();
208 QString hwSettingsName = board->
getHwUAVO();
215 vehicle[
"type"] = autotuneShareForm->acType->currentText();
216 vehicle[
"size"] = autotuneShareForm->acVehicleSize->text();
217 vehicle[
"weight"] = autotuneShareForm->acWeight->text();
218 vehicle[
"batteryCells"] = autotuneShareForm->acBatteryCells->currentText();
219 vehicle[
"esc"] = autotuneShareForm->acEscs->text();
220 vehicle[
"motor"] = autotuneShareForm->acMotors->text();
221 vehicle[
"props"] = autotuneShareForm->acProps->text();
222 json[
"vehicle"] = vehicle;
224 json[
"userObservations"] = autotuneShareForm->teObservations->toPlainText();
226 QJsonObject identification;
227 QJsonObject roll_ident;
228 roll_ident[
"gain"] = tuneState->
beta[0];
229 roll_ident[
"bias"] = tuneState->
bias[0];
230 roll_ident[
"noise"] = tuneState->
noise[0];
231 roll_ident[
"tau"] = tuneState->
tau[0];
232 identification[
"roll"] = roll_ident;
234 QJsonObject pitch_ident;
235 pitch_ident[
"gain"] = tuneState->
beta[1];
236 pitch_ident[
"bias"] = tuneState->
bias[1];
237 pitch_ident[
"noise"] = tuneState->
noise[1];
238 pitch_ident[
"tau"] = tuneState->
tau[1];
239 identification[
"pitch"] = pitch_ident;
241 QJsonObject yaw_ident;
242 yaw_ident[
"gain"] = tuneState->
beta[2];
243 yaw_ident[
"bias"] = tuneState->
bias[2];
244 yaw_ident[
"noise"] = tuneState->
noise[2];
245 yaw_ident[
"tau"] = tuneState->
tau[2];
246 identification[
"yaw"] = yaw_ident;
248 identification[
"tau"] = tuneState->
tau[0];
249 json[
"identification"] = identification;
251 QJsonObject tuning, parameters, computed, misc;
252 parameters[
"damping"] = tuneState->
damping;
253 parameters[
"noiseSensitivity"] = tuneState->
noiseSens;
255 tuning[
"parameters"] = parameters;
256 computed[
"naturalFrequency"] = tuneState->
naturalFreq;
258 computed[
"converged"] = tuneState->
converged;
259 computed[
"iterations"] = tuneState->
iterations;
262 QJsonObject roll_gain, pitch_gain, yaw_gain, outer_gain, vert_gain;
263 roll_gain[
"kp"] = tuneState->
kp[0];
264 roll_gain[
"ki"] = tuneState->
ki[0];
265 roll_gain[
"kd"] = tuneState->
kd[0];
266 gains[
"roll"] = roll_gain;
267 pitch_gain[
"kp"] = tuneState->
kp[1];
268 pitch_gain[
"ki"] = tuneState->
ki[1];
269 pitch_gain[
"kd"] = tuneState->
kd[1];
270 gains[
"pitch"] = pitch_gain;
271 yaw_gain[
"kp"] = tuneState->
kp[2];
272 yaw_gain[
"ki"] = tuneState->
ki[2];
273 yaw_gain[
"kd"] = tuneState->
kd[2];
274 gains[
"yaw"] = yaw_gain;
275 outer_gain[
"kp"] = tuneState->
outerKp;
276 outer_gain[
"ki"] = tuneState->
outerKi;
277 gains[
"outer"] = outer_gain;
280 vert_gain[
"poskp"] = tuneState->
vertPosKp;
281 computed[
"gains"] = gains;
282 tuning[
"computed"] = computed;
283 json[
"tuning"] = tuning;
285 json[
"rawSettings"] = rawSettings;
287 QByteArray compressedData = qCompress(tuneState->
data, 9);
288 json[
"rawTuneData"] = QString(compressedData.toBase64());
290 return QJsonDocument(json);
293 void ConfigAutotuneWidget::persistShareForm(
AutotuneFinalPage *autotuneShareForm)
297 settings->
setObservations(autotuneShareForm->teObservations->toPlainText());
298 settings->
setBoardType(autotuneShareForm->acBoard->text());
299 settings->
setMotors(autotuneShareForm->acMotors->text());
300 settings->
setESCs(autotuneShareForm->acEscs->text());
301 settings->
setProps(autotuneShareForm->acProps->text());
302 settings->
setWeight(autotuneShareForm->acWeight->text().toInt());
303 settings->
setVehicleSize(autotuneShareForm->acVehicleSize->text().toInt());
304 settings->
setVehicleType(autotuneShareForm->acType->currentText());
305 settings->
setBatteryCells(autotuneShareForm->acBatteryCells->currentText().toInt());
313 autotuneShareForm->teObservations->setText(settings->
getObservations());
314 autotuneShareForm->acBoard->setText(settings->
getBoardType());
315 autotuneShareForm->acMotors->setText(settings->
getMotors());
316 autotuneShareForm->acEscs->setText(settings->
getESCs());
317 autotuneShareForm->acProps->setText(settings->
getProps());
318 autotuneShareForm->acWeight->setText(QString::number(settings->
getWeight()));
319 autotuneShareForm->acVehicleSize->setText(QString::number(settings->
getVehicleSize()));
320 autotuneShareForm->acType->setCurrentText(settings->
getVehicleType());
321 autotuneShareForm->acBatteryCells->setCurrentText(QString::number(settings->
getBatteryCells()));
323 SystemSettings *sysSettings = SystemSettings::GetInstance(
getObjectManager());
325 UAVObjectField *frameType = sysSettings->getField(
"AirframeType");
327 autotuneShareForm->acType->clear();
328 autotuneShareForm->acType->addItems(frameType->
getOptions());
330 QString currentFrameType;
331 currentFrameType = frameType->
getValue().toString();
332 if (!currentFrameType.isNull()) {
333 autotuneShareForm->acType->setEditable(
false);
334 autotuneShareForm->acType->setCurrentText(currentFrameType);
342 autotuneShareForm->acBoard->setText(board->
shortName());
343 autotuneShareForm->acBoard->setEnabled(
false);
347 void ConfigAutotuneWidget::openAutotuneFile()
350 QFileDialog::getOpenFileName(
this, tr(
"Open autotune partition"),
"",
351 tr(
"Partition image Files (*.bin) ;; All files (*.*)"));
353 if (fileName.isEmpty()) {
357 QFile
file(fileName);
358 if (!
file.open(QIODevice::ReadOnly)) {
366 openAutotuneDialog(
false, &vals);
369 void ConfigAutotuneWidget::openAutotuneDialog()
371 openAutotuneDialog(
false);
374 void ConfigAutotuneWidget::openAutotuneDialog(
bool autoOpened,
377 QWizard wizard(NULL, Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint
378 | Qt::WindowCloseButtonHint);
380 wizard.setPixmap(QWizard::BackgroundPixmap, QPixmap(
":/configgadget/images/autotunebg.png"));
395 wizard.setOption(QWizard::NoCancelButton,
false);
397 wizard.setMinimumSize(735, 600);
399 wizard.addPage(beginning);
410 wizard.setWindowTitle(
"Autotune Wizard");
413 if (av.
valid && (wizard.result() == QDialog::Accepted) && av.
converged) {
415 StabilizationSettings *stabilizationSettings =
417 Q_ASSERT(stabilizationSettings);
418 if (!stabilizationSettings) {
419 qWarning() <<
"Abandoning autotune commit because no StabSettings";
423 StabilizationSettings::DataFields stabData = stabilizationSettings->getData();
425 stabData.RollRatePID[StabilizationSettings::ROLLRATEPID_KP] = av.
kp[0];
426 stabData.RollRatePID[StabilizationSettings::ROLLRATEPID_KI] = av.
ki[0];
427 stabData.RollRatePID[StabilizationSettings::ROLLRATEPID_KD] = av.
kd[0];
428 stabData.PitchRatePID[StabilizationSettings::PITCHRATEPID_KP] = av.
kp[1];
429 stabData.PitchRatePID[StabilizationSettings::PITCHRATEPID_KI] = av.
ki[1];
430 stabData.PitchRatePID[StabilizationSettings::PITCHRATEPID_KD] = av.
kd[1];
432 stabData.YawRatePID[StabilizationSettings::YAWRATEPID_KP] = av.
kp[2];
433 stabData.YawRatePID[StabilizationSettings::YAWRATEPID_KI] = av.
ki[2];
434 stabData.YawRatePID[StabilizationSettings::YAWRATEPID_KD] = av.
kd[2];
439 stabData.RollPI[StabilizationSettings::ROLLPI_KP] = av.
outerKp;
440 stabData.RollPI[StabilizationSettings::ROLLPI_KI] = av.
outerKi;
441 stabData.PitchPI[StabilizationSettings::PITCHPI_KP] = av.
outerKp;
442 stabData.PitchPI[StabilizationSettings::PITCHPI_KI] = av.
outerKi;
444 stabilizationSettings->setData(stabData);
445 stabilizationSettings->updated();
452 SystemIdent::DataFields systemIdentData = systemIdent->getData();
454 for (
int i = 0;
i < 3;
i++) {
455 systemIdentData.Tau[
i] = av.
tau[
i];
456 systemIdentData.Beta[
i] = av.
beta[
i];
459 systemIdent->setData(systemIdentData);
460 systemIdent->updated();
466 AltitudeHoldSettings *altSettings =
470 qWarning() <<
"Not committing alt hold data because obj not present";
472 altSettings->setPositionKp(av.
vertPosKp);
475 altSettings->updated();
480 if (pg->shareBox->isChecked()) {
481 persistShareForm(pg);
485 QJsonDocument json = getResultsJson(pg, &av);
488 QUrl url(databaseUrl);
489 QNetworkRequest request(url);
490 request.setHeader(QNetworkRequest::ContentTypeHeader,
491 "application/json; charset=utf-8");
492 QNetworkAccessManager *manager =
new QNetworkAccessManager(
this);
493 QNetworkReply *reply = manager->post(request, json.toJson());
494 connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
501 : QWizardPage(parent)
505 this->tuneState = autoValues;
508 QChart *AutotuneMeasuredPropertiesPage::makeChart(
int axis) {
511 chart =
new QChart();
513 tuneState->
actual[axis]->setName(tr(
"Actual"));
514 chart->addSeries(tuneState->
actual[axis]);
515 tuneState->
model[axis]->setName(tr(
"Predicted"));
516 chart->addSeries(tuneState->
model[axis]);
518 chart->createDefaultAxes();
520 chart->axisX()->setTitleText(tr(
"Time"));
521 dynamic_cast<QValueAxis *
>(chart->axisX())->setLabelFormat(
"%.0f ms");
522 chart->axisY()->setTitleText(tr(
"Angular acceleration"));
523 chart->axisY()->setLabelsVisible(
false);
530 measuredRollGain->setText(QString::number(tuneState->
beta[0],
'f', 2));
531 measuredPitchGain->setText(QString::number(tuneState->
beta[1],
'f', 2));
532 measuredYawGain->setText(QString::number(tuneState->
beta[2],
'f', 2));
534 measuredRollBias->setText(QString::number(tuneState->
bias[0],
'f', 3));
535 measuredPitchBias->setText(QString::number(tuneState->
bias[1],
'f', 3));
536 measuredYawBias->setText(QString::number(tuneState->
bias[2],
'f', 3));
538 rollTau->setText(QString::number(tuneState->
tau[0],
'f', 4));
539 pitchTau->setText(QString::number(tuneState->
tau[1],
'f', 4));
540 yawTau->setText(QString::number(tuneState->
tau[2],
'f', 4));
542 measuredRollNoise->setText(QString::number(tuneState->
noise[0],
'f', 2));
543 measuredPitchNoise->setText(QString::number(tuneState->
noise[1],
'f', 2));
544 measuredYawNoise->setText(QString::number(tuneState->
noise[2],
'f', 2));
546 rollChartView->setRenderHint(QPainter::Antialiasing);
547 rollChartView->setChart(makeChart(0));
549 pitchChartView->setRenderHint(QPainter::Antialiasing);
550 pitchChartView->setChart(makeChart(1));
552 yawChartView->setRenderHint(QPainter::Antialiasing);
553 yawChartView->setChart(makeChart(2));
557 : QWizardPage(parent)
561 tuneState = autoValues;
564 connect(rateDamp, &QAbstractSlider::valueChanged,
this, &AutotuneSlidersPage::compute);
565 connect(rateNoise, &QAbstractSlider::valueChanged,
this, &AutotuneSlidersPage::compute);
566 connect(cbUseYaw, &QAbstractButton::toggled,
this, &AutotuneSlidersPage::compute);
567 connect(cbUseOuterKi, &QAbstractButton::toggled,
this, &AutotuneSlidersPage::compute);
568 connect(cbTuneAlt, &QAbstractButton::toggled,
this, &AutotuneSlidersPage::computeThrust);
570 connect(btnResetSliders, &QAbstractButton::pressed,
this, &AutotuneSlidersPage::resetSliders);
579 void AutotuneSlidersPage::resetSliders()
581 rateDamp->setValue(105);
582 rateNoise->setValue(10);
593 void AutotuneSlidersPage::setText(QLabel *lbl,
double value,
int precision)
598 lbl->setText(QString::number(value,
'f', precision));
602 void AutotuneSlidersPage::computeThrust()
604 const double baseKp = 0.5;
605 const double tauDerate = 0.025;
606 const double kiAdjust = 1.5;
607 const double outerSlowdown = 0.125;
608 const double okpCeiling = 0.9 * GRAVITY / 4.0;
610 double hoverThrust = 0;
611 double thrustTau = (tuneState->
tau[0] + tuneState->
tau[1]) / 2 +
625 SystemIdent *systemIdent =
nullptr;
628 systemIdent = SystemIdent::GetInstance(objMngr);
632 hoverThrust = systemIdent->getHoverThrottle();
635 if ((hoverThrust < 0.05) ||
636 (hoverThrust > 0.6) ||
637 (thrustTau < 0.005) ||
638 (thrustTau > 0.200)) {
639 cbTuneAlt->setChecked(
false);
640 cbTuneAlt->setEnabled(
false);
643 if (cbTuneAlt->isChecked()) {
644 tuneState->
vertSpeedKp = (baseKp * hoverThrust / GRAVITY) /
647 (kiAdjust * 2 * M_PI * thrustTau);
648 tuneState->
vertPosKp = outerSlowdown / thrustTau;
664 void AutotuneSlidersPage::compute()
674 const double ghf = rateNoise->value() / 1000.0;
675 const double damp = rateDamp->value() / 100.0;
681 double tau = (tuneState->
tau[0] + tuneState->
tau[1]) / 2.0;
682 double beta_roll = tuneState->
beta[0];
683 double beta_pitch = tuneState->
beta[1];
684 double beta_yaw = tuneState->
beta[2];
687 lblWarnings->setText(
"");
689 if (beta_yaw < 6.8) {
690 lblWarnings->setText(tr(
"Unable to auto-calculate yaw gains for this craft."));
691 cbUseYaw->setChecked(
false);
692 cbUseYaw->setEnabled(
false);
695 bool doYaw = cbUseYaw->isChecked();
696 bool doOuterKi = cbUseOuterKi->isChecked();
698 double wn = 1 / tau, wn_last = 1 / tau + 10;
699 double tau_d = 0, tau_d_last = 1000;
701 const int iteration_limit = 100, stability_limit = 5;
702 bool converged =
false;
704 int stable_iterations = 0;
706 while (!converged && (++iterations <= iteration_limit)) {
708 (2 * damp * tau * wn - 1) / (4 * tau * damp * damp * wn * wn - 2 * damp * wn
709 - tau * wn * wn + exp(beta_roll) * ghf);
711 (2 * damp * tau * wn - 1) / (4 * tau * damp * damp * wn * wn - 2 * damp * wn
712 - tau * wn * wn + exp(beta_pitch) * ghf);
715 tau_d = (tau_d_roll > tau_d_pitch) ? tau_d_roll : tau_d_pitch;
716 wn = (tau + tau_d) / (tau * tau_d) / (2 * damp + 2);
719 if (fabs(tau_d - tau_d_last) <= 0.00001 && fabs(wn - wn_last) <= 0.00001) {
720 if (++stable_iterations >= stability_limit)
723 stable_iterations = 0;
738 const double a = ((tau + tau_d) / tau / tau_d - 2 * damp * wn) / 25.0;
739 const double b = ((tau + tau_d) / tau / tau_d - 2 * damp * wn - a);
741 CONF_ATUNE_QXTLOG_DEBUG(
"ghf: ", ghf);
742 CONF_ATUNE_QXTLOG_DEBUG(
"wn: ", wn,
"tau_d: ", tau_d);
743 CONF_ATUNE_QXTLOG_DEBUG(
"a: ", a,
" b: ", b);
748 const double zeta_o = 1.3;
749 tuneState->
outerKp = 1 / 4.0 / (zeta_o * zeta_o) / (1 / wn);
759 if (tuneState->
outerKp > 7.0) {
767 tuneState->
outerKi = 0.75 * tuneState->
outerKp / (2 * M_PI * tau * 15.0);
772 for (
int i = 0;
i < 3;
i++) {
773 double beta = exp(tuneState->
beta[
i]);
779 ki = a * b * wn * wn * tau * tau_d / beta;
780 kp = tau * tau_d * ((a + b) * wn * wn + 2 * a * b * damp * wn) / beta - ki * tau_d;
781 kd = (tau * tau_d * (a * b + wn * wn + (a + b) * 2 * damp * wn) - 1) / beta - kp * tau_d;
783 tuneState->
kp[
i] = kp;
784 tuneState->
ki[
i] = ki;
785 tuneState->
kd[
i] = kd;
789 tuneState->
kp[2] = -1;
790 tuneState->
ki[2] = -1;
791 tuneState->
kd[2] = -1;
796 lblWarnings->setText(tr(
"<span style=\"color: red\">Error:</span> Tune didn't converge! "
797 "Check noise and damping sliders."));
800 emit completeChanged();
802 setText(rollRateKp, tuneState->
kp[0], 5);
803 setText(rollRateKi, tuneState->
ki[0], 5);
804 setText(rollRateKd, tuneState->
kd[0], 6);
806 setText(pitchRateKp, tuneState->
kp[1], 5);
807 setText(pitchRateKi, tuneState->
ki[1], 5);
808 setText(pitchRateKd, tuneState->
kd[1], 6);
810 setText(yawRateKp, tuneState->
kp[2], 5);
811 setText(yawRateKi, tuneState->
ki[2], 5);
812 setText(yawRateKd, tuneState->
kd[2], 6);
814 setText(lblOuterKp, tuneState->
outerKp, 2);
815 setText(lblOuterKi, tuneState->
outerKi, 2);
818 setText(lblDamp, damp, 2);
819 lblNoise->setText(QString::number(ghf * 100,
'f', 1) +
" %");
823 : QWizardPage(parent)
828 lblCongrats->setText(lblCongrats->text().replace(tr(
"\"Finish\""), tr(
"\"Done\"")));
834 : QWizardPage(parent)
836 tuneState = autoValues;
837 this->autoOpened = autoOpened;
842 QString AutotuneBeginningPage::tuneValid(
bool *okToContinue)
const
844 if ((!tuneState->
valid) || (tuneState->
tau[0] == 0)) {
847 *okToContinue =
false;
848 return tr(
"<span style=\"color: red\">It doesn't appear an autotune was successfully "
849 "completed and saved; we are unable to continue.</span>");
854 *okToContinue =
true;
856 if (tuneState->
tau[0] < 0.005) {
858 retVal.append(tr(
"Error: Autotune did not measure valid values for this craft (low tau). "
859 "Consider slightly lowering the starting roll/pitch rate P values or "
860 "slightly decreasing Motor Input/Output Curve Fit on the output pane."));
861 retVal.append(
"<br/>");
862 *okToContinue =
false;
863 }
else if (tuneState->
tau[0] < 0.0074) {
865 retVal.append(tr(
"Warning: The tau value measured for this craft is very low."));
866 retVal.append(
"<br/>");
867 }
else if (tuneState->
tau[0] > .240) {
869 retVal.append(tr(
"Warning: The tau value measured for this craft is very high."));
870 retVal.append(
"<br/>");
874 if (tuneState->
beta[0] < 7.25) {
876 tr(
"Error: Autotune did not measure valid values for this craft (low roll gain)."));
877 retVal.append(
"<br/>");
878 *okToContinue =
false;
881 if (tuneState->
beta[0] < 7.25) {
883 tr(
"Error: Autotune did not measure valid values for this craft (low pitch gain)."));
884 retVal.append(
"<br/>");
885 *okToContinue =
false;
888 retVal.replace(QRegExp(
"(\\w+:)"),
"<span style=\"color: red\"><b>\\1</b></span>");
891 if (retVal.isEmpty()) {
892 retVal.append(tr(
"Everything checks out, and we're ready to proceed!"));
895 tr(
"<br/>These warnings may result in an invalid tune. Proceed with caution."));
899 tr(
"<br/>Unable to complete the autotune process because of the above error(s)."));
905 void AutotuneBeginningPage::doDownloadAndProcess()
907 if (!tuneState->
valid) {
912 if (tuneState->
data.isEmpty()) {
914 int fraction = (100 * progress) / 32768.0;
920 progressBar->setValue(fraction);
931 progressBar->setValue(90);
933 processAutotuneData();
935 progressBar->setValue(100);
937 QString initialWarnings = tuneValid(&dataValid);
939 status->setText(initialWarnings);
941 emit completeChanged();
946 setTitle(tr(
"Preparing autotune..."));
949 subtitle->setText(tr(
"It looks like you have run a new autotune since you last connected to the flight "
950 "controller. This wizard will assist you in applying a set of autotune "
951 "measurements to your aircraft."));
953 subtitle->setText(tr(
"This wizard will assist you in applying a set of autotune "
954 "measurements to your aircraft."));
957 progressBar->setRange(0, 100);
958 progressBar->setValue(0);
960 QMetaObject::invokeMethod(
this,
"doDownloadAndProcess", Qt::QueuedConnection);
965 return tuneState->
valid && dataValid;
972 void AutotuneBeginningPage::biquadFilter(
float cutoff,
int pts,
973 QVector<float> &data)
975 float f = 1.0f / tan(M_PI * cutoff);
978 float y2 = 0, y1 = 0, x2 = 0, x1 = 0;
980 float b0 = 1.0f / (1.0f + q * f + f * f);
981 float a1 = 2.0f * (f * f - 1.0f) * b0;
982 float a2 = -(1.0f - q * f + f * f) * b0;
984 for (
int i = 0;
i < pts;
i++) {
985 float y = b0 * (data[
i] + 2.0f * x1 + x2) + a1 * y1 + a2 * y2;
994 for (
int i = 0;
i < pts;
i++) {
995 float y = b0 * (data[
i] + 2.0f * x1 + x2) + a1 * y1 + a2 * y2;
1008 float AutotuneBeginningPage::getSampleDelay(
int pts,
1009 const QVector<float> &delayed,
const QVector<float> &orig,
1015 QVector<float> delayed_fft(pts);
1016 fft.do_fft(delayed_fft.data(), delayed.data());
1018 QVector<float> orig_fft(pts);
1019 fft.do_fft(orig_fft.data(), orig.data());
1029 QVector<float> product(pts);
1034 for (
int i = 0;
i < fpts;
i++) {
1035 float x = delayed_fft[
i];
1036 float y = delayed_fft[
i + fpts];
1037 float u = orig_fft[
i];
1038 float v = orig_fft[
i + fpts];
1040 product[
i] = -(u *
x) - (v * y);
1041 product[
i + fpts] = (v *
x) - (u * y);
1045 QVector<float> prod_time(pts);
1047 fft.do_ifft(product.data(), prod_time.data());
1050 QVector<float> mags(fpts);
1055 for (
int i = 0;
i < fpts / seriesCutoff;
i++) {
1056 float real = prod_time[
i];
1057 float imag = prod_time[
i + fpts];
1058 mags[
i] = sqrt(real * real + imag * imag);
1060 if (mags[
i] > max_val) {
1075 bool AutotuneBeginningPage::processAutotuneData()
1077 QByteArray &loadedFile = tuneState->
data;
1079 const at_flash *flash_data =
reinterpret_cast<const at_flash *
>((
const void *)loadedFile);
1081 unsigned int size = loadedFile.size();
1084 if ((size <
sizeof(at_flash)) || (flash_data->hdr.magic != ATFLASH_MAGIC)) {
1088 unsigned int size_expected =
sizeof(at_flash)
1089 +
sizeof(at_measurement) * flash_data->hdr.wiggle_points + flash_data->hdr.aux_data_len;
1091 if (size < size_expected) {
1095 float duration = (float)flash_data->hdr.wiggle_points / flash_data->hdr.sample_rate;
1097 if ((duration < 0.25f) || (duration > 5.0f)) {
1101 int pts = flash_data->hdr.wiggle_points;
1103 for (
int axis = 0; axis < 3; axis++) {
1104 QVector<float> gyro_deriv(pts);
1105 QVector<float> actu_desired(pts);
1107 for (
int i = 0;
i < pts;
i++) {
1108 actu_desired[
i] = flash_data->data[
i].u[axis];
1112 for (
int i = 1;
i < pts;
i++) {
1113 gyro_deriv[
i] = flash_data->data[
i].y[axis] - flash_data->data[
i - 1].y[axis];
1116 gyro_deriv[0] = flash_data->data[0].y[axis] - flash_data->data[pts - 1].y[axis];
1118 float sample_tau = getSampleDelay(pts, gyro_deriv, actu_desired,
1119 (axis == 2) ? 8 : 4);
1121 float tau = sample_tau / flash_data->hdr.sample_rate;
1123 biquadFilter(1 / (sample_tau * M_PI * 1.414), pts, actu_desired);
1125 QVector<float> gyro_sorted = gyro_deriv;
1126 QVector<float> actu_sorted = actu_desired;
1128 std::sort(gyro_sorted.begin(), gyro_sorted.end());
1129 std::sort(actu_sorted.begin(), actu_sorted.end());
1131 int low_idx = pts * 0.05 + 0.5;
1132 int high_idx = pts - 1 - low_idx;
1134 float gyro_span = gyro_sorted[high_idx] - gyro_sorted[low_idx];
1135 float actu_span = actu_sorted[high_idx] - actu_sorted[low_idx];
1137 float gain = gyro_span / actu_span * flash_data->hdr.sample_rate;
1139 float avg = std::accumulate(gyro_deriv.begin(), gyro_deriv.end(), 0.0f) / pts;
1141 for (
int i = 0;
i < pts;
i++) {
1142 gyro_deriv[
i] = gyro_deriv[
i] - avg;
1145 float avg_act = std::accumulate(actu_desired.begin(), actu_desired.end(), 0.0f) / pts;
1147 for (
int i = 0;
i < pts;
i++) {
1148 actu_desired[
i] = (actu_desired[
i] - avg_act) * (gain / flash_data->hdr.sample_rate);
1151 tuneState->
model[axis] =
new QLineSeries(
this);
1152 tuneState->
actual[axis] =
new QLineSeries(
this);
1154 for (
int i = 0;
i < pts;
i++) {
1155 int tm = (
i * 1000) / flash_data->hdr.sample_rate;
1157 tuneState->
model[axis]->append(tm, actu_desired[
i]);
1158 tuneState->
actual[axis]->append(tm, gyro_deriv[i]);
1161 float bias = avg - avg_act * (gain / flash_data->hdr.sample_rate);
1165 for (
int i = 0; i < pts; i++) {
1166 noise += (actu_desired[
i] - gyro_deriv[
i]) * (actu_desired[i] - gyro_deriv[i]);
1169 noise = sqrt(noise / pts);
1171 qDebug() <<
"Series " << axis <<
": tau=" << tau <<
"; gain=" << gain <<
" (" << log(gain)
1172 <<
"); bias=" << bias <<
" noise=" << noise <<
"";
1174 tuneState->
tau[axis] = tau;
1175 tuneState->
beta[axis] = log(gain);
1176 tuneState->
bias[axis] = bias;
1177 tuneState->
noise[axis] = noise;
1180 tuneState->
valid =
true;
void setMotors(QString motors)
void setWeight(int weight)
AutotuneSlidersPage(QWidget *parent, AutotunedValues *autoValues)
void setBatteryCells(int cells)
void setProps(QString props)
Core plugin system that manages the plugins, their life cycle and their registered objects...
QVariant getValue(int index=0) const
void setESCs(QString escs)
void setVehicleSize(int spacing)
QJsonObject getJsonRepresentation()
QString getObservations()
QStringList getOptions() const
virtual QString getHwUAVO()=0
void setVehicleType(QString type)
QByteArray * downloadFile(quint32 fileId, quint32 maxSize, std::function< void(quint32)>progressCb)
void setBoardType(QString type)
AutotuneFinalPage(QWidget *parent)
ConfigAutotuneWidget(ConfigGadgetWidget *parent=nullptr)
virtual QString shortName()=0
bool getBoardDescriptionStruct(deviceDescriptorStruct &device)
AutotuneBeginningPage(QWidget *parent, bool autoOpened, AutotunedValues *autoValues)
UAVObject * getObject(const QString &name, quint32 instId=0)
Core::IBoardType * getBoardType()
Get the IBoardType corresponding to the connected board.
QByteArray getBoardCPUSerial()
AutotuneMeasuredPropertiesPage(QWidget *parent, AutotunedValues *autoValues)
void setObservations(QString value)