1""" 2Direct laser writing module. Import this into your script and then use the 3movement and shutter control functions to perform DLW. 4""" 5import nidaqmx 6import pipython 7import sys 8import time 9 10from pipython import datarectools, pitools 11 12class Writer: 13""" 14 Main class for direct laser writing. Sets up communication with the stage 15 and shutter and allows control of each. 16 """ 17 18def__init__(self, stage_model='E-727', shutter_channel="cDAQ1Mod3/port0/line2") 19 20# Assign instance variables 21 self.stage_model = stage_model 22 self.shutter_channel = shutter_channel 23 24# Initialise stage and shutter 25 self.stage =Stage(self.stage_model) 26 self.shutter =Shutter(self.shutter_channel) 27 28 29class Stage: 30""" 31 Represents a PI stage using the pipython package 32 """ 33 34def__init__(self, model): 35""" 36 Connect to the PI stage over USB. Tested on a PI E-727 piezo stage 37 controller connected over USB. The pipython package has minimal 38 documentation so it is useful to look inside the code. Unfortunately, 39 PI only provides a wheel, no source code, but once installed you can 40 import pipython and run `print pipython.__path__` to get the path 41 where it is installed, and then you can find all the code there. 42 """ 43# Set up stage 44 self._pidevice = pipython.GCSDevice(self.stage_model) 45 46# Attempt to connect to stage 47# If this fails, don't worry, we'll try again when some functionality 48# is called for 49try: 50 self._setup() 51 self.initialised =True 52except: 53 self.initialised =False 54 55 56def_setup(self): 57""" 58 Attempt to connect to and initialise the stage 59 """ 60# Connect to stage over USB 61 usb_devices = self._pidevice.EnumerateUSB() 62iflen(usb_devices) <1: 63raiseException("No PI stages found") 64 65# Connect to the first USB device found 66 pidevice.ConnectUSB(usb_devices[0].split(' ')[-1]) 67 pitools.startup(self._pidevice, servostates=True) 68 69# Enable velocity control for all axes 70 self._pidevice.VCO(self._pidevice.axes) 71 72# Wait for the stage to stabilise 73 pitools.waitontarget(self._pidevice, self._pidevice.axes) 74 75defset_pos(self, coords, wait=True): 76""" 77 Move to coordinates specified in coords. Coords should be a dictionary 78 with axes indices as keys and positions as values. If wait is specified, 79 wait until the target is reached. 80 81 Example call: 82 stage.moveto({1: 35, 2: 9, 3: 20.9}) 83 will move the stage to (x, y, z) position (35, 9, 20.9). 84 """ 85if not self.initialised: 86 self._setup() 87 88# Move to coordinates 89 self._pidevice.MOV(coords) 90 91if wait: 92# Wait for stage to reach coordinates 93 pitools.waitontarget(self._pidevice,list(coords.keys())) 94 95defget_pos(self): 96""" 97 Returns the current position of all axes 98 """ 99if not self.initialised: 100 self._setup() 101return self._pidevice.qPOS(self._pidevice.axes) 102 103defset_vel(self, vel): 104""" 105 Set the velocity for some or all axes. When moveto is called, the stage 106 will move at the specified velocities. vel is a dictionary or float. 107 """ 108if not self.initialised: 109 self._setup() 110 self._pidevice.VEL(vel) 111 112defget_vel(self): 113""" 114 Returns the currently set velocities for all axes 115 """ 116if not self.initialised: 117 self._setup() 118return self._pidevice.qVEL(self._pidevice.axes) 119 120defset_acc(self, acc): 121""" 122 Set the acceleration for some or all axes. When moveto is called, the 123 stage will accelerate at the specified rates. acc is a dictionary or 124 float. 125 """ 126if not self.initialised: 127 self._setup() 128 self._pidevice.ACC(acc) 129 130defget_acc(self): 131""" 132 Returns the currently set accelerations for all axes 133 """ 134if not self.initialised: 135 self._setup() 136return self._pidevice.qACC(self._pidevice.axes) 137 138 139class Shutter: 140""" 141 Represents a shutter using an NI DAQ with the nidaqmx package 142 """ 143 144def__init__(self, channel): 145""" 146 Set up shutter instance 147 """ 148 self.channel = channel 149 150try: 151 self._setup() 152 self.initialised =True 153except: 154 self.initialised =False 155 156 157def_setup(self): 158""" 159 Connect to DAQ 160 """ 161 self._task = nidaqmx.Task() 162 self._task.do_channels.add_do_chan(self.channel, 163 line_grouping=nidaqmx.constants.LineGrouping.CHAN_PER_LINE) 164 self._task.start() 165 166defopen(self): 167""" 168 Open the shutter 169 """ 170if not self.initialised: 171 self._setup() 172 self._task.write(True) 173 174defclose(self): 175""" 176 Close the shutter 177 """ 178if not self.initialised: 179 self._setup() 180 self._task.write(False) 181 182defget_status(self): 183""" 184 Get the current status of the shutter. True/1 = open, False/0 = closed 185 """ 186if not self.initialised: 187 self._setup() 188returnbool(self._task.read()) 189