# -*- coding: utf-8 -*-
import os
import sys
if sys.platform == 'win32':
import winreg
import time
import math
import numpy as np
import matplotlib.pyplot as plt
import ast
try:
from .mountaxis import Mountaxis
except:
from mountaxis import Mountaxis
try:
from .mounttools import Mounttools
except:
from mounttools import Mounttools
try:
from .mountlog import Mountlog
except:
from mountlog import Mountlog
try:
from .mountpad import Mountpad
except:
from mountpad import Mountpad
path = os.path.join(os.path.dirname(__file__), '..')
if path not in sys.path:
sys.path.append(path)
# --- celme imports
modulename = 'celme'
if modulename in dir():
del celme
if modulename not in dir():
import celme
# #####################################################################
# #####################################################################
# #####################################################################
# Class Mountastro
# #####################################################################
# #####################################################################
# This is an abstract Class
# This class does not communicate to devices
# Use a child class to use the protocol language
# #####################################################################
[docs]class Mountastro(Mounttools):
"""
Class to define a mount.
The first element of args is a string to define the mount type amongst:
* HADEC: Eqquatorial mount.
* HADECROT: Eqquatorial mount + field rotator.
* AZELEV: Altazimutal mount.
* AZELEVROT: Altazimutal mount + field rotator.
Dictionnary of motion parameters are:
* NAME: A string to identify the mount in memory.
* LABEL: A string to identify the mount for prints.
:Example:
::
>>> mymount = Mountastro("HADEC", name = "My telescope")
A mount is constituted of many axes instanciated automatically using the Mountaxis class.
The class Mountastro provides methods to convert astronomical coordinates
into low level orders for controlers (i.e. increments). For example:
* radec_coord(): To read the current position of the mount axes.
* radec_synchronize(): To synchronize the current position of the mount axes.
* radec_goto(): To slew the mount axes to a target position.
These methods are implemented only in simulation mode in the Mountastro class.
All these mods call a second one prefixed by _my_ to communicate physically with
the controller. For example, radec_coord() calls _my_radec_coord(). In the class
Mountastro the methos _my_* are only abstracts. The concrete methods will be defined
in another class specific to the langage of the controller. For exemple the
AstroMECCA commands are written in the class Mount_Astromecca which inherites
metohds of the Mountastro class.
:Example:
::
>>> mymount = Mountastro_Astromecca("HADEC", name = "My telescope")
>>> mymount.set_channel_params("SERIAL", port="COM1", baud_rate=115200)
>>> ra, dec, pierside = mymount.radec_coords()
"""
# === Constant for error codes
NO_ERROR = 0
ERR_UNKNOWN = 1
ERR_FILE_NOT_EXISTS = 101
# === Constants
# === Private variables
_last_errno = NO_ERROR
# --- Axis parameters
axisp = None
axisb = None
# === constants for saving coords
SAVE_NONE = 0
SAVE_AS_SIMU = 1
SAVE_AS_REAL = 2
SAVE_ALL = 3
# === Constants for returning long or short outputs
OUTPUT_SHORT = 0
OUTPUT_LONG = 1
# ===
LX200_0X06 = 0x06
LX200_HIGH_PRECISION = "HIGH PRECISION"
LX200_LOW_PRECISION = "LOW PRECISION"
# === List of Threads for the pad GUI
_threads = []
_drift_hadec_ha_deg_per_sec = 0
_drift_hadec_dec_deg_per_sec = 0
_drift_radec_ra_deg_per_sec = 0
_drift_radec_dec_deg_per_sec = 0
_sideral_sec_per_day = 86164.0
# --- last actions
_last_goto_drift_deg_per_secs = []
# --- slewing and tracking states for ASCOM
_slewing_state = False
_tracking_state = False
# =====================================================================
# =====================================================================
# Private methods
# =====================================================================
# =====================================================================
def _create(self, mount_name, mount_type):
self._delete()
def _delete(self):
self._last_errno = self.NO_ERROR
# =====================================================================
# =====================================================================
# Methods for using a pad GUI
# =====================================================================
# =====================================================================
# to use it:
# mymount = Mountastro("HADEC", name="Test Mount")
# try:
# mymount.pad_create("pad_dev1")
# except (KeyboardInterrupt, SystemExit):
# pass
# except:
# raise
# =====================================================================
def pad_create(self, pad_type):
Mountpad(self, pad_type)
# =====================================================================
# =====================================================================
# Methods for debug
# =====================================================================
# =====================================================================
[docs] def disp(self):
""" Display a summary of the Mount parameters, the current values of encoders and celestial angles.
This method is used to check and debug the mount.
"""
incsimus = ["" for kaxis in range(Mountaxis.AXIS_MAX)]
increals, incsimus = self.read_encs(incsimus)
increalb, rotrealb, celrealb, increalp, rotrealp, celrealp, piersidereal, incsimub, rotsimub, celsimub, incsimup, rotsimup, celsimup, piersidesimu = self.enc2cel(incsimus, output_format=self.OUTPUT_LONG, save=self.SAVE_ALL)
if self._mount_type=="HADEC":
hareal, decreal = self.cel2hadec(celrealb, celrealp, "H0.2", "d+090.1")
hasimu, decsimu = self.cel2hadec(celsimub, celsimup, "H0.2", "d+090.1")
if self._mount_type=="AZELEV":
azreal, elevreal = self.cel2azelev(celrealb, celrealp, "D0.2", "d+090.1")
azsimu, elevsimu = self.cel2azelev(celsimub, celsimup, "D0.2", "d+090.1")
print("{}".format(20*"-"))
print("MOUNT name = {} ".format(self._name))
print("mount_type = {} {}".format(self._mount_type, self._mount_params["CONFIGURATION"]))
print("home = {} ".format(self.site.gps))
for kaxis in range(Mountaxis.AXIS_MAX):
current_axis = self.axis[kaxis]
if current_axis == None:
continue
for disp_real in (False,True):
if disp_real==True and current_axis.real == False:
continue
# --- get inc and compute rot, cel
if disp_real==True:
msg_simu = "REAL"
inc = increals[kaxis]
else:
msg_simu = "SIMU"
inc = incsimus[kaxis]
rot, pierside = current_axis.inc2rot(inc, self.SAVE_NONE)
cel = current_axis.rot2ang(rot, pierside, self.SAVE_NONE)
# --- additional informations
msg_coord = ""
if self._mount_type=="HADEC":
if current_axis.axis_type=="HA":
if disp_real==True:
msg_coord = hareal
else:
msg_coord = hasimu
if current_axis.axis_type=="DEC":
if disp_real==True:
msg_coord = decreal
else:
msg_coord = decsimu
if self._mount_type=="AZELEV":
if current_axis.axis_type=="AZ":
if disp_real==True:
msg_coord = azreal
else:
msg_coord = azsimu
if current_axis.axis_type=="ELEV":
if disp_real==True:
msg_coord = elevreal
else:
msg_coord = elevsimu
# ---
label_pierside = "Unknown"
if pierside==1:
label_pierside = self._mount_params["LABEL_REGULAR"]
elif pierside==-1:
label_pierside = self._mount_params["LABEL_FLIPED"]
# ---
print("{} {} {} {}".format(20*"-",current_axis.name,msg_simu,current_axis.axis_type))
print("inc = {:12.1f} : ".format(inc))
print("rot = {:12.7f} : ".format(rot))
print("pierside = {:d} : {}".format(pierside, label_pierside))
print("cel = {:12.7f} : {} {}".format(cel,current_axis.axis_type,msg_coord))
def set_param(self, key, value):
self._mount_params[key] = value
def get_param(self, key):
keys = self._mount_params.keys()
if key in keys:
value = self._mount_params[key]
else:
value = None
return value
def get_params(self):
return self._mount_params
# =====================================================================
# =====================================================================
# Methods to read the encoders
# =====================================================================
# =====================================================================
# Level 1
# =====================================================================
[docs] def _my_read_encs(self, incsimus:list)->list:
"""
Read the real raw increment values of the axes
:param incsimus: List of simulated increments.
:type incsimus: list
:returns: List of real increments.
:rtype: list
Inputs are simulated increments. Outputs are real increments if a real mount exists.
This is an abstract method. Please overload it according your language protocol to read real increments.
This conversion method is at level 1/4.
"""
# --- abstract method.
# --- Please overload it according your language protocol
increals = incsimus
return increals
[docs] def read_encs(self, simulation_incs:list)->list:
"""
Read the simulated and real raw increment values of the axes
:param incsimus: List of simulated increments.
:type incsimus: list
:returns: List of real increments.
:rtype: list
For the simulation:
* if simulation_incs=="" the value is calculated from simu_update_inc
* if simulation_incs==34.5 the value is taken equal to 34.5
For real:
* if the axis is not real then real=simulated value
* else the encoder is read
Output = Raw calues of encoders (inc)
This conversion method is at level 1/4.
"""
# === Simulated values of inc
incsimus = [0 for kaxis in range(Mountaxis.AXIS_MAX)]
# --- Loop over all the possible axis types
for kaxis in range(Mountaxis.AXIS_MAX):
current_axis = self.axis[kaxis]
if current_axis == None:
continue
# --- This axis is valid. We compute the simulation
simulation_inc = simulation_incs[kaxis]
if isinstance(simulation_inc,(int,float))==True:
incsimus[kaxis] = simulation_inc
else:
incsimus[kaxis] = current_axis.simu_update_inc()
# === Read real values of inc if possible
increals = self._my_read_encs(incsimus)
# ---
if self._record_positions==True:
with open("positions.txt","a",encoding='utf-8') as fid:
msg = "{} {} {}\n".format(time.time(), increals[Mountaxis.BASE], incsimus[Mountaxis.BASE])
fid.write(msg)
# ---
return (increals, incsimus)
# =====================================================================
# =====================================================================
# Methods to convert encoders into celestial
# =====================================================================
# =====================================================================
# Level 2
# =====================================================================
[docs] def enc2cel(self, simulation_incs:list, output_format=OUTPUT_SHORT, save=SAVE_NONE)->tuple:
"""
Read encoder values and convert them into celestial apparent coordinates
:param simulation_incs: List of simulated increments.
:type simulation_incs: list
:param output_format: OUTPUT_SHORT or OUTPUT_LONG.
:type output_format: int
:param save: SAVE_NONE or SAVE_AS_SIMU or SAVE_AS_REAL or SAVE_ALL.
:type save: int
:returns: Celestial coordinates (degrees)
:rtype: tuple of 3 or 14 elements
Input = Raw encoder values (inc)
Output = HA, Dec, pier side (any celme Angle units)
This conversion method is at level 2/4.
"""
increals, incsimus = self.read_encs(simulation_incs)
# --- shortcuts
axisb = self.axis[Mountaxis.BASE]
axisp = self.axis[Mountaxis.POLAR]
incsimub = incsimus[Mountaxis.BASE]
incsimup = incsimus[Mountaxis.POLAR]
increalb = increals[Mountaxis.BASE]
increalp = increals[Mountaxis.POLAR]
# --- update the axis parameters (start with polar axis to deduce pierside)
# --- update for simulations
if save==self.SAVE_ALL or save==self.SAVE_AS_SIMU:
savesimu = self.SAVE_AS_SIMU
else:
savesimu = self.SAVE_NONE
rotsimup, piersidesimu = axisp.inc2rot(incsimup, savesimu)
celsimup = axisp.rot2ang(rotsimup, piersidesimu, savesimu)
rotsimub, dummy = axisb.inc2rot(incsimub, savesimu)
celsimub = axisb.rot2ang(rotsimub, piersidesimu, savesimu)
# --- update for real
if save==self.SAVE_ALL or save==self.SAVE_AS_REAL:
savereal = self.SAVE_AS_REAL
else:
savereal = self.SAVE_NONE
rotrealp, piersidereal = axisp.inc2rot(increalp, savereal)
celrealp = axisp.rot2ang(rotrealp, piersidereal, savereal)
rotrealb, dummy = axisb.inc2rot(increalb, savereal)
celrealb = axisb.rot2ang(rotrealb, piersidereal, savereal)
# --- select results as simulation or real
if axisp.real == False:
celp = celsimup
pierside = piersidesimu
else:
celp = celrealp
pierside = piersidereal
if axisb.real == False:
celb = celsimub
else:
celb = celrealb
# ---
if output_format==self.OUTPUT_SHORT:
return celb, celp, pierside
else:
# all angle output
return increalb, rotrealb, celrealb, increalp, rotrealp, celrealp, piersidereal, incsimub, rotsimub, celsimub, incsimup, rotsimup, celsimup, piersidesimu
[docs] def cel2enc(self, celb:float, celp:float, pierside:int, output_format=OUTPUT_SHORT, save=SAVE_NONE) -> tuple:
"""
Convert celestial apparent coordinates into encoder values.
:param celb: Celestial coordinate of the base axis (degrees).
:type celb: float
:param celp: Celestial coordinate of the polar axis (degrees).
:type celp: float
:param pierside: Pier side: Mountaxis().PIERSIDE_AUTO or Mountaxis().PIERSIDE_POS1 or Mountaxis().PIERSIDE_POS2.
:type pierside: int
:param output_format: OUTPUT_SHORT or OUTPUT_LONG.
:type output_format: int
:param save: SAVE_NONE or SAVE_AS_SIMU or SAVE_AS_REAL or SAVE_ALL.
:type save: int
:returns: Increment coordinates
:rtype: tuple of 2 or 14 elements
Input = celb, celp, pier side (deg units)
Output = Raw encoder values (inc)
This conversion method is at level 2/4.
"""
# --- shortcuts
axisb = self.axis[Mountaxis.BASE]
axisp = self.axis[Mountaxis.POLAR]
# --- update for simulations
if save==self.SAVE_ALL or save==self.SAVE_AS_SIMU:
savesimu = self.SAVE_AS_SIMU
else:
savesimu = self.SAVE_NONE
celsimub = celb
celsimup = celp
piersidesimu = pierside
rotsimup = axisp.ang2rot(celsimup, pierside, savesimu)
incsimup = axisp.rot2inc(rotsimup, savesimu)
rotsimub = axisb.ang2rot(celsimub, pierside, savesimu)
incsimub = axisb.rot2inc(rotsimub, savesimu)
# --- update for real
if save==self.SAVE_ALL or save==self.SAVE_AS_REAL:
savereal = self.SAVE_AS_REAL
else:
savereal = self.SAVE_NONE
celrealb = celb
celrealp = celp
piersidereal = pierside
rotrealp = axisp.ang2rot(celrealp, pierside, savereal)
increalp = axisp.rot2inc(rotrealp, savereal)
rotrealb = axisb.ang2rot(celrealb, pierside, savereal)
increalb = axisb.rot2inc(rotrealb, savereal)
# --- select results as simulation or real
if axisp.real == False:
incp = incsimup
else:
incp = increalp
if axisb.real == False:
incb = incsimub
else:
incb = increalb
# --- update the output axis parameters
if output_format==self.OUTPUT_SHORT:
# short output
return incb, incp
else:
# all angle output
return increalb, rotrealb, celrealb, increalp, rotrealp, celrealp, piersidereal, incsimub, rotsimub, celsimup, incsimup, rotsimup, celsimup, piersidesimu
[docs] def speedslew(self, *args)-> tuple:
"""
Update the speed slewing velocities (deg/sec).
The order of velocities must be respected.
:returns: tuple of velocities
:rtype: tuple of 1 to 3 elements
This conversion method is at level 2/4.
"""
argc = len(args)
karg = 0
speedslew = ()
for kaxis in range(Mountaxis.AXIS_MAX):
current_axis = self.axis[kaxis]
if current_axis == None:
continue
# --- read or update the speed
if karg<argc:
current_axis.slew_deg_per_sec = abs(args[karg]) # slew speed is always positive
speedslew += (current_axis.slew_deg_per_sec,)
return speedslew
# =====================================================================
# =====================================================================
# Methods to convert celestial into astronomical coordinates
# =====================================================================
# =====================================================================
# Level 3
# =====================================================================
[docs] def hadec2cel(self, ha:celme.Angle, dec:celme.Angle)->tuple:
"""
Convert (H.A,Dec) coordinates into celestial coordinates.
:param ha: Hour angle (unit defined in celme.Angle).
:type ha: celme.Angle
:param dec: Declination (unit defined in celme.Angle).
:type dec: celme.Angle
:returns: tuple of celestial coordinates (basis, polar, rotation) (degrees)
:rtype: tuple of 3 elements
This conversion method is at level 3/4.
"""
# ---
ha = celme.Angle(ha).deg()
dec = celme.Angle(dec).deg()
# ---
meca = celme.Mechanics()
if self._mount_type.find("HADEC")>=0:
# --- astro coord are HADEC and cel are HADEC
celb = ha
celp = dec
celr = 0
if self._mount_type.find("AZELEV")>=0:
# --- astro coord are HADEC and cel are AZELEV
ha *= self._d2r
dec *= self._d2r
latitude = celme.Angle(self.site.latitude).rad()
az, elev = meca._mc_hd2ah(ha, dec, latitude)
rotator = meca._mc_hd2parallactic(ha, dec, latitude)
celb = az * self._r2d
celp = elev * self._r2d
celr = rotator * self._r2d
# ---
return celb, celp, celr
[docs] def azelev2cel(self, az:celme.Angle, elev:celme.Angle)->tuple:
"""
Convert (azimuth, elevation) coordinates into celestial coordinates.
:param ha: Azimuth (unit defined in celme.Angle).
:type ha: celme.Angle
:param dec: Elevation (unit defined in celme.Angle).
:type dec: celme.Angle
:returns: tuple of celestial coordinates (basis, polar, rotation) (degrees)
:rtype: tuple of 3 elements
This conversion method is at level 3/4.
"""
# ---
az = celme.Angle(az).deg()
elev = celme.Angle(elev).deg()
# ---
meca = celme.Mechanics()
if self._mount_type.find("HADEC")>=0:
# --- astro coord are AZELEV and cel are HADEC
az *= self._d2r
elev *= self._d2r
latitude = celme.Angle(self.site.latitude).rad()
ha, dec= meca._mc_ah2hd(az, elev, latitude)
rotator = meca._mc_hd2parallactic(ha, dec, latitude)
celb = ha * self._r2d
celp = dec * self._r2d
celr = rotator * self._r2d
if self._mount_type.find("AZELEV")>=0:
# --- astro coord are AZELEV and cel are AZELEV
celb = az
celp = elev
celr = 0
# ---
return celb, celp, celr
[docs] def astro2cel(self, astro_type:str, base:celme.Angle, polar:celme.Angle, base_deg_per_sec:str="", polar_deg_per_sec:str="")->tuple:
"""
Convert any astronomical coordinate system (astro_type) into celestial coordinates and the corresponding velocities.
astro_type can be "HADEC" or "AZELEV":
* base = ha or az (according astro_type)
* polar = dec or elev (according astro_type)
* base_deg_per_sec = dha or daz (according astro_type)
* polar_deg_per_sec = ddec or delev (according astro_type)
:param astro_type: Specification of the astronomical coordinate system.
:type astro_type: str
:param base: Hour angle or azimuth (unit defined in celme.Angle).
:type base: celme.Angle
:param polar: Declination or elevation (unit defined in celme.Angle).
:type polar: celme.Angle
:param base_deg_per_sec: Declination or elevation (unit defined in celme.Angle).
:type base_deg_per_sec: celme.Angle
:param base_deg_per_sec: Declination or elevation (unit defined in celme.Angle).
:type base_deg_per_sec: celme.Angle
:returns: tuple of celestial coordinates (basis, polar, rotation) (degrees) and their derivatives (deg/sec)
:rtype: tuple of 6 elements
This conversion method is at level 3/4.
"""
base = celme.Angle(base).deg()
polar = celme.Angle(polar).deg()
# --- special case when the drifts are sideral
if base_deg_per_sec=="sideral" or polar_deg_per_sec=="sideral":
# --- compute ha,dec
if astro_type.find("AZELEV")>=0:
meca = celme.Mechanics()
# --- here all angles are in radians
latitude = celme.Angle(self.site.latitude).rad()
az = base * self._d2r
elev = polar * self._d2r
ha, dec = meca._mc_ah2hd(az, elev, latitude)
ha *= self._r2d
dec *= self._r2d
if astro_type.find("HADEC")>=0:
ha = base
dec = polar
# ---
if base_deg_per_sec=="sideral":
dha = 360.0/self._sideral_sec_per_day
else:
dha = base_deg_per_sec
if base_deg_per_sec=="sideral":
ddec = 0
else:
ddec = polar_deg_per_sec
astro_type = "HADEC"
base = ha
polar = dec
base_deg_per_sec = dha
polar_deg_per_sec = ddec
# --- compute the derivative
dt = 1.0 # sec
base1 = base - 0.5*dt*base_deg_per_sec
polar1 = polar - 0.5*dt*polar_deg_per_sec
base2 = base + 0.5*dt*base_deg_per_sec
polar2 = polar + 0.5*dt*polar_deg_per_sec
if astro_type.find("HADEC")>=0:
celb1, celp1, celr1 = self.hadec2cel(base1, polar1)
celb2, celp2, celr2 = self.hadec2cel(base2, polar2)
celb, celp, celr = self.hadec2cel(base, polar)
if astro_type.find("AZELEV")>=0:
celb1, celp1, celr1 = self.azelev2cel(base1, polar1)
celb2, celp2, celr2 = self.azelev2cel(base2, polar2)
celb, celp, celr = self.azelev2cel(base, polar)
# ---
dcelb = (celb2-celb1)/dt
dcelp = (celp2-celp1)/dt
dcelr = (celr2-celr1)/dt
return celb, celp, celr, dcelb, dcelp, dcelr
[docs] def cel2astro(self, celb:float, celp:float, unit_ha:str="", unit_dec:str="", unit_az:str="", unit_elev:str="")->tuple:
"""
Convert celestial coordinates into (H.A., Dec) (azimuth, elevation, rotation) astronomical coordinates
It is possible to choice the unit of the outputs for each astronomical coordinate.
:param celb: Celestial base coordinate (degrees).
:type celb: float
:param celp: Celestial polar coordinate (degrees).
:type celp: float
:param unit_ha: Unit of the Hour angle (unit defined in celme.Angle).
:type unit_ha: str
:param unit_dec: Unit of the déclination (unit defined in celme.Angle).
:type unit_dec: str
:param unit_az: Unit of the azimuth (unit defined in celme.Angle).
:type unit_az: str
:param unit_elelv: Unit of the elevation (unit defined in celme.Angle).
:type unit_elev: str
:returns: tuple of celestial coordinates (ha, dec, az, elev, rotation) (degrees)
:rtype: tuple of 5 elements
This conversion method is at level 3/4.
"""
meca = celme.Mechanics()
# --- here all angles are in radians
latitude = celme.Angle(self.site.latitude).rad()
if self._mount_type.find("HADEC")>=0:
ha = celb * self._d2r
dec = celp * self._d2r
az, elev = meca._mc_hd2ah(ha, dec, latitude)
if self._mount_type.find("AZELEV")>=0:
az = celb * self._d2r
elev = celp * self._d2r
ha, dec = meca._mc_ah2hd(az, elev, latitude)
# --- rotator computation
rotator = meca._mc_hd2parallactic(ha, dec, latitude)
# --- conversion into degrees
ha *= self._r2d
dec *= self._r2d
az *= self._r2d
elev *= self._r2d
rotator *= self._r2d
# --- default units
if unit_ha=="":
unit_ha="H0.2"
if unit_dec=="":
unit_ha="d+090.1"
if unit_az=="":
unit_az="D0.2"
if unit_elev=="":
unit_elev="d+090.1"
# --- conversion into sexagesimal if needed
if unit_ha!="deg":
ha = celme.Angle(ha).sexagesimal(unit_ha)
if unit_dec!="deg":
dec = celme.Angle(dec).sexagesimal(unit_dec)
if unit_az!="deg":
az = celme.Angle(az).sexagesimal(unit_az)
if unit_elev!="deg":
elev = celme.Angle(elev).sexagesimal(unit_elev)
return ha, dec, az, elev, rotator
[docs] def cel2hadec(self, celb:float, celp:float, unit_ha:str="", unit_dec:str="")->tuple:
"""
Convert celestial coordinates into (H.A., Dec) astronomical coordinates
It is possible to choice the unit of the outputs for each astronomical coordinate.
:param celb: Celestial base coordinate (degrees).
:type celb: float
:param celp: Celestial polar coordinate (degrees).
:type celp: float
:param unit_ha: Unit of the Hour angle (unit defined in celme.Angle).
:type unit_ha: str
:param unit_dec: Unit of the déclination (unit defined in celme.Angle).
:type unit_dec: str
:returns: tuple of celestial coordinates (ha, dec) (degrees)
:rtype: tuple of 2 elements
This conversion method is at level 3/4.
"""
# ---
ha, dec, az, elev, rotator = self.cel2astro(celb, celp, unit_ha, unit_dec, "", "")
return ha, dec
[docs] def cel2azelev(self, celb:float, celp:float, unit_az:str="", unit_elev:str="")->tuple:
"""
Convert celestial coordinates into (azimuth, elevation, rotation) astronomical coordinates
It is possible to choice the unit of the outputs for each astronomical coordinate.
:param celb: Celestial base coordinate (degrees).
:type celb: float
:param celp: Celestial polar coordinate (degrees).
:type celp: float
:param unit_az: Unit of the azimuth (unit defined in celme.Angle).
:type unit_az: str
:param unit_elelv: Unit of the elevation (unit defined in celme.Angle).
:type unit_elev: str
:returns: tuple of celestial coordinates (az, elev, rotation) (degrees)
:rtype: tuple of 3 elements
This conversion method is at level 3/4.
"""
# ---
ha, dec, az, elev, rotator = self.cel2astro(celb, celp, "", "", unit_az, unit_elev)
return az, elev, rotator
# =====================================================================
# =====================================================================
# Methods hadec for users
# =====================================================================
# =====================================================================
# Level 4
# =====================================================================
[docs] def hadec_travel_compute(self, ha_target:celme.Angle, dec_target:celme.Angle, pierside_target:int=Mountaxis.PIERSIDE_AUTO)->tuple:
"""
Compute the duration of a slewing from the current position to a target.
:param ha_target: Hour angle (unit defined in celme.Angle).
:type ha_target: celme.Angle
:param dec_target: Declination (unit defined in celme.Angle).
:type dec_target: celme.Angle
:param pierside_target: Mountaxis().PIERSIDE_AUTO or Mountaxis().PIERSIDE_POS1 or Mountaxis().PIERSIDE_POS2.
:type pierside_target: int
:returns: tuple of celestial coordinates (elevmin, ts, elevs)
:rtype: tuple of 3 elements
Returned values are:
* elevmin: Minimum elevation (degrees).
* ts: List of time from the start of slewing (sec).
* elevs: List of computed elevations for each element of ts (degrees).
This conversion method is at level 4/4.
"""
# --- shortcuts
axisb = self.axis[Mountaxis.BASE]
axisp = self.axis[Mountaxis.POLAR]
# === Read the current position
incsimus = ["" for kaxis in range(Mountaxis.AXIS_MAX)]
increalb, rotrealb, celrealb, increalp, rotrealp, celrealp, piersidereal, incsimub, rotsimub, celsimup, incsimup, rotsimup, celsimup, piersidesimu = self.enc2cel(incsimus,self.OUTPUT_LONG, self.SAVE_ALL)
if axisb.real==True:
incb_start = increalb
else:
incb_start = incsimub
if axisp.real==True:
incp_start = increalp
pierside_start = piersidereal
else:
incp_start = incsimup
pierside_start = piersidesimu
# === Read the target position
if pierside_target==Mountaxis.PIERSIDE_AUTO:
pierside_target = pierside_start
celb, celp, celr, dcelb, dcelp, dcelr = self.astro2cel("HADEC", ha_target, dec_target, self._hadec_speeddrift_ha_deg_per_sec, self._hadec_speeddrift_dec_deg_per_sec)
increalb, rotrealb, celrealb, increalp, rotrealp, celrealp, piersidereal, incsimub, rotsimub, celsimup, incsimup, rotsimup, celsimup, piersidesimu = self.cel2enc(celb, celp, pierside_target, self.OUTPUT_LONG, self.SAVE_NONE)
if axisb.real==True:
incb_target = increalb
else:
incb_target = incsimub
if axisp.real==True:
incp_target = increalp
else:
incp_target = incsimup
# --- delta incs for the travel (signed incs)
dincb = incb_target - incb_start
dincp = incp_target - incp_start
#print("dincb={} incb_target={} incb_start={} dincp={} incp_target={} incp_start={}".format(dincb, incb_target, incb_start, dincp, incp_target, incp_start))
# --- slew velocity (positive inc/sec)
inc_per_secb = axisb.slew_deg_per_sec * axisb.inc_per_deg
if dincb<0:
inc_per_secb *= -1
inc_per_secp = axisp.slew_deg_per_sec * axisb.inc_per_deg
if dincp<0:
inc_per_secp *= -1
#print("inc_per_secb={} inc_per_secp={}".format(inc_per_secb, inc_per_secp))
# --- delays of slewing (sec)
delayb = abs(dincb / inc_per_secb)
delayp = abs(dincp / inc_per_secp)
if delayb>delayp:
delay = delayb
else:
delay = delayp
return delayb, delayp
#print("delayb={} delayp={} delay={}".format(delayb, delayp, delay))
# --- fraction of a turn of 360 deg (no unit)
fincb = abs(dincb / axisb._inc_per_sky_rev)
fincp = abs(dincp / axisp._inc_per_sky_rev)
if fincb>fincp:
finc = fincb
else:
finc = fincp
# --- Compute the number of positions during the travel
ddeg = 1.0 ; # increment in degrees
npos = math.ceil(finc*360.0/ddeg)
if npos<3:
npos = 3
#print("fincb={} fincp={} finc={}".format(fincb, fincp, finc))
# --- list of positions
ts = np.linspace(0,delay,npos) ; # sec
pincbs = ts * 0
pincps = ts * 0
for kpos in range(0,npos):
t = ts[kpos] ; # sec
pincbs[kpos] = incb_start + inc_per_secb * t
if dincb>=0 and pincbs[kpos]>incb_target:
pincbs[kpos] = incb_target
if dincb<0 and pincbs[kpos]<incb_target:
pincbs[kpos] = incb_target
pincps[kpos] = incp_start + inc_per_secp * t
if dincp>=0 and pincps[kpos]>incp_target:
pincps[kpos] = incp_target
if dincp<0 and pincps[kpos]<incp_target:
pincps[kpos] = incp_target
print("pincbs={} pincps={}".format(pincbs, pincps))
# --- utc time
#jdnow = celme.Date("now").jd()
#jds = jdnow + ts/86400.
# --- compute the az,elev
azims = ts * 0
elevs = ts * 0
elevmin = 90
incposs = ["" for kaxis in range(Mountaxis.AXIS_MAX)]
for kpos in range(0,npos):
incposs[Mountaxis.BASE] = pincbs[kpos] ; # inc
incposs[Mountaxis.POLAR] = pincbs[kpos] ; # inc
celb, celp, pierside = self.enc2cel(incposs,self.OUTPUT_SHORT, self.SAVE_NONE)
ha, dec, az, elev, rotator = self.cel2astro(celb, celp, unit_ha="deg", unit_dec="deg", unit_az="deg", unit_elev="deg")
azims[kpos] = az
elevs[kpos] = dec
elevmin = np.amin(elevs)
# --- return
return elevmin, ts, elevs
def _my_hadec_synchronize(self, ha:celme.Angle, dec:celme.Angle, pierside:int="")->tuple:
# --- abstract method.
# --- Please overload it according your language protocol
err = self.NO_ERROR
res = 0
return err, res
[docs] def hadec_synchronize(self, ha:celme.Angle, dec:celme.Angle, pierside:int="")-> tuple:
"""
Synchronize the encoders of the current position with the given astronomical coordinates.
:param ha: Hour angle (unit defined in celme.Angle).
:type ha: celme.Angle
:param dec: Declination (unit defined in celme.Angle).
:type dec: celme.Angle
:param pierside:
* Mountaxis().PIERSIDE_AUTO
* Mountaxis().PIERSIDE_POS1
* Mountaxis().PIERSIDE_POS2.
:type pierside: int
:returns: tuple of astronomical coordinates (ha, dec, pierside)
:rtype: tuple of 3 elements
:Example:
::
>>> mymount = Mountastro("HADEC", name = "My telescope")
>>> mymount.hadec_synchronize("12h28m47s", "+5d45m28s", Mountaxis().PIERSIDE_POS1)
"""
# === Read the current position
incsimus = ["" for kaxis in range(Mountaxis.AXIS_MAX)]
increalb, rotrealb, celrealb, increalp, rotrealp, celrealp, piersidereal, incsimub, rotsimub, celsimub, incsimup, rotsimup, celsimup, piersidesimu = self.enc2cel(incsimus, self.OUTPUT_LONG, self.SAVE_ALL)
# === Assign the side at the current position if not notified
if pierside=="":
pierside = piersidereal
# === Target celestial position
celb, celp, celr = self.hadec2cel(ha, dec)
# --- update inc0 on each axis
for kaxis in range(Mountaxis.AXIS_MAX):
current_axis = self.axis[kaxis]
if current_axis == None:
continue
if current_axis.real==True:
if kaxis == Mountaxis.BASE:
inc = increalb
cel = celb
elif kaxis == Mountaxis.POLAR:
inc = increalp
cel = celp
else:
if kaxis == Mountaxis.BASE:
inc = incsimub
cel = celb
elif kaxis == Mountaxis.POLAR:
inc = incsimup
cel = celp
print("kaxis={} inc={} cel={}".format(kaxis,inc,cel))
current_axis.update_inc0(inc, cel, pierside)
# --- Real inits
err,res = self._my_hadec_synchronize(ha, dec, pierside)
# --- return the current new position
return self.hadec_coord()
[docs] def hadec_coord(self, **kwargs:dict)->tuple:
"""
Read the current astronomical coordinates.
:param kwargs: Parameters for output units.
:type kwargs: dict
:returns: tuple of (ha, dec, pierside)
:rtype: tuple
Dictionnary of unit parameters are:
* UNIT_HA: A string (uspzad format).
* UNIT_DEC: A string (uspzad format).
:Example:
::
>>> mymount = Mountastro("HADEC", name = "My telescope")
>>> mymount.hadec_coords("H0.2", "d+090.1")
"""
# --- Dicos of optional and mandatory parameters
params_optional = {}
params_optional["UNIT_HA"] = (str,'H0.2')
params_optional["UNIT_DEC"] = (str,'d+090.1')
params_mandatory = {}
# --- Decode parameters
params = self.decode_kwargs(params_optional, params_mandatory, **kwargs)
# --- Get the simu and real coordinates of all axis
incsimus = ["" for kaxis in range(Mountaxis.AXIS_MAX)]
celb, celp, pierside = self.enc2cel(incsimus,self.OUTPUT_SHORT, self.SAVE_ALL)
ha, dec = self.cel2hadec(celb, celp, params["UNIT_HA"], params["UNIT_DEC"])
return ha, dec, pierside
def _my_hadec_drift(self, hadec_speeddrift_ha_deg_per_sec:float, hadec_speeddrift_dec_deg_per_sec:float):
# --- abstract method.
# --- Please overload it according your language protocol
err = self.NO_ERROR
res = 0
return err, res
[docs] def hadec_drift(self, hadec_speeddrift_ha_deg_per_sec:float, hadec_speeddrift_dec_deg_per_sec:float):
"""
Drift the mount
:param hadec_speeddrift_ha_deg_per_sec: Hour angle drift (deg/sec)
:type hadec_speeddrift_ha_deg_per_sec: float
:param hadec_speeddrift_dec_deg_per_sec: Declination drift (deg/sec)
:type hadec_speeddrift_dec_deg_per_sec: float
:Example:
::
>>> mymount = Mountastro("HADEC", name = "My telescope")
>>> mymount.hadec_drift(0.0,-0.05)
"""
err = self.NO_ERROR
res = 0
ha_target = 0 # any value is correct
dec_target = 0 # any value is correct
# --- drifts after slewing
param = hadec_speeddrift_ha_deg_per_sec
if param == "sideral":
param = 360.0/self._sideral_sec_per_day
else:
param = float(param)
hadec_speeddrift_ha_deg_per_sec = param
param = hadec_speeddrift_dec_deg_per_sec
if param == "sideral":
param = 0
else:
param = float(param)
hadec_speeddrift_dec_deg_per_sec = param
# --- Update the drift parmeters for next movings
self._hadec_speeddrift_ha_deg_per_sec = hadec_speeddrift_ha_deg_per_sec
self._hadec_speeddrift_dec_deg_per_sec = hadec_speeddrift_dec_deg_per_sec
# --- Compute incs of the target and the drifts (for any mount_type)
celb, celp, celr, dcelb, dcelp, dcelr = self.astro2cel("HADEC", ha_target, dec_target, hadec_speeddrift_ha_deg_per_sec, hadec_speeddrift_dec_deg_per_sec)
# ---
for kaxis in range(Mountaxis.AXIS_MAX):
current_axis = self.axis[kaxis]
if current_axis == None:
continue
# === Target drift
if kaxis == Mountaxis.BASE:
dcel = dcelb
elif kaxis == Mountaxis.POLAR:
dcel = dcelp
elif kaxis == Mountaxis.ROTATOR:
dcel = dcelr
# === Drift Velocity inc/sec
inc_per_sec_drift = dcel * current_axis.senseinc * current_axis.inc_per_deg
if self.site.latitude>=0:
inc_per_sec_drift *= -1
# === Simulation. It runs even if there is a real hardware)
current_axis.simu_motion_start("DRIFT", frame='inc', drift=inc_per_sec_drift)
# === Real hardware
err, res = self._my_hadec_drift( hadec_speeddrift_ha_deg_per_sec, hadec_speeddrift_dec_deg_per_sec )
# --- Update ASCOM attributes
self.slewing_state = False
self.tracking_state = True
# ---
return (err, res)
def _my_hadec_goto(self, ha_target, dec_target, pierside_target):
# --- abstract method.
# --- Please overload it according your language protocol
err = self.NO_ERROR
res = 0
return err, res
[docs] def hadec_goto(self, ha:celme.Angle, dec:celme.Angle, **kwargs):
"""
Slew the mount to a target defined by astronomical coordinates.
:param ha: Hour angle target (unit defined in celme.Angle).
:type ha: celme.Angle
:param dec: Declination target (unit defined in celme.Angle).
:type dec: celme.Angle
:param kwargs: Parameters for pointing.
:type kwargs: dict
Dictionnary of pointing parameters are:
* BLOCKING: A boolean to block the programm until the mount is arrived (False by default).
* SIDE: Integer to indicate the back flip action:
* PIERSIDE_AUTO (=0) back flip is performed if needed
* PIERSIDE_POS1 (=1) pointing in normal position
* PIERSIDE_POS2 (=-1) pointing in back flip position
:Example:
::
>>> mymount = Mountastro("HADEC", name = "My telescope")
>>> mymount.hadec_goto("12h28m47s", "+5d45m28s", side = Mountaxis().PIERSIDE_AUTO)
"""
err = self.NO_ERROR
res = 0
# --- Dicos of optional and mandatory parameters
params_optional = {}
params_optional["BLOCKING"] = (bool,False)
params_optional["SIDE"] = (int,Mountaxis.PIERSIDE_AUTO)
params_optional["DRIFT_HA"] = (str,"0")
params_optional["DRIFT_DEC"] = (str,"0")
params_mandatory = {}
# --- Decode parameters
params = self.decode_kwargs(params_optional, params_mandatory, **kwargs)
# === Read the current position
incsimus = ["" for kaxis in range(Mountaxis.AXIS_MAX)]
celb, celp, pierside = self.enc2cel(incsimus,self.OUTPUT_SHORT, self.SAVE_ALL)
ha_start, dec_start = self.cel2hadec(celb, celp, "deg", "deg")
pierside_start = pierside
# === Target celestial position for slewing
# --- convert angles into deg [-180 ; 180]
ha_target = math.fmod(720+celme.Angle(ha).deg(), 360)
if ha_target>180:
ha_target -= 360
dec_target = math.fmod(720+celme.Angle(dec).deg(), 360)
if dec_target>180:
dec_target -= 360
# --- compute the target pierside
if self.get_param("CAN_REVERSE")==True:
lim_side_east = self.get_param("LIME_REVERSE") ; # Tube west = PIERSIDE_POS1 = [-180 : lim_side_east]
lim_side_west = self.get_param("LIMW_REVERSE") ; # Tube east = PIERSIDE_POS2 = [lim_side_west : +180]
if params["SIDE"]==Mountaxis.PIERSIDE_AUTO:
if ha_target>lim_side_west and ha_target<lim_side_east:
# --- the target position is in the both possibilitiy range
pierside_target = pierside_start
else:
if ha_target>lim_side_east:
# --- the target is after the limit of side=PIERSIDE_POS1
pierside_target = Mountaxis.PIERSIDE_POS2
else:
# --- the target is before the limit of side=PIERSIDE_POS2
pierside_target = Mountaxis.PIERSIDE_POS1
else:
pierside_target = params["SIDE"]
else:
pierside_target = Mountaxis.PIERSIDE_POS1
#print("ha_start={:.4f} ha_target={:.4f} pierside_start={} params[\"SIDE\"]={} pierside_target={}".format(ha_start, ha_target, pierside_start, params["SIDE"], pierside_target))
# --- drifts after slewing
param = params["DRIFT_HA"]
if param == "sideral":
param = 360.0/self._sideral_sec_per_day
else:
param = float(param)
hadec_speeddrift_ha_deg_per_sec = param
param = params["DRIFT_DEC"]
if param == "sideral":
param = 0
else:
param = float(param)
hadec_speeddrift_dec_deg_per_sec = param
#print("HADEC drifts : {} {}".format(hadec_speeddrift_ha_deg_per_sec,hadec_speeddrift_dec_deg_per_sec))
# --- Update the drift parmeters for next movings
self._hadec_speeddrift_ha_deg_per_sec = hadec_speeddrift_ha_deg_per_sec
self._hadec_speeddrift_dec_deg_per_sec = hadec_speeddrift_dec_deg_per_sec
# --- Compute incs of the target and the drifts (for any mount_type)
#print("GOTO ha={} dec={}".format(ha_target, dec_target))
celb, celp, celr, dcelb, dcelp, dcelr = self.astro2cel("HADEC", ha_target, dec_target, hadec_speeddrift_ha_deg_per_sec, hadec_speeddrift_dec_deg_per_sec)
incb, incp = self.cel2enc(celb, celp, pierside_target, self.OUTPUT_SHORT, self.SAVE_NONE)
increalb, rotrealb, celrealb, increalp, rotrealp, celrealp, piersidereal, incsimub, rotsimub, celsimup, incsimup, rotsimup, celsimup, piersidesimu = self.cel2enc(celb, celp, pierside_target, self.OUTPUT_LONG, self.SAVE_NONE)
#print("celrealb={:.4f} rotrealb={:.4f} pierside_target={} -> increalb={} incb={} incp={}".format(celrealb, rotrealb, piersidereal, increalb, incb, incp))
incr = 0
# ---
for kaxis in range(Mountaxis.AXIS_MAX):
current_axis = self.axis[kaxis]
if current_axis == None:
continue
# === Target position and drift
if kaxis == Mountaxis.BASE:
inc = incb
dcel = dcelb
elif kaxis == Mountaxis.POLAR:
inc = incp
dcel = dcelp
elif kaxis == Mountaxis.ROTATOR:
inc = incr
dcel = dcelr
dslw = current_axis.slew_deg_per_sec
# === Slew Velocity inc/sec
inc_per_sec_slew = dslw * current_axis.senseinc * current_axis.inc_per_deg
# === Drift Velocity inc/sec
inc_per_sec_drift = dcel * current_axis.senseinc * current_axis.inc_per_deg
if self.site.latitude>=0:
inc_per_sec_drift *= -1
# === Simulation. It runs even if there is a real hardware)
current_axis.simu_motion_start("SLEW", frame='inc', velocity=inc_per_sec_slew, position=inc, drift=inc_per_sec_drift)
# === Real hardware
err, res = self._my_hadec_goto(ha_target, dec_target, pierside_target)
# === Wait the end of motion if needed
if params["BLOCKING"]==True and dcelb==0 and dcelb==0 and dcelr==0:
coord1 = self.hadec_coord(unit_ha="deg", unit_dec="deg")
t0 = time.time()
while True:
time.sleep(0.1)
dt = time.time()-t0
if dt>60:
break
coord2 = self.hadec_coord(unit_ha="deg", unit_dec="deg")
if coord1 == coord2:
break
coord1 = coord2
# --- Update ASCOM attributes
self.slewing_state = True
self.tracking_state = False
# ---
return (err, res)
def _my_hadec_move(self, ha_move_deg_per_sec, dec_move_deg_per_sec):
# --- abstract method.
# --- Please overload it according your language protocol
err = self.NO_ERROR
res = 0
return err, res
[docs] def hadec_move(self, ha_move_deg_per_sec, dec_move_deg_per_sec) -> tuple:
"""
Slew or modify the drift of the mount.
:param ha_drift_deg_per_sec: Hour angle velocity (deg/s).
:type ha_drift_deg_per_sec: float
:param dec_drift_deg_per_sec: Declination velocity (deg/s).
:type dec_drift_deg_per_sec: float
:returns: tuple of (error code, result)
:rtype: tuple
:Example:
::
>>> mymount = Mountastro("HADEC", name = "My telescope")
>>> mymount.hadec_move(0.1,-0.2)
"""
err = self.NO_ERROR
res = 0
ha_target = 0 # any value is correct
dec_target = 0 # any value is correct
# --- Compute incs of the target and the drifts (for any mount_type)
celb, celp, celr, dcelb, dcelp, dcelr = self.astro2cel("HADEC", ha_target, dec_target, self._hadec_speeddrift_ha_deg_per_sec, self._hadec_speeddrift_dec_deg_per_sec)
# ---
for kaxis in range(Mountaxis.AXIS_MAX):
current_axis = self.axis[kaxis]
if current_axis == None:
continue
# === Target position and drift
if kaxis == Mountaxis.BASE:
dcel = dcelb
vel = ha_move_deg_per_sec
elif kaxis == Mountaxis.POLAR:
dcel = dcelp
vel = dec_move_deg_per_sec
elif kaxis == Mountaxis.ROTATOR:
dcel = dcelr
vel = 0
# === Slew Velocity inc/sec
inc_per_sec_slew = vel * current_axis.senseinc * current_axis.inc_per_deg
# === Drift Velocity inc/sec
inc_per_sec_drift = dcel * current_axis.senseinc * current_axis.inc_per_deg
if self.site.latitude>=0:
inc_per_sec_drift *= -1
# === Simulation. It runs even if there is a real hardware)
current_axis.simu_motion_start("MOVE", frame='inc', velocity=inc_per_sec_slew, drift=inc_per_sec_drift)
# === Real hardware
err, res = self._my_hadec_move(ha_move_deg_per_sec, dec_move_deg_per_sec)
# --- Update ASCOM attributes
self.slewing_state = True
self.tracking_state = False
# ---
return err, res
def _my_hadec_move_stop(self):
# --- abstract method.
# --- Please overload it according your language protocol
err = self.NO_ERROR
res = 0
return err, res
[docs] def hadec_move_stop(self):
"""
Stop the mount motion.
:Example:
::
>>> mymount = Mountastro("HADEC", name = "My telescope")
>>> mymount.hadec_move_stop()
"""
err = self.NO_ERROR
res = 0
# --- shortcuts
axisb = self.axis[Mountaxis.BASE]
axisp = self.axis[Mountaxis.POLAR]
# === Simulation. It runs even if there is a real hardware)
axisb.simu_motion_stop_move()
axisp.simu_motion_stop_move()
# === Real hardware
err, res = self._my_hadec_move_stop()
# --- Update ASCOM attributes
self.slewing_state = False
self.tracking_state = True
# ---
return err, res
def _my_hadec_stop(self):
# --- abstract method.
# --- Please overload it according your language protocol
err = self.NO_ERROR
res = 0
return err, res
[docs] def hadec_stop(self):
"""
Stop any motion of the mount.
:returns: tuple of (error code, result)
:rtype: tuple
:Example:
::
>>> mymount = Mountastro("HADEC", name = "My telescope")
>>> mymount.hadec_stop()
"""
# === Real hardware
err, res = self._my_hadec_stop()
# === Read the current position
incsimus = ["" for kaxis in range(Mountaxis.AXIS_MAX)]
celb, celp, pierside = self.enc2cel(incsimus,self.OUTPUT_SHORT, self.SAVE_ALL)
# === Stop the simulation and update the simulated position by the real one if exists
for kaxis in range(Mountaxis.AXIS_MAX):
current_axis = self.axis[kaxis]
if current_axis == None:
continue
current_axis.simu_motion_stop()
if current_axis.real == True:
current_axis.synchro_real2simu()
# --- Update ASCOM attributes
self.slewing_state = False
self.tracking_state = False
# ---
return err, res
def hadec_park(self, ha:celme.Angle, dec:celme.Angle, pierside:int):
# === Target celestial position for slewing
# --- convert angles into deg [-180 ; 180]
ha_target = math.fmod(720+celme.Angle(ha).deg(), 360)
if ha_target>180:
ha_target -= 360
dec_target = math.fmod(720+celme.Angle(dec).deg(), 360)
if dec_target>180:
dec_target -= 360
#err, res = self._my_goto_park(incb, incp, incr)
params = {}
params["DRIFT_HA"] = 0
params["DRIFT_DEC"] = 0
params["SIDE"] = pierside
# --- cal the HADEC GOTO
err, res = self.hadec_goto(ha_target, dec_target, **params)
# --- Update ASCOM attributes
#self.slewing_state = True
#self.tracking_state = False
# ---
return err, res
# =====================================================================
# =====================================================================
# Methods radec for users
# =====================================================================
# =====================================================================
# Level 4
# =====================================================================
def radec_app2cat(self, jd, ha, dec, params):
longuai = self.site.longitude*self._d2r
ha *= self._d2r
dec *= self._d2r
meca = celme.Mechanics()
ra = meca._mc_hd2ad(jd, longuai, ha)
equinox = celme.Date(params["EQUINOX"]).jd()
# --- calcul de la precession ---*/
#print("ha={} ra={} equinox={}".format(ha,ra,equinox))
ra_equinox, dec_equinox = meca._mc_precad(jd,ra,dec,equinox)
#ra_equinox, dec_equinox = (ra,dec)
#print("ra_2000={} dec_2000={}".format(ra_equinox/self._d2r,dec_equinox/self._d2r))
ra_equinox *= self._r2d
dec_equinox *= self._r2d
#print("ha={} dec={} ra={} ra_2000={} dec_2000={}".format(ha/self._d2r,dec/self._d2r,ra/self._d2r,ra_equinox,dec_equinox))
return ra_equinox, dec_equinox
[docs] def radec_coord(self, **kwargs):
"""
Read the current astronomical coordinates.
:param kwargs: Parameters for output units.
:type kwargs: dict
:returns: tuple of (ra, dec, pierside)
:rtype: tuple
Dictionnary of unit parameters are:
* EQUINOX: Equinox of the ra,dec coordinates (J2000 by default).
* UNIT_RA: A string (uspzad format).
* UNIT_DEC: A string (uspzad format).
:Example:
::
>>> mymount = Mountastro("HADEC", name = "My telescope")
>>> mymount.radec_coords("H0.2", "d+090.1")
"""
# --- Dicos of optional and mandatory parameters
params_optional = {}
params_optional["UNIT_RA"] = (str,'H0.2')
params_optional["UNIT_DEC"] = (str,'d+090.1')
params_optional["EQUINOX"] = (str,'J2000')
params_mandatory = {}
# --- Decode parameters
params = self.decode_kwargs(params_optional, params_mandatory, **kwargs)
# --- Get HA,Dec
ha, dec, pierside = self.hadec_coord(UNIT_HA="deg",UNIT_DEC="deg")
jd = celme.Date("now").jd()
# --- app2cat
ra_equinox, dec_equinox = self.radec_app2cat(jd, ha, dec, params)
# --- Output unit conversion
if params["UNIT_RA"]!="deg":
ra_equinox = celme.Angle(ra_equinox).sexagesimal(params["UNIT_RA"])
if params["UNIT_DEC"]!="deg":
dec_equinox = celme.Angle(dec_equinox).sexagesimal(params["UNIT_DEC"])
return ra_equinox, dec_equinox, pierside
def radec_cat2app(self, jd, ra_equinox, dec_equinox, params):
equinox = celme.Date(params["EQUINOX"]).jd()
meca = celme.Mechanics()
ra_equinox *= self._d2r
dec_equinox *= self._d2r
# --- calcul de la precession ---*/
ra, dec = meca._mc_precad(equinox,ra_equinox,dec_equinox,jd)
#print("ra({})={} dec({})={}".format(params["EQUINOX"], ra_equinox*self._r2d, params["EQUINOX"], dec_equinox*self._r2d))
#print("ra(date)={} dec(date)={}".format(ra*self._r2d, dec*self._r2d))
#ra, dec = (ra_equinox,dec_equinox)
longuai = celme.Angle(self.site.longitude).rad()
ha = meca._mc_ad2hd(jd, longuai, ra)
ha *= self._r2d
dec *= self._r2d
return ha, dec
[docs] def radec_synchronize(self, ra_angle:celme.Angle, dec_angle:celme.Angle, **kwargs)->tuple:
"""
Synchronize the encoders of the current position with the given astronomical coordinates.
:param ra_angle: Right ascension (unit defined in celme.Angle).
:type ra_angle: celme.Angle
:param dec_angle: Declination (unit defined in celme.Angle).
:type dec_angle: celme.Angle
:param pierside:
* Mountaxis().PIERSIDE_AUTO
* Mountaxis().PIERSIDE_POS1
* Mountaxis().PIERSIDE_POS2.
:type pierside: int
:param kwargs: Pointing parameters
:type kwargs: dict
:returns: tuple of astronomical coordinates (ra, dec, pierside)
:rtype: tuple of 3 elements
Dictionnary of pointing parameters are:
* EQUINOX: Equinox of the ra,dec coordinates (J2000 by default).
* SIDE: Integer to indicate the back flip action:
* PIERSIDE_AUTO (=0) back flip is performed if needed
* PIERSIDE_POS1 (=1) pointing in normal position
* PIERSIDE_POS2 (=-1) pointing in back flip position
:Example:
::
>>> mymount = Mountastro("HADEC", name = "My telescope")
>>> mymount.radec_synchronize("12h28m47s", "+5d45m28s", Mountaxis().PIERSIDE_POS1)
"""
# --- Dicos of optional and mandatory parameters
params_optional = {}
params_optional["EQUINOX"] = (str,'J2000')
params_optional["SIDE"] = (int,Mountaxis.PIERSIDE_AUTO)
params_mandatory = {}
# --- Decode parameters
params = self.decode_kwargs(params_optional, params_mandatory, **kwargs)
pierside_target = params["SIDE"]
# --- Get HA,Dec
ra_equinox = celme.Angle(ra_angle).deg()
dec_equinox = celme.Angle(dec_angle).deg()
jd = celme.Date("now").jd()
# --- cat2app
ha_target, dec_target = self.radec_cat2app(jd, ra_equinox, dec_equinox,params)
self.hadec_synchronize(ha_target, dec_target, pierside_target)
return self.radec_coord()
[docs] def radec_goto(self, ra_angle:celme.Angle, dec_angle:celme.Angle, **kwargs):
"""
Slew the mount to a target defined by astronomical coordinates.
:param ha_angle: Right ascension target (unit defined in celme.Angle).
:type ha_angle: celme.Angle
:param dec_angle: Declination target (unit defined in celme.Angle).
:type dec_angle: celme.Angle
:param kwargs: Parameters for pointing.
:type kwargs: dict
:returns: tuple of (error code, result)
:rtype: tuple
Dictionnary of pointing parameters are:
* EQUINOX: Equinox of the ra,dec coordinates (J2000 by default).
* BLOCKING: A boolean to block the programm until the mount is arrived (False by default).
* SIDE: Integer to indicate the back flip action:
* PIERSIDE_AUTO (=0) back flip is performed if needed
* PIERSIDE_POS1 (=1) pointing in normal position
* PIERSIDE_POS2 (=-1) pointing in back flip position
:Example:
::
>>> mymount = Mountastro("HADEC", name = "My telescope")
>>> mymount.radec_goto("12h28m47s", "+5d45m28s", side = Mountaxis().PIERSIDE_AUTO)
"""
# --- Dicos of optional and mandatory parameters
params_optional = {}
params_optional["EQUINOX"] = (str,'J2000')
params_optional["BLOCKING"] = (bool,False)
params_optional["SIDE"] = (int,Mountaxis.PIERSIDE_AUTO)
params_optional["DRIFT_RA"] = (str,"sideral")
params_optional["DRIFT_DEC"] = (str,"0")
params_mandatory = {}
# --- Decode parameters
params = self.decode_kwargs(params_optional, params_mandatory, **kwargs)
pierside_target = params["SIDE"]
# --- Get HA,Dec
ra_equinox = celme.Angle(ra_angle).deg()
dec_equinox = celme.Angle(dec_angle).deg()
jd = celme.Date("now").jd()
# --- cat2app
ha_target, dec_target = self.radec_cat2app(jd, ra_equinox, dec_equinox, params)
# --- compute the time of slewing
delayb, delayp = self.hadec_travel_compute(ha_target, dec_target, pierside_target)
# --- Temporal offset to anticipate the delay of slewing
dt = 2.4 + delayb ; # (sec)
#print("delayb={} dt={}".format(delayb,dt))
jd += dt/86400
# --- cat2app
ha_target, dec_target = self.radec_cat2app(jd, ra_equinox, dec_equinox, params)
# --- drifts after slewing
param = params["DRIFT_RA"]
if param == "sideral":
param = 0
else:
param = float(param)
param = 360./self._sideral_sec_per_day - param
params["DRIFT_HA"] = param
# -
param = params["DRIFT_DEC"]
if param == "sideral":
param = 0
else:
param = float(param)
params["DRIFT_DEC"] = param
# --- Update the drift parmeters for next movings
self._radec_speeddrift_ha_deg_per_sec = params["DRIFT_HA"]
self._radec_speeddrift_dec_deg_per_sec = params["DRIFT_DEC"]
# --- cal the HADEC GOTO
#print("=== _drift_hadec_ha_deg_per_sec={}".format(self._drift_hadec_ha_deg_per_sec))
err, res = self.hadec_goto(ha_target, dec_target, **params)
# --- Update ASCOM attributes
self.slewing_state = True
self.tracking_state = False
# ---
return (err, res)
# =====================================================================
# =====================================================================
# Methods inc for users
# =====================================================================
# =====================================================================
def _my_inc_goto(self, axis_id:int, inc:float, inc_per_sec_slew:float):
# --- abstract method.
# --- Please overload it according your language protocol
err = self.NO_ERROR
res = 0
return err, res
def inc_goto(self, axis_id:int, inc:float, inc_per_sec_slew:float):
# === Simulation. It runs even if there is a real hardware)
err = self.NO_ERROR
res = 0
kaxis = axis_id
current_axis = self.axis[kaxis]
current_axis.simu_motion_start("ABSOLUTE", frame='inc', velocity=inc_per_sec_slew, position=inc, drift=0)
# === Real
err, res = self._my_inc_goto(axis_id, inc, inc_per_sec_slew)
return err, res
def _my_goto_park(self, incb:float, incp:float, incr:float):
# --- abstract method.
# --- Please overload it according your language protocol
err = self.NO_ERROR
res = 0
return err, res
def goto_park(self, incb="", incp="", incr=""):
err, res = self._my_goto_park(incb, incp, incr)
# --- Update ASCOM attributes
#self.slewing_state = True
#self.tracking_state = False
# ---
return err, res
[docs] def plot_rot(self, lati, azim, elev, rotb, rotp, outfile=""):
"""
Vizualize the rotation angles of the mount according the local coordinates
# --- Site latitude
lati (deg) : Site latitude
# --- Observer view
elev = 15 # turn around the X axis
azim = 140 # turn around the Z axis (azim=0 means W foreground, azim=90 means N foreground)
# --- rob, rotp
"""
if lati=="":
lati = self.site.latitude
if lati>=0:
latitude = lati
cards="SNEW"
else:
latitude = -lati
cards="NSWE"
toplots = []
# --- cartesian frame
options = {"linewisth":0.5}
toplots.append(["text",[0, 0, 0],"o",'k',{}])
toplots.append(["line",[0, 0, 0],[1, 0, 0],'k',options])
toplots.append(["line",[0, 0, 0],[-1, 0, 0],'k',options])
toplots.append(["text",[1, 0, 0],cards[0],'k',{}])
toplots.append(["text",[-1, 0, 0],cards[1],'k',{}])
toplots.append(["text",[0, 1, 0],cards[2],'k',{}])
toplots.append(["text",[0, -1, 0],cards[3],'k',{}])
toplots.append(["line",[0, 0, 0],[0, 1, 0],'k',options])
toplots.append(["line",[0, 0, 0],[0, -1, 0],'k',options])
toplots.append(["line",[0, 0, 0],[0, 0, 1],'k',options])
toplots.append(["line",[0, 0, 0],[0, 0, -1],'k',options])
toplots.append(["text",[0, 0, 1.1],"zenith",'k',options])
# --- great circle tangeant to the projection plane
toplots.append(["circle",1,[[90,0,0], [-elev,0,0], [0,0,-azim]],0,360,'k',options])
#toplots.append(["circle",1,[[90,-elev,-azim]],0,360,'k',{"linewisth":1}])
# --- local horizon
toplots.append(["circle",1,[[0,0,0]],0,360,'k',{"linewisth":0.5}])
# --- local meridian
toplots.append(["circle",1,[[90,0,0]],0,360,'k',{"linewisth":0.5}])
# --- local equator
rotxyzs = [[0, latitude, 0]]
options = {"linewisth":2}
color = 'r'
toplots.append(["circle",1,rotxyzs,0,360,color,options])
toplots.append(["linefrom0",1,rotxyzs,color,options])
toplots.append(["linefrom0",-1,rotxyzs,color,options])
toplots.append(["textfrom0",1.05,rotxyzs,"x",color,options])
rotxyzs = [[0, 0, 90]]
toplots.append(["linefrom0",1,rotxyzs,color,options])
toplots.append(["linefrom0",-1,rotxyzs,color,options])
toplots.append(["textfrom0",1.15,rotxyzs,"y",color,options])
rotxyzs = [[0, latitude+90, 0]]
toplots.append(["linefrom0",1,rotxyzs,color,options])
toplots.append(["linefrom0",-1,rotxyzs,color,options])
toplots.append(["textfrom0",1.05,rotxyzs,"z = visible pole ({})".format(cards[1]),color,options])
# --- pointing Rotp
rotxyzs = [[90,0,0], [0,0,rotb], [0, latitude, 0]]
options = {"linewisth":0.5}
color = 'r'
toplots.append(["circle",1,rotxyzs,0,360,color,options])
options = {"linewisth":2}
color = 'g'
toplots.append(["circle",1,rotxyzs,90,90-rotp,color,options])
rotxyzs = [[0,90-rotp,0], [0,0,rotb], [0, latitude, 0]]
options = {"linewisth":1}
toplots.append(["linefrom0",1,rotxyzs,color,options])
toplots.append(["textfrom0",1.1,rotxyzs,"rotp",color,options])
rotxyzs = [[0,90,0], [0,0,rotb], [0, latitude, 0]]
toplots.append(["linefrom0",1,rotxyzs,color,options])
# --- pointing Rotb
rotxyzs = [[0,0,rotb], [0, latitude, 0]]
options = {"linewisth":2}
color = 'b'
toplots.append(["circle",1,rotxyzs,0,-rotb,color,options])
options = {"linewisth":1}
toplots.append(["linefrom0",1,rotxyzs,color,options])
toplots.append(["textfrom0",1.3,rotxyzs,"rotb",color,options])
rotxyzs = [[0, latitude, 0]]
options = {"linewisth":1}
toplots.append(["linefrom0",1,rotxyzs,color,options])
# ===
fig = plt.figure()
#ax = fig.add_subplot(1,1,1,projection='3d')
#ax.view_init(elev=elev, azim=azim)
ax = fig.add_subplot(1,1,1)
for toplot in toplots:
ptype = toplot[0]
if ptype=="line":
dummy, xyz1, xyz2, color, options = toplot
xyz0s = []
xyz0 = np.array(xyz1)
xyz0s.append(xyz0)
xyz0 = np.array(xyz2)
xyz0s.append(xyz0)
na = len(xyz0s)
elif ptype=="text":
dummy, xyz, text, color, options = toplot
xyz0s = []
xyz0 = np.array(xyz)
xyz0s.append(xyz0)
na = len(xyz0s)
elif ptype=="linefrom0":
dummy, length, rotxyzs, color, options = toplot
xyz0s = []
xyz0 = np.array([0, 0, 0])
xyz0s.append(xyz0)
xyz0 = np.array([length, 0 ,0])
xyz0s.append(xyz0)
na = len(xyz0s)
elif ptype=="textfrom0":
dummy, length, rotxyzs, text, color, options = toplot
xyz0s = []
xyz0 = np.array([length, 0 ,0])
xyz0s.append(xyz0)
na = len(xyz0s)
elif ptype=="circle":
dummy, radius, rotxyzs, ang1, ang2, color, options = toplot
na = 50
alphas =np.linspace(ang1,ang2,na)
# --- cercle dans le plan (x,y)
xyz0s = []
for alpha in alphas:
alpha = math.radians(alpha)
x = radius*math.cos(alpha)
y = radius*math.sin(alpha)
z = 0
xyz0 = np.array([x, y, z])
xyz0s.append(xyz0)
na = len(xyz0s)
else:
continue
# --- rotations
if ptype=="linefrom0" or ptype=="textfrom0" or ptype=="circle":
for rotxyz in rotxyzs:
rotx, roty, rotz = rotxyz
cosrx = math.cos(math.radians(rotx))
sinrx = math.sin(math.radians(rotx))
cosry = math.cos(math.radians(roty))
sinry = math.sin(math.radians(roty))
cosrz = math.cos(math.radians(rotz))
sinrz = math.sin(math.radians(rotz))
rotrx = np.array([ [1, 0, 0], [0, cosrx, -sinrx], [0, sinrx, cosrx] ])
rotry = np.array([ [cosry, 0, -sinry], [0, 1, 0], [sinry, 0, cosry] ])
rotrz = np.array([ [cosrz, -sinrz, 0], [sinrz, cosrz, 0] , [0, 0, 1] ])
xyz1s = []
for xyz in xyz0s:
xyz = np.dot(rotrx, xyz)
xyz = np.dot(rotry, xyz)
xyz = np.dot(rotrz, xyz)
xyz1s.append(xyz)
xyz0s = xyz1s # ready for a second rotation
else:
xyz1s = xyz0s
# --- projections
cosaz = math.cos(math.radians(azim))
sinaz = math.sin(math.radians(azim))
cosel = math.cos(math.radians(elev))
sinel = math.sin(math.radians(elev))
rotaz = np.array([ [cosaz, -sinaz, 0], [sinaz, cosaz, 0] , [0, 0, 1] ])
#rotel = np.array([ [cosel, 0, -sinel], [0, 1, 0], [sinel, 0, cosel] ])
rotel = np.array([ [1, 0, 0], [0, cosel, -sinel], [0, sinel, cosel] ])
xyz2s = []
for xyz in xyz1s:
xyz = np.dot(rotaz, xyz)
xyz = np.dot(rotel, xyz)
xyz2s.append(xyz)
# --- plot
if ptype=="textfrom0" or ptype=="text":
x,y,z = xyz2s[0]
h = ax.text(x,z,text)
h.set_color(color)
else:
for ka in range(0,na-1):
xyz1 = xyz2s[ka]
xyz2 = xyz2s[ka+1]
x = [xyz1[0], xyz2[0]]
y = [xyz1[1], xyz2[1]]
z = [xyz1[2], xyz2[2]]
if y[0]>1e-3 or y[1]>1e-3:
symbol = color+':'
else:
symbol = color+'-'
h = ax.plot(x,z,symbol,'linewidth',1.0)
for option in options.items():
key = option[0]
val = option[1]
if key=="linewisth":
h[0].set_linewidth(val)
# ---
ax.axis('equal')
#fig.patch.set_visible(False)
ax.axis('off')
plt.title("Rotation angles for latitude {} deg".format(lati))
plt.show()
if outfile!="":
plt.savefig(outfile, facecolor='w', edgecolor='w')
#def pad(self, pad_type="dev"):
# self.pad = Mountpad(self,pad_type)
# self.pad.start()
[docs] def remote_command_protocol(self, remote_command_protocol="LX200"):
"""
Set the langage protocol when this code is used as server.
:param remote_command_protocol: Command to execute
:type remote_command_protocol: str
:Example:
::
>>> mymount = Mountastro("HADEC", name = "My telescope")
>>> mymount.remote_command_protocol("LX200")
"""
remote_command_protocol = remote_command_protocol.upper()
self._remote_command_protocol=remote_command_protocol
# === specific default states
if remote_command_protocol=="LX200":
self._remote_command_protocol="LX200"
self._lx200_precision = self.LX200_HIGH_PRECISION
self._lx200_setra_deg = 0.0
self._lx200_setdec_deg = 0.0
self._lx200_24_12_hour_time_format = 24
self._lx200_slew_rate = 5
if remote_command_protocol=="ASCOM":
self._remote_command_protocol="ASCOM"
self._ascom_TargetRightAscension = 0.0
self._ascom_TargetDeclination = 0.0
self._ascom_RightAscensionRate = 0.0 # arcsec/sec
self._ascom_DeclinationRate = 0.0 # arcsec/sec
self._ascom_TrackingRate = 0 # 0=sideral 1=lunar 2=soler 3=King
self._ascom_SideOfPier = -1 # -1=unknown 0=tube east seeing western 1=tube west seeing eastern
def _langage_ascom_trackingrate2hadrift(self)->float:
# 0=sideral 1=lunar 2=soler 3=King
ha_drift_deg_per_sec = 360.0/self._sideral_sec_per_day # sideral
if self._ascom_TrackingRate == 1:
ha_drift_deg_per_sec = 14.685/3600. # lunar
elif self._ascom_TrackingRate == 2:
ha_drift_deg_per_sec = 360.0/86400. # solar
elif self._ascom_TrackingRate == 3:
ha_drift_deg_per_sec = 15.0369/3600. # King
return ha_drift_deg_per_sec
[docs] def _langage_mcs_req_decode(self, command:str)->tuple:
"""
Format of the request messages:
message = "{typemsg: {action: {cmd: val}}}"
typemsg, action, cmd, val = self._langage_mcs_req_decode(command)
"""
message = ""
acolade = 0
cmd = ""
for car in command:
if car=="{":
acolade += 1
if car=="}":
acolade -= 1
cmd += car
if acolade == 0:
# --- end of the command
message = cmd
break
# ---
typemsg = ""
action = ""
cmd = ""
val = ""
# --- cast the str into dict
obj = ast.literal_eval(message)
if isinstance(obj,dict):
typemsg = list(obj.keys())[0]
obj = obj[typemsg]
if isinstance(obj,dict):
action = list(obj.keys())[0]
obj = obj[action]
if isinstance(obj,dict):
cmd = list(obj.keys())[0]
val = obj[cmd]
else:
cmd = str(obj)
else:
action = str(obj)
else:
typemsg = str(obj)
#print("typemsg={} action={} cmd={} val={}".format(typemsg, action, cmd, val))
return typemsg, action, cmd, val
def _my_remote_command_processing(self, command):
# --- abstract method.
# --- Please overload it according your language protocol
res = ""
return res
[docs] def remote_command_processing(self, command):
"""
Execute a command when this code is used as server.
:param command: Command to execute
:type command: str
:returns: error code
:rtype: int
:Example:
::
>>> mymount = Mountastro("HADEC", name = "My telescope")
>>> mymount.remote_command_protocol("LX200")
>>> mymount.remote_command_processing(":GD")
"""
res = ""
if self._remote_command_protocol=="LX200":
#if command.startswith(":GD")!=True and command.startswith(":GR")!=True:
# print("RECU command={}".format(command))
# --- 0x06 - Special command
if command.startswith(chr(6))==True:
res = "P"
# --- C - Sync Control
elif command.startswith(":CM")==True:
self.radec_synchronize(self._lx200_setra_deg, self._lx200_setdec_deg)
# --- G - Get Telescope Information
elif command.startswith(":Gc")==True:
res = str(self._lx200_24_12_hour_time_format)
elif command.startswith(":GC")==True:
iso = celme.Date("now").iso()
res = iso[5:7] + "/" + iso[8:10] + "/" + iso[2:4]
elif command.startswith(":GD")==True:
ra, dec, side = self.radec_coord(UNIT_RA="H:0.0",UNIT_DEC="d:+090.0", equinox="now")
dec = dec[0:3] + "*" + dec[4:6] + "'" + dec[7:9]
if self._lx200_precision == self.LX200_LOW_PRECISION:
dec = dec[0:6]
res = dec
elif command.startswith(":Gg")==True:
deg = self.site.longitude
res = celme.Angle(deg).sexagesimal("d +0180")
res = res[0:4] + "*" + res[5:7]
elif command.startswith(":GL")==True:
iso = celme.Date("now").iso()
res = iso[11:19]
elif command.startswith(":Gm")==True:
ha, dec, side = self.hadec_coord()
if side==1:
res = "W"
else:
res = "E"
elif command.startswith(":GR")==True:
ra, dec, side = self.radec_coord(UNIT_RA="H:0.0",UNIT_DEC="d:+090.0", equinox="now")
if self._lx200_precision == self.LX200_LOW_PRECISION:
sec = int(ra[6:8])
sec = "{:.1f}".format(sec/60.0)
ra = ra[0:5]+sec[1:]
res = ra
elif command.startswith(":Gt")==True:
deg = self.site.latitude
res = celme.Angle(deg).sexagesimal("d +090")
res = res[0:3] + "*" + res[4:6]
# --- H - Time Format Command
elif command.startswith(":H")==True:
if self._lx200_24_12_hour_time_format == 24:
self._lx200_24_12_hour_time_format = 12
else:
self._lx200_24_12_hour_time_format = 24
# --- M - Telescope Movement Commands
elif command.startswith(":Me")==True:
self.hadec_move(self._lx200_slew_rate,0)
elif command.startswith(":Mn")==True:
self.hadec_move(0,-self._lx200_slew_rate)
elif command.startswith(":Ms")==True:
self.hadec_move(0,self._lx200_slew_rate)
elif command.startswith(":Mw")==True:
#print("radec_move({},{})".format(-self._lx200_slew_rate,0))
self.hadec_move(-self._lx200_slew_rate,0)
elif command.startswith(":MS")==True:
self.radec_goto(self._lx200_setra_deg, self._lx200_setdec_deg, equinox="J2000.0")
# --- P - High Precision Toggle
elif command.startswith(":P")==True:
res = self._lx200_precision
# --- Q - Movement Commands
elif command.startswith(":Qe")==True:
self.hadec_move_stop()
elif command.startswith(":Qn")==True:
self.hadec_move_stop()
elif command.startswith(":Qs")==True:
self.hadec_move_stop()
elif command.startswith(":Qw")==True:
self.hadec_move_stop()
elif command.startswith(":Q")==True:
self.hadec_stop()
# --- R - Slew Rate Commands
elif command.startswith(":RC")==True:
self._lx200_slew_rate = 0.5 * 360.0/self._sideral_sec_per_day
elif command.startswith(":RG")==True:
self._lx200_slew_rate = 5 * 360.0/self._sideral_sec_per_day
elif command.startswith(":RM")==True:
self._lx200_slew_rate = 0.5
elif command.startswith(":RS")==True:
self._lx200_slew_rate = 5
# --- S - Telescope Set Commands
elif command.startswith(":Sr")==True:
angle = command[3:]
self._lx200_setra_deg = celme.Angle(angle).deg() * 15.0
res = str(1)
elif command.startswith(":Sd")==True:
angle = command[3:]
self._lx200_setdec_deg = celme.Angle(angle).deg()
res = str(1)
elif command.startswith(":Sg")==True:
angle = command[3:]
self.site.longitude = celme.Angle(angle).deg()
res = str(1)
elif command.startswith(":Sts")==True:
angle = command[3:]
self.site.latitude = celme.Angle(angle).deg()
res = str(1)
# --- U - Precision Toggle
elif command.startswith(":U")==True:
if self._lx200_precision == self.LX200_HIGH_PRECISION:
self._lx200_precision = self.LX200_LOW_PRECISION
else:
self._lx200_precision = self.LX200_HIGH_PRECISION
if self._remote_command_protocol=="MCS":
# --- Split the string to a list of dictionaries
# String example : command = {"req":{"cmd":{"PRESET":5}}}{"req":{"get": ""}}}
# List of dictionaries : commands = ['{"req":{"cmd":{"PRESET":5}}}', '{"req":{"get": ""}}']
#print("MCS {} commands={}".format(self._remote_command_protocol,commands))
# --- Loop over commands
#
# --- process one command
typemsg, action, cmd, val = self._langage_mcs_req_decode(command)
typemsg_found = False
action_found = False
cmd_found = False
err_msg_typemsg = "Type message not found amongst "
err_msg_action = "Action not found amongst "
err_msg_cmd = "Cmd not found amongst "
if typemsg == "req":
typemsg_found = True
if action == "do":
action_found = True
if cmd == "exec":
cmd_found = True
print("val={}".format(val))
exec(f"""locals()['temp'] = {val}""")
response = {cmd : str(locals()['temp'])}
if cmd_found == False:
response = {"error" : err_msg_cmd + "exec."}
if action == "get":
action_found = True
response = []
if cmd == "radec" or cmd == "":
# --- return only radec coords
cmd_found = True
ra, dec, side = self.radec_coord(UNIT_RA="deg",UNIT_DEC="deg")
res = {"ra":ra, "dec":dec, "side":side}
response.append(res)
if cmd == "hadec" or cmd == "":
# --- return only hadec coords
cmd_found = True
ha, dec, side = self.hadec_coord(UNIT_RA="deg",UNIT_DEC="deg")
res = {"ha":ha, "dec":dec, "side":side}
response.append(res)
if cmd_found == False:
response = {"error" : err_msg_cmd + "radec, hadec."}
if action_found == False:
response = {"error" : err_msg_action + "do, get."}
if typemsg_found == False:
response = {"error" : err_msg_typemsg + "req."}
res = {typemsg : {action : {cmd : response}}}
print("{} res={}".format(self._remote_command_protocol,res))
res = str(res)
if self._remote_command_protocol=="ASCOM":
command = command.replace(",",".")
mots = command.split()
print("="*20)
print("mots recus ={}".format(mots))
msg = ""
# ---
if command.startswith("RightAscension")==True:
ra, dec, side = self.radec_coord(UNIT_RA="deg")
print("{} ra={}".format(mots[0],ra))
msg = "{}".format(float(ra)/15.)
# ---
if command.startswith("RightAscensionRate")==True:
n = len(mots)
if n>1:
# --- Set
print("mots[1]={}".format(mots[1]))
self._ascom_RightAscensionRate = float(mots[1])
msg = mots[1]
else:
# --- Get
msg = str(self._ascom_RightAscensionRate)
# ---
if command.startswith("Declination")==True:
ra, dec, side = self.radec_coord(UNIT_DEC="deg")
print("{} dec={}".format(mots[0],dec))
msg = str(dec)
# ---
if command.startswith("SlewToCoordinates")==True or command.startswith("SlewToCoordinatesAsync")==True:
ra = float(mots[1])*15.
dec = float(mots[2])
ra_drift_deg_per_sec = self._langage_ascom_trackingrate2hadrift() - 360.0/self._sideral_sec_per_day
dec_drift_deg_per_sec = 0.0
if self._ascom_RightAscensionRate != 0:
# self._ascom_RightAscensionRate arcsec/sec
ra_drift_deg_per_sec += self._ascom_RightAscensionRate / 3600.0
if self._ascom_DeclinationRate != 0:
dec_drift_deg_per_sec += self._ascom_ascom_DeclinationRate / 3600.0
print("{} ra={} dec={}".format(mots[0],ra,dec))
self.radec_goto(ra, dec, EQUINOX="NOW", RA_DRIFT=ra_drift_deg_per_sec, DEC_DRIFT=dec_drift_deg_per_sec)
# ---
if command.startswith("SlewToTarget")==True or command.startswith("SlewToTargetAsync")==True:
ra = self._ascom_TargetRightAscension * 15
dec = self._ascom_TargetDeclination
ra_drift_deg_per_sec = self._langage_ascom_trackingrate2hadrift() - 360.0/self._sideral_sec_per_day
dec_drift_deg_per_sec = 0.0
if self._ascom_RightAscensionRate != 0:
# self._ascom_RightAscensionRate arcsec/sec
ra_drift_deg_per_sec += self._ascom_RightAscensionRate / 3600.0
if self._ascom_DeclinationRate != 0:
dec_drift_deg_per_sec += self._ascom_ascom_DeclinationRate / 3600.0
print("{} ra={} dec={}".format(mots[0],ra,dec))
self.radec_goto(ra, dec, EQUINOX="NOW", RA_DRIFT=ra_drift_deg_per_sec, DEC_DRIFT=dec_drift_deg_per_sec)
# ---
if command.startswith("SyncToCoordinates")==True or command.startswith("SyncToCoordinatesAsync")==True:
ra = float(mots[1])*15.
dec = float(mots[2])
sideofpier = self._ascom_SideOfPier
side = 0
if sideofpier == 0:
side = -1
if sideofpier == 1:
side = 1
print("{} ra={} dec={}".format(mots[0],ra,dec))
self.radec_synchronize(ra, dec, EQUINOX="NOW", SIDE=side)
# ---
if command.startswith("SyncToTarget")==True or command.startswith("SyncToTargetAsync")==True:
ra = self._ascom_TargetRightAscension * 15
dec = self._ascom_TargetDeclination
sideofpier = self._ascom_SideOfPier
side = 0
if sideofpier == 0:
side = -1
if sideofpier == 1:
side = 1
print("{} ra={} dec={}".format(mots[0],ra,dec))
self.radec_synchronize(ra, dec, EQUINOX="NOW", SIDE=side)
# ---
if command.startswith("MoveAxis")==True:
kaxis = int(mots[1])
rate = float(mots[2])
print("{} kaxis={} move={}".format(mots[0],kaxis,rate))
dra = 0
ddec = 0
if kaxis==0:
dra = rate
ddec = 0
if kaxis==1:
dra = 0
ddec = rate
if rate==0:
self.hadec_move_stop()
else:
self.hadec_move(dra, ddec)
# ---
if command.startswith("Slewing")==True:
self.update_motion_states()
if self.slewing_state==False:
msg = "False"
else:
msg = "True"
# ---
if command.startswith("AbortSlew")==True:
self.hadec_stop()
# ---
if command.startswith("SideOfPier")==True:
# -1=unknown 0=tube east seeing western 1=tube west seeing eastern
n = len(mots)
if n>1:
# --- Set
print("mots[1]={}".format(mots[1]))
self._ascom_SideOfPier = int(mots[1])
msg = mots[1]
else:
# --- Get
ra, dec, side = self.radec_coord(UNIT_RA="deg")
sideofpier = -1
if side==-1:
sideofpier = 0
if side==1:
sideofpier = 1
self._ascom_SideOfPier = sideofpier
msg = str(self._ascom_SideOfPier)
# ---
if command.startswith("Tracking")==True:
n = len(mots)
if n>1:
# --- Set
print("mots[1]={}".format(mots[1]))
if mots[1]=="True":
ha_drift_deg_per_sec = self._langage_ascom_trackingrate2hadrift()
dec_drift_deg_per_sec = 0
if self._ascom_RightAscensionRate != 0:
# self._ascom_RightAscensionRate arcsec/sec
ha_drift_deg_per_sec -= self._ascom_RightAscensionRate / 3600.0
if self._ascom_DeclinationRate != 0:
dec_drift_deg_per_sec += self._ascom_ascom_DeclinationRate / 3600.0
self.hadec_drift(ha_drift_deg_per_sec, dec_drift_deg_per_sec)
elif mots[1]=="False":
self.hadec_stop()
msg = mots[1]
else:
# --- Get
self.update_motion_states()
if self.tracking_state==False:
msg = "False"
else:
msg = "True"
# ---
if command.startswith("TargetRightAscension")==True:
n = len(mots)
if n>1:
# --- Set
print("mots[1]={}".format(mots[1]))
self._ascom_TargetRightAscension = float(mots[1])
msg = mots[1]
else:
# --- Get
msg = str(self._ascom_TargetRightAscension)
# ---
if command.startswith("TargetDeclination")==True:
n = len(mots)
if n>1:
# --- Set
print("mots[1]={}".format(mots[1]))
self._ascom_TargetDeclination = float(mots[1])
msg = mots[1]
else:
# --- Get
msg = str(self._ascom_TargetDeclination)
# ---
if command.startswith("TrackingRate")==True:
n = len(mots)
if n>1:
# --- Set
print("mots[1]={}".format(mots[1]))
trackingRate = int(mots[1])
if trackingRate<0:
trackingRate = 0
if trackingRate>3:
trackingRate = 3
self._ascom_TrackingRate = trackingRate
msg = mots[1]
else:
# --- Get
msg = str(self._ascom_TrackingRate)
# ---
if command.startswith("Park")==True:
ha = 270.0
dec = 90.0
side = 1
print("{} ha={} dec={} side={}".format(mots[0],ha,dec,side))
self.hadec_goto(ha, dec, side=side)
# --- send the EQMOD answer to ASCOM
msg = msg.replace(".",",")
print("msg renvoyé ={}".format(msg))
res = msg
else:
pass
#print("{} res={}".format(self._remote_command_protocol,res))
if res=="":
res = self._my_remote_command_processing(command)
return res
# =====================================================================
# =====================================================================
# ASCOM methods
# =====================================================================
# =====================================================================
def _update_motion_states(self):
# --- abstract method.
# --- Please overload it according your language protocol
axes_motion_state_reals = []
for kaxis in range(Mountaxis.AXIS_MAX):
axes_motion_state_reals.append(Mountaxis.MOTION_STATE_UNKNOWN)
return axes_motion_state_reals
[docs] def update_motion_states(self):
""" Get the current motions states of the axes
:returns: slewing_state, tracking_state, list of axes_motion_states
:rtype: tuple
slewing_state and tracking_state are booleans. These states are computer according the combination of all active axes (real and simulated ones).
axes_motion_states is a list of states for each axis combining real and simulated.
"""
# === Real hardware
axes_motion_state_reals = self._update_motion_states()
# --- Get the current simulated motions
incsimus = ["" for kaxis in range(Mountaxis.AXIS_MAX)]
increals, incsimus = self.read_encs(incsimus)
# --- Combine real and simulation motions
axes_motion_states = []
motion_states = []
for kaxis in range(Mountaxis.AXIS_MAX):
current_axis = self.axis[kaxis]
if current_axis == None:
axes_motion_states.append(Mountaxis.MOTION_STATE_UNKNOWN)
continue
if current_axis.real == True:
motion_state = axes_motion_state_reals[kaxis]
else:
motion_state = current_axis.motion_state_simu
motion_states.append(motion_state)
axes_motion_states.append(motion_state)
# - Count the motion axis states
ks = 0
kd = 0
km = 0
for motion_state in motion_states:
if motion_state == Mountaxis.MOTION_STATE_SLEWING:
ks += 1
if motion_state == Mountaxis.MOTION_STATE_DRIFTING:
kd += 1
if motion_state == Mountaxis.MOTION_STATE_MOVING:
km += 1
# - Set the global motion state
self.slewing_state = False
self.tracking_state = False
if km > 0 or ks > 0:
self.slewing_state = True
self.tracking_state = False
if kd > 0 and km == 0 and km == 0:
self.slewing_state = False
self.tracking_state = True
# --- return slewing, tracking states and all axis states
return self.slewing_state, self.tracking_state, axes_motion_states
[docs] def _get_slewing_state(self) -> bool:
"""
True if telescope is currently moving in response to one of the Slew methods or the MoveAxis(TelescopeAxes, Double) method, False at all other times.
Reading the property will raise an error if the value is unavailable. If the telescope is not capable of asynchronous slewing, this property will always be False. The definition of "slewing" excludes motion caused by sidereal tracking, PulseGuide, RightAscensionRate, and DeclinationRate. It reflects only motion caused by one of the Slew commands, flipping caused by changing the SideOfPier property, or MoveAxis(TelescopeAxes, Double).
"""
return self._slewing_state
[docs] def _set_slewing_state(self, state:bool):
"""
True if telescope is moving in response to one of the Slew methods or the MoveAxis(TelescopeAxes, Double) method, False at all other times.
Internal for the Python code
"""
self._slewing_state = state
[docs] def _get_tracking_state(self) -> bool:
"""
The state of the telescope's sidereal tracking drive.
Tracking Read must be implemented and must not throw a PropertyNotImplementedException.
Tracking Write can throw a PropertyNotImplementedException.
Changing the value of this property will turn the sidereal drive on and off. However, some telescopes may not support changing the value of this property and thus may not support turning tracking on and off. See the CanSetTracking property.
"""
return self._tracking_state
[docs] def _set_tracking_state(self, state:bool):
"""
The state of the telescope's sidereal tracking drive.
See details in the documentation of _get_tracking_state()
"""
self._tracking_state = state
tracking_state = property(_get_tracking_state, _set_tracking_state)
slewing_state = property(_get_slewing_state, _set_slewing_state)
# =====================================================================
# =====================================================================
# Special methods
# =====================================================================
# =====================================================================
def __init__(self, *args, **kwargs):
"""
Conversion from Uniform Python object into protocol language
Usage : Mountastro("HADEC", name="SCX11")
"""
# --- Dico of optional parameters for all axis_types
param_optionals = {}
param_optionals["MODEL"] = (str, "")
param_optionals["MANUFACTURER"] = (str, "")
param_optionals["SERIAL_NUMBER"] = (str, "")
param_optionals["REAL"] = (bool, False)
param_optionals["DESCRIPTION"] = (str, "No description.")
param_optionals["SITE"] = (celme.Site,"GPS 0 E 45 100")
param_optionals["LABEL_REGULAR"] = (str,"Regular")
param_optionals["LABEL_FLIPED"] = (str,"Fliped")
param_optionals["CONFIGURATION"] = (str,"German")
param_optionals["CAN_REVERSE"] = (bool,True)
param_optionals["LIME_REVERSE"] = (float,30)
param_optionals["LIMW_REVERSE"] = (float,-30)
# --- Dico of axis_types and their parameters
mount_types = {}
mount_types["HADEC"]= {"MANDATORY" : {"NAME":[str,"Unknown"]}, "OPTIONAL" : {"LABEL":[str,"Equatorial"]} }
mount_types["HADECROT"]= {"MANDATORY" : {"NAME":[str,"Unknown"]}, "OPTIONAL" : {"LABEL":[str,"Equatorial"]} }
mount_types["AZELEV"]= {"MANDATORY" : {"NAME":[str,"Unknown"]}, "OPTIONAL" : {"LABEL":[str,"Altazimutal"]} }
mount_types["AZELEVROT"]= {"MANDATORY" : {"NAME":[str,"Unknown"]}, "OPTIONAL" : {"LABEL":[str,"Altazimutal"]} }
# --- Decode args and kwargs parameters
self._mount_params = self.decode_args_kwargs(0, mount_types, param_optionals, *args, **kwargs)
# ===
self._mount_type = self._mount_params["SELECTED_ARG"]
self._name = self._mount_params["NAME"]
self._description = self._mount_params["DESCRIPTION"]
self._model = self._mount_params["MODEL"]
self._manufacturer = self._mount_params["MANUFACTURER"]
self._serial_number= self._mount_params["SERIAL_NUMBER"]
# === local
if type(self._mount_params["SITE"])==celme.site.Site:
self.site = self._mount_params["SITE"]
else:
self.site = celme.Home(self._mount_params["SITE"])
# === Initial state real or simulation
real = self._mount_params["REAL"]
# === Initialisation of axis list according the mount_type
self.axis = [None for kaxis in range(Mountaxis.AXIS_MAX)] # or Mountaxis.AXIS_NOT_DEFINED
if self._mount_type.find("HA")>=0:
current_axis = Mountaxis("HA", name = "Hour angle")
current_axis.update_inc0(0,0,current_axis.PIERSIDE_POS1)
self.axis[Mountaxis.BASE] = current_axis
if self._mount_type.find("DEC")>=0:
current_axis = Mountaxis("DEC", name = "Declination")
current_axis.update_inc0(0,90,current_axis.PIERSIDE_POS1)
self.axis[Mountaxis.POLAR] = current_axis
if self._mount_type.find("AZ")>=0:
current_axis = Mountaxis("AZ", name = "Azimuth")
current_axis.update_inc0(0,0,current_axis.PIERSIDE_POS1)
self.axis[Mountaxis.BASE] = current_axis
if self._mount_type.find("ELEV")>=0:
current_axis = Mountaxis("ELEV", name = "Elevation")
current_axis.update_inc0(0,90,current_axis.PIERSIDE_POS1)
self.axis[Mountaxis.POLAR] = current_axis
if self._mount_type.find("ROT")>=0:
current_axis = Mountaxis("ROT", name = "Rotator")
current_axis.update_inc0(0,0,current_axis.PIERSIDE_POS1)
self.axis[Mountaxis.ROT] = current_axis
if self._mount_type.find("ROLL")>=0:
current_axis = Mountaxis("ROLL", name = "Roll")
current_axis.update_inc0(0,0,current_axis.PIERSIDE_POS1)
if self._mount_type.find("PITCH")>=0:
current_axis = Mountaxis("PITCH", name = "Pitch")
current_axis.update_inc0(0,90,current_axis.PIERSIDE_POS1)
self.axis[Mountaxis.POLAR] = current_axis
if self._mount_type.find("YAW")>=0:
current_axis = Mountaxis("YAW", name = "Yaw")
current_axis.update_inc0(0,0,current_axis.PIERSIDE_POS1)
self.axis[Mountaxis.YAW] = current_axis
# === Default Setup
ratio_wheel_puley = 1 ; # 5.25
ratio_puley_motor = 100.0 ; # harmonic reducer
inc_per_motor_rev = 1000.0 ; # IMC parameter. System Confg -> System Parameters - Distance/Revolution
for kaxis in range(Mountaxis.AXIS_MAX):
current_axis = self.axis[kaxis]
if current_axis == None:
continue
current_axis.slewmax_deg_per_sec = 30
current_axis.slew_deg_per_sec = 30
current_axis.real = real
current_axis.latitude = self.site.latitude
current_axis.ratio_wheel_puley = ratio_wheel_puley
current_axis.ratio_puley_motor = ratio_puley_motor
current_axis.inc_per_motor_rev = inc_per_motor_rev
# === Pads
self._pads = []
# === Remote commands
self._remote_command_protocol=""
self.remote_command_protocol("LX200")
if sys.platform == 'win32':
# - not used now but interresting
with winreg.OpenKey(winreg.HKEY_CURRENT_USER,r"Control Panel\International") as access_key:
value, vtype = winreg.QueryValueEx(access_key,'sDecimal')
# === Log positions
self._record_positions = False
# ===
self._hadec_speeddrift_ha_deg_per_sec = 0.0
self._hadec_speeddrift_dec_deg_per_sec = 0.0
self._radec_speeddrift_ha_deg_per_sec = -360.0/self._sideral_sec_per_day
self._radec_speeddrift_dec_deg_per_sec = 0.0
# ===
self.slewing_state = False
self.tracking_state = False
# === Log
path_data = os.getcwd()
self.log = Mountlog(self._name,self.site.gps,path_data)
self.log.print("Launch log")
# #####################################################################
# #####################################################################
# #####################################################################
# Main
# #####################################################################
# #####################################################################
# #####################################################################
if __name__ == "__main__":
cwd = os.getcwd()
example = 4
print("Example = {}".format(example))
if example == 1:
# === SCX11
home = celme.Home("GPS 2.25 E 43.567 148")
site = celme.Site(home)
mount = Mountastro("HADEC", name="Test Mount",site=site)
if example == 2:
home = celme.Home("GPS 2.25 E 43.567 148")
#horizon = [(0,0), (360,0)]
site = celme.Site(home)
mount_scx11 = Mountastro("HADEC", name="Guitalens Mount", manufacturer="Astro MECCA", model="TM350", site=site)
mount_eqmod = Mountastro("HADEC", name="Guitalens Mount", manufacturer="Astro MECCA", model="EQ 6", site=site)
# --- shortcuts
mount_scx11_axisb = mount_scx11.axis[Mountaxis.BASE]
mount_scx11_axisp = mount_scx11.axis[Mountaxis.POLAR]
mount_eqmod_axisb = mount_eqmod.axis[Mountaxis.BASE]
mount_eqmod_axisp = mount_eqmod.axis[Mountaxis.POLAR]
# --- simulation or not
mount_scx11_axisb.real = False
mount_scx11_axisp.real = False
mount_eqmod_axisb.real = False
mount_eqmod_axisp.real = False
# ======= SCX11
incsimus = [0 for kaxis in range(Mountaxis.AXIS_MAX)]
increals, incsimus = mount_scx11.read_encs(incsimus)
# ---
incb, rotb, celb, incp, rotp, celp, pierside, incsimub, rotsimub, celsimub, incsimup, rotsimup, celsimup, piersidesimu = mount_scx11.enc2cel(incsimus, mount_scx11.OUTPUT_LONG, mount_scx11.SAVE_ALL)
print("SCX11 incb={:.0f} rotb={:.3f} celb={:.3f} incp={:.0f} rotp={:.3f} celp={:.3f} pierside={:.0f}".format(incsimub, rotsimub, celsimub, incsimup, rotsimup, celsimup, piersidesimu))
incb, rotb, celb, incp, rotp, celp, pierside, incsimub, rotsimub, celsimub, incsimup, rotsimup, celsimup, piersidesimu = mount_scx11.enc2cel(incsimus, mount_scx11.OUTPUT_LONG, mount_scx11.SAVE_ALL)
print("SCX11 incb={:.0f} rotb={:.3f} celb={:.3f} incp={:.0f} rotp={:.3f} celp={:.3f} pierside={:.0f}".format(incsimub, rotsimub, celsimub, incsimup, rotsimup, celsimup, piersidesimu))
# --- update EQMOD parameters
incb, rotb, celb, incp, rotp, celp, pierside, incsimub, rotsimub, celsimub, incsimup, rotsimup, celsimup, piersidesimu = mount_eqmod.enc2cel(incsimus, mount_scx11.OUTPUT_LONG, mount_scx11.SAVE_ALL)
print("EQMOD incb={:.0f} rotb={:.3f} celb={:.3f} incp={:.0f} rotp={:.3f} celp={:.3f} pierside={:.0f}".format(incsimub, rotsimub, celsimub, incsimup, rotsimup, celsimup, piersidesimu))
incb, rotb, celb, incp, rotp, celp, pierside, incsimub, rotsimub, celsimub, incsimup, rotsimup, celsimup, piersidesimu = mount_eqmod.enc2cel(incsimus, mount_scx11.OUTPUT_LONG, mount_scx11.SAVE_ALL)
print("EQMOD incb={:.0f} rotb={:.3f} celb={:.3f} incp={:.0f} rotp={:.3f} celp={:.3f} pierside={:.0f}".format(incsimub, rotsimub, celsimub, incsimup, rotsimup, celsimup, piersidesimu))
if example == 3:
if False:
# --- Site latitude
latitude = 30
# --- observer view
elev = 15 # tourne autour de l'axe x
azim = 140 # tourne autour de de l'axe z (azim=0 on regarde W devant, azim=90 N devant)
outfile = cwd+"/rotbp_n.png"
else:
# --- Site latitude
latitude = -30
# --- observer view
elev = 15 # tourne autour de l'axe x
azim = 140 # tourne autour de de l'axe z (azim=0 on regarde W devant, azim=90 N devant)
outfile = cwd+"/rotbp_s.png"
# --- rob, rotp
rotb = 60
rotp = 30
home = celme.Home("GPS 2.25 E 43.567 148")
site = celme.Site(home)
mount = Mountastro("HADEC", name="Example Mount", site=site)
mount.plot_rot(latitude, azim, elev, rotb, rotp, outfile)
if example==4:
home = celme.Home("GPS 2.25 E 43.567 148")
#horizon = [(0,0), (360,0)]
site = celme.Site(home)
mount_scx11 = Mountastro("HADEC", name="Guitalens Mount", manufacturer="Astro MECCA", model="TM350", site=site)
# --- shortcuts
mount_scx11_axisb = mount_scx11.axis[Mountaxis.BASE]
mount_scx11_axisp = mount_scx11.axis[Mountaxis.POLAR]
# --- simulation or not
mount_scx11_axisb.real = False
mount_scx11_axisp.real = False
# ======= SCX11
mount_scx11.speedslew(10,10)
ha_start = 70
dec_start = 60
ha_target = 10
dec_target = -25
pierside_target = 1
res = mount_scx11.hadec_travel_compute(ha_target, dec_target, pierside_target)