diff --git a/kstars/ekos/guide/guide.h b/kstars/ekos/guide/guide.h --- a/kstars/ekos/guide/guide.h +++ b/kstars/ekos/guide/guide.h @@ -10,6 +10,7 @@ #pragma once #include "ui_guide.h" +#include "guideinterface.h" #include "ekos/ekos.h" #include "indi/indiccd.h" #include "indi/inditelescope.h" @@ -27,7 +28,6 @@ namespace Ekos { -class GuideInterface; class OpsCalibration; class OpsGuide; class InternalGuider; @@ -401,6 +401,7 @@ void handleVerticalPlotSizeChange(); void handleHorizontalPlotSizeChange(); void clearGuideGraphs(); + void clearCalibrationGraphs(); void slotAutoScaleGraphs(); void buildTarget(); void guideHistory(); @@ -457,6 +458,7 @@ void setAxisDelta(double ra, double de); void setAxisSigma(double ra, double de); void setAxisPulse(double ra, double de); + void calibrationUpdate(GuideInterface::CalibrationUpdateType type, const QString& message = QString(""), double dx = 0, double dy = 0); void processGuideOptions(); @@ -535,6 +537,9 @@ // Init Functions void initPlots(); + void initDriftGraph(); + void initDriftPlot(); + void initCalibrationPlot(); void initView(); void initConnections(); @@ -644,5 +649,7 @@ //autostar is not selected, and the user has chosen a star. //This connection storage is so that the connection can be disconnected after enforcement QMetaObject::Connection guideConnect; + + QCPItemText *calLabel { nullptr }; }; } diff --git a/kstars/ekos/guide/guide.cpp b/kstars/ekos/guide/guide.cpp --- a/kstars/ekos/guide/guide.cpp +++ b/kstars/ekos/guide/guide.cpp @@ -147,12 +147,16 @@ { driftPlot->xAxis->setScaleRatio(driftPlot->yAxis, 1.0); driftPlot->replot(); + calibrationPlot->xAxis->setScaleRatio(calibrationPlot->yAxis, 1.0); + calibrationPlot->replot(); } void Guide::handleVerticalPlotSizeChange() { driftPlot->yAxis->setScaleRatio(driftPlot->xAxis, 1.0); driftPlot->replot(); + calibrationPlot->yAxis->setScaleRatio(calibrationPlot->xAxis, 1.0); + calibrationPlot->replot(); } void Guide::guideAfterMeridianFlip() @@ -274,6 +278,15 @@ setupNSEWLabels(); } +void Guide::clearCalibrationGraphs() +{ + calibrationPlot->graph(0)->data()->clear(); //RA out + calibrationPlot->graph(1)->data()->clear(); //RA back + calibrationPlot->graph(2)->data()->clear(); //DEC out + calibrationPlot->graph(3)->data()->clear(); //DEC back + calibrationPlot->replot(); +} + void Guide::setupNSEWLabels() { //Labels for N/S/E/W @@ -362,6 +375,15 @@ driftPlot->xAxis->setScaleRatio(driftPlot->yAxis, 1.0); driftPlot->replot(); + + calibrationPlot->xAxis->setRange(-10, 10); + calibrationPlot->yAxis->setRange(-10, 10); + calibrationPlot->graph(0)->rescaleAxes(true); + + calibrationPlot->yAxis->setScaleRatio(calibrationPlot->xAxis, 1.0); + calibrationPlot->xAxis->setScaleRatio(calibrationPlot->yAxis, 1.0); + + calibrationPlot->replot(); } void Guide::guideHistory() @@ -1808,6 +1830,7 @@ break; case GUIDE_CALIBRATING: + clearCalibrationGraphs(); appendLogText(i18n("Calibration started.")); setBusy(true); break; @@ -2191,6 +2214,7 @@ connect(guider, &Ekos::GuideInterface::newAxisDelta, this, &Ekos::Guide::setAxisDelta); connect(guider, &Ekos::GuideInterface::newAxisPulse, this, &Ekos::Guide::setAxisPulse); connect(guider, &Ekos::GuideInterface::newAxisSigma, this, &Ekos::Guide::setAxisSigma); + connect(guider, &Ekos::GuideInterface::calibrationUpdate, this, &Ekos::Guide::calibrationUpdate); connect(guider, &Ekos::GuideInterface::guideEquipmentUpdated, this, &Ekos::Guide::configurePHD2Camera); } @@ -2562,6 +2586,30 @@ emit newProfilePixmap(profilePixmap); } +void Guide::calibrationUpdate(GuideInterface::CalibrationUpdateType type, const QString& message, + double dx, double dy) +{ + switch (type) + { + case GuideInterface::RA_IN: + calibrationPlot->graph(0)->addData(dx, dy); + break; + case GuideInterface::RA_OUT: + calibrationPlot->graph(1)->addData(dx, dy); + break; + case GuideInterface::DEC_IN: + calibrationPlot->graph(2)->addData(dx, dy); + break; + case GuideInterface::DEC_OUT: + calibrationPlot->graph(3)->addData(dx, dy); + break; + case GuideInterface::CALIBRATION_MESSAGE_ONLY: + ; + } + calLabel->setText(message); + calibrationPlot->replot(); +} + void Guide::setAxisSigma(double ra, double de) { l_ErrRA->setText(QString::number(ra, 'f', 2)); @@ -3180,6 +3228,25 @@ } void Guide::initPlots() +{ + initDriftGraph(); + initDriftPlot(); + initCalibrationPlot(); + + connect(rightLayout, &QSplitter::splitterMoved, this, &Ekos::Guide::handleVerticalPlotSizeChange); + connect(driftSplitter, &QSplitter::splitterMoved, this, &Ekos::Guide::handleHorizontalPlotSizeChange); + + //This sets the values of all the Graph Options that are stored. + accuracyRadiusSpin->setValue(Options::guiderAccuracyThreshold()); + showRAPlotCheck->setChecked(Options::rADisplayedOnGuideGraph()); + showDECPlotCheck->setChecked(Options::dEDisplayedOnGuideGraph()); + showRACorrectionsCheck->setChecked(Options::rACorrDisplayedOnGuideGraph()); + showDECorrectionsCheck->setChecked(Options::dECorrDisplayedOnGuideGraph()); + + buildTarget(); +} + +void Guide::initDriftGraph() { // Drift Graph Color Settings driftGraph->setBackground(QBrush(Qt::black)); @@ -3304,7 +3371,19 @@ connect(driftGraph, &QCustomPlot::mouseMove, this, &Ekos::Guide::driftMouseOverLine); connect(driftGraph, &QCustomPlot::mousePress, this, &Ekos::Guide::driftMouseClicked); + //This sets the visibility of graph components to the stored values. + driftGraph->graph(0)->setVisible(Options::rADisplayedOnGuideGraph()); //RA data + driftGraph->graph(1)->setVisible(Options::dEDisplayedOnGuideGraph()); //DEC data + driftGraph->graph(2)->setVisible(Options::rADisplayedOnGuideGraph()); //RA highlighted point + driftGraph->graph(3)->setVisible(Options::dEDisplayedOnGuideGraph()); //DEC highlighted point + driftGraph->graph(4)->setVisible(Options::rACorrDisplayedOnGuideGraph()); //RA Pulses + driftGraph->graph(5)->setVisible(Options::dECorrDisplayedOnGuideGraph()); //DEC Pulses + updateCorrectionsScaleVisibility(); +} + +void Guide::initDriftPlot() +{ //drift plot double accuracyRadius = 2; @@ -3358,29 +3437,85 @@ driftPlot->graph(1)->setLineStyle(QCPGraph::lsNone); driftPlot->graph(1)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssPlusCircle, QPen(Qt::yellow, 2), QBrush(), 10)); - connect(rightLayout, &QSplitter::splitterMoved, this, &Ekos::Guide::handleVerticalPlotSizeChange); - connect(driftSplitter, &QSplitter::splitterMoved, this, &Ekos::Guide::handleHorizontalPlotSizeChange); + driftPlot->resize(190, 190); + driftPlot->replot(); +} - //This sets the values of all the Graph Options that are stored. - accuracyRadiusSpin->setValue(Options::guiderAccuracyThreshold()); - showRAPlotCheck->setChecked(Options::rADisplayedOnGuideGraph()); - showDECPlotCheck->setChecked(Options::dEDisplayedOnGuideGraph()); - showRACorrectionsCheck->setChecked(Options::rACorrDisplayedOnGuideGraph()); - showDECorrectionsCheck->setChecked(Options::dECorrDisplayedOnGuideGraph()); +void Guide::initCalibrationPlot() +{ + calibrationPlot->setBackground(QBrush(Qt::black)); + calibrationPlot->setSelectionTolerance(10); - //This sets the visibility of graph components to the stored values. - driftGraph->graph(0)->setVisible(Options::rADisplayedOnGuideGraph()); //RA data - driftGraph->graph(1)->setVisible(Options::dEDisplayedOnGuideGraph()); //DEC data - driftGraph->graph(2)->setVisible(Options::rADisplayedOnGuideGraph()); //RA highlighted point - driftGraph->graph(3)->setVisible(Options::dEDisplayedOnGuideGraph()); //DEC highlighted point - driftGraph->graph(4)->setVisible(Options::rACorrDisplayedOnGuideGraph()); //RA Pulses - driftGraph->graph(5)->setVisible(Options::dECorrDisplayedOnGuideGraph()); //DEC Pulses - updateCorrectionsScaleVisibility(); + calibrationPlot->xAxis->setBasePen(QPen(Qt::white, 1)); + calibrationPlot->yAxis->setBasePen(QPen(Qt::white, 1)); - driftPlot->resize(190, 190); - driftPlot->replot(); + calibrationPlot->xAxis->setTickPen(QPen(Qt::white, 1)); + calibrationPlot->yAxis->setTickPen(QPen(Qt::white, 1)); - buildTarget(); + calibrationPlot->xAxis->setSubTickPen(QPen(Qt::white, 1)); + calibrationPlot->yAxis->setSubTickPen(QPen(Qt::white, 1)); + + calibrationPlot->xAxis->setTickLabelColor(Qt::white); + calibrationPlot->yAxis->setTickLabelColor(Qt::white); + + calibrationPlot->xAxis->setLabelColor(Qt::white); + calibrationPlot->yAxis->setLabelColor(Qt::white); + + calibrationPlot->xAxis->setLabelFont(QFont(font().family(), 10)); + calibrationPlot->yAxis->setLabelFont(QFont(font().family(), 10)); + calibrationPlot->xAxis->setTickLabelFont(QFont(font().family(), 9)); + calibrationPlot->yAxis->setTickLabelFont(QFont(font().family(), 9)); + + calibrationPlot->xAxis->setLabelPadding(2); + calibrationPlot->yAxis->setLabelPadding(2); + + calibrationPlot->xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); + calibrationPlot->yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); + calibrationPlot->xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); + calibrationPlot->yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); + calibrationPlot->xAxis->grid()->setZeroLinePen(QPen(Qt::gray)); + calibrationPlot->yAxis->grid()->setZeroLinePen(QPen(Qt::gray)); + + calibrationPlot->xAxis->setLabel(i18n("x (pixels)")); + calibrationPlot->yAxis->setLabel(i18n("y (pixels)")); + + calibrationPlot->xAxis->setRange(-10, 10); + calibrationPlot->yAxis->setRange(-10, 10); + + calibrationPlot->setInteractions(QCP::iRangeZoom); + calibrationPlot->setInteraction(QCP::iRangeDrag, true); + + calibrationPlot->addGraph(); + calibrationPlot->graph(0)->setLineStyle(QCPGraph::lsNone); + calibrationPlot->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"), 2), QBrush(), 6)); + calibrationPlot->graph(0)->setName("RA out"); + + calibrationPlot->addGraph(); + calibrationPlot->graph(1)->setLineStyle(QCPGraph::lsNone); + calibrationPlot->graph(1)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QPen(Qt::white, 2), QBrush(), 4)); + calibrationPlot->graph(1)->setName("RA in"); + + calibrationPlot->addGraph(); + calibrationPlot->graph(2)->setLineStyle(QCPGraph::lsNone); + calibrationPlot->graph(2)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"), 2), QBrush(), 6)); + calibrationPlot->graph(2)->setName("DEC out"); + + calibrationPlot->addGraph(); + calibrationPlot->graph(3)->setLineStyle(QCPGraph::lsNone); + calibrationPlot->graph(3)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QPen(Qt::yellow, 2), QBrush(), 4)); + calibrationPlot->graph(3)->setName("DEC in"); + + calLabel = new QCPItemText(calibrationPlot); + calLabel->setColor(QColor(255,255,255)); + calLabel->setPositionAlignment(Qt::AlignTop|Qt::AlignHCenter); + calLabel->position->setType(QCPItemPosition::ptAxisRectRatio); + calLabel->position->setCoords(0.5, 0); + calLabel->setText(""); + calLabel->setFont(QFont(font().family(), 10)); + calLabel->setVisible(true); + + calibrationPlot->resize(190, 190); + calibrationPlot->replot(); } void Guide::initView() diff --git a/kstars/ekos/guide/guide.ui b/kstars/ekos/guide/guide.ui --- a/kstars/ekos/guide/guide.ui +++ b/kstars/ekos/guide/guide.ui @@ -1146,7 +1146,7 @@ - Control parameters + Control @@ -1425,6 +1425,41 @@ + + + Calibration Plot + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 200 + 200 + + + + + + diff --git a/kstars/ekos/guide/guideinterface.h b/kstars/ekos/guide/guideinterface.h --- a/kstars/ekos/guide/guideinterface.h +++ b/kstars/ekos/guide/guideinterface.h @@ -58,15 +58,24 @@ virtual void setStarPosition(QVector3D& starCenter); + enum CalibrationUpdateType + { + RA_IN, + RA_OUT, + DEC_IN, + DEC_OUT, + CALIBRATION_MESSAGE_ONLY + }; + signals: void newLog(const QString &); void newStatus(Ekos::GuideState); void newAxisDelta(double delta_ra, double delta_dec); void newAxisSigma(double sigma_ra, double sigma_dec); void newAxisPulse(double pulse_ra, double pulse_dec); void newStarPosition(const QVector3D &newCenter, bool updateNow); void newStarPixmap(QPixmap &); - + void calibrationUpdate(CalibrationUpdateType type, const QString &message = QString(""), double x = 0, double y = 0); void frameCaptureRequested(); void guideEquipmentUpdated(); diff --git a/kstars/ekos/guide/internalguide/internalguider.cpp b/kstars/ekos/guide/internalguide/internalguider.cpp --- a/kstars/ekos/guide/internalguide/internalguider.cpp +++ b/kstars/ekos/guide/internalguide/internalguider.cpp @@ -425,7 +425,7 @@ calibrationStage = CAL_ERROR; emit newStatus(Ekos::GUIDE_CALIBRATION_ERROR); - + emit calibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Failed: Lost guide star.")); return; } @@ -489,6 +489,7 @@ m_CalibrationParams.last_pulse = Options::calibrationPulseDuration(); + emit calibrationUpdate(GuideInterface::RA_IN, i18n("Guide Star found."), 0, 0); qCDebug(KSTARS_EKOS_GUIDE) << "Auto Iteration #" << m_CalibrationParams.auto_drift_time << "Default pulse:" << m_CalibrationParams.last_pulse; qCDebug(KSTARS_EKOS_GUIDE) << "Start X1 " << m_CalibrationCoords.start_x1 << " Start Y1 " << m_CalibrationCoords.start_y1; @@ -512,6 +513,9 @@ double cur_x, cur_y; pmath->getStarScreenPosition(&cur_x, &cur_y); + emit calibrationUpdate(GuideInterface::RA_IN, i18n("Calibrating RA Out"), + cur_x - m_CalibrationCoords.start_x1, cur_y - m_CalibrationCoords.start_y1); + qCDebug(KSTARS_EKOS_GUIDE) << "Iteration #" << m_CalibrationParams.ra_iterations << ": STAR " << cur_x << "," << cur_y; qCDebug(KSTARS_EKOS_GUIDE) << "Iteration " << m_CalibrationParams.ra_iterations << " Direction: RA_INC_DIR" << " Duration: " << m_CalibrationParams.last_pulse << " ms."; @@ -551,7 +555,7 @@ calibrationStage = CAL_ERROR; emit newStatus(Ekos::GUIDE_CALIBRATION_ERROR); - + emit calibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Failed: Drift too short.")); KSNotification::event(QLatin1String("CalibrationFailed"), i18n("Guiding calibration failed with errors"), KSNotification::EVENT_ALERT); @@ -587,6 +591,8 @@ double cur_x, cur_y; pmath->getStarScreenPosition(&cur_x, &cur_y); + emit calibrationUpdate(GuideInterface::RA_OUT, i18n("Calibrating RA In"), + cur_x - m_CalibrationCoords.start_x1, cur_y - m_CalibrationCoords.start_y1); qCDebug(KSTARS_EKOS_GUIDE) << "Iteration #" << m_CalibrationParams.ra_iterations << ": STAR " << cur_x << "," << cur_y; qCDebug(KSTARS_EKOS_GUIDE) << "Iteration " << m_CalibrationParams.ra_iterations << " Direction: RA_DEC_DIR" << " Duration: " << m_CalibrationParams.last_pulse << " ms."; @@ -645,7 +651,7 @@ calibrationStage = CAL_ERROR; emit newStatus(Ekos::GUIDE_CALIBRATION_ERROR); - + emit calibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Failed: couldn't reach start.")); emit newLog(i18np("Guide RA: Scope cannot reach the start point after %1 iteration. Possible mount or " "backlash problems...", "GUIDE_RA: Scope cannot reach the start point after %1 iterations. Possible mount or " @@ -694,7 +700,7 @@ calibrationStage = CAL_ERROR; emit newStatus(Ekos::GUIDE_CALIBRATION_ERROR); - + emit calibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Failed: drift too short.")); KSNotification::event(QLatin1String("CalibrationFailed"), i18n("Guiding calibration failed with errors"), KSNotification::EVENT_ALERT); } @@ -709,6 +715,9 @@ double cur_x, cur_y; pmath->getStarScreenPosition(&cur_x, &cur_y); + emit calibrationUpdate(GuideInterface::DEC_IN, i18n("Calibrating DEC Out"), + cur_x - m_CalibrationCoords.start_x2, cur_y - m_CalibrationCoords.start_y2); + qCDebug(KSTARS_EKOS_GUIDE) << "Iteration #" << m_CalibrationParams.dec_iterations << ": STAR " << cur_x << "," << cur_y; qCDebug(KSTARS_EKOS_GUIDE) << "Iteration " << m_CalibrationParams.dec_iterations << " Direction: DEC_INC_DIR" << " Duration: " << m_CalibrationParams.last_pulse << " ms."; @@ -745,7 +754,7 @@ calibrationStage = CAL_ERROR; emit newStatus(Ekos::GUIDE_CALIBRATION_ERROR); - + emit calibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Failed: couldn't reach start point.")); emit newLog(i18np("Guide DEC: Scope cannot reach the start point after %1 iteration.\nPossible mount " "or backlash problems...", "GUIDE DEC: Scope cannot reach the start point after %1 iterations.\nPossible mount " @@ -784,6 +793,9 @@ double cur_x, cur_y; pmath->getStarScreenPosition(&cur_x, &cur_y); + emit calibrationUpdate(GuideInterface::DEC_OUT, i18n("Calibrating DEC In"), + cur_x - m_CalibrationCoords.start_x2, cur_y - m_CalibrationCoords.start_y2); + // Star position resulting from LAST guiding pulse to mount qCDebug(KSTARS_EKOS_GUIDE) << "Iteration #" << m_CalibrationParams.dec_iterations << ": STAR " << cur_x << "," << cur_y; qCDebug(KSTARS_EKOS_GUIDE) << "Iteration " << m_CalibrationParams.dec_iterations << " Direction: DEC_DEC_DIR" << @@ -833,6 +845,7 @@ calibrationStage = CAL_ERROR; emit newStatus(Ekos::GUIDE_CALIBRATION_ERROR); + emit calibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Failed: couldn't reach start point.")); emit newLog(i18np("Guide DEC: Scope cannot reach the start point after %1 iteration.\nPossible mount " "or backlash problems...", @@ -864,6 +877,7 @@ emit DESwapChanged(swap_dec); + emit calibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Successful")); KSNotification::event(QLatin1String("CalibrationSuccessful"), i18n("Guiding calibration completed successfully")); @@ -873,6 +887,7 @@ else { emit newLog(i18n("Calibration rejected. Star drift is too short. Check for mount, cable, or backlash problems.")); + emit calibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Failed: drift too short.")); emit newStatus(Ekos::GUIDE_CALIBRATION_ERROR);