def _handleNewChunk(self, chunk): self._cumBuf = np.concatenate((self._cumBuf, chunk)) while len(self._cumBuf) >= self.chunkSize: properChunk = self._cumBuf[:self.chunkSize].copy() self._cumBuf = self._cumBuf[self.chunkSize:].copy() if self._axis is None: axis = Q_(np.arange(len(properChunk))) else: axis = self._axis.copy() properChunk = Q_(properChunk, 'V') dataSet = DataSet(properChunk, [axis]) self.set_trait('currentDataSet', dataSet) cur = time.perf_counter() rate = 1.0 / (cur - self._lastTime) self.set_trait('dataRate', Q_(rate, 'Hz')) self._lastTime = cur self._chunkReady(dataSet) for fut in self.__pendingFutures: if not fut.done(): fut.set_result(dataSet) self.__pendingFutures = []
def __init__(self, connection=None, axis=1, pitch=Q_(1), objectName=None, loop=None): """ Axis `axis` at connection `connection`. Has pitch `pitch` in units of 'full step count/length'.""" super().__init__(objectName=objectName, loop=loop) self.connection = connection self.axis = axis self._status = '?' self.set_trait('statusMessage', self._StatusMap[self._status]) self._isMovingFuture = asyncio.Future() self._isMovingFuture.set_result(None) self.prefPosUnit = (ureg.count / pitch).units self.prefVelocUnit = (ureg.count / ureg.s / pitch).units self.setPreferredUnits(self.prefPosUnit, self.prefVelocUnit) self._microstepResolution = 50 self._pitch = pitch self.define_context() if not pitch.dimensionless: self.velocity = Q_(1, 'mm/s') else: self.velocity = Q_(2000, 'count/s')
async def initialize(self): self.clearStack() self.set_trait('identification', await self._raw.nidentify(type=str)) limits = await self._raw.getnlimit(type=float) self._hardwareMinimum = Q_(limits[0], 'mm') self._hardwareMaximum = Q_(limits[1], 'mm') self.velocity = Q_(await self._raw.gnv(type=float), 'mm/s') # 500 mm/s accelleration should be good enough self._raw.sna(500)
def __init__(self, objectName=None, loop=None): super().__init__(objectName='PI tabular measurements', loop=loop) self.dataSaver = DataSaver(objectName="Data Saver") self.pi_conn = PI.Connection(PI_port) #self.mani_conn2 = PI.Connection(Manip2_comport) pi_stage = PI.AxisAtController(self.pi_conn) pi_stage.objectName = "PI C-867 DLine" pi_stage.setPreferredUnits(ureg.ps, ureg.ps / ureg.s) self.TimeDomainScan = Scan(objectName='TimeDomainScan') self.TimeDomainScan.manipulator = pi_stage resource = rm.open_resource(SR7230_LAN_Port) self.TimeDomainScan.dataSource = SR7230(resource, ethernet=True) self.TimeDomainScan.dataSource.objectName = "SR7230" self.TimeDomainScan.continuousScan = True self.TimeDomainScan.minimumValue = Q_(840, 'ps') self.TimeDomainScan.maximumValue = Q_(910, 'ps') self.TimeDomainScan.overscan = Q_(1, 'ps') self.TimeDomainScan.step = Q_(0.05, 'ps') self.TimeDomainScan.positioningVelocity = Q_(40, 'ps/s') self.TimeDomainScan.scanVelocity = Q_(1, 'ps/s') self.TimeDomainScan.retractAtEnd = True self.dataSource = self.TimeDomainScan self.mani_conn1 = PI.Connection(Manip1_comport) manipulator1 = PI.AxisAtController(self.mani_conn1) manipulator1.setPreferredUnits(ureg.mm, ureg.mm / ureg.s) manipulator1.objectName = "PI C-863 Manip" self.manipulator1 = manipulator1 self.positioningVelocityM1 = Q_(4, 'mm/s') self.scanVelocity = Q_(4, 'mm/s') manipulator2 = DummyManipulator( ) # PI.AxisAtController(self.mani_conn2) manipulator2.setPreferredUnits(ureg.mm, ureg.mm / ureg.s) manipulator2.objectName = 'DummyManipulator 2' self.manipulator2 = manipulator2 self.positioningVelocityM1 = Q_(4, 'mm/s') self.scanVelocity = Q_(4, 'mm/s') self.dataSaver.registerManipulator(self.manipulator1, 'Position1') self.dataSaver.registerManipulator(self.manipulator2, 'Position2') self.dataSaver.registerObjectAttribute(self, 'currentMeasurementName', 'currentTableEntry') self.dataSaver.fileNameTemplate = '{date}-{name}-{currentTableEntry}-{Position1}-{Position2}' self.dataSaver.set_trait('path', Path(r'')) self.TimeDomainScan.addDataSetReadyCallback(self.dataSaver.process) self.TimeDomainScan.addDataSetReadyCallback(self.setCurrentData) self._backAndForth = True
async def readDataSet(self): if self.samplingMode == SR7230.SamplingMode.SingleShot: data = np.array(await self.readCurrentOutput()) dataSet = DataSet(Q_(data), []) self._dataSetReady(dataSet) return dataSet elif self.samplingMode == SR7230.SamplingMode.Buffered: data = await self.readDataBuffer() data = np.array(data) dataSet = DataSet(Q_(data), [Q_(np.arange(0, len(data)))]) self._dataSetReady(dataSet) return dataSet
def __init__(self, objectName=None, loop=None): super().__init__(objectName='PI tabular measurements', loop=loop) self.dataSaver = DataSaver(objectName="Data Saver") self.pi_conn = PI.Connection(PI_Comport) self.mani_conn = PI.Connection(PI_Manipulator) pi_stage = PI.AxisAtController( self.pi_conn, ignore216=True) # ignore216 implemented by JanO Warning! pi_stage.objectName = "PI C-863 DLine" pi_stage.setPreferredUnits(ureg.ps, ureg.ps / ureg.s) self.TimeDomainScan = Scan(objectName='TimeDomainScan') self.TimeDomainScan.manipulator = pi_stage self.TimeDomainScan.dataSource = SR830(rm.open_resource(SR800_Port)) self.TimeDomainScan.dataSource.objectName = "SR830" self.TimeDomainScan.continuousScan = True self.TimeDomainScan.minimumValue = Q_(1250, 'ps') self.TimeDomainScan.maximumValue = Q_(1315, 'ps') self.TimeDomainScan.overscan = Q_(3, 'ps') self.TimeDomainScan.step = Q_(0.05, 'ps') self.TimeDomainScan.positioningVelocity = Q_(30, 'ps/s') self.TimeDomainScan.scanVelocity = Q_(1.6, 'ps/s') self.TimeDomainScan.retractAtEnd = True self.dataSource = self.TimeDomainScan manipulator1 = PI.AxisAtController( self.mani_conn, ignore216=True) # ignore216 implemented by JanO Warning! # ignore216 = True means that the error 216 (driven into end switch) will be ignored. There is a problem with the # PI stage being used as a manipulator. It is showing this error despite being far away form the end siwtch or even not moving manipulator1.setPreferredUnits(ureg.mm, ureg.mm / ureg.s) # added JanO 22.1.2019 manipulator1.objectName = 'PI C-863' self.manipulator1 = manipulator1 self.positioningVelocityM1 = Q_(4, 'mm/s') self.scanVelocity = Q_(4, 'mm/s') manipulator2 = TMCL(objectName="TMCL Rotator", port=tmcl_port) manipulator2.setPreferredUnits( ureg.deg, ureg.dimensionless) # ureg.dimensionless, ureg.mm / ureg.s self.manipulator2 = manipulator2 self.dataSaver.registerManipulator(self.manipulator1, 'Position') self.dataSaver.registerManipulator(self.manipulator2, 'Rotation') self.dataSaver.registerObjectAttribute(self, 'currentMeasurementName', 'currentTableEntry') self.dataSaver.fileNameTemplate = '{date}-{name}-{currentTableEntry}-{Position}-{Rotation}' self.dataSaver.set_trait('path', Path( 'E:/Messdaten/test/')) #added by Cornelius as standard savepath self.TimeDomainScan.addDataSetReadyCallback(self.dataSaver.process) self.TimeDomainScan.addDataSetReadyCallback(self.setCurrentData) self._backAndForth = True
async def singleUpdate(self): movFut = self._isMovingFuture self._status = await self.send("SRG?", 1) self.set_trait('value', Q_(await self.send(b'POS?'), 'mm')) self.set_trait('isReferenced', bool(await self.send(b'FRF?'))) self.set_trait('isReferencing', bool(self._status & self.StatusBits.Referencing.value)) self.set_trait('isOnTarget', bool(self._status & self.StatusBits.OnTarget.value)) self.set_trait('isServoOn', bool(self._status & self.StatusBits.ServoMode.value)) self.set_trait( 'isMoving', bool(self._status & self.StatusBits.Moving.value) or self.isReferencing) if self.isMoving: self.set_trait('status', self.Status.Moving) else: self.set_trait('status', self.Status.Idle) if not movFut.done() and not self.isMoving: movFut.set_result(None)
async def singleUpdate(self): val = IselStage.cdll.stagedriver_current_position(self.handle) self.set_trait('value', Q_(val, 'microm')) self._updateDigitalInputFlags() self._updateStatusWord() self._updateErrorByte() hm = bool(IselStage.cdll.stagedriver_homing_complete(self.handle)) tr = bool(IselStage.cdll.stagedriver_target_reached(self.handle)) mv = bool(IselStage.cdll.stagedriver_movement_active(self.handle)) self.set_trait('homingComplete', hm) self.set_trait('isOnTarget', tr) self.set_trait('isMoving', mv) if not self.isMoving: self.set_trait('status', self.Status.Idle) if not self._isMovingFuture.done(): self._isMovingFuture.set_result(None) else: self.set_trait('status', self.Status.Moving) self._isOpen = bool(IselStage.cdll.stagedriver_is_open(self.handle)) if not self._isOpen: logging.info('Connection To IselStage at ' + self.comport + ' Lost')
class ThorlabsPM100(DataSource): power = Quantity(Q_(0, 'mW'), read_only=True).tag(name='Power') def __init__(self, resource=None, objectName=None, loop=None): super().__init__(objectName, loop) self._lock = Lock() self.resource = resource async def __aenter__(self): await super().__aenter__() self._continuousUpdateFut = \ ensure_weakly_binding_future(self._continuousRead) return self async def __aexit__(self, *args): await super().__aexit__(*args) self._continuousUpdateFut.cancel() async def _continuousRead(self): while True: await self.readDataSet() await asyncio.sleep(0.1) @threaded_async def _guardedRead(self): with self._lock: return float(self.resource.ask('READ?')) async def readDataSet(self): val = await self._guardedRead() * 1000 dset = DataSet(Q_(np.array(val), 'mW')) self.set_trait('power', Q_(val, 'mW')) self._dataSetReady(dset)
async def readAllParameters(self): self._traitChangesDueToStatusUpdate = True for name, trait in self.traits().items(): command = trait.metadata.get('command') if command is None: continue else: auxs = '' if command.find('AUX') >= 0: auxs = ' ' + name[-1] result = await self.query(command + '?' + auxs) if isinstance(trait, traitlets.Enum): val = int(result) val = [item for item in trait.values if item.value == val][0] elif isinstance(trait, Quantity): val = Q_(float(result), trait.default_value.units) elif isinstance(trait, traitlets.Integer): val = int(result) self.set_trait(name, val) self._traitChangesDueToStatusUpdate = False logging.info('SR830: Lockin-Parameter read')
async def getVelocity(self): #seems not to work ? #vel = self.send(str(self.axis) + 'R4000074010')[4:] vel = await self.connection.send(self.axis + b'R4000004040') vel = vel[4:] vel = Q_(int(vel, 16) / 300.0 * self._leadpitch, 'mm/s') return vel
async def readAllParameters(self): """ Reads all parameters from the device and updates the attributes of this class accordingly. """ self._traitChangesDueToStatusUpdate = True for name, trait in self.traits().items(): command = trait.metadata.get('command') if command is None: continue else: answer = await self.query(command) if len(answer) == 1: result = answer[0] else: result = answer if isinstance(trait, traitlets.Enum): if len(answer) == 1: val = int(result) val = [item for item in trait.values if item.value == val][0] else: res = [] for i in answer: ival = int(i) res.append(ival) # if first element is 0, (like [0, 1]) then LF is off if res[0] != 0: val = [ item for item in trait.values if item.value == res ][0] else: val = list(trait.values)[0] elif isinstance(trait, Quantity): val = Q_(float(result), trait.default_value.units) elif isinstance(trait, traitlets.Int): val = int(result) elif isinstance(trait, traitlets.Bool): result_int = 0 try: result_int = int(result) except ValueError: print('Failed to read answer from ' + command + " answer was " + str(result)) logging.info('Failed to read answer from ' + command + " answer was " + str(result)) val = True if result_int == 1 else False else: val = result self.set_trait(name, val) self._traitChangesDueToStatusUpdate = False logging.info('SR7230: Lockin-Parameter read')
def __init__(self, port, baud=9600, axis=0, objectName=None, loop=None): super().__init__(objectName=objectName, loop=loop) self.comm_lock = Lock() self.comm = TMCLCommunicator(port, 1, 4, 0, float('inf'), float('inf'), float('inf')) self.comm._ser.baudrate = baud self.axis = axis self.setPreferredUnits(ureg.deg, ureg.dimensionless) self.velocity = Q_(20) self.set_trait('value', Q_(0, 'deg')) self.set_trait('status', self.Status.Idle) self._isMovingFuture = asyncio.Future() self._isMovingFuture.set_result(None)
def _handleNewDataSet(self): read = mx.int32() buf = np.zeros((self.dataPoints, )) self.currentTask.ReadAnalogF64( mx.DAQmx_Val_Auto, 0, # timeout mx.DAQmx_Val_GroupByScanNumber, buf, buf.size, mx.byref(read), None) dset = DataSet(Q_(buf, 'V'), [self._axis.copy()]) self._currentFuture.set_result(dset) self.set_trait('dataSet', dset) cur = time.perf_counter() rate = 1.0 / (cur - self._lastTime) self.set_trait('dataRate', Q_(rate, 'Hz')) self._loop.create_task(self.stop()) return 0
async def _singleUpdate(self): stepPos = await self._get_param(1) self.set_trait('value', Q_(self._steps2angle(stepPos), 'deg')) movFut = self._isMovingFuture if not movFut.done(): # check for target reached reached = await self._get_param(8) if reached and not movFut.done(): movFut.set_result(None)
def __init__(self, objectName=None, loop=None): super().__init__(objectName='Goniometer Scan', loop=loop) self.dataSaver = DataSaver(objectName="Data Saver") self.pi_conn = PI.Connection(PI_Comport) pi_stage = PI.AxisAtController(self.pi_conn) pi_stage.objectName = "PI C-863" pi_stage.setPreferredUnits(ureg.ps, ureg.ps / ureg.s) self.manipulator = pi_stage self.dataSource = SR830(rm.open_resource(SR800_Port)) self.dataSource.objectName = "SR830" self.continuousScan = True self.minimumValue = Q_(1180, 'ps') self.maximumValue = Q_(1250, 'ps') self.overscan = Q_(3, 'ps') self.step = Q_(0.05, 'ps') self.positioningVelocity = Q_(30, 'ps/s') self.scanVelocity = Q_(1, 'ps/s') self.dataSaver.fileNameTemplate = '{date}-{name}' self.addDataSetReadyCallback(self.dataSaver.process) self._backAndForth = True
async def configureTrigger(self, axis, triggerId=1): axis = axis.to('mm').magnitude step = np.mean(np.diff(axis)) start = axis[0] N = len(axis) # let the trigger output end half a step after the last position stop = start + (N - 1) * step + step / 2 # enable trig output on axis await self.send(b"CTO", triggerId, 2, self.axis, includeAxis=False) # set trig output to pos+offset mode await self.send(b"CTO", triggerId, 3, 7, includeAxis=False) # set trig distance to ``step`` await self.send(b"CTO", triggerId, 1, step, includeAxis=False) # trigger start position await self.send(b"CTO", triggerId, 10, start, includeAxis=False) # trigger stop position await self.send(b"CTO", triggerId, 9, stop, includeAxis=False) # enable trigger output await self.send(b"TRO", triggerId, 1, includeAxis=False) # ask for the actually set start, stop and step parameters self._trigStep = Q_( await self.send(b"CTO?", triggerId, 1, includeAxis=False), 'mm') self._trigStart = Q_( await self.send(b"CTO?", triggerId, 10, includeAxis=False), 'mm') self._trigStop = Q_( await self.send(b"CTO?", triggerId, 9, includeAxis=False), 'mm') return np.arange(self._trigStart.magnitude, self._trigStop.magnitude, self._trigStep.magnitude) * ureg.mm
async def statusUpdate(self): """ Performs a status update and updates the class attributes according to answers from the device. """ if self.status != Manipulator.Status.Moving and self.status != Manipulator.Status.Error: # and not self.stopped: currentPosition = (await self.query("@0P"))[0] # print("pos answer: " + str(currentPosition)) currentPosition = int(currentPosition, 16) self.set_trait('value', Q_(currentPosition / self.stepsPerRev, 'cm')) self._isMovingFuture.set_result(None)
async def singleUpdate(self): movFut = self._isMovingFuture self._status = await self._raw.nst(type=int) self.set_trait('value', Q_(await self._raw.np(type=float), 'mm')) self.set_trait('numberParamStack', await self._raw.gsp(includeAxis=False, type=int)) self.set_trait( 'status', self.Status.Moving if bool(self._status & self.StatusBits.AxisMoving.value) else self.Status.Idle) if self.status != self.Status.Moving and not movFut.done(): movFut.set_result(None)
async def __aenter__(self): await super().__aenter__() self._identification = await self.send(b'*IDN?', includeAxis=False) self._hardwareMinimum = await self.send(b'TMN?') self._hardwareMaximum = await self.send(b'TMX?') self.velocity = Q_(await self.send(b'VEL?'), 'mm/s') self._isReferenced = bool(await self.send(b'FRF?')) await self.send("RON", 1) await self.send("SVO", 1) self._updateFuture = ensure_weakly_binding_future(self.updateStatus) return self
async def setVelocity(self, velocity=Q_(10, 'mm/s'), acceleration=0.1): velocity = int(velocity.to('mm/s').magnitude * 300 / self._leadpitch) velocity = b'%04X' % velocity if len(velocity) > 4: logging.info('IAI {}: velocity too high'.format(self.axis)) velocity = b'02EE' acceleration = int(acceleration * 5883.99 / self._leadpitch) acceleration = b'%04X' % acceleration if len(acceleration) > 4: logging.info('IAI {}: acceleration too high'.format(self.axis)) acceleration = b'0093' sendstr = self.axis + b'v2' + velocity + acceleration + b'0' await self.connection.send(sendstr)
async def run(): transport, hydra = await loop.create_connection( Hydra, 'localhost', 4000) async with hydra: print("Moving to start...") await hydra.moveTo(Q_(20, 'mm'), Q_(10, 'mm/s')) await hydra.configureTrigger(Q_(0.05, 'mm'), Q_(21, 'mm'), Q_(29, 'mm')) print("Moving to end...") fut = loop.create_task(hydra.moveTo(Q_(30, 'mm'), Q_(5, 'mm/s'))) while not fut.done(): print("Position:", hydra.value) await asyncio.sleep(0.5) print("Done.")
async def reference(self): if self.isMoving: logging.info('{} {}: Please finish'.format(self, self.axis) + 'movement before searching Limit Switch') return False self._setSpeedProfile(Q_(5, 'deg/s')) self.cdll.SetRunFreeFrq(self.axis, 100) self.cdll.SetRunFreeSteps(self.axis, 32000) self.cdll.SearchLS(self.axis, ord('-')) self._isMovingFuture = asyncio.Future() await self._isMovingFuture self.cdll.FindLS(self.axis, ord('-')) self.cdll.RunLSFree(self.axis, ord('-')) self._isMovingFuture = asyncio.Future() await self._isMovingFuture self.cdll.SetPosition(self.axis, 0)
def __init__(self, axis=0, encoderMode=EncoderMode.A_BSignal4fold, objectName=None, loop=None): super().__init__(objectName, loop) self.setPreferredUnits(ureg.deg, ureg.deg / ureg.s) if Goniometer.connection is None: Goniometer.connection = GonioConn() self.cdll = Goniometer.connection.dll self.axis = axis self.cdll.InitEncoder(self.axis, encoderMode.value) self.cdll.SetEncoder(self.axis, 0) self.cdll.SetRunFreeFrq(self.axis, 100) self.cdll.SetRunFreeSteps(self.axis, 32000) # don't know if important self.cdll.SetPosition(self.axis, 0) self.set_trait('value', self._stepToDeg( self.cdll.GetPosition(self.axis))) self.velocity = Q_(5, 'deg/s') self._statusRefresh = 0.1 self._isMovingFuture = asyncio.Future() self._isMovingFuture.set_result(None) self._updateFuture = ensure_weakly_binding_future(self.updateStatus)
async def run(loop): async with Goniometer(1, objectName='Detektor') as detector: async with Goniometer(0, objectName='Emitter') as emitter: async with TimeDomainScan(loop=loop) as tdscan: detector.calibrate(Q_(180.0, 'deg')) emitter.calibrate(Q_(180.0, 'deg')) for angle in np.arange(10, 80, 1): emitterpos = 90 + angle detectorpos = 270 - angle await asyncio.wait([ detector.moveTo(Q_(detectorpos, 'deg')), emitter.moveTo(Q_(emitterpos, 'deg')) ]) print('angle: {}'.format(angle)) tdscan.dataSaver.mainFileName = 'Referenz-{}'.format(angle) await tdscan.readDataSet() await asyncio.wait([ detector.moveTo(Q_(180, 'deg')), emitter.moveTo(Q_(180, 'deg')) ])
class IselIT116(Manipulator): class AxisDirection(enum.Enum): Normal = 0 Inverse = 1 class ReferenceDirection(enum.Enum): Normal = 0 Inverse = 1 class LimitSwitch1(enum.Enum): Disabled = 0 Enabled = 1 class LimitSwitch2(enum.Enum): Disabled = 0 Enabled = 1 class ActiveLevelLimitSwitch1(enum.Enum): LowActive = 0 HighActive = 1 class ActiveLevelLimitSwitch2(enum.Enum): LowActive = 0 HighActive = 1 DEFAULT_TIMEOUT = 1000 MOVEMENT_TIMEOUT = 100000 STATUS_UPDATE_RATE = 3 # Instrument Info Traitlets controlUnitInfo = traitlets.Unicode(read_only=True, name="Control Unit Info", group="Instrument Info") # Parameters # Todo: find correct default value referenceSpeed = traitlets.Int(name="Reference Speed", group="Parameters", default_value=900, max=2500, command="@0d") acceleration = Quantity(name="Acceleration", group="Parameters", default_value=Q_(100, "Hz/ms"), min=Q_(1, "Hz/ms"), max=Q_(1000, "Hz/ms"), command="@0g") startStopFrequency = Quantity(name="Start Stop Frequency", group="Parameters", default_value=Q_(300, "Hz"), min=Q_(20, "Hz"), max=Q_(40000, "Hz"), command="@0j") axisDirection = traitlets.Enum(AxisDirection, name="Axis Direction", group="Parameters", default_value=AxisDirection.Normal, command="@0ID") referenceDirection = traitlets.Enum( ReferenceDirection, name="Reference Direction", group="Parameters", default_value=ReferenceDirection.Normal) # Relative Movement relativeMovementPath = traitlets.Int(name="Movement Path", group="Relative Movement", default_value=0) relativeMovementSpeed = traitlets.Int(name="Speed", group="Relative Movement", default_value=900) # Absolute Movement absoluteMovementPosition = traitlets.Int(name="Target Position", group="Absolute Movement", default_value=0) absoluteMovementSpeed = traitlets.Int(name="Speed", group="Absolute Movement", default_value=900) stopped = traitlets.Bool(name="Stopped", default_value=False, read_only=True) parameterTraits = [ "referenceSpeed", "acceleration", "startStopFrequency", "axisDirection", "referenceDirection" ] def __init__(self, comport, baudRate=19200, stepsPerRev=800, objectName=None, loop=None): """ Parameters ---------- """ super().__init__(objectName, loop) self._lock = Lock() self.comport = comport self.stepsPerRev = 2 * stepsPerRev # not sure if correct (@0P gives correct distance) if os.name == 'posix': rm = visa.ResourceManager('@py') elif os.name == 'nt': rm = visa.ResourceManager() try: self.resource = rm.open_resource(comport) except visa.errors.VisaIOError: raise Exception('Failed to open Isel IT116 stage at comport: ' + comport) self.resource.read_termination = '' self.resource.write_termination = chr(13) # CR self.resource.baud_rate = baudRate self.resource.timeout = self.DEFAULT_TIMEOUT self.setPreferredUnits(ureg.mm, ureg.mm / ureg.s) self.observe(self.setParameterOnDevice, self.parameterTraits) self.set_trait('status', self.Status.Idle) self._isMovingFuture = asyncio.Future() self._isMovingFuture.set_result(None) async def __aenter__(self): await super().__aenter__() await self.initializeControlUnit() await self.getControlUnitInfo() await self.statusUpdate() self._statusUpdateFuture = ensure_weakly_binding_future( self.continuousStatusUpdate) return self async def __aexit__(self, *args): await super().__aexit__(*args) self._statusUpdateFuture.cancel() @action("Stop") def stop(self): self.resource.write_raw(bytes([253])) asyncio.ensure_future(self.stopImplementation()) async def stopImplementation(self): result = await self.read() self.set_trait("stopped", True) if result is None: return result = result[0:-2] if result == "STOP": self.set_trait("stopped", False) if not self._isMovingFuture.done(): self._isMovingFuture.cancel() @action("Start") async def start(self): """ Sends a start command to the device after it has been stopped. Due to weird behavior of the device, this function first executes a break command causing the device to forget the last movement command. """ await self.softwareBreak() result = (await self.query("@0S"))[0] print("start result: " + result) if result == "0" or result == "G": self.set_trait("stopped", False) # await asyncio.sleep(0.1) await self.read() self.set_trait("status", self.Status.Idle) @action("Break") async def softwareBreak(self): self.resource.write_raw(bytes([255])) await self.read() @action("Software Reset") async def softwareReset(self): self.resource.write_raw(bytes([254])) await self.read() @action("Load Parameters from Flash", group="Parameters") async def loadParametersFromFlash(self): await self.write("@0IL") @action("Save Parameters to Flash", group="Parameters") async def saveParametersToFlash(self): await self.write("@0IW") @action("Load Default Parameters", group="Parameters") async def loadDefaultParameters(self): await self.write("@0IX") @action("Reference Run") async def referenceRun(self): await self.executeMovementCommand("@0R1") @action("Simulate Reference Run") async def simulateReferenceRun(self): await self.write("@0N1") @action("Set Zero Point") async def setZeroPointCurrentLocation(self): await self.write("@0n1") @action("Move", group="Absolute Movement") async def moveAbsolute(self): await self.moveTo(self.absoluteMovementPosition, self.absoluteMovementSpeed) @action("Move", group="Relative Movement") async def moveRelative(self): command = "@0A" + str(self.relativeMovementPath) + "," + str( self.relativeMovementSpeed) await self.executeMovementCommand(command) @threaded_async def query(self, command, timeout=None): """ Sends a command to the device and reads the answer. Parameters ---------- command : str The command to send to the device. timeout : int Custom timeout in ms. Returns ------- list A list of answer strings from the device. """ with self._lock: # remove parameter placeholders from command paramIndex = command.find(" {}") if paramIndex != -1: command = command[:paramIndex] print('IselIT116: query ' + str(command)) logging.info('{}: {}'.format(self, command)) if timeout is not None: prevTimeout = self.resource.timeout self.resource.timeout = timeout self.resource.write(command) answerBytes = self.readAllBytes() answerString = b''.join(answerBytes).decode("utf-8") print('IselIT116: answer: ' + answerString) if timeout is not None: self.resource.timeout = prevTimeout result = [] for s in str.split(answerString, ','): result.append(s) return result @threaded_async def write(self, command, lock=True): """ Sends a command to the device. Parameters ---------- command : str The command to send to the device. lock : bool Use the lock if true. Prevents simultaneous access on the instrument. """ logging.info('{}: {}'.format(self, command)) if lock: with self._lock: self.resource.write(command) self.readAllBytes() else: self.resource.write(command) self.readAllBytes() @threaded_async def read(self): """ Reads the current content of the receive buffer Returns ------- result : str The read content of the receive buffer. """ with self._lock: readBytes = self.readAllBytes() if len(readBytes) > 0: result = b''.join(readBytes).decode("utf-8") print("read(): result: " + result) return result def readAllBytes(self): """ Reads all bytes from the receive buffer. Returns ------- allBytes : list All bytes read from the receive buffer. """ time.sleep( 0.05 ) # self.resource.bytes_in_buffer gives wrong result if called right after write allBytes = [] try: allBytes.append(self.resource.read_bytes(1)) except: print("readAllBytes: no bytes in buffer") while self.resource.bytes_in_buffer > 0: allBytes.append(self.resource.read_bytes(1)) # some commands return "0" "handshake" before actual value # this is probably the wrong way to handle it if (allBytes[0] == b'0' and len(allBytes) != 1): allBytes = allBytes[1:] return allBytes def setParameterOnDevice(self, change): """ Sets parameter on the device. This is the function that is called by all traits that get observed. Tries to update the changed attribute on the device by sending the corresponding command. Parameters ---------- change : list change object of the observed trait. """ trait = self.traits().get(change['name']) command = trait.metadata.get('command') value = change['new'] if command is None: return self.set_trait(trait.name, value) if isinstance(value, enum.Enum): value = value.value elif isinstance(value, Q_): value = value.magnitude elif isinstance(value, bool): value = 1 if value else 0 commandString = str() paramIndex = command.find("{}") if paramIndex == -1: commandString = command + '{}'.format(value) elif command.find("{},{}") != -1: commandString = command.format(value[0], value[1]) elif paramIndex != -1: commandString = command.format(value) asyncio.ensure_future(self.write(commandString)) async def continuousStatusUpdate(self): """ Requests a status update every STATUS_UPDATE_RATE seconds. """ while True: await asyncio.sleep(self.STATUS_UPDATE_RATE) await self.statusUpdate() async def statusUpdate(self): """ Performs a status update and updates the class attributes according to answers from the device. """ if self.status != Manipulator.Status.Moving and self.status != Manipulator.Status.Error: # and not self.stopped: currentPosition = (await self.query("@0P"))[0] # print("pos answer: " + str(currentPosition)) currentPosition = int(currentPosition, 16) self.set_trait('value', Q_(currentPosition / self.stepsPerRev, 'cm')) self._isMovingFuture.set_result(None) async def initializeControlUnit(self): """ Initialisation, setting number of axes. """ await self.write("@01") async def getControlUnitInfo(self): """ Queries info of the control unit. """ info = await self.query("@0V") info = info[0] self.set_trait("controlUnitInfo", info[0:-2]) async def moveTo(self, val: float, velocity=None): if self.stopped: print("Device is stopped. Can't process commands until started") return self.__blockTargetValueUpdate = True if velocity is None: velocity = self.velocity if not isinstance(val, int) and not isinstance(val, float): val = val.to("cm").magnitude val *= self.stepsPerRev val = int(val) if not isinstance(velocity, int) and not isinstance(velocity, float): velocity = velocity.to('cm/s').magnitude velocity *= 1600 # self.stepsPerRev ? velocity = int(velocity) # print("speed: " + str(velocity)) command = "@0M" + str(val) + "," + str(velocity) await self.executeMovementCommand(command) self.__blockTargetValueUpdate = False async def executeMovementCommand(self, command): """ Sends a command to the instrument that results in a movement of the axis. Since the IT116 can't process any other commands until the movement is completed, this function waits for the device's response that the movement was completed. Also sets the status to moving while the stage is moving. Parameters ---------- command : str Movement command to send to the device. """ self.set_trait("status", self.Status.Moving) result = (await self.query(command, self.MOVEMENT_TIMEOUT))[0] self._isMovingFuture = asyncio.Future() print("movement result: " + result) if result == "0": self.set_trait("status", self.Status.Idle) await self.statusUpdate() elif result == "F": print("movement stopped") logging.info('{}: {}'.format(self, "movement stopped. Press start")) self.set_trait("status", self.Status.Error) else: self.set_trait("status", self.Status.Error) async def waitForTargetReached(self): return await self._isMovingFuture
class SR7230(DataSource): """ Implementation of the Lock-In SR7230 as a DataSource This class implements the Lock-In Amplifier SR7230 as a DataSource using PyVisa for the connection to the device. Most attributes of this class represent attributes of the device. Refer to the official manual of the SR7230 for more details. """ class SamplingMode(enum.Enum): SingleShot = 0 Buffered = 1 # Signal Channel class InputMode(enum.Enum): VoltageInputMode = 0 CurrentModeHighBandwidth = 1 CurrentModeLowNoise = 2 class VoltageInputMode(enum.Enum): BothInputsGrounded = 0 AInputOnly = 1 BInputOnly = 2 ABDifferentialMode = 3 class InputConnectorShieldControl(enum.Enum): Ground = 0 Float = 1 class InputDevice(enum.Enum): Bipolar = 0 FET = 1 class InputCoupling(enum.Enum): AC = 0 DC = 1 class SensitivityIMode0(enum.Enum): Sens_10nV = 3 Sens_20nV = 4 Sens_50nV = 5 Sens_100nV = 6 Sens_200nV = 7 Sens_500nV = 8 Sens_1muV = 9 Sens_2muV = 10 Sens_5muV = 11 Sens_10muV = 12 Sens_20muV = 13 Sens_50muV = 14 Sens_100muV = 15 Sens_200muV = 16 Sens_500muV = 17 Sens_1mV = 18 Sens_2mV = 19 Sens_5mV = 20 Sens_10mV = 21 Sens_20mV = 22 Sens_50mV = 23 Sens_100mV = 24 Sens_200mV = 25 Sens_500mV = 26 Sens_1V = 27 class ACGain(enum.Enum): Gain_0dB = 0 Gain_6dB = 1 Gain_12dB = 2 Gain_18dB = 3 Gain_24dB = 4 Gain_30dB = 5 Gain_36dB = 6 Gain_42dB = 7 Gain_48dB = 8 Gain_54dB = 9 Gain_60dB = 10 Gain_66dB = 11 Gain_72dB = 12 Gain_78dB = 13 Gain_84dB = 14 Gain_90dB = 15 class ACGainControl(enum.Enum): Manual = 0 Automatic = 1 class NotchFilter(enum.Enum): Off = [0, 0] NotchFilter_50Hz = [1, 0] NotchFilter_60Hz = [1, 1] NotchFilter_100Hz = [2, 0] NotchFilter_120Hz = [2, 1] NotchFilter_50Hz_100Hz = [3, 0] NotchFilter_60Hz_120Hz = [3, 1] class NotchFilters(enum.Enum): Off = 0 NotchFilter50or60Hz = 1 NotchFilter100or120Hz = 2 Both = 3 class NotchFilterCenterFrequencies(enum.Enum): Freq_60_120_Hz = 0 Freq_50_100_Hz = 1 # Reference Channel class ReferenceMode(enum.Enum): SingleReference = 0 DualHarmonic = 1 DualReference = 2 class ReferenceSource(enum.Enum): Internal = 0 ExternalTTL = 1 ExternalAnalog = 2 class ReferenceChannelSelection(enum.Enum): CH1_Internal_CH2_External = 0 CH2_Internal_CH1_External = 1 class ReferenceMonitorControl(enum.Enum): TrigOutByCurveBuffer = 0 TrigOutTTLAtReferenceFreq = 1 # Signal Channel Output Filters class FilterTimeConstant(enum.Enum): TimeConstant_10mus = 0 TimeConstant_20mus = 1 TimeConstant_50mus = 2 TimeConstant_100mus = 3 TimeConstant_200mus = 4 TimeConstant_500mus = 5 TimeConstant_1ms = 6 TimeConstant_2ms = 7 TimeConstant_5ms = 8 TimeConstant_10ms = 9 TimeConstant_20ms = 10 TimeConstant_50ms = 11 TimeConstant_100ms = 12 TimeConstant_200ms = 13 TimeConstant_500ms = 14 TimeConstant_1s = 15 TimeConstant_2s = 16 TimeConstant_5s = 17 TimeConstant_10s = 18 TimeConstant_20s = 19 TimeConstant_50s = 20 TimeConstant_100s = 21 TimeConstant_200s = 22 TimeConstant_500s = 23 TimeConstant_1ks = 24 TimeConstant_2ks = 25 TimeConstant_5ks = 26 TimeConstant_10ks = 27 TimeConstant_20ks = 28 TimeConstant_50ks = 29 TimeConstant_100ks = 30 class LowPassFilterSlope(enum.Enum): FilterSlope_6db_octave = 0 FilterSlope_12db_octave = 1 FilterSlope_18db_octave = 2 FilterSlope_24db_octave = 3 # Curve Buffer class CurveBufferMode(enum.Enum): Standard = 0 Fast = 1 class CurveBufferTriggerOutput(enum.Enum): PerCurve = 0 PerPoint = 1 class CurveBufferTriggerOutputPolarity(enum.Enum): RisingEdge = 0 FallingEdge = 1 class TakeDataMode(enum.Enum): TakeData = 0 TakeDataTriggered = 1 TakeDataContinuously = 2 class TakeDataTriggeredTriggerMode(enum.Enum): Start_ExtRising_Sample_NA_Stop_LEN = 0 Start_Cmd_Sample_ExtRising_Stop_LEN = 1 Start_ExtFalling_Sample_NA_Stop_LEN = 2 Start_Cmd_Sample_ExtFalling_Stop_LEN = 3 Start_ExtRising_Sample_NA_Stop_Cmd = 4 Start_Cmd_Sample_ExtRising_Stop_Cmd = 5 Start_ExtFalling_Sample_NA_Stop_Cmd = 6 Start_Cmd_Sample_ExtFalling_Stop_Cmd = 7 Start_ExtRising_Sample_NA_Stop_ExtFalling = 8 Start_ExtFalling_Sample_NA_Stop_ExtRising = 9 class StatusBits(enum.Enum): CommandComplete = 0x1 InvalidCommand = 0x2 CommandParameterError = 0x4 ReferenceUnlock = 0x8 OutputOverload = 0x10 NewADCValues = 0x20 InputOverload = 0x40 DataAvailable = 0x80 class OverloadBits(enum.Enum): X = 0x1 Y = 0x2 X2 = 0x4 Y2 = 0x8 CH1 = 0x10 CH2 = 0x20 CH3 = 0x40 CH4 = 0x80 class CurveAcquisitionStatusInts(enum.Enum): NoCurveActivity = 0 AcquisitionTD = 1 AcquisitionTDC = 2 AcquisitionHaltedTD = 5 AcquisitionHaltedTDC = 6 statusMessages = { 'overload': { 0x1: 'X channel output overload', 0x2: 'Y channel output overload', 0x4: 'X2 channel output overload', 0x8: 'Y2 channel output overload', 0x10: 'CH1 channel output overload', 0x20: 'CH2 channel output overload', 0x40: 'CH3 channel output overload', 0x80: 'CH4 channel output overload' } } STATUS_UPDATE_RATE = 5 # Instrument Info Traitlets identification = traitlets.Unicode(read_only=True, name="Identification", group="Instrument Info") instrumentName = traitlets.Unicode(name="Instrument Name", group="Instrument Info", command="NAME") firmwareVersion = traitlets.Unicode(read_only=True, name="Firmware Version", group="Instrument Info") # General Traitlets Traitlets samplingMode = traitlets.Enum( SamplingMode, SamplingMode.Buffered).tag(name="Sampling mode") # Signal Channel Traitlets inputMode = traitlets.Enum(InputMode, default_value=InputMode.VoltageInputMode).tag( group="Signal Channel", command="IMODE") voltageInputMode = traitlets.Enum(VoltageInputMode).tag( group="Signal Channel", command="VMODE") inputConnectorShieldControl = traitlets.Enum(InputConnectorShieldControl, default_value=InputConnectorShieldControl.Ground) \ .tag(group="Signal Channel", command="FLOAT") inputDevice = traitlets.Enum( InputDevice, default_value=InputDevice.FET).tag(group="Signal Channel", command="FET") inputCoupling = traitlets.Enum(InputCoupling, default_value=InputCoupling.AC).tag( group="Signal Channel", command="DCCOUPLE") sensitivity = traitlets.Enum( SensitivityIMode0, default_value=SensitivityIMode0.Sens_200mV).tag(group="Signal Channel", command="SEN") acGain = traitlets.Enum(ACGain, default_value=ACGain.Gain_0dB).tag( group="Signal Channel", command="ACGAIN") acAutomaticGainControl = traitlets.Bool(default_value=False, group="Signal Channel", command="AUTOMATIC") notchFilter = traitlets.Enum(NotchFilter, default_value=NotchFilter.Off, group="Signal Channel", command="LF {} {}") # Reference Channel Traitlets referenceMode = traitlets.Enum(ReferenceMode, default_value=ReferenceMode.SingleReference, group="Reference Channel", command="REFMODE") referenceSource = traitlets.Enum(ReferenceSource, default_value=ReferenceSource.Internal, group="Reference Channel", command="IE") referenceChannelSelection = traitlets.Enum(ReferenceChannelSelection, group="Reference Channel", command="INT") referenceHarmonicMode = traitlets.Int(default_value=1, min=1, max=127, group="Reference Channel", command="REFN") referenceMonitorControl = traitlets.Enum(ReferenceMonitorControl, group="Reference Channel", command="REFMON") referencePhase = Quantity(default_value=Q_(0, "mdeg"), min=Q_(-360000, "mdeg"), max=Q_(360000, "mdeg")) referencePhase.tag(group="Reference Channel", command="REFP") referenceFrequencyMeter = Quantity(default_value=Q_(0, 'mHz'), read_only=True) referenceFrequencyMeter.tag(group="Reference Channel", command="FRQ") enterVirtualReferenceMode = traitlets.Bool(group="Reference Channel", command="VRLOCK") # Signal Channel Output Filters noiseMode = traitlets.Bool(default_value=False, read_only=True, group="Signal Channel Output Filters", command="NOISEMODE") fastMode = traitlets.Bool(default_value=True, read_only=False, group="Signal Channel Output Filters", command="FASTMODE") filterTimeConstant = traitlets.Enum(FilterTimeConstant, group="Signal Channel Output Filters", command="TC") synchronousTimeConstantControl = traitlets.Bool( default_value=True, group="Signal Channel Output Filters", command="SYNC") lowPassFilterSlope = traitlets.Enum( LowPassFilterSlope, default_value=LowPassFilterSlope.FilterSlope_12db_octave, group="Signal Channel Output Filters", command="SLOPE") # Data Curve Buffer Traitlets bufferMode = traitlets.Enum(CurveBufferMode, default_value=CurveBufferMode.Standard, read_only=True, command="CMODE", group="Data Curve Buffer") bufferTriggerOutput = traitlets.Enum(CurveBufferTriggerOutput, command="TRIGOUT", group="Data Curve Buffer") bufferTriggerOutputPolarity = traitlets.Enum( CurveBufferTriggerOutputPolarity, command="TRIGOUTPOL", group="Data Curve Buffer") storageTimeInterval = traitlets.Int(default_value=10).tag( name="Storage Time Interval", command="STR", group="Data Curve Buffer") bufferLength = traitlets.Int(default_value=100000).tag( name="Buffer Length", command="LEN", group="Data Curve Buffer") takeDataMode = traitlets.Enum(TakeDataMode, TakeDataMode.TakeDataTriggered).tag( name="Take Data Mode", group="Data Curve Buffer") takeDataTriggeredTriggerMode = traitlets.Enum( TakeDataTriggeredTriggerMode, default_value=TakeDataTriggeredTriggerMode. Start_Cmd_Sample_ExtRising_Stop_Cmd, group="Data Curve Buffer") curveAcquisitionInProgressTD = traitlets.Bool( default_value=False, read_only=True).tag(name="Acquisition in Progress by TD", group='Data Curve Buffer') curveAcquisitionInProgressTDC = traitlets.Bool( default_value=False, read_only=True).tag(name="Continuous Acquisition in Progress", group='Data Curve Buffer') curveAcquisitionHaltedTD = traitlets.Bool( default_value=False, read_only=True).tag(name="Acquisition by TD Halted", group='Data Curve Buffer') curveAcquisitionHaltedTDC = traitlets.Bool( default_value=False, read_only=True).tag(name="Continuous Acquisition by TD Halted", group='Data Curve Buffer') pointsAcquired = traitlets.Int(default_value=0, read_only=True).tag( name="Points Acquired", group='Data Curve Buffer') # Status Traitlets curveAcquisitionInProgress = traitlets.Bool( default_value=False, read_only=True).tag(name="Curve Acquisition in Progress", group='Status') commandComplete = traitlets.Bool(default_value=False, read_only=True).tag( name="Command Complete", group="Status") invalidCommand = traitlets.Bool(default_value=False, read_only=True).tag(name="Invalid Command", group="Status") commandParameterError = traitlets.Bool(default_value=False, read_only=True).tag( name="Command Parameter Error", group="Status") referenceUnlock = traitlets.Bool(default_value=False, read_only=True).tag( name="Reference Unlock", group="Status") outputOverload = traitlets.Bool(default_value=False, read_only=True).tag(name="Output Overload", group="Status") newADCValues = traitlets.Bool(default_value=False, read_only=True).tag(name="New ADC Values", group="Status") inputOverload = traitlets.Bool(default_value=False, read_only=True).tag(name="Input Overload", group="Status") dataAvailable = traitlets.Bool(default_value=False, read_only=True).tag(name="Data Available", group="Status") def __init__(self, resource, ethernet=False): """ Parameters ---------- resource : Resource PyVisa Resource object of the connected device. ethernet : bool Indicates if the connection to the device is an ethernet connection. """ super().__init__(objectName=None, loop=None) self.resource = resource self.ethernet = ethernet self.resource.timeout = 1000 #self.resource.set_visa_attribute(pyvisa_consts.VI_ATTR_SUPPRESS_END_EN, pyvisa_consts.VI_FALSE) if ethernet: self.resource.read_termination = chr(0) else: self.resource.read_termination = '' self.resource.write_termination = chr(0) self.observe(self.setParameter, traitlets.All) self._traitChangesDueToStatusUpdate = True self._lock = Lock() self._statusUpdateFuture = ensure_weakly_binding_future( self.contStatusUpdate) async def __aenter__(self): await super().__aenter__() self.set_trait("identification", (await self.query("ID"))[0]) self.set_trait("instrumentName", (await self.query("NAME"))[0]) self.set_trait("firmwareVersion", (await self.query("VER"))[0]) await self.readAllParameters() await self.statusUpdate() return self async def __aexit__(self, *args): await super().__aexit__(*args) self._statusUpdateFuture.cancel() @threaded_async def query(self, command): """ Sends a command to the device and reads the answer. Parameters ---------- command : str The command to send to the device. Returns ------- list a list of answer strings from the device. """ with self._lock: # remove parameter placeholders from command paramIndex = command.find(" {}") if paramIndex != -1: command = command[:paramIndex] print('SR7230: query ' + str(command)) logging.info('{}: {}'.format(self, command)) answer = self.resource.query(command) if self.ethernet: self.resource.read_raw() else: end = answer.find(chr(0)) answer = answer[:end] print('SR7230: answer: ' + answer) result = [] for s in str.split(answer, ','): result.append(s) return result @threaded_async def write(self, command, lock=True): """ Sends a command to the device. Parameters ---------- command : str The command to send to the device. """ logging.info('{}: {}'.format(self, command)) if lock: with self._lock: ret = self.resource.query(command) if self.ethernet: self.resource.read_raw() return ret else: ret = self.resource.query(command) if self.ethernet: self.resource.read_raw() return ret async def getCurveAcquisitionStatusMonitor(self): """ Gets the current curve acquisition status. Returns ------- list a list of the curve acquisition status monitor values. """ answer = await self.query('M') # if answer[-1] == '\n': # answer = answer[:-1] # result = [] # for s in str.split(answer, ','): # result.append(int(s)) return answer async def getNumberOfPointsAcquired(self): """ Gets the current number of acquired points from the device. Returns ------- int the number of points acquired. """ result = await self.getCurveAcquisitionStatusMonitor() return result[3] @action("Start") async def start(self): print('start sr7230') await self.write('NC') # new curve await self.write('CBD 1') # select channel x if self.takeDataMode == self.TakeDataMode.TakeData: await self.write('TD') elif self.takeDataMode == self.TakeDataMode.TakeDataContinuously: await self.write('TDC 0') elif self.takeDataMode == self.TakeDataMode.TakeDataTriggered: await self.write("TDT {}".format( self.takeDataTriggeredTriggerMode.value)) await self.statusUpdate() @action("Stop") async def stop(self): print('stop sr7230') await self.write('HC') @action("Clear Buffer", group="Data Curve Buffer") async def clear(self): """ Clears the buffer of the device. """ await self.write("NC") async def readAllParameters(self): """ Reads all parameters from the device and updates the attributes of this class accordingly. """ self._traitChangesDueToStatusUpdate = True for name, trait in self.traits().items(): command = trait.metadata.get('command') if command is None: continue else: answer = await self.query(command) if len(answer) == 1: result = answer[0] else: result = answer if isinstance(trait, traitlets.Enum): if len(answer) == 1: val = int(result) val = [item for item in trait.values if item.value == val][0] else: res = [] for i in answer: ival = int(i) res.append(ival) # if first element is 0, (like [0, 1]) then LF is off if res[0] != 0: val = [ item for item in trait.values if item.value == res ][0] else: val = list(trait.values)[0] elif isinstance(trait, Quantity): val = Q_(float(result), trait.default_value.units) elif isinstance(trait, traitlets.Int): val = int(result) elif isinstance(trait, traitlets.Bool): result_int = 0 try: result_int = int(result) except ValueError: print('Failed to read answer from ' + command + " answer was " + str(result)) logging.info('Failed to read answer from ' + command + " answer was " + str(result)) val = True if result_int == 1 else False else: val = result self.set_trait(name, val) self._traitChangesDueToStatusUpdate = False logging.info('SR7230: Lockin-Parameter read') def setParameter(self, change): """ Sets parameter on the device. This is the function that is called by all traits that get observed. Tries to update the changed attribute on the device by sending the corresponding command. Parameters ---------- change : list change object of the observed trait. """ if self._traitChangesDueToStatusUpdate: return trait = self.traits().get(change['name']) command = trait.metadata.get('command') value = change['new'] if command is None: return self.set_trait(trait.name, value) if isinstance(value, enum.Enum): value = value.value elif isinstance(value, Q_): if 'REFP' in command: value = int(value.magnitude) else: value = value.magnitude elif isinstance(value, bool): value = 1 if value else 0 commandString = str() paramIndex = command.find(" {}") if paramIndex == -1: commandString = command + ' {}'.format(value) elif command.find("{} {}") != -1: commandString = command.format(value[0], value[1]) elif paramIndex != -1: commandString = command.format(value) asyncio.ensure_future(self.write(commandString)) # Auto Functions @action('Readout Settings', group='Auto Functions') def readSettings(self): asyncio.ensure_future(self.readAllParameters()) @action('Auto Sensitivity', group='Auto Functions') def autoSensitivity(self): asyncio.ensure_future(self.write('AS')) asyncio.ensure_future(self.readAllParameters()) @action('Auto Measure Operation', group='Auto Functions') def autoMeasureOperation(self): asyncio.ensure_future(self.write('ASM')) asyncio.ensure_future(self.readAllParameters()) @action('Auto Phase', group='Auto Functions') def autoPhase(self): asyncio.ensure_future(self.write('AQN')) asyncio.ensure_future(self.readAllParameters()) @action('Auto Offset', group='Auto Functions') def autoOffset(self): asyncio.ensure_future(self.write('AXO')) asyncio.ensure_future(self.readAllParameters()) @action('Update Gain and Phase Correction Parameters', group='Reference Channel') def systemLockControl(self): asyncio.ensure_future(self.write('LOCK')) asyncio.ensure_future(self.readAllParameters()) async def contStatusUpdate(self): """ Requests a status update every STATUS_UPDATE_RATE seconds. """ while True: await asyncio.sleep(self.STATUS_UPDATE_RATE) await self.statusUpdate() async def statusUpdate(self): """ Performs a status update and updates the class attributes according to answers from the device. """ curveAcquisitionStatusMonitor = await self.getCurveAcquisitionStatusMonitor( ) try: curveAcquisitionStatus = int(curveAcquisitionStatusMonitor[0]) except Exception as e: logging.info(e) await self.statusUpdate() status = int(curveAcquisitionStatusMonitor[2]) self.set_trait( "curveAcquisitionInProgressTD", curveAcquisitionStatus == SR7230.CurveAcquisitionStatusInts.AcquisitionTD.value) self.set_trait( "curveAcquisitionInProgressTDC", curveAcquisitionStatus == SR7230.CurveAcquisitionStatusInts.AcquisitionTDC.value) self.set_trait( "curveAcquisitionHaltedTD", curveAcquisitionStatus == SR7230.CurveAcquisitionStatusInts.AcquisitionHaltedTD.value) self.set_trait( "curveAcquisitionHaltedTDC", curveAcquisitionStatus == SR7230.CurveAcquisitionStatusInts.AcquisitionHaltedTDC.value) self.set_trait("pointsAcquired", int(curveAcquisitionStatusMonitor[3])) self.set_trait( "curveAcquisitionInProgress", curveAcquisitionStatus != SR7230.CurveAcquisitionStatusInts.NoCurveActivity.value) self.set_trait("commandComplete", bool(status & SR7230.StatusBits.CommandComplete.value)) self.set_trait("invalidCommand", bool(status & SR7230.StatusBits.InvalidCommand.value)) self.set_trait( "commandParameterError", bool(status & SR7230.StatusBits.CommandParameterError.value)) self.set_trait("referenceUnlock", bool(status & SR7230.StatusBits.ReferenceUnlock.value)) self.set_trait("outputOverload", bool(status & SR7230.StatusBits.OutputOverload.value)) self.set_trait("newADCValues", bool(status & SR7230.StatusBits.NewADCValues.value)) self.set_trait("inputOverload", bool(status & SR7230.StatusBits.InputOverload.value)) self.set_trait("dataAvailable", bool(status & SR7230.StatusBits.DataAvailable.value)) if self.outputOverload: overloadByte = await self.query("N") logging.info(SR7230.statusMessages['overload'][overloadByte]) async def readCurrentOutput(self, channel='X'): """ Reads the current output of a channel from the device. Parameters ---------- channel : str the channel to read from. Returns ------- float the current output. """ return float(await self.query(channel)) async def readDataBuffer(self): """ Reads the data buffer of the device Returns ------- list a list of the read data points from the device's data buffer. """ numberOfPoints = await self.getNumberOfPointsAcquired() print('number of points: ' + str(numberOfPoints)) if numberOfPoints == 0: return [] data = await self.query('DC 0') data = data[0] result = [] for s in str.split(data, '\n'): try: dataPoint = float(s) result.append(dataPoint) except ValueError: pass return result async def readDataSet(self): if self.samplingMode == SR7230.SamplingMode.SingleShot: data = np.array(await self.readCurrentOutput()) dataSet = DataSet(Q_(data), []) self._dataSetReady(dataSet) return dataSet elif self.samplingMode == SR7230.SamplingMode.Buffered: data = await self.readDataBuffer() data = np.array(data) dataSet = DataSet(Q_(data), [Q_(np.arange(0, len(data)))]) self._dataSetReady(dataSet) return dataSet
def __init__(self, objectName=None, loop=None): super().__init__(objectName="Y Scan", loop=loop) self.title = "Taipan - Schweißgüte 2" self.dataSaver = DataSaver(objectName="Data Saver") self.tem_fs = TEMFiberStretcher(tem_serial1, tem_serial2, objectName="TEM FiberStretcher", loop=loop) self.tem_fs.rec_Start = Q_(4, 'ps') self.tem_fs.rec_Stop = Q_(190, 'ps') self.tem_fs_av = AverageDataSource(self.tem_fs, objectName="Averager") """ self.manipulatorX = IselStage(monsterstage_x, objectName="Manipulator x", loop=loop) """ self.manipulatorX = DummyManipulator() """ self.manipulatorY = IselStage(monsterstage_y, objectName="Manipulator y", loop=loop) """ self.manipulatorY = DummyManipulator() #define the x scan self.scanx = Scan(self.manipulatorX, self.tem_fs_av) self.scanx.minimumValue = Q_(0, 'mm') self.scanx.maximumValue = Q_(10, 'mm') self.scanx.step = Q_(1, 'mm') self.scanx.scanVelocity = Q_(10, 'mm/s') self.scanx.positioningVelocity = Q_(100, 'mm/s') self.scanx.objectName = "X Scan" self.scanx.retractAtEnd = True #define the y scan self.dataSource = self.scanx self._oldScanXStart = self.dataSource.start self._oldScanXStop = self.dataSource.stop self.dataSource.start = self.startMotorScan self.dataSource.stop = self.stopMotorScan self.manipulator = self.manipulatorY self.retractAtEnd = True self.minimumValue = Q_(0, 'mm') self.maximumValue = Q_(10, 'mm') self.step = Q_(2.5, 'mm') self.positioningVelocity = Q_(100, 'mm/s') self.scanVelocity = Q_(10, 'mm/s') #register the manipulators in the dataSaver self.dataSaver.registerManipulator(self.manipulatorX, 'X') self.dataSaver.registerManipulator(self.manipulatorY, 'Y') self.dataSaver.fileNameTemplate = '{date}-{name}-{X}-{Y}' self.tem_fs_av.addDataSetReadyCallback(self.dataSaver.process) self.resetCounter(self.resetCounterRow)
class Goniometer(Manipulator): class EncoderMode(enum.Enum): A_BSignal1fold = 0xC0 A_BSignal2fold = 0xE0 A_BSignal4fold = 0xF0 class Ramping(enum.Enum): Ramping = 0 NoRamping = 1 Errors = { 170: 'Maximum relative positioning Distance Exceeded', 175: 'Minimum relative positioning Distance Exceeded', 1200: 'Acceleration too steep', 1201: 'deceleration too steep', 1250: 'acceleration too flat', 1251: 'deceleration too flat', 1300: 'speed value too high', 1350: 'speed value too low', 9000: 'Axis not ready' } connection = None positiveLimitSwitch = traitlets.Bool(False, read_only=True).tag(group='Status') negativeLimitSwitch = traitlets.Bool(False, read_only=True).tag(group='Status') calibrateToDegree = Quantity(Q_(0, 'deg'), read_only=False) calibrateToDegree.tag(group='Status') isMoving = traitlets.Bool(False, read_only=True).tag(group='Status') startSpeed = Quantity(Q_(0.25, 'deg/s')).tag(group='Velocity Settings') acceleration = Quantity(Q_(0.0125, 'deg/s**2')) acceleration.tag(group='Velocity Settings') deceleration = Quantity(Q_(0.0125, 'deg/s**2')) deceleration.tag(group='Velocity Settings') def __init__(self, axis=0, encoderMode=EncoderMode.A_BSignal4fold, objectName=None, loop=None): super().__init__(objectName, loop) self.setPreferredUnits(ureg.deg, ureg.deg / ureg.s) if Goniometer.connection is None: Goniometer.connection = GonioConn() self.cdll = Goniometer.connection.dll self.axis = axis self.cdll.InitEncoder(self.axis, encoderMode.value) self.cdll.SetEncoder(self.axis, 0) self.cdll.SetRunFreeFrq(self.axis, 100) self.cdll.SetRunFreeSteps(self.axis, 32000) # don't know if important self.cdll.SetPosition(self.axis, 0) self.set_trait('value', self._stepToDeg( self.cdll.GetPosition(self.axis))) self.velocity = Q_(5, 'deg/s') self._statusRefresh = 0.1 self._isMovingFuture = asyncio.Future() self._isMovingFuture.set_result(None) self._updateFuture = ensure_weakly_binding_future(self.updateStatus) async def updateStatus(self): while True: await asyncio.sleep(self._statusRefresh) if (Goniometer.connection is None): continue await self.singleUpdate() async def singleUpdate(self): steps = self.cdll.GetPosition(self.axis) self.set_trait('value', self._stepToDeg(steps)) ls = self.cdll.GetLSStatus(self.axis) self.set_trait('positiveLimitSwitch', bool(ls & 1)) self.set_trait('negativeLimitSwitch', bool(ls & 2)) self.set_trait('isMoving', not bool(self.cdll.GetReadyStatus(self.axis))) if self.isMoving: self.set_trait('status', self.Status.Moving) else: self.set_trait('status', self.Status.Idle) if not self._isMovingFuture.done(): self._isMovingFuture.set_result(None) async def __aexit__(self, *args): self.stop() self._updateFuture.cancel() await super().__aexit__(*args) @action("Stop") def stop(self, stopMode=Ramping.Ramping): self.cdll.StopMotion(self.axis, stopMode.value) self._isMovingFuture.cancel() #@action("Reference") async def reference(self): if self.isMoving: logging.info('{} {}: Please finish'.format(self, self.axis) + 'movement before searching Limit Switch') return False self._setSpeedProfile(Q_(5, 'deg/s')) self.cdll.SetRunFreeFrq(self.axis, 100) self.cdll.SetRunFreeSteps(self.axis, 32000) self.cdll.SearchLS(self.axis, ord('-')) self._isMovingFuture = asyncio.Future() await self._isMovingFuture self.cdll.FindLS(self.axis, ord('-')) self.cdll.RunLSFree(self.axis, ord('-')) self._isMovingFuture = asyncio.Future() await self._isMovingFuture self.cdll.SetPosition(self.axis, 0) def _setSpeedProfile(self, velocity): ss = int(self.startSpeed.to('deg/s').magnitude*400) fs = int(velocity.to('deg/s').magnitude*400) ac = int(self.acceleration.to('deg/s**2').magnitude*400) dc = int(self.deceleration.to('deg/s**2').magnitude*400) error = self.cdll.SetSpeedProfile(self.axis, ss, fs, ac, dc) if error != 0: error = self.cdll.SetSpeedProfile(self.axis, 100, 2000, 5, 5) logging.error('{} {}: '.format(self, self.axis) + Goniometer.Errors.get(error)) logging.error('{} {}: Setting Speed command ignored' .format(self, self.axis)) return False else: return True async def moveTo(self, val: float, velocity=None): if velocity is None: velocity = self.velocity # The Goniometer ignores new position commands, if the stage is moving if self.isMoving: self.stop() while self.status != self.Status.Idle: await asyncio.sleep(0) error = self.cdll.SetDestination(self.axis, self._degToStep(val), ord('a')) if error != 0: logging.error('{} {}: '.format(self, self.axis) + Goniometer.Errors.get(error)) logging.error('{} {}: Positioning Command ignored' .format(self, self.axis)) return False self._setSpeedProfile(velocity) error = self.cdll.StartMotion(self.axis, Goniometer.Ramping.Ramping.value) if error != 0: logging.error('{} {}: '.format(self, self.axis) + Goniometer.Errors.get(error)) logging.error('{} {}: Positioning Command ignored' .format(self, self.axis)) return False self._isMovingFuture = asyncio.Future() await self._isMovingFuture @action('Set Calibration') def calibrate(self, value=None): if value is None: value = self.calibrateToDegree self.cdll.SetPosition(self.axis, self._degToStep(value)) def _degToStep(self, degs): return int(degs.to('deg').magnitude*400) def _stepToDeg(self, steps): return Q_(steps/400.0, 'deg')
def _stepToDeg(self, steps): return Q_(steps/400.0, 'deg')