From f98949b7984f93a1b85c8708d37a0d67a2fa21f3 Mon Sep 17 00:00:00 2001 From: jens Date: Thu, 28 Jul 2022 11:17:26 +0200 Subject: [PATCH] Relevante Dateien und Umgebung gesammelt --- .gitignore | 4 + jfs_info.txt | 14 + jfs_main01.py | 307 +++++++ poseidon_controller_gui2.py | 963 +++++++++++++++++++++ poseidon_controller_gui2.ui | 1609 +++++++++++++++++++++++++++++++++++ poseidon_main.py | 1530 +++++++++++++++++++++++++++++++++ show_html.py | 250 ++++++ systemHtml.py | 38 + test.html | 52 ++ test_settings.txt | 21 + 10 files changed, 4788 insertions(+) create mode 100644 .gitignore create mode 100644 jfs_info.txt create mode 100644 jfs_main01.py create mode 100644 poseidon_controller_gui2.py create mode 100644 poseidon_controller_gui2.ui create mode 100644 poseidon_main.py create mode 100644 show_html.py create mode 100644 systemHtml.py create mode 100644 test.html create mode 100644 test_settings.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..00606a6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +build/ +dist/ +__pycache__/ + diff --git a/jfs_info.txt b/jfs_info.txt new file mode 100644 index 0000000..8e9b707 --- /dev/null +++ b/jfs_info.txt @@ -0,0 +1,14 @@ +Juni 2022 +This creates an Environment for the Software based on +poseidon https://github.com/pachterlab/poseidon +PyQtGraph https://www.pyqtgraph.org/ + +conda create --name piPyGra +conda activate piPyGra +conda install -c conda-forge pyqtgraph +conda install pyserial +pip install pyinstaller pyqt5 +pip install PyQtWebEngine + +... +conda deactivate \ No newline at end of file diff --git a/jfs_main01.py b/jfs_main01.py new file mode 100644 index 0000000..828d013 --- /dev/null +++ b/jfs_main01.py @@ -0,0 +1,307 @@ + +from poseidon_main import MainWindow, Thread +import sys, time +import serial +from PyQt5 import QtCore, QtWidgets +import pyqtgraph as pg + + +class MainWindow2( MainWindow): + + leftsignal = QtCore.pyqtSignal(float) + + def __init__(self): + super(MainWindow2,self).__init__() + self.setWindowTitle('Pyshi´ne drag and drop') + #print(self.globports) + #print(self.microstepping) + self.threadx = {} + ## grapfic output + self.timeBase=50 + self.x = [] + self.y = [] + self.grafwg = pg.PlotWidget() + self.ui.gridLayout_2.addWidget(self.grafwg, 0, 1, 1, 1) + self.data_line = self.grafwg.plot(self.x,self.y,pen=(0,255,0)) + ## limit to stop the flow + self.wait2Stopflow = False + self.stopFlowLimit = 0 + ## serail things + if self.globports == []: + self.populate_ports() + self.ui.rheo_port_comboBox.addItems(self.globports) + self.ui.comboBox.addItems(self.globports) + #self.ui.rheo_port_comboBox.currentIndexChanged['QString'].connect(self.setRheoPort) + self.ui.openRheo_btn.clicked.connect(self.connectESP32) + self.ui.closeRheo_btn.clicked.connect(self.disconnectESP32) + self.ui.clearDisplay.clicked.connect(self.clearPlot) + self.ui.start_btn.clicked.connect(self.startesp32) + self.ui.stop_btn.clicked.connect(self.stopesp32) + self.ui.comboBox_tb.setCurrentText(str(self.timeBase)) + self.ui.comboBox_tb.currentIndexChanged['QString'].connect(self.setTimeBase) + self.ui.checkBox.stateChanged.connect(self.clickedBox) + self.ui.lineEdit.returnPressed.connect(self.setFrequency) + self.ui.checkBox_2.stateChanged.connect(self.flowBox) + + self.ui.pushButton.clicked.connect(self.connectRheo) + self.ui.pushButton_2.clicked.connect(self.disconnectRheo) + self.ui.checkBox_3.stateChanged.connect(self.clickedBox3) + self.ui.pushButton_3.clicked.connect(self.sendRheoHome) + self.ui.pushButton_4.clicked.connect(self.sendRheoInject) + self.leftsignal.connect(self.setwhatsleft) + + ### ESP32 + def setFrequency(self): + s = self.ui.lineEdit.text() + cmd='o'+str(s)+'\n' + thread = Thread(self.sendToEsp32, cmd) + thread.finished.connect(lambda:self.thread_finished(thread)) + thread.start() + + def sendToEsp32(self, sendStr): + self.esp32_serial.write(sendStr.encode('utf-8')) + self.esp32_serial.flushInput() + + def clickedBox(self,state): + if state == QtCore.Qt.Checked: + print('checkes') + self.threadx[2] =ThC_2(parent=None,port = self.esp32_serial) + self.threadx[2].start() + else: + print('no') + self.threadx[2].stop() + + def flowBox(self,state): + if state == QtCore.Qt.Checked: + print('checkes') + self.wait2Stopflow=True + self.stopFlowLimit = float(self.ui.lineEdit_2.text()) + else: + print('no') + self.wait2Stopflow=False + + + def startesp32(self): + self.threadx[1] = ThC(parent=None,index=1,port = self.esp32_serial,base=self.timeBase) + self.threadx[1].start() + self.threadx[1].datasignal.connect(self.updateData) + self.ui.start_btn.setEnabled(False) + self.ui.stop_btn.setEnabled(True) + + def stopesp32(self): + self.threadx[1].stop() + self.ui.start_btn.setEnabled(True) + self.ui.stop_btn.setEnabled(False) + + def setTimeBase(self): + self.timeBase=int(self.ui.comboBox_tb.currentText()) + + def connectRheo(self): + self.rheo_port = self.ui.comboBox.currentText() + self.statusBar().showMessage("You clicked CONNECT TO Rheo Ventil") + try: + port_declared = self.port in vars() + try: + print(self.rheo_port) + self.rheo_serial = serial.Serial() + self.rheo_serial.port = self.rheo_port + self.rheo_serial.baudrate = 115200 + self.rheo_serial.parity = serial.PARITY_NONE + self.rheo_serial.stopbits = serial.STOPBITS_ONE + self.rheo_serial.bytesize = serial.EIGHTBITS + self.rheo_serial.timeout = 1 + self.rheo_serial.open() + # self.ui.closeRheo_btn.setEnabled(True) + # self.ui.openRheo_btn.setEnabled(False) + # self.ui.start_btn.setEnabled(True) + # self.ui.stop_btn.setEnabled(False) + + # self.ui.connect_BTN.setEnabled(False) + time.sleep(1) + self.statusBar().showMessage("Successfully connected to Rheo board.") + + 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.") + + def disconnectRheo(self): + self.statusBar().showMessage("You clicked DISCONNECT FROM Rheo") + print("Disconnecting from board..") + time.sleep(0.1) + self.rheo_serial.close() + print("Board has been disconnected") + + def clickedBox3(self,state): + if state == QtCore.Qt.Checked: + print('checkes') + self.sendRheoLoad() + else: + print('no') + self.sendRheoVentil() + + def sendRheoInject(self): + xx = int(self.ui.lineEdit_3.text()) + if (xx > 7) or (xx<0): + cmd=str(xx)+'\r\n' + self.sendToRheo(cmd) + + def sendRheoHome(self): + cmd=str(3)+'\r\n' + self.sendToRheo(cmd) + + def sendRheoLoad(self): + cmd=str(1)+'\r\n' + self.sendToRheo(cmd) + + def sendRheoVentil(self): + cmd=str(2)+'\r\n' + self.sendToRheo(cmd) + + def sendToRheo(self,cmd): + thread = Thread(self.sendRheo, cmd) + thread.finished.connect(lambda:self.thread_finished(thread)) + thread.start() + + def setwhatsleft(self,xx): + print (f'that left {xx} ') + + def sendRheo(self, sendStr): + self.rheo_serial.flushInput() + self.rheo_serial.write(sendStr.encode('utf-8')) + cmd=str(5)+'\r\n' + self.rheo_serial.write(sendStr.encode('utf-8')) + inp = self.rheo_serial.readline().decode('utf') + self.leftsignal.emit(float(inp)) + + + def connectESP32(self): + self.esp32_port = self.ui.rheo_port_comboBox.currentText() + self.statusBar().showMessage("You clicked CONNECT TO Esp32") + try: + port_declared = self.port in vars() + try: + print(self.esp32_port) + self.esp32_serial = serial.Serial() + self.esp32_serial.port = self.esp32_port + self.esp32_serial.baudrate = 115200 + self.esp32_serial.parity = serial.PARITY_NONE + self.esp32_serial.stopbits = serial.STOPBITS_ONE + self.esp32_serial.bytesize = serial.EIGHTBITS + self.esp32_serial.timeout = 1 + self.esp32_serial.open() + self.ui.closeRheo_btn.setEnabled(True) + self.ui.openRheo_btn.setEnabled(False) + self.ui.start_btn.setEnabled(True) + self.ui.stop_btn.setEnabled(False) + + # self.ui.connect_BTN.setEnabled(False) + time.sleep(1) + self.statusBar().showMessage("Successfully connected to esp32 board.") + + 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.") + + + def disconnectESP32(self): + self.statusBar().showMessage("You clicked DISCONNECT FROM ESP32") + print("Disconnecting from board..") + time.sleep(0.1) + self.esp32_serial.close() + print("Board has been disconnected") + + self.ui.openRheo_btn.setEnabled(True) + self.ui.closeRheo_btn.setEnabled(False) + self.ui.start_btn.setEnabled(False) + self.ui.stop_btn.setEnabled(False) + + def checkForStopFlow(self): + if self.checkForStopFlow : + if self.y[-1] > self.stopFlowLimit : + self.ui.pause_BTN.clicked.emit() + + + + def updateData(self,x,y): + self.x.append(x) + self.y.append(y) + self.data_line.setData(self.x,self.y) + if self.wait2Stopflow == True: + if (self.y[-1] >= self.stopFlowLimit): + self.ui.pause_BTN.clicked.emit() + self.wait2Stopflow = False + self.ui.checkBox_2.setChecked(False) + + + def clearPlot(self): + self.x.clear() + self.y.clear() + self.data_line.setData(self.x,self.y) + + + def sendToEsp32(self, sendStr): + self.esp32_serial.write(sendStr.encode()) + self.esp32_serial.flushInput() + + + +class ThC(QtCore.QThread): + datasignal = QtCore.pyqtSignal(int,float) + def __init__(self,parent=None,port=None,index=0,base=100): + super(ThC, self).__init__(parent) + self.index = index + self.is_running = True + self.port = port + self.base = base + def run(self): + print(f"Thread {self.index} started") + self.port.flushOutput() + self.port.flushInput() + i = self.base*1000 + cmd = 's'+str(i)+'\n' + self.port.write(cmd.encode('utf-8')) + cnt = 0; + while True: + cnt+=1 + inp = self.port.readline() + if inp[0] == 62 and inp[-3] == 60 : + inp = inp[1:-3] + y = float(inp.decode('utf-8')) + self.datasignal.emit(cnt,y) + + time.sleep(0.001) + def stop(self): + self.is_running=False + print(f"Thread {self.index} stopped") + self.terminate() + +class ThC_2(QtCore.QThread): + def __init__(self,parent=None,port=None): + super(ThC_2,self).__init__(parent) + self.is_running = True + self.port=port + def run(self): + cnt=0 + while True: + cnt+= 1 + if cnt >= 100 : cnt = 1 + cmd = 'o'+str(cnt*10000)+'\n' + print(cmd) + self.port.write(cmd.encode('utf-8')) + time.sleep(1) + def stop(self): + self.is_running=False + print(f'Thread ThC-2 stopped') + self.terminate() + + + +if __name__ == '__main__': + app = QtWidgets.QApplication(sys.argv) + window = MainWindow2() + window.show() + sys.exit(app.exec_()) \ No newline at end of file diff --git a/poseidon_controller_gui2.py b/poseidon_controller_gui2.py new file mode 100644 index 0000000..eae78b5 --- /dev/null +++ b/poseidon_controller_gui2.py @@ -0,0 +1,963 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'poseidon_controller_gui2.ui' +# +# Created by: PyQt5 UI code generator 5.15.4 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(1071, 869) + self.centralwidget = QtWidgets.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) + self.verticalLayout.setObjectName("verticalLayout") + self.tabWidget = QtWidgets.QTabWidget(self.centralwidget) + self.tabWidget.setFocusPolicy(QtCore.Qt.TabFocus) + self.tabWidget.setAcceptDrops(False) + self.tabWidget.setTabPosition(QtWidgets.QTabWidget.North) + self.tabWidget.setTabShape(QtWidgets.QTabWidget.Triangular) + self.tabWidget.setIconSize(QtCore.QSize(16, 16)) + self.tabWidget.setMovable(False) + self.tabWidget.setObjectName("tabWidget") + self.control = QtWidgets.QWidget() + self.control.setObjectName("control") + self.horizontalLayout_10 = QtWidgets.QHBoxLayout(self.control) + self.horizontalLayout_10.setObjectName("horizontalLayout_10") + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.verticalLayout_9 = QtWidgets.QVBoxLayout() + self.verticalLayout_9.setObjectName("verticalLayout_9") + self.gridLayout_6 = QtWidgets.QGridLayout() + self.gridLayout_6.setObjectName("gridLayout_6") + self.line_4 = QtWidgets.QFrame(self.control) + self.line_4.setFrameShadow(QtWidgets.QFrame.Raised) + self.line_4.setLineWidth(3) + self.line_4.setFrameShape(QtWidgets.QFrame.VLine) + self.line_4.setObjectName("line_4") + self.gridLayout_6.addWidget(self.line_4, 0, 2, 1, 1) + self.label = QtWidgets.QLabel(self.control) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label.setFont(font) + self.label.setText("") + self.label.setAlignment(QtCore.Qt.AlignCenter) + self.label.setObjectName("label") + self.gridLayout_6.addWidget(self.label, 0, 0, 1, 1) + self.p2_incremental_DISP = QtWidgets.QLCDNumber(self.control) + self.p2_incremental_DISP.setFrameShape(QtWidgets.QFrame.Panel) + self.p2_incremental_DISP.setFrameShadow(QtWidgets.QFrame.Sunken) + self.p2_incremental_DISP.setDigitCount(5) + self.p2_incremental_DISP.setObjectName("p2_incremental_DISP") + self.gridLayout_6.addWidget(self.p2_incremental_DISP, 2, 3, 1, 1) + self.p3_remain_DISP = QtWidgets.QLCDNumber(self.control) + self.p3_remain_DISP.setFrameShape(QtWidgets.QFrame.Panel) + self.p3_remain_DISP.setFrameShadow(QtWidgets.QFrame.Sunken) + self.p3_remain_DISP.setDigitCount(5) + self.p3_remain_DISP.setObjectName("p3_remain_DISP") + self.gridLayout_6.addWidget(self.p3_remain_DISP, 3, 4, 1, 1) + self.horizontalLayout_12 = QtWidgets.QHBoxLayout() + self.horizontalLayout_12.setObjectName("horizontalLayout_12") + self.p2_activate_CHECKBOX = QtWidgets.QCheckBox(self.control) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.p2_activate_CHECKBOX.sizePolicy().hasHeightForWidth()) + self.p2_activate_CHECKBOX.setSizePolicy(sizePolicy) + self.p2_activate_CHECKBOX.setText("") + self.p2_activate_CHECKBOX.setObjectName("p2_activate_CHECKBOX") + self.horizontalLayout_12.addWidget(self.p2_activate_CHECKBOX) + self.label_6 = QtWidgets.QLabel(self.control) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_6.setFont(font) + self.label_6.setAlignment(QtCore.Qt.AlignCenter) + self.label_6.setObjectName("label_6") + self.horizontalLayout_12.addWidget(self.label_6) + self.gridLayout_6.addLayout(self.horizontalLayout_12, 0, 3, 1, 1) + self.label_56 = QtWidgets.QLabel(self.control) + font = QtGui.QFont() + font.setPointSize(15) + self.label_56.setFont(font) + self.label_56.setAlignment(QtCore.Qt.AlignCenter) + self.label_56.setObjectName("label_56") + self.gridLayout_6.addWidget(self.label_56, 2, 0, 1, 1) + self.p3_incremental_DISP = QtWidgets.QLCDNumber(self.control) + self.p3_incremental_DISP.setFrameShape(QtWidgets.QFrame.Panel) + self.p3_incremental_DISP.setFrameShadow(QtWidgets.QFrame.Sunken) + self.p3_incremental_DISP.setDigitCount(5) + self.p3_incremental_DISP.setObjectName("p3_incremental_DISP") + self.gridLayout_6.addWidget(self.p3_incremental_DISP, 2, 4, 1, 1) + self.horizontalLayout_14 = QtWidgets.QHBoxLayout() + self.horizontalLayout_14.setObjectName("horizontalLayout_14") + self.p1_activate_CHECKBOX = QtWidgets.QCheckBox(self.control) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.p1_activate_CHECKBOX.sizePolicy().hasHeightForWidth()) + self.p1_activate_CHECKBOX.setSizePolicy(sizePolicy) + self.p1_activate_CHECKBOX.setText("") + self.p1_activate_CHECKBOX.setObjectName("p1_activate_CHECKBOX") + self.horizontalLayout_14.addWidget(self.p1_activate_CHECKBOX) + self.label_8 = QtWidgets.QLabel(self.control) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_8.setFont(font) + self.label_8.setAlignment(QtCore.Qt.AlignCenter) + self.label_8.setObjectName("label_8") + self.horizontalLayout_14.addWidget(self.label_8) + self.gridLayout_6.addLayout(self.horizontalLayout_14, 0, 1, 1, 1) + self.label_57 = QtWidgets.QLabel(self.control) + font = QtGui.QFont() + font.setPointSize(15) + self.label_57.setFont(font) + self.label_57.setAlignment(QtCore.Qt.AlignCenter) + self.label_57.setObjectName("label_57") + self.gridLayout_6.addWidget(self.label_57, 3, 0, 1, 1) + self.p2_absolute_DISP = QtWidgets.QLCDNumber(self.control) + self.p2_absolute_DISP.setFrameShape(QtWidgets.QFrame.Panel) + self.p2_absolute_DISP.setFrameShadow(QtWidgets.QFrame.Sunken) + self.p2_absolute_DISP.setDigitCount(5) + self.p2_absolute_DISP.setObjectName("p2_absolute_DISP") + self.gridLayout_6.addWidget(self.p2_absolute_DISP, 1, 3, 1, 1) + self.p1_remain_DISP = QtWidgets.QLCDNumber(self.control) + self.p1_remain_DISP.setFrameShape(QtWidgets.QFrame.Panel) + self.p1_remain_DISP.setFrameShadow(QtWidgets.QFrame.Sunken) + self.p1_remain_DISP.setDigitCount(5) + self.p1_remain_DISP.setObjectName("p1_remain_DISP") + self.gridLayout_6.addWidget(self.p1_remain_DISP, 3, 1, 1, 1) + self.p1_incremental_DISP = QtWidgets.QLCDNumber(self.control) + self.p1_incremental_DISP.setFrameShape(QtWidgets.QFrame.Panel) + self.p1_incremental_DISP.setFrameShadow(QtWidgets.QFrame.Sunken) + self.p1_incremental_DISP.setDigitCount(5) + self.p1_incremental_DISP.setObjectName("p1_incremental_DISP") + self.gridLayout_6.addWidget(self.p1_incremental_DISP, 2, 1, 1, 1) + self.label_58 = QtWidgets.QLabel(self.control) + font = QtGui.QFont() + font.setPointSize(15) + self.label_58.setFont(font) + self.label_58.setAlignment(QtCore.Qt.AlignCenter) + self.label_58.setObjectName("label_58") + self.gridLayout_6.addWidget(self.label_58, 1, 0, 1, 1) + self.p3_absolute_DISP = QtWidgets.QLCDNumber(self.control) + self.p3_absolute_DISP.setFrameShape(QtWidgets.QFrame.Panel) + self.p3_absolute_DISP.setFrameShadow(QtWidgets.QFrame.Sunken) + self.p3_absolute_DISP.setDigitCount(5) + self.p3_absolute_DISP.setObjectName("p3_absolute_DISP") + self.gridLayout_6.addWidget(self.p3_absolute_DISP, 1, 4, 1, 1) + self.p2_remain_DISP = QtWidgets.QLCDNumber(self.control) + self.p2_remain_DISP.setFrameShape(QtWidgets.QFrame.Panel) + self.p2_remain_DISP.setFrameShadow(QtWidgets.QFrame.Sunken) + self.p2_remain_DISP.setDigitCount(5) + self.p2_remain_DISP.setObjectName("p2_remain_DISP") + self.gridLayout_6.addWidget(self.p2_remain_DISP, 3, 3, 1, 1) + self.horizontalLayout_13 = QtWidgets.QHBoxLayout() + self.horizontalLayout_13.setObjectName("horizontalLayout_13") + self.line_5 = QtWidgets.QFrame(self.control) + self.line_5.setFrameShadow(QtWidgets.QFrame.Raised) + self.line_5.setLineWidth(3) + self.line_5.setFrameShape(QtWidgets.QFrame.VLine) + self.line_5.setObjectName("line_5") + self.horizontalLayout_13.addWidget(self.line_5) + self.p3_activate_CHECKBOX = QtWidgets.QCheckBox(self.control) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.p3_activate_CHECKBOX.sizePolicy().hasHeightForWidth()) + self.p3_activate_CHECKBOX.setSizePolicy(sizePolicy) + self.p3_activate_CHECKBOX.setText("") + self.p3_activate_CHECKBOX.setObjectName("p3_activate_CHECKBOX") + self.horizontalLayout_13.addWidget(self.p3_activate_CHECKBOX) + self.label_25 = QtWidgets.QLabel(self.control) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_25.setFont(font) + self.label_25.setAlignment(QtCore.Qt.AlignCenter) + self.label_25.setObjectName("label_25") + self.horizontalLayout_13.addWidget(self.label_25) + self.gridLayout_6.addLayout(self.horizontalLayout_13, 0, 4, 1, 1) + self.p1_absolute_DISP = QtWidgets.QLCDNumber(self.control) + self.p1_absolute_DISP.setFrameShape(QtWidgets.QFrame.Panel) + self.p1_absolute_DISP.setFrameShadow(QtWidgets.QFrame.Sunken) + self.p1_absolute_DISP.setDigitCount(4) + self.p1_absolute_DISP.setObjectName("p1_absolute_DISP") + self.gridLayout_6.addWidget(self.p1_absolute_DISP, 1, 1, 1, 1) + self.verticalLayout_9.addLayout(self.gridLayout_6) + self.line_3 = QtWidgets.QFrame(self.control) + self.line_3.setFrameShadow(QtWidgets.QFrame.Raised) + self.line_3.setLineWidth(2) + self.line_3.setFrameShape(QtWidgets.QFrame.HLine) + self.line_3.setObjectName("line_3") + self.verticalLayout_9.addWidget(self.line_3) + self.gridLayout_3 = QtWidgets.QGridLayout() + self.gridLayout_3.setObjectName("gridLayout_3") + self.horizontalLayout_8 = QtWidgets.QHBoxLayout() + self.horizontalLayout_8.setObjectName("horizontalLayout_8") + self.horizontalLayout_9 = QtWidgets.QHBoxLayout() + self.horizontalLayout_9.setObjectName("horizontalLayout_9") + self.p2_amount_INPUT = QtWidgets.QDoubleSpinBox(self.control) + self.p2_amount_INPUT.setDecimals(3) + self.p2_amount_INPUT.setMinimum(-99.0) + self.p2_amount_INPUT.setObjectName("p2_amount_INPUT") + self.horizontalLayout_9.addWidget(self.p2_amount_INPUT) + self.horizontalLayout_8.addLayout(self.horizontalLayout_9) + self.p2_units_LABEL_2 = QtWidgets.QLabel(self.control) + self.p2_units_LABEL_2.setAlignment(QtCore.Qt.AlignCenter) + self.p2_units_LABEL_2.setObjectName("p2_units_LABEL_2") + self.horizontalLayout_8.addWidget(self.p2_units_LABEL_2) + self.gridLayout_3.addLayout(self.horizontalLayout_8, 3, 3, 1, 1) + self.horizontalLayout_15 = QtWidgets.QHBoxLayout() + self.horizontalLayout_15.setObjectName("horizontalLayout_15") + self.horizontalLayout_16 = QtWidgets.QHBoxLayout() + self.horizontalLayout_16.setObjectName("horizontalLayout_16") + self.p3_amount_INPUT = QtWidgets.QDoubleSpinBox(self.control) + self.p3_amount_INPUT.setDecimals(3) + self.p3_amount_INPUT.setMinimum(-99.0) + self.p3_amount_INPUT.setObjectName("p3_amount_INPUT") + self.horizontalLayout_16.addWidget(self.p3_amount_INPUT) + self.horizontalLayout_15.addLayout(self.horizontalLayout_16) + self.p3_units_LABEL_2 = QtWidgets.QLabel(self.control) + self.p3_units_LABEL_2.setAlignment(QtCore.Qt.AlignCenter) + self.p3_units_LABEL_2.setObjectName("p3_units_LABEL_2") + self.horizontalLayout_15.addWidget(self.p3_units_LABEL_2) + self.gridLayout_3.addLayout(self.horizontalLayout_15, 4, 3, 1, 1) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.horizontalLayout_6 = QtWidgets.QHBoxLayout() + self.horizontalLayout_6.setObjectName("horizontalLayout_6") + self.p1_amount_INPUT = QtWidgets.QDoubleSpinBox(self.control) + self.p1_amount_INPUT.setDecimals(3) + self.p1_amount_INPUT.setMinimum(-99.0) + self.p1_amount_INPUT.setObjectName("p1_amount_INPUT") + self.horizontalLayout_6.addWidget(self.p1_amount_INPUT) + self.horizontalLayout.addLayout(self.horizontalLayout_6) + self.p1_units_LABEL_2 = QtWidgets.QLabel(self.control) + self.p1_units_LABEL_2.setAlignment(QtCore.Qt.AlignCenter) + self.p1_units_LABEL_2.setObjectName("p1_units_LABEL_2") + self.horizontalLayout.addWidget(self.p1_units_LABEL_2) + self.gridLayout_3.addLayout(self.horizontalLayout, 2, 3, 1, 1) + self.label_23 = QtWidgets.QLabel(self.control) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setItalic(False) + font.setUnderline(False) + font.setWeight(75) + self.label_23.setFont(font) + self.label_23.setText("") + self.label_23.setAlignment(QtCore.Qt.AlignCenter) + self.label_23.setObjectName("label_23") + self.gridLayout_3.addWidget(self.label_23, 1, 0, 1, 1) + self.label_14 = QtWidgets.QLabel(self.control) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_14.setFont(font) + self.label_14.setAlignment(QtCore.Qt.AlignCenter) + self.label_14.setObjectName("label_14") + self.gridLayout_3.addWidget(self.label_14, 3, 0, 1, 1) + self.label_15 = QtWidgets.QLabel(self.control) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_15.setFont(font) + self.label_15.setAlignment(QtCore.Qt.AlignCenter) + self.label_15.setObjectName("label_15") + self.gridLayout_3.addWidget(self.label_15, 4, 0, 1, 1) + self.label_24 = QtWidgets.QLabel(self.control) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setItalic(False) + font.setUnderline(False) + font.setWeight(75) + self.label_24.setFont(font) + self.label_24.setAlignment(QtCore.Qt.AlignCenter) + self.label_24.setObjectName("label_24") + self.gridLayout_3.addWidget(self.label_24, 1, 2, 1, 1) + self.p1_units_LABEL = QtWidgets.QLabel(self.control) + self.p1_units_LABEL.setAlignment(QtCore.Qt.AlignCenter) + self.p1_units_LABEL.setObjectName("p1_units_LABEL") + self.gridLayout_3.addWidget(self.p1_units_LABEL, 2, 2, 1, 1) + self.p3_syringe_LABEL = QtWidgets.QLabel(self.control) + self.p3_syringe_LABEL.setAlignment(QtCore.Qt.AlignCenter) + self.p3_syringe_LABEL.setObjectName("p3_syringe_LABEL") + self.gridLayout_3.addWidget(self.p3_syringe_LABEL, 4, 1, 1, 1) + self.p2_units_LABEL = QtWidgets.QLabel(self.control) + self.p2_units_LABEL.setAlignment(QtCore.Qt.AlignCenter) + self.p2_units_LABEL.setObjectName("p2_units_LABEL") + self.gridLayout_3.addWidget(self.p2_units_LABEL, 3, 2, 1, 1) + self.label_13 = QtWidgets.QLabel(self.control) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_13.setFont(font) + self.label_13.setAlignment(QtCore.Qt.AlignCenter) + self.label_13.setObjectName("label_13") + self.gridLayout_3.addWidget(self.label_13, 2, 0, 1, 1) + self.label_27 = QtWidgets.QLabel(self.control) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setItalic(False) + font.setUnderline(False) + font.setWeight(75) + self.label_27.setFont(font) + self.label_27.setAlignment(QtCore.Qt.AlignCenter) + self.label_27.setObjectName("label_27") + self.gridLayout_3.addWidget(self.label_27, 1, 1, 1, 1) + self.p3_units_LABEL = QtWidgets.QLabel(self.control) + self.p3_units_LABEL.setAlignment(QtCore.Qt.AlignCenter) + self.p3_units_LABEL.setObjectName("p3_units_LABEL") + self.gridLayout_3.addWidget(self.p3_units_LABEL, 4, 2, 1, 1) + self.p2_syringe_LABEL = QtWidgets.QLabel(self.control) + self.p2_syringe_LABEL.setAlignment(QtCore.Qt.AlignCenter) + self.p2_syringe_LABEL.setObjectName("p2_syringe_LABEL") + self.gridLayout_3.addWidget(self.p2_syringe_LABEL, 3, 1, 1, 1) + self.p1_syringe_LABEL = QtWidgets.QLabel(self.control) + self.p1_syringe_LABEL.setAlignment(QtCore.Qt.AlignCenter) + self.p1_syringe_LABEL.setObjectName("p1_syringe_LABEL") + self.gridLayout_3.addWidget(self.p1_syringe_LABEL, 2, 1, 1, 1) + self.label_10 = QtWidgets.QLabel(self.control) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setItalic(False) + font.setUnderline(False) + font.setWeight(75) + self.label_10.setFont(font) + self.label_10.setAlignment(QtCore.Qt.AlignCenter) + self.label_10.setObjectName("label_10") + self.gridLayout_3.addWidget(self.label_10, 1, 3, 1, 1) + self.verticalLayout_9.addLayout(self.gridLayout_3) + self.horizontalLayout_3.addLayout(self.verticalLayout_9) + self.line = QtWidgets.QFrame(self.control) + self.line.setFrameShadow(QtWidgets.QFrame.Raised) + self.line.setLineWidth(2) + self.line.setFrameShape(QtWidgets.QFrame.VLine) + self.line.setObjectName("line") + self.horizontalLayout_3.addWidget(self.line) + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.horizontalLayout_11 = QtWidgets.QHBoxLayout() + self.horizontalLayout_11.setObjectName("horizontalLayout_11") + self.run_BTN = QtWidgets.QPushButton(self.control) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.run_BTN.sizePolicy().hasHeightForWidth()) + self.run_BTN.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.run_BTN.setFont(font) + self.run_BTN.setObjectName("run_BTN") + self.horizontalLayout_11.addWidget(self.run_BTN) + self.pause_BTN = QtWidgets.QPushButton(self.control) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pause_BTN.sizePolicy().hasHeightForWidth()) + self.pause_BTN.setSizePolicy(sizePolicy) + self.pause_BTN.setObjectName("pause_BTN") + self.horizontalLayout_11.addWidget(self.pause_BTN) + self.zero_BTN = QtWidgets.QPushButton(self.control) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.zero_BTN.sizePolicy().hasHeightForWidth()) + self.zero_BTN.setSizePolicy(sizePolicy) + self.zero_BTN.setObjectName("zero_BTN") + self.horizontalLayout_11.addWidget(self.zero_BTN) + self.verticalLayout_2.addLayout(self.horizontalLayout_11) + self.stop_BTN = QtWidgets.QPushButton(self.control) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.stop_BTN.sizePolicy().hasHeightForWidth()) + self.stop_BTN.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.stop_BTN.setFont(font) + self.stop_BTN.setObjectName("stop_BTN") + self.verticalLayout_2.addWidget(self.stop_BTN) + self.line_2 = QtWidgets.QFrame(self.control) + self.line_2.setFrameShadow(QtWidgets.QFrame.Raised) + self.line_2.setLineWidth(2) + self.line_2.setFrameShape(QtWidgets.QFrame.HLine) + self.line_2.setObjectName("line_2") + self.verticalLayout_2.addWidget(self.line_2) + self.horizontalLayout_4 = QtWidgets.QHBoxLayout() + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.verticalLayout_12 = QtWidgets.QVBoxLayout() + self.verticalLayout_12.setObjectName("verticalLayout_12") + self.jog_plus_BTN = QtWidgets.QPushButton(self.control) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.jog_plus_BTN.sizePolicy().hasHeightForWidth()) + self.jog_plus_BTN.setSizePolicy(sizePolicy) + self.jog_plus_BTN.setObjectName("jog_plus_BTN") + self.verticalLayout_12.addWidget(self.jog_plus_BTN) + self.jog_minus_BTN = QtWidgets.QPushButton(self.control) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.jog_minus_BTN.sizePolicy().hasHeightForWidth()) + self.jog_minus_BTN.setSizePolicy(sizePolicy) + self.jog_minus_BTN.setObjectName("jog_minus_BTN") + self.verticalLayout_12.addWidget(self.jog_minus_BTN) + self.horizontalLayout_4.addLayout(self.verticalLayout_12) + self.line_15 = QtWidgets.QFrame(self.control) + self.line_15.setFrameShadow(QtWidgets.QFrame.Raised) + self.line_15.setLineWidth(2) + self.line_15.setFrameShape(QtWidgets.QFrame.VLine) + self.line_15.setObjectName("line_15") + self.horizontalLayout_4.addWidget(self.line_15) + self.verticalLayout_3 = QtWidgets.QVBoxLayout() + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.label_43 = QtWidgets.QLabel(self.control) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_43.sizePolicy().hasHeightForWidth()) + self.label_43.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_43.setFont(font) + self.label_43.setAlignment(QtCore.Qt.AlignCenter) + self.label_43.setObjectName("label_43") + self.verticalLayout_3.addWidget(self.label_43) + self.absolute_RADIO = QtWidgets.QRadioButton(self.control) + font = QtGui.QFont() + font.setPointSize(15) + self.absolute_RADIO.setFont(font) + self.absolute_RADIO.setChecked(True) + self.absolute_RADIO.setObjectName("absolute_RADIO") + self.verticalLayout_3.addWidget(self.absolute_RADIO) + self.incremental_RADIO = QtWidgets.QRadioButton(self.control) + font = QtGui.QFont() + font.setPointSize(15) + self.incremental_RADIO.setFont(font) + self.incremental_RADIO.setObjectName("incremental_RADIO") + self.verticalLayout_3.addWidget(self.incremental_RADIO) + self.horizontalLayout_4.addLayout(self.verticalLayout_3) + self.verticalLayout_2.addLayout(self.horizontalLayout_4) + self.horizontalLayout_3.addLayout(self.verticalLayout_2) + self.horizontalLayout_10.addLayout(self.horizontalLayout_3) + self.tabWidget.addTab(self.control, "") + self.camera = QtWidgets.QWidget() + self.camera.setObjectName("camera") + self.verticalLayout_11 = QtWidgets.QVBoxLayout(self.camera) + self.verticalLayout_11.setObjectName("verticalLayout_11") + self.imgLabel = QtWidgets.QLabel(self.camera) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.imgLabel.sizePolicy().hasHeightForWidth()) + self.imgLabel.setSizePolicy(sizePolicy) + self.imgLabel.setText("") + self.imgLabel.setAlignment(QtCore.Qt.AlignCenter) + self.imgLabel.setObjectName("imgLabel") + self.verticalLayout_11.addWidget(self.imgLabel) + self.verticalLayout_10 = QtWidgets.QVBoxLayout() + self.verticalLayout_10.setObjectName("verticalLayout_10") + self.horizontalLayout_5 = QtWidgets.QHBoxLayout() + self.horizontalLayout_5.setObjectName("horizontalLayout_5") + self.camera_connect_BTN = QtWidgets.QPushButton(self.camera) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.camera_connect_BTN.sizePolicy().hasHeightForWidth()) + self.camera_connect_BTN.setSizePolicy(sizePolicy) + self.camera_connect_BTN.setObjectName("camera_connect_BTN") + self.horizontalLayout_5.addWidget(self.camera_connect_BTN) + self.camera_disconnect_BTN = QtWidgets.QPushButton(self.camera) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.camera_disconnect_BTN.sizePolicy().hasHeightForWidth()) + self.camera_disconnect_BTN.setSizePolicy(sizePolicy) + self.camera_disconnect_BTN.setObjectName("camera_disconnect_BTN") + self.horizontalLayout_5.addWidget(self.camera_disconnect_BTN) + self.camera_capture_image_BTN = QtWidgets.QPushButton(self.camera) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.camera_capture_image_BTN.sizePolicy().hasHeightForWidth()) + self.camera_capture_image_BTN.setSizePolicy(sizePolicy) + self.camera_capture_image_BTN.setObjectName("camera_capture_image_BTN") + self.horizontalLayout_5.addWidget(self.camera_capture_image_BTN) + self.verticalLayout_10.addLayout(self.horizontalLayout_5) + self.verticalLayout_11.addLayout(self.verticalLayout_10) + self.tabWidget.addTab(self.camera, "") + self.setup = QtWidgets.QWidget() + self.setup.setObjectName("setup") + self.verticalLayout_14 = QtWidgets.QVBoxLayout(self.setup) + self.verticalLayout_14.setObjectName("verticalLayout_14") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.label_7 = QtWidgets.QLabel(self.setup) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_7.sizePolicy().hasHeightForWidth()) + self.label_7.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setPointSize(15) + self.label_7.setFont(font) + self.label_7.setObjectName("label_7") + self.horizontalLayout_2.addWidget(self.label_7) + self.port_DROPDOWN = QtWidgets.QComboBox(self.setup) + self.port_DROPDOWN.setObjectName("port_DROPDOWN") + self.horizontalLayout_2.addWidget(self.port_DROPDOWN) + self.refresh_ports_BTN = QtWidgets.QPushButton(self.setup) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.refresh_ports_BTN.sizePolicy().hasHeightForWidth()) + self.refresh_ports_BTN.setSizePolicy(sizePolicy) + self.refresh_ports_BTN.setObjectName("refresh_ports_BTN") + self.horizontalLayout_2.addWidget(self.refresh_ports_BTN) + self.verticalLayout_14.addLayout(self.horizontalLayout_2) + self.horizontalLayout_17 = QtWidgets.QHBoxLayout() + self.horizontalLayout_17.setObjectName("horizontalLayout_17") + self.label_5 = QtWidgets.QLabel(self.setup) + font = QtGui.QFont() + font.setPointSize(15) + self.label_5.setFont(font) + self.label_5.setObjectName("label_5") + self.horizontalLayout_17.addWidget(self.label_5) + self.microstepping_DROPDOWN = QtWidgets.QComboBox(self.setup) + self.microstepping_DROPDOWN.setObjectName("microstepping_DROPDOWN") + self.horizontalLayout_17.addWidget(self.microstepping_DROPDOWN) + self.verticalLayout_14.addLayout(self.horizontalLayout_17) + self.line_6 = QtWidgets.QFrame(self.setup) + self.line_6.setFrameShadow(QtWidgets.QFrame.Raised) + self.line_6.setFrameShape(QtWidgets.QFrame.HLine) + self.line_6.setObjectName("line_6") + self.verticalLayout_14.addWidget(self.line_6) + self.verticalLayout_13 = QtWidgets.QVBoxLayout() + self.verticalLayout_13.setObjectName("verticalLayout_13") + self.gridLayout = QtWidgets.QGridLayout() + self.gridLayout.setObjectName("gridLayout") + self.p3_units_DROPDOWN = QtWidgets.QComboBox(self.setup) + self.p3_units_DROPDOWN.setObjectName("p3_units_DROPDOWN") + self.gridLayout.addWidget(self.p3_units_DROPDOWN, 3, 2, 1, 1) + self.p2_units_DROPDOWN = QtWidgets.QComboBox(self.setup) + self.p2_units_DROPDOWN.setObjectName("p2_units_DROPDOWN") + self.gridLayout.addWidget(self.p2_units_DROPDOWN, 2, 2, 1, 1) + self.p2_accel_INPUT = QtWidgets.QDoubleSpinBox(self.setup) + self.p2_accel_INPUT.setMaximum(99999.99) + self.p2_accel_INPUT.setObjectName("p2_accel_INPUT") + self.gridLayout.addWidget(self.p2_accel_INPUT, 2, 4, 1, 1) + self.label_19 = QtWidgets.QLabel(self.setup) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_19.setFont(font) + self.label_19.setObjectName("label_19") + self.gridLayout.addWidget(self.label_19, 0, 4, 1, 1) + self.p1_speed_INPUT = QtWidgets.QDoubleSpinBox(self.setup) + self.p1_speed_INPUT.setDecimals(4) + self.p1_speed_INPUT.setMaximum(9999.999) + self.p1_speed_INPUT.setObjectName("p1_speed_INPUT") + self.gridLayout.addWidget(self.p1_speed_INPUT, 1, 3, 1, 1) + self.p2_syringe_DROPDOWN = QtWidgets.QComboBox(self.setup) + self.p2_syringe_DROPDOWN.setObjectName("p2_syringe_DROPDOWN") + self.gridLayout.addWidget(self.p2_syringe_DROPDOWN, 2, 1, 1, 1) + self.p2_speed_INPUT = QtWidgets.QDoubleSpinBox(self.setup) + self.p2_speed_INPUT.setDecimals(4) + self.p2_speed_INPUT.setMaximum(9999.999) + self.p2_speed_INPUT.setObjectName("p2_speed_INPUT") + self.gridLayout.addWidget(self.p2_speed_INPUT, 2, 3, 1, 1) + self.p1_accel_INPUT = QtWidgets.QDoubleSpinBox(self.setup) + self.p1_accel_INPUT.setMaximum(99999.99) + self.p1_accel_INPUT.setObjectName("p1_accel_INPUT") + self.gridLayout.addWidget(self.p1_accel_INPUT, 1, 4, 1, 1) + self.p3_syringe_DROPDOWN = QtWidgets.QComboBox(self.setup) + self.p3_syringe_DROPDOWN.setObjectName("p3_syringe_DROPDOWN") + self.gridLayout.addWidget(self.p3_syringe_DROPDOWN, 3, 1, 1, 1) + self.p3_speed_INPUT = QtWidgets.QDoubleSpinBox(self.setup) + self.p3_speed_INPUT.setDecimals(4) + self.p3_speed_INPUT.setMaximum(9999.999) + self.p3_speed_INPUT.setObjectName("p3_speed_INPUT") + self.gridLayout.addWidget(self.p3_speed_INPUT, 3, 3, 1, 1) + self.p1_units_DROPDOWN = QtWidgets.QComboBox(self.setup) + self.p1_units_DROPDOWN.setObjectName("p1_units_DROPDOWN") + self.gridLayout.addWidget(self.p1_units_DROPDOWN, 1, 2, 1, 1) + self.p1_syringe_DROPDOWN = QtWidgets.QComboBox(self.setup) + self.p1_syringe_DROPDOWN.setObjectName("p1_syringe_DROPDOWN") + self.gridLayout.addWidget(self.p1_syringe_DROPDOWN, 1, 1, 1, 1) + self.label_16 = QtWidgets.QLabel(self.setup) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_16.setFont(font) + self.label_16.setObjectName("label_16") + self.gridLayout.addWidget(self.label_16, 0, 1, 1, 1) + self.label_20 = QtWidgets.QLabel(self.setup) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_20.setFont(font) + self.label_20.setObjectName("label_20") + self.gridLayout.addWidget(self.label_20, 0, 5, 1, 1) + self.label_2 = QtWidgets.QLabel(self.setup) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_2.setFont(font) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) + self.label_3 = QtWidgets.QLabel(self.setup) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_3.setFont(font) + self.label_3.setObjectName("label_3") + self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1) + self.label_18 = QtWidgets.QLabel(self.setup) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_18.setFont(font) + self.label_18.setObjectName("label_18") + self.gridLayout.addWidget(self.label_18, 0, 3, 1, 1) + self.label_17 = QtWidgets.QLabel(self.setup) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_17.setFont(font) + self.label_17.setObjectName("label_17") + self.gridLayout.addWidget(self.label_17, 0, 2, 1, 1) + self.p3_accel_INPUT = QtWidgets.QDoubleSpinBox(self.setup) + self.p3_accel_INPUT.setMaximum(99999.99) + self.p3_accel_INPUT.setObjectName("p3_accel_INPUT") + self.gridLayout.addWidget(self.p3_accel_INPUT, 3, 4, 1, 1) + self.label_4 = QtWidgets.QLabel(self.setup) + font = QtGui.QFont() + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.label_4.setFont(font) + self.label_4.setObjectName("label_4") + self.gridLayout.addWidget(self.label_4, 3, 0, 1, 1) + self.p1_setup_send_BTN = QtWidgets.QPushButton(self.setup) + self.p1_setup_send_BTN.setObjectName("p1_setup_send_BTN") + self.gridLayout.addWidget(self.p1_setup_send_BTN, 1, 6, 1, 1) + self.p2_setup_send_BTN = QtWidgets.QPushButton(self.setup) + self.p2_setup_send_BTN.setObjectName("p2_setup_send_BTN") + self.gridLayout.addWidget(self.p2_setup_send_BTN, 2, 6, 1, 1) + self.p3_setup_send_BTN = QtWidgets.QPushButton(self.setup) + self.p3_setup_send_BTN.setObjectName("p3_setup_send_BTN") + self.gridLayout.addWidget(self.p3_setup_send_BTN, 3, 6, 1, 1) + self.p1_setup_jog_delta_INPUT = QtWidgets.QComboBox(self.setup) + self.p1_setup_jog_delta_INPUT.setObjectName("p1_setup_jog_delta_INPUT") + self.gridLayout.addWidget(self.p1_setup_jog_delta_INPUT, 1, 5, 1, 1) + self.p2_setup_jog_delta_INPUT = QtWidgets.QComboBox(self.setup) + self.p2_setup_jog_delta_INPUT.setObjectName("p2_setup_jog_delta_INPUT") + self.gridLayout.addWidget(self.p2_setup_jog_delta_INPUT, 2, 5, 1, 1) + self.p3_setup_jog_delta_INPUT = QtWidgets.QComboBox(self.setup) + self.p3_setup_jog_delta_INPUT.setObjectName("p3_setup_jog_delta_INPUT") + self.gridLayout.addWidget(self.p3_setup_jog_delta_INPUT, 3, 5, 1, 1) + self.verticalLayout_13.addLayout(self.gridLayout) + self.horizontalLayout_7 = QtWidgets.QHBoxLayout() + self.horizontalLayout_7.setObjectName("horizontalLayout_7") + self.connect_BTN = QtWidgets.QPushButton(self.setup) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.connect_BTN.sizePolicy().hasHeightForWidth()) + self.connect_BTN.setSizePolicy(sizePolicy) + self.connect_BTN.setObjectName("connect_BTN") + self.horizontalLayout_7.addWidget(self.connect_BTN) + self.disconnect_BTN = QtWidgets.QPushButton(self.setup) + self.disconnect_BTN.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.disconnect_BTN.sizePolicy().hasHeightForWidth()) + self.disconnect_BTN.setSizePolicy(sizePolicy) + self.disconnect_BTN.setObjectName("disconnect_BTN") + self.horizontalLayout_7.addWidget(self.disconnect_BTN) + self.send_all_BTN = QtWidgets.QPushButton(self.setup) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.send_all_BTN.sizePolicy().hasHeightForWidth()) + self.send_all_BTN.setSizePolicy(sizePolicy) + self.send_all_BTN.setAcceptDrops(True) + self.send_all_BTN.setObjectName("send_all_BTN") + self.horizontalLayout_7.addWidget(self.send_all_BTN) + self.verticalLayout_13.addLayout(self.horizontalLayout_7) + self.verticalLayout_14.addLayout(self.verticalLayout_13) + self.experiment_notes = QtWidgets.QLineEdit(self.setup) + self.experiment_notes.setObjectName("experiment_notes") + self.verticalLayout_14.addWidget(self.experiment_notes) + self.tabWidget.addTab(self.setup, "") + self.rheo = QtWidgets.QWidget() + self.rheo.setObjectName("rheo") + self.gridLayout_4 = QtWidgets.QGridLayout(self.rheo) + self.gridLayout_4.setObjectName("gridLayout_4") + self.gridLayout_2 = QtWidgets.QGridLayout() + self.gridLayout_2.setObjectName("gridLayout_2") + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout_2.addItem(spacerItem, 1, 1, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout_2.addItem(spacerItem1, 0, 0, 1, 1) + self.jfscanvas = QtWidgets.QWidget(self.rheo) + self.jfscanvas.setObjectName("jfscanvas") + self.gridLayout_2.addWidget(self.jfscanvas, 0, 1, 1, 1) + self.gridLayout_4.addLayout(self.gridLayout_2, 1, 0, 1, 1) + self.horizontalLayout_18 = QtWidgets.QHBoxLayout() + self.horizontalLayout_18.setObjectName("horizontalLayout_18") + self.label_9 = QtWidgets.QLabel(self.rheo) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_9.sizePolicy().hasHeightForWidth()) + self.label_9.setSizePolicy(sizePolicy) + self.label_9.setObjectName("label_9") + self.horizontalLayout_18.addWidget(self.label_9) + self.rheo_port_comboBox = QtWidgets.QComboBox(self.rheo) + self.rheo_port_comboBox.setObjectName("rheo_port_comboBox") + self.horizontalLayout_18.addWidget(self.rheo_port_comboBox) + self.openRheo_btn = QtWidgets.QPushButton(self.rheo) + self.openRheo_btn.setObjectName("openRheo_btn") + self.horizontalLayout_18.addWidget(self.openRheo_btn) + self.closeRheo_btn = QtWidgets.QPushButton(self.rheo) + self.closeRheo_btn.setObjectName("closeRheo_btn") + self.horizontalLayout_18.addWidget(self.closeRheo_btn) + self.label_11 = QtWidgets.QLabel(self.rheo) + self.label_11.setObjectName("label_11") + self.horizontalLayout_18.addWidget(self.label_11) + self.comboBox_tb = QtWidgets.QComboBox(self.rheo) + self.comboBox_tb.setObjectName("comboBox_tb") + self.comboBox_tb.addItem("") + self.comboBox_tb.addItem("") + self.comboBox_tb.addItem("") + self.comboBox_tb.addItem("") + self.comboBox_tb.addItem("") + self.comboBox_tb.addItem("") + self.comboBox_tb.addItem("") + self.horizontalLayout_18.addWidget(self.comboBox_tb) + self.start_btn = QtWidgets.QPushButton(self.rheo) + self.start_btn.setObjectName("start_btn") + self.horizontalLayout_18.addWidget(self.start_btn) + self.stop_btn = QtWidgets.QPushButton(self.rheo) + self.stop_btn.setObjectName("stop_btn") + self.horizontalLayout_18.addWidget(self.stop_btn) + self.clearDisplay = QtWidgets.QPushButton(self.rheo) + self.clearDisplay.setObjectName("clearDisplay") + self.horizontalLayout_18.addWidget(self.clearDisplay) + self.checkBox = QtWidgets.QCheckBox(self.rheo) + self.checkBox.setObjectName("checkBox") + self.horizontalLayout_18.addWidget(self.checkBox) + self.label_12 = QtWidgets.QLabel(self.rheo) + self.label_12.setObjectName("label_12") + self.horizontalLayout_18.addWidget(self.label_12) + self.lineEdit = QtWidgets.QLineEdit(self.rheo) + self.lineEdit.setMaxLength(12) + self.lineEdit.setObjectName("lineEdit") + self.horizontalLayout_18.addWidget(self.lineEdit) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_18.addItem(spacerItem2) + self.gridLayout_4.addLayout(self.horizontalLayout_18, 0, 0, 1, 1) + self.horizontalLayout_19 = QtWidgets.QHBoxLayout() + self.horizontalLayout_19.setObjectName("horizontalLayout_19") + self.label_21 = QtWidgets.QLabel(self.rheo) + self.label_21.setObjectName("label_21") + self.horizontalLayout_19.addWidget(self.label_21) + self.lineEdit_2 = QtWidgets.QLineEdit(self.rheo) + self.lineEdit_2.setMaximumSize(QtCore.QSize(50, 16777215)) + self.lineEdit_2.setObjectName("lineEdit_2") + self.horizontalLayout_19.addWidget(self.lineEdit_2) + self.checkBox_2 = QtWidgets.QCheckBox(self.rheo) + self.checkBox_2.setObjectName("checkBox_2") + self.horizontalLayout_19.addWidget(self.checkBox_2) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_19.addItem(spacerItem3) + self.label_22 = QtWidgets.QLabel(self.rheo) + self.label_22.setObjectName("label_22") + self.horizontalLayout_19.addWidget(self.label_22) + self.comboBox = QtWidgets.QComboBox(self.rheo) + self.comboBox.setObjectName("comboBox") + self.horizontalLayout_19.addWidget(self.comboBox) + self.pushButton = QtWidgets.QPushButton(self.rheo) + self.pushButton.setObjectName("pushButton") + self.horizontalLayout_19.addWidget(self.pushButton) + self.pushButton_2 = QtWidgets.QPushButton(self.rheo) + self.pushButton_2.setObjectName("pushButton_2") + self.horizontalLayout_19.addWidget(self.pushButton_2) + self.checkBox_3 = QtWidgets.QCheckBox(self.rheo) + self.checkBox_3.setObjectName("checkBox_3") + self.horizontalLayout_19.addWidget(self.checkBox_3) + self.pushButton_3 = QtWidgets.QPushButton(self.rheo) + self.pushButton_3.setObjectName("pushButton_3") + self.horizontalLayout_19.addWidget(self.pushButton_3) + self.pushButton_4 = QtWidgets.QPushButton(self.rheo) + self.pushButton_4.setObjectName("pushButton_4") + self.horizontalLayout_19.addWidget(self.pushButton_4) + self.lineEdit_3 = QtWidgets.QLineEdit(self.rheo) + self.lineEdit_3.setMaxLength(60) + self.lineEdit_3.setObjectName("lineEdit_3") + self.horizontalLayout_19.addWidget(self.lineEdit_3) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_19.addItem(spacerItem4) + self.gridLayout_4.addLayout(self.horizontalLayout_19, 2, 0, 1, 1) + self.tabWidget.addTab(self.rheo, "") + self.verticalLayout.addWidget(self.tabWidget) + MainWindow.setCentralWidget(self.centralwidget) + self.status_bar_DISP = QtWidgets.QStatusBar(MainWindow) + self.status_bar_DISP.setObjectName("status_bar_DISP") + MainWindow.setStatusBar(self.status_bar_DISP) + self.menuBar = QtWidgets.QMenuBar(MainWindow) + self.menuBar.setGeometry(QtCore.QRect(0, 0, 1071, 26)) + self.menuBar.setNativeMenuBar(False) + self.menuBar.setObjectName("menuBar") + self.menuFile = QtWidgets.QMenu(self.menuBar) + self.menuFile.setObjectName("menuFile") + MainWindow.setMenuBar(self.menuBar) + self.load_settings_INPUT = QtWidgets.QAction(MainWindow) + self.load_settings_INPUT.setObjectName("load_settings_INPUT") + self.save_settings_INPUT = QtWidgets.QAction(MainWindow) + self.save_settings_INPUT.setObjectName("save_settings_INPUT") + self.load_settings_BTN = QtWidgets.QAction(MainWindow) + self.load_settings_BTN.setObjectName("load_settings_BTN") + self.save_settings_BTN = QtWidgets.QAction(MainWindow) + self.save_settings_BTN.setObjectName("save_settings_BTN") + self.menuFile.addAction(self.load_settings_BTN) + self.menuFile.addAction(self.save_settings_BTN) + self.menuBar.addAction(self.menuFile.menuAction()) + + self.retranslateUi(MainWindow) + self.tabWidget.setCurrentIndex(3) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "Poseidon Controller")) + self.label_6.setText(_translate("MainWindow", "Pump 2")) + self.label_56.setText(_translate("MainWindow", "Incremental")) + self.label_8.setText(_translate("MainWindow", "Pump 1")) + self.label_57.setText(_translate("MainWindow", "Remain")) + self.label_58.setText(_translate("MainWindow", "Absolute")) + self.label_25.setText(_translate("MainWindow", "Pump 3")) + self.p2_units_LABEL_2.setText(_translate("MainWindow", "[units]")) + self.p3_units_LABEL_2.setText(_translate("MainWindow", "[units]")) + self.p1_units_LABEL_2.setText(_translate("MainWindow", "[units]")) + self.label_14.setText(_translate("MainWindow", "Pump 2")) + self.label_15.setText(_translate("MainWindow", "Pump 3")) + self.label_24.setText(_translate("MainWindow", "Speed")) + self.p1_units_LABEL.setText(_translate("MainWindow", "[units]")) + self.p3_syringe_LABEL.setText(_translate("MainWindow", "syringe")) + self.p2_units_LABEL.setText(_translate("MainWindow", "[units]")) + self.label_13.setText(_translate("MainWindow", "Pump 1")) + self.label_27.setText(_translate("MainWindow", "Syringe")) + self.p3_units_LABEL.setText(_translate("MainWindow", "[units]")) + self.p2_syringe_LABEL.setText(_translate("MainWindow", "syringe")) + self.p1_syringe_LABEL.setText(_translate("MainWindow", "syringe")) + self.label_10.setText(_translate("MainWindow", "Amount ")) + self.run_BTN.setText(_translate("MainWindow", "Run")) + self.pause_BTN.setText(_translate("MainWindow", "Pause")) + self.zero_BTN.setText(_translate("MainWindow", "Zero")) + self.stop_BTN.setText(_translate("MainWindow", "STOP")) + self.jog_plus_BTN.setText(_translate("MainWindow", "Jog +")) + self.jog_minus_BTN.setText(_translate("MainWindow", "Jog -")) + self.label_43.setText(_translate("MainWindow", "Coord.")) + self.absolute_RADIO.setText(_translate("MainWindow", "Abs.")) + self.incremental_RADIO.setText(_translate("MainWindow", "Incr.")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.control), _translate("MainWindow", "Syringe Control")) + self.camera_connect_BTN.setText(_translate("MainWindow", "Connect")) + self.camera_disconnect_BTN.setText(_translate("MainWindow", "Disconnect")) + self.camera_capture_image_BTN.setText(_translate("MainWindow", "Capture Image")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.camera), _translate("MainWindow", "Camera")) + self.label_7.setText(_translate("MainWindow", "Select port:")) + self.refresh_ports_BTN.setText(_translate("MainWindow", "Refresh ports")) + self.label_5.setText(_translate("MainWindow", "Set Microstepping:")) + self.label_19.setText(_translate("MainWindow", "Accel")) + self.label_16.setText(_translate("MainWindow", "Syringe")) + self.label_20.setText(_translate("MainWindow", "Jog Delta")) + self.label_2.setText(_translate("MainWindow", "Pump 1")) + self.label_3.setText(_translate("MainWindow", "Pump 2")) + self.label_18.setText(_translate("MainWindow", "Speed")) + self.label_17.setText(_translate("MainWindow", "Units")) + self.label_4.setText(_translate("MainWindow", "Pump 3")) + self.p1_setup_send_BTN.setText(_translate("MainWindow", "Send")) + self.p2_setup_send_BTN.setText(_translate("MainWindow", "Send")) + self.p3_setup_send_BTN.setText(_translate("MainWindow", "Send")) + self.connect_BTN.setText(_translate("MainWindow", "Connect to Controller")) + self.disconnect_BTN.setText(_translate("MainWindow", "Disconnect from Controller")) + self.send_all_BTN.setText(_translate("MainWindow", "Send all settings")) + self.experiment_notes.setPlaceholderText(_translate("MainWindow", "Write notes about your experiment here. These will be appended to the end of your settings file.")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.setup), _translate("MainWindow", "Setup")) + self.label_9.setText(_translate("MainWindow", "Port")) + self.openRheo_btn.setText(_translate("MainWindow", "open port")) + self.closeRheo_btn.setText(_translate("MainWindow", "close port")) + self.label_11.setText(_translate("MainWindow", "Timebase [ms]")) + self.comboBox_tb.setCurrentText(_translate("MainWindow", "50")) + self.comboBox_tb.setItemText(0, _translate("MainWindow", "1")) + self.comboBox_tb.setItemText(1, _translate("MainWindow", "5")) + self.comboBox_tb.setItemText(2, _translate("MainWindow", "10")) + self.comboBox_tb.setItemText(3, _translate("MainWindow", "50")) + self.comboBox_tb.setItemText(4, _translate("MainWindow", "100")) + self.comboBox_tb.setItemText(5, _translate("MainWindow", "500")) + self.comboBox_tb.setItemText(6, _translate("MainWindow", "1000")) + self.start_btn.setText(_translate("MainWindow", "start")) + self.stop_btn.setText(_translate("MainWindow", "stop")) + self.clearDisplay.setText(_translate("MainWindow", "clear display")) + self.checkBox.setText(_translate("MainWindow", "Test Run")) + self.label_12.setText(_translate("MainWindow", "set Freqency")) + self.label_21.setText(_translate("MainWindow", "limit for stop flow")) + self.checkBox_2.setText(_translate("MainWindow", "check the limit")) + self.label_22.setText(_translate("MainWindow", "Rheo Port")) + self.pushButton.setText(_translate("MainWindow", "open port")) + self.pushButton_2.setText(_translate("MainWindow", "close port")) + self.checkBox_3.setText(_translate("MainWindow", "load")) + self.pushButton_3.setText(_translate("MainWindow", "Home")) + self.pushButton_4.setText(_translate("MainWindow", "inject..")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.rheo), _translate("MainWindow", "Counter")) + self.menuFile.setTitle(_translate("MainWindow", "File")) + self.load_settings_INPUT.setText(_translate("MainWindow", "Load settings")) + self.save_settings_INPUT.setText(_translate("MainWindow", "Save settings")) + self.load_settings_BTN.setText(_translate("MainWindow", "Load settings")) + self.save_settings_BTN.setText(_translate("MainWindow", "Save settings")) + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + MainWindow = QtWidgets.QMainWindow() + ui = Ui_MainWindow() + ui.setupUi(MainWindow) + MainWindow.show() + sys.exit(app.exec_()) diff --git a/poseidon_controller_gui2.ui b/poseidon_controller_gui2.ui new file mode 100644 index 0000000..8e0bad3 --- /dev/null +++ b/poseidon_controller_gui2.ui @@ -0,0 +1,1609 @@ + + + MainWindow + + + + 0 + 0 + 1071 + 869 + + + + Poseidon Controller + + + + + + + Qt::TabFocus + + + false + + + QTabWidget::North + + + QTabWidget::Triangular + + + 3 + + + + 16 + 16 + + + + false + + + + Syringe Control + + + + + + + + + + + + QFrame::Raised + + + 3 + + + Qt::Vertical + + + + + + + + 15 + 75 + true + + + + + + + Qt::AlignCenter + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + 5 + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + 5 + + + + + + + + + + 0 + 0 + + + + + + + + + + + + 15 + 75 + true + + + + Pump 2 + + + Qt::AlignCenter + + + + + + + + + + 15 + + + + Incremental + + + Qt::AlignCenter + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + 5 + + + + + + + + + + 0 + 0 + + + + + + + + + + + + 15 + 75 + true + + + + Pump 1 + + + Qt::AlignCenter + + + + + + + + + + 15 + + + + Remain + + + Qt::AlignCenter + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + 5 + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + 5 + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + 5 + + + + + + + + 15 + + + + Absolute + + + Qt::AlignCenter + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + 5 + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + 5 + + + + + + + + + QFrame::Raised + + + 3 + + + Qt::Vertical + + + + + + + + 0 + 0 + + + + + + + + + + + + 15 + 75 + true + + + + Pump 3 + + + Qt::AlignCenter + + + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + 4 + + + + + + + + + QFrame::Raised + + + 2 + + + Qt::Horizontal + + + + + + + + + + + + + 3 + + + -99.000000000000000 + + + + + + + + + [units] + + + Qt::AlignCenter + + + + + + + + + + + + + 3 + + + -99.000000000000000 + + + + + + + + + [units] + + + Qt::AlignCenter + + + + + + + + + + + + + 3 + + + -99.000000000000000 + + + + + + + + + [units] + + + Qt::AlignCenter + + + + + + + + + + 15 + 75 + false + true + false + + + + + + + Qt::AlignCenter + + + + + + + + 15 + 75 + true + + + + Pump 2 + + + Qt::AlignCenter + + + + + + + + 15 + 75 + true + + + + Pump 3 + + + Qt::AlignCenter + + + + + + + + 15 + 75 + false + true + false + + + + Speed + + + Qt::AlignCenter + + + + + + + [units] + + + Qt::AlignCenter + + + + + + + syringe + + + Qt::AlignCenter + + + + + + + [units] + + + Qt::AlignCenter + + + + + + + + 15 + 75 + true + + + + Pump 1 + + + Qt::AlignCenter + + + + + + + + 15 + 75 + false + true + false + + + + Syringe + + + Qt::AlignCenter + + + + + + + [units] + + + Qt::AlignCenter + + + + + + + syringe + + + Qt::AlignCenter + + + + + + + syringe + + + Qt::AlignCenter + + + + + + + + 15 + 75 + false + true + false + + + + Amount + + + Qt::AlignCenter + + + + + + + + + + + QFrame::Raised + + + 2 + + + Qt::Vertical + + + + + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Run + + + + + + + + 0 + 0 + + + + Pause + + + + + + + + 0 + 0 + + + + Zero + + + + + + + + + + 0 + 0 + + + + + 75 + true + + + + STOP + + + + + + + QFrame::Raised + + + 2 + + + Qt::Horizontal + + + + + + + + + + + + 0 + 0 + + + + Jog + + + + + + + + + 0 + 0 + + + + Jog - + + + + + + + + + QFrame::Raised + + + 2 + + + Qt::Vertical + + + + + + + + + + 0 + 0 + + + + + 15 + 75 + true + + + + Coord. + + + Qt::AlignCenter + + + + + + + + 15 + + + + Abs. + + + true + + + + + + + + 15 + + + + Incr. + + + + + + + + + + + + + + + + Camera + + + + + + + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + + + + + + + 0 + 0 + + + + Connect + + + + + + + + 0 + 0 + + + + Disconnect + + + + + + + + 0 + 0 + + + + Capture Image + + + + + + + + + + + + Setup + + + + + + + + + 0 + 0 + + + + + 15 + + + + Select port: + + + + + + + + + + + 0 + 0 + + + + Refresh ports + + + + + + + + + + + + 15 + + + + Set Microstepping: + + + + + + + + + + + + QFrame::Raised + + + Qt::Horizontal + + + + + + + + + + + + + + + + + 99999.990000000005239 + + + + + + + + 15 + 75 + true + + + + Accel + + + + + + + 4 + + + 9999.998999999999796 + + + + + + + + + + 4 + + + 9999.998999999999796 + + + + + + + 99999.990000000005239 + + + + + + + + + + 4 + + + 9999.998999999999796 + + + + + + + + + + + + + + 15 + 75 + true + + + + Syringe + + + + + + + + 15 + 75 + true + + + + Jog Delta + + + + + + + + 15 + 75 + true + + + + Pump 1 + + + + + + + + 15 + 75 + true + + + + Pump 2 + + + + + + + + 15 + 75 + true + + + + Speed + + + + + + + + 15 + 75 + true + + + + Units + + + + + + + 99999.990000000005239 + + + + + + + + 15 + 75 + true + + + + Pump 3 + + + + + + + Send + + + + + + + Send + + + + + + + Send + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + Connect to Controller + + + + + + + false + + + + 0 + 0 + + + + Disconnect from Controller + + + + + + + + 0 + 0 + + + + true + + + Send all settings + + + + + + + + + + + Write notes about your experiment here. These will be appended to the end of your settings file. + + + + + + + + Counter + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + 0 + 0 + + + + Port + + + + + + + + + + open port + + + + + + + close port + + + + + + + Timebase [ms] + + + + + + + 50 + + + + 1 + + + + + 5 + + + + + 10 + + + + + 50 + + + + + 100 + + + + + 500 + + + + + 1000 + + + + + + + + start + + + + + + + stop + + + + + + + clear display + + + + + + + Test Run + + + + + + + set Freqency + + + + + + + 12 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + limit for stop flow + + + + + + + + 50 + 16777215 + + + + + + + + check the limit + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Rheo Port + + + + + + + + + + open port + + + + + + + close port + + + + + + + load + + + + + + + Home + + + + + + + inject.. + + + + + + + 60 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + 0 + 0 + 1071 + 26 + + + + false + + + + File + + + + + + + + + Load settings + + + + + Save settings + + + + + Load settings + + + + + Save settings + + + + + + diff --git a/poseidon_main.py b/poseidon_main.py new file mode 100644 index 0000000..b0de345 --- /dev/null +++ b/poseidon_main.py @@ -0,0 +1,1530 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import serial +import time +import glob +import sys +from datetime import datetime +import time +import os +# This gets the Qt stuff + +from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5.QtWidgets import QMainWindow, QApplication, QFileDialog + +import cv2 +#from PyQt5 import cv2 +# note, had to use version 3.2.0.8 otherwise it had its own +# pyqt packages that conflicted with mine + +import numpy as np +from decimal import Decimal +# This is our window from QtCreator +import poseidon_controller_gui2 +import pdb +import traceback, sys + +# ############################## +# MULTITHREADING : SIGNALS CLASS +# ############################## +class WorkerSignals(QtCore.QObject): + ''' + Defines the signals available from a running worker thread. + + Supported signals are: + + finished + No data + + error + `tuple` (exctype, value, traceback.format_exc() ) + + result + `object` data returned from processing, anything + + ''' + finished = QtCore.pyqtSignal() + error = QtCore.pyqtSignal(tuple) + result = QtCore.pyqtSignal(object) + progress = QtCore.pyqtSignal(int) + +# ############################# +# MULTITHREADING : WORKER CLASS +# ############################# + + +class Thread(QtCore.QThread): + def __init__(self, fn, *args, **kwargs): + parent = None + super(Thread, self).__init__(parent) + self.runs = True + self.fn = fn + self.args = args + self.kwargs = kwargs + self.signals = WorkerSignals() + + def run(self): + try: + #self.serial.flushInput() + #self.serial.flushOutput() + result = self.fn(*self.args, **self.kwargs) + except: + traceback.print_exc() + exctype, value = sys.exc_info()[:2] + self.signals.error.emit((exctype, value, traceback.format_exc())) + else: + self.signals.result.emit(result) # Return the result of the processing + finally: + self.signals.finished.emit() # Done + self.stop() + + print("Job completed") + + def stop(self): + self.runs = False + + + + +# ##################################### +# ERROR HANDLING : CANNOT CONNECT CLASS +# ##################################### +class CannotConnectException(Exception): + pass + +# ####################### +# GUI : MAIN WINDOW CLASS +# ####################### +class MainWindow(QtWidgets.QMainWindow, poseidon_controller_gui2.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_gui2.Ui_MainWindow() + self.ui.setupUi(self) + + #====================================== Jfs Display try + # aktueller Content in the syringe + self.p1_left = 0 + self.p2_left = 0 + self.p3_left = 0 + self.globports =[] + #====================================================== + + # Put comments here + self.populate_microstepping() + self.populate_syringe_sizes() + self.populate_pump_jog_delta() + self.populate_pump_units() + self.setting_variables() + if self.globports == []: + self.populate_ports() + self.set_port() + + + + 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 = 44 # , + + # Initializing multithreading to allow parallel operations + self.threadpool = QtCore.QThreadPool() + print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount()) + + + # Camera setup + self.timer = QtCore.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 + #self.microstepping = 1 + #print(self.microstepping) + + + 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.experiment_notes = "" + + def thread_finished(self, th): + print("Your thread has completed. Now terminating..") + th.stop() + print("Thread has been terminated.") + print("=============================\n\n") + # here is where you need to end the thread + + + # =================================== + # 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 (population done earlier) + self.ui.refresh_ports_BTN.clicked.connect(self.refresh_ports) + self.ui.port_DROPDOWN.currentIndexChanged.connect(self.set_port) + + self.ui.experiment_notes.editingFinished.connect(self.set_experiment_notes) + + # Set the microstepping value, default is 1 + self.ui.microstepping_DROPDOWN.currentIndexChanged.connect(self.set_microstepping) + + # 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 + + # Px syringe size, populate then connect (population done earlier) + 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) + # warning to send the info to the controller + self.ui.p1_syringe_DROPDOWN.currentIndexChanged.connect(self.send_p1_warning) + self.ui.p2_syringe_DROPDOWN.currentIndexChanged.connect(self.send_p2_warning) + self.ui.p3_syringe_DROPDOWN.currentIndexChanged.connect(self.send_p3_warning) + + # 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) + # warning to send the info to the controller + self.ui.p1_units_DROPDOWN.currentIndexChanged.connect(self.send_p1_warning) + self.ui.p2_units_DROPDOWN.currentIndexChanged.connect(self.send_p2_warning) + self.ui.p3_units_DROPDOWN.currentIndexChanged.connect(self.send_p3_warning) + + # 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) + # warning to send the info to the controller + self.ui.p1_speed_INPUT.valueChanged.connect(self.send_p1_warning) + self.ui.p2_speed_INPUT.valueChanged.connect(self.send_p2_warning) + self.ui.p3_speed_INPUT.valueChanged.connect(self.send_p3_warning) + + # 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) + # warning to send the info to the controller + self.ui.p1_accel_INPUT.valueChanged.connect(self.send_p1_warning) + self.ui.p2_accel_INPUT.valueChanged.connect(self.send_p2_warning) + self.ui.p3_accel_INPUT.valueChanged.connect(self.send_p3_warning) + + # 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) + # warning to send the info to the contorller + self.ui.p1_setup_jog_delta_INPUT.currentIndexChanged.connect(self.send_p1_warning) + self.ui.p2_setup_jog_delta_INPUT.currentIndexChanged.connect(self.send_p2_warning) + self.ui.p3_setup_jog_delta_INPUT.currentIndexChanged.connect(self.send_p3_warning) + + + # 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) + # remove warning to send settings + self.ui.p1_setup_send_BTN.clicked.connect(self.send_p1_success) + self.ui.p2_setup_send_BTN.clicked.connect(self.send_p2_success) + self.ui.p3_setup_send_BTN.clicked.connect(self.send_p3_success) + + # 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 send_p1_warning(self): + self.ui.p1_setup_send_BTN.setStyleSheet("background-color: green; color: black") + + def send_p2_warning(self): + self.ui.p2_setup_send_BTN.setStyleSheet("background-color: green; color: black") + + def send_p3_warning(self): + self.ui.p3_setup_send_BTN.setStyleSheet("background-color: green; color: black") + + def send_p1_success(self): + self.ui.p1_setup_send_BTN.setStyleSheet("background-color: none") + + def send_p2_success(self): + self.ui.p2_setup_send_BTN.setStyleSheet("background-color: none") + + def send_p3_success(self): + self.ui.p3_setup_send_BTN.setStyleSheet("background-color: none") + + 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) + + self.ui.run_BTN.setStyleSheet("background-color: green; color: black") + self.ui.pause_BTN.setStyleSheet("background-color: yellow; color: black") + self.ui.stop_BTN.setStyleSheet("background-color: red; color: black") + + # ~~~~~~~~~~~~~~~~ + # 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, self.microstepping)) + p2_input_displacement = str(self.convert_displacement(self.p2_amount, self.p2_units, self.p2_syringe_area, self.microstepping)) + p3_input_displacement = str(self.convert_displacement(self.p3_amount, self.p3_units, self.p3_syringe_area, self.microstepping)) + + pumps_2_run = ''.join(map(str,active_pumps)) + + cmd = "" + + testData.append(cmd) + + print("Sending RUN command..") + thread = Thread(self.runTest, testData) + thread.finished.connect(lambda:self.thread_finished(thread)) + thread.start() + print("RUN command sent.") + else: + self.statusBar().showMessage("No pumps enabled.") + + # Clean up this text + def pause(self): + active_pumps = self.get_active_pumps() + pumps_2_run = ''.join(map(str,active_pumps)) + + if self.ui.pause_BTN.text() == "Pause": + self.statusBar().showMessage("You clicked PAUSE") + testData = [] + cmd = "" + testData.append(cmd) + + print("Sending PAUSE command..") + thread = Thread(self.runTest, testData) + thread.finished.connect(lambda:self.thread_finished(thread)) + thread.start() + print("PAUSE command sent.") + + self.ui.pause_BTN.setText("Resume") + + elif self.ui.pause_BTN.text() == "Resume": + self.statusBar().showMessage("You clicked RESUME") + testData = [] + cmd = "" + testData.append(cmd) + + print("Sending RESUME command..") + thread = Thread(self.runTest, testData) + thread.finished.connect(lambda:self.thread_finished(thread)) + thread.start() + print("RESUME command sent.") + + self.ui.pause_BTN.setText("Pause") + + # fix + def zero(self): + self.statusBar().showMessage("You clicked ZERO") + testData = [] + + cmd = "" + + print("Sending ZERO command..") + thread = Thread(self.runTest, testData) + thread.finished.connect(lambda:self.thread_finished(thread)) + thread.start() + ##jfs + self.p1_left=int(self.p1_syringe.split(sep=' ')[1]) + self.ui.p1_remain_DISP.display(self.p1_left) + self.p2_left=int(self.p2_syringe.split(sep=' ')[1]) + self.ui.p2_remain_DISP.display(self.p2_left) + self.p3_left=int(self.p3_syringe.split(sep=' ')[1]) + self.ui.p3_remain_DISP.display(self.p3_left) + + ##jfs + print("ZERO command sent.") + + + def stop(self): + self.statusBar().showMessage("You clicked STOP") + cmd = "" + + print("Sending STOP command..") + thread = Thread(self.send_single_command, cmd) + thread.finished.connect(lambda:self.thread_finished(thread)) + thread.start() + print("STOP command sent.") + + def jog(self, btn): + self.statusBar().showMessage("You clicked JOG") + #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 +": + self.statusBar().showMessage("You clicked JOG +") + f_cmd = "" + testData.append(f_cmd) + + print("Sending JOG command..") + + thread = Thread(self.runTest, testData) + thread.finished.connect(lambda:self.thread_finished(thread)) + thread.start() + print("JOG command sent.") + + elif btn.text() == "Jog -": + self.statusBar().showMessage("You clicked JOG -") + b_cmd = "" + testData.append(b_cmd) + + print("Sending JOG command..") + thread = Thread(self.runTest, testData) + thread.finished.connect(lambda:self.thread_finished(thread)) + thread.start() + print("JOG command sent.") + else: + self.statusBar().showMessage("No pumps enabled.") + + # ====================== + # FUNCTIONS : Camera + # ====================== + + # Initialize the camera + def start_camera(self): + self.statusBar().showMessage("You clicked START CAMERA") + 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 = QtCore.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): + if not os.path.exists("./images"): + os.mkdir("images") + + 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 + """ + print("Populating ports..") + 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) + self.globports = result + print("Ports have been populated.",self.globports) + + # Refresh the list of ports + def refresh_ports(self): + self.statusBar().showMessage("You clicked REFRESH PORTS") + self.ui.port_DROPDOWN.clear() + self.populate_ports() + self.set_port() + + # Set the port that is selected from the dropdown menu + def set_port(self): + self.port = self.ui.port_DROPDOWN.currentText() + + # Set the microstepping amount from the dropdown menu + # TODO: There is definitely a better way of updating different variables + # after there is a change of some input from the user. need to figure out. + def set_microstepping(self): + self.microstepping = int(self.ui.microstepping_DROPDOWN.currentText()) + self.set_p1_units() + self.set_p1_speed() + self.set_p1_accel() + self.set_p1_setup_jog_delta() + self.set_p1_amount() + + self.set_p2_units() + self.set_p2_speed() + self.set_p2_accel() + self.set_p2_setup_jog_delta() + self.set_p2_amount() + + self.set_p3_units() + self.set_p3_speed() + self.set_p3_accel() + self.set_p3_setup_jog_delta() + self.set_p3_amount() + + print(self.microstepping) + + def set_experiment_notes(self): + self.experiment_notes = self.ui.experiment_notes.text() + + # Set the name of the log file + # Can probably delete + def set_log_file_name(self): + """ + 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): + # TODO: if you cancel then it gives error, fix this + # TODO: add comment + 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) + + ## 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) + + ## Experiment Notes + experiment_notes = self.experiment_notes + + text = [] + text.append("File name: " + name + ".txt" + "\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 + text.append("Exp Note: " + experiment_notes) # line 20 + + if name: + with open(name + ".txt", 'w') as f: + f.writelines(text) + self.statusBar().showMessage("Settings saved in " + name + ".txt") + + def load_settings(self): + # need to make name an tuple otherwise i had an error and app crashed + name, _ = QFileDialog.getOpenFileName(self, 'Open File', options=QFileDialog.DontUseNativeDialog, filter = "Text (*.txt)") + + if name: + 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] + 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] + + experiment_notes = text[20] + + #print(fname, date_string, p1_syringe, p1_units, p1_speed, p1_accel, p1_setup_jog_delta) + + # Here we are setting all of the values as given by the settings file + 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)) + + AllItems = [self.ui.p1_setup_jog_delta_INPUT.itemText(i) for i in range(self.ui.p1_setup_jog_delta_INPUT.count())] + + p1_setup_jog_delta_index = self.ui.p1_setup_jog_delta_INPUT.findText(p1_setup_jog_delta, QtCore.Qt.MatchFixedString) + 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.ui.experiment_notes.setText(experiment_notes) + + self.statusBar().showMessage("Settings loaded from: " + text[1]) + else: + self.statusBar().showMessage("No file selected.") + + # Populate the microstepping amounts for the dropdown menu + def populate_microstepping(self): + self.microstepping_values = ['1', '2', '4', '8', '16', '32'] + self.ui.microstepping_DROPDOWN.addItems(self.microstepping_values) + self.microstepping = 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() + + self.set_p1_units() + self.set_p1_speed() + self.set_p1_accel() + self.set_p1_setup_jog_delta() + self.set_p1_amount() + + 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() + + self.set_p2_units() + self.set_p2_speed() + self.set_p2_accel() + self.set_p2_setup_jog_delta() + self.set_p2_amount() + + 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() + + self.set_p3_units() + self.set_p3_speed() + self.set_p3_accel() + self.set_p3_setup_jog_delta() + self.set_p3_amount() + + # Set Px units + def set_p1_units(self): + self.p1_units = self.ui.p1_units_DROPDOWN.currentText() + + length = self.p1_units.split("/")[0] + self.ui.p1_units_LABEL_2.setText(length) + + 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() + + length = self.p2_units.split("/")[0] + self.ui.p2_units_LABEL_2.setText(length) + + 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() + + length = self.p3_units.split("/")[0] + self.ui.p3_units_LABEL_2.setText(length) + + self.set_p3_speed() + self.set_p3_accel() + self.set_p3_setup_jog_delta() + self.set_p3_amount() + + + def populate_pump_units(self): + 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'] + 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 + 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, self.microstepping) + + 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, self.microstepping) + + 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, self.microstepping) + + # Set Px accel + 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, self.microstepping) + + 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, self.microstepping) + + 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, self.microstepping) + + # Set Px jog delta (setup) + 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, self.microstepping) + + 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, self.microstepping) + + 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, self.microstepping) + + # Send Px settings + def send_p1_settings(self): + self.statusBar().showMessage("You clicked SEND P1 SETTINGS") + self.p1_settings = [] + self.p1_settings.append("") + self.p1_settings.append("") + self.p1_settings.append("") + + print("Sending P1 SETTINGS..") + thread = Thread(self.runTest, self.p1_settings) + thread.finished.connect(lambda:self.thread_finished(thread)) + thread.start() + print("P1 SETTINGS sent.") + + def send_p2_settings(self): + self.statusBar().showMessage("You clicked SEND P2 SETTINGS") + self.p2_settings = [] + self.p2_settings.append("") + self.p2_settings.append("") + self.p2_settings.append("") + + print("Sending P2 SETTINGS..") + thread = Thread(self.runTest, self.p2_settings) + thread.finished.connect(lambda:self.thread_finished(thread)) + thread.start() + print("P2 SETTINGS sent.") + + def send_p3_settings(self): + self.statusBar().showMessage("You clicked SEND P3 SETTINGS") + self.p3_settings = [] + self.p3_settings.append("") + self.p3_settings.append("") + self.p3_settings.append("") + + print("Sending P3 SETTINGS..") + thread = Thread(self.runTest, self.p3_settings) + thread.finished.connect(lambda:self.thread_finished(thread)) + thread.start() + print("P3 SETTINGS sent.") + + # 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("You clicked CONNECT TO CONTROLLER") + try: + port_declared = self.port in vars() + try: + self.serial = serial.Serial() + self.serial.port = self.port + self.serial.baudrate = 230400 + 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.serial.flushInput() + + # This is a thread that always runs and listens to commands from the Arduino + #self.global_listener_thread = Thread(self.listening) + #self.global_listener_thread.finished.connect(lambda:self.self.thread_finished(self.global_listener_thread)) + #self.global_listener_thread.start() + + # ~~~~~~~~~~~~~~~~ + # 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) + time.sleep(1) + self.statusBar().showMessage("Successfully connected to board.") + 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 + # TODO: figure out how to handle error.. + def disconnect(self): + self.statusBar().showMessage("You clicked DISCONNECT FROM BOARD") + print("Disconnecting from board..") + #self.global_listener_thread.stop() + time.sleep(3) + self.serial.close() + print("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.statusBar().showMessage("You clicked SEND ALL SETTINGS") + + self.settings = [] + self.settings.append("") + self.settings.append("") + self.settings.append("") + + self.settings.append("") + self.settings.append("") + self.settings.append("") + + self.settings.append("") + self.settings.append("") + self.settings.append("") + + print("Sending all settings..") + thread = Thread(self.runTest, self.settings) + thread.finished.connect(lambda:self.thread_finished(thread)) + thread.start() + + self.ui.p1_setup_send_BTN.setStyleSheet("background-color: none") + self.ui.p2_setup_send_BTN.setStyleSheet("background-color: none") + self.ui.p3_setup_send_BTN.setStyleSheet("background-color: none") + + 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 + mm = steps/200/self.microstepping*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,self.microstepping) + return uL + + + def mm2steps(self, mm, microsteps): + steps = mm/0.8*200*microsteps + #steps = mm*200/0.8 + return steps + + def mL2steps(self, mL, syringe_area, microsteps): + # note syringe_area is in mm^2 + steps = self.mm2steps(self.mL2mm3(mL)/syringe_area, microsteps) + return steps + + def uL2steps(self, uL, syringe_area, microsteps): + steps = self.mm2steps(self.uL2mm3(uL)/syringe_area, microsteps) + 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 + return value_per_sec + + def convert_displacement(self, displacement, units, syringe_area, microsteps): + length = units.split("/")[0] + time = units.split("/")[1] + inp_displacement = displacement + # convert length first + if length == "mm": + displacement = self.mm2steps(displacement, microsteps) + elif length == "mL": + displacement = self.mL2steps(displacement, syringe_area, microsteps) + elif length == "µL": + displacement = self.uL2steps(displacement, syringe_area, microsteps) + + print('______________________________') + print("INPUT DISPLACEMENT: " + str(inp_displacement) + ' ' + length) + print("OUTPUT DISPLACEMENT: " + str(displacement) + ' steps') + print('\n############################################################\n') + return displacement + + def convert_speed(self, inp_speed, units, syringe_area, microsteps): + length = units.split("/")[0] + time = units.split("/")[1] + + + # convert length first + if length == "mm": + speed = self.mm2steps(inp_speed, microsteps) + elif length == "mL": + speed = self.mL2steps(inp_speed, syringe_area, microsteps) + elif length == "µL": + speed = self.uL2steps(inp_speed, syringe_area, microsteps) + + + # convert time next + if time == "s": + pass + elif time == "min": + speed = self.permin2persec(speed) + elif time == "hr": + speed = self.perhour2persec(speed) + + + + print("INPUT SPEED: " + str(inp_speed) + ' ' + units) + print("OUTPUT SPEED: " + str(speed) + ' steps/s') + return speed + + def convert_accel(self, accel, units, syringe_area, microsteps): + length = units.split("/")[0] + time = units.split("/")[1] + inp_accel = accel + accel = accel + + # convert length first + if length == "mm": + accel = self.mm2steps(accel, microsteps) + elif length == "mL": + accel = self.mL2steps(accel, syringe_area, microsteps) + elif length == "µL": + accel = self.uL2steps(accel, syringe_area, microsteps) + + # 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)) + + print('______________________________') + print("INPUT ACCEL: " + str(inp_accel) + ' ' + units + '/' + time) + print("OUTPUT ACCEL: " + str(accel) + ' steps/s/s') + 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. + ''' + + def convert2volume(self, steps, units, syringe_area): + length = units.split("/")[0] + inp_steps = float(steps) + # convert length first + if length == "ul": + displacement = self.steps2uL(inp_steps, syringe_area) + else: + displacement = self.steps2mL(inp_steps, syringe_area) + return displacement + + + #====================================== Reading and Writing to Arduino + + def sendToArduino(self, sendStr): + self.serial.write(sendStr.encode()) + self.serial.flushInput() + + + def recvPositionArduino(self): + startMarker = self.startMarker + midMarker = self.midMarker + endMarker = self.endMarker + + ck = "" + x = "z" # any value that is not an end- or startMarker + + # 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('midMarker jfs ',ck) + if ck.startswith('p1') and self.is_p1_active: + out = self.convert2volume(ck.split(sep=':')[1],self.p1_units, self.p1_syringe_area) + self.p1_left -= out + self.ui.p1_remain_DISP.display(self.p1_left) + if ck.startswith('p2') and self.is_p2_active: + out = self.convert2volume(ck.split(sep=':')[1],self.p2_units, self.p2_syringe_area) + self.p2_left -= out + self.ui.p2_remain_DISP.display(self.p2_left) + if ck.startswith('p3') and self.is_p3_active: + out = self.convert2volume(ck.split(sep=':')[1],self.p3_units, self.p3_syringe_area) + self.p3_left -= out + self.ui.p3_remain_DISP.display(self.p3_left) + + ck = "" + x = self.serial.read() + + if ord(x) != startMarker: + #print(x) + ck = ck + x.decode() + + x = self.serial.read() + + return(ck) + + #============================ + + + 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 -- " + teststr) + waitingForReply = True + + if waitingForReply == True: + + while self.serial.inWaiting() == 0: + pass + + dataRecvd = self.recvPositionArduino() + print("Reply Received -- " + dataRecvd) + n += 1 + waitingForReply = False + + + 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() + data_received = "from other func" + print("Reply Received -- " + data_received) + waiting_for_reply = False + print("=============================\n\n") + print("Sent a single command") + + + # def listening(self): + # startMarker = self.startMarker + # midMarker = self.midMarker + # endMarker = self.endMarker + # posMarker = ord('?') + # i = 0 + + # while (True): + # self.serial.flushInput() + # x = "z" + # ck = "" + # isDisplay = "asdf" + # while self.serial.inWaiting() == 0: + # pass + # while not x or ord(x) != startMarker: + # x = self.serial.read() + # #if ord(x) == posMarker: + # # return self.get_position() + # while ord(x) != endMarker: + # if ord(x) == midMarker: + # i += 1 + # print(ck) + # #isDisplay = ck + # #if i % 100 == 0: + # # self.ui.p1_absolute_DISP.display(ck) + # ck = "" + # x = self.serial.read() + + # if ord(x) != startMarker: + # ck = ck + x.decode() + + # x = self.serial.read() + # # TODO + # #if isDisplay == "START": + # # print("This is ck: " + ck) + # #motorID = int(ck) + # #self.is_p1_running = True + # #run thread(self.display_position, motorID) + + # #toDisp = self.steps2mm(float(ck)) + # #print("Pump num " + toDisp + " is now running.")i + # #self.ui.p1_absolute_DISP.display(toDisp) + # #isDisplay = "" + + # #self.serial.flushInput() + # #print(self.serial.read(self.serial.inWaiting()).decode('ascii')) + # print(ck) + # print("\n") + + # TODO + # def display_position(self, motorID): + # if motorID == 1: + + # seconds = 0 + # p1_speed = self.p1_speed_to_send + # p1_dist = 0 + # p1_time = p1_dist/p1_speed + + # time_start = time.start() + # while self.is_p1_running: + # pass + + + + # def get_position(self): + # ck = "" + # x = self.serial.read() + + # while ord(x) != self.endMarker: + # if ord(x) == self.midMarker: + # print(ck) + # ck = "" + # x = self.serial.read() + # ck = ck + x.decode() + # x = self.serial.read() + # print(ck) + # return (ck) + + + + def closeEvent(self, event): + try: + #self.global_listener_thread.stop() + self.serial.close() + #self.threadpool.end() + + except AttributeError: + pass + sys.exit() + +# I feel better having one of these +def main(): + # a new app instance + app = QtWidgets.QApplication(sys.argv) + window = MainWindow() + window.setWindowTitle("Poseidon Pumps Controller - Pachter Lab Caltech 2018") + window.show() + # without this, the script exits immediately. + sys.exit(app.exec_()) + +if __name__ == "__main__": + main() diff --git a/show_html.py b/show_html.py new file mode 100644 index 0000000..b0de764 --- /dev/null +++ b/show_html.py @@ -0,0 +1,250 @@ + +import sys,os +from PyQt5.QtCore import * +from PyQt5.QtWebEngineWidgets import * +from PyQt5.QtWidgets import QApplication + +app = QApplication(sys.argv) + +web =QWebEngineView() +#web.load(QUrl('http://192.168.2.242:8000/')) + + +script_dir = os.path.dirname(__file__) +file_path = os.path.join(script_dir, 'test.html') +with open(file_path,encoding="UTF-8") as f: + html = f.read() +print(file_path) + +web.load(QUrl.fromLocalFile(file_path)) + +web.show() + +sys.exit(app.exec_()) + +# import pandas as pd +# from bokeh import plotting, embed, resources +# from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets +# import os + +# class Widget(QtWidgets.QWidget): +# def __init__(self, parent=None): +# super(Widget, self).__init__(parent) + +# button = QtWidgets.QPushButton("Submit") +# saveit = QtWidgets.QPushButton('save') +# self.m_output = QtWebEngineWidgets.QWebEngineView() + +# button.clicked.connect(self.on_button_clicked) +# saveit.clicked.connect(self.do_save) + +# lay = QtWidgets.QVBoxLayout(self) +# lay.addWidget(button) +# lay.addWidget(saveit) +# lay.addWidget(self.m_output) +# self.resize(640, 480) + +# @QtCore.pyqtSlot() +# def do_save(self): +# p = plotting.figure(plot_width=300, plot_height=300) +# data = {"Day": [0, 1, 2, 3, 0, 1], "Num": [0, 0, 1, 1, 2, 3]} +# df = pd.DataFrame(data) +# p.hexbin(df.Day, df.Num, size=0.5) +# html = embed.file_html(p, resources.CDN, "my plot") +# script_dir = os.path.dirname(__file__) +# file_path = os.path.join(script_dir, './test.html') +# with open(file_path,'w',encoding='utf_8') as f: +# f.write(html) + + +# print(html) +# self.m_output.setHtml(html) + + +# @QtCore.pyqtSlot() +# def on_button_clicked(self): +# # p = plotting.figure(plot_width=300, plot_height=300) +# # data = {"Day": [0, 1, 2, 3, 0, 1], "Num": [0, 0, 1, 1, 2, 3]} +# # df = pd.DataFrame(data) +# # p.hexbin(df.Day, df.Num, size=0.5) +# # html = embed.file_html(p, resources.CDN, "my plot") +# # self.m_output.setHtml(html) +# #self.m_output.setContent(html,"text/html;charset=UTF-8","") +# # html ='' +# # script_dir = os.path.dirname(__file__) +# # file_path = os.path.join(script_dir, './test.html') +# # with open(file_path,encoding="UTF-8") as f: +# # html = f.read() +# # print(html) +# self.m_output.load(QtCore.QUrl('https://t-online.de')) + +# if __name__ == "__main__": +# import sys + +# app = QtWidgets.QApplication(sys.argv) + +# w = Widget() +# w.show() + +# sys.exit(app.exec_()) + +# from PyQt5.QtWidgets import QApplication +# from PyQt5.QtWebEngineWidgets import QWebEngineView +# from PyQt5.QtWebChannel import QWebChannel + +# from PyQt5.QtCore import QObject, pyqtSlot, QUrl, QVariant + +# import os + +# class CallHandler(QObject): + + +# @pyqtSlot(result=QVariant) +# def test(self): +# print('call received') +# return QVariant({"abc": "def", "ab": 22}) + +# # take an argument from javascript - JS: handler.test1('hello!') +# @pyqtSlot(QVariant, result=QVariant) +# def test1(self, args): +# print('i got') +# print(args) +# return "ok" + +# class WebView(QWebEngineView): + +# def __init__(self): +# super(WebView, self).__init__() + +# self.channel = QWebChannel() +# self.handler = CallHandler() +# self.channel.registerObject('handler', self.handler) +# self.page().setWebChannel(self.channel) + +# file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "test.html")) +# local_url = QUrl.fromLocalFile(file_path) + +# self.load(local_url) + + + +# if __name__ == "__main__": +# app = QApplication([]) +# view = WebView() +# view.show() +# app.exec_() + + + + +# from bokeh.plotting import figure, show + +# # prepare some data +# x = [1, 2, 3, 4, 5] +# y = [6, 7, 2, 4, 5] + +# # create a new plot with a title and axis labels +# p = figure(title="Simple line example", x_axis_label="x", y_axis_label="y") + +# # add a line renderer with legend and line thickness +# p.line(x, y, legend_label="Temp.", line_width=2) + +# # show the results +# show(p) + +# import sys +# from pathlib import Path + +# from PyQt5 import QAxContainer +# from PyQt5.QtCore import Qt +# from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QLineEdit, QApplication + +# import sys +# from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout +# from PyQt5.QtWebEngineWidgets import QWebEngineView +# from PyQt5.QtCore import pyqtSlot + +# from bokeh.layouts import column +# from bokeh.models import ColumnDataSource, CustomJS, Slider +# from bokeh.plotting import Figure, output_file +# from bokeh.embed import file_html +# from bokeh.resources import CDN + +# class App(QWidget): + +# def __init__(self): +# super().__init__() +# self.resize(500, 500) +# self.initUI() + +# def initUI(self): +# button = QPushButton('start', self) +# button.move(100, 70) +# button.clicked.connect(self.on_click) +# self.layout = QVBoxLayout() +# self.layout1 = QVBoxLayout() +# self.layout1.addWidget(button) + +# self.layout2 = QVBoxLayout() +# self.layout.addLayout(self.layout1) +# self.layout.addLayout(self.layout2) +# self.setLayout(self.layout) + + +# self.show() + +# @pyqtSlot() +# def on_click(self): +# print('PyQt5 button click') +# self.m_output = QWebEngineView() +# self.layout2.addWidget(self.m_output) +# #html_file = self.bokeh_function() +# html_file = self.test_html() +# self.m_output.setHtml(html_file) +# self.m_output.show() + + +# def bokeh_function(self): +# # taken from https://docs.bokeh.org/en/latest/docs/user_guide/interaction/callbacks.html +# output_file("js_on_change.html") + +# x = [x * 0.005 for x in range(0, 200)] +# y = x + +# source = ColumnDataSource(data=dict(x=x, y=y)) + +# plot = Figure(width=400, height=400) +# plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6) + +# callback = CustomJS(args=dict(source=source), code=""" +# const data = source.data; +# const f = cb_obj.value +# const x = data['x'] +# const y = data['y'] +# for (let i = 0; i < x.length; i++) { +# y[i] = Math.pow(x[i], f) +# } +# source.change.emit(); +# """) + +# slider = Slider(start=0.1, end=4, value=1, step=.1, title="power") +# slider.js_on_change('value', callback) + +# layout = column(slider, plot) +# html = file_html(layout, CDN, "my plot") +# return html + +# def test_html(self): +# html = '' +# html += '' +# html += '' +# #html += plotly.offline.plot(fig, include_plotlyjs=False, output_type='div') +# html += 'Hi there!' +# html += '' +# return html + + +# if __name__ == '__main__': +# app = QApplication(sys.argv) +# ex = App() +# sys.exit(app.exec_()) diff --git a/systemHtml.py b/systemHtml.py new file mode 100644 index 0000000..e4a28f4 --- /dev/null +++ b/systemHtml.py @@ -0,0 +1,38 @@ +from PyQt5.QtCore import QUrl +from PyQt5.QtWidgets import QMainWindow, QApplication +from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage +from PyQt5.QtGui import QDesktopServices + +import os +import sys + + +class CustomWebEnginePage(QWebEnginePage): + """ Custom WebEnginePage to customize how we handle link navigation """ + # Store external windows. + external_windows = [] + + def acceptNavigationRequest(self, url, _type, isMainFrame): + if (_type == QWebEnginePage.NavigationTypeLinkClicked and + url.host() != 'next.jefro.de'): + # Send the URL to the system default URL handler. + QDesktopServices.openUrl(url) + return False + return super().acceptNavigationRequest(url, _type, isMainFrame) + + +class MainWindow(QMainWindow): + def __init__(self, *args, **kwargs): + super(MainWindow, self).__init__(*args, **kwargs) + + self.browser = QWebEngineView() + self.browser.setPage(CustomWebEnginePage(self)) + self.browser.setUrl(QUrl("https://next.jefro.de/")) + self.setCentralWidget(self.browser) + + +app = QApplication(sys.argv) +window = MainWindow() +window.show() + +app.exec_() \ No newline at end of file diff --git a/test.html b/test.html new file mode 100644 index 0000000..f57855a --- /dev/null +++ b/test.html @@ -0,0 +1,52 @@ + + + + + my plot + + + + +
+ + + + + \ No newline at end of file diff --git a/test_settings.txt b/test_settings.txt new file mode 100644 index 0000000..c05cfe3 --- /dev/null +++ b/test_settings.txt @@ -0,0 +1,21 @@ +File name: /Users/sinabooeshaghi/Dropbox (Personal)/Caltech/Research/Syringe Pump/poseidon/SOFTWARE/test_settings.txt +Date time: 2018-12-03 15_39_08 +:================================ +P1 Syrin: BD 60 mL +P1 Units: ml/s +P1 Speed: 0.02 +P1 Accel: 5.0 +P1 Jog D: 1.0 +:================================ +P2 Syrin: BD 60 mL +P2 Units: ml/s +P2 Speed: 0.02 +P2 Accel: 5.0 +P2 Jog D: 1.0 +:================================ +P3 Syrin: BD 60 mL +P3 Units: ml/s +P3 Speed: 0.02 +P3 Accel: 5.0 +P3 Jog D: 1.0 +Exp Note: \ No newline at end of file