Kstars

calibrationprocess.cpp
1#include "calibrationprocess.h"
2
3#include "gmath.h"
4#include "ekos_guide_debug.h"
5#include "gmath.h"
6#include "guidelog.h"
7
8#include "Options.h"
9
10namespace Ekos
11{
12
13QString stageString(Ekos::CalibrationProcess::CalibrationStage stage)
14{
15 switch(stage)
16 {
17 case Ekos::CalibrationProcess::CAL_IDLE:
18 return ("CAL_IDLE");
19 case Ekos::CalibrationProcess::CAL_ERROR:
20 return("CAL_ERROR");
21 case Ekos::CalibrationProcess::CAL_CAPTURE_IMAGE:
22 return("CAL_CAPTURE_IMAGE");
23 case Ekos::CalibrationProcess::CAL_SELECT_STAR:
24 return("CAL_SELECT_STAR");
25 case Ekos::CalibrationProcess::CAL_START:
26 return("CAL_START");
27 case Ekos::CalibrationProcess::CAL_RA_INC:
28 return("CAL_RA_INC");
29 case Ekos::CalibrationProcess::CAL_RA_DEC:
30 return("CAL_RA_DEC");
31 case Ekos::CalibrationProcess::CAL_DEC_INC:
32 return("CAL_DEC_INC");
33 case Ekos::CalibrationProcess::CAL_DEC_DEC:
34 return("CAL_DEC_DEC");
35 case Ekos::CalibrationProcess::CAL_BACKLASH:
36 return("CAL_BACKLASH");
37 default:
38 return("???");
39 };
40}
41
42CalibrationProcess::CalibrationProcess(double startX, double startY, bool raOnlyEnabled)
43{
44 calibrationStage = CAL_START;
45 raOnly = raOnlyEnabled;
46 start_x1 = startX;
47 start_y1 = startY;
48}
49
50void CalibrationProcess::useCalibration(Calibration *calibrationPtr)
51{
52 calibration = calibrationPtr;
53 tempCalibration = *calibration;
54}
55
56void CalibrationProcess::startup()
57{
58 calibrationStage = CAL_START;
59}
60
61void CalibrationProcess::setGuideLog(GuideLog *guideLogPtr)
62{
63 guideLog = guideLogPtr;
64}
65
66bool CalibrationProcess::inProgress() const
67{
68 return calibrationStage > CAL_START;
69}
70
71void CalibrationProcess::addCalibrationUpdate(
72 GuideInterface::CalibrationUpdateType type,
73 QString message, double x, double y)
74{
75 updateType = type;
76 calibrationUpdate = message;
77 updateX = x;
78 updateY = y;
79}
80
81void CalibrationProcess::getCalibrationUpdate(
82 GuideInterface::CalibrationUpdateType *type,
83 QString *message, double *x, double *y) const
84{
85 *type = updateType;
86 *message = calibrationUpdate;
87 *x = updateX;
88 *y = updateY;
89}
90
91QString CalibrationProcess::getLogStatus() const
92{
93 return logString;
94}
95
96void CalibrationProcess::addLogStatus(const QString &message)
97{
98 logString = message;
99}
100
101void CalibrationProcess::addPulse(GuideDirection dir, int msecs)
102{
103 pulseDirection = dir;
104 pulseMsecs = msecs;
105}
106
107void CalibrationProcess::getPulse(GuideDirection *dir, int *msecs) const
108{
109 *dir = pulseDirection;
110 *msecs = pulseMsecs;
111}
112
113void CalibrationProcess::addStatus(Ekos::GuideState s)
114{
115 status = s;
116}
117
118Ekos::GuideState CalibrationProcess::getStatus() const
119{
120 return status;
121}
122
123void CalibrationProcess::initializeIteration()
124{
125 axisCalibrationComplete = false;
126
127 logString.clear();
128
129 calibrationUpdate.clear();
130 updateType = GuideInterface::CALIBRATION_MESSAGE_ONLY;
131 updateX = 0;
132 updateY = 0;
133
134 addStatus(Ekos::GUIDE_CALIBRATING);
135
136 pulseDirection = NO_DIR;
137 pulseMsecs = 0;
138}
139
140void CalibrationProcess::iterate(double x, double y)
141{
142 initializeIteration();
143 switch (calibrationStage)
144 {
145 case CAL_START:
146 startState();
147 break;
148 case CAL_RA_INC:
149 raOutState(x, y);
150 break;
151 case CAL_RA_DEC:
152 raInState(x, y);
153 break;
154 case CAL_BACKLASH:
155 decBacklashState(x, y);
156 break;
157 case CAL_DEC_INC:
158 decOutState(x, y);
159 break;
160 case CAL_DEC_DEC:
161 decInState(x, y);
162 break;
163 default:
164 break;
165 }
166}
167
168void CalibrationProcess::startState()
169{
170 maximumSteps = Options::autoModeIterations();
171 turn_back_time = maximumSteps * 7;
172
173 ra_iterations = 0;
174 dec_iterations = 0;
175 backlash_iterations = 0;
176 ra_total_pulse = de_total_pulse = 0;
177
178 addLogStatus(i18n("RA drifting forward..."));
179
180 last_pulse = Options::calibrationPulseDuration();
181
182 addCalibrationUpdate(GuideInterface::RA_OUT, i18n("Guide Star found."), 0, 0);
183
184 qCDebug(KSTARS_EKOS_GUIDE) << "Auto Iteration #" << maximumSteps << "Default pulse:" << last_pulse;
185 qCDebug(KSTARS_EKOS_GUIDE) << "Start X1 " << start_x1 << " Start Y1 " << start_y1;
186
187 last_x = start_x1;
188 last_y = start_x2;
189
190 addPulse(RA_INC_DIR, last_pulse);
191
192 ra_iterations++;
193
194 calibrationStage = CAL_RA_INC;
195 if (guideLog)
196 guideLog->addCalibrationData(RA_INC_DIR, start_x1, start_y1, start_x1, start_y1);
197}
198
199
200void CalibrationProcess::raOutState(double cur_x, double cur_y)
201{
202 addCalibrationUpdate(GuideInterface::RA_OUT, i18n("Calibrating RA Out"),
203 cur_x - start_x1, cur_y - start_y1);
204
205 qCDebug(KSTARS_EKOS_GUIDE) << "Iteration #" << ra_iterations << ": STAR " << cur_x << "," << cur_y;
206 qCDebug(KSTARS_EKOS_GUIDE) << "Iteration " << ra_iterations << " Direction: RA_INC_DIR" << " Duration: "
207 << last_pulse << " ms.";
208
209 if (guideLog)
210 guideLog->addCalibrationData(RA_INC_DIR, cur_x, cur_y, start_x1, start_y1);
211
212 // Must pass at least 1.5 pixels to move on to the next stage.
213 // If we've moved 15 pixels, we can cut short the requested number of iterations.
214 const double xDrift = cur_x - start_x1;
215 const double yDrift = cur_y - start_y1;
216 if (((ra_iterations >= maximumSteps) ||
217 (std::hypot(xDrift, yDrift) > Options::calibrationMaxMove()))
218 && (fabs(xDrift) > 1.5 || fabs(yDrift) > 1.5))
219 {
220 ra_total_pulse += last_pulse;
221 calibrationStage = CAL_RA_DEC;
222
223 end_x1 = cur_x;
224 end_y1 = cur_y;
225
226 last_x = cur_x;
227 last_y = cur_y;
228
229 qCDebug(KSTARS_EKOS_GUIDE) << "End X1 " << end_x1 << " End Y1 " << end_y1;
230
231 // This temporary calibration is just used to help find our way back to the origin.
232 // total_pulse is not used, but valid.
233 tempCalibration.calculate1D(start_x1, start_y1, end_x1, end_y1, ra_total_pulse);
234
235 ra_distance = 0;
236 backlash = 0;
237
238 addPulse(RA_DEC_DIR, last_pulse);
239 ra_iterations++;
240
241 addLogStatus(i18n("RA drifting reverse..."));
242 if (guideLog)
243 guideLog->endCalibrationSection(RA_INC_DIR, tempCalibration.getAngle());
244 }
245 else if (ra_iterations > turn_back_time)
246 {
247 addLogStatus(i18n("Calibration rejected. Star drift is too short. Check for mount, cable, or backlash problems."));
248 calibrationStage = CAL_ERROR;
249 addStatus(Ekos::GUIDE_CALIBRATION_ERROR);
250 addCalibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Failed: Drift too short."));
251 if (guideLog)
252 guideLog->endCalibration(0, 0);
253 }
254 else
255 {
256 // Aggressive pulse in case we're going slow
257 if (fabs(cur_x - last_x) < 0.5 && fabs(cur_y - last_y) < 0.5)
258 {
259 // 200%
260 last_pulse = Options::calibrationPulseDuration() * 2;
261 }
262 else
263 {
264 ra_total_pulse += last_pulse;
265 last_pulse = Options::calibrationPulseDuration();
266 }
267
268 last_x = cur_x;
269 last_y = cur_y;
270
271 addPulse(RA_INC_DIR, last_pulse);
272
273 ra_iterations++;
274 }
275}
276
277void CalibrationProcess::raInState(double cur_x, double cur_y)
278{
279 addCalibrationUpdate(GuideInterface::RA_IN, i18n("Calibrating RA In"),
280 cur_x - start_x1, cur_y - start_y1);
281 qCDebug(KSTARS_EKOS_GUIDE) << "Iteration #" << ra_iterations << ": STAR " << cur_x << "," << cur_y;
282 qCDebug(KSTARS_EKOS_GUIDE) << "Iteration " << ra_iterations << " Direction: RA_DEC_DIR" << " Duration: "
283 << last_pulse << " ms.";
284
285 double driftRA, driftDEC;
286 tempCalibration.computeDrift(GuiderUtils::Vector(cur_x, cur_y, 0), GuiderUtils::Vector(start_x1, start_y1, 0),
287 &driftRA, &driftDEC);
288
289 qCDebug(KSTARS_EKOS_GUIDE) << "Star x pos is " << driftRA << " from original point.";
290
291 if (ra_distance == 0.0)
292 ra_distance = driftRA;
293
294 if (guideLog)
295 guideLog->addCalibrationData(RA_DEC_DIR, cur_x, cur_y, start_x1, start_y1);
296
297 // start point reached... so exit
298 if (driftRA < 1.5)
299 {
300 last_pulse = Options::calibrationPulseDuration();
301 axisCalibrationComplete = true;
302 }
303 // If we'not moving much, try increasing pulse to 200% to clear any backlash
304 // Also increase pulse width if we are going FARTHER and not back to our original position
305 else if ( (fabs(cur_x - last_x) < 0.5 && fabs(cur_y - last_y) < 0.5)
306 || driftRA > ra_distance)
307 {
308 backlash++;
309
310 // Increase pulse to 200% after we tried to fight against backlash 2 times at least
311 if (backlash > 2)
312 last_pulse = Options::calibrationPulseDuration() * 2;
313 else
314 last_pulse = Options::calibrationPulseDuration();
315 }
316 else
317 {
318 //ra_total_pulse += last_pulse;
319 last_pulse = Options::calibrationPulseDuration();
320 backlash = 0;
321 }
322 last_x = cur_x;
323 last_y = cur_y;
324
325 if (axisCalibrationComplete == false)
326 {
327 if (ra_iterations < turn_back_time)
328 {
329 addPulse(RA_DEC_DIR, last_pulse);
330 ra_iterations++;
331 return;
332 }
333
334 calibrationStage = CAL_ERROR;
335 addStatus(Ekos::GUIDE_CALIBRATION_ERROR);
336 addCalibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Failed: couldn't reach start."));
337 addLogStatus(i18np("Guide RA: Scope cannot reach the start point after %1 iteration. Possible mount or "
338 "backlash problems...",
339 "GUIDE_RA: Scope cannot reach the start point after %1 iterations. Possible mount or "
340 "backlash problems...",
341 ra_iterations));
342 return;
343 }
344
345 if (raOnly == false)
346 {
347 if (Options::guideCalibrationBacklash())
348 {
349 calibrationStage = CAL_BACKLASH;
350 last_x = cur_x;
351 last_y = cur_y;
352 start_backlash_x = cur_x;
353 start_backlash_y = cur_y;
354 addPulse(DEC_INC_DIR, Options::calibrationPulseDuration());
355 backlash_iterations++;
356 addLogStatus(i18n("DEC backlash..."));
357 }
358 else
359 {
360 calibrationStage = CAL_DEC_INC;
361 start_x2 = cur_x;
362 start_y2 = cur_y;
363 last_x = cur_x;
364 last_y = cur_y;
365
366 qCDebug(KSTARS_EKOS_GUIDE) << "Start X2 " << start_x2 << " start Y2 " << start_y2;
367 addPulse(DEC_INC_DIR, Options::calibrationPulseDuration());
368 dec_iterations++;
369 addLogStatus(i18n("DEC drifting forward..."));
370 }
371 return;
372 }
373 // calc orientation
374 if (calibration->calculate1D(start_x1, start_y1, end_x1, end_y1, ra_total_pulse))
375 {
376 calibration->save();
377 calibrationStage = CAL_IDLE;
378 addStatus(Ekos::GUIDE_CALIBRATION_SUCCESS);
379 // Below converts from ms/arcsecond to arcseconds/second.
380 if (guideLog)
381 guideLog->endCalibration(1000.0 / calibration->raPulseMillisecondsPerArcsecond(), 0);
382 }
383 else
384 {
385 addLogStatus(i18n("Calibration rejected. Star drift is too short. Check for mount, cable, or backlash problems."));
386 calibrationStage = CAL_ERROR;
387 addStatus(Ekos::GUIDE_CALIBRATION_ERROR);
388 addCalibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Failed: drift too short."));
389 if (guideLog)
390 guideLog->endCalibration(0, 0);
391 }
392}
393
394void CalibrationProcess::decBacklashState(double cur_x, double cur_y)
395{
396 double driftRA, driftDEC;
397 tempCalibration.computeDrift(
398 GuiderUtils::Vector(cur_x, cur_y, 0),
399 GuiderUtils::Vector(start_backlash_x, start_backlash_y, 0),
400 &driftRA, &driftDEC);
401
402 // Exit the backlash phase either after 5 pulses, or after we've moved sufficiently in the
403 // DEC direction.
404 constexpr int MIN_DEC_BACKLASH_MOVE_PIXELS = 3;
405 if ((++backlash_iterations >= 5) ||
406 (fabs(driftDEC) > MIN_DEC_BACKLASH_MOVE_PIXELS))
407 {
408 addCalibrationUpdate(GuideInterface::BACKLASH, i18n("Calibrating DEC Backlash"),
409 cur_x - start_x1, cur_y - start_y1);
410 qCDebug(KSTARS_EKOS_GUIDE) << QString("Stopping dec backlash caibration after %1 iterations, offset %2")
411 .arg(backlash_iterations - 1)
412 .arg(driftDEC, 4, 'f', 2);
413 calibrationStage = CAL_DEC_INC;
414 start_x2 = cur_x;
415 start_y2 = cur_y;
416 last_x = cur_x;
417 last_y = cur_y;
418
419 qCDebug(KSTARS_EKOS_GUIDE) << "Start X2 " << start_x2 << " start Y2 " << start_y2;
420 addPulse(DEC_INC_DIR, Options::calibrationPulseDuration());
421 dec_iterations++;
422 addLogStatus(i18n("DEC drifting forward..."));
423 return;
424 }
425 addCalibrationUpdate(GuideInterface::BACKLASH, i18n("Calibrating DEC Backlash"),
426 cur_x - start_x1, cur_y - start_y1);
427 qCDebug(KSTARS_EKOS_GUIDE) << "Backlash iter" << backlash_iterations << "position" << cur_x << cur_y;
428 addPulse(DEC_INC_DIR, Options::calibrationPulseDuration());
429}
430
431
432void CalibrationProcess::decOutState(double cur_x, double cur_y)
433{
434 addCalibrationUpdate(GuideInterface::DEC_OUT, i18n("Calibrating DEC Out"),
435 cur_x - start_x1, cur_y - start_y1);
436
437 qCDebug(KSTARS_EKOS_GUIDE) << "Iteration #" << dec_iterations << ": STAR " << cur_x << "," << cur_y;
438 qCDebug(KSTARS_EKOS_GUIDE) << "Iteration " << dec_iterations << " Direction: DEC_INC_DIR" <<
439 " Duration: " << last_pulse << " ms.";
440
441 // Don't yet know how to tell NORTH vs SOUTH
442 if (guideLog)
443 guideLog->addCalibrationData(DEC_INC_DIR, cur_x, cur_y,
444 start_x2, start_y2);
445 const double xDrift = cur_x - start_x2;
446 const double yDrift = cur_y - start_y2;
447 if (((dec_iterations >= maximumSteps) ||
448 (std::hypot(xDrift, yDrift) > Options::calibrationMaxMove()))
449 && (fabs(xDrift) > 1.5 || fabs(yDrift) > 1.5))
450 {
451 calibrationStage = CAL_DEC_DEC;
452
453 de_total_pulse += last_pulse;
454
455 end_x2 = cur_x;
456 end_y2 = cur_y;
457
458 last_x = cur_x;
459 last_y = cur_y;
460
461 axisCalibrationComplete = false;
462
463 qCDebug(KSTARS_EKOS_GUIDE) << "End X2 " << end_x2 << " End Y2 " << end_y2;
464
465 tempCalibration.calculate1D(start_x2, start_y2, end_x2, end_y2, de_total_pulse);
466
467 de_distance = 0;
468
469 addPulse(DEC_DEC_DIR, last_pulse);
470 addLogStatus(i18n("DEC drifting reverse..."));
471 dec_iterations++;
472 if (guideLog)
473 guideLog->endCalibrationSection(DEC_INC_DIR, tempCalibration.getAngle());
474 }
475 else if (dec_iterations > turn_back_time)
476 {
477 calibrationStage = CAL_ERROR;
478
479 addStatus(Ekos::GUIDE_CALIBRATION_ERROR);
480 addCalibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Failed: couldn't reach start point."));
481 addLogStatus(i18np("Guide DEC: Scope cannot reach the start point after %1 iteration.\nPossible mount "
482 "or backlash problems...",
483 "GUIDE DEC: Scope cannot reach the start point after %1 iterations.\nPossible mount "
484 "or backlash problems...",
485 dec_iterations));
486
487 if (guideLog)
488 guideLog->endCalibration(0, 0);
489 }
490 else
491 {
492 if (fabs(cur_x - last_x) < 0.5 && fabs(cur_y - last_y) < 0.5)
493 {
494 // Increase pulse by 200%
495 last_pulse = Options::calibrationPulseDuration() * 2;
496 }
497 else
498 {
499 de_total_pulse += last_pulse;
500 last_pulse = Options::calibrationPulseDuration();
501 }
502 last_x = cur_x;
503 last_y = cur_y;
504
505 addPulse(DEC_INC_DIR, last_pulse);
506
507 dec_iterations++;
508 }
509}
510
511void CalibrationProcess::decInState(double cur_x, double cur_y)
512{
513 addCalibrationUpdate(GuideInterface::DEC_IN, i18n("Calibrating DEC In"),
514 cur_x - start_x1, cur_y - start_y1);
515
516 // Star position resulting from LAST guiding pulse to mount
517 qCDebug(KSTARS_EKOS_GUIDE) << "Iteration #" << dec_iterations << ": STAR " << cur_x << "," << cur_y;
518 qCDebug(KSTARS_EKOS_GUIDE) << "Iteration " << dec_iterations << " Direction: DEC_DEC_DIR" <<
519 " Duration: " << last_pulse << " ms.";
520
521 // Note: the way this temp calibration was set up above, with the DEC drifts, the ra axis is really dec.
522 // This will help the dec find its way home. Could convert to a full RA/DEC calibration.
523 double driftRA, driftDEC;
524 tempCalibration.computeDrift(
525 GuiderUtils::Vector(cur_x, cur_y, 0),
526 GuiderUtils::Vector(start_x1, start_y1, 0),
527 &driftRA, &driftDEC);
528
529 qCDebug(KSTARS_EKOS_GUIDE) << "Currently " << driftRA << driftDEC << " from original point.";
530
531 // Keep track of distance
532 if (de_distance == 0.0)
533 de_distance = driftRA;
534
535 if (guideLog)
536 guideLog->addCalibrationData(DEC_DEC_DIR, cur_x, cur_y, start_x2, start_y2);
537
538 // start point reached... so exit
539 if (driftRA < 1.5)
540 {
541 last_pulse = Options::calibrationPulseDuration();
542 axisCalibrationComplete = true;
543 }
544 // Increase pulse if we're not moving much or if we are moving _away_ from target.
545 else if ( (fabs(cur_x - last_x) < 0.5 && fabs(cur_y - last_y) < 0.5)
546 || driftRA > de_distance)
547 {
548 // Increase pulse by 200%
549 last_pulse = Options::calibrationPulseDuration() * 2;
550 }
551 else
552 {
553 last_pulse = Options::calibrationPulseDuration();
554 }
555
556 if (axisCalibrationComplete == false)
557 {
558 if (dec_iterations < turn_back_time)
559 {
560 addPulse(DEC_DEC_DIR, last_pulse);
561 dec_iterations++;
562 return;
563 }
564
565 calibrationStage = CAL_ERROR;
566
567 addStatus(Ekos::GUIDE_CALIBRATION_ERROR);
568 addCalibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Failed: couldn't reach start point."));
569
570 addLogStatus(i18np("Guide DEC: Scope cannot reach the start point after %1 iteration.\nPossible mount "
571 "or backlash problems...",
572 "Guide DEC: Scope cannot reach the start point after %1 iterations.\nPossible mount "
573 "or backlash problems...",
574 dec_iterations));
575 return;
576 }
577
578 bool swap_dec = false;
579 // calc orientation
580 if (calibration->calculate2D(start_x1, start_y1, end_x1, end_y1, start_x2, start_y2, end_x2, end_y2,
581 &swap_dec, ra_total_pulse, de_total_pulse))
582 {
583 calibration->save();
584 calibrationStage = CAL_IDLE;
585 if (swap_dec)
586 addLogStatus(i18n("DEC swap enabled."));
587 else
588 addLogStatus(i18n("DEC swap disabled."));
589
590 addStatus(Ekos::GUIDE_CALIBRATION_SUCCESS);
591
592 addCalibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Successful"));
593
594 // Below converts from ms/arcsecond to arcseconds/second.
595 if (guideLog)
596 guideLog->endCalibration(
597 1000.0 / calibration->raPulseMillisecondsPerArcsecond(),
598 1000.0 / calibration->decPulseMillisecondsPerArcsecond());
599 return;
600 }
601 else
602 {
603 addLogStatus(i18n("Calibration rejected. Star drift is too short. Check for mount, cable, or backlash problems."));
604 addCalibrationUpdate(GuideInterface::CALIBRATION_MESSAGE_ONLY, i18n("Calibration Failed: drift too short."));
605 addStatus(Ekos::GUIDE_CALIBRATION_ERROR);
606 calibrationStage = CAL_ERROR;
607 if (guideLog)
608 guideLog->endCalibration(0, 0);
609 return;
610 }
611}
612
613} // namespace Ekos
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:83
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
KIOCORE_EXPORT QString dir(const QString &fileClass)
QString arg(Args &&... args) const const
void clear()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Dec 27 2024 11:51:45 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.