Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions slicecamd/slicecam_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ namespace Slicecam {

// start the state machine
this->fineacquire_state.reset();
this->fineacq_total_dra = 0.0; // reset per-run ACAM->slit residual accumulators
this->fineacq_total_ddec = 0.0;

// snapshot this run's goal (DB target) coords from the TARGETINFO published message; NAN if no target
// has been published (manual runs log nan). Frozen for the run via the is_fineacquire_running handoff.
this->fineacq_goal_ra = this->targetinfo_ra_deg.load();
this->fineacq_goal_dec = this->targetinfo_dec_deg.load();

this->is_fineacquire_locked.store(false, std::memory_order_release);
this->is_fineacquire_running.store(true, std::memory_order_release);
this->is_autoexpose_running.store(false, std::memory_order_release); // fineacquire supersedes auto-exposure
Expand Down Expand Up @@ -461,6 +469,25 @@ namespace Slicecam {
<< " scatter=(" << sig_dra << "," << sig_ddec << ") arcsec)"
<< " goal=" << this->fineacquire_state.goal_arcsec << " arcsec";
logwrite( function, oss.str() );

// One structured per-run line for building an ACAM->slit geometric (flexure) model
// over time. fineacq_total_{dra,ddec} is the total correction applied this run = the
// ACAM->slit residual that acam-acquire left behind. We log it against the GOAL
// (database target) coordinates -- the INPUT to the SCOPE->ACAM transform -- plus the
// cassegrain angle. Altitude/hour-angle are derived offline from GOALRA/GOALDEC + this
// line's timestamp. We deliberately do NOT log the telescope's actual RA/DEC: that is
// the transform's OUTPUT and drifts as fine-acquire applies offsets, so it cannot be
// used to fit the geometry.
std::ostringstream acqmodel;
acqmodel << "[ACQMODEL] acam2slit dRA=" << this->fineacq_total_dra
<< " dDEC=" << this->fineacq_total_ddec << " arcsec"
<< " GOALRA=" << this->fineacq_goal_ra
<< " GOALDEC=" << this->fineacq_goal_dec
<< " CASANGLE=" << this->telem.angle_scope
<< " n=" << n
<< " cam=" << which;
logwrite( function, acqmodel.str() );

this->is_fineacquire_locked.store( true, std::memory_order_release );
this->is_fineacquire_running.store( false, std::memory_order_release );
this->fineacquire_state.reset();
Expand Down Expand Up @@ -542,6 +569,11 @@ namespace Slicecam {
return;
}

// accumulate the applied correction (arcsec). Summed over the run this is the
// total ACAM->slit residual that acam-acquire left behind (the [ACQMODEL] line).
this->fineacq_total_dra += cmd_dra * 3600.0;
this->fineacq_total_ddec += cmd_ddec * 3600.0;

// reset samples and discard settle_count frames for telescope settling
this->fineacquire_state.reset();
this->fineacquire_state.settle_frames = this->fineacquire_state.settle_count;
Expand Down Expand Up @@ -960,6 +992,32 @@ namespace Slicecam {
/***** Slicecam::Interface::handletopic_tcsd ********************************/


/***** Slicecam::Interface::handletopic_targetinfo **************************/
/**
* @brief what to do when the topic is Topic::TARGETINFO
* @details This receives target RA/DEC and stores them in the class
* as decimal degrees.
* @param[in] jmessage_in subscribed-received JSON message
*
*/
void Interface::handletopic_targetinfo( const nlohmann::json &jmessage ) {
std::string ra_hms, dec_dms;

Common::extract_telemetry_value( jmessage, Key::TargetInfo::RA, ra_hms );
Common::extract_telemetry_value( jmessage, Key::TargetInfo::DECL, dec_dms );

try {
this->targetinfo_ra_deg.store( radec_to_decimal( ra_hms ) * TO_DEGREES );
this->targetinfo_dec_deg.store( radec_to_decimal( dec_dms ) );
}
catch( const std::exception &e ) {
this->targetinfo_ra_deg.store(NAN);
this->targetinfo_dec_deg.store(NAN);
}
}
/***** Slicecam::Interface::handletopic_targetinfo **************************/


/***** Slicecam::Interface::publish_status **********************************/
/**
* @brief publishes my important status on change
Expand Down Expand Up @@ -2187,6 +2245,7 @@ namespace Slicecam {

this->is_fineacquire_running.store( false, std::memory_order_release );
this->is_fineacquire_locked.store( false, std::memory_order_release );

this->publish_status();
this->cv.notify_all(); // send notification that the loop has stopped

Expand Down
20 changes: 19 additions & 1 deletion slicecamd/slicecam_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,15 @@ namespace Slicecam {

FineAcqState fineacquire_state;

// Per-run accumulators for the ACAM->slit residual, summed over a fine-acquire
// run and logged once at lock (the [ACQMODEL] line) to build a flexure model of
// the ACAM->slit pointing offset vs geometry over time. Touched only from the
// single framegrab thread, so plain doubles are sufficient.
double fineacq_total_dra = 0.0; ///< sum of applied dRA corrections this run [arcsec]
double fineacq_total_ddec = 0.0; ///< sum of applied dDEC corrections this run [arcsec]
double fineacq_goal_ra = NAN; ///< per-run snapshot of goal RA [deg], taken at fineacquire start, logged at lock
double fineacq_goal_dec = NAN; ///< per-run snapshot of goal DEC [deg], taken at fineacquire start, logged at lock

/// per-frame auto-exposure runtime (ACAM-window pre-tuning). Brightness is
/// sampled over a window of frames; a high percentile (near-max) is used
/// because telescope motion only smears light out (lowering brightness),
Expand Down Expand Up @@ -184,6 +193,12 @@ namespace Slicecam {

std::atomic<int64_t> last_acam_pubtime{0}; ///< pubtime (us) of latest received acamd status

// Latest target (goal) coords published on Topic::TARGETINFO
// NAN until a TARGETINFO arrives, so manual runs with no sequencer target log nan.
//
std::atomic<double> targetinfo_ra_deg{NAN}; ///< latest goal RA [deg] from TARGETINFO
std::atomic<double> targetinfo_dec_deg{NAN}; ///< latest goal DEC [deg] from TARGETINFO

/// Max acceptable age (us) for cached ACAM status used by fineacquire.
static constexpr int64_t ACAM_STATUS_MAX_AGE_US = 10'000'000;

Expand Down Expand Up @@ -258,7 +273,9 @@ namespace Slicecam {
{ Topic::TCSD, std::function<void(const nlohmann::json&)>(
[this](const nlohmann::json &msg) { handletopic_tcsd(msg); } ) },
{ Topic::SLITD, std::function<void(const nlohmann::json&)>(
[this](const nlohmann::json &msg) { handletopic_slitd(msg); } ) }
[this](const nlohmann::json &msg) { handletopic_slitd(msg); } ) },
{ Topic::TARGETINFO, std::function<void(const nlohmann::json&)>(
[this](const nlohmann::json &msg) { handletopic_targetinfo(msg); } ) }
};
}

Expand Down Expand Up @@ -298,6 +315,7 @@ namespace Slicecam {
void handletopic_acamd( const nlohmann::json &jmessage );
void handletopic_slitd( const nlohmann::json &jmessage );
void handletopic_tcsd( const nlohmann::json &jmessage );
void handletopic_targetinfo( const nlohmann::json &jmessage );
void publish_status(bool force=false);
void publish_snapshot();
void publish_temperature(); ///< publish only the andor temperatures on Topic::SLICECAMD (periodic)
Expand Down
3 changes: 2 additions & 1 deletion slicecamd/slicecamd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ int main(int argc, char **argv) {
//
if ( slicecamd.interface.init_pubsub( { Topic::SLITD,
Topic::ACAMD,
Topic::TCSD }) == ERROR ) {
Topic::TCSD,
Topic::TARGETINFO }) == ERROR ) {
logwrite(function, "ERROR initializing publisher-subscriber handler");
slicecamd.exit_cleanly();
}
Expand Down
Loading