Commit 5e858ef9cfe92775903cdd656759ac6b376b0b10
1 parent
55ae73d4
Exists in
master
Prepare ASCOM device camera
Showing
4 changed files
with
218 additions
and
7 deletions
Show diff stats
@@ -0,0 +1,177 @@ | @@ -0,0 +1,177 @@ | ||
1 | +import numpy as np | ||
2 | +import os | ||
3 | +import sys | ||
4 | +import time | ||
5 | +import traceback | ||
6 | + | ||
7 | +paths = ["../../src", "../../../guitastro_device_ascomcam/src"] | ||
8 | +for path in paths: | ||
9 | + if path not in sys.path: | ||
10 | + sys.path.insert(0,path) | ||
11 | + | ||
12 | +from guitastro_device_ascomcam import Device_Ascomcam | ||
13 | + | ||
14 | +from pymodbus.client.sync import ModbusTcpClient | ||
15 | + | ||
16 | +if __name__ == "__main__": | ||
17 | + | ||
18 | + client = ModbusTcpClient(host='172.16.10.10', port=502) | ||
19 | + client.connect() | ||
20 | + | ||
21 | + name = "T1M_FinderCam" | ||
22 | + device = "ASCOM.ASICamera2.Camera" | ||
23 | + model = "ZWO" | ||
24 | + serial_number = "12345" | ||
25 | + description = "Test" | ||
26 | + dev = Device_Ascomcam("ASCOMCAM", transport="USB", name=name, description=description, model=model, serial_number=serial_number, device=device) | ||
27 | + # ------------------------ | ||
28 | + real = False | ||
29 | + dev.open(real) | ||
30 | + # ------------------------ | ||
31 | + cam = dev.components['camera'][1] | ||
32 | + # ------------------------ | ||
33 | + cam.ima.fcontext_create("t1m_guide", "Test autoguiding") | ||
34 | + cam.ima.fcontext = "t1m_guide" | ||
35 | + cam.ima.extension = ".fit" | ||
36 | + rootdir0 = cam.ima.rootdir | ||
37 | + cam.ima.rootdir = os.path.join(rootdir0, "t1m") | ||
38 | + print(f"{cam.__repr__()}") | ||
39 | + | ||
40 | + # ------------------------ | ||
41 | + if real == False: | ||
42 | + import shutil | ||
43 | + fname_in = os.path.join(cam.ima.rootdir, "..", "..", "data", "m57.fit") | ||
44 | + fname_out = os.path.join(cam.ima.rootdir, "m57.fit") | ||
45 | + shutil.copy(fname_in, fname_out) | ||
46 | + | ||
47 | + # ------------------------ | ||
48 | + for k in range(4): | ||
49 | + try: | ||
50 | + if real: | ||
51 | + # ------------------------ | ||
52 | + exptime = 0.001 | ||
53 | + cmd = f"camera SET exptime {exptime}" | ||
54 | + print("*"*20,f"\ncmd => \"{cmd}\"") | ||
55 | + dev.commandstring(cmd) | ||
56 | + # ------------------------ | ||
57 | + cmd = "camera DO ACQ START" | ||
58 | + print("*"*20,f"\ncmd => \"{cmd}\"") | ||
59 | + dev.commandstring(cmd) | ||
60 | + while True: | ||
61 | + time.sleep(0.5) | ||
62 | + # ------------------------ | ||
63 | + cmd = "camera GET timer" | ||
64 | + timer = dev.commandstring(cmd) | ||
65 | + if timer == -1: | ||
66 | + break | ||
67 | + else: | ||
68 | + cam.ima.load(fname_out) | ||
69 | + time.sleep(5) | ||
70 | + # ----------------------- | ||
71 | + astrotable = cam.ima.sextractor(kappa_sigma = 3) | ||
72 | + astrotable.useFileNames = True | ||
73 | + astrotable.fn.fcontext_create("t1m_guide") | ||
74 | + astrotable.fn.fcontext = "t1m_guide" | ||
75 | + astrotable.fn.rootdir = cam.ima.rootdir | ||
76 | + fname = astrotable.fn.join("sextractor.txt") | ||
77 | + astrotable.write(fname, format="astrotable", overwrite=True) | ||
78 | + astrotable.keepcols(['x','y','flux', 'flag', 'fwhm']) | ||
79 | + array = np.array([astrotable.getcol('x'),astrotable.getcol('y'),astrotable.getcol('flux'),astrotable.getcol('flag'),astrotable.getcol('fwhm')]).T | ||
80 | + # --- Sort the matrix by the column index 2 | ||
81 | + array_sorted = array[np.lexsort(([-1]*array[:,[2]]).T)] | ||
82 | + INDX_X = 0 | ||
83 | + INDX_Y = 1 | ||
84 | + INDX_FLUX = 2 | ||
85 | + INDX_FLAG = 3 | ||
86 | + INDX_FWHM = 4 | ||
87 | + astrotable.setcol('x', array_sorted[:,INDX_X]) | ||
88 | + astrotable.setcol('y', array_sorted[:,INDX_Y]) | ||
89 | + astrotable.setcol('flux', array_sorted[:,INDX_FLUX]) | ||
90 | + astrotable.setcol('flag', array_sorted[:,INDX_FLAG]) | ||
91 | + astrotable.setcol('fwhm', array_sorted[:,INDX_FWHM]) | ||
92 | + fname = astrotable.fn.join("sextractor_sorted.txt") | ||
93 | + astrotable.write(fname, format="astrotable", overwrite=True) | ||
94 | + # --- | ||
95 | + naxis1 = cam.ima.getkwd("NAXIS1") | ||
96 | + naxis2 = cam.ima.getkwd("NAXIS2") | ||
97 | + border = 50 | ||
98 | + xmin = border | ||
99 | + xmax = naxis1-border | ||
100 | + ymin = border | ||
101 | + ymax = naxis2-border | ||
102 | + ident_limit = 5 | ||
103 | + ident_limit2 = ident_limit*ident_limit | ||
104 | + nb_star = 5 | ||
105 | + # --- | ||
106 | + if k == 0: | ||
107 | + nlig, ncol = array_sorted.shape | ||
108 | + valids = np.ones(nlig) | ||
109 | + for klig in range(nlig): | ||
110 | + if array_sorted[klig, INDX_FLAG] > 0: | ||
111 | + valids[klig] = 0 | ||
112 | + x = array_sorted[klig, INDX_X] | ||
113 | + if x < xmin or x > xmax: | ||
114 | + valids[klig] = 0 | ||
115 | + y = array_sorted[klig, INDX_Y] | ||
116 | + if y < ymin or y > ymax: | ||
117 | + valids[klig] = 0 | ||
118 | + array_sorted0 = array_sorted.copy() | ||
119 | + else: | ||
120 | + # --- match stars and compute dx, dy | ||
121 | + nlig0, ncol0 = array_sorted0.shape | ||
122 | + nlig, ncol = array_sorted.shape | ||
123 | + decals = [] | ||
124 | + kstar = 0 | ||
125 | + for klig0 in range(nlig0): | ||
126 | + if kstar > nb_star: | ||
127 | + break | ||
128 | + if valids[klig0] == 0: | ||
129 | + continue | ||
130 | + x0 = array_sorted0[klig0, INDX_X] | ||
131 | + y0 = array_sorted0[klig0, INDX_Y] | ||
132 | + for klig in range(nlig): | ||
133 | + x = array_sorted[klig, INDX_X] | ||
134 | + y = array_sorted[klig, INDX_Y] | ||
135 | + if not real: | ||
136 | + x += 0.1*np.random.normal(1) | ||
137 | + y += 0.1*np.random.normal(1) | ||
138 | + dx = x - x0 | ||
139 | + dy = y - y0 | ||
140 | + d2 = dx*dx + dy*dy | ||
141 | + if d2 < ident_limit2: | ||
142 | + # --- same star | ||
143 | + decal = [dx, dy, x0, y0] | ||
144 | + decals.append(decal) | ||
145 | + continue | ||
146 | + kstar += 1 | ||
147 | + decals = np.array(decals) | ||
148 | + #print(f"{decals=}") | ||
149 | + # --- compute median of dx, dy | ||
150 | + dxs = decals[:,0] | ||
151 | + dys = decals[:,1] | ||
152 | + dx_med = np.median(dxs) | ||
153 | + dy_med = np.median(dys) | ||
154 | + print(f"{dx_med=:.2f} {dy_med=:.2f}") | ||
155 | + # ---------------------------- | ||
156 | + if dx_med < 0: | ||
157 | + m_alpha = 54 | ||
158 | + else: | ||
159 | + m_alpha = 55 | ||
160 | + if dy_med < 0: | ||
161 | + m_delta = 50 | ||
162 | + else: | ||
163 | + m_delta = 51 | ||
164 | + client.write_coils(m_alpha, True, unit=0) | ||
165 | + client.write_coils(m_delta, True, unit=0) | ||
166 | + time.sleep(0.3) | ||
167 | + client.write_coils(m_alpha, False, unit=0) | ||
168 | + client.write_coils(m_delta, False, unit=0) | ||
169 | + # ---------------------------- | ||
170 | + | ||
171 | + | ||
172 | + except: | ||
173 | + traceback.print_exc(file=sys.stdout) | ||
174 | + # ------------------------ | ||
175 | + print("*"*20,"\nClose") | ||
176 | + dev.close() | ||
177 | + |
src/guitastro/component_sensor_detector.py
@@ -37,10 +37,18 @@ class ComponentSensorDetectorException(GuitastroException): | @@ -37,10 +37,18 @@ class ComponentSensorDetectorException(GuitastroException): | ||
37 | 37 | ||
38 | ERR_DETECTOR_IS_EXPOSING = 1 | 38 | ERR_DETECTOR_IS_EXPOSING = 1 |
39 | ERR_DETECTOR_IS_READING = 2 | 39 | ERR_DETECTOR_IS_READING = 2 |
40 | + ERR_CANNOT_SET_TEMPERATURE = 3 | ||
41 | + ERR_SUBKEY_COOLER_NOT_VALID = 4 | ||
42 | + ERR_CANNOT_SET_GAIN = 5 | ||
43 | + ERR_ACQUISTION_TIMEOUT = 6 | ||
40 | 44 | ||
41 | - errors = [""]*3 | 45 | + errors = [""]*7 |
42 | errors[ERR_DETECTOR_IS_EXPOSING] = "The detector is in exposure. Cannot start other exposures" | 46 | errors[ERR_DETECTOR_IS_EXPOSING] = "The detector is in exposure. Cannot start other exposures" |
43 | errors[ERR_DETECTOR_IS_READING] = "The detector is reading. Cannot start other exposures" | 47 | errors[ERR_DETECTOR_IS_READING] = "The detector is reading. Cannot start other exposures" |
48 | + errors[ERR_CANNOT_SET_TEMPERATURE] = "Cannot set the temparture of this camera" | ||
49 | + errors[ERR_SUBKEY_COOLER_NOT_VALID] = "Sub key of cooler is not valid" | ||
50 | + errors[ERR_CANNOT_SET_GAIN] = "Cannont set the gain of this camera" | ||
51 | + errors[ERR_ACQUISTION_TIMEOUT] = "Acquisition timeout" | ||
44 | 52 | ||
45 | 53 | ||
46 | class ComponentSensorDetector(ComponentSensorDetectorException, Component, GuitastroTools): | 54 | class ComponentSensorDetector(ComponentSensorDetectorException, Component, GuitastroTools): |
@@ -105,7 +113,7 @@ class ComponentSensorDetector(ComponentSensorDetectorException, Component, Guita | @@ -105,7 +113,7 @@ class ComponentSensorDetector(ComponentSensorDetectorException, Component, Guita | ||
105 | self.siteobs = Siteobs(self._sensor_params["SITE"]) | 113 | self.siteobs = Siteobs(self._sensor_params["SITE"]) |
106 | # === Image in memory | 114 | # === Image in memory |
107 | self.ima = Ima() | 115 | self.ima = Ima() |
108 | - self.ima.longitude(self.siteobs.longitude) | 116 | + self.ima.longitude = self.siteobs.longitude |
109 | if str(type(self._sensor_params["ETC"])) == "<class 'etc.ExposureTimeCalculator'>": | 117 | if str(type(self._sensor_params["ETC"])) == "<class 'etc.ExposureTimeCalculator'>": |
110 | self.ima.etc = self._sensor_params["ETC"] | 118 | self.ima.etc = self._sensor_params["ETC"] |
111 | # === Name | 119 | # === Name |
@@ -122,6 +130,7 @@ class ComponentSensorDetector(ComponentSensorDetectorException, Component, Guita | @@ -122,6 +130,7 @@ class ComponentSensorDetector(ComponentSensorDetectorException, Component, Guita | ||
122 | param = {} | 130 | param = {} |
123 | param['exptime'] = 0.1 | 131 | param['exptime'] = 0.1 |
124 | param['binning'] = [1, 1] | 132 | param['binning'] = [1, 1] |
133 | + param['status'] = self.SENSOR_STATE_UNKNOWN | ||
125 | self._queue.put(param) | 134 | self._queue.put(param) |
126 | 135 | ||
127 | # ------------ prop | 136 | # ------------ prop |
@@ -164,6 +173,8 @@ class ComponentSensorDetector(ComponentSensorDetectorException, Component, Guita | @@ -164,6 +173,8 @@ class ComponentSensorDetector(ComponentSensorDetectorException, Component, Guita | ||
164 | return "" | 173 | return "" |
165 | 174 | ||
166 | def _do_acq(self, *args, **kwargs): | 175 | def _do_acq(self, *args, **kwargs): |
176 | + """ For real and simu | ||
177 | + """ | ||
167 | result = None | 178 | result = None |
168 | operation = args[0].upper() | 179 | operation = args[0].upper() |
169 | # --- Manage sub operations of ACQ | 180 | # --- Manage sub operations of ACQ |
@@ -179,6 +190,8 @@ class ComponentSensorDetector(ComponentSensorDetectorException, Component, Guita | @@ -179,6 +190,8 @@ class ComponentSensorDetector(ComponentSensorDetectorException, Component, Guita | ||
179 | binning = param['binning'] | 190 | binning = param['binning'] |
180 | # TBD | 191 | # TBD |
181 | # --- call the real | 192 | # --- call the real |
193 | + param['status'] = self.SENSOR_STATE_EXPOSING | ||
194 | + param = self.database.query(param) | ||
182 | if self.real: | 195 | if self.real: |
183 | result = self._my_do_acq(*args, **kwargs) | 196 | result = self._my_do_acq(*args, **kwargs) |
184 | return result | 197 | return result |
src/guitastro/filenames.py
@@ -444,6 +444,9 @@ class FileNames(FileNamesException, GuitastroTools): | @@ -444,6 +444,9 @@ class FileNames(FileNamesException, GuitastroTools): | ||
444 | fn = FileNames() | 444 | fn = FileNames() |
445 | fn.naming("PyROS.img.1") | 445 | fn.naming("PyROS.img.1") |
446 | 446 | ||
447 | + Raises: | ||
448 | + FileNamesException: The naming is not found. | ||
449 | + | ||
447 | """ | 450 | """ |
448 | if len(args) >= 1: | 451 | if len(args) >= 1: |
449 | new_naming = args[0] | 452 | new_naming = args[0] |
@@ -966,6 +969,9 @@ class FileNames(FileNamesException, GuitastroTools): | @@ -966,6 +969,9 @@ class FileNames(FileNamesException, GuitastroTools): | ||
966 | params = fn.naming_get("L0A_20221109_235406123456_1_TNC_CH1_0123456789_001_012") | 969 | params = fn.naming_get("L0A_20221109_235406123456_1_TNC_CH1_0123456789_001_012") |
967 | 970 | ||
968 | The answer (params dict) should be {'ftype': 'L0A', 'date': '20221109', 'time': '235406123456', 'version': '1', 'unit': 'TNC', 'channel': 'CH1', 'id_seq': '0123456789', 'plane': '001', 'frame': '012'} | 971 | The answer (params dict) should be {'ftype': 'L0A', 'date': '20221109', 'time': '235406123456', 'version': '1', 'unit': 'TNC', 'channel': 'CH1', 'id_seq': '0123456789', 'plane': '001', 'frame': '012'} |
972 | + | ||
973 | + Raises: | ||
974 | + FileNamesException: Bad file name rules. | ||
969 | """ | 975 | """ |
970 | param = {} | 976 | param = {} |
971 | see_rules = self._see_naming_rules | 977 | see_rules = self._see_naming_rules |
src/guitastro/guitastrotools.py
@@ -30,6 +30,14 @@ if os.path.exists(conf_guitastro['path_products']) == False: | @@ -30,6 +30,14 @@ if os.path.exists(conf_guitastro['path_products']) == False: | ||
30 | conf_guitastro['path_products'] = os.path.join(path_tmp,"guitastro","products") | 30 | conf_guitastro['path_products'] = os.path.join(path_tmp,"guitastro","products") |
31 | os.makedirs(conf_guitastro['path_products'], exist_ok=True) | 31 | os.makedirs(conf_guitastro['path_products'], exist_ok=True) |
32 | 32 | ||
33 | +# - This condition is to avoid to download de421.bsp if no internet connection | ||
34 | +if not os.path.exists(os.path.join(conf_guitastro['path'],"de421.bsp")): | ||
35 | + de421_out = os.path.join(conf_guitastro['path'],"de421.bsp") | ||
36 | + de421_in = os.path.join(conf_guitastro['path'],"..", "..","resources","solar_system","de421.bsp") | ||
37 | + print(f"{de421_in=}") | ||
38 | + print(f"{de421_out=}") | ||
39 | + shutil.copy(de421_in, de421_out) | ||
40 | + | ||
33 | # ##################################################################### | 41 | # ##################################################################### |
34 | # ##################################################################### | 42 | # ##################################################################### |
35 | # ##################################################################### | 43 | # ##################################################################### |
@@ -449,7 +457,7 @@ class GuitastroDev(GuitastroDevException): | @@ -449,7 +457,7 @@ class GuitastroDev(GuitastroDevException): | ||
449 | shutil.rmtree(path_to) | 457 | shutil.rmtree(path_to) |
450 | except: | 458 | except: |
451 | pass | 459 | pass |
452 | - ignore = shutil.ignore_patterns('__pycache__', 'build', "de421.bsp") | 460 | + ignore = shutil.ignore_patterns('__pycache__', '.git', 'build', "de421.bsp") |
453 | shutil.copytree(path_from, path_to, ignore=ignore) | 461 | shutil.copytree(path_from, path_to, ignore=ignore) |
454 | # --- List all the files in the module | 462 | # --- List all the files in the module |
455 | root = path_to | 463 | root = path_to |
@@ -478,11 +486,14 @@ class GuitastroDev(GuitastroDevException): | @@ -478,11 +486,14 @@ class GuitastroDev(GuitastroDevException): | ||
478 | # --- Change directories with the new module name | 486 | # --- Change directories with the new module name |
479 | for inpd in inpds: | 487 | for inpd in inpds: |
480 | outd = inpd.replace(from_name, to_name) | 488 | outd = inpd.replace(from_name, to_name) |
481 | - os.rename(inpd, outd) | 489 | + try: |
490 | + os.rename(inpd, outd) | ||
491 | + except: | ||
492 | + pass | ||
482 | # --- List all the files in the module | 493 | # --- List all the files in the module |
483 | root = path_to | 494 | root = path_to |
484 | inpfiles = [os.path.join(path, name) for path, subdirs, files in os.walk(root) for name in files] | 495 | inpfiles = [os.path.join(path, name) for path, subdirs, files in os.walk(root) for name in files] |
485 | - # --- Collect all the possibilities² to find input name | 496 | + # --- Collect all the possibilities to find input name |
486 | inpnames = [] | 497 | inpnames = [] |
487 | inpnameu = from_name.upper() | 498 | inpnameu = from_name.upper() |
488 | inpnamel = len(from_name) | 499 | inpnamel = len(from_name) |
@@ -512,7 +523,11 @@ class GuitastroDev(GuitastroDevException): | @@ -512,7 +523,11 @@ class GuitastroDev(GuitastroDevException): | ||
512 | # --- Replace | 523 | # --- Replace |
513 | for inpfilemod in inpfilemods: | 524 | for inpfilemod in inpfilemods: |
514 | with open(inpfilemod, "r") as fid: | 525 | with open(inpfilemod, "r") as fid: |
515 | - lines = fid.read() | 526 | + print(f"{inpfilemod=}") |
527 | + try: | ||
528 | + lines = fid.read() | ||
529 | + except: | ||
530 | + continue | ||
516 | for inpname in inpnames: | 531 | for inpname in inpnames: |
517 | if inpname == from_capname: | 532 | if inpname == from_capname: |
518 | outname = to_capname | 533 | outname = to_capname |
@@ -648,7 +663,7 @@ if __name__ == "__main__": | @@ -648,7 +663,7 @@ if __name__ == "__main__": | ||
648 | Create initial source code of a new device. | 663 | Create initial source code of a new device. |
649 | """ | 664 | """ |
650 | gta1 = GuitastroDev() | 665 | gta1 = GuitastroDev() |
651 | - res = gta1.create_device_module("Flipro", "Quickaudine") | 666 | + res = gta1.create_device_module("Flipro", "Ascomcam") |
652 | print(f"res={res}") | 667 | print(f"res={res}") |
653 | 668 | ||
654 | if example == 2: | 669 | if example == 2: |