Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migration to NIDAQmx python wrapper #8

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
0f854b1
new simple counter of all type
jerlfan Nov 17, 2023
5d37aa4
Update daq_0Dviewer_DAQmx_counter.py
jerlfan Nov 18, 2023
730c40d
using nidaqmx
jerlfan Nov 21, 2023
b3b8991
adding the use of the nidaqmx module
jerlfan Dec 7, 2023
a34f000
replacing PyDAQmx by nidaqmx in daqmx-ni
jerlfan Dec 8, 2023
feb7235
working version of wrapper daqmxni
jerlfan Dec 14, 2023
9919dee
NIDAQmx structure
Soungai00 Sep 17, 2024
ab58aea
New daq_viewer_NIDAQmx + wrapper modifs
Soungai00 Sep 19, 2024
2742e27
code adapted to nidaqmx + live visu ok
Soungai00 Sep 26, 2024
2ebd341
Reorder & update nidaqmx constants & variables
Soungai00 Dec 5, 2024
9193b7e
Clarify code
Soungai00 Dec 5, 2024
3631908
Remove old PyDAQMX based-on method
Soungai00 Dec 5, 2024
a1989ae
devices attributes not a list of string anymore but a list of nidaqmx…
Soungai00 Dec 5, 2024
4f7bf5d
Clarify code
Soungai00 Dec 5, 2024
daf959c
PEP + syntax
Soungai00 Dec 5, 2024
7d44cc5
nidaqmx.task parameters
Soungai00 Dec 5, 2024
31c5d6a
PEP + syntax
Soungai00 Dec 5, 2024
612e403
Callback method
Soungai00 Dec 5, 2024
697d4be
PEP + syntax
Soungai00 Dec 5, 2024
7a317b7
Optimizing plugin structure by separating Move & Viewer from NIDAQmx …
Soungai00 Dec 5, 2024
8288ab9
Attributes & methods from inheritance
Soungai00 Dec 5, 2024
e0559a3
Main file reworked for callback tests
Soungai00 Dec 5, 2024
f0e25f3
add config files .toml
Soungai00 Dec 6, 2024
7371774
Fixed imports
Soungai00 Dec 6, 2024
7ba5d55
Import config from .toml files
Soungai00 Dec 6, 2024
91dbcfe
Add use of toml files: config sequence + generates scalablegroup from…
Soungai00 Dec 9, 2024
9d0b673
Minor modifs (PEP, unused imports, info logged)
Soungai00 Dec 9, 2024
186b66b
Clarify & optimize code + fix minors problems
Soungai00 Dec 9, 2024
6782d28
Update README
Soungai00 Dec 9, 2024
46cf0ca
removed CustomEnum to use the ones from nidaq.constants
loicguilmard Dec 18, 2024
17d444d
migrated to pyproject.toml
loicguilmard Dec 18, 2024
ba2ec80
extended nidaqmx.constants : UsageTypeAI, Edge, TerminalConfiguration…
loicguilmard Dec 19, 2024
d916856
Using the extended nidaqmx.constants
loicguilmard Dec 19, 2024
0e4be2e
[Cleaning] aliasing task and System, using explicit enum.Input and PE…
loicguilmard Dec 19, 2024
974fbd1
[Cleaning] aliasing Device and typos
loicguilmard Dec 19, 2024
a964c7d
Fixes
loicguilmard Dec 19, 2024
d4731a9
using enums instead of hardcoded strings.
loicguilmard Dec 19, 2024
9797e14
Added DAQ_NIDAQ_source OD, 1D, Actuator
loicguilmard Dec 19, 2024
bf1df4b
enums typos and mix-ups
loicguilmard Dec 20, 2024
7db1596
Added aenum to dependencies
loicguilmard Dec 20, 2024
5469912
Merge pull request #1 from loicguilmard/nidaq_cethil_multimodule
Soungai00 Dec 21, 2024
004e910
Fix viewer & move double implementation
Soungai00 Jan 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Contributors

* Amelie Jarnac
* Aurore Finco
* Sébastien Guerrero ([email protected])

Instruments
===========
Expand All @@ -40,6 +41,6 @@ Viewer0D
++++++++

* **DAQmx_PLcounter**: Single photon counting

* **NIDAQmx: Analog Input (current-voltage-temperature), working with cDAQ & DAQ-USB


2 changes: 1 addition & 1 deletion plugin_info.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ license = 'MIT'

[plugin-install]
#packages required for your plugin:
packages-required = ['pydaqmx', 'pymodaq>4.0.1']
packages-required = ['pydaqmx','nidaqmx','pymodaq>4.0.1']
##

[features] # defines the plugin features contained into this plugin
Expand Down
3 changes: 3 additions & 0 deletions src/pymodaq_plugins_daqmx/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from pathlib import Path
from pymodaq.utils.logger import set_logger # to be imported by other modules.

from .utils import Config
config = Config()

with open(str(Path(__file__).parent.joinpath('resources/VERSION')), 'r') as fvers:
__version__ = fvers.read().strip()
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from ..hardware.national_instruments.daq_NIDAQmx import DAQ_NIDAQmx_Actuator
from ..hardware.national_instruments.daq_NIDAQmx_Move import DAQ_NIDAQmx_Actuator


class DAQ_Move_DAQmx(DAQ_NIDAQmx_Actuator):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import PyDAQmx


class DAQ_Move_DAQmx_MultipleScannerControl(DAQ_Move_base):
"""Plugin to control a piezo scanners with a NI card. This modules requires a clock channel to handle the
timing of the movement and display the position, and this clock channel is shared between the master and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import PyDAQmx


class DAQ_Move_DAQmx_ScannerControl(DAQ_Move_base):
"""Plugin to control a piezo scanner with a NI card. This modules requires a clock channel to handle the
timing of the movement and display the position. Avoid using several scanners (ie several analog outputs)
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pymodaq_plugins_daqmx.hardware.national_instruments.daq_NIDAQmx import DAQ_NIDAQmx_Viewer
from pymodaq_plugins_daqmx.hardware.national_instruments.daq_NIDAQmx_Viewer import DAQ_NIDAQmx_Viewer
from pymodaq.control_modules.viewer_utility_classes import main


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@
Edge, ClockSettings, Counter, ClockCounter, TriggerSettings

from PyDAQmx import DAQmx_Val_ContSamps
# DAQmx_Val_DoNotInvertPolarity, DAQmxConnectTerms,
# DAQmx_Val_FiniteSamps, DAQmx_Val_CurrReadPos, \
# DAQmx_Val_DoNotOverwriteUnreadSamps


class DAQ_0DViewer_DAQmx_PLcounter(DAQ_Viewer_base):
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import numpy as np
from pymodaq.utils.daq_utils import ThreadCommand
from pymodaq.utils.data import DataWithAxes, DataToExport, DataSource
from pymodaq.control_modules.viewer_utility_classes import DAQ_Viewer_base, comon_parameters, main
from pymodaq.utils.parameter import Parameter
import nidaqmx

from pymodaq_plugins_daqmx.hardware.national_instruments.daqmxni import DAQmx, Edge, Counter


class DAQ_0DViewer_DAQmx_counter(DAQ_Viewer_base):
"""
Plugin for a 0D PL counter, based on a NI card.
"""
params = comon_parameters+[
{"title": "Counting channel:", "name": "counter_channel",
"type": "list", "limits": DAQmx.get_NIDAQ_channels(source_type="Counter")},
{"title": "Acq. Time (s):", "name": "acq_time",
"type": "float", "value": 1., "default": 1.},
]

def ini_attributes(self):
self.controller = None
self.clock_channel = None
self.counter_channel = None
self.live = False # True during a continuous grab
self.counting_time = 0.1

def commit_settings(self, param: Parameter):
"""Apply the consequences of a change of value in the detector settings

Parameters
----------
param: Parameter
A given parameter (within detector_settings) whose value has been changed by the user
"""
if param.name() == "acq_time":
self.counting_time = param.value()
self.update_tasks()

def ini_detector(self, controller=None):
"""Detector communication initialization

Parameters
----------
controller: (object)
custom object of a PyMoDAQ plugin (Slave case). None if only one actuator/detector by controller
(Master case)

Returns
-------
info: str
initialized: bool
False if initialization failed otherwise True
"""
self.controller = DAQmx() #{"clock": DAQmx(), "counter": DAQmx()}
try:
self.update_tasks()
initialized = True
info = "NI card based counter"
self.counting_time = self.settings.child("acq_time").value()
except Exception as e:
print(e)
initialized = False
info = "Error"

return info, initialized

def close(self):
"""Terminate the communication protocol"""
pass
#self.controller["clock"].close()
#self.controller["counter"].close()

def grab_data(self, Naverage=1, **kwargs):
"""Start a grab from the detector

Parameters
----------
Naverage: int
Number of hardware averaging not relevant here.
kwargs: dict
others optionals arguments
"""
#update = False # to decide if we do the initial set up or not


#if 'live' in kwargs:
# if kwargs['live'] != self.live:
# update = True
# self.live = kwargs['live']
# """
#if 'live' in kwargs:
# if kwargs['live'] == self.live:
# update = False # we are already live
# self.live = kwargs['live']
# """

#if update:
# self.update_tasks()
# self.controller["clock"].start()

read_data = 32#self.controller.readCounter()#, counting_time=self.counting_time)
data = read_data #/self.counting_time # convert to cts/s
self.dte_signal.emit(DataToExport(name='Counts',
data=[DataWithAxes(name='Counts', data=[np.array([data])],
source=DataSource['raw'],
dim='Data0D', labels=['Counts (Hz)'])]))

def stop(self):
"""Stop the current grab hardware wise if necessary"""
self.task.stop()
self.close()
self.emit_status(ThreadCommand('Update_Status', ['Acquisition stopped.']))
return ''

def update_tasks(self):
"""Set up the counting tasks in the NI card."""
# Create channels

self.counter_channel = Counter(name=self.settings.child("counter_channel").value(),
source="Counter", edge=Edge.names()[0])
#
#self.controller["clock"].update_task(channels=[self.clock_channel],
# clock_settings=ClockSettings(),
# trigger_settings=TriggerSettings())
#self.controller["clock"].task.CfgImplicitTiming(DAQmx_Val_ContSamps, 1)
#
#self.controller["counter"].update_task(channels=[self.counter_channel],
# clock_settings=ClockSettings(),
# trigger_settings=TriggerSettings())

# connect the clock to the counter
#self.controller["counter"].task.SetSampClkSrc("/" + self.clock_channel.name + "InternalOutput")


if __name__ == '__main__':
main(__file__)
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
from pymodaq.control_modules.viewer_utility_classes import main
from pymodaq.control_modules.viewer_utility_classes import comon_parameters as viewer_params
from pymodaq_plugins_daqmx import config
from pymodaq_plugins_daqmx.hardware.national_instruments.daqmxni import AIChannel, AIThermoChannel, DAQmx, nidaqmx,\
DAQ_termination, DAQ_thermocouples
from pymodaq_plugins_daqmx.hardware.national_instruments.daq_NIDAQmx import DAQ_NIDAQmx_base
from pymodaq_plugins_daqmx.hardware.national_instruments.daq_NIDAQmx_Viewer import DAQ_NIDAQmx_Viewer
from pymodaq.utils.logger import set_logger, get_module_name
logger = set_logger(get_module_name(__file__))


class DAQ_0DViewer_NIDAQmx(DAQ_NIDAQmx_Viewer):
"""
Plugin for a 0D data visualization & acquisition with various NI modules plugged in a NI cDAQ.
"""

config_channels: list
channels_ai: list
config: config
controller: DAQmx
config_devices: list
config_modules: list
current_device: nidaqmx.system.Device
live: bool
Naverage: int

param_devices = DAQmx.get_NIDAQ_devices().device_names
params = viewer_params + [
{'title': 'Display type:', 'name': 'display', 'type': 'list', 'limits': ['0D', '1D']},
{'title': 'Devices :', 'name': 'devices', 'type': 'list', 'limits': param_devices,
'value': param_devices[0]
},
{'title': 'Device To Use:', 'name': 'dev_to_use', 'type': 'list', 'limits': param_devices,
},
] + DAQ_NIDAQmx_base.params

def __init__(self, parent=None, params_state=None):
super().__init__(parent, params_state)

def ini_attributes(self):
super().ini_attributes()
self.channels_ai = []
self.config = config
self.config_channels = []
self.config_devices = []
self.config_modules = []
self.live = False
self.Naverage = 1

def close(self):
self.live = False
self.controller.stop()
self.controller.close()
pass


if __name__ == '__main__':
"""Main section used during development tests"""
main_file = False
if main_file:
main(__file__)
else:
try:
print("In main")
import nidaqmx as ni
from pymodaq_plugins_daqmx.hardware.national_instruments.daqmxni import CurrentUnits, TemperatureUnits,\
VoltageUnits, CJCSource

# EXPLORE DEVICES
devices = ni.system.System.local().devices
print("devices {}".format(devices))
print("devices names {}".format(devices.device_names))
print("devices types {}".format([dev.product_type for dev in devices]))
cdaq = devices[0]
mod1 = cdaq.chassis_module_devices[0] # Equivalent devices[1]
mod2 = devices[2]
mod3 = devices[3]
try:
usb1 = devices[4]
except Exception as e:
pass
print("cDAQ modules: {}".format(mod.compact_daq_chassis_device.product_type for mod in [mod1, mod2, mod3]))

# TEST RESOURCES
try:
for device in devices:
device.self_test_device()
except Exception as e:
print("Resources test failed: {}" .format(e))

# CREATE CHANNELS
channels_th = [AIThermoChannel(name="cDAQ1Mod1/ai0",
source='Analog_Input',
analog_type='Thermocouple',
value_min=-100,
value_max=1000,
thermo_type=DAQ_thermocouples.K),
]
channels_voltage = [AIChannel(name="cDAQ1Mod3/ai0",
source='Analog_Input',
analog_type='voltage',
value_min=-80.0e-3,
value_max=80.0e-3,
termination=DAQ_termination.Auto,
),
AIChannel(name="cDAQ1Mod3/ai1",
source='Analog_Input',
analog_type='voltage',
value_min=-80.0e-3,
value_max=80.0e-3,
termination=DAQ_termination.Auto,
),
]
# CREATE TASK
task_9211 = nidaqmx.Task()
task_9205 = nidaqmx.Task()

def callback_9211(task_handle, every_n_samples_event_type, number_of_samples, callback_data):
data9211 = task_9211.read(5)
print(data9211)

def callback_9205(task_handle, every_n_samples_event_type, number_of_samples, callback_data):
data9205 = task_9205.read(5)
print(data9205)

for channel in channels_th:
task_9211.ai_channels.add_ai_thrmcpl_chan(channel.name,
"",
channel.value_min,
channel.value_max,
TemperatureUnits.DEG_C,
channel.thermo_type,
CJCSource.BUILT_IN,
0.,
"")
for channel in channels_voltage:
task_9205.ai_channels.add_ai_voltage_chan(channel.name,
"",
channel.termination,
channel.value_min,
channel.value_max,
VoltageUnits.VOLTS,
"")
task_9211.timing.cfg_samp_clk_timing(5.0, None, nidaqmx.constants.Edge.RISING,
nidaqmx.constants.AcquisitionType.CONTINUOUS, 5)
task_9211.register_every_n_samples_acquired_into_buffer_event(10, callback_9211)

task_9205.timing.cfg_samp_clk_timing(10, None, nidaqmx.constants.Edge.RISING,
nidaqmx.constants.AcquisitionType.CONTINUOUS, 10)
task_9205.register_every_n_samples_acquired_into_buffer_event(2, callback_9205)

task_9211.start()
task_9205.start()

print("Acquisition in progress... Press enter to stop")
input()

task_9211.close()
task_9205.close()

except Exception as e:
print("Exception ({}): {}".format(type(e), str(e)))
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pymodaq_plugins_daqmx.hardware.national_instruments.daq_NIDAQmx import DAQ_NIDAQmx_Viewer
from pymodaq_plugins_daqmx.hardware.national_instruments.daq_NIDAQmx_Viewer import DAQ_NIDAQmx_Viewer
from pymodaq.control_modules.viewer_utility_classes import main


Expand Down
Loading