This commit is contained in:
Timur A. Fatkhullin 2025-07-19 19:52:30 +03:00
parent 464c262e08
commit 9cd52267d6
11 changed files with 628 additions and 58 deletions

View File

@ -134,7 +134,10 @@ target_include_directories(${MCC_LIBRARY} INTERFACE ${FITPACK_INCLUDE_DIR})
set(ASIBFM700_LIB_SRC asibfm700_hardware.h asibfm700_hardware.cpp)
set(ASIBFM700_LIB asibfm700)
add_library(${ASIBFM700_LIB} STATIC ${ASIBFM700_LIB_SRC})
add_library(${ASIBFM700_LIB} STATIC ${ASIBFM700_LIB_SRC}
asibfm700_slew_model.h asibfm700_slew_model.cpp
asibfm700_common.h)
target_include_directories(${ASIBFM700_LIB} PRIVATE ${FITPACK_INCLUDE_DIR})
# set(MOUNT_SERVER_APP_SRC mount.h mount_state.h mount_server.cpp comm_server.h comm_server_endpoint.h comm_server_configfile.h mount_astrom.h
# mount_astrom_default.h mcc_coord.h mount_pz.h mcc_fsm.h mcc_fsm_utils.h mcc_finite_state_machine.h mcc_mount_events_states.h)

45
cxx/asibfm700_common.h Normal file
View File

@ -0,0 +1,45 @@
#pragma once
/* AstroSIB-FM700 FORK MOUNT CONTROL LIBRARY */
/* COMMON DEFINITIONS */
#include "mcc_mount_astro_erfa.h"
#include "mcc_mount_pec.h"
#include "mcc_mount_telemetry.h"
#include "asibfm700_hardware.h"
namespace asibfm700
{
typedef mcc::astrom::erfa::MccMountAstromEngineERFA<mcc::MccAngle> AsibFM700AstromEngine;
typedef mcc::MccMountDefaultPEC<mcc::MccMountType::FORK_TYPE> AsibFM700PointingErrorCorrection;
struct AsibFM700TelemetryData : mcc::MccMountTelemetryData<AsibFM700AstromEngine, AsibFM700PointingErrorCorrection> {
// apparent target (user-input) current coordinates
coord_t tagRA, tagDEC;
coord_t tagHA;
coord_t tagAZ, tagALT;
coord_t tagPA;
};
typedef mcc::MccMountTelemetry<AsibFM700AstromEngine,
AsibFM700PointingErrorCorrection,
AsibFM700Hardware,
AsibFM700TelemetryData>
AsibFM700Telemetry;
// global mount configuration
struct AsibFM700Config {
std::chrono::milliseconds hardwareAskingPeriod{100}; // main cycle period
// mount hardware config
AsibFM700Hardware::hardware_config_t hardwareConfig;
};
} // namespace asibfm700

View File

@ -93,7 +93,8 @@ std::string_view AsibFM700Hardware::id() const
AsibFM700Hardware::error_t AsibFM700Hardware::setPos(AsibFM700Hardware::axes_pos_t pos)
{
double X = pos.x, Y = pos.y;
// according to hardware configuration (encoders pins (Eddy said)) X is DEC-axis and Y is HA-axis
double X = pos.y, Y = pos.x;
auto err = static_cast<AsibFM700HardwareErrorCode>(Mount.moveTo(&X, &Y));
return err;
@ -115,8 +116,9 @@ AsibFM700Hardware::error_t AsibFM700Hardware::getPos(AsibFM700Hardware::axes_pos
pos.time_point = time_point_t{std::chrono::duration_cast<time_point_t::duration>(secs)};
pos.x = data.encposition.X;
pos.y = data.encposition.Y;
// according to hardware configuration (encoders pins (Eddy said)) X is DEC-axis and Y is HA-axis
pos.x = data.encposition.Y;
pos.y = data.encposition.X;
}
return err;

View File

@ -71,20 +71,6 @@ public:
coord_t x, y;
};
// c++ish wrapper to 'conf_t' struct
struct device_config_t {
std::string MountDevPath; // path to mount device
int MountDevSpeed; // serial speed
std::string EncoderDevPath; // path to encoder device
int EncoderDevSpeed; // serial speed
int SepEncoder; // ==1 if encoder works as separate serial device, ==2 if there's new version with two devices
std::string EncoderXDevPath; // paths to new controller devices
std::string EncoderYDevPath;
double MountReqInterval; // interval between subsequent mount requests (seconds)
double EncoderReqInterval; // interval between subsequent encoder requests (seconds)
};
struct hardware_config_t {
// the 'char*' fields from conf_t:
@ -113,6 +99,7 @@ public:
error_t setPos(axes_pos_t);
error_t getPos(axes_pos_t&);
error_t stop();
error_t init();

View File

@ -0,0 +1,110 @@
#include "asibfm700_slew_model.h"
namespace asibfm700
{
/* error category implementation */
const char* AsibFM700SlewModelErrorCategory::name() const noexcept
{
return "ASTROSIB FM700 MOUNT SLEW MODEL ERROR CATEGORY";
}
std::string AsibFM700SlewModelErrorCategory::message(int ec) const
{
AsibFM700SlewModelErrorCode code = static_cast<AsibFM700SlewModelErrorCode>(ec);
std::string msg;
switch (code) {
case AsibFM700SlewModelErrorCode::ERROR_OK:
msg = "OK";
default:
msg = "UNKNOWN ERROR";
}
return msg;
}
const AsibFM700SlewModelErrorCategory& AsibFM700SlewModelErrorCategory::get()
{
static const AsibFM700SlewModelErrorCategory constInst;
return constInst;
}
AsibFM700SlewModel::AsibFM700SlewModel(AsibFM700Hardware& hw_control, AsibFM700AstromEngine& astrom_engine)
: _hwControl(hw_control), _astromEngine(astrom_engine)
{
}
AsibFM700SlewModel::error_t AsibFM700SlewModel::slew(const slew_params_t& slew_pars, AsibFM700Telemetry& telemetry)
{
using astrom_t = std::remove_reference_t<decltype(_astromEngine)>;
using coord_t = typename astrom_t::coord_t;
using jd_t = typename astrom_t::juldate_t;
AsibFM700SlewModel::error_t res_err = AsibFM700SlewModelErrorCode::ERROR_OK;
AsibFM700Hardware::axes_pos_t ax_pos;
if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_XY) {
// trivial case (the pair is interpretated as raw encoder coordinates)
ax_pos.x = slew_pars.x;
ax_pos.y = slew_pars.y;
} else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // catalog coordinates
jd_t jd;
coord_t ra_app, dec_app, ha, az, alt;
typename astrom_t::eo_t eo;
auto err = _astromEngine.greg2jul(std::chrono::system_clock::now(), jd);
if (!err) {
err = _astromEngine.icrs2obs(slew_pars.x, slew_pars.y, jd, ra_app, dec_app, ha, az, alt, eo);
if (!err) {
res_err = slew({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP,
.x = ha,
.y = dec_app,
.stop = slew_pars.stop},
telemetry);
}
}
} else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_RADEC_APP) { // apparent
jd_t jd;
typename astrom_t::eo_t eo;
auto err = _astromEngine.greg2jul(std::chrono::system_clock::now(), jd);
if (!err) {
typename astrom_t::sideral_time_t lst;
err = _astromEngine.apparentSiderTime(jd, lst, true);
if (!err) {
err = _astromEngine.eqOrigins(jd, eo);
if (!err) {
res_err = slew({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP,
.x = lst - slew_pars.x + eo, // HA = LST - RA_APP + EO
.y = slew_pars.y,
.stop = slew_pars.stop},
telemetry);
}
}
}
} else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP) { // apparent
// compute encoders coordinates
} else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_AZALT) {
} else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_AZZD) {
}
auto err = _hwControl.setPos(std::move(ax_pos));
while (true) {
}
return res_err;
}
} // namespace asibfm700

View File

@ -0,0 +1,75 @@
#pragma once
/* AstroSIB-FM700 FORK MOUNT CONTROL LIBRARY */
/* SLEW MODEL IMPLEMENTATION */
#include "asibfm700_common.h"
namespace asibfm700
{
enum class AsibFM700SlewModelErrorCode : int { ERROR_OK };
// error category
struct AsibFM700SlewModelErrorCategory : public std::error_category {
const char* name() const noexcept;
std::string message(int ec) const;
static const AsibFM700SlewModelErrorCategory& get();
};
inline std::error_code make_error_code(AsibFM700SlewModelErrorCode ec)
{
return std::error_code(static_cast<int>(ec), AsibFM700SlewModelErrorCategory::get());
}
} // namespace asibfm700
namespace std
{
template <>
class is_error_code_enum<asibfm700::AsibFM700SlewModelErrorCode> : public true_type
{
};
} // namespace std
namespace asibfm700
{
class AsibFM700SlewModel final
{
public:
typedef std::error_code error_t;
struct slew_params_t {
typedef mcc::MccAngle coord_t;
mcc::MccCoordPairKind coordPairKind{mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP};
coord_t x{0.0};
coord_t y{0.0};
bool stop{false};
};
AsibFM700SlewModel(AsibFM700Hardware& hw_control, AsibFM700AstromEngine& astrom_engine);
~AsibFM700SlewModel();
error_t slew(const slew_params_t&, AsibFM700Telemetry&);
private:
AsibFM700Hardware& _hwControl;
AsibFM700AstromEngine& _astromEngine;
};
} // namespace asibfm700

View File

@ -186,6 +186,7 @@ concept mcc_mount_hardware_c = !std::copyable<T> && std::movable<T> && requires(
{ t.setPos(std::declval<typename T::axes_pos_t>()) } -> std::same_as<typename T::error_t>;
{ t.getPos(std::declval<typename T::axes_pos_t&>()) } -> std::same_as<typename T::error_t>;
{ t.stop() } -> std::same_as<typename T::error_t>;
{ t.init() } -> std::same_as<typename T::error_t>;
};
@ -215,7 +216,7 @@ concept mcc_mount_pec_c = requires(T t, const T t_const) {
{
t.compute(std::declval<const typename T::coord_t&>(), std::declval<const typename T::coord_t&>(),
std::declval<typename T::pec_result_t>())
std::declval<typename T::pec_result_t&>())
} -> std::same_as<typename T::error_t>;
};
@ -226,6 +227,7 @@ concept mcc_mount_pec_c = requires(T t, const T t_const) {
template <typename T>
concept mcc_mount_telemetry_data_c = requires(T telemetry) {
typename T::coord_t;
typename T::time_point_t;
// // target current coordinates
// requires std::same_as<decltype(telemetry.tagRA), typename T::coord_t>; // apparent RA
@ -297,7 +299,7 @@ concept mcc_slew_params_c = std::movable<T> && requires(T t) {
template <typename T, typename TelemetryT>
concept mcc_slew_model_c = mcc_mount_telemetry_c<TelemetryT> && requires(T t) {
typename T::error_t;
requires mcc_error_c<typename T::error_t>;
requires mcc_slew_params_c<typename T::slew_params_t>;
{

View File

@ -397,7 +397,9 @@ static auto operator*(const T1& v1, const T2& v2)
} else if constexpr (std::is_arithmetic_v<T2>) {
return v1 *= v2;
} else {
static_assert(false, "INCOMPATIBLE TYPES!");
using res_t = std::conditional_t<std::convertible_to<T1, T2> && std::derived_from<T1, MccAngle>, T1, T2>;
return res_t{(double)v1 * (double)v2};
// static_assert(false, "INCOMPATIBLE TYPES!");
}
}

View File

@ -28,6 +28,7 @@ class MccMountDefaultPEC final
public:
static constexpr MccMountType mountType = MOUNT_TYPE;
typedef std::error_code error_t;
typedef MccAngle coord_t;
struct pec_result_t {
@ -117,11 +118,12 @@ public:
return _pecData.type;
}
// X and Y axis encoder coordinates
pec_result_t compute(const coord_t& x, const coord_t& y)
// The computed PEC quantities must be interpretated as:
// apparent_X = encoder_X + pec_result_t.dx
// apparent_Y = encoder_Y + pec_result_t.dy
// so, input x and y are assumed to be mount axis encoder coordinates
error_t compute(const coord_t& x, const coord_t& y, pec_result_t& res)
{
pec_result_t res{0.0, 0.0};
std::lock_guard lock(_pecDataMutex);
if constexpr (mcc_is_equatorial_mount<MOUNT_TYPE>) { // equatorial
@ -163,7 +165,7 @@ public:
if (ret) {
res.dx = std::numeric_limits<double>::quiet_NaN();
res.dy = std::numeric_limits<double>::quiet_NaN();
return res;
return std::error_code(); // !!!!!!!!!!!!!!
}
@ -173,7 +175,7 @@ public:
if (ret) {
res.dx = std::numeric_limits<double>::quiet_NaN();
res.dy = std::numeric_limits<double>::quiet_NaN();
return res;
return std::error_code(); // !!!!!!!!!!!!!!
}
@ -185,9 +187,48 @@ public:
static_assert(false, "UNSUPPORTED");
}
return res;
return std::error_code();
}
// from celestial to encoder (use of iterative scheme)
error_t reverseCompute(const coord_t& x, const coord_t& y, pec_result_t& res, coord_t eps, size_t max_iter = 5)
{
coord_t e2 = eps * eps;
coord_t xi = x, yi = y;
coord_t xp, yp;
size_t iter = 1;
// the first iteration
auto err = compute(x, y, res);
if (!err) {
xp = x - res.dx;
yp = y - res.dy;
bool ok = ((xp - x) * (xp - x) + (yp - y) * (yp - y)) <= e2;
if (ok) {
return std::error_code();
}
while (iter < max_iter) {
xi = xp;
yi = xp;
err = compute(xi, yi, res);
xp -= res.dx;
yp -= res.dy;
ok = ((xp - xi) * (xp - xi) + (yp - yi) * (yp - yi)) <= e2;
if (ok) {
return std::error_code();
}
}
// err = "exceed max iterations";!!!
}
return err;
}
private:
@ -203,4 +244,7 @@ private:
typedef MccMountDefaultPEC<MccMountType::ALTAZ_TYPE> MccMountDefaultAltAzPec;
typedef MccMountDefaultPEC<MccMountType::FORK_TYPE> MccMountDefaultForkPec;
static_assert(traits::mcc_mount_pec_c<MccMountDefaultForkPec>, "");
} // namespace mcc

View File

@ -13,9 +13,95 @@ namespace mcc
{
namespace traits
{
/* enhanced telemetry data concept */
/* in general it correspond to definitions used in astrometry engine (see its concept) */
template <typename T, typename ASTROM_ENGINE_T, typename PEC_T>
concept mcc_mount_telemetry_enh_data_c = mcc_mount_telemetry_data_c<T> && requires(T t) {
requires traits::mcc_astrom_engine_c<ASTROM_ENGINE_T>;
requires traits::mcc_mount_pec_c<PEC_T>;
// check for types definitions and its consistency
requires std::same_as<typename T::coord_t, typename ASTROM_ENGINE_T::coord_t>;
requires std::same_as<typename T::time_point_t, typename ASTROM_ENGINE_T::time_point_t>;
requires std::same_as<typename T::juldate_t,
typename ASTROM_ENGINE_T::juldate_t>; // a type to represent Julian date
requires std::same_as<typename T::sideral_time_t,
typename ASTROM_ENGINE_T::sideral_time_t>; // a type to represent sideral time
requires std::same_as<typename T::pa_t,
typename ASTROM_ENGINE_T::pa_t>; // a type to represent parallactic angle
// typename T::eo_t; // a type to represent equation of origins
requires std::same_as<decltype(t.jd), typename T::juldate_t>; // Julian date
requires std::same_as<decltype(t.siderTime), typename T::sideral_time_t>; // sideral time
requires std::same_as<decltype(t.mntRA), typename T::pa_t>; // parallactic angle
// encoder-measured (non-corrected for PCS) current mount position and moving speed (in radians, radians/s)
// X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
requires std::same_as<decltype(t.mntPosX), typename T::coord_t>;
requires std::same_as<decltype(t.mntPosY), typename T::coord_t>;
// current refraction coefficients
requires std::same_as<decltype(t.currRefrCoeffs), typename PEC_T::pec_result_t>;
// current refraction correction (for mntALT)
requires std::same_as<decltype(t.currRefr), typename T::coord_t>;
// PEC (pointing error correction):
// X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
requires std::same_as<decltype(t.pecX), typename T::coord_t>;
requires std::same_as<decltype(t.pecY), typename T::coord_t>;
};
} // namespace traits
// default generic telemetry data definition
template <traits::mcc_astrom_engine_c ASTROM_ENGINE_T, traits::mcc_mount_pec_c PEC_T>
struct MccMountTelemetryData {
typedef typename ASTROM_ENGINE_T::coord_t coord_t;
typedef typename ASTROM_ENGINE_T::time_point_t time_point_t;
typedef typename ASTROM_ENGINE_T::juldate_t juldate_t;
typedef typename ASTROM_ENGINE_T::sideral_time_t sideral_time_t;
typedef typename ASTROM_ENGINE_T::pa_t pa_t;
// time-related
time_point_t utc; // time point of measurements, UTC
juldate_t jd; // Julian date
sideral_time_t siderTime; // local apperant sideral time
// encoder-measured current mount coordinates
coord_t mntRA, mntDEC;
coord_t mntHA;
coord_t mntAZ, mntALT;
pa_t mntPA;
// encoder-measured (non-corrected for PCS) current mount position
// X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
coord_t mntPosX, mntPosY;
// current refraction coefficients
typename PEC_T::pec_result_t currRefrCoeffs;
// current refraction correction (for mntALT)
coord_t currRefr;
// PEC (pointing error correction):
// X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
coord_t pecX, pecY;
};
template <traits::mcc_astrom_engine_c ASTROM_ENGINE_T,
traits::mcc_mount_pec_c PEC_T,
traits::mcc_mount_hardware_c HARDWARE_T>
traits::mcc_mount_hardware_c HARDWARE_T,
traits::mcc_mount_telemetry_enh_data_c<ASTROM_ENGINE_T, PEC_T> DATA_T =
MccMountTelemetryData<ASTROM_ENGINE_T, PEC_T>>
class MccMountTelemetry
{
public:
@ -51,42 +137,44 @@ public:
static_assert(std::convertible_to<typename hardware_t::time_point_t, typename astrom_engine_t::time_point_t>,
"HARDWARE TIME-POINT TYPE MUST BE CONVERTIBLE TO ASTROMETRY ENGINE ONE!");
typedef DATA_T mount_telemetry_data_t;
// mount current telemetry data: time, position and related quantities
struct mount_telemetry_data_t {
typedef typename astrom_engine_t::coord_t coord_t;
// struct mount_telemetry_data_t {
// typedef typename astrom_engine_t::coord_t coord_t;
// time-related
typename astrom_engine_t::time_point_t utc; // time point of measurements, UTC
typename astrom_engine_t::juldate_t jd; // Julian date
typename astrom_engine_t::sideral_time_t siderTime; // local apperant sideral time
// typename astrom_engine_t::time_point_t ut1; // Universal time
// typename astrom_engine_t::time_point_t tt; // Terrestial time
// // time-related
// typename astrom_engine_t::time_point_t utc; // time point of measurements, UTC
// typename astrom_engine_t::juldate_t jd; // Julian date
// typename astrom_engine_t::sideral_time_t siderTime; // local apperant sideral time
// // typename astrom_engine_t::time_point_t ut1; // Universal time
// // typename astrom_engine_t::time_point_t tt; // Terrestial time
// apparent target (user-input) current coordinates (in radians)
coord_t tagRA, tagDEC;
coord_t tagHA;
coord_t tagAZ, tagALT;
coord_t tagPA; // paralactic angle
// // apparent target (user-input) current coordinates (in radians)
// coord_t tagRA, tagDEC;
// coord_t tagHA;
// coord_t tagAZ, tagALT;
// coord_t tagPA; // paralactic angle
// encoder-measured current mount coordinates (in radians)
coord_t mntRA, mntDEC;
coord_t mntHA;
coord_t mntAZ, mntALT;
typename astrom_engine_t::pa_t mntPA;
// // encoder-measured current mount coordinates (in radians)
// coord_t mntRA, mntDEC;
// coord_t mntHA;
// coord_t mntAZ, mntALT;
// typename astrom_engine_t::pa_t mntPA;
// encoder-measured (non-corrected for PCS) current mount position and moving speed (in radians, radians/s)
// X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
coord_t mntPosX, mntPosY;
// // encoder-measured (non-corrected for PCS) current mount position and moving speed (in radians, radians/s)
// // X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
// coord_t mntPosX, mntPosY;
// current refraction coefficients
typename pec_t::pec_result_t currRefrCoeffs;
// current refraction correction (for mntALT)
coord_t currRefr;
// // current refraction coefficients
// typename pec_t::pec_result_t currRefrCoeffs;
// // current refraction correction (for mntALT)
// coord_t currRefr;
// PEC (pointing error correction):
// X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
coord_t pecX, pecY;
};
// // PEC (pointing error correction):
// // X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
// coord_t pecX, pecY;
// };
MccMountTelemetry(astrom_engine_t& astrom_engine, pec_t& pec, hardware_t& hardware)
: _astromEngine(astrom_engine), _pec(pec), _hardware(hardware)

212
cxx/mcc_slew_model.h Normal file
View File

@ -0,0 +1,212 @@
#pragma once
/* MOUNT CONTROL COMPONENTS LIBRARY */
/* A VERY SIMPLE SLEW MODEL GENERIC IMPLEMENTATION */
#include "mcc_mount_concepts.h"
namespace mcc
{
/*
* WARNING: it is assumed that coordinates are in radians!
* but this fact is only used if slew coordinate pair are given as
* [azimuth, zenithal distance] (see sources code below)
*/
template <traits::mcc_mount_telemetry_c TELEMETRY_T>
class MccSimpleSlewModel
{
public:
typedef std::error_code error_t;
struct slew_params_t {
typedef mcc::MccAngle coord_t;
mcc::MccCoordPairKind coordPairKind{mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP};
coord_t x{0.0};
coord_t y{0.0};
bool stop{false};
};
template <traits::mcc_mount_hardware_c HARDWARE_T,
traits::mcc_astrom_engine_c ASTROM_T,
traits::mcc_mount_pec_c PEC_T>
MccSimpleSlewModel(HARDWARE_T& hardware, ASTROM_T& astrom_engine, PEC_T& pec)
{
const auto p_hardware = &hardware;
const auto p_astrom_engine = &astrom_engine;
const auto p_pec = &pec;
_slewFunc = [p_hardware, p_astrom_engine, p_pec](this auto&& self, const slew_params_t& slew_pars,
TELEMETRY_T& telemetry) {
using coord_t = typename ASTROM_T::coord_t;
using jd_t = typename ASTROM_T::juldate_t;
typename HARDWARE_T::axes_pos_t ax_pos;
error_t res_err;
typename ASTROM_T::error_t ast_err;
if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_XY) {
// trivial case (the pair is interpretated as raw encoder coordinates)
ax_pos.x = slew_pars.x;
ax_pos.y = slew_pars.y;
} else if (slew_pars.coordPairKind ==
mcc::MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // catalog coordinates
jd_t jd;
coord_t ra_app, dec_app, ha, az, alt;
typename ASTROM_T::eo_t eo;
ast_err = p_astrom_engine->greg2jul(std::chrono::system_clock::now(), jd);
if (!ast_err) {
ast_err = p_astrom_engine->icrs2obs(slew_pars.x, slew_pars.y, jd, ra_app, dec_app, ha, az, alt, eo);
if (!ast_err) {
if constexpr (mccIsEquatorialMount(PEC_T::mountType)) {
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP,
.x = ha,
.y = dec_app,
.stop = slew_pars.stop},
telemetry);
} else if constexpr (mccIsAltAzMount(PEC_T::mountType)) {
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_AZALT,
.x = az,
.y = alt,
.stop = slew_pars.stop},
telemetry);
} else {
static_assert(false, "UNKNOWN MOUNT TYPE!");
}
}
}
} else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_RADEC_APP) { // apparent
jd_t jd;
typename ASTROM_T::eo_t eo;
ast_err = p_astrom_engine->greg2jul(std::chrono::system_clock::now(), jd);
if (!ast_err) {
typename ASTROM_T::sideral_time_t lst;
ast_err = p_astrom_engine->apparentSiderTime(jd, lst, true);
if (!ast_err) {
ast_err = p_astrom_engine->eqOrigins(jd, eo);
if (!ast_err) {
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP,
.x = lst - slew_pars.x + eo, // HA = LST - RA_APP + EO
.y = slew_pars.y,
.stop = slew_pars.stop},
telemetry);
}
}
}
} else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP) { // apparent
if constexpr (mccIsEquatorialMount(PEC_T::mountType)) { // compute encoder coordinates
coord_t eps = 1.0 / 3600.0 * std::numbers::pi / 180.0;
typename PEC_T::pec_result_t pec_res;
auto err = p_pec->reverseCompute(slew_pars.x, slew_pars.y, pec_res, eps, 10);
if (!err) {
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_XY,
.x = slew_pars.x - pec_res.dx,
.y = slew_pars.y - pec_res.dy,
.stop = slew_pars.stop},
telemetry);
}
} else if constexpr (mccIsAltAzMount(PEC_T::mountType)) {
coord_t az, alt;
ast_err = p_astrom_engine->hadec2azalt(slew_pars.x, slew_pars.y, az, alt);
if (!ast_err) {
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_AZALT,
.x = az,
.y = alt,
.stop = slew_pars.stop},
telemetry);
}
} else {
static_assert(false, "UNKNOWN MOUNT TYPE!");
}
} else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_AZALT) {
if constexpr (mccIsEquatorialMount(PEC_T::mountType)) {
coord_t ha, dec;
ast_err = p_astrom_engine->azalt2hadec(slew_pars.x, slew_pars.y, ha, dec);
if (!ast_err) {
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP,
.x = ha,
.y = dec,
.stop = slew_pars.stop},
telemetry);
}
} else if constexpr (mccIsAltAzMount(PEC_T::mountType)) { // compute encoder coordinates
coord_t eps = 1.0 / 3600.0 * std::numbers::pi / 180.0;
typename PEC_T::pec_result_t pec_res;
auto err = p_pec->reverseCompute(slew_pars.x, slew_pars.y, pec_res, eps, 10);
if (!err) {
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_XY,
.x = slew_pars.x - pec_res.dx,
.y = slew_pars.y - pec_res.dy,
.stop = slew_pars.stop},
telemetry);
}
} else {
static_assert(false, "UNKNOWN MOUNT TYPE!");
}
} else if (slew_pars.coordPairKind == mcc::MccCoordPairKind::COORDS_KIND_AZZD) {
//
// WARNING: it is assumed that coordinates are in radians!
//
res_err = self({.coordPairKind = mcc::MccCoordPairKind::COORDS_KIND_AZALT,
.x = slew_pars.x,
.y = std::numbers::pi / 2.0 - slew_pars.y,
.stop = slew_pars.stop},
telemetry);
}
if (res_err) {
return res_err;
}
if (!ast_err) {
auto err = p_hardware->setPos(std::move(ax_pos));
while (true) {
}
}
};
}
error_t slew(const slew_params_t& pars, TELEMETRY_T& telemetry)
{
error_t res_err = _slewFunc(pars, telemetry);
return res_err;
}
protected:
std::function<error_t(const slew_params_t&, TELEMETRY_T&)> _slewFunc{};
};
// static_assert(traits::mcc_slew_model_c<>);
} // namespace mcc