2024-10-28 08:05:03 +00:00
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'test.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
########## beim Static workflow funktionieren die Threads ab dem zweiten nicht mehr
#from PyQt5 import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QProgressBar
from PyQt5 import QtCore , QtGui , QtWidgets
from PyQt5 . QtWidgets import QApplication , QComboBox
from PyQt5 . QtCore import QTimer , QThread , pyqtSignal , QObject
from PyQt5 . QtGui import QColor
import serial
import binascii
import math
import mariadb
import time
import threading
from CameraStream import YOLOv8CameraStream # Import the YOLOv8CameraStream class
import cv2
db_config = {
' user ' : ' dbUser ' ,
' password ' : ' dbPassword ' ,
' host ' : ' 127.0.0.1 ' , # 'host': 'localhost',
' database ' : ' projectGeislinger ' ,
' port ' : 3306 # Standard port for MariaDB
}
# Establishing the connection
conn = mariadb . connect ( * * db_config )
# Create a cursor to execute queries
cursor = conn . cursor ( )
# # Konfiguration der seriellen Schnittstelle
# ser = serial.Serial('/dev/ttyUSB0', 9600)
# Configuration of the serial port
try :
ser = serial . Serial ( ' /dev/serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0 ' , 9600 )
print ( " Serial port connected successfully. " )
except serial . SerialException :
ser = None
2024-10-28 09:48:00 +00:00
print ( " Warning: Serial port not found. Continuing without serial connection. Only working for demo-purposes. " )
2024-10-28 08:05:03 +00:00
waageEingeschwungen = False
def wahrscheinlichkeitsDichte ( x , mue , var ) :
# in der Funktion wird der Wahrscheinlichkeitsdichtenwert der Variable x für eine bestimmte Normalverteilung berechnet
standardabweichung = var * * 0.5
result = 1 / ( standardabweichung * ( 2 * math . pi ) * * 0.5 ) * math . exp ( - 0.5 * ( ( x - mue ) / standardabweichung ) * * 2 )
return result
def calcWahrscheinlichkeitFromDichte ( x , mue , var ) :
# in der Funktion wird die Wahrscheinlichkeit via der Wahrscheinlichkeitsdichte berechnet, indem das Verhältnis aus der dem Bauteil zugehörigen Wahrscheinlichkeitsdichte zu der maximalen Wahrscheinlichkeitsdichte berechnet wird
p1 = wahrscheinlichkeitsDichte ( x , mue , var )
p_max = wahrscheinlichkeitsDichte ( mue , mue , var )
return p1 / p_max
#class Worker(QThread):
class Worker ( QObject ) :
#progress = pyqtSignal(int)
objectDetectionStartSignal = pyqtSignal ( str )
objectDetectionFinishedSignal = pyqtSignal ( int , object )
checkWaageStartSignal = pyqtSignal ( int , int , str )
checkWaageUpdateSignal = pyqtSignal ( int , int )
checkWaageFinishedSignal = pyqtSignal ( int )
waageStoppedSignal = pyqtSignal ( int )
stopLoopSignal = pyqtSignal ( bool ) #das Signal wird verwendet um direkt den stopLoop-Wert zu ändern (also kein Funktionsaufruf)
stopLoop = False
btTypeIsSet = False
correctBtNr = False
def __init__ ( self ) :
super ( Worker , self ) . __init__ ( )
stopLoop = False
def getDataOfArticleType ( self , allArticles , articleType ) :
# die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück
for i in allArticles :
if i [ 1 ] == articleType :
return i
return - 1
def waageNichtEingeschwungenOutput ( self ) :
print ( " Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft. " )
def readWaage ( self ) :
# in folgender Funktion wird die Waage ausgelesen
#print("connection is open: ", ser.is_open) #Debuggingausgabe
#print("port to which it is connected: ", ser.portstr) #Debuggingausgabe
if ser . is_open == False :
ser . open ( )
#an die Waage den Befehl senden, dass sie ausgelesen werden soll
ser . write ( b ' getWeight \n ' )
#ser.write(b'tare\n')
serialString = ser . readline ( ) . decode ( ' utf-8 ' ) . rstrip ( ) #Auslesen des Serial-Strings/der Messung der Waage
# wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft
lenString = len ( serialString ) - 1
if serialString [ lenString ] == " g " and serialString [ lenString - 1 ] == " k " :
#print("ist eingeschwungen") #Debuggingausgabe
waageEingeschwungen = True
else :
print ( " die Waage ist noch nicht eingeschwungen " )
waageEingeschwungen = False
#aus dem String werden alle Zeichen, welche nicht zur Darstellung der Zahl benötigt werden entfernt
intString = " "
for i in serialString :
if i == " - " or i == " 0 " or i == " . " or i == " 1 " or i == " 2 " or i == " 3 " or i == " 4 " or i == " 5 " or i == " 6 " or i == " 7 " or i == " 8 " or i == " 9 " :
intString = intString + i
print ( " Wert, welcher von der Waage ausgelesen wurde: " + intString + " kg " )
## Waage auslesen - ENDE
ser . close ( )
#print("connection is open: ", ser.is_open) #Debuggingausgabe
return waageEingeschwungen , intString
def objectTypeDetectionThread ( self , auftragsnummer ) :
# in dieser Funktion wird der Typ des Bauteils automatisch erkannt
#print("objectTypeDetectionThread - Running in thread:", threading.current_thread().name) #Debuggausgabe
# Parameterdefinition
propDensVect = [ ]
self . btTypeIsSet = False
while ( self . btTypeIsSet == False and self . stopLoop == False ) :
# Auslesen der Waage
waageEingeschwungen , intString = self . readWaage ( )
if waageEingeschwungen == False :
self . waageNichtEingeschwungenOutput ( )
else :
# Datenbankabfrage
sql_query = " SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer
cursor . execute ( sql_query )
auftragEinzelteilDaten = cursor . fetchall ( )
'''
# Display data #Debugausgabe
print ( " Ausgabe der Auftragsdetails des obigen Auftrags, inklusive Einzelteildetails: " )
for row in auftragEinzelteilDaten :
print ( row )
'''
# in der Folge werden alle Wahrscheinlichkeitsdichten der Auftragsbauteile berechnet und in dem Vektor gesammelt
for row in auftragEinzelteilDaten :
propDensVect . append ( [ wahrscheinlichkeitsDichte ( float ( intString ) , float ( row [ 6 ] ) , float ( row [ 7 ] ) ) , row [ 1 ] , row [ 5 ] ] )
# Jenen Eintrag des propDensVect raussuchen, welcher die größte Wahrscheinlichkeitsdichte beinhaltet
maxpropDens = 0
einzelteilID = 0
rowData = None
for row in propDensVect :
if row [ 0 ] > maxpropDens :
maxpropDens = row [ 0 ]
einzelteilID = row [ 1 ]
rowData = row
# überprüfen, ob das aufliegende Bauteil in der Auftragstabelle vorhanden ist
if ( einzelteilID == 0 ) :
print ( " Es wurde kein Bauteil aus der Auftragsliste (Tabelle) erkannt. " )
else :
print ( " Bei dem Bauteil " , einzelteilID , " wurde die höchste Wahrscheinlichkeitsdichte berechnet. " )
# Wahrscheinlichkeit berechnen, dass das angegebene Bauteil auch wirklich diesem entspricht
prop = 0
for row in auftragEinzelteilDaten :
if row [ 1 ] == einzelteilID :
prop = calcWahrscheinlichkeitFromDichte ( float ( intString ) , float ( row [ 6 ] ) , float ( row [ 7 ] ) )
break
print ( " Die Wahrscheinlichkeit, dass es das Bauteil ist, beträgt: " , prop )
# den Bool auf true setzen, damit die Schleife beendet wird - dieser wird auf True gesetzt, wenn ein Bauteiltyp erkannt wird
self . btTypeIsSet = True
if ( self . stopLoop == False ) :
# ein Signal zurück an den MainThreat senden, mit den Infos/Ergebnissen, der Typenbestimmung
self . objectDetectionFinishedSignal . emit ( einzelteilID , rowData )
else :
self . waageStoppedSignal . emit ( einzelteilID )
def checkWaageThread ( self , einzelteilID , teileZuViel , auftragsnummer ) :
self . correctBtNr = False
prevAnzahl = 0
anzahl = 0
einzelteilID = einzelteilID
while ( self . correctBtNr == False and self . stopLoop == False ) :
#überprüfen, ob die Waage eingeschwungen ist (und damit korrekte Ergebnisse liefert)
waageEingeschwungen , intString = self . readWaage ( )
if waageEingeschwungen == False :
self . waageNichtEingeschwungenOutput ( )
else :
# Datenbankabfrage - holen der Auftrags- und Bauteilinfos
sql_query = " SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer
cursor . execute ( sql_query )
auftragDaten = cursor . fetchall ( )
'''
# Display data - zum Debuggen
print ( " Ausgabe der Auftragsdetails: " )
print ( " id|EinzelteilID|Auftragsnummer|Anzahl " )
for row in auftragDaten :
print ( row )
'''
#auslesen, wie viele Bauteile des Types laut Auftrag vorhanden sein sollen
anzBauteile_soll = 0
idVorhanden = False
for row in auftragDaten :
if row [ 1 ] == einzelteilID :
anzBauteile_soll = row [ 3 ]
idVorhanden = True
if ( idVorhanden == False ) :
print ( " Die gewählte Pos.Nr ist nicht in der Auftragsliste (Tabelle) vorhanden. " )
return
# Berechnen der Wahrscheinlichkeitsdichten - der Betrag aller Wahrscheinlichkeitsdichten werden im propDensVect gespeichert
propDensVect = [ ]
articleData = self . getDataOfArticleType ( auftragDaten , einzelteilID )
for i in range ( 1 , anzBauteile_soll + teileZuViel + 1 ) :
# Mathematische Sätze, auf welchen die Berechnung basiert:
# seien X1,..., Xn unabhängige Zufallsvariablen die N(mue_i, sigma_i^2) verteilt sind, dann ist X = X1+...+Xn - N(mue, sigma^2) verteilt mit mue=mue1+...+mue_n, sigma^2 = sigma_1^2+...+sigma_n^2
mueGes = float ( articleData [ 6 ] ) * i # Berechnen des äquivalenten Mittelwert
varGes = float ( articleData [ 7 ] ) * i # Berechnen der äquivalenten Varianz
propDensVect . append ( [ wahrscheinlichkeitsDichte ( float ( intString ) , mueGes , varGes ) , i ] )
# durch den propDensVect iterieren und jenen Eintrag mit der höchsten Wahrscheinlichkeitsdichte raussuchen
maxpropDens = 0
for row in propDensVect :
if row [ 0 ] > maxpropDens :
maxpropDens = row [ 0 ]
anzahl = row [ 1 ]
# damit nur etwas gemacht wird (zb ein Updatesignal an den Hauptthread zurücksenden), wenn sich die berechnete Anzahl ändert
if prevAnzahl != anzahl :
prevAnzahl = anzahl
# Die Wahrscheinlichkeit berechnen, dass das obige Ergebnis auch dem Bauteil entspricht
if anzahl > 0 :
for row in auftragDaten :
if row [ 1 ] == einzelteilID :
prop = calcWahrscheinlichkeitFromDichte ( float ( intString ) , float ( row [ 6 ] ) * anzahl , float ( row [ 7 ] ) * anzahl )
break
print ( " Die Wahrscheinlichkeit, dass es das Bauteil ist, beträgt: " , prop )
# wenn genug Bauteile vorhanden sind, dann soll die Schleife beendet werden
if ( anzahl == anzBauteile_soll ) :
self . correctBtNr = True
# Konsolenausgabe
if maxpropDens > 0 :
print ( " Bei der Anzahl " , anzahl , " des Bauteiltypes " , einzelteilID , " ,wurde die höchste Wahrscheinlichkeitsdichte berechnet. " )
self . checkWaageUpdateSignal . emit ( einzelteilID , anzahl )
else :
print ( " Von der ausgewählten Bauteiltype liegt die berechnete Wahrscheinlichkeit bei 0, dass zwischen 0 und " , anzBauteile_soll + teileZuViel , " Bauteilen auf der Waage liegen. " )
print ( " Falls die korrekte Anzhl an Bauteilen auf der Waage liegt, könnte der Fehler in einer falschen Kalibrierung der Waage liegen (TARE). " )
if ( self . stopLoop == False ) :
self . checkWaageFinishedSignal . emit ( einzelteilID )
else :
self . waageStoppedSignal . emit ( einzelteilID )
class Ui_MainWindow ( object ) :
def setupUi ( self , MainWindow ) :
self . auftragsnummer = " "
self . teileZuViel = 0 # 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 ( 1090 , 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 " )
self . AuftragsdetailsTable = QtWidgets . QTableWidget ( self . centralwidget )
self . AuftragsdetailsTable . setGeometry ( QtCore . QRect ( 10 , 300 , 661 , 192 ) )
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 )
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 , 150 , 161 , 25 ) )
self . bauteilTypBtn . setObjectName ( " bauteilTypBtn " )
self . checkWaageBtn = QtWidgets . QPushButton ( self . centralwidget )
self . checkWaageBtn . setGeometry ( QtCore . QRect ( 700 , 460 , 161 , 25 ) )
self . checkWaageBtn . setObjectName ( " checkWaageBtn " )
self . stopLoopBtn = QtWidgets . QPushButton ( self . centralwidget )
self . stopLoopBtn . setGeometry ( QtCore . QRect ( 700 , 500 , 161 , 25 ) )
self . stopLoopBtn . setObjectName ( " stopLoopBtn " )
self . waageTareBtn = QtWidgets . QPushButton ( self . centralwidget )
self . waageTareBtn . setGeometry ( QtCore . QRect ( 700 , 100 , 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 . BezeichnungLabel . setObjectName ( " BezeichnungLabel " )
self . teileZuVielLabel = QtWidgets . QLabel ( self . centralwidget )
self . teileZuVielLabel . setGeometry ( QtCore . QRect ( 700 , 350 , 350 , 17 ) )
self . teileZuVielLabel . setObjectName ( " teileZuVielLabel " )
self . teileZuVielTxtFeld = QtWidgets . QTextEdit ( self . centralwidget )
self . teileZuVielTxtFeld . setGeometry ( QtCore . QRect ( 700 , 370 , 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 ( 700 , 10 , 151 , 23 ) )
self . checkBox . setObjectName ( " checkBox " )
# button and checkbox for camera workflow + graphicsview widget
self . startCamBtn = QtWidgets . QPushButton ( self . centralwidget )
self . startCamBtn . setGeometry ( QtCore . QRect ( 900 , 45 , 161 , 25 ) )
self . startCamBtn . setObjectName ( " startCamBtn " )
self . stopCamBtn = QtWidgets . QPushButton ( self . centralwidget )
self . stopCamBtn . setGeometry ( QtCore . QRect ( 900 , 45 + 25 , 161 , 25 ) )
self . stopCamBtn . setObjectName ( " stopCamBtn " )
self . camWorkFlowcheckBox = QtWidgets . QCheckBox ( self . centralwidget )
self . camWorkFlowcheckBox . setGeometry ( QtCore . QRect ( 900 , 10 , 151 , 23 ) )
self . camWorkFlowcheckBox . setObjectName ( " camWorkFlowcheckBox " )
self . graphicsView = QtWidgets . QGraphicsView ( self . centralwidget )
self . graphicsView . setGeometry ( QtCore . QRect ( 1100 , 20 , int ( 640 * 1.2 ) , int ( 480 * 1.2 ) ) ) # position and size of camera frame
self . graphicsView . setObjectName ( " graphicsView " )
#self.myTestLambda = lambda: self.worker.checkWaageStartSignal.emit(einzelteilID, self.teileZuViel, self.auftragsnummer)
'''
item = QtWidgets . QTableWidgetItem ( )
font = QtGui . QFont ( )
font . setPointSize ( 8 )
item . setFont ( font )
self . AuftragsdetailsTable . setVerticalHeaderItem ( 0 , item )
'''
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 )
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 " ) )
self . label . setText ( _translate ( " M ainWindow " , " Auftragsnummer: " ) )
self . bauteilTypBtn . setText ( _translate ( " MainWindow " , " Bauteiltyp erkennen " ) )
self . bauteilTypBtn . clicked . connect ( self . objectTypeDetection )
self . AuftragsdetailsTable . cellClicked . connect ( self . onTableCellClick )
#self.AuftragsdetailsTable.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers)
#item = self.AuftragsdetailsTable.verticalHeaderItem(0)
#item.setText(_translate("MainWindow", "test"))
self . BezeichnungLabel . setText ( _translate ( " MainWindow " , " Bezeichnung " ) )
self . PosNrLabel . setText ( _translate ( " MainWindow " , " Pos.-Nr: " ) )
self . teileZuVielLabel . setText ( _translate ( " MainWindow " , " Zu prüfende Teileanzahl über Auftragsanzahl: " ) )
self . teileZuVielTxtFeld . setText ( str ( self . teileZuViel ) )
self . checkWaageBtn . setText ( _translate ( " MainWindow " , " check Waage " ) )
self . checkWaageBtn . clicked . connect ( self . checkWaage )
self . stopLoopBtn . setText ( _translate ( " MainWindow " , " stop loop " ) )
self . stopLoopBtn . clicked . connect ( self . stopLoopClicked )
self . waageTareBtn . setText ( _translate ( " MainWindow " , " Waage tarieren " ) )
self . waageTareBtn . clicked . connect ( self . onTareClick )
self . checkBox . setText ( _translate ( " MainWindow " , " static workflow " ) )
self . checkBox . clicked . connect ( self . onCheckboxCheck )
# new camera workflow
self . startCamBtn . setText ( _translate ( " MainWindow " , " Start Camera " ) )
# self.startCamBtn.clicked.connect(self.startCamBtnClicked)
self . stopCamBtn . setText ( _translate ( " MainWindow " , " Stop Camera " ) )
self . camWorkFlowcheckBox . setText ( _translate ( " MainWindow " , " Camera Workflow " ) )
# self.camWorkFlowcheckBox.clicked.connect(self.onCheckboxCheck)
def 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 getRowNr ( self , posNr ) :
for i in range ( 0 , self . AuftragsdetailsTable . rowCount ( ) ) :
if ( self . AuftragsdetailsTable . item ( i , 0 ) . text ( ) == str ( posNr ) ) :
return i
# brauche ich hier vermutlich nicht mehr - ist in den Worker Thread kopiert worden
def waageNichtEingeschwungenOutput ( self ) :
print ( " Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft. " )
def onTableCellClick ( self ) :
self . PosNrTxtFeld . setText ( self . AuftragsdetailsTable . item ( self . AuftragsdetailsTable . currentRow ( ) , 0 ) . text ( ) )
self . bauteiltypTextbox . setText ( self . AuftragsdetailsTable . item ( self . AuftragsdetailsTable . currentRow ( ) , 2 ) . text ( ) )
def setAuftragsnummer ( self ) :
self . auftragsnummer = self . textEdit . toPlainText ( )
if ( not self . auftragsnummer ) :
self . auftragsnummer = " "
self . textEdit . setText ( " " )
def checkAuftragsnummerEmpty ( self ) :
if self . auftragsnummer == " " :
print ( " Das Auftragsnummernfeld ist leer. " )
return True
else :
return False
def checkPosNrEmpty ( self ) :
if self . PosNrTxtFeld . toPlainText ( ) == " " :
return True
else :
return False
# eventuell benötigt man die Funktion hier nicht mehr, da sie zu den Threads kopiert wurde
def getDataOfArticleType ( self , allArticles , articleType ) :
# die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück
for i in allArticles :
if i [ 1 ] == articleType :
return i
return - 1
def updateGUI ( self ) :
self . PosNrLabel . repaint ( ) #GUI aktualisieren
QApplication . processEvents ( ) #GUI aktualisieren
def setRowColor ( self , rowID , r , g , b ) :
self . AuftragsdetailsTable . item ( rowID , 0 ) . setBackground ( QtGui . QColor ( r , g , b ) )
self . AuftragsdetailsTable . item ( rowID , 1 ) . setBackground ( QtGui . QColor ( r , g , b ) )
self . AuftragsdetailsTable . item ( rowID , 2 ) . setBackground ( QtGui . QColor ( r , g , b ) )
self . AuftragsdetailsTable . item ( rowID , 3 ) . setBackground ( QtGui . QColor ( r , g , b ) )
self . AuftragsdetailsTable . item ( rowID , 4 ) . setBackground ( QtGui . QColor ( r , g , b ) )
self . AuftragsdetailsTable . item ( rowID , 5 ) . setBackground ( QtGui . QColor ( r , g , b ) )
#wird hier vermutlich nicht mehr benötigt - wurde in die Workerklasse kopiert
def readWaage ( self ) :
# in folgender Funktion wird die Waage ausgelesen
#print("connection is open: ", ser.is_open) #Debuggingausgabe
#print("port to which it is connected: ", ser.portstr) #Debuggingausgabe
self . checkPosNrEmpty ( )
if ser . is_open == False :
ser . open ( )
#an die Waage den Befehl senden, dass sie ausgelesen werden soll
ser . write ( b ' getWeight \n ' )
#ser.write(b'tare\n')
serialString = ser . readline ( ) . decode ( ' utf-8 ' ) . rstrip ( ) #Auslesen des Serial-Strings/der Messung der Waage
# wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft
lenString = len ( serialString ) - 1
if serialString [ lenString ] == " g " and serialString [ lenString - 1 ] == " k " :
#print("ist eingeschwungen") #Debuggingausgabe
waageEingeschwungen = True
else :
print ( " die Waage ist noch nicht eingeschwungen " )
waageEingeschwungen = False
#aus dem String werden alle Zeichen, welche nicht zur Darstellung der Zahl benötigt werden entfernt
intString = " "
for i in serialString :
if i == " - " or i == " 0 " or i == " . " or i == " 1 " or i == " 2 " or i == " 3 " or i == " 4 " or i == " 5 " or i == " 6 " or i == " 7 " or i == " 8 " or i == " 9 " :
intString = intString + i
print ( " Wert, welcher von der Waage ausgelesen wurde: " + intString + " kg " )
## Waage auslesen - ENDE
ser . close ( )
#print("connection is open: ", ser.is_open) #Debuggingausgabe
return waageEingeschwungen , intString
def auftragsBtnClicked ( self ) :
databaseQueryWorking = False #wird für die Überprüfung, ob die Datenbankabfrage fehlerhaft ist, verwendet
auftragEinzelteilDaten = [ ]
self . setAuftragsnummer ( )
if ( not self . checkAuftragsnummerEmpty ( ) ) :
sql_query = " SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + self . auftragsnummer
try :
cursor . execute ( sql_query )
# Fetch results
auftragEinzelteilDaten = cursor . fetchall ( )
databaseQueryWorking = True
except :
print ( " Fehler in der Datenbankabfrage. " )
if databaseQueryWorking == True and len ( auftragEinzelteilDaten ) > 0 :
'''
# Display data
print ( " Ausgabe der Auftragsdetails des obigen Auftrags, inklusive Einzelteildetails: " )
for row in auftragEinzelteilDaten :
if str ( row [ 2 ] ) == self . auftragsnummer :
print ( " passt " )
print ( row )
'''
### die Auftragsdaten in die Tabelle laden
self . AuftragsdetailsTable . setRowCount ( len ( auftragEinzelteilDaten ) )
self . item = QtWidgets . QTableWidgetItem ( )
counter = 0
for row in auftragEinzelteilDaten :
self . item = QtWidgets . QTableWidgetItem ( )
self . AuftragsdetailsTable . setItem ( counter , 0 , self . item )
self . item . setText ( str ( row [ 1 ] ) )
self . item . setFlags ( self . item . flags ( ) & ~ QtCore . Qt . ItemIsEditable )
self . item = QtWidgets . QTableWidgetItem ( )
self . AuftragsdetailsTable . setItem ( counter , 1 , self . item )
self . item . setFlags ( self . item . flags ( ) & ~ QtCore . Qt . ItemIsEditable )
self . item = QtWidgets . QTableWidgetItem ( )
self . AuftragsdetailsTable . setItem ( counter , 2 , self . item )
self . item . setText ( str ( row [ 5 ] ) )
self . item . setFlags ( self . item . flags ( ) & ~ QtCore . Qt . ItemIsEditable )
self . item = QtWidgets . QTableWidgetItem ( )
self . AuftragsdetailsTable . setItem ( counter , 3 , self . item )
self . item . setText ( str ( row [ 3 ] ) )
self . item . setFlags ( self . item . flags ( ) & ~ QtCore . Qt . ItemIsEditable )
self . item = QtWidgets . QTableWidgetItem ( )
self . AuftragsdetailsTable . setItem ( counter , 4 , self . item )
self . item . setText ( str ( " 0 " ) )
self . item = QtWidgets . QTableWidgetItem ( )
self . AuftragsdetailsTable . setItem ( counter , 5 , self . item )
self . item . setFlags ( self . item . flags ( ) & ~ QtCore . Qt . ItemIsEditable )
# Dropdown für Farben in die 6. Spalte einfügen
#self.item = QtWidgets.QTableWidgetItem()
#self.AuftragsdetailsTable.setItem(counter, 6, self.item)
combo = QComboBox ( )
combo . addItems ( [ " Farbe " , " Weiß " , " Orange " , " Grün " ] )
combo . currentIndexChanged . connect ( lambda index , rowId = counter : self . change_row_color ( rowId , index ) )
self . AuftragsdetailsTable . setCellWidget ( counter , 6 , combo )
counter = counter + 1
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 ( row , 255 , 255 , 255 )
if ( color_index == 2 ) :
self . setRowColor ( row , 255 , 165 , 0 )
if ( color_index == 3 ) :
self . setRowColor ( 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 checkWaage ( self ) :
#print("Running in thread:", threading.current_thread().name) # Debuggingausgabe
QApplication . processEvents ( )
# die Loopvariable des Workers auf False setzten, damit die Schleife durchgelaufen wird (diese wird zum Abbruch der Schleife benötigt -> siehe stopLoop)
#self.checkWaageWorker.stopLoopSignal.emit(False)
# überprüfen, ob der Auftrag geladen wurde
if ( self . AuftragsdetailsTable . item ( 0 , 0 ) == None ) :
print ( " Der Auftrag muss zuerst geladen werden. " )
return
# überprüfen, ob ein Bauteiltyp gesetzt wurde
if ( self . checkPosNrEmpty ( ) == True and self . checkBox . isChecked ( ) == False ) :
print ( " Das Pos.-Nr.-Feld ist leer. " )
return
# den GUI Wert von Textfeld TeileZuViel in die Variable schreiben
self . teileZuViel = int ( float ( self . teileZuVielTxtFeld . toPlainText ( ) ) )
self . teileZuVielTxtFeld . setText ( str ( self . teileZuViel ) )
einzelteilID = - 1 # Initialisieren der Variable mit einem Defaultwert, welcher nie eingenommen werden können sollte
if ( self . checkBox . isChecked ( ) == False ) :
#übernehmen der BauteilID aus dem Feld Pos.-Nr - wenn der Workflow dynamisch gewählt wurde
einzelteilID = int ( self . PosNrTxtFeld . toPlainText ( ) )
else :
# wenn der Workflow statisch gesetzt wurde, dann soll das erste Item aus der Auftragsliste geladen werden, von welchem noch nicht genug Bauteile auf der Waage liegen
for i in range ( 0 , self . AuftragsdetailsTable . rowCount ( ) ) :
if self . AuftragsdetailsTable . item ( i , 3 ) . text ( ) != self . AuftragsdetailsTable . item ( i , 4 ) . text ( ) :
einzelteilID = int ( self . AuftragsdetailsTable . item ( i , 0 ) . text ( ) )
self . PosNrTxtFeld . setText ( str ( self . AuftragsdetailsTable . item ( i , 0 ) . text ( ) ) )
self . bauteiltypTextbox . setText ( str ( self . AuftragsdetailsTable . item ( i , 2 ) . text ( ) ) )
break
if einzelteilID == - 1 :
# den Thread beenden
self . checkWaageThread . quit ( )
self . checkWaageThread . wait ( )
try :
self . checkWaageThread . started . disconnect ( ) # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt
print ( " Der Thread wurde beendet. " )
except :
print ( " Disconnecting the thread did not work. " )
return
#zum setzen den Farbe der gesamten Reihe auf Orange
self . setRowColor ( self . getRowNr ( einzelteilID ) , 255 , 165 , 0 )
# 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 . getRowNr ( einzelteilID ) , 0 , 255 , 0 ) #zum setzen den Farbe der gesamten Reihe auf Grün
# den Thread beenden
self . checkWaageThread . quit ( )
self . checkWaageThread . wait ( )
# auch wenn die Länge der Liste überschritten wurde
# wenn der statische Workflow aktiviert ist, dann soll die checkwaage-funktion erneut aufgerufen werden
if ( self . checkBox . isChecked ( ) == True ) :
self . checkWaage ( )
# GUI updaten
#self.updateGUI()
def objectTypeDetection ( self ) :
# in dieser Funktion wird der Typ des Bauteils automatisch erkannt
# wenn der statische Workflow ausgewählt wurde, dann soll die checkWaage Funktion aufgerufen werden, auch wenn die detectBauteiltyp-Funkion aufgerufen wurde
if self . checkBox . isChecked ( ) == True :
self . checkWaage ( )
return
'''
if ( self . checkPosNrEmpty ( ) == True ) :
print ( " Das Pos.-Nr.-Feld ist leer. " )
return
'''
# die Loopvariable des Workers auf False setzten, damit die Schleife durchgelaufen wird (diese wird zum Abbruch der Schleife benötigt -> siehe stopLoop)
#self.objectDetectionWorker.stopLoopSignal.emit(False)
# überprüfen, ob der Auftrag in die Tabelle geladen wurde
if ( self . AuftragsdetailsTable . item ( 0 , 0 ) == None ) :
print ( " Der Auftrag muss zuerst geladen werden. " )
return
# speichert den Wert, welcher im Textfeld steht in Variablen im Code
self . setAuftragsnummer ( )
# starten des Threats, welcher den Bauteiltyp zurück gibt
self . objectDetectionWorker = Worker ( )
self . objectDetectionThread = QThread ( )
self . objectDetectionWorker . moveToThread ( self . objectDetectionThread )
self . objectDetectionWorker . objectDetectionStartSignal . connect ( self . objectDetectionWorker . objectTypeDetectionThread )
self . objectDetectionWorker . objectDetectionFinishedSignal . connect ( self . objectTypeDetectionFinished )
self . objectDetectionWorker . waageStoppedSignal . connect ( self . threadStopped )
self . objectDetectionWorker . stopLoopSignal . connect ( lambda status : setattr ( self . objectDetectionWorker , ' stopLoop ' , status ) ) #wird fürs aktive Stoppen des Threads benötigt
self . objectDetectionThread . started . connect ( lambda : self . objectDetectionWorker . objectDetectionStartSignal . emit ( self . auftragsnummer ) )
self . objectDetectionThread . start ( )
def objectTypeDetectionFinished ( self , einzelteilID , rowData ) :
# wenn der Typ des Objektes erkannt wurde, dann soll die Funktion aufgerufen werden
# Schreiben der Bauteiltype und Pos.-Nr in die jeweiligen Felder
self . PosNrTxtFeld . setText ( str ( rowData [ 1 ] ) )
self . bauteiltypTextbox . setText ( rowData [ 2 ] )
# setzt den Boolean, um aus der Schleife raus zu gehen
self . btTypeIsSet = True
#zum setzen den Farbe der gesamten Reihe auf Orange
self . setRowColor ( self . getRowNr ( einzelteilID ) , 255 , 165 , 0 )
# den Thread beenden
self . objectDetectionThread . quit ( )
self . objectDetectionThread . wait ( )
'''
try :
self . objectDetectionThread . started . disconnect ( ) # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt
except :
print ( f " Error while disconnecting: { e } " )
print ( " Disconnecting the thread did not work. " )
'''
# wenn der Bauteiltyp erkannt wurde, dann soll die GUI aktualisiert werden und anschließend die CheckWaage-Funktion aufgerufen werden
self . updateGUI ( )
self . checkWaage ( )
def threadStopped ( self , einzelteilID ) :
# wenn kein Bauteil erkannt wurde, dann ist die EinzenteilID = 0
if ( einzelteilID > 0 ) :
self . setRowColor ( self . getRowNr ( einzelteilID ) , 255 , 255 , 255 ) #zum setzen den Farbe der gesamten Reihe auf Weiß
# den Thread beenden
if hasattr ( self , ' objectDetectionThread ' ) :
self . objectDetectionThread . quit ( )
self . objectDetectionThread . wait ( )
print ( " Der ObjektDetection-Thread wurde beendet. " )
if hasattr ( self , ' checkWaageThread ' ) :
self . checkWaageThread . quit ( )
self . checkWaageThread . wait ( )
print ( " Der CheckWaage-Thread wurde beendet. " )
# new class for Camera Object detection with YOLOv8
class CameraStreamApp ( QtWidgets . QMainWindow ) :
def __init__ ( self , ui ) :
super ( ) . __init__ ( )
self . ui = ui
self . yolo_stream = None # Initialize YOLOv8CameraStream as None
self . timer = QtCore . QTimer ( self )
self . timer . timeout . connect ( self . update_frame )
self . ui . startCamBtn . clicked . connect ( self . start_camera ) # start camera if button LoadAuftrag is clicked
self . scene = QtWidgets . QGraphicsScene ( self )
self . ui . graphicsView . setScene ( self . scene )
def start_camera ( self ) :
# Start the YOLOv8 camera stream (only if not already started)
if self . yolo_stream is None :
self . yolo_stream = YOLOv8CameraStream ( model_path = " models/yolov8m_seg_e300.pt " , logging_level = " high " )
# self.yolo_stream.start() # Start the YOLOv8 stream
self . timer . start ( 30 ) # Start the timer to update the frame every 30ms (about 33 FPS)
def update_frame ( self ) :
# Update the frame from YOLOv8 stream
if self . yolo_stream :
ret , frame = self . yolo_stream . cap . read ( ) # Capture frame from YOLOv8 stream
if ret :
# new part including processing via yolo model
processed_frame = self . yolo_stream . process_frame ( frame )
# Convert the frame from BGR (OpenCV format) to RGB
# frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = cv2 . cvtColor ( processed_frame , cv2 . COLOR_BGR2RGB ) # might change nomenclature later?
# Convert the frame to QImage
h , w , ch = frame . shape
bytes_per_line = ch * w
qt_image = QtGui . QImage ( frame . data , w , h , bytes_per_line , QtGui . QImage . Format_RGB888 )
# Add the QImage to a QPixmap
pixmap = QtGui . QPixmap . fromImage ( qt_image )
# Get the size of the graphicsView and scale the pixmap to fit
view_size = self . ui . graphicsView . size ( )
scaled_pixmap = pixmap . scaled ( view_size , QtCore . Qt . KeepAspectRatio )
# Update the scene with the scaled pixmap
self . scene . clear ( )
self . scene . addPixmap ( scaled_pixmap )
def closeEvent ( self , event ) :
# Release the camera when the application is closed
if self . yolo_stream is not None :
self . yolo_stream . cap . release ( )
event . accept ( )
if __name__ == " __main__ " :
import sys
app = QtWidgets . QApplication ( sys . argv )
MainWindow = QtWidgets . QMainWindow ( )
ui = Ui_MainWindow ( )
ui . setupUi ( MainWindow )
# Initialize the CameraStreamApp with the UI
camera_app = CameraStreamApp ( ui )
MainWindow . show ( )
sys . exit ( app . exec_ ( ) )