dlw / dlw.pyon commit add dlw module; clean up for handover (d7cac70)
   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
  18    def __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
  34    def __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
  49        try:
  50            self._setup()
  51            self.initialised = True
  52        except:
  53            self.initialised = False
  54
  55
  56    def _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()
  62        if len(usb_devices) < 1:
  63            raise Exception("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
  75    def set_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        """
  85        if not self.initialised:
  86            self._setup()
  87
  88        # Move to coordinates
  89        self._pidevice.MOV(coords)
  90
  91        if wait:
  92            # Wait for stage to reach coordinates
  93            pitools.waitontarget(self._pidevice, list(coords.keys()))
  94
  95    def get_pos(self):
  96        """
  97        Returns the current position of all axes
  98        """
  99        if not self.initialised:
 100            self._setup()
 101        return self._pidevice.qPOS(self._pidevice.axes)
 102
 103    def set_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        """
 108        if not self.initialised:
 109            self._setup()
 110        self._pidevice.VEL(vel)
 111
 112    def get_vel(self):
 113        """
 114        Returns the currently set velocities for all axes
 115        """
 116        if not self.initialised:
 117            self._setup()
 118        return self._pidevice.qVEL(self._pidevice.axes)
 119
 120    def set_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        """
 126        if not self.initialised:
 127            self._setup()
 128        self._pidevice.ACC(acc)
 129
 130    def get_acc(self):
 131        """
 132        Returns the currently set accelerations for all axes
 133        """
 134        if not self.initialised:
 135            self._setup()
 136        return 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
 144    def __init__(self, channel):
 145        """
 146        Set up shutter instance
 147        """
 148        self.channel = channel
 149
 150        try:
 151            self._setup()
 152            self.initialised = True
 153        except:
 154            self.initialised = False
 155            
 156
 157    def _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
 166    def open(self):
 167        """
 168        Open the shutter
 169        """
 170        if not self.initialised:
 171            self._setup()
 172        self._task.write(True)
 173
 174    def close(self):
 175        """
 176        Close the shutter
 177        """
 178        if not self.initialised:
 179            self._setup()
 180        self._task.write(False)
 181
 182    def get_status(self):
 183        """
 184        Get the current status of the shutter. True/1 = open, False/0 = closed
 185        """
 186        if not self.initialised:
 187            self._setup()
 188        return bool(self._task.read())
 189