pyForceDAQ 2.0.3.dev1__py3-none-any.whl → 2.0.5.dev2__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.
pyforcedaq/__main__.py CHANGED
@@ -1,8 +1,13 @@
1
1
  import argparse
2
2
 
3
- from . import __author__, __version__
3
+ from . import __author__, __version__, constants
4
4
 
5
5
 
6
+ def print_version():
7
+ print("+" + "-" * 23 + "+")
8
+ print(f"| pyforceDAQ {__version__}".ljust(24) + "|")
9
+ print("+" + "-" * 23 + "+")
10
+
6
11
  def cli():
7
12
 
8
13
  parser = argparse.ArgumentParser(
@@ -31,12 +36,29 @@ def cli():
31
36
  default=False,
32
37
  help="Omit launcher GUI and start recording directly",
33
38
  )
34
- print("+" + "-" * 23 + "+")
35
- print(f"| pyforceDAQ {__version__}".ljust(24) + "|")
36
- print("+" + "-" * 23 + "+")
39
+
40
+ parser.add_argument(
41
+ "--mock",
42
+ action="store_true",
43
+ default=False,
44
+ help="Use mock sensor",
45
+ )
46
+
47
+ parser.add_argument(
48
+ "--dll",
49
+ action="store_true",
50
+ default=False,
51
+ help="Use self compiled ATI DLL",
52
+ )
37
53
 
38
54
  args = parser.parse_args()
55
+ if args.mock:
56
+ constants.DAQ_TYPE = constants.MOCK_SENSOR
57
+ else:
58
+ constants.DAQ_TYPE = constants.NIDAQMX # use NI-DAQmx
59
+ constants.USE_AIFTT = not args.dll
39
60
 
61
+ print_version()
40
62
  if not args.omit_launcher:
41
63
  if len(args.SETTINGS_FILE) > 0:
42
64
  print("Can't use launcher and settings file")
@@ -53,3 +75,4 @@ def cli():
53
75
 
54
76
  if __name__ == "__main__": # required because of threading
55
77
  cli()
78
+ cli()
@@ -14,6 +14,7 @@ from time import asctime, localtime, strftime
14
14
  from typing import List
15
15
 
16
16
  from .. import __version__ as forceDAQVersion
17
+ from .. import constants
17
18
  from .clock import wait_ms
18
19
  from .misc import set_logging
19
20
  from .process_priority_manager import ProcessPriorityManager
@@ -49,6 +50,11 @@ class DataRecorder(object):
49
50
 
50
51
  polling_priority has to be types.PollingPriority.{HIGH},
51
52
  {REALTIME} or {NORMAL} or None
53
+
54
+ You can change the used modules by settings the following constants before creating the
55
+ DataRecorder instance:
56
+ * set constants.DAQ_TYPE to constants.PYDAQMX, constants.NIDAQMX or constants.MOCK_SENSOR
57
+ * set constants.USE_AIFTT to True or False
52
58
  """
53
59
 
54
60
  if not isinstance(force_sensor_settings, list):
@@ -66,6 +72,8 @@ class DataRecorder(object):
66
72
  fst = SensorProcess(
67
73
  sensor_settings=fs,
68
74
  recording_settings=recording_settings,
75
+ daq_type=constants.DAQ_TYPE,
76
+ use_aiftt=constants.USE_AIFTT,
69
77
  pipe_buffered_data_after_pause=True,
70
78
  )
71
79
  fst.start()
@@ -16,7 +16,7 @@ class ProcessPriorityManager(object):
16
16
  platform = sys.platform
17
17
  pybits = 32 + int(sys.maxsize > 2**32) * 32
18
18
  main_process_id = psutil.Process().pid
19
- _normal_nice_value = psutil.Process().nice() # usied on Linux
19
+ _normal_nice_value = psutil.Process().nice() # used on Linux
20
20
 
21
21
  def __init__(self):
22
22
  self._subprocs = []
pyforcedaq/_lib/sensor.py CHANGED
@@ -7,38 +7,53 @@ __author__ = "Oliver Lindemann"
7
7
 
8
8
  import numpy as np
9
9
 
10
- from ..daq import CalibrationConverter, DAQReadAnalog
10
+ from .. import constants
11
11
  from .clock import local_clock
12
12
  from .settings import SensorSettings
13
13
  from .types import ForceSensorData
14
14
 
15
15
 
16
- class Sensor(DAQReadAnalog):
16
+ class Sensor(object):
17
17
  # channel 0:5 for FT sensor, channel 6 for trigger
18
18
  SENSOR_CHANNELS = range(0, 5 + 1)
19
19
  # channel 7 for trigger synchronization validation
20
20
  TRIGGER_CHANNELS = range(5, 6 + 1)
21
21
 
22
- def __init__(self, s_settings: SensorSettings):
22
+ def __init__(self, s_settings: SensorSettings,
23
+ daq_type: int,
24
+ use_aiftt: bool):
23
25
  """DOC"""
24
26
 
25
27
  assert isinstance(s_settings, SensorSettings)
26
28
  assert len(self.SENSOR_CHANNELS) == len(ForceSensorData.forces_names)
27
29
 
28
- super(Sensor, self).__init__(
29
- configuration=s_settings,
30
+ if daq_type == constants.NIDAQMX:
31
+ from ..daq.read_daq_nidaqmx import DAQReadAnalog
32
+ elif daq_type == constants.PYDAQMX:
33
+ from ..daq.read_daq_pydaqmx import DAQReadAnalog
34
+ elif daq_type == constants.MOCK_SENSOR:
35
+ from ..daq.read_daq_mock_sensor import DAQReadAnalog
36
+ else:
37
+ raise RuntimeError(f"Unsupported daq_type: {daq_type}")
38
+
39
+ if use_aiftt:
40
+ from ..daq.calibration_iaftt import CalibrationConverter
41
+ else:
42
+ from ..daq.calibration_dll import CalibrationConverter
43
+
44
+ self.daq = DAQReadAnalog(configuration=s_settings,
30
45
  read_array_size_in_samples=len(Sensor.SENSOR_CHANNELS)
31
- + len(Sensor.TRIGGER_CHANNELS),
32
- )
46
+ + len(Sensor.TRIGGER_CHANNELS))
33
47
 
34
- self.sensor_id = s_settings.sensor_id
35
- self.device_label = s_settings.device_label
36
- self.convert_to_FT = s_settings.convert_to_FT
37
- if self.DAQ_TYPE == "mock_sensor":
48
+ if daq_type == constants.MOCK_SENSOR:
38
49
  self._calib_converter = None
39
50
  else:
40
51
  self._calib_converter = CalibrationConverter(s_settings.calibration_file)
41
52
 
53
+ self.sensor_id = s_settings.sensor_id
54
+ self.device_label = s_settings.device_label
55
+ self.convert_to_FT = s_settings.convert_to_FT
56
+
42
57
  self._reverse_vector = np.ones(len(ForceSensorData.forces_names))
43
58
  if s_settings.reverse_parameter_names is not None:
44
59
  if isinstance(s_settings.reverse_parameter_names, str):
@@ -55,11 +70,11 @@ class Sensor(DAQReadAnalog):
55
70
  def determine_bias(self, n_samples=100):
56
71
  """determines the bias"""
57
72
 
58
- task_was_running = self._task_is_started
59
- self.start_data_acquisition()
73
+ task_was_running = self.daq.is_acquiring_data
74
+ self.daq.start_data_acquisition()
60
75
  data = None
61
76
  for _ in range(n_samples):
62
- read_buffer, _read_samples = self.read_analog()
77
+ read_buffer, _ = self.daq.read_analog()
63
78
  sample = read_buffer[Sensor.SENSOR_CHANNELS]
64
79
  if data is None:
65
80
  data = sample
@@ -67,7 +82,7 @@ class Sensor(DAQReadAnalog):
67
82
  data = np.vstack((data, sample))
68
83
 
69
84
  if not task_was_running:
70
- self.stop_data_acquisition()
85
+ self.daq.stop_data_acquisition()
71
86
 
72
87
  if self._calib_converter is not None and isinstance(data, np.ndarray):
73
88
  self._calib_converter.bias(np.mean(data, axis=0))
@@ -88,7 +103,7 @@ class Sensor(DAQReadAnalog):
88
103
  """
89
104
 
90
105
  start = local_clock()
91
- data, _read_samples = self.read_analog()
106
+ data, _read_samples = self.daq.read_analog()
92
107
  if self.convert_to_FT and self._calib_converter is not None:
93
108
  forces = np.asarray(
94
109
  self._calib_converter.convertToFT(voltages=data[Sensor.SENSOR_CHANNELS])
@@ -107,4 +122,4 @@ class Sensor(DAQReadAnalog):
107
122
  sensor_id=self.sensor_id,
108
123
  forces=forces,
109
124
  trigger=data[Sensor.TRIGGER_CHANNELS],
110
- )
125
+ )
@@ -8,9 +8,9 @@ from multiprocessing import Array, Event, Pipe, Process, Value
8
8
  import numpy as np
9
9
  from numpy import typing as npt
10
10
 
11
+ from .. import constants
11
12
  from .clock import local_clock, wait_ms
12
13
  from .lsl import LSLSream, cf_float32
13
- from .polling_time_profile import PollingTimeProfile
14
14
  from .process_priority_manager import get_priority
15
15
  from .sensor import Sensor
16
16
  from .settings import RecordingSettings, SensorSettings
@@ -22,6 +22,8 @@ class SensorProcess(Process):
22
22
  self,
23
23
  sensor_settings: SensorSettings,
24
24
  recording_settings: RecordingSettings,
25
+ daq_type: int,
26
+ use_aiftt: bool,
25
27
  pipe_buffered_data_after_pause=True,
26
28
  chunk_size=10000,
27
29
  ):
@@ -43,6 +45,12 @@ class SensorProcess(Process):
43
45
  )
44
46
 
45
47
  super(SensorProcess, self).__init__()
48
+
49
+ if daq_type not in [constants.NIDAQMX, constants.PYDAQMX, constants.MOCK_SENSOR]:
50
+ raise RuntimeError(f"Unsupported daq_type: {daq_type}")
51
+
52
+ self._daq_type = daq_type
53
+ self._use_aiftt = use_aiftt
46
54
  self.sensor_settings = sensor_settings
47
55
  self.recording_settings = recording_settings
48
56
  self._pipe_buffer_after_pause = pipe_buffered_data_after_pause
@@ -152,14 +160,16 @@ class SensorProcess(Process):
152
160
  def run(self):
153
161
  buffer = []
154
162
  self._buffer_size.value = 0
155
- sensor = Sensor(self.sensor_settings)
163
+ sensor = Sensor(self.sensor_settings,
164
+ daq_type=self._daq_type,
165
+ use_aiftt=self._use_aiftt)
166
+
156
167
  stream_forces = self.recording_settings.array_write_forces()
157
168
  stream_trigger = self.recording_settings.array_write_trigger()
158
169
 
159
170
  self._event_is_polling.clear()
160
171
  self._event_sending_data.clear()
161
172
  is_polling = False
162
- ptp = PollingTimeProfile() # TODO just for testing?
163
173
 
164
174
  ## create init LSL
165
175
  lsl_data_steam = LSLSream()
@@ -190,7 +200,7 @@ class SensorProcess(Process):
190
200
  if not is_polling:
191
201
  # start NI device and acquire one first sample to
192
202
  # ensure good timing
193
- sensor.start_data_acquisition()
203
+ sensor.daq.start_data_acquisition()
194
204
  buffer.append(
195
205
  DAQEvents(
196
206
  time=local_clock(), code="started:" + sensor.device_label
@@ -215,7 +225,6 @@ class SensorProcess(Process):
215
225
  if any(tr): # only stream if at least one trigger is active
216
226
  lsl_hardware_trigger_stream.outlet.push_sample(tr) # type: ignore
217
227
 
218
- ptp.update(d.time) # needed? TODO
219
228
  self._dat[:] = d.forces
220
229
  self._sample_cnt.value += 1 # type: ignore
221
230
 
@@ -230,7 +239,7 @@ class SensorProcess(Process):
230
239
  else:
231
240
  # pause: not polling
232
241
  if is_polling:
233
- sensor.stop_data_acquisition()
242
+ sensor.daq.stop_data_acquisition()
234
243
  buffer.append(
235
244
  DAQEvents(
236
245
  time=local_clock(), code="pause:" + sensor.device_label
@@ -244,7 +253,6 @@ class SensorProcess(Process):
244
253
  get_priority(self.pid),
245
254
  )
246
255
  is_polling = False
247
- ptp.stop()
248
256
 
249
257
  if self._pipe_buffer_after_pause and self._buffer_size.value > 0:
250
258
  # sending data to force
@@ -268,10 +276,9 @@ class SensorProcess(Process):
268
276
  self._event_is_polling.wait(timeout=0.1)
269
277
 
270
278
  # stop process
271
- sensor.stop_data_acquisition()
279
+ sensor.daq.stop_data_acquisition()
272
280
  self._buffer_size.value = 0
273
281
 
274
- logging.info("Sensor quit, %s, %s", sensor.device_label, ptp.get_profile_str())
275
-
282
+ logging.info("Sensor quit, %s", sensor.device_label)
276
283
 
277
284
  # FIXME check trigger processing and UDP connections#FIXME check trigger processing and UDP connections
@@ -86,8 +86,8 @@ class RecordingSettings(ABCSettings):
86
86
  calibration_files: List[str] = field(default_factory=lambda: ["FT9334.cal"])
87
87
  calibration_folder: str = CALIBRATION_FOLDER
88
88
 
89
- lsl_stream: bool = False
90
- save_data: bool = True
89
+ lsl_stream: bool = True
90
+ save_data: bool = False
91
91
  sampling_rate: int = 1000
92
92
 
93
93
  write_Fx: bool = True
@@ -11,7 +11,6 @@ from multiprocessing import Event, Process, Queue
11
11
  from subprocess import check_output
12
12
 
13
13
  from .clock import local_clock, wait_ms
14
- from .polling_time_profile import PollingTimeProfile
15
14
  from .process_priority_manager import get_priority
16
15
  from .types import UDPData
17
16
 
@@ -275,7 +274,6 @@ class UDPConnectionProcess(Process):
275
274
  udp_connection = UDPConnection(udp_port=5005)
276
275
  self.start_polling()
277
276
 
278
- ptp = PollingTimeProfile()
279
277
  prev_event_polling = None
280
278
 
281
279
  while not self._event_quit_request.is_set():
@@ -290,14 +288,12 @@ class UDPConnectionProcess(Process):
290
288
  )
291
289
  else:
292
290
  logging.warning("UDP stop")
293
- ptp.stop()
294
291
 
295
292
  if not self._event_is_polling.is_set():
296
293
  self._event_is_polling.wait(timeout=0.1)
297
294
  else:
298
295
  data = udp_connection.poll()
299
296
  t = local_clock()
300
- ptp.update(t)
301
297
  if data is not None:
302
298
  d = UDPData(string=data, time=t)
303
299
  self.receive_queue.put(d)
@@ -324,4 +320,4 @@ class UDPConnectionProcess(Process):
324
320
 
325
321
  udp_connection.unconnect_peer()
326
322
 
327
- logging.warning("UDP quit, {}".format(ptp.get_profile_str()))
323
+ logging.warning("UDP quit")
pyforcedaq/constants.py CHANGED
@@ -1,6 +1,9 @@
1
- USE_MOCK_SENSOR = False # <-- change for usage in lab to False
2
- USE_PYDAQMX = False # <-- change to True to use pyDAQmx instead of nidaqmx, requires pyDAQmx installation
3
- USE_ATI_DLL = False # <-- change to True to use ATI DLL for calibration conversion, otherwise use atiiaftt
1
+ NIDAQMX = 1
2
+ PYDAQMX = 2
3
+ MOCK_SENSOR = 9
4
+
5
+ DAQ_TYPE = NIDAQMX # default to nidaqmx, use constants.MOCK_SENSOR for mock sensor, constants.PYDAQMX for PyDAQmx
6
+ USE_AIFTT = True # <-- change to False to use ATI DLL for calibration conversion, otherwise use atiiaftt
4
7
 
5
8
  SETTINGS_FILE_EXTENSION = ".settings.toml"
6
9
  DEFAULT_SETTINGS_FILE = "pyForceDAQ" + SETTINGS_FILE_EXTENSION
@@ -1,28 +1,68 @@
1
1
  __author__ = "Oliver Lindemann"
2
2
 
3
- from ..constants import USE_ATI_DLL, USE_MOCK_SENSOR, USE_PYDAQMX
4
-
5
- if USE_MOCK_SENSOR:
6
- print("Using mock sensor instead.")
7
- from ._mock_sensor import DAQReadAnalog
8
-
9
- else:
10
- try:
11
- if USE_PYDAQMX:
12
- print("Using PyDAQmx for DAQ access.")
13
- from ._use_pydaqmx import DAQReadAnalog
14
- else:
15
- print("Using nidaqmx for DAQ access.")
16
- from ._use_nidaqmx import DAQReadAnalog
17
- except (ImportError, ModuleNotFoundError, NotImplementedError) as e:
18
- print("Error importing DAQReadAnalog: {0}".format(e))
19
- print("Warning: PyDAQmx or nidaqmx not found. Using mock sensor instead.")
20
- from ._mock_sensor import DAQReadAnalog
21
-
22
- if not USE_ATI_DLL:
23
- print("Using ATI IAFTT for calibration conversion.")
24
- from ._calibration_iaftt import CalibrationConverter
25
-
26
- else:
27
- print("ATI_CDLL for calibration conversion.")
28
- from ._calibration_dll import CalibrationConverter
3
+ from abc import ABC, abstractmethod
4
+ from typing import Tuple
5
+
6
+ import numpy.typing as npt
7
+
8
+ from .._lib.settings import DAQConfiguration
9
+
10
+
11
+ class DAQReadAnalogABC(ABC):
12
+ """Abstract base class for DAQ analog reading."""
13
+
14
+ @abstractmethod
15
+ def __init__(self,
16
+ configuration: DAQConfiguration,
17
+ read_array_size_in_samples: int):
18
+ """Initialize the DAQ device."""
19
+ pass
20
+
21
+ @property
22
+ @abstractmethod
23
+ def is_acquiring_data(self) -> bool:
24
+ """Return whether data acquisition is in progress."""
25
+ pass
26
+
27
+
28
+ @abstractmethod
29
+ def start_data_acquisition(self) -> None:
30
+ """Start data acquisition."""
31
+ pass
32
+
33
+ @abstractmethod
34
+ def stop_data_acquisition(self) -> None:
35
+ """Stop data acquisition."""
36
+ pass
37
+
38
+ @abstractmethod
39
+ def read_analog(self) -> Tuple[npt.NDArray, int]:
40
+ """Read analog data.
41
+
42
+ Returns
43
+ -------
44
+ read_buffer : numpy array
45
+ The read data.
46
+ read_samples : int
47
+ The number of samples actually read.
48
+ """
49
+ pass
50
+
51
+
52
+ class CalibrationConverterABC(ABC):
53
+ """Abstract base class for Calibration Converters."""
54
+
55
+ @abstractmethod
56
+ def __init__(self, calibration_file: str):
57
+ """Initialize the calibration converter with a calibration file."""
58
+ pass
59
+
60
+ @abstractmethod
61
+ def convertToFT(self, voltages: npt.NDArray) -> list:
62
+ """Convert voltages to force and torque values."""
63
+ pass
64
+
65
+ @abstractmethod
66
+ def bias(self, bias_values: npt.NDArray) -> None:
67
+ """Set the bias for the calibration."""
68
+ pass
@@ -1,19 +1,21 @@
1
1
  import ctypes as ct
2
- from typing import List
3
2
 
4
3
  from numpy.typing import NDArray
5
4
 
5
+ from . import CalibrationConverterABC
6
6
  from ._pyATIDAQ import ATI_CDLL
7
7
 
8
+ print("Using self compiled ATI DLL for calibration conversion.")
9
+
10
+ class CalibrationConverter(CalibrationConverterABC):
8
11
 
9
- class CalibrationConverter(object):
10
12
  def __init__(self, calibration_file: str):
11
13
  self._atidaq = ATI_CDLL()
12
14
  self._atidaq.createCalibration(calibration_file, ct.c_short(1))
13
15
  self._atidaq.setForceUnits("N")
14
16
  self._atidaq.setTorqueUnits("N-m")
15
17
 
16
- def convertToFT(self, voltages: NDArray):
18
+ def convertToFT(self, voltages: NDArray) -> list:
17
19
  return self._atidaq.convertToFT(voltages)
18
20
 
19
21
  def bias(self, bias_values: NDArray):
@@ -0,0 +1,17 @@
1
+ import atiiaftt
2
+ from numpy.typing import NDArray
3
+
4
+ from . import CalibrationConverterABC
5
+
6
+ print("Using ATI IAFTT for calibration conversion.")
7
+
8
+ class CalibrationConverter(CalibrationConverterABC): # type: ignore
9
+
10
+ def __init__(self, calibration_file:str):
11
+ self._ftsensor = atiiaftt.FTSensor(calibration_file, index=1)
12
+
13
+ def convertToFT(self, voltages:NDArray) -> list:
14
+ return self._ftsensor.convertToFt(voltages.tolist()) #TODO: to list needed?
15
+
16
+ def bias(self, bias_values: NDArray) -> None:
17
+ self._ftsensor.bias(bias_values.tolist())
@@ -6,9 +6,11 @@ from typing import Tuple
6
6
  import numpy as np
7
7
 
8
8
  from .._lib.clock import StopWatch
9
+ from . import DAQReadAnalogABC
9
10
 
11
+ print("Using mock sensor!!")
10
12
 
11
- class DAQReadAnalog(object):
13
+ class DAQReadAnalog(DAQReadAnalogABC):
12
14
  NUM_SAMPS_PER_CHAN = 1
13
15
  TIMEOUT = 1.0
14
16
  NI_DAQ_BUFFER_SIZE = 1000
@@ -69,7 +71,7 @@ class DAQReadAnalog(object):
69
71
 
70
72
  # fill in data
71
73
  if not self._task_is_started:
72
- return None, None
74
+ return np.array([]), 0
73
75
 
74
76
  n_new_samples = int(self._simulation_timer.time_ms) - self._sample_cnt
75
77
  while n_new_samples <= 0: # wait until new sample is available
@@ -5,15 +5,18 @@ import numpy as np
5
5
  from nidaqmx import constants as nidaq_consts
6
6
 
7
7
  from .._lib.settings import DAQConfiguration
8
+ from . import DAQReadAnalogABC
8
9
 
10
+ print("Using nidaqmx for DAQ access.")
9
11
 
10
- class DAQReadAnalog(nidaqmx.Task):
12
+ class DAQReadAnalog(nidaqmx.Task, DAQReadAnalogABC):
11
13
  NUM_SAMPS_PER_CHAN = 1
12
14
  TIMEOUT = 1
13
15
  DAQ_TYPE = "nidaqmx"
14
16
 
15
17
  def __init__(
16
- self, configuration: DAQConfiguration, read_array_size_in_samples: int
18
+ self, configuration: DAQConfiguration,
19
+ read_array_size_in_samples: int
17
20
  ):
18
21
  """DOC
19
22
  read_array_size_in_samples for ReadAnalogF64 call
@@ -43,10 +46,10 @@ class DAQReadAnalog(nidaqmx.Task):
43
46
  self.read_array_size_in_samples = read_array_size_in_samples
44
47
 
45
48
  @property
46
- def is_acquiring_data(self):
49
+ def is_acquiring_data(self) -> bool:
47
50
  return self._task_is_started
48
51
 
49
- def start_data_acquisition(self):
52
+ def start_data_acquisition(self) -> None:
50
53
  """Start data acquisition of the NI device
51
54
  call always before polling
52
55
 
@@ -56,7 +59,7 @@ class DAQReadAnalog(nidaqmx.Task):
56
59
  self.start()
57
60
  self._task_is_started = True
58
61
 
59
- def stop_data_acquisition(self):
62
+ def stop_data_acquisition(self) -> None:
60
63
  """Stop data acquisition of the NI device"""
61
64
 
62
65
  if self._task_is_started:
@@ -83,6 +86,6 @@ class DAQReadAnalog(nidaqmx.Task):
83
86
  """
84
87
 
85
88
  # fill in data
86
- data = self.read(self.NUM_SAMPS_PER_CHAN, self.TIMEOUT)
89
+ data = self.read(self.NUM_SAMPS_PER_CHAN, self.TIMEOUT) # type: ignore
87
90
  np_data = np.reshape(np.array(data), (-1,)) # reshape to vector
88
91
  return np_data, len(np_data)
@@ -16,9 +16,11 @@ import numpy as np
16
16
  import PyDAQmx
17
17
 
18
18
  from .._lib.settings import DAQConfiguration
19
+ from . import DAQReadAnalogABC
19
20
 
21
+ print("Using PyDAQmx for DAQ access.")
20
22
 
21
- class DAQReadAnalog(PyDAQmx.Task):
23
+ class DAQReadAnalog(PyDAQmx.Task, DAQReadAnalogABC):
22
24
  NUM_SAMPS_PER_CHAN = ct.c_int32(1)
23
25
  TIMEOUT = ct.c_longdouble(1.0) # one second
24
26
  NI_DAQ_BUFFER_SIZE = 1000
@@ -100,7 +102,7 @@ class DAQReadAnalog(PyDAQmx.Task):
100
102
  """
101
103
 
102
104
  # fill in data
103
- read_samples = ct.c_int32()
105
+ read_samples = ct.c_int32(0)
104
106
  read_buffer = np.zeros((self.read_array_size_in_samples,), dtype=np.float64)
105
107
 
106
108
  error = self.ReadAnalogF64(
pyforcedaq/launcher.py CHANGED
@@ -4,11 +4,10 @@ from typing import List
4
4
 
5
5
  import PySimpleGUI as _sg
6
6
 
7
- from . import __version__
7
+ from . import __version__, constants
8
8
  from ._lib.misc import list_settings_files
9
9
  from ._lib.settings import AppSettings
10
10
  from ._lib.udp_connection import UDPConnection
11
- from .constants import DEFAULT_SETTINGS_FILE, USE_MOCK_SENSOR
12
11
 
13
12
 
14
13
  def _check_sensor_calibration_settings(
@@ -66,7 +65,7 @@ def _windows_run(settings: AppSettings):
66
65
  info = [[_sg.Text(f"version: {__version__}")]]
67
66
  info.append([_sg.Text(f"IP address: {UDPConnection.MY_IP}")])
68
67
 
69
- if USE_MOCK_SENSOR:
68
+ if constants.DAQ_TYPE == constants.MOCK_SENSOR:
70
69
  info.append([_sg.Text("!!! USING MOCK SENSORS !!!", text_color="red")])
71
70
 
72
71
  layout = [
@@ -78,7 +77,7 @@ def _windows_run(settings: AppSettings):
78
77
  key="Start",
79
78
  )
80
79
  ],
81
- [_sg.Frame("Info", size=(280, 80), layout=info)],
80
+ [_sg.Frame("Info", size=(280, 150), layout=info)],
82
81
  [_sg.Frame("Settings", size=(280, 140), expand_y=True, layout=info_settings)],
83
82
  ]
84
83
  layout.append(
@@ -140,7 +139,7 @@ def load_settings_file(settings_file: str | Path) -> AppSettings:
140
139
 
141
140
  def run_launcher():
142
141
  _sg.theme("DarkBlue14") # please make your windows colorful
143
- settings = load_settings_file(DEFAULT_SETTINGS_FILE)
142
+ settings = load_settings_file(constants.DEFAULT_SETTINGS_FILE)
144
143
 
145
144
  while True:
146
145
  event, values, settings = _windows_run(settings)
@@ -1,18 +1,15 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pyForceDAQ
3
- Version: 2.0.3.dev1
3
+ Version: 2.0.5.dev2
4
4
  Summary: A Python package for data acquisition and analysis in force-based experiments.
5
5
  Author: Oliver Lindemann
6
6
  Author-email: Oliver Lindemann <lindemann@essb.eur.nl>
7
7
  Requires-Dist: atiiaftt>=0.1.1
8
8
  Requires-Dist: expyriment>=1.0.1
9
- Requires-Dist: icecream>=2.2.0
10
9
  Requires-Dist: nidaqmx>=1.5.0
11
10
  Requires-Dist: numpy>=2.4.4
12
11
  Requires-Dist: psutil>=7.2.2
13
- Requires-Dist: pydaqmx>=1.4.7
14
12
  Requires-Dist: pylsl>=1.18.2
15
13
  Requires-Dist: pysimplegui>=6.0
16
- Requires-Dist: pyxdf>=1.17.4
17
14
  Requires-Dist: tomlkit>=0.15.0
18
15
  Requires-Python: >=3.12, <3.14
@@ -1,25 +1,24 @@
1
1
  pyforcedaq/__init__.py,sha256=XlQ9TuycbGbJSN0p36XShcf22ETQ_JfftqHejS-C_oI,853
2
- pyforcedaq/__main__.py,sha256=GF4RJZGOvNKcToHal4zayh3j2vIY2wgNYeJQCb8h1vM,1377
2
+ pyforcedaq/__main__.py,sha256=N_gT06qOd6WxZDO5_hfoksqGRFsT_cKLoIndkdnvfi0,1897
3
3
  pyforcedaq/_lib/__init__.py,sha256=GBiextmC_Xz9iMQlLBnU1qsw7YFVQaiZ8nV5ln3B7Wk,32
4
4
  pyforcedaq/_lib/clock.py,sha256=2QrQ5J_FAWH_RndM5mnBUVZUxiPaK1nCxRzzFL0zvkY,978
5
- pyforcedaq/_lib/data_recorder.py,sha256=Cf91hv4mxhrHfNsO_5l3eYarPK4dmo73aJGL9LaoSRI,13371
5
+ pyforcedaq/_lib/data_recorder.py,sha256=JeiUMd4mSaAlyb-xZTC5hMLgLJlS0w98nuOD6VaMRiE,13781
6
6
  pyforcedaq/_lib/lsl.py,sha256=3hUq5DH7nVe-vjq-8w6VvXJhIGwkQdsTkK7pBSM4vu4,2096
7
7
  pyforcedaq/_lib/misc.py,sha256=9vfm7GOCrR4ddhTvmjtF3rCgoyLE0Ys1L8wfyhObzls,5450
8
- pyforcedaq/_lib/polling_time_profile.py,sha256=iHoRg78y1IkJHJLCT2LNjJHLauH5FWnz4RbxU20HRUA,1591
9
- pyforcedaq/_lib/process_priority_manager.py,sha256=MDA-E6kaYgBNtyEsHc1bLSrpQjSkrLZjB8Z7gCV5oo4,4196
10
- pyforcedaq/_lib/sensor.py,sha256=cEY9w88MzGQzAA92MBZ_LeZ_tXyR4jvYOP47Fv6DF-Q,3684
11
- pyforcedaq/_lib/sensor_process.py,sha256=BSSJ8QzSG9kqZZ1MiGXozqiUK6fgXz9oXww6I0Frd9k,9708
12
- pyforcedaq/_lib/settings.py,sha256=nHq9CVzafBw_HPaCMZjv-03cAGK9CwC9YzoJiapH4f4,6826
8
+ pyforcedaq/_lib/process_priority_manager.py,sha256=eRDzhW7sCINRRo5sm40E88w0EHtOuLGrCt1Co18dm0w,4195
9
+ pyforcedaq/_lib/sensor.py,sha256=Oay70h46U-hIaIEJtsSf2TvFKtBpnlasp4fuHzJVmBk,4276
10
+ pyforcedaq/_lib/sensor_process.py,sha256=WdzlDj0VnJfWvxOq_zbSgCFvAesWE-ltAytwejRix3s,9900
11
+ pyforcedaq/_lib/settings.py,sha256=0aI2iIn8s4AD_i1SaD1hTQzFQ1A8zi6nUoNjEs4EfGk,6826
13
12
  pyforcedaq/_lib/types.py,sha256=DS3-g1JYM_xi_q6YZJRr-BD2WX1fcKhDN6w4Y4l8d_M,10041
14
- pyforcedaq/_lib/udp_connection.py,sha256=FznfKS9vppEjivPgi9rHRxiT0HCB14x173QMUjNy5Kc,10061
15
- pyforcedaq/constants.py,sha256=Pu4zcT-RS3Qxxi8QNW2lIPsEo6_iOizgeOa87lJ2qeg,470
16
- pyforcedaq/daq/__init__.py,sha256=HVnOCs9q5uVHYZVSzCa-inZSR-D9RNVXzm16cdeotPo,977
17
- pyforcedaq/daq/_calibration_dll.py,sha256=HeGYX8TaJu6XbVGtHWLUydI74tW6UisjNr3sk7FN0t4,564
18
- pyforcedaq/daq/_calibration_iaftt.py,sha256=E4KsW9OhLhmWYtkFvj-RHKJq_MWioRjbTXVT0f6iwCE,501
19
- pyforcedaq/daq/_mock_sensor.py,sha256=KhbQ8CiIN5UNbYrg7O7NjKvlI8EjA8na2w2vR07MGq0,2192
13
+ pyforcedaq/_lib/udp_connection.py,sha256=N3TRuW8kTTx7vwKHQaXsReFiGQAy5Dpr3eLG1ThPYdk,9878
14
+ pyforcedaq/constants.py,sha256=EXED-LTh61cQ1wv_Dpfk-Svh3UtmN6DCuBW1rfGjISk,454
15
+ pyforcedaq/daq/__init__.py,sha256=f5Uj85LlWEyxB-vElYvBsFFMSxK_8BhojzeGaRxn7jg,1677
20
16
  pyforcedaq/daq/_pyATIDAQ.py,sha256=XZqPoTCX73ZoosocZB_pxqKr-icUUFOONRd94pHTMQs,10834
21
- pyforcedaq/daq/_use_nidaqmx.py,sha256=OPUmWbvVNsDUcdKB2tZksMObCGJDrsxHG2s8u67KcG4,2397
22
- pyforcedaq/daq/_use_pydaqmx.py,sha256=QhvgRIbdaVKPMfHxveK004bJV0mWftzUwkqm-PJaCVg,3164
17
+ pyforcedaq/daq/calibration_dll.py,sha256=QVQkJ57Za9Z-dIUzyqnCtBDRu-Au7WyKwKXjQ6qOYAU,669
18
+ pyforcedaq/daq/calibration_iaftt.py,sha256=ms0Nt_6_H5ddez29LJsVSZSD3ShA3hglpz_rNP3Mi2w,567
19
+ pyforcedaq/daq/read_daq_mock_sensor.py,sha256=RV4RJanU87oE_SK4i8NF3tsQoCTGzvgTpdYl7jX-y0E,2267
20
+ pyforcedaq/daq/read_daq_nidaqmx.py,sha256=XUqJoCGzpSfjfMjatQqGHa3pBpQaIsbqL0B3Tz6OCps,2532
21
+ pyforcedaq/daq/read_daq_pydaqmx.py,sha256=89BRuLhvVplKoBENuKlEUpG5CN25PrN__oWAm-k1Q4s,3253
23
22
  pyforcedaq/extras/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
23
  pyforcedaq/extras/convert.py,sha256=N8r5gl0Te3GHafkggeC4btFD94nUwBzM9cctH1jiSEA,8601
25
24
  pyforcedaq/extras/read_force_data.py,sha256=ZjrEHexz40OW8L8JlRFgAFxQuBAS8c66t2-jVN9NeBg,2147
@@ -33,8 +32,8 @@ pyforcedaq/gui/_plotter.py,sha256=wVgy3ovX4BeXKJpuxYTw-xJ1lC4GzNni2exojzlhgAM,82
33
32
  pyforcedaq/gui/_run.py,sha256=BHeFiXtqnCiYkrBJxwyCKC5z91ERAfEwf8stckZVBEQ,18692
34
33
  pyforcedaq/gui/_scaling.py,sha256=mb9OMGqqS9_cOaYtdMqjGIS8VRrEQlDBc4m6KZF5TVQ,1918
35
34
  pyforcedaq/gui/forceDAQ_logo.png,sha256=-bn6ZQQjKf2Pxd9mJ4r-wulibtjuv_bEkhG567GR1vc,15624
36
- pyforcedaq/launcher.py,sha256=CnTRqjUZbLVwAUk5xHrfDC7Uxs4obOHKIkm8ZlJrVfE,4970
37
- pyforcedaq-2.0.3.dev1.dist-info/WHEEL,sha256=Q9FtwzuR2QE37l-JIkuyklGnJJiCBHKnsPVQ9vzCMzQ,81
38
- pyforcedaq-2.0.3.dev1.dist-info/entry_points.txt,sha256=0VDGqAldPs3uUCun3y9v4ue8Uae8n-D6-R5YpamgJwQ,56
39
- pyforcedaq-2.0.3.dev1.dist-info/METADATA,sha256=5oxwMRa8HtILboqaEkY1Aui_X9b_fN66dNUKFZqQ0PA,591
40
- pyforcedaq-2.0.3.dev1.dist-info/RECORD,,
35
+ pyforcedaq/launcher.py,sha256=Tph9wdYQZcFOezFbp6MUHrKCCkGe6eMijMZFQ2u4xRY,4958
36
+ pyforcedaq-2.0.5.dev2.dist-info/WHEEL,sha256=Q9FtwzuR2QE37l-JIkuyklGnJJiCBHKnsPVQ9vzCMzQ,81
37
+ pyforcedaq-2.0.5.dev2.dist-info/entry_points.txt,sha256=0VDGqAldPs3uUCun3y9v4ue8Uae8n-D6-R5YpamgJwQ,56
38
+ pyforcedaq-2.0.5.dev2.dist-info/METADATA,sha256=TtD6QzyYFDaCAJQpka2u5tKhMs3ENzlJNFObMTFgSQs,501
39
+ pyforcedaq-2.0.5.dev2.dist-info/RECORD,,
@@ -1,57 +0,0 @@
1
- import numpy as np
2
-
3
- from .clock import local_clock
4
-
5
-
6
- class PollingTimeProfile(object):
7
- def __init__(self, timing_range_ms=10):
8
- self._last = None
9
- self._timing_range_ms = 10
10
- self._zero_cnt = 0
11
-
12
- # self._zero_time_polling_frequency = {}
13
- self.profile_frequency = np.array([0] * (timing_range_ms + 1))
14
-
15
- def stop(self):
16
- self._last = None
17
-
18
- def update(self, time: float):
19
-
20
- time_ms = int(time * 1000)
21
- if self._last is not None:
22
- d = time_ms - self._last
23
- if d > self._timing_range_ms:
24
- d = self._timing_range_ms
25
- self.profile_frequency[d] += 1
26
-
27
- # if d == 0:
28
- # self._zero_cnt += 1
29
- # elif self._zero_cnt > 0:
30
- # try:
31
- # self._zero_time_polling_frequency[self._zero_cnt] += 1
32
- # except:
33
- # self._zero_time_polling_frequency[self._zero_cnt] = 1
34
- # self._zero_cnt = 0
35
-
36
- self._last = time_ms
37
-
38
- def tick(self):
39
- self.update(local_clock())
40
-
41
- @property
42
- def profile_percent(self):
43
- n = np.sum(self.profile_frequency)
44
- return self.profile_frequency / n
45
-
46
- def get_profile_str(self):
47
- rtn = (
48
- str(list(self.profile_frequency))
49
- .replace("[", "")
50
- .replace("]", "")
51
- .replace(" ", "")
52
- )
53
- return "polling profile [{}]".format(rtn)
54
-
55
- # @property
56
- # def zero_time_polling_frequency(self):
57
- # return np.array(list(self._zero_time_polling_frequency.items()))
@@ -1,17 +0,0 @@
1
- from typing import List
2
-
3
- import atiiaftt
4
- from numpy.typing import NDArray
5
-
6
-
7
- class CalibrationConverter(object): # type: ignore
8
-
9
- def __init__(self, calibration_file:str):
10
- self._ftsensor = atiiaftt.FTSensor(calibration_file, index=1)
11
-
12
- def convertToFT(self, voltages:NDArray):
13
- return self._ftsensor.convertToFt(voltages.tolist()) # FIXME reverse parameter
14
- #TODO: to list needed?
15
-
16
- def bias(self, bias_values: NDArray):
17
- self._ftsensor.bias(bias_values.tolist())