microeye 2.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. microEye/__init__.py +47 -0
  2. microEye/_version.py +2 -0
  3. microEye/analysis/__init__.py +1 -0
  4. microEye/analysis/checklist_dialog.py +143 -0
  5. microEye/analysis/cmosMaps.py +228 -0
  6. microEye/analysis/filters/__init__.py +9 -0
  7. microEye/analysis/filters/base.py +21 -0
  8. microEye/analysis/filters/spatial.py +338 -0
  9. microEye/analysis/filters/temporal.py +76 -0
  10. microEye/analysis/fitting/__init__.py +0 -0
  11. microEye/analysis/fitting/fit.py +680 -0
  12. microEye/analysis/fitting/nena.py +375 -0
  13. microEye/analysis/fitting/phasor_fit.py +90 -0
  14. microEye/analysis/fitting/processing.py +317 -0
  15. microEye/analysis/fitting/psf/__init__.py +6 -0
  16. microEye/analysis/fitting/psf/extract.py +1129 -0
  17. microEye/analysis/fitting/psf/rubost_mean.py +150 -0
  18. microEye/analysis/fitting/psf/spline.py +167 -0
  19. microEye/analysis/fitting/psf/stats/__init__.py +12 -0
  20. microEye/analysis/fitting/psf/stats/core.py +295 -0
  21. microEye/analysis/fitting/psf/stats/curve_fit.py +708 -0
  22. microEye/analysis/fitting/psf/stats/io.py +104 -0
  23. microEye/analysis/fitting/psf/stats/slope_fit.py +171 -0
  24. microEye/analysis/fitting/psf/temp.py +147 -0
  25. microEye/analysis/fitting/psf/test.py +47 -0
  26. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUfunctions.py +657 -0
  27. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUmleFit_LM.py +1336 -0
  28. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUsplineLib.py +270 -0
  29. microEye/analysis/fitting/pyfit3Dcspline/CPU/__init__.py +1 -0
  30. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUfunctions.py +609 -0
  31. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUmleFit_LM_EMCCD.py +1396 -0
  32. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUmleFit_LM_sCMOS.py +1426 -0
  33. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUsplineLib.py +231 -0
  34. microEye/analysis/fitting/pyfit3Dcspline/GPU/__init__.py +2 -0
  35. microEye/analysis/fitting/pyfit3Dcspline/__init__.py +10 -0
  36. microEye/analysis/fitting/pyfit3Dcspline/constants.py +27 -0
  37. microEye/analysis/fitting/pyfit3Dcspline/mainfunctions.py +903 -0
  38. microEye/analysis/fitting/results.py +917 -0
  39. microEye/analysis/fitting/results_stats.py +251 -0
  40. microEye/analysis/fitting/tardis.py +209 -0
  41. microEye/analysis/multi_viewer.py +568 -0
  42. microEye/analysis/processing/__init__.py +1 -0
  43. microEye/analysis/processing/frc.py +120 -0
  44. microEye/analysis/rendering/__init__.py +3 -0
  45. microEye/analysis/rendering/base.py +452 -0
  46. microEye/analysis/rendering/cloud.py +215 -0
  47. microEye/analysis/rendering/core.py +47 -0
  48. microEye/analysis/rendering/volumetric.py +198 -0
  49. microEye/analysis/tools/__init__.py +0 -0
  50. microEye/analysis/tools/kymograms.py +1079 -0
  51. microEye/analysis/tools/roi_selectors.py +556 -0
  52. microEye/analysis/utils/__init__.py +3 -0
  53. microEye/analysis/utils/coordinates.py +18 -0
  54. microEye/analysis/utils/images.py +68 -0
  55. microEye/analysis/utils/windows.py +19 -0
  56. microEye/analysis/viewer/__init__.py +3 -0
  57. microEye/analysis/viewer/image_options_widget.py +615 -0
  58. microEye/analysis/viewer/images.py +1225 -0
  59. microEye/analysis/viewer/layers_widget.py +415 -0
  60. microEye/analysis/viewer/localizations.py +1304 -0
  61. microEye/analysis/viewer/psf.py +1003 -0
  62. microEye/analysis/viewer/volume.py +456 -0
  63. microEye/hardware/__init__.py +3 -0
  64. microEye/hardware/cams/__init__.py +29 -0
  65. microEye/hardware/cams/camera_calibration.py +99 -0
  66. microEye/hardware/cams/camera_list.py +528 -0
  67. microEye/hardware/cams/camera_options.py +694 -0
  68. microEye/hardware/cams/camera_panel.py +941 -0
  69. microEye/hardware/cams/dummy/__init__.py +1 -0
  70. microEye/hardware/cams/dummy/dummy_panel.py +759 -0
  71. microEye/hardware/cams/jobs.py +497 -0
  72. microEye/hardware/cams/line_profiler.py +99 -0
  73. microEye/hardware/cams/linescan/IR_Cam.py +474 -0
  74. microEye/hardware/cams/linescan/__init__.py +1 -0
  75. microEye/hardware/cams/micam.py +524 -0
  76. microEye/hardware/cams/pco/__init__.py +58 -0
  77. microEye/hardware/cams/pco/enums.py +382 -0
  78. microEye/hardware/cams/pco/pco_cam.py +761 -0
  79. microEye/hardware/cams/pco/pco_panel.py +477 -0
  80. microEye/hardware/cams/shortcuts.py +312 -0
  81. microEye/hardware/cams/thorlabs/__init__.py +1 -0
  82. microEye/hardware/cams/thorlabs/thorlabs.py +1508 -0
  83. microEye/hardware/cams/thorlabs/thorlabs_panel.py +850 -0
  84. microEye/hardware/cams/ueye/__init__.py +1 -0
  85. microEye/hardware/cams/ueye/ueye_camera.py +1023 -0
  86. microEye/hardware/cams/ueye/ueye_panel.py +861 -0
  87. microEye/hardware/cams/vimba/__init__.py +1 -0
  88. microEye/hardware/cams/vimba/vimba_cam.py +1000 -0
  89. microEye/hardware/cams/vimba/vimba_panel.py +813 -0
  90. microEye/hardware/device.py +60 -0
  91. microEye/hardware/lasers/__init__.py +13 -0
  92. microEye/hardware/lasers/io_matchbox.py +791 -0
  93. microEye/hardware/lasers/io_params.py +85 -0
  94. microEye/hardware/lasers/io_single_laser.py +742 -0
  95. microEye/hardware/lasers/laser_relay.py +594 -0
  96. microEye/hardware/mieye/__init__.py +1 -0
  97. microEye/hardware/mieye/acquisition_manager.py +467 -0
  98. microEye/hardware/mieye/devices_manager.py +533 -0
  99. microEye/hardware/mieye/miEye.py +659 -0
  100. microEye/hardware/misc/__init__.py +0 -0
  101. microEye/hardware/misc/acquisition_view.py +71 -0
  102. microEye/hardware/misc/reglo.py +761 -0
  103. microEye/hardware/misc/temp.py +188 -0
  104. microEye/hardware/port_config.py +59 -0
  105. microEye/hardware/protocols/__init__.py +2 -0
  106. microEye/hardware/protocols/actions.py +402 -0
  107. microEye/hardware/protocols/actions_items.py +703 -0
  108. microEye/hardware/protocols/designer.py +244 -0
  109. microEye/hardware/protocols/scene_manager.py +191 -0
  110. microEye/hardware/protocols/serialization.py +97 -0
  111. microEye/hardware/pycromanager/__init__.py +16 -0
  112. microEye/hardware/pycromanager/core.py +1433 -0
  113. microEye/hardware/pycromanager/devices.py +461 -0
  114. microEye/hardware/pycromanager/enums.py +107 -0
  115. microEye/hardware/pycromanager/headless.py +153 -0
  116. microEye/hardware/pycromanager/utils.py +34 -0
  117. microEye/hardware/pycromanager/widgets/__init__.py +5 -0
  118. microEye/hardware/pycromanager/widgets/bridges.py +407 -0
  119. microEye/hardware/pycromanager/widgets/headless_manager.py +258 -0
  120. microEye/hardware/pycromanager/widgets/headless_options.py +224 -0
  121. microEye/hardware/pycromanager/widgets/pycro_panel.py +455 -0
  122. microEye/hardware/stages/__init__.py +18 -0
  123. microEye/hardware/stages/elliptec/__init__.py +5 -0
  124. microEye/hardware/stages/elliptec/baseDevice.py +314 -0
  125. microEye/hardware/stages/elliptec/device.py +384 -0
  126. microEye/hardware/stages/elliptec/deviceID.py +212 -0
  127. microEye/hardware/stages/elliptec/devicePort.py +379 -0
  128. microEye/hardware/stages/elliptec/deviceStatus.py +65 -0
  129. microEye/hardware/stages/elliptec/devicesView.py +706 -0
  130. microEye/hardware/stages/elliptec/ellDevices.py +134 -0
  131. microEye/hardware/stages/elliptec/messageUpdater.py +34 -0
  132. microEye/hardware/stages/elliptec/motorInfo.py +153 -0
  133. microEye/hardware/stages/elliptec/stage.py +62 -0
  134. microEye/hardware/stages/elliptec/test.py +139 -0
  135. microEye/hardware/stages/kinesis/__init__.py +1 -0
  136. microEye/hardware/stages/kinesis/kdc101/__init__.py +1 -0
  137. microEye/hardware/stages/kinesis/kdc101/enums.py +1002 -0
  138. microEye/hardware/stages/kinesis/kdc101/factory.py +171 -0
  139. microEye/hardware/stages/kinesis/kdc101/kdc101.py +718 -0
  140. microEye/hardware/stages/kinesis/kinesis.py +776 -0
  141. microEye/hardware/stages/piezo_concept.py +607 -0
  142. microEye/hardware/stages/stabilizer.py +785 -0
  143. microEye/hardware/stages/stage.py +89 -0
  144. microEye/hardware/widgets/__init__.py +10 -0
  145. microEye/hardware/widgets/controller.py +246 -0
  146. microEye/hardware/widgets/devices.py +133 -0
  147. microEye/hardware/widgets/focusWidget.py +264 -0
  148. microEye/hardware/widgets/qlist_slider.py +113 -0
  149. microEye/hardware/widgets/scan_acquisition.py +424 -0
  150. microEye/icons/1024.png +0 -0
  151. microEye/icons/128.png +0 -0
  152. microEye/icons/16.png +0 -0
  153. microEye/icons/24.png +0 -0
  154. microEye/icons/256.png +0 -0
  155. microEye/icons/32.png +0 -0
  156. microEye/icons/48.png +0 -0
  157. microEye/icons/512.png +0 -0
  158. microEye/icons/64.png +0 -0
  159. microEye/icons/__init__.py +0 -0
  160. microEye/icons/close.svg +88 -0
  161. microEye/icons/mieye.png +0 -0
  162. microEye/icons/min.svg +83 -0
  163. microEye/icons/viewer.png +0 -0
  164. microEye/launcher.py +42 -0
  165. microEye/qt.py +181 -0
  166. microEye/utils/__init__.py +2 -0
  167. microEye/utils/enum_encoder.py +10 -0
  168. microEye/utils/expandable_groupbox.py +93 -0
  169. microEye/utils/gui_helper.py +457 -0
  170. microEye/utils/hid/__init__.py +8 -0
  171. microEye/utils/hid/controller.py +153 -0
  172. microEye/utils/hid/device.py +63 -0
  173. microEye/utils/hid/enums.py +140 -0
  174. microEye/utils/hid/utils.py +58 -0
  175. microEye/utils/labelled_slider.py +134 -0
  176. microEye/utils/metadata.py +599 -0
  177. microEye/utils/metadata_tree.py +718 -0
  178. microEye/utils/micro_launcher.py +245 -0
  179. microEye/utils/parameter_tree.py +325 -0
  180. microEye/utils/pyscripting.py +444 -0
  181. microEye/utils/retry_exec.py +35 -0
  182. microEye/utils/start_gui.py +112 -0
  183. microEye/utils/thread_worker.py +115 -0
  184. microEye/utils/uImage.py +1512 -0
  185. microeye-2.3.2.dist-info/METADATA +401 -0
  186. microeye-2.3.2.dist-info/RECORD +190 -0
  187. microeye-2.3.2.dist-info/WHEEL +5 -0
  188. microeye-2.3.2.dist-info/entry_points.txt +2 -0
  189. microeye-2.3.2.dist-info/licenses/LICENSE +674 -0
  190. microeye-2.3.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,776 @@
1
+ from collections import deque
2
+ from dataclasses import dataclass
3
+ from enum import Enum, auto
4
+ from typing import Callable, Optional, Union
5
+
6
+ import serial
7
+ from pyqtgraph.parametertree import Parameter
8
+ from pyqtgraph.parametertree.parameterTypes import ActionParameter
9
+
10
+ from microEye.hardware.port_config import port_config
11
+ from microEye.hardware.stages.kinesis.kdc101 import KDC101Controller
12
+ from microEye.hardware.stages.stage import XYStageParams
13
+ from microEye.qt import QtCore, QtSerialPort, QtWidgets, Signal
14
+ from microEye.utils.parameter_tree import Tree
15
+ from microEye.utils.thread_worker import *
16
+
17
+
18
+ class KinesisXY(QtCore.QObject):
19
+ '''Class for controlling Two Kinesis Devices as an XY Stage'''
20
+
21
+ asyncStarted = Signal()
22
+ asyncFinished = Signal()
23
+
24
+ def __init__(self, x_port='COM12', y_port='COM11', parent=None, **kwargs):
25
+ super().__init__(parent=parent)
26
+ self.X = KDC101Controller(portName=x_port)
27
+ self.Y = KDC101Controller(portName=y_port)
28
+ self.min = kwargs.get('min', [0, 0])
29
+ self.max = kwargs.get('max', [25, 25])
30
+ self.center_pos = kwargs.get('center', [17, 13])
31
+ self.prec = 4
32
+ self.busy = False
33
+
34
+ @property
35
+ def position(self) -> tuple[float, float]:
36
+ return self.X.position, self.Y.position
37
+
38
+ def home(self, is_async=True):
39
+ self.run_async(self.X.home, is_async=is_async)
40
+ self.run_async(self.Y.home, is_async=is_async)
41
+
42
+ def center(self, x_center=None, y_center=None, is_async=True):
43
+ '''Move to the center of the stage.'''
44
+ self.move_absolute(
45
+ x_center if x_center is not None else self.center_pos[0],
46
+ y_center if y_center is not None else self.center_pos[1],
47
+ is_async=is_async,
48
+ )
49
+
50
+ def move_absolute(self, x, y, force=False, is_async=True):
51
+ x = round(max(self.min[0], min(self.max[0], x)), self.prec)
52
+ y = round(max(self.min[1], min(self.max[1], y)), self.prec)
53
+ if x != self.X.position or force:
54
+ self.run_async(self.X.move_absolute, x, is_async=is_async)
55
+ if y != self.Y.position or force:
56
+ self.run_async(self.Y.move_absolute, y, is_async=is_async)
57
+
58
+ def move_relative(self, x, y, is_async=True):
59
+ x = round(x, self.prec)
60
+ y = round(y, self.prec)
61
+ if x != 0:
62
+ self.run_async(self.X.move_relative, x, is_async=is_async)
63
+ if y != 0:
64
+ self.run_async(self.Y.move_relative, y, is_async=is_async)
65
+
66
+ def stop(self):
67
+ self.X.move_stop()
68
+ self.Y.move_stop()
69
+
70
+ def open(self):
71
+ '''Opens the serial ports.'''
72
+ res = self.X.open() and self.Y.open()
73
+ return res
74
+
75
+ def close(self):
76
+ '''Closes the serial ports.'''
77
+ self.X.close()
78
+ self.Y.close()
79
+
80
+ def run_async(self, callback, *args, is_async=True):
81
+ if self.isOpen() and not self.busy:
82
+ self.X.clearResponses()
83
+ self.Y.clearResponses()
84
+
85
+ def worker_callback():
86
+ try:
87
+ self.busy = True
88
+ self.asyncStarted.emit()
89
+ callback(*args)
90
+ except Exception as e:
91
+ traceback.print_exc()
92
+ finally:
93
+ self.busy = False
94
+ self.asyncFinished.emit()
95
+
96
+ if is_async:
97
+ _worker = QThreadWorker(worker_callback, nokwargs=True)
98
+
99
+ QtCore.QThreadPool.globalInstance().start(_worker)
100
+ else:
101
+ worker_callback()
102
+
103
+ def isOpen(self):
104
+ return all([self.X.isOpen(), self.Y.isOpen()])
105
+
106
+ def get_config(self) -> dict:
107
+ return {
108
+ 'X': {
109
+ 'port': self.X.portName(),
110
+ 'baudrate': self.X.baudRate(),
111
+ },
112
+ 'Y': {
113
+ 'port': self.Y.portName(),
114
+ 'baudrate': self.Y.baudRate(),
115
+ },
116
+ }
117
+
118
+ def load_config(self, config: dict):
119
+ if isinstance(config, dict):
120
+ x_config = config.get('X', {})
121
+ y_config = config.get('Y', {})
122
+
123
+ if isinstance(x_config, dict):
124
+ self.X.setBaudRate(x_config.get('baudrate', 115200))
125
+ self.X.setPortName(x_config.get('port', 'COM12'))
126
+
127
+ if isinstance(y_config, dict):
128
+ self.Y.setBaudRate(y_config.get('baudrate', 115200))
129
+ self.Y.setPortName(y_config.get('port', 'COM13'))
130
+
131
+ def getViewWidget(self):
132
+ '''Generates a QGroupBox with XY
133
+ stage controls.'''
134
+ view = KinesisView(stage=self)
135
+
136
+ return view
137
+
138
+
139
+ class KinesisView(Tree):
140
+ '''View class for the Kinesis stage controller.'''
141
+
142
+ def __init__(
143
+ self, parent: Optional['QtWidgets.QWidget'] = None, stage: KinesisXY = None
144
+ ):
145
+ if not isinstance(stage, KinesisXY):
146
+ raise ValueError('stage must be an instance of KinesisXY.')
147
+
148
+ self.__stage = stage if stage else KinesisXY()
149
+ self.__threadpool = QtCore.QThreadPool.globalInstance()
150
+
151
+ super().__init__(parent)
152
+
153
+ def create_parameters(self):
154
+ params = [
155
+ {
156
+ 'name': str(XYStageParams.MODEL),
157
+ 'type': 'str',
158
+ 'value': str(self),
159
+ 'readonly': True,
160
+ },
161
+ {
162
+ 'name': str(XYStageParams.STATUS),
163
+ 'type': 'str',
164
+ 'value': 'Idle',
165
+ 'readonly': True,
166
+ },
167
+ {
168
+ 'name': str(XYStageParams.X_POSITION),
169
+ 'type': 'float',
170
+ 'value': 0.0,
171
+ 'decimals': 6,
172
+ 'suffix': 'mm',
173
+ },
174
+ {
175
+ 'name': str(XYStageParams.Y_POSITION),
176
+ 'type': 'float',
177
+ 'value': 0.0,
178
+ 'decimals': 6,
179
+ 'suffix': 'mm',
180
+ },
181
+ {
182
+ 'name': str(XYStageParams.MOVE),
183
+ 'type': 'action',
184
+ },
185
+ {
186
+ 'name': str(XYStageParams.HOME),
187
+ 'type': 'action',
188
+ },
189
+ {
190
+ 'name': str(XYStageParams.CENTER),
191
+ 'type': 'action',
192
+ },
193
+ {
194
+ 'name': str(XYStageParams.STOP),
195
+ 'type': 'action',
196
+ },
197
+ {
198
+ 'name': str(XYStageParams.CONTROLS),
199
+ 'type': 'group',
200
+ 'expanded': False,
201
+ 'children': [
202
+ {
203
+ 'name': str(XYStageParams.X_JUMP_P),
204
+ 'type': 'action',
205
+ },
206
+ {
207
+ 'name': str(XYStageParams.X_STEP_P),
208
+ 'type': 'action',
209
+ },
210
+ {
211
+ 'name': str(XYStageParams.X_STEP_N),
212
+ 'type': 'action',
213
+ },
214
+ {
215
+ 'name': str(XYStageParams.X_JUMP_N),
216
+ 'type': 'action',
217
+ },
218
+ {
219
+ 'name': str(XYStageParams.Y_JUMP_P),
220
+ 'type': 'action',
221
+ },
222
+ {
223
+ 'name': str(XYStageParams.Y_STEP_P),
224
+ 'type': 'action',
225
+ },
226
+ {
227
+ 'name': str(XYStageParams.Y_STEP_N),
228
+ 'type': 'action',
229
+ },
230
+ {
231
+ 'name': str(XYStageParams.Y_JUMP_N),
232
+ 'type': 'action',
233
+ },
234
+ ],
235
+ },
236
+ {
237
+ 'name': str(XYStageParams.OPTIONS),
238
+ 'type': 'group',
239
+ 'expanded': False,
240
+ 'children': [
241
+ {
242
+ 'name': str(XYStageParams.STEP),
243
+ 'type': 'float',
244
+ 'value': 0.05,
245
+ 'suffix': 'mm',
246
+ },
247
+ {
248
+ 'name': str(XYStageParams.JUMP),
249
+ 'type': 'float',
250
+ 'value': 0.5,
251
+ 'suffix': 'mm',
252
+ },
253
+ {
254
+ 'name': str(XYStageParams.ID_X),
255
+ 'type': 'action',
256
+ },
257
+ {
258
+ 'name': str(XYStageParams.ID_Y),
259
+ 'type': 'action',
260
+ },
261
+ ],
262
+ },
263
+ {
264
+ 'name': str(XYStageParams.SERIAL_PORT),
265
+ 'type': 'group',
266
+ 'expanded': False,
267
+ 'children': [
268
+ {
269
+ 'name': str(XYStageParams.PORT),
270
+ 'type': 'list',
271
+ 'limits': KinesisView._get_available_ports(),
272
+ },
273
+ {
274
+ 'name': str(XYStageParams.BAUDRATE),
275
+ 'type': 'list',
276
+ 'default': 115200,
277
+ 'limits': KinesisView._get_baudrates(),
278
+ },
279
+ {
280
+ 'name': str(XYStageParams.SET_PORT_X),
281
+ 'type': 'action',
282
+ },
283
+ {
284
+ 'name': str(XYStageParams.SET_PORT_Y),
285
+ 'type': 'action',
286
+ },
287
+ {'name': str(XYStageParams.OPEN), 'type': 'action'},
288
+ {'name': str(XYStageParams.CLOSE), 'type': 'action'},
289
+ {
290
+ 'name': str(XYStageParams.REFRESH),
291
+ 'type': 'action',
292
+ },
293
+ {
294
+ 'name': str(XYStageParams.PORT_STATE),
295
+ 'type': 'str',
296
+ 'value': 'closed',
297
+ 'readonly': True,
298
+ },
299
+ ],
300
+ },
301
+ ]
302
+
303
+ self.param_tree = Parameter.create(name='', type='group', children=params)
304
+ # self.param_tree.sigTreeStateChanged.connect(self.change)
305
+ self.header().setSectionResizeMode(
306
+ QtWidgets.QHeaderView.ResizeMode.ResizeToContents
307
+ )
308
+
309
+ self.initializeSignals()
310
+
311
+ self.__stage.asyncStarted.connect(
312
+ lambda: self.set_param_value(XYStageParams.STATUS, 'busy')
313
+ )
314
+ self.__stage.asyncFinished.connect(self.updateControls)
315
+
316
+ def initializeSignals(self):
317
+ self._connect_movement_signals()
318
+ self._connect_identification_signals()
319
+ self._connect_configuration_signals()
320
+
321
+ def _connect_movement_signals(self):
322
+ movement_params = [
323
+ XYStageParams.MOVE,
324
+ XYStageParams.HOME,
325
+ XYStageParams.CENTER,
326
+ XYStageParams.STOP,
327
+ XYStageParams.X_JUMP_P,
328
+ XYStageParams.X_JUMP_N,
329
+ XYStageParams.X_STEP_P,
330
+ XYStageParams.X_STEP_N,
331
+ XYStageParams.Y_JUMP_P,
332
+ XYStageParams.Y_JUMP_N,
333
+ XYStageParams.Y_STEP_P,
334
+ XYStageParams.Y_STEP_N,
335
+ ]
336
+ for param in movement_params:
337
+ self.get_param(param).sigActivated.connect(self._handle_movement_signal)
338
+
339
+ def _handle_movement_signal(self, action: Parameter):
340
+ path = self.get_param_path(action)
341
+ if not path:
342
+ return
343
+
344
+ param = XYStageParams('.'.join(path))
345
+
346
+ if param == XYStageParams.MOVE:
347
+ self.__stage.move_absolute(
348
+ self.get_param_value(XYStageParams.X_POSITION),
349
+ self.get_param_value(XYStageParams.Y_POSITION),
350
+ )
351
+ elif param == XYStageParams.HOME:
352
+ self.__stage.home()
353
+ elif param == XYStageParams.CENTER:
354
+ self.__stage.center()
355
+ elif param == XYStageParams.STOP:
356
+ self.__stage.stop()
357
+ elif param == XYStageParams.X_JUMP_P:
358
+ self.__stage.move_relative(self.get_param_value(XYStageParams.JUMP), 0)
359
+ elif param == XYStageParams.X_JUMP_N:
360
+ self.__stage.move_relative(-self.get_param_value(XYStageParams.JUMP), 0)
361
+ elif param == XYStageParams.X_STEP_P:
362
+ self.__stage.move_relative(self.get_param_value(XYStageParams.STEP), 0)
363
+ elif param == XYStageParams.X_STEP_N:
364
+ self.__stage.move_relative(-self.get_param_value(XYStageParams.STEP), 0)
365
+ elif param == XYStageParams.Y_JUMP_P:
366
+ self.__stage.move_relative(0, self.get_param_value(XYStageParams.JUMP))
367
+ elif param == XYStageParams.Y_JUMP_N:
368
+ self.__stage.move_relative(0, -self.get_param_value(XYStageParams.JUMP))
369
+ elif param == XYStageParams.Y_STEP_P:
370
+ self.__stage.move_relative(0, self.get_param_value(XYStageParams.STEP))
371
+ elif param == XYStageParams.Y_STEP_N:
372
+ self.__stage.move_relative(0, -self.get_param_value(XYStageParams.STEP))
373
+
374
+ def _connect_identification_signals(self):
375
+ identification_params = [
376
+ XYStageParams.ID_X,
377
+ XYStageParams.ID_Y,
378
+ ]
379
+ for param in identification_params:
380
+ self.get_param(param).sigActivated.connect(
381
+ self._handle_identification_signal
382
+ )
383
+
384
+ def _handle_identification_signal(self, action: Parameter):
385
+ path = self.get_param_path(action)
386
+ if not path:
387
+ return
388
+
389
+ param = XYStageParams('.'.join(path))
390
+
391
+ if param == XYStageParams.ID_X:
392
+ self.__stage.X.identify()
393
+ elif param == XYStageParams.ID_Y:
394
+ self.__stage.Y.identify()
395
+
396
+ def _connect_configuration_signals(self):
397
+ configuration_params = [
398
+ XYStageParams.SET_PORT_X,
399
+ XYStageParams.SET_PORT_Y,
400
+ XYStageParams.OPEN,
401
+ XYStageParams.CLOSE,
402
+ XYStageParams.REFRESH,
403
+ ]
404
+ for param in configuration_params:
405
+ self.get_param(param).sigActivated.connect(
406
+ self._handle_configuration_signal
407
+ )
408
+
409
+ def _handle_configuration_signal(self, action: Parameter):
410
+ path = self.get_param_path(action)
411
+ if not path:
412
+ return
413
+
414
+ param = XYStageParams('.'.join(path))
415
+
416
+ if param == XYStageParams.SET_PORT_X:
417
+ self.setConfig()
418
+ elif param == XYStageParams.SET_PORT_Y:
419
+ self.setConfig(X=False)
420
+ elif param == XYStageParams.OPEN:
421
+ self.open()
422
+ elif param == XYStageParams.CLOSE:
423
+ self.__stage.close()
424
+ elif param == XYStageParams.REFRESH:
425
+ self._refresh_ports()
426
+
427
+ def isOpen(self):
428
+ return self.__stage.isOpen()
429
+
430
+ def setConfig(self, X: bool = True):
431
+ if not self.__stage.isOpen():
432
+ self.__stage.close()
433
+
434
+ self.setPortName(self.get_param_value(XYStageParams.PORT), X)
435
+ # self.setBaudRate(self.get_param_value(XYStageParams.BAUDRATE), X)
436
+
437
+ def setPortName(self, name: str, X: bool = True):
438
+ serial: KDC101Controller = self.__stage.X if X else self.__stage.Y
439
+ if not serial.isOpen():
440
+ serial.setPortName(name)
441
+
442
+ def open(self):
443
+ res = self.__stage.open()
444
+
445
+ if res:
446
+ self.set_param_value(XYStageParams.X_POSITION, self.__stage.position[0])
447
+ self.set_param_value(XYStageParams.Y_POSITION, self.__stage.position[1])
448
+ self.set_expanded(XYStageParams.SERIAL_PORT)
449
+
450
+ def getStep(self):
451
+ return self.get_param_value(XYStageParams.STEP)
452
+
453
+ def setStep(self, value: float):
454
+ self.set_param_value(XYStageParams.STEP, value)
455
+
456
+ def getJump(self):
457
+ return self.get_param_value(XYStageParams.JUMP)
458
+
459
+ def setJump(self, value: float):
460
+ self.set_param_value(XYStageParams.JUMP, value)
461
+
462
+ def center(self):
463
+ self.get_param(XYStageParams.CENTER).activate()
464
+
465
+ def stop(self):
466
+ self.get_param(XYStageParams.STOP).activate()
467
+
468
+ def move(self, X: bool, jump: bool, direction: bool):
469
+ if jump:
470
+ param = (
471
+ XYStageParams.X_JUMP_P
472
+ if X and direction
473
+ else XYStageParams.X_JUMP_N
474
+ if X and not direction
475
+ else XYStageParams.Y_JUMP_P
476
+ if not X and direction
477
+ else XYStageParams.Y_JUMP_N
478
+ )
479
+ else:
480
+ param = (
481
+ XYStageParams.X_STEP_P
482
+ if X and direction
483
+ else XYStageParams.X_STEP_N
484
+ if X and not direction
485
+ else XYStageParams.Y_STEP_P
486
+ if not X and direction
487
+ else XYStageParams.Y_STEP_N
488
+ )
489
+
490
+ self.get_param(param).activate()
491
+
492
+ def moveRelative(self, x: float, y: float):
493
+ self.__stage.move_relative(x, y)
494
+
495
+ def moveAbsolute(self, x: float, y: float):
496
+ self.__stage.move_absolute(x, y)
497
+
498
+ def updateHighlight(self):
499
+ '''
500
+ Updates the highlight style of the "Connect" action.
501
+ '''
502
+ style = ''
503
+ if self.isOpen():
504
+ style = 'background-color: #004CB6'
505
+ else:
506
+ style = 'background-color: black'
507
+
508
+ next(self.get_param(XYStageParams.OPEN).items.keys()).button.setStyleSheet(
509
+ style
510
+ )
511
+
512
+ def updateControls(self, value: bool):
513
+ step_params = [
514
+ XYStageParams.X_STEP_N,
515
+ XYStageParams.X_STEP_P,
516
+ XYStageParams.Y_STEP_N,
517
+ XYStageParams.Y_STEP_P,
518
+ ]
519
+
520
+ for param in step_params:
521
+ next(self.get_param(param).items.keys()).button.setStyleSheet(
522
+ 'background-color: #004CB6' if not value else ''
523
+ )
524
+
525
+ jump_params = [
526
+ XYStageParams.X_JUMP_N,
527
+ XYStageParams.X_JUMP_P,
528
+ XYStageParams.Y_JUMP_N,
529
+ XYStageParams.Y_JUMP_P,
530
+ ]
531
+
532
+ for param in jump_params:
533
+ next(self.get_param(param).items.keys()).button.setStyleSheet(
534
+ 'background-color: #004CB6' if value else ''
535
+ )
536
+
537
+ def updatePositions(self):
538
+ self.set_param_value(XYStageParams.STATUS, 'idle')
539
+
540
+ self.set_param_value(XYStageParams.X_POSITION, self.__stage.X.state.position)
541
+ self.set_param_value(XYStageParams.Y_POSITION, self.__stage.Y.state.position)
542
+
543
+ def __str__(self):
544
+ return 'Kinesis KDC101 + Z825B'
545
+
546
+ @staticmethod
547
+ def _get_available_ports():
548
+ return [
549
+ info.portName() for info in QtSerialPort.QSerialPortInfo.availablePorts()
550
+ ]
551
+
552
+ @staticmethod
553
+ def _get_baudrates():
554
+ return [
555
+ baudrate for baudrate in QtSerialPort.QSerialPortInfo.standardBaudRates()
556
+ ]
557
+
558
+ def _refresh_ports(self):
559
+ self.get_param(XYStageParams.PORT).setLimits(self._get_available_ports())
560
+
561
+
562
+ # class OldKinesisView(QtWidgets.QGroupBox):
563
+ # '''View class for the Kinesis stage controller.'''
564
+
565
+ # def __init__(
566
+ # self, parent: Optional['QtWidgets.QWidget'] = None, stage: KinesisXY = None
567
+ # ):
568
+ # super().__init__(parent)
569
+
570
+ # self.setTitle(KinesisXY.__name__)
571
+ # self.stage = stage if stage else KinesisXY()
572
+ # self.threadpool = QtCore.QThreadPool.globalInstance()
573
+ # self.init_ui()
574
+
575
+ # def init_ui(self):
576
+ # container = QtWidgets.QVBoxLayout()
577
+ # self.setLayout(container)
578
+
579
+ # self._connect_btn = QtWidgets.QPushButton(
580
+ # 'Connect', clicked=lambda: self.stage.open()
581
+ # )
582
+ # self._disconnect_btn = QtWidgets.QPushButton(
583
+ # 'Disconnect', clicked=lambda: self.stage.close()
584
+ # )
585
+ # self._config_btn = QtWidgets.QPushButton(
586
+ # 'Config.', clicked=lambda: self.stage.open_dialog()
587
+ # )
588
+
589
+ # self._stop_btn = QtWidgets.QPushButton(
590
+ # 'STOP!', clicked=lambda: self.stage.stop()
591
+ # )
592
+
593
+ # btns = QtWidgets.QHBoxLayout()
594
+ # btns.addWidget(self._connect_btn)
595
+ # btns.addWidget(self._disconnect_btn)
596
+ # btns.addWidget(self._config_btn)
597
+ # btns.addWidget(self._stop_btn)
598
+ # container.addLayout(btns)
599
+
600
+ # self.controlsWidget = QtWidgets.QWidget()
601
+ # hLayout = QtWidgets.QVBoxLayout()
602
+ # self.controlsWidget.setLayout(hLayout)
603
+ # formLayout = QtWidgets.QFormLayout()
604
+ # hLayout.addLayout(formLayout, 3)
605
+ # container.addWidget(self.controlsWidget)
606
+ # container.addStretch()
607
+
608
+ # self.x_spin = QtWidgets.QDoubleSpinBox()
609
+ # self.y_spin = QtWidgets.QDoubleSpinBox()
610
+ # self.x_spin.setDecimals(self.stage.prec)
611
+ # self.y_spin.setDecimals(self.stage.prec)
612
+ # self.x_spin.setSingleStep(10 ** (-self.stage.prec))
613
+ # self.y_spin.setSingleStep(10 ** (-self.stage.prec))
614
+ # self.x_spin.setValue(self.stage.position[0])
615
+ # self.y_spin.setValue(self.stage.position[1])
616
+ # self.x_spin.setMinimum(self.stage.min[0])
617
+ # self.y_spin.setMinimum(self.stage.min[1])
618
+ # self.x_spin.setMaximum(self.stage.max[0])
619
+ # self.y_spin.setMaximum(self.stage.max[1])
620
+
621
+ # formLayout.addRow(QtWidgets.QLabel('X [mm]'), self.x_spin)
622
+ # formLayout.addRow(QtWidgets.QLabel('Y [mm]'), self.y_spin)
623
+
624
+ # self.step_spin = QtWidgets.QDoubleSpinBox()
625
+ # self.jump_spin = QtWidgets.QDoubleSpinBox()
626
+ # self.step_spin.setDecimals(self.stage.prec)
627
+ # self.jump_spin.setDecimals(self.stage.prec)
628
+ # self.step_spin.setSingleStep(10 ** (-self.stage.prec))
629
+ # self.jump_spin.setSingleStep(10 ** (-self.stage.prec))
630
+ # self.step_spin.setMinimum(self.stage.min[0])
631
+ # self.jump_spin.setMinimum(self.stage.min[1])
632
+ # self.step_spin.setMaximum(self.stage.max[0])
633
+ # self.jump_spin.setMaximum(self.stage.max[1])
634
+ # self.step_spin.setValue(0.050)
635
+ # self.jump_spin.setValue(0.5)
636
+
637
+ # formLayout.addRow(QtWidgets.QLabel('Step [mm]'), self.step_spin)
638
+ # formLayout.addRow(QtWidgets.QLabel('Jump [mm]'), self.jump_spin)
639
+
640
+ # self._move_btn = QtWidgets.QPushButton(
641
+ # 'Move',
642
+ # clicked=lambda: self.doAsync(
643
+ # self.stage.move_absolute,
644
+ # self.x_spin.value(),
645
+ # self.y_spin.value(),
646
+ # ),
647
+ # )
648
+ # self._home_btn = QtWidgets.QPushButton(
649
+ # 'Home', clicked=lambda: self.doAsync(self.stage.home)
650
+ # )
651
+ # self._center_btn = QtWidgets.QPushButton(
652
+ # 'Center',
653
+ # clicked=lambda: self.doAsync(self.stage.center),
654
+ # )
655
+ # self.x_id_btn = QtWidgets.QPushButton(
656
+ # 'ID X', clicked=lambda: self.stage.X_Kinesis.identify()
657
+ # )
658
+ # self.y_id_btn = QtWidgets.QPushButton(
659
+ # 'ID Y', clicked=lambda: self.stage.Y_Kinesis.identify()
660
+ # )
661
+
662
+ # controls = QtWidgets.QHBoxLayout()
663
+ # controls.addWidget(self._move_btn)
664
+ # controls.addWidget(self._home_btn)
665
+ # controls.addWidget(self._center_btn)
666
+ # controls.addWidget(self.x_id_btn)
667
+ # controls.addWidget(self.y_id_btn)
668
+ # formLayout.addRow(controls)
669
+
670
+ # self.n_x_jump_btn = QtWidgets.QPushButton(
671
+ # 'x--',
672
+ # clicked=lambda: self.doAsync(
673
+ # self.stage.move_relative, -self.jump_spin.value(), 0
674
+ # ),
675
+ # )
676
+ # self.n_x_step_btn = QtWidgets.QPushButton(
677
+ # 'x-',
678
+ # clicked=lambda: self.doAsync(
679
+ # self.stage.move_relative, -self.step_spin.value(), 0
680
+ # ),
681
+ # )
682
+ # self.p_x_step_btn = QtWidgets.QPushButton(
683
+ # 'x+',
684
+ # clicked=lambda: self.doAsync(
685
+ # self.stage.move_relative, self.step_spin.value(), 0
686
+ # ),
687
+ # )
688
+ # self.p_x_jump_btn = QtWidgets.QPushButton(
689
+ # 'x++',
690
+ # clicked=lambda: self.doAsync(
691
+ # self.stage.move_relative, self.jump_spin.value(), 0
692
+ # ),
693
+ # )
694
+
695
+ # self.n_y_jump_btn = QtWidgets.QPushButton(
696
+ # 'y--',
697
+ # clicked=lambda: self.doAsync(
698
+ # self.stage.move_relative, 0, -self.jump_spin.value()
699
+ # ),
700
+ # )
701
+ # self.n_y_step_btn = QtWidgets.QPushButton(
702
+ # 'y-',
703
+ # clicked=lambda: self.doAsync(
704
+ # self.stage.move_relative, 0, -self.step_spin.value()
705
+ # ),
706
+ # )
707
+ # self.p_y_step_btn = QtWidgets.QPushButton(
708
+ # 'y+',
709
+ # clicked=lambda: self.doAsync(
710
+ # self.stage.move_relative, 0, self.step_spin.value()
711
+ # ),
712
+ # )
713
+ # self.p_y_jump_btn = QtWidgets.QPushButton(
714
+ # 'y++',
715
+ # clicked=lambda: self.doAsync(
716
+ # self.stage.move_relative, 0, self.jump_spin.value()
717
+ # ),
718
+ # )
719
+
720
+ # self.n_x_step_btn.setStyleSheet('background-color: #004CB6')
721
+ # self.n_y_step_btn.setStyleSheet('background-color: #004CB6')
722
+ # self.p_x_step_btn.setStyleSheet('background-color: #004CB6')
723
+ # self.p_y_step_btn.setStyleSheet('background-color: #004CB6')
724
+
725
+ # grid = QtWidgets.QGridLayout()
726
+ # grid.addWidget(self.n_x_jump_btn, 2, 0)
727
+ # grid.addWidget(self.n_x_step_btn, 2, 1)
728
+ # grid.addWidget(self.p_x_step_btn, 2, 3)
729
+ # grid.addWidget(self.p_x_jump_btn, 2, 4)
730
+
731
+ # grid.addWidget(self.n_y_jump_btn, 4, 2)
732
+ # grid.addWidget(self.n_y_step_btn, 3, 2)
733
+ # grid.addWidget(self.p_y_step_btn, 1, 2)
734
+ # grid.addWidget(self.p_y_jump_btn, 0, 2)
735
+
736
+ # hLayout.addLayout(grid, 1)
737
+ # hLayout.addStretch()
738
+
739
+ # def doAsync(self, callback, *args):
740
+ # res = self.stage.isOpen()
741
+ # if res[0] and res[1]:
742
+ # self.stage.X_Kinesis.serial.read_all()
743
+ # self.stage.Y_Kinesis.serial.read_all()
744
+ # if self.controlsWidget is not None:
745
+ # self.controlsWidget.setEnabled(False)
746
+ # _worker = QThreadWorker(callback, *args, nokwargs=True)
747
+ # # Execute
748
+ # _worker.signals.result.connect(lambda: self.update())
749
+
750
+ # _worker.setAutoDelete(True)
751
+
752
+ # _worker.signals.finished.connect(lambda: self.threadpool.clear())
753
+
754
+ # self.threadpool.start(_worker)
755
+
756
+ # def update(self):
757
+ # self.x_spin.setValue(self.stage.position[0])
758
+ # self.y_spin.setValue(self.stage.position[1])
759
+ # if self.controlsWidget is not None:
760
+ # self.controlsWidget.setEnabled(True)
761
+
762
+
763
+ if __name__ == '__main__':
764
+ XY = KinesisXY('COM11', 'COM12')
765
+
766
+ # print(XY.home())
767
+ print(XY.center())
768
+
769
+ # for i in range(10):
770
+ # k = 0.01
771
+ # XY.move_relative(k, k)
772
+ # sleep(1)
773
+ # for i in range(10):
774
+ # k = - 0.01
775
+ # XY.move_relative(k, k)
776
+ # sleep(1)