Changeset View
Changeset View
Standalone View
Standalone View
kstars/ekos/scheduler/scheduler.cpp
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show All 25 Lines | |||||
26 | #include "ekos/manager.h" | 26 | #include "ekos/manager.h" | ||
27 | #include "ekos/capture/sequencejob.h" | 27 | #include "ekos/capture/sequencejob.h" | ||
28 | #include "skyobjects/starobject.h" | 28 | #include "skyobjects/starobject.h" | ||
29 | 29 | | |||
30 | #include <KNotifications/KNotification> | 30 | #include <KNotifications/KNotification> | ||
31 | 31 | | |||
32 | #include <ekos_scheduler_debug.h> | 32 | #include <ekos_scheduler_debug.h> | ||
33 | 33 | | |||
34 | #define BAD_SCORE -1000 | 34 | #define BAD_SCORE -1000 | ||
35 | #define MAX_FAILURE_ATTEMPTS 5 | 35 | #define MAX_FAILURE_ATTEMPTS 5 | ||
36 | #define UPDATE_PERIOD_MS 1000 | 36 | #define UPDATE_PERIOD_MS 1000 | ||
37 | #define RESTART_GUIDING_DELAY_MS 5000 | ||||
37 | 38 | | |||
38 | #define DEFAULT_CULMINATION_TIME -60 | 39 | #define DEFAULT_CULMINATION_TIME -60 | ||
39 | #define DEFAULT_MIN_ALTITUDE 15 | 40 | #define DEFAULT_MIN_ALTITUDE 15 | ||
40 | #define DEFAULT_MIN_MOON_SEPARATION 0 | 41 | #define DEFAULT_MIN_MOON_SEPARATION 0 | ||
41 | 42 | | |||
42 | namespace Ekos | 43 | namespace Ekos | ||
43 | { | 44 | { | ||
44 | Scheduler::Scheduler() | 45 | Scheduler::Scheduler() | ||
Show All 37 Lines | 46 | { | |||
82 | 83 | | |||
83 | connect(&sleepTimer, &QTimer::timeout, this, &Scheduler::wakeUpScheduler); | 84 | connect(&sleepTimer, &QTimer::timeout, this, &Scheduler::wakeUpScheduler); | ||
84 | schedulerTimer.setInterval(UPDATE_PERIOD_MS); | 85 | schedulerTimer.setInterval(UPDATE_PERIOD_MS); | ||
85 | jobTimer.setInterval(UPDATE_PERIOD_MS); | 86 | jobTimer.setInterval(UPDATE_PERIOD_MS); | ||
86 | 87 | | |||
87 | connect(&schedulerTimer, &QTimer::timeout, this, &Scheduler::checkStatus); | 88 | connect(&schedulerTimer, &QTimer::timeout, this, &Scheduler::checkStatus); | ||
88 | connect(&jobTimer, &QTimer::timeout, this, &Scheduler::checkJobStage); | 89 | connect(&jobTimer, &QTimer::timeout, this, &Scheduler::checkJobStage); | ||
89 | 90 | | |||
91 | restartGuidingTimer.setSingleShot(true); | ||||
92 | restartGuidingTimer.setInterval(RESTART_GUIDING_DELAY_MS); | ||||
93 | connect(&restartGuidingTimer, &QTimer::timeout, this, [this]() | ||||
94 | { | ||||
95 | startGuiding(true); | ||||
96 | }); | ||||
97 | | ||||
90 | pi = new QProgressIndicator(this); | 98 | pi = new QProgressIndicator(this); | ||
91 | bottomLayout->addWidget(pi, 0, nullptr); | 99 | bottomLayout->addWidget(pi, 0, nullptr); | ||
92 | 100 | | |||
93 | geo = KStarsData::Instance()->geo(); | 101 | geo = KStarsData::Instance()->geo(); | ||
94 | 102 | | |||
95 | raBox->setDegType(false); //RA box should be HMS-style | 103 | raBox->setDegType(false); //RA box should be HMS-style | ||
96 | 104 | | |||
97 | /* FIXME: Find a way to have multi-line tooltips in the .ui file, then move the widget configuration there - what about i18n? */ | 105 | /* FIXME: Find a way to have multi-line tooltips in the .ui file, then move the widget configuration there - what about i18n? */ | ||
▲ Show 20 Lines • Show All 1062 Lines • ▼ Show 20 Line(s) | 1152 | { | |||
1160 | } | 1168 | } | ||
1161 | 1169 | | |||
1162 | if (wasAborted) | 1170 | if (wasAborted) | ||
1163 | KNotification::event(QLatin1String("SchedulerAborted"), i18n("Scheduler aborted.")); | 1171 | KNotification::event(QLatin1String("SchedulerAborted"), i18n("Scheduler aborted.")); | ||
1164 | } | 1172 | } | ||
1165 | 1173 | | |||
1166 | schedulerTimer.stop(); | 1174 | schedulerTimer.stop(); | ||
1167 | jobTimer.stop(); | 1175 | jobTimer.stop(); | ||
1176 | restartGuidingTimer.stop(); | ||||
1168 | 1177 | | |||
1169 | state = SCHEDULER_IDLE; | 1178 | state = SCHEDULER_IDLE; | ||
1170 | emit newStatus(state); | 1179 | emit newStatus(state); | ||
1171 | ekosState = EKOS_IDLE; | 1180 | ekosState = EKOS_IDLE; | ||
1172 | indiState = INDI_IDLE; | 1181 | indiState = INDI_IDLE; | ||
1173 | 1182 | | |||
1174 | parkWaitState = PARKWAIT_IDLE; | 1183 | parkWaitState = PARKWAIT_IDLE; | ||
1175 | 1184 | | |||
▲ Show 20 Lines • Show All 2054 Lines • ▼ Show 20 Line(s) | 3221 | { | |||
3230 | else currentOperationTime.restart(); | 3239 | else currentOperationTime.restart(); | ||
3231 | } | 3240 | } | ||
3232 | break; | 3241 | break; | ||
3233 | 3242 | | |||
3234 | case SchedulerJob::STAGE_GUIDING: | 3243 | case SchedulerJob::STAGE_GUIDING: | ||
3235 | // Let's make sure guide module does not become unresponsive | 3244 | // Let's make sure guide module does not become unresponsive | ||
3236 | if (currentOperationTime.elapsed() > GUIDE_INACTIVITY_TIMEOUT) | 3245 | if (currentOperationTime.elapsed() > GUIDE_INACTIVITY_TIMEOUT) | ||
3237 | { | 3246 | { | ||
3238 | QVariant const status = guideInterface->property("status"); | 3247 | GuideState guideStatus = getGuidingStatus(); | ||
3239 | Ekos::GuideState guideStatus = static_cast<Ekos::GuideState>(status.toInt()); | | |||
3240 | 3248 | | |||
3241 | if (guideStatus == Ekos::GUIDE_IDLE || guideStatus == Ekos::GUIDE_CONNECTED || guideStatus == Ekos::GUIDE_DISCONNECTED) | 3249 | if (guideStatus == Ekos::GUIDE_IDLE || guideStatus == Ekos::GUIDE_CONNECTED || guideStatus == Ekos::GUIDE_DISCONNECTED) | ||
3242 | { | 3250 | { | ||
3243 | if (guideFailureCount++ < MAX_FAILURE_ATTEMPTS) | 3251 | if (guideFailureCount++ < MAX_FAILURE_ATTEMPTS) | ||
3244 | { | 3252 | { | ||
3245 | qCDebug(KSTARS_EKOS_SCHEDULER) << "guide module timed out. Restarting request..."; | 3253 | qCDebug(KSTARS_EKOS_SCHEDULER) << "guide module timed out. Restarting request..."; | ||
3246 | startGuiding(); | 3254 | startGuiding(); | ||
3247 | } | 3255 | } | ||
▲ Show 20 Lines • Show All 312 Lines • ▼ Show 20 Line(s) | 3566 | case SchedulerJob::STAGE_IDLE: | |||
3560 | { | 3568 | { | ||
3561 | if (currentJob->getStepPipeline() & SchedulerJob::USE_TRACK) | 3569 | if (currentJob->getStepPipeline() & SchedulerJob::USE_TRACK) | ||
3562 | startSlew(); | 3570 | startSlew(); | ||
3563 | else if (currentJob->getStepPipeline() & SchedulerJob::USE_FOCUS && autofocusCompleted == false) | 3571 | else if (currentJob->getStepPipeline() & SchedulerJob::USE_FOCUS && autofocusCompleted == false) | ||
3564 | startFocusing(); | 3572 | startFocusing(); | ||
3565 | else if (currentJob->getStepPipeline() & SchedulerJob::USE_ALIGN) | 3573 | else if (currentJob->getStepPipeline() & SchedulerJob::USE_ALIGN) | ||
3566 | startAstrometry(); | 3574 | startAstrometry(); | ||
3567 | else if (currentJob->getStepPipeline() & SchedulerJob::USE_GUIDE) | 3575 | else if (currentJob->getStepPipeline() & SchedulerJob::USE_GUIDE) | ||
3576 | if (getGuidingStatus() == GUIDE_GUIDING) | ||||
3577 | { | ||||
3578 | appendLogText(i18n("Guiding already running, directly start capturing.")); | ||||
3579 | startCapture(); | ||||
3580 | } | ||||
3581 | else | ||||
3568 | startGuiding(); | 3582 | startGuiding(); | ||
3569 | else | 3583 | else | ||
3570 | startCapture(); | 3584 | startCapture(); | ||
3571 | } | 3585 | } | ||
3572 | else | 3586 | else | ||
3573 | { | 3587 | { | ||
3574 | if (currentJob->getStepPipeline()) | 3588 | if (currentJob->getStepPipeline()) | ||
3575 | appendLogText( | 3589 | appendLogText( | ||
▲ Show 20 Lines • Show All 971 Lines • ▼ Show 20 Line(s) | 4523 | { | |||
4547 | 4561 | | |||
4548 | /* FIXME: not supposed to modify the job */ | 4562 | /* FIXME: not supposed to modify the job */ | ||
4549 | currentJob->setStage(SchedulerJob::STAGE_ALIGNING); | 4563 | currentJob->setStage(SchedulerJob::STAGE_ALIGNING); | ||
4550 | currentOperationTime.restart(); | 4564 | currentOperationTime.restart(); | ||
4551 | } | 4565 | } | ||
4552 | 4566 | | |||
4553 | void Scheduler::startGuiding(bool resetCalibration) | 4567 | void Scheduler::startGuiding(bool resetCalibration) | ||
4554 | { | 4568 | { | ||
4569 | // avoid starting the guider twice | ||||
4570 | if (resetCalibration == false && getGuidingStatus() == GUIDE_GUIDING) | ||||
4571 | { | ||||
4572 | appendLogText(i18n("Guiding already running for %1 ...", currentJob->getName())); | ||||
4573 | currentJob->setStage(SchedulerJob::STAGE_GUIDING); | ||||
4574 | currentOperationTime.restart(); | ||||
4575 | return; | ||||
4576 | } | ||||
4577 | | ||||
4555 | // Connect Guider | 4578 | // Connect Guider | ||
4556 | guideInterface->call(QDBus::AutoDetect, "connectGuider"); | 4579 | guideInterface->call(QDBus::AutoDetect, "connectGuider"); | ||
4557 | 4580 | | |||
4558 | // Set Auto Star to true | 4581 | // Set Auto Star to true | ||
4559 | QVariant arg(true); | 4582 | QVariant arg(true); | ||
4560 | guideInterface->call(QDBus::AutoDetect, "setCalibrationAutoStar", arg); | 4583 | guideInterface->call(QDBus::AutoDetect, "setCalibrationAutoStar", arg); | ||
4561 | 4584 | | |||
4562 | // Only reset calibration on trouble | 4585 | // Only reset calibration on trouble | ||
▲ Show 20 Lines • Show All 2044 Lines • ▼ Show 20 Line(s) | 6615 | { | |||
6607 | { | 6630 | { | ||
6608 | qCDebug(KSTARS_EKOS_SCHEDULER) << "Calibration & Guide stage..."; | 6631 | qCDebug(KSTARS_EKOS_SCHEDULER) << "Calibration & Guide stage..."; | ||
6609 | 6632 | | |||
6610 | // If calibration stage complete? | 6633 | // If calibration stage complete? | ||
6611 | if (status == Ekos::GUIDE_GUIDING) | 6634 | if (status == Ekos::GUIDE_GUIDING) | ||
6612 | { | 6635 | { | ||
6613 | appendLogText(i18n("Job '%1' guiding is in progress.", currentJob->getName())); | 6636 | appendLogText(i18n("Job '%1' guiding is in progress.", currentJob->getName())); | ||
6614 | guideFailureCount = 0; | 6637 | guideFailureCount = 0; | ||
6638 | // if guiding recovered while we are waiting, abort the restart | ||||
6639 | restartGuidingTimer.stop(); | ||||
6615 | 6640 | | |||
6616 | currentJob->setStage(SchedulerJob::STAGE_GUIDING_COMPLETE); | 6641 | currentJob->setStage(SchedulerJob::STAGE_GUIDING_COMPLETE); | ||
6617 | getNextAction(); | 6642 | getNextAction(); | ||
6618 | } | 6643 | } | ||
6619 | else if (status == Ekos::GUIDE_CALIBRATION_ERROR || | 6644 | else if (status == Ekos::GUIDE_CALIBRATION_ERROR || | ||
6620 | status == Ekos::GUIDE_ABORTED) | 6645 | status == Ekos::GUIDE_ABORTED) | ||
6621 | { | 6646 | { | ||
6622 | if (status == Ekos::GUIDE_ABORTED) | 6647 | if (status == Ekos::GUIDE_ABORTED) | ||
6623 | appendLogText(i18n("Warning: job '%1' guiding failed.", currentJob->getName())); | 6648 | appendLogText(i18n("Warning: job '%1' guiding failed.", currentJob->getName())); | ||
6624 | else | 6649 | else | ||
6625 | appendLogText(i18n("Warning: job '%1' calibration failed.", currentJob->getName())); | 6650 | appendLogText(i18n("Warning: job '%1' calibration failed.", currentJob->getName())); | ||
6626 | 6651 | | |||
6652 | // if the timer for restarting the guiding is already running, we do nothing and | ||||
6653 | // wait for the action triggered by the timer. This way we avoid that a small guiding problem | ||||
6654 | // abort the scheduler job | ||||
6655 | | ||||
6656 | if (restartGuidingTimer.isActive()) | ||||
6657 | return; | ||||
6658 | | ||||
6627 | if (guideFailureCount++ < MAX_FAILURE_ATTEMPTS) | 6659 | if (guideFailureCount++ < MAX_FAILURE_ATTEMPTS) | ||
6628 | { | 6660 | { | ||
6629 | if (status == Ekos::GUIDE_CALIBRATION_ERROR && | 6661 | if (status == Ekos::GUIDE_CALIBRATION_ERROR && | ||
6630 | Options::realignAfterCalibrationFailure()) | 6662 | Options::realignAfterCalibrationFailure()) | ||
6631 | { | 6663 | { | ||
6632 | appendLogText(i18n("Restarting %1 alignment procedure...", currentJob->getName())); | 6664 | appendLogText(i18n("Restarting %1 alignment procedure...", currentJob->getName())); | ||
6633 | // JM: We have to go back to startSlew() since if we just call startAstrometry() | 6665 | // JM: We have to go back to startSlew() since if we just call startAstrometry() | ||
6634 | // It would captureAndSolve at the _current_ coords which could be way off center if the calibration | 6666 | // It would captureAndSolve at the _current_ coords which could be way off center if the calibration | ||
6635 | // process took a wild ride search for a suitable guide star and then failed. So startSlew() would ensure | 6667 | // process took a wild ride search for a suitable guide star and then failed. So startSlew() would ensure | ||
6636 | // we're back on our target and then it proceed to alignment (focus is skipped since it is done if it was checked anyway). | 6668 | // we're back on our target and then it proceed to alignment (focus is skipped since it is done if it was checked anyway). | ||
6637 | startSlew(); | 6669 | startSlew(); | ||
6638 | } | 6670 | } | ||
6639 | else | 6671 | else | ||
6640 | { | 6672 | { | ||
6641 | appendLogText(i18n("Job '%1' is guiding, and is restarting its guiding procedure.", currentJob->getName())); | 6673 | appendLogText(i18n("Job '%1' is guiding, guiding procedure will be restarted in %2 seconds.", currentJob->getName(), (RESTART_GUIDING_DELAY_MS * guideFailureCount)/1000)); | ||
6642 | startGuiding(true); | 6674 | restartGuidingTimer.start(RESTART_GUIDING_DELAY_MS * guideFailureCount); | ||
6643 | } | 6675 | } | ||
6644 | } | 6676 | } | ||
6645 | else | 6677 | else | ||
6646 | { | 6678 | { | ||
6647 | appendLogText(i18n("Warning: job '%1' guiding procedure failed, marking terminated due to errors.", currentJob->getName())); | 6679 | appendLogText(i18n("Warning: job '%1' guiding procedure failed, marking terminated due to errors.", currentJob->getName())); | ||
6648 | currentJob->setState(SchedulerJob::JOB_ERROR); | 6680 | currentJob->setState(SchedulerJob::JOB_ERROR); | ||
6649 | 6681 | | |||
6650 | findNextJob(); | 6682 | findNextJob(); | ||
6651 | } | 6683 | } | ||
6652 | } | 6684 | } | ||
6653 | } | 6685 | } | ||
6654 | } | 6686 | } | ||
6655 | 6687 | | |||
6688 | GuideState Scheduler::getGuidingStatus() | ||||
6689 | { | ||||
6690 | QVariant guideStatus = guideInterface->property("status"); | ||||
6691 | Ekos::GuideState gStatus = static_cast<Ekos::GuideState>(guideStatus.toInt()); | ||||
6692 | | ||||
6693 | return gStatus; | ||||
6694 | } | ||||
6695 | | ||||
6656 | void Scheduler::setCaptureStatus(Ekos::CaptureState status) | 6696 | void Scheduler::setCaptureStatus(Ekos::CaptureState status) | ||
6657 | { | 6697 | { | ||
6658 | if (state == SCHEDULER_PAUSED || currentJob == nullptr) | 6698 | if (state == SCHEDULER_PAUSED || currentJob == nullptr) | ||
6659 | return; | 6699 | return; | ||
6660 | 6700 | | |||
6661 | qCDebug(KSTARS_EKOS_SCHEDULER) << "Capture State" << Ekos::getCaptureStatusString(status); | 6701 | qCDebug(KSTARS_EKOS_SCHEDULER) << "Capture State" << Ekos::getCaptureStatusString(status); | ||
6662 | 6702 | | |||
6663 | /* If current job is scheduled and has not started yet, wait */ | 6703 | /* If current job is scheduled and has not started yet, wait */ | ||
Show All 11 Lines | 6714 | { | |||
6675 | appendLogText(i18n("Warning: job '%1' failed to capture target.", currentJob->getName())); | 6715 | appendLogText(i18n("Warning: job '%1' failed to capture target.", currentJob->getName())); | ||
6676 | 6716 | | |||
6677 | if (captureFailureCount++ < MAX_FAILURE_ATTEMPTS) | 6717 | if (captureFailureCount++ < MAX_FAILURE_ATTEMPTS) | ||
6678 | { | 6718 | { | ||
6679 | // If capture failed due to guiding error, let's try to restart that | 6719 | // If capture failed due to guiding error, let's try to restart that | ||
6680 | if (currentJob->getStepPipeline() & SchedulerJob::USE_GUIDE) | 6720 | if (currentJob->getStepPipeline() & SchedulerJob::USE_GUIDE) | ||
6681 | { | 6721 | { | ||
6682 | // Check if it is guiding related. | 6722 | // Check if it is guiding related. | ||
6683 | QVariant guideStatus = guideInterface->property("status"); | 6723 | Ekos::GuideState gStatus = getGuidingStatus(); | ||
6684 | Ekos::GuideState gStatus = static_cast<Ekos::GuideState>(guideStatus.toInt()); | | |||
6685 | if (gStatus == Ekos::GUIDE_ABORTED || | 6724 | if (gStatus == Ekos::GUIDE_ABORTED || | ||
6686 | gStatus == Ekos::GUIDE_CALIBRATION_ERROR || | 6725 | gStatus == Ekos::GUIDE_CALIBRATION_ERROR || | ||
6687 | gStatus == GUIDE_DITHERING_ERROR) | 6726 | gStatus == GUIDE_DITHERING_ERROR) | ||
6688 | { | 6727 | { | ||
6689 | appendLogText(i18n("Job '%1' is capturing, is restarting its guiding procedure (attempt #%2 of %3).", currentJob->getName(), captureFailureCount, MAX_FAILURE_ATTEMPTS)); | 6728 | appendLogText(i18n("Job '%1' is capturing, is restarting its guiding procedure (attempt #%2 of %3).", currentJob->getName(), captureFailureCount, MAX_FAILURE_ATTEMPTS)); | ||
6690 | startGuiding(true); | 6729 | startGuiding(true); | ||
6691 | return; | 6730 | return; | ||
6692 | } | 6731 | } | ||
▲ Show 20 Lines • Show All 325 Lines • Show Last 20 Lines |