05-09-2019 05:06 AM
I am trying to create an GUI program using python and tkinder with multithreading. However while trying to pass AnalogMultiChannelReader(task.in_stream) instance to seperate thread so, it can run in the background, gives several errors. Below is the code I used, the code works perfectly, If i pass some random numbers but for AnalogMultiChannelReader instance doesn't work.
Any suggestions on what I am doing wrong here?
# -*- coding: utf-8 -*-
"""
import tkinter as tk
from tkinter import *
import threading
import random
import time
from queue import Queue, Empty
import matplotlib
matplotlib.use('TkAgg')
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import nidaqmx
from nidaqmx.constants import AcquisitionType
from nidaqmx.stream_readers import AnalogMultiChannelReader
#%%
root = tk.Tk()
fig = Figure(figsize=(5,5), dpi=100)
graph = fig.add_subplot(111)
canvas = FigureCanvasTkAgg(fig,root)
canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
def DAQ(q, Read, out):
while True:
Read.read_many_sample(data = out,number_of_samples_per_channel = 10000)# read from DAQ
out = np.around(out, 6) #Round all values to 6 decimals to avoid overflow
q.put((out))
time.sleep(1)
def update_data(queue, root):
try:
vibrations = queue.get_nowait()
except Empty:
pass
else:
graph.plot(vibrations)
canvas.draw()
root.after(1, update_data, queue, root)
data_queue = Queue()
with nidaqmx.Task() as task:
task.ai_channels.add_ai_accel_chan("cDAQ9181-1BB3669Mod1/ai0:2")
task.timing.cfg_samp_clk_timing(10000, source="", sample_mode=AcquisitionType.CONTINUOUS, samps_per_chan=10000)
reader = AnalogMultiChannelReader(task.in_stream)
output = np.zeros([3, 10000])
task.start()
t = threading.Thread(target=DAQ, args=(data_queue, reader, output,))
t.daemon = True
t.start()
update_data(data_queue, root)
root.mainloop()
if I can successfully run the sample program provided from here
The error code I get after running my code is as follow:
Exception in thread Thread-7:
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\threading.py", line 917, in _bootstrap_inner
self.run()
File "C:\ProgramData\Anaconda3\lib\threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "<ipython-input-4-35e645b9e6e9>", line 16, in DAQ
Read.read_many_sample(data = out,number_of_samples_per_channel = 10000)# read from DAQ
File "C:\ProgramData\Anaconda3\lib\site-packages\nidaqmx\stream_readers.py", line 330, in read_many_sample
self._verify_array(data, number_of_samples_per_channel, True, True)
File "C:\ProgramData\Anaconda3\lib\site-packages\nidaqmx\stream_readers.py", line 78, in _verify_array
channels_to_read = self._in_stream.channels_to_read
File "C:\ProgramData\Anaconda3\lib\site-packages\nidaqmx\_task_modules\in_stream.py", line 223, in channels_to_read
check_for_error(size_or_code)
File "C:\ProgramData\Anaconda3\lib\site-packages\nidaqmx\errors.py", line 127, in check_for_error
raise DaqError(error_buffer.value.decode("utf-8"), error_code)
nidaqmx.errors.DaqError: Task specified is invalid or does not exist.
Status Code: -200088
Any suggestion on how to fix it would be really helpful.
Thank You.
08-06-2019 10:11 PM
Hi
Sorry, I am not familiar with this, but I can provide you with some reference information:
May I know what kind of data type of the random numbers that you pass in?
08-07-2019 10:29 AM
# -*- coding: utf-8 -*-
"""
import tkinter as tk
from tkinter import *
import threading
import random
import time
from queue import Queue, Empty
import matplotlib
matplotlib.use('TkAgg')
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import nidaqmx
from nidaqmx.constants import AcquisitionType
from nidaqmx.stream_readers import AnalogMultiChannelReader
#%%
root = tk.Tk()
fig = Figure(figsize=(5,5), dpi=100)
graph = fig.add_subplot(111)
canvas = FigureCanvasTkAgg(fig,root)
canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
def DAQ(q,):
with nidaqmx.Task() as task:
task.ai_channels.add_ai_accel_chan("cDAQ9181-1BB3669Mod1/ai0:2")
task.timing.cfg_samp_clk_timing(10000, source="", sample_mode=AcquisitionType.CONTINUOUS, samps_per_chan=10000)
reader = AnalogMultiChannelReader(task.in_stream)
output = np.zeros([3, 10000])
task.start()
while True:
reader.read_many_sample(data = out,number_of_samples_per_channel = 10000)# read from DAQ
out = np.around(out, 6) #Round all values to 6 decimals to avoid overflow
q.put((out))
time.sleep(1)
def update_data(queue, root):
try:
vibrations = queue.get_nowait()
except Empty:
pass
else:
graph.plot(vibrations)
canvas.draw()
root.after(1, update_data, queue, root)
data_queue = Queue()
t = threading.Thread(target=DAQ, args=(data_queue, reader, output,))
t.daemon = True
t.start()
update_data(data_queue, root)
root.mainloop()
I was able to fix this problem by starting the task with the function. I am not sure why this is happening since I didn't investigate the C-API of NI-DAQmx. I think it has something to do with passing the AnalogMultiChannelReader() object through to the different thread. Probably the task needs to be initiated in the same thread as the reader. Python module for NI-DAQmx is not thread safe. Since this question I haven't seen any updates in their library either. All in all together, I gave up on NI products and moved on to good old serial bus and TCP/IP DAQ cards where I have more control over data and multi-threading.
Thanks for the reply.
04-05-2023 01:03 PM
Any good alternatives on DAQs to NI?
04-05-2023 08:43 PM
@eduardomp8 wrote:
Any good alternatives on DAQs to NI?
There are several low cost alternatives but the support and performance may not be the same level.
MCC DAQ is one such alternative.