pymodaq 5.0.17__py3-none-any.whl → 5.1.0__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.
Potentially problematic release.
This version of pymodaq might be problematic. Click here for more details.
- pymodaq/__init__.py +23 -11
- pymodaq/control_modules/__init__.py +1 -0
- pymodaq/control_modules/daq_move.py +458 -246
- pymodaq/control_modules/daq_move_ui/__init__.py +0 -0
- pymodaq/control_modules/daq_move_ui/factory.py +48 -0
- pymodaq/control_modules/{daq_move_ui.py → daq_move_ui/ui_base.py} +168 -210
- pymodaq/control_modules/daq_move_ui/uis/__init__.py +0 -0
- pymodaq/control_modules/daq_move_ui/uis/binary.py +139 -0
- pymodaq/control_modules/daq_move_ui/uis/original.py +120 -0
- pymodaq/control_modules/daq_move_ui/uis/relative.py +124 -0
- pymodaq/control_modules/daq_move_ui/uis/simple.py +126 -0
- pymodaq/control_modules/daq_viewer.py +113 -101
- pymodaq/control_modules/daq_viewer_ui.py +41 -31
- pymodaq/control_modules/mocks.py +2 -2
- pymodaq/control_modules/move_utility_classes.py +113 -41
- pymodaq/control_modules/thread_commands.py +137 -0
- pymodaq/control_modules/ui_utils.py +72 -0
- pymodaq/control_modules/utils.py +107 -63
- pymodaq/control_modules/viewer_utility_classes.py +13 -17
- pymodaq/dashboard.py +1294 -625
- pymodaq/examples/qt_less_standalone_module.py +48 -11
- pymodaq/extensions/__init__.py +8 -3
- pymodaq/extensions/adaptive/__init__.py +2 -0
- pymodaq/extensions/adaptive/adaptive_optimization.py +179 -0
- pymodaq/extensions/adaptive/loss_function/_1d_loss_functions.py +73 -0
- pymodaq/extensions/adaptive/loss_function/_2d_loss_functions.py +73 -0
- pymodaq/extensions/adaptive/loss_function/__init__.py +3 -0
- pymodaq/extensions/adaptive/loss_function/loss_factory.py +110 -0
- pymodaq/extensions/adaptive/utils.py +123 -0
- pymodaq/extensions/bayesian/__init__.py +1 -1
- pymodaq/extensions/bayesian/acquisition/__init__.py +2 -0
- pymodaq/extensions/bayesian/acquisition/acquisition_function_factory.py +80 -0
- pymodaq/extensions/bayesian/acquisition/base_acquisition_function.py +105 -0
- pymodaq/extensions/bayesian/bayesian_optimization.py +143 -0
- pymodaq/extensions/bayesian/utils.py +71 -297
- pymodaq/extensions/daq_logger/daq_logger.py +7 -12
- pymodaq/extensions/daq_logger/h5logging.py +1 -1
- pymodaq/extensions/daq_scan.py +30 -55
- pymodaq/extensions/data_mixer/__init__.py +0 -0
- pymodaq/extensions/data_mixer/daq_0Dviewer_DataMixer.py +97 -0
- pymodaq/extensions/data_mixer/data_mixer.py +262 -0
- pymodaq/extensions/data_mixer/model.py +108 -0
- pymodaq/extensions/data_mixer/models/__init__.py +0 -0
- pymodaq/extensions/data_mixer/models/equation_model.py +91 -0
- pymodaq/extensions/data_mixer/models/gaussian_fit_model.py +65 -0
- pymodaq/extensions/data_mixer/parser.py +53 -0
- pymodaq/extensions/data_mixer/utils.py +23 -0
- pymodaq/extensions/h5browser.py +3 -34
- pymodaq/extensions/optimizers_base/__init__.py +0 -0
- pymodaq/extensions/optimizers_base/optimizer.py +1016 -0
- pymodaq/extensions/optimizers_base/thread_commands.py +22 -0
- pymodaq/extensions/optimizers_base/utils.py +427 -0
- pymodaq/extensions/pid/actuator_controller.py +3 -2
- pymodaq/extensions/pid/daq_move_PID.py +107 -30
- pymodaq/extensions/pid/pid_controller.py +613 -287
- pymodaq/extensions/pid/utils.py +8 -5
- pymodaq/extensions/utils.py +17 -2
- pymodaq/resources/config_template.toml +57 -0
- pymodaq/resources/preset_default.xml +1 -1
- pymodaq/utils/config.py +13 -4
- pymodaq/utils/daq_utils.py +14 -0
- pymodaq/utils/data.py +1 -0
- pymodaq/utils/gui_utils/loader_utils.py +25 -15
- pymodaq/utils/h5modules/module_saving.py +134 -22
- pymodaq/utils/leco/daq_move_LECODirector.py +123 -84
- pymodaq/utils/leco/daq_xDviewer_LECODirector.py +84 -97
- pymodaq/utils/leco/director_utils.py +32 -16
- pymodaq/utils/leco/leco_director.py +104 -27
- pymodaq/utils/leco/pymodaq_listener.py +186 -97
- pymodaq/utils/leco/rpc_method_definitions.py +43 -0
- pymodaq/utils/leco/utils.py +25 -25
- pymodaq/utils/managers/batchscan_manager.py +12 -11
- pymodaq/utils/managers/modules_manager.py +74 -33
- pymodaq/utils/managers/overshoot_manager.py +11 -10
- pymodaq/utils/managers/preset_manager.py +100 -64
- pymodaq/utils/managers/preset_manager_utils.py +163 -107
- pymodaq/utils/managers/remote_manager.py +21 -16
- pymodaq/utils/scanner/scan_factory.py +18 -4
- pymodaq/utils/scanner/scan_selector.py +1 -3
- pymodaq/utils/scanner/scanner.py +35 -6
- pymodaq/utils/scanner/scanners/_1d_scanners.py +15 -46
- pymodaq/utils/scanner/scanners/_2d_scanners.py +21 -68
- pymodaq/utils/scanner/scanners/sequential.py +50 -31
- pymodaq/utils/scanner/scanners/tabular.py +45 -28
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/METADATA +7 -6
- pymodaq-5.1.0.dist-info/RECORD +154 -0
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/entry_points.txt +0 -2
- pymodaq/extensions/bayesian/bayesian_optimisation.py +0 -685
- pymodaq/utils/leco/desktop.ini +0 -2
- pymodaq-5.0.17.dist-info/RECORD +0 -121
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/WHEEL +0 -0
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,19 +6,21 @@ Created the 23/11/2022
|
|
|
6
6
|
"""
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
from typing import Union, List, Dict, Tuple, TYPE_CHECKING
|
|
9
|
+
from typing import Union, List, Dict, Tuple, TYPE_CHECKING, Iterable
|
|
10
10
|
import xml.etree.ElementTree as ET
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
import numpy as np
|
|
14
14
|
from pymodaq_utils.logger import set_logger, get_module_name
|
|
15
|
+
from pymodaq_utils.enums import BaseEnum
|
|
15
16
|
from pymodaq_utils.abstract import ABCMeta, abstract_attribute, abstractmethod
|
|
16
17
|
from pymodaq_utils.utils import capitalize
|
|
17
18
|
from pymodaq_data.data import Axis, DataDim, DataWithAxes, DataToExport, DataDistribution
|
|
18
19
|
from pymodaq_data.h5modules.saving import H5SaverLowLevel
|
|
19
20
|
from pymodaq_data.h5modules.backends import GROUP, CARRAY, Node, GroupType
|
|
20
|
-
from pymodaq_data.h5modules.data_saving import (
|
|
21
|
-
|
|
21
|
+
from pymodaq_data.h5modules.data_saving import (
|
|
22
|
+
DataToExportSaver, AxisSaverLoader, DataToExportEnlargeableSaver,
|
|
23
|
+
DataToExportTimedSaver, DataToExportExtendedSaver)
|
|
22
24
|
from pymodaq_gui.parameter import ioxml
|
|
23
25
|
|
|
24
26
|
if TYPE_CHECKING:
|
|
@@ -31,9 +33,17 @@ if TYPE_CHECKING:
|
|
|
31
33
|
logger = set_logger(get_module_name(__file__))
|
|
32
34
|
|
|
33
35
|
|
|
36
|
+
class GroupModuleType(BaseEnum):
|
|
37
|
+
DETECTOR = 0
|
|
38
|
+
ACTUATOR = 1
|
|
39
|
+
SCAN = 2
|
|
40
|
+
DATALOGGER = 3
|
|
41
|
+
OPTIMIZER = 4
|
|
42
|
+
|
|
43
|
+
|
|
34
44
|
class ModuleSaver(metaclass=ABCMeta):
|
|
35
45
|
"""Abstract base class to save info and data from main modules (DAQScan, DAQViewer, DAQMove, ...)"""
|
|
36
|
-
group_type:
|
|
46
|
+
group_type: GroupModuleType = abstract_attribute()
|
|
37
47
|
_module = abstract_attribute()
|
|
38
48
|
_h5saver: H5SaverLowLevel = abstract_attribute()
|
|
39
49
|
_module_group: GROUP = abstract_attribute()
|
|
@@ -119,11 +129,11 @@ class ModuleSaver(metaclass=ABCMeta):
|
|
|
119
129
|
|
|
120
130
|
def get_last_node_index(self, where: Union[Node, str] = None):
|
|
121
131
|
node = self.get_last_node(where)
|
|
122
|
-
return int(node.name.split(capitalize(self.group_type.name))[1])
|
|
132
|
+
return int(node.name.split(capitalize(self.group_type.name.lower()))[1])
|
|
123
133
|
|
|
124
134
|
def get_next_node_name(self, where: Union[Node, str] = None):
|
|
125
135
|
index = self.get_last_node_index(where)
|
|
126
|
-
return f'{capitalize(self.group_type.name)}{index+1:03d}'
|
|
136
|
+
return f'{capitalize(self.group_type.name.lower())}{index+1:03d}'
|
|
127
137
|
|
|
128
138
|
|
|
129
139
|
class DetectorSaver(ModuleSaver):
|
|
@@ -133,7 +143,7 @@ class DetectorSaver(ModuleSaver):
|
|
|
133
143
|
----------
|
|
134
144
|
module
|
|
135
145
|
"""
|
|
136
|
-
group_type =
|
|
146
|
+
group_type = GroupModuleType.DETECTOR
|
|
137
147
|
|
|
138
148
|
def __init__(self, module: DAQ_Viewer):
|
|
139
149
|
self._datatoexport_saver: DataToExportSaver = None
|
|
@@ -176,8 +186,8 @@ class DetectorSaver(ModuleSaver):
|
|
|
176
186
|
return self._h5saver.add_det_group(where, title=self._module.title, settings_as_xml=ET.tostring(settings_xml),
|
|
177
187
|
metadata=metadata)
|
|
178
188
|
|
|
179
|
-
def add_data(self, where: Union[Node, str], data: DataToExport):
|
|
180
|
-
self._datatoexport_saver.add_data(where, data)
|
|
189
|
+
def add_data(self, where: Union[Node, str], data: DataToExport, **kwargs):
|
|
190
|
+
self._datatoexport_saver.add_data(where, data, **kwargs)
|
|
181
191
|
|
|
182
192
|
def add_bkg(self, where: Union[Node, str], data_bkg: DataToExport):
|
|
183
193
|
""" Adds a DataToExport as a background node in the h5file
|
|
@@ -213,14 +223,14 @@ class DetectorSaver(ModuleSaver):
|
|
|
213
223
|
self.logger.exception(str(e))
|
|
214
224
|
|
|
215
225
|
|
|
216
|
-
class
|
|
226
|
+
class DetectorTimeSaver(DetectorSaver):
|
|
217
227
|
"""Implementation of the ModuleSaver class dedicated to DAQ_Viewer modules in order to save enlargeable data
|
|
218
228
|
|
|
219
229
|
Parameters
|
|
220
230
|
----------
|
|
221
231
|
module
|
|
222
232
|
"""
|
|
223
|
-
group_type =
|
|
233
|
+
group_type = GroupModuleType.DETECTOR
|
|
224
234
|
|
|
225
235
|
def __init__(self, module: DAQ_Viewer):
|
|
226
236
|
super().__init__(module)
|
|
@@ -230,6 +240,28 @@ class DetectorEnlargeableSaver(DetectorSaver):
|
|
|
230
240
|
self._datatoexport_saver = DataToExportTimedSaver(self.h5saver)
|
|
231
241
|
|
|
232
242
|
|
|
243
|
+
class DetectorEnlargeableSaver(DetectorSaver):
|
|
244
|
+
"""Implementation of the ModuleSaver class dedicated to DAQ_Viewer modules in order to save enlargeable data
|
|
245
|
+
|
|
246
|
+
Parameters
|
|
247
|
+
----------
|
|
248
|
+
module
|
|
249
|
+
"""
|
|
250
|
+
group_type = GroupModuleType.DETECTOR
|
|
251
|
+
|
|
252
|
+
def __init__(self, module: DAQ_Viewer,
|
|
253
|
+
enl_axis_names: Iterable[str] = None,
|
|
254
|
+
enl_axis_units: Iterable[str] = None,):
|
|
255
|
+
super().__init__(module)
|
|
256
|
+
self.enl_axis_names = enl_axis_names
|
|
257
|
+
self.enl_axis_units = enl_axis_units
|
|
258
|
+
self._datatoexport_saver: DataToExportEnlargeableSaver = None
|
|
259
|
+
|
|
260
|
+
def update_after_h5changed(self):
|
|
261
|
+
self._datatoexport_saver = DataToExportEnlargeableSaver(
|
|
262
|
+
self.h5saver, self.enl_axis_names, self.enl_axis_units)
|
|
263
|
+
|
|
264
|
+
|
|
233
265
|
class DetectorExtendedSaver(DetectorSaver):
|
|
234
266
|
"""Implementation of the ModuleSaver class dedicated to DAQ_Viewer modules in order to save enlargeable data
|
|
235
267
|
|
|
@@ -237,7 +269,7 @@ class DetectorExtendedSaver(DetectorSaver):
|
|
|
237
269
|
----------
|
|
238
270
|
module
|
|
239
271
|
"""
|
|
240
|
-
group_type =
|
|
272
|
+
group_type = GroupModuleType.DETECTOR
|
|
241
273
|
|
|
242
274
|
def __init__(self, module: DAQ_Viewer, extended_shape: Tuple[int]):
|
|
243
275
|
super().__init__(module)
|
|
@@ -263,18 +295,20 @@ class ActuatorSaver(ModuleSaver):
|
|
|
263
295
|
h5saver
|
|
264
296
|
module
|
|
265
297
|
"""
|
|
266
|
-
group_type =
|
|
298
|
+
group_type = GroupModuleType.ACTUATOR
|
|
267
299
|
|
|
268
300
|
def __init__(self, module: DAQ_Move):
|
|
269
|
-
self._datatoexport_saver:
|
|
301
|
+
self._datatoexport_saver: DataToExportSaver = None
|
|
270
302
|
self._module_group: GROUP = None
|
|
271
303
|
self._module: DAQ_Move = module
|
|
272
304
|
self._h5saver = None
|
|
273
305
|
|
|
274
306
|
def update_after_h5changed(self, ):
|
|
275
|
-
self._datatoexport_saver =
|
|
307
|
+
self._datatoexport_saver = DataToExportSaver(self.h5saver)
|
|
276
308
|
|
|
277
|
-
def _add_module(self, where: Union[Node, str] = None, metadata=
|
|
309
|
+
def _add_module(self, where: Union[Node, str] = None, metadata=None):
|
|
310
|
+
if metadata is None:
|
|
311
|
+
metadata={}
|
|
278
312
|
if where is None:
|
|
279
313
|
where = self._h5saver.raw_group
|
|
280
314
|
|
|
@@ -288,6 +322,46 @@ class ActuatorSaver(ModuleSaver):
|
|
|
288
322
|
self._datatoexport_saver.add_data(where, data)
|
|
289
323
|
|
|
290
324
|
|
|
325
|
+
class ActuatorTimeSaver(ActuatorSaver):
|
|
326
|
+
def __init__(self, module: DAQ_Move):
|
|
327
|
+
super().__init__(module)
|
|
328
|
+
self._datatoexport_saver: DataToExportTimedSaver = None
|
|
329
|
+
|
|
330
|
+
def update_after_h5changed(self, ):
|
|
331
|
+
self._datatoexport_saver = DataToExportTimedSaver(self.h5saver)
|
|
332
|
+
|
|
333
|
+
def add_data(self, where: Union[Node, str], data: DataToExport):
|
|
334
|
+
self._datatoexport_saver.add_data(where, data)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
class ActuatorEnlargeableSaver(ActuatorTimeSaver):
|
|
338
|
+
"""Implementation of the ModuleSaver class dedicated to DAQ_Move modules
|
|
339
|
+
|
|
340
|
+
Parameters
|
|
341
|
+
----------
|
|
342
|
+
h5saver
|
|
343
|
+
module
|
|
344
|
+
"""
|
|
345
|
+
|
|
346
|
+
def __init__(self, module: DAQ_Move,
|
|
347
|
+
enl_axis_names: Iterable[str] = None,
|
|
348
|
+
enl_axis_units: Iterable[str] = None,):
|
|
349
|
+
super().__init__(module)
|
|
350
|
+
self.enl_axis_names = enl_axis_names
|
|
351
|
+
self.enl_axis_units = enl_axis_units
|
|
352
|
+
self._datatoexport_saver: DataToExportEnlargeableSaver = None
|
|
353
|
+
|
|
354
|
+
def update_after_h5changed(self, ):
|
|
355
|
+
self._datatoexport_saver = DataToExportEnlargeableSaver(
|
|
356
|
+
self.h5saver, self.enl_axis_names, self.enl_axis_units)
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def add_data(self, where: Union[Node, str], data: DataToExport,
|
|
360
|
+
axis_values: List[Union[float, np.ndarray]] = None,
|
|
361
|
+
**kwargs):
|
|
362
|
+
self._datatoexport_saver.add_data(where, data, axis_values, **kwargs)
|
|
363
|
+
|
|
364
|
+
|
|
291
365
|
class ScanSaver(ModuleSaver):
|
|
292
366
|
"""Implementation of the ModuleSaver class dedicated to DAQScan module
|
|
293
367
|
|
|
@@ -296,7 +370,7 @@ class ScanSaver(ModuleSaver):
|
|
|
296
370
|
h5saver
|
|
297
371
|
module
|
|
298
372
|
"""
|
|
299
|
-
group_type =
|
|
373
|
+
group_type = GroupModuleType.SCAN
|
|
300
374
|
|
|
301
375
|
def __init__(self, module):
|
|
302
376
|
self._module_group: GROUP = None
|
|
@@ -341,7 +415,7 @@ class ScanSaver(ModuleSaver):
|
|
|
341
415
|
module.module_and_data_saver.get_set_node(self._module_group)
|
|
342
416
|
return self._module_group
|
|
343
417
|
|
|
344
|
-
def _add_module(self, where: Union[Node, str] = None, metadata=
|
|
418
|
+
def _add_module(self, where: Union[Node, str] = None, metadata=None) -> Node:
|
|
345
419
|
"""
|
|
346
420
|
|
|
347
421
|
Parameters
|
|
@@ -354,6 +428,8 @@ class ScanSaver(ModuleSaver):
|
|
|
354
428
|
-------
|
|
355
429
|
|
|
356
430
|
"""
|
|
431
|
+
if metadata is None:
|
|
432
|
+
metadata = {}
|
|
357
433
|
if where is None:
|
|
358
434
|
where = self._h5saver.raw_group
|
|
359
435
|
|
|
@@ -363,16 +439,17 @@ class ScanSaver(ModuleSaver):
|
|
|
363
439
|
saver_xml = ET.SubElement(settings_xml, 'H5Saver', type='group')
|
|
364
440
|
saver_xml.append(ioxml.walk_parameters_to_xml(param=self._h5saver.settings))
|
|
365
441
|
|
|
366
|
-
return self._h5saver.
|
|
442
|
+
return self._h5saver.add_generic_group(where, title=self._module.title,
|
|
367
443
|
settings_as_xml=ET.tostring(settings_xml),
|
|
368
|
-
metadata=metadata
|
|
444
|
+
metadata=metadata,
|
|
445
|
+
group_type=self.group_type.name)
|
|
369
446
|
|
|
370
447
|
def add_nav_axes(self, axes: List[Axis]):
|
|
371
448
|
for detector in self._module.modules_manager.detectors:
|
|
372
449
|
detector.module_and_data_saver.add_nav_axes(self._module_group, axes)
|
|
373
450
|
|
|
374
451
|
def add_data(self, dte: DataToExport = None, indexes: Tuple[int] = None,
|
|
375
|
-
distribution=DataDistribution['uniform']):
|
|
452
|
+
distribution=DataDistribution['uniform'], **kwargs):
|
|
376
453
|
for detector in self._module.modules_manager.detectors:
|
|
377
454
|
try:
|
|
378
455
|
detector.insert_data(indexes, where=self._module_group, distribution=distribution)
|
|
@@ -390,7 +467,7 @@ class LoggerSaver(ScanSaver):
|
|
|
390
467
|
h5saver
|
|
391
468
|
module
|
|
392
469
|
"""
|
|
393
|
-
group_type =
|
|
470
|
+
group_type = GroupModuleType.DATALOGGER
|
|
394
471
|
|
|
395
472
|
def add_data(self, dte: DataToExport):
|
|
396
473
|
"""Add data to it's corresponding control module
|
|
@@ -407,3 +484,38 @@ class LoggerSaver(ScanSaver):
|
|
|
407
484
|
return
|
|
408
485
|
|
|
409
486
|
control_module.append_data(dte=dte, where=self._module_group)
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
class OptimizerSaver(ScanSaver):
|
|
490
|
+
"""Implementation of the ModuleSaver class dedicated to Optimizer based modules
|
|
491
|
+
|
|
492
|
+
Parameters
|
|
493
|
+
----------
|
|
494
|
+
h5saver
|
|
495
|
+
module
|
|
496
|
+
"""
|
|
497
|
+
group_type = GroupModuleType.OPTIMIZER
|
|
498
|
+
|
|
499
|
+
def __init__(self, module,
|
|
500
|
+
enl_axis_names: Iterable[str] = None,
|
|
501
|
+
enl_axis_units: Iterable[str] = None,):
|
|
502
|
+
super().__init__(module)
|
|
503
|
+
self.enl_axis_names = enl_axis_names
|
|
504
|
+
self.enl_axis_units = enl_axis_units
|
|
505
|
+
|
|
506
|
+
def update_after_h5changed(self, ):
|
|
507
|
+
for module in self._module.modules_manager.detectors:
|
|
508
|
+
module.module_and_data_saver = DetectorEnlargeableSaver(
|
|
509
|
+
module, self.enl_axis_names, self.enl_axis_units)
|
|
510
|
+
module.module_and_data_saver.h5saver = self.h5saver
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
def add_data(self, *args, axis_values: List[Union[float, np.ndarray]] = None,
|
|
514
|
+
**kwargs):
|
|
515
|
+
for module in self._module.modules_manager.detectors:
|
|
516
|
+
try:
|
|
517
|
+
module.append_data(where=self._module_group,
|
|
518
|
+
axis_values=axis_values,
|
|
519
|
+
**kwargs)
|
|
520
|
+
except Exception as e:
|
|
521
|
+
logger.exception(f'Cannot append data: {str(e)}')
|
|
@@ -7,17 +7,27 @@ running: `python -m pyleco.coordinators.coordinator`
|
|
|
7
7
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
from typing import Optional, Union
|
|
11
13
|
|
|
12
14
|
from pymodaq.control_modules.move_utility_classes import (DAQ_Move_base, comon_parameters_fun, main,
|
|
13
15
|
DataActuatorType, DataActuator)
|
|
16
|
+
from pymodaq.control_modules.thread_commands import ThreadStatus, ThreadStatusMove
|
|
14
17
|
|
|
15
18
|
from pymodaq_utils.utils import ThreadCommand
|
|
19
|
+
from pymodaq_utils.utils import find_dict_in_list_from_key_val
|
|
20
|
+
from pymodaq_utils.serialize.factory import SerializableFactory
|
|
16
21
|
from pymodaq_gui.parameter import Parameter
|
|
17
22
|
|
|
18
|
-
from pymodaq.utils.leco.leco_director import LECODirector, leco_parameters
|
|
23
|
+
from pymodaq.utils.leco.leco_director import (LECODirector, leco_parameters, DirectorCommands,
|
|
24
|
+
DirectorReceivedCommands)
|
|
19
25
|
from pymodaq.utils.leco.director_utils import ActuatorDirector
|
|
20
|
-
|
|
26
|
+
|
|
27
|
+
from pymodaq_utils.logger import set_logger, get_module_name
|
|
28
|
+
|
|
29
|
+
logger = set_logger(get_module_name(__file__))
|
|
30
|
+
|
|
21
31
|
|
|
22
32
|
class DAQ_Move_LECODirector(LECODirector, DAQ_Move_base):
|
|
23
33
|
"""A control module, which in the dashboard, allows to control a remote Move module.
|
|
@@ -35,38 +45,44 @@ class DAQ_Move_LECODirector(LECODirector, DAQ_Move_base):
|
|
|
35
45
|
utility_classes.DAQ_TCP_server
|
|
36
46
|
"""
|
|
37
47
|
settings: Parameter
|
|
38
|
-
controller: ActuatorDirector
|
|
48
|
+
controller: Optional[ActuatorDirector]
|
|
49
|
+
_axis_names = ['']
|
|
50
|
+
_controller_units = ['']
|
|
51
|
+
_epsilon = 1
|
|
39
52
|
|
|
40
53
|
params_client = [] # parameters of a client grabber
|
|
41
|
-
data_actuator_type = DataActuatorType
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def __init__(
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
data_actuator_type = DataActuatorType.DataActuator
|
|
55
|
+
params = comon_parameters_fun(axis_names=_axis_names, epsilon=_epsilon) + leco_parameters
|
|
56
|
+
|
|
57
|
+
for param_name in ('multiaxes', 'units', 'epsilon', 'bounds', 'scaling'):
|
|
58
|
+
param_dict = find_dict_in_list_from_key_val(params, 'name', param_name)
|
|
59
|
+
if param_dict is not None:
|
|
60
|
+
param_dict['visible'] = False
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self, parent=None, params_state=None, host: Optional[str] = None, port: Optional[int] = None, **kwargs
|
|
64
|
+
) -> None:
|
|
65
|
+
DAQ_Move_base.__init__(self, parent=parent, params_state=params_state)
|
|
66
|
+
if host is not None:
|
|
67
|
+
self.settings["host"] = host
|
|
68
|
+
if port is not None:
|
|
69
|
+
self.settings["port"] = port
|
|
70
|
+
LECODirector.__init__(self, host=self.settings["host"], port=self.settings["port"])
|
|
52
71
|
self.register_rpc_methods((
|
|
53
|
-
self.
|
|
72
|
+
self.set_units, # to set units accordingly to the one of the actor
|
|
73
|
+
))
|
|
74
|
+
|
|
75
|
+
self.register_binary_rpc_methods((
|
|
76
|
+
self.send_position, # to display the actor position
|
|
77
|
+
self.set_move_done, # to set the move as done
|
|
54
78
|
))
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
# copied, I think it is good:
|
|
64
|
-
self.settings.child('bounds').hide()
|
|
65
|
-
self.settings.child('scaling').hide()
|
|
66
|
-
self.settings.child('epsilon').setValue(1)
|
|
67
|
-
|
|
68
|
-
def commit_settings(self, param) -> None:
|
|
69
|
-
self.commit_leco_settings(param=param)
|
|
79
|
+
self.start_timer()
|
|
80
|
+
# To distinguish how to encode positions, it needs to now if it deals
|
|
81
|
+
# with a json-accepting or a binary-accepting actuator
|
|
82
|
+
# It is set to False by default. It then use the first received message
|
|
83
|
+
# from the actuator that should contain its position to decide if it
|
|
84
|
+
# need to switch to json.
|
|
85
|
+
self.json = False
|
|
70
86
|
|
|
71
87
|
def ini_stage(self, controller=None):
|
|
72
88
|
"""Actuator communication initialization
|
|
@@ -83,96 +99,119 @@ class DAQ_Move_LECODirector(LECODirector, DAQ_Move_base):
|
|
|
83
99
|
initialized: bool
|
|
84
100
|
False if initialization failed otherwise True
|
|
85
101
|
"""
|
|
86
|
-
actor_name = self.settings
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
self.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return
|
|
102
|
+
actor_name = self.settings["actor_name"]
|
|
103
|
+
|
|
104
|
+
if self.is_master:
|
|
105
|
+
self.controller = ActuatorDirector(actor=actor_name, communicator=self.communicator)
|
|
106
|
+
try:
|
|
107
|
+
self.controller.set_remote_name(self.communicator.full_name)
|
|
108
|
+
except TimeoutError:
|
|
109
|
+
logger.warning("Timeout setting remote name.")
|
|
110
|
+
else:
|
|
111
|
+
self.controller = controller
|
|
112
|
+
|
|
113
|
+
self.json = False
|
|
114
|
+
# send a command to the Actor whose name is actor_name to send its settings
|
|
115
|
+
self.controller.get_settings()
|
|
116
|
+
|
|
117
|
+
info = f"LECODirector: {self._title} is initialized"
|
|
118
|
+
initialized = True
|
|
119
|
+
return info, initialized
|
|
104
120
|
|
|
105
121
|
def move_abs(self, position: DataActuator) -> None:
|
|
106
122
|
position = self.check_bound(position)
|
|
107
123
|
position = self.set_position_with_scaling(position)
|
|
108
|
-
|
|
109
|
-
self.controller.move_abs(position=position)
|
|
110
|
-
|
|
111
124
|
self.target_value = position
|
|
125
|
+
if self.json:
|
|
126
|
+
# if it's 0D, just send the position as a scalar
|
|
127
|
+
if hasattr(self, 'shape') and self.shape == ():
|
|
128
|
+
position = position.value(self.axis_unit)
|
|
129
|
+
else:
|
|
130
|
+
# Until the GUI allows for it (next line), we send the single value repeated
|
|
131
|
+
# position = [data.m_as(self.axis_unit) for data in position.quantities]
|
|
132
|
+
position = np.full(self.shape, position.value(self.axis_unit)).tolist()
|
|
133
|
+
self.controller.move_abs(position=position)
|
|
112
134
|
|
|
113
135
|
def move_rel(self, position: DataActuator) -> None:
|
|
114
136
|
position = self.check_bound(self.current_value + position) - self.current_value # type: ignore # noqa
|
|
115
137
|
self.target_value = position + self.current_value
|
|
116
138
|
|
|
117
139
|
position = self.set_position_relative_with_scaling(position)
|
|
140
|
+
if self.json:
|
|
141
|
+
# if it's 0D, just send the position as a scalar
|
|
142
|
+
if hasattr(self, 'ndim') and self.shape == ():
|
|
143
|
+
position = position.value(self.axis_unit)
|
|
144
|
+
else:
|
|
145
|
+
# Until the GUI allows for it (next line), we send the single value repeated
|
|
146
|
+
#position = [data.m_as(self.axis_unit) for data in position.quantities]
|
|
147
|
+
position = np.full(self.shape, position.value(self.axis_unit)).tolist()
|
|
148
|
+
|
|
118
149
|
self.controller.move_rel(position=position)
|
|
119
150
|
|
|
120
151
|
def move_home(self):
|
|
121
152
|
self.controller.move_home()
|
|
122
153
|
|
|
123
154
|
def get_actuator_value(self) -> DataActuator:
|
|
124
|
-
"""
|
|
125
|
-
Get the current hardware position with scaling conversion given by
|
|
126
|
-
`get_position_with_scaling`.
|
|
127
|
-
|
|
128
|
-
See Also
|
|
129
|
-
--------
|
|
130
|
-
daq_move_base.get_position_with_scaling, daq_utils.ThreadCommand
|
|
131
|
-
"""
|
|
132
|
-
self.controller.set_remote_name(self.communicator.full_name) # to ensure communication
|
|
155
|
+
""" Get the current hardware value """
|
|
133
156
|
self.controller.get_actuator_value()
|
|
134
157
|
return self._current_value
|
|
135
158
|
|
|
136
159
|
def stop_motion(self) -> None:
|
|
137
160
|
"""
|
|
138
|
-
See Also
|
|
139
|
-
--------
|
|
140
|
-
daq_move_base.move_done
|
|
141
161
|
"""
|
|
142
162
|
self.controller.stop_motion()
|
|
143
163
|
|
|
144
164
|
# Methods accessible via remote calls
|
|
145
165
|
def _set_position_value(
|
|
146
|
-
self,
|
|
166
|
+
self, data: Union[dict, list, str, float, None], additional_payload=None
|
|
147
167
|
) -> DataActuator:
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
168
|
+
|
|
169
|
+
# This is the first received message, if position is set then
|
|
170
|
+
# it's included in the json payload and the director should
|
|
171
|
+
# usejson
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
if data is not None:
|
|
175
|
+
position = data.get('position', [])
|
|
176
|
+
|
|
177
|
+
self.shape = np.array(position).shape
|
|
178
|
+
position = [np.atleast_1d(position)]
|
|
179
|
+
|
|
180
|
+
pos = DataActuator(data=position)
|
|
181
|
+
self.json = True
|
|
182
|
+
elif additional_payload:
|
|
183
|
+
pos = SerializableFactory().get_apply_deserializer(additional_payload[0])
|
|
156
184
|
else:
|
|
157
185
|
raise ValueError("No position given")
|
|
158
186
|
pos = self.get_position_with_scaling(pos) # type: ignore
|
|
159
187
|
self._current_value = pos
|
|
160
188
|
return pos
|
|
161
189
|
|
|
162
|
-
def
|
|
163
|
-
pos = self._set_position_value(
|
|
164
|
-
self.emit_status(ThreadCommand(
|
|
190
|
+
def send_position(self, data: Union[dict, list, str, float, None], additional_payload=None) -> None:
|
|
191
|
+
pos = self._set_position_value(data=data, additional_payload=additional_payload)
|
|
192
|
+
self.emit_status(ThreadCommand(ThreadStatusMove.GET_ACTUATOR_VALUE, pos))
|
|
193
|
+
|
|
194
|
+
def set_move_done(self, data: Union[dict, list, str, float, None], additional_payload=None) -> None:
|
|
195
|
+
pos = self._set_position_value(data=data, additional_payload=additional_payload)
|
|
196
|
+
self.emit_status(ThreadCommand(ThreadStatusMove.MOVE_DONE, pos))
|
|
197
|
+
|
|
198
|
+
def set_units(self, units: str, additional_payload=None) -> None:
|
|
199
|
+
if units not in self.axis_units:
|
|
200
|
+
self.axis_units.append(units)
|
|
201
|
+
self.axis_unit = units
|
|
165
202
|
|
|
166
|
-
def
|
|
167
|
-
|
|
168
|
-
|
|
203
|
+
def set_director_settings(self, settings: bytes):
|
|
204
|
+
""" Get the content of the actor settings to pe populated in this plugin
|
|
205
|
+
'settings_client' parameter
|
|
169
206
|
|
|
170
|
-
|
|
171
|
-
|
|
207
|
+
Then set the plugin units from this information"""
|
|
208
|
+
super().set_director_settings(settings)
|
|
209
|
+
self.axis_unit = self.settings['settings_client', 'units']
|
|
172
210
|
|
|
173
|
-
def
|
|
174
|
-
|
|
211
|
+
def close(self) -> None:
|
|
212
|
+
""" Clear the content of the settings_clients setting"""
|
|
213
|
+
super().close()
|
|
175
214
|
|
|
176
215
|
|
|
177
216
|
if __name__ == '__main__':
|
|
178
|
-
main(__file__)
|
|
217
|
+
main(__file__, init=False)
|