#pragma once /* MOUNT CONTROL COMPONENTS LIBRARY */ /* MOUNT TELEMETRY OBJECT CONCEPT AND POSSIBLE IMPLEMENTATION */ #include #include "mcc_mount_concepts.h" namespace mcc { template class MccMountTelemetry { public: typedef ASTROM_ENGINE_T astrom_engine_t; typedef PEC_T pec_t; typedef HARDWARE_T hardware_t; enum error_t : int { TEL_ERROR_OK = 0, TEL_ERROR_HARDWARE, TEL_ERROR_ASTROMETRY_COMP, TEL_ERROR_PEC }; // check for coordinate types consistency static_assert(std::convertible_to, "HARDWARE COORDINATE TYPE MUST BE CONVERTIBLE TO ASTROMETRY ENGINE ONE!"); static_assert(std::convertible_to, "HARDWARE COORDINATE TYPE MUST BE CONVERTIBLE TO PEC ONE!"); // static_assert(std::convertible_to, // "ASTROMETRY ENGINE COORDINATE TYPE MUST BE CONVERTIBLE TO PEC ONE!"); // mandatory arithmetic operations static_assert( // for CIO-based apparent RA computation and PEC correction addition (see below) requires(typename astrom_engine_t::coord_t v1, typename astrom_engine_t::coord_t v2, typename pec_t::coord_t v3) { { v1 + v2 } -> std::convertible_to; { v1 - v2 } -> std::convertible_to; v1 += v3; }, "ASTROMETRY ENGINE COORDINATE TYPE MUST DEFINE '+', '+=' AND '-' ARITHMETIC OPERATIONS!"); // check for time point types consistency static_assert(std::convertible_to, "HARDWARE TIME-POINT TYPE MUST BE CONVERTIBLE TO ASTROMETRY ENGINE ONE!"); // mount current telemetry data: time, position and related quantities 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 // 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 (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; // 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) { } virtual ~MccMountTelemetry() = default; // update current data method error_t update() { mount_telemetry_data_t current_data; typename hardware_t::axes_pos_t ax_pos; auto err = _hardware.getPos(ax_pos); if (err) { // logging?!!! return TEL_ERROR_HARDWARE; } _data.utc = ax_pos.time_point; _data.mntPosX = static_cast(ax_pos.x); _data.mntPosY = static_cast(ax_pos.y); // compute Julian date auto ast_err = _astromEngine.greg2jul(_data.utc, _data.jd); if (ast_err) { return TEL_ERROR_ASTROMETRY_COMP; } // compute local apparent sideral time ast_err = _astromEngine.apparentSiderTime(_data.jd, _data.siderTime, true); if (ast_err) { return TEL_ERROR_ASTROMETRY_COMP; } // compute equation of origins typename astrom_engine_t::eo_t eo; ast_err = _astromEngine.eqOrigins(_data.jd, eo); if (ast_err) { return TEL_ERROR_ASTROMETRY_COMP; } typename pec_t::pec_result_t pec_res; auto pec_err = _pec.compute(ax_pos.x, ax_pos.y, pec_res); if (pec_err) { return TEL_ERROR_PEC; } if constexpr (mccIsEquatorialMount(pec_t::mountType)) { _data.mntHA = _data.mntPosX; _data.mntDEC = _data.mntPosY; _data.mntHA += pec_res.dx; _data.mntDEC += pec_res.dy; ast_err = _astromEngine.hadec2azalt(_data.mntHA, _data.mntDEC, _data.mntAZ, _data.mntALT); if (ast_err) { return TEL_ERROR_ASTROMETRY_COMP; } } else if constexpr (mccIsAltAzMount(pec_t::mountType)) { _data.mntAZ = _data.mntPosX; _data.mntALT = _data.mntPosY; _data.mntAZ += pec_res.dx; _data.mntALT += pec_res.dy; ast_err = _astromEngine.azalt2hadec(_data.mntAZ, _data.mntALT, _data.mntHA, _data.mntDEC); if (ast_err) { return TEL_ERROR_ASTROMETRY_COMP; } } else { static_assert(false, "UNSUPPORTED MOUNT TYPE!"); } // compute CIO-based apparent RA _data.mntRA = _data.siderTime - _data.mntHA + eo; // compute PA ast_err = _astromEngine.hadec2pa(_data.mntHA, _data.mntDEC, _data.mntPA); if (ast_err) { return TEL_ERROR_ASTROMETRY_COMP; } ast_err = _astromEngine.refraction(_data.currRefrCoeffs); if (ast_err) { return TEL_ERROR_ASTROMETRY_COMP; } ast_err = _astromEngine.refractCorrection(_data.mntALT, _data.currRefrCoeffs, _data.currRefr); if (ast_err) { return TEL_ERROR_ASTROMETRY_COMP; } std::lock_guard lock{_updateMutex}; _data = std::move(current_data); return TEL_ERROR_OK; } mount_telemetry_data_t data() { std::lock_guard lock{_updateMutex}; return std::move(_data); } std::string_view errorString(error_t err) const { if (err == TEL_ERROR_OK) { return "OK"; } else if (err == TEL_ERROR_ASTROMETRY_COMP) { return "astrometry computation error"; } else if (err == TEL_ERROR_PEC) { return "PEC computation error"; } else if (err == TEL_ERROR_HARDWARE) { return "hardware request error"; } else { return "unknown error"; } } protected: mount_telemetry_data_t _data{}; astrom_engine_t& _astromEngine; pec_t& _pec; hardware_t& _hardware; std::mutex _updateMutex; }; } // namespace mcc