pymodaq 3.6.12__py3-none-any.whl → 4.0.1__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.

Files changed (233) hide show
  1. pymodaq/__init__.py +13 -6
  2. pymodaq/control_modules/__init__.py +0 -7
  3. pymodaq/control_modules/daq_move.py +965 -2
  4. pymodaq/control_modules/daq_move_ui.py +319 -0
  5. pymodaq/control_modules/daq_viewer.py +1573 -3
  6. pymodaq/control_modules/daq_viewer_ui.py +393 -0
  7. pymodaq/control_modules/mocks.py +51 -0
  8. pymodaq/control_modules/move_utility_classes.py +709 -8
  9. pymodaq/control_modules/utils.py +256 -0
  10. pymodaq/control_modules/viewer_utility_classes.py +663 -6
  11. pymodaq/daq_utils.py +89 -0
  12. pymodaq/dashboard.py +91 -72
  13. pymodaq/examples/custom_app.py +12 -11
  14. pymodaq/examples/custom_viewer.py +10 -10
  15. pymodaq/examples/function_plotter.py +16 -13
  16. pymodaq/examples/nonlinearscanner.py +8 -6
  17. pymodaq/examples/parameter_ex.py +7 -7
  18. pymodaq/examples/preset_MockCamera.xml +1 -0
  19. pymodaq/extensions/__init__.py +16 -0
  20. pymodaq/extensions/console.py +76 -0
  21. pymodaq/{daq_logger.py → extensions/daq_logger.py} +115 -65
  22. pymodaq/extensions/daq_scan.py +1339 -0
  23. pymodaq/extensions/daq_scan_ui.py +240 -0
  24. pymodaq/extensions/h5browser.py +23 -0
  25. pymodaq/{pid → extensions/pid}/__init__.py +4 -2
  26. pymodaq/{pid → extensions/pid}/daq_move_PID.py +2 -2
  27. pymodaq/{pid → extensions/pid}/pid_controller.py +48 -36
  28. pymodaq/{pid → extensions/pid}/utils.py +52 -6
  29. pymodaq/extensions/utils.py +40 -0
  30. pymodaq/post_treatment/__init__.py +6 -0
  31. pymodaq/{daq_analysis → post_treatment/daq_analysis}/daq_analysis_main.py +17 -17
  32. pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_main.py +8 -14
  33. pymodaq/post_treatment/load_and_plot.py +219 -0
  34. pymodaq/post_treatment/process_to_scalar.py +263 -0
  35. pymodaq/resources/QtDesigner_Ressources/Icon_Library/run_all.png +0 -0
  36. pymodaq/resources/QtDesigner_Ressources/Icon_Library/stop_all.png +0 -0
  37. pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources.bat +1 -1
  38. pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources.qrc +1 -0
  39. pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources_rc.py +109784 -109173
  40. pymodaq/resources/QtDesigner_Ressources/icons.svg +142 -0
  41. pymodaq/resources/VERSION +1 -1
  42. pymodaq/resources/config_template.toml +32 -13
  43. pymodaq/resources/preset_default.xml +1 -1
  44. pymodaq/{daq_utils → utils}/Tuto innosetup/script_full_setup.iss +1 -1
  45. pymodaq/utils/__init__.py +0 -29
  46. pymodaq/utils/abstract/__init__.py +48 -0
  47. pymodaq/{daq_utils → utils}/abstract/logger.py +7 -3
  48. pymodaq/utils/array_manipulation.py +379 -8
  49. pymodaq/{daq_utils → utils}/calibration_camera.py +6 -6
  50. pymodaq/{daq_utils → utils}/chrono_timer.py +1 -1
  51. pymodaq/utils/config.py +448 -0
  52. pymodaq/utils/conftests.py +5 -0
  53. pymodaq/utils/daq_utils.py +828 -8
  54. pymodaq/utils/data.py +1873 -7
  55. pymodaq/{daq_utils → utils}/db/db_logger/db_logger.py +86 -47
  56. pymodaq/{daq_utils → utils}/db/db_logger/db_logger_models.py +31 -10
  57. pymodaq/{daq_utils → utils}/enums.py +12 -7
  58. pymodaq/utils/exceptions.py +37 -0
  59. pymodaq/utils/factory.py +82 -0
  60. pymodaq/{daq_utils → utils}/gui_utils/__init__.py +1 -1
  61. pymodaq/utils/gui_utils/custom_app.py +129 -0
  62. pymodaq/utils/gui_utils/file_io.py +66 -0
  63. pymodaq/{daq_utils → utils}/gui_utils/layout.py +2 -2
  64. pymodaq/{daq_utils → utils}/gui_utils/utils.py +13 -3
  65. pymodaq/{daq_utils → utils}/gui_utils/widgets/__init__.py +2 -2
  66. pymodaq/utils/gui_utils/widgets/label.py +24 -0
  67. pymodaq/{daq_utils → utils}/gui_utils/widgets/lcd.py +12 -7
  68. pymodaq/{daq_utils → utils}/gui_utils/widgets/push.py +66 -2
  69. pymodaq/{daq_utils → utils}/gui_utils/widgets/qled.py +6 -4
  70. pymodaq/utils/gui_utils/widgets/spinbox.py +24 -0
  71. pymodaq/{daq_utils → utils}/gui_utils/widgets/table.py +2 -2
  72. pymodaq/utils/h5modules/__init__.py +1 -0
  73. pymodaq/{daq_utils/h5backend.py → utils/h5modules/backends.py} +200 -112
  74. pymodaq/utils/h5modules/browsing.py +683 -0
  75. pymodaq/utils/h5modules/data_saving.py +839 -0
  76. pymodaq/utils/h5modules/h5logging.py +110 -0
  77. pymodaq/utils/h5modules/module_saving.py +350 -0
  78. pymodaq/utils/h5modules/saving.py +914 -0
  79. pymodaq/utils/h5modules/utils.py +85 -0
  80. pymodaq/utils/logger.py +64 -6
  81. pymodaq/utils/managers/action_manager.py +460 -0
  82. pymodaq/{daq_utils → utils}/managers/batchscan_manager.py +144 -112
  83. pymodaq/{daq_utils → utils}/managers/modules_manager.py +188 -114
  84. pymodaq/{daq_utils → utils}/managers/overshoot_manager.py +3 -3
  85. pymodaq/utils/managers/parameter_manager.py +110 -0
  86. pymodaq/{daq_utils → utils}/managers/preset_manager.py +17 -13
  87. pymodaq/{daq_utils → utils}/managers/preset_manager_utils.py +8 -7
  88. pymodaq/{daq_utils → utils}/managers/remote_manager.py +7 -6
  89. pymodaq/{daq_utils → utils}/managers/roi_manager.py +148 -57
  90. pymodaq/utils/math_utils.py +546 -10
  91. pymodaq/{daq_utils → utils}/messenger.py +5 -1
  92. pymodaq/utils/parameter/__init__.py +2 -15
  93. pymodaq/{daq_utils → utils}/parameter/ioxml.py +12 -6
  94. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/__init__.py +1 -3
  95. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/filedir.py +1 -1
  96. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/itemselect.py +3 -0
  97. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/led.py +1 -1
  98. pymodaq/utils/parameter/pymodaq_ptypes/pixmap.py +161 -0
  99. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/slide.py +1 -1
  100. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/table.py +1 -1
  101. pymodaq/utils/parameter/utils.py +206 -11
  102. pymodaq/utils/plotting/data_viewers/__init__.py +6 -0
  103. pymodaq/utils/plotting/data_viewers/viewer.py +393 -0
  104. pymodaq/utils/plotting/data_viewers/viewer0D.py +251 -0
  105. pymodaq/utils/plotting/data_viewers/viewer1D.py +574 -0
  106. pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer1Dbasic.py +8 -3
  107. pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer2D.py +292 -357
  108. pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer2D_basic.py +58 -75
  109. pymodaq/utils/plotting/data_viewers/viewerND.py +738 -0
  110. pymodaq/{daq_utils → utils}/plotting/gant_chart.py +2 -2
  111. pymodaq/{daq_utils → utils}/plotting/items/axis_scaled.py +4 -2
  112. pymodaq/{daq_utils → utils}/plotting/items/image.py +8 -6
  113. pymodaq/utils/plotting/navigator.py +355 -0
  114. pymodaq/utils/plotting/scan_selector.py +480 -0
  115. pymodaq/utils/plotting/utils/axes_viewer.py +88 -0
  116. pymodaq/utils/plotting/utils/filter.py +538 -0
  117. pymodaq/utils/plotting/utils/lineout.py +224 -0
  118. pymodaq/{daq_utils → utils}/plotting/utils/plot_utils.py +196 -84
  119. pymodaq/{daq_utils → utils}/plotting/utils/signalND.py +21 -13
  120. pymodaq/utils/plotting/widgets.py +76 -0
  121. pymodaq/utils/scanner/__init__.py +10 -0
  122. pymodaq/utils/scanner/scan_factory.py +204 -0
  123. pymodaq/utils/scanner/scanner.py +271 -0
  124. pymodaq/utils/scanner/scanners/_1d_scanners.py +117 -0
  125. pymodaq/utils/scanner/scanners/_2d_scanners.py +293 -0
  126. pymodaq/utils/scanner/scanners/sequential.py +192 -0
  127. pymodaq/utils/scanner/scanners/tabular.py +294 -0
  128. pymodaq/utils/scanner/utils.py +83 -0
  129. pymodaq/utils/slicing.py +47 -0
  130. pymodaq/utils/svg/__init__.py +6 -0
  131. pymodaq/utils/svg/svg_renderer.py +20 -0
  132. pymodaq/utils/svg/svg_view.py +35 -0
  133. pymodaq/utils/svg/svg_viewer2D.py +51 -0
  134. pymodaq/{daq_utils → utils}/tcp_server_client.py +36 -37
  135. pymodaq/{daq_utils → utils}/tree_layout/tree_layout_main.py +50 -35
  136. pymodaq/utils/units.py +216 -0
  137. pymodaq-4.0.1.dist-info/METADATA +159 -0
  138. {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info}/RECORD +167 -170
  139. {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info}/WHEEL +1 -2
  140. pymodaq-4.0.1.dist-info/entry_points.txt +8 -0
  141. pymodaq/daq_move/daq_move_gui.py +0 -279
  142. pymodaq/daq_move/daq_move_gui.ui +0 -534
  143. pymodaq/daq_move/daq_move_main.py +0 -1042
  144. pymodaq/daq_move/process_from_QtDesigner_DAQ_Move_GUI.bat +0 -2
  145. pymodaq/daq_move/utility_classes.py +0 -671
  146. pymodaq/daq_scan.py +0 -2160
  147. pymodaq/daq_utils/array_manipulation.py +0 -386
  148. pymodaq/daq_utils/config.py +0 -273
  149. pymodaq/daq_utils/conftests.py +0 -7
  150. pymodaq/daq_utils/custom_parameter_tree.py +0 -9
  151. pymodaq/daq_utils/daq_enums.py +0 -133
  152. pymodaq/daq_utils/daq_utils.py +0 -1402
  153. pymodaq/daq_utils/exceptions.py +0 -71
  154. pymodaq/daq_utils/gui_utils/custom_app.py +0 -103
  155. pymodaq/daq_utils/gui_utils/file_io.py +0 -75
  156. pymodaq/daq_utils/gui_utils/widgets/spinbox.py +0 -9
  157. pymodaq/daq_utils/h5exporter_hyperspy.py +0 -115
  158. pymodaq/daq_utils/h5exporters.py +0 -242
  159. pymodaq/daq_utils/h5modules.py +0 -1559
  160. pymodaq/daq_utils/h5utils.py +0 -241
  161. pymodaq/daq_utils/managers/action_manager.py +0 -236
  162. pymodaq/daq_utils/managers/parameter_manager.py +0 -57
  163. pymodaq/daq_utils/math_utils.py +0 -705
  164. pymodaq/daq_utils/parameter/__init__.py +0 -1
  165. pymodaq/daq_utils/parameter/oldpymodaq_ptypes.py +0 -1626
  166. pymodaq/daq_utils/parameter/pymodaq_ptypes/pixmap.py +0 -85
  167. pymodaq/daq_utils/parameter/utils.py +0 -136
  168. pymodaq/daq_utils/plotting/data_viewers/__init__.py +0 -0
  169. pymodaq/daq_utils/plotting/data_viewers/process_from_QtDesigner_0DViewer_GUI.bat +0 -2
  170. pymodaq/daq_utils/plotting/data_viewers/viewer0D.py +0 -204
  171. pymodaq/daq_utils/plotting/data_viewers/viewer0D_GUI.py +0 -89
  172. pymodaq/daq_utils/plotting/data_viewers/viewer0D_GUI.ui +0 -131
  173. pymodaq/daq_utils/plotting/data_viewers/viewer1D.py +0 -781
  174. pymodaq/daq_utils/plotting/data_viewers/viewerND.py +0 -894
  175. pymodaq/daq_utils/plotting/data_viewers/viewerbase.py +0 -64
  176. pymodaq/daq_utils/plotting/items/__init__.py +0 -0
  177. pymodaq/daq_utils/plotting/navigator.py +0 -500
  178. pymodaq/daq_utils/plotting/scan_selector.py +0 -289
  179. pymodaq/daq_utils/plotting/utils/__init__.py +0 -0
  180. pymodaq/daq_utils/plotting/utils/filter.py +0 -236
  181. pymodaq/daq_utils/plotting/viewer0D/__init__.py +0 -0
  182. pymodaq/daq_utils/plotting/viewer0D/viewer0D_main.py +0 -4
  183. pymodaq/daq_utils/plotting/viewer1D/__init__.py +0 -0
  184. pymodaq/daq_utils/plotting/viewer1D/viewer1D_main.py +0 -4
  185. pymodaq/daq_utils/plotting/viewer1D/viewer1Dbasic.py +0 -4
  186. pymodaq/daq_utils/plotting/viewer2D/viewer_2D_basic.py +0 -4
  187. pymodaq/daq_utils/plotting/viewer2D/viewer_2D_main.py +0 -4
  188. pymodaq/daq_utils/plotting/viewerND/__init__.py +0 -0
  189. pymodaq/daq_utils/plotting/viewerND/viewerND_main.py +0 -4
  190. pymodaq/daq_utils/scanner.py +0 -1289
  191. pymodaq/daq_utils/tree_layout/__init__.py +0 -0
  192. pymodaq/daq_viewer/__init__.py +0 -0
  193. pymodaq/daq_viewer/daq_gui_settings.py +0 -237
  194. pymodaq/daq_viewer/daq_gui_settings.ui +0 -441
  195. pymodaq/daq_viewer/daq_viewer_main.py +0 -2225
  196. pymodaq/daq_viewer/process_from_QtDesigner_DAQ_GUI_settings.bat +0 -2
  197. pymodaq/daq_viewer/utility_classes.py +0 -673
  198. pymodaq/examples/logger_image/__init__.py +0 -0
  199. pymodaq/examples/logger_image/logger_displayer.py +0 -121
  200. pymodaq/examples/logger_image/setup.svg +0 -3119
  201. pymodaq/examples/logger_image/setup_svg.py +0 -114
  202. pymodaq/h5browser.py +0 -39
  203. pymodaq/utils/scanner.py +0 -15
  204. pymodaq-3.6.12.dist-info/METADATA +0 -39
  205. pymodaq-3.6.12.dist-info/entry_points.txt +0 -8
  206. pymodaq-3.6.12.dist-info/top_level.txt +0 -1
  207. /pymodaq/{daq_analysis → post_treatment/daq_analysis}/__init__.py +0 -0
  208. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/__init__.py +0 -0
  209. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_GUI.py +0 -0
  210. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_GUI.ui +0 -0
  211. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/process_from_QtDesigner_DAQ_Measurement_GUI.bat +0 -0
  212. /pymodaq/{daq_utils → utils}/Tuto innosetup/Tuto innosetup.odt +0 -0
  213. /pymodaq/{daq_utils → utils}/Tuto innosetup/Tuto innosetup.pdf +0 -0
  214. /pymodaq/{daq_move → utils/db}/__init__.py +0 -0
  215. /pymodaq/{daq_utils → utils/db/db_logger}/__init__.py +0 -0
  216. /pymodaq/{daq_utils → utils}/gui_utils/dock.py +0 -0
  217. /pymodaq/{daq_utils → utils}/gui_utils/list_picker.py +0 -0
  218. /pymodaq/{daq_utils/abstract → utils/managers}/__init__.py +0 -0
  219. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/bool.py +0 -0
  220. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/date.py +0 -0
  221. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/list.py +0 -0
  222. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/numeric.py +0 -0
  223. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/tableview.py +0 -0
  224. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/text.py +0 -0
  225. /pymodaq/{daq_utils/db → utils/plotting}/__init__.py +0 -0
  226. /pymodaq/{daq_utils → utils}/plotting/image_viewer.py +0 -0
  227. /pymodaq/{daq_utils/db/db_logger → utils/plotting/items}/__init__.py +0 -0
  228. /pymodaq/{daq_utils → utils}/plotting/items/crosshair.py +0 -0
  229. /pymodaq/{daq_utils/managers → utils/plotting/utils}/__init__.py +0 -0
  230. /pymodaq/{daq_utils → utils}/qvariant.py +0 -0
  231. /pymodaq/{daq_utils/plotting/viewer2D → utils/scanner/scanners}/__init__.py +0 -0
  232. /pymodaq/{daq_utils/plotting → utils/tree_layout}/__init__.py +0 -0
  233. {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info/licenses}/LICENSE +0 -0
@@ -1,8 +1,709 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- Created the 21/10/2022
4
-
5
- @author: Sebastien Weber
6
- """
7
- from pymodaq.daq_move.utility_classes import DAQ_Move_base, comon_parameters, comon_parameters_fun, main,\
8
- DAQ_Move_TCP_server
1
+ from qtpy import QtWidgets
2
+ from qtpy.QtCore import QObject, Slot, Signal, QTimer
3
+
4
+
5
+ from easydict import EasyDict as edict
6
+ import pymodaq.utils.daq_utils as utils
7
+ import pymodaq.utils.parameter.utils as putils
8
+ from pymodaq.utils.logger import set_logger, get_module_name, get_module_name
9
+ from pymodaq.utils.parameter import ioxml
10
+ from pyqtgraph.parametertree import Parameter
11
+ from pymodaq.utils.daq_utils import ThreadCommand, getLineInfo
12
+ from pymodaq.utils.config import Config
13
+ from pymodaq.utils.tcp_server_client import TCPServer, tcp_parameters
14
+ from pymodaq.utils.messenger import deprecation_msg
15
+ import numpy as np
16
+ from time import perf_counter
17
+
18
+ logger = set_logger(get_module_name(__file__))
19
+ config = Config()
20
+
21
+
22
+ def comon_parameters(epsilon=config('actuator', 'epsilon_default')):
23
+ return [{'title': 'Units:', 'name': 'units', 'type': 'str', 'value': '', 'readonly': True},
24
+ {'title': 'Epsilon:', 'name': 'epsilon', 'type': 'float',
25
+ 'value': epsilon,
26
+ 'tip': 'Differential Value at which the controller considers it reached the target position'},
27
+ {'title': 'Timeout (s):', 'name': 'timeout', 'type': 'int',
28
+ 'value': config('actuator', 'polling_timeout_s')},
29
+ {'title': 'Bounds:', 'name': 'bounds', 'type': 'group', 'children': [
30
+ {'title': 'Set Bounds:', 'name': 'is_bounds', 'type': 'bool', 'value': False},
31
+ {'title': 'Min:', 'name': 'min_bound', 'type': 'float', 'value': 0, 'default': 0},
32
+ {'title': 'Max:', 'name': 'max_bound', 'type': 'float', 'value': 1, 'default': 1}, ]},
33
+ {'title': 'Scaling:', 'name': 'scaling', 'type': 'group', 'children': [
34
+ {'title': 'Use scaling:', 'name': 'use_scaling', 'type': 'bool', 'value': False,
35
+ 'default': False},
36
+ {'title': 'Scaling factor:', 'name': 'scaling', 'type': 'float', 'value': 1., 'default': 1.},
37
+ {'title': 'Offset factor:', 'name': 'offset', 'type': 'float', 'value': 0., 'default': 0.}]}]
38
+
39
+ MOVE_COMMANDS = ['abs', 'rel', 'home']
40
+
41
+
42
+ class MoveCommand:
43
+ """Utility class to contain a given move type and value
44
+
45
+ Attributes
46
+ ----------
47
+ move_type: str
48
+ either:
49
+
50
+ * 'abs': performs an absolute action
51
+ * 'rel': performs a relative action
52
+ * 'home': find the actuator's home
53
+ value: float
54
+ the value the move should reach
55
+
56
+ """
57
+ def __init__(self, move_type, value=0):
58
+ if move_type not in MOVE_COMMANDS:
59
+ raise ValueError(f'The allowed move types fro an actuator are {MOVE_COMMANDS}')
60
+ self.move_type = move_type
61
+ self.value = value
62
+
63
+
64
+ def comon_parameters_fun(is_multiaxes=False, axes_names=[], master=True, epsilon=config('actuator', 'epsilon_default')):
65
+ """Function returning the common and mandatory parameters that should be on the actuator plugin level
66
+
67
+ Parameters
68
+ ----------
69
+ is_multiaxes: bool
70
+ If True, display the particular settings to define which axis the controller is driving
71
+ axes_names: list of str
72
+ The string identifier of every axis the controller can drive
73
+ master: bool
74
+ If True consider this plugin has to init the controller, otherwise use an already initialized instance
75
+ """
76
+ params = [{'title': 'MultiAxes:', 'name': 'multiaxes', 'type': 'group', 'visible': is_multiaxes, 'children': [
77
+ {'title': 'is Multiaxes:', 'name': 'ismultiaxes', 'type': 'bool', 'value': is_multiaxes,
78
+ 'default': False},
79
+ {'title': 'Status:', 'name': 'multi_status', 'type': 'list', 'value': 'Master' if master else 'Slave',
80
+ 'limits': ['Master', 'Slave']},
81
+ {'title': 'Axis:', 'name': 'axis', 'type': 'list', 'limits': axes_names},
82
+
83
+ ]}] + comon_parameters(epsilon)
84
+ return params
85
+
86
+
87
+ params = [
88
+ {'title': 'Main Settings:', 'name': 'main_settings', 'type': 'group', 'children': [
89
+ {'title': 'Actuator type:', 'name': 'move_type', 'type': 'str', 'value': '', 'readonly': True},
90
+ {'title': 'Actuator name:', 'name': 'module_name', 'type': 'str', 'value': '', 'readonly': True},
91
+ {'title': 'Controller ID:', 'name': 'controller_ID', 'type': 'int', 'value': 0, 'default': 0},
92
+ {'title': 'Refresh value (ms):', 'name': 'refresh_timeout', 'type': 'int',
93
+ 'value': config('actuator', 'refresh_timeout_ms')},
94
+ {'title': 'TCP/IP options:', 'name': 'tcpip', 'type': 'group', 'visible': True, 'expanded': False,
95
+ 'children': [
96
+ {'title': 'Connect to server:', 'name': 'connect_server', 'type': 'bool_push', 'label': 'Connect',
97
+ 'value': False},
98
+ {'title': 'Connected?:', 'name': 'tcp_connected', 'type': 'led', 'value': False},
99
+ {'title': 'IP address:', 'name': 'ip_address', 'type': 'str',
100
+ 'value': config('network', 'tcp-server', 'ip')},
101
+ {'title': 'Port:', 'name': 'port', 'type': 'int', 'value': config('network', 'tcp-server', 'port')},
102
+ ]},
103
+ ]},
104
+ {'title': 'Actuator Settings:', 'name': 'move_settings', 'type': 'group'}
105
+ ]
106
+
107
+
108
+ def main(plugin_file, init=True, title='test'):
109
+ """
110
+ this method start a DAQ_Move object with this defined plugin as actuator
111
+ Returns
112
+ -------
113
+
114
+ """
115
+ import sys
116
+ from qtpy import QtWidgets
117
+ from pymodaq.control_modules.daq_move import DAQ_Move
118
+ from pathlib import Path
119
+ app = QtWidgets.QApplication(sys.argv)
120
+ if config('style', 'darkstyle'):
121
+ import qdarkstyle
122
+ app.setStyleSheet(qdarkstyle.load_stylesheet())
123
+
124
+ Form = QtWidgets.QWidget()
125
+ prog = DAQ_Move(Form, title=title,)
126
+ Form.show()
127
+ prog.actuator = Path(plugin_file).stem[9:]
128
+ if init:
129
+ prog.init_hardware_ui()
130
+
131
+ sys.exit(app.exec_())
132
+
133
+
134
+ class DAQ_Move_base(QObject):
135
+ """ The base class to be herited by all actuator modules
136
+
137
+ This base class implements all necessary parameters and methods for the plugin to communicate with its parent (the
138
+ DAQ_Move module)
139
+
140
+ Parameters
141
+ ----------
142
+ parent : DAQ_Move_stage instance (see daq_viewer_main module)
143
+ params_state : Parameter instance (pyqtgraph) from which the module will get the initial settings (as defined in the managers)
144
+
145
+
146
+ :ivar move_done_signal: Signal signal represented by a float. Is emitted each time the hardware reached the target
147
+ position within the epsilon precision (see comon_parameters variable)
148
+
149
+ :ivar controller: the object representing the hardware in the plugin. Used to access hardware functionality
150
+
151
+ :ivar status: easydict instance to set information (str), controller object, stage object (if required) and initialized
152
+ state (bool) to return to parent after initialization
153
+
154
+ :ivar settings: Parameter instance representing the hardware settings defined from the params attribute. Modifications
155
+ on the GUI settings will be transferred to this attribute. It stores at all times the current state of the hardware/plugin
156
+
157
+ :ivar params: class level attribute. List of dict used to create a Parameter object. Its definition on the class level enable
158
+ the automatic update of the GUI settings when changing plugins (even in managers mode creation). To be populated
159
+ on the plugin level as the base class does't represents a real hardware
160
+
161
+ :ivar is_multiaxes: class level attribute (bool). Defines if the plugin controller controls multiple axes. If True, one has to define
162
+ a Master instance of this plugin and slave instances of this plugin (all sharing the same controller_ID Parameter)
163
+
164
+ :ivar current_value: (float) stores the current position after each call to the get_actuator_value in the child module
165
+
166
+ :ivar target_value: (float) stores the target position the controller should reach within epsilon
167
+
168
+ """
169
+
170
+ move_done_signal = Signal(float)
171
+ is_multiaxes = False
172
+ stage_names = []
173
+ axes_name = []
174
+ params = []
175
+ _controller_units = ''
176
+ _epsilon = 1
177
+
178
+ def __init__(self, parent=None, params_state=None):
179
+ QObject.__init__(self) # to make sure this is the parent class
180
+ self.move_is_done = False
181
+ self.parent = parent
182
+ self.shamrock_controller = None
183
+ self.stage = None
184
+ self.status = edict(info="", controller=None, stage=None, initialized=False)
185
+ self.current_value = 0.
186
+ self.target_value = 0.
187
+ self._ispolling = True
188
+ self.parent_parameters_path = [] # this is to be added in the send_param_status to take into account when the
189
+ # current class instance parameter list is a child of some other class
190
+ self.settings = Parameter.create(name='Settings', type='group', children=self.params)
191
+ if params_state is not None:
192
+ if isinstance(params_state, dict):
193
+ self.settings.restoreState(params_state)
194
+ elif isinstance(params_state, Parameter):
195
+ self.settings.restoreState(params_state.saveState())
196
+
197
+ self.settings.sigTreeStateChanged.connect(self.send_param_status)
198
+ self.controller_units = self._controller_units
199
+
200
+ self.poll_timer = QTimer()
201
+ self.poll_timer.setInterval(config('actuator', 'polling_interval_ms'))
202
+ self._poll_timeout = config('actuator', 'polling_timeout_s')
203
+ self.poll_timer.timeout.connect(self.check_target_reached)
204
+
205
+ self.ini_attributes()
206
+
207
+ def ini_attributes(self):
208
+ self.controller = None
209
+
210
+ def ini_stage_init(self, old_controller=None, new_controller=None):
211
+ """Manage the Master/Slave controller issue
212
+
213
+ First initialize the status dictionnary
214
+ Then check whether this stage is controlled by a multiaxe controller (to be defined for each plugin)
215
+ if it is a multiaxes controller then:
216
+ * if it is Master: init the controller here
217
+ * if it is Slave: use an already initialized controller (defined in the preset of the dashboard)
218
+
219
+ Parameters
220
+ ----------
221
+ old_controller: object
222
+ The particular object that allow the communication with the hardware, in general a python wrapper around the
223
+ hardware library. In case of Slave this one comes from a previously initialized plugin
224
+ new_controller: object
225
+ The particular object that allow the communication with the hardware, in general a python wrapper around the
226
+ hardware library. In case of Master it is the new instance of your plugin controller
227
+ """
228
+ self.status.update(edict(info="", controller=None, initialized=False))
229
+ if self.settings['multiaxes', 'ismultiaxes'] and self.settings['multiaxes', 'multi_status'] == "Slave":
230
+ if old_controller is None:
231
+ raise Exception('no controller has been defined externally while this axe is a slave one')
232
+ else:
233
+ controller = old_controller
234
+ else: # Master stage
235
+ controller = new_controller
236
+ self.controller = controller
237
+ return controller
238
+
239
+ @property
240
+ def current_position(self):
241
+ deprecation_msg('current_position attribute should not be used, use current_value')
242
+ return self.current_value
243
+
244
+ @current_position.setter
245
+ def current_position(self, value):
246
+ self.current_value = value
247
+
248
+ @property
249
+ def target_position(self):
250
+ deprecation_msg('target_position attribute should not be used, use target_value')
251
+ return self.target_value
252
+
253
+ @target_position.setter
254
+ def target_position(self, value):
255
+ self.target_value = value
256
+
257
+ @property
258
+ def controller_units(self):
259
+ return self._controller_units
260
+
261
+ @controller_units.setter
262
+ def controller_units(self, units: str = ''):
263
+ self._controller_units = units
264
+ try:
265
+ self.settings.child('units').setValue(units)
266
+ except Exception:
267
+ pass
268
+
269
+ @property
270
+ def ispolling(self):
271
+ return self._ispolling
272
+
273
+ @ispolling.setter
274
+ def ispolling(self, polling=True):
275
+ self._ispolling = polling
276
+
277
+ def check_bound(self, position):
278
+ """
279
+
280
+ Parameters
281
+ ----------
282
+ position
283
+
284
+ Returns
285
+ -------
286
+
287
+ """
288
+ if self.settings.child('bounds', 'is_bounds').value():
289
+ if position > self.settings.child('bounds', 'max_bound').value():
290
+ position = self.settings.child('bounds', 'max_bound').value()
291
+ self.emit_status(ThreadCommand('outofbounds', []))
292
+ elif position < self.settings.child('bounds', 'min_bound').value():
293
+ position = self.settings.child('bounds', 'min_bound').value()
294
+ self.emit_status(ThreadCommand('outofbounds', []))
295
+ return position
296
+
297
+ def get_actuator_value(self):
298
+ if hasattr(self, 'check_position'):
299
+ deprecation_msg('check_position method in plugins is deprecated, use get_actuator_value',3)
300
+ return self.check_position()
301
+ else:
302
+ raise NotImplementedError
303
+
304
+ def move_abs(self, value):
305
+ if hasattr(self, 'move_Abs'):
306
+ deprecation_msg('move_Abs method in plugins is deprecated, use move_abs',3)
307
+ self.move_Abs(value)
308
+ else:
309
+ raise NotImplementedError
310
+
311
+ def move_rel(self, value):
312
+ if hasattr(self, 'move_Rel'):
313
+ deprecation_msg('move_Rel method in plugins is deprecated, use move_rel',3)
314
+ self.move_Rel(value)
315
+ else:
316
+ raise NotImplementedError
317
+
318
+ def move_home(self, value):
319
+ if hasattr(self, 'move_Home'):
320
+ deprecation_msg('move_Home method in plugins is deprecated, use move_home', 3)
321
+ self.move_Home()
322
+ else:
323
+ raise NotImplementedError
324
+
325
+ def emit_status(self, status):
326
+ """
327
+ | Emit the statut signal from the given status parameter.
328
+ |
329
+ | The signal is sended to the gui to update the user interface.
330
+
331
+ =============== ===================== ========================================================================================================================================
332
+ **Parameters** **Type** **Description**
333
+ *status* ordered dictionnary dictionnary containing keys:
334
+ * *info* : string displaying various info
335
+ * *controller*: instance of the controller object in order to control other axes without the need to init the same controller twice
336
+ * *stage*: instance of the stage (axis or whatever) object
337
+ * *initialized*: boolean indicating if initialization has been done corretly
338
+ =============== ===================== ========================================================================================================================================
339
+ """
340
+ if self.parent is not None:
341
+ self.parent.status_sig.emit(status)
342
+ QtWidgets.QApplication.processEvents()
343
+ else:
344
+ print(status)
345
+
346
+ def emit_value(self, pos):
347
+ self.emit_status(ThreadCommand('get_actuator_value', [pos]))
348
+
349
+ def commit_settings(self, param):
350
+ """
351
+ to subclass to transfer parameters to hardware
352
+ """
353
+ pass
354
+
355
+ def commit_common_settings(self, param):
356
+ pass
357
+
358
+ def get_position_with_scaling(self, pos):
359
+ """
360
+ Get the current position from the hardware with scaling conversion.
361
+
362
+ =============== ========= =====================
363
+ **Parameters** **Type** **Description**
364
+ *pos* float the current position
365
+ =============== ========= =====================
366
+
367
+ Returns
368
+ =======
369
+ float
370
+ the computed position.
371
+ """
372
+ if self.settings.child('scaling', 'use_scaling').value():
373
+ pos = (pos - self.settings.child('scaling', 'offset').value()) * self.settings.child('scaling',
374
+ 'scaling').value()
375
+ return pos
376
+
377
+ def move_done(self, position=None): # the position argument is just there to match some signature of child classes
378
+ """
379
+ | Emit a move done signal transmitting the float position to hardware.
380
+ | The position argument is just there to match some signature of child classes.
381
+
382
+ =============== ========== =============================================================================
383
+ **Arguments** **Type** **Description**
384
+ *position* float The position argument is just there to match some signature of child classes
385
+ =============== ========== =============================================================================
386
+
387
+ """
388
+ if position is None:
389
+ position = self.get_actuator_value()
390
+ self.move_done_signal.emit(position)
391
+ self.move_is_done = True
392
+
393
+ def poll_moving(self):
394
+ """
395
+ Poll the current moving. In case of timeout emit the raise timeout Thread command.
396
+
397
+ See Also
398
+ --------
399
+ DAQ_utils.ThreadCommand, move_done
400
+ """
401
+ if 'TCPServer' not in self.__class__.__name__:
402
+ self.start_time = perf_counter()
403
+ if self.ispolling:
404
+ self.poll_timer.start()
405
+ else:
406
+ self.current_value = self.get_actuator_value()
407
+ logger.debug(f'Current position: {self.current_value}')
408
+ self.move_done(self.current_value)
409
+
410
+ def check_target_reached(self):
411
+ logger.debug(f"epsilon value is {self.settings.child('epsilon').value()}")
412
+ logger.debug(f"current_value value is {self.current_value}")
413
+ logger.debug(f"target_value value is {self.target_value}")
414
+ if np.abs(self.current_value - self.target_value) > self.settings.child('epsilon').value():
415
+ logger.debug(f'Check move_is_done: {self.move_is_done}')
416
+ if self.move_is_done:
417
+ self.emit_status(ThreadCommand('Move has been stopped', ))
418
+ logger.info(f'Move has been stopped')
419
+
420
+ self.current_value = self.get_actuator_value()
421
+ self.emit_value(self.current_value)
422
+ logger.debug(f'Current value: {self.current_value}')
423
+
424
+ if perf_counter() - self.start_time >= self.settings.child('timeout').value():
425
+ self.poll_timer.stop()
426
+ self.emit_status(ThreadCommand('raise_timeout', ))
427
+ logger.info(f'Timeout activated')
428
+ else:
429
+ self.poll_timer.stop()
430
+ logger.debug(f'Current value: {self.current_value}')
431
+ self.move_done(self.current_value)
432
+
433
+ def send_param_status(self, param, changes):
434
+ """
435
+ | Send changes value updates to the gui to update consequently the User Interface.
436
+ | The message passing is made via the Thread Command "update_settings".
437
+
438
+ =============== =================================== ==================================================
439
+ **Parameters** **Type** **Description**
440
+ *param* instance of pyqtgraph parameter The parameter to be checked
441
+ *changes* (parameter,change,infos)tuple list The (parameter,change,infos) list to be treated
442
+ =============== =================================== ==================================================
443
+
444
+ See Also
445
+ ========
446
+ DAQ_utils.ThreadCommand
447
+ """
448
+
449
+ for param, change, data in changes:
450
+ path = self.settings.childPath(param)
451
+ if change == 'childAdded':
452
+ self.emit_status(ThreadCommand('update_settings',
453
+ [self.parent_parameters_path + path, [data[0].saveState(), data[1]],
454
+ 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
455
+ elif change == 'value' or change == 'limits' or change == 'options':
456
+ self.emit_status(ThreadCommand('update_settings', [self.parent_parameters_path + path, data,
457
+ change])) # send parameters values/limits back to the GUI
458
+ elif change == 'parent':
459
+ pass
460
+
461
+ def set_position_with_scaling(self, pos):
462
+ """
463
+ Set the current position from the parameter and hardware with scaling conversion.
464
+
465
+ =============== ========= ==========================
466
+ **Parameters** **Type** **Description**
467
+ *pos* float the position to be setted
468
+ =============== ========= ==========================
469
+
470
+ Returns
471
+ =======
472
+ float
473
+ the computed position.
474
+ """
475
+ if self.settings.child('scaling', 'use_scaling').value():
476
+ pos = pos / self.settings.child('scaling', 'scaling').value() + self.settings.child('scaling',
477
+ 'offset').value()
478
+ return pos
479
+
480
+ def set_position_relative_with_scaling(self, pos):
481
+ """
482
+ Set the scaled positions in case of relative moves
483
+ """
484
+ if self.settings.child('scaling', 'use_scaling').value():
485
+ pos = pos / self.settings.child('scaling', 'scaling').value()
486
+ return pos
487
+
488
+ @Slot(edict)
489
+ def update_settings(self, settings_parameter_dict): # settings_parameter_dict=edict(path=path,param=param)
490
+ """
491
+ Receive the settings_parameter signal from the param_tree_changed method and make hardware updates of mmodified values.
492
+
493
+ ========================== =========== ==========================================================================================================
494
+ **Arguments** **Type** **Description**
495
+ *settings_parameter_dict* dictionnary Dictionnary with the path of the parameter in hardware structure as key and the parameter name as element
496
+ ========================== =========== ==========================================================================================================
497
+
498
+ See Also
499
+ --------
500
+ send_param_status, commit_settings
501
+ """
502
+ path = settings_parameter_dict['path']
503
+ param = settings_parameter_dict['param']
504
+ change = settings_parameter_dict['change']
505
+ try:
506
+ self.settings.sigTreeStateChanged.disconnect(self.send_param_status)
507
+ except Exception:
508
+ pass
509
+ if change == 'value':
510
+ self.settings.child(*path[1:]).setValue(param.value()) # blocks signal back to main UI
511
+ elif change == 'childAdded':
512
+ child = Parameter.create(name='tmp')
513
+ child.restoreState(param)
514
+ self.settings.child(*path[1:]).addChild(child) # blocks signal back to main UI
515
+ param = child
516
+
517
+ elif change == 'parent':
518
+ children = putils.get_param_from_name(self.settings, param.name())
519
+
520
+ if children is not None:
521
+ path = putils.get_param_path(children)
522
+ self.settings.child(*path[1:-1]).removeChild(children)
523
+
524
+ self.settings.sigTreeStateChanged.connect(self.send_param_status)
525
+ self.commit_common_settings(param)
526
+ self.commit_settings(param)
527
+
528
+
529
+ class DAQ_Move_TCP_server(DAQ_Move_base, TCPServer):
530
+ """
531
+ ================= ==============================
532
+ **Attributes** **Type**
533
+ *command_server* instance of Signal
534
+ *x_axis* 1D numpy array
535
+ *y_axis* 1D numpy array
536
+ *data* double precision float array
537
+ ================= ==============================
538
+
539
+ See Also
540
+ --------
541
+ utility_classes.DAQ_TCP_server
542
+ """
543
+ params_client = [] # parameters of a client grabber
544
+ command_server = Signal(list)
545
+
546
+ message_list = ["Quit", "Status", "Done", "Server Closed", "Info", "Infos", "Info_xml", "move_abs",
547
+ 'move_home', 'move_rel', 'get_actuator_value', 'stop_motion', 'position_is', 'move_done']
548
+ socket_types = ["ACTUATOR"]
549
+ params = comon_parameters() + tcp_parameters
550
+
551
+ def __init__(self, parent=None, params_state=None):
552
+ """
553
+
554
+ Parameters
555
+ ----------
556
+ parent
557
+ params_state
558
+ """
559
+ self.client_type = "ACTUATOR"
560
+ DAQ_Move_base.__init__(self, parent, params_state) # initialize base class with commom attribute and methods
561
+ self.settings.child(('bounds')).hide()
562
+ self.settings.child(('scaling')).hide()
563
+ self.settings.child(('epsilon')).setValue(1)
564
+
565
+ TCPServer.__init__(self, self.client_type)
566
+
567
+ def command_to_from_client(self, command):
568
+ sock = self.find_socket_within_connected_clients(self.client_type)
569
+ if sock is not None: # if client 'ACTUATOR' is connected then send it the command
570
+
571
+ if command == 'position_is':
572
+ pos = sock.get_scalar()
573
+
574
+ pos = self.get_position_with_scaling(pos)
575
+ self.current_value = pos
576
+ self.emit_status(ThreadCommand('get_actuator_value', [pos]))
577
+
578
+ elif command == 'move_done':
579
+ pos = sock.get_scalar()
580
+ pos = self.get_position_with_scaling(pos)
581
+ self.current_value = pos
582
+ self.emit_status(ThreadCommand('move_done', [pos]))
583
+ else:
584
+ self.send_command(sock, command)
585
+
586
+ def commit_settings(self, param):
587
+
588
+ if param.name() in putils.iter_children(self.settings.child(('settings_client')), []):
589
+ actuator_socket = [client['socket'] for client in self.connected_clients if client['type'] == 'ACTUATOR'][0]
590
+ actuator_socket.send_string('set_info')
591
+ path = putils.get_param_path(param)[2:]
592
+ # get the path of this param as a list starting at parent 'infos'
593
+
594
+ actuator_socket.send_list(path)
595
+
596
+ # send value
597
+ data = ioxml.parameter_to_xml_string(param)
598
+ actuator_socket.send_string(data)
599
+
600
+ def ini_stage(self, controller=None):
601
+ """
602
+ | Initialisation procedure of the detector updating the status dictionnary.
603
+ |
604
+ | Init axes from image , here returns only None values (to tricky to di it with the server and not really necessary for images anyway)
605
+
606
+ See Also
607
+ --------
608
+ utility_classes.DAQ_TCP_server.init_server, get_xaxis, get_yaxis
609
+ """
610
+ self.status.update(edict(initialized=False, info="", x_axis=None, y_axis=None, controller=None))
611
+ try:
612
+ self.settings.child(('infos')).addChildren(self.params_client)
613
+
614
+ self.init_server()
615
+
616
+ self.settings.child('units').hide()
617
+ self.settings.child('epsilon').hide()
618
+
619
+ self.status.info = 'TCP Server actuator'
620
+ self.status.initialized = True
621
+ self.status.controller = self.serversocket
622
+ return self.status
623
+
624
+ except Exception as e:
625
+ self.status.info = getLineInfo() + str(e)
626
+ self.status.initialized = False
627
+ return self.status
628
+
629
+ def close(self):
630
+ """
631
+ Should be used to uninitialize hardware.
632
+
633
+ See Also
634
+ --------
635
+ utility_classes.DAQ_TCP_server.close_server
636
+ """
637
+ self.listening = False
638
+ self.close_server()
639
+
640
+ def move_abs(self, position):
641
+ """
642
+
643
+ """
644
+ position = self.check_bound(position)
645
+ self.target_value = position
646
+
647
+ position = self.set_position_with_scaling(position)
648
+
649
+ sock = self.find_socket_within_connected_clients(self.client_type)
650
+ if sock is not None: # if client self.client_type is connected then send it the command
651
+ sock.send_string('move_abs')
652
+ sock.send_scalar(position)
653
+
654
+ def move_rel(self, position):
655
+ position = self.check_bound(self.current_value + position) - self.current_value
656
+ self.target_value = position + self.current_value
657
+
658
+ position = self.set_position_relative_with_scaling(position)
659
+ sock = self.find_socket_within_connected_clients(self.client_type)
660
+ if sock is not None: # if client self.client_type is connected then send it the command
661
+ sock.send_string('move_rel')
662
+ sock.send_scalar(position)
663
+
664
+ def move_home(self):
665
+ """
666
+ Make the absolute move to original position (0).
667
+
668
+ See Also
669
+ --------
670
+ move_Abs
671
+ """
672
+ sock = self.find_socket_within_connected_clients(self.client_type)
673
+ if sock is not None: # if client self.client_type is connected then send it the command
674
+ sock.send_string('move_home')
675
+
676
+ def get_actuator_value(self):
677
+ """
678
+ Get the current hardware position with scaling conversion given by get_position_with_scaling.
679
+
680
+ See Also
681
+ --------
682
+ daq_move_base.get_position_with_scaling, daq_utils.ThreadCommand
683
+ """
684
+ sock = self.find_socket_within_connected_clients(self.client_type)
685
+ if sock is not None: # if client self.client_type is connected then send it the command
686
+ self.send_command(sock, 'get_actuator_value')
687
+
688
+ return self.current_value
689
+
690
+ def stop_motion(self):
691
+ """
692
+ See Also
693
+ --------
694
+ daq_move_base.move_done
695
+ """
696
+ sock = self.find_socket_within_connected_clients(self.client_type)
697
+ if sock is not None: # if client self.client_type is connected then send it the command
698
+ self.send_command(sock, 'stop_motion')
699
+
700
+ def stop(self):
701
+ """
702
+ not implemented.
703
+ """
704
+ pass
705
+ return ""
706
+
707
+
708
+ if __name__ == '__main__':
709
+ test = DAQ_Move_base()