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?
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.
I actually do NIDAQmx with Python using PyDAQmx. We take data at 20kHz (by setting the clock timer on the NI board, and streaming the data to a file in chunks of 2000 at 10hz).
I would highly recommend separating your GUI process from your data acquisition process if temporal precision is important.
If you are just wanting to log the data every 2 seconds, you could set your sample clock on your NIDAQ to something like 1000, buffer size 1000, and use an AutoRegisterEveryNSamplesEvent callback to write the last index of data for every other buffer (which should be every two seconds) to a file or pipe it to your GUI process. This will ensure that your processing queue for your GUI won't affect the precision that your data is sampled with.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With