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 @@ |
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 | 37 | |
38 | 38 | ERR_DETECTOR_IS_EXPOSING = 1 |
39 | 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 | 46 | errors[ERR_DETECTOR_IS_EXPOSING] = "The detector is in exposure. Cannot start other exposures" |
43 | 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 | 54 | class ComponentSensorDetector(ComponentSensorDetectorException, Component, GuitastroTools): |
... | ... | @@ -105,7 +113,7 @@ class ComponentSensorDetector(ComponentSensorDetectorException, Component, Guita |
105 | 113 | self.siteobs = Siteobs(self._sensor_params["SITE"]) |
106 | 114 | # === Image in memory |
107 | 115 | self.ima = Ima() |
108 | - self.ima.longitude(self.siteobs.longitude) | |
116 | + self.ima.longitude = self.siteobs.longitude | |
109 | 117 | if str(type(self._sensor_params["ETC"])) == "<class 'etc.ExposureTimeCalculator'>": |
110 | 118 | self.ima.etc = self._sensor_params["ETC"] |
111 | 119 | # === Name |
... | ... | @@ -122,6 +130,7 @@ class ComponentSensorDetector(ComponentSensorDetectorException, Component, Guita |
122 | 130 | param = {} |
123 | 131 | param['exptime'] = 0.1 |
124 | 132 | param['binning'] = [1, 1] |
133 | + param['status'] = self.SENSOR_STATE_UNKNOWN | |
125 | 134 | self._queue.put(param) |
126 | 135 | |
127 | 136 | # ------------ prop |
... | ... | @@ -164,6 +173,8 @@ class ComponentSensorDetector(ComponentSensorDetectorException, Component, Guita |
164 | 173 | return "" |
165 | 174 | |
166 | 175 | def _do_acq(self, *args, **kwargs): |
176 | + """ For real and simu | |
177 | + """ | |
167 | 178 | result = None |
168 | 179 | operation = args[0].upper() |
169 | 180 | # --- Manage sub operations of ACQ |
... | ... | @@ -179,6 +190,8 @@ class ComponentSensorDetector(ComponentSensorDetectorException, Component, Guita |
179 | 190 | binning = param['binning'] |
180 | 191 | # TBD |
181 | 192 | # --- call the real |
193 | + param['status'] = self.SENSOR_STATE_EXPOSING | |
194 | + param = self.database.query(param) | |
182 | 195 | if self.real: |
183 | 196 | result = self._my_do_acq(*args, **kwargs) |
184 | 197 | return result | ... | ... |
src/guitastro/filenames.py
... | ... | @@ -444,6 +444,9 @@ class FileNames(FileNamesException, GuitastroTools): |
444 | 444 | fn = FileNames() |
445 | 445 | fn.naming("PyROS.img.1") |
446 | 446 | |
447 | + Raises: | |
448 | + FileNamesException: The naming is not found. | |
449 | + | |
447 | 450 | """ |
448 | 451 | if len(args) >= 1: |
449 | 452 | new_naming = args[0] |
... | ... | @@ -966,6 +969,9 @@ class FileNames(FileNamesException, GuitastroTools): |
966 | 969 | params = fn.naming_get("L0A_20221109_235406123456_1_TNC_CH1_0123456789_001_012") |
967 | 970 | |
968 | 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 | 976 | param = {} |
971 | 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 | 30 | conf_guitastro['path_products'] = os.path.join(path_tmp,"guitastro","products") |
31 | 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 | 457 | shutil.rmtree(path_to) |
450 | 458 | except: |
451 | 459 | pass |
452 | - ignore = shutil.ignore_patterns('__pycache__', 'build', "de421.bsp") | |
460 | + ignore = shutil.ignore_patterns('__pycache__', '.git', 'build', "de421.bsp") | |
453 | 461 | shutil.copytree(path_from, path_to, ignore=ignore) |
454 | 462 | # --- List all the files in the module |
455 | 463 | root = path_to |
... | ... | @@ -478,11 +486,14 @@ class GuitastroDev(GuitastroDevException): |
478 | 486 | # --- Change directories with the new module name |
479 | 487 | for inpd in inpds: |
480 | 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 | 493 | # --- List all the files in the module |
483 | 494 | root = path_to |
484 | 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 | 497 | inpnames = [] |
487 | 498 | inpnameu = from_name.upper() |
488 | 499 | inpnamel = len(from_name) |
... | ... | @@ -512,7 +523,11 @@ class GuitastroDev(GuitastroDevException): |
512 | 523 | # --- Replace |
513 | 524 | for inpfilemod in inpfilemods: |
514 | 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 | 531 | for inpname in inpnames: |
517 | 532 | if inpname == from_capname: |
518 | 533 | outname = to_capname |
... | ... | @@ -648,7 +663,7 @@ if __name__ == "__main__": |
648 | 663 | Create initial source code of a new device. |
649 | 664 | """ |
650 | 665 | gta1 = GuitastroDev() |
651 | - res = gta1.create_device_module("Flipro", "Quickaudine") | |
666 | + res = gta1.create_device_module("Flipro", "Ascomcam") | |
652 | 667 | print(f"res={res}") |
653 | 668 | |
654 | 669 | if example == 2: | ... | ... |