diff --git a/hardwarelibrary/communication/.idea/.gitignore b/hardwarelibrary/communication/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/hardwarelibrary/communication/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/hardwarelibrary/communication/.idea/communication.iml b/hardwarelibrary/communication/.idea/communication.iml new file mode 100644 index 0000000..8b8c395 --- /dev/null +++ b/hardwarelibrary/communication/.idea/communication.iml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/hardwarelibrary/communication/.idea/inspectionProfiles/profiles_settings.xml b/hardwarelibrary/communication/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/hardwarelibrary/communication/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/hardwarelibrary/communication/.idea/misc.xml b/hardwarelibrary/communication/.idea/misc.xml new file mode 100644 index 0000000..d56657a --- /dev/null +++ b/hardwarelibrary/communication/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/hardwarelibrary/communication/.idea/modules.xml b/hardwarelibrary/communication/.idea/modules.xml new file mode 100644 index 0000000..be19bad --- /dev/null +++ b/hardwarelibrary/communication/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/hardwarelibrary/communication/.idea/vcs.xml b/hardwarelibrary/communication/.idea/vcs.xml new file mode 100644 index 0000000..b2bdec2 --- /dev/null +++ b/hardwarelibrary/communication/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/hardwarelibrary/communication/serialport.py b/hardwarelibrary/communication/serialport.py index ea8516d..370910f 100644 --- a/hardwarelibrary/communication/serialport.py +++ b/hardwarelibrary/communication/serialport.py @@ -74,9 +74,9 @@ def isOpen(self): else: return self.port.is_open - def open(self): + def open(self, baudRate=57600, timeout=0.3): if self.port is None: - self.port = serial.Serial(self.portPath, 57600, timeout=0.3) + self.port = serial.Serial(self.portPath, baudRate, timeout=timeout) else: self.port.open() diff --git a/hardwarelibrary/motion/sutter.py b/hardwarelibrary/motion/sutter.py new file mode 100644 index 0000000..ca7e7df --- /dev/null +++ b/hardwarelibrary/motion/sutter.py @@ -0,0 +1,127 @@ +from struct import * +import time +import serial +from motion import sutterDevice + +# class SutterDevice: +# def __init__(self): +# """ +# SutterDevice represents a XYZ stage. +# """ + +# self.port = serial.Serial("/dev/cu.usbserial-SI8YCLBE", timeout=5, baudrate=128000) + +# self.microstepsPerMicrons = 16 + +# def initializeDevice(self): +# """ +# We do a late initialization: if the device is not present at creation, it can still be +# initialized later. +# """ +# if self.port is not None: +# return + +# self.port = serial.Serial("/dev/cu.usbserial-SI8YCLBE", timeout=5, baudrate=128000) +# if self.port is None: +# raise IOError("Can't find Sutter device") + +# def shutdownDevice(self): +# """ +# If the device fails, we shut everything down. We should probably flush the buffers also. +# """ +# self.port.close() + +# def sendCommand(self, commandBytes): +# """ The function to write a command to the endpoint. It will initialize the device +# if it is not alread initialized. On failure, it will warn and shutdown.""" +# try: +# if self.port is None: +# self.initializeDevice() + +# self.port.write(commandBytes) + +# except Exception as err: +# print('Error when sending command: {0}'.format(err)) +# self.shutdownDevice() + +# def readReply(self, size, format) -> tuple: +# """ The function to read a reply from the endpoint. It will initialize the device +# if it is not already initialized. On failure, it will warn and shutdown. +# It will unpack the reply into a tuple. +# """ +# try: +# if self.port is None: +# self.initializeDevice() + +# replyBytes = self.port.read(size) +# if len(replyBytes) == size: +# theTuple = unpack(format, replyBytes) +# return theTuple + +# except Exception as err: +# print('Error when reading reply: {0}'.format(err)) +# self.shutdownDevice() +# return None + +# def positionInMicrosteps(self) -> (int,int,int): +# """ Returns the position in microsteps """ +# commandBytes = pack(' (float, float, float): +# """ Returns the position in microns """ + +# position = self.positionInMicrosteps() +# if position is not None: +# return (position[1]/self.microstepsPerMicrons, +# position[2]/self.microstepsPerMicrons, +# position[3]/self.microstepsPerMicrons) +# else: +# return None + +# def moveTo(self, position): +# """ Move to a position in microns """ +# x,y,z = position +# positionInMicrosteps = (x*self.microstepsPerMicrons, +# y*self.microstepsPerMicrons, +# z*self.microstepsPerMicrons) +# self.moveInMicrostepsTo(positionInMicrosteps) + +# def moveBy(self, delta) -> bool: +# #Move by a delta displacement (dx, dy, dz) from current position in microns +# dx,dy,dz = delta +# position = self.position() +# if position is not None: +# x,y,z = position +# self.moveTo((x+dx, y+dy, z+dz)) + + +if __name__ == "__main__": + device = SutterDevice(serialNumber="debug") + nbDonnees = 5 + dist = 1000 + + for i in range(nbDonnees+1): + if i == 0: + #device.home() + device.work() + print(device.position()) + time.sleep(1) + if i % 2 == 0: + fac = 1 + else: + fac = -1 + for ii in range(nbDonnees+1): + if ii != nbDonnees: + device.moveBy((dist*fac, 0, 0)) + else: + device.moveBy((0, dist, 0)) + print(device.position()) + time.sleep(1) diff --git a/hardwarelibrary/motion/sutterdevice.py b/hardwarelibrary/motion/sutterdevice.py index 7a61344..f4bd48e 100644 --- a/hardwarelibrary/motion/sutterdevice.py +++ b/hardwarelibrary/motion/sutterdevice.py @@ -8,7 +8,7 @@ import time from struct import * -class SutterDevice(PhysicalDevice, LinearMotionDevice): +class SutterDevice(PhysicalDevice): def __init__(self, bsdPath=None, portPath=None, serialNumber: str = None, productId: np.uint32 = None, vendorId: np.uint32 = None): @@ -21,7 +21,6 @@ def __init__(self, bsdPath=None, portPath=None, serialNumber: str = None, self.portPath = None PhysicalDevice.__init__(self, serialNumber, vendorId, productId) - LinearMotionDevice.__init__(self) self.port = None self.xMinLimit = 0 self.yMinLimit = 0 @@ -29,7 +28,7 @@ def __init__(self, bsdPath=None, portPath=None, serialNumber: str = None, self.xMaxLimit = 25000 self.yMaxLimit = 25000 self.zMaxLimit = 25000 - + self.microstepsPerMicrons = 16 def __del__(self): try: @@ -43,12 +42,12 @@ def doInitializeDevice(self): if self.portPath == "debug": self.port = SutterDebugSerialPort() else: - self.port = CommunicationPort(portPath=self.portPath) + self.port = SerialPort(idVendor=4930, idProduct=0x0001) if self.port is None: raise PhysicalDeviceUnableToInitialize("Cannot allocate port {0}".format(self.portPath)) - self.port.open() + self.port.open(baudRate=128000, timeout=10) self.doGetPosition() except Exception as error: @@ -65,6 +64,95 @@ def doShutdownDevice(self): self.port = None return + def sendCommand(self, commandBytes): + """ The function to write a command to the endpoint. It will initialize the device + if it is not alread initialized. On failure, it will warn and shutdown.""" + try: + if self.port is None: + self.initializeDevice() + + self.port.writeData(commandBytes) + reply = self.readReply(1) + + except Exception as err: + print('Error when sending command: {0}'.format(err)) + self.shutdownDevice() + + def readReply(self, size, format=None) -> tuple: + """ The function to read a reply from the endpoint. It will initialize the device + if it is not already initialized. On failure, it will warn and shutdown. + It will unpack the reply into a tuple. + """ + try: + if self.port is None: + self.initializeDevice() + + replyBytes = self.port.readData(size) + if len(replyBytes) == size: + if format is not None: + theTuple = unpack(format, replyBytes) + return theTuple + else: + return () + else: + raise Exception("Not enough bytes read") + + except Exception as err: + print('Error when reading reply: {0}'.format(err)) + self.shutdownDevice() + return None + + def positionInMicrosteps(self) -> (int,int,int): + """ Returns the position in microsteps """ + commandBytes = pack(' (float, float, float): + """ Returns the position in microns """ + + position = self.positionInMicrosteps() + if position is not None: + return (position[0]/self.microstepsPerMicrons, + position[1]/self.microstepsPerMicrons, + position[2]/self.microstepsPerMicrons) + else: + return (None, None, None) + + def moveTo(self, position): + """ Move to a position in microns """ + x,y,z = position + positionInMicrosteps = (x*self.microstepsPerMicrons, + y*self.microstepsPerMicrons, + z*self.microstepsPerMicrons) + self.moveInMicrostepsTo(positionInMicrosteps) + + def moveBy(self, delta) -> bool: + #Move by a delta displacement (dx, dy, dz) from current position in microns + dx,dy,dz = delta + position = self.position() + if position is not None: + x,y,z = position + self.moveTo((x+dx, y+dy, z+dz)) + + def home(self): + commandBytes = pack('> 1) ^ polynomial + else: + value = value >> 1 + temp = temp >> 1 + table[i] = value + return table + +# Test 6 : Is the table produced with the previous function is of 256 characters and not only zeros? + def testTableCreation(self): + table = self.createCRCTable() + self.assertTrue(len(table) == 256) + self.assertTrue(sum(table) != 0) +# Calculates the crc for the optotune part 2. + def calculateCRC16bit(self, data) -> bytearray: + """ + The C implementation is like this from the manual: + ushort crc = 0; // initial CRC value + for (int i = 0; i < bytes.Length; ++i) { + byte index = (byte)(crc ^ bytes[i]); + crc = (ushort)((crc >> 8) ^ table[index]); + } + """ + table = self.createCRCTable() + crc = 0 + for byte in data: + index = (crc ^ byte) & 0xff + crc = (crc >> 8) ^ table[index] + + crcBytes = struct.pack('0) + self.assertTrue(y>0) + self.assertTrue(z>0) + def testDeviceMove(self): + destination = (1,2,3) + self.device.moveTo( destination ) + + (x,y,z) = self.device.position() + self.assertTrue(x==destination[0]) + self.assertTrue(y==destination[1]) + self.assertTrue(z==destination[2]) + + def testDeviceMoveBy(self): + (xo,yo,zo) = self.device.position() + + self.device.moveBy( (10,20,30) ) + + (x,y,z) = self.device.position() + self.assertTrue(x-x0 == 10) + self.assertTrue(y-y0 == 20) + self.assertTrue(z-z0 == 30) + if __name__ == '__main__': unittest.main() diff --git a/hardwarelibrary/tests/testsIntegra.py b/hardwarelibrary/tests/testsIntegra.py index 0c928de..cf73d68 100644 --- a/hardwarelibrary/tests/testsIntegra.py +++ b/hardwarelibrary/tests/testsIntegra.py @@ -9,6 +9,11 @@ class TestIntegraPort(unittest.TestCase): port = None def setUp(self): self.port = USBPort(idVendor=0x1ad5, idProduct=0x0300, interfaceNumber=0, defaultEndPoints=(1,2)) + try: + self.port.open() + except: + self.fail("No devices connected") + def tearDown(self): self.port.close() diff --git a/test.py b/test.py new file mode 100644 index 0000000..cd23026 --- /dev/null +++ b/test.py @@ -0,0 +1,30 @@ +from hardwarelibrary.motion import SutterDevice + +device = SutterDevice(serialNumber="debug") +nbDonnees = 5 +dist = 1000 + +for i in range(nbDonnees+1): + if i == 0: + #Move to home position before moving to work position + commandBytes = pack('