Search code examples
pythonuser-interfacenidaqmx

Data Acquistion using Python


I'm working on a project using National Instruments boards to do data acquistion. I have functional C codes for doing the tasks, but would like to use Python, so the GUI programming is less painful. In my C-code, I use the API call setTimer, which raises a WM_TIMER event at regular intervals. Is there a similar, mechanism in a Tk loop? I tried using the following code.

def DAQ(self):
    if self.do_DAQ:
        result = self.myDAQ.getData()
        currTime = time.time() - self.start_time
        self.time_label.config(text="{:.1f} seconds".format(currTime))
        self.volt_label.config(text="{:.4f} volts".format(result))
        self.time_data[self.i] = currTime
        self.volt_data[self.i] = result
        self.i += 1
        self.after(1962, self.DAQ)

The magic "1962" in the after() was determined by trial and error to give about a 2 second delay, but the time slices drift depending on what else is in the queue. Is there a way I can do this so my time slices are more accurate? Specifically, can I force Tk to do my DAQ event before other things in the queue?


Solution

  • Here's a sort of quickie example of what I'm talking about in my comment:

    import Tkinter as tk
    import threading
    import random
    import time
    from Queue import Queue, Empty
    
    root = tk.Tk()
    time_label = tk.Label(root, text='<unknown> seconds')
    volt_label = tk.Label(root, text='<unknown> volts')
    time_label.pack()
    volt_label.pack()
    
    def DAQ(q):
        while True:
            q.put((time.time(), random.randrange(100)))
            time.sleep(2)
    
    def update_data(queue, root):
        try:
            timestamp, volts = queue.get_nowait()
        except Empty:
            pass
        else:
            time_label.config(text='{:.1f} seconds'.format(timestamp))
            volt_label.config(text='{:.4f} volts'.format(volts))
        root.after(100, update_data, queue, root)
    
    data_queue = Queue()
    t = threading.Thread(target=DAQ, args=(data_queue,))
    t.daemon = True
    t.start()
    update_data(data_queue, root)
    root.mainloop()
    

    Obviously the above DAQ() function is just a stand-in for the real thing. The point is, as @ballsdotballs suggested in their answer, you can sample at whatever rate you want in your DAQ thread, add the values to a queue, and then update the GUI at a more appropriate rate.