...
This commit is contained in:
parent
464c262e08
commit
9cd52267d6
@ -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_SRC asibfm700_hardware.h asibfm700_hardware.cpp)
|
||||||
set(ASIBFM700_LIB asibfm700)
|
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
|
# 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)
|
# 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
45
cxx/asibfm700_common.h
Normal 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
|
||||||
@ -93,7 +93,8 @@ std::string_view AsibFM700Hardware::id() const
|
|||||||
|
|
||||||
AsibFM700Hardware::error_t AsibFM700Hardware::setPos(AsibFM700Hardware::axes_pos_t pos)
|
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));
|
auto err = static_cast<AsibFM700HardwareErrorCode>(Mount.moveTo(&X, &Y));
|
||||||
|
|
||||||
return err;
|
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.time_point = time_point_t{std::chrono::duration_cast<time_point_t::duration>(secs)};
|
||||||
|
|
||||||
pos.x = data.encposition.X;
|
// according to hardware configuration (encoders pins (Eddy said)) X is DEC-axis and Y is HA-axis
|
||||||
pos.y = data.encposition.Y;
|
pos.x = data.encposition.Y;
|
||||||
|
pos.y = data.encposition.X;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|||||||
@ -71,20 +71,6 @@ public:
|
|||||||
coord_t x, y;
|
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 {
|
struct hardware_config_t {
|
||||||
// the 'char*' fields from conf_t:
|
// the 'char*' fields from conf_t:
|
||||||
@ -113,6 +99,7 @@ public:
|
|||||||
|
|
||||||
error_t setPos(axes_pos_t);
|
error_t setPos(axes_pos_t);
|
||||||
error_t getPos(axes_pos_t&);
|
error_t getPos(axes_pos_t&);
|
||||||
|
|
||||||
error_t stop();
|
error_t stop();
|
||||||
error_t init();
|
error_t init();
|
||||||
|
|
||||||
|
|||||||
110
cxx/asibfm700_slew_model.cpp
Normal file
110
cxx/asibfm700_slew_model.cpp
Normal 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
|
||||||
75
cxx/asibfm700_slew_model.h
Normal file
75
cxx/asibfm700_slew_model.h
Normal 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
|
||||||
@ -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.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.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.stop() } -> std::same_as<typename T::error_t>;
|
||||||
{ t.init() } -> 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&>(),
|
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>;
|
} -> 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>
|
template <typename T>
|
||||||
concept mcc_mount_telemetry_data_c = requires(T telemetry) {
|
concept mcc_mount_telemetry_data_c = requires(T telemetry) {
|
||||||
typename T::coord_t;
|
typename T::coord_t;
|
||||||
|
typename T::time_point_t;
|
||||||
|
|
||||||
// // target current coordinates
|
// // target current coordinates
|
||||||
// requires std::same_as<decltype(telemetry.tagRA), typename T::coord_t>; // apparent RA
|
// 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>
|
template <typename T, typename TelemetryT>
|
||||||
concept mcc_slew_model_c = mcc_mount_telemetry_c<TelemetryT> && requires(T t) {
|
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>;
|
requires mcc_slew_params_c<typename T::slew_params_t>;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@ -397,7 +397,9 @@ static auto operator*(const T1& v1, const T2& v2)
|
|||||||
} else if constexpr (std::is_arithmetic_v<T2>) {
|
} else if constexpr (std::is_arithmetic_v<T2>) {
|
||||||
return v1 *= v2;
|
return v1 *= v2;
|
||||||
} else {
|
} 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!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,7 @@ class MccMountDefaultPEC final
|
|||||||
public:
|
public:
|
||||||
static constexpr MccMountType mountType = MOUNT_TYPE;
|
static constexpr MccMountType mountType = MOUNT_TYPE;
|
||||||
|
|
||||||
|
typedef std::error_code error_t;
|
||||||
typedef MccAngle coord_t;
|
typedef MccAngle coord_t;
|
||||||
|
|
||||||
struct pec_result_t {
|
struct pec_result_t {
|
||||||
@ -117,11 +118,12 @@ public:
|
|||||||
return _pecData.type;
|
return _pecData.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// X and Y axis encoder coordinates
|
// The computed PEC quantities must be interpretated as:
|
||||||
pec_result_t compute(const coord_t& x, const coord_t& y)
|
// 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);
|
std::lock_guard lock(_pecDataMutex);
|
||||||
|
|
||||||
if constexpr (mcc_is_equatorial_mount<MOUNT_TYPE>) { // equatorial
|
if constexpr (mcc_is_equatorial_mount<MOUNT_TYPE>) { // equatorial
|
||||||
@ -163,7 +165,7 @@ public:
|
|||||||
if (ret) {
|
if (ret) {
|
||||||
res.dx = std::numeric_limits<double>::quiet_NaN();
|
res.dx = std::numeric_limits<double>::quiet_NaN();
|
||||||
res.dy = 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) {
|
if (ret) {
|
||||||
res.dx = std::numeric_limits<double>::quiet_NaN();
|
res.dx = std::numeric_limits<double>::quiet_NaN();
|
||||||
res.dy = 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");
|
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:
|
private:
|
||||||
@ -203,4 +244,7 @@ private:
|
|||||||
typedef MccMountDefaultPEC<MccMountType::ALTAZ_TYPE> MccMountDefaultAltAzPec;
|
typedef MccMountDefaultPEC<MccMountType::ALTAZ_TYPE> MccMountDefaultAltAzPec;
|
||||||
typedef MccMountDefaultPEC<MccMountType::FORK_TYPE> MccMountDefaultForkPec;
|
typedef MccMountDefaultPEC<MccMountType::FORK_TYPE> MccMountDefaultForkPec;
|
||||||
|
|
||||||
|
static_assert(traits::mcc_mount_pec_c<MccMountDefaultForkPec>, "");
|
||||||
|
|
||||||
|
|
||||||
} // namespace mcc
|
} // namespace mcc
|
||||||
|
|||||||
@ -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,
|
template <traits::mcc_astrom_engine_c ASTROM_ENGINE_T,
|
||||||
traits::mcc_mount_pec_c PEC_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
|
class MccMountTelemetry
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -51,42 +137,44 @@ public:
|
|||||||
static_assert(std::convertible_to<typename hardware_t::time_point_t, typename astrom_engine_t::time_point_t>,
|
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!");
|
"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
|
// mount current telemetry data: time, position and related quantities
|
||||||
struct mount_telemetry_data_t {
|
// struct mount_telemetry_data_t {
|
||||||
typedef typename astrom_engine_t::coord_t coord_t;
|
// typedef typename astrom_engine_t::coord_t coord_t;
|
||||||
|
|
||||||
// time-related
|
// // time-related
|
||||||
typename astrom_engine_t::time_point_t utc; // time point of measurements, UTC
|
// 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::juldate_t jd; // Julian date
|
||||||
typename astrom_engine_t::sideral_time_t siderTime; // local apperant sideral time
|
// 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 ut1; // Universal time
|
||||||
// typename astrom_engine_t::time_point_t tt; // Terrestial time
|
// // typename astrom_engine_t::time_point_t tt; // Terrestial time
|
||||||
|
|
||||||
// apparent target (user-input) current coordinates (in radians)
|
// // apparent target (user-input) current coordinates (in radians)
|
||||||
coord_t tagRA, tagDEC;
|
// coord_t tagRA, tagDEC;
|
||||||
coord_t tagHA;
|
// coord_t tagHA;
|
||||||
coord_t tagAZ, tagALT;
|
// coord_t tagAZ, tagALT;
|
||||||
coord_t tagPA; // paralactic angle
|
// coord_t tagPA; // paralactic angle
|
||||||
|
|
||||||
// encoder-measured current mount coordinates (in radians)
|
// // encoder-measured current mount coordinates (in radians)
|
||||||
coord_t mntRA, mntDEC;
|
// coord_t mntRA, mntDEC;
|
||||||
coord_t mntHA;
|
// coord_t mntHA;
|
||||||
coord_t mntAZ, mntALT;
|
// coord_t mntAZ, mntALT;
|
||||||
typename astrom_engine_t::pa_t mntPA;
|
// typename astrom_engine_t::pa_t mntPA;
|
||||||
|
|
||||||
// encoder-measured (non-corrected for PCS) current mount position and moving speed (in radians, radians/s)
|
// // 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
|
// // X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
|
||||||
coord_t mntPosX, mntPosY;
|
// coord_t mntPosX, mntPosY;
|
||||||
|
|
||||||
// current refraction coefficients
|
// // current refraction coefficients
|
||||||
typename pec_t::pec_result_t currRefrCoeffs;
|
// typename pec_t::pec_result_t currRefrCoeffs;
|
||||||
// current refraction correction (for mntALT)
|
// // current refraction correction (for mntALT)
|
||||||
coord_t currRefr;
|
// coord_t currRefr;
|
||||||
|
|
||||||
// PEC (pointing error correction):
|
// // PEC (pointing error correction):
|
||||||
// X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
|
// // X - HA, Y - DEC for equatorial-type mount; X - AZ, Y - ALT for horizontal-type one
|
||||||
coord_t pecX, pecY;
|
// coord_t pecX, pecY;
|
||||||
};
|
// };
|
||||||
|
|
||||||
MccMountTelemetry(astrom_engine_t& astrom_engine, pec_t& pec, hardware_t& hardware)
|
MccMountTelemetry(astrom_engine_t& astrom_engine, pec_t& pec, hardware_t& hardware)
|
||||||
: _astromEngine(astrom_engine), _pec(pec), _hardware(hardware)
|
: _astromEngine(astrom_engine), _pec(pec), _hardware(hardware)
|
||||||
|
|||||||
212
cxx/mcc_slew_model.h
Normal file
212
cxx/mcc_slew_model.h
Normal 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
|
||||||
Loading…
x
Reference in New Issue
Block a user