diff --git a/.gitignore b/.gitignore
index 5d5ff07..820848b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -110,3 +110,5 @@ ENV/
# PyCharm project settings
.idea
+
+tests/standa_prove.py
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/instruments/Standastage.py b/instruments/Standastage.py
deleted file mode 100644
index 07e1904..0000000
--- a/instruments/Standastage.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Created on Fri Apr 26 20:04:53 2019
-
-@author: vgrigore
-"""
-
-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
diff --git a/instruments/delaystage.py b/instruments/delaystage.py
deleted file mode 100644
index 3e6cfb4..0000000
--- a/instruments/delaystage.py
+++ /dev/null
@@ -1,260 +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
-try:
- import thorlabs_apt as apt
-except:
- print("no thorlabs_apt found")
-sys.path.insert(0,'./..')
-
-from instruments import generic
-#import _PyUSMC as _PyUSMC
-
-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
-#%%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
-
- 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 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()
\ No newline at end of file
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..dcd5799
--- /dev/null
+++ b/instruments/delaystage/__init__.py
@@ -0,0 +1,35 @@
+# -*- 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 .
+
+"""
+import logging
+from .generic import DelayStage
+from instruments.delaystage.standa import Standa_8SMC5
+
+
+logging.getLogger(__name__).addHandler(logging.NullHandler())
+
+
+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..3be8d39
--- /dev/null
+++ b/instruments/delaystage/generic.py
@@ -0,0 +1,81 @@
+# -*- 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 .
+
+"""
+from instruments import generic
+import time
+
+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
+
+
+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..64a78b3
--- /dev/null
+++ b/instruments/delaystage/newport.py
@@ -0,0 +1,117 @@
+# -*- 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 .
+
+"""
+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():
+ 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..ab54f93
--- /dev/null
+++ b/instruments/delaystage/standa.py
@@ -0,0 +1,378 @@
+# -*- 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 .
+
+"""
+import time
+import sys, os
+from instruments.delaystage.generic import DelayStage
+
+
+
+
+
+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 = '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":
+ 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 = 400
+ 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
new file mode 100644
index 0000000..01752f6
--- /dev/null
+++ b/instruments/delaystage/thorlabs.py
@@ -0,0 +1,61 @@
+# -*- 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 .
+
+"""
+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():
+ pass
+
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
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)
diff --git a/measurement/fastscan.py b/measurement/fastscan.py
index c5c9b7c..a6f7992 100644
--- a/measurement/fastscan.py
+++ b/measurement/fastscan.py
@@ -43,10 +43,11 @@
from scipy.optimize import curve_fit
from instruments.cryostat import ITC503s as Cryostat
+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:
- raise Exception
+ # raise Exception
from measurement.cscripts.project import project, project_r0
print('Successfully loaded cython projector')
@@ -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)
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
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
+
+