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
15 changes: 14 additions & 1 deletion camerad/astrocam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2185,6 +2185,20 @@ namespace AstroCam {
logwrite(function, message.str());
#endif

// The flexure compensation can change after the exposure starts, so this
// channel's flexure positions are taken at its end, with SHUTTIME, before
// its readout.
//
{
std::lock_guard<std::mutex> lock( server.live_telemetry_mtx );
auto flex = server.live_telemetry.find( Topic::FLEXURED );
if ( flex != server.live_telemetry.end() ) {
for ( const auto &k : FitsHeaderKeys::FlexureInfoKeys ) {
if ( con.channel == k.chan ) con.expinfo[expbuf].telemkeys.add_json_key( flex->second, k.jkey, k.keyword, k.comment, k.type, EXT, k.chan );
}
}
}

// Wait for any shutter delay before reading out.
//
if ( cam.get_shutter_delay() > 0 ) cam.wait_shutter_delay();
Expand Down Expand Up @@ -2858,7 +2872,6 @@ namespace AstroCam {
add( Topic::SLITD, FitsHeaderKeys::SlitInfoKeys ); // primary
add( Topic::TARGETINFO, FitsHeaderKeys::TargetInfoKeys ); // primary
add( Topic::TCSD, FitsHeaderKeys::TcsInfoKeys ); // primary
add( Topic::FLEXURED, FitsHeaderKeys::FlexureInfoKeys ); // extension
add( Topic::FOCUSD, FitsHeaderKeys::FocusInfoKeys ); // extension
add( Topic::THERMALD, FitsHeaderKeys::ThermalInfoKeys ); // extension

Expand Down
58 changes: 49 additions & 9 deletions sequencerd/sequence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,23 @@ namespace Sequencer {
std::lock_guard<std::mutex> lock(camerad_mtx);
if (jmessage.contains(Key::Camerad::READY)) {
int isready = jmessage[Key::Camerad::READY].get<bool>();
// ready again: the expose command's series has ended, re-apply no more
if ( isready && !this->can_expose.load() ) this->expose_nexp = 0;
this->can_expose.store(isready);
}

// The shutter closing, other than to pause, ends an integration. The
// telescope keeps tracking, so while another sub-exposure of the expose
// command follows, re-apply the flexure compensation.
//
if (jmessage.contains(Key::Camerad::SHUTTEROPEN)) {
bool open = jmessage[Key::Camerad::SHUTTEROPEN].get<bool>();
bool paused = jmessage.contains(Key::Camerad::PAUSED) && jmessage[Key::Camerad::PAUSED].get<bool>();
if ( !open && !paused && this->last_shutteropen && ++this->shutter_closes < this->expose_nexp ) {
std::thread( &Sequencer::Sequence::flexure_set, this ).detach();
}
this->last_shutteropen = open;
}
this->camerad_cv.notify_all();
}
/***** Sequencer::Sequence::handletopic_camerad ****************************/
Expand Down Expand Up @@ -742,7 +757,6 @@ namespace Sequencer {
worker_threads = { { THR_MOVE_TO_TARGET, std::bind(&Sequence::move_to_target, this) },
{ THR_CAMERA_SET, std::bind(&Sequence::camera_set, this) },
{ THR_FOCUS_SET, std::bind(&Sequence::focus_set, this) },
{ THR_FLEXURE_SET, std::bind(&Sequence::flexure_set, this) },
{ THR_CALIB_SET, std::bind(&Sequence::calib_set, this) },
// for CAL targets, slit comes from database, otherwise use VSM acquire position
{ THR_SLIT_SET, std::bind(&Sequence::slit_set, this,
Expand Down Expand Up @@ -840,6 +854,15 @@ namespace Sequencer {
return;
}
}
}

// Set the flexure compensation for the pointing to be exposed, every time,
// however the target was acquired (automatically, by hand, or not at
// all) and after any target offset. Nothing waits for it.
//
std::thread( &Sequencer::Sequence::flexure_set, this ).detach();

if ( !this->target.iscal ) {
// ensure slit offset is in "expose" position when needed
try {
error |= this->slit_set(Sequencer::VSM_EXPOSE);
Expand Down Expand Up @@ -2426,7 +2449,9 @@ namespace Sequencer {
* compensation origin (flexured adds the computed delta to defpos),
* so this is the neutral state; it prevents a previous target's
* compensation from being left applied to every subsequent target.
* @return NO_ERROR
* Runs in a detached thread and nothing waits for it, so it does
* not throw: a failure is reported and the sequence goes on.
* @return ERROR | NO_ERROR
*
*/
long Sequence::flexure_set() {
Expand All @@ -2452,22 +2477,28 @@ namespace Sequencer {
return NO_ERROR;
}

if ( this->cancel_flag.load() ) return NO_ERROR;

// build up list of activate chans
std::ostringstream activechans;
const std::string calname = std::string(this->target.iscal ? this->target.name : "SCIENCE");
const auto &calinfo = this->caltarget.get_info(calname);
for (const auto &[chan,active] : calinfo.channel_active) {
if (active) activechans << " " << chan;
try {
const auto &calinfo = this->caltarget.get_info(calname);
for (const auto &[chan,active] : calinfo.channel_active) {
if (active) activechans << " " << chan;
}
}
catch ( const std::exception &e ) {
this->broadcast.error( function, "setting flexure compensator: "+std::string(e.what()) );
return ERROR;
}

std::ostringstream comp;
comp << FLEXURED_COMPENSATE << activechans.str();

if ( !this->cancel_flag.load() &&
this->flexured.command( comp.str() ) != NO_ERROR ) {
if ( this->flexured.command( comp.str() ) != NO_ERROR ) {
this->broadcast.error( function, "setting flexure compensator" );
this->thread_error_manager.set( THR_FLEXURE_SET );
throw std::runtime_error("setting flexure compensator");
return ERROR;
}

this->is_flexure_default.store(false);
Expand Down Expand Up @@ -2840,6 +2871,12 @@ namespace Sequencer {
return NO_ERROR;
}

// Set the flexure compensation for the pointing now, once camera_set has
// seen the camera ready (the previous exposure may still have been
// integrating). Nothing waits for it.
//
std::thread( &Sequencer::Sequence::flexure_set, this ).detach();

// Start the exposure in a thread...
//
auto start_exposure = std::async(std::launch::async, &Sequence::trigger_exposure, this);
Expand Down Expand Up @@ -2890,6 +2927,9 @@ namespace Sequencer {
//
if ( this->tcs_preauth_time > 0 ) this->notify_tcs_next_target = true; else this->notify_tcs_next_target = false;

this->shutter_closes = 0; // counted per expose command
this->expose_nexp = this->target.nexp;

this->arm_readout_flag = true; // enables the async_listener to look for the readout and clear the EXPOSE bit

this->set_imgtype();
Expand Down
3 changes: 3 additions & 0 deletions sequencerd/sequence.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,8 @@ namespace Sequencer {
std::atomic<bool> is_science_frame_transfer; ///< is frame transfer enabled for science cameras
std::atomic<bool> notify_tcs_next_target; ///< notify TCS of next target when remaining time within TCS_PREAUTH_TIME
std::atomic<bool> arm_readout_flag; ///<
std::atomic<int> shutter_closes{0}; ///< shutter closes since the last expose command
std::atomic<int> expose_nexp{0}; ///< sub-exposures of the last expose command
std::atomic<bool> cancel_flag{false};
std::atomic<bool> is_ontarget{false}; ///< remotely set by the TCS operator to indicate that the target is ready
std::atomic<bool> is_usercontinue{false}; ///< remotely set by the user to continue
Expand Down Expand Up @@ -431,6 +433,7 @@ namespace Sequencer {
std::condition_variable acam_cv;
std::mutex camerad_mtx;
std::condition_variable camerad_cv;
bool last_shutteropen = false; ///< SHUTTEROPEN in camerad's latest report (camerad_mtx)
std::mutex slitd_mtx;
std::condition_variable slitd_cv;
std::mutex tcsd_mtx;
Expand Down
Loading