diff --git a/GUI_16_10_staticWorkflow_Multithreading.py b/GUI_16_10_staticWorkflow_Multithreading.py index b08c694..776caf1 100644 --- a/GUI_16_10_staticWorkflow_Multithreading.py +++ b/GUI_16_10_staticWorkflow_Multithreading.py @@ -24,6 +24,14 @@ import time import threading +# db_config = { +# 'user': 'dbUser', +# 'password': 'dbPassword', +# 'host': '127.0.0.1', # 'host': 'localhost', +# 'database': 'projectGeislinger', +# 'port': 3306 # Standard port for MariaDB +# } + db_config = { 'user': 'dbUser', 'password': 'dbPassword', diff --git a/__pycache__/CameraStream.cpython-311.pyc b/__pycache__/CameraStream.cpython-311.pyc index 6e06be7..add8033 100644 Binary files a/__pycache__/CameraStream.cpython-311.pyc and b/__pycache__/CameraStream.cpython-311.pyc differ diff --git a/bjoerntest10.py b/bjoerntest10.py new file mode 100644 index 0000000..620471a --- /dev/null +++ b/bjoerntest10.py @@ -0,0 +1,1042 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'test.ui' +# +# Created by: PyQt5 UI code generator 5.15.9 +# +# 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. + + +########## beim Static workflow funktionieren die Threads ab dem zweiten nicht mehr + +#from PyQt5 import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QProgressBar +from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5.QtWidgets import QApplication, QComboBox +from PyQt5.QtCore import QTimer, QThread, pyqtSignal, QObject, Qt +from PyQt5.QtGui import QColor + +import serial +import binascii +import math +import mariadb +import time +import threading + +from CameraStream import YOLOv8CameraStream # Import the YOLOv8CameraStream class +import cv2 + +# db_config = { +# 'user': 'dbUser', +# 'password': 'dbPassword', +# 'host': '127.0.0.1', # 'host': 'localhost', +# 'database': 'projectGeislinger', +# 'port': 3306 # Standard port for MariaDB +# } + +db_config = { + 'user': 'dbUser', + 'password': 'dbPassword', + 'host': '127.0.0.1', # 'host': 'localhost', + 'database': 'projectGeislinger', + 'port': 3306 # Standard port for MariaDB +} + + +# Establishing the connection +conn = mariadb.connect(**db_config) +# Create a cursor to execute queries +cursor = conn.cursor() + +# Configuration of the serial port +try: + ser = serial.Serial('/dev/serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0', 9600) + print("Serial port connected successfully.") +except serial.SerialException: + ser = None + print("Warning: Serial port not found. Continuing without serial connection. Only working for demo-purposes.") +#ser = serial.Serial('/dev/serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0', 9600) #dadurch garantiert immer die gleiche Schnittstelle verwendet +# und nicht die Schnittstelle, welche die Bezeichnung ttyUSB0 verwendet (welche sich ändern könnte) +# um die ID der USB-Schnittstelle heraus zu finden im Terminal folgendes eingeben: ls -l /dev/serial/by-id/ + + +waageEingeschwungen = False + + +def wahrscheinlichkeitsDichte(x,mue, var): + # in der Funktion wird der Wahrscheinlichkeitsdichtenwert der Variable x für eine bestimmte Normalverteilung berechnet + standardabweichung = var**0.5 + + result = 1/(standardabweichung * (2*math.pi)**0.5 ) * math.exp(-0.5 * ((x-mue)/standardabweichung)**2) + + return result + +def calcWahrscheinlichkeitFromDichte(x,mue, var): + # in der Funktion wird die Wahrscheinlichkeit via der Wahrscheinlichkeitsdichte berechnet, indem das Verhältnis aus der dem Bauteil zugehörigen Wahrscheinlichkeitsdichte zu der maximalen Wahrscheinlichkeitsdichte berechnet wird + p1 = wahrscheinlichkeitsDichte(x,mue, var) + p_max = wahrscheinlichkeitsDichte(mue,mue, var) + + return p1/p_max + + + +#class Worker(QThread): +class Worker(QObject): + #progress = pyqtSignal(int) + objectDetectionStartSignal = pyqtSignal(str) + objectDetectionFinishedSignal = pyqtSignal(int, object) + + checkWaageStartSignal = pyqtSignal(int, int, str) + checkWaageUpdateSignal = pyqtSignal(int, int) + checkWaageFinishedSignal = pyqtSignal(int) + + waageStoppedSignal = pyqtSignal(int) + stopLoopSignal = pyqtSignal(bool) #das Signal wird verwendet um direkt den stopLoop-Wert zu ändern (also kein Funktionsaufruf) + + stopLoop = False + btTypeIsSet = False + correctBtNr = False + + + def __init__(self): + super(Worker, self).__init__() + stopLoop = False + + + def getDataOfArticleType(self, allArticles, articleType): + # die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück + for i in allArticles: + if i[1] == articleType: + return i + + return -1 + + def waageNichtEingeschwungenOutput(self): + print("Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft.") + + def readWaage(self): + # in folgender Funktion wird die Waage ausgelesen + + #print("connection is open: ", ser.is_open) #Debuggingausgabe + #print("port to which it is connected: ", ser.portstr) #Debuggingausgabe + + + if ser.is_open == False: + ser.open() + + + #an die Waage den Befehl senden, dass sie ausgelesen werden soll + ser.write(b'getWeight\n') + #ser.write(b'tare\n') + serialString = ser.readline().decode('utf-8').rstrip() #Auslesen des Serial-Strings/der Messung der Waage + + # wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft + lenString = len(serialString)-1 + if serialString[lenString] == "g" and serialString[lenString-1] == "k": + #print("ist eingeschwungen") #Debuggingausgabe + waageEingeschwungen = True + else: + print("die Waage ist noch nicht eingeschwungen") + waageEingeschwungen = False + + #aus dem String werden alle Zeichen, welche nicht zur Darstellung der Zahl benötigt werden entfernt + intString = "" + for i in serialString: + if i=="-" or i=="0" or i=="." or i=="1" or i=="2" or i=="3" or i=="4" or i=="5" or i=="6" or i=="7" or i=="8" or i=="9": + intString = intString + i + print("Wert, welcher von der Waage ausgelesen wurde: " + intString + "kg") + ## Waage auslesen - ENDE + + ser.close() + #print("connection is open: ", ser.is_open) #Debuggingausgabe + + return waageEingeschwungen, intString + + def objectTypeDetectionThread(self, auftragsnummer): + # in dieser Funktion wird der Typ des Bauteils automatisch erkannt + + #print("objectTypeDetectionThread - Running in thread:", threading.current_thread().name) #Debuggausgabe + + # Parameterdefinition + propDensVect = [] + + self.btTypeIsSet = False + + while(self.btTypeIsSet == False and self.stopLoop == False): + + # Auslesen der Waage + waageEingeschwungen, intString = self.readWaage() + if waageEingeschwungen == False: + self.waageNichtEingeschwungenOutput() + else: + + # Datenbankabfrage + sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer + cursor.execute(sql_query) + auftragEinzelteilDaten = cursor.fetchall() + + ''' + # Display data #Debugausgabe + print("Ausgabe der Auftragsdetails des obigen Auftrags, inklusive Einzelteildetails:") + for row in auftragEinzelteilDaten: + print(row) + ''' + + # in der Folge werden alle Wahrscheinlichkeitsdichten der Auftragsbauteile berechnet und in dem Vektor gesammelt + for row in auftragEinzelteilDaten: + propDensVect.append([wahrscheinlichkeitsDichte(float(intString),float(row[6]), float(row[7])), row[1], row[5]]) + + # Jenen Eintrag des propDensVect raussuchen, welcher die größte Wahrscheinlichkeitsdichte beinhaltet + maxpropDens = 0 + einzelteilID = 0 + rowData = None + for row in propDensVect: + if row[0] > maxpropDens: + maxpropDens = row[0] + einzelteilID = row[1] + rowData = row + + # überprüfen, ob das aufliegende Bauteil in der Auftragstabelle vorhanden ist + if(einzelteilID == 0): + print("Es wurde kein Bauteil aus der Auftragsliste (Tabelle) erkannt.") + else: + print("Bei dem Bauteil" , einzelteilID , "wurde die höchste Wahrscheinlichkeitsdichte berechnet.") + + # Wahrscheinlichkeit berechnen, dass das angegebene Bauteil auch wirklich diesem entspricht + prop = 0 + for row in auftragEinzelteilDaten: + if row[1] == einzelteilID: + prop = calcWahrscheinlichkeitFromDichte(float(intString),float(row[6]), float(row[7])) + break + print("Die Wahrscheinlichkeit, dass es das Bauteil ist, beträgt: ", prop) + + # den Bool auf true setzen, damit die Schleife beendet wird - dieser wird auf True gesetzt, wenn ein Bauteiltyp erkannt wird + self.btTypeIsSet = True + + if(self.stopLoop == False): + # ein Signal zurück an den MainThreat senden, mit den Infos/Ergebnissen, der Typenbestimmung + self.objectDetectionFinishedSignal.emit(einzelteilID, rowData) + else: + self.waageStoppedSignal.emit(einzelteilID) + + def checkWaageThread(self, einzelteilID, teileZuViel, auftragsnummer): + + self.correctBtNr = False + prevAnzahl = 0 + anzahl = 0 + einzelteilID = einzelteilID + + while (self.correctBtNr == False and self.stopLoop == False): + + #überprüfen, ob die Waage eingeschwungen ist (und damit korrekte Ergebnisse liefert) + waageEingeschwungen, intString = self.readWaage() + if waageEingeschwungen == False: + self.waageNichtEingeschwungenOutput() + else: + + # Datenbankabfrage - holen der Auftrags- und Bauteilinfos + sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer + cursor.execute(sql_query) + auftragDaten = cursor.fetchall() + + ''' + # Display data - zum Debuggen + print("Ausgabe der Auftragsdetails:") + print("id|EinzelteilID|Auftragsnummer|Anzahl") + for row in auftragDaten: + print(row) + ''' + + #auslesen, wie viele Bauteile des Types laut Auftrag vorhanden sein sollen + anzBauteile_soll = 0 + idVorhanden = False + + for row in auftragDaten: + if row[1] == einzelteilID: + anzBauteile_soll = row[3] + idVorhanden = True + + if(idVorhanden == False): + print("Die gewählte Pos.Nr ist nicht in der Auftragsliste (Tabelle) vorhanden.") + return + + # Berechnen der Wahrscheinlichkeitsdichten - der Betrag aller Wahrscheinlichkeitsdichten werden im propDensVect gespeichert + propDensVect = [] + articleData = self.getDataOfArticleType(auftragDaten, einzelteilID) + for i in range(1,anzBauteile_soll+teileZuViel+1): + # Mathematische Sätze, auf welchen die Berechnung basiert: + # seien X1,..., Xn unabhängige Zufallsvariablen die N(mue_i, sigma_i^2) verteilt sind, dann ist X = X1+...+Xn - N(mue, sigma^2) verteilt mit mue=mue1+...+mue_n, sigma^2 = sigma_1^2+...+sigma_n^2 + mueGes = float(articleData[6])*i # Berechnen des äquivalenten Mittelwert + varGes = float(articleData[7])*i # Berechnen der äquivalenten Varianz + propDensVect.append([wahrscheinlichkeitsDichte(float(intString),mueGes, varGes), i]) + + # durch den propDensVect iterieren und jenen Eintrag mit der höchsten Wahrscheinlichkeitsdichte raussuchen + maxpropDens = 0 + for row in propDensVect: + if row[0] > maxpropDens: + maxpropDens = row[0] + anzahl = row[1] + + # damit nur etwas gemacht wird (zb ein Updatesignal an den Hauptthread zurücksenden), wenn sich die berechnete Anzahl ändert + if prevAnzahl != anzahl: + prevAnzahl = anzahl + + # Die Wahrscheinlichkeit berechnen, dass das obige Ergebnis auch dem Bauteil entspricht + if anzahl > 0: + for row in auftragDaten: + if row[1] == einzelteilID: + prop = calcWahrscheinlichkeitFromDichte(float(intString),float(row[6])*anzahl, float(row[7])*anzahl) + break + print("Die Wahrscheinlichkeit, dass es das Bauteil ist, beträgt: ", prop) + + # wenn genug Bauteile vorhanden sind, dann soll die Schleife beendet werden + if (anzahl == anzBauteile_soll): + self.correctBtNr = True + + # Konsolenausgabe + if maxpropDens > 0: + print("Bei der Anzahl" , anzahl , "des Bauteiltypes", einzelteilID, ",wurde die höchste Wahrscheinlichkeitsdichte berechnet.") + self.checkWaageUpdateSignal.emit(einzelteilID, anzahl) + + else: + print("Von der ausgewählten Bauteiltype liegt die berechnete Wahrscheinlichkeit bei 0, dass zwischen 0 und", anzBauteile_soll+teileZuViel, "Bauteilen auf der Waage liegen.") + print("Falls die korrekte Anzhl an Bauteilen auf der Waage liegt, könnte der Fehler in einer falschen Kalibrierung der Waage liegen (TARE).") + + if(self.stopLoop == False): + self.checkWaageFinishedSignal.emit(einzelteilID) + else: + self.waageStoppedSignal.emit(einzelteilID) + + + + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + self.auftragsnummer = "" + self.teileZuViel = 100 # Anzahl an Bauteilen, welche zu viel drinnen sein können - der Parameter kann selbst gesetzt werden ##### + self.correctBtNr = False + self.btTypeIsSet = False + + + MainWindow.setObjectName("MainWindow") + MainWindow.resize(1400, 675) + self.centralwidget = QtWidgets.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.btn1 = QtWidgets.QPushButton(self.centralwidget) + self.btn1.setGeometry(QtCore.QRect(700, 45, 111, 25)) + self.btn1.setObjectName("btn1") + # Tabelle zur Darstellung der Auftragsdetails + self.AuftragsdetailsTable = QtWidgets.QTableWidget(self.centralwidget) + self.AuftragsdetailsTable.setGeometry(QtCore.QRect(10, 100, 661, 400)) + self.AuftragsdetailsTable.setObjectName("AuftragsdetailsTable") + self.AuftragsdetailsTable.setColumnCount(7) + self.AuftragsdetailsTable.setRowCount(0) + item = QtWidgets.QTableWidgetItem() + font = QtGui.QFont() + font.setPointSize(8) + item.setFont(font) + self.AuftragsdetailsTable.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + font = QtGui.QFont() + font.setPointSize(8) + item.setFont(font) + self.AuftragsdetailsTable.setHorizontalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + font = QtGui.QFont() + font.setPointSize(8) + item.setFont(font) + self.AuftragsdetailsTable.setHorizontalHeaderItem(2, item) + item = QtWidgets.QTableWidgetItem() + font = QtGui.QFont() + font.setPointSize(8) + item.setFont(font) + self.AuftragsdetailsTable.setHorizontalHeaderItem(3, item) + item = QtWidgets.QTableWidgetItem() + font = QtGui.QFont() + font.setPointSize(8) + item.setFont(font) + self.AuftragsdetailsTable.setHorizontalHeaderItem(5, item) + item = QtWidgets.QTableWidgetItem() + font = QtGui.QFont() + font.setPointSize(8) + item.setFont(font) + self.AuftragsdetailsTable.setHorizontalHeaderItem(4, item) + item = QtWidgets.QTableWidgetItem() + font = QtGui.QFont() + font.setPointSize(8) + item.setFont(font) + self.AuftragsdetailsTable.setHorizontalHeaderItem(6, item) + + # Tabelle zur Darstellung der Arbeitsschritte + self.ArbeitsschrittTable = QtWidgets.QTableWidget(self.centralwidget) + self.ArbeitsschrittTable.setGeometry(QtCore.QRect(1000, 50, 395, 400)) + self.ArbeitsschrittTable.setObjectName("AuftragsdetailsTable") + self.ArbeitsschrittTable.setColumnCount(2) + self.ArbeitsschrittTable.setRowCount(4) + self.ArbeitsschrittTable.setColumnWidth(0, 100) + self.ArbeitsschrittTable.setColumnWidth(1, 280) + self.ArbeitsschrittTable.setRowHeight(0, 80) + self.ArbeitsschrittTable.setRowHeight(1, 180) + self.ArbeitsschrittTable.setRowHeight(2, 50) + self.ArbeitsschrittTable.setRowHeight(3, 50) + item = QtWidgets.QTableWidgetItem() + font = QtGui.QFont() + font.setPointSize(8) + item.setFont(font) + self.ArbeitsschrittTable.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + font = QtGui.QFont() + font.setPointSize(8) + item.setFont(font) + self.ArbeitsschrittTable.setHorizontalHeaderItem(1, item) + + self.label = QtWidgets.QLabel(self.centralwidget) + self.label.setGeometry(QtCore.QRect(500, 20, 121, 17)) + self.label.setObjectName("label") + self.textEdit = QtWidgets.QTextEdit(self.centralwidget) + self.textEdit.setGeometry(QtCore.QRect(450, 40, 221, 31)) + self.textEdit.setObjectName("textEdit") + self.bauteilTypBtn = QtWidgets.QPushButton(self.centralwidget) + self.bauteilTypBtn.setGeometry(QtCore.QRect(700, 100, 161, 25)) + self.bauteilTypBtn.setObjectName("bauteilTypBtn") + self.checkWaageBtn = QtWidgets.QPushButton(self.centralwidget) + self.checkWaageBtn.setGeometry(QtCore.QRect(700, 150, 161, 25)) + self.checkWaageBtn.setObjectName("checkWaageBtn") + self.stopLoopBtn = QtWidgets.QPushButton(self.centralwidget) + self.stopLoopBtn.setGeometry(QtCore.QRect(700, 350, 161, 25)) + self.stopLoopBtn.setObjectName("stopLoopBtn") + self.waageTareBtn = QtWidgets.QPushButton(self.centralwidget) + self.waageTareBtn.setGeometry(QtCore.QRect(700, 400, 161, 25)) + self.waageTareBtn.setObjectName("waageTareBtn") + self.bauteiltypTextbox = QtWidgets.QTextEdit(self.centralwidget) + self.bauteiltypTextbox.setGeometry(QtCore.QRect(700, 290, 221, 31)) + self.bauteiltypTextbox.setObjectName("bauteiltypTextbox") + self.BezeichnungLabel = QtWidgets.QLabel(self.centralwidget) + self.BezeichnungLabel.setGeometry(QtCore.QRect(700, 270, 181, 20)) + self.BezeichnungLabel.setObjectName("BezeichnungLabel") + self.PosNrLabel = QtWidgets.QLabel(self.centralwidget) + self.PosNrLabel.setGeometry(QtCore.QRect(700, 200, 67, 17)) + self.PosNrLabel.setObjectName("PosNrLabel") + self.PosNrTxtFeld = QtWidgets.QTextEdit(self.centralwidget) + self.PosNrTxtFeld.setGeometry(QtCore.QRect(700, 220, 191, 31)) + self.PosNrTxtFeld.setObjectName("PosNrTxtFeld") + self.teileZuVielLabel = QtWidgets.QLabel(self.centralwidget) + self.teileZuVielLabel.setGeometry(QtCore.QRect(1000, 560, 350, 17)) + self.teileZuVielLabel.setObjectName("teileZuVielLabel") + self.teileZuVielTxtFeld = QtWidgets.QTextEdit(self.centralwidget) + self.teileZuVielTxtFeld.setGeometry(QtCore.QRect(1000, 580, 191, 31)) + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 1090, 22)) + self.menubar.setObjectName("menubar") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QtWidgets.QStatusBar(MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + self.checkBox = QtWidgets.QCheckBox(self.centralwidget) + self.checkBox.setGeometry(QtCore.QRect(1000, 480, 151, 23)) + self.checkBox.setObjectName("checkBox") + self.checkBoxAutoTare = QtWidgets.QCheckBox(self.centralwidget) + self.checkBoxAutoTare.setGeometry(QtCore.QRect(1000, 520, 180, 23)) + self.checkBoxAutoTare.setObjectName("checkBoxAutoTare") + + # button and checkbox for camera workflow + graphicsview widget + self.startCamBtn = QtWidgets.QPushButton(self.centralwidget) + self.startCamBtn.setGeometry(QtCore.QRect(900, int(1080/2)+100, 161, 25)) + self.startCamBtn.setObjectName("startCamBtn") + self.stopCamBtn = QtWidgets.QPushButton(self.centralwidget) + self.stopCamBtn.setGeometry(QtCore.QRect(900, int(1080/2)+100+25, 161, 25)) + self.stopCamBtn.setObjectName("stopCamBtn") + self.camWorkFlowcheckBox = QtWidgets.QCheckBox(self.centralwidget) + self.camWorkFlowcheckBox.setGeometry(QtCore.QRect(900, int(1080/2)+100-25, 151, 23)) + self.camWorkFlowcheckBox.setObjectName("camWorkFlowcheckBox") + self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget) + self.graphicsView.setGeometry(QtCore.QRect(10, int(1080/2), int(640*1.2), int(480*1.2))) # position and size of camera frame + self.graphicsView.setObjectName("graphicsView") + + #self.myTestLambda = lambda: self.worker.checkWaageStartSignal.emit(einzelteilID, self.teileZuViel, self.auftragsnummer) + + ''' + item = QtWidgets.QTableWidgetItem() + font = QtGui.QFont() + font.setPointSize(8) + item.setFont(font) + self.AuftragsdetailsTable.setVerticalHeaderItem(0,item) + ''' + + # Maximize the window on startup + MainWindow.showMaximized() + + self.retranslateUi(MainWindow) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) + self.btn1.setText(_translate("MainWindow", "load Auftrag")) + self.btn1.clicked.connect(self.auftragsBtnClicked) + + # Tabelle zur Darstellung der Auftragsdetails + item = self.AuftragsdetailsTable.horizontalHeaderItem(0) + item.setText(_translate("MainWindow", "Pos.-Nr")) + item = self.AuftragsdetailsTable.horizontalHeaderItem(1) + item.setText(_translate("MainWindow", "Matnr mit hoechster Version")) + item = self.AuftragsdetailsTable.horizontalHeaderItem(2) + item.setText(_translate("MainWindow", "Bezeichnung + Werkstoff")) + item = self.AuftragsdetailsTable.horizontalHeaderItem(3) + item.setText(_translate("MainWindow", "Soll-Menge")) + item = self.AuftragsdetailsTable.horizontalHeaderItem(4) + item.setText(_translate("MainWindow", "Ist-Menge")) + item = self.AuftragsdetailsTable.horizontalHeaderItem(5) + item.setText(_translate("MainWindow", "Lgort")) + item = self.AuftragsdetailsTable.horizontalHeaderItem(6) + item.setText(_translate("MainWindow", "set Farbe")) + + # Tabelle zur Darstellung der Arbeitsschritte + item = self.ArbeitsschrittTable.horizontalHeaderItem(0) + item.setText(_translate("MainWindow", "Arbeitsschritt")) + item = self.ArbeitsschrittTable.horizontalHeaderItem(1) + item.setText(_translate("MainWindow", "ToDo:")) + + # Befüllen der Arbeisschritttabelle mit Text + #item = self.ArbeitsschrittTable. + # Ein neues QTableWidgetItem erstellen und den Text setzen + item = QtWidgets.QTableWidgetItem("Auftrag laden") + self.ArbeitsschrittTable.setItem(0, 0, item) + item = QtWidgets.QTableWidgetItem("--> Auftragsnummer eingeben \n--> \"load Auftrag\" Buttonclick") + self.ArbeitsschrittTable.setItem(0, 1, item) + item = QtWidgets.QTableWidgetItem("Bauteiltyp erkennen") + self.ArbeitsschrittTable.setItem(1, 0, item) + item = QtWidgets.QTableWidgetItem("visuell: \n--> ein Bauteil in die Kamera halten\n\nWaage: \n--> ein Bauteil auf die Waage legen\n--> \"Bauteiltyp erkennen\" Buttonclick\n\nmanuell:\n--> Bauteiltypen auswählen\n-->\"ckeck Waage\" Button click") + self.ArbeitsschrittTable.setItem(1, 1, item) + item = QtWidgets.QTableWidgetItem("Bauteilanzahl erkennen") + self.ArbeitsschrittTable.setItem(2, 0, item) + item = QtWidgets.QTableWidgetItem("--> Bauteile auflegen") + self.ArbeitsschrittTable.setItem(2, 1, item) + item = QtWidgets.QTableWidgetItem("Prozess beendet") + self.ArbeitsschrittTable.setItem(3, 0, item) + self.ArbeitsschrittTable.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) + + #self.ArbeitsschrittTable.item(0,0).setText("test") + + #einzelteilID = int(self.AuftragsdetailsTable.item(i,0).text()) + #self.PosNrTxtFeld.setText(str(self.AuftragsdetailsTable.item(i,0).text())) + #self.bauteiltypTextbox.setText(str(self.AuftragsdetailsTable.item(i,2).text())) + + self.label.setText(_translate("MainWindow", "Auftragsnummer:")) + self.bauteilTypBtn.setText(_translate("MainWindow", "Bauteiltyp erkennen")) + self.bauteilTypBtn.clicked.connect(self.objectTypeDetection) + self.AuftragsdetailsTable.cellClicked.connect(self.onTableCellClick) + #self.AuftragsdetailsTable.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) + #item = self.AuftragsdetailsTable.verticalHeaderItem(0) + #item.setText(_translate("MainWindow", "test")) + self.BezeichnungLabel.setText(_translate("MainWindow", "Bezeichnung")) + self.PosNrLabel.setText(_translate("MainWindow", "Pos.-Nr:")) + self.teileZuVielLabel.setText(_translate("MainWindow", "Zu prüfende Teileanzahl über Auftragsanzahl:")) + self.teileZuVielTxtFeld.setText(str(self.teileZuViel)) + self.checkWaageBtn.setText(_translate("MainWindow", "check Waage")) + self.checkWaageBtn.clicked.connect(self.checkWaage) + self.stopLoopBtn.setText(_translate("MainWindow", "stop loop")) + self.stopLoopBtn.clicked.connect(self.stopLoopClicked) + self.waageTareBtn.setText(_translate("MainWindow", "Waage tarieren")) + self.waageTareBtn.clicked.connect(self.onTareClick) + self.checkBox.setText(_translate("MainWindow", "static workflow")) + self.checkBox.clicked.connect(self.onCheckboxCheck) + self.checkBoxAutoTare.setText(_translate("MainWindow", "automatisches Tarieren")) + self.checkBoxAutoTare.clicked.connect(self.autoTareCheck) + + self.setRowColor(self.ArbeitsschrittTable, 0,255,165,0) # zum setzen der ersten Spalte der Arbeitsschrittetabelle auf orange + self.checkBoxAutoTare.setCheckState(Qt.Checked) + self.checkBox.setCheckState(Qt.Unchecked) + + # new camera workflow + self.startCamBtn.setText(_translate("MainWindow", "Start Camera")) + # self.startCamBtn.clicked.connect(self.startCamBtnClicked) + self.stopCamBtn.setText(_translate("MainWindow", "Stop Camera")) + self.camWorkFlowcheckBox.setText(_translate("MainWindow", "Camera Workflow")) + # self.camWorkFlowcheckBox.clicked.connect(self.onCheckboxCheck) + + + def mousePressEvent(self, event): + print("Das MainWindow wurde angeklickt.") + self.setFocus() + super().mousePressEvent(event) + + + def onTareClick(self): + #Tarieren der Waage + if ser.is_open == False: + ser.open() + ser.write(b'tare\n') + ser.close() + + + def onCheckboxCheck(self): + if self.checkBox.isChecked() == True: + print("static workflow activated") + else: + print("static workflow deactivated") + + def autoTareCheck(self): + if self.checkBoxAutoTare.isChecked() == True: + print("automatisches Tarieren ist aktiviert") + else: + print("automatisches Tarieren ist deaktiviert") + + def getRowNr(self, posNr): + for i in range(0,self.AuftragsdetailsTable.rowCount()): + if(self.AuftragsdetailsTable.item(i,0).text() == str(posNr)): + return i +# brauche ich hier vermutlich nicht mehr - ist in den Worker Thread kopiert worden + def waageNichtEingeschwungenOutput(self): + print("Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft.") + + def onTableCellClick(self): + self.PosNrTxtFeld.setText(self.AuftragsdetailsTable.item(self.AuftragsdetailsTable.currentRow(),0).text()) + self.bauteiltypTextbox.setText(self.AuftragsdetailsTable.item(self.AuftragsdetailsTable.currentRow(),2).text()) + + def setAuftragsnummer(self): + self.auftragsnummer = self.textEdit.toPlainText() + if(not self.auftragsnummer): + self.auftragsnummer = "" + self.textEdit.setText("") + + def checkAuftragsnummerEmpty(self): + if self.auftragsnummer == "": + print("Das Auftragsnummernfeld ist leer.") + return True + else: + return False + + def checkPosNrEmpty(self): + if self.PosNrTxtFeld.toPlainText() == "": + return True + else: + return False + + +# eventuell benötigt man die Funktion hier nicht mehr, da sie zu den Threads kopiert wurde + def getDataOfArticleType(self, allArticles, articleType): + # die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück + for i in allArticles: + if i[1] == articleType: + return i + return -1 + + def updateGUI(self): + self.PosNrLabel.repaint() #GUI aktualisieren + QApplication.processEvents() #GUI aktualisieren + + + def setRowColor(self, tableObject, rowID,r,g,b): + for col in range(tableObject.columnCount()-1): + tableObject.item(rowID, col).setBackground(QtGui.QColor(r,g,b)) + ''' + die alte Version der Programmierung + tableObject.item(rowID, 0).setBackground(QtGui.QColor(r,g,b)) + tableObject.item(rowID, 1).setBackground(QtGui.QColor(r,g,b)) + tableObject.item(rowID, 2).setBackground(QtGui.QColor(r,g,b)) + tableObject.item(rowID, 3).setBackground(QtGui.QColor(r,g,b)) + tableObject.item(rowID, 4).setBackground(QtGui.QColor(r,g,b)) + tableObject.item(rowID, 5).setBackground(QtGui.QColor(r,g,b)) + ''' + +#wird hier vermutlich nicht mehr benötigt - wurde in die Workerklasse kopiert + def readWaage(self): + # in folgender Funktion wird die Waage ausgelesen + + #print("connection is open: ", ser.is_open) #Debuggingausgabe + #print("port to which it is connected: ", ser.portstr) #Debuggingausgabe + self.checkPosNrEmpty() + + if ser.is_open == False: + ser.open() + + + #an die Waage den Befehl senden, dass sie ausgelesen werden soll + ser.write(b'getWeight\n') + #ser.write(b'tare\n') + serialString = ser.readline().decode('utf-8').rstrip() #Auslesen des Serial-Strings/der Messung der Waage + + # wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft + lenString = len(serialString)-1 + if serialString[lenString] == "g" and serialString[lenString-1] == "k": + #print("ist eingeschwungen") #Debuggingausgabe + waageEingeschwungen = True + else: + print("die Waage ist noch nicht eingeschwungen") + waageEingeschwungen = False + + #aus dem String werden alle Zeichen, welche nicht zur Darstellung der Zahl benötigt werden entfernt + intString = "" + for i in serialString: + if i=="-" or i=="0" or i=="." or i=="1" or i=="2" or i=="3" or i=="4" or i=="5" or i=="6" or i=="7" or i=="8" or i=="9": + intString = intString + i + print("Wert, welcher von der Waage ausgelesen wurde: " + intString + "kg") + ## Waage auslesen - ENDE + + ser.close() + #print("connection is open: ", ser.is_open) #Debuggingausgabe + + return waageEingeschwungen, intString + + def auftragsBtnClicked(self): + databaseQueryWorking = False #wird für die Überprüfung, ob die Datenbankabfrage fehlerhaft ist, verwendet + auftragEinzelteilDaten = [] + + self.setAuftragsnummer() + if(not self.checkAuftragsnummerEmpty()): + + sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + self.auftragsnummer + try: + cursor.execute(sql_query) + # Fetch results + auftragEinzelteilDaten = cursor.fetchall() + databaseQueryWorking = True + except: + print("Fehler in der Datenbankabfrage.") + + + + if databaseQueryWorking==True and len(auftragEinzelteilDaten)>0: + ''' + # Display data + print("Ausgabe der Auftragsdetails des obigen Auftrags, inklusive Einzelteildetails:") + for row in auftragEinzelteilDaten: + if str(row[2]) == self.auftragsnummer: + print("passt") + print(row) + ''' + + ### die Auftragsdaten in die Tabelle laden + self.AuftragsdetailsTable.setRowCount(len(auftragEinzelteilDaten)) + self.item = QtWidgets.QTableWidgetItem() + counter = 0 + for row in auftragEinzelteilDaten: + self.item = QtWidgets.QTableWidgetItem() + self.AuftragsdetailsTable.setItem(counter, 0, self.item) + self.item.setText(str(row[1])) + self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable) + self.item = QtWidgets.QTableWidgetItem() + self.AuftragsdetailsTable.setItem(counter, 1, self.item) + self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable) + self.item = QtWidgets.QTableWidgetItem() + self.AuftragsdetailsTable.setItem(counter, 2, self.item) + self.item.setText(str(row[5])) + self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable) + self.item = QtWidgets.QTableWidgetItem() + self.AuftragsdetailsTable.setItem(counter, 3, self.item) + self.item.setText(str(row[3])) + self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable) + self.item = QtWidgets.QTableWidgetItem() + self.AuftragsdetailsTable.setItem(counter, 4, self.item) + self.item.setText(str("0")) + self.item = QtWidgets.QTableWidgetItem() + self.AuftragsdetailsTable.setItem(counter, 5, self.item) + self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable) + + # Dropdown für Farben in die 6. Spalte einfügen + #self.item = QtWidgets.QTableWidgetItem() + #self.AuftragsdetailsTable.setItem(counter, 6, self.item) + combo = QComboBox() + combo.addItems(["Farbe", "Weiß", "Orange", "Grün"]) + combo.currentIndexChanged.connect(lambda index, rowId =counter: self.change_row_color(rowId, index)) + self.AuftragsdetailsTable.setCellWidget(counter, 6, combo) + counter = counter +1 + + self.setRowColor(self.ArbeitsschrittTable, 0,0,255,0) #zum setzen der ersten Zeile der Auftragstabelle auf grün + self.setRowColor(self.ArbeitsschrittTable, 1,255,165,0) #zum setzen der zweiten Zeile der Auftragstabelle auf orange + self.setRowColor(self.ArbeitsschrittTable, 2,255,255,255) #zum setzen der dritten Zeile der Auftragstabelle auf weiß + self.setRowColor(self.ArbeitsschrittTable, 3,255,255,255) #zum setzen der vierten Zeile der Auftragstabelle auf weiß + + # setzen der beiden Felder auf einen leeren String, um Fehler zu Vermeiden, wenn ein neuer Auftrag geladen wird + self.bauteiltypTextbox.setText("") + self.PosNrTxtFeld.setText("") + + + elif(databaseQueryWorking==True and len(auftragEinzelteilDaten)==0): + print("Es wurde in der Datenbank kein Auftrag mit dieser Auftragsnummer gefunden.") + + def change_row_color(self, row, color_index): + if(color_index == 1): + self.setRowColor(self.AuftragsdetailsTable, row,255,255,255) + if(color_index == 2): + self.setRowColor(self.AuftragsdetailsTable, row,255,165,0) + if(color_index == 3): + self.setRowColor(self.AuftragsdetailsTable, row,0,255,0) + + def stopLoopClicked(self): + # damit wird beim Klick auf den Stopbutton der stopLoop-boolWert in der Workerklasse auf true gesetzt -> der Stop des Threads wird initiiert + if hasattr(self, 'objectDetectionWorker'): + self.objectDetectionWorker.stopLoopSignal.emit(True) + + if hasattr(self, 'checkWaageWorker'): + self.checkWaageWorker.stopLoopSignal.emit(True) + + def checkFinished(self): + #die Funktion geht alle Zeilen der Auftragsliste durch und schaut, ob die richtige Anzahl an Teilen vorhanden sind + for i in range(0,self.AuftragsdetailsTable.rowCount()): + if self.AuftragsdetailsTable.item(i,3).text() != self.AuftragsdetailsTable.item(i,4).text(): + return False + return True + + + def checkWaage(self): + #print("Running in thread:", threading.current_thread().name) # Debuggingausgabe + QApplication.processEvents() + + # die Loopvariable des Workers auf False setzten, damit die Schleife durchgelaufen wird (diese wird zum Abbruch der Schleife benötigt -> siehe stopLoop) + #self.checkWaageWorker.stopLoopSignal.emit(False) + + # überprüfen, ob der Auftrag geladen wurde + if(self.AuftragsdetailsTable.item(0,0) == None): + print("Der Auftrag muss zuerst geladen werden.") + return + + # überprüfen, ob ein Bauteiltyp gesetzt wurde + if(self.checkPosNrEmpty()==True and self.checkBox.isChecked() == False): + print("Das Pos.-Nr.-Feld ist leer.") + return + + # den GUI Wert von Textfeld TeileZuViel in die Variable schreiben + self.teileZuViel = int(float(self.teileZuVielTxtFeld.toPlainText())) + self.teileZuVielTxtFeld.setText(str(self.teileZuViel)) + + einzelteilID = -1 # Initialisieren der Variable mit einem Defaultwert, welcher nie eingenommen werden können sollte + if (self.checkBox.isChecked() == False): + #übernehmen der BauteilID aus dem Feld Pos.-Nr - wenn der Workflow dynamisch gewählt wurde + einzelteilID = int(self.PosNrTxtFeld.toPlainText()) + else: + # wenn der Workflow statisch gesetzt wurde, dann soll das erste Item aus der Auftragsliste geladen werden, von welchem noch nicht genug Bauteile auf der Waage liegen + for i in range(0,self.AuftragsdetailsTable.rowCount()): + if self.AuftragsdetailsTable.item(i,3).text() != self.AuftragsdetailsTable.item(i,4).text(): + einzelteilID = int(self.AuftragsdetailsTable.item(i,0).text()) + self.PosNrTxtFeld.setText(str(self.AuftragsdetailsTable.item(i,0).text())) + self.bauteiltypTextbox.setText(str(self.AuftragsdetailsTable.item(i,2).text())) + break + + if einzelteilID == -1: + # den Thread beenden + self.checkWaageThread.quit() + self.checkWaageThread.wait() + try: + self.checkWaageThread.started.disconnect() # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt + print("Der Thread wurde beendet.") + except: + print("Disconnecting the thread did not work.") + return + + + #zum setzen den Farbe der gesamten Reihe auf Orange + self.setRowColor(self.AuftragsdetailsTable, self.getRowNr(einzelteilID),255,165,0) + self.setRowColor(self.ArbeitsschrittTable, 1,0,255,0) # zum setzen der zweiten Spalte der Arbeitsschrittetabelle auf grün + self.setRowColor(self.ArbeitsschrittTable, 2,255,165,0) # zum setzen der dritten Spalte der Arbeitsschrittetabelle auf orange + + # den Thread starten, welcher die Bauteilanzahl überprüft + self.checkWaageWorker = Worker() + self.checkWaageThread = QThread() + + self.checkWaageWorker.moveToThread(self.checkWaageThread) + + self.checkWaageWorker.checkWaageStartSignal.connect(self.checkWaageWorker.checkWaageThread) + self.checkWaageWorker.checkWaageUpdateSignal.connect(self.checkWaageUpdate) + self.checkWaageWorker.checkWaageFinishedSignal.connect(self.checkWaageFinished) + self.checkWaageWorker.waageStoppedSignal.connect(self.threadStopped) + self.checkWaageWorker.stopLoopSignal.connect(lambda status: setattr(self.checkWaageWorker, 'stopLoop', status)) #wird fürs aktive Stoppen des Threads benötigt + + self.checkWaageThread.started.connect(lambda: self.checkWaageWorker.checkWaageStartSignal.emit(einzelteilID, self.teileZuViel, self.auftragsnummer)) + self.checkWaageThread.start() + + def checkWaageUpdate(self, einzelteilID, anzahl): + # die Funktion updated die (vom Thread) berechnete Bauteilanzahl in der GUI + self.AuftragsdetailsTable.item(self.getRowNr(einzelteilID), 4).setText(str(anzahl)) # in die Tabelle die Anzahl an berechneten Bauteilen reinschreiben + + def checkWaageFinished(self, einzelteilID): + self.setRowColor(self.AuftragsdetailsTable, self.getRowNr(einzelteilID),0,255,0) #zum setzen den Farbe der gesamten Reihe auf Grün + + if self.checkFinished(): # wenn alle Bauteile auf der Waage liegen, soll folgender Code ausgeführt werden + self.setRowColor(self.ArbeitsschrittTable, 2,0,255,0) # zum setzen der zweiten Spalte der Arbeitsschrittetabelle auf orange + self.setRowColor(self.ArbeitsschrittTable, 3,0,255,0) # zum setzen der dritten Spalte der Arbeitsschrittetabelle auf weiß + else: # wenn noch nicht alle Bauteile des Auftrags auf der Waage liegen, soll folgernder Code ausgeführt werden + self.setRowColor(self.ArbeitsschrittTable, 1,255,165,0) # zum setzen der zweiten Spalte der Arbeitsschrittetabelle auf orange + self.setRowColor(self.ArbeitsschrittTable, 2,255,255,255) # zum setzen der dritten Spalte der Arbeitsschrittetabelle auf weiß + if self.checkBoxAutoTare.isChecked(): + self.onTareClick() + + # den Thread beenden + self.checkWaageThread.quit() + self.checkWaageThread.wait() + + # auch wenn die Länge der Liste überschritten wurde + # wenn der statische Workflow aktiviert ist, dann soll die checkwaage-funktion erneut aufgerufen werden + if(self.checkBox.isChecked() == True): + self.checkWaage() + + # GUI updaten + #self.updateGUI() + + def objectTypeDetection(self): + # in dieser Funktion wird der Typ des Bauteils automatisch erkannt + + # wenn der statische Workflow ausgewählt wurde, dann soll die checkWaage Funktion aufgerufen werden, auch wenn die detectBauteiltyp-Funkion aufgerufen wurde + if self.checkBox.isChecked() == True: + self.checkWaage() + return + + ''' + if(self.checkPosNrEmpty()==True): + print("Das Pos.-Nr.-Feld ist leer.") + return + ''' + + # die Loopvariable des Workers auf False setzten, damit die Schleife durchgelaufen wird (diese wird zum Abbruch der Schleife benötigt -> siehe stopLoop) + #self.objectDetectionWorker.stopLoopSignal.emit(False) + + # überprüfen, ob der Auftrag in die Tabelle geladen wurde + if(self.AuftragsdetailsTable.item(0,0) == None): + print("Der Auftrag muss zuerst geladen werden.") + return + + # speichert den Wert, welcher im Textfeld steht in Variablen im Code + self.setAuftragsnummer() + + # starten des Threats, welcher den Bauteiltyp zurück gibt + self.objectDetectionWorker = Worker() + self.objectDetectionThread = QThread() + + self.objectDetectionWorker.moveToThread(self.objectDetectionThread) + + self.objectDetectionWorker.objectDetectionStartSignal.connect(self.objectDetectionWorker.objectTypeDetectionThread) + self.objectDetectionWorker.objectDetectionFinishedSignal.connect(self.objectTypeDetectionFinished) + self.objectDetectionWorker.waageStoppedSignal.connect(self.threadStopped) + self.objectDetectionWorker.stopLoopSignal.connect(lambda status: setattr(self.objectDetectionWorker, 'stopLoop', status)) #wird fürs aktive Stoppen des Threads benötigt + + self.objectDetectionThread.started.connect(lambda: self.objectDetectionWorker.objectDetectionStartSignal.emit(self.auftragsnummer)) + self.objectDetectionThread.start() + + def objectTypeDetectionFinished(self, einzelteilID, rowData): + # wenn der Typ des Objektes erkannt wurde, dann soll die Funktion aufgerufen werden + + # Schreiben der Bauteiltype und Pos.-Nr in die jeweiligen Felder + self.PosNrTxtFeld.setText(str(rowData[1])) + self.bauteiltypTextbox.setText(rowData[2]) + + # setzt den Boolean, um aus der Schleife raus zu gehen + self.btTypeIsSet = True + + #zum setzen den Farbe der gesamten Reihe auf Orange + self.setRowColor(self.AuftragsdetailsTable, self.getRowNr(einzelteilID),255,165,0) + + # den Thread beenden + self.objectDetectionThread.quit() + self.objectDetectionThread.wait() + + ''' + try: + self.objectDetectionThread.started.disconnect() # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt + except: + print(f"Error while disconnecting: {e}") + print("Disconnecting the thread did not work.") + ''' + + # wenn der Bauteiltyp erkannt wurde, dann soll die GUI aktualisiert werden und anschließend die CheckWaage-Funktion aufgerufen werden + self.updateGUI() + self.checkWaage() + + def threadStopped(self, einzelteilID): + # wenn kein Bauteil erkannt wurde, dann ist die EinzenteilID = 0 + if self.checkFinished() == False: + if(einzelteilID > 0): + self.setRowColor(self.AuftragsdetailsTable, self.getRowNr(einzelteilID),255,255,255) #zum setzen den Farbe der gesamten Reihe auf Weiß + self.setRowColor(self.ArbeitsschrittTable, 2,255,255,255) + self.setRowColor(self.ArbeitsschrittTable, 1,255,165,0) + + # den Thread beenden + if hasattr(self, 'objectDetectionThread'): + self.objectDetectionThread.quit() + self.objectDetectionThread.wait() + print("Der ObjektDetection-Thread wurde beendet.") + + if hasattr(self, 'checkWaageThread'): + self.checkWaageThread.quit() + self.checkWaageThread.wait() + print("Der CheckWaage-Thread wurde beendet.") + + +# new class for Camera Object detection with YOLOv8 +class CameraStreamApp(QtWidgets.QMainWindow): + def __init__(self, ui): + super().__init__() + self.ui = ui + self.yolo_stream = None # Initialize YOLOv8CameraStream as None + self.timer = QtCore.QTimer(self) + self.timer.timeout.connect(self.update_frame) + self.ui.startCamBtn.clicked.connect(self.start_camera) # start camera if button LoadAuftrag is clicked + self.ui.stopCamBtn.clicked.connect(self.stop_camera) # start camera if button LoadAuftrag is clicked + self.scene = QtWidgets.QGraphicsScene(self) + self.ui.graphicsView.setScene(self.scene) + + def start_camera(self): + # Start the YOLOv8 camera stream (only if not already started) + if self.yolo_stream is None: + self.yolo_stream = YOLOv8CameraStream(model_path="models/yolov8m_seg_e300.pt", logging_level="high") + # self.yolo_stream.start() # Start the YOLOv8 stream + self.timer.start(30) # Start the timer to update the frame every 30ms (about 33 FPS) + + def stop_camera(self): + # Stop the camera stream and processing + if self.yolo_stream is not None: + self.timer.stop() # Stop the timer + self.yolo_stream.cap.release() # Release the camera resource + self.yolo_stream = None # Reset the YOLOv8 stream object + self.scene.clear() # Clear the displayed frame from the graphicsView + print("Camera stream stopped and resources released.") + + def update_frame(self): + # Update the frame from YOLOv8 stream + if self.yolo_stream: + ret, frame = self.yolo_stream.cap.read() # Capture frame from YOLOv8 stream + + if ret: + # new part including processing via yolo model + processed_frame = self.yolo_stream.process_frame(frame) + + # Convert the frame from BGR (OpenCV format) to RGB + # frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + frame = cv2.cvtColor(processed_frame, cv2.COLOR_BGR2RGB) # might change nomenclature later? + + # Convert the frame to QImage + h, w, ch = frame.shape + bytes_per_line = ch * w + qt_image = QtGui.QImage(frame.data, w, h, bytes_per_line, QtGui.QImage.Format_RGB888) + + # Add the QImage to a QPixmap + pixmap = QtGui.QPixmap.fromImage(qt_image) + + # Get the size of the graphicsView and scale the pixmap to fit + view_size = self.ui.graphicsView.size() + scaled_pixmap = pixmap.scaled(view_size, QtCore.Qt.KeepAspectRatio) + + # Update the scene with the scaled pixmap + self.scene.clear() + self.scene.addPixmap(scaled_pixmap) + + def closeEvent(self, event): + # Release the camera when the application is closed + if self.yolo_stream is not None: + self.yolo_stream.cap.release() + event.accept() + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + MainWindow = QtWidgets.QMainWindow() + ui = Ui_MainWindow() + ui.setupUi(MainWindow) + + # Initialize the CameraStreamApp with the UI + camera_app = CameraStreamApp(ui) + + MainWindow.show() + sys.exit(app.exec_()) \ No newline at end of file diff --git a/bjoerntest9.py b/bjoerntest9.py index c3fbc1a..3fb7269 100644 --- a/bjoerntest9.py +++ b/bjoerntest9.py @@ -49,7 +49,7 @@ try: print("Serial port connected successfully.") except serial.SerialException: ser = None - print("Warning: Serial port not found. Continuing without serial connection.") + print("Warning: Serial port not found. Continuing without serial connection. Only working for demo-purposes.") waageEingeschwungen = False diff --git a/detections.log b/detections.log index 1805ad0..0b3c35c 100644 --- a/detections.log +++ b/detections.log @@ -125,3 +125,49 @@ 2024-10-28 08:16:31 - Detected: hand with confidence 0.90 2024-10-28 09:00:57 - Detected: hand with confidence 0.92 2024-10-28 09:00:58 - Detected: hand with confidence 0.91 +2024-10-28 09:50:16 - Detected: oring_d300_b with confidence 0.96 +2024-10-28 09:50:23 - Detected: hand with confidence 0.92 +2024-10-28 09:50:23 - Detected: hand with confidence 0.91 +2024-10-28 09:50:23 - Detected: hand with confidence 0.93 +2024-10-28 09:50:24 - Detected: hand with confidence 0.92 +2024-10-28 09:50:24 - Detected: hand with confidence 0.92 +2024-10-28 09:50:24 - Detected: hand with confidence 0.92 +2024-10-28 09:50:24 - Detected: hand with confidence 0.96 +2024-10-28 09:50:24 - Detected: hand with confidence 0.94 +2024-10-28 09:50:24 - Detected: hand with confidence 0.95 +2024-10-28 09:50:24 - Detected: hand with confidence 0.93 +2024-10-28 09:50:24 - Detected: hand with confidence 0.94 +2024-10-28 09:50:24 - Detected: hand with confidence 0.92 +2024-10-28 09:50:25 - Detected: hand with confidence 0.92 +2024-10-28 09:50:26 - Detected: hand with confidence 0.93 +2024-10-28 09:50:26 - Detected: hand with confidence 0.92 +2024-10-28 09:50:27 - Detected: hand with confidence 0.93 +2024-10-28 09:50:27 - Detected: hand with confidence 0.97 +2024-10-28 09:50:27 - Detected: hand with confidence 0.96 +2024-10-28 09:50:27 - Detected: hand with confidence 0.93 +2024-10-28 09:50:27 - Detected: hand with confidence 0.90 +2024-10-28 09:50:28 - Detected: hand with confidence 0.94 +2024-10-28 09:50:28 - Detected: hand with confidence 0.95 +2024-10-28 09:50:28 - Detected: hand with confidence 0.91 +2024-10-28 09:50:28 - Detected: hand with confidence 0.92 +2024-10-28 09:50:28 - Detected: hand with confidence 0.92 +2024-10-28 09:50:28 - Detected: hand with confidence 0.90 +2024-10-28 09:50:29 - Detected: hand with confidence 0.91 +2024-10-28 09:50:29 - Detected: hand with confidence 0.90 +2024-10-28 09:50:29 - Detected: hand with confidence 0.93 +2024-10-28 09:50:29 - Detected: hand with confidence 0.92 +2024-10-28 09:50:29 - Detected: hand with confidence 0.96 +2024-10-28 09:50:29 - Detected: hand with confidence 0.95 +2024-10-28 09:50:29 - Detected: hand with confidence 0.94 +2024-10-28 09:50:29 - Detected: hand with confidence 0.92 +2024-10-28 09:50:30 - Detected: hand with confidence 0.93 +2024-10-28 09:50:30 - Detected: hand with confidence 0.92 +2024-10-28 09:50:30 - Detected: hand with confidence 0.90 +2024-10-28 09:50:30 - Detected: hand with confidence 0.90 +2024-10-28 09:50:30 - Detected: hand with confidence 0.90 +2024-10-28 09:50:30 - Detected: hand with confidence 0.95 +2024-10-28 09:50:31 - Detected: hand with confidence 0.91 +2024-10-28 09:50:31 - Detected: hand with confidence 0.92 +2024-10-28 09:50:31 - Detected: hand with confidence 0.92 +2024-10-28 09:50:31 - Detected: hand with confidence 0.92 +2024-10-28 09:50:31 - Detected: hand with confidence 0.92 diff --git a/environment.yaml b/environment.yaml new file mode 100644 index 0000000..561c2cc --- /dev/null +++ b/environment.yaml @@ -0,0 +1,15 @@ +name: geislinger +channels: + - conda-forge +dependencies: + - pip=24.2 + - python=3.11 + - ultralytics=8 + - mariadb + - pytorch + - torchvision + - torchaudio + - pytorch-cuda=11.8 + - opencv + - pyqt + - pyserial \ No newline at end of file diff --git a/saved_frames/hand_20241028_095023.jpg b/saved_frames/hand_20241028_095023.jpg new file mode 100644 index 0000000..cd4e74c Binary files /dev/null and b/saved_frames/hand_20241028_095023.jpg differ diff --git a/saved_frames/hand_20241028_095024.jpg b/saved_frames/hand_20241028_095024.jpg new file mode 100644 index 0000000..60b4a13 Binary files /dev/null and b/saved_frames/hand_20241028_095024.jpg differ diff --git a/saved_frames/hand_20241028_095025.jpg b/saved_frames/hand_20241028_095025.jpg new file mode 100644 index 0000000..684fcb4 Binary files /dev/null and b/saved_frames/hand_20241028_095025.jpg differ diff --git a/saved_frames/hand_20241028_095026.jpg b/saved_frames/hand_20241028_095026.jpg new file mode 100644 index 0000000..a549477 Binary files /dev/null and b/saved_frames/hand_20241028_095026.jpg differ diff --git a/saved_frames/hand_20241028_095027.jpg b/saved_frames/hand_20241028_095027.jpg new file mode 100644 index 0000000..9ec6b47 Binary files /dev/null and b/saved_frames/hand_20241028_095027.jpg differ diff --git a/saved_frames/hand_20241028_095028.jpg b/saved_frames/hand_20241028_095028.jpg new file mode 100644 index 0000000..602af33 Binary files /dev/null and b/saved_frames/hand_20241028_095028.jpg differ diff --git a/saved_frames/hand_20241028_095029.jpg b/saved_frames/hand_20241028_095029.jpg new file mode 100644 index 0000000..0f79999 Binary files /dev/null and b/saved_frames/hand_20241028_095029.jpg differ diff --git a/saved_frames/hand_20241028_095030.jpg b/saved_frames/hand_20241028_095030.jpg new file mode 100644 index 0000000..48f8a7d Binary files /dev/null and b/saved_frames/hand_20241028_095030.jpg differ diff --git a/saved_frames/hand_20241028_095031.jpg b/saved_frames/hand_20241028_095031.jpg new file mode 100644 index 0000000..0dfe8b5 Binary files /dev/null and b/saved_frames/hand_20241028_095031.jpg differ diff --git a/saved_frames/oring_d300_b_20241028_095016.jpg b/saved_frames/oring_d300_b_20241028_095016.jpg new file mode 100644 index 0000000..a15991b Binary files /dev/null and b/saved_frames/oring_d300_b_20241028_095016.jpg differ