class MainWindow(QMainWindow, poseidon_controller_gui.Ui_MainWindow): # ======================================================= # INITIALIZING : The UI and setting some needed variables # ======================================================= def __init__(self): # Setting the UI to a class variable and connecting all GUI Components super(MainWindow, self).__init__() self.ui = poseidon_controller_gui.Ui_MainWindow() self.ui.setupUi(self) self.populate_syringe_sizes() self.populate_pump_jog_delta() self.populate_pump_units() self.setting_variables() self.populate_ports() self.connect_all_gui_components() self.grey_out_components() # Declaring start, mid, and end marker for sending code to Arduino self.startMarker = 60# < self.endMarker = 62 # ,F,0.0> self.midMarker = 124 # | # Initializing multithreading to allow parallel operations self.threadpool = QThreadPool() print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount()) self.timer = QTimer() self.timer.setInterval(1000) self.timer.timeout.connect(self.recurring_timer) self.timer.start() self.counter = 0 # Random other things I need self.image = None def recurring_timer(self): self.counter +=1 # ============================= # SETTING : important variables # ============================= def setting_variables(self): self.set_p1_syringe() self.set_p2_syringe() self.set_p3_syringe() self.set_p1_units() self.set_p2_units() self.set_p3_units() self.is_p1_active = False self.is_p2_active = False self.is_p3_active = False #self.set_p2_speed() #self.set_p3_speed() #self.set_p1_accel() #self.set_p2_accel() #self.set_p3_accel() #self.set_p1_setup_jog_delta() #self.set_p2_setup_jog_delta() #self.set_p3_setup_jog_delta() # =================================== # CONNECTING : all the GUI Components # =================================== def connect_all_gui_components(self): # ~~~~~~~~~~~~~~~ # MAIN : MENU BAR # ~~~~~~~~~~~~~~~ self.ui.load_settings_BTN.triggered.connect(self.load_settings) self.ui.save_settings_BTN.triggered.connect(self.save_settings) # ~~~~~~~~~~~~~~~~ # TAB : Controller # ~~~~~~~~~~~~~~~~ # Px active checkboxes self.ui.p1_activate_CHECKBOX.stateChanged.connect(self.toggle_p1_activation) self.ui.p2_activate_CHECKBOX.stateChanged.connect(self.toggle_p2_activation) self.ui.p3_activate_CHECKBOX.stateChanged.connect(self.toggle_p3_activation) # Px display (TODO) # Px syringe display self.ui.p1_syringe_DROPDOWN.currentIndexChanged.connect(self.display_p1_syringe) self.ui.p2_syringe_DROPDOWN.currentIndexChanged.connect(self.display_p2_syringe) self.ui.p3_syringe_DROPDOWN.currentIndexChanged.connect(self.display_p3_syringe) # Px speed display self.ui.p1_units_DROPDOWN.currentIndexChanged.connect(self.display_p1_speed) self.ui.p2_units_DROPDOWN.currentIndexChanged.connect(self.display_p2_speed) self.ui.p3_units_DROPDOWN.currentIndexChanged.connect(self.display_p3_speed) #self.populate_pump_units() # Px amount self.ui.p1_amount_INPUT.valueChanged.connect(self.set_p1_amount) self.ui.p2_amount_INPUT.valueChanged.connect(self.set_p2_amount) self.ui.p3_amount_INPUT.valueChanged.connect(self.set_p3_amount) # Px jog delta #self.ui.p1_jog_delta_INPUT.valueChanged.connect(self.set_p1_jog_delta) #self.ui.p2_jog_delta_INPUT.valueChanged.connect(self.set_p2_jog_delta) #self.ui.p3_jog_delta_INPUT.valueChanged.connect(self.set_p3_jog_delta) # Action buttons self.ui.run_BTN.clicked.connect(self.run) self.ui.pause_BTN.clicked.connect(self.pause) self.ui.zero_BTN.clicked.connect(self.zero) self.ui.stop_BTN.clicked.connect(self.stop) self.ui.jog_plus_BTN.clicked.connect(lambda:self.jog(self.ui.jog_plus_BTN)) self.ui.jog_minus_BTN.clicked.connect(lambda:self.jog(self.ui.jog_minus_BTN)) # Set coordinate system self.ui.absolute_RADIO.toggled.connect(lambda:self.set_coordinate(self.ui.absolute_RADIO)) self.ui.incremental_RADIO.toggled.connect(lambda:self.set_coordinate(self.ui.incremental_RADIO)) # ~~~~~~~~~~~~ # TAB : Camera # ~~~~~~~~~~~~ # Setting camera action buttons self.ui.camera_connect_BTN.clicked.connect(self.start_camera) self.ui.camera_disconnect_BTN.clicked.connect(self.stop_camera) self.ui.camera_capture_image_BTN.clicked.connect(self.save_image) # ~~~~~~~~~~~ # TAB : Setup # ~~~~~~~~~~~ # Port, first populate it then connect it #self.populate_ports() self.ui.refresh_ports_BTN.clicked.connect(self.refresh_ports) self.ui.port_DROPDOWN.currentIndexChanged.connect(self.set_port) # Set the log file name self.date_string = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.date_string = self.date_string.replace(":","_") # Replace semicolons with underscores #self.log_file_name = self.ui.log_file_name_INPUT.text() + "_" + self.date_string + ".txt" #self.ui.log_file_name_INPUT.textEdited.connect(self.set_log_file_name) # Px syringe size, populate then connect #self.populate_syringe_sizes() self.ui.p1_syringe_DROPDOWN.currentIndexChanged.connect(self.set_p1_syringe) self.ui.p2_syringe_DROPDOWN.currentIndexChanged.connect(self.set_p2_syringe) self.ui.p3_syringe_DROPDOWN.currentIndexChanged.connect(self.set_p3_syringe) # Px units self.ui.p1_units_DROPDOWN.currentIndexChanged.connect(self.set_p1_units) self.ui.p2_units_DROPDOWN.currentIndexChanged.connect(self.set_p2_units) self.ui.p3_units_DROPDOWN.currentIndexChanged.connect(self.set_p3_units) # Px speed self.ui.p1_speed_INPUT.valueChanged.connect(self.set_p1_speed) self.ui.p2_speed_INPUT.valueChanged.connect(self.set_p2_speed) self.ui.p3_speed_INPUT.valueChanged.connect(self.set_p3_speed) # Px accel self.ui.p1_accel_INPUT.valueChanged.connect(self.set_p1_accel) self.ui.p2_accel_INPUT.valueChanged.connect(self.set_p2_accel) self.ui.p3_accel_INPUT.valueChanged.connect(self.set_p3_accel) # Px jog delta (setup) self.ui.p1_setup_jog_delta_INPUT.currentIndexChanged.connect(self.set_p1_setup_jog_delta) self.ui.p2_setup_jog_delta_INPUT.currentIndexChanged.connect(self.set_p2_setup_jog_delta) self.ui.p3_setup_jog_delta_INPUT.currentIndexChanged.connect(self.set_p3_setup_jog_delta) # Px send settings self.ui.p1_setup_send_BTN.clicked.connect(self.send_p1_settings) self.ui.p2_setup_send_BTN.clicked.connect(self.send_p2_settings) self.ui.p3_setup_send_BTN.clicked.connect(self.send_p3_settings) # Connect to arduino self.ui.connect_BTN.clicked.connect(self.connect) self.ui.disconnect_BTN.clicked.connect(self.disconnect) # Send all the settings at once self.ui.send_all_BTN.clicked.connect(self.send_all) def grey_out_components(self): # ~~~~~~~~~~~~~~~~ # TAB : Controller # ~~~~~~~~~~~~~~~~ self.ui.run_BTN.setEnabled(False) self.ui.pause_BTN.setEnabled(False) self.ui.zero_BTN.setEnabled(False) self.ui.stop_BTN.setEnabled(False) self.ui.jog_plus_BTN.setEnabled(False) self.ui.jog_minus_BTN.setEnabled(False) # ~~~~~~~~~~~~~~~~ # TAB : Setup # ~~~~~~~~~~~~~~~~ self.ui.p1_setup_send_BTN.setEnabled(False) self.ui.p2_setup_send_BTN.setEnabled(False) self.ui.p3_setup_send_BTN.setEnabled(False) self.ui.send_all_BTN.setEnabled(False) def ungrey_out_components(self): # ~~~~~~~~~~~~~~~~ # TAB : Controller # ~~~~~~~~~~~~~~~~ self.ui.run_BTN.setEnabled(True) self.ui.pause_BTN.setEnabled(True) self.ui.zero_BTN.setEnabled(True) self.ui.stop_BTN.setEnabled(True) self.ui.jog_plus_BTN.setEnabled(True) self.ui.jog_minus_BTN.setEnabled(True) # ~~~~~~~~~~~~~~~~ # TAB : Setup # ~~~~~~~~~~~~~~~~ self.ui.p1_setup_send_BTN.setEnabled(True) self.ui.p2_setup_send_BTN.setEnabled(True) self.ui.p3_setup_send_BTN.setEnabled(True) self.ui.send_all_BTN.setEnabled(True) # ====================== # FUNCTIONS : Controller # ====================== def toggle_p1_activation(self): if self.ui.p1_activate_CHECKBOX.isChecked(): self.is_p1_active = True else: self.is_p1_active = False def toggle_p2_activation(self): if self.ui.p2_activate_CHECKBOX.isChecked(): self.is_p2_active = True else: self.is_p2_active = False def toggle_p3_activation(self): if self.ui.p3_activate_CHECKBOX.isChecked(): self.is_p3_active = True else: self.is_p3_active = False # Get a list of active pumps (IDK if this is the best way to do this) def get_active_pumps(self): pumps_list = [self.is_p1_active, self.is_p2_active, self.is_p3_active] active_pumps = [i+1 for i in range(len(pumps_list)) if pumps_list[i]] return active_pumps def display_p1_syringe(self): self.ui.p1_syringe_LABEL.setText(self.ui.p1_syringe_DROPDOWN.currentText()) def display_p2_syringe(self): self.ui.p2_syringe_LABEL.setText(self.ui.p2_syringe_DROPDOWN.currentText()) def display_p3_syringe(self): self.ui.p3_syringe_LABEL.setText(self.ui.p3_syringe_DROPDOWN.currentText()) def display_p1_speed(self): self.ui.p1_units_LABEL.setText(str(self.p1_speed) + " " + self.ui.p1_units_DROPDOWN.currentText()) def display_p2_speed(self): self.ui.p2_units_LABEL.setText(str(self.p2_speed) + " " + self.ui.p2_units_DROPDOWN.currentText()) def display_p3_speed(self): self.ui.p3_units_LABEL.setText(str(self.p3_speed) + " " + self.ui.p3_units_DROPDOWN.currentText()) # Set Px distance to move def set_p1_amount(self): self.p1_amount = self.ui.p1_amount_INPUT.value() def set_p2_amount(self): self.p2_amount = self.ui.p2_amount_INPUT.value() def set_p3_amount(self): self.p3_amount = self.ui.p3_amount_INPUT.value() # Set Px jog delta #def set_p1_jog_delta(self): # self.p1_jog_delta = self.ui.p1_jog_delta_INPUT.value() #def set_p2_jog_delta(self): # self.p2_jog_delta = self.ui.p2_jog_delta_INPUT.value() #def set_p3_jog_delta(self): # self.p3_jog_delta = self.ui.p3_jog_delta_INPUT.value() # Set the coordinate system for the pump def set_coordinate(self, radio): if radio.text() == "Abs.": if radio.isChecked(): self.coordinate = "absolute" if radio.text() == "Incr.": if radio.isChecked(): self.coordinate = "incremental" def run(self): self.statusBar().showMessage("You clicked Run") testData = [] active_pumps = self.get_active_pumps() if len(active_pumps) > 0: p1_input_displacement = str(self.convert_displacement(self.p1_amount, self.p1_units, self.p1_syringe_area)) p2_input_displacement = str(self.convert_displacement(self.p2_amount, self.p2_units, self.p2_syringe_area)) p3_input_displacement = str(self.convert_displacement(self.p3_amount, self.p3_units, self.p3_syringe_area)) pumps_2_run = ''.join(map(str,active_pumps)) cmd = "<RUN,DIST,"+pumps_2_run+",0.0,F," + p1_input_displacement + "," + p2_input_displacement + "," + p3_input_displacement + ">" testData.append(cmd) worker = Worker(self.runTest, testData) print("Sending Jog Information") time.sleep(3) self.threadpool.start(worker) #self.runTest(testData) #send jog forward command else: self.statusBar().showMessage("No pumps enabled.") def pause(self): testData = [] cmd = "<RESUME,BLAH,BLAH,BLAH,F,0.0,0.0,0.0>" testData.append(cmd) worker = Worker(self.runTest, testData) self.threadpool.start(worker) def resume(self): cmd = "<RESUME,BLAH,BLAH,BLAH,F,0.0,0.0,0.0>" testData.append(cmd) worker = Worker(self.runTest, testData) self.threadpool.start(worker) def zero(self): self.statusBar().showMessage("You clicked Zero") testData = [] cmd = "<ZERO,BLAH,BLAH,BLAH,F,0.0,0.0,0.0>" worker = Worker(self.runTest, testData) print("Sending Setup Information") time.sleep(3) self.threadpool.start(worker) def stop(self): cmd = "<STOP,BLAH,BLAH,BLAH,F,0.0,0.0,0.0>" worker = Worker(self.send_single_command, cmd) print("Stopping") self.threadpool.start(worker) def jog(self, btn): #self.serial.flushInput() testData = [] active_pumps = self.get_active_pumps() if len(active_pumps) > 0: pumps_2_run = ''.join(map(str,active_pumps)) one_jog = str(self.p1_setup_jog_delta_to_send) two_jog = str(self.p2_setup_jog_delta_to_send) three_jog = str(self.p3_setup_jog_delta_to_send) if btn.text() == "Jog +": f_cmd = "<RUN,DIST," + pumps_2_run +",0,F," + one_jog + "," + two_jog + "," + three_jog + ">" testData.append(f_cmd) worker = Worker(self.runTest, testData) print("Sending Jog Information") #time.sleep(3) self.threadpool.start(worker) #send jog forward command if btn.text() == "Jog -": #add optional argument for direction b_cmd = "<RUN,DIST," + pumps_2_run +",0,B," + one_jog + "," + two_jog + "," + three_jog + ">" testData.append(b_cmd) worker = Worker(self.runTest, testData) print("Sending Jog Information") #time.sleep(3) self.threadpool.start(worker) #send jog forward command else: self.statusBar().showMessage("No pumps enabled.") # ====================== # FUNCTIONS : Camera # ====================== # Initialize the camera def start_camera(self): camera_port = 0 self.capture = cv2.VideoCapture(camera_port) #TODO check the native resolution of the camera and scale the size down here self.capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 800) self.capture.set(cv2.CAP_PROP_FRAME_WIDTH, 400) self.timer = QTimer(self) self.timer.timeout.connect(self.update_frame) self.timer.start(5) # Update frame function def update_frame(self): ret, self.image = self.capture.read() self.image = cv2.flip(self.image, 1) self.display_image(self.image, 1) # Display image in frame def display_image(self, image, window=1): qformat = QtGui.QImage.Format_Indexed8 if len(image.shape) == 3: # if image.shape[2] == 4: qformat = QtGui.QImage.Format_RGBA8888 else: qformat = QtGui.QImage.Format_RGB888 print(image.shape[0], image.shape[1], image.shape[2]) self.img_2_display = QtGui.QImage(image, image.shape[1], image.shape[0], image.strides[0], qformat) self.img_2_display = QtGui.QImage.rgbSwapped(self.img_2_display) if window == 1: self.ui.imgLabel.setPixmap(QtGui.QPixmap.fromImage(self.img_2_display)) self.ui.imgLabel.setScaledContents(False) # Save image to set location def save_image(self): # Create a date string self.date_string = datetime.now().strftime("%Y-%m-%d %H:%M:%S") # Replace semicolons with underscores self.date_string = self.date_string.replace(":","_") self.write_image_loc = './images/'+self.date_string + '.png' cv2.imwrite(self.write_image_loc, self.image) self.statusBar().showMessage("Captured Image, saved to: " + self.write_image_loc) # Stop camera def stop_camera(self): self.timer.stop() # ====================== # FUNCTIONS : Setup # ====================== # Populate the available ports def populate_ports(self): """ :raises EnvironmentError: On unsupported or unknown platforms :returns: A list of the serial ports available on the system """ if sys.platform.startswith('win'): ports = ['COM%s' % (i + 1) for i in range(256)] elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'): # this excludes your current terminal "/dev/tty" ports = glob.glob('/dev/tty[A-Za-z]*') elif sys.platform.startswith('darwin'): ports = glob.glob('/dev/tty.*') else: raise EnvironmentError('Unsupported platform') result = [] for port in ports: try: s = serial.Serial(port) s.close() result.append(port) except (OSError, serial.SerialException): pass self.ui.port_DROPDOWN.addItems(result) # Refresh the list of ports def refresh_ports(self): self.ui.port_DROPDOWN.clear() self.populate_ports() # Set the port that is selected from the dropdown menu def set_port(self): self.port = self.ui.port_DROPDOWN.currentText() # Set the name of the log file def set_log_file_name(self): r""" Sets the file name for the current test run, enables us to log data to the file. Callback setter method from the 'self.ui.logFileNameInput' to set the name of the log file. The log file name is of the form label_Year-Month-Date hour_min_sec.txt """ # Create a date string self.date_string = datetime.now().strftime("%Y-%m-%d %H:%M:%S") # Replace semicolons with underscores self.date_string = self.date_string.replace(":","_") self.log_file_name = self.ui.log_file_name_INPUT.text() + "_" + self.date_string + ".png" def save_settings(self): name, _ = QFileDialog.getSaveFileName(self,'Save File', options=QFileDialog.DontUseNativeDialog) # Create a date string self.date_string = datetime.now().strftime("%Y-%m-%d %H:%M:%S") # Replace semicolons with underscores self.date_string = self.date_string.replace(":","_") date_string = self.date_string # write all of the settings here ## Settings for pump 1 p1_syringe = str(self.p1_syringe) p1_units = str(self.p1_units) p1_speed = str(self.p1_speed) p1_accel = str(self.p1_accel) p1_setup_jog_delta = str(self.p1_setup_jog_delta) print(p1_setup_jog_delta) ## Settings for pump 2 p2_syringe = str(self.p2_syringe) p2_units = str(self.p2_units) p2_speed = str(self.p2_speed) p2_accel = str(self.p2_accel) p2_setup_jog_delta = str(self.p2_setup_jog_delta) ## Settings for pump 3 p3_syringe = str(self.p3_syringe) p3_units = str(self.p3_units) p3_speed = str(self.p3_speed) p3_accel = str(self.p3_accel) p3_setup_jog_delta = str(self.p3_setup_jog_delta) text = [] text.append("File name: " + name + "\n") # line 0 text.append("Date time: " + date_string + "\n") # line 1 text.append(":================================ \n") # line 2 text.append("P1 Syrin: " + p1_syringe + "\n") # line 3 text.append("P1 Units: " + p1_units + "\n") # line 4 text.append("P1 Speed: " + p1_speed + "\n") # line 5 text.append("P1 Accel: " + p1_accel + "\n") # line 6 text.append("P1 Jog D: " + p1_setup_jog_delta + "\n") # line 7 text.append(":================================ \n") # line 8 text.append("P2 Syrin: " + p2_syringe + "\n") # line 9 text.append("P2 Units: " + p2_units + "\n") # line 10 text.append("P2 Speed: " + p2_speed + "\n") # line 11 text.append("P2 Accel: " + p2_accel + "\n") # line 12 text.append("P2 Jog D: " + p2_setup_jog_delta + "\n") # line 13 text.append(":================================ \n") # line 14 text.append("P3 Syrin: " + p3_syringe + "\n") # line 15 text.append("P3 Units: " + p3_units + "\n") # line 16 text.append("P3 Speed: " + p3_speed + "\n") # line 17 text.append("P3 Accel: " + p3_accel + "\n") # line 18 text.append("P3 Jog D: " + p3_setup_jog_delta + "\n") # line 19 with open(name, 'w') as f: f.writelines(text) def load_settings(self): # need to make name an tupple otherwise i had an error and app crashed name, _ = QFileDialog.getOpenFileName(self, 'Open File', options=QFileDialog.DontUseNativeDialog) with open(name, 'r') as f: text = f.readlines() # here is where you load all of your variables # reformatting the text text = [line.split(':')[-1].strip('\n')[1:] for line in text] print(text) fname = text[0] date_string = text[1] p1_syringe = text[3] p1_units = text[4] p1_speed = text[5] p1_accel = text[6] p1_setup_jog_delta = text[7] p2_syringe = text[9] p2_units = text[10] p2_speed = text[11] p2_accel = text[12] p2_setup_jog_delta = text[13] p3_syringe = text[15] p3_units = text[16] p3_speed = text[17] p3_accel = text[18] p3_setup_jog_delta = text[19] #print(fname, date_string, p1_syringe, p1_units, p1_speed, p1_accel, p1_setup_jog_delta) p1_syringe_index = self.ui.p1_syringe_DROPDOWN.findText(p1_syringe, QtCore.Qt.MatchFixedString) self.ui.p1_syringe_DROPDOWN.setCurrentIndex(p1_syringe_index) p1_units_index = self.ui.p1_units_DROPDOWN.findText(p1_units, QtCore.Qt.MatchFixedString) self.ui.p1_units_DROPDOWN.setCurrentIndex(p1_units_index) self.ui.p1_speed_INPUT.setValue(float(p1_speed)) self.ui.p1_accel_INPUT.setValue(float(p1_accel)) print('==================') print("This is the jog: ", p1_setup_jog_delta) print('type: ', str(type(p1_setup_jog_delta))) print('==================') AllItems = [self.ui.p1_setup_jog_delta_INPUT.itemText(i) for i in range(self.ui.p1_setup_jog_delta_INPUT.count())] print("This is the list of jogs: ",AllItems) p1_setup_jog_delta_index = self.ui.p1_setup_jog_delta_INPUT.findText(p1_setup_jog_delta, QtCore.Qt.MatchFixedString) print("p1_setup_jog_delta_index is: ",p1_setup_jog_delta_index) self.ui.p1_setup_jog_delta_INPUT.setCurrentIndex(p1_setup_jog_delta_index) p2_syringe_index = self.ui.p2_syringe_DROPDOWN.findText(p2_syringe, QtCore.Qt.MatchFixedString) self.ui.p2_syringe_DROPDOWN.setCurrentIndex(p2_syringe_index) p2_units_index = self.ui.p2_units_DROPDOWN.findText(p2_units, QtCore.Qt.MatchFixedString) self.ui.p2_units_DROPDOWN.setCurrentIndex(p2_units_index) self.ui.p2_speed_INPUT.setValue(float(p2_speed)) self.ui.p2_accel_INPUT.setValue(float(p2_accel)) p2_setup_jog_delta_index = self.ui.p2_setup_jog_delta_INPUT.findText(p2_setup_jog_delta, QtCore.Qt.MatchFixedString) self.ui.p2_setup_jog_delta_INPUT.setCurrentIndex(p2_setup_jog_delta_index) p3_syringe_index = self.ui.p3_syringe_DROPDOWN.findText(p3_syringe, QtCore.Qt.MatchFixedString) self.ui.p3_syringe_DROPDOWN.setCurrentIndex(p3_syringe_index) p3_units_index = self.ui.p3_units_DROPDOWN.findText(p3_units, QtCore.Qt.MatchFixedString) self.ui.p3_units_DROPDOWN.setCurrentIndex(p3_units_index) self.ui.p3_speed_INPUT.setValue(float(p3_speed)) self.ui.p3_accel_INPUT.setValue(float(p3_accel)) p3_setup_jog_delta_index = self.ui.p3_setup_jog_delta_INPUT.findText(p3_setup_jog_delta, QtCore.Qt.MatchFixedString) self.ui.p3_setup_jog_delta_INPUT.setCurrentIndex(p3_setup_jog_delta_index) self.statusBar().showMessage("Settings loaded from: " + text[1]) # Populate the list of possible syringes to the dropdown menus def populate_syringe_sizes(self): self.syringe_options = ["BD 1 mL", "BD 3 mL", "BD 5 mL", "BD 10 mL", "BD 20 mL", "BD 30 mL", "BD 60 mL"] self.syringe_volumes = [1, 3, 5, 10, 20, 30, 60] self.syringe_areas = [17.34206347, 57.88559215, 112.9089185, 163.539454, 285.022957, 366.0961536, 554.0462538] self.ui.p1_syringe_DROPDOWN.addItems(self.syringe_options) self.ui.p2_syringe_DROPDOWN.addItems(self.syringe_options) self.ui.p3_syringe_DROPDOWN.addItems(self.syringe_options) # Set Px syringe def set_p1_syringe(self): self.p1_syringe = self.ui.p1_syringe_DROPDOWN.currentText() self.p1_syringe_area = self.syringe_areas[self.syringe_options.index(self.p1_syringe)] self.display_p1_syringe() def set_p2_syringe(self): self.p2_syringe = self.ui.p2_syringe_DROPDOWN.currentText() self.p2_syringe_area = self.syringe_areas[self.syringe_options.index(self.p2_syringe)] self.display_p2_syringe() def set_p3_syringe(self): self.p3_syringe = self.ui.p3_syringe_DROPDOWN.currentText() self.p3_syringe_area = self.syringe_areas[self.syringe_options.index(self.p3_syringe)] self.display_p3_syringe() # Set Px units def set_p1_units(self): self.p1_units = self.ui.p1_units_DROPDOWN.currentText() self.set_p1_speed() self.set_p1_accel() self.set_p1_setup_jog_delta() self.set_p1_amount() def set_p2_units(self): self.p2_units = self.ui.p2_units_DROPDOWN.currentText() self.set_p2_speed() self.set_p2_accel() self.set_p2_setup_jog_delta() self.set_p2_amount() def set_p3_units(self): self.p3_units = self.ui.p3_units_DROPDOWN.currentText() self.set_p3_speed() self.set_p3_accel() self.set_p3_setup_jog_delta() self.set_p3_amount() def populate_pump_units(self): print("I DID UNITS") self.units = ['mm/s', 'mL/s', 'mL/hr', 'µL/hr'] self.ui.p1_units_DROPDOWN.addItems(self.units) self.ui.p2_units_DROPDOWN.addItems(self.units) self.ui.p3_units_DROPDOWN.addItems(self.units) def populate_pump_jog_delta(self): self.jog_delta = ['0.01', '0.1', '1.0', '10.0'] print("I DID THIS") self.ui.p1_setup_jog_delta_INPUT.addItems(self.jog_delta) self.ui.p2_setup_jog_delta_INPUT.addItems(self.jog_delta) self.ui.p3_setup_jog_delta_INPUT.addItems(self.jog_delta) # Set Px speed TODO def set_p1_speed(self): self.p1_speed = self.ui.p1_speed_INPUT.value() self.ui.p1_units_LABEL.setText(str(self.p1_speed) + " " + self.ui.p1_units_DROPDOWN.currentText()) self.p1_speed_to_send = self.convert_speed(self.p1_speed, self.p1_units, self.p1_syringe_area) #print(str(self.p1_speed) + " // " + str(self.p1_speed_to_send)) def set_p2_speed(self): self.p2_speed = self.ui.p2_speed_INPUT.value() self.ui.p2_units_LABEL.setText(str(self.p2_speed) + " " + self.ui.p2_units_DROPDOWN.currentText()) self.p2_speed_to_send = self.convert_speed(self.p2_speed, self.p2_units, self.p2_syringe_area) print(str(self.p2_speed) + " // " + str(self.p2_speed_to_send)) def set_p3_speed(self): self.p3_speed = self.ui.p3_speed_INPUT.value() self.ui.p3_units_LABEL.setText(str(self.p3_speed) + " " + self.ui.p3_units_DROPDOWN.currentText()) self.p3_speed_to_send = self.convert_speed(self.p3_speed, self.p3_units, self.p3_syringe_area) print(str(self.p3_speed) + " // " + str(self.p3_speed_to_send)) # Set Px accel TODO def set_p1_accel(self): self.p1_accel = self.ui.p1_accel_INPUT.value() self.p1_accel_to_send = self.convert_accel(self.p1_accel, self.p1_units, self.p1_syringe_area) print(str(self.p1_accel) + " // " + str(self.p1_accel_to_send)) def set_p2_accel(self): self.p2_accel = self.ui.p2_accel_INPUT.value() self.p2_accel_to_send = self.convert_accel(self.p2_accel, self.p2_units, self.p2_syringe_area) def set_p3_accel(self): self.p3_accel = self.ui.p3_accel_INPUT.value() self.p3_accel_to_send = self.convert_accel(self.p3_accel, self.p3_units, self.p3_syringe_area) # Set Px jog delta (setup) TODO def set_p1_setup_jog_delta(self): self.p1_setup_jog_delta = self.ui.p1_setup_jog_delta_INPUT.currentText() self.p1_setup_jog_delta = float(self.ui.p1_setup_jog_delta_INPUT.currentText()) self.p1_setup_jog_delta_to_send = self.convert_displacement(self.p1_setup_jog_delta, self.p1_units, self.p1_syringe_area) def set_p2_setup_jog_delta(self): self.p2_setup_jog_delta = float(self.ui.p2_setup_jog_delta_INPUT.currentText()) self.p2_setup_jog_delta_to_send = self.convert_displacement(self.p2_setup_jog_delta, self.p2_units, self.p2_syringe_area) def set_p3_setup_jog_delta(self): self.p3_setup_jog_delta = float(self.ui.p3_setup_jog_delta_INPUT.currentText()) self.p3_setup_jog_delta_to_send = self.convert_displacement(self.p3_setup_jog_delta, self.p3_units, self.p3_syringe_area) # Send Px settings def send_p1_settings(self): self.p1_settings = [] self.p1_settings.append("<SETTING,SPEED,1," + str(self.p1_speed_to_send) + ",F,0.0,0.0,0.0>") self.p1_settings.append("<SETTING,ACCEL,1," + str(self.p1_accel_to_send) + ",F,0.0,0.0,0.0>") self.p1_settings.append("<SETTING,DELTA,1," + str(self.p1_setup_jog_delta_to_send) + ",F,0.0,0.0,0.0>") worker = Worker(self.runTest, self.p1_settings) print("Sending P1 Setup Information") self.statusBar().showMessage("Sending P1 setup information.") self.threadpool.start(worker) def send_p2_settings(self): self.p2_settings = [] self.p2_settings.append("<SETTING,SPEED,2," + str(self.p2_speed_to_send) + ",F,0.0,0.0,0.0>") self.p2_settings.append("<SETTING,ACCEL,2," + str(self.p2_accel_to_send) + ",F,0.0,0.0,0.0>") self.p2_settings.append("<SETTING,DELTA,2," + str(self.p2_setup_jog_delta_to_send) + ",F,0.0,0.0,0.0>") worker = Worker(self.runTest, self.p2_settings) print("Sending P2 Setup Information") self.statusBar().showMessage("Sending P2 setup information.") self.threadpool.start(worker) def send_p3_settings(self): self.p3_settings = [] self.p3_settings.append("<SETTING,SPEED,3," + str(self.p3_speed_to_send) + ",F,0.0,0.0,0.0>") self.p3_settings.append("<SETTING,ACCEL,3," + str(self.p3_accel_to_send) + ",F,0.0,0.0,0.0>") self.p3_settings.append("<SETTING,DELTA,3," + str(self.p3_setup_jog_delta_to_send) + ",F,0.0,0.0,0.0>") worker = Worker(self.runTest, self.p3_settings) print("Sending P3 Setup Information") self.statusBar().showMessage("Sending P3 setup information.") self.threadpool.start(worker) # Connect to the Arduino board def connect(self): #self.port_nano = '/dev/cu.usbserial-A9M11B77' #self.port_uno = "/dev/cu.usbmodem1411" #self.baudrate = baudrate self.statusBar().showMessage("Attempting to connect to board..") try: port_declared = self.port in vars() try: self.serial = serial.Serial() self.serial.port = self.port self.serial.baudrate = 115200 self.serial.parity = serial.PARITY_NONE self.serial.stopbits = serial.STOPBITS_ONE self.serial.bytesize = serial.EIGHTBITS self.serial.timeout = 1 self.serial.open() self.wait_for_arduino() self.statusBar().showMessage("Successfully connected to board.") # ~~~~~~~~~~~~~~~~ # TAB : Setup # ~~~~~~~~~~~~~~~~ self.ui.disconnect_BTN.setEnabled(True) self.ui.p1_setup_send_BTN.setEnabled(True) self.ui.p2_setup_send_BTN.setEnabled(True) self.ui.p3_setup_send_BTN.setEnabled(True) self.ui.send_all_BTN.setEnabled(True) self.ui.connect_BTN.setEnabled(False) except: self.statusBar().showMessage("Cannot connect to board. Try again..") raise CannotConnectException except AttributeError: self.statusBar().showMessage("Please plug in the board and select a proper port, then press connect.") # Disconnect from the Arduino board def disconnect(self): self.serial.close() self.statusBar().showMessage("The board has been disconnected.") self.grey_out_components() self.ui.connect_BTN.setEnabled(True) self.ui.disconnect_BTN.setEnabled(False) # Send all settings def send_all(self): self.settings = [] self.settings.append("<SETTING,SPEED,1,"+str(self.p1_speed_to_send)+",F,0.0,0.0,0.0>") self.settings.append("<SETTING,ACCEL,1,"+str(self.p1_accel_to_send)+",F,0.0,0.0,0.0>") self.settings.append("<SETTING,DELTA,1,"+str(self.p1_setup_jog_delta_to_send)+",F,0.0,0.0,0.0>") self.settings.append("<SETTING,SPEED,2,"+str(self.p2_speed_to_send)+",F,0.0,0.0,0.0>") self.settings.append("<SETTING,ACCEL,2,"+str(self.p2_accel_to_send)+",F,0.0,0.0,0.0>") self.settings.append("<SETTING,DELTA,2,"+str(self.p2_setup_jog_delta_to_send)+",F,0.0,0.0,0.0>") self.settings.append("<SETTING,SPEED,3,"+str(self.p3_speed_to_send)+",F,0.0,0.0,0.0>") self.settings.append("<SETTING,ACCEL,3,"+str(self.p3_accel_to_send)+",F,0.0,0.0,0.0>") self.settings.append("<SETTING,DELTA,3,"+str(self.p3_setup_jog_delta_to_send)+",F,0.0,0.0,0.0>") worker = Worker(self.runTest, self.settings) print("Sending all setup information") self.statusBar().showMessage("Sending all setup information.") self.threadpool.start(worker) self.ungrey_out_components() # ======================= # MISC : Functions I need # ======================= def steps2mm(self, steps): # 200 steps per rev # one rev is 0.8mm dist mm = steps/200/32*0.8 return mm def steps2mL(self, steps, syringe_area): mL = self.mm32mL(self.steps2mm(steps)*syringe_area) return mL def steps2uL(self, steps, syringe_area): uL = self.mm32uL(self.steps2mm(steps)*syringe_area) return uL def mm2steps(self, mm): steps = mm/0.8*200*32 return steps def mL2steps(self, mL, syringe_area): # note syringe_area is in mm^2 steps = self.mm2steps(self.mL2mm3(mL)/syringe_area) return steps def uL2steps(self, uL, syringe_area): steps = self.mm2steps(self.uL2mm3(uL)/syringe_area) return steps def mL2uL(self, mL): return mL*1000.0 def mL2mm3(self, mL): return mL*1000.0 def uL2mL(self, uL): return uL/1000.0 def uL2mm3(self, uL): return uL def mm32mL(self, mm3): return mm3/1000.0 def mm32uL(self, mm3): return mm3 def persec2permin(self, value_per_sec): value_per_min = value_per_sec*60.0 return value_per_min def persec2perhour(self, value_per_sec): value_per_hour = value_per_sec*60.0*60.0 return value_per_hour def permin2perhour(self, value_per_min): value_per_hour = value_per_min*60.0 return value_per_hour def permin2persec(self, value_per_min): value_per_sec = value_per_min/60.0 return value_per_sec def perhour2permin(self, value_per_hour): value_per_min = value_per_hour/60.0 return value_per_min def perhour2persec(self, value_per_hour): value_per_sec = value_per_hour/60.0/60.0 def convert_displacement(self, displacement, units, syringe_area): length = units.split("/")[0] time = units.split("/")[1] # convert length first if length == "mm": displacement = self.mm2steps(displacement) elif length == "mL": displacement = self.mL2steps(displacement, syringe_area) elif length == "µL": displacement = self.uL2steps(displacement, syringe_area) return displacement def convert_speed(self, speed, units, syringe_area): length = units.split("/")[0] time = units.split("/")[1] # convert length first if length == "mm": speed = self.mm2steps(speed) elif length == "mL": speed = self.mL2steps(speed, syringe_area) elif length == "µL": speed = self.uL2steps(speed, syringe_area) # convert time next if time == "s": pass elif time == "min": speed = self.permin2persec(speed) elif time == "hr": speed = self.perhour2persec(speed) return speed def convert_accel(self, accel, units, syringe_area): length = units.split("/")[0] time = units.split("/")[1] # convert length first if length == "mm": accel = self.mm2steps(accel) elif length == "mL": accel = self.mL2steps(accel, syringe_area) elif length == "µL": accel = self.uL2steps(accel, syringe_area) # convert time next if time == "s": pass elif time == "min": accel = self.permin2persec(self.permin2persec(accel)) elif time == "hr": accel = self.perhour2persec(self.perhour2persec(accel)) return accel ''' Syringe Volume (mL) | Syringe Area (mm^2) ----------------------------------------------- 1 | 17.34206347 3 | 57.88559215 5 | 112.9089185 10 | 163.539454 20 | 285.022957 30 | 366.0961536 60 | 554.0462538 IMPORTANT: These are for BD Plastic syringes ONLY!! Others will vary. ''' #====================================== Reading and Writing to Arduino def sendToArduino(self, sendStr): self.serial.write(sendStr.encode()) self.serial.flushInput() def recvFromArduino2(self): startMarker = self.startMarker midMarker = self.midMarker endMarker = self.endMarker i = 0 ck = "" x = "z" # any value that is not an end- or startMarker byteCount = -1 # to allow for the fact that the last increment will be one too many # wait for the start character while ord(x) != startMarker: x = self.serial.read() # save data until the end marker is found while ord(x) != endMarker: if ord(x) == midMarker: i += 1 print(ck) if i % 100 == 0: self.ui.p1_absolute_DISP.display(ck) ck = "" x = self.serial.read() if ord(x) != startMarker: #print(x) ck = ck + x.decode() byteCount += 1 x = self.serial.read() return(ck) def recvPositionArduino(self): startMarker = self.startMarker midMarker = self.midMarker endMarker = self.endMarker ck = "" x = "z" # any value that is not an end- or startMarker byteCount = -1 # to allow for the fact that the last increment will be one too many # wait for the start character while ord(x) != startMarker: x = self.serial.read() # save data until the end marker is found while ord(x) != endMarker: if ord(x) == midMarker: print(ck) self.ui.p1_absolute_DISP.display(ck) ck = "" x = self.serial.read() if ord(x) != startMarker: #print(x) ck = ck + x.decode() byteCount += 1 x = self.serial.read() return(ck) #============================ def wait_for_arduino(self): # wait until the Arduino sends 'Arduino Ready' - allows time for Arduino reset # it also ensures that any bytes left over from a previous message are discarded startMarker = self.startMarker midMarker = self.midMarker endMarker = self.endMarker msg = "" while msg.find("Arduino is ready") == -1: while self.serial.inWaiting() == 0: pass msg = self.recvFromArduino2() print(msg + "\n") def runTest(self,td): numLoops = len(td) waitingForReply = False n = 0 while n < numLoops: teststr = td[n] if waitingForReply == False: self.sendToArduino(teststr) print("Sent from PC -- LOOP NUM " + str(n) + " STR " + teststr) waitingForReply = True if waitingForReply == True: while self.serial.inWaiting() == 0: pass dataRecvd = self.recvFromArduino2() print("Reply Received -- " + dataRecvd) n += 1 waitingForReply = False print("=============================\n\n") time.sleep(0.1) print("Send and receive complete\n\n") def send_single_command(self, command): waiting_for_reply = False if waiting_for_reply == False: self.sendToArduino(command) print("Sent from PC -- STR " + command) waiting_for_reply = True if waiting_for_reply == True: while self.serial.inWaiting() == 0: pass data_received = self.recvFromArduino2() print("Reply Received -- " + data_received) waiting_for_reply = False print("=============================\n\n") print("Sent a single command") def closeEvent(self, event): try: self.serial.close() self.threadpool.end() except AttributeError: pass sys.exit()