add dlw module; clean up for handover
[direct-laser-writing.git] / write_path / write_path.py
index cffa8a8a52f00844e517b944e0856c33b4b6ac77..e8fe94219ca82acc3c26f08d6bb73f010a0cfd54 100644 (file)
@@ -2,25 +2,264 @@ import nidaqmx
 import pipython
 import sys
 import time
+import numpy as np
+import matplotlib.pyplot as plt
+import threading
 
+from pipython import datarectools, pitools
 
-# Set up stage
-pidevice = pipython.GCSDevice('E-727')
+def setup():
 
-usb_devices = pidevice.EnumerateUSB()
-if len(usb_devices) < 1:
-    print("No PI stages found - exiting")
-    sys.exit()
+    # Set up stage
+    pidevice = pipython.GCSDevice('E-727')
 
-pidevice.ConnectUSB(usb_devices[0].split(' ')[-1])
+    usb_devices = pidevice.EnumerateUSB()
+    if len(usb_devices) < 1:
+        print("No PI stages found - exiting")
+        sys.exit()
 
-with nidaqmx.Task() as task:
+    pidevice.ConnectUSB(usb_devices[0].split(' ')[-1])
+    pitools.startup(pidevice, servostates=True)
+    pitools.waitontarget(pidevice, [1, 2, 3])
+    tstart = time.time_ns()
+    print(pidevice.qPOS([1, 2, 3]))
+    print(time.time_ns() - tstart)
+
+    task = nidaqmx.Task()
     task.do_channels.add_do_chan("cDAQ1Mod3/port0/line2",
-                                 line_grouping=nidaqmx.constants.LineGrouping.CHAN_PER_LINE)
+                                    line_grouping=nidaqmx.constants.LineGrouping.CHAN_PER_LINE)
     task.start()
-    while True:
+
+    return (task, pidevice)
+
+
+class BufferTimer(threading.Thread):
+    def __init__(self, event, fn, interval):
+        threading.Thread.__init__(self)
+        self.stopped = event
+        self.fn = fn
+        self.interval = interval
+    def run(self):
+        while not self.stopped.wait(self.interval):
+            self.fn()
+
+class Recorder:
+    """
+    Wrapper for the PiPython GCS 2.0 data recorder
+    """
+
+    def __init__(self, pidevice, sample_rate=500, sources=None, options=None):
+        self.sample_rate = sample_rate
+        self._drec = datarectools.Datarecorder(pidevice)
+        if options is None:
+            # Default: actual position
+            options = datarectools.RecordOptions.ACTUAL_POSITION_2
+        if sources is None:
+            # Default: all axes
+            sources = pidevice.axes
+
+        self._drec.samplefrequ = sample_rate
+        self._drec.options = options
+        self._drec.sources = sources
+        self._drec.trigsources = datarectools.TriggerSources.TRIGGER_IMMEDIATELY_4
+        self.maxsamples = int(datarectools.getmaxnumvalues(pidevice) / len(sources))
+
+        self.interval = self.maxsamples * self._drec.sampletime / 1.5
+        print(self.interval)
+        self._stop_flag = threading.Event()
+        self._refresh_thread = BufferTimer(self._stop_flag, self.get_data, self.interval)
+        self.read_in_progress = False
+        
+        self.data = np.zeros((0, len(self._drec.sources)+1))
+        self.headers = []
+        self._time_start = []
+        self._time_end = []
+
+    def start(self):
+        self._drec.arm()
+        self._time_start.append(time.time_ns())
+        print("Starting recording at {}".format((self._time_start[-1] - self._time_start[0])/1e9))
+        self._refresh_thread.start()
+    
+    def refresh(self):
+        self._drec._gcs.DRT(0, datarectools.TriggerSources.TRIGGER_IMMEDIATELY_4)
+        self._time_start.append(time.time_ns())
+
+    def get_data(self, refresh=True):
+        self.read_in_progress = True
+        time_start = self._time_start[-1]
+        time_current = time.time_ns()
+        print("Starting reading at {}".format((time_current - self._time_start[0])/1e9))
+        elapsed_time = (time_current - time_start) / 1e9
+        
+        read_no_samples = int(elapsed_time / self._drec.sampletime)
+        extra_samples = int(0.5*read_no_samples)
+        read_no_samples += extra_samples
+        data = np.zeros((read_no_samples, len(self._drec.sources)+1))
+        print("Data: {}".format(data.shape))
+        start_timeval = (self._time_start[-1] - self._time_start[0])/1e9
+        print("Start timeval: {}".format(start_timeval))
+        print("Predicted elapsed time: {}, Actual elapsed time: {}".format(read_no_samples*self._drec.sampletime, elapsed_time))
+        times = np.arange(start_timeval, start_timeval+elapsed_time-self._drec.sampletime + extra_samples*self._drec.sampletime, step=self._drec.sampletime)
+        print("Times: {}".format(times.shape))
+        data[:,0] = times
+        tables = list(range(1, len(self._drec.sources)+1))
+        header = pidevice.qDRR(tables, 1, read_no_samples)
+        while pidevice.bufstate is not True:
+            time.sleep(0.01)
+        if refresh:
+            self.refresh()
+        d = np.array(pidevice.bufdata).transpose()
+        data[:,1:] = d
+        print(d[0,1:3])
+        print(d[-1,1:3])
+        
+        self.data = np.vstack((self.data, data))
+        self.read_in_progress = False
+
+    def _plot_data(self, data):
+        fig, ax = plt.subplots()
+        ax.plot(data[:,0], data[:,1], label='x', marker='.')
+        ax.plot(data[:,0], data[:,2], label='y', marker='.')
+        ax.plot(data[:,0], data[:,3], label='z', marker='.')
+        plt.legend()
+        plt.show()     
+
+    def stop(self, plot=False):
+        print("Saving")
+        self._stop_flag.set()
+        while self.read_in_progress is True:
+            time.sleep(0.1)
+        self.get_data(refresh=False)
+        diffs = np.diff(self.data[:,0])
+        max_diff = np.max(diffs)
+        print("Max gap: {}".format(max_diff))
+        np.savetxt("data.txt", self.data, delimiter=',')
+        if plot:
+            self._plot_data(self.data)
+
+
+
+def lines(task, pidevice):
+
+    focus_top = 9
+    focus_bottom = 9
+    focus_range = 50
+    start_x = 116
+    start_y = 100
+    pitch = 3
+    line_length = 20
+
+    # Go to origin
+    pidevice.MOV({1: start_x, 2: start_y, 3: focus_top})
+
+    # set velocity
+    velocities = [0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000]
+    #velocities = [1]
+    pidevice.VCO({2: True})
+
+    for i, vel in enumerate(velocities):
+
+        # Calculate x coordinate for this line
+        x = i * pitch
+        z = focus_top + (focus_bottom - focus_top) / focus_range * x
+
+        # Go to start position
+        pidevice.VEL({2: 100})
+        pidevice.MOV({1: start_x + x, 2: start_y, 3: z})
+        pitools.waitontarget(pidevice, [1, 2, 3])
+        time.sleep(0.2)
+
+        # Turn on laser
+        task.write(True)
+        time.sleep(0.006)
+
+        # Start line
+        pidevice.VEL({2: vel})
+        pidevice.MOV({2: start_y + line_length})
+        pitools.waitontarget(pidevice, [1, 2, 3])
+
+        # Turn off laser
+        task.write(False)
+        time.sleep(0.2)
+        
+    # Go to origin
+    pidevice.VEL({2: 100})
+    pidevice.MOV({1: start_x, 2: start_y, 3: focus_top})
+    pitools.waitontarget(pidevice, [1, 2, 3])
+
+def dots(task, pidevice):
+
+    # Focusing procedure:
+    # Get two z values where the beam is in focus at two points: the left 
+    # and right sides of the writing area. Put these values in focus_*,
+    # and the distance between the two sample points in focus_range.
+    focus_left = 8.5
+    focus_right = 8.5
+    focus_range = 10
+
+    # Positioning parameters
+    start_x = 25
+    start_y = 0
+    pitch = 5
+
+    # Go to origin
+    #pidevice.MOV({1: start_x, 2: start_y, 3: focus_left})
+    pidevice.MOV({1: start_x, 2: start_y})
+
+    # Set exposure times in ms
+    #times = np.array([10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000])
+    times = np.array([10, 20, 50, 100, 200, 500, 1000])
+    for i, t in enumerate(times):
+
+        # Go to dot position
+        y = start_y + i * pitch
+        z = focus_left + (focus_right - focus_left) / focus_range * y
+        #pidevice.MOV({2: y, 3: z})
+        pidevice.MOV({2: y})
+        #pitools.waitontarget(pidevice, [1, 2, 3])
+        pitools.waitontarget(pidevice, [1, 2])
+        time.sleep(0.1)
+
+        # Write dot
+        print("{} of {}: {} ms".format(i+1, len(times), t))
         task.write(True)
-        time.sleep(1)
+        time.sleep(t/1e3)
         task.write(False)
-        time.sleep(1)
 
+        time.sleep(0.5)
+
+    # Go to origin
+    #pidevice.MOV({1: start_x, 2: start_y, 3: focus_left})
+    #pitools.waitontarget(pidevice, [1, 2, 3])
+    pidevice.MOV({1: start_x, 2: start_y})
+    pitools.waitontarget(pidevice, [1, 2])
+
+def test_rec(pidevice):
+    pidevice.VCO({1: True, 2: True})
+    pidevice.VEL({1: 1000, 2: 1000})
+    pidevice.MOV({1: 0, 2: 0})
+    pitools.waitontarget(pidevice, [1, 2])
+    pidevice.VEL({1: 20, 2: 20})
+    rec = Recorder(pidevice)
+    rec.start()
+    pidevice.MOV({1: 100, 2: 100})
+    #pitools.waitontarget(pidevice, [1, 2, 2])
+    time.sleep(15)
+    #rec.get_data()
+    #pitools.waitontarget(pidevice, [1, 2, 3])
+    #rec.get_data()
+    # time.sleep(5)
+    # rec.get_data()
+    rec.stop(plot=True)
+
+
+if __name__ == "__main__":
+    task, pidevice = setup()
+    try:
+        #lines(task, pidevice)
+        dots(task, pidevice)
+        #test_rec(pidevice)
+    finally:
+        pitools.stopall(pidevice)
+        task.close()
\ No newline at end of file