[education/kstars] kstars/ekos/guide: Guide: Don't arm the streaming pulse-guard during calibration
Jasem Mutlaq <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 387f9a462f6b2c0e43962cb350c348573d71ec23 by Jasem Mutlaq, on behalf of Andreas R..
Committed on 01/08/2026 at 05:19.
Pushed by mutlaqja into branch 'master'.
Guide: Don't arm the streaming pulse-guard during calibration
# Guide: Don't arm the streaming pulse-guard during calibration
## Summary
In streaming guide mode, calibration on fast / harmonic mounts can fail with
repeated **"Lost track of the guide star"** and aborts, which also starves the
AI Guider's system-identification run (no pulse-response data is collected, so
the harmonic spring model is never fit). This MR fixes the calibration failure
by making the streaming pulse-guard phase-aware.
## Root cause
In streaming mode a single-shot guard (`m_streamingPulseGuard`) discards
incoming frames for the duration of each guide pulse (pulse length + margin) so
that continuously arriving stream frames cannot stack up overlapping correction
pulses. That is correct for closed-loop guiding, but **calibration is caught by
the same gate**.
Calibration is frame-driven: every processed frame runs one `iterate()` that
measures the star's drift from the start point and issues the next pulse. While
the guard is active the frames are dropped, so:
1. the star is no longer tracked as it moves, and
2. the measured drift looks stalled between the frames that do get through.
Calibration then takes its "star barely moved" branch and doubles the pulse
(up to 2×), which flings the star out of the tracking box and aborts with
"Lost track of the guide star". Because calibration never completes cleanly,
the AI sysid protocol never reaches usable pulse-response phases, and the
harmonic model falls back to defaults (`κ = 0`, `PE = 0`).
## Fix
Exclude `GUIDE_CALIBRATING` from the streaming pulse-guard in
`Guide::sendMultiPulse()` and `Guide::sendSinglePulse()`:
```cpp
else if (m_StreamingGuide && followWithCapture == DontCaptureAfterPulses
&& m_State != GUIDE_CALIBRATING)
```
The guard still gates overlapping correction pulses during closed-loop guiding
(its actual purpose). During calibration, frames now keep flowing so the star
stays tracked while it drifts across the field — which is what streaming
calibration already intends (`internalguider` forces `DontCaptureAfterPulses`
in streaming precisely so frames arrive continuously).
## Testing
- Builds clean (`KStarsLib` / `guide.cpp`).
- Behavioural change is limited to the calibration phase in streaming mode;
the guiding-path guard is unchanged.
- Needs on-sky verification of a streaming calibration on a harmonic mount
## Note / follow-up
Calibration now issues roughly one pulse per stream frame. If the calibration
pulse duration exceeds the frame interval, pulses can mildly overlap; since
calibration measures cumulative drift from the start point it is tolerant of
this. If overlap proves significant in practice, a follow-up can keep tracking
frames during the guard while suppressing only the *next pulse* (a larger
change in the guide cycle).
M +10 -2 kstars/ekos/guide/guide.cpp
https://invent.kde.org/education/kstars/-/commit/387f9a462f6b2c0e43962cb350c348573d71ec23
diff --git a/kstars/ekos/guide/guide.cpp b/kstars/ekos/guide/guide.cpp
index 4b150af72a..647e7e138a 100644
--- a/kstars/ekos/guide/guide.cpp
+++ b/kstars/ekos/guide/guide.cpp
@@ -1533,7 +1533,7 @@ bool Guide::sendMultiPulse(GuideDirection ra_dir, int ra_msecs, GuideDirection d
m_PulseTimer.start(delay);
}
- else if (m_StreamingGuide)
+ else if (m_StreamingGuide && m_State != GUIDE_CALIBRATING)
{
// In streaming mode frames keep arriving continuously, so we must gate them
// while the mount is still responding to this pulse. Without this guard every
@@ -1541,6 +1541,12 @@ bool Guide::sendMultiPulse(GuideDirection ra_dir, int ra_msecs, GuideDirection d
// rapid-fire overlapping pulses that produce oscillations.
// The gate duration is the longer of the two pulse lengths plus a small
// propagation margin, floored by the user's guide delay setting.
+ //
+ // Calibration is deliberately excluded: it is frame-driven and must observe the
+ // star move through every pulse to measure the mount response. Discarding frames
+ // during calibration loses star tracking and makes the drift look stalled, which
+ // pushes calibration into its "double the pulse" branch and flings the star out
+ // of the box ("Lost track of the guide star").
auto ms = std::max(ra_msecs, dec_msecs) + 100;
auto delay = std::max(static_cast<int>(guideDelay->value() * 1000), ms);
qCDebug(KSTARS_EKOS_GUIDE) << "Streaming pulse guard started for" << delay << "ms";
@@ -1594,9 +1600,11 @@ bool Guide::sendSinglePulse(GuideDirection dir, int msecs, CaptureAfterPulses fo
m_PulseTimer.start(delay);
}
- else if (m_StreamingGuide && followWithCapture == DontCaptureAfterPulses)
+ else if (m_StreamingGuide && followWithCapture == DontCaptureAfterPulses && m_State != GUIDE_CALIBRATING)
{
// Same pulse-in-flight gate as sendMultiPulse() above — correction pulses only.
+ // Calibration is excluded on purpose (see sendMultiPulse): its per-axis pulses need
+ // continuous frames so the star stays tracked while it drifts across the field.
auto ms = msecs + 100;
auto delay = std::max(static_cast<int>(guideDelay->value() * 1000), ms);
qCDebug(KSTARS_EKOS_GUIDE) << "Streaming pulse guard started for" << delay << "ms (single pulse)";