Skip to content

Commit

Permalink
deploy: d078267
Browse files Browse the repository at this point in the history
  • Loading branch information
seb5g committed Nov 21, 2024
0 parents commit b6a4f4d
Show file tree
Hide file tree
Showing 96 changed files with 6,919 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .buildinfo
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Sphinx build info version 1
# This file records the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 4efee7d35dde64efe3b2d8c12cea76e8
tags: 645f666f9bcd5a90fca523b33c5a78b7
Binary file added .doctrees/creating_plugin.doctree
Binary file not shown.
Binary file added .doctrees/daqmx.doctree
Binary file not shown.
Binary file added .doctrees/environment.pickle
Binary file not shown.
Binary file added .doctrees/index.doctree
Binary file not shown.
Binary file added .doctrees/introduction.doctree
Binary file not shown.
Binary file added .doctrees/user_guide.doctree
Binary file not shown.
Binary file added .doctrees/user_guide/counter_details.doctree
Binary file not shown.
Binary file added .doctrees/user_guide/counter_use.doctree
Binary file not shown.
Binary file added .doctrees/user_guide/scanner_details.doctree
Binary file not shown.
Binary file added .doctrees/user_guide/scanner_use.doctree
Binary file not shown.
Empty file added .nojekyll
Empty file.
Binary file added _images/PLcounter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/Xscanner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/Yscanner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions _sources/creating_plugin.rst.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.. _create_plugin:

Creating a plugin for your specific needs
=========================================

In order to create a plugin using a NI card to acquire some data or control an actuator, or even synchronize the acquisition of data with another device, you should start as usual from the `plugin template <https://github.com/PyMoDAQ/pymodaq_plugins_template>`_. It is also strongly recommended that you read the tutorial about instrument plugins `available in the PyMoDAQ documentation <http://pymodaq.cnrs.fr/en/latest/tutorials/plugin_development.html#>`_.

Then you have to analyze the experiment that you want to perform and find the best type of controller that you should use:

* a single ``DAQmx`` object, if you need to perform only one type of task.

* a dict of several ``DAQmx`` objects, like in the PLcounter example, if you will only use the NI card but need to combine several tasks.

* a dict of ``DAQmx`` objects and other hardware controllers, for example if you want to synchronise your acquisition with an actuator which will be triggered by the NI card.

* Another more complicated object (that you will need to write!), like in the MultipleScannerControl example, if you need to share some resources of the NI card between different instrument plugins which control independent parameters/measurements. Beware in particular of the Scan extension which sends all the move commands at the same time.
36 changes: 36 additions & 0 deletions _sources/daqmx.rst.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
The DAQmx object
================

You will find its definition in the file ``hardware/national_instruments/daqmx.py``. This is building block for this plugin, this is the object that you will use as a controller inside your custom plugin.

The ``DAQmx`` object has an attribute ``task``, which corresponds to a Task for the NIDAQmx driver. Each ``DAQmx`` can only handle a single task, but a task can be executed on several channels. You will find in the same file the definition of many different Channel classes, which are all the channel types that are available physically on such NI devices.

The list of these channels is:

- AChannel (Analog Channel)

- AIChannel: Analog Input
- AIThermoChannel: Specific analog input for thermocouples
- AOChannel: Analog Output

- Counter (Regular edge counter)

- ClockCounter: a counter that you use as a clock
- SemiPeriodCounter: another specific type of counter which might be useful to count between state transitions of a signal

- DigitalChannel

- DOChannel: Digital Output
- DIChannel: Digital Input

To use the ``DAQmx``, you therefore need to create Channels of the type you need, specifying the appropriate ``ClockSettings`` and ``TriggerSettings`` (these are also defined in the same file). Then, you pass these channels to the ``update_task`` method of the ``DAQmx``. Be careful that a task can only handle one channel type, if you need several, you need several ``DAQmx``. The ``update_task`` method sets everything up, but if you are using channels as trigger or clock for other channels, you will need to connects them yourself after calling ``update_task``.

Once the task is properly set up, you can start it with the method ``start()`` of the ``DAQmx`` object. Several convenient methods of the ``DAQmx`` object are available to read or write data, depending on the task you are performing. They have self-explaining names:

- ``writeAnalog(Nsamples, Nchannels, values, autostart=False)``
- ``readAnalog(Nchannels)``
- ``readCounter(Nchannels, counting_time=10., read_function='Ex')``
- ``readDigital(Nchannels)``
- ``writeDigital(Nchannes, values, autostart=False)``

You can also stop the task with the ``stop()`` method.
26 changes: 26 additions & 0 deletions _sources/index.rst.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.. pymodaq_plugins_daqmx documentation master file, created by
sphinx-quickstart on Thu Sep 14 15:41:39 2023.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pymodaq_plugins_daqmx's documentation!
=================================================

This PyMoDAQ plugin is devoted to the National Instrument signal acquisition and generation using the NiDAQmx library. It contains generic objects which should be used as a basis to build actuators and viewers performing custom signal acquisition and generation.
In addition, and they are also meant as examples, it provides actuator plugins which can be used to move piezo scanners using the analog output functions of NI acquisition cards, as well as a 0D viewer corresponding to a single photon counter.

This documentation is written as a tutorial to guide you when setting up your NI acquisition devices with PyMoDAQ.

**Caution! The 0D and 1D Viewers DAQmx and the Move DAQmx are not working properly. Write your own plugin for your specific needs.**

This plugin is compatible with PymoDAQ 4.

.. toctree::
:maxdepth: 1
:caption: Contents:

introduction
user_guide
daqmx
creating_plugin

15 changes: 15 additions & 0 deletions _sources/introduction.rst.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Introduction
============

.. _introduction:

NI acquisition and signal generation devices are very versatile instruments, which can be used both as actuators and detectors. They offer the possibility to generate or acquire both analog and digital signals, with external or internal timing of the tasks. As a consequence, one can hardly provide a generic PyMoDAQ plugin to operate a NI acquisition card, and you will most probably need to build your own module to perform the precise task that you have in mind.

Installation
------------

Of course, you need a working PyMoDAQ installation, see `here <http://pymodaq.cnrs.fr/en/latest/user_folder/installation.html>`_ the installation procedure. You also need to have the NIDAQmx driver on your computer, together with the acquisition device. Use the NI MAX software to test your hardware.

Then you can install the *pymodaq_plugins_daqmx* module, from the `plugin manager <http://pymodaq.cnrs.fr/en/latest/user_folder/installation.html#plugin-manager>`_ or with ``pip install pymodaq_plugins_daqmx``.
The interface between the NIDAQmx driver and python (and thus PyMoDAQ) is done by the package `PyDAQmx <https://pythonhosted.org/PyDAQmx/>`_.

30 changes: 30 additions & 0 deletions _sources/user_guide.rst.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
User guide
==========

Now that you have a working installation, two options are possible: either there is already a plugin doing exactly what you need, or most probably, you need to build your own daq_move or daq_viewer.
The available specific functions are:

* counting single photons (``DAQmx_PL_counter``).
* using an analog output to move a piezoelectric scanner at a desired (slow) speed (``DAQmx_ScannerControl`` and ``DAQmx_MultipleScannerControl``).

This user guide will first explain how to use these two plugins, and then detail how they work.

.. toctree::
:maxdepth: 1

user_guide/counter_use
user_guide/scanner_use

For any other use, you will need to create your own move or viewer based on this plugin. See the :ref:`create_plugin` guide for a detailed procedure.

Working principle of the plugins
--------------------------------

The controller object, which is usually the wrapper to your hardware, will always be a ``DAQmx`` object. These are defined in ``hardware\national_instruments\daqmx.py``. Such an object contains a **task**, which is configured and then sent to the NI device. Beware that a task can only contain one channel type. The channel types are Analog Output, Analog Input, Digital Output, Digital Input or Counter. As a consequence, if you need to combine several of them, your controller will be a bit more complicated. It might be a dict containing several ``DAQmx`` objects, as in the photon counter example, or you might even need to create a specific object to handle these ``DAQmx`` objects, as in the scanner control example. More details about these two situations are given in the following sections.

.. toctree::
:maxdepth: 1

user_guide/counter_details
user_guide/scanner_details

13 changes: 13 additions & 0 deletions _sources/user_guide/counter_details.rst.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Details about the implementation of the OD viewer PLcounter
===========================================================

As you have seen from the configuration of the plugin, we use two counter channels to perform the measurement: a first one which is counting and a second one to handle the measurement timing. These are 2 separate tasks, although the channels will be connected together. As a result, we cannot use a single ``DAQmx`` object as hardware controller.

The controller here is a dict containing two ``DAQmx``, one of them is the "clock" and the other the "counter". Each of them contains a single task.

* The clock channel is set up as a ``ClockCounter`` object (see the file ``daqmx.py`` for its definition).
* The counter channel is a ``Counter``, and its timing source is the clock channel.

**Continous grab or snap**

By default, the ``grab_data`` function resets both the clock and the counting tasks. For a single snap, this is not an issue, but for continuous acquisition, this does not make sense, so we use the ``"live"`` parameter sent to ``grab_data`` to decide if we update the tasks or not.
38 changes: 38 additions & 0 deletions _sources/user_guide/counter_use.rst.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Using the 0D viewer PLcounter
=============================

This plugin is meant to be used to count single photons with a NI card. The signal consists of TTL pulses sent by a detector (mainly an avalanche photodiode (APD)).

The signal is displayed in kcounts/s.

It was tested only with NI PCIe 63XX devices.

Configuration
-------------

You need to provide 4 parameters, as shown in the screenshot below.

* **Counting channel**: the internal counting channel that you will use to count the rising edges of the signal, something like ``Dev[X]/ctr[Y]``

* **Photon source**: the channel on which you send the signal from the APD, something like ``/Dev[X]/PFI[Y]``, to choose from a given list.

* **Clock frequency**: the acquisition rate, each data point corresponds to counting during the associated time interval.

* **Clock channel**: the channel which you will use for measurement timing, something like ``Dev[X]/ctr[Y]``. You cannot use the same as for the counting channel!

.. image:: /images/PLcounter.png
:width: 800

This plugin is not intended to be used with a "Slave" configuration, but you can definitely use the same NI card device as hardware for other plugins at the same time.

Be careful to use as photon source the default input terminal corresponding to the counting channel, check the documentation of your NI device about this.


Use
---

It works as a usual 0D viewer plugin. It is recommended to start with a snap before launching a continuous grab.

If you need to use one of the counter/clock channels with another plugin, do not forget to stop the measurement, otherwise you will get an error about the resource being busy.

You might get many warnings in the log about the task being stopped before being finished, do not worry about it, the measurement is still fine. If you know how to solve this, please contribute!
30 changes: 30 additions & 0 deletions _sources/user_guide/scanner_details.rst.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Details about the implementation of the MultipleScannerControl move
===================================================================

Similarly to the case of the PLcounter, we need to use several channels together to make the scanner work, a clock and an analog output. In principle, we can use the same trick as for the PLcounter and define the controller as a dict containing 2 ``DAQmx`` objects. This is what is done in the ScannerControl plugin, but its means that you need one clock channel for each analog output channel, so if you have many scanners, it will very quickly become an issue. In addition, with a scanner, you most probably want to use the Scan extension. For each movement, the extension sends the command to move to every actuator roughly simultaneously: if your scanners share the same clock, you will get into trouble.

Introduction of a new object to use as controller
-------------------------------------------------

The solution proposed with the MultipleScannerControl plugin is to add an additional object to handle the synchronisation of the different scanners. This object is the ``AO_with_clock_DAQmx`` which is defined in the file ``daqmx_objects.py``, which is used as controller instead of the ``DAQmx``.

The ``AO_with_clock_DAQmx`` has 2 attributes, ``clock`` and ``analog`` which are ``DAQmx`` objects, each of them containing, as usual, a single task.

The clock will thus be shared by all the scanners connected to the ``AO_with_clock_DAQmx`` controller. The parameters of the clock can thus only be modified in the settings of the Master scanner.

The analog DAQmx object has an AnalogOutput task with several output channels, one for each scanner. The list of these channels is stored in the attribute ``AOchannels`` As a result, the list of positions sent by each scanner plugins to describe the movement have to be reformatted, as values have to be sent to all the channels. For exemple, to move the X scanner from 1 to 5 µm in steps of 1 µm, the plugins sends the list ``[1000, 2000, 3000, 4000, 5000]``, but if a Y scanner is also connected to the ``AO_with_clock_DAQmx``, it needs to be reformatted to ``[[1000, 2000, 3000, 4000, 5000], [current_Y_position, current_Y_position, current_Y_position, current_Y_position, current_Y_position]]``. This reformatting is done by the ``AO_with_clock_DAQmx`` controller.

Handling of the timing
----------------------

Having a single controller object allows performing the movements of each scanners one after the other, without conflicts in the use of the clock counters by the different scanners. This is achieved by locking the ``AO_with_clock_DAQmx`` controller during the movement of any scanner. When a move command is sent, the ``locked`` attribute of the controller is set to ``True``.
As long as this variable is set to ``True``, no other movement is started. If another scanner gets a command for moving, then it is set to a waiting state (the attribute ``waiting_to_move`` from the scanner plugin is set to ``True``) until the signal ``ni_card_ready_for_moving`` is received from the controller indicating that the movement can resume.

When the movement is over, the scanner plugin received a ``move_done_signal`` from PymoDAQ, which is emitted when the current position is close enough to the current position. This signal is connected to the ``AO_with_clock_DAQmx`` controller, which switches to the unlocked state (``locked`` attribute set back to ``False``) and emits the signal ``ni_card_ready_for_moving``.


Reading the scanner position
----------------------------
Another issue with using a NI card to pilot a piezo scanner is that **one cannot read the current voltage applied at an analog output.** In order to know the current position of the scanner, the solution used here is to **get the current index of the clock** from the NI card, and then display the corresponding position in the list that was sent to the device.

As a consequence, the position is set to 1 nm when restarting the plugin, as the current position cannot be read from the hardware. This might cause quick movements, so be careful to go back to zero before closing the plugin.
56 changes: 56 additions & 0 deletions _sources/user_guide/scanner_use.rst.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
Using the ScannerControl and MultipleScannerControl moves
=========================================================

These plugins allow you to use an analog output of a NI device to control a piezoelectric scanner. It was made for use with Attocube scanners, with an amplifier between the NI card and the scanner, but it should work with any type of scanner that takes a voltage as input.
The main difference between the two is that ``ScannerControl`` cannot reliably be used with the Scan extension. It is therefore recommended to use MultipleScannerControl, which can also control a single scanner. This page is thus focussing on the latter.

The position is set in nm. The primary use of this plugin is to control the XY scanning of an atomic force microscope, meaning that the movement is quite slow on purpose, to avoid damaging the tip. Very fast operation is not tested.

Configuration
-------------

Master
++++++

As you can see on the screenshot below, you need to specify several parameters:

* **Output channel**: the output of the NI card which is connected to the scanner, something like ``Dev[X]/ao[Y]``.

* **Clock channel**: the channel that you will use for timing of the movement, to set a specific movement speed of the scanner, something like ``Dev[X]/ctr[Y]``.

* **Step size**: in nm.

* **Step time**: in ms, the combination of step size and step time sets the moving speed.

* **Conversion factor**: in nm/V, this is the coefficient to convert the voltage at the output of the card into a displacement.

* **Status**: set it to "Master" for the first scanner, the others will be treated as "Slaves" sharing the same clock, see below.

* **Timeout**: in s, be careful to set it large enough for slow movements if needed.

* **Bounds**: in nm, you should set them to the range reachable by your scanner.

.. image:: /images/Xscanner.png
:width: 800

Slave
+++++

As there is a small number of counter/clock channels available on a NI card, you most probably cannot use a different clock channel for each scanner. The MultipleScannerControl plugin allows you to configure scanners as "Slave" of the initial one, as shown in the screenshot below.

.. image:: /images/Yscanner.png
:width: 800

The parameters to set are identical, except that there is no clock channel or step time, as these parameters will be taken from the master scanner. Be careful to set the proper Controller ID.


Use
---

This plugin works as a regular daq move plugin. You will notice that the position never goes to 0 but stays at 1 nm because it was creating errors. **Be careful that when the plugin restarts, the scanner goes back to 1 nm in one single step, as there is no way to read the scanner position from the NI card.**

As mentioned before, this plugin is meant for **slow** movements. If you ask for a position change larger than the step size parameter, a list of positions will be sent to the NI card to perform the movement in several steps, waiting for the duration indicated by step time between each step. Related to this, during a scan, you should avoid making several steps between each pixel, so **it is recommended to set the step size in the scanner configuration to a larger value than the step size in the Scan extension.**

If you need to use one of the clock channel with another plugin, do not forget to stop the movement by clicking on the red square, otherwise you will get an error about the resource being busy. Do it even if the movement looks over.

You might get many warnings in the log about the task being stopped before being finished, do not worry about it, the scanner is still fine. If you know how to solve this, please contribute!
Loading

0 comments on commit b6a4f4d

Please sign in to comment.