0

I want to run a measurment program which gets measurement from two different devices during the same period. I want to start and stop the measurement within a small gui. As I need a while loop to measure, plot and save one of the measurments and run it until I interrupt it with the stop button, I thought I need to call it as a different thread to not freeze the gui and be able to use the stop button. Also I thought that I should not use .join() to not freeze the gui. But somehow my gui still seems to freeze and I can't use the stop button. I already read similar questions in forums, but I can't figure out what I am doing wrong. It actually is my first project using threadings, so I don#t have any experiance with options and events, but I also couln't see how they would help me.

So I have a class to communicate with my arduino, one to communicate with saleae (second device) and one data_treatment class to plot and save the data from the arduino.

So in my main I have a small gui with a start and stop button. When I press the start button, I'd like to start the saleae measurment (it runs comfortably in its own program) and to call my record function of my ardunio class. That function has a while loop which reads the values and gives them to the function of data_treatment. When I press start, it starts the saleae measurement and the arduino measurement, and all works as planned, but I can't press stop, because the gui seems to wait for the other threat which doesn't end until I press stop.

So here is my main function (cambine_func) is just a function to be able to call several functions with the button), and below is the arduino class:

if __name__ == '__main__':
window = gui.Window("Measurement")

start_button = window.add_button("Start")
start_button.pack(pady = 20)
gui.on("btnPress", start_button, lambda: combine_funcs(saleae.start_measurement(),
                                                       threading.Thread(target = arduino.record_values(300)).start()))

stop_button = window.add_button("Stopp")
stop_button.pack(pady = 20)
gui.on("btnPress", stop_button, lambda: combine_funcs(saleae.end_measurement(),
                                                      saleae.save_data(),
                                                      arduino.close_port(),
                                                      window.destroy()))

window.start()




import time

class Arduino_communication:
"""
reads what comes in from Arduino and transformes it into single values
"""
def __init__(self, arduino, data_treatment):
    self.arduino = arduino
    self.data_treatment = data_treatment
    self.interrupted = False

def record_values(self, measurement_period):
    """
    reads values from the Arduino and converts it into single values,
    counts faulty lines received from Arduino
    :return: array of 6 columns (roll, pitch, yaw, x-position, y-position, z-position)
    """
    faulty_values = 0
    data = [0, 0, 0, 0, 0, 0]
    start_time = float(time.time())
    time_vector = []

    while self.interrupted == False:

        self.arduino.flushInput()               # delete what's in buffer
        self.arduino.readline()                 # read a byte string and throw away (deleting buffer may lead to uncomplete line)
        b = self.arduino.readline()             # read next line
        time_vector.append(float(time.time())-start_time)

        try:
            string_n = b.decode()               # decode byte string into Unicode
        except UnicodeDecodeError:              # Arduino sometimes sends faulty lines
            faulty_values += 1
        string = string_n.rstrip()              # remove \n and \r
        single_strings = string.split('/')
        try:
            data = [float(j) for j in single_strings]  # convert string to float
        except (ValueError, UnicodeDecodeError): # Arduino sometimes sends faulty lines
            faulty_values += 1

        self.data_treatment.plot_new_data_line(time_vector[-1], data)
        self.data_treatment.write_to_csv(time_vector[-1], data)

    print('Es gab ', faulty_values, ' fehlerhafte Übertragungen.')
    self.data_treatment.finish_plotting()

def close_port(self):
    """
    stops measurement and closes arduino port
    """
    self.interrupted = True
    self.arduino.close()
asc
  • 79
  • 8

2 Answers2

0

You have:

threading.Thread(target = arduino.record_values(300)).start()

This calls the method and then starts a thread with the result as its target.

Where you desire:

threading.Thread(target=arduino.record_values, args=[300]).start()

This starts a thread with the target arduino.record_values and the argument 300.

You might want to hold on to that Thread so that you can prevent the start button from starting another recording thread while the recording thread is recording.

Dan D.
  • 73,243
  • 15
  • 104
  • 123
  • Thanks for the fast answer! I tried that but then somhow the arduino measures just one time and then the gui closes. That would mean that tho loop is not working, which makes no sense for me. – asc Oct 24 '19 at 13:16
  • I don't know which GUI library you are using but most require a call to the GUI main loop to keep the program and its windows open. In PyGTK, this was `gtk.mainloop()`. – Dan D. Oct 24 '19 at 13:27
  • oh, that's true, thanks. But somehow changing window.start() to window.mainloop() doesn't help... – asc Oct 24 '19 at 13:45
  • I didn't think that would work. I wanted to know what GUI library you were using so I could look up the equivalent. – Dan D. Oct 24 '19 at 15:15
  • oh ok, sorry. The one I used was just called gui, but I tried it with tkinter where it is `.mainloop` i guess and I could not get it working there – asc Oct 24 '19 at 16:40
0

I could not figure out the solution I thought would work but I found this answer which I could adapt to my project and it now works as I wished.

asc
  • 79
  • 8