2024-11-24 14:11:18 +00:00
#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
2024-11-24 17:18:27 +00:00
# ## Aufsetzen der Datenbank und Waagenverbindung
# # Definieren der Datenbankverbindung
2024-11-24 14:11:18 +00:00
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
}
2024-11-24 17:18:27 +00:00
# # 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
2024-11-24 14:11:18 +00:00
# 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 \n Waage: \n --> ein Bauteil auf die Waage legen \n --> \" Bauteiltyp erkennen \" Buttonclick \n \n manuell: \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 " ) )
2024-11-26 07:33:45 +00:00
self . blinkLightBtn . setText ( _translate ( " MainWindow " , " Blink Yellow LED " ) )
2024-11-24 14:11:18 +00:00
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 ) )
2024-11-26 09:48:31 +00:00
# # call change led color
# later_instance = light_app_reference()
# later_instance.map_color_to_led(r,g,b)
2024-11-24 17:18:27 +00:00
2024-11-24 14:11:18 +00:00
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)
2024-11-24 17:18:27 +00:00
frame = cv2 . cvtColor ( processed_frame , cv2 . COLOR_BGR2RGB )
2024-11-24 14:11:18 +00:00
# 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
2024-11-24 17:18:27 +00:00
# init relay control
2024-11-24 14:11:18 +00:00
self . ui . startSpotlightBtn . clicked . connect ( self . spot_on )
self . ui . stopSpotlightBtn . clicked . connect ( self . spot_off )
self . r = sainsmartrelay . SainsmartRelay ( )
2024-11-24 17:18:27 +00:00
# init led control
2024-11-24 14:11:18 +00:00
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 )
2024-11-26 07:33:45 +00:00
self . ui . blinkLightBtn . clicked . connect ( self . blink_yellow )
2024-11-24 14:11:18 +00:00
self . w = wledControl . WLEDController ( port = " /dev/serial/by-path/pci-0000:00:14.0-usbv2-0:1:1.0-port0 " )
2024-11-26 07:33:45 +00:00
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
2024-11-24 17:18:27 +00:00
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 ( )
2024-11-24 14:11:18 +00:00
2024-11-24 17:18:27 +00:00
# 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 ( )
2024-11-24 14:11:18 +00:00
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 ( )
2024-11-26 07:33:45 +00:00
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 ( )
2024-11-24 14:11:18 +00:00
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_ ( ) )