From 2c6554883b0611ebf9c1ca7981f8fb635989f552 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Thu, 21 May 2026 18:27:15 +0300 Subject: [PATCH] ... --- asibfm700_config.h | 205 ++++++++++++++++++++++++++++++------------ asibfm700_pcm_fit.cpp | 4 + 2 files changed, 154 insertions(+), 55 deletions(-) diff --git a/asibfm700_config.h b/asibfm700_config.h index cbe5be1..f9f698f 100644 --- a/asibfm700_config.h +++ b/asibfm700_config.h @@ -36,15 +36,15 @@ static auto Asibfm700MountConfigurationDefaults = std::make_tuple( /* geographic coordinates of the observation site */ - make_config_record("siteLatitude", mcc::impl::MccAngle(SAORAS_LATITUDE), {"site latitude in degrees"}), - make_config_record("siteLongitude", mcc::impl::MccAngle(SAORAS_LONGITUDE), {"site longitude in degrees"}), - make_config_record("siteElevation", 2070.0, {"site elevation in meters"}), + make_config_record("siteLatitude", mcc::impl::MccAngle(SAORAS_LATITUDE), {" site latitude in degrees"}), + make_config_record("siteLongitude", mcc::impl::MccAngle(SAORAS_LONGITUDE), {" site longitude in degrees"}), + make_config_record("siteElevation", 2070.0, {" site elevation in meters"}), /* celestial coordinate transformation */ - make_config_record("refractWavelength", 0.55, {"wavelength at which refraction is calculated (in mkm)"}), - make_config_record("leapSecondFilename", std::string(), {"an empty filename means default precompiled string"}), - make_config_record("bulletinAFilename", std::string(), {"an empty filename means default precompiled string"}), + make_config_record("refractWavelength", 0.55, {" wavelength at which refraction is calculated (in mkm)"}), + make_config_record("leapSecondFilename", std::string(), {" an empty filename means default precompiled string"}), + make_config_record("bulletinAFilename", std::string(), {" an empty filename means default precompiled string"}), /* pointing correction model */ @@ -52,14 +52,14 @@ static auto Asibfm700MountConfigurationDefaults = std::make_tuple( make_config_record( "pcmType", mcc::impl::MccDefaultPCMType::PCM_TYPE_GEOMETRY, - {"PCM type:", "a case-sensetive string:", " GEOMETRY - 'classic' geometry-based correction coefficients", - " GEOMETRY-BSPLINE - previous one and additional 2D B-spline corrections", - " BSPLINE - pure 2D B-spline corrections"}), + {" PCM type:", " a case-sensetive string:", " GEOMETRY - 'classic' geometry-based correction coefficients", + " GEOMETRY-BSPLINE - previous one and additional 2D B-spline corrections", + " BSPLINE - pure 2D B-spline corrections"}), // PCM geometrical coefficients make_config_record("pcmGeomCoeffs", std::vector{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - {"PCM geometrical coefficients"}), + {" PCM geometrical coefficients"}), // make_config_record("pcmBsplineDegree", std::vector{3, 3}, {"PCM B-spline degrees"}), @@ -68,9 +68,9 @@ static auto Asibfm700MountConfigurationDefaults = std::make_tuple( // Thus the array length must be equal to or greater than 2! make_config_record("pcmBsplineXknots", mcc::impl::mccGenerateBsplineKnots(0.0, 360.0_degs, 8), - {"PCM B-spline knots along X-axis (HA-angle or azimuth). By default from 0 to 2*PI radians", - "NOTE: The first and last values are interpretated as border knots!!!", - " Thus the array length must be equal to or greater than 2!"}), + {" PCM B-spline knots along X-axis (HA-angle or azimuth). By default from 0 to 2*PI radians", + " NOTE: The first and last values are interpretated as border knots!!!", + " Thus the array length must be equal to or greater than 2!"}), // PCM B-spline knots along Y-axis (declination or zenithal distance). // By default from -SAORAS-latitude to PI/2 radians @@ -79,27 +79,29 @@ static auto Asibfm700MountConfigurationDefaults = std::make_tuple( make_config_record( "pcmBsplineYknots", mcc::impl::mccGenerateBsplineKnots(-SAORAS_LATITUDE, 90.0_degs, 8), - {"PCM B-spline knots along Y-axis (declination or zenithal distance). By default from -PI/6 to PI/2 radians", - "NOTE: The first and last values are interpretated as border knots!!!", - " Thus the array length must be equal to or greater than 2!"}), + {" PCM B-spline knots along Y-axis (declination or zenithal distance). By default from -PI/6 to PI/2 radians", + " NOTE: The first and last values are interpretated as border knots!!!", + " Thus the array length must be equal to or greater than 2!"}), // PCM B-spline coeffs for along X-axis (HA-angle or azimuth) - make_config_record("pcmBsplineXcoeffs", std::vector{}, {"PCM B-spline coeffs for along X-axis (HA-angle)"}), + make_config_record("pcmBsplineXcoeffs", + std::vector{}, + {" PCM B-spline coeffs for along X-axis (HA-angle)"}), // PCM B-spline coeffs for along Y-axis (declination or zenithal distance) make_config_record("pcmBsplineYcoeffs", std::vector{}, - {"PCM B-spline coeffs for along Y-axis (declination angle)"}), + {" PCM B-spline coeffs for along Y-axis (declination angle)"}), // inverse PCM B-spline coeffs for along X-axis (HA-angle or azimuth) make_config_record("pcmInverseBsplineXcoeffs", std::vector{}, - {"Inverse PCM B-spline coeffs for along X-axis (HA-angle)"}), + {" Inverse PCM B-spline coeffs for along X-axis (HA-angle)"}), // inverse PCM B-spline coeffs for along Y-axis (declination or zenithal distance) make_config_record("pcmInverseBsplineYcoeffs", std::vector{}, - {"Inverse PCM B-spline coeffs for along Y-axis (declination angle)"}), + {" Inverse PCM B-spline coeffs for along Y-axis (declination angle)"}), /* prohibited zones */ @@ -107,116 +109,168 @@ static auto Asibfm700MountConfigurationDefaults = std::make_tuple( // minimal altitude (default: 10.0 degrees and SAO RAS latitude) make_config_record("altLimPZ", mcc::impl::MccAltLimitPZ{10.0_degs, SAORAS_LATITUDE}, - {"minimal altitude prohibited zone"}), + {" minimal altitude prohibited zone"}), // HA-axis limit switch make_config_record( "axisLimitSwitchHA", mcc::impl::MccAxisLimitSwitchPZ{-170.0_degs, 170.0_degs, nullptr}, - {"HA-axis limit switch stop angles"}), + {" HA-axis limit switch stop angles"}), // DEC-axis limit switch make_config_record( "axisLimitSwitchDEC", mcc::impl::MccAxisLimitSwitchPZ{-90.0_degs, 90.0_degs, nullptr}, - {"DEC-axis limit switch stop angles"}), + {" DEC-axis limit switch stop angles"}), /* hardware-related */ // hardware mode: 1 - model mode, otherwise real mode - make_config_record("RunModel", 0, {"hardware mode: 1 - model mode, otherwise real mode"}), + make_config_record("RunModel", 0, {" hardware mode: 1 - model mode, otherwise real mode"}), // mount serial device paths - make_config_record("MountDevPath", std::string("/dev/ttyUSB0"), {"mount serial device paths"}), + make_config_record("MountDevPath", std::string("/dev/ttyUSB0"), {" mount serial device paths"}), // mount serial device speed - make_config_record("MountDevSpeed", 19200, {"mount serial device speed"}), + make_config_record("MountDevSpeed", 19200, {" mount serial device speed"}), // motor encoders serial device path - make_config_record("EncoderDevPath", std::string(""), {"motor encoders serial device path"}), + make_config_record("EncoderDevPath", std::string(""), {" motor encoders serial device path"}), // X-axis encoder serial device path - make_config_record("EncoderXDevPath", std::string("/dev/encoder_X0"), {"X-axis encoder serial device path"}), + make_config_record("EncoderXDevPath", std::string("/dev/encoder_X0"), {" X-axis encoder serial device path"}), // Y-axis encoder serial device path - make_config_record("EncoderYDevPath", std::string("/dev/encoder_Y0"), {"Y-axis encoder serial device path"}), + make_config_record("EncoderYDevPath", std::string("/dev/encoder_Y0"), {" Y-axis encoder serial device path"}), // encoders serial device speed - make_config_record("EncoderDevSpeed", 153000, {"encoders serial device speed"}), + make_config_record("EncoderDevSpeed", 153000, {" encoders serial device speed"}), // ==1 if encoder works as separate serial device, ==2 if there's new version with two devices - make_config_record("SepEncoder", - 2, - {"==1 if encoder works as separate serial device, ==2 if there's new version with two devices"}), + make_config_record( + "SepEncoder", + 2, + {" ==1 if encoder works as separate serial device, ==2 if there's new version with two devices"}), // mount polling interval in millisecs - make_config_record("MountReqInterval", std::chrono::milliseconds(100), {"mount polling interval in millisecs"}), + make_config_record("MountReqInterval", std::chrono::milliseconds(100), {" mount polling interval in millisecs"}), // encoders polling interval in millisecs - make_config_record("EncoderReqInterval", std::chrono::milliseconds(1), {"encoders polling interval in millisecs"}), + make_config_record("EncoderReqInterval", std::chrono::milliseconds(1), {" encoders polling interval in millisecs"}), // mount axes rate calculation interval in millisecs make_config_record("EncoderSpeedInterval", std::chrono::milliseconds(50), - {"mount axes rate calculation interval in millisecs"}), + {" mount axes rate calculation interval in millisecs"}), make_config_record("PIDMaxDt", std::chrono::milliseconds(1000), - {"maximal PID refresh time interval in millisecs", - "NOTE: if PID data will be refreshed with interval longer than this value (e.g. user polls " - "encoder data too rarely)", - "then the PID 'expired' data will be cleared and new computing loop is started"}), + {" maximal PID refresh time interval in millisecs", + " NOTE: if PID data will be refreshed with interval longer than this value (e.g. user polls " + " encoder data too rarely)", + " then the PID 'expired' data will be cleared and new computing loop is started"}), - make_config_record("PIDRefreshDt", std::chrono::milliseconds(100), {"PID refresh interval"}), + make_config_record("PIDRefreshDt", std::chrono::milliseconds(100), {" PID refresh interval"}), make_config_record("PIDCycleDt", std::chrono::milliseconds(5000), - {"PID I cycle time (analog of 'RC' for PID on opamps)"}), + {" PID I cycle time (analog of 'RC' for PID on opamps)"}), - // X-axis coordinate PID P,I,D-params - make_config_record("XPIDC", std::vector{0.5, 0.1, 0.2}, {"X-axis coordinate PID P,I,D-params"}), + // // X-axis coordinate PID P,I,D-params + // make_config_record("XPIDC", std::vector{0.5, 0.1, 0.2}, {" X-axis coordinate PID P,I,D-params"}), // X-axis rate PID P,I,D-params - make_config_record("XPIDV", std::vector{0.09, 0.0, 0.05}, {"X-axis rate PID P,I,D-params"}), + make_config_record("XPIDV", std::vector{0.09, 0.0, 0.05}, {" X-axis rate PID P,I,D-params"}), - // Y-axis coordinate PID P, I, D-params - make_config_record("YPIDC", std::vector{0.5, 0.1, 0.2}, {"Y-axis coordinate PID P, I, D-params"}), + // // Y-axis coordinate PID P, I, D-params + // make_config_record("YPIDC", std::vector{0.5, 0.1, 0.2}, {" Y-axis coordinate PID P, I, D-params"}), // Y-axis rate PID P,I,D-params - make_config_record("YPIDV", std::vector{0.09, 0.0, 0.05}, {"Y-axis rate PID P,I,D-params"}), + make_config_record("YPIDV", std::vector{0.09, 0.0, 0.05}, {" Y-axis rate PID P,I,D-params"}), // maximal moving rate (degrees per second) along HA-axis (Y-axis of Sidereal servo microcontroller) make_config_record( "hwMaxRateHA", mcc::impl::MccAngle(8.0_degs), - {"maximal moving rate (degrees per second) along HA-axis (Y-axis of Sidereal servo microcontroller)"}), + {" maximal moving rate (degrees per second) along HA-axis (Y-axis of Sidereal servo microcontroller)"}), // maximal moving rate (degrees per second) along DEC-axis (X-axis of Sidereal servo microcontroller) make_config_record( "hwMaxRateDEC", mcc::impl::MccAngle(10.0_degs), - {"maximal moving rate (degrees per second) along DEC-axis (X-axis of Sidereal servo microcontroller)"}), + {" maximal moving rate (degrees per second) along DEC-axis (X-axis of Sidereal servo microcontroller)"}), make_config_record("MaxPointingErr", mcc::impl::MccAngle(8.0_degs), - {"slewing-to-pointing mode angular limit in degrees"}), + {" slewing-to-pointing mode angular limit in degrees"}), make_config_record("MaxFinePointingErr", mcc::impl::MccAngle(1.5_degs), - {"pointing-to-guiding mode angular limit in degrees"}), + {" pointing-to-guiding mode angular limit in degrees"}), make_config_record("MaxGuidingErr", mcc::impl::MccAngle(0.5_arcsecs), - {"guiding 'good'-flag error cirle radius (mount-to-target distance) in degrees"}), + {" guiding 'good'-flag error cirle radius (mount-to-target distance) in degrees"}), - make_config_record("XEncZero", (int64_t)0, {"X-axis encoder zero-point in ticks"}), + make_config_record("XEncZero", (int64_t)0, {" X-axis encoder zero-point in ticks"}), + + make_config_record("YEncZero", (int64_t)0, {" Y-axis encoder zero-point in ticks"}), + + + /* movement related common parameters */ + + // timeout for telemetry updating in milliseconds + make_config_record("telemetryTimeout", + std::chrono::milliseconds(3000), + {" timeout for telemetry updating in milliseconds"}), + + // mount stopping process timeout in seconds + make_config_record("stopTimeout", std::chrono::seconds(30), {" mount stopping process timeout in seconds"}), + + // minimal allowed time in seconds to prohibited zone + make_config_record("minTimeToPZone", + std::chrono::seconds(10), + {" minimal allowed time in seconds to prohibited zone"}), + + /* slewing and tracking parameters */ + + // telemetry request interval (in millisecs) in slewing mode + make_config_record("slewingTelemetryInterval", + std::chrono::milliseconds(100), + {" telemetry request interval (in millisecs) in slewing mode"}), + + + // slew process timeout in seconds + make_config_record("slewTimeout", std::chrono::seconds(3600), {" slew process timeout in seconds"}), + + // slewing trajectory filename (used for debugging purposes) + // if it is an empty - just skip saving + make_config_record("slewingPathFilename", + std::string(), + {" slewing trajectory filename", "if it is an empty - just skip saving"}), + + + make_config_record("trackingTelemetryInterval", + std::chrono::milliseconds(100), + {" telemetry request interval (in millisecs) in tracking mode"}), + + + // maximal valid target-to-mount distance for tracking process (arcsecs) + // if current distance is greater than assume current mount coordinate as target point + make_config_record("trackingMaxCoordDiff", + 20.0, + {" maximal valid target-to-mount distance for tracking process (arcsecs)", + " if current distance is greater than assume current mount coordinate as target point"}), + + make_config_record("trackingPathFilename", + std::string(), + {" tracking trajectory filename", "if it is an empty - just skip saving"}) - make_config_record("YEncZero", (int64_t)0, {"Y-axis encoder zero-point in ticks"}) ); @@ -403,6 +457,47 @@ public: return save(_lastConfigPath); } + std::error_code dumpDefaultsToFile(const std::filesystem::path& path) + { + std::error_code ec{}; + std::string output_buffer; + + auto write_rec = [&output_buffer, &ec, this](this auto& self) { + if constexpr (I < NUMBER_OF_RECORDS) { + // add an empty string within records + std::format_to(std::back_inserter(output_buffer), "{}", DEFAULT_RECORD_DELIMITER); + + ec = formatRecord(output_buffer, DEFAULT_RECORD_DELIMITER, true); + if (ec) { + return; + } + + + self.template operator()(); + } + }; + + write_rec(); + if (!ec) { + std::ofstream fst(path, std::ios_base::trunc); + if (!fst.is_open()) { + ec = std::make_error_code(std::errc::io_error); + } else { + try { + fst << generateHeader(); + fst << output_buffer; + } catch (std::ios_base::failure const& ex) { + ec = ex.code(); + } catch (...) { + ec = std::make_error_code(std::errc::operation_canceled); + } + } + } + + return ec; + } + + std::filesystem::path configFilename() const { return _lastConfigPath; diff --git a/asibfm700_pcm_fit.cpp b/asibfm700_pcm_fit.cpp index bb674d4..4d5f910 100644 --- a/asibfm700_pcm_fit.cpp +++ b/asibfm700_pcm_fit.cpp @@ -8,6 +8,7 @@ #include #include +#include "asibfm700_config.h" #include "asibfm700_configfile.h" // static constexpr mcc::MccMountType MOUNT_TYPE{mcc::MccMountType::CROSSAXIS_TYPE}; @@ -37,6 +38,9 @@ int main(int argc, char* argv[]) mcc::impl::MccPCMFitter::compute_params_t comp_pars; asibfm700::Asibfm700MountConfig mount_cfg; + asibfm700::Asibfm700MountConfiguration cfg; + + cfg.dumpDefaultsToFile("eecc.cfg"); try { auto opt_result = options.parse(argc, argv);