From b452a3df741ccb3e8ffc6fe7d86a898015c61e5f Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 2 Dec 2024 08:17:02 +0100 Subject: [PATCH] update: delete unnecessary files --- workflow.py | 310 +++++----------- workflow2.py | 1012 -------------------------------------------------- workflow3.py | 991 ------------------------------------------------ 3 files changed, 84 insertions(+), 2229 deletions(-) delete mode 100644 workflow2.py delete mode 100644 workflow3.py diff --git a/workflow.py b/workflow.py index 23a87c4..13e21ac 100644 --- a/workflow.py +++ b/workflow.py @@ -1,14 +1,3 @@ -# -*- 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 @@ -31,6 +20,12 @@ import os import lib.sainsmartrelay as sainsmartrelay import lib.wledControl as wledControl + +# ## in der Ui_MainWindow-Klasse wird die GUI erstellt - der MainThread läuft in dieser -> Farben Drop Down + + +# ## Aufsetzen der Datenbank und Waagenverbindung +# # Definieren der Datenbankverbindung db_config = { 'user': 'dbUser', 'password': 'dbPassword', @@ -39,11 +34,24 @@ db_config = { 'port': 3306 # Standard port for MariaDB } +# # Establishing the connection +# conn = mariadb.connect(**db_config) +# # Create a cursor to execute queries +# cursor = conn.cursor() + +try: + # Attempt to establish the connection + conn = mariadb.connect(**db_config) + print("Database connection established successfully.") + + # Create a cursor to execute queries + cursor = conn.cursor() +except mariadb.Error as e: + # Handle connection errors + print(f"Error connecting to the database: {e}") + conn = None + cursor = None -# Establishing the connection -conn = mariadb.connect(**db_config) -# Create a cursor to execute queries -cursor = conn.cursor() # Configuration of the serial port try: @@ -52,34 +60,8 @@ try: 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/ -# addition: now 2 ESP32 are used: 1 for reading the scale and 1 for controlling the led light. Problem is they both use the same id so -# physical port is selected instead. - -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): +# die Workerklasse ist dazu da die Schleifen - in welchen der Bauteiltyp erkannt wird und die Anzahl der Bauteile, welche auf der Waage liegen - in einem seperaten Thread auszuführen, um ein Blockieren des Mainthreads zu verhindern class Worker(QObject): #progress = pyqtSignal(int) objectDetectionStartSignal = pyqtSignal(str) @@ -92,6 +74,7 @@ class Worker(QObject): waageStoppedSignal = pyqtSignal(int) stopLoopSignal = pyqtSignal(bool) #das Signal wird verwendet um direkt den stopLoop-Wert zu ändern (also kein Funktionsaufruf) + waageEingeschwungen = False stopLoop = False btTypeIsSet = False correctBtNr = False @@ -103,7 +86,7 @@ class Worker(QObject): 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 + ''' 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 @@ -113,26 +96,27 @@ class Worker(QObject): def waageNichtEingeschwungenOutput(self): print("Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft.") + def wahrscheinlichkeitsDichte(self, 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 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 - + ''' in folgender Funktion wird die Waage ausgelesen ''' 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") @@ -144,17 +128,13 @@ class Worker(QObject): 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 + ''' in dieser Funktion wird der Typ des Bauteils automatisch erkannt ''' # Parameterdefinition propDensVect = [] @@ -174,16 +154,9 @@ class Worker(QObject): 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]]) + propDensVect.append([self.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 @@ -201,14 +174,6 @@ class Worker(QObject): 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 @@ -219,7 +184,8 @@ class Worker(QObject): self.waageStoppedSignal.emit(einzelteilID) def checkWaageThread(self, einzelteilID, teileZuViel, auftragsnummer): - + ''' in dieser Funktion wird die Stückzahl der Bauteile, welche auf der Waage liegen, berechnet ''' + self.correctBtNr = False prevAnzahl = 0 anzahl = 0 @@ -237,14 +203,6 @@ class Worker(QObject): 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 @@ -267,7 +225,7 @@ class Worker(QObject): # 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]) + propDensVect.append([self.wahrscheinlichkeitsDichte(float(intString),mueGes, varGes), i]) # durch den propDensVect iterieren und jenen Eintrag mit der höchsten Wahrscheinlichkeitsdichte raussuchen maxpropDens = 0 @@ -280,14 +238,6 @@ class Worker(QObject): 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 @@ -307,8 +257,7 @@ class Worker(QObject): self.waageStoppedSignal.emit(einzelteilID) - - +## in der Ui_MainWindow-Klasse wird die GUI erstellt - der MainThread läuft in dieser class Ui_MainWindow(object): def setupUi(self, MainWindow): self.auftragsnummer = "" @@ -316,7 +265,6 @@ class Ui_MainWindow(object): self.correctBtNr = False self.btTypeIsSet = False - MainWindow.setObjectName("MainWindow") MainWindow.resize(1400, 675) self.centralwidget = QtWidgets.QWidget(MainWindow) @@ -476,16 +424,6 @@ class Ui_MainWindow(object): self.blinkLightBtn = QtWidgets.QPushButton(self.centralwidget) self.blinkLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+300, 161, 25)) - #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() @@ -520,8 +458,6 @@ class Ui_MainWindow(object): 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) @@ -539,19 +475,10 @@ class Ui_MainWindow(object): 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:")) @@ -573,10 +500,8 @@ class Ui_MainWindow(object): # 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) self.modelComboBox # relay control buttons @@ -588,23 +513,20 @@ class Ui_MainWindow(object): self.yellowLightBtn.setText(_translate("MainWindow", "Turn on yellow LED")) self.greenLightBtn.setText(_translate("MainWindow", "Turn on green LED")) self.offLightBtn.setText(_translate("MainWindow", "Turn off all LEDs")) - self.blinkLightBtn.setText(_translate("MainWindow", "Blink last LED")) - + self.blinkLightBtn.setText(_translate("MainWindow", "Blink Yellow LED")) def mousePressEvent(self, event): print("Das MainWindow wurde angeklickt.") self.setFocus() super().mousePressEvent(event) - def onTareClick(self): - #Tarieren der Waage + ''' 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") @@ -621,9 +543,6 @@ class Ui_MainWindow(object): 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()) @@ -647,72 +566,22 @@ class Ui_MainWindow(object): 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 + # # call change led color + # Check if the 'w' object already exists + # hier könnte noch nachgearbeitet werden + if not hasattr(self, 'w'): + w = wledControl.WLEDController(port="/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:1:1.0-port0") + w.connect() + w.map_color_to_led([r,g,b]) def auftragsBtnClicked(self): databaseQueryWorking = False #wird für die Überprüfung, ob die Datenbankabfrage fehlerhaft ist, verwendet @@ -731,16 +600,7 @@ class Ui_MainWindow(object): 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)) @@ -787,7 +647,6 @@ class Ui_MainWindow(object): 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.") @@ -800,7 +659,7 @@ class Ui_MainWindow(object): 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 + ''' 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) @@ -808,20 +667,15 @@ class Ui_MainWindow(object): 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 + ''' 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.") @@ -910,22 +764,13 @@ class Ui_MainWindow(object): #self.updateGUI() def objectTypeDetection(self): - # in dieser Funktion wird der Typ des Bauteils automatisch erkannt + ''' 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.") @@ -949,7 +794,7 @@ class Ui_MainWindow(object): self.objectDetectionThread.start() def objectTypeDetectionFinished(self, einzelteilID, rowData): - # wenn der Typ des Objektes erkannt wurde, dann soll die Funktion aufgerufen werden + ''' 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])) @@ -965,20 +810,12 @@ class Ui_MainWindow(object): 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 + ''' 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ß @@ -996,7 +833,6 @@ class Ui_MainWindow(object): 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): @@ -1048,7 +884,7 @@ class CameraStreamApp(QtWidgets.QMainWindow): # 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? + frame = cv2.cvtColor(processed_frame, cv2.COLOR_BGR2RGB) # Convert the frame to QImage h, w, ch = frame.shape @@ -1078,17 +914,31 @@ class LightControl(QtWidgets.QMainWindow): super().__init__() self.ui = ui + # init relay control self.ui.startSpotlightBtn.clicked.connect(self.spot_on) self.ui.stopSpotlightBtn.clicked.connect(self.spot_off) self.r = sainsmartrelay.SainsmartRelay() - + + # init led control self.ui.redLightBtn.clicked.connect(self.red_on) self.ui.yellowLightBtn.clicked.connect(self.yellow_on) self.ui.greenLightBtn.clicked.connect(self.green_on) self.ui.offLightBtn.clicked.connect(self.leds_off) - self.ui.blinkLightBtn.clicked.connect(self.leds_blink) + self.ui.blinkLightBtn.clicked.connect(self.blink_yellow) self.w = wledControl.WLEDController(port="/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:1:1.0-port0") + self.w.connect() + #self.w.switch_to_green() # at appstart the light is green + self.w.blink_green() # and switches to green blinking until the workflow gets started successfully# + # Connect app exit signal to the cleanup method + app.aboutToQuit.connect(self.cleanup) + + def cleanup(self): + """Clean up resources and switch off LEDs.""" + print("Cleaning up resources and switching off LEDs") + self.leds_off() # Turn off LEDs + self.w.disconnect() # Disconnect WLED controller + def spot_on(self): print("Turn on light clicked") self.r.turn_on(1) @@ -1113,9 +963,17 @@ class LightControl(QtWidgets.QMainWindow): print("LEDs are off") self.w.turn_off_all() - def leds_blink(self): - print("Previous color is blinking") - self.w.change_effect() + def blink_yellow(self): + print("Yellow color is blinking") + self.w.blink_yellow() + + def blink_red(self): + print("Red color is blinking") + self.w.blink_red() + + def blink_green(self): + print("Green color is blinking") + self.w.blink_green() if __name__ == "__main__": import sys diff --git a/workflow2.py b/workflow2.py deleted file mode 100644 index 8b73f61..0000000 --- a/workflow2.py +++ /dev/null @@ -1,1012 +0,0 @@ - -#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 lib.CameraStream import YOLOv8CameraStream # Import the YOLOv8CameraStream class -import cv2 - -import os - -import lib.sainsmartrelay as sainsmartrelay -import lib.wledControl as wledControl - - -# ## in der Ui_MainWindow-Klasse wird die GUI erstellt - der MainThread läuft in dieser -> Farben Drop Down - - -# ## Aufsetzen der Datenbank und Waagenverbindung -# # Definieren der Datenbankverbindung -db_config = { - 'user': 'dbUser', - 'password': 'dbPassword', - 'host': '127.0.0.1', # 'host': 'localhost', changed because more compatible - '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() - -try: - # Attempt to establish the connection - conn = mariadb.connect(**db_config) - print("Database connection established successfully.") - - # Create a cursor to execute queries - cursor = conn.cursor() -except mariadb.Error as e: - # Handle connection errors - print(f"Error connecting to the database: {e}") - conn = None - cursor = None - - -# Configuration of the serial port -try: - ser = serial.Serial('/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:3:1.0-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.") - - -# die Workerklasse ist dazu da die Schleifen - in welchen der Bauteiltyp erkannt wird und die Anzahl der Bauteile, welche auf der Waage liegen - in einem seperaten Thread auszuführen, um ein Blockieren des Mainthreads zu verhindern -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) - - waageEingeschwungen = False - 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 wahrscheinlichkeitsDichte(self, 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 readWaage(self): - ''' in folgender Funktion wird die Waage ausgelesen ''' - - if ser.is_open == False: - ser.open() - - #an die Waage den Befehl senden, dass sie ausgelesen werden soll - ser.write(b'getWeight\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": - 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") - - ser.close() - - return waageEingeschwungen, intString - - def objectTypeDetectionThread(self, auftragsnummer): - ''' in dieser Funktion wird der Typ des Bauteils automatisch erkannt ''' - - # 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() - - # in der Folge werden alle Wahrscheinlichkeitsdichten der Auftragsbauteile berechnet und in dem Vektor gesammelt - for row in auftragEinzelteilDaten: - propDensVect.append([self.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.") - - # 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): - ''' in dieser Funktion wird die Stückzahl der Bauteile, welche auf der Waage liegen, berechnet ''' - - 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() - - #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([self.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 - - # 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) - - -## in der Ui_MainWindow-Klasse wird die GUI erstellt - der MainThread läuft in dieser -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.camWorkFlowcheckBox = QtWidgets.QCheckBox(self.centralwidget) - self.camWorkFlowcheckBox.setGeometry(QtCore.QRect(700, int(1080/2), 151, 23)) - self.camWorkFlowcheckBox.setObjectName("camWorkFlowcheckBox") - self.modelComboBox = QtWidgets.QComboBox(self.centralwidget) - self.modelComboBox.setGeometry(QtCore.QRect(700, int(1080/2)+50, 161, 25)) - self.modelComboBox.setObjectName("modelComboBox") - self.startCamBtn = QtWidgets.QPushButton(self.centralwidget) - self.startCamBtn.setGeometry(QtCore.QRect(700, int(1080/2)+100, 161, 25)) #int(1080/2)+100 - self.startCamBtn.setObjectName("startCamBtn") - self.stopCamBtn = QtWidgets.QPushButton(self.centralwidget) - self.stopCamBtn.setGeometry(QtCore.QRect(700, int(1080/2)+150, 161, 25)) - self.stopCamBtn.setObjectName("stopCamBtn") - self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget) - self.graphicsView.setGeometry(QtCore.QRect(10, int(1080/2), 661, int(480*1.05))) # position and size of camera frame # int(640*1.05) - self.graphicsView.setObjectName("graphicsView") - - # relay control buttons - self.startSpotlightBtn = QtWidgets.QPushButton(self.centralwidget) - self.startSpotlightBtn.setGeometry(QtCore.QRect(700+200, int(1080/2)+100, 161, 25)) #int(1080/2)+100 - self.startSpotlightBtn.setObjectName("startSpotlightBtn") - self.stopSpotlightBtn = QtWidgets.QPushButton(self.centralwidget) - self.stopSpotlightBtn.setGeometry(QtCore.QRect(700+200, int(1080/2)+150, 161, 25)) - self.stopSpotlightBtn.setObjectName("stopSpotlightBtn") - - # led control buttons - self.redLightBtn = QtWidgets.QPushButton(self.centralwidget) - self.redLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+100, 161, 25)) - self.yellowLightBtn = QtWidgets.QPushButton(self.centralwidget) - self.yellowLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+150, 161, 25)) - self.greenLightBtn = QtWidgets.QPushButton(self.centralwidget) - self.greenLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+200, 161, 25)) - self.offLightBtn = QtWidgets.QPushButton(self.centralwidget) - self.offLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+250, 161, 25)) - self.blinkLightBtn = QtWidgets.QPushButton(self.centralwidget) - self.blinkLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+300, 161, 25)) - - # 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:")) - - # 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.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.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.stopCamBtn.setText(_translate("MainWindow", "Stop Camera")) - self.camWorkFlowcheckBox.setText(_translate("MainWindow", "Camera Workflow")) - self.modelComboBox - - # relay control buttons - self.startSpotlightBtn.setText(_translate("MainWindow", "Turn on light")) - self.stopSpotlightBtn.setText(_translate("MainWindow", "Turn off light")) - - # led control buttons - self.redLightBtn.setText(_translate("MainWindow", "Turn on red LED")) - self.yellowLightBtn.setText(_translate("MainWindow", "Turn on yellow LED")) - self.greenLightBtn.setText(_translate("MainWindow", "Turn on green LED")) - self.offLightBtn.setText(_translate("MainWindow", "Turn off all LEDs")) - self.blinkLightBtn.setText(_translate("MainWindow", "Blink Yellow LED")) - - 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 - - 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 - - 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)) - - # # call change led color - # later_instance = light_app_reference() - # later_instance.map_color_to_led(r,g,b) - - 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: - - ### 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): - QApplication.processEvents() - - # ü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 - - # ü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() - - # 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) - - # Populate the model dropdown menu - self.populate_model_dropdown() - - 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 populate_model_dropdown(self): - """Populate the dropdown menu with model files from the models directory.""" - models_dir = "models" - model_files = [f for f in os.listdir(models_dir) if f.endswith(".pt")] - self.ui.modelComboBox.clear() - self.ui.modelComboBox.addItems(model_files) - - 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) - - # 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() - -# new class for light control -class LightControl(QtWidgets.QMainWindow): - def __init__(self, ui): - super().__init__() - self.ui = ui - - # init relay control - self.ui.startSpotlightBtn.clicked.connect(self.spot_on) - self.ui.stopSpotlightBtn.clicked.connect(self.spot_off) - self.r = sainsmartrelay.SainsmartRelay() - - # init led control - self.ui.redLightBtn.clicked.connect(self.red_on) - self.ui.yellowLightBtn.clicked.connect(self.yellow_on) - self.ui.greenLightBtn.clicked.connect(self.green_on) - self.ui.offLightBtn.clicked.connect(self.leds_off) - self.ui.blinkLightBtn.clicked.connect(self.blink_yellow) - self.w = wledControl.WLEDController(port="/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:1:1.0-port0") - self.w.connect() - #self.w.switch_to_green() # at appstart the light is green - self.w.blink_green() # and switches to green blinking until the workflow gets started successfully# - - # Connect app exit signal to the cleanup method - app.aboutToQuit.connect(self.cleanup) - - def cleanup(self): - """Clean up resources and switch off LEDs.""" - print("Cleaning up resources and switching off LEDs") - self.leds_off() # Turn off LEDs - self.w.disconnect() # Disconnect WLED controller - - def map_color(self, color): - """ - Map an RGB color to the corresponding WLED action based on predefined ranges. - - :param color: A tuple of (R, G, B) values, where each component is an integer between 0 and 255. - """ - red, green, blue = color - - # Check if the color is red (high R, low G and B) - if red > 200 and green < 100 and blue < 100: - self.switch_to_red() - - # Check if the color is green (high G, low R and B) - elif red < 100 and green > 200 and blue < 100: - self.switch_to_green() - - # Check if the color is yellow (high R and G, low B) - elif red > 200 and green > 200 and blue < 100: - self.switch_to_yellow() - - # If none of the above, turn off the LEDs - else: - self.turn_off_all() - - def spot_on(self): - print("Turn on light clicked") - self.r.turn_on(1) - - def spot_off(self): - print("Turn off light clicked") - self.r.turn_off(1) - - def red_on(self): - print("Red light is on") - self.w.switch_to_red() - - def yellow_on(self): - print("Yellow light is on") - self.w.switch_to_yellow() - - def green_on(self): - print("Green light is on") - self.w.switch_to_green() - - def leds_off(self): - print("LEDs are off") - self.w.turn_off_all() - - def blink_yellow(self): - print("Yellow color is blinking") - self.w.blink_yellow() - - def blink_red(self): - print("Red color is blinking") - self.w.blink_red() - - def blink_green(self): - print("Green color is blinking") - self.w.blink_green() - -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) - # initialize light control app - light_app = LightControl(ui) - - MainWindow.show() - sys.exit(app.exec_()) \ No newline at end of file diff --git a/workflow3.py b/workflow3.py deleted file mode 100644 index 13e21ac..0000000 --- a/workflow3.py +++ /dev/null @@ -1,991 +0,0 @@ - -#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 lib.CameraStream import YOLOv8CameraStream # Import the YOLOv8CameraStream class -import cv2 - -import os - -import lib.sainsmartrelay as sainsmartrelay -import lib.wledControl as wledControl - - -# ## in der Ui_MainWindow-Klasse wird die GUI erstellt - der MainThread läuft in dieser -> Farben Drop Down - - -# ## Aufsetzen der Datenbank und Waagenverbindung -# # Definieren der Datenbankverbindung -db_config = { - 'user': 'dbUser', - 'password': 'dbPassword', - 'host': '127.0.0.1', # 'host': 'localhost', changed because more compatible - '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() - -try: - # Attempt to establish the connection - conn = mariadb.connect(**db_config) - print("Database connection established successfully.") - - # Create a cursor to execute queries - cursor = conn.cursor() -except mariadb.Error as e: - # Handle connection errors - print(f"Error connecting to the database: {e}") - conn = None - cursor = None - - -# Configuration of the serial port -try: - ser = serial.Serial('/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:3:1.0-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.") - -# die Workerklasse ist dazu da die Schleifen - in welchen der Bauteiltyp erkannt wird und die Anzahl der Bauteile, welche auf der Waage liegen - in einem seperaten Thread auszuführen, um ein Blockieren des Mainthreads zu verhindern -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) - - waageEingeschwungen = False - 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 wahrscheinlichkeitsDichte(self, 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 readWaage(self): - ''' in folgender Funktion wird die Waage ausgelesen ''' - - if ser.is_open == False: - ser.open() - - #an die Waage den Befehl senden, dass sie ausgelesen werden soll - ser.write(b'getWeight\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": - 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") - - ser.close() - - return waageEingeschwungen, intString - - def objectTypeDetectionThread(self, auftragsnummer): - ''' in dieser Funktion wird der Typ des Bauteils automatisch erkannt ''' - - # 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() - - # in der Folge werden alle Wahrscheinlichkeitsdichten der Auftragsbauteile berechnet und in dem Vektor gesammelt - for row in auftragEinzelteilDaten: - propDensVect.append([self.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.") - - # 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): - ''' in dieser Funktion wird die Stückzahl der Bauteile, welche auf der Waage liegen, berechnet ''' - - 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() - - #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([self.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 - - # 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) - - -## in der Ui_MainWindow-Klasse wird die GUI erstellt - der MainThread läuft in dieser -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.camWorkFlowcheckBox = QtWidgets.QCheckBox(self.centralwidget) - self.camWorkFlowcheckBox.setGeometry(QtCore.QRect(700, int(1080/2), 151, 23)) - self.camWorkFlowcheckBox.setObjectName("camWorkFlowcheckBox") - self.modelComboBox = QtWidgets.QComboBox(self.centralwidget) - self.modelComboBox.setGeometry(QtCore.QRect(700, int(1080/2)+50, 161, 25)) - self.modelComboBox.setObjectName("modelComboBox") - self.startCamBtn = QtWidgets.QPushButton(self.centralwidget) - self.startCamBtn.setGeometry(QtCore.QRect(700, int(1080/2)+100, 161, 25)) #int(1080/2)+100 - self.startCamBtn.setObjectName("startCamBtn") - self.stopCamBtn = QtWidgets.QPushButton(self.centralwidget) - self.stopCamBtn.setGeometry(QtCore.QRect(700, int(1080/2)+150, 161, 25)) - self.stopCamBtn.setObjectName("stopCamBtn") - self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget) - self.graphicsView.setGeometry(QtCore.QRect(10, int(1080/2), 661, int(480*1.05))) # position and size of camera frame # int(640*1.05) - self.graphicsView.setObjectName("graphicsView") - - # relay control buttons - self.startSpotlightBtn = QtWidgets.QPushButton(self.centralwidget) - self.startSpotlightBtn.setGeometry(QtCore.QRect(700+200, int(1080/2)+100, 161, 25)) #int(1080/2)+100 - self.startSpotlightBtn.setObjectName("startSpotlightBtn") - self.stopSpotlightBtn = QtWidgets.QPushButton(self.centralwidget) - self.stopSpotlightBtn.setGeometry(QtCore.QRect(700+200, int(1080/2)+150, 161, 25)) - self.stopSpotlightBtn.setObjectName("stopSpotlightBtn") - - # led control buttons - self.redLightBtn = QtWidgets.QPushButton(self.centralwidget) - self.redLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+100, 161, 25)) - self.yellowLightBtn = QtWidgets.QPushButton(self.centralwidget) - self.yellowLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+150, 161, 25)) - self.greenLightBtn = QtWidgets.QPushButton(self.centralwidget) - self.greenLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+200, 161, 25)) - self.offLightBtn = QtWidgets.QPushButton(self.centralwidget) - self.offLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+250, 161, 25)) - self.blinkLightBtn = QtWidgets.QPushButton(self.centralwidget) - self.blinkLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+300, 161, 25)) - - # 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:")) - - # 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.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.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.stopCamBtn.setText(_translate("MainWindow", "Stop Camera")) - self.camWorkFlowcheckBox.setText(_translate("MainWindow", "Camera Workflow")) - self.modelComboBox - - # relay control buttons - self.startSpotlightBtn.setText(_translate("MainWindow", "Turn on light")) - self.stopSpotlightBtn.setText(_translate("MainWindow", "Turn off light")) - - # led control buttons - self.redLightBtn.setText(_translate("MainWindow", "Turn on red LED")) - self.yellowLightBtn.setText(_translate("MainWindow", "Turn on yellow LED")) - self.greenLightBtn.setText(_translate("MainWindow", "Turn on green LED")) - self.offLightBtn.setText(_translate("MainWindow", "Turn off all LEDs")) - self.blinkLightBtn.setText(_translate("MainWindow", "Blink Yellow LED")) - - 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 - - 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 - - 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)) - - # # call change led color - # Check if the 'w' object already exists - # hier könnte noch nachgearbeitet werden - if not hasattr(self, 'w'): - w = wledControl.WLEDController(port="/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:1:1.0-port0") - w.connect() - w.map_color_to_led([r,g,b]) - - 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: - - ### 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): - QApplication.processEvents() - - # ü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 - - # ü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() - - # 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) - - # Populate the model dropdown menu - self.populate_model_dropdown() - - 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 populate_model_dropdown(self): - """Populate the dropdown menu with model files from the models directory.""" - models_dir = "models" - model_files = [f for f in os.listdir(models_dir) if f.endswith(".pt")] - self.ui.modelComboBox.clear() - self.ui.modelComboBox.addItems(model_files) - - 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) - - # 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() - -# new class for light control -class LightControl(QtWidgets.QMainWindow): - def __init__(self, ui): - super().__init__() - self.ui = ui - - # init relay control - self.ui.startSpotlightBtn.clicked.connect(self.spot_on) - self.ui.stopSpotlightBtn.clicked.connect(self.spot_off) - self.r = sainsmartrelay.SainsmartRelay() - - # init led control - self.ui.redLightBtn.clicked.connect(self.red_on) - self.ui.yellowLightBtn.clicked.connect(self.yellow_on) - self.ui.greenLightBtn.clicked.connect(self.green_on) - self.ui.offLightBtn.clicked.connect(self.leds_off) - self.ui.blinkLightBtn.clicked.connect(self.blink_yellow) - self.w = wledControl.WLEDController(port="/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:1:1.0-port0") - self.w.connect() - #self.w.switch_to_green() # at appstart the light is green - self.w.blink_green() # and switches to green blinking until the workflow gets started successfully# - - # Connect app exit signal to the cleanup method - app.aboutToQuit.connect(self.cleanup) - - def cleanup(self): - """Clean up resources and switch off LEDs.""" - print("Cleaning up resources and switching off LEDs") - self.leds_off() # Turn off LEDs - self.w.disconnect() # Disconnect WLED controller - - def spot_on(self): - print("Turn on light clicked") - self.r.turn_on(1) - - def spot_off(self): - print("Turn off light clicked") - self.r.turn_off(1) - - def red_on(self): - print("Red light is on") - self.w.switch_to_red() - - def yellow_on(self): - print("Yellow light is on") - self.w.switch_to_yellow() - - def green_on(self): - print("Green light is on") - self.w.switch_to_green() - - def leds_off(self): - print("LEDs are off") - self.w.turn_off_all() - - def blink_yellow(self): - print("Yellow color is blinking") - self.w.blink_yellow() - - def blink_red(self): - print("Red color is blinking") - self.w.blink_red() - - def blink_green(self): - print("Green color is blinking") - self.w.blink_green() - -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) - # initialize light control app - light_app = LightControl(ui) - - MainWindow.show() - sys.exit(app.exec_()) \ No newline at end of file