This commit is contained in:
2025-07-23 19:44:05 +03:00
parent 14f3bb7a83
commit fd67d04ca2
8 changed files with 423 additions and 163 deletions

View File

@@ -19,7 +19,10 @@ enum class MccSimpleGuidingModelErrorCode : int {
ERROR_ASTROM_COMP,
ERROR_TELEMETRY_DATA,
ERROR_PEC_COMP,
ERROR_HARDWARE_SETPOS,
ERROR_INVALID_CONTEXT_PARAM,
ERROR_INVALID_THRESH,
ERROR_INVALID_CORR_RANGE,
};
} // namespace mcc
@@ -56,12 +59,22 @@ struct MccSimpleGuidingModelCategory : public std::error_category {
switch (err) {
case MccSimpleGuidingModelErrorCode::ERROR_OK:
return "OK";
case MccSimpleGuidingModelErrorCode::ERROR_UNSUPPORTED_COORD_PAIR:
return "slew model: unsupported coordinate pair";
case MccSimpleGuidingModelErrorCode::ERROR_ASTROM_COMP:
return "guiding model: cannot perform astrometrical computations";
case MccSimpleGuidingModelErrorCode::ERROR_TELEMETRY_DATA:
return "guiding model: cannot get telemetry data";
case MccSimpleGuidingModelErrorCode::ERROR_PEC_COMP:
return "guiding model: cannot compute PEC corrections";
case MccSimpleGuidingModelErrorCode::ERROR_HARDWARE_SETPOS:
return "guiding model: cannot set position";
case MccSimpleGuidingModelErrorCode::ERROR_INVALID_CONTEXT_PARAM:
return "guiding model: invalid context parameter";
case MccSimpleGuidingModelErrorCode::ERROR_INVALID_THRESH:
return "guiding model: invalid guiding residual threshold";
case MccSimpleGuidingModelErrorCode::ERROR_INVALID_CORR_RANGE:
return "guiding model: invalid guiding correction range";
default:
return "UNKNOWN";
}
@@ -123,34 +136,38 @@ public:
typedef std::error_code error_t;
struct guiding_context_t {
double corrThresh{MccAngle("00:00:00.2"_dms)}; // correction threshold
double corrThresh{MccAngle("00:00:00.2"_dms)}; // correction threshold
double correctionRange[2]{MccAngle("00:00:00.5"_dms), MccAngle("00:00:05"_dms)};
std::chrono::duration<double> predictedTrackDuration{10.0}; // 10 seconds
std::chrono::duration<double> predictedTrackResolution{0.1}; // 0.1 seconds
};
struct guiding_point_t {
typedef double coord_t;
typedef MccCelestialPoint guiding_point_t;
mcc::MccCoordPairKind coordPairKind{mcc::MccCoordPairKind::COORDS_KIND_RADEC_ICRS};
// struct guiding_point_t {
// typedef double coord_t;
coord_t x, y;
};
// mcc::MccCoordPairKind coordPairKind{mcc::MccCoordPairKind::COORDS_KIND_RADEC_ICRS};
// coord_t x, y;
// };
template <traits::mcc_mount_controls_c MOUNT_CONTROLS_T, typename... LoggerCtorArgTs>
MccSimpleGuidingModel(MOUNT_CONTROLS_T& mount_controls, LoggerCtorArgTs&&... ctor_args)
MccSimpleGuidingModel(MOUNT_CONTROLS_T& mount_controls, guiding_context_t context, LoggerCtorArgTs&&... ctor_args)
requires(!std::same_as<LoggerT, MccNullLogger>)
: LoggerT(std::forward<LoggerCtorArgTs>(ctor_args)...)
{
logDebug(std::format("Create 'MccSimpleGuidingModel' class instance ({})", (void*)this));
init(mount_controls);
init(mount_controls, std::move(context));
}
template <traits::mcc_mount_controls_c MOUNT_CONTROLS_T>
MccSimpleGuidingModel(MOUNT_CONTROLS_T& mount_controls)
MccSimpleGuidingModel(MOUNT_CONTROLS_T& mount_controls, guiding_context_t context)
requires(std::same_as<LoggerT, MccNullLogger>)
{
init(mount_controls);
init(mount_controls, std::move(context));
}
virtual ~MccSimpleGuidingModel()
@@ -159,7 +176,20 @@ public:
}
error_t guiding(guiding_point_t guiding_point) {}
error_t guiding(guiding_point_t guiding_point)
{
return _guidingFunc(std::move(guiding_point));
}
error_t stopGuiding(bool off)
{
_doCorrection = off;
}
bool inGuiding()
{
return _doCorrection;
}
protected:
std::function<error_t()> _guidingFunc{};
@@ -182,10 +212,63 @@ protected:
return MccSimpleGuidingModelErrorCode::ERROR_INVALID_CONTEXT_PARAM;
}
auto resi_thresh2 = context.corrThresh * context.corrThresh;
if (utils::isEqual(resi_thresh2, 0.0)) {
return MccSimpleGuidingModelErrorCode::ERROR_INVALID_THRESH;
}
const auto p_mount_controls = &mount_controls;
_guidingFunc = [p_mount_controls, context = std::move(context), predicted_Npoints](
auto check_zones = [p_mount_controls, this]() {
return [this]<size_t... Is>(std::index_sequence<Is...>) {
error_t ret;
(
[&ret]() {
if constexpr (Is > 0) {
if (ret) {
return;
}
}
typename telemetry_t::mount_telemetry_data_t tdata;
auto tel_err = p_mount_controls->telemetry.data(tdata);
if (tel_err) {
if constexpr (std::same_as<decltype(tel_err), error_t>) {
ret = tel_err;
} else {
ret = MccSimpleGuidingModelErrorCode::ERROR_TELEMETRY_DATA;
}
} else {
ret = std::get<Is>(p_mount_controls->prohibitedZones).inZone(tdata)
? MccSimpleGuidingModelErrorCode::ERROR_IN_PROHIBITED_ZONE
: MccSimpleGuidingModelErrorCode::ERROR_OK;
if (ret) {
auto log_str = std::format("given coordinates are in prohibited zone '{}'",
std::get<Is>(p_mount_controls->prohibitedZones).name());
logError(log_str);
}
}
}(),
...);
return ret;
}(std::make_index_sequence<Nzones>{});
};
_guidingFunc = [p_mount_controls, context = std::move(context), predicted_Npoints, this](
this auto&& self, guiding_point_t guiding_point) {
if (context.correctionRange[0] >= context.correctionRange[1]) {
return MccSimpleGuidingModelErrorCode::ERROR_INVALID_THRESH;
}
auto low_corr_limit = context.correctionRange[0] * context.correctionRange[0];
auto high_corr_limit = context.correctionRange[1] * context.correctionRange[1];
auto& astrom_engine = p_mount_controls->astrometryEngine;
auto& hardware = p_mount_controls->hardware;
auto& pec = p_mount_controls->PEC;
@@ -196,8 +279,6 @@ protected:
jd_t jd;
typename hardware_t::axes_pos_t ax_pos;
error_t res_err;
typename astrom_engine_t::error_t ast_err;
typename pec_t::error_t pec_err;
@@ -297,7 +378,7 @@ protected:
}
if (guiding_point.coordPairKind != mcc::MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
ast_err = astrom_engine.greg2jul(std::chrono::system_clock::now(), jd);
ast_err = astrom_engine.greg2jul(astrom_engine_t::timePointNow(), jd);
if (!ast_err) {
ast_err = astrom_engine.obs2icrs(guiding_point.coordPairKind, guiding_point.x, guiding_point.y, jd,
ra_icrs, dec_icrs);
@@ -321,11 +402,33 @@ protected:
coord_t ha, ra_app, dec_app, az, alt, eo;
coord_t xr, yr, coord_diff;
typename hardware_t::axes_pos_t ax_pos;
while (true) {
// check prohibited zones ...
ast_err = astrom_engine.greg2jul(std::chrono::system_clock::now(), jd);
ast_err = astrom_engine.icrs2obs(ra_icrs, dec_icrs, jd, ra_app, dec_app, ha, az, alt, eo);
if ((res_err = check_zones())) {
return res_err;
}
ast_err = astrom_engine.greg2jul(astrom_engine_t::timePointNow(), jd);
if (!ast_err) {
ast_err = astrom_engine.icrs2obs(ra_icrs, dec_icrs, jd, ra_app, dec_app, ha, az, alt, eo);
}
if (ast_err) {
if constexpr (std::same_as<decltype(ast_err), error_t>) {
logError(
std::format("An error occured while performing astrometry computations: code = {} ({})",
ast_err.value(), ast_err.message()));
return ast_err;
} else {
if constexpr (traits::mcc_formattable<decltype(ast_err)>) {
logError(std::format("An error occured while performing astrometry computations: code = {}",
ast_err));
}
return MccSimpleGuidingModelErrorCode::ERROR_ASTROM_COMP;
}
}
t_err = telemetry.data(t_data);
if (t_err) {
@@ -342,6 +445,50 @@ protected:
}
// compare t_data with computed coordinates ...
if (_doCorrection) {
if constexpr (mccIsEquatorialMount(pec_t::mountType)) {
xr = t_data.mntHA - ha;
yr = t_data.mntDEC - dec_app;
} else if constexpr (mccIsAltAzMount(pec_t::mountType)) {
xr = t_data.mntAZ - az;
yr = t_data.mntALT - alt;
} else {
static_assert(false, "UNSUPPORTED MOUNT TYPE!");
}
coord_diff = xr * xr + yr * yr;
if (coord_diff < low_corr_limit) {
continue;
}
if (coord_diff > high_corr_limit) {
logWarn(std::format(
"guiding model: the 'mount-target' difference exceeds the limit (diff = {}; lim = {})",
(double)coord_diff, (double)high_corr_limit));
continue;
}
// do correction
ax_pos.state = hardware_t::hw_state_t::HW_STATE_TRACK;
ax_pos.x = t_data.mntPosX;
ax_pos.y = t_data.mntPosY;
// asynchronous operation!
auto err = hardware.setPos(std::move(ax_pos));
if (err) {
if constexpr (std::same_as<decltype(err), error_t>) {
logError(
std::format("An hardware error occured: code = {} ({})", err.value(), err.message()));
return err;
} else {
if constexpr (traits::mcc_formattable<decltype(err)>) {
logError(std::format("An hardware error occured: code = {}", err));
}
return MccSimpleGuidingModelErrorCode::ERROR_HARDWARE_SETPOS;
}
}
}
}
return MccSimpleGuidingModelErrorCode::ERROR_OK;