Commit 336a023b authored by Tammo Jan Dijkema's avatar Tammo Jan Dijkema
Browse files

Start big refactor into proper python

parent f354062a
#!/usr/bin/env python
from setuptools import setup, find_packages
from setuptools import setup
meta = dict(name='telescope',
version='1.1.1',
author='Tammo Jan Dijkema',
author_email='T.J.Dijkema@camras.nl',
url='https://gitlab.camras.nl/dijkema/telescope',
description='Software for the CAMRAS Dwingeloo Radio Telescope',
platforms='Linux, Mac OSX',
py_modules=['telescope'],
include_package_data=True,
data_files=[('', ['telescope.ini',]),],
install_requires=['astropy','configparser','numpy']
meta = dict(name = 'telescope',
version = '1.1.1',
author = 'Tammo Jan Dijkema',
author_email = 'T.J.Dijkema@camras.nl',
url = 'https://gitlab.camras.nl/dijkema/telescope',
description = 'Software for the CAMRAS Dwingeloo Radio Telescope',
platforms = 'Linux, Mac OSX',
py_modules = ['telescope'],
include_package_data = True,
data_files=[('', ['telescope.ini',]), ],
install_requires=['astropy', 'configparser', 'numpy']
)
setup(**meta)
......@@ -2,17 +2,16 @@ from __future__ import print_function
import socket
import logging
from astropy.coordinates import SkyCoord, AltAz, RangeError
from astropy import units as u
from astropy.coordinates import SkyCoord, RangeError
from configparser import ConfigParser
import astropy.units as u
import os.path
import numpy as np
import threading
import select
import time
config = ConfigParser()
config.readfp(open(os.path.join(os.path.dirname(__file__), 'telescope.ini')))
config.read_file(open(os.path.join(os.path.dirname(__file__), 'telescope.ini')))
logging.basicConfig(level=logging.DEBUG)
......@@ -20,22 +19,25 @@ _telescope__num_instances = 0
__version__ = "1.1.1"
class telescope():
def __init__(self, setmode=None, consoleHost=None):
'''
Initializes a telescope instance. The mode for writing can be
'J2000' or 'AZEL'.
'''
global __num_instances
if setmode not in ('J2000', 'AZEL', None):
raise ValueError("Mode must be None, 'J2000' or 'AZEL', not " + setmode)
self.setmode = setmode
class Telescope:
def __init__(self, setMode=None, consoleHost=None):
"""
Initializes a telescope instance
:param setMode: The mode for writing. Can be 'J2000' or 'AZEL'
:param consoleHost: Address of the console. E.g. 'console' or 'consoledemo.dmz.camras.nl'
"""
global _telescope__num_instances
if setMode not in ('J2000', 'AZEL', None):
raise ValueError("Mode must be None, 'J2000' or 'AZEL', not " + setMode)
self.setmode = setMode
if consoleHost is None:
consoleHost = config.get('Console','HostName')
consoleHost = config.get('Console', 'HostName')
if consoleHost == 'console':
if socket.gethostname()=="mercurius":
if setMode is not None and socket.gethostname() == "mercurius":
logging.warning("You are using the actual console, not a demo!")
else:
raise ValueError("Talking to the actual console can only be done from mercurius")
......@@ -49,22 +51,22 @@ class telescope():
self.speed_el = None
self.focusbox_pos = None
__num_instances += 1
_telescope__num_instances += 1
if __num_instances != 1:
if _telescope__num_instances != 1:
raise RuntimeError("Do not make more than one telescope instance.")
self._outsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if self.setmode == 'J2000':
try:
self._outsocket.connect((consoleHost,
config.getint('Console','Port_Write_J2000')))
config.getint('Console', 'Port_Write_J2000')))
except socket.gaierror as e:
raise IOError("Could not connect to DT J2000 port: " + str(e))
elif self.setmode == 'AZEL':
try:
self._outsocket.connect((consoleHost,
config.getint('Console','Port_Write_AzEl')))
config.getint('Console', 'Port_Write_AzEl')))
except socket.gaierror as e:
raise IOError("Could not connect to DT AZEL port: " + str(e))
......@@ -73,38 +75,41 @@ class telescope():
self._offsetsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self._offsetsocket.connect((consoleHost,
config.getint('Console','Port_Write_Offset')))
config.getint('Console', 'Port_Write_Offset')))
except socket.gaierror as e:
raise IOError("Could not connect to DT Offset port: " + str(e))
self._event_j2000 = threading.Event()
thread_read_j2000 = threading.Thread(target=self._readj2000, args=(
consoleHost,
config.getint('Console','Port_Read_J2000')))
consoleHost,
config.getint('Console', 'Port_Read_J2000')))
thread_read_j2000.daemon = True
thread_read_j2000.start()
self._event_traces = threading.Event()
thread_read_traces = threading.Thread(target=self._readtraces, args=(
consoleHost,
config.getint('Console', 'Port_Trace2Port')))
consoleHost,
config.getint('Console', 'Port_Trace2Port')))
thread_read_traces.daemon = True
thread_read_traces.start()
def _readj2000(self, consolehost, j2000_read_port):
'''
Poll the socket with the j2000 info, store its values in class members.
'''
def _readj2000(self, consoleHost, j2000_read_port):
"""
Poll the socket with the J2000 info, store its values in class members
:param consoleHost: Hostname
:param j2000_read_port: Port with J200 info
:return: None
"""
try:
self._j2000socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._j2000socket.connect((consolehost, j2000_read_port))
self._j2000socket.connect((consoleHost, j2000_read_port))
except socket.error:
raise IOError("Cannot connect to j2000 status server")
while True:
readable, writable, exceptional = select.select(
[self._j2000socket], [], [])
if len(exceptional)>0:
[self._j2000socket], [], [])
if len(exceptional) > 0:
raise IOError("Error with j2000 read socket")
msg = readable[0].recv(4096).decode("UTF-8")
vals = msg.strip().split()
......@@ -119,6 +124,13 @@ class telescope():
self._event_j2000.set()
def _readtraces(self, tracehost, traceport):
"""
Poll the socket with the traces (a running 'trace2port' instance), store the trace values
in class members
:param tracehost: Hostname
:param traceport: Port at which trace2port is running
:return: None
"""
'''
Poll the socket with the traces, store their values in class members
'''
......@@ -130,21 +142,27 @@ class telescope():
while True:
readable, writable, exceptional = select.select(
[self._tracesocket], [], [])
if len(exceptional)>0:
[self._tracesocket], [], [])
if len(exceptional) > 0:
raise IOError("Error with trace read socket")
msg = readable[0].recv(4096).decode("UTF-8")
vals = msg.strip().split()
self.az = (float(vals[0])*u.rad).to(u.deg)
self.el = (float(vals[1])*u.rad).to(u.deg)
self.dist_az = (float(vals[2])*u.rad).to(u.deg)
self.dist_el = (float(vals[3])*u.rad).to(u.deg)
self.az = (float(vals[0]) * u.rad).to(u.deg)
self.el = (float(vals[1]) * u.rad).to(u.deg)
self.dist_az = (float(vals[2]) * u.rad).to(u.deg)
self.dist_el = (float(vals[3]) * u.rad).to(u.deg)
self.speed_az = float(vals[4])
self.speed_el = float(vals[5])
self.focusbox_pos = float(vals[6])
self._event_traces.set()
def setRaDec(self, setpoint):
"""
Set the J2000 setpoint of the telescope.
Only works if the telescope is in J2000 mode.
:param setpoint: New setpoint. An astropy SkyCoord or a tuple (ra, dec) in radians
:return: None
"""
'''
Set the J2000 setpoint of the telescope.
Only works if the setmode is 'J2000'.
......@@ -155,22 +173,23 @@ class telescope():
raise ValueError("Cannot set Ra/Dec if mode is not J2000")
if isinstance(setpoint, tuple):
coord = SkyCoord(ra =setpoint[0] * u.radian,
dec=setpoint[1] * u.radian)
setpoint = SkyCoord(ra=setpoint[0] * u.radian,
dec=setpoint[1] * u.radian)
(ra, dec) = setpoint.to_string('hmsdms').split()
(ra, dec) = setpoint.to_string('hmsdms').split()
cmd = '{:s}\t{:s}\n'.format(ra, dec.strip('+')).encode('UTF-8')
logging.info('J2000 setpoint sent to DT: {}'.format(cmd))
self._outsocket.send(cmd)
def setAzEl(self, setpoint):
'''
"""
Set the AzEl setpoint of the telescope.
Only works if the setmode is 'AZEL'
setpoint should be a tuple of degrees or of astropy Quantity
'''
:param setpoint: New setpoint. A tuple of floats (interpreted as degrees), or
a tuple of astropy Quantity
:return: None
"""
if self.setmode != 'AZEL':
raise ValueError("Cannot set Az/El if mode is not AZEL")
......@@ -185,11 +204,12 @@ class telescope():
self._outsocket.send(cmd)
def setOffset(self, offset):
'''
"""
Set the offset of the telescope in Az / El.
offset should be a tuple of degrees or of astropy Quantity
'''
:param offset: New setpoint. A tuple of floats (interpreted as radians), or
a tuple of astropy Quantity
:return: None
"""
if self.setmode is None:
raise ValueError("Cannot set offset if mode is None")
......@@ -208,103 +228,109 @@ class telescope():
self._offsetsocket.send(cmd)
def getFocusboxPosition(self, waitForUpdate=False):
'''
Get the focusbox position. If waitForUpdate=True, it waits for the
next signal from the socket.
Returns an astropy quantity
'''
"""
Get the focusbox position.
:param waitForUpdate: wait for the next signal from the socket
:return: Astropy quantity with the focusbox position
"""
if waitForUpdate or self.focusbox_pos is None:
self._event_traces.clear()
self._event_traces.wait()
return self.focusbox_pos * 0.1 * u.m
def getAzEl(self, waitForUpdate=False):
'''
"""
Get azimut and elevation. If waitForUpdate=True, it waits for the
next signal from the socket.
Returns a tuple (az, el) as astropy quantity
'''
"""
if waitForUpdate or self.az is None or self.radec is None:
self._event_traces.clear()
self._event_traces.wait()
return (self.az, self.el)
def getDistance(self, waitForUpdate=False):
'''
"""
Get distance in azimut and elevation. If waitForUpdate=True, it waits
for the next signal from the socket.
Returns a tuple (dist_az, dist_el) as astropy quantity
'''
"""
if waitForUpdate or self.dist_az is None or self.dist_el is None:
self._event_traces.clear()
self._event_traces.wait()
return (self.dist_az, self.dist_el)
def getRaDec(self, waitForUpdate=False):
'''
"""
Get current Ra/Dec. If waitForUpdate=True, it waits for the
next signal from the socket.
Returns an astropy SkyCoord
'''
"""
if waitForUpdate or self.radec is None:
self._event_traces.clear()
self._event_traces.wait()
return self.radec
def getSetpoint_RaDec(self, waitForUpdate=False):
'''
"""
Get current Ra/Dec setpoint. If waitForUpdate=True, it waits for the
next signal from the socket.
Returns an astropy SkyCoord
'''
"""
if waitForUpdate or self.radec is None:
self._event_traces.clear()
self._event_traces.wait()
return self.setpoint_radec
def waitUntilThere(self, tolerance=0.01*u.deg):
'''
def waitUntilThere(self, tolerance=0.01 * u.deg):
"""
Wait until distance to the setpoint gets within tolerance
'''
"""
logging.info("Waiting to reach setpoint")
distIsSmall = False
while not distIsSmall:
diff = self.getDistance(waitForUpdate=True)
distIsSmall = abs(self.dist_el)<tolerance and abs(self.dist_az)<tolerance
distIsSmall = abs(self.dist_el) < tolerance and abs(self.dist_az) < tolerance
def waitUntilMoving(self, tolerance=0.01*u.deg):
'''
def waitUntilMoving(self, tolerance=0.01 * u.deg):
"""
Wait until the telescope reckognizes that it is not at its setpoint
'''
"""
logging.info("Waiting to set setpoint")
distIsBig = False
while not distIsBig:
dist = self.getDistance(waitForUpdate=True)
distIsBig = dist[0]>tolerance or dist[1]>tolerance
distIsBig = dist[0] > tolerance or dist[1] > tolerance
def getJ2000(self):
'''
"""
Generates dicts with 'radec' and 'setpoint_radec',
containing radec and setpoint_radec, at whichever
speed the console is outputting them (probably once a second).
'''
"""
self._event_traces.clear()
while True:
self._event_j2000.wait()
self._event_j2000.clear()
yield({'radec': self.radec,
'setpoint_radec': self.setpoint_radec})
yield ({'radec': self.radec,
'setpoint_radec': self.setpoint_radec})
def getTraces(self):
'''
"""
Generates a dict of all traces from trace2port at whichever
rate trace2port generates them (probably once a second).
'''
"""
self._event_traces.clear()
while True:
self._event_traces.wait()
self._event_traces.clear()
yield({'position_azel': (self.az, self.el),
'distance': (self.dist_az, self.dist_el),
'speed': (self.speed_az, self.speed_el)})
yield ({'position_azel': (self.az, self.el),
'distance': (self.dist_az, self.dist_el),
'speed': (self.speed_az, self.speed_el)})
class telescope(Telescope):
def __init__(self, *args, **kwargs):
super(Telescope, self).__init__(*args, **kwargs)
logging.warning("Please use the new class name Telescope (with capital T)")
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment