diff --git a/sequencerd/sequence.cpp b/sequencerd/sequence.cpp index 5f004244..26790e7c 100644 --- a/sequencerd/sequence.cpp +++ b/sequencerd/sequence.cpp @@ -744,9 +744,26 @@ namespace Sequencer { break; } + // Detect a repeat of the same target: same coordinates AND same science offsets + // AND same slit angle as the last target we acquired. (Two list entries can share + // RA/DEC but differ in offset/angle -- e.g. one offset star used to reach several + // science targets -- and those are NOT the same target; they must be fully + // re-acquired.) On a true repeat the telescope was not moved (move_to_target skips + // it), acquisition was already performed, and the science offset was already + // applied, so skip ACAM acquire, fine acquire, and the science re-offset, and let + // the observer continue straight to the exposure. Guiding state is intentionally + // NOT consulted (left to the observer). Use "clearlasttarget" to force re-acquisition. + // + const bool repeat_target = ( !this->target.ra_hms.empty() && + this->target.ra_hms == this->last_acquire_ra_hms && + this->target.dec_dms == this->last_acquire_dec_dms && + this->target.offset_ra == this->last_acquire_offset_ra && + this->target.offset_dec == this->last_acquire_offset_dec && + this->target.slitangle == this->last_acquire_slitangle ); + // If not a calibration target then acquire, first acam then slicecam // - if ( !this->target.iscal ) { + if ( !this->target.iscal && !repeat_target ) { // during acam acquisition, enable slicecam autoexpose to try to get the // exposure time set before fine acquisition starts. @@ -780,18 +797,43 @@ namespace Sequencer { return; } } + + // remember the target we just acquired (coords + science offsets + slit angle) + // so a repeat (GO on the same target) skips re-acquisition + this->last_acquire_ra_hms = this->target.ra_hms; + this->last_acquire_dec_dms = this->target.dec_dms; + this->last_acquire_offset_ra = this->target.offset_ra; + this->last_acquire_offset_dec = this->target.offset_dec; + this->last_acquire_slitangle = this->target.slitangle; + } + + // Repeat of the same target: skip all re-acquisition and just wait for the + // observer to continue (or cancel) before exposing. + if ( !this->target.iscal && repeat_target ) { + this->broadcast.notice( function, "repeat of same target -- skipping re-acquisition" ); + if ( this->wait_for_user()==ABORT ) { + this->broadcast.notice( function, "cancelled" ); + return; + } } if ( !this->target.iscal ) { - // send offsets only on fineacquire, otherwise user needs to fix things - if ( this->is_fineacquire_locked.load() && + // Apply the science (telescope) offset only when NOT a repeat. On a repeat it + // was already applied last time and re-applying would double it (is_fineacquire_locked + // is telemetry-driven and can be stale-true on a repeat). + if ( !repeat_target && this->is_fineacquire_locked.load() && this->target_offset() == ERROR ) { if (this->wait_for_user()==ABORT) { this->broadcast.notice( function, "cancelled" ); return; } } - // ensure slit offset is in "expose" position when needed + // Always set the slit to EXPOSE -- this applies the slit WIDTH from the target + // entry (so a width change for a repeat exposure is honored) and re-asserts the + // EXPOSE offset. On a repeat the offset is unchanged, so the slit does NOT + // translate (it stays at the science position); only the width is (re)applied. + // The VSM_ACQUIRE worker above self-skips on a repeat, so the slit was never + // moved off the science position. try { error |= this->slit_set(Sequencer::VSM_EXPOSE); } @@ -4788,6 +4830,8 @@ namespace Sequencer { // if ( testname == "clearlasttarget" ) { this->last_target=""; + this->last_acquire_ra_hms = mysqlx::string{}; // force a fresh acquisition on the same target + this->last_acquire_dec_dms = mysqlx::string{}; error=NO_ERROR; } else diff --git a/sequencerd/sequence.h b/sequencerd/sequence.h index 6b2e7a6f..db569422 100644 --- a/sequencerd/sequence.h +++ b/sequencerd/sequence.h @@ -449,6 +449,15 @@ namespace Sequencer { std::string last_target; mysqlx::string last_ra_hms; mysqlx::string last_dec_dms; + // Identity of the last target ACQUIRED, used to skip re-acquisition only on a + // true repeat. Includes the science offsets and slit angle: two list entries can + // share RA/DEC but differ in offset/angle (e.g. one offset star -> several science + // targets) -- those are NOT the same target and must be fully re-acquired. + mysqlx::string last_acquire_ra_hms; + mysqlx::string last_acquire_dec_dms; + double last_acquire_offset_ra{0.0}; + double last_acquire_offset_dec{0.0}; + double last_acquire_slitangle{0.0}; std::string tcs_which; ///< configured TCS std::string tcs_name; ///< name of TCS set on tcs initialization and shutdown