From bd3bce54a5cbbc12a8cc5d07d73593240a50b2af Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 15 Jan 2020 16:14:28 +0100 Subject: [PATCH 01/10] add Standa 8SMC5 class --- instruments/Standastage.py | 375 ++++++++++++++++++++++++++++++++++--- instruments/delaystage.py | 138 +++++++------- 2 files changed, 424 insertions(+), 89 deletions(-) diff --git a/instruments/Standastage.py b/instruments/Standastage.py index 07e1904..9ecf941 100644 --- a/instruments/Standastage.py +++ b/instruments/Standastage.py @@ -5,28 +5,355 @@ @author: vgrigore """ +import sys, os +import platform import ctypes -mydll=ctypes.cdll.LoadLibrary('USMCDLL.dll') - -class USMC_Devices(ctypes.Structure): - """Wrapper class for USMC_Devices structure. - - Attributes - ---------- - NOD : int - Number of stepper motor controllers (axes). - Serial : list of strings - List containing the serial numbers of all controllers. - Version : list of string - List containing the version number of all controllers. - - """ - _fields_ = [ - ("NOD", ctypes.wintypes.DWORD), - ("Serial", ctypes.POINTER(ctypes.c_char_p)), - ("Version", ctypes.POINTER(ctypes.c_char_p)), - ] - -a=USMC_Devices() -mydll.USMC_Init(a) -print(a.NOD) \ No newline at end of file +from ctypes import byref, cast, POINTER, c_int, string_at +import time +import platform +import tempfile +import re +import numpy as np +import logging +from utilities.exceptions import DeviceNotFoundError +from instruments.delaystage import DelayStage, StageError + +ximc_dir = 'E:/STANDA_TESTS/ximc-2.10.5/ximc/' +ximc_package_dir = os.path.join(ximc_dir, "crossplatform", "wrappers", "python") +sys.path.append(ximc_package_dir) +if platform.system() == "Windows": + arch_dir = "win64" if "64" in platform.architecture()[0] else "win32" + libdir = os.path.join(ximc_dir, arch_dir) + os.environ["Path"] = libdir + ";" + os.environ["Path"] # add dll + +try: + import pyximc + + lib = pyximc.lib +except ImportError as err: + print( + "Can't import pyximc module. The most probable reason is that you changed the relative location of the testpython.py and pyximc.py files. See developers' documentation for details.") +except OSError as err: + print( + "Can't load libximc library. Please add all shared libraries to the appropriate places. It is decribed in detail in developers' documentation. On Linux make sure you installed libximc-dev package.\nmake sure that the architecture of the system and the interpreter is the same") + + +class StandaStage_8SMC5(DelayStage): + + + def __init__(self): + super(StandaStage_8SMC5, self).__init__() + self.logger = logging.getLogger('{}.Standa_8SMC5'.format(__name__)) + self.logger.info('Created new instance') + self.step_to_um_factor = 1.25 + self.step_to_ps_factor = 2 * 0.00333564 * self.step_to_um_factor + self.max_speed = 1000 + self.pos_zero = 0 + self.pos_max = 10000 + self.pos_min = 0 + self._devenum = None + self.device_number = None + self.dev_id = None + + def step_to_um(self, pos, uPos): + return (pos + uPos / 256) * self.step_to_um_factor + + def step_to_ps(self, pos, uPos): + return (pos + uPos / 256) * self.step_to_ps_factor + + def um_to_step(self, val): + pos = int(val // self.step_to_um_factor) + uPos = int((val % self.step_to_um_factor) * 256) + return pos, uPos + + def ps_to_step(self, val): + pos = int(val // self.step_to_ps_factor) + uPos = int((val % self.step_to_ps_factor) * 256) + return pos, uPos + + def connect(self, device_number=None): + if device_number is not None: + self.device_number = device_number + if self._devenum is None: + self._devenum = self.get_device_list() + + open_name = lib.get_device_name(self._devenum, self.device_number) + self.dev_id = lib.open_device(open_name) + self.logger.debug("Device id: " + repr(self.dev_id)) + result = lib.get_device_information(self.dev_id, byref(pyximc.device_information_t())) + if result == 0: + self.logger.debug("Connected to device ID: {}".format(self.dev_id)) + + def disconnect(self): + lib.close_device(byref(cast(self.dev_id, POINTER(c_int)))) + self.logger.debug("Disconnected stage ID: {}".format(self.dev_id)) + + def move_absolute(self, new_position, unit='ps'): + """ move stage to given position, expressed in the defined units ,relative to zero_position""" + # new_position += self.zero_position # uncomment to use zero position + if unit == 'ps': + pos,uPos = self.ps_to_step(new_position) + elif unit == 'um': + pos,uPos = self.um_to_step(new_position) + else: + raise ValueError('Could not understand {} as unit. please use ps (picoseconds) or um (micrometers)'.format(unit)) + self.logger.debug("Move Absolute dev{} to {} {}".format(self.dev_id,new_position, unit)) + self._move_to(pos,uPos) + + + def move_relative(self, distance,unit='ps'): + """ Evaluate shift in unit of stepper motor steps, and go there.""" + + cpos,cuPos = self._get_current_position() + if unit == 'ps': + pos, uPos = self.ps_to_step(distance) + elif unit == 'um': + pos, uPos = self.um_to_step(distance) + else: + raise ValueError('Could not understand {} as unit. please use ps (picoseconds) or um (micrometers)'.format(unit)) + self.logger.debug("Move relative dev{} by {} {}".format(self.dev_id,distance, unit)) + + self._move_to(cpos+pos, cuPos+uPos) + + def _move_to(self, pos, uPos=0): + """ Move stage to the indicated position. In units of steps and microsteps.""" + uPos = uPos % 256 + pos = pos + uPos // 256 + result = lib.command_move(self.dev_id, pos, uPos) + if result == 0: + cur_pos, cur_uPos = self._get_current_position() + d = np.abs(pos - cur_pos) + ud = np.abs(uPos - cur_uPos) + wait = (d + ud / 256) / self.speed + .1 + self.logger.debug('Stage{} moved by {}.{}, to {}.{}. Waiting {}s'.format(self.dev_id,d,ud,pos,uPos,wait)) + time.sleep(wait) + else: + raise StageError('Standa stage error code {}'.format(result)) + + + def set_zero_position(self): #TODO: implement zero positioning. + raise NotImplementedError + # print('Zero position set to ' + str(self.position_current)) + # self.pos_zero = self.position_current + # self.position_max = self.position_max - self.position_current + # self.position_min = self.position_min - self.position_current + # self.position_current = 0 + + def _get_current_position(self): + x_pos = pyximc.get_position_t() + result = lib.get_position(self.dev_id, byref(x_pos)) + if self.error_lookup(result): + pos = x_pos.Position + uPos = x_pos.uPosition + self.logger.debug('dev_{} @ position: {}.{} steps'.format(self.dev_id,pos,uPos)) + return pos,uPos + + @property + def position_um(self): + pos, upos = self._get_current_position() + return self.step_to_um(pos, upos) + + @position_um.setter + def position_um(self, val): + pos, uPos = self.um_to_step(val) + self._move_to(pos, uPos) + + @property + def position_ps(self): + pos, upos = self._get_current_position() + return self.step_to_ps(pos, upos) + + @position_ps.setter + def position_ps(self, val): + pos, uPos = self.ps_to_step(val) + self._move_to(pos, uPos) + + @property + def position_step(self): + pos, upos = self._get_current_position() + return pos, upos + + @position_step.setter + def position_step(self, step,uStep): + self._move_to(step, uStep) + + @property + def serial(self): + x_serial = ctypes.c_uint() + result = lib.get_serial_number(self.dev_id, byref(x_serial)) + if self.error_lookup(result): + return (repr(x_serial.value)) + + @property + def speed(self): + mvst = pyximc.move_settings_t() + result = lib.get_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + return mvst.Speed + + @speed.setter + def speed(self, val): + assert 0 < val < self.max_speed + mvst = pyximc.move_settings_t() + result = lib.get_move_settings(self.dev_id, byref(mvst)) + mvst.Speed = int(val) + result = lib.set_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + print('Speed set to {} step/s'.format(val)) + + @property + def uSpeed(self): + mvst = pyximc.move_settings_t() + result = lib.get_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + return mvst.uSpeed + + @uSpeed.setter + def uSpeed(self, val): + mvst = pyximc.move_settings_t() + mvst.uSpeed = int(val) + result = lib.set_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + print('uSpeed set to {} uStep/s'.format(val)) + + @property + def acceleration(self): + mvst = pyximc.move_settings_t() + result = lib.get_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + return mvst.Accel + + @acceleration.setter + def acceleration(self, val): + mvst = pyximc.move_settings_t() + mvst.Accel = int(val) + result = lib.set_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + print('Acceleration changed to {}'.format(val)) + + @property + def deceleration(self): + mvst = pyximc.move_settings_t() + result = lib.get_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + return mvst.Decel + + @deceleration.setter + def deceleration(self, val): + mvst = pyximc.move_settings_t() + mvst.Decel = int(val) + result = lib.set_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + print('Deceleration changed to {}'.format(val)) + + def error_lookup(self, id): + if id == 0: + return True + elif id == -1: + raise Exception('Standa stage error code {}'.format(id)) + elif id == -2: + raise NotImplementedError('Standa stage error code {}'.format(id)) + elif id == -3: + raise ValueError('Standa stage error code {}'.format(id)) + elif id == -4: + raise DeviceNotFoundError('Standa stage error code {}'.format(id)) + + @staticmethod + def get_device_list(): + """ Find all available devices and return the enumeration of them.""" + probe_flags = pyximc.EnumerateFlags.ENUMERATE_PROBE # + EnumerateFlags.ENUMERATE_NETWORK + enum_hints = b"addr=192.168.0.1,172.16.2.3" + devenum = lib.enumerate_devices(probe_flags, enum_hints) + dev_count = lib.get_device_count(devenum) + print("Device count: " + repr(dev_count)) + controller_name = pyximc.controller_name_t() + for dev_ind in range(0, dev_count): + enum_name = lib.get_device_name(devenum, dev_ind) + result = lib.get_enumerate_device_controller_name(devenum, dev_ind, byref(controller_name)) + if result == pyximc.Result.Ok: + print("Enumerated device #{} name (port name): ".format(dev_ind) + repr( + enum_name) + ". Friendly name: " + repr(controller_name.ControllerName) + ".") + + return devenum + + def device_info(self): + if self.dev_id is not None: + x_device_information = pyximc.device_information_t() + result = lib.get_device_information(self.dev_id, byref(x_device_information)) + if self.error_lookup(result): + print('Device info:') + print("Device information:") + print(" Manufacturer: " + + repr(string_at(x_device_information.Manufacturer).decode())) + print(" ManufacturerId: " + + repr(string_at(x_device_information.ManufacturerId).decode())) + print(" ProductDescription: " + + repr(string_at(x_device_information.ProductDescription).decode())) + print(" Major: " + repr(x_device_information.Major)) + print(" Minor: " + repr(x_device_information.Minor)) + print(" Release: " + repr(x_device_information.Release)) + else: + print('no device selected yet') + + def get_device_status(self): + if self.dev_id is not None: + x_status = pyximc.status_t() + result = lib.get_status(self.dev_id, byref(x_status)) + if self.error_lookup(result): + fields = [x for x in dir(x_status) if '_' not in x] + status = {} + for field in fields: + status[field] = repr(getattr(x_status,field)) + else: + print('no device selected yet') + + def print_device_status(self): + d = self.get_device_status() + if d is not None: + print('Status of device {}'.format(self.dev_id)) + for key,val in d.items(): + print(' - {}: {}'.format(key,val)) + + +if __name__ == "__main__": + import logging + from logging.config import fileConfig + + logging.basicConfig(format='%(levelname)s | %(message)s', level=logging.DEBUG)#, filename='example.log') + logger = logging.getLogger(__name__) + logger.setLevel(logging.DEBUG) + logger.debug('Started logger') + + + + sc = StandaStage_8SMC5() + sc.connect(0) + sc.print_device_status() + print('Current speed settings: {}'.format(sc.speed)) + setspeed = 900 + sc.speed = setspeed + print('Speed changed to {} speed settings reads: {}\n'.format(setspeed,sc.speed)) + + print('\ncurrent pos: {} ps | {} um| {},{} step \n'.format(sc.position_ps,sc.position_um,*sc.position_step)) + moveby = -1#ps + print('move by {} ps'.format(sc.ps_to_step(moveby))) + sc.move_relative(moveby,unit='ps') + print('\ncurrent pos: {} ps | {} um| {},{} step \n'.format(sc.position_ps,sc.position_um,*sc.position_step)) + # + positions = np.linspace(100,110,1) + print(positions) + y = [] + for pos in positions: + print('going to pos {}'.format(pos)) + sc.move_absolute(pos) + y.append(sc.position_ps) + # import matplotlib.pyplot as plt + # plt.figure() + # plt.plot(positions,y) + # plt.show() + # TODO: try improve precision with accel and decel + for vv in zip(positions,y,(y-positions)*1000): + print(*vv,sep=' | ') + # print('---- Y ----\n',*y,sep='\n') + # print(*positions,sep='\n') + sc.disconnect() diff --git a/instruments/delaystage.py b/instruments/delaystage.py index 3e6cfb4..eef99b3 100644 --- a/instruments/delaystage.py +++ b/instruments/delaystage.py @@ -21,15 +21,20 @@ """ import time -import sys +import sys, os + try: import thorlabs_apt as apt except: print("no thorlabs_apt found") -sys.path.insert(0,'./..') +sys.path.insert(0, './..') + +from instruments import generic -from instruments import generic -#import _PyUSMC as _PyUSMC +try: + import _PyUSMC as _PyUSMC +except: + pass try: import clr @@ -83,11 +88,10 @@ def set_zero_position(self): self.position_min = self.position_min - self.position_current self.position_current = 0 - def position_get(self): return self.position_current -#%% + class NewportXPS(DelayStage): def __init__(self): @@ -167,94 +171,98 @@ def XPS_GetControllerState(self, myXPS, flag): else: print('ControllerStatusGet Error => ', errString) return result, state -#%%standa stage - + + class StandaStage(DelayStage): def __init__(self): - #super(StandaStage, self).__init__() - self.standa=_PyUSMC.StepperMotorController() - self.stage_N=0 - self.mm_in_step=0.000325 #depend on your stage typ: 0.000125 for standa 055709; 0.000325 for standa 026424 - + # super(StandaStage, self).__init__() + self.standa = _PyUSMC.StepperMotorController() + self.stage_N = 0 + self.mm_in_step = 0.000325 # depend on your stage typ: 0.000125 for standa 055709; 0.000325 for standa 026424 + def connect(self): self.standa.Init() - print(str(len(self.standa.motors))+' stages were connected. Change self.stage_N to switch between stages') - self.motor=self.standa.motors[self.stage_N] - + print(str(len(self.standa.motors)) + ' stages were connected. Change self.stage_N to switch between stages') + self.motor = self.standa.motors[self.stage_N] + self.motor.position.maxSpeed = 500.0 - + # Set controller parameters self.motor.parameters.Set( - MaxTemp = 70.0, - AccelT = 200.0, - DecelT = 200.0, - BTimeout1 = 0.0, - BTimeout2 = 1000.0, - BTimeout3 = 1000.0, - BTimeout4 = 1000.0, - BTO1P = 10.0, - BTO2P = 100.0, - BTO3P = 400.0, - BTO4P = 800.0, - MinP = 500.0, - BTimeoutR = 500.0, - LoftPeriod = 500.0, - RTDelta = 200, - RTMinError = 15, - EncMult = 2.5, - MaxLoft = 32, - PTimeout = 100.0, - SynOUTP = 1) + MaxTemp=70.0, + AccelT=200.0, + DecelT=200.0, + BTimeout1=0.0, + BTimeout2=1000.0, + BTimeout3=1000.0, + BTimeout4=1000.0, + BTO1P=10.0, + BTO2P=100.0, + BTO3P=400.0, + BTO4P=800.0, + MinP=500.0, + BTimeoutR=500.0, + LoftPeriod=500.0, + RTDelta=200, + RTMinError=15, + EncMult=2.5, + MaxLoft=32, + PTimeout=100.0, + SynOUTP=1) # Set start parameters self.motor.startParameters.Set( - SDivisor = 8, - DefDir = False, - LoftEn = False, - SlStart = False, - WSyncIN = False, - SyncOUTR = False, - ForceLoft = False) - + SDivisor=8, + DefDir=False, + LoftEn=False, + SlStart=False, + WSyncIN=False, + SyncOUTR=False, + ForceLoft=False) + # Power on self.motor.mode.PowerOn() - + def move_absolute(self, new_position): - self.motor.Start(int(new_position/self.mm_in_step)) + self.motor.Start(int(new_position / self.mm_in_step)) self.position_current = new_position - + def position_get(self): '''returns current position in mm (accurding to the mm in step parametr)''' - self.position_current =self.motor.GetPos()*self.mm_in_step - print(self.motor.GetPos()*self.mm_in_step) - return self.motor.GetPos()*self.mm_in_step - + self.position_current = self.motor.GetPos() * self.mm_in_step + print(self.motor.GetPos() * self.mm_in_step) + return self.motor.GetPos() * self.mm_in_step + def disconnect(self): self.standa.StopMotors(True) self.standa.Close() - - - - -class ThorLabs_rotational_stage(DelayStage): #added by Amon sorry if not good + + +class StageError(Exception): + pass + + +class ThorLabs_rotational_stage(DelayStage): # added by Amon sorry if not good def __init__(self): - #super(StandaStage, self).__init__() - self.serial_N=27504383 - + # super(StandaStage, self).__init__() + self.serial_N = 27504383 + def connect(self): - self.serial_N=apt.list_available_devices()[0][1] - self.motor=apt.Motor(self.serial_N) + self.serial_N = apt.list_available_devices()[0][1] + self.motor = apt.Motor(self.serial_N) self.motor.disable() self.motor.enable() - #self.motor.move_home() + # self.motor.move_home() while self.motor.is_in_motion: time.sleep(1) - def move_absolute(self,position): + + def move_absolute(self, position): while self.motor.is_in_motion: time.sleep(1) self.motor.move_to(position) while self.motor.is_in_motion: time.sleep(1) + def disconnect(self): pass - #self.motor.disable() \ No newline at end of file + # self.motor.disable() From ab06aca7147b766ad087ba478518e79181b6e930 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 15 Jan 2020 16:15:12 +0100 Subject: [PATCH 02/10] add default settings add default settings --- FastScan.py | 4 +++- utilities/defaultSETTINGS.ini | 42 +++++++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/FastScan.py b/FastScan.py index 1ff94a2..098cd52 100644 --- a/FastScan.py +++ b/FastScan.py @@ -47,7 +47,9 @@ def main(): sys.excepthook = my_exception_hook # create main logger - fileConfig('./cfg/logging_config.ini') + # fileConfig('./cfg/logging_config.ini') + fileConfig('./SETTINGS.ini') + logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) logger.debug('Started logger') diff --git a/utilities/defaultSETTINGS.ini b/utilities/defaultSETTINGS.ini index 71e686c..4f2309f 100644 --- a/utilities/defaultSETTINGS.ini +++ b/utilities/defaultSETTINGS.ini @@ -19,24 +19,58 @@ shaker_ps_per_step = 0.05 shaker_gain = 1 acquisition_mode = triggered dark_control = True +use_r0 = False n_processors = 6 -n_averages = 200 +n_averages = 50 [fastscan - simulation] function = sech2_fwhm -amplitude = 0.5 +amplitude = 1 center_position = -1. fwhm = 0.085 offset = 1 -shaker_amplitude = 5 +shaker_amplitude = 100 [ni_signal_channels] shaker_position = Dev1/ai0 signal = Dev1/ai1 -dark_control = Dev1/ai2 +darkcontrol = Dev1/ai2 reference = Dev1/ai3 [ni_trigger_channels] shaker_trigger = /Dev1/PFI1 laser_trigger = /Dev1/PFI0 +[loggers] +keys=root + +[handlers] +keys=stream_handler,file_handler + +[formatters] +keys=stream_formatter,file_formatter + +[logger_root] +level=DEBUG +handlers=stream_handler,file_handler + +[handler_stream_handler] +class=StreamHandler +level=DEBUG +formatter=stream_formatter +args=(sys.stdout,) + +[handler_file_handler] +class=FileHandler +level=DEBUG +formatter=file_formatter +args=('./cfg/debug_log.log','w+') + +[formatter_stream_formatter] +format=%(asctime)s.%(msecs)03d |%(levelname)-8s| %(name)-30s| %(message)s +datefmt=%H:%M:%S + +[formatter_file_formatter] +format=%(asctime)s |%(levelname)-8s| %(name)-12s %(levelname)-8s %(message)s + + From b498ea7e72732575342bd7d9bf329a0496c74904 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 15 Jan 2020 16:15:40 +0100 Subject: [PATCH 03/10] projector nan fix --- measurement/cscripts/projectPy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/measurement/cscripts/projectPy.py b/measurement/cscripts/projectPy.py index c3c48a4..a20eb18 100644 --- a/measurement/cscripts/projectPy.py +++ b/measurement/cscripts/projectPy.py @@ -53,7 +53,7 @@ def project_r0(spos,signal,dark_control,reference,use_dark_control): result_ref[spos[i]-pos_min] += reference[i] norm_array[spos[i]-pos_min] += 1. - r0 = np.mean(np.nan_to_num(result_ref/norm_array)) + r0 = np.nanmean(result_ref/norm_array) return result_val/(norm_array*r0) From 53583ef30f1cca4fccf58b68ba31b48bcd8edd14 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 15 Jan 2020 16:20:42 +0100 Subject: [PATCH 04/10] update ignore list --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 5d5ff07..badadca 100644 --- a/.gitignore +++ b/.gitignore @@ -110,3 +110,5 @@ ENV/ # PyCharm project settings .idea + +instruments/standa_prove.py From 3b995504d3d58fe77cab0ce018300cb75296d750 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 15 Jan 2020 16:21:10 +0100 Subject: [PATCH 05/10] assign standa stage to measurement code --- measurement/fastscan.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/measurement/fastscan.py b/measurement/fastscan.py index c5c9b7c..ef45e99 100644 --- a/measurement/fastscan.py +++ b/measurement/fastscan.py @@ -43,6 +43,7 @@ from scipy.optimize import curve_fit from instruments.cryostat import ITC503s as Cryostat +from instruments.Standastage import StandaStage_8SMC5 from utilities.math import sech2_fwhm, sin, gaussian_fwhm, gaussian, transient_1expdec, update_average from utilities.settings import parse_setting, parse_category, write_setting try: @@ -94,7 +95,7 @@ def __init__(self): self.spos_fit_pars = None # initialize the fit parameters for shaker position self.cryo = Cryostat(parse_setting('instruments','cryostat_com')) - # self.delay_stage = DelayStage() + self.delay_stage = StandaStage_8SMC5() self.timer = QtCore.QTimer() self.timer.setInterval(1) From 75f4d2cfa036a7be0993ce421434669c73685dde Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 15 Jan 2020 16:41:05 +0100 Subject: [PATCH 06/10] reorganize instruments --- .gitignore | 2 +- instruments/Standastage.py | 359 ------ instruments/delaystage.py | 268 ----- instruments/{ => delaystage}/_PyUSMC.py | 1468 +++++++++++------------ instruments/delaystage/__init__.py | 29 + instruments/delaystage/generic.py | 29 + instruments/delaystage/newport.py | 29 + instruments/delaystage/standa.py | 29 + instruments/delaystage/thorlabs.py | 29 + measurement/fastscan.py | 2 +- {instruments => tests}/SetupTest.py | 224 ++-- {instruments => tests}/plt.py | 198 +-- {instruments => tests}/thorlabs.py | 26 +- 13 files changed, 1105 insertions(+), 1587 deletions(-) delete mode 100644 instruments/Standastage.py delete mode 100644 instruments/delaystage.py rename instruments/{ => delaystage}/_PyUSMC.py (96%) create mode 100644 instruments/delaystage/__init__.py create mode 100644 instruments/delaystage/generic.py create mode 100644 instruments/delaystage/newport.py create mode 100644 instruments/delaystage/standa.py create mode 100644 instruments/delaystage/thorlabs.py rename {instruments => tests}/SetupTest.py (95%) rename {instruments => tests}/plt.py (96%) rename {instruments => tests}/thorlabs.py (94%) diff --git a/.gitignore b/.gitignore index badadca..820848b 100644 --- a/.gitignore +++ b/.gitignore @@ -111,4 +111,4 @@ ENV/ .idea -instruments/standa_prove.py +tests/standa_prove.py diff --git a/instruments/Standastage.py b/instruments/Standastage.py deleted file mode 100644 index 9ecf941..0000000 --- a/instruments/Standastage.py +++ /dev/null @@ -1,359 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Apr 26 20:04:53 2019 - -@author: vgrigore -""" - -import sys, os -import platform -import ctypes -from ctypes import byref, cast, POINTER, c_int, string_at -import time -import platform -import tempfile -import re -import numpy as np -import logging -from utilities.exceptions import DeviceNotFoundError -from instruments.delaystage import DelayStage, StageError - -ximc_dir = 'E:/STANDA_TESTS/ximc-2.10.5/ximc/' -ximc_package_dir = os.path.join(ximc_dir, "crossplatform", "wrappers", "python") -sys.path.append(ximc_package_dir) -if platform.system() == "Windows": - arch_dir = "win64" if "64" in platform.architecture()[0] else "win32" - libdir = os.path.join(ximc_dir, arch_dir) - os.environ["Path"] = libdir + ";" + os.environ["Path"] # add dll - -try: - import pyximc - - lib = pyximc.lib -except ImportError as err: - print( - "Can't import pyximc module. The most probable reason is that you changed the relative location of the testpython.py and pyximc.py files. See developers' documentation for details.") -except OSError as err: - print( - "Can't load libximc library. Please add all shared libraries to the appropriate places. It is decribed in detail in developers' documentation. On Linux make sure you installed libximc-dev package.\nmake sure that the architecture of the system and the interpreter is the same") - - -class StandaStage_8SMC5(DelayStage): - - - def __init__(self): - super(StandaStage_8SMC5, self).__init__() - self.logger = logging.getLogger('{}.Standa_8SMC5'.format(__name__)) - self.logger.info('Created new instance') - self.step_to_um_factor = 1.25 - self.step_to_ps_factor = 2 * 0.00333564 * self.step_to_um_factor - self.max_speed = 1000 - self.pos_zero = 0 - self.pos_max = 10000 - self.pos_min = 0 - self._devenum = None - self.device_number = None - self.dev_id = None - - def step_to_um(self, pos, uPos): - return (pos + uPos / 256) * self.step_to_um_factor - - def step_to_ps(self, pos, uPos): - return (pos + uPos / 256) * self.step_to_ps_factor - - def um_to_step(self, val): - pos = int(val // self.step_to_um_factor) - uPos = int((val % self.step_to_um_factor) * 256) - return pos, uPos - - def ps_to_step(self, val): - pos = int(val // self.step_to_ps_factor) - uPos = int((val % self.step_to_ps_factor) * 256) - return pos, uPos - - def connect(self, device_number=None): - if device_number is not None: - self.device_number = device_number - if self._devenum is None: - self._devenum = self.get_device_list() - - open_name = lib.get_device_name(self._devenum, self.device_number) - self.dev_id = lib.open_device(open_name) - self.logger.debug("Device id: " + repr(self.dev_id)) - result = lib.get_device_information(self.dev_id, byref(pyximc.device_information_t())) - if result == 0: - self.logger.debug("Connected to device ID: {}".format(self.dev_id)) - - def disconnect(self): - lib.close_device(byref(cast(self.dev_id, POINTER(c_int)))) - self.logger.debug("Disconnected stage ID: {}".format(self.dev_id)) - - def move_absolute(self, new_position, unit='ps'): - """ move stage to given position, expressed in the defined units ,relative to zero_position""" - # new_position += self.zero_position # uncomment to use zero position - if unit == 'ps': - pos,uPos = self.ps_to_step(new_position) - elif unit == 'um': - pos,uPos = self.um_to_step(new_position) - else: - raise ValueError('Could not understand {} as unit. please use ps (picoseconds) or um (micrometers)'.format(unit)) - self.logger.debug("Move Absolute dev{} to {} {}".format(self.dev_id,new_position, unit)) - self._move_to(pos,uPos) - - - def move_relative(self, distance,unit='ps'): - """ Evaluate shift in unit of stepper motor steps, and go there.""" - - cpos,cuPos = self._get_current_position() - if unit == 'ps': - pos, uPos = self.ps_to_step(distance) - elif unit == 'um': - pos, uPos = self.um_to_step(distance) - else: - raise ValueError('Could not understand {} as unit. please use ps (picoseconds) or um (micrometers)'.format(unit)) - self.logger.debug("Move relative dev{} by {} {}".format(self.dev_id,distance, unit)) - - self._move_to(cpos+pos, cuPos+uPos) - - def _move_to(self, pos, uPos=0): - """ Move stage to the indicated position. In units of steps and microsteps.""" - uPos = uPos % 256 - pos = pos + uPos // 256 - result = lib.command_move(self.dev_id, pos, uPos) - if result == 0: - cur_pos, cur_uPos = self._get_current_position() - d = np.abs(pos - cur_pos) - ud = np.abs(uPos - cur_uPos) - wait = (d + ud / 256) / self.speed + .1 - self.logger.debug('Stage{} moved by {}.{}, to {}.{}. Waiting {}s'.format(self.dev_id,d,ud,pos,uPos,wait)) - time.sleep(wait) - else: - raise StageError('Standa stage error code {}'.format(result)) - - - def set_zero_position(self): #TODO: implement zero positioning. - raise NotImplementedError - # print('Zero position set to ' + str(self.position_current)) - # self.pos_zero = self.position_current - # self.position_max = self.position_max - self.position_current - # self.position_min = self.position_min - self.position_current - # self.position_current = 0 - - def _get_current_position(self): - x_pos = pyximc.get_position_t() - result = lib.get_position(self.dev_id, byref(x_pos)) - if self.error_lookup(result): - pos = x_pos.Position - uPos = x_pos.uPosition - self.logger.debug('dev_{} @ position: {}.{} steps'.format(self.dev_id,pos,uPos)) - return pos,uPos - - @property - def position_um(self): - pos, upos = self._get_current_position() - return self.step_to_um(pos, upos) - - @position_um.setter - def position_um(self, val): - pos, uPos = self.um_to_step(val) - self._move_to(pos, uPos) - - @property - def position_ps(self): - pos, upos = self._get_current_position() - return self.step_to_ps(pos, upos) - - @position_ps.setter - def position_ps(self, val): - pos, uPos = self.ps_to_step(val) - self._move_to(pos, uPos) - - @property - def position_step(self): - pos, upos = self._get_current_position() - return pos, upos - - @position_step.setter - def position_step(self, step,uStep): - self._move_to(step, uStep) - - @property - def serial(self): - x_serial = ctypes.c_uint() - result = lib.get_serial_number(self.dev_id, byref(x_serial)) - if self.error_lookup(result): - return (repr(x_serial.value)) - - @property - def speed(self): - mvst = pyximc.move_settings_t() - result = lib.get_move_settings(self.dev_id, byref(mvst)) - if self.error_lookup(result): - return mvst.Speed - - @speed.setter - def speed(self, val): - assert 0 < val < self.max_speed - mvst = pyximc.move_settings_t() - result = lib.get_move_settings(self.dev_id, byref(mvst)) - mvst.Speed = int(val) - result = lib.set_move_settings(self.dev_id, byref(mvst)) - if self.error_lookup(result): - print('Speed set to {} step/s'.format(val)) - - @property - def uSpeed(self): - mvst = pyximc.move_settings_t() - result = lib.get_move_settings(self.dev_id, byref(mvst)) - if self.error_lookup(result): - return mvst.uSpeed - - @uSpeed.setter - def uSpeed(self, val): - mvst = pyximc.move_settings_t() - mvst.uSpeed = int(val) - result = lib.set_move_settings(self.dev_id, byref(mvst)) - if self.error_lookup(result): - print('uSpeed set to {} uStep/s'.format(val)) - - @property - def acceleration(self): - mvst = pyximc.move_settings_t() - result = lib.get_move_settings(self.dev_id, byref(mvst)) - if self.error_lookup(result): - return mvst.Accel - - @acceleration.setter - def acceleration(self, val): - mvst = pyximc.move_settings_t() - mvst.Accel = int(val) - result = lib.set_move_settings(self.dev_id, byref(mvst)) - if self.error_lookup(result): - print('Acceleration changed to {}'.format(val)) - - @property - def deceleration(self): - mvst = pyximc.move_settings_t() - result = lib.get_move_settings(self.dev_id, byref(mvst)) - if self.error_lookup(result): - return mvst.Decel - - @deceleration.setter - def deceleration(self, val): - mvst = pyximc.move_settings_t() - mvst.Decel = int(val) - result = lib.set_move_settings(self.dev_id, byref(mvst)) - if self.error_lookup(result): - print('Deceleration changed to {}'.format(val)) - - def error_lookup(self, id): - if id == 0: - return True - elif id == -1: - raise Exception('Standa stage error code {}'.format(id)) - elif id == -2: - raise NotImplementedError('Standa stage error code {}'.format(id)) - elif id == -3: - raise ValueError('Standa stage error code {}'.format(id)) - elif id == -4: - raise DeviceNotFoundError('Standa stage error code {}'.format(id)) - - @staticmethod - def get_device_list(): - """ Find all available devices and return the enumeration of them.""" - probe_flags = pyximc.EnumerateFlags.ENUMERATE_PROBE # + EnumerateFlags.ENUMERATE_NETWORK - enum_hints = b"addr=192.168.0.1,172.16.2.3" - devenum = lib.enumerate_devices(probe_flags, enum_hints) - dev_count = lib.get_device_count(devenum) - print("Device count: " + repr(dev_count)) - controller_name = pyximc.controller_name_t() - for dev_ind in range(0, dev_count): - enum_name = lib.get_device_name(devenum, dev_ind) - result = lib.get_enumerate_device_controller_name(devenum, dev_ind, byref(controller_name)) - if result == pyximc.Result.Ok: - print("Enumerated device #{} name (port name): ".format(dev_ind) + repr( - enum_name) + ". Friendly name: " + repr(controller_name.ControllerName) + ".") - - return devenum - - def device_info(self): - if self.dev_id is not None: - x_device_information = pyximc.device_information_t() - result = lib.get_device_information(self.dev_id, byref(x_device_information)) - if self.error_lookup(result): - print('Device info:') - print("Device information:") - print(" Manufacturer: " + - repr(string_at(x_device_information.Manufacturer).decode())) - print(" ManufacturerId: " + - repr(string_at(x_device_information.ManufacturerId).decode())) - print(" ProductDescription: " + - repr(string_at(x_device_information.ProductDescription).decode())) - print(" Major: " + repr(x_device_information.Major)) - print(" Minor: " + repr(x_device_information.Minor)) - print(" Release: " + repr(x_device_information.Release)) - else: - print('no device selected yet') - - def get_device_status(self): - if self.dev_id is not None: - x_status = pyximc.status_t() - result = lib.get_status(self.dev_id, byref(x_status)) - if self.error_lookup(result): - fields = [x for x in dir(x_status) if '_' not in x] - status = {} - for field in fields: - status[field] = repr(getattr(x_status,field)) - else: - print('no device selected yet') - - def print_device_status(self): - d = self.get_device_status() - if d is not None: - print('Status of device {}'.format(self.dev_id)) - for key,val in d.items(): - print(' - {}: {}'.format(key,val)) - - -if __name__ == "__main__": - import logging - from logging.config import fileConfig - - logging.basicConfig(format='%(levelname)s | %(message)s', level=logging.DEBUG)#, filename='example.log') - logger = logging.getLogger(__name__) - logger.setLevel(logging.DEBUG) - logger.debug('Started logger') - - - - sc = StandaStage_8SMC5() - sc.connect(0) - sc.print_device_status() - print('Current speed settings: {}'.format(sc.speed)) - setspeed = 900 - sc.speed = setspeed - print('Speed changed to {} speed settings reads: {}\n'.format(setspeed,sc.speed)) - - print('\ncurrent pos: {} ps | {} um| {},{} step \n'.format(sc.position_ps,sc.position_um,*sc.position_step)) - moveby = -1#ps - print('move by {} ps'.format(sc.ps_to_step(moveby))) - sc.move_relative(moveby,unit='ps') - print('\ncurrent pos: {} ps | {} um| {},{} step \n'.format(sc.position_ps,sc.position_um,*sc.position_step)) - # - positions = np.linspace(100,110,1) - print(positions) - y = [] - for pos in positions: - print('going to pos {}'.format(pos)) - sc.move_absolute(pos) - y.append(sc.position_ps) - # import matplotlib.pyplot as plt - # plt.figure() - # plt.plot(positions,y) - # plt.show() - # TODO: try improve precision with accel and decel - for vv in zip(positions,y,(y-positions)*1000): - print(*vv,sep=' | ') - # print('---- Y ----\n',*y,sep='\n') - # print(*positions,sep='\n') - sc.disconnect() diff --git a/instruments/delaystage.py b/instruments/delaystage.py deleted file mode 100644 index eef99b3..0000000 --- a/instruments/delaystage.py +++ /dev/null @@ -1,268 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Sat Apr 21 16:22:35 2018 - -@author: Vladimir Grigorev, Steinn Ymir Agustsson - - Copyright (C) 2018 Steinn Ymir Agustsson, Vladimir Grigorev - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -""" -import time -import sys, os - -try: - import thorlabs_apt as apt -except: - print("no thorlabs_apt found") -sys.path.insert(0, './..') - -from instruments import generic - -try: - import _PyUSMC as _PyUSMC -except: - pass - -try: - import clr - import System -except ImportError: - print('missing packages for Newport stage.') - - -class DelayStage(generic.Instrument): - def __init__(self): - super(DelayStage, self).__init__() - self.position_zero = 0 - self.position_current = 0 - self.path = 1 - self.position_max = 150 - self.position_min = -150 - self.position_in_ps = 2 * 3.33333 * self.path * self.position_current - self.configuration = {'zero position': 0} - self.velocity = 10 # units per second - - def connect(self): - print('connetcted to fake stage. current position=' + str(self.position_current) + '; zero possition' + str( - self.position_zero)) - - def disconnect(self): - print('Fake stage has been disconnected') - - def move_absolute(self, new_position): - # pos=new_position-self.position_zero - time_to_sleep = (abs(self.position_current - new_position)) / self.velocity - if (new_position <= self.position_max) and (new_position >= self.position_min): - 'here should be command for real stage; use pos for the real stage' - self.position_current = new_position - time.sleep(time_to_sleep) - print('Fake stage was moved to ' + str(new_position)) - else: - print('position is out of range') - - def move_relative(self, shift): - if (self.position_current + shift <= self.position_max) and ( - self.position_current + shift >= self.position_min): - self.move_absolute(self.position_current + shift) - print('Fake stage was moved by ' + str(shift)) - else: - print('position is out of range') - - def set_zero_position(self): - print('Zero position set to ' + str(self.position_current)) - self.position_zero = self.position_current - self.position_max = self.position_max - self.position_current - self.position_min = self.position_min - self.position_current - self.position_current = 0 - - def position_get(self): - return self.position_current - - -class NewportXPS(DelayStage): - - def __init__(self): - super(NewportXPS, self).__init__() - if 'CommandInterfaceXPS' not in sys.modules: # TODO: fix imports for XPS stage - # TODO: implement test and ask for correct path in case of faliure - self.NETAssemblyPath = r'C:\Windows\Microsoft.NET\assembly\GAC_64\Newport.XPS.CommandInterface\v4.0_1.0.0.0__9a267756cf640dcf' - sys.path.append(self.NETAssemblyPath) - clr.AddReference("Newport.XPS.CommandInterface") - import CommandInterfaceXPS - - self.myXPS = CommandInterfaceXPS.XPS() - self.Address = '192.168.254.254' - self.Port = 5001 - self.StageName = "CykBlyat" - self.velocity = 500 - self.position_zero = -100 - self.position_current = 0 - self.position_max = 150 - self.position_min = -150 - - def XPS_Open(self): - # Create XPS interface - # Open a socket - timeout = 1000 - result = self.myXPS.OpenInstrument(self.Address, self.Port, timeout) - if result == 0: - print('Open ', self.Address, ":", self.Port, " => Successful") - else: - print('Open ', self.Address, ":", self.Port, " => failure ", result) - - def connect(self): - self.XPS_Open() - self.myXPS.GroupKill(System.String(self.StageName), System.String("")) - self.myXPS.GroupInitialize(System.String(self.StageName), System.String("")) - time.sleep(1) - self.myXPS.GroupHomeSearch(System.String(self.StageName), System.String("")) - self.myXPS.GroupMotionEnable(System.String(self.StageName), System.String("")) - self.move_absolute(self.position_zero) - - def move_absolute(self, new_position): - '''Moves stage to the given position in range of +/- 150 mm ''' - - time_to_sleep = (abs(self.position_current - new_position)) / self.velocity - if (new_position < self.position_max) and (new_position > self.position_min): - self.myXPS.GroupMoveAbsolute(System.String(self.StageName), [System.Double(new_position)], System.Int32(1), - System.String("")) - self.position_current = new_position - time.sleep(time_to_sleep) - print('DelayStage was moved to ' + str(new_position)) - else: - print('position is out of range') - - def position_get(self): - pos = self.myXPS.GetCurrentPosition(System.Double(0), System.Double(0), System.Int32(1), System.Int32(1), - System.Int32(1), System.Int32(1), System.String(self.StageName)) - return pos - - def disconnect(self): - self.myXPS.GroupKill(System.String(self.StageName), System.String("")) - print('DelayStage has been disconnected') - - def XPS_GetControllerVersion(self, myXPS, flag): - result, version, errString = self.myXPS.FirmwareVersionGet(System.String(""), System.String("")) - if flag == 1: - if result == 0: - print('XPS firmware version => ', version) - else: - print('FirmwareVersionGet Error => ', errString) - return result, version - - def XPS_GetControllerState(self, myXPS, flag): - result, state, errString = self.myXPS.ControllerStatusGet(System.Int32(0), System.String("")) - if flag == 1: - if result == 0: - print('XPS controller state => ', state) - else: - print('ControllerStatusGet Error => ', errString) - return result, state - - -class StandaStage(DelayStage): - def __init__(self): - # super(StandaStage, self).__init__() - self.standa = _PyUSMC.StepperMotorController() - self.stage_N = 0 - self.mm_in_step = 0.000325 # depend on your stage typ: 0.000125 for standa 055709; 0.000325 for standa 026424 - - def connect(self): - self.standa.Init() - print(str(len(self.standa.motors)) + ' stages were connected. Change self.stage_N to switch between stages') - self.motor = self.standa.motors[self.stage_N] - - self.motor.position.maxSpeed = 500.0 - - # Set controller parameters - self.motor.parameters.Set( - MaxTemp=70.0, - AccelT=200.0, - DecelT=200.0, - BTimeout1=0.0, - BTimeout2=1000.0, - BTimeout3=1000.0, - BTimeout4=1000.0, - BTO1P=10.0, - BTO2P=100.0, - BTO3P=400.0, - BTO4P=800.0, - MinP=500.0, - BTimeoutR=500.0, - LoftPeriod=500.0, - RTDelta=200, - RTMinError=15, - EncMult=2.5, - MaxLoft=32, - PTimeout=100.0, - SynOUTP=1) - - # Set start parameters - self.motor.startParameters.Set( - SDivisor=8, - DefDir=False, - LoftEn=False, - SlStart=False, - WSyncIN=False, - SyncOUTR=False, - ForceLoft=False) - - # Power on - self.motor.mode.PowerOn() - - def move_absolute(self, new_position): - self.motor.Start(int(new_position / self.mm_in_step)) - self.position_current = new_position - - def position_get(self): - '''returns current position in mm (accurding to the mm in step parametr)''' - self.position_current = self.motor.GetPos() * self.mm_in_step - print(self.motor.GetPos() * self.mm_in_step) - return self.motor.GetPos() * self.mm_in_step - - def disconnect(self): - self.standa.StopMotors(True) - self.standa.Close() - - -class StageError(Exception): - pass - - -class ThorLabs_rotational_stage(DelayStage): # added by Amon sorry if not good - def __init__(self): - # super(StandaStage, self).__init__() - self.serial_N = 27504383 - - def connect(self): - self.serial_N = apt.list_available_devices()[0][1] - self.motor = apt.Motor(self.serial_N) - self.motor.disable() - self.motor.enable() - # self.motor.move_home() - while self.motor.is_in_motion: - time.sleep(1) - - def move_absolute(self, position): - while self.motor.is_in_motion: - time.sleep(1) - self.motor.move_to(position) - while self.motor.is_in_motion: - time.sleep(1) - - def disconnect(self): - pass - # self.motor.disable() diff --git a/instruments/_PyUSMC.py b/instruments/delaystage/_PyUSMC.py similarity index 96% rename from instruments/_PyUSMC.py rename to instruments/delaystage/_PyUSMC.py index 50546b6..0c4f161 100644 --- a/instruments/_PyUSMC.py +++ b/instruments/delaystage/_PyUSMC.py @@ -1,734 +1,734 @@ -"""This is a wrapper module to control Standa 8SMC1-USBhF stepper motor -controllers (http://www.standa.lt/products/catalog/motorised_positioners?item=175) -from Python. The module requires C/C++ developement package (MicroSMC) to be -installed and USMCDLL.dll in path. - -""" -import time -from ctypes import WinDLL, c_int, c_float, c_char_p, POINTER, \ - c_char, Structure, wintypes, create_string_buffer, c_size_t - -__all__ = ["StepperMotorController", "RotationalStage"] - -#=============================================================================== -# Helper structures -#=============================================================================== - -class USMC_Devices(Structure): - """Wrapper class for USMC_Devices structure. - - Attributes - ---------- - NOD : int - Number of stepper motor controllers (axes). - Serial : list of strings - List containing the serial numbers of all controllers. - Version : list of string - List containing the version number of all controllers. - - """ - _fields_ = [ - ("NOD", wintypes.DWORD), - ("Serial", POINTER(c_char_p)), - ("Version", POINTER(c_char_p)), - ] - - -class _SettingsBase(Structure): - """Helper base class for simplifying the setting and updating the settings. - - Parameters - ---------- - motor : `Motor` - Instance of the motor whose settings are being controlled. - - """ - - def __init__(self, motor): - self._motor = motor - self._controller = motor._controller - self._dll = motor._dll - Structure.__init__(self) - - self.Refresh() - - def Refresh(self): - """This method updates the setting values by requesting up-to-date - information from the controller. - - """ - raise NotImplementedError() - - def Apply(self): - """This method transfers the modified settings to the controller - - """ - raise NotImplementedError() - - def Set(self, **kwargs): - """Helper function to set parameters. Sam functionality could be - achived also by modifying the member and then calling `Apply` method. - - """ - allowedKeys, _ = zip(*self._fields_) - for key, value in kwargs.items(): - if not key in allowedKeys: - raise Exception("No such key %s in %s" % (key, self)) - self.__setattr__(key, value) - self.Apply() - self.Refresh() - - def Get(self, variable): - """Helper method to get latest value of `variable`. Internally calls - `Refresh` method and then returns the value. - - Returns - ------- - The value of the `variable`. - - """ - allowedKeys, _ = zip(*self._fields_) - if not variable in allowedKeys: - raise ValueError("No such key %s in %s" % (variable, self)) - self.Refresh() - return getattr(self, variable) - - def ProcessErrorCode(self, errCode): - self._controller.ProcessErrorCode(errCode) - - def __str__(self): - res = ["---Settings---:"] - for member, _ in self._fields_: - res.append("%s = %s" % (member, getattr(self, member))) - return "\n".join(res) - - -class USMC_Parameters(_SettingsBase): - """Wrapper class for `USMC_Parameters` structure. - - Attributes - ---------- - See the user manual of the controller - http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf - - """ - _fields_ = [ - ("AccelT", c_float), - ("DecelT", c_float), - ("PTimeout", c_float), - ("BTimeout1", c_float), - ("BTimeout2", c_float), - ("BTimeout3", c_float), - ("BTimeout4", c_float), - ("BTimeoutR", c_float), - ("BTimeoutD", c_float), - ("MinP", c_float), - ("BTO1P", c_float), - ("BTO2P", c_float), - ("BTO3P", c_float), - ("BTO4P", c_float), - ("MaxLoft", wintypes.WORD), - ("StartPos", wintypes.DWORD), - ("RTDelta", wintypes.WORD), - ("RTMinError", wintypes.WORD), - ("MaxTemp", c_float), - ("SynOUTP", wintypes.BYTE), - ("LoftPeriod", c_float), - ("EncMult", c_float), - ("Reserved", wintypes.BYTE * 16), - ] - - def Refresh(self): - errCode = self._dll.USMC_GetParameters(self._motor.index, self) - self.ProcessErrorCode(errCode) - - def Apply(self): - errCode = self._dll.USMC_SetParameters(self._motor.index, self) - self.ProcessErrorCode(errCode) - - -class USMC_StartParameters(_SettingsBase): - """Wrapper class for `USMC_StartParameters` structure. - - Attributes - ---------- - See the user manual of the controller - http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf - - """ - _fields_ = [ - ("SDivisor", wintypes.BYTE), - ("DefDir", wintypes.BOOL), - ("LoftEn", wintypes.BOOL), - ("SlStart", wintypes.BOOL), - ("WSyncIN", wintypes.BOOL), - ("SyncOUTR", wintypes.BOOL), - ("ForceLoft", wintypes.BOOL), - ("Reserved", wintypes.BOOL * 4), - ] - - def Refresh(self): - errCode = self._dll.USMC_GetStartParameters(self._motor.index, self) - self.ProcessErrorCode(errCode) - - def Apply(self): - pass - - -class USMC_Mode(_SettingsBase): - """Wrapper class for `USMC_Mode` structure. - - Attributes - ---------- - See the user manual of the controller - http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf - - """ - _fields_ = [ - ("PMode", wintypes.BOOL), - ("PReg", wintypes.BOOL), - ("ResetD", wintypes.BOOL), - ("EMReset", wintypes.BOOL), - ("Tr1T", wintypes.BOOL), - ("Tr2T", wintypes.BOOL), - ("RotTrT", wintypes.BOOL), - ("TrSwap", wintypes.BOOL), - ("Tr1En", wintypes.BOOL), - ("Tr2En", wintypes.BOOL), - ("RotTeEn", wintypes.BOOL), - ("RotTrOp", wintypes.BOOL), - ("Butt1T", wintypes.BOOL), - ("Butt2T", wintypes.BOOL), - ("ResetRT", wintypes.BOOL), - ("SyncOUTEn", wintypes.BOOL), - ("SyncOUTR", wintypes.BOOL), - ("SyncINOp", wintypes.BOOL), - ("SyncCount", wintypes.DWORD), - ("SyncInvert", wintypes.BOOL), - ("EncoderEn", wintypes.BOOL), - ("EncoderInv", wintypes.BOOL), - ("ResBEnc", wintypes.BOOL), - ("ResEnc", wintypes.BOOL), - ("Reserved", wintypes.BYTE * 8), - ] - - def Refresh(self): - errCode = self._dll.USMC_GetMode(self._motor.index, self) - self.ProcessErrorCode(errCode) - - def Apply(self): - errCode = self._dll.USMC_SetMode(self._motor.index, self) - self.ProcessErrorCode(errCode) - - def PowerOn(self): - """Helper method to power on the stepper motor. - - """ - self.Set(ResetD = False) - - def PowerOff(self): - """Helper method to power off the stepper motor. - - """ - self.Set(ResetD = True) - - def LimitSwitchEn(self, value): - """Helper method to disable/enable limit switches. - - """ - self.Set(Tr1En = value, Tr2En = value) - - -class USMC_State(_SettingsBase): - """Wrapper class for `USMC_State` structure. - - Attributes - ---------- - See the user manual of the controller - http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf - - """ - _fields_ = [ - ("CurPos", c_int), - ("Temp", c_float), - ("SDivisor", wintypes.BYTE), - ("Loft", wintypes.BOOL), - ("FullPower", wintypes.BOOL), - ("CW_CCW", wintypes.BOOL), - ("Power", wintypes.BOOL), - ("FullSpeed", wintypes.BOOL), - ("AReset", wintypes.BOOL), - ("RUN", wintypes.BOOL), - ("SyncIN", wintypes.BOOL), - ("SyncOUT", wintypes.BOOL), - ("RotTr", wintypes.BOOL), - ("RotTrErr", wintypes.BOOL), - ("EmReset", wintypes.BOOL), - ("Trailer1", wintypes.BOOL), - ("Trailer2", wintypes.BOOL), - ("Voltage", c_float), - ("Reserved", wintypes.BYTE * 8), - ] - - def Refresh(self): - errCode = self._dll.USMC_GetState(self._motor.index, self) - self.ProcessErrorCode(errCode) - - def Running(self): - """Helper method to get the state (moving or not) of the motor. - - """ - return self.Get("RUN") - - -class USMC_EncoderState(_SettingsBase): - """Wrapper class for `USMC_EncoderState` structure. - - Attributes - ---------- - See the user manual of the controller - http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf - - """ - _fields_ = [ - ("EncoderPos", c_int), - ("ECurPos", c_int), - ("Reserved", wintypes.BYTE * 8), - ] - - def Refresh(self): - errCode = self._dll.USMC_GetEncoderState(self._motor.index, self) - self.ProcessErrorCode(errCode) - - -class USMC_Info(_SettingsBase): - """Wrapper class for `USMC_Info` structure. - - Attributes - ---------- - See the user manual of the controller - http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf - - """ - _fields_ = [ - ("serial", c_char * 17), - ("dwVersion", wintypes.DWORD), - ("DevName", c_char * 32), - ("CurPos", c_int), - ("DestPos", c_int), - ("Speed", c_float), - ("ErrState", wintypes.BOOL), - ("Reserved", wintypes.BYTE * 16), - ] - -#=============================================================================== -# Stage classes -#=============================================================================== - -class _StageBaseClass: - """Helper base class to handle conversion between ticks and real units ( - degrees in case of rotational stage and millimeters in case of linear - actuators). - - """ - - def ToUSMCPos(self, value): - """Converts units to number of stepper motor ticks. - - Parameters - ---------- - value : float - The position in units. - - Returns - ------- - int - The position of stepper motor in ticks. - - """ - raise NotImplementedError() - - def ToUSMCSpeed(self, value): - """Converts speed to speed in ticks. - - Parameters - ---------- - value : float - The speed in units per second. - - Returns - ------- - float - Speed in ticks per second. - - """ - raise NotImplementedError() - - def FromUSMCPos(self, value): - """Inverse of `ToUSMCPos`. - - Parameters - ---------- - value : int - Position in ticks. - - Returns - ------- - float - Position in units. - - """ - raise NotImplementedError() - - def GetMaxSpeed(self): - """Returns maximum speed of the motor in ticks per second. - - Returns - ------- - float - Maximum speed (ticks/second). - - """ - return self.maxSpeed / (self._motor.startParameters.SDivisor+1) - -class RotationalStage(_StageBaseClass): - """This class helps to convert the angle of the rotational stage to the - ticks of the stepper motor and the other way around. - - Parameters - ---------- - motor : `Motor` - Instance of the motor. - degreeInTicks : float - Number of ticks in one degree. Default 800. - maxSpeed : float - Maximum speed of the rotational stage (full steps per second). Default - 48.0. - - """ - - def __init__(self, motor, degreeInTicks = 800.0, maxSpeed = 48.0): - self._motor = motor - self.degreeInTicks = degreeInTicks - self.maxSpeed = maxSpeed # fullsteps / sec - - def ToUSMCPos(self, angle): - """Converts units (usually degrees) to number of stepper motor ticks. - - Parameters - ---------- - angle : float - The angle of the rotational stage. - - Returns - ------- - int - The position of stepper motor in ticks. - - """ - res = int(angle * self.degreeInTicks) - return res - - def ToUSMCSpeed(self, angularSpeed): - """Converts angular speed to speed in ticks. - - Parameters - ---------- - angularSpeed : float - The speed in degrees per second. - - Returns - ------- - float - Speed in ticks per second. - - """ - res = float(self.ToUSMCPos(angularSpeed)) / 8.0 * self._motor.startParameters.SDivisor - return res - - def FromUSMCPos(self, value): - """Inverse of `ToUSMCPos`. - - Parameters - ---------- - value : int - Position in ticks. - - Returns - ------- - float - Position in degrees. - - """ - res = float(value) / self.degreeInTicks - return res - -#=============================================================================== -# StepperMotorController -#=============================================================================== - -class StepperMotorController: - """Main class for connecting to Standa 8SMC1-USBhF controllers. This class - connects to USMCDLL.dll module and initializes all motors. By default, all - motors are asuumed to be rotational stages Standa 8MR190-2, however it - could be reconfigured by `position` attribute of the `Motor` class. - - Attributes - ---------- - N : int - Number of motors connected to PC. - motors : list - List of instances to `Motor` class - - """ - - def __init__(self): - # Init variables - self.motors = [] - - # DLL - self._dll = WinDLL(r"USMCDLL.dll") - - self._dll.USMC_Init.argtypes = [USMC_Devices] - self._dll.USMC_Init.restype = wintypes.DWORD - - self._dll.USMC_GetState.argtypes = [wintypes.DWORD, USMC_State] - self._dll.USMC_GetState.restype = wintypes.DWORD - - self._dll.USMC_SaveParametersToFlash.argtypes = [wintypes.DWORD] - self._dll.USMC_SaveParametersToFlash.restype = wintypes.DWORD - - self._dll.USMC_SetCurrentPosition.argtypes = [wintypes.DWORD, c_int] - self._dll.USMC_SetCurrentPosition.restype = wintypes.DWORD - - self._dll.USMC_GetMode.argtypes = [wintypes.DWORD, USMC_Mode] - self._dll.USMC_GetMode.restype = wintypes.DWORD - - self._dll.USMC_SetMode.argtypes = [wintypes.DWORD, USMC_Mode] - self._dll.USMC_SetMode.restype = wintypes.DWORD - - self._dll.USMC_GetParameters.argtypes = [wintypes.DWORD, USMC_Parameters] - self._dll.USMC_GetParameters.restype = wintypes.DWORD - - self._dll.USMC_SetParameters.argtypes = [wintypes.DWORD, USMC_Parameters] - self._dll.USMC_SetParameters.restype = wintypes.DWORD - - self._dll.USMC_GetStartParameters.argtypes = [wintypes.DWORD, USMC_StartParameters] - self._dll.USMC_GetStartParameters.restype = wintypes.DWORD - - self._dll.USMC_Start.argtypes = [wintypes.DWORD, c_int, POINTER(c_float), USMC_StartParameters] - self._dll.USMC_Start.restype = wintypes.DWORD - - self._dll.USMC_Stop.argtypes = [wintypes.DWORD] - self._dll.USMC_Stop.restype = wintypes.DWORD - - self._dll.USMC_GetLastErr.argtypes = [c_char_p, c_size_t] - - self._dll.USMC_Close.argtypes = [] - self._dll.USMC_Close.restype = wintypes.DWORD - - self._dll.USMC_GetEncoderState.argtypes = [wintypes.DWORD, USMC_EncoderState] - self._dll.USMC_GetEncoderState.restype = wintypes.DWORD - - def Init(self): - """Initializes all stepper motor axes. Must be called before any other - method to populate the `motors` list. - - """ - self._devices = USMC_Devices() - errCode = self._dll.USMC_Init(self._devices) - self.ProcessErrorCode(errCode) - - # Create Motor instances - for i in range(self.N): - self.motors.append(Motor(self, i)) - - def Close(self): - """Closes connection to stepper motor controllers. - - """ - if len(self.motors) > 0: - errCode = self._dll.USMC_Close() - self.ProcessErrorCode(errCode) - - def WaitToStop(self): - """This method blocks until all motors are stopped. - - """ - for m in self.motors: - m.WaitToStop() - - def StopMotors(self, powerOff = False): - """Stops all motors. - - Parameters - ---------- - powerOff : bool - If True, then the power of all motors will be disconnected after - stopping. By default False. - - """ - for m in self.motors: - m.Stop(powerOff) - - def Running(self): - """Checks if at least one of the motor is moving. - - Returns - ------- - bool - True if at least one motor is moving. - - """ - for m in self.motors: - if m.state.Running(): - return True - return False - - def ProcessErrorCode(self, errCode): - """Helper function to postprocess the error codes. If error code is not - 0, the RuntimeError is raised. - - """ - if errCode != 0: - errorStr = create_string_buffer(100) - self._dll.USMC_GetLastErr(errorStr, len(errorStr)) - raise RuntimeError("Error: %d, %s" % (errCode, errorStr.value)) - - @property - def N(self): - return self._devices.NOD - -#=============================================================================== -# Motor -#=============================================================================== - -class Motor: - """Class for controlling single stepper motor. The conversion between the real - units (degrees/meters) are done by stage class (`position` instance). By - default ``RotationalStage` is asssumed. This class is usually only - initialized by `StepperMotorController` class. - - Attributes - ---------- - parameters : USMC_Parameters - mode : USMC_Mode - state : USMC_State - startParameters : USMC_StartParameters - encoderState : USMC_EncoderState - - """ - def __init__(self, controller, index): - self._dll = controller._dll - self._controller = controller - self._index = index - self.position = RotationalStage(self) - - # Settings - self.parameters = USMC_Parameters(self) - self.mode = USMC_Mode(self) - self.state = USMC_State(self) - self.startParameters = USMC_StartParameters(self) - self.encoderState = USMC_EncoderState(self) - - def SetCurrentPosition(self, curPos): - """Sets current position of the rotational stage. See - http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf - - Parameters - ---------- - curPos : float - Desired current position of the motor. - - """ - errCode = self._dll.USMC_SetCurrentPosition(self.index, self.position.ToUSMCPos(curPos)) - self._controller.ProcessErrorCode(errCode) - print("Current to set", self.position.ToUSMCPos(curPos)) - print("State", self.state.Get("CurPos")) - - def Start(self, destPos, speed = None): - """Moves the stepper motor to `destPos` with speed `speed`. The method - is non-blocking. - - Parameters - ---------- - destPos : float - Desired position of the motor. - speed : float - Maximum speed of the movement. If None (default), half of the - maximum speed is used. - - """ - if speed == None: - tmpSpeed = self.position.GetMaxSpeed() / 2 - else: - tmpSpeed = speed - - if destPos == float("inf"): - destPos = self.GetPos() + 1000.0 - - if destPos == float("-inf"): - destPos = self.GetPos() - 1000.0 - - speed = c_float(self.position.ToUSMCSpeed(tmpSpeed)) - errCode = self._dll.USMC_Start(self.index, destPos, \ - speed, self.startParameters) - self._controller.ProcessErrorCode(errCode) - - def Stop(self, powerOff = False): - """Stops teh movement of the motor. - - Parameters - ---------- - powerOff : bool - If True, then the power of all motors will be disconnected after - stopping. By default False. - - """ - - errCode = self._dll.USMC_Stop(self.index) - self._controller.ProcessErrorCode(errCode) - - if powerOff: - self.mode.PowerOff() - - def GetPos(self): - """Helper method to get current position of the motor. - - Returns - ------- - float - Current position of the motor. - """ - return self.state.Get("CurPos") - - def WaitToStop(self): - """This method blocks until all the motor is stopped. - - """ - time.sleep(0.05) - while self.state.Running(): - time.sleep(0.01) - - def SaveParametersToFlash(self): - """Saves parameters to flash. See - http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf - - """ - errCode = self._dll.USMC_SaveParametersToFlash(self.index) - self._controller.ProcessErrorCode(errCode) - - @property - def serial(self): - return self._controller._devices.Serial[self.index] - - @property - def version(self): - return self._controller._devices.Version[self.index] - - @property - def index(self): - return self._index - -if __name__ == "__main__": - pass +"""This is a wrapper module to control Standa 8SMC1-USBhF stepper motor +controllers (http://www.standa.lt/products/catalog/motorised_positioners?item=175) +from Python. The module requires C/C++ developement package (MicroSMC) to be +installed and USMCDLL.dll in path. + +""" +import time +from ctypes import WinDLL, c_int, c_float, c_char_p, POINTER, \ + c_char, Structure, wintypes, create_string_buffer, c_size_t + +__all__ = ["StepperMotorController", "RotationalStage"] + +#=============================================================================== +# Helper structures +#=============================================================================== + +class USMC_Devices(Structure): + """Wrapper class for USMC_Devices structure. + + Attributes + ---------- + NOD : int + Number of stepper motor controllers (axes). + Serial : list of strings + List containing the serial numbers of all controllers. + Version : list of string + List containing the version number of all controllers. + + """ + _fields_ = [ + ("NOD", wintypes.DWORD), + ("Serial", POINTER(c_char_p)), + ("Version", POINTER(c_char_p)), + ] + + +class _SettingsBase(Structure): + """Helper base class for simplifying the setting and updating the settings. + + Parameters + ---------- + motor : `Motor` + Instance of the motor whose settings are being controlled. + + """ + + def __init__(self, motor): + self._motor = motor + self._controller = motor._controller + self._dll = motor._dll + Structure.__init__(self) + + self.Refresh() + + def Refresh(self): + """This method updates the setting values by requesting up-to-date + information from the controller. + + """ + raise NotImplementedError() + + def Apply(self): + """This method transfers the modified settings to the controller + + """ + raise NotImplementedError() + + def Set(self, **kwargs): + """Helper function to set parameters. Sam functionality could be + achived also by modifying the member and then calling `Apply` method. + + """ + allowedKeys, _ = zip(*self._fields_) + for key, value in kwargs.items(): + if not key in allowedKeys: + raise Exception("No such key %s in %s" % (key, self)) + self.__setattr__(key, value) + self.Apply() + self.Refresh() + + def Get(self, variable): + """Helper method to get latest value of `variable`. Internally calls + `Refresh` method and then returns the value. + + Returns + ------- + The value of the `variable`. + + """ + allowedKeys, _ = zip(*self._fields_) + if not variable in allowedKeys: + raise ValueError("No such key %s in %s" % (variable, self)) + self.Refresh() + return getattr(self, variable) + + def ProcessErrorCode(self, errCode): + self._controller.ProcessErrorCode(errCode) + + def __str__(self): + res = ["---Settings---:"] + for member, _ in self._fields_: + res.append("%s = %s" % (member, getattr(self, member))) + return "\n".join(res) + + +class USMC_Parameters(_SettingsBase): + """Wrapper class for `USMC_Parameters` structure. + + Attributes + ---------- + See the user manual of the controller + http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf + + """ + _fields_ = [ + ("AccelT", c_float), + ("DecelT", c_float), + ("PTimeout", c_float), + ("BTimeout1", c_float), + ("BTimeout2", c_float), + ("BTimeout3", c_float), + ("BTimeout4", c_float), + ("BTimeoutR", c_float), + ("BTimeoutD", c_float), + ("MinP", c_float), + ("BTO1P", c_float), + ("BTO2P", c_float), + ("BTO3P", c_float), + ("BTO4P", c_float), + ("MaxLoft", wintypes.WORD), + ("StartPos", wintypes.DWORD), + ("RTDelta", wintypes.WORD), + ("RTMinError", wintypes.WORD), + ("MaxTemp", c_float), + ("SynOUTP", wintypes.BYTE), + ("LoftPeriod", c_float), + ("EncMult", c_float), + ("Reserved", wintypes.BYTE * 16), + ] + + def Refresh(self): + errCode = self._dll.USMC_GetParameters(self._motor.index, self) + self.ProcessErrorCode(errCode) + + def Apply(self): + errCode = self._dll.USMC_SetParameters(self._motor.index, self) + self.ProcessErrorCode(errCode) + + +class USMC_StartParameters(_SettingsBase): + """Wrapper class for `USMC_StartParameters` structure. + + Attributes + ---------- + See the user manual of the controller + http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf + + """ + _fields_ = [ + ("SDivisor", wintypes.BYTE), + ("DefDir", wintypes.BOOL), + ("LoftEn", wintypes.BOOL), + ("SlStart", wintypes.BOOL), + ("WSyncIN", wintypes.BOOL), + ("SyncOUTR", wintypes.BOOL), + ("ForceLoft", wintypes.BOOL), + ("Reserved", wintypes.BOOL * 4), + ] + + def Refresh(self): + errCode = self._dll.USMC_GetStartParameters(self._motor.index, self) + self.ProcessErrorCode(errCode) + + def Apply(self): + pass + + +class USMC_Mode(_SettingsBase): + """Wrapper class for `USMC_Mode` structure. + + Attributes + ---------- + See the user manual of the controller + http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf + + """ + _fields_ = [ + ("PMode", wintypes.BOOL), + ("PReg", wintypes.BOOL), + ("ResetD", wintypes.BOOL), + ("EMReset", wintypes.BOOL), + ("Tr1T", wintypes.BOOL), + ("Tr2T", wintypes.BOOL), + ("RotTrT", wintypes.BOOL), + ("TrSwap", wintypes.BOOL), + ("Tr1En", wintypes.BOOL), + ("Tr2En", wintypes.BOOL), + ("RotTeEn", wintypes.BOOL), + ("RotTrOp", wintypes.BOOL), + ("Butt1T", wintypes.BOOL), + ("Butt2T", wintypes.BOOL), + ("ResetRT", wintypes.BOOL), + ("SyncOUTEn", wintypes.BOOL), + ("SyncOUTR", wintypes.BOOL), + ("SyncINOp", wintypes.BOOL), + ("SyncCount", wintypes.DWORD), + ("SyncInvert", wintypes.BOOL), + ("EncoderEn", wintypes.BOOL), + ("EncoderInv", wintypes.BOOL), + ("ResBEnc", wintypes.BOOL), + ("ResEnc", wintypes.BOOL), + ("Reserved", wintypes.BYTE * 8), + ] + + def Refresh(self): + errCode = self._dll.USMC_GetMode(self._motor.index, self) + self.ProcessErrorCode(errCode) + + def Apply(self): + errCode = self._dll.USMC_SetMode(self._motor.index, self) + self.ProcessErrorCode(errCode) + + def PowerOn(self): + """Helper method to power on the stepper motor. + + """ + self.Set(ResetD = False) + + def PowerOff(self): + """Helper method to power off the stepper motor. + + """ + self.Set(ResetD = True) + + def LimitSwitchEn(self, value): + """Helper method to disable/enable limit switches. + + """ + self.Set(Tr1En = value, Tr2En = value) + + +class USMC_State(_SettingsBase): + """Wrapper class for `USMC_State` structure. + + Attributes + ---------- + See the user manual of the controller + http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf + + """ + _fields_ = [ + ("CurPos", c_int), + ("Temp", c_float), + ("SDivisor", wintypes.BYTE), + ("Loft", wintypes.BOOL), + ("FullPower", wintypes.BOOL), + ("CW_CCW", wintypes.BOOL), + ("Power", wintypes.BOOL), + ("FullSpeed", wintypes.BOOL), + ("AReset", wintypes.BOOL), + ("RUN", wintypes.BOOL), + ("SyncIN", wintypes.BOOL), + ("SyncOUT", wintypes.BOOL), + ("RotTr", wintypes.BOOL), + ("RotTrErr", wintypes.BOOL), + ("EmReset", wintypes.BOOL), + ("Trailer1", wintypes.BOOL), + ("Trailer2", wintypes.BOOL), + ("Voltage", c_float), + ("Reserved", wintypes.BYTE * 8), + ] + + def Refresh(self): + errCode = self._dll.USMC_GetState(self._motor.index, self) + self.ProcessErrorCode(errCode) + + def Running(self): + """Helper method to get the state (moving or not) of the motor. + + """ + return self.Get("RUN") + + +class USMC_EncoderState(_SettingsBase): + """Wrapper class for `USMC_EncoderState` structure. + + Attributes + ---------- + See the user manual of the controller + http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf + + """ + _fields_ = [ + ("EncoderPos", c_int), + ("ECurPos", c_int), + ("Reserved", wintypes.BYTE * 8), + ] + + def Refresh(self): + errCode = self._dll.USMC_GetEncoderState(self._motor.index, self) + self.ProcessErrorCode(errCode) + + +class USMC_Info(_SettingsBase): + """Wrapper class for `USMC_Info` structure. + + Attributes + ---------- + See the user manual of the controller + http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf + + """ + _fields_ = [ + ("serial", c_char * 17), + ("dwVersion", wintypes.DWORD), + ("DevName", c_char * 32), + ("CurPos", c_int), + ("DestPos", c_int), + ("Speed", c_float), + ("ErrState", wintypes.BOOL), + ("Reserved", wintypes.BYTE * 16), + ] + +#=============================================================================== +# Stage classes +#=============================================================================== + +class _StageBaseClass: + """Helper base class to handle conversion between ticks and real units ( + degrees in case of rotational stage and millimeters in case of linear + actuators). + + """ + + def ToUSMCPos(self, value): + """Converts units to number of stepper motor ticks. + + Parameters + ---------- + value : float + The position in units. + + Returns + ------- + int + The position of stepper motor in ticks. + + """ + raise NotImplementedError() + + def ToUSMCSpeed(self, value): + """Converts speed to speed in ticks. + + Parameters + ---------- + value : float + The speed in units per second. + + Returns + ------- + float + Speed in ticks per second. + + """ + raise NotImplementedError() + + def FromUSMCPos(self, value): + """Inverse of `ToUSMCPos`. + + Parameters + ---------- + value : int + Position in ticks. + + Returns + ------- + float + Position in units. + + """ + raise NotImplementedError() + + def GetMaxSpeed(self): + """Returns maximum speed of the motor in ticks per second. + + Returns + ------- + float + Maximum speed (ticks/second). + + """ + return self.maxSpeed / (self._motor.startParameters.SDivisor+1) + +class RotationalStage(_StageBaseClass): + """This class helps to convert the angle of the rotational stage to the + ticks of the stepper motor and the other way around. + + Parameters + ---------- + motor : `Motor` + Instance of the motor. + degreeInTicks : float + Number of ticks in one degree. Default 800. + maxSpeed : float + Maximum speed of the rotational stage (full steps per second). Default + 48.0. + + """ + + def __init__(self, motor, degreeInTicks = 800.0, maxSpeed = 48.0): + self._motor = motor + self.degreeInTicks = degreeInTicks + self.maxSpeed = maxSpeed # fullsteps / sec + + def ToUSMCPos(self, angle): + """Converts units (usually degrees) to number of stepper motor ticks. + + Parameters + ---------- + angle : float + The angle of the rotational stage. + + Returns + ------- + int + The position of stepper motor in ticks. + + """ + res = int(angle * self.degreeInTicks) + return res + + def ToUSMCSpeed(self, angularSpeed): + """Converts angular speed to speed in ticks. + + Parameters + ---------- + angularSpeed : float + The speed in degrees per second. + + Returns + ------- + float + Speed in ticks per second. + + """ + res = float(self.ToUSMCPos(angularSpeed)) / 8.0 * self._motor.startParameters.SDivisor + return res + + def FromUSMCPos(self, value): + """Inverse of `ToUSMCPos`. + + Parameters + ---------- + value : int + Position in ticks. + + Returns + ------- + float + Position in degrees. + + """ + res = float(value) / self.degreeInTicks + return res + +#=============================================================================== +# StepperMotorController +#=============================================================================== + +class StepperMotorController: + """Main class for connecting to Standa 8SMC1-USBhF controllers. This class + connects to USMCDLL.dll module and initializes all motors. By default, all + motors are asuumed to be rotational stages Standa 8MR190-2, however it + could be reconfigured by `position` attribute of the `Motor` class. + + Attributes + ---------- + N : int + Number of motors connected to PC. + motors : list + List of instances to `Motor` class + + """ + + def __init__(self): + # Init variables + self.motors = [] + + # DLL + self._dll = WinDLL(r"USMCDLL.dll") + + self._dll.USMC_Init.argtypes = [USMC_Devices] + self._dll.USMC_Init.restype = wintypes.DWORD + + self._dll.USMC_GetState.argtypes = [wintypes.DWORD, USMC_State] + self._dll.USMC_GetState.restype = wintypes.DWORD + + self._dll.USMC_SaveParametersToFlash.argtypes = [wintypes.DWORD] + self._dll.USMC_SaveParametersToFlash.restype = wintypes.DWORD + + self._dll.USMC_SetCurrentPosition.argtypes = [wintypes.DWORD, c_int] + self._dll.USMC_SetCurrentPosition.restype = wintypes.DWORD + + self._dll.USMC_GetMode.argtypes = [wintypes.DWORD, USMC_Mode] + self._dll.USMC_GetMode.restype = wintypes.DWORD + + self._dll.USMC_SetMode.argtypes = [wintypes.DWORD, USMC_Mode] + self._dll.USMC_SetMode.restype = wintypes.DWORD + + self._dll.USMC_GetParameters.argtypes = [wintypes.DWORD, USMC_Parameters] + self._dll.USMC_GetParameters.restype = wintypes.DWORD + + self._dll.USMC_SetParameters.argtypes = [wintypes.DWORD, USMC_Parameters] + self._dll.USMC_SetParameters.restype = wintypes.DWORD + + self._dll.USMC_GetStartParameters.argtypes = [wintypes.DWORD, USMC_StartParameters] + self._dll.USMC_GetStartParameters.restype = wintypes.DWORD + + self._dll.USMC_Start.argtypes = [wintypes.DWORD, c_int, POINTER(c_float), USMC_StartParameters] + self._dll.USMC_Start.restype = wintypes.DWORD + + self._dll.USMC_Stop.argtypes = [wintypes.DWORD] + self._dll.USMC_Stop.restype = wintypes.DWORD + + self._dll.USMC_GetLastErr.argtypes = [c_char_p, c_size_t] + + self._dll.USMC_Close.argtypes = [] + self._dll.USMC_Close.restype = wintypes.DWORD + + self._dll.USMC_GetEncoderState.argtypes = [wintypes.DWORD, USMC_EncoderState] + self._dll.USMC_GetEncoderState.restype = wintypes.DWORD + + def Init(self): + """Initializes all stepper motor axes. Must be called before any other + method to populate the `motors` list. + + """ + self._devices = USMC_Devices() + errCode = self._dll.USMC_Init(self._devices) + self.ProcessErrorCode(errCode) + + # Create Motor instances + for i in range(self.N): + self.motors.append(Motor(self, i)) + + def Close(self): + """Closes connection to stepper motor controllers. + + """ + if len(self.motors) > 0: + errCode = self._dll.USMC_Close() + self.ProcessErrorCode(errCode) + + def WaitToStop(self): + """This method blocks until all motors are stopped. + + """ + for m in self.motors: + m.WaitToStop() + + def StopMotors(self, powerOff = False): + """Stops all motors. + + Parameters + ---------- + powerOff : bool + If True, then the power of all motors will be disconnected after + stopping. By default False. + + """ + for m in self.motors: + m.Stop(powerOff) + + def Running(self): + """Checks if at least one of the motor is moving. + + Returns + ------- + bool + True if at least one motor is moving. + + """ + for m in self.motors: + if m.state.Running(): + return True + return False + + def ProcessErrorCode(self, errCode): + """Helper function to postprocess the error codes. If error code is not + 0, the RuntimeError is raised. + + """ + if errCode != 0: + errorStr = create_string_buffer(100) + self._dll.USMC_GetLastErr(errorStr, len(errorStr)) + raise RuntimeError("Error: %d, %s" % (errCode, errorStr.value)) + + @property + def N(self): + return self._devices.NOD + +#=============================================================================== +# Motor +#=============================================================================== + +class Motor: + """Class for controlling single stepper motor. The conversion between the real + units (degrees/meters) are done by stage class (`position` instance). By + default ``RotationalStage` is asssumed. This class is usually only + initialized by `StepperMotorController` class. + + Attributes + ---------- + parameters : USMC_Parameters + mode : USMC_Mode + state : USMC_State + startParameters : USMC_StartParameters + encoderState : USMC_EncoderState + + """ + def __init__(self, controller, index): + self._dll = controller._dll + self._controller = controller + self._index = index + self.position = RotationalStage(self) + + # Settings + self.parameters = USMC_Parameters(self) + self.mode = USMC_Mode(self) + self.state = USMC_State(self) + self.startParameters = USMC_StartParameters(self) + self.encoderState = USMC_EncoderState(self) + + def SetCurrentPosition(self, curPos): + """Sets current position of the rotational stage. See + http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf + + Parameters + ---------- + curPos : float + Desired current position of the motor. + + """ + errCode = self._dll.USMC_SetCurrentPosition(self.index, self.position.ToUSMCPos(curPos)) + self._controller.ProcessErrorCode(errCode) + print("Current to set", self.position.ToUSMCPos(curPos)) + print("State", self.state.Get("CurPos")) + + def Start(self, destPos, speed = None): + """Moves the stepper motor to `destPos` with speed `speed`. The method + is non-blocking. + + Parameters + ---------- + destPos : float + Desired position of the motor. + speed : float + Maximum speed of the movement. If None (default), half of the + maximum speed is used. + + """ + if speed == None: + tmpSpeed = self.position.GetMaxSpeed() / 2 + else: + tmpSpeed = speed + + if destPos == float("inf"): + destPos = self.GetPos() + 1000.0 + + if destPos == float("-inf"): + destPos = self.GetPos() - 1000.0 + + speed = c_float(self.position.ToUSMCSpeed(tmpSpeed)) + errCode = self._dll.USMC_Start(self.index, destPos, \ + speed, self.startParameters) + self._controller.ProcessErrorCode(errCode) + + def Stop(self, powerOff = False): + """Stops teh movement of the motor. + + Parameters + ---------- + powerOff : bool + If True, then the power of all motors will be disconnected after + stopping. By default False. + + """ + + errCode = self._dll.USMC_Stop(self.index) + self._controller.ProcessErrorCode(errCode) + + if powerOff: + self.mode.PowerOff() + + def GetPos(self): + """Helper method to get current position of the motor. + + Returns + ------- + float + Current position of the motor. + """ + return self.state.Get("CurPos") + + def WaitToStop(self): + """This method blocks until all the motor is stopped. + + """ + time.sleep(0.05) + while self.state.Running(): + time.sleep(0.01) + + def SaveParametersToFlash(self): + """Saves parameters to flash. See + http://www.standa.lt/files/usb/8SMC1-USBhF%20User%20Manual.pdf + + """ + errCode = self._dll.USMC_SaveParametersToFlash(self.index) + self._controller.ProcessErrorCode(errCode) + + @property + def serial(self): + return self._controller._devices.Serial[self.index] + + @property + def version(self): + return self._controller._devices.Version[self.index] + + @property + def index(self): + return self._index + +if __name__ == "__main__": + pass diff --git a/instruments/delaystage/__init__.py b/instruments/delaystage/__init__.py new file mode 100644 index 0000000..4e40da4 --- /dev/null +++ b/instruments/delaystage/__init__.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +""" + +@author: Steinn Ymir Agustsson + + Copyright (C) 2018 Steinn Ymir Agustsson + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +""" + + +def main(): + pass + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/instruments/delaystage/generic.py b/instruments/delaystage/generic.py new file mode 100644 index 0000000..4e40da4 --- /dev/null +++ b/instruments/delaystage/generic.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +""" + +@author: Steinn Ymir Agustsson + + Copyright (C) 2018 Steinn Ymir Agustsson + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +""" + + +def main(): + pass + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/instruments/delaystage/newport.py b/instruments/delaystage/newport.py new file mode 100644 index 0000000..4e40da4 --- /dev/null +++ b/instruments/delaystage/newport.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +""" + +@author: Steinn Ymir Agustsson + + Copyright (C) 2018 Steinn Ymir Agustsson + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +""" + + +def main(): + pass + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/instruments/delaystage/standa.py b/instruments/delaystage/standa.py new file mode 100644 index 0000000..4e40da4 --- /dev/null +++ b/instruments/delaystage/standa.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +""" + +@author: Steinn Ymir Agustsson + + Copyright (C) 2018 Steinn Ymir Agustsson + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +""" + + +def main(): + pass + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/instruments/delaystage/thorlabs.py b/instruments/delaystage/thorlabs.py new file mode 100644 index 0000000..4e40da4 --- /dev/null +++ b/instruments/delaystage/thorlabs.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +""" + +@author: Steinn Ymir Agustsson + + Copyright (C) 2018 Steinn Ymir Agustsson + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +""" + + +def main(): + pass + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/measurement/fastscan.py b/measurement/fastscan.py index ef45e99..4c16971 100644 --- a/measurement/fastscan.py +++ b/measurement/fastscan.py @@ -43,7 +43,7 @@ from scipy.optimize import curve_fit from instruments.cryostat import ITC503s as Cryostat -from instruments.Standastage import StandaStage_8SMC5 +from instruments.delaystage import Standa_8SMC5 from utilities.math import sech2_fwhm, sin, gaussian_fwhm, gaussian, transient_1expdec, update_average from utilities.settings import parse_setting, parse_category, write_setting try: diff --git a/instruments/SetupTest.py b/tests/SetupTest.py similarity index 95% rename from instruments/SetupTest.py rename to tests/SetupTest.py index 4b79619..74c5bc1 100644 --- a/instruments/SetupTest.py +++ b/tests/SetupTest.py @@ -1,113 +1,113 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Nov 24 14:51:16 2017 - -@author: vgrigore -""" - -import CurrentSupplyLib -import lockinamplifier -import cryostat -import time -import h5py -import numpy as np -import matplotlib - -Lockin=lockinamplifier.SR830() -Lockin.connect() -cryo=cryostat.MercuryITC() -cryo.connect() -Magnet=CurrentSupplyLib.CurrentSUP() -Magnet.initcurrentsupply() -Magnet.SetVoltage(40) -Magnet.SetCurrent(0) -Magnet.SwitchForward() - - -def MeasureHys(filename): - time.sleep(1) - Magnet.SwitchForward() - Magnet.OutputON() - Currents=[] - Currents2=[] - CurrStart=0 - CurrStop=10 - step=0.5 - Signal=[] - for i in range(0,20): - Currents.append(CurrStart+i*step) - for i in range(0,21): - Currents.append(CurrStop - i*step) - for item in Currents: - Currents2.append(-item) - for item in Currents2: - Currents.append(item) - - - for item in Currents2: - print(-item) - Magnet.SetCurrent(-item) - time.sleep(3) - Signal.append(Meas()) - Magnet.OutputOFF() - time.sleep(1) - Magnet.SwitchReverse() - Magnet.OutputON() - - for item in Currents2: - print(item) - Magnet.SetCurrent(-item) - time.sleep(3) - Signal.append(Meas()) - Magnet.OutputOFF() - matplotlib.pyplot.plot(Currents, Signal) - SaveHys(filename,Currents, Signal) - -def Meas(): - signal=[] - avg=10 - for i in range(avg): - signal.append(Lockin.read_value('R')) - print(signal) - val=sum(signal)/avg - return val - -def SaveHys(name,X,Y): - File=h5py.File(name+".hdf5", "w") - data=np.array([X,Y]) - dset=File.create_dataset("Hys",(len(X),2)) - dset[...]=data.T - File.close() - - - -def temperature_scan(): - temperature=[4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,11,12,13,14,15,16,17,18,19,20] - for item in temperature: - cryo.change_temperature(item) - filename='RuCl3-Micra-Kerr-temperature'+str(item)+str(time.time()) - MeasureHys(filename) - -MeasureHys('test') - -#temperature_scan() -#Magnet.SetCurrent(5) -#Magnet.SwitchForward() -#Magnet.OutputON() -#time.sleep(10) -#Lockin.ReadValue('R') -#Lockin.ReadValue('R') -#Lockin.ReadValue('R') -#Lockin.ReadValue('R') -#Lockin.ReadValue('R') -#Magnet.OutputOFF() -#Magnet.SwitchReverse() -#Magnet.OutputON() -#time.sleep(10) -#Lockin.ReadValue('R') -#Lockin.ReadValue('R') -#Lockin.ReadValue('R') -#Lockin.ReadValue('R') -#Lockin.ReadValue('R') -#Magnet.initcurrentsupply() +# -*- coding: utf-8 -*- +""" +Created on Fri Nov 24 14:51:16 2017 + +@author: vgrigore +""" + +import CurrentSupplyLib +import lockinamplifier +import cryostat +import time +import h5py +import numpy as np +import matplotlib + +Lockin=lockinamplifier.SR830() +Lockin.connect() +cryo=cryostat.MercuryITC() +cryo.connect() +Magnet=CurrentSupplyLib.CurrentSUP() +Magnet.initcurrentsupply() +Magnet.SetVoltage(40) +Magnet.SetCurrent(0) +Magnet.SwitchForward() + + +def MeasureHys(filename): + time.sleep(1) + Magnet.SwitchForward() + Magnet.OutputON() + Currents=[] + Currents2=[] + CurrStart=0 + CurrStop=10 + step=0.5 + Signal=[] + for i in range(0,20): + Currents.append(CurrStart+i*step) + for i in range(0,21): + Currents.append(CurrStop - i*step) + for item in Currents: + Currents2.append(-item) + for item in Currents2: + Currents.append(item) + + + for item in Currents2: + print(-item) + Magnet.SetCurrent(-item) + time.sleep(3) + Signal.append(Meas()) + Magnet.OutputOFF() + time.sleep(1) + Magnet.SwitchReverse() + Magnet.OutputON() + + for item in Currents2: + print(item) + Magnet.SetCurrent(-item) + time.sleep(3) + Signal.append(Meas()) + Magnet.OutputOFF() + matplotlib.pyplot.plot(Currents, Signal) + SaveHys(filename,Currents, Signal) + +def Meas(): + signal=[] + avg=10 + for i in range(avg): + signal.append(Lockin.read_value('R')) + print(signal) + val=sum(signal)/avg + return val + +def SaveHys(name,X,Y): + File=h5py.File(name+".hdf5", "w") + data=np.array([X,Y]) + dset=File.create_dataset("Hys",(len(X),2)) + dset[...]=data.T + File.close() + + + +def temperature_scan(): + temperature=[4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,11,12,13,14,15,16,17,18,19,20] + for item in temperature: + cryo.change_temperature(item) + filename='RuCl3-Micra-Kerr-temperature'+str(item)+str(time.time()) + MeasureHys(filename) + +MeasureHys('test') + +#temperature_scan() +#Magnet.SetCurrent(5) +#Magnet.SwitchForward() +#Magnet.OutputON() +#time.sleep(10) +#Lockin.ReadValue('R') +#Lockin.ReadValue('R') +#Lockin.ReadValue('R') +#Lockin.ReadValue('R') +#Lockin.ReadValue('R') +#Magnet.OutputOFF() +#Magnet.SwitchReverse() +#Magnet.OutputON() +#time.sleep(10) +#Lockin.ReadValue('R') +#Lockin.ReadValue('R') +#Lockin.ReadValue('R') +#Lockin.ReadValue('R') +#Lockin.ReadValue('R') +#Magnet.initcurrentsupply() #Magnet.ToLocalMode() \ No newline at end of file diff --git a/instruments/plt.py b/tests/plt.py similarity index 96% rename from instruments/plt.py rename to tests/plt.py index 1b3fa88..8d1c696 100644 --- a/instruments/plt.py +++ b/tests/plt.py @@ -1,100 +1,100 @@ -# -*- coding: utf-8 -*- -""" -Created on Mon Oct 22 20:09:57 2018 - -@author: vgrigore -""" - -import matplotlib.pyplot as plt -import os -import h5py -import numpy as np - -class scan(object): - def __init__(self): - self.X=[] - self.Y=[] - self.Y1=[] - self.temperature=0 - - def import_file(self,filename): - file=h5py.File(filename) - d=np.array(file['Hys']) - self.X=d.T[0] - self.Y=d.T[1] - self.Y1=self.Y - self.Y[10] - #self.temperature=float(filename[20:22]) - - def plot(self,offset=0): - fig, ax=plt.subplots() - Y1=self.Y1+offset - ax.plot(self.X,Y1, label='temp='+str(self.temperature)+' k') - leg = ax.legend() -#%% -class scans(object): - def __init__(self): - self.scans=[] - self.filenames=[] - - def import_all(self): - files=os.listdir() - for item in files: - if item[0:3]=='RuC': - self.filenames.append(item) - for item in self.filenames: - sc=scan() - sc.import_file(item) - self.scans.append(sc) - - - - def plot_all(self): - fig,ax=plt.subplots() - for i,item in enumerate(self.scans): - - ax.plot(item.X,item.Y1+item.temperature*0.0001,label='temp='+str(item.temperature)+' k') - - ax.legend() - - -#%% -def plot_one(filename,offset=0): - #filename='BNA-pu-0.75-pr-0.2-4-87.5--80-420Mon Oct 22 19-39-25 2018.h5' - file=h5py.File(filename) - d=np.array(file['stepscan']) - X=d.T[0] - X_time=X - Y=d.T[1] - Y1=Y-Y[5]+offset - temperature=float(filename[20:22]) - fig, ax=plt.subplots() - ax.plot(X_time,Y1,lebal='temp='+str(temperature)+' k') - leg=ax.legend() - -def plot_all(): - files=os.listdir() - filenames=[] - for item in files: - if item[0:3]=='BNA': - filenames.append(item) - - for i, item in enumerate(filenames): - plot_one(item,offset=i*0.00008) - - -def fit_one(filename): - file=h5py.File(filename) - d=np.array(file['stepscan']) - X=d.T[0] - X_time=X*2/0.3 + 578 - Y=d.T[1] - Y1=Y-Y[5] - - - -scs=scans() -scs.import_all() -scs.plot_all() -#plot_all() -#filename='BNA-pu-0.75-pr-0.2-4-87.5--80-420Mon Oct 22 19-39-25 2018.h5' +# -*- coding: utf-8 -*- +""" +Created on Mon Oct 22 20:09:57 2018 + +@author: vgrigore +""" + +import matplotlib.pyplot as plt +import os +import h5py +import numpy as np + +class scan(object): + def __init__(self): + self.X=[] + self.Y=[] + self.Y1=[] + self.temperature=0 + + def import_file(self,filename): + file=h5py.File(filename) + d=np.array(file['Hys']) + self.X=d.T[0] + self.Y=d.T[1] + self.Y1=self.Y - self.Y[10] + #self.temperature=float(filename[20:22]) + + def plot(self,offset=0): + fig, ax=plt.subplots() + Y1=self.Y1+offset + ax.plot(self.X,Y1, label='temp='+str(self.temperature)+' k') + leg = ax.legend() +#%% +class scans(object): + def __init__(self): + self.scans=[] + self.filenames=[] + + def import_all(self): + files=os.listdir() + for item in files: + if item[0:3]=='RuC': + self.filenames.append(item) + for item in self.filenames: + sc=scan() + sc.import_file(item) + self.scans.append(sc) + + + + def plot_all(self): + fig,ax=plt.subplots() + for i,item in enumerate(self.scans): + + ax.plot(item.X,item.Y1+item.temperature*0.0001,label='temp='+str(item.temperature)+' k') + + ax.legend() + + +#%% +def plot_one(filename,offset=0): + #filename='BNA-pu-0.75-pr-0.2-4-87.5--80-420Mon Oct 22 19-39-25 2018.h5' + file=h5py.File(filename) + d=np.array(file['stepscan']) + X=d.T[0] + X_time=X + Y=d.T[1] + Y1=Y-Y[5]+offset + temperature=float(filename[20:22]) + fig, ax=plt.subplots() + ax.plot(X_time,Y1,lebal='temp='+str(temperature)+' k') + leg=ax.legend() + +def plot_all(): + files=os.listdir() + filenames=[] + for item in files: + if item[0:3]=='BNA': + filenames.append(item) + + for i, item in enumerate(filenames): + plot_one(item,offset=i*0.00008) + + +def fit_one(filename): + file=h5py.File(filename) + d=np.array(file['stepscan']) + X=d.T[0] + X_time=X*2/0.3 + 578 + Y=d.T[1] + Y1=Y-Y[5] + + + +scs=scans() +scs.import_all() +scs.plot_all() +#plot_all() +#filename='BNA-pu-0.75-pr-0.2-4-87.5--80-420Mon Oct 22 19-39-25 2018.h5' #plot_one('BNA-pu-0.75-pr-0.2-T-10-[(-87.2, -86, 300), (-86, -80, 100), (-80, -50, 20)]Thu Oct 25 01-41-55 2018.h5') \ No newline at end of file diff --git a/instruments/thorlabs.py b/tests/thorlabs.py similarity index 94% rename from instruments/thorlabs.py rename to tests/thorlabs.py index 0c54437..2eed94a 100644 --- a/instruments/thorlabs.py +++ b/tests/thorlabs.py @@ -1,14 +1,14 @@ -# -*- coding: utf-8 -*- -""" -Created on Wed May 29 17:19:23 2019 - -@author: vgrigore -""" - - -import thorlabs_apt as apt -apt.list_available_devices() -[(31, 27504383)] -motor = apt.Motor(27504377) -motor.move_home(True) +# -*- coding: utf-8 -*- +""" +Created on Wed May 29 17:19:23 2019 + +@author: vgrigore +""" + + +import thorlabs_apt as apt +apt.list_available_devices() +[(31, 27504383)] +motor = apt.Motor(27504377) +motor.move_home(True) motor.move_by(45) \ No newline at end of file From 2fc463fabb43a39a437c034795415dbee562540e Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 15 Jan 2020 16:42:26 +0100 Subject: [PATCH 07/10] reorganize instruments --- instruments/delaystage/__init__.py | 6 + instruments/delaystage/generic.py | 51 +++++ instruments/delaystage/newport.py | 88 +++++++ instruments/delaystage/standa.py | 357 ++++++++++++++++++++++++++++- instruments/delaystage/thorlabs.py | 32 +++ 5 files changed, 530 insertions(+), 4 deletions(-) diff --git a/instruments/delaystage/__init__.py b/instruments/delaystage/__init__.py index 4e40da4..dcd5799 100644 --- a/instruments/delaystage/__init__.py +++ b/instruments/delaystage/__init__.py @@ -19,6 +19,12 @@ along with this program. If not, see . """ +import logging +from .generic import DelayStage +from instruments.delaystage.standa import Standa_8SMC5 + + +logging.getLogger(__name__).addHandler(logging.NullHandler()) def main(): diff --git a/instruments/delaystage/generic.py b/instruments/delaystage/generic.py index 4e40da4..17765e9 100644 --- a/instruments/delaystage/generic.py +++ b/instruments/delaystage/generic.py @@ -19,7 +19,58 @@ along with this program. If not, see . """ +from instruments import generic +class DelayStage(generic.Instrument): + def __init__(self): + super(DelayStage, self).__init__() + self.position_zero = 0 + self.position_current = 0 + self.path = 1 + self.position_max = 150 + self.position_min = -150 + self.position_in_ps = 2 * 3.33333 * self.path * self.position_current + self.configuration = {'zero position': 0} + self.velocity = 10 # units per second + + def connect(self): + print('connetcted to fake stage. current position=' + str(self.position_current) + '; zero possition' + str( + self.position_zero)) + + def disconnect(self): + print('Fake stage has been disconnected') + + def move_absolute(self, new_position): + # pos=new_position-self.position_zero + time_to_sleep = (abs(self.position_current - new_position)) / self.velocity + if (new_position <= self.position_max) and (new_position >= self.position_min): + 'here should be command for real stage; use pos for the real stage' + self.position_current = new_position + time.sleep(time_to_sleep) + print('Fake stage was moved to ' + str(new_position)) + else: + print('position is out of range') + + def move_relative(self, shift): + if (self.position_current + shift <= self.position_max) and ( + self.position_current + shift >= self.position_min): + self.move_absolute(self.position_current + shift) + print('Fake stage was moved by ' + str(shift)) + else: + print('position is out of range') + + def set_zero_position(self): + print('Zero position set to ' + str(self.position_current)) + self.position_zero = self.position_current + self.position_max = self.position_max - self.position_current + self.position_min = self.position_min - self.position_current + self.position_current = 0 + + def position_get(self): + return self.position_current + +class StageError(Exception): + pass def main(): pass diff --git a/instruments/delaystage/newport.py b/instruments/delaystage/newport.py index 4e40da4..64a78b3 100644 --- a/instruments/delaystage/newport.py +++ b/instruments/delaystage/newport.py @@ -19,6 +19,94 @@ along with this program. If not, see . """ +import time +import sys, os +from .generic import DelayStage +try: + import clr + import System +except ImportError: + print('missing packages for Newport stage.') + +class NewportXPS(DelayStage): + + def __init__(self): + super(NewportXPS, self).__init__() + if 'CommandInterfaceXPS' not in sys.modules: # TODO: fix imports for XPS stage + # TODO: implement test and ask for correct path in case of faliure + self.NETAssemblyPath = r'C:\Windows\Microsoft.NET\assembly\GAC_64\Newport.XPS.CommandInterface\v4.0_1.0.0.0__9a267756cf640dcf' + sys.path.append(self.NETAssemblyPath) + clr.AddReference("Newport.XPS.CommandInterface") + import CommandInterfaceXPS + + self.myXPS = CommandInterfaceXPS.XPS() + self.Address = '192.168.254.254' + self.Port = 5001 + self.StageName = "CykBlyat" + self.velocity = 500 + self.position_zero = -100 + self.position_current = 0 + self.position_max = 150 + self.position_min = -150 + + def XPS_Open(self): + # Create XPS interface + # Open a socket + timeout = 1000 + result = self.myXPS.OpenInstrument(self.Address, self.Port, timeout) + if result == 0: + print('Open ', self.Address, ":", self.Port, " => Successful") + else: + print('Open ', self.Address, ":", self.Port, " => failure ", result) + + def connect(self): + self.XPS_Open() + self.myXPS.GroupKill(System.String(self.StageName), System.String("")) + self.myXPS.GroupInitialize(System.String(self.StageName), System.String("")) + time.sleep(1) + self.myXPS.GroupHomeSearch(System.String(self.StageName), System.String("")) + self.myXPS.GroupMotionEnable(System.String(self.StageName), System.String("")) + self.move_absolute(self.position_zero) + + def move_absolute(self, new_position): + '''Moves stage to the given position in range of +/- 150 mm ''' + + time_to_sleep = (abs(self.position_current - new_position)) / self.velocity + if (new_position < self.position_max) and (new_position > self.position_min): + self.myXPS.GroupMoveAbsolute(System.String(self.StageName), [System.Double(new_position)], System.Int32(1), + System.String("")) + self.position_current = new_position + time.sleep(time_to_sleep) + print('DelayStage was moved to ' + str(new_position)) + else: + print('position is out of range') + + def position_get(self): + pos = self.myXPS.GetCurrentPosition(System.Double(0), System.Double(0), System.Int32(1), System.Int32(1), + System.Int32(1), System.Int32(1), System.String(self.StageName)) + return pos + + def disconnect(self): + self.myXPS.GroupKill(System.String(self.StageName), System.String("")) + print('DelayStage has been disconnected') + + def XPS_GetControllerVersion(self, myXPS, flag): + result, version, errString = self.myXPS.FirmwareVersionGet(System.String(""), System.String("")) + if flag == 1: + if result == 0: + print('XPS firmware version => ', version) + else: + print('FirmwareVersionGet Error => ', errString) + return result, version + + def XPS_GetControllerState(self, myXPS, flag): + result, state, errString = self.myXPS.ControllerStatusGet(System.Int32(0), System.String("")) + if flag == 1: + if result == 0: + print('XPS controller state => ', state) + else: + print('ControllerStatusGet Error => ', errString) + return result, state def main(): diff --git a/instruments/delaystage/standa.py b/instruments/delaystage/standa.py index 4e40da4..4df32ea 100644 --- a/instruments/delaystage/standa.py +++ b/instruments/delaystage/standa.py @@ -19,11 +19,360 @@ along with this program. If not, see . """ +import time +import sys, os +from instruments.delaystage.generic import DelayStage -def main(): - pass -if __name__ == '__main__': - main() \ No newline at end of file + +import sys, os +import ctypes +from ctypes import byref, cast, POINTER, c_int, string_at +import time +import platform +import numpy as np +import logging +from utilities.exceptions import DeviceNotFoundError +from instruments.delaystage.generic import DelayStage, StageError + +ximc_dir = 'E:/STANDA_TESTS/ximc-2.10.5/ximc/' +ximc_package_dir = os.path.join(ximc_dir, "crossplatform", "wrappers", "python") +sys.path.append(ximc_package_dir) +if platform.system() == "Windows": + arch_dir = "win64" if "64" in platform.architecture()[0] else "win32" + libdir = os.path.join(ximc_dir, arch_dir) + os.environ["Path"] = libdir + ";" + os.environ["Path"] # add dll + +try: + import pyximc + + lib = pyximc.lib +except ImportError as err: + print( + "Can't import pyximc module. The most probable reason is that you changed the relative location of the testpython.py and pyximc.py files. See developers' documentation for details.") +except OSError as err: + print( + "Can't load libximc library. Please add all shared libraries to the appropriate places. It is decribed in detail in developers' documentation. On Linux make sure you installed libximc-dev package.\nmake sure that the architecture of the system and the interpreter is the same") + + +class Standa_8SMC5(DelayStage): + + + def __init__(self): + super(Standa_8SMC5, self).__init__() + self.logger = logging.getLogger('{}.Standa_8SMC5'.format(__name__)) + self.logger.info('Created new instance') + self.step_to_um_factor = 1.25 + self.step_to_ps_factor = 2 * 0.00333564 * self.step_to_um_factor + self.max_speed = 1000 + self.pos_zero = 0 + self.pos_max = 10000 + self.pos_min = 0 + self._devenum = None + self.device_number = None + self.dev_id = None + + def step_to_um(self, pos, uPos): + return (pos + uPos / 256) * self.step_to_um_factor + + def step_to_ps(self, pos, uPos): + return (pos + uPos / 256) * self.step_to_ps_factor + + def um_to_step(self, val): + pos = int(val // self.step_to_um_factor) + uPos = int((val % self.step_to_um_factor) * 256) + return pos, uPos + + def ps_to_step(self, val): + pos = int(val // self.step_to_ps_factor) + uPos = int((val % self.step_to_ps_factor) * 256) + return pos, uPos + + def connect(self, device_number=None): + if device_number is not None: + self.device_number = device_number + if self._devenum is None: + self._devenum = self.get_device_list() + + open_name = lib.get_device_name(self._devenum, self.device_number) + self.dev_id = lib.open_device(open_name) + self.logger.debug("Device id: " + repr(self.dev_id)) + result = lib.get_device_information(self.dev_id, byref(pyximc.device_information_t())) + if result == 0: + self.logger.debug("Connected to device ID: {}".format(self.dev_id)) + + def disconnect(self): + lib.close_device(byref(cast(self.dev_id, POINTER(c_int)))) + self.logger.debug("Disconnected stage ID: {}".format(self.dev_id)) + + def move_absolute(self, new_position, unit='ps'): + """ move stage to given position, expressed in the defined units ,relative to zero_position""" + # new_position += self.zero_position # uncomment to use zero position + if unit == 'ps': + pos,uPos = self.ps_to_step(new_position) + elif unit == 'um': + pos,uPos = self.um_to_step(new_position) + else: + raise ValueError('Could not understand {} as unit. please use ps (picoseconds) or um (micrometers)'.format(unit)) + self.logger.debug("Move Absolute dev{} to {} {}".format(self.dev_id,new_position, unit)) + self._move_to(pos,uPos) + + + def move_relative(self, distance,unit='ps'): + """ Evaluate shift in unit of stepper motor steps, and go there.""" + + cpos,cuPos = self._get_current_position() + if unit == 'ps': + pos, uPos = self.ps_to_step(distance) + elif unit == 'um': + pos, uPos = self.um_to_step(distance) + else: + raise ValueError('Could not understand {} as unit. please use ps (picoseconds) or um (micrometers)'.format(unit)) + self.logger.debug("Move relative dev{} by {} {}".format(self.dev_id,distance, unit)) + + self._move_to(cpos+pos, cuPos+uPos) + + def _move_to(self, pos, uPos=0): + """ Move stage to the indicated position. In units of steps and microsteps.""" + uPos = uPos % 256 + pos = pos + uPos // 256 + result = lib.command_move(self.dev_id, pos, uPos) + if result == 0: + cur_pos, cur_uPos = self._get_current_position() + d = np.abs(pos - cur_pos) + ud = np.abs(uPos - cur_uPos) + wait = (d + ud / 256) / self.speed + .1 + self.logger.debug('Stage{} moved by {}.{}, to {}.{}. Waiting {}s'.format(self.dev_id,d,ud,pos,uPos,wait)) + time.sleep(wait) + else: + raise StageError('Standa stage error code {}'.format(result)) + + + def set_zero_position(self): #TODO: implement zero positioning. + raise NotImplementedError + # print('Zero position set to ' + str(self.position_current)) + # self.pos_zero = self.position_current + # self.position_max = self.position_max - self.position_current + # self.position_min = self.position_min - self.position_current + # self.position_current = 0 + + def _get_current_position(self): + x_pos = pyximc.get_position_t() + result = lib.get_position(self.dev_id, byref(x_pos)) + if self.error_lookup(result): + pos = x_pos.Position + uPos = x_pos.uPosition + self.logger.debug('dev_{} @ position: {}.{} steps'.format(self.dev_id,pos,uPos)) + return pos,uPos + + @property + def position_um(self): + pos, upos = self._get_current_position() + return self.step_to_um(pos, upos) + + @position_um.setter + def position_um(self, val): + pos, uPos = self.um_to_step(val) + self._move_to(pos, uPos) + + @property + def position_ps(self): + pos, upos = self._get_current_position() + return self.step_to_ps(pos, upos) + + @position_ps.setter + def position_ps(self, val): + pos, uPos = self.ps_to_step(val) + self._move_to(pos, uPos) + + @property + def position_step(self): + pos, upos = self._get_current_position() + return pos, upos + + @position_step.setter + def position_step(self, step,uStep): + self._move_to(step, uStep) + + @property + def serial(self): + x_serial = ctypes.c_uint() + result = lib.get_serial_number(self.dev_id, byref(x_serial)) + if self.error_lookup(result): + return (repr(x_serial.value)) + + @property + def speed(self): + mvst = pyximc.move_settings_t() + result = lib.get_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + return mvst.Speed + + @speed.setter + def speed(self, val): + assert 0 < val < self.max_speed + mvst = pyximc.move_settings_t() + result = lib.get_move_settings(self.dev_id, byref(mvst)) + mvst.Speed = int(val) + result = lib.set_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + print('Speed set to {} step/s'.format(val)) + + @property + def uSpeed(self): + mvst = pyximc.move_settings_t() + result = lib.get_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + return mvst.uSpeed + + @uSpeed.setter + def uSpeed(self, val): + mvst = pyximc.move_settings_t() + mvst.uSpeed = int(val) + result = lib.set_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + print('uSpeed set to {} uStep/s'.format(val)) + + @property + def acceleration(self): + mvst = pyximc.move_settings_t() + result = lib.get_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + return mvst.Accel + + @acceleration.setter + def acceleration(self, val): + mvst = pyximc.move_settings_t() + mvst.Accel = int(val) + result = lib.set_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + print('Acceleration changed to {}'.format(val)) + + @property + def deceleration(self): + mvst = pyximc.move_settings_t() + result = lib.get_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + return mvst.Decel + + @deceleration.setter + def deceleration(self, val): + mvst = pyximc.move_settings_t() + mvst.Decel = int(val) + result = lib.set_move_settings(self.dev_id, byref(mvst)) + if self.error_lookup(result): + print('Deceleration changed to {}'.format(val)) + + def error_lookup(self, id): + if id == 0: + return True + elif id == -1: + raise Exception('Standa stage error code {}'.format(id)) + elif id == -2: + raise NotImplementedError('Standa stage error code {}'.format(id)) + elif id == -3: + raise ValueError('Standa stage error code {}'.format(id)) + elif id == -4: + raise DeviceNotFoundError('Standa stage error code {}'.format(id)) + + @staticmethod + def get_device_list(): + """ Find all available devices and return the enumeration of them.""" + probe_flags = pyximc.EnumerateFlags.ENUMERATE_PROBE # + EnumerateFlags.ENUMERATE_NETWORK + enum_hints = b"addr=192.168.0.1,172.16.2.3" + devenum = lib.enumerate_devices(probe_flags, enum_hints) + dev_count = lib.get_device_count(devenum) + print("Device count: " + repr(dev_count)) + controller_name = pyximc.controller_name_t() + for dev_ind in range(0, dev_count): + enum_name = lib.get_device_name(devenum, dev_ind) + result = lib.get_enumerate_device_controller_name(devenum, dev_ind, byref(controller_name)) + if result == pyximc.Result.Ok: + print("Enumerated device #{} name (port name): ".format(dev_ind) + repr( + enum_name) + ". Friendly name: " + repr(controller_name.ControllerName) + ".") + + return devenum + + def device_info(self): + if self.dev_id is not None: + x_device_information = pyximc.device_information_t() + result = lib.get_device_information(self.dev_id, byref(x_device_information)) + if self.error_lookup(result): + print('Device info:') + print("Device information:") + print(" Manufacturer: " + + repr(string_at(x_device_information.Manufacturer).decode())) + print(" ManufacturerId: " + + repr(string_at(x_device_information.ManufacturerId).decode())) + print(" ProductDescription: " + + repr(string_at(x_device_information.ProductDescription).decode())) + print(" Major: " + repr(x_device_information.Major)) + print(" Minor: " + repr(x_device_information.Minor)) + print(" Release: " + repr(x_device_information.Release)) + else: + print('no device selected yet') + + def get_device_status(self): + if self.dev_id is not None: + x_status = pyximc.status_t() + result = lib.get_status(self.dev_id, byref(x_status)) + if self.error_lookup(result): + fields = [x for x in dir(x_status) if '_' not in x] + status = {} + for field in fields: + status[field] = repr(getattr(x_status,field)) + else: + print('no device selected yet') + + def print_device_status(self): + d = self.get_device_status() + if d is not None: + print('Status of device {}'.format(self.dev_id)) + for key,val in d.items(): + print(' - {}: {}'.format(key,val)) + + +if __name__ == "__main__": + import logging + from logging.config import fileConfig + + logging.basicConfig(format='%(levelname)s | %(message)s', level=logging.DEBUG)#, filename='example.log') + logger = logging.getLogger(__name__) + logger.setLevel(logging.DEBUG) + logger.debug('Started logger') + + + + sc = Standa_8SMC5() + sc.connect(0) + sc.print_device_status() + print('Current speed settings: {}'.format(sc.speed)) + setspeed = 900 + sc.speed = setspeed + print('Speed changed to {} speed settings reads: {}\n'.format(setspeed,sc.speed)) + + print('\ncurrent pos: {} ps | {} um| {},{} step \n'.format(sc.position_ps,sc.position_um,*sc.position_step)) + moveby = -1#ps + print('move by {} ps'.format(sc.ps_to_step(moveby))) + sc.move_relative(moveby,unit='ps') + print('\ncurrent pos: {} ps | {} um| {},{} step \n'.format(sc.position_ps,sc.position_um,*sc.position_step)) + # + positions = np.linspace(100,110,1) + print(positions) + y = [] + for pos in positions: + print('going to pos {}'.format(pos)) + sc.move_absolute(pos) + y.append(sc.position_ps) + # import matplotlib.pyplot as plt + # plt.figure() + # plt.plot(positions,y) + # plt.show() + # TODO: try improve precision with accel and decel + for vv in zip(positions,y,(y-positions)*1000): + print(*vv,sep=' | ') + # print('---- Y ----\n',*y,sep='\n') + # print(*positions,sep='\n') + sc.disconnect() diff --git a/instruments/delaystage/thorlabs.py b/instruments/delaystage/thorlabs.py index 4e40da4..01752f6 100644 --- a/instruments/delaystage/thorlabs.py +++ b/instruments/delaystage/thorlabs.py @@ -19,6 +19,38 @@ along with this program. If not, see . """ +import sys, os +from instruments.delaystage.generic import DelayStage, StageError +try: + import thorlabs_apt as apt +except: + print("no thorlabs_apt found") +sys.path.insert(0, './..') + +class ThorLabs_rotational_stage(DelayStage): # added by Amon sorry if not good + def __init__(self): + # super(StandaStage, self).__init__() + self.serial_N = 27504383 + + def connect(self): + self.serial_N = apt.list_available_devices()[0][1] + self.motor = apt.Motor(self.serial_N) + self.motor.disable() + self.motor.enable() + # self.motor.move_home() + while self.motor.is_in_motion: + time.sleep(1) + + def move_absolute(self, position): + while self.motor.is_in_motion: + time.sleep(1) + self.motor.move_to(position) + while self.motor.is_in_motion: + time.sleep(1) + + def disconnect(self): + pass + # self.motor.disable() def main(): From fe6d283f45116017096f7699dc9d9a98f558a755 Mon Sep 17 00:00:00 2001 From: Steinn Date: Fri, 17 Jan 2020 17:15:38 +0100 Subject: [PATCH 08/10] unlock cython scripts usage --- measurement/fastscan.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/measurement/fastscan.py b/measurement/fastscan.py index 4c16971..a6f7992 100644 --- a/measurement/fastscan.py +++ b/measurement/fastscan.py @@ -47,7 +47,7 @@ from utilities.math import sech2_fwhm, sin, gaussian_fwhm, gaussian, transient_1expdec, update_average from utilities.settings import parse_setting, parse_category, write_setting try: - raise Exception + # raise Exception from measurement.cscripts.project import project, project_r0 print('Successfully loaded cython projector') @@ -95,7 +95,7 @@ def __init__(self): self.spos_fit_pars = None # initialize the fit parameters for shaker position self.cryo = Cryostat(parse_setting('instruments','cryostat_com')) - self.delay_stage = StandaStage_8SMC5() + # self.delay_stage = StandaStage_8SMC5() self.timer = QtCore.QTimer() self.timer.setInterval(1) From 5c04a5ec1d8fd32218874f1a0b199994281045d8 Mon Sep 17 00:00:00 2001 From: Steinn Date: Fri, 17 Jan 2020 17:15:55 +0100 Subject: [PATCH 09/10] change stage control for THz setup --- instruments/delaystage/standa.py | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/instruments/delaystage/standa.py b/instruments/delaystage/standa.py index 4df32ea..ab54f93 100644 --- a/instruments/delaystage/standa.py +++ b/instruments/delaystage/standa.py @@ -37,7 +37,7 @@ from utilities.exceptions import DeviceNotFoundError from instruments.delaystage.generic import DelayStage, StageError -ximc_dir = 'E:/STANDA_TESTS/ximc-2.10.5/ximc/' +ximc_dir = 'C:/code/standa_stage/ximc-2.10.5/ximc/' ximc_package_dir = os.path.join(ximc_dir, "crossplatform", "wrappers", "python") sys.path.append(ximc_package_dir) if platform.system() == "Windows": @@ -349,7 +349,7 @@ def print_device_status(self): sc.connect(0) sc.print_device_status() print('Current speed settings: {}'.format(sc.speed)) - setspeed = 900 + setspeed = 400 sc.speed = setspeed print('Speed changed to {} speed settings reads: {}\n'.format(setspeed,sc.speed)) @@ -359,20 +359,20 @@ def print_device_status(self): sc.move_relative(moveby,unit='ps') print('\ncurrent pos: {} ps | {} um| {},{} step \n'.format(sc.position_ps,sc.position_um,*sc.position_step)) # - positions = np.linspace(100,110,1) - print(positions) - y = [] - for pos in positions: - print('going to pos {}'.format(pos)) - sc.move_absolute(pos) - y.append(sc.position_ps) - # import matplotlib.pyplot as plt - # plt.figure() - # plt.plot(positions,y) - # plt.show() - # TODO: try improve precision with accel and decel - for vv in zip(positions,y,(y-positions)*1000): - print(*vv,sep=' | ') - # print('---- Y ----\n',*y,sep='\n') - # print(*positions,sep='\n') + # positions = np.linspace(100,110,1) + # print(positions) + # y = [] + # for pos in positions: + # print('going to pos {}'.format(pos)) + # sc.move_absolute(pos) + # y.append(sc.position_ps) + # # import matplotlib.pyplot as plt + # # plt.figure() + # # plt.plot(positions,y) + # # plt.show() + # # TODO: try improve precision with accel and decel + # for vv in zip(positions,y,(y-positions)*1000): + # print(*vv,sep=' | ') + # # print('---- Y ----\n',*y,sep='\n') + # # print(*positions,sep='\n') sc.disconnect() From 61349513199d61548b89e66c6f7b19d2eac6002d Mon Sep 17 00:00:00 2001 From: Unknown Date: Mon, 20 Jan 2020 12:48:59 +0100 Subject: [PATCH 10/10] import fix --- instruments/delaystage/generic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/instruments/delaystage/generic.py b/instruments/delaystage/generic.py index 17765e9..3be8d39 100644 --- a/instruments/delaystage/generic.py +++ b/instruments/delaystage/generic.py @@ -20,6 +20,7 @@ """ from instruments import generic +import time class DelayStage(generic.Instrument): def __init__(self):