[education/kstars] kstars/ekos: Rename to m_RotatorParityRetried to avoid confusion with rotator own reverse functionality
Jasem Mutlaq <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 5d0543c975045a7661016825abe5315ab6832a7e by Jasem Mutlaq.
Committed on 30/07/2026 at 13:32.
Pushed by mutlaqja into branch 'master'.
Rename to m_RotatorParityRetried to avoid confusion with rotator own reverse functionality
M +4 -2 kstars/ekos/align/align.h
M +12 -3 kstars/ekos/align/align_goto.cpp
M +6 -6 kstars/ekos/align/align_solver.cpp
M +5 -4 kstars/ekos/auxiliary/rotatorutils.cpp
https://invent.kde.org/education/kstars/-/commit/5d0543c975045a7661016825abe5315ab6832a7e
diff --git a/kstars/ekos/align/align.h b/kstars/ekos/align/align.h
index 56ceb6e896..0211118f2f 100644
--- a/kstars/ekos/align/align.h
+++ b/kstars/ekos/align/align.h
@@ -823,8 +823,10 @@ class Align : public QWidget, public Ui::Align
ISD::Mount::PierSide m_PAValidPierSide { ISD::Mount::PIER_UNKNOWN };
/// Previous PA error before the last rotation command (to detect wrong direction)
double m_PreviousPAError { -1 };
- /// Auto-reverse rotator direction attempted for current alignment
- bool m_RotatorAutoReversed { false };
+ /// Whether a software parity-correction retry has already been attempted this alignment
+ /// (limits to one retry, gates persisting the correction, and gates the flip-tolerance
+ /// heuristic in checkIfRotationRequired() from swallowing an in-flight retry).
+ bool m_RotatorParityRetried { false };
/// Solver iterations count
uint8_t solverIterations { 0 };
/// Was solving with scale off used?
diff --git a/kstars/ekos/align/align_goto.cpp b/kstars/ekos/align/align_goto.cpp
index eb213ffd0a..36b0561bc0 100644
--- a/kstars/ekos/align/align_goto.cpp
+++ b/kstars/ekos/align/align_goto.cpp
@@ -60,7 +60,7 @@ void Align::stop(Ekos::AlignState mode)
m_CaptureTimeoutCounter = 0;
m_SlewErrorCounter = 0;
m_PreviousPAError = -1;
- m_RotatorAutoReversed = false;
+ m_RotatorParityRetried = false;
m_RemoteAlignTimer.stop();
disconnect(m_Camera, &ISD::Camera::newImage, this, &Ekos::Align::processData);
@@ -333,6 +333,7 @@ void Align::updateProperty(INDI::Property prop)
appendLogText(i18n("Rotator error detected. Aborting alignment."));
m_RotatorTimer.invalidate();
m_PreviousPAError = -1;
+ m_RotatorParityRetried = false;
setState(ALIGN_FAILED);
Q_EMIT newStatus(state);
solveB->setEnabled(true);
@@ -354,7 +355,7 @@ void Align::updateProperty(INDI::Property prop)
// NOTE: this "reached" signal only means the raw encoder matches the value
// that was *commanded* (computed from the current offset/parity model) — it is
// not confirmed by an actual plate solve. Deliberately do NOT clear
- // m_PreviousPAError/m_RotatorAutoReversed here: doing so would erase the
+ // m_PreviousPAError/m_RotatorParityRetried here: doing so would erase the
// baseline the wrong-direction check in align_solver.cpp needs to compare
// against once the next (real, solve-verified) measurement comes in. Both
// trackers are only cleared once that check has actually run and reached a
@@ -387,6 +388,7 @@ void Align::updateProperty(INDI::Property prop)
{
appendLogText(i18n("Rotator failed to arrive at the requested position angle (Deviation %1 arcmin).", diff));
m_PreviousPAError = -1;
+ m_RotatorParityRetried = false;
setState(ALIGN_FAILED);
Q_EMIT newStatus(state);
solveB->setEnabled(true);
@@ -637,7 +639,13 @@ bool Align::checkIfRotationRequired()
m_TargetPositionAngle = RotatorUtils::Instance()->calcCameraAngle(sRawAngle, true);
RotatorUtils::Instance()->setImagePierside(ISD::Mount::PIER_UNKNOWN); // ... once!
}
- else if (Options::astrometryFlipRotationAllowed())
+ // Skip the flip-tolerance guess while a parity-correction retry is in flight
+ // (m_RotatorParityRetried): a wrong-direction rotator produces the exact same
+ // ~180°-off symptom as a genuine optical flip, but here we've already
+ // determined via a more reliable before/after comparison (align_solver.cpp)
+ // that it's a direction problem, not a flip to preserve. Falling through to
+ // the rotation command below is what the retry actually needs to happen.
+ else if (Options::astrometryFlipRotationAllowed() && !m_RotatorParityRetried)
{
double paDiff = std::abs(KSUtils::rangePA(currentRotatorPA - m_TargetPositionAngle));
if (std::abs(paDiff - 180.0) < ROTATOR_FLIP_TOLERANCE)
@@ -719,6 +727,7 @@ void Align::checkRotatorTimeout()
Options::captureOperationsTimeout()));
m_RotatorTimer.invalidate();
m_PreviousPAError = -1;
+ m_RotatorParityRetried = false;
setState(ALIGN_FAILED);
Q_EMIT newStatus(state);
solveB->setEnabled(true);
diff --git a/kstars/ekos/align/align_solver.cpp b/kstars/ekos/align/align_solver.cpp
index 049109a9cc..a9543c99a6 100644
--- a/kstars/ekos/align/align_solver.cpp
+++ b/kstars/ekos/align/align_solver.cpp
@@ -905,14 +905,14 @@ void Align::solverFinished(double orientation, double ra, double dec, double pix
<< "Previous PA error:" << m_PreviousPAError
<< "New PA error:" << newPAError
<< "Raw angle:" << sRawAngle
- << "Auto-reversed:" << m_RotatorAutoReversed;
+ << "Parity retried:" << m_RotatorParityRetried;
if (newPAError > m_PreviousPAError + 0.5)
{
// First wrong-direction detection: try correcting via the software-only
// per-train parity flag. We never touch the driver's ROTATOR_REVERSE
// switch — that would depend on trusting this specific driver's
// implementation of it.
- if (!m_RotatorAutoReversed)
+ if (!m_RotatorParityRetried)
{
appendLogText(i18n("Rotator is moving in the wrong direction. "
"Automatically compensating rotator direction and retrying..."));
@@ -929,7 +929,7 @@ void Align::solverFinished(double orientation, double ra, double dec, double pix
double correctedOffset = RotatorUtils::Instance()->calcOffsetAngle(sRawAngle, solverPA);
RotatorUtils::Instance()->updateOffset(correctedOffset);
- m_RotatorAutoReversed = true;
+ m_RotatorParityRetried = true;
m_PreviousPAError = -1;
// Re-issue the rotation command with the corrected parity
checkIfRotationRequired();
@@ -948,7 +948,7 @@ void Align::solverFinished(double orientation, double ra, double dec, double pix
RotatorUtils::Instance()->revertParity();
m_TargetPositionAngle = std::numeric_limits<double>::quiet_NaN();
m_PreviousPAError = -1;
- m_RotatorAutoReversed = false;
+ m_RotatorParityRetried = false;
setState(ALIGN_FAILED);
emit newStatus(state);
solveB->setEnabled(true);
@@ -958,12 +958,12 @@ void Align::solverFinished(double orientation, double ra, double dec, double pix
// PA error did not increase — rotation was in the correct direction.
// If this confirms a parity trial, persist it so this train never has to
// rediscover its direction again.
- if (m_RotatorAutoReversed)
+ if (m_RotatorParityRetried)
RotatorUtils::Instance()->commitParity();
// Reset error tracking since the rotation succeeded.
qCDebug(KSTARS_EKOS_ALIGN) << "PA error decreased or unchanged — resetting previous error tracker.";
m_PreviousPAError = -1;
- m_RotatorAutoReversed = false;
+ m_RotatorParityRetried = false;
}
appendLogText(i18n("Camera position angle is %1 degrees.", solverPA));
diff --git a/kstars/ekos/auxiliary/rotatorutils.cpp b/kstars/ekos/auxiliary/rotatorutils.cpp
index c5b0e3499a..71da885d55 100644
--- a/kstars/ekos/auxiliary/rotatorutils.cpp
+++ b/kstars/ekos/auxiliary/rotatorutils.cpp
@@ -193,10 +193,11 @@ bool RotatorUtils::checkImageFlip()
double RotatorUtils::DiffPA(double diff)
{
- if (diff > 180)
- return (360 - diff);
- else
- return diff;
+ // Wrap into (-180,180]. The previous version only unwrapped diff > 180 (e.g. 350 -> 10)
+ // but left diff < -180 untouched, so a raw difference like -340 (current/target PA
+ // straddling the +/-180 boundary, genuinely only 20 degrees apart) was returned as-is,
+ // making callers that do abs(DiffPA(...)) see a bogus ~340 degree deviation instead of 20.
+ return KSUtils::rangePA(diff);
}
void RotatorUtils::initTimeFrame(const double EndAngle)