Skip to content
Merged
Show file tree
Hide file tree
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
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ name = "pymodaq_plugins_piezoconcept"
description = 'Set of PyMoDAQ plugins for Actuators from Piezoconcept (Tested on the Bio200 XY stage. Include a version of the controller firmware emulating functions from PhysikInstrumente)'

dependencies = [
"pymodaq>=5.0.0",
"pymodaq>=5.0.9",
'pyserial',
'pyvisa',
]
Expand Down Expand Up @@ -51,7 +51,8 @@ classifiers = [
[build-system]
requires = [
"hatchling>=1.9.0",
"hatch-vcs", "toml",
"hatch-vcs",
"toml",
"pymodaq_utils>=0.0.6",
]
build-backend = "hatchling.build"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
from qtpy.QtCore import QThread
from pymodaq.control_modules.move_utility_classes import DAQ_Move_base, comon_parameters_fun, main
from pymodaq.control_modules.move_utility_classes import (DAQ_Move_base, comon_parameters_fun, main,
DataActuatorType, DataActuator)

from pymodaq_plugins_piezoconcept.hardware.piezoconcept.piezoconcept import PiezoConcept, Position, Time
from pymodaq_plugins_piezoconcept.utils import Config

config = Config()

# find available COM ports
import serial.tools.list_ports

ports = [str(port)[0:4] for port in list(serial.tools.list_ports.comports())]
port = config('com_port') if config('com_port') in ports else ports[0] if len(ports) > 0 else ''


class DAQ_Move_PiezoConcept(DAQ_Move_base):
"""
Plugin to drive piezoconcpet XY (Z) stages. There is a string nonlinear offset between the set position and the read
Plugin to drive piezoconcpet XY (Z) stages. There is a nonlinear offset between the set position and the read
position. It seems to bnot be problem in the sens where a given displacement is maintained. But because the read
position is not "accurate", I've decided to ignore it and just trust the set position. So the return will be always
strictly equal to the set position. However, if there is more that 10% difference raise a warning
"""

axis_names = ['X', 'Y', 'Z']
_controller_units = 'µm'
_epsilons = [1, 1, 1]

#find available COM ports
import serial.tools.list_ports
ports = [str(port)[0:4] for port in list(serial.tools.list_ports.comports())]
port = config('com_port') if config('com_port') in ports else ports[0] if len(ports) > 0 else ''
#if ports==[]:
# ports.append('')
_epsilon = 1

is_multiaxes = True
stage_names = ['X', 'Y', 'Z']
min_bound = -95 #*µm
max_bound = 95 #µm
offset = 100 #µm

data_actuator_type = DataActuatorType.DataActuator

params= [{'title': 'Time interval (ms):', 'name': 'time_interval', 'type': 'int', 'value': 200},
{'title': 'Controller Info:', 'name': 'controller_id', 'type': 'text', 'value': '', 'readonly': True},
{'title': 'COM Port:', 'name': 'com_port', 'type': 'list', 'limits': ports, 'value': port},
] + comon_parameters_fun(is_multiaxes, stage_names, epsilon=_epsilon)
] + comon_parameters_fun(axis_names=axis_names)

def ini_attributes(self):
self.controller: PiezoConcept = None
Expand All @@ -43,9 +44,10 @@ def ini_stage(self, controller=None):
"""

"""

self.ini_stage_init(old_controller=controller,
new_controller=PiezoConcept())
if self.is_master:
self.controller = PiezoConcept()
else:
self.controller = controller

controller_id = self.do_init()

Expand All @@ -54,7 +56,7 @@ def ini_stage(self, controller=None):
return info, initialized

def do_init(self) -> str:
if self.settings['multiaxes', 'multi_status'] == "Master":
if self.is_master:
self.controller.init_communication(self.settings['com_port'])

controller_id = self.controller.get_controller_infos()
Expand All @@ -65,29 +67,30 @@ def do_init(self) -> str:
self.settings.child('bounds', 'max_bound').setValue(self.max_bound)
self.settings.child('scaling', 'use_scaling').setValue(True)
self.settings.child('scaling', 'offset').setValue(self.offset)
self.move_abs(0)
self.move_abs(DataActuator(data=0, units=self.axis_unit))
return controller_id

def close(self):
"""
close the current instance of Piezo instrument.
"""
if self.controller is not None:
self.move_abs(0)
self.move_abs(DataActuator(0, units='um'))
QThread.msleep(1000)
self.controller.close_communication()
self.controller = None

def get_actuator_value(self):
def get_actuator_value(self) -> DataActuator:
"""
"""
position = self.controller.get_position(self.settings.child('multiaxes', 'axis').value()) #in mm
pos = position.pos/1000 # in um
pos = self.get_position_with_scaling(pos)
pos: Position = self.controller.get_position(self.axis_name)
position = DataActuator(data=pos.pos,
units='nm' if pos.unit == 'n' else 'um')
position = self.get_position_with_scaling(position)
self.current_position = self.target_position #should be pos but not precise enough conpared to set position
return self.target_position

def move_abs(self, position):
def move_abs(self, position: DataActuator):
"""

Parameters
Expand All @@ -100,39 +103,25 @@ def move_abs(self, position):
"""
position = self.check_bound(position) #limits the position within the specified bounds (-100,100)
self.target_position = position
position = self.set_position_with_scaling(position)

#get positions in controller units
position = self.set_position_with_scaling(position)
pos = Position(self.settings.child('multiaxes', 'axis').value(), int(position*1000), unit='n')
pos = Position(self.axis_name, position.value('nm'), unit='n')
out = self.controller.move_axis('ABS', pos)
#self.move_is_done = True
QThread.msleep(50) #to make sure the closed loop converged

def move_rel(self,position):
"""
Make the hardware relative move of the Piezo instrument from the given position after thread command signal was received in DAQ_Move_main.

=============== ========= =======================
**Parameters** **Type** **Description**

*position* float The absolute position
=============== ========= =======================

See Also
--------
DAQ_Move_base.set_position_with_scaling, DAQ_Move_base.poll_moving
QThread.msleep(50) # to make sure the closed loop converged

def move_rel(self, position: DataActuator):
""" Make the hardware relative move of the Piezo instrument from the given position
"""
position = self.check_bound(self.current_position+position)-self.current_position
self.target_position = position+self.current_position

position = self.set_position_relative_with_scaling(position)

pos = Position(self.settings.child('multiaxes', 'axis').value(), position*1000, unit='n') # always use microns for simplicity
pos = Position(self.axis_name, position.value('nm'), unit='n')
out = self.controller.move_axis('REL', pos)
QThread.msleep(50) # to make sure the closed loop converged


def move_home(self):
"""
Move to the absolute vlue 100 corresponding the default point of the Piezo instrument.
Expand All @@ -141,7 +130,8 @@ def move_home(self):
--------
DAQ_Move_base.move_abs
"""
self.move_abs(100) #put the axis on the middle position so 100µm
self.move_abs(DataActuator(data=100, units='um'))
# put the axis on the middle position so 100µm

def stop_motion(self):
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
title = 'this is the configuration file of the Piezoconcept plugin'

com_port = 'COM6'
com_port = 'COM5'