Skip to content
Open
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@

from typing import Union, List, Dict
from pymodaq.control_modules.move_utility_classes import (DAQ_Move_base, comon_parameters_fun,
main, DataActuatorType, DataActuator)

from pymodaq_utils.utils import ThreadCommand # object used to send info back to the main thread
from pymodaq_gui.parameter import Parameter


from pymodaq_plugins_teaching.hardware.spectrometer import Spectrometer


class DAQ_Move_Monochromator(DAQ_Move_base):
""" Instrument plugin class for an actuator.

This object inherits all functionalities to communicate with PyMoDAQ’s DAQ_Move module through inheritance via
DAQ_Move_base. It makes a bridge between the DAQ_Move module and the Python wrapper of a particular instrument.

TODO (in the end) Complete the docstring of your plugin with:
* The set of controllers and actuators that should be compatible with this instrument plugin.
* With which instrument and controller it has been tested.
* The version of PyMoDAQ during the test.
* The version of the operating system.
* Installation instructions: what manufacturer’s drivers should be installed to make it run?

Attributes:
-----------
controller: object
The particular object that allow the communication with the hardware, in general a python wrapper around the
hardware library.

# TODO add your particular attributes here if any

"""
is_multiaxes = False # set to True if this plugin is controlled for a multiaxis controller
_axis_names: Union[List[str], Dict[str, int]] = [''] # complete the list, put correct number of axes
_controller_units: Union[str, List[str]] = 'nm' # the correct unit here, it could be a single str (the same one is applied to all axes) or a list of str (as much as the number of axes)
_epsilon: Union[float, List[float]] = 0.1 # a value that is correct depending on your controller it could be a single float of a list of float (as much as the number of axes)
data_actuator_type = DataActuatorType.DataActuator # whether you use the new data style for actuator otherwise set this
# as DataActuatorType.float (or entirely remove the line)

params = [{'title': 'info:', 'name': 'info', 'type': 'str', 'value': '' },
{'title': 'grating:', 'name': 'grating', 'type': 'list', 'value': Spectrometer.gratings[0] }] + comon_parameters_fun(is_multiaxes, axis_names=_axis_names, epsilon=_epsilon)
# _epsilon is the initial default value for the epsilon parameter allowing pymodaq to know if the controller reached
# the target value. It is the developer responsibility to put here a meaningful value

def ini_attributes(self):
# declare the type of the wrapper (and assign it to self.controller) you're going to use for easy
# autocompletion
self.controller: Spectrometer = None

# declare here attributes you want/need to init with a default value
pass

def get_actuator_value(self):
"""Get the current value from the hardware with scaling conversion.

Returns
-------
float: The position obtained after scaling conversion.
"""

pos = DataActuator(data=self.controller.get_wavelength(), units='nm') # when writing your own plugin replace this line
pos = self.get_position_with_scaling(pos)
return pos

def user_condition_to_reach_target(self) -> bool:
""" Implement a condition for exiting the polling mechanism and specifying that the
target value has been reached

Returns
-------
bool: if True, PyMoDAQ considers the target value has been reached
"""
# TODO either delete this method if the usual polling is fine with you, but if need you can
# add here some other condition to be fullfilled either a completely new one or
# using or/and operations between the epsilon_bool and some other custom booleans
# for a usage example see DAQ_Move_brushlessMotor from the Thorlabs plugin
return True

def close(self):

self.controller.close_communication() # when writing your own plugin replace this line

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
"""
## TODO for your custom plugin
if param.name() == 'axis':
self.axis_unit = self.controller.your_method_to_get_correct_axis_unit()
# do this only if you can and if the units are not known beforehand, for instance
# if the motors connected to the controller are of different type (mm, µm, nm, , etc...)
# see BrushlessDCMotor from the thorlabs plugin for an exemple

elif param.name() == "a_parameter_you've_added_in_self.params":
self.controller.your_method_to_apply_this_param_change()

elif param.name() == "grating":
self.controller.your_method_to_apply_this_param_change()

else:
pass

def ini_stage(self, controller=None):
"""Actuator communication initialization

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

Returns
-------
info: str
initialized: bool
False if initialization failed otherwise True
"""

self.ini_stage_init(slave_controller=controller) # will be useful when controller is slave

if self.is_master: # is needed when controller is master
self.controller = Spectrometer() # arguments for instantiation!)
# enter here whatever is needed for your controller initialization and eventual
# opening of the communication channel

info = "Monochromator initialized"
initialized = self.controller.open_communication() #
return info, initialized

def move_abs(self, value: DataActuator):
""" Move the actuator to the absolute target defined by value

Parameters
----------
value: (float) value of the absolute target positioning
"""

value = self.check_bound(value) #if user checked bounds, the defined bounds are applied here
self.target_value = value
value = self.set_position_with_scaling(value) # apply scaling if the user specified one
self.controller.set_wavelength(value.value('nm'),set_type='abs') # when writing your own plugin replace this line
self.emit_status(ThreadCommand('Update_Status', ['Abs move done']))

def move_rel(self, value: DataActuator):
""" Move the actuator to the relative target actuator value defined by value

Parameters
----------
value: (float) value of the relative target positioning
"""
value = self.check_bound(self.current_position + value) - self.current_position
self.target_value = value + self.current_position
value = self.set_position_relative_with_scaling(value)

self.controller.set_wavelength(value.value('nm'),set_type='rel') # when writing your own plugin replace this line
self.emit_status(ThreadCommand('Update_Status', ['Rel move done']))

def move_home(self):
"""Call the reference method of the controller"""

## TODO for your custom plugin
raise NotImplemented # when writing your own plugin remove this line
self.controller.your_method_to_get_to_a_known_reference() # when writing your own plugin replace this line
self.emit_status(ThreadCommand('Update_Status', ['Some info you want to log']))

def stop_motion(self):
"""Stop the actuator and emits move_done signal"""

self.controller.stop() # when writing your own plugin replace this line
self.emit_status(ThreadCommand('Update_Status', ['Motion stopped']))


if __name__ == '__main__':
main(__file__)