update: delete unnecessary files
This commit is contained in:
parent
d89ae03a64
commit
b452a3df74
304
workflow.py
304
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 QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QProgressBar
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
@ -31,6 +20,12 @@ import os
|
|||||||
import lib.sainsmartrelay as sainsmartrelay
|
import lib.sainsmartrelay as sainsmartrelay
|
||||||
import lib.wledControl as wledControl
|
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 = {
|
db_config = {
|
||||||
'user': 'dbUser',
|
'user': 'dbUser',
|
||||||
'password': 'dbPassword',
|
'password': 'dbPassword',
|
||||||
@ -39,11 +34,24 @@ db_config = {
|
|||||||
'port': 3306 # Standard port for MariaDB
|
'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
|
# Configuration of the serial port
|
||||||
try:
|
try:
|
||||||
@ -52,34 +60,8 @@ try:
|
|||||||
except serial.SerialException:
|
except serial.SerialException:
|
||||||
ser = None
|
ser = None
|
||||||
print("Warning: Serial port not found. Continuing without serial connection. Only working for demo-purposes.")
|
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.
|
|
||||||
|
|
||||||
|
# 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
|
||||||
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):
|
class Worker(QObject):
|
||||||
#progress = pyqtSignal(int)
|
#progress = pyqtSignal(int)
|
||||||
objectDetectionStartSignal = pyqtSignal(str)
|
objectDetectionStartSignal = pyqtSignal(str)
|
||||||
@ -92,6 +74,7 @@ class Worker(QObject):
|
|||||||
waageStoppedSignal = pyqtSignal(int)
|
waageStoppedSignal = pyqtSignal(int)
|
||||||
stopLoopSignal = pyqtSignal(bool) #das Signal wird verwendet um direkt den stopLoop-Wert zu ändern (also kein Funktionsaufruf)
|
stopLoopSignal = pyqtSignal(bool) #das Signal wird verwendet um direkt den stopLoop-Wert zu ändern (also kein Funktionsaufruf)
|
||||||
|
|
||||||
|
waageEingeschwungen = False
|
||||||
stopLoop = False
|
stopLoop = False
|
||||||
btTypeIsSet = False
|
btTypeIsSet = False
|
||||||
correctBtNr = False
|
correctBtNr = False
|
||||||
@ -103,7 +86,7 @@ class Worker(QObject):
|
|||||||
|
|
||||||
|
|
||||||
def getDataOfArticleType(self, allArticles, articleType):
|
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:
|
for i in allArticles:
|
||||||
if i[1] == articleType:
|
if i[1] == articleType:
|
||||||
return i
|
return i
|
||||||
@ -113,26 +96,27 @@ class Worker(QObject):
|
|||||||
def waageNichtEingeschwungenOutput(self):
|
def waageNichtEingeschwungenOutput(self):
|
||||||
print("Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft.")
|
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):
|
def readWaage(self):
|
||||||
# in folgender Funktion wird die Waage ausgelesen
|
''' 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:
|
if ser.is_open == False:
|
||||||
ser.open()
|
ser.open()
|
||||||
|
|
||||||
|
|
||||||
#an die Waage den Befehl senden, dass sie ausgelesen werden soll
|
#an die Waage den Befehl senden, dass sie ausgelesen werden soll
|
||||||
ser.write(b'getWeight\n')
|
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
|
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
|
# wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft
|
||||||
lenString = len(serialString)-1
|
lenString = len(serialString)-1
|
||||||
if serialString[lenString] == "g" and serialString[lenString-1] == "k":
|
if serialString[lenString] == "g" and serialString[lenString-1] == "k":
|
||||||
#print("ist eingeschwungen") #Debuggingausgabe
|
|
||||||
waageEingeschwungen = True
|
waageEingeschwungen = True
|
||||||
else:
|
else:
|
||||||
print("die Waage ist noch nicht eingeschwungen")
|
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":
|
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
|
intString = intString + i
|
||||||
print("Wert, welcher von der Waage ausgelesen wurde: " + intString + "kg")
|
print("Wert, welcher von der Waage ausgelesen wurde: " + intString + "kg")
|
||||||
## Waage auslesen - ENDE
|
|
||||||
|
|
||||||
ser.close()
|
ser.close()
|
||||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
|
||||||
|
|
||||||
return waageEingeschwungen, intString
|
return waageEingeschwungen, intString
|
||||||
|
|
||||||
def objectTypeDetectionThread(self, auftragsnummer):
|
def objectTypeDetectionThread(self, auftragsnummer):
|
||||||
# in dieser Funktion wird der Typ des Bauteils automatisch erkannt
|
''' in dieser Funktion wird der Typ des Bauteils automatisch erkannt '''
|
||||||
|
|
||||||
#print("objectTypeDetectionThread - Running in thread:", threading.current_thread().name) #Debuggausgabe
|
|
||||||
|
|
||||||
# Parameterdefinition
|
# Parameterdefinition
|
||||||
propDensVect = []
|
propDensVect = []
|
||||||
@ -174,16 +154,9 @@ class Worker(QObject):
|
|||||||
cursor.execute(sql_query)
|
cursor.execute(sql_query)
|
||||||
auftragEinzelteilDaten = cursor.fetchall()
|
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
|
# in der Folge werden alle Wahrscheinlichkeitsdichten der Auftragsbauteile berechnet und in dem Vektor gesammelt
|
||||||
for row in auftragEinzelteilDaten:
|
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
|
# Jenen Eintrag des propDensVect raussuchen, welcher die größte Wahrscheinlichkeitsdichte beinhaltet
|
||||||
maxpropDens = 0
|
maxpropDens = 0
|
||||||
@ -201,14 +174,6 @@ class Worker(QObject):
|
|||||||
else:
|
else:
|
||||||
print("Bei dem Bauteil" , einzelteilID , "wurde die höchste Wahrscheinlichkeitsdichte berechnet.")
|
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
|
# den Bool auf true setzen, damit die Schleife beendet wird - dieser wird auf True gesetzt, wenn ein Bauteiltyp erkannt wird
|
||||||
self.btTypeIsSet = True
|
self.btTypeIsSet = True
|
||||||
|
|
||||||
@ -219,6 +184,7 @@ class Worker(QObject):
|
|||||||
self.waageStoppedSignal.emit(einzelteilID)
|
self.waageStoppedSignal.emit(einzelteilID)
|
||||||
|
|
||||||
def checkWaageThread(self, einzelteilID, teileZuViel, auftragsnummer):
|
def checkWaageThread(self, einzelteilID, teileZuViel, auftragsnummer):
|
||||||
|
''' in dieser Funktion wird die Stückzahl der Bauteile, welche auf der Waage liegen, berechnet '''
|
||||||
|
|
||||||
self.correctBtNr = False
|
self.correctBtNr = False
|
||||||
prevAnzahl = 0
|
prevAnzahl = 0
|
||||||
@ -238,14 +204,6 @@ class Worker(QObject):
|
|||||||
cursor.execute(sql_query)
|
cursor.execute(sql_query)
|
||||||
auftragDaten = cursor.fetchall()
|
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
|
#auslesen, wie viele Bauteile des Types laut Auftrag vorhanden sein sollen
|
||||||
anzBauteile_soll = 0
|
anzBauteile_soll = 0
|
||||||
idVorhanden = False
|
idVorhanden = False
|
||||||
@ -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
|
# 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
|
mueGes = float(articleData[6])*i # Berechnen des äquivalenten Mittelwert
|
||||||
varGes = float(articleData[7])*i # Berechnen der äquivalenten Varianz
|
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
|
# durch den propDensVect iterieren und jenen Eintrag mit der höchsten Wahrscheinlichkeitsdichte raussuchen
|
||||||
maxpropDens = 0
|
maxpropDens = 0
|
||||||
@ -280,14 +238,6 @@ class Worker(QObject):
|
|||||||
if prevAnzahl != anzahl:
|
if prevAnzahl != anzahl:
|
||||||
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
|
# wenn genug Bauteile vorhanden sind, dann soll die Schleife beendet werden
|
||||||
if (anzahl == anzBauteile_soll):
|
if (anzahl == anzBauteile_soll):
|
||||||
self.correctBtNr = True
|
self.correctBtNr = True
|
||||||
@ -307,8 +257,7 @@ class Worker(QObject):
|
|||||||
self.waageStoppedSignal.emit(einzelteilID)
|
self.waageStoppedSignal.emit(einzelteilID)
|
||||||
|
|
||||||
|
|
||||||
|
## in der Ui_MainWindow-Klasse wird die GUI erstellt - der MainThread läuft in dieser
|
||||||
|
|
||||||
class Ui_MainWindow(object):
|
class Ui_MainWindow(object):
|
||||||
def setupUi(self, MainWindow):
|
def setupUi(self, MainWindow):
|
||||||
self.auftragsnummer = ""
|
self.auftragsnummer = ""
|
||||||
@ -316,7 +265,6 @@ class Ui_MainWindow(object):
|
|||||||
self.correctBtNr = False
|
self.correctBtNr = False
|
||||||
self.btTypeIsSet = False
|
self.btTypeIsSet = False
|
||||||
|
|
||||||
|
|
||||||
MainWindow.setObjectName("MainWindow")
|
MainWindow.setObjectName("MainWindow")
|
||||||
MainWindow.resize(1400, 675)
|
MainWindow.resize(1400, 675)
|
||||||
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
||||||
@ -476,16 +424,6 @@ class Ui_MainWindow(object):
|
|||||||
self.blinkLightBtn = QtWidgets.QPushButton(self.centralwidget)
|
self.blinkLightBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||||
self.blinkLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+300, 161, 25))
|
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
|
# Maximize the window on startup
|
||||||
MainWindow.showMaximized()
|
MainWindow.showMaximized()
|
||||||
|
|
||||||
@ -520,8 +458,6 @@ class Ui_MainWindow(object):
|
|||||||
item = self.ArbeitsschrittTable.horizontalHeaderItem(1)
|
item = self.ArbeitsschrittTable.horizontalHeaderItem(1)
|
||||||
item.setText(_translate("MainWindow", "ToDo:"))
|
item.setText(_translate("MainWindow", "ToDo:"))
|
||||||
|
|
||||||
# Befüllen der Arbeisschritttabelle mit Text
|
|
||||||
#item = self.ArbeitsschrittTable.
|
|
||||||
# Ein neues QTableWidgetItem erstellen und den Text setzen
|
# Ein neues QTableWidgetItem erstellen und den Text setzen
|
||||||
item = QtWidgets.QTableWidgetItem("Auftrag laden")
|
item = QtWidgets.QTableWidgetItem("Auftrag laden")
|
||||||
self.ArbeitsschrittTable.setItem(0, 0, item)
|
self.ArbeitsschrittTable.setItem(0, 0, item)
|
||||||
@ -539,19 +475,10 @@ class Ui_MainWindow(object):
|
|||||||
self.ArbeitsschrittTable.setItem(3, 0, item)
|
self.ArbeitsschrittTable.setItem(3, 0, item)
|
||||||
self.ArbeitsschrittTable.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers)
|
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.label.setText(_translate("MainWindow", "Auftragsnummer:"))
|
||||||
self.bauteilTypBtn.setText(_translate("MainWindow", "Bauteiltyp erkennen"))
|
self.bauteilTypBtn.setText(_translate("MainWindow", "Bauteiltyp erkennen"))
|
||||||
self.bauteilTypBtn.clicked.connect(self.objectTypeDetection)
|
self.bauteilTypBtn.clicked.connect(self.objectTypeDetection)
|
||||||
self.AuftragsdetailsTable.cellClicked.connect(self.onTableCellClick)
|
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.BezeichnungLabel.setText(_translate("MainWindow", "Bezeichnung"))
|
||||||
self.PosNrLabel.setText(_translate("MainWindow", "Pos.-Nr:"))
|
self.PosNrLabel.setText(_translate("MainWindow", "Pos.-Nr:"))
|
||||||
self.teileZuVielLabel.setText(_translate("MainWindow", "Zu prüfende Teileanzahl über Auftragsanzahl:"))
|
self.teileZuVielLabel.setText(_translate("MainWindow", "Zu prüfende Teileanzahl über Auftragsanzahl:"))
|
||||||
@ -573,10 +500,8 @@ class Ui_MainWindow(object):
|
|||||||
|
|
||||||
# new camera workflow
|
# new camera workflow
|
||||||
self.startCamBtn.setText(_translate("MainWindow", "Start Camera"))
|
self.startCamBtn.setText(_translate("MainWindow", "Start Camera"))
|
||||||
# self.startCamBtn.clicked.connect(self.startCamBtnClicked)
|
|
||||||
self.stopCamBtn.setText(_translate("MainWindow", "Stop Camera"))
|
self.stopCamBtn.setText(_translate("MainWindow", "Stop Camera"))
|
||||||
self.camWorkFlowcheckBox.setText(_translate("MainWindow", "Camera Workflow"))
|
self.camWorkFlowcheckBox.setText(_translate("MainWindow", "Camera Workflow"))
|
||||||
# self.camWorkFlowcheckBox.clicked.connect(self.onCheckboxCheck)
|
|
||||||
self.modelComboBox
|
self.modelComboBox
|
||||||
|
|
||||||
# relay control buttons
|
# relay control buttons
|
||||||
@ -588,23 +513,20 @@ class Ui_MainWindow(object):
|
|||||||
self.yellowLightBtn.setText(_translate("MainWindow", "Turn on yellow LED"))
|
self.yellowLightBtn.setText(_translate("MainWindow", "Turn on yellow LED"))
|
||||||
self.greenLightBtn.setText(_translate("MainWindow", "Turn on green LED"))
|
self.greenLightBtn.setText(_translate("MainWindow", "Turn on green LED"))
|
||||||
self.offLightBtn.setText(_translate("MainWindow", "Turn off all LEDs"))
|
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):
|
def mousePressEvent(self, event):
|
||||||
print("Das MainWindow wurde angeklickt.")
|
print("Das MainWindow wurde angeklickt.")
|
||||||
self.setFocus()
|
self.setFocus()
|
||||||
super().mousePressEvent(event)
|
super().mousePressEvent(event)
|
||||||
|
|
||||||
|
|
||||||
def onTareClick(self):
|
def onTareClick(self):
|
||||||
#Tarieren der Waage
|
''' Tarieren der Waage '''
|
||||||
if ser.is_open == False:
|
if ser.is_open == False:
|
||||||
ser.open()
|
ser.open()
|
||||||
ser.write(b'tare\n')
|
ser.write(b'tare\n')
|
||||||
ser.close()
|
ser.close()
|
||||||
|
|
||||||
|
|
||||||
def onCheckboxCheck(self):
|
def onCheckboxCheck(self):
|
||||||
if self.checkBox.isChecked() == True:
|
if self.checkBox.isChecked() == True:
|
||||||
print("static workflow activated")
|
print("static workflow activated")
|
||||||
@ -621,9 +543,6 @@ class Ui_MainWindow(object):
|
|||||||
for i in range(0,self.AuftragsdetailsTable.rowCount()):
|
for i in range(0,self.AuftragsdetailsTable.rowCount()):
|
||||||
if(self.AuftragsdetailsTable.item(i,0).text() == str(posNr)):
|
if(self.AuftragsdetailsTable.item(i,0).text() == str(posNr)):
|
||||||
return i
|
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):
|
def onTableCellClick(self):
|
||||||
self.PosNrTxtFeld.setText(self.AuftragsdetailsTable.item(self.AuftragsdetailsTable.currentRow(),0).text())
|
self.PosNrTxtFeld.setText(self.AuftragsdetailsTable.item(self.AuftragsdetailsTable.currentRow(),0).text())
|
||||||
@ -648,71 +567,21 @@ class Ui_MainWindow(object):
|
|||||||
else:
|
else:
|
||||||
return False
|
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):
|
def updateGUI(self):
|
||||||
self.PosNrLabel.repaint() #GUI aktualisieren
|
self.PosNrLabel.repaint() #GUI aktualisieren
|
||||||
QApplication.processEvents() #GUI aktualisieren
|
QApplication.processEvents() #GUI aktualisieren
|
||||||
|
|
||||||
|
|
||||||
def setRowColor(self, tableObject, rowID,r,g,b):
|
def setRowColor(self, tableObject, rowID,r,g,b):
|
||||||
for col in range(tableObject.columnCount()-1):
|
for col in range(tableObject.columnCount()-1):
|
||||||
tableObject.item(rowID, col).setBackground(QtGui.QColor(r,g,b))
|
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
|
# # call change led color
|
||||||
def readWaage(self):
|
# Check if the 'w' object already exists
|
||||||
# in folgender Funktion wird die Waage ausgelesen
|
# hier könnte noch nachgearbeitet werden
|
||||||
|
if not hasattr(self, 'w'):
|
||||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
w = wledControl.WLEDController(port="/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:1:1.0-port0")
|
||||||
#print("port to which it is connected: ", ser.portstr) #Debuggingausgabe
|
w.connect()
|
||||||
self.checkPosNrEmpty()
|
w.map_color_to_led([r,g,b])
|
||||||
|
|
||||||
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):
|
def auftragsBtnClicked(self):
|
||||||
databaseQueryWorking = False #wird für die Überprüfung, ob die Datenbankabfrage fehlerhaft ist, verwendet
|
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.")
|
print("Fehler in der Datenbankabfrage.")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if databaseQueryWorking==True and len(auftragEinzelteilDaten)>0:
|
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
|
### die Auftragsdaten in die Tabelle laden
|
||||||
self.AuftragsdetailsTable.setRowCount(len(auftragEinzelteilDaten))
|
self.AuftragsdetailsTable.setRowCount(len(auftragEinzelteilDaten))
|
||||||
@ -787,7 +647,6 @@ class Ui_MainWindow(object):
|
|||||||
self.bauteiltypTextbox.setText("")
|
self.bauteiltypTextbox.setText("")
|
||||||
self.PosNrTxtFeld.setText("")
|
self.PosNrTxtFeld.setText("")
|
||||||
|
|
||||||
|
|
||||||
elif(databaseQueryWorking==True and len(auftragEinzelteilDaten)==0):
|
elif(databaseQueryWorking==True and len(auftragEinzelteilDaten)==0):
|
||||||
print("Es wurde in der Datenbank kein Auftrag mit dieser Auftragsnummer gefunden.")
|
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)
|
self.setRowColor(self.AuftragsdetailsTable, row,0,255,0)
|
||||||
|
|
||||||
def stopLoopClicked(self):
|
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'):
|
if hasattr(self, 'objectDetectionWorker'):
|
||||||
self.objectDetectionWorker.stopLoopSignal.emit(True)
|
self.objectDetectionWorker.stopLoopSignal.emit(True)
|
||||||
|
|
||||||
@ -808,20 +667,15 @@ class Ui_MainWindow(object):
|
|||||||
self.checkWaageWorker.stopLoopSignal.emit(True)
|
self.checkWaageWorker.stopLoopSignal.emit(True)
|
||||||
|
|
||||||
def checkFinished(self):
|
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()):
|
for i in range(0,self.AuftragsdetailsTable.rowCount()):
|
||||||
if self.AuftragsdetailsTable.item(i,3).text() != self.AuftragsdetailsTable.item(i,4).text():
|
if self.AuftragsdetailsTable.item(i,3).text() != self.AuftragsdetailsTable.item(i,4).text():
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def checkWaage(self):
|
def checkWaage(self):
|
||||||
#print("Running in thread:", threading.current_thread().name) # Debuggingausgabe
|
|
||||||
QApplication.processEvents()
|
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
|
# überprüfen, ob der Auftrag geladen wurde
|
||||||
if(self.AuftragsdetailsTable.item(0,0) == None):
|
if(self.AuftragsdetailsTable.item(0,0) == None):
|
||||||
print("Der Auftrag muss zuerst geladen werden.")
|
print("Der Auftrag muss zuerst geladen werden.")
|
||||||
@ -910,22 +764,13 @@ class Ui_MainWindow(object):
|
|||||||
#self.updateGUI()
|
#self.updateGUI()
|
||||||
|
|
||||||
def objectTypeDetection(self):
|
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
|
# 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:
|
if self.checkBox.isChecked() == True:
|
||||||
self.checkWaage()
|
self.checkWaage()
|
||||||
return
|
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
|
# überprüfen, ob der Auftrag in die Tabelle geladen wurde
|
||||||
if(self.AuftragsdetailsTable.item(0,0) == None):
|
if(self.AuftragsdetailsTable.item(0,0) == None):
|
||||||
print("Der Auftrag muss zuerst geladen werden.")
|
print("Der Auftrag muss zuerst geladen werden.")
|
||||||
@ -949,7 +794,7 @@ class Ui_MainWindow(object):
|
|||||||
self.objectDetectionThread.start()
|
self.objectDetectionThread.start()
|
||||||
|
|
||||||
def objectTypeDetectionFinished(self, einzelteilID, rowData):
|
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
|
# Schreiben der Bauteiltype und Pos.-Nr in die jeweiligen Felder
|
||||||
self.PosNrTxtFeld.setText(str(rowData[1]))
|
self.PosNrTxtFeld.setText(str(rowData[1]))
|
||||||
@ -965,20 +810,12 @@ class Ui_MainWindow(object):
|
|||||||
self.objectDetectionThread.quit()
|
self.objectDetectionThread.quit()
|
||||||
self.objectDetectionThread.wait()
|
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
|
# wenn der Bauteiltyp erkannt wurde, dann soll die GUI aktualisiert werden und anschließend die CheckWaage-Funktion aufgerufen werden
|
||||||
self.updateGUI()
|
self.updateGUI()
|
||||||
self.checkWaage()
|
self.checkWaage()
|
||||||
|
|
||||||
def threadStopped(self, einzelteilID):
|
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 self.checkFinished() == False:
|
||||||
if(einzelteilID > 0):
|
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.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()
|
self.checkWaageThread.wait()
|
||||||
print("Der CheckWaage-Thread wurde beendet.")
|
print("Der CheckWaage-Thread wurde beendet.")
|
||||||
|
|
||||||
|
|
||||||
# new class for Camera Object detection with YOLOv8
|
# new class for Camera Object detection with YOLOv8
|
||||||
class CameraStreamApp(QtWidgets.QMainWindow):
|
class CameraStreamApp(QtWidgets.QMainWindow):
|
||||||
def __init__(self, ui):
|
def __init__(self, ui):
|
||||||
@ -1048,7 +884,7 @@ class CameraStreamApp(QtWidgets.QMainWindow):
|
|||||||
|
|
||||||
# Convert the frame from BGR (OpenCV format) to RGB
|
# Convert the frame from BGR (OpenCV format) to RGB
|
||||||
# frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
# 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
|
# Convert the frame to QImage
|
||||||
h, w, ch = frame.shape
|
h, w, ch = frame.shape
|
||||||
@ -1078,16 +914,30 @@ class LightControl(QtWidgets.QMainWindow):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.ui = ui
|
self.ui = ui
|
||||||
|
|
||||||
|
# init relay control
|
||||||
self.ui.startSpotlightBtn.clicked.connect(self.spot_on)
|
self.ui.startSpotlightBtn.clicked.connect(self.spot_on)
|
||||||
self.ui.stopSpotlightBtn.clicked.connect(self.spot_off)
|
self.ui.stopSpotlightBtn.clicked.connect(self.spot_off)
|
||||||
self.r = sainsmartrelay.SainsmartRelay()
|
self.r = sainsmartrelay.SainsmartRelay()
|
||||||
|
|
||||||
|
# init led control
|
||||||
self.ui.redLightBtn.clicked.connect(self.red_on)
|
self.ui.redLightBtn.clicked.connect(self.red_on)
|
||||||
self.ui.yellowLightBtn.clicked.connect(self.yellow_on)
|
self.ui.yellowLightBtn.clicked.connect(self.yellow_on)
|
||||||
self.ui.greenLightBtn.clicked.connect(self.green_on)
|
self.ui.greenLightBtn.clicked.connect(self.green_on)
|
||||||
self.ui.offLightBtn.clicked.connect(self.leds_off)
|
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 = 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):
|
def spot_on(self):
|
||||||
print("Turn on light clicked")
|
print("Turn on light clicked")
|
||||||
@ -1113,9 +963,17 @@ class LightControl(QtWidgets.QMainWindow):
|
|||||||
print("LEDs are off")
|
print("LEDs are off")
|
||||||
self.w.turn_off_all()
|
self.w.turn_off_all()
|
||||||
|
|
||||||
def leds_blink(self):
|
def blink_yellow(self):
|
||||||
print("Previous color is blinking")
|
print("Yellow color is blinking")
|
||||||
self.w.change_effect()
|
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__":
|
if __name__ == "__main__":
|
||||||
import sys
|
import sys
|
||||||
|
1012
workflow2.py
1012
workflow2.py
File diff suppressed because it is too large
Load Diff
991
workflow3.py
991
workflow3.py
@ -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_())
|
|
Loading…
Reference in New Issue
Block a user