From 77d00f0229ec7c26af03067cca49745da4392c52 Mon Sep 17 00:00:00 2001 From: Ian Dobbie Date: Tue, 9 Jul 2019 21:51:17 +0100 Subject: [PATCH 1/2] Added priorProScanIII controls --- microscope/stages/priorProScanIII.py | 158 +++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 microscope/stages/priorProScanIII.py diff --git a/microscope/stages/priorProScanIII.py b/microscope/stages/priorProScanIII.py new file mode 100644 index 00000000..47eace40 --- /dev/null +++ b/microscope/stages/priorProScanIII.py @@ -0,0 +1,158 @@ +#!/usr/bin/python +# -*- coding: utf-8 +# +# Copyright 2019 Ian Dobbie (Ian.Dobbie@gmail.com) +# +# 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 +# (at your option) 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 . + + +#still to implement +#get position per axis +#getmovement time +#set speed and accelleration +#cleanupupafterexperiment function? + + + +import serial +import Pyro4 +import time + +from microscope import devices + + +@Pyro4.expose +class PriorProScanIII( devices.SerialDeviceMixIn, devices.StageDevice): + + def __init__(self, hardlimits, com=None, baud=9600, timeout=0.1, *args, **kwargs): + # default baufd rate is 9600 + # no parity or flow control + # timeout is recomended to be over 0.5 + super(PriorProScanIII, self).__init__(*args, **kwargs) + self.hardlimits=hardlimits + self.connection = serial.Serial(port = com, + baudrate = baud, timeout = timeout, + stopbits = serial.STOPBITS_ONE, + bytesize = serial.EIGHTBITS, parity = serial.PARITY_NONE) + #check axis encoder states. + self.encoderState=self._encoder_state() + #turn on encoders if needed and set servo mode off + for axis in self.encoderState: + if not self.encoderState[axis]: + self.send(b'ENCODER,'+axis.encode()+b',1') + + #turn off servo mode by default + self.send(b'SERVO,b,0') + # setup individual movement axis commands + self.move_axis_abs=[self._move_X_abs, self._move_Y_abs ] + self.move_axis_rel=[self._move_X_rel, self._move_Y_rel ] + + def _write(self, command): + """Send a command to the prior device. + + This is not a simple passthrough to ``serial.Serial.write``, + it will append ``b'\\r'`` to command. This overides the + defualt write method + """ + return self.connection.write(command + b'\r') + + def send(self, command): + """Send command and retrieve response.""" + self._write(command) + return self._readline() + +# @devices.SerialDeviceMixIn.lock_comms +# def clearFault(self): +# self.flush_buffer() +# return self.get_status() + + def _flush_buffer(self): + line = b' ' + while len(line) > 0: + line = self._readline() + + @devices.SerialDeviceMixIn.lock_comms + def get_status(self): + result = self.send(b'?') + return result.split(b'\r') + + @devices.SerialDeviceMixIn.lock_comms + def get_position(self): + result = self.send(b'P').split(b',') + return ([int(result[0]),int(result[1])]) + + @devices.SerialDeviceMixIn.lock_comms + def stop(self): + self.send(b'I') + + def move_abs(self,axis,pos): + self.move_axis_abs[axis](pos) + + @devices.SerialDeviceMixIn.lock_comms + def _move_X_abs(self,pos): + position="%f"%(pos) + self.send(b'GX,'+position.encode()) + #move returns a responce + self._readline() + + @devices.SerialDeviceMixIn.lock_comms + def _move_Y_abs(self,pos): + position="%f"%(pos) + self.send(b'GY,'+position.encode()) + #move returns a responce + self._readline() + + def move_relative(self,axis,pos): + self.move_axis_rel[axis](pos) + + @devices.SerialDeviceMixIn.lock_comms + def _move_X_rel(self,pos): + position="%f"%(pos) + self.send(b'GR,'+position.encode()+b',0.0') + #move returns a responce + self._readline() + + @devices.SerialDeviceMixIn.lock_comms + def _move_Y_rel(self,pos): + position="%f"%(pos) + self.send(b'GR,0.0,'+position.encode()) + #move returns a responce + self._readline() + + @devices.SerialDeviceMixIn.lock_comms + def get_is_moving(self): + responce=self.send(b'$') + responce=responce.split(b'\r')[0] + if responce == b'0': + return False + else: + return True + + @devices.SerialDeviceMixIn.lock_comms + def get_serialnumber(self): + return(self.send(b'SERIAL').strip(b'\r')) + + @devices.SerialDeviceMixIn.lock_comms + def home(self): + self.send(b'RIS') + + @devices.SerialDeviceMixIn.lock_comms + def _encoder_state(self): + encoderState=int(self.send(b'ENCODER')) + responce= {'X': True if (encoderState & 1) else False , + 'Y': True if (encoderState & 2) else False } + return (responce) + + def get_hard_limits(self): + return(self.hardlimits) From e0d38471729fe1f5b4ac3cf63df4569d6376523a Mon Sep 17 00:00:00 2001 From: Ian Dobbie Date: Tue, 9 Jul 2019 21:51:47 +0100 Subject: [PATCH 2/2] Added StageDevice and abstract methods --- microscope/devices.py | 53 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/microscope/devices.py b/microscope/devices.py index 1fc29718..a07fabdb 100644 --- a/microscope/devices.py +++ b/microscope/devices.py @@ -1125,3 +1125,56 @@ def set_position(self, position): def get_filters(self): return [(k,v) for k,v in self._filters.items()] + +class StageDevice(Device): + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def __init__(self, **kwargs): + super(StageDevice, self).__init__(**kwargs) + + @abc.abstractmethod + def get_status(self): + """Query and return the stage status.""" + result = [] + # ... + return result + + @abc.abstractmethod + def send(self): + """Send a message to the stage.""" + result = [] + # ... + return result + + @abc.abstractmethod + def get_position(self): + """Return the stage position.""" + result = [] + # ... + return result + + @abc.abstractmethod + def stop(self): + """Stops all stage motion""" + pass + + @abc.abstractmethod + def move_abs(self): + """Move to a passed absolute position""" + pass + + @abc.abstractmethod + def move_relative(self): + """Move to a passed relative position""" + pass + + @abc.abstractmethod + def get_hard_limits(self): + """Return stage hard limits""" + pass + + @abc.abstractmethod + def get_is_moving(self): + """Returns True if stage is moving and False if not""" + pass