mountcontrol/mcc/mcc_moving_model_common.h
Timur A. Fatkhullin 1c774d2d69 Asibfm700Mount is now MccGenericMount (not MccGenericFsmMount)
fix mount initialization (add EEPROM reading, assign correponded
mount config items)
rewrite computing distance to pzones in slewing mode (add braking
aceleration)
add more informative errors description for serialization (network
protocol)
2025-11-15 16:01:42 +03:00

197 lines
7.0 KiB
C++

#pragma once
/* MOUNT CONTROL COMPONENTS LIBRARY */
/* COMMON DEFINITIONS FOR SIMPLE SLEWING, TRACKING AND GUIDING MODEL IMPLEMENTATIONS */
#include <chrono>
#include "mcc_angle.h"
#include "mcc_generics.h"
namespace mcc
{
struct MccSimpleMovingModelParams {
// ******* common for all modes *******
// mean celestial rate
static constexpr double sideralRate = 15.0410686_arcsecs; // in radians per second
// timeout to telemetry updating
std::chrono::milliseconds telemetryTimeout{3000};
// minimal time to prohibited zone (at current speed in slewing mode). if it is lesser then exit with error
std::chrono::seconds minTimeToPZone{10};
// time interval to update prohibited zones related quantities (e.g. intersection points)
std::chrono::milliseconds updatingPZoneInterval{5000};
// ******* slewing mode *******
bool slewAndStop{false}; // slew to target and stop mount
// coordinates difference to stop slewing (in radians)
double slewToleranceRadius{5.0_arcsecs};
// target-mount coordinate difference to start adjusting of slewing (in radians)
double adjustCoordDiff{slewToleranceRadius * 10.0};
// slew process timeout
std::chrono::seconds slewTimeout{3600};
double slewRateX{0.0}; // maximal slewing rate (0 means move with maximal allowed rate????!!!!!)
double slewRateY{0.0}; // maximal slewing rate (0 means move with maximal allowed rate????!!!!!)
std::chrono::milliseconds adjustCycleInterval{500}; // minimum time between two successive adjustments
double adjustRateX{5.0_arcmins}; // maximal adjusting rate (a rate at the final slewing stage)
double adjustRateY{5.0_arcmins}; // maximal adjusting rate (a rate at the final slewing stage)
// braking acceleration after execution of mount stopping command (in rads/s^2)
// it must be given as non-negative value!!!
double brakingAccelX{0.0};
double brakingAccelY{0.0};
// ******* tracking mode *******
double trackSpeedX{};
double trackSpeedY{};
std::chrono::milliseconds trackingCycleInterval{500}; // minimum time between two successive tracking corrections
bool dualAxisTracking{true}; // mount must be of an equatorial type: false means guiding along only HA-axis
// time shift into future to compute target position in future (UT1-scale time duration)
std::chrono::milliseconds timeShiftToTargetPoint{10000};
// maximal target-to-mount difference for tracking process (in arcsecs)
// it it is greater then the current mount coordinates are used as target one
double trackingMaxCoordDiff{20.0};
// ******* guiding mode *******
double guidingCorrectionRange[2]{0.3_arcsecs, 3.0_arcsecs};
std::chrono::milliseconds guidingMinInterval{500}; // minimum time between two successive corrections
bool dualAxisGuiding{true}; // mount must be of an equatorial type: false means guiding along only HA-axis
};
// calculate the distances along the X and Y axes that the mount will travel at the current speed in a given time,
// taking into account the braking acceleration
//
// WARNING:
// It is assumed that the given braking accelerations are non-negative,
// while speeds may have a sign according to motion direction.
// The latter means that returned distances can be negative!
std::pair<double, double> mcc_compute_distance(mcc_telemetry_data_c auto const& tdata,
double time_in_secs,
mcc_angle_c auto const& braking_accelX,
mcc_angle_c auto const& braking_accelY)
{
std::pair<double, double> res;
// first, check if the mount will stop after given time_in_secs to prevent traveled path to be
// negative
//
// the traveled path: s = V_ini*t - a*t*t/2, V_ini - initial speed, a - braking accel, t - the time
// then, for s>=0, t <= 2*V_ini/a
//
double term_x = 2.0 * std::abs(tdata.speedX) / braking_accelX;
double term_y = 2.0 * std::abs(tdata.speedY) / braking_accelY;
double tx = time_in_secs;
double ty = time_in_secs;
if (std::isfinite(term_x) && (time_in_secs > term_x)) {
tx = term_x;
}
if (std::isfinite(term_y) && (time_in_secs > term_y)) {
ty = term_y;
}
// here, one must take into account the sign of the speed!!!
res.first = tdata.speedX * tx - std::copysign(braking_accelX, tdata.speedX) * tx * tx / 2.0;
res.second = tdata.speedY * ty - std::copysign(braking_accelY, tdata.speedY) * ty * ty / 2.0;
return res;
}
template <mcc_pzone_container_c PZoneContT>
bool mcc_is_near_pzones(PZoneContT* pz_cont,
mcc_telemetry_data_c auto const& tdata,
traits::mcc_time_duration_c auto const& min_timeto,
typename PZoneContT::error_t& err)
{
using res_t = std::decay_t<decltype(min_timeto)>;
std::vector<res_t> pz_timeto; // in seconds
err = pz_cont->timeToPZone(tdata, &pz_timeto);
if (err) {
return false;
}
for (auto const& t : pz_timeto) {
if (t <= min_timeto) {
return true;
}
}
return false;
}
template <mcc_pzone_container_c PZoneContT>
typename PZoneContT::error_t mcc_find_closest_pzone(PZoneContT* pz_cont,
mcc_telemetry_data_c auto const& tdata,
mcc_eqt_hrz_coord_c auto* closest_coords)
{
using res_t = std::decay_t<decltype(*closest_coords)>;
if (closest_coords == nullptr) {
return {};
}
res_t c;
mcc_tp2tp(tdata.time_point, c.time_point);
mcc_tp2tp(tdata.time_point, closest_coords->time_point);
closest_coords->X = std::numeric_limits<double>::quiet_NaN();
closest_coords->Y = std::numeric_limits<double>::quiet_NaN();
closest_coords->RA_APP = std::numeric_limits<double>::quiet_NaN();
closest_coords->DEC_APP = std::numeric_limits<double>::quiet_NaN();
closest_coords->HA = std::numeric_limits<double>::quiet_NaN();
closest_coords->AZ = std::numeric_limits<double>::quiet_NaN();
closest_coords->ZD = std::numeric_limits<double>::quiet_NaN();
closest_coords->ALT = std::numeric_limits<double>::quiet_NaN();
std::vector<res_t> pz_coords(pz_cont->sizePZones(), c);
double dha, dha_min = std::numeric_limits<double>::max();
auto err = pz_cont->intersectPZone(tdata, &pz_coords);
if (!err) {
for (auto const& rpt : pz_coords) {
if (std::isfinite(rpt.X) && std::isfinite(rpt.Y)) {
dha = rpt.HA - tdata.HA;
if (dha < 0.0) {
dha += std::numbers::pi * 2.0;
}
if (dha < dha_min) {
dha_min = dha;
mcc_copy_eqt_hrz_coord(rpt, closest_coords);
}
}
}
}
return err;
}
} // namespace mcc