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
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import numbers
|
|
2
2
|
|
|
3
|
+
from abc import abstractmethod
|
|
3
4
|
from time import perf_counter
|
|
4
|
-
from typing import Union, List, Dict, TYPE_CHECKING, Optional
|
|
5
|
+
from typing import Union, List, Dict, TYPE_CHECKING, Optional, TypeVar
|
|
5
6
|
from numbers import Number
|
|
6
7
|
from collections.abc import Iterable
|
|
7
8
|
|
|
@@ -34,11 +35,19 @@ from pymodaq_utils.serialize.serializer_legacy import DeSerializer, Serializer
|
|
|
34
35
|
from pymodaq import Unit
|
|
35
36
|
from pint.errors import OffsetUnitCalculusError
|
|
36
37
|
|
|
38
|
+
from pymodaq.control_modules.thread_commands import ThreadStatus, ThreadStatusMove
|
|
39
|
+
from pymodaq.utils.config import Config as ControlModulesConfig
|
|
40
|
+
from pymodaq.control_modules.daq_move_ui.factory import ActuatorUIFactory
|
|
41
|
+
|
|
37
42
|
if TYPE_CHECKING:
|
|
38
43
|
from pymodaq.control_modules.daq_move import DAQ_Move_Hardware
|
|
39
44
|
|
|
40
45
|
logger = set_logger(get_module_name(__file__))
|
|
41
|
-
|
|
46
|
+
|
|
47
|
+
config_utils = configmod.Config()
|
|
48
|
+
config = ControlModulesConfig()
|
|
49
|
+
|
|
50
|
+
HardwareController = TypeVar("HardwareController")
|
|
42
51
|
|
|
43
52
|
|
|
44
53
|
def check_units(dwa: DataActuator, units: str):
|
|
@@ -115,6 +124,7 @@ class MoveCommand:
|
|
|
115
124
|
the value the move should reach
|
|
116
125
|
|
|
117
126
|
"""
|
|
127
|
+
|
|
118
128
|
def __init__(self, move_type, value=0):
|
|
119
129
|
if move_type not in MOVE_COMMANDS:
|
|
120
130
|
raise ValueError(f'The allowed move types fro an actuator are {MOVE_COMMANDS}')
|
|
@@ -126,7 +136,6 @@ def comon_parameters_fun(is_multiaxes=False, axes_names=None,
|
|
|
126
136
|
axis_names: Union[List, Dict] = [],
|
|
127
137
|
master=True,
|
|
128
138
|
epsilon: float = config('actuator', 'epsilon_default')):
|
|
129
|
-
|
|
130
139
|
"""Function returning the common and mandatory parameters that should be on the actuator plugin level
|
|
131
140
|
|
|
132
141
|
Parameters
|
|
@@ -166,7 +175,7 @@ def comon_parameters_fun(is_multiaxes=False, axes_names=None,
|
|
|
166
175
|
'default': 0},
|
|
167
176
|
{'title': 'Status:', 'name': 'multi_status', 'type': 'list',
|
|
168
177
|
'value': 'Master' if master else 'Slave', 'limits': ['Master', 'Slave']},
|
|
169
|
-
{'title': 'Axis:', 'name': 'axis', 'type': 'list', 'limits': axis_names,
|
|
178
|
+
{'title': 'Axis:', 'name': 'axis', 'type': 'list', 'limits': axis_names.copy(),
|
|
170
179
|
'value': axis_name},
|
|
171
180
|
]},
|
|
172
181
|
] + comon_parameters(epsilon)
|
|
@@ -177,18 +186,22 @@ params = [
|
|
|
177
186
|
{'title': 'Main Settings:', 'name': 'main_settings', 'type': 'group', 'children': [
|
|
178
187
|
{'title': 'Actuator type:', 'name': 'move_type', 'type': 'str', 'value': '', 'readonly': True},
|
|
179
188
|
{'title': 'Actuator name:', 'name': 'module_name', 'type': 'str', 'value': '', 'readonly': True},
|
|
189
|
+
{'title': 'UI type:', 'name': 'ui_type', 'type': 'list',
|
|
190
|
+
'value': config('actuator', 'ui') if config('actuator', 'ui') in ActuatorUIFactory.keys() else
|
|
191
|
+
ActuatorUIFactory.keys()[0],
|
|
192
|
+
'limits': ActuatorUIFactory.keys()},
|
|
180
193
|
{'title': 'Plugin Config:', 'name': 'plugin_config', 'type': 'bool_push', 'label': 'Show Config', },
|
|
181
194
|
|
|
182
195
|
{'title': 'Refresh value (ms):', 'name': 'refresh_timeout', 'type': 'int',
|
|
183
|
-
|
|
196
|
+
'value': config('actuator', 'refresh_timeout_ms')},
|
|
184
197
|
{'title': 'TCP/IP options:', 'name': 'tcpip', 'type': 'group', 'visible': True, 'expanded': False,
|
|
185
198
|
'children': [
|
|
186
199
|
{'title': 'Connect to server:', 'name': 'connect_server', 'type': 'bool_push', 'label': 'Connect',
|
|
187
200
|
'value': False},
|
|
188
201
|
{'title': 'Connected?:', 'name': 'tcp_connected', 'type': 'led', 'value': False},
|
|
189
202
|
{'title': 'IP address:', 'name': 'ip_address', 'type': 'str',
|
|
190
|
-
'value':
|
|
191
|
-
{'title': 'Port:', 'name': 'port', 'type': 'int', 'value':
|
|
203
|
+
'value': config_utils('network', 'tcp-server', 'ip')},
|
|
204
|
+
{'title': 'Port:', 'name': 'port', 'type': 'int', 'value': config_utils('network', 'tcp-server', 'port')},
|
|
192
205
|
]},
|
|
193
206
|
{'title': 'LECO options:', 'name': 'leco', 'type': 'group', 'visible': True, 'expanded': False,
|
|
194
207
|
'children': [
|
|
@@ -196,8 +209,9 @@ params = [
|
|
|
196
209
|
'value': False},
|
|
197
210
|
{'title': 'Connected?:', 'name': 'leco_connected', 'type': 'led', 'value': False},
|
|
198
211
|
{'title': 'Name', 'name': 'leco_name', 'type': 'str', 'value': "", 'default': ""},
|
|
199
|
-
{'title': 'Host:', 'name': 'host', 'type': 'str', 'value':
|
|
200
|
-
|
|
212
|
+
{'title': 'Host:', 'name': 'host', 'type': 'str', 'value': config_utils('network', "leco-server", "host"),
|
|
213
|
+
"default": "localhost"},
|
|
214
|
+
{'title': 'Port:', 'name': 'port', 'type': 'int', 'value': config_utils('network', 'leco-server', 'port')},
|
|
201
215
|
]},
|
|
202
216
|
]},
|
|
203
217
|
{'title': 'Actuator Settings:', 'name': 'move_settings', 'type': 'group'}
|
|
@@ -274,14 +288,14 @@ class DAQ_Move_base(QObject):
|
|
|
274
288
|
_epsilons: Union[float, List[float], Dict[str, float]] = None
|
|
275
289
|
_epsilon = 1.0 # deprecated
|
|
276
290
|
|
|
277
|
-
|
|
278
291
|
params = []
|
|
279
292
|
|
|
280
293
|
data_actuator_type = DataActuatorType.float
|
|
281
|
-
data_shape = (1,
|
|
294
|
+
data_shape = (1,) # expected shape of the underlying actuator's value (in general a float so shape = (1, ))
|
|
282
295
|
|
|
283
296
|
def __init__(self, parent: Optional['DAQ_Move_Hardware'] = None,
|
|
284
|
-
params_state: Optional[dict] = None
|
|
297
|
+
params_state: Optional[dict] = None,
|
|
298
|
+
**kwargs):
|
|
285
299
|
QObject.__init__(self) # to make sure this is the parent class
|
|
286
300
|
self.move_is_done = False
|
|
287
301
|
self.parent = parent
|
|
@@ -307,7 +321,10 @@ class DAQ_Move_base(QObject):
|
|
|
307
321
|
self._title = "myactuator"
|
|
308
322
|
|
|
309
323
|
self._axis_units: Union[Dict[str, str], List[str]] = None
|
|
310
|
-
|
|
324
|
+
if isinstance(self._controller_units, str):
|
|
325
|
+
self.axis_units = self._controller_units
|
|
326
|
+
else:
|
|
327
|
+
self.axis_units = self._controller_units.copy()
|
|
311
328
|
if self._epsilons is None:
|
|
312
329
|
self._epsilons = self._epsilon
|
|
313
330
|
self.epsilons = self._epsilons
|
|
@@ -341,7 +358,7 @@ class DAQ_Move_base(QObject):
|
|
|
341
358
|
def axis_unit(self, unit: str):
|
|
342
359
|
self.axis_units[self.axis_index_key] = unit
|
|
343
360
|
self.settings.child('units').setValue(unit)
|
|
344
|
-
self.emit_status(ThreadCommand(
|
|
361
|
+
self.emit_status(ThreadCommand(ThreadStatusMove.UNITS, unit))
|
|
345
362
|
|
|
346
363
|
@property
|
|
347
364
|
def axis_units(self) -> Union[List[str], Dict[str, str]]:
|
|
@@ -436,6 +453,8 @@ class DAQ_Move_base(QObject):
|
|
|
436
453
|
return self.settings['multiaxes', 'axis']
|
|
437
454
|
elif isinstance(limits, dict):
|
|
438
455
|
return find_keys_from_val(limits, val=self.settings['multiaxes', 'axis'])[0]
|
|
456
|
+
else:
|
|
457
|
+
return ''
|
|
439
458
|
|
|
440
459
|
@axis_name.setter
|
|
441
460
|
def axis_name(self, name: str):
|
|
@@ -495,7 +514,12 @@ class DAQ_Move_base(QObject):
|
|
|
495
514
|
""" To be subclassed, in order to init specific attributes needed by the real implementation"""
|
|
496
515
|
self.controller = None
|
|
497
516
|
|
|
498
|
-
def ini_stage_init(
|
|
517
|
+
def ini_stage_init(
|
|
518
|
+
self,
|
|
519
|
+
old_controller: Optional[HardwareController] = None,
|
|
520
|
+
new_controller: Optional[HardwareController] = None,
|
|
521
|
+
slave_controller: Optional[HardwareController] = None,
|
|
522
|
+
) -> Optional[HardwareController]:
|
|
499
523
|
"""Manage the Master/Slave controller issue
|
|
500
524
|
|
|
501
525
|
First initialize the status dictionary
|
|
@@ -624,35 +648,36 @@ class DAQ_Move_base(QObject):
|
|
|
624
648
|
position = self.settings['bounds', 'min_bound']
|
|
625
649
|
return position
|
|
626
650
|
|
|
651
|
+
@abstractmethod
|
|
627
652
|
def get_actuator_value(self):
|
|
628
653
|
if hasattr(self, 'check_position'):
|
|
629
654
|
deprecation_msg('check_position method in plugins is deprecated, use get_actuator_value',3)
|
|
630
|
-
return self.check_position()
|
|
655
|
+
return self.check_position() # type: ignore
|
|
631
656
|
else:
|
|
632
657
|
raise NotImplementedError
|
|
633
658
|
|
|
634
|
-
|
|
635
|
-
def close(self):
|
|
659
|
+
@abstractmethod
|
|
660
|
+
def close(self) -> None:
|
|
636
661
|
raise NotImplementedError
|
|
637
662
|
|
|
638
663
|
def move_abs(self, value: Union[float, DataActuator]):
|
|
639
664
|
if hasattr(self, 'move_Abs'):
|
|
640
665
|
deprecation_msg('move_Abs method in plugins is deprecated, use move_abs', 3)
|
|
641
|
-
self.move_Abs(value)
|
|
666
|
+
self.move_Abs(value) # type: ignore
|
|
642
667
|
else:
|
|
643
668
|
raise NotImplementedError
|
|
644
669
|
|
|
645
670
|
def move_rel(self, value: Union[float, DataActuator]):
|
|
646
671
|
if hasattr(self, 'move_Rel'):
|
|
647
672
|
deprecation_msg('move_Rel method in plugins is deprecated, use move_rel', 3)
|
|
648
|
-
self.move_Rel(value)
|
|
673
|
+
self.move_Rel(value) # type: ignore
|
|
649
674
|
else:
|
|
650
675
|
raise NotImplementedError
|
|
651
676
|
|
|
652
677
|
def move_home(self, value: Union[float, DataActuator]):
|
|
653
678
|
if hasattr(self, 'move_Home'):
|
|
654
679
|
deprecation_msg('move_Home method in plugins is deprecated, use move_home', 3)
|
|
655
|
-
self.move_Home()
|
|
680
|
+
self.move_Home() # type: ignore
|
|
656
681
|
else:
|
|
657
682
|
raise NotImplementedError
|
|
658
683
|
|
|
@@ -668,7 +693,7 @@ class DAQ_Move_base(QObject):
|
|
|
668
693
|
def emit_value(self, pos: DataActuator):
|
|
669
694
|
"""Convenience method to emit the current actuator value back to the UI"""
|
|
670
695
|
|
|
671
|
-
self.emit_status(ThreadCommand(
|
|
696
|
+
self.emit_status(ThreadCommand(ThreadStatusMove.GET_ACTUATOR_VALUE, pos))
|
|
672
697
|
|
|
673
698
|
def commit_settings(self, param: Parameter):
|
|
674
699
|
"""
|
|
@@ -678,7 +703,8 @@ class DAQ_Move_base(QObject):
|
|
|
678
703
|
def commit_common_settings(self, param):
|
|
679
704
|
pass
|
|
680
705
|
|
|
681
|
-
def move_done(self, position: Optional[
|
|
706
|
+
def move_done(self, position: Optional[
|
|
707
|
+
DataActuator] = None): # the position argument is just there to match some signature of child classes
|
|
682
708
|
"""
|
|
683
709
|
| Emit a move done signal transmitting the float position to hardware.
|
|
684
710
|
| The position argument is just there to match some signature of child classes.
|
|
@@ -709,7 +735,8 @@ class DAQ_Move_base(QObject):
|
|
|
709
735
|
--------
|
|
710
736
|
DAQ_utils.ThreadCommand, move_done
|
|
711
737
|
"""
|
|
712
|
-
if 'TCPServer'
|
|
738
|
+
if not ('TCPServer' in self.__class__.__name__ or
|
|
739
|
+
'LECODirector' in self.__class__.__name__):
|
|
713
740
|
self.start_time = perf_counter()
|
|
714
741
|
if self.ispolling:
|
|
715
742
|
self.poll_timer.start()
|
|
@@ -729,7 +756,24 @@ class DAQ_Move_base(QObject):
|
|
|
729
756
|
logger.debug(f'Current position: {self._current_value}')
|
|
730
757
|
self.move_done(self._current_value)
|
|
731
758
|
|
|
732
|
-
def _condition_to_reach_target(self) -> bool:
|
|
759
|
+
def _condition_to_reach_target(self, check_absolute_difference=True,) -> bool:
|
|
760
|
+
"""Implement the condition for exiting the polling mechanism and specifying that the
|
|
761
|
+
target value has been reached
|
|
762
|
+
|
|
763
|
+
Returns
|
|
764
|
+
-------
|
|
765
|
+
bool: if True, PyMoDAQ considers the target value has been reached
|
|
766
|
+
See Also
|
|
767
|
+
--------
|
|
768
|
+
absolute_difference_condition_to_reach_target
|
|
769
|
+
user_condition_to_reach_target
|
|
770
|
+
"""
|
|
771
|
+
cond = True
|
|
772
|
+
if check_absolute_difference:
|
|
773
|
+
cond = self.absolute_difference_condition_to_reach_target()
|
|
774
|
+
return cond and self.user_condition_to_reach_target()
|
|
775
|
+
|
|
776
|
+
def absolute_difference_condition_to_reach_target(self) -> bool:
|
|
733
777
|
""" Implement the condition for exiting the polling mechanism and specifying that the
|
|
734
778
|
target value has been reached
|
|
735
779
|
|
|
@@ -756,7 +800,7 @@ class DAQ_Move_base(QObject):
|
|
|
756
800
|
else:
|
|
757
801
|
raise e
|
|
758
802
|
|
|
759
|
-
return (epsilon_calculated < self.epsilon)
|
|
803
|
+
return (epsilon_calculated < self.epsilon)
|
|
760
804
|
|
|
761
805
|
def user_condition_to_reach_target(self) -> bool:
|
|
762
806
|
""" Implement a user defined condition for exiting the polling mechanism and specifying
|
|
@@ -779,7 +823,7 @@ class DAQ_Move_base(QObject):
|
|
|
779
823
|
|
|
780
824
|
logger.debug(f'Check move_is_done: {self.move_is_done}')
|
|
781
825
|
if self.move_is_done:
|
|
782
|
-
self.emit_status(ThreadCommand('Move has been stopped', ))
|
|
826
|
+
self.emit_status(ThreadCommand(ThreadStatus.UPDATE_STATUS, 'Move has been stopped', ))
|
|
783
827
|
logger.info('Move has been stopped')
|
|
784
828
|
self.current_value = self.get_actuator_value()
|
|
785
829
|
self.emit_value(self._current_value)
|
|
@@ -787,7 +831,7 @@ class DAQ_Move_base(QObject):
|
|
|
787
831
|
|
|
788
832
|
if perf_counter() - self.start_time >= self.settings['timeout']:
|
|
789
833
|
self.poll_timer.stop()
|
|
790
|
-
self.emit_status(ThreadCommand(
|
|
834
|
+
self.emit_status(ThreadCommand(ThreadStatus.RAISE_TIMEOUT, ))
|
|
791
835
|
logger.info('Timeout activated')
|
|
792
836
|
else:
|
|
793
837
|
self.poll_timer.stop()
|
|
@@ -804,17 +848,19 @@ class DAQ_Move_base(QObject):
|
|
|
804
848
|
for param, change, data in changes:
|
|
805
849
|
path = self.settings.childPath(param)
|
|
806
850
|
if change == 'childAdded':
|
|
807
|
-
self.emit_status(ThreadCommand(
|
|
851
|
+
self.emit_status(ThreadCommand(ThreadStatus.UPDATE_SETTINGS,
|
|
808
852
|
[self.parent_parameters_path + path, [data[0].saveState(), data[1]],
|
|
809
853
|
change])) # send parameters values/limits back to the GUI. Send kind of a copy back the GUI otherwise the child reference will be the same in both th eUI and the plugin so one of them will be removed
|
|
810
854
|
elif change == 'value' or change == 'limits' or change == 'options':
|
|
811
|
-
self.emit_status(ThreadCommand(
|
|
812
|
-
|
|
855
|
+
self.emit_status(ThreadCommand(ThreadStatus.UPDATE_SETTINGS,
|
|
856
|
+
[self.parent_parameters_path + path, data,
|
|
857
|
+
change])) # send parameters values/limits back to the GUI
|
|
813
858
|
elif change == 'parent':
|
|
814
859
|
pass
|
|
815
860
|
elif change == 'limits':
|
|
816
|
-
self.emit_status(ThreadCommand(
|
|
817
|
-
|
|
861
|
+
self.emit_status(ThreadCommand(ThreadStatus.UPDATE_SETTINGS,
|
|
862
|
+
[self.parent_parameters_path + path, data,
|
|
863
|
+
change]))
|
|
818
864
|
|
|
819
865
|
def get_position_with_scaling(self, pos: DataActuator) -> DataActuator:
|
|
820
866
|
""" Get the current position from the hardware with scaling conversion.
|
|
@@ -868,12 +914,14 @@ class DAQ_Move_base(QObject):
|
|
|
868
914
|
except ValueError:
|
|
869
915
|
apply_settings = False
|
|
870
916
|
elif change == 'parent':
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
if children is not None:
|
|
874
|
-
path = putils.get_param_path(children)
|
|
875
|
-
self.settings.child(*path[1:-1]).removeChild(children)
|
|
917
|
+
try:
|
|
918
|
+
children = putils.get_param_from_name(self.settings, param.name())
|
|
876
919
|
|
|
920
|
+
if children is not None:
|
|
921
|
+
path = putils.get_param_path(children)
|
|
922
|
+
self.settings.child(*path[1:-1]).removeChild(children)
|
|
923
|
+
except IndexError:
|
|
924
|
+
logger.debug(f'Could not remove children from {param.name()}')
|
|
877
925
|
self.settings.sigTreeStateChanged.connect(self.send_param_status)
|
|
878
926
|
if apply_settings:
|
|
879
927
|
self.commit_common_settings(param)
|
|
@@ -884,6 +932,29 @@ class DAQ_Move_base(QObject):
|
|
|
884
932
|
elif param.name() == 'epsilon':
|
|
885
933
|
self.epsilon = param.value()
|
|
886
934
|
|
|
935
|
+
# abstract methods to be overwritten by the concrete implementations
|
|
936
|
+
@abstractmethod
|
|
937
|
+
def ini_stage(self, controller: Optional[HardwareController] = None) -> tuple[str, bool]:
|
|
938
|
+
"""Actuator communication initialization
|
|
939
|
+
|
|
940
|
+
Parameters
|
|
941
|
+
----------
|
|
942
|
+
controller: (object)
|
|
943
|
+
custom object of a PyMoDAQ plugin (Slave case). None if only one actuator by controller (Master case)
|
|
944
|
+
|
|
945
|
+
Returns
|
|
946
|
+
-------
|
|
947
|
+
info: str
|
|
948
|
+
initialized: bool
|
|
949
|
+
False if initialization failed otherwise True
|
|
950
|
+
"""
|
|
951
|
+
pass
|
|
952
|
+
|
|
953
|
+
@abstractmethod
|
|
954
|
+
def stop_motion(self, value: DataActuator) -> None:
|
|
955
|
+
"""Stop the actuator and emit move_done signal."""
|
|
956
|
+
pass
|
|
957
|
+
|
|
887
958
|
|
|
888
959
|
class DAQ_Move_TCP_server(DAQ_Move_base, TCPServer):
|
|
889
960
|
"""
|
|
@@ -933,20 +1004,21 @@ class DAQ_Move_TCP_server(DAQ_Move_base, TCPServer):
|
|
|
933
1004
|
|
|
934
1005
|
pos = self.get_position_with_scaling(pos)
|
|
935
1006
|
self._current_value = pos
|
|
936
|
-
self.emit_status(ThreadCommand(
|
|
1007
|
+
self.emit_status(ThreadCommand(ThreadStatusMove.GET_ACTUATOR_VALUE, pos))
|
|
937
1008
|
|
|
938
1009
|
elif command == 'move_done':
|
|
939
1010
|
pos = DeSerializer(sock).dwa_deserialization()
|
|
940
1011
|
pos = self.get_position_with_scaling(pos)
|
|
941
1012
|
self._current_value = pos
|
|
942
|
-
self.emit_status(ThreadCommand(
|
|
1013
|
+
self.emit_status(ThreadCommand(ThreadStatusMove.MOVE_DONE, pos))
|
|
943
1014
|
else:
|
|
944
1015
|
self.send_command(sock, command)
|
|
945
1016
|
|
|
946
1017
|
def commit_settings(self, param):
|
|
947
1018
|
|
|
948
1019
|
if param.name() in putils.iter_children(self.settings.child('settings_client'), []):
|
|
949
|
-
actuator_socket: Socket =
|
|
1020
|
+
actuator_socket: Socket = \
|
|
1021
|
+
[client['socket'] for client in self.connected_clients if client['type'] == 'ACTUATOR'][0]
|
|
950
1022
|
actuator_socket.check_sended_with_serializer('set_info')
|
|
951
1023
|
path = putils.get_param_path(param)[2:]
|
|
952
1024
|
# get the path of this param as a list starting at parent 'infos'
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
from pymodaq_utils.enums import StrEnum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ThreadStatus(StrEnum):
|
|
5
|
+
""" Allowed Generic commands sent from a plugin using the method: emit_status
|
|
6
|
+
|
|
7
|
+
Valid both for DAQ_Move and DAQ_Viewer control modules
|
|
8
|
+
|
|
9
|
+
See Also
|
|
10
|
+
--------
|
|
11
|
+
ControlModule.thread_status
|
|
12
|
+
"""
|
|
13
|
+
UPDATE_STATUS = 'update_status'
|
|
14
|
+
CLOSE = 'close'
|
|
15
|
+
UPDATE_SETTINGS = 'update_settings'
|
|
16
|
+
UPDATE_MAIN_SETTINGS = 'update_main_settings'
|
|
17
|
+
UPDATE_UI = 'update_ui'
|
|
18
|
+
RAISE_TIMEOUT = 'raise_timeout'
|
|
19
|
+
SHOW_SPLASH = 'show_splash'
|
|
20
|
+
CLOSE_SPLASH = 'close_splash'
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ThreadStatusMove(StrEnum):
|
|
24
|
+
""" Allowed Generic commands sent from a plugin using the method: emit_status
|
|
25
|
+
|
|
26
|
+
Valid only for DAQ_Move control module
|
|
27
|
+
|
|
28
|
+
See Also
|
|
29
|
+
--------
|
|
30
|
+
DAQ_Move.thread_status
|
|
31
|
+
"""
|
|
32
|
+
INI_STAGE = 'ini_stage'
|
|
33
|
+
GET_ACTUATOR_VALUE = 'get_actuator_value'
|
|
34
|
+
MOVE_DONE = 'move_done'
|
|
35
|
+
OUT_OF_BOUNDS = 'outofbounds'
|
|
36
|
+
SET_ALLOWED_VALUES = 'set_allowed_values'
|
|
37
|
+
STOP = 'stop'
|
|
38
|
+
UNITS = 'units'
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ThreadStatusViewer(StrEnum):
|
|
42
|
+
""" Allowed Generic commands sent from a plugin using the method: emit_status
|
|
43
|
+
|
|
44
|
+
Valid only for DAQ_Viewer control module
|
|
45
|
+
|
|
46
|
+
See Also
|
|
47
|
+
--------
|
|
48
|
+
DAQ_Viewer.thread_status
|
|
49
|
+
"""
|
|
50
|
+
INI_DETECTOR = 'ini_detector'
|
|
51
|
+
GRAB = 'grab'
|
|
52
|
+
GRAB_STOPPED = 'grab_stopped'
|
|
53
|
+
INI_LCD = 'init_lcd'
|
|
54
|
+
LCD = 'lcd'
|
|
55
|
+
STOP = 'stop'
|
|
56
|
+
UPDATE_CHANNELS = 'update_channels'
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ControlToHardwareMove(StrEnum):
|
|
61
|
+
""" Allowed commands sent from a DAQ_Move to its DAQ_Move_Hardware in another thread
|
|
62
|
+
using the method: command_hardware
|
|
63
|
+
|
|
64
|
+
Valid only for DAQ_Move command_hardware commands
|
|
65
|
+
|
|
66
|
+
"""
|
|
67
|
+
INI_STAGE = 'ini_stage'
|
|
68
|
+
STOP_MOTION = 'stop_motion'
|
|
69
|
+
RESET_STOP_MOTION = 'reset_stop_motion'
|
|
70
|
+
MOVE_ABS = 'move_abs'
|
|
71
|
+
MOVE_REL = 'move_rel'
|
|
72
|
+
MOVE_HOME = 'move_home'
|
|
73
|
+
GET_ACTUATOR_VALUE = 'get_actuator_value'
|
|
74
|
+
CLOSE = 'close'
|
|
75
|
+
|
|
76
|
+
class ControlToHardwareViewer(StrEnum):
|
|
77
|
+
""" Allowed commands sent from a DAQ_Viewer to its DAQ_Detector in another thread
|
|
78
|
+
using the method: command_hardware
|
|
79
|
+
|
|
80
|
+
Valid only for DAQ_Viewer command_hardware commands
|
|
81
|
+
|
|
82
|
+
"""
|
|
83
|
+
INI_DETECTOR = 'ini_detector'
|
|
84
|
+
|
|
85
|
+
SINGLE = 'single'
|
|
86
|
+
GRAB = 'grab'
|
|
87
|
+
STOP_GRAB = 'stop_grab'
|
|
88
|
+
ROI_SELECT = 'roi_select'
|
|
89
|
+
UPDATE_SCANNER = 'update_scanner' # may be deprecated
|
|
90
|
+
CROSSHAIR = 'crosshair'
|
|
91
|
+
UPDATE_WAIT_TIME = 'update_wait_time'
|
|
92
|
+
CLOSE = 'close'
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class UiToMainMove(StrEnum):
|
|
96
|
+
""" Allowed Commands to be sent from the DAQ_Move_UI to the DAQ_Move
|
|
97
|
+
"""
|
|
98
|
+
INIT = 'init'
|
|
99
|
+
QUIT = 'quit'
|
|
100
|
+
SHOW_LOG = 'show_log'
|
|
101
|
+
SHOW_CONFIG = 'show_config'
|
|
102
|
+
STOP = 'stop'
|
|
103
|
+
|
|
104
|
+
MOVE_ABS = 'move_abs'
|
|
105
|
+
MOVE_REL = 'move_rel'
|
|
106
|
+
|
|
107
|
+
ACTUATOR_CHANGED = 'actuator_changed'
|
|
108
|
+
|
|
109
|
+
GET_VALUE = 'get_value'
|
|
110
|
+
|
|
111
|
+
FIND_HOME = 'find_home'
|
|
112
|
+
REL_VALUE = 'rel_value'
|
|
113
|
+
|
|
114
|
+
LOOP_GET_VALUE = 'loop_get_value'
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class UiToMainViewer(StrEnum):
|
|
118
|
+
""" Allowed Commands to be sent from the DAQ_Viewer_UI to the DAQ_Viewer
|
|
119
|
+
"""
|
|
120
|
+
INIT = 'init'
|
|
121
|
+
QUIT = 'quit'
|
|
122
|
+
SHOW_LOG = 'show_log'
|
|
123
|
+
SHOW_CONFIG = 'show_config'
|
|
124
|
+
STOP = 'stop'
|
|
125
|
+
|
|
126
|
+
SNAP = 'snap'
|
|
127
|
+
GRAB = 'grab'
|
|
128
|
+
SAVE_CURRENT = 'save_current'
|
|
129
|
+
SAVE_NEW = 'save_new'
|
|
130
|
+
OPEN = 'open'
|
|
131
|
+
|
|
132
|
+
DETECTOR_CHANGED = 'detector_changed'
|
|
133
|
+
VIEWERS_CHANGED = 'viewers_changed'
|
|
134
|
+
DAQ_TYPE_CHANGED = 'daq_type_changed'
|
|
135
|
+
|
|
136
|
+
DO_BKG = 'do_bkg'
|
|
137
|
+
TAKE_BKG = 'take_bkg'
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from importlib import import_module
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from qtpy import QtCore
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
from pymodaq_gui.utils import CustomApp
|
|
8
|
+
|
|
9
|
+
from pymodaq_utils.utils import ThreadCommand
|
|
10
|
+
from pymodaq_utils.config import Config as ConfigUtils
|
|
11
|
+
from pymodaq.utils.config import Config
|
|
12
|
+
|
|
13
|
+
config_utils = ConfigUtils()
|
|
14
|
+
config = Config()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ControlModuleUI(CustomApp):
|
|
18
|
+
""" Base Class for ControlModules UIs
|
|
19
|
+
|
|
20
|
+
Attributes
|
|
21
|
+
----------
|
|
22
|
+
command_sig: Signal[Threadcommand]
|
|
23
|
+
This signal is emitted whenever some actions done by the user has to be
|
|
24
|
+
applied on the main module. Possible commands are:
|
|
25
|
+
See specific implementation
|
|
26
|
+
|
|
27
|
+
See Also
|
|
28
|
+
--------
|
|
29
|
+
:class:`daq_move_ui.DAQ_Move_UI`, :class:`daq_viewer_ui.DAQ_Viewer_UI`
|
|
30
|
+
"""
|
|
31
|
+
command_sig = QtCore.Signal(ThreadCommand)
|
|
32
|
+
|
|
33
|
+
def __init__(self, parent):
|
|
34
|
+
super().__init__(parent)
|
|
35
|
+
self.config = config
|
|
36
|
+
|
|
37
|
+
def display_status(self, txt, wait_time=config_utils('general', 'message_status_persistence')):
|
|
38
|
+
if self.statusbar is not None:
|
|
39
|
+
self.statusbar.showMessage(txt, wait_time)
|
|
40
|
+
|
|
41
|
+
def do_init(self, do_init=True):
|
|
42
|
+
"""Programmatically press the Init button
|
|
43
|
+
API entry
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
do_init: bool
|
|
47
|
+
will fire the Init button depending on the argument value and the button check state
|
|
48
|
+
"""
|
|
49
|
+
raise NotImplementedError
|
|
50
|
+
|
|
51
|
+
def send_init(self, checked: bool):
|
|
52
|
+
"""Should be implemented to send to the main app the fact that someone (un)checked init."""
|
|
53
|
+
raise NotImplementedError
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def register_uis(parent_module_name: str = 'pymodaq.control_modules.daq_move_ui'):
|
|
57
|
+
uis = []
|
|
58
|
+
try:
|
|
59
|
+
scanner_module = import_module(f'{parent_module_name}.uis')
|
|
60
|
+
|
|
61
|
+
scanner_path = Path(scanner_module.__path__[0])
|
|
62
|
+
|
|
63
|
+
for file in scanner_path.iterdir():
|
|
64
|
+
if file.is_file() and 'py' in file.suffix and file.stem != '__init__':
|
|
65
|
+
try:
|
|
66
|
+
uis.append(import_module(f'.{file.stem}', scanner_module.__name__))
|
|
67
|
+
except (ModuleNotFoundError, Exception) as e:
|
|
68
|
+
pass
|
|
69
|
+
except ModuleNotFoundError:
|
|
70
|
+
pass
|
|
71
|
+
finally:
|
|
72
|
+
return uis
|