-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontroller.py
More file actions
177 lines (159 loc) · 6.42 KB
/
controller.py
File metadata and controls
177 lines (159 loc) · 6.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import win32com.client
import datetime
import time
import os
import sys
import logging
import uuid
from astropy.io import fits
filter_positions = [
"Luminance",
"Red",
"Green",
"Blue",
"g'",
"r'",
"i'",
"z'",
"u'",
"B",
"V",
"R",
"I'",
"Ha",
"dark",
"open",
]
class Controller:
telescope = None
camera = None
filter_wheel = None
logger = logging.getLogger(__name__)
def __init__(self, telescope_prog_id, camera_prog_id, filter_wheel_prog_id):
logging.basicConfig(
filename="controller.log",
format="%(asctime)s %(levelname)s:%(message)s",
level=logging.DEBUG,
)
if Controller.telescope is None:
try:
Controller.telescope = win32com.client.Dispatch(telescope_prog_id)
except Exception as e:
Controller.logger.error("Error connecting to telescope: " + str(e))
raise IOError("Error connecting to telescope: " + str(e))
Controller.telescope.Connected = True
Controller.logger.info("Connected to telescope")
print("Connected to telescope")
if Controller.camera is None:
try:
Controller.camera = win32com.client.Dispatch(camera_prog_id)
except Exception as e:
Controller.logger.error("Error connecting to camera: " + str(e))
raise IOError("Error connecting to camera: " + str(e))
Controller.camera.Connected = True
Controller.logger.info("Connected to camera")
print("Connected to camera")
if Controller.filter_wheel is None and filter_wheel_prog_id is not None and filter_wheel_prog_id != "None":
with HiddenPrints():
try:
Controller.filter_wheel = win32com.client.Dispatch(
filter_wheel_prog_id
)
except Exception as e:
Controller.logger.error(
"Error connecting to filter wheel: " + str(e)
)
raise IOError("Error connecting to filter wheel: " + str(e))
Controller.filter_wheel.Connected = True
Controller.logger.info("Connected to filter wheel")
print("Connected to filter wheel")
def disconnect_all(self):
self.disconnect_telescope()
self.disconnect_camera()
self.disconnect_filter_wheel()
def disconnect_telescope(self):
if Controller.telescope and Controller.telescope.Connected:
Controller.telescope.Tracking = False
Controller.telescope.Connected = False
Controller.logger.info("Disconnected from telescope")
def disconnect_camera(self):
if Controller.camera:
Controller.camera.Connected = False
Controller.logger.info("Disconnected from camera")
def disconnect_filter_wheel(self):
if Controller.filter_wheel:
Controller.filter_wheel.Connected = False
Controller.logger.info("Disconnected from filter wheel")
def move_to_target(self, altitude, azimuth):
try:
altitude = float(altitude)
azimuth = float(azimuth)
if altitude < 35 or altitude > 90:
raise ValueError("Altitude must be between 30 and 90")
if azimuth < 0 or azimuth > 360:
raise ValueError("Azimuth must be between 0 and 360")
except ValueError as e:
Controller.logger.error("Coordinates invalid: " + str(e))
self.disconnect_all()
raise e
Controller.logger.info("Slewing to alt: {} az: {}".format(altitude, azimuth))
Controller.telescope.SlewToAltAz(azimuth, altitude)
# Wait for telescope to finish slewing
while Controller.telescope.Slewing:
time.sleep(0.5)
# Ensure tracking after slewing
Controller.telescope.Tracking = True
Controller.logger.info("Slew finished, tracking on")
def change_filter(self, filter_number):
if Controller.filter_wheel is None:
Controller.logger.warn("No filter wheel")
return
try:
filter_number = int(filter_number)
if filter_number < 0 or filter_number > 15:
raise ValueError("Filter number must be between 0 and 15")
except ValueError as e:
Controller.logger.error("Filter number invalid: " + str(e))
self.disconnect_all()
raise e
Controller.logger.info("Changing filter to: {}".format(filter_number))
Controller.filter_wheel.Position = filter_number
while Controller.filter_wheel.Position == -1:
time.sleep(0.1)
Controller.logger.info("Filter change complete")
def take_exposure(self, exposure_time, save_image=False):
# Take an exposure with the camera
Controller.logger.info("Taking exposure of {} seconds".format(exposure_time))
start_time = datetime.datetime.utcnow()
Controller.camera.StartExposure(exposure_time, True)
end_time = start_time + datetime.timedelta(seconds=exposure_time)
while Controller.camera.ImageReady == False:
time.sleep(0.1)
Controller.logger.info("Exposure complete")
if save_image:
image = Controller.camera.ImageArray
file_id = uuid.uuid4().hex
filename = os.path.join(
os.path.abspath(os.path.dirname(__file__)),
"image/{}.fits".format(file_id),
)
hdu = fits.PrimaryHDU(image)
header = hdu.header
header["EXPTIME"] = exposure_time
header["DATE-OBS"] = start_time.isoformat()
header["FILTER"] = filter_positions[Controller.filter_wheel.Position]
header["END_TIME"] = end_time.isoformat()
header["FILE-ID"] = file_id
hdul = fits.HDUList([hdu])
# Write the FITS file
hdul.writeto(filename, overwrite=True)
Controller.logger.info("Image saved to: " + filename)
return (start_time, end_time, file_id, hdul)
return (start_time, end_time)
class HiddenPrints:
def __enter__(self):
self._original_stdout = sys.stdout
sys.stdout = open(os.devnull, "w")
def __exit__(self, exc_type, exc_val, exc_tb):
sys.stdout.close()
sys.stdout = self._original_stdout