Compare commits
1 Commits
main
...
status_cle
Author | SHA1 | Date | |
---|---|---|---|
|
231d461f45 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
saved_frames/
|
||||
archive
|
||||
__pycache__
|
||||
.~lock*
|
||||
*.log
|
1
.~lock.Messungen des Einzelteile.ods#
Normal file
1
.~lock.Messungen des Einzelteile.ods#
Normal file
@ -0,0 +1 @@
|
||||
,clemens,cps-aio-001,01.07.2024 13:17,file:///home/clemens/.config/libreoffice/4;
|
@ -1 +0,0 @@
|
||||
{"rev":[1,0],"vid":2410270,"id":{"mdns":"wled-9986c8","name":"cps-warnlight-wled1","inv":"Light","sui":false},"nw":{"espnow":false,"linked_remote":"","ins":[{"ssid":"cpsWlan24GHz","pskl":10,"ip":[0,0,0,0],"gw":[0,0,0,0],"sn":[255,255,255,0]}],"dns":[10,71,1,1]},"ap":{"ssid":"wled_warnLight-AP","pskl":8,"chan":1,"hide":0,"behav":0,"ip":[4,3,2,1]},"wifi":{"sleep":false,"phy":false,"txpwr":78},"hw":{"led":{"total":18,"maxpwr":850,"ledma":0,"cct":false,"cr":false,"ic":false,"cb":0,"fps":42,"rgbwm":255,"ld":true,"ins":[{"start":0,"len":6,"pin":[16],"order":0,"rev":false,"skip":0,"type":22,"ref":false,"rgbwm":0,"freq":0,"maxpwr":283,"ledma":55},{"start":6,"len":6,"pin":[17],"order":0,"rev":false,"skip":0,"type":22,"ref":false,"rgbwm":0,"freq":0,"maxpwr":283,"ledma":55},{"start":12,"len":6,"pin":[18],"order":0,"rev":false,"skip":0,"type":22,"ref":false,"rgbwm":0,"freq":0,"maxpwr":283,"ledma":55}]},"com":[],"btn":{"max":4,"pull":true,"ins":[{"type":2,"pin":[0],"macros":[0,0,0]},{"type":0,"pin":[-1],"macros":[0,0,0]},{"type":0,"pin":[-1],"macros":[0,0,0]},{"type":0,"pin":[-1],"macros":[0,0,0]}],"tt":32,"mqtt":true},"ir":{"pin":-1,"type":0,"sel":true},"relay":{"pin":-1,"rev":false,"odrain":false},"baud":1152,"if":{"i2c-pin":[-1,-1],"spi-pin":[-1,-1,-1]}},"light":{"scale-bri":100,"pal-mode":0,"aseg":true,"gc":{"bri":1,"col":2.8,"val":2.8},"tr":{"mode":true,"fx":true,"dur":7,"pal":false,"rpc":5,"hrp":true},"nl":{"mode":1,"dur":60,"tbri":0,"macro":0}},"def":{"ps":4,"on":true,"bri":128},"if":{"sync":{"port0":21324,"port1":65506,"espnow":false,"recv":{"bri":true,"col":true,"fx":true,"pal":true,"grp":1,"seg":false,"sb":false},"send":{"en":false,"dir":false,"btn":false,"va":false,"hue":true,"grp":1,"ret":0}},"nodes":{"list":true,"bcast":true},"live":{"en":true,"mso":false,"rlm":true,"port":5568,"mc":false,"dmx":{"uni":1,"seqskip":false,"e131prio":0,"addr":1,"dss":0,"mode":4},"timeout":25,"maxbri":false,"no-gc":true,"offset":0},"va":{"alexa":false,"macros":[0,0],"p":0},"mqtt":{"en":true,"broker":"10.71.1.103","port":1883,"user":"cpsMqtt","pskl":10,"cid":"WLED-9986c8","rtn":false,"topics":{"device":"wled/9986c8","group":"wled/all"}},"hue":{"en":false,"id":1,"iv":25,"recv":{"on":true,"bri":true,"col":true},"ip":[10,71,1,0]},"ntp":{"en":false,"host":"0.wled.pool.ntp.org","tz":0,"offset":0,"ampm":false,"ln":0,"lt":0}},"ol":{"clock":0,"cntdwn":false,"min":0,"max":29,"o12pix":0,"o5m":false,"osec":false,"osb":false},"timers":{"cntdwn":{"goal":[20,1,1,0,0,0],"macro":0},"ins":[]},"ota":{"lock":false,"lock-wifi":false,"pskl":7,"aota":true},"um":{"AudioReactive":{"enabled":false,"add-palettes":false,"analogmic":{"pin":-1},"digitalmic":{"type":1,"pin":[32,15,14,-1]},"config":{"squelch":10,"gain":60,"AGC":0},"frequency":{"scale":3},"dynamics":{"limiter":true,"rise":80,"fall":1400},"sync":{"port":11988,"mode":0}}}}
|
File diff suppressed because one or more lines are too long
@ -1,3 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'test.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
########## beim Static workflow funktionieren die Threads ab dem zweiten nicht mehr
|
||||
|
||||
#from PyQt5 import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QProgressBar
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
@ -12,56 +23,48 @@ 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
|
||||
'host': 'localhost',
|
||||
'database': 'projectGeislinger',
|
||||
'port': 3306 # Standard port for MariaDB
|
||||
}
|
||||
|
||||
# # Establishing the connection
|
||||
# conn = mariadb.connect(**db_config)
|
||||
# # Create a cursor to execute queries
|
||||
# cursor = conn.cursor()
|
||||
# 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
|
||||
# Konfiguration der seriellen Schnittstelle
|
||||
ser = serial.Serial('/dev/ttyUSB0', 9600)
|
||||
#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/
|
||||
|
||||
|
||||
# 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.")
|
||||
waageEingeschwungen = False
|
||||
|
||||
# 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
|
||||
|
||||
def wahrscheinlichkeitsDichte(x,mue, var):
|
||||
# in der Funktion wird der Wahrscheinlichkeitsdichtenwert der Variable x für eine bestimmte Normalverteilung berechnet
|
||||
standardabweichung = var**0.5
|
||||
|
||||
result = 1/(standardabweichung * (2*math.pi)**0.5 ) * math.exp(-0.5 * ((x-mue)/standardabweichung)**2)
|
||||
|
||||
return result
|
||||
|
||||
def calcWahrscheinlichkeitFromDichte(x,mue, var):
|
||||
# in der Funktion wird die Wahrscheinlichkeit via der Wahrscheinlichkeitsdichte berechnet, indem das Verhältnis aus der dem Bauteil zugehörigen Wahrscheinlichkeitsdichte zu der maximalen Wahrscheinlichkeitsdichte berechnet wird
|
||||
p1 = wahrscheinlichkeitsDichte(x,mue, var)
|
||||
p_max = wahrscheinlichkeitsDichte(mue,mue, var)
|
||||
|
||||
return p1/p_max
|
||||
|
||||
|
||||
|
||||
#class Worker(QThread):
|
||||
class Worker(QObject):
|
||||
#progress = pyqtSignal(int)
|
||||
objectDetectionStartSignal = pyqtSignal(str)
|
||||
@ -74,7 +77,6 @@ class Worker(QObject):
|
||||
waageStoppedSignal = pyqtSignal(int)
|
||||
stopLoopSignal = pyqtSignal(bool) #das Signal wird verwendet um direkt den stopLoop-Wert zu ändern (also kein Funktionsaufruf)
|
||||
|
||||
waageEingeschwungen = False
|
||||
stopLoop = False
|
||||
btTypeIsSet = False
|
||||
correctBtNr = False
|
||||
@ -86,7 +88,7 @@ class Worker(QObject):
|
||||
|
||||
|
||||
def getDataOfArticleType(self, allArticles, articleType):
|
||||
''' die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück '''
|
||||
# die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück
|
||||
for i in allArticles:
|
||||
if i[1] == articleType:
|
||||
return i
|
||||
@ -96,27 +98,26 @@ class Worker(QObject):
|
||||
def waageNichtEingeschwungenOutput(self):
|
||||
print("Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft.")
|
||||
|
||||
def wahrscheinlichkeitsDichte(self, x,mue, var):
|
||||
''' in der Funktion wird der Wahrscheinlichkeitsdichtenwert der Variable x für eine bestimmte Normalverteilung berechnet '''
|
||||
standardabweichung = var**0.5
|
||||
|
||||
result = 1/(standardabweichung * (2*math.pi)**0.5 ) * math.exp(-0.5 * ((x-mue)/standardabweichung)**2)
|
||||
|
||||
return result
|
||||
|
||||
def readWaage(self):
|
||||
''' in folgender Funktion wird die Waage ausgelesen '''
|
||||
# in folgender Funktion wird die Waage ausgelesen
|
||||
|
||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
||||
#print("port to which it is connected: ", ser.portstr) #Debuggingausgabe
|
||||
|
||||
|
||||
if ser.is_open == False:
|
||||
ser.open()
|
||||
|
||||
|
||||
#an die Waage den Befehl senden, dass sie ausgelesen werden soll
|
||||
ser.write(b'getWeight\n')
|
||||
#ser.write(b'tare\n')
|
||||
serialString = ser.readline().decode('utf-8').rstrip() #Auslesen des Serial-Strings/der Messung der Waage
|
||||
|
||||
# wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft
|
||||
lenString = len(serialString)-1
|
||||
if serialString[lenString] == "g" and serialString[lenString-1] == "k":
|
||||
#print("ist eingeschwungen") #Debuggingausgabe
|
||||
waageEingeschwungen = True
|
||||
else:
|
||||
print("die Waage ist noch nicht eingeschwungen")
|
||||
@ -128,13 +129,17 @@ class Worker(QObject):
|
||||
if i=="-" or i=="0" or i=="." or i=="1" or i=="2" or i=="3" or i=="4" or i=="5" or i=="6" or i=="7" or i=="8" or i=="9":
|
||||
intString = intString + i
|
||||
print("Wert, welcher von der Waage ausgelesen wurde: " + intString + "kg")
|
||||
## Waage auslesen - ENDE
|
||||
|
||||
ser.close()
|
||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
||||
|
||||
return waageEingeschwungen, intString
|
||||
|
||||
def objectTypeDetectionThread(self, auftragsnummer):
|
||||
''' in dieser Funktion wird der Typ des Bauteils automatisch erkannt '''
|
||||
# in dieser Funktion wird der Typ des Bauteils automatisch erkannt
|
||||
|
||||
#print("objectTypeDetectionThread - Running in thread:", threading.current_thread().name) #Debuggausgabe
|
||||
|
||||
# Parameterdefinition
|
||||
propDensVect = []
|
||||
@ -154,9 +159,16 @@ class Worker(QObject):
|
||||
cursor.execute(sql_query)
|
||||
auftragEinzelteilDaten = cursor.fetchall()
|
||||
|
||||
'''
|
||||
# Display data #Debugausgabe
|
||||
print("Ausgabe der Auftragsdetails des obigen Auftrags, inklusive Einzelteildetails:")
|
||||
for row in auftragEinzelteilDaten:
|
||||
print(row)
|
||||
'''
|
||||
|
||||
# in der Folge werden alle Wahrscheinlichkeitsdichten der Auftragsbauteile berechnet und in dem Vektor gesammelt
|
||||
for row in auftragEinzelteilDaten:
|
||||
propDensVect.append([self.wahrscheinlichkeitsDichte(float(intString),float(row[6]), float(row[7])), row[1], row[5]])
|
||||
propDensVect.append([wahrscheinlichkeitsDichte(float(intString),float(row[6]), float(row[7])), row[1], row[5]])
|
||||
|
||||
# Jenen Eintrag des propDensVect raussuchen, welcher die größte Wahrscheinlichkeitsdichte beinhaltet
|
||||
maxpropDens = 0
|
||||
@ -174,6 +186,14 @@ class Worker(QObject):
|
||||
else:
|
||||
print("Bei dem Bauteil" , einzelteilID , "wurde die höchste Wahrscheinlichkeitsdichte berechnet.")
|
||||
|
||||
# Wahrscheinlichkeit berechnen, dass das angegebene Bauteil auch wirklich diesem entspricht
|
||||
prop = 0
|
||||
for row in auftragEinzelteilDaten:
|
||||
if row[1] == einzelteilID:
|
||||
prop = calcWahrscheinlichkeitFromDichte(float(intString),float(row[6]), float(row[7]))
|
||||
break
|
||||
print("Die Wahrscheinlichkeit, dass es das Bauteil ist, beträgt: ", prop)
|
||||
|
||||
# den Bool auf true setzen, damit die Schleife beendet wird - dieser wird auf True gesetzt, wenn ein Bauteiltyp erkannt wird
|
||||
self.btTypeIsSet = True
|
||||
|
||||
@ -184,8 +204,7 @@ class Worker(QObject):
|
||||
self.waageStoppedSignal.emit(einzelteilID)
|
||||
|
||||
def checkWaageThread(self, einzelteilID, teileZuViel, auftragsnummer):
|
||||
''' in dieser Funktion wird die Stückzahl der Bauteile, welche auf der Waage liegen, berechnet '''
|
||||
|
||||
|
||||
self.correctBtNr = False
|
||||
prevAnzahl = 0
|
||||
anzahl = 0
|
||||
@ -203,6 +222,14 @@ class Worker(QObject):
|
||||
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer
|
||||
cursor.execute(sql_query)
|
||||
auftragDaten = cursor.fetchall()
|
||||
|
||||
'''
|
||||
# Display data - zum Debuggen
|
||||
print("Ausgabe der Auftragsdetails:")
|
||||
print("id|EinzelteilID|Auftragsnummer|Anzahl")
|
||||
for row in auftragDaten:
|
||||
print(row)
|
||||
'''
|
||||
|
||||
#auslesen, wie viele Bauteile des Types laut Auftrag vorhanden sein sollen
|
||||
anzBauteile_soll = 0
|
||||
@ -225,7 +252,7 @@ class Worker(QObject):
|
||||
# seien X1,..., Xn unabhängige Zufallsvariablen die N(mue_i, sigma_i^2) verteilt sind, dann ist X = X1+...+Xn - N(mue, sigma^2) verteilt mit mue=mue1+...+mue_n, sigma^2 = sigma_1^2+...+sigma_n^2
|
||||
mueGes = float(articleData[6])*i # Berechnen des äquivalenten Mittelwert
|
||||
varGes = float(articleData[7])*i # Berechnen der äquivalenten Varianz
|
||||
propDensVect.append([self.wahrscheinlichkeitsDichte(float(intString),mueGes, varGes), i])
|
||||
propDensVect.append([wahrscheinlichkeitsDichte(float(intString),mueGes, varGes), i])
|
||||
|
||||
# durch den propDensVect iterieren und jenen Eintrag mit der höchsten Wahrscheinlichkeitsdichte raussuchen
|
||||
maxpropDens = 0
|
||||
@ -238,6 +265,14 @@ class Worker(QObject):
|
||||
if prevAnzahl != anzahl:
|
||||
prevAnzahl = anzahl
|
||||
|
||||
# Die Wahrscheinlichkeit berechnen, dass das obige Ergebnis auch dem Bauteil entspricht
|
||||
if anzahl > 0:
|
||||
for row in auftragDaten:
|
||||
if row[1] == einzelteilID:
|
||||
prop = calcWahrscheinlichkeitFromDichte(float(intString),float(row[6])*anzahl, float(row[7])*anzahl)
|
||||
break
|
||||
print("Die Wahrscheinlichkeit, dass es das Bauteil ist, beträgt: ", prop)
|
||||
|
||||
# wenn genug Bauteile vorhanden sind, dann soll die Schleife beendet werden
|
||||
if (anzahl == anzBauteile_soll):
|
||||
self.correctBtNr = True
|
||||
@ -257,7 +292,8 @@ class Worker(QObject):
|
||||
self.waageStoppedSignal.emit(einzelteilID)
|
||||
|
||||
|
||||
## in der Ui_MainWindow-Klasse wird die GUI erstellt - der MainThread läuft in dieser
|
||||
|
||||
|
||||
class Ui_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
self.auftragsnummer = ""
|
||||
@ -265,6 +301,7 @@ class Ui_MainWindow(object):
|
||||
self.correctBtNr = False
|
||||
self.btTypeIsSet = False
|
||||
|
||||
|
||||
MainWindow.setObjectName("MainWindow")
|
||||
MainWindow.resize(1400, 675)
|
||||
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
||||
@ -387,46 +424,15 @@ class Ui_MainWindow(object):
|
||||
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.myTestLambda = lambda: self.worker.checkWaageStartSignal.emit(einzelteilID, self.teileZuViel, self.auftragsnummer)
|
||||
|
||||
'''
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(8)
|
||||
item.setFont(font)
|
||||
self.AuftragsdetailsTable.setVerticalHeaderItem(0,item)
|
||||
'''
|
||||
self.retranslateUi(MainWindow)
|
||||
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||
|
||||
@ -458,6 +464,8 @@ class Ui_MainWindow(object):
|
||||
item = self.ArbeitsschrittTable.horizontalHeaderItem(1)
|
||||
item.setText(_translate("MainWindow", "ToDo:"))
|
||||
|
||||
# Befüllen der Arbeisschritttabelle mit Text
|
||||
#item = self.ArbeitsschrittTable.
|
||||
# Ein neues QTableWidgetItem erstellen und den Text setzen
|
||||
item = QtWidgets.QTableWidgetItem("Auftrag laden")
|
||||
self.ArbeitsschrittTable.setItem(0, 0, item)
|
||||
@ -475,10 +483,19 @@ class Ui_MainWindow(object):
|
||||
self.ArbeitsschrittTable.setItem(3, 0, item)
|
||||
self.ArbeitsschrittTable.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers)
|
||||
|
||||
#self.ArbeitsschrittTable.item(0,0).setText("test")
|
||||
|
||||
#einzelteilID = int(self.AuftragsdetailsTable.item(i,0).text())
|
||||
#self.PosNrTxtFeld.setText(str(self.AuftragsdetailsTable.item(i,0).text()))
|
||||
#self.bauteiltypTextbox.setText(str(self.AuftragsdetailsTable.item(i,2).text()))
|
||||
|
||||
self.label.setText(_translate("MainWindow", "Auftragsnummer:"))
|
||||
self.bauteilTypBtn.setText(_translate("MainWindow", "Bauteiltyp erkennen"))
|
||||
self.bauteilTypBtn.clicked.connect(self.objectTypeDetection)
|
||||
self.AuftragsdetailsTable.cellClicked.connect(self.onTableCellClick)
|
||||
#self.AuftragsdetailsTable.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers)
|
||||
#item = self.AuftragsdetailsTable.verticalHeaderItem(0)
|
||||
#item.setText(_translate("MainWindow", "test"))
|
||||
self.BezeichnungLabel.setText(_translate("MainWindow", "Bezeichnung"))
|
||||
self.PosNrLabel.setText(_translate("MainWindow", "Pos.-Nr:"))
|
||||
self.teileZuVielLabel.setText(_translate("MainWindow", "Zu prüfende Teileanzahl über Auftragsanzahl:"))
|
||||
@ -498,35 +515,21 @@ class Ui_MainWindow(object):
|
||||
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 '''
|
||||
#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")
|
||||
@ -543,6 +546,9 @@ class Ui_MainWindow(object):
|
||||
for i in range(0,self.AuftragsdetailsTable.rowCount()):
|
||||
if(self.AuftragsdetailsTable.item(i,0).text() == str(posNr)):
|
||||
return i
|
||||
# brauche ich hier vermutlich nicht mehr - ist in den Worker Thread kopiert worden
|
||||
def waageNichtEingeschwungenOutput(self):
|
||||
print("Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft.")
|
||||
|
||||
def onTableCellClick(self):
|
||||
self.PosNrTxtFeld.setText(self.AuftragsdetailsTable.item(self.AuftragsdetailsTable.currentRow(),0).text())
|
||||
@ -566,22 +572,72 @@ class Ui_MainWindow(object):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
# eventuell benötigt man die Funktion hier nicht mehr, da sie zu den Threads kopiert wurde
|
||||
def getDataOfArticleType(self, allArticles, articleType):
|
||||
# die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück
|
||||
for i in allArticles:
|
||||
if i[1] == articleType:
|
||||
return i
|
||||
return -1
|
||||
|
||||
def updateGUI(self):
|
||||
self.PosNrLabel.repaint() #GUI aktualisieren
|
||||
QApplication.processEvents() #GUI aktualisieren
|
||||
|
||||
|
||||
def setRowColor(self, tableObject, rowID,r,g,b):
|
||||
for col in range(tableObject.columnCount()-1):
|
||||
tableObject.item(rowID, col).setBackground(QtGui.QColor(r,g,b))
|
||||
'''
|
||||
die alte Version der Programmierung
|
||||
tableObject.item(rowID, 0).setBackground(QtGui.QColor(r,g,b))
|
||||
tableObject.item(rowID, 1).setBackground(QtGui.QColor(r,g,b))
|
||||
tableObject.item(rowID, 2).setBackground(QtGui.QColor(r,g,b))
|
||||
tableObject.item(rowID, 3).setBackground(QtGui.QColor(r,g,b))
|
||||
tableObject.item(rowID, 4).setBackground(QtGui.QColor(r,g,b))
|
||||
tableObject.item(rowID, 5).setBackground(QtGui.QColor(r,g,b))
|
||||
'''
|
||||
|
||||
# # 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])
|
||||
#wird hier vermutlich nicht mehr benötigt - wurde in die Workerklasse kopiert
|
||||
def readWaage(self):
|
||||
# in folgender Funktion wird die Waage ausgelesen
|
||||
|
||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
||||
#print("port to which it is connected: ", ser.portstr) #Debuggingausgabe
|
||||
self.checkPosNrEmpty()
|
||||
|
||||
if ser.is_open == False:
|
||||
ser.open()
|
||||
|
||||
|
||||
#an die Waage den Befehl senden, dass sie ausgelesen werden soll
|
||||
ser.write(b'getWeight\n')
|
||||
#ser.write(b'tare\n')
|
||||
serialString = ser.readline().decode('utf-8').rstrip() #Auslesen des Serial-Strings/der Messung der Waage
|
||||
|
||||
# wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft
|
||||
lenString = len(serialString)-1
|
||||
if serialString[lenString] == "g" and serialString[lenString-1] == "k":
|
||||
#print("ist eingeschwungen") #Debuggingausgabe
|
||||
waageEingeschwungen = True
|
||||
else:
|
||||
print("die Waage ist noch nicht eingeschwungen")
|
||||
waageEingeschwungen = False
|
||||
|
||||
#aus dem String werden alle Zeichen, welche nicht zur Darstellung der Zahl benötigt werden entfernt
|
||||
intString = ""
|
||||
for i in serialString:
|
||||
if i=="-" or i=="0" or i=="." or i=="1" or i=="2" or i=="3" or i=="4" or i=="5" or i=="6" or i=="7" or i=="8" or i=="9":
|
||||
intString = intString + i
|
||||
print("Wert, welcher von der Waage ausgelesen wurde: " + intString + "kg")
|
||||
## Waage auslesen - ENDE
|
||||
|
||||
ser.close()
|
||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
||||
|
||||
return waageEingeschwungen, intString
|
||||
|
||||
def auftragsBtnClicked(self):
|
||||
databaseQueryWorking = False #wird für die Überprüfung, ob die Datenbankabfrage fehlerhaft ist, verwendet
|
||||
@ -600,7 +656,16 @@ class Ui_MainWindow(object):
|
||||
print("Fehler in der Datenbankabfrage.")
|
||||
|
||||
|
||||
|
||||
if databaseQueryWorking==True and len(auftragEinzelteilDaten)>0:
|
||||
'''
|
||||
# Display data
|
||||
print("Ausgabe der Auftragsdetails des obigen Auftrags, inklusive Einzelteildetails:")
|
||||
for row in auftragEinzelteilDaten:
|
||||
if str(row[2]) == self.auftragsnummer:
|
||||
print("passt")
|
||||
print(row)
|
||||
'''
|
||||
|
||||
### die Auftragsdaten in die Tabelle laden
|
||||
self.AuftragsdetailsTable.setRowCount(len(auftragEinzelteilDaten))
|
||||
@ -647,6 +712,7 @@ class Ui_MainWindow(object):
|
||||
self.bauteiltypTextbox.setText("")
|
||||
self.PosNrTxtFeld.setText("")
|
||||
|
||||
|
||||
elif(databaseQueryWorking==True and len(auftragEinzelteilDaten)==0):
|
||||
print("Es wurde in der Datenbank kein Auftrag mit dieser Auftragsnummer gefunden.")
|
||||
|
||||
@ -659,7 +725,7 @@ class Ui_MainWindow(object):
|
||||
self.setRowColor(self.AuftragsdetailsTable, row,0,255,0)
|
||||
|
||||
def stopLoopClicked(self):
|
||||
''' damit wird beim Klick auf den Stopbutton der stopLoop-boolWert in der Workerklasse auf true gesetzt -> der Stop des Threads wird initiiert '''
|
||||
# damit wird beim Klick auf den Stopbutton der stopLoop-boolWert in der Workerklasse auf true gesetzt -> der Stop des Threads wird initiiert
|
||||
if hasattr(self, 'objectDetectionWorker'):
|
||||
self.objectDetectionWorker.stopLoopSignal.emit(True)
|
||||
|
||||
@ -667,15 +733,20 @@ class Ui_MainWindow(object):
|
||||
self.checkWaageWorker.stopLoopSignal.emit(True)
|
||||
|
||||
def checkFinished(self):
|
||||
''' die Funktion geht alle Zeilen der Auftragsliste durch und schaut, ob die richtige Anzahl an Teilen vorhanden sind '''
|
||||
#die Funktion geht alle Zeilen der Auftragsliste durch und schaut, ob die richtige Anzahl an Teilen vorhanden sind
|
||||
for i in range(0,self.AuftragsdetailsTable.rowCount()):
|
||||
if self.AuftragsdetailsTable.item(i,3).text() != self.AuftragsdetailsTable.item(i,4).text():
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def checkWaage(self):
|
||||
#print("Running in thread:", threading.current_thread().name) # Debuggingausgabe
|
||||
QApplication.processEvents()
|
||||
|
||||
# die Loopvariable des Workers auf False setzten, damit die Schleife durchgelaufen wird (diese wird zum Abbruch der Schleife benötigt -> siehe stopLoop)
|
||||
#self.checkWaageWorker.stopLoopSignal.emit(False)
|
||||
|
||||
# überprüfen, ob der Auftrag geladen wurde
|
||||
if(self.AuftragsdetailsTable.item(0,0) == None):
|
||||
print("Der Auftrag muss zuerst geladen werden.")
|
||||
@ -764,13 +835,22 @@ class Ui_MainWindow(object):
|
||||
#self.updateGUI()
|
||||
|
||||
def objectTypeDetection(self):
|
||||
''' in dieser Funktion wird der Typ des Bauteils automatisch erkannt '''
|
||||
# in dieser Funktion wird der Typ des Bauteils automatisch erkannt
|
||||
|
||||
# wenn der statische Workflow ausgewählt wurde, dann soll die checkWaage Funktion aufgerufen werden, auch wenn die detectBauteiltyp-Funkion aufgerufen wurde
|
||||
if self.checkBox.isChecked() == True:
|
||||
self.checkWaage()
|
||||
return
|
||||
|
||||
'''
|
||||
if(self.checkPosNrEmpty()==True):
|
||||
print("Das Pos.-Nr.-Feld ist leer.")
|
||||
return
|
||||
'''
|
||||
|
||||
# die Loopvariable des Workers auf False setzten, damit die Schleife durchgelaufen wird (diese wird zum Abbruch der Schleife benötigt -> siehe stopLoop)
|
||||
#self.objectDetectionWorker.stopLoopSignal.emit(False)
|
||||
|
||||
# überprüfen, ob der Auftrag in die Tabelle geladen wurde
|
||||
if(self.AuftragsdetailsTable.item(0,0) == None):
|
||||
print("Der Auftrag muss zuerst geladen werden.")
|
||||
@ -794,7 +874,7 @@ class Ui_MainWindow(object):
|
||||
self.objectDetectionThread.start()
|
||||
|
||||
def objectTypeDetectionFinished(self, einzelteilID, rowData):
|
||||
''' wenn der Typ des Objektes erkannt wurde, dann soll die Funktion aufgerufen werden '''
|
||||
# wenn der Typ des Objektes erkannt wurde, dann soll die Funktion aufgerufen werden
|
||||
|
||||
# Schreiben der Bauteiltype und Pos.-Nr in die jeweiligen Felder
|
||||
self.PosNrTxtFeld.setText(str(rowData[1]))
|
||||
@ -810,12 +890,20 @@ class Ui_MainWindow(object):
|
||||
self.objectDetectionThread.quit()
|
||||
self.objectDetectionThread.wait()
|
||||
|
||||
'''
|
||||
try:
|
||||
self.objectDetectionThread.started.disconnect() # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt
|
||||
except:
|
||||
print(f"Error while disconnecting: {e}")
|
||||
print("Disconnecting the thread did not work.")
|
||||
'''
|
||||
|
||||
# wenn der Bauteiltyp erkannt wurde, dann soll die GUI aktualisiert werden und anschließend die CheckWaage-Funktion aufgerufen werden
|
||||
self.updateGUI()
|
||||
self.checkWaage()
|
||||
|
||||
def threadStopped(self, einzelteilID):
|
||||
''' wenn kein Bauteil erkannt wurde, dann ist die EinzenteilID = 0 '''
|
||||
# wenn kein Bauteil erkannt wurde, dann ist die EinzenteilID = 0
|
||||
if self.checkFinished() == False:
|
||||
if(einzelteilID > 0):
|
||||
self.setRowColor(self.AuftragsdetailsTable, self.getRowNr(einzelteilID),255,255,255) #zum setzen den Farbe der gesamten Reihe auf Weiß
|
||||
@ -833,147 +921,10 @@ class Ui_MainWindow(object):
|
||||
self.checkWaageThread.wait()
|
||||
print("Der CheckWaage-Thread wurde beendet.")
|
||||
|
||||
# new class for Camera Object detection with YOLOv8
|
||||
class CameraStreamApp(QtWidgets.QMainWindow):
|
||||
def __init__(self, ui):
|
||||
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
|
||||
@ -981,11 +932,10 @@ if __name__ == "__main__":
|
||||
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_())
|
||||
sys.exit(app.exec_())
|
||||
|
||||
|
||||
|
||||
|
||||
|
751
GUI_19_09_staticWorkflow_Multithreading.py
Normal file
751
GUI_19_09_staticWorkflow_Multithreading.py
Normal file
@ -0,0 +1,751 @@
|
||||
# -*- 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.
|
||||
|
||||
|
||||
##########Es muss noch überprüft werden, ob der PC mit der Waage überhaupt verbunden ist
|
||||
|
||||
#from PyQt5 import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QProgressBar
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
from PyQt5.QtCore import QTimer, QThread, pyqtSignal, QObject
|
||||
import serial
|
||||
import binascii
|
||||
import math
|
||||
import mariadb
|
||||
import time
|
||||
import threading
|
||||
|
||||
|
||||
db_config = {
|
||||
'user': 'dbUser',
|
||||
'password': 'dbPassword',
|
||||
'host': 'localhost',
|
||||
'database': 'projectGeislinger',
|
||||
'port': 3306 # Standard port for MariaDB
|
||||
}
|
||||
|
||||
# Establishing the connection
|
||||
conn = mariadb.connect(**db_config)
|
||||
# Create a cursor to execute queries
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Konfiguration der seriellen Schnittstelle
|
||||
ser = serial.Serial('/dev/ttyUSB0', 9600)
|
||||
|
||||
waageEingeschwungen = False
|
||||
|
||||
|
||||
def wahrscheinlichkeitsDichte(x,mue, var):
|
||||
# in der Funktion wird der Wahrscheinlichkeitsdichtenwert der Variable x für eine bestimmte Normalverteilung berechnet
|
||||
standardabweichung = var**0.5
|
||||
|
||||
result = 1/(standardabweichung * (2*math.pi)**0.5 ) * math.exp(-0.5 * ((x-mue)/standardabweichung)**2)
|
||||
|
||||
return result
|
||||
|
||||
def calcWahrscheinlichkeitFromDichte(x,mue, var):
|
||||
# in der Funktion wird die Wahrscheinlichkeit via der Wahrscheinlichkeitsdichte berechnet, indem das Verhältnis aus der dem Bauteil zugehörigen Wahrscheinlichkeitsdichte zu der maximalen Wahrscheinlichkeitsdichte berechnet wird
|
||||
p1 = wahrscheinlichkeitsDichte(x,mue, var)
|
||||
p_max = wahrscheinlichkeitsDichte(mue,mue, var)
|
||||
|
||||
return p1/p_max
|
||||
|
||||
|
||||
|
||||
#class Worker(QThread):
|
||||
class Worker(QObject):
|
||||
#progress = pyqtSignal(int)
|
||||
objectDetectionStartSignal = pyqtSignal(str)
|
||||
objectDetectionFinishedSignal = pyqtSignal(int, object)
|
||||
|
||||
checkWaageStartSignal = pyqtSignal(int, int, str)
|
||||
checkWaageUpdateSignal = pyqtSignal(int, int)
|
||||
checkWaageFinishedSignal = pyqtSignal(int)
|
||||
|
||||
waageStoppedSignal = pyqtSignal(int)
|
||||
stopLoopSignal = pyqtSignal(bool) #das Signal wird verwendet um direkt den stopLoop-Wert zu ändern (also kein Funktionsaufruf)
|
||||
|
||||
stopLoop = False
|
||||
btTypeIsSet = False
|
||||
correctBtNr = False
|
||||
|
||||
|
||||
def __init__(self):
|
||||
super(Worker, self).__init__()
|
||||
stopLoop = False
|
||||
|
||||
|
||||
def getDataOfArticleType(self, allArticles, articleType):
|
||||
# die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück
|
||||
for i in allArticles:
|
||||
if i[1] == articleType:
|
||||
return i
|
||||
|
||||
return -1
|
||||
|
||||
def waageNichtEingeschwungenOutput(self):
|
||||
print("Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft.")
|
||||
|
||||
def readWaage(self):
|
||||
# in folgender Funktion wird die Waage ausgelesen
|
||||
|
||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
||||
#print("port to which it is connected: ", ser.portstr) #Debuggingausgabe
|
||||
|
||||
|
||||
if ser.is_open == False:
|
||||
ser.open()
|
||||
|
||||
|
||||
#an die Waage den Befehl senden, dass sie ausgelesen werden soll
|
||||
ser.write(b'getWeight\n')
|
||||
#ser.write(b'tare\n')
|
||||
serialString = ser.readline().decode('utf-8').rstrip() #Auslesen des Serial-Strings/der Messung der Waage
|
||||
|
||||
# wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft
|
||||
lenString = len(serialString)-1
|
||||
if serialString[lenString] == "g" and serialString[lenString-1] == "k":
|
||||
#print("ist eingeschwungen") #Debuggingausgabe
|
||||
waageEingeschwungen = True
|
||||
else:
|
||||
print("die Waage ist noch nicht eingeschwungen")
|
||||
waageEingeschwungen = False
|
||||
|
||||
#aus dem String werden alle Zeichen, welche nicht zur Darstellung der Zahl benötigt werden entfernt
|
||||
intString = ""
|
||||
for i in serialString:
|
||||
if i=="-" or i=="0" or i=="." or i=="1" or i=="2" or i=="3" or i=="4" or i=="5" or i=="6" or i=="7" or i=="8" or i=="9":
|
||||
intString = intString + i
|
||||
print("Wert, welcher von der Waage ausgelesen wurde: " + intString + "kg")
|
||||
## Waage auslesen - ENDE
|
||||
|
||||
ser.close()
|
||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
||||
|
||||
return waageEingeschwungen, intString
|
||||
|
||||
def objectTypeDetectionThread(self, auftragsnummer):
|
||||
# in dieser Funktion wird der Typ des Bauteils automatisch erkannt
|
||||
|
||||
#print("objectTypeDetectionThread - Running in thread:", threading.current_thread().name) #Debuggausgabe
|
||||
|
||||
# Parameterdefinition
|
||||
propDensVect = []
|
||||
|
||||
self.btTypeIsSet = False
|
||||
|
||||
while(self.btTypeIsSet == False and self.stopLoop == False):
|
||||
|
||||
# Auslesen der Waage
|
||||
waageEingeschwungen, intString = self.readWaage()
|
||||
if waageEingeschwungen == False:
|
||||
self.waageNichtEingeschwungenOutput()
|
||||
else:
|
||||
|
||||
# Datenbankabfrage
|
||||
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer
|
||||
cursor.execute(sql_query)
|
||||
auftragEinzelteilDaten = cursor.fetchall()
|
||||
|
||||
'''
|
||||
# Display data #Debugausgabe
|
||||
print("Ausgabe der Auftragsdetails des obigen Auftrags, inklusive Einzelteildetails:")
|
||||
for row in auftragEinzelteilDaten:
|
||||
print(row)
|
||||
'''
|
||||
|
||||
# in der Folge werden alle Wahrscheinlichkeitsdichten der Auftragsbauteile berechnet und in dem Vektor gesammelt
|
||||
for row in auftragEinzelteilDaten:
|
||||
propDensVect.append([wahrscheinlichkeitsDichte(float(intString),float(row[6]), float(row[7])), row[1], row[5]])
|
||||
|
||||
# Jenen Eintrag des propDensVect raussuchen, welcher die größte Wahrscheinlichkeitsdichte beinhaltet
|
||||
maxpropDens = 0
|
||||
einzelteilID = 0
|
||||
rowData = None
|
||||
for row in propDensVect:
|
||||
if row[0] > maxpropDens:
|
||||
maxpropDens = row[0]
|
||||
einzelteilID = row[1]
|
||||
rowData = row
|
||||
|
||||
# überprüfen, ob das aufliegende Bauteil in der Auftragstabelle vorhanden ist
|
||||
if(einzelteilID == 0):
|
||||
print("Es wurde kein Bauteil aus der Auftragsliste (Tabelle) erkannt.")
|
||||
else:
|
||||
print("Bei dem Bauteil" , einzelteilID , "wurde die höchste Wahrscheinlichkeitsdichte berechnet.")
|
||||
|
||||
# Wahrscheinlichkeit berechnen, dass das angegebene Bauteil auch wirklich diesem entspricht
|
||||
prop = 0
|
||||
for row in auftragEinzelteilDaten:
|
||||
if row[1] == einzelteilID:
|
||||
prop = calcWahrscheinlichkeitFromDichte(float(intString),float(row[6]), float(row[7]))
|
||||
break
|
||||
print("Die Wahrscheinlichkeit, dass es das Bauteil ist, beträgt: ", prop)
|
||||
|
||||
# den Bool auf true setzen, damit die Schleife beendet wird - dieser wird auf True gesetzt, wenn ein Bauteiltyp erkannt wird
|
||||
self.btTypeIsSet = True
|
||||
|
||||
if(self.stopLoop == False):
|
||||
# ein Signal zurück an den MainThreat senden, mit den Infos/Ergebnissen, der Typenbestimmung
|
||||
self.objectDetectionFinishedSignal.emit(einzelteilID, rowData)
|
||||
else:
|
||||
self.waageStoppedSignal.emit(einzelteilID)
|
||||
|
||||
|
||||
|
||||
def checkWaageThread(self, einzelteilID, teileZuViel, auftragsnummer):
|
||||
|
||||
|
||||
self.correctBtNr = False
|
||||
prevAnzahl = 0
|
||||
anzahl = 0
|
||||
einzelteilID = einzelteilID
|
||||
|
||||
while (self.correctBtNr == False and self.stopLoop == False):
|
||||
|
||||
#überprüfen, ob die Waage eingeschwungen ist (und damit korrekte Ergebnisse liefert)
|
||||
waageEingeschwungen, intString = self.readWaage()
|
||||
if waageEingeschwungen == False:
|
||||
self.waageNichtEingeschwungenOutput()
|
||||
else:
|
||||
|
||||
# Datenbankabfrage - holen der Auftrags- und Bauteilinfos
|
||||
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer
|
||||
cursor.execute(sql_query)
|
||||
auftragDaten = cursor.fetchall()
|
||||
|
||||
'''
|
||||
# Display data - zum Debuggen
|
||||
print("Ausgabe der Auftragsdetails:")
|
||||
print("id|EinzelteilID|Auftragsnummer|Anzahl")
|
||||
for row in auftragDaten:
|
||||
print(row)
|
||||
'''
|
||||
|
||||
#auslesen, wie viele Bauteile des Types laut Auftrag vorhanden sein sollen
|
||||
anzBauteile_soll = 0
|
||||
idVorhanden = False
|
||||
for row in auftragDaten:
|
||||
if row[1] == einzelteilID:
|
||||
anzBauteile_soll = row[3]
|
||||
idVorhanden = True
|
||||
|
||||
if(idVorhanden == False):
|
||||
print("Die gewählte Pos.Nr ist nicht in der Auftragsliste (Tabelle) vorhanden.")
|
||||
return
|
||||
|
||||
# Berechnen der Wahrscheinlichkeitsdichten - der Betrag aller Wahrscheinlichkeitsdichten werden im propDensVect gespeichert
|
||||
propDensVect = []
|
||||
articleData = self.getDataOfArticleType(auftragDaten, einzelteilID)
|
||||
for i in range(1,anzBauteile_soll+teileZuViel+1):
|
||||
# Mathematische Sätze, auf welchen die Berechnung basiert:
|
||||
# seien X1,..., Xn unabhängige Zufallsvariablen die N(mue_i, sigma_i^2) verteilt sind, dann ist X = X1+...+Xn - N(mue, sigma^2) verteilt mit mue=mue1+...+mue_n, sigma^2 = sigma_1^2+...+sigma_n^2
|
||||
mueGes = float(articleData[6])*i # Berechnen des äquivalenten Mittelwert
|
||||
varGes = float(articleData[7])*i # Berechnen der äquivalenten Varianz
|
||||
propDensVect.append([wahrscheinlichkeitsDichte(float(intString),mueGes, varGes), i])
|
||||
|
||||
# durch den propDensVect iterieren und jenen Eintrag mit der höchsten Wahrscheinlichkeitsdichte raussuchen
|
||||
maxpropDens = 0
|
||||
for row in propDensVect:
|
||||
if row[0] > maxpropDens:
|
||||
maxpropDens = row[0]
|
||||
anzahl = row[1]
|
||||
|
||||
# damit nur etwas gemacht wird (zb ein Updatesignal an den Hauptthread zurücksenden), wenn sich die berechnete Anzahl ändert
|
||||
if prevAnzahl != anzahl:
|
||||
prevAnzahl = anzahl
|
||||
|
||||
# Die Wahrscheinlichkeit berechnen, dass das obige Ergebnis auch dem Bauteil entspricht
|
||||
if anzahl > 0:
|
||||
for row in auftragDaten:
|
||||
if row[1] == einzelteilID:
|
||||
prop = calcWahrscheinlichkeitFromDichte(float(intString),float(row[6])*anzahl, float(row[7])*anzahl)
|
||||
break
|
||||
print("Die Wahrscheinlichkeit, dass es das Bauteil ist, beträgt: ", prop)
|
||||
|
||||
# wenn genug Bauteile vorhanden sind, dann soll die Schleife beendet werden
|
||||
if (anzahl == anzBauteile_soll):
|
||||
self.correctBtNr = True
|
||||
|
||||
# Konsolenausgabe
|
||||
if maxpropDens > 0:
|
||||
print("Bei der Anzahl" , anzahl , "des Bauteiltypes", einzelteilID, ",wurde die höchste Wahrscheinlichkeitsdichte berechnet.")
|
||||
self.checkWaageUpdateSignal.emit(einzelteilID, anzahl)
|
||||
|
||||
else:
|
||||
print("Von der ausgewählten Bauteiltype liegt die berechnete Wahrscheinlichkeit bei 0, dass zwischen 0 und", anzBauteile_soll+teileZuViel, "Bauteilen auf der Waage liegen.")
|
||||
print("Falls die korrekte Anzhl an Bauteilen auf der Waage liegt, könnte der Fehler in einer falschen Kalibrierung der Waage liegen (TARE).")
|
||||
|
||||
if(self.stopLoop == False):
|
||||
self.checkWaageFinishedSignal.emit(einzelteilID)
|
||||
else:
|
||||
self.waageStoppedSignal.emit(einzelteilID)
|
||||
|
||||
|
||||
|
||||
|
||||
class Ui_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
self.auftragsnummer = ""
|
||||
self.teileZuViel = 0 # Anzahl an Bauteilen, welche zu viel drinnen sein können - der Parameter kann selbst gesetzt werden #####
|
||||
self.correctBtNr = False
|
||||
self.btTypeIsSet = False
|
||||
|
||||
|
||||
MainWindow.setObjectName("MainWindow")
|
||||
MainWindow.resize(1090, 675)
|
||||
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
||||
self.centralwidget.setObjectName("centralwidget")
|
||||
self.btn1 = QtWidgets.QPushButton(self.centralwidget)
|
||||
self.btn1.setGeometry(QtCore.QRect(700, 45, 111, 25))
|
||||
self.btn1.setObjectName("btn1")
|
||||
self.AuftragsdetailsTable = QtWidgets.QTableWidget(self.centralwidget)
|
||||
self.AuftragsdetailsTable.setGeometry(QtCore.QRect(10, 300, 661, 192))
|
||||
self.AuftragsdetailsTable.setObjectName("AuftragsdetailsTable")
|
||||
self.AuftragsdetailsTable.setColumnCount(6)
|
||||
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)
|
||||
self.label = QtWidgets.QLabel(self.centralwidget)
|
||||
self.label.setGeometry(QtCore.QRect(500, 20, 121, 17))
|
||||
self.label.setObjectName("label")
|
||||
self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
|
||||
self.textEdit.setGeometry(QtCore.QRect(450, 40, 221, 31))
|
||||
self.textEdit.setObjectName("textEdit")
|
||||
self.bauteilTypBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||
self.bauteilTypBtn.setGeometry(QtCore.QRect(700, 150, 161, 25))
|
||||
self.bauteilTypBtn.setObjectName("bauteilTypBtn")
|
||||
self.checkWaageBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||
self.checkWaageBtn.setGeometry(QtCore.QRect(700, 460, 161, 25))
|
||||
self.checkWaageBtn.setObjectName("checkWaageBtn")
|
||||
self.stopLoopBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||
self.stopLoopBtn.setGeometry(QtCore.QRect(700, 500, 161, 25))
|
||||
self.stopLoopBtn.setObjectName("stopLoopBtn")
|
||||
self.waageTareBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||
self.waageTareBtn.setGeometry(QtCore.QRect(700, 100, 161, 25))
|
||||
self.waageTareBtn.setObjectName("waageTareBtn")
|
||||
self.bauteiltypTextbox = QtWidgets.QTextEdit(self.centralwidget)
|
||||
self.bauteiltypTextbox.setGeometry(QtCore.QRect(700, 290, 221, 31))
|
||||
self.bauteiltypTextbox.setObjectName("bauteiltypTextbox")
|
||||
self.BezeichnungLabel = QtWidgets.QLabel(self.centralwidget)
|
||||
self.BezeichnungLabel.setGeometry(QtCore.QRect(700, 270, 181, 20))
|
||||
self.BezeichnungLabel.setObjectName("BezeichnungLabel")
|
||||
self.PosNrLabel = QtWidgets.QLabel(self.centralwidget)
|
||||
self.PosNrLabel.setGeometry(QtCore.QRect(700, 200, 67, 17))
|
||||
self.PosNrLabel.setObjectName("PosNrLabel")
|
||||
self.PosNrTxtFeld = QtWidgets.QTextEdit(self.centralwidget)
|
||||
self.PosNrTxtFeld.setGeometry(QtCore.QRect(700, 220, 191, 31))
|
||||
self.BezeichnungLabel.setObjectName("BezeichnungLabel")
|
||||
self.teileZuVielLabel = QtWidgets.QLabel(self.centralwidget)
|
||||
self.teileZuVielLabel.setGeometry(QtCore.QRect(700, 350, 350, 17))
|
||||
self.teileZuVielLabel.setObjectName("teileZuVielLabel")
|
||||
self.teileZuVielTxtFeld = QtWidgets.QTextEdit(self.centralwidget)
|
||||
self.teileZuVielTxtFeld.setGeometry(QtCore.QRect(700, 370, 191, 31))
|
||||
MainWindow.setCentralWidget(self.centralwidget)
|
||||
self.menubar = QtWidgets.QMenuBar(MainWindow)
|
||||
self.menubar.setGeometry(QtCore.QRect(0, 0, 1090, 22))
|
||||
self.menubar.setObjectName("menubar")
|
||||
MainWindow.setMenuBar(self.menubar)
|
||||
self.statusbar = QtWidgets.QStatusBar(MainWindow)
|
||||
self.statusbar.setObjectName("statusbar")
|
||||
MainWindow.setStatusBar(self.statusbar)
|
||||
'''
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(8)
|
||||
item.setFont(font)
|
||||
self.AuftragsdetailsTable.setVerticalHeaderItem(0,item)
|
||||
'''
|
||||
self.retranslateUi(MainWindow)
|
||||
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||
|
||||
def retranslateUi(self, MainWindow):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
|
||||
self.btn1.setText(_translate("MainWindow", "load Auftrag"))
|
||||
self.btn1.clicked.connect(self.auftragsBtnClicked)
|
||||
item = self.AuftragsdetailsTable.horizontalHeaderItem(0)
|
||||
item.setText(_translate("MainWindow", "Pos.-Nr"))
|
||||
item = self.AuftragsdetailsTable.horizontalHeaderItem(1)
|
||||
item.setText(_translate("MainWindow", "Matnr mit hoechster Version"))
|
||||
item = self.AuftragsdetailsTable.horizontalHeaderItem(2)
|
||||
item.setText(_translate("MainWindow", "Bezeichnung + Werkstoff"))
|
||||
item = self.AuftragsdetailsTable.horizontalHeaderItem(3)
|
||||
item.setText(_translate("MainWindow", "Soll-Menge"))
|
||||
item = self.AuftragsdetailsTable.horizontalHeaderItem(4)
|
||||
item.setText(_translate("MainWindow", "Ist-Menge"))
|
||||
item = self.AuftragsdetailsTable.horizontalHeaderItem(5)
|
||||
item.setText(_translate("MainWindow", "Lgort"))
|
||||
self.label.setText(_translate("MainWindow", "Auftragsnummer:"))
|
||||
self.bauteilTypBtn.setText(_translate("MainWindow", "Bauteiltyp erkennen"))
|
||||
self.bauteilTypBtn.clicked.connect(self.objectTypeDetection)
|
||||
self.AuftragsdetailsTable.cellClicked.connect(self.onTableCellClick)
|
||||
#self.AuftragsdetailsTable.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers)
|
||||
#item = self.AuftragsdetailsTable.verticalHeaderItem(0)
|
||||
#item.setText(_translate("MainWindow", "test"))
|
||||
self.BezeichnungLabel.setText(_translate("MainWindow", "Bezeichnung"))
|
||||
self.PosNrLabel.setText(_translate("MainWindow", "Pos.-Nr:"))
|
||||
self.teileZuVielLabel.setText(_translate("MainWindow", "Zu prüfende Teileanzahl über Auftragsanzahl:"))
|
||||
self.teileZuVielTxtFeld.setText(str(self.teileZuViel))
|
||||
self.checkWaageBtn.setText(_translate("MainWindow", "check Waage"))
|
||||
self.checkWaageBtn.clicked.connect(self.checkWaage)
|
||||
self.stopLoopBtn.setText(_translate("MainWindow", "stop loop"))
|
||||
self.stopLoopBtn.clicked.connect(self.stopLoopClicked)
|
||||
self.waageTareBtn.setText(_translate("MainWindow", "Waage tarieren"))
|
||||
self.waageTareBtn.clicked.connect(self.onTareClick)
|
||||
|
||||
self.thread = QThread()
|
||||
self.worker = Worker()
|
||||
self.worker.moveToThread(self.thread)
|
||||
self.worker.objectDetectionFinishedSignal.connect(self.objectTypeDetectionFinished)
|
||||
self.worker.waageStoppedSignal.connect(self.threadStopped)
|
||||
self.worker.stopLoopSignal.connect(lambda status: setattr(self.worker, 'stopLoop', status))
|
||||
|
||||
|
||||
|
||||
|
||||
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("clickedCheckboxTrue")
|
||||
else:
|
||||
print("clickedCheckboxFalse")
|
||||
|
||||
def getRowNr(self, posNr):
|
||||
for i in range(0,self.AuftragsdetailsTable.rowCount()):
|
||||
if(self.AuftragsdetailsTable.item(i,0).text() == str(posNr)):
|
||||
return i
|
||||
# brauche ich hier vermutlich nicht mehr - ist in den Worker Thread kopiert worden
|
||||
def waageNichtEingeschwungenOutput(self):
|
||||
print("Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft.")
|
||||
|
||||
|
||||
def onTableCellClick(self):
|
||||
self.PosNrTxtFeld.setText(self.AuftragsdetailsTable.item(self.AuftragsdetailsTable.currentRow(),0).text())
|
||||
self.bauteiltypTextbox.setText(self.AuftragsdetailsTable.item(self.AuftragsdetailsTable.currentRow(),2).text())
|
||||
|
||||
|
||||
def setAuftragsnummer(self):
|
||||
self.auftragsnummer = self.textEdit.toPlainText()
|
||||
if(not self.auftragsnummer):
|
||||
self.auftragsnummer = ""
|
||||
self.textEdit.setText("")
|
||||
|
||||
def checkAuftragsnummerEmpty(self):
|
||||
if self.auftragsnummer == "":
|
||||
print("Das Auftragsnummernfeld ist leer.")
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def checkPosNrEmpty(self):
|
||||
if self.PosNrTxtFeld.toPlainText() == "":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# eventuell benötigt man die Funktion hier nicht mehr, da sie zu den Threads kopiert wurde
|
||||
def getDataOfArticleType(self, allArticles, articleType):
|
||||
# die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück
|
||||
for i in allArticles:
|
||||
if i[1] == articleType:
|
||||
return i
|
||||
|
||||
return -1
|
||||
|
||||
def updateGUI(self):
|
||||
self.PosNrLabel.repaint() #GUI aktualisieren
|
||||
QApplication.processEvents() #GUI aktualisieren
|
||||
|
||||
def setRowColor(self, rowID,r,g,b):
|
||||
self.AuftragsdetailsTable.item(rowID, 0).setBackground(QtGui.QColor(r,g,b))
|
||||
self.AuftragsdetailsTable.item(rowID, 1).setBackground(QtGui.QColor(r,g,b))
|
||||
self.AuftragsdetailsTable.item(rowID, 2).setBackground(QtGui.QColor(r,g,b))
|
||||
self.AuftragsdetailsTable.item(rowID, 3).setBackground(QtGui.QColor(r,g,b))
|
||||
self.AuftragsdetailsTable.item(rowID, 4).setBackground(QtGui.QColor(r,g,b))
|
||||
self.AuftragsdetailsTable.item(rowID, 5).setBackground(QtGui.QColor(r,g,b))
|
||||
|
||||
#wird hier vermutlich nicht mehr benötigt - wurde in die Workerklasse kopiert
|
||||
def readWaage(self):
|
||||
# in folgender Funktion wird die Waage ausgelesen
|
||||
|
||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
||||
#print("port to which it is connected: ", ser.portstr) #Debuggingausgabe
|
||||
self.checkPosNrEmpty()
|
||||
|
||||
if ser.is_open == False:
|
||||
ser.open()
|
||||
|
||||
|
||||
#an die Waage den Befehl senden, dass sie ausgelesen werden soll
|
||||
ser.write(b'getWeight\n')
|
||||
#ser.write(b'tare\n')
|
||||
serialString = ser.readline().decode('utf-8').rstrip() #Auslesen des Serial-Strings/der Messung der Waage
|
||||
|
||||
# wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft
|
||||
lenString = len(serialString)-1
|
||||
if serialString[lenString] == "g" and serialString[lenString-1] == "k":
|
||||
#print("ist eingeschwungen") #Debuggingausgabe
|
||||
waageEingeschwungen = True
|
||||
else:
|
||||
print("die Waage ist noch nicht eingeschwungen")
|
||||
waageEingeschwungen = False
|
||||
|
||||
#aus dem String werden alle Zeichen, welche nicht zur Darstellung der Zahl benötigt werden entfernt
|
||||
intString = ""
|
||||
for i in serialString:
|
||||
if i=="-" or i=="0" or i=="." or i=="1" or i=="2" or i=="3" or i=="4" or i=="5" or i=="6" or i=="7" or i=="8" or i=="9":
|
||||
intString = intString + i
|
||||
print("Wert, welcher von der Waage ausgelesen wurde: " + intString + "kg")
|
||||
## Waage auslesen - ENDE
|
||||
|
||||
ser.close()
|
||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
||||
|
||||
return waageEingeschwungen, intString
|
||||
|
||||
def auftragsBtnClicked(self):
|
||||
databaseQueryWorking = False #wird für die Überprüfung, ob die Datenbankabfrage fehlerhaft ist, verwendet
|
||||
auftragEinzelteilDaten = []
|
||||
|
||||
self.setAuftragsnummer()
|
||||
if(not self.checkAuftragsnummerEmpty()):
|
||||
|
||||
|
||||
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + self.auftragsnummer
|
||||
try:
|
||||
cursor.execute(sql_query)
|
||||
# Fetch results
|
||||
auftragEinzelteilDaten = cursor.fetchall()
|
||||
databaseQueryWorking = True
|
||||
except:
|
||||
print("Fehler in der Datenbankabfrage.")
|
||||
|
||||
|
||||
|
||||
if databaseQueryWorking==True and len(auftragEinzelteilDaten)>0:
|
||||
'''
|
||||
# Display data
|
||||
print("Ausgabe der Auftragsdetails des obigen Auftrags, inklusive Einzelteildetails:")
|
||||
for row in auftragEinzelteilDaten:
|
||||
if str(row[2]) == self.auftragsnummer:
|
||||
print("passt")
|
||||
print(row)
|
||||
'''
|
||||
|
||||
### die Auftragsdaten in die Tabelle laden
|
||||
self.AuftragsdetailsTable.setRowCount(len(auftragEinzelteilDaten))
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
counter = 0
|
||||
for row in auftragEinzelteilDaten:
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 0, self.item)
|
||||
self.item.setText(str(row[1]))
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 1, self.item)
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 2, self.item)
|
||||
self.item.setText(str(row[5]))
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 3, self.item)
|
||||
self.item.setText(str(row[3]))
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 4, self.item)
|
||||
self.item.setText(str("0"))
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 5, self.item)
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
counter = counter +1
|
||||
|
||||
elif(databaseQueryWorking==True and len(auftragEinzelteilDaten)==0):
|
||||
print("Es wurde in der Datenbank kein Auftrag mit dieser Auftragsnummer gefunden.")
|
||||
|
||||
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
|
||||
self.worker.stopLoopSignal.emit(True)
|
||||
|
||||
|
||||
def checkWaage(self):
|
||||
#print("Running in thread:", threading.current_thread().name) # Debuggingausgabe
|
||||
|
||||
QApplication.processEvents()
|
||||
|
||||
# die Loopvariable des Workers auf False setzten, damit die Schleife durchgelaufen wird (diese wird zum Abbruch der Schleife benötigt -> siehe stopLoop)
|
||||
self.worker.stopLoopSignal.emit(False)
|
||||
|
||||
# überprüfen, ob ein Bauteiltyp gesetzt wurde
|
||||
if(self.checkPosNrEmpty()==True):
|
||||
print("Das Pos.-Nr.-Feld ist leer.")
|
||||
return
|
||||
|
||||
if(self.AuftragsdetailsTable.item(0,0) == None):
|
||||
print("Der Auftrag muss zuerst geladen werden.")
|
||||
return
|
||||
|
||||
# den GUI Wert von Textfeld TeileZuViel in die Variable schreiben
|
||||
self.teileZuViel = int(float(self.teileZuVielTxtFeld.toPlainText()))
|
||||
self.teileZuVielTxtFeld.setText(str(self.teileZuViel))
|
||||
|
||||
#übernehmen der BauteilID aus dem Feld Pos.-Nr
|
||||
einzelteilID = int(self.PosNrTxtFeld.toPlainText())
|
||||
|
||||
#zum setzen den Farbe der gesamten Reihe auf Orange
|
||||
self.setRowColor(self.getRowNr(einzelteilID),255,165,0)
|
||||
|
||||
# den Thread starten, welcher die Bauteilanzahl überprüft
|
||||
self.worker.checkWaageStartSignal.connect(self.worker.checkWaageThread)
|
||||
self.worker.checkWaageUpdateSignal.connect(self.checkWaageUpdate)
|
||||
self.worker.checkWaageFinishedSignal.connect(self.checkWaageFinished)
|
||||
self.thread.started.connect(lambda: self.worker.checkWaageStartSignal.emit(einzelteilID, self.teileZuViel, self.auftragsnummer))
|
||||
self.thread.start()
|
||||
|
||||
def checkWaageUpdate(self, einzelteilID, anzahl):
|
||||
# die Funktion updated die (vom Thread) berechnete Bauteilanzahl in der GUI
|
||||
self.AuftragsdetailsTable.item(self.getRowNr(einzelteilID), 4).setText(str(anzahl)) # in die Tabelle die Anzahl an berechneten Bauteilen reinschreiben
|
||||
|
||||
|
||||
def checkWaageFinished(self, einzelteilID):
|
||||
self.setRowColor(self.getRowNr(einzelteilID),0,255,0) #zum setzen den Farbe der gesamten Reihe auf Grün
|
||||
|
||||
# den Thread beenden
|
||||
self.thread.quit()
|
||||
self.thread.wait()
|
||||
try:
|
||||
self.thread.started.disconnect(lambda: self.worker.checkWaageStartSignal.emit(einzelteilID, self.teileZuViel, self.auftragsnummer)) # 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.") # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt
|
||||
|
||||
# GUI updaten
|
||||
#self.updateGUI()
|
||||
|
||||
def objectTypeDetection(self):
|
||||
# in dieser Funktion wird der Typ des Bauteils automatisch erkannt
|
||||
|
||||
'''
|
||||
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.worker.stopLoopSignal.emit(False)
|
||||
|
||||
# überprüfen, ob der Auftrag in die Tabelle geladen wurde
|
||||
if(self.AuftragsdetailsTable.item(0,0) == None):
|
||||
print("Der Auftrag muss zuerst geladen werden.")
|
||||
return
|
||||
|
||||
# speichert den Wert, welcher im Textfeld steht in Variablen im Code
|
||||
self.setAuftragsnummer()
|
||||
|
||||
# starten des Threats, welcher den Bauteiltyp zurück gibt
|
||||
self.worker.objectDetectionStartSignal.connect(self.worker.objectTypeDetectionThread)
|
||||
self.thread.started.connect(lambda: self.worker.objectDetectionStartSignal.emit(self.auftragsnummer))
|
||||
self.thread.start()
|
||||
|
||||
def objectTypeDetectionFinished(self, einzelteilID, rowData):
|
||||
# wenn der Typ des Objektes erkannt wurde, dann soll die Funktion aufgerufen werden
|
||||
|
||||
# Schreiben der Bauteiltype und Pos.-Nr in die jeweiligen Felder
|
||||
self.PosNrTxtFeld.setText(str(rowData[1]))
|
||||
self.bauteiltypTextbox.setText(rowData[2])
|
||||
|
||||
# setzt den Boolean, um aus der Schleife raus zu gehen
|
||||
self.btTypeIsSet = True
|
||||
|
||||
#zum setzen den Farbe der gesamten Reihe auf Orange
|
||||
self.setRowColor(self.getRowNr(einzelteilID),255,165,0)
|
||||
|
||||
# den Thread beenden
|
||||
self.thread.quit()
|
||||
self.thread.wait()
|
||||
try:
|
||||
self.thread.started.disconnect() # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt
|
||||
except:
|
||||
print("Disconnecting the thread did not work.")
|
||||
|
||||
# wenn der Bauteiltyp erkannt wurde, dann soll die GUI aktualisiert werden und anschließend die CheckWaage-Funktion aufgerufen werden
|
||||
self.updateGUI()
|
||||
self.checkWaage()
|
||||
|
||||
def threadStopped(self, einzelteilID):
|
||||
# wenn kein Bauteil erkannt wurde, dann ist die EinzenteilID = 0
|
||||
if(einzelteilID > 0):
|
||||
self.setRowColor(self.getRowNr(einzelteilID),255,255,255) #zum setzen den Farbe der gesamten Reihe auf Weiß
|
||||
|
||||
# den Thread beenden
|
||||
self.thread.quit()
|
||||
self.thread.wait()
|
||||
try:
|
||||
self.thread.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.")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
MainWindow = QtWidgets.QMainWindow()
|
||||
ui = Ui_MainWindow()
|
||||
ui.setupUi(MainWindow)
|
||||
MainWindow.show()
|
||||
sys.exit(app.exec_())
|
||||
|
||||
|
||||
|
||||
|
||||
|
849
GUI_22_10_staticWorkflow_Multithreading.py
Normal file
849
GUI_22_10_staticWorkflow_Multithreading.py
Normal file
@ -0,0 +1,849 @@
|
||||
|
||||
#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
|
||||
|
||||
|
||||
db_config = {
|
||||
'user': 'dbUser',
|
||||
'password': 'dbPassword',
|
||||
'host': 'localhost',
|
||||
'database': 'projectGeislinger',
|
||||
'port': 3306 # Standard port for MariaDB
|
||||
}
|
||||
|
||||
# Establishing the connection
|
||||
conn = mariadb.connect(**db_config)
|
||||
# Create a cursor to execute queries
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Konfiguration der seriellen Schnittstelle
|
||||
ser = serial.Serial('/dev/ttyUSB0', 9600)
|
||||
#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/
|
||||
|
||||
|
||||
|
||||
#class Worker(QThread):
|
||||
class Worker(QObject):
|
||||
#progress = pyqtSignal(int)
|
||||
objectDetectionStartSignal = pyqtSignal(str)
|
||||
objectDetectionFinishedSignal = pyqtSignal(int, object)
|
||||
|
||||
checkWaageStartSignal = pyqtSignal(int, int, str)
|
||||
checkWaageUpdateSignal = pyqtSignal(int, int)
|
||||
checkWaageFinishedSignal = pyqtSignal(int)
|
||||
|
||||
waageStoppedSignal = pyqtSignal(int)
|
||||
stopLoopSignal = pyqtSignal(bool) #das Signal wird verwendet um direkt den stopLoop-Wert zu ändern (also kein Funktionsaufruf)
|
||||
|
||||
stopLoop = False
|
||||
btTypeIsSet = False
|
||||
correctBtNr = False
|
||||
waageEingeschwungen = False
|
||||
|
||||
|
||||
def __init__(self):
|
||||
super(Worker, self).__init__()
|
||||
stopLoop = False
|
||||
|
||||
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 getDataOfArticleType(self, allArticles, articleType):
|
||||
# die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück
|
||||
for i in allArticles:
|
||||
if i[1] == articleType:
|
||||
return i
|
||||
|
||||
return -1
|
||||
|
||||
def waageNichtEingeschwungenOutput(self):
|
||||
print("Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft.")
|
||||
|
||||
def readWaage(self):
|
||||
# in folgender Funktion wird die Waage ausgelesen
|
||||
|
||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
||||
#print("port to which it is connected: ", ser.portstr) #Debuggingausgabe
|
||||
|
||||
|
||||
if ser.is_open == False:
|
||||
ser.open()
|
||||
|
||||
|
||||
#an die Waage den Befehl senden, dass sie ausgelesen werden soll
|
||||
ser.write(b'getWeight\n')
|
||||
#ser.write(b'tare\n')
|
||||
serialString = ser.readline().decode('utf-8').rstrip() #Auslesen des Serial-Strings/der Messung der Waage
|
||||
|
||||
# wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft
|
||||
lenString = len(serialString)-1
|
||||
if serialString[lenString] == "g" and serialString[lenString-1] == "k":
|
||||
#print("ist eingeschwungen") #Debuggingausgabe
|
||||
self.waageEingeschwungen = True
|
||||
else:
|
||||
print("die Waage ist noch nicht eingeschwungen")
|
||||
self.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 self.waageEingeschwungen, intString
|
||||
|
||||
def objectTypeDetectionThread(self, auftragsnummer):
|
||||
# in dieser Funktion wird der Typ des Bauteils automatisch erkannt
|
||||
|
||||
#print("objectTypeDetectionThread - Running in thread:", threading.current_thread().name) #Debuggausgabe
|
||||
|
||||
# Parameterdefinition
|
||||
propDensVect = []
|
||||
|
||||
self.btTypeIsSet = False
|
||||
|
||||
while(self.btTypeIsSet == False and self.stopLoop == False):
|
||||
|
||||
# Auslesen der Waage
|
||||
self.waageEingeschwungen, intString = self.readWaage()
|
||||
if self.waageEingeschwungen == False:
|
||||
self.waageNichtEingeschwungenOutput()
|
||||
else:
|
||||
|
||||
# Datenbankabfrage
|
||||
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer
|
||||
cursor.execute(sql_query)
|
||||
auftragEinzelteilDaten = cursor.fetchall()
|
||||
|
||||
'''
|
||||
# Display data #Debugausgabe
|
||||
print("Ausgabe der Auftragsdetails des obigen Auftrags, inklusive Einzelteildetails:")
|
||||
for row in auftragEinzelteilDaten:
|
||||
print(row)
|
||||
'''
|
||||
|
||||
# in der Folge werden alle Wahrscheinlichkeitsdichten der Auftragsbauteile berechnet und in dem Vektor gesammelt
|
||||
for row in auftragEinzelteilDaten:
|
||||
propDensVect.append([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.")
|
||||
|
||||
'''
|
||||
# Wahrscheinlichkeit berechnen, dass das angegebene Bauteil auch wirklich diesem entspricht
|
||||
prop = 0
|
||||
for row in auftragEinzelteilDaten:
|
||||
if row[1] == einzelteilID:
|
||||
prop = calcWahrscheinlichkeitFromDichte(float(intString),float(row[6]), float(row[7]))
|
||||
break
|
||||
print("Die Wahrscheinlichkeit, dass es das Bauteil ist, beträgt: ", prop)
|
||||
'''
|
||||
|
||||
# den Bool auf true setzen, damit die Schleife beendet wird - dieser wird auf True gesetzt, wenn ein Bauteiltyp erkannt wird
|
||||
self.btTypeIsSet = True
|
||||
|
||||
if(self.stopLoop == False):
|
||||
# ein Signal zurück an den MainThreat senden, mit den Infos/Ergebnissen, der Typenbestimmung
|
||||
self.objectDetectionFinishedSignal.emit(einzelteilID, rowData)
|
||||
else:
|
||||
self.waageStoppedSignal.emit(einzelteilID)
|
||||
|
||||
def checkWaageThread(self, einzelteilID, teileZuViel, auftragsnummer):
|
||||
|
||||
self.correctBtNr = False
|
||||
prevAnzahl = -1
|
||||
anzahl = 0
|
||||
einzelteilID = einzelteilID
|
||||
|
||||
while (self.correctBtNr == False and self.stopLoop == False):
|
||||
|
||||
#überprüfen, ob die Waage eingeschwungen ist (und damit korrekte Ergebnisse liefert)
|
||||
self.waageEingeschwungen, intString = self.readWaage()
|
||||
if self.waageEingeschwungen == False:
|
||||
self.waageNichtEingeschwungenOutput()
|
||||
else:
|
||||
|
||||
# Datenbankabfrage - holen der Auftrags- und Bauteilinfos
|
||||
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer
|
||||
cursor.execute(sql_query)
|
||||
auftragDaten = cursor.fetchall()
|
||||
|
||||
'''
|
||||
# Display data - zum Debuggen
|
||||
print("Ausgabe der Auftragsdetails:")
|
||||
print("id|EinzelteilID|Auftragsnummer|Anzahl")
|
||||
for row in auftragDaten:
|
||||
print(row)
|
||||
'''
|
||||
|
||||
#auslesen, wie viele Bauteile des Types laut Auftrag vorhanden sein sollen
|
||||
anzBauteile_soll = 0
|
||||
idVorhanden = False
|
||||
|
||||
for row in auftragDaten:
|
||||
if row[1] == einzelteilID:
|
||||
anzBauteile_soll = row[3]
|
||||
idVorhanden = True
|
||||
|
||||
if(idVorhanden == False):
|
||||
print("Die gewählte Pos.Nr ist nicht in der Auftragsliste (Tabelle) vorhanden.")
|
||||
return
|
||||
|
||||
# Berechnen der Wahrscheinlichkeitsdichten - der Betrag aller Wahrscheinlichkeitsdichten werden im propDensVect gespeichert
|
||||
propDensVect = []
|
||||
articleData = self.getDataOfArticleType(auftragDaten, einzelteilID)
|
||||
#for i in range(1,anzBauteile_soll+teileZuViel+1):
|
||||
for i in range(0,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
|
||||
# das if wird eingeführt, um auch die Bauteilanzahl 0 korrekt berücksichtigen zu können
|
||||
if i == 0:
|
||||
varGes = float(articleData[7])
|
||||
else:
|
||||
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
|
||||
|
||||
'''
|
||||
# Die Wahrscheinlichkeit berechnen, dass das obige Ergebnis auch dem Bauteil entspricht
|
||||
if anzahl > 0:
|
||||
for row in auftragDaten:
|
||||
if row[1] == einzelteilID:
|
||||
prop = calcWahrscheinlichkeitFromDichte(float(intString),float(row[6])*anzahl, float(row[7])*anzahl)
|
||||
break
|
||||
print("Die Wahrscheinlichkeit, dass es das Bauteil ist, beträgt: ", prop)
|
||||
'''
|
||||
|
||||
# wenn genug Bauteile vorhanden sind, dann soll die Schleife beendet werden
|
||||
if (anzahl == anzBauteile_soll):
|
||||
self.correctBtNr = True
|
||||
|
||||
# Konsolenausgabe
|
||||
if maxpropDens > 0:
|
||||
print("Bei der Anzahl" , anzahl , "des Bauteiltypes", einzelteilID, ",wurde die höchste Wahrscheinlichkeitsdichte berechnet.")
|
||||
self.checkWaageUpdateSignal.emit(einzelteilID, anzahl)
|
||||
|
||||
else:
|
||||
print("Von der ausgewählten Bauteiltype liegt die berechnete Wahrscheinlichkeit bei 0, dass zwischen 0 und", anzBauteile_soll+teileZuViel, "Bauteilen auf der Waage liegen.")
|
||||
print("Falls die korrekte Anzhl an Bauteilen auf der Waage liegt, könnte der Fehler in einer falschen Kalibrierung der Waage liegen (TARE).")
|
||||
|
||||
if(self.stopLoop == False):
|
||||
self.checkWaageFinishedSignal.emit(einzelteilID)
|
||||
else:
|
||||
self.waageStoppedSignal.emit(einzelteilID)
|
||||
|
||||
|
||||
|
||||
|
||||
class Ui_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
self.auftragsnummer = ""
|
||||
self.teileZuViel = 100 # Anzahl an Bauteilen, welche zu viel drinnen sein können - der Parameter kann selbst gesetzt werden #####
|
||||
self.correctBtNr = False
|
||||
self.btTypeIsSet = False
|
||||
|
||||
|
||||
MainWindow.setObjectName("MainWindow")
|
||||
MainWindow.resize(1400, 675)
|
||||
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
||||
self.centralwidget.setObjectName("centralwidget")
|
||||
self.btn1 = QtWidgets.QPushButton(self.centralwidget)
|
||||
self.btn1.setGeometry(QtCore.QRect(700, 45, 111, 25))
|
||||
self.btn1.setObjectName("btn1")
|
||||
# Tabelle zur Darstellung der Auftragsdetails
|
||||
self.AuftragsdetailsTable = QtWidgets.QTableWidget(self.centralwidget)
|
||||
self.AuftragsdetailsTable.setGeometry(QtCore.QRect(10, 100, 661, 400))
|
||||
self.AuftragsdetailsTable.setObjectName("AuftragsdetailsTable")
|
||||
self.AuftragsdetailsTable.setColumnCount(6)
|
||||
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")
|
||||
|
||||
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"))
|
||||
|
||||
# Tabelle zur Darstellung der Arbeitsschritte
|
||||
item = self.ArbeitsschrittTable.horizontalHeaderItem(0)
|
||||
item.setText(_translate("MainWindow", "Arbeitsschritt"))
|
||||
item = self.ArbeitsschrittTable.horizontalHeaderItem(1)
|
||||
item.setText(_translate("MainWindow", "ToDo:"))
|
||||
|
||||
# Befüllen der Arbeisschritttabelle mit Text
|
||||
#item = self.ArbeitsschrittTable.
|
||||
# Ein neues QTableWidgetItem erstellen und den Text setzen
|
||||
item = QtWidgets.QTableWidgetItem("Auftrag laden")
|
||||
self.ArbeitsschrittTable.setItem(0, 0, item)
|
||||
item = QtWidgets.QTableWidgetItem("--> Auftragsnummer eingeben \n--> \"load Auftrag\" Buttonclick")
|
||||
self.ArbeitsschrittTable.setItem(0, 1, item)
|
||||
item = QtWidgets.QTableWidgetItem("Bauteiltyp erkennen")
|
||||
self.ArbeitsschrittTable.setItem(1, 0, item)
|
||||
item = QtWidgets.QTableWidgetItem("visuell: \n--> ein Bauteil in die Kamera halten\n\nWaage: \n--> ein Bauteil auf die Waage legen\n--> \"Bauteiltyp erkennen\" Buttonclick\n\nmanuell:\n--> Bauteiltypen auswählen\n-->\"ckeck Waage\" Button click")
|
||||
self.ArbeitsschrittTable.setItem(1, 1, item)
|
||||
item = QtWidgets.QTableWidgetItem("Bauteilanzahl erkennen")
|
||||
self.ArbeitsschrittTable.setItem(2, 0, item)
|
||||
item = QtWidgets.QTableWidgetItem("--> Bauteile auflegen")
|
||||
self.ArbeitsschrittTable.setItem(2, 1, item)
|
||||
item = QtWidgets.QTableWidgetItem("Prozess beendet")
|
||||
self.ArbeitsschrittTable.setItem(3, 0, item)
|
||||
self.ArbeitsschrittTable.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers)
|
||||
|
||||
#self.ArbeitsschrittTable.item(0,0).setText("test")
|
||||
|
||||
#einzelteilID = int(self.AuftragsdetailsTable.item(i,0).text())
|
||||
#self.PosNrTxtFeld.setText(str(self.AuftragsdetailsTable.item(i,0).text()))
|
||||
#self.bauteiltypTextbox.setText(str(self.AuftragsdetailsTable.item(i,2).text()))
|
||||
|
||||
self.label.setText(_translate("MainWindow", "Auftragsnummer:"))
|
||||
self.bauteilTypBtn.setText(_translate("MainWindow", "Bauteiltyp erkennen"))
|
||||
self.bauteilTypBtn.clicked.connect(self.objectTypeDetection)
|
||||
self.AuftragsdetailsTable.cellClicked.connect(self.onTableCellClick)
|
||||
#self.AuftragsdetailsTable.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers)
|
||||
#item = self.AuftragsdetailsTable.verticalHeaderItem(0)
|
||||
#item.setText(_translate("MainWindow", "test"))
|
||||
self.BezeichnungLabel.setText(_translate("MainWindow", "Bezeichnung"))
|
||||
self.PosNrLabel.setText(_translate("MainWindow", "Pos.-Nr:"))
|
||||
self.teileZuVielLabel.setText(_translate("MainWindow", "Zu prüfende Teileanzahl über Auftragsanzahl:"))
|
||||
self.teileZuVielTxtFeld.setText(str(self.teileZuViel))
|
||||
self.checkWaageBtn.setText(_translate("MainWindow", "check Waage"))
|
||||
self.checkWaageBtn.clicked.connect(self.checkWaage)
|
||||
self.stopLoopBtn.setText(_translate("MainWindow", "stop loop"))
|
||||
self.stopLoopBtn.clicked.connect(self.stopLoopClicked)
|
||||
self.waageTareBtn.setText(_translate("MainWindow", "Waage tarieren"))
|
||||
self.waageTareBtn.clicked.connect(self.onTareClick)
|
||||
self.checkBox.setText(_translate("MainWindow", "static workflow"))
|
||||
self.checkBox.clicked.connect(self.onCheckboxCheck)
|
||||
self.checkBoxAutoTare.setText(_translate("MainWindow", "automatisches Tarieren"))
|
||||
self.checkBoxAutoTare.clicked.connect(self.autoTareCheck)
|
||||
|
||||
self.setRowColor(self.ArbeitsschrittTable, 0,255,165,0) # zum setzen der ersten Spalte der Arbeitsschrittetabelle auf orange
|
||||
self.checkBoxAutoTare.setCheckState(Qt.Checked)
|
||||
self.checkBox.setCheckState(Qt.Unchecked)
|
||||
|
||||
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):
|
||||
# tableObject = das Tabellenobjekt, von welchem die Zeile gefärbt werden soll
|
||||
# rowID = die Nr der Zeile, welche eingefärbt werden soll
|
||||
# r,g,b = Farbe, welche die Zeile annehmen soll
|
||||
|
||||
# folgendes If-Statement hat ausschließlich einen Ästethischen Zweck -> und zwar, dass bei der Arbeitsschritttabelle lediglich die erste
|
||||
# Spelte eingefärbt wird, anstatt beide Spalten
|
||||
if tableObject == self.ArbeitsschrittTable:
|
||||
nrColNoColor = 1
|
||||
else:
|
||||
nrColNoColor = 0
|
||||
|
||||
# Einfärben der Zellen einer Spalte
|
||||
for col in range(tableObject.columnCount()-nrColNoColor):
|
||||
tableObject.item(rowID, col).setBackground(QtGui.QColor(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:
|
||||
'''
|
||||
# Display data
|
||||
print("Ausgabe der Auftragsdetails des obigen Auftrags, inklusive Einzelteildetails:")
|
||||
for row in auftragEinzelteilDaten:
|
||||
if str(row[2]) == self.auftragsnummer:
|
||||
print("passt")
|
||||
print(row)
|
||||
'''
|
||||
|
||||
### die Auftragsdaten in die Tabelle laden
|
||||
self.AuftragsdetailsTable.setRowCount(len(auftragEinzelteilDaten))
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
counter = 0
|
||||
for row in auftragEinzelteilDaten:
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 0, self.item)
|
||||
self.item.setText(str(row[1]))
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 1, self.item)
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 2, self.item)
|
||||
self.item.setText(str(row[5]))
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 3, self.item)
|
||||
self.item.setText(str(row[3]))
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 4, self.item)
|
||||
self.item.setText(str("0"))
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 5, self.item)
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
|
||||
counter = counter +1
|
||||
|
||||
self.setRowColor(self.ArbeitsschrittTable, 0,0,255,0) #zum setzen der ersten Zeile der Auftragstabelle auf grün
|
||||
self.setRowColor(self.ArbeitsschrittTable, 1,255,165,0) #zum setzen der zweiten Zeile der Auftragstabelle auf orange
|
||||
self.setRowColor(self.ArbeitsschrittTable, 2,255,255,255) #zum setzen der dritten Zeile der Auftragstabelle auf weiß
|
||||
self.setRowColor(self.ArbeitsschrittTable, 3,255,255,255) #zum setzen der vierten Zeile der Auftragstabelle auf weiß
|
||||
|
||||
# setzen der beiden Felder auf einen leeren String, um Fehler zu Vermeiden, wenn ein neuer Auftrag geladen wird
|
||||
self.bauteiltypTextbox.setText("")
|
||||
self.PosNrTxtFeld.setText("")
|
||||
|
||||
|
||||
elif(databaseQueryWorking==True and len(auftragEinzelteilDaten)==0):
|
||||
print("Es wurde in der Datenbank kein Auftrag mit dieser Auftragsnummer gefunden.")
|
||||
|
||||
def change_row_color(self, row, color_index):
|
||||
if(color_index == 1):
|
||||
self.setRowColor(self.AuftragsdetailsTable, row,255,255,255)
|
||||
if(color_index == 2):
|
||||
self.setRowColor(self.AuftragsdetailsTable, row,255,165,0)
|
||||
if(color_index == 3):
|
||||
self.setRowColor(self.AuftragsdetailsTable, row,0,255,0)
|
||||
|
||||
def stopLoopClicked(self):
|
||||
# damit wird beim Klick auf den Stopbutton der stopLoop-boolWert in der Workerklasse auf true gesetzt -> der Stop des Threads wird initiiert
|
||||
if hasattr(self, 'objectDetectionWorker'):
|
||||
self.objectDetectionWorker.stopLoopSignal.emit(True)
|
||||
|
||||
if hasattr(self, 'checkWaageWorker'):
|
||||
self.checkWaageWorker.stopLoopSignal.emit(True)
|
||||
|
||||
def checkFinished(self):
|
||||
#die Funktion geht alle Zeilen der Auftragsliste durch und schaut, ob die richtige Anzahl an Teilen vorhanden sind
|
||||
for i in range(0,self.AuftragsdetailsTable.rowCount()):
|
||||
if self.AuftragsdetailsTable.item(i,3).text() != self.AuftragsdetailsTable.item(i,4).text():
|
||||
return False
|
||||
return True
|
||||
|
||||
def checkWaage(self):
|
||||
#print("Running in thread:", threading.current_thread().name) # Debuggingausgabe
|
||||
QApplication.processEvents()
|
||||
|
||||
# die Loopvariable des Workers auf False setzten, damit die Schleife durchgelaufen wird (diese wird zum Abbruch der Schleife benötigt -> siehe stopLoop)
|
||||
#self.checkWaageWorker.stopLoopSignal.emit(False)
|
||||
|
||||
# überprüfen, ob der Auftrag geladen wurde
|
||||
if(self.AuftragsdetailsTable.item(0,0) == None):
|
||||
print("Der Auftrag muss zuerst geladen werden.")
|
||||
return
|
||||
|
||||
# überprüfen, ob ein Bauteiltyp gesetzt wurde
|
||||
if(self.checkPosNrEmpty()==True and self.checkBox.isChecked() == False):
|
||||
print("Das Pos.-Nr.-Feld ist leer.")
|
||||
return
|
||||
|
||||
# den GUI Wert von Textfeld TeileZuViel in die Variable schreiben
|
||||
self.teileZuViel = int(float(self.teileZuVielTxtFeld.toPlainText()))
|
||||
self.teileZuVielTxtFeld.setText(str(self.teileZuViel))
|
||||
|
||||
einzelteilID = -1 # Initialisieren der Variable mit einem Defaultwert, welcher nie eingenommen werden können sollte
|
||||
if (self.checkBox.isChecked() == False):
|
||||
#übernehmen der BauteilID aus dem Feld Pos.-Nr - wenn der Workflow dynamisch gewählt wurde
|
||||
einzelteilID = int(self.PosNrTxtFeld.toPlainText())
|
||||
else:
|
||||
# wenn der Workflow statisch gesetzt wurde, dann soll das erste Item aus der Auftragsliste geladen werden, von welchem noch nicht genug Bauteile auf der Waage liegen
|
||||
for i in range(0,self.AuftragsdetailsTable.rowCount()):
|
||||
if self.AuftragsdetailsTable.item(i,3).text() != self.AuftragsdetailsTable.item(i,4).text():
|
||||
einzelteilID = int(self.AuftragsdetailsTable.item(i,0).text())
|
||||
self.PosNrTxtFeld.setText(str(self.AuftragsdetailsTable.item(i,0).text()))
|
||||
self.bauteiltypTextbox.setText(str(self.AuftragsdetailsTable.item(i,2).text()))
|
||||
break
|
||||
|
||||
if einzelteilID == -1:
|
||||
# den Thread beenden
|
||||
self.checkWaageThread.quit()
|
||||
self.checkWaageThread.wait()
|
||||
try:
|
||||
self.checkWaageThread.started.disconnect() # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt
|
||||
print("Der Thread wurde beendet.")
|
||||
except:
|
||||
print("Disconnecting the thread did not work.")
|
||||
return
|
||||
|
||||
|
||||
#zum setzen den Farbe der gesamten Reihe auf Orange
|
||||
self.setRowColor(self.AuftragsdetailsTable, self.getRowNr(einzelteilID),255,165,0)
|
||||
self.setRowColor(self.ArbeitsschrittTable, 1,0,255,0) # zum setzen der zweiten Spalte der Arbeitsschrittetabelle auf grün
|
||||
self.setRowColor(self.ArbeitsschrittTable, 2,255,165,0) # zum setzen der dritten Spalte der Arbeitsschrittetabelle auf orange
|
||||
|
||||
# den Thread starten, welcher die Bauteilanzahl überprüft
|
||||
self.checkWaageWorker = Worker()
|
||||
self.checkWaageThread = QThread()
|
||||
|
||||
self.checkWaageWorker.moveToThread(self.checkWaageThread)
|
||||
|
||||
self.checkWaageWorker.checkWaageStartSignal.connect(self.checkWaageWorker.checkWaageThread)
|
||||
self.checkWaageWorker.checkWaageUpdateSignal.connect(self.checkWaageUpdate)
|
||||
self.checkWaageWorker.checkWaageFinishedSignal.connect(self.checkWaageFinished)
|
||||
self.checkWaageWorker.waageStoppedSignal.connect(self.threadStopped)
|
||||
self.checkWaageWorker.stopLoopSignal.connect(lambda status: setattr(self.checkWaageWorker, 'stopLoop', status)) #wird fürs aktive Stoppen des Threads benötigt
|
||||
|
||||
self.checkWaageThread.started.connect(lambda: self.checkWaageWorker.checkWaageStartSignal.emit(einzelteilID, self.teileZuViel, self.auftragsnummer))
|
||||
self.checkWaageThread.start()
|
||||
|
||||
def checkWaageUpdate(self, einzelteilID, anzahl):
|
||||
# die Funktion updated die (vom Thread) berechnete Bauteilanzahl in der GUI
|
||||
self.AuftragsdetailsTable.item(self.getRowNr(einzelteilID), 4).setText(str(anzahl)) # in die Tabelle die Anzahl an berechneten Bauteilen reinschreiben
|
||||
|
||||
def checkWaageFinished(self, einzelteilID):
|
||||
self.setRowColor(self.AuftragsdetailsTable, self.getRowNr(einzelteilID),0,255,0) #zum setzen den Farbe der gesamten Reihe auf Grün
|
||||
|
||||
if self.checkFinished(): # wenn alle Bauteile auf der Waage liegen, soll folgender Code ausgeführt werden
|
||||
self.setRowColor(self.ArbeitsschrittTable, 2,0,255,0) # zum setzen der dritten Spalte der Arbeitsschrittetabelle auf grün
|
||||
self.setRowColor(self.ArbeitsschrittTable, 3,0,255,0) # zum setzen der vierte Spalte der Arbeitsschrittetabelle auf grün
|
||||
else: # wenn noch nicht alle Bauteile des Auftrags auf der Waage liegen, soll folgernder Code ausgeführt werden
|
||||
self.setRowColor(self.ArbeitsschrittTable, 1,255,165,0) # zum setzen der zweiten Spalte der Arbeitsschrittetabelle auf orange
|
||||
self.setRowColor(self.ArbeitsschrittTable, 2,255,255,255) # zum setzen der dritten Spalte der Arbeitsschrittetabelle auf weiß
|
||||
if self.checkBoxAutoTare.isChecked():
|
||||
self.onTareClick()
|
||||
|
||||
# den Thread beenden
|
||||
self.checkWaageThread.quit()
|
||||
self.checkWaageThread.wait()
|
||||
|
||||
# auch wenn die Länge der Liste überschritten wurde
|
||||
# wenn der statische Workflow aktiviert ist, dann soll die checkwaage-funktion erneut aufgerufen werden
|
||||
if(self.checkBox.isChecked() == True):
|
||||
self.checkWaage()
|
||||
|
||||
# GUI updaten
|
||||
#self.updateGUI()
|
||||
|
||||
def objectTypeDetection(self):
|
||||
# in dieser Funktion wird der Typ des Bauteils automatisch erkannt
|
||||
|
||||
# wenn der statische Workflow ausgewählt wurde, dann soll die checkWaage Funktion aufgerufen werden, auch wenn die detectBauteiltyp-Funkion aufgerufen wurde
|
||||
if self.checkBox.isChecked() == True:
|
||||
self.checkWaage()
|
||||
return
|
||||
|
||||
'''
|
||||
if(self.checkPosNrEmpty()==True):
|
||||
print("Das Pos.-Nr.-Feld ist leer.")
|
||||
return
|
||||
'''
|
||||
|
||||
# die Loopvariable des Workers auf False setzten, damit die Schleife durchgelaufen wird (diese wird zum Abbruch der Schleife benötigt -> siehe stopLoop)
|
||||
#self.objectDetectionWorker.stopLoopSignal.emit(False)
|
||||
|
||||
# überprüfen, ob der Auftrag in die Tabelle geladen wurde
|
||||
if(self.AuftragsdetailsTable.item(0,0) == None):
|
||||
print("Der Auftrag muss zuerst geladen werden.")
|
||||
return
|
||||
|
||||
# speichert den Wert, welcher im Textfeld steht in Variablen im Code
|
||||
self.setAuftragsnummer()
|
||||
|
||||
# starten des Threats, welcher den Bauteiltyp zurück gibt
|
||||
self.objectDetectionWorker = Worker()
|
||||
self.objectDetectionThread = QThread()
|
||||
|
||||
self.objectDetectionWorker.moveToThread(self.objectDetectionThread)
|
||||
|
||||
self.objectDetectionWorker.objectDetectionStartSignal.connect(self.objectDetectionWorker.objectTypeDetectionThread)
|
||||
self.objectDetectionWorker.objectDetectionFinishedSignal.connect(self.objectTypeDetectionFinished)
|
||||
self.objectDetectionWorker.waageStoppedSignal.connect(self.threadStopped)
|
||||
self.objectDetectionWorker.stopLoopSignal.connect(lambda status: setattr(self.objectDetectionWorker, 'stopLoop', status)) #wird fürs aktive Stoppen des Threads benötigt
|
||||
|
||||
self.objectDetectionThread.started.connect(lambda: self.objectDetectionWorker.objectDetectionStartSignal.emit(self.auftragsnummer))
|
||||
self.objectDetectionThread.start()
|
||||
|
||||
def objectTypeDetectionFinished(self, einzelteilID, rowData):
|
||||
# wenn der Typ des Objektes erkannt wurde, dann soll die Funktion aufgerufen werden
|
||||
|
||||
# Schreiben der Bauteiltype und Pos.-Nr in die jeweiligen Felder
|
||||
self.PosNrTxtFeld.setText(str(rowData[1]))
|
||||
self.bauteiltypTextbox.setText(rowData[2])
|
||||
|
||||
# setzt den Boolean, um aus der Schleife raus zu gehen
|
||||
self.btTypeIsSet = True
|
||||
|
||||
#zum setzen den Farbe der gesamten Reihe auf Orange
|
||||
self.setRowColor(self.AuftragsdetailsTable, self.getRowNr(einzelteilID),255,165,0)
|
||||
|
||||
# den Thread beenden
|
||||
self.objectDetectionThread.quit()
|
||||
self.objectDetectionThread.wait()
|
||||
|
||||
# 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.")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
MainWindow = QtWidgets.QMainWindow()
|
||||
ui = Ui_MainWindow()
|
||||
ui.setupUi(MainWindow)
|
||||
MainWindow.show()
|
||||
sys.exit(app.exec_())
|
||||
|
||||
|
||||
|
||||
|
||||
|
823
GUI_26_09_staticWorkflow_Multithreading.py
Normal file
823
GUI_26_09_staticWorkflow_Multithreading.py
Normal file
@ -0,0 +1,823 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'test.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
########## beim Static workflow funktionieren die Threads ab dem zweiten nicht mehr
|
||||
|
||||
#from PyQt5 import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QProgressBar
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
from PyQt5.QtWidgets import QApplication, QComboBox
|
||||
from PyQt5.QtCore import QTimer, QThread, pyqtSignal, QObject
|
||||
from PyQt5.QtGui import QColor
|
||||
|
||||
import serial
|
||||
import binascii
|
||||
import math
|
||||
import mariadb
|
||||
import time
|
||||
import threading
|
||||
|
||||
|
||||
db_config = {
|
||||
'user': 'dbUser',
|
||||
'password': 'dbPassword',
|
||||
'host': 'localhost',
|
||||
'database': 'projectGeislinger',
|
||||
'port': 3306 # Standard port for MariaDB
|
||||
}
|
||||
|
||||
# Establishing the connection
|
||||
conn = mariadb.connect(**db_config)
|
||||
# Create a cursor to execute queries
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Konfiguration der seriellen Schnittstelle
|
||||
ser = serial.Serial('/dev/ttyUSB0', 9600)
|
||||
|
||||
waageEingeschwungen = False
|
||||
|
||||
|
||||
def wahrscheinlichkeitsDichte(x,mue, var):
|
||||
# in der Funktion wird der Wahrscheinlichkeitsdichtenwert der Variable x für eine bestimmte Normalverteilung berechnet
|
||||
standardabweichung = var**0.5
|
||||
|
||||
result = 1/(standardabweichung * (2*math.pi)**0.5 ) * math.exp(-0.5 * ((x-mue)/standardabweichung)**2)
|
||||
|
||||
return result
|
||||
|
||||
def calcWahrscheinlichkeitFromDichte(x,mue, var):
|
||||
# in der Funktion wird die Wahrscheinlichkeit via der Wahrscheinlichkeitsdichte berechnet, indem das Verhältnis aus der dem Bauteil zugehörigen Wahrscheinlichkeitsdichte zu der maximalen Wahrscheinlichkeitsdichte berechnet wird
|
||||
p1 = wahrscheinlichkeitsDichte(x,mue, var)
|
||||
p_max = wahrscheinlichkeitsDichte(mue,mue, var)
|
||||
|
||||
return p1/p_max
|
||||
|
||||
|
||||
|
||||
#class Worker(QThread):
|
||||
class Worker(QObject):
|
||||
#progress = pyqtSignal(int)
|
||||
objectDetectionStartSignal = pyqtSignal(str)
|
||||
objectDetectionFinishedSignal = pyqtSignal(int, object)
|
||||
|
||||
checkWaageStartSignal = pyqtSignal(int, int, str)
|
||||
checkWaageUpdateSignal = pyqtSignal(int, int)
|
||||
checkWaageFinishedSignal = pyqtSignal(int)
|
||||
|
||||
waageStoppedSignal = pyqtSignal(int)
|
||||
stopLoopSignal = pyqtSignal(bool) #das Signal wird verwendet um direkt den stopLoop-Wert zu ändern (also kein Funktionsaufruf)
|
||||
|
||||
stopLoop = False
|
||||
btTypeIsSet = False
|
||||
correctBtNr = False
|
||||
|
||||
|
||||
def __init__(self):
|
||||
super(Worker, self).__init__()
|
||||
stopLoop = False
|
||||
|
||||
|
||||
def getDataOfArticleType(self, allArticles, articleType):
|
||||
# die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück
|
||||
for i in allArticles:
|
||||
if i[1] == articleType:
|
||||
return i
|
||||
|
||||
return -1
|
||||
|
||||
def waageNichtEingeschwungenOutput(self):
|
||||
print("Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft.")
|
||||
|
||||
def readWaage(self):
|
||||
# in folgender Funktion wird die Waage ausgelesen
|
||||
|
||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
||||
#print("port to which it is connected: ", ser.portstr) #Debuggingausgabe
|
||||
|
||||
|
||||
if ser.is_open == False:
|
||||
ser.open()
|
||||
|
||||
|
||||
#an die Waage den Befehl senden, dass sie ausgelesen werden soll
|
||||
ser.write(b'getWeight\n')
|
||||
#ser.write(b'tare\n')
|
||||
serialString = ser.readline().decode('utf-8').rstrip() #Auslesen des Serial-Strings/der Messung der Waage
|
||||
|
||||
# wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft
|
||||
lenString = len(serialString)-1
|
||||
if serialString[lenString] == "g" and serialString[lenString-1] == "k":
|
||||
#print("ist eingeschwungen") #Debuggingausgabe
|
||||
waageEingeschwungen = True
|
||||
else:
|
||||
print("die Waage ist noch nicht eingeschwungen")
|
||||
waageEingeschwungen = False
|
||||
|
||||
#aus dem String werden alle Zeichen, welche nicht zur Darstellung der Zahl benötigt werden entfernt
|
||||
intString = ""
|
||||
for i in serialString:
|
||||
if i=="-" or i=="0" or i=="." or i=="1" or i=="2" or i=="3" or i=="4" or i=="5" or i=="6" or i=="7" or i=="8" or i=="9":
|
||||
intString = intString + i
|
||||
print("Wert, welcher von der Waage ausgelesen wurde: " + intString + "kg")
|
||||
## Waage auslesen - ENDE
|
||||
|
||||
ser.close()
|
||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
||||
|
||||
return waageEingeschwungen, intString
|
||||
|
||||
def objectTypeDetectionThread(self, auftragsnummer):
|
||||
# in dieser Funktion wird der Typ des Bauteils automatisch erkannt
|
||||
|
||||
#print("objectTypeDetectionThread - Running in thread:", threading.current_thread().name) #Debuggausgabe
|
||||
|
||||
# Parameterdefinition
|
||||
propDensVect = []
|
||||
|
||||
self.btTypeIsSet = False
|
||||
|
||||
while(self.btTypeIsSet == False and self.stopLoop == False):
|
||||
|
||||
# Auslesen der Waage
|
||||
waageEingeschwungen, intString = self.readWaage()
|
||||
if waageEingeschwungen == False:
|
||||
self.waageNichtEingeschwungenOutput()
|
||||
else:
|
||||
|
||||
# Datenbankabfrage
|
||||
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer
|
||||
cursor.execute(sql_query)
|
||||
auftragEinzelteilDaten = cursor.fetchall()
|
||||
|
||||
'''
|
||||
# Display data #Debugausgabe
|
||||
print("Ausgabe der Auftragsdetails des obigen Auftrags, inklusive Einzelteildetails:")
|
||||
for row in auftragEinzelteilDaten:
|
||||
print(row)
|
||||
'''
|
||||
|
||||
# in der Folge werden alle Wahrscheinlichkeitsdichten der Auftragsbauteile berechnet und in dem Vektor gesammelt
|
||||
for row in auftragEinzelteilDaten:
|
||||
propDensVect.append([wahrscheinlichkeitsDichte(float(intString),float(row[6]), float(row[7])), row[1], row[5]])
|
||||
|
||||
# Jenen Eintrag des propDensVect raussuchen, welcher die größte Wahrscheinlichkeitsdichte beinhaltet
|
||||
maxpropDens = 0
|
||||
einzelteilID = 0
|
||||
rowData = None
|
||||
for row in propDensVect:
|
||||
if row[0] > maxpropDens:
|
||||
maxpropDens = row[0]
|
||||
einzelteilID = row[1]
|
||||
rowData = row
|
||||
|
||||
# überprüfen, ob das aufliegende Bauteil in der Auftragstabelle vorhanden ist
|
||||
if(einzelteilID == 0):
|
||||
print("Es wurde kein Bauteil aus der Auftragsliste (Tabelle) erkannt.")
|
||||
else:
|
||||
print("Bei dem Bauteil" , einzelteilID , "wurde die höchste Wahrscheinlichkeitsdichte berechnet.")
|
||||
|
||||
# Wahrscheinlichkeit berechnen, dass das angegebene Bauteil auch wirklich diesem entspricht
|
||||
prop = 0
|
||||
for row in auftragEinzelteilDaten:
|
||||
if row[1] == einzelteilID:
|
||||
prop = calcWahrscheinlichkeitFromDichte(float(intString),float(row[6]), float(row[7]))
|
||||
break
|
||||
print("Die Wahrscheinlichkeit, dass es das Bauteil ist, beträgt: ", prop)
|
||||
|
||||
# den Bool auf true setzen, damit die Schleife beendet wird - dieser wird auf True gesetzt, wenn ein Bauteiltyp erkannt wird
|
||||
self.btTypeIsSet = True
|
||||
|
||||
if(self.stopLoop == False):
|
||||
# ein Signal zurück an den MainThreat senden, mit den Infos/Ergebnissen, der Typenbestimmung
|
||||
self.objectDetectionFinishedSignal.emit(einzelteilID, rowData)
|
||||
else:
|
||||
self.waageStoppedSignal.emit(einzelteilID)
|
||||
|
||||
def checkWaageThread(self, einzelteilID, teileZuViel, auftragsnummer):
|
||||
|
||||
self.correctBtNr = False
|
||||
prevAnzahl = 0
|
||||
anzahl = 0
|
||||
einzelteilID = einzelteilID
|
||||
|
||||
while (self.correctBtNr == False and self.stopLoop == False):
|
||||
|
||||
#überprüfen, ob die Waage eingeschwungen ist (und damit korrekte Ergebnisse liefert)
|
||||
waageEingeschwungen, intString = self.readWaage()
|
||||
if waageEingeschwungen == False:
|
||||
self.waageNichtEingeschwungenOutput()
|
||||
else:
|
||||
|
||||
# Datenbankabfrage - holen der Auftrags- und Bauteilinfos
|
||||
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer
|
||||
cursor.execute(sql_query)
|
||||
auftragDaten = cursor.fetchall()
|
||||
|
||||
'''
|
||||
# Display data - zum Debuggen
|
||||
print("Ausgabe der Auftragsdetails:")
|
||||
print("id|EinzelteilID|Auftragsnummer|Anzahl")
|
||||
for row in auftragDaten:
|
||||
print(row)
|
||||
'''
|
||||
|
||||
#auslesen, wie viele Bauteile des Types laut Auftrag vorhanden sein sollen
|
||||
anzBauteile_soll = 0
|
||||
idVorhanden = False
|
||||
|
||||
for row in auftragDaten:
|
||||
if row[1] == einzelteilID:
|
||||
anzBauteile_soll = row[3]
|
||||
idVorhanden = True
|
||||
|
||||
if(idVorhanden == False):
|
||||
print("Die gewählte Pos.Nr ist nicht in der Auftragsliste (Tabelle) vorhanden.")
|
||||
return
|
||||
|
||||
# Berechnen der Wahrscheinlichkeitsdichten - der Betrag aller Wahrscheinlichkeitsdichten werden im propDensVect gespeichert
|
||||
propDensVect = []
|
||||
articleData = self.getDataOfArticleType(auftragDaten, einzelteilID)
|
||||
for i in range(1,anzBauteile_soll+teileZuViel+1):
|
||||
# Mathematische Sätze, auf welchen die Berechnung basiert:
|
||||
# seien X1,..., Xn unabhängige Zufallsvariablen die N(mue_i, sigma_i^2) verteilt sind, dann ist X = X1+...+Xn - N(mue, sigma^2) verteilt mit mue=mue1+...+mue_n, sigma^2 = sigma_1^2+...+sigma_n^2
|
||||
mueGes = float(articleData[6])*i # Berechnen des äquivalenten Mittelwert
|
||||
varGes = float(articleData[7])*i # Berechnen der äquivalenten Varianz
|
||||
propDensVect.append([wahrscheinlichkeitsDichte(float(intString),mueGes, varGes), i])
|
||||
|
||||
# durch den propDensVect iterieren und jenen Eintrag mit der höchsten Wahrscheinlichkeitsdichte raussuchen
|
||||
maxpropDens = 0
|
||||
for row in propDensVect:
|
||||
if row[0] > maxpropDens:
|
||||
maxpropDens = row[0]
|
||||
anzahl = row[1]
|
||||
|
||||
# damit nur etwas gemacht wird (zb ein Updatesignal an den Hauptthread zurücksenden), wenn sich die berechnete Anzahl ändert
|
||||
if prevAnzahl != anzahl:
|
||||
prevAnzahl = anzahl
|
||||
|
||||
# Die Wahrscheinlichkeit berechnen, dass das obige Ergebnis auch dem Bauteil entspricht
|
||||
if anzahl > 0:
|
||||
for row in auftragDaten:
|
||||
if row[1] == einzelteilID:
|
||||
prop = calcWahrscheinlichkeitFromDichte(float(intString),float(row[6])*anzahl, float(row[7])*anzahl)
|
||||
break
|
||||
print("Die Wahrscheinlichkeit, dass es das Bauteil ist, beträgt: ", prop)
|
||||
|
||||
# wenn genug Bauteile vorhanden sind, dann soll die Schleife beendet werden
|
||||
if (anzahl == anzBauteile_soll):
|
||||
self.correctBtNr = True
|
||||
|
||||
# Konsolenausgabe
|
||||
if maxpropDens > 0:
|
||||
print("Bei der Anzahl" , anzahl , "des Bauteiltypes", einzelteilID, ",wurde die höchste Wahrscheinlichkeitsdichte berechnet.")
|
||||
self.checkWaageUpdateSignal.emit(einzelteilID, anzahl)
|
||||
|
||||
else:
|
||||
print("Von der ausgewählten Bauteiltype liegt die berechnete Wahrscheinlichkeit bei 0, dass zwischen 0 und", anzBauteile_soll+teileZuViel, "Bauteilen auf der Waage liegen.")
|
||||
print("Falls die korrekte Anzhl an Bauteilen auf der Waage liegt, könnte der Fehler in einer falschen Kalibrierung der Waage liegen (TARE).")
|
||||
|
||||
if(self.stopLoop == False):
|
||||
self.checkWaageFinishedSignal.emit(einzelteilID)
|
||||
else:
|
||||
self.waageStoppedSignal.emit(einzelteilID)
|
||||
|
||||
|
||||
|
||||
|
||||
class Ui_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
self.auftragsnummer = ""
|
||||
self.teileZuViel = 0 # Anzahl an Bauteilen, welche zu viel drinnen sein können - der Parameter kann selbst gesetzt werden #####
|
||||
self.correctBtNr = False
|
||||
self.btTypeIsSet = False
|
||||
|
||||
|
||||
MainWindow.setObjectName("MainWindow")
|
||||
MainWindow.resize(1090, 675)
|
||||
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
||||
self.centralwidget.setObjectName("centralwidget")
|
||||
self.btn1 = QtWidgets.QPushButton(self.centralwidget)
|
||||
self.btn1.setGeometry(QtCore.QRect(700, 45, 111, 25))
|
||||
self.btn1.setObjectName("btn1")
|
||||
self.AuftragsdetailsTable = QtWidgets.QTableWidget(self.centralwidget)
|
||||
self.AuftragsdetailsTable.setGeometry(QtCore.QRect(10, 300, 661, 192))
|
||||
self.AuftragsdetailsTable.setObjectName("AuftragsdetailsTable")
|
||||
self.AuftragsdetailsTable.setColumnCount(7)
|
||||
self.AuftragsdetailsTable.setRowCount(0)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(8)
|
||||
item.setFont(font)
|
||||
self.AuftragsdetailsTable.setHorizontalHeaderItem(0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(8)
|
||||
item.setFont(font)
|
||||
self.AuftragsdetailsTable.setHorizontalHeaderItem(1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(8)
|
||||
item.setFont(font)
|
||||
self.AuftragsdetailsTable.setHorizontalHeaderItem(2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(8)
|
||||
item.setFont(font)
|
||||
self.AuftragsdetailsTable.setHorizontalHeaderItem(3, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(8)
|
||||
item.setFont(font)
|
||||
self.AuftragsdetailsTable.setHorizontalHeaderItem(5, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(8)
|
||||
item.setFont(font)
|
||||
self.AuftragsdetailsTable.setHorizontalHeaderItem(4, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(8)
|
||||
item.setFont(font)
|
||||
self.AuftragsdetailsTable.setHorizontalHeaderItem(6, item)
|
||||
|
||||
self.label = QtWidgets.QLabel(self.centralwidget)
|
||||
self.label.setGeometry(QtCore.QRect(500, 20, 121, 17))
|
||||
self.label.setObjectName("label")
|
||||
self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
|
||||
self.textEdit.setGeometry(QtCore.QRect(450, 40, 221, 31))
|
||||
self.textEdit.setObjectName("textEdit")
|
||||
self.bauteilTypBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||
self.bauteilTypBtn.setGeometry(QtCore.QRect(700, 150, 161, 25))
|
||||
self.bauteilTypBtn.setObjectName("bauteilTypBtn")
|
||||
self.checkWaageBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||
self.checkWaageBtn.setGeometry(QtCore.QRect(700, 460, 161, 25))
|
||||
self.checkWaageBtn.setObjectName("checkWaageBtn")
|
||||
self.stopLoopBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||
self.stopLoopBtn.setGeometry(QtCore.QRect(700, 500, 161, 25))
|
||||
self.stopLoopBtn.setObjectName("stopLoopBtn")
|
||||
self.waageTareBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||
self.waageTareBtn.setGeometry(QtCore.QRect(700, 100, 161, 25))
|
||||
self.waageTareBtn.setObjectName("waageTareBtn")
|
||||
self.bauteiltypTextbox = QtWidgets.QTextEdit(self.centralwidget)
|
||||
self.bauteiltypTextbox.setGeometry(QtCore.QRect(700, 290, 221, 31))
|
||||
self.bauteiltypTextbox.setObjectName("bauteiltypTextbox")
|
||||
self.BezeichnungLabel = QtWidgets.QLabel(self.centralwidget)
|
||||
self.BezeichnungLabel.setGeometry(QtCore.QRect(700, 270, 181, 20))
|
||||
self.BezeichnungLabel.setObjectName("BezeichnungLabel")
|
||||
self.PosNrLabel = QtWidgets.QLabel(self.centralwidget)
|
||||
self.PosNrLabel.setGeometry(QtCore.QRect(700, 200, 67, 17))
|
||||
self.PosNrLabel.setObjectName("PosNrLabel")
|
||||
self.PosNrTxtFeld = QtWidgets.QTextEdit(self.centralwidget)
|
||||
self.PosNrTxtFeld.setGeometry(QtCore.QRect(700, 220, 191, 31))
|
||||
self.BezeichnungLabel.setObjectName("BezeichnungLabel")
|
||||
self.teileZuVielLabel = QtWidgets.QLabel(self.centralwidget)
|
||||
self.teileZuVielLabel.setGeometry(QtCore.QRect(700, 350, 350, 17))
|
||||
self.teileZuVielLabel.setObjectName("teileZuVielLabel")
|
||||
self.teileZuVielTxtFeld = QtWidgets.QTextEdit(self.centralwidget)
|
||||
self.teileZuVielTxtFeld.setGeometry(QtCore.QRect(700, 370, 191, 31))
|
||||
MainWindow.setCentralWidget(self.centralwidget)
|
||||
self.menubar = QtWidgets.QMenuBar(MainWindow)
|
||||
self.menubar.setGeometry(QtCore.QRect(0, 0, 1090, 22))
|
||||
self.menubar.setObjectName("menubar")
|
||||
MainWindow.setMenuBar(self.menubar)
|
||||
self.statusbar = QtWidgets.QStatusBar(MainWindow)
|
||||
self.statusbar.setObjectName("statusbar")
|
||||
MainWindow.setStatusBar(self.statusbar)
|
||||
self.checkBox = QtWidgets.QCheckBox(self.centralwidget)
|
||||
self.checkBox.setGeometry(QtCore.QRect(700, 10, 151, 23))
|
||||
self.checkBox.setObjectName("checkBox")
|
||||
|
||||
#self.myTestLambda = lambda: self.worker.checkWaageStartSignal.emit(einzelteilID, self.teileZuViel, self.auftragsnummer)
|
||||
|
||||
'''
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(8)
|
||||
item.setFont(font)
|
||||
self.AuftragsdetailsTable.setVerticalHeaderItem(0,item)
|
||||
'''
|
||||
self.retranslateUi(MainWindow)
|
||||
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||
|
||||
def retranslateUi(self, MainWindow):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
|
||||
self.btn1.setText(_translate("MainWindow", "load Auftrag"))
|
||||
self.btn1.clicked.connect(self.auftragsBtnClicked)
|
||||
item = self.AuftragsdetailsTable.horizontalHeaderItem(0)
|
||||
item.setText(_translate("MainWindow", "Pos.-Nr"))
|
||||
item = self.AuftragsdetailsTable.horizontalHeaderItem(1)
|
||||
item.setText(_translate("MainWindow", "Matnr mit hoechster Version"))
|
||||
item = self.AuftragsdetailsTable.horizontalHeaderItem(2)
|
||||
item.setText(_translate("MainWindow", "Bezeichnung + Werkstoff"))
|
||||
item = self.AuftragsdetailsTable.horizontalHeaderItem(3)
|
||||
item.setText(_translate("MainWindow", "Soll-Menge"))
|
||||
item = self.AuftragsdetailsTable.horizontalHeaderItem(4)
|
||||
item.setText(_translate("MainWindow", "Ist-Menge"))
|
||||
item = self.AuftragsdetailsTable.horizontalHeaderItem(5)
|
||||
item.setText(_translate("MainWindow", "Lgort"))
|
||||
item = self.AuftragsdetailsTable.horizontalHeaderItem(6)
|
||||
item.setText(_translate("MainWindow", "set Farbe"))
|
||||
|
||||
self.label.setText(_translate("MainWindow", "Auftragsnummer:"))
|
||||
self.bauteilTypBtn.setText(_translate("MainWindow", "Bauteiltyp erkennen"))
|
||||
self.bauteilTypBtn.clicked.connect(self.objectTypeDetection)
|
||||
self.AuftragsdetailsTable.cellClicked.connect(self.onTableCellClick)
|
||||
#self.AuftragsdetailsTable.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers)
|
||||
#item = self.AuftragsdetailsTable.verticalHeaderItem(0)
|
||||
#item.setText(_translate("MainWindow", "test"))
|
||||
self.BezeichnungLabel.setText(_translate("MainWindow", "Bezeichnung"))
|
||||
self.PosNrLabel.setText(_translate("MainWindow", "Pos.-Nr:"))
|
||||
self.teileZuVielLabel.setText(_translate("MainWindow", "Zu prüfende Teileanzahl über Auftragsanzahl:"))
|
||||
self.teileZuVielTxtFeld.setText(str(self.teileZuViel))
|
||||
self.checkWaageBtn.setText(_translate("MainWindow", "check Waage"))
|
||||
self.checkWaageBtn.clicked.connect(self.checkWaage)
|
||||
self.stopLoopBtn.setText(_translate("MainWindow", "stop loop"))
|
||||
self.stopLoopBtn.clicked.connect(self.stopLoopClicked)
|
||||
self.waageTareBtn.setText(_translate("MainWindow", "Waage tarieren"))
|
||||
self.waageTareBtn.clicked.connect(self.onTareClick)
|
||||
self.checkBox.setText(_translate("MainWindow", "static workflow"))
|
||||
self.checkBox.clicked.connect(self.onCheckboxCheck)
|
||||
|
||||
def onTareClick(self):
|
||||
#Tarieren der Waage
|
||||
if ser.is_open == False:
|
||||
ser.open()
|
||||
ser.write(b'tare\n')
|
||||
ser.close()
|
||||
|
||||
|
||||
def onCheckboxCheck(self):
|
||||
if self.checkBox.isChecked() == True:
|
||||
print("static workflow activated")
|
||||
else:
|
||||
print("static workflow deactivated")
|
||||
|
||||
def getRowNr(self, posNr):
|
||||
for i in range(0,self.AuftragsdetailsTable.rowCount()):
|
||||
if(self.AuftragsdetailsTable.item(i,0).text() == str(posNr)):
|
||||
return i
|
||||
# brauche ich hier vermutlich nicht mehr - ist in den Worker Thread kopiert worden
|
||||
def waageNichtEingeschwungenOutput(self):
|
||||
print("Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft.")
|
||||
|
||||
def onTableCellClick(self):
|
||||
self.PosNrTxtFeld.setText(self.AuftragsdetailsTable.item(self.AuftragsdetailsTable.currentRow(),0).text())
|
||||
self.bauteiltypTextbox.setText(self.AuftragsdetailsTable.item(self.AuftragsdetailsTable.currentRow(),2).text())
|
||||
|
||||
def setAuftragsnummer(self):
|
||||
self.auftragsnummer = self.textEdit.toPlainText()
|
||||
if(not self.auftragsnummer):
|
||||
self.auftragsnummer = ""
|
||||
self.textEdit.setText("")
|
||||
|
||||
def checkAuftragsnummerEmpty(self):
|
||||
if self.auftragsnummer == "":
|
||||
print("Das Auftragsnummernfeld ist leer.")
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def checkPosNrEmpty(self):
|
||||
if self.PosNrTxtFeld.toPlainText() == "":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
# eventuell benötigt man die Funktion hier nicht mehr, da sie zu den Threads kopiert wurde
|
||||
def getDataOfArticleType(self, allArticles, articleType):
|
||||
# die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück
|
||||
for i in allArticles:
|
||||
if i[1] == articleType:
|
||||
return i
|
||||
return -1
|
||||
|
||||
def updateGUI(self):
|
||||
self.PosNrLabel.repaint() #GUI aktualisieren
|
||||
QApplication.processEvents() #GUI aktualisieren
|
||||
|
||||
def setRowColor(self, rowID,r,g,b):
|
||||
self.AuftragsdetailsTable.item(rowID, 0).setBackground(QtGui.QColor(r,g,b))
|
||||
self.AuftragsdetailsTable.item(rowID, 1).setBackground(QtGui.QColor(r,g,b))
|
||||
self.AuftragsdetailsTable.item(rowID, 2).setBackground(QtGui.QColor(r,g,b))
|
||||
self.AuftragsdetailsTable.item(rowID, 3).setBackground(QtGui.QColor(r,g,b))
|
||||
self.AuftragsdetailsTable.item(rowID, 4).setBackground(QtGui.QColor(r,g,b))
|
||||
self.AuftragsdetailsTable.item(rowID, 5).setBackground(QtGui.QColor(r,g,b))
|
||||
|
||||
#wird hier vermutlich nicht mehr benötigt - wurde in die Workerklasse kopiert
|
||||
def readWaage(self):
|
||||
# in folgender Funktion wird die Waage ausgelesen
|
||||
|
||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
||||
#print("port to which it is connected: ", ser.portstr) #Debuggingausgabe
|
||||
self.checkPosNrEmpty()
|
||||
|
||||
if ser.is_open == False:
|
||||
ser.open()
|
||||
|
||||
|
||||
#an die Waage den Befehl senden, dass sie ausgelesen werden soll
|
||||
ser.write(b'getWeight\n')
|
||||
#ser.write(b'tare\n')
|
||||
serialString = ser.readline().decode('utf-8').rstrip() #Auslesen des Serial-Strings/der Messung der Waage
|
||||
|
||||
# wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft
|
||||
lenString = len(serialString)-1
|
||||
if serialString[lenString] == "g" and serialString[lenString-1] == "k":
|
||||
#print("ist eingeschwungen") #Debuggingausgabe
|
||||
waageEingeschwungen = True
|
||||
else:
|
||||
print("die Waage ist noch nicht eingeschwungen")
|
||||
waageEingeschwungen = False
|
||||
|
||||
#aus dem String werden alle Zeichen, welche nicht zur Darstellung der Zahl benötigt werden entfernt
|
||||
intString = ""
|
||||
for i in serialString:
|
||||
if i=="-" or i=="0" or i=="." or i=="1" or i=="2" or i=="3" or i=="4" or i=="5" or i=="6" or i=="7" or i=="8" or i=="9":
|
||||
intString = intString + i
|
||||
print("Wert, welcher von der Waage ausgelesen wurde: " + intString + "kg")
|
||||
## Waage auslesen - ENDE
|
||||
|
||||
ser.close()
|
||||
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
||||
|
||||
return waageEingeschwungen, intString
|
||||
|
||||
def auftragsBtnClicked(self):
|
||||
databaseQueryWorking = False #wird für die Überprüfung, ob die Datenbankabfrage fehlerhaft ist, verwendet
|
||||
auftragEinzelteilDaten = []
|
||||
|
||||
self.setAuftragsnummer()
|
||||
if(not self.checkAuftragsnummerEmpty()):
|
||||
|
||||
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + self.auftragsnummer
|
||||
try:
|
||||
cursor.execute(sql_query)
|
||||
# Fetch results
|
||||
auftragEinzelteilDaten = cursor.fetchall()
|
||||
databaseQueryWorking = True
|
||||
except:
|
||||
print("Fehler in der Datenbankabfrage.")
|
||||
|
||||
|
||||
|
||||
if databaseQueryWorking==True and len(auftragEinzelteilDaten)>0:
|
||||
'''
|
||||
# Display data
|
||||
print("Ausgabe der Auftragsdetails des obigen Auftrags, inklusive Einzelteildetails:")
|
||||
for row in auftragEinzelteilDaten:
|
||||
if str(row[2]) == self.auftragsnummer:
|
||||
print("passt")
|
||||
print(row)
|
||||
'''
|
||||
|
||||
### die Auftragsdaten in die Tabelle laden
|
||||
self.AuftragsdetailsTable.setRowCount(len(auftragEinzelteilDaten))
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
counter = 0
|
||||
for row in auftragEinzelteilDaten:
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 0, self.item)
|
||||
self.item.setText(str(row[1]))
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 1, self.item)
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 2, self.item)
|
||||
self.item.setText(str(row[5]))
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 3, self.item)
|
||||
self.item.setText(str(row[3]))
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 4, self.item)
|
||||
self.item.setText(str("0"))
|
||||
self.item = QtWidgets.QTableWidgetItem()
|
||||
self.AuftragsdetailsTable.setItem(counter, 5, self.item)
|
||||
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||
|
||||
# Dropdown für Farben in die 6. Spalte einfügen
|
||||
#self.item = QtWidgets.QTableWidgetItem()
|
||||
#self.AuftragsdetailsTable.setItem(counter, 6, self.item)
|
||||
combo = QComboBox()
|
||||
combo.addItems(["Farbe", "Weiß", "Orange", "Grün"])
|
||||
combo.currentIndexChanged.connect(lambda index, rowId =counter: self.change_row_color(rowId, index))
|
||||
self.AuftragsdetailsTable.setCellWidget(counter, 6, combo)
|
||||
counter = counter +1
|
||||
|
||||
elif(databaseQueryWorking==True and len(auftragEinzelteilDaten)==0):
|
||||
print("Es wurde in der Datenbank kein Auftrag mit dieser Auftragsnummer gefunden.")
|
||||
|
||||
def change_row_color(self, row, color_index):
|
||||
if(color_index == 1):
|
||||
self.setRowColor(row,255,255,255)
|
||||
if(color_index == 2):
|
||||
self.setRowColor(row,255,165,0)
|
||||
if(color_index == 3):
|
||||
self.setRowColor(row,0,255,0)
|
||||
|
||||
|
||||
|
||||
|
||||
def stopLoopClicked(self):
|
||||
# damit wird beim Klick auf den Stopbutton der stopLoop-boolWert in der Workerklasse auf true gesetzt -> der Stop des Threads wird initiiert
|
||||
if hasattr(self, 'objectDetectionWorker'):
|
||||
self.objectDetectionWorker.stopLoopSignal.emit(True)
|
||||
|
||||
if hasattr(self, 'checkWaageWorker'):
|
||||
self.checkWaageWorker.stopLoopSignal.emit(True)
|
||||
|
||||
def checkWaage(self):
|
||||
#print("Running in thread:", threading.current_thread().name) # Debuggingausgabe
|
||||
QApplication.processEvents()
|
||||
|
||||
# die Loopvariable des Workers auf False setzten, damit die Schleife durchgelaufen wird (diese wird zum Abbruch der Schleife benötigt -> siehe stopLoop)
|
||||
#self.checkWaageWorker.stopLoopSignal.emit(False)
|
||||
|
||||
# überprüfen, ob der Auftrag geladen wurde
|
||||
if(self.AuftragsdetailsTable.item(0,0) == None):
|
||||
print("Der Auftrag muss zuerst geladen werden.")
|
||||
return
|
||||
|
||||
# überprüfen, ob ein Bauteiltyp gesetzt wurde
|
||||
if(self.checkPosNrEmpty()==True and self.checkBox.isChecked() == False):
|
||||
print("Das Pos.-Nr.-Feld ist leer.")
|
||||
return
|
||||
|
||||
# den GUI Wert von Textfeld TeileZuViel in die Variable schreiben
|
||||
self.teileZuViel = int(float(self.teileZuVielTxtFeld.toPlainText()))
|
||||
self.teileZuVielTxtFeld.setText(str(self.teileZuViel))
|
||||
|
||||
einzelteilID = -1 # Initialisieren der Variable mit einem Defaultwert, welcher nie eingenommen werden können sollte
|
||||
if (self.checkBox.isChecked() == False):
|
||||
#übernehmen der BauteilID aus dem Feld Pos.-Nr - wenn der Workflow dynamisch gewählt wurde
|
||||
einzelteilID = int(self.PosNrTxtFeld.toPlainText())
|
||||
else:
|
||||
# wenn der Workflow statisch gesetzt wurde, dann soll das erste Item aus der Auftragsliste geladen werden, von welchem noch nicht genug Bauteile auf der Waage liegen
|
||||
for i in range(0,self.AuftragsdetailsTable.rowCount()):
|
||||
if self.AuftragsdetailsTable.item(i,3).text() != self.AuftragsdetailsTable.item(i,4).text():
|
||||
einzelteilID = int(self.AuftragsdetailsTable.item(i,0).text())
|
||||
self.PosNrTxtFeld.setText(str(self.AuftragsdetailsTable.item(i,0).text()))
|
||||
self.bauteiltypTextbox.setText(str(self.AuftragsdetailsTable.item(i,2).text()))
|
||||
break
|
||||
|
||||
if einzelteilID == -1:
|
||||
# den Thread beenden
|
||||
self.checkWaageThread.quit()
|
||||
self.checkWaageThread.wait()
|
||||
try:
|
||||
self.checkWaageThread.started.disconnect() # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt
|
||||
print("Der Thread wurde beendet.")
|
||||
except:
|
||||
print("Disconnecting the thread did not work.")
|
||||
return
|
||||
|
||||
|
||||
#zum setzen den Farbe der gesamten Reihe auf Orange
|
||||
self.setRowColor(self.getRowNr(einzelteilID),255,165,0)
|
||||
|
||||
# den Thread starten, welcher die Bauteilanzahl überprüft
|
||||
self.checkWaageWorker = Worker()
|
||||
self.checkWaageThread = QThread()
|
||||
|
||||
self.checkWaageWorker.moveToThread(self.checkWaageThread)
|
||||
|
||||
self.checkWaageWorker.checkWaageStartSignal.connect(self.checkWaageWorker.checkWaageThread)
|
||||
self.checkWaageWorker.checkWaageUpdateSignal.connect(self.checkWaageUpdate)
|
||||
self.checkWaageWorker.checkWaageFinishedSignal.connect(self.checkWaageFinished)
|
||||
self.checkWaageWorker.waageStoppedSignal.connect(self.threadStopped)
|
||||
self.checkWaageWorker.stopLoopSignal.connect(lambda status: setattr(self.checkWaageWorker, 'stopLoop', status)) #wird fürs aktive Stoppen des Threads benötigt
|
||||
|
||||
self.checkWaageThread.started.connect(lambda: self.checkWaageWorker.checkWaageStartSignal.emit(einzelteilID, self.teileZuViel, self.auftragsnummer))
|
||||
self.checkWaageThread.start()
|
||||
|
||||
def checkWaageUpdate(self, einzelteilID, anzahl):
|
||||
# die Funktion updated die (vom Thread) berechnete Bauteilanzahl in der GUI
|
||||
self.AuftragsdetailsTable.item(self.getRowNr(einzelteilID), 4).setText(str(anzahl)) # in die Tabelle die Anzahl an berechneten Bauteilen reinschreiben
|
||||
|
||||
def checkWaageFinished(self, einzelteilID):
|
||||
self.setRowColor(self.getRowNr(einzelteilID),0,255,0) #zum setzen den Farbe der gesamten Reihe auf Grün
|
||||
|
||||
# den Thread beenden
|
||||
self.checkWaageThread.quit()
|
||||
self.checkWaageThread.wait()
|
||||
|
||||
# auch wenn die Länge der Liste überschritten wurde
|
||||
# wenn der statische Workflow aktiviert ist, dann soll die checkwaage-funktion erneut aufgerufen werden
|
||||
if(self.checkBox.isChecked() == True):
|
||||
self.checkWaage()
|
||||
|
||||
# GUI updaten
|
||||
#self.updateGUI()
|
||||
|
||||
def objectTypeDetection(self):
|
||||
# in dieser Funktion wird der Typ des Bauteils automatisch erkannt
|
||||
|
||||
# wenn der statische Workflow ausgewählt wurde, dann soll die checkWaage Funktion aufgerufen werden, auch wenn die detectBauteiltyp-Funkion aufgerufen wurde
|
||||
if self.checkBox.isChecked() == True:
|
||||
self.checkWaage()
|
||||
return
|
||||
|
||||
'''
|
||||
if(self.checkPosNrEmpty()==True):
|
||||
print("Das Pos.-Nr.-Feld ist leer.")
|
||||
return
|
||||
'''
|
||||
|
||||
# die Loopvariable des Workers auf False setzten, damit die Schleife durchgelaufen wird (diese wird zum Abbruch der Schleife benötigt -> siehe stopLoop)
|
||||
#self.objectDetectionWorker.stopLoopSignal.emit(False)
|
||||
|
||||
# überprüfen, ob der Auftrag in die Tabelle geladen wurde
|
||||
if(self.AuftragsdetailsTable.item(0,0) == None):
|
||||
print("Der Auftrag muss zuerst geladen werden.")
|
||||
return
|
||||
|
||||
# speichert den Wert, welcher im Textfeld steht in Variablen im Code
|
||||
self.setAuftragsnummer()
|
||||
|
||||
# starten des Threats, welcher den Bauteiltyp zurück gibt
|
||||
self.objectDetectionWorker = Worker()
|
||||
self.objectDetectionThread = QThread()
|
||||
|
||||
self.objectDetectionWorker.moveToThread(self.objectDetectionThread)
|
||||
|
||||
self.objectDetectionWorker.objectDetectionStartSignal.connect(self.objectDetectionWorker.objectTypeDetectionThread)
|
||||
self.objectDetectionWorker.objectDetectionFinishedSignal.connect(self.objectTypeDetectionFinished)
|
||||
self.objectDetectionWorker.waageStoppedSignal.connect(self.threadStopped)
|
||||
self.objectDetectionWorker.stopLoopSignal.connect(lambda status: setattr(self.objectDetectionWorker, 'stopLoop', status)) #wird fürs aktive Stoppen des Threads benötigt
|
||||
|
||||
self.objectDetectionThread.started.connect(lambda: self.objectDetectionWorker.objectDetectionStartSignal.emit(self.auftragsnummer))
|
||||
self.objectDetectionThread.start()
|
||||
|
||||
def objectTypeDetectionFinished(self, einzelteilID, rowData):
|
||||
# wenn der Typ des Objektes erkannt wurde, dann soll die Funktion aufgerufen werden
|
||||
|
||||
# Schreiben der Bauteiltype und Pos.-Nr in die jeweiligen Felder
|
||||
self.PosNrTxtFeld.setText(str(rowData[1]))
|
||||
self.bauteiltypTextbox.setText(rowData[2])
|
||||
|
||||
# setzt den Boolean, um aus der Schleife raus zu gehen
|
||||
self.btTypeIsSet = True
|
||||
|
||||
#zum setzen den Farbe der gesamten Reihe auf Orange
|
||||
self.setRowColor(self.getRowNr(einzelteilID),255,165,0)
|
||||
|
||||
# den Thread beenden
|
||||
self.objectDetectionThread.quit()
|
||||
self.objectDetectionThread.wait()
|
||||
|
||||
'''
|
||||
try:
|
||||
self.objectDetectionThread.started.disconnect() # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt
|
||||
except:
|
||||
print(f"Error while disconnecting: {e}")
|
||||
print("Disconnecting the thread did not work.")
|
||||
'''
|
||||
|
||||
# wenn der Bauteiltyp erkannt wurde, dann soll die GUI aktualisiert werden und anschließend die CheckWaage-Funktion aufgerufen werden
|
||||
self.updateGUI()
|
||||
self.checkWaage()
|
||||
|
||||
def threadStopped(self, einzelteilID):
|
||||
# wenn kein Bauteil erkannt wurde, dann ist die EinzenteilID = 0
|
||||
if(einzelteilID > 0):
|
||||
self.setRowColor(self.getRowNr(einzelteilID),255,255,255) #zum setzen den Farbe der gesamten Reihe auf Weiß
|
||||
|
||||
# den Thread beenden
|
||||
if hasattr(self, 'objectDetectionThread'):
|
||||
self.objectDetectionThread.quit()
|
||||
self.objectDetectionThread.wait()
|
||||
print("Der ObjektDetection-Thread wurde beendet.")
|
||||
|
||||
if hasattr(self, 'checkWaageThread'):
|
||||
self.checkWaageThread.quit()
|
||||
self.checkWaageThread.wait()
|
||||
print("Der CheckWaage-Thread wurde beendet.")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
MainWindow = QtWidgets.QMainWindow()
|
||||
ui = Ui_MainWindow()
|
||||
ui.setupUi(MainWindow)
|
||||
MainWindow.show()
|
||||
sys.exit(app.exec_())
|
||||
|
||||
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
24
compose.yml
24
compose.yml
@ -1,24 +0,0 @@
|
||||
# Use root/example as user/password credentials
|
||||
version: '3.1'
|
||||
|
||||
services:
|
||||
|
||||
db:
|
||||
image: mariadb
|
||||
restart: always
|
||||
environment:
|
||||
MARIADB_ROOT_PASSWORD: example
|
||||
MARIADB_USER: dbUser
|
||||
MARIADB_PASSWORD: dbPassword
|
||||
MARIADB_DATABASE: projectGeislinger
|
||||
ports:
|
||||
- 3306:3306
|
||||
# network_mode: host
|
||||
# volumes:
|
||||
# - /tmp/mysql.sock:/tmp/mysql.sock
|
||||
|
||||
adminer:
|
||||
image: adminer
|
||||
restart: always
|
||||
ports:
|
||||
- 8082:8080
|
@ -1,17 +0,0 @@
|
||||
name: geislinger
|
||||
channels:
|
||||
- conda-forge
|
||||
- nvidia
|
||||
- pytorch
|
||||
dependencies:
|
||||
- pip=24.2
|
||||
- python=3.11
|
||||
- ultralytics=8
|
||||
- mariadb
|
||||
- pytorch
|
||||
- torchvision
|
||||
- torchaudio
|
||||
- pytorch-cuda=11.8
|
||||
- opencv
|
||||
- pyqt
|
||||
- pyserial
|
@ -1,149 +0,0 @@
|
||||
import cv2
|
||||
import os
|
||||
from datetime import datetime
|
||||
from ultralytics import YOLO
|
||||
|
||||
class YOLOv8CameraStream:
|
||||
def __init__(self, model_path: str, camera_source=0, confidence_threshold=0.5, save_threshold=0.9,
|
||||
log_file="detections.log", logging_level="high"):
|
||||
self.model = YOLO(model_path)
|
||||
self.camera_source = camera_source
|
||||
self.confidence_threshold = confidence_threshold
|
||||
self.default_confidence_threshold = confidence_threshold
|
||||
self.save_threshold = save_threshold
|
||||
self.default_save_threshold = save_threshold
|
||||
self.log_file = log_file
|
||||
self.logging_level = logging_level
|
||||
self.cap = cv2.VideoCapture(camera_source)
|
||||
|
||||
# Create directories for saved frames and archived logs if they don't exist
|
||||
os.makedirs("saved_frames", exist_ok=True)
|
||||
os.makedirs("archive", exist_ok=True)
|
||||
|
||||
# Initialize display settings
|
||||
self.show_thresholds = True
|
||||
|
||||
def log_detection(self, label, confidence):
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
self.check_log_size() # Check log size before logging
|
||||
with open(self.log_file, "a") as log:
|
||||
log.write(f"{timestamp} - Detected: {label} with confidence {confidence:.2f}\n")
|
||||
|
||||
def check_log_size(self):
|
||||
"""Checks the size of the log file and archives it if it exceeds 5 MB."""
|
||||
if os.path.exists(self.log_file) and os.path.getsize(self.log_file) > 5 * 1024 * 1024: # 5 MB
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
archived_log_file = f"archive/{self.log_file}_{timestamp}.log"
|
||||
os.rename(self.log_file, archived_log_file) # Rename the old log file
|
||||
print(f"Archived old log file to {archived_log_file}")
|
||||
# Create a new log file
|
||||
open(self.log_file, 'w').close() # Create an empty log file
|
||||
|
||||
def save_frame(self, frame, label):
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
filename = f"saved_frames/{label}_{timestamp}.jpg"
|
||||
cv2.imwrite(filename, frame)
|
||||
print(f"Frame saved: {filename}")
|
||||
|
||||
def get_color_for_confidence(self, confidence):
|
||||
if confidence > 0.75:
|
||||
return (0, 255, 0)
|
||||
elif confidence > 0.5:
|
||||
return (0, 255, 255)
|
||||
else:
|
||||
return (0, 0, 255)
|
||||
|
||||
def process_frame(self, frame):
|
||||
results = self.model.predict(frame)
|
||||
for result in results:
|
||||
for box in result.boxes:
|
||||
confidence = float(box.conf.item())
|
||||
if self.logging_level == "high" and confidence < self.save_threshold:
|
||||
continue
|
||||
|
||||
if confidence > self.confidence_threshold:
|
||||
x1, y1, x2, y2 = map(int, box.xyxy[0])
|
||||
class_id = int(box.cls.item())
|
||||
label = f"{result.names[class_id]} {confidence:.2f}"
|
||||
color = self.get_color_for_confidence(confidence)
|
||||
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
|
||||
cv2.putText(frame, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
|
||||
|
||||
self.log_detection(result.names[class_id], confidence)
|
||||
|
||||
if confidence > self.save_threshold:
|
||||
self.save_frame(frame, result.names[class_id])
|
||||
|
||||
if self.show_thresholds:
|
||||
self.display_thresholds(frame)
|
||||
self.display_keyboard_options(frame)
|
||||
|
||||
return frame
|
||||
|
||||
def display_thresholds(self, frame):
|
||||
text = f"Confidence Threshold: {self.confidence_threshold:.2f} | Save Threshold: {self.save_threshold:.2f}"
|
||||
cv2.putText(frame, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
|
||||
|
||||
def display_keyboard_options(self, frame):
|
||||
options = [
|
||||
"Keyboard Controls:",
|
||||
"'c' - Increase Confidence Threshold | 'v' - Decrease Confidence Threshold",
|
||||
"'s' - Increase Save Threshold | 'x' - Decrease Save Threshold",
|
||||
"'t' - Toggle Threshold Display | 'r' - Reset Thresholds to Default",
|
||||
"'q' - Quit"
|
||||
]
|
||||
for i, option in enumerate(options):
|
||||
cv2.putText(frame, option, (10, 50 + i * 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
||||
|
||||
def adjust_thresholds(self):
|
||||
print("\nPress 'c' to increase confidence threshold, 'v' to decrease it.")
|
||||
print("Press 's' to increase save threshold, 'x' to decrease it.")
|
||||
print("Press 't' to toggle threshold display, 'r' to reset thresholds to default.")
|
||||
print("Press 'q' to quit the program.\n")
|
||||
|
||||
def start(self):
|
||||
if not self.cap.isOpened():
|
||||
print("Error: Could not open video source.")
|
||||
return
|
||||
|
||||
self.adjust_thresholds()
|
||||
|
||||
while True:
|
||||
ret, frame = self.cap.read()
|
||||
if not ret:
|
||||
print("Error: Failed to capture frame.")
|
||||
break
|
||||
|
||||
processed_frame = self.process_frame(frame)
|
||||
cv2.imshow("YOLOv8 Camera Stream", processed_frame)
|
||||
|
||||
key = cv2.waitKey(1) & 0xFF
|
||||
if key == ord('q'):
|
||||
break
|
||||
elif key == ord('c'):
|
||||
self.confidence_threshold = min(self.confidence_threshold + 0.05, 1.0)
|
||||
print(f"Confidence threshold increased to {self.confidence_threshold:.2f}")
|
||||
elif key == ord('v'):
|
||||
self.confidence_threshold = max(self.confidence_threshold - 0.05, 0.0)
|
||||
print(f"Confidence threshold decreased to {self.confidence_threshold:.2f}")
|
||||
elif key == ord('s'):
|
||||
self.save_threshold = min(self.save_threshold + 0.05, 1.0)
|
||||
print(f"Save threshold increased to {self.save_threshold:.2f}")
|
||||
elif key == ord('x'):
|
||||
self.save_threshold = max(self.save_threshold - 0.05, 0.0)
|
||||
print(f"Save threshold decreased to {self.save_threshold:.2f}")
|
||||
elif key == ord('t'):
|
||||
self.show_thresholds = not self.show_thresholds
|
||||
print(f"Threshold display toggled to {'on' if self.show_thresholds else 'off'}")
|
||||
elif key == ord('r'):
|
||||
self.confidence_threshold = self.default_confidence_threshold
|
||||
self.save_threshold = self.default_save_threshold
|
||||
print("Thresholds reset to default values.")
|
||||
|
||||
self.cap.release()
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
# Run the object detection stream
|
||||
if __name__ == "__main__":
|
||||
yolo_stream = YOLOv8CameraStream(model_path="models/yolov8m_seg_e300.pt", logging_level="high")
|
||||
yolo_stream.start()
|
@ -1,53 +0,0 @@
|
||||
import subprocess
|
||||
|
||||
class SainsmartRelay:
|
||||
def __init__(self, executable="sainsmartrelay"):
|
||||
self.executable = executable
|
||||
|
||||
def _run_command(self, args):
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[self.executable] + args,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
return result.stdout.strip()
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error: {e.stderr.strip()}")
|
||||
return None
|
||||
|
||||
def turn_on(self, relays):
|
||||
"""Turn on specified relays."""
|
||||
relays_str = ','.join(map(str, relays)) if isinstance(relays, (list, tuple)) else str(relays)
|
||||
return self._run_command(["--on", relays_str])
|
||||
|
||||
def turn_off(self, relays):
|
||||
"""Turn off specified relays."""
|
||||
relays_str = ','.join(map(str, relays)) if isinstance(relays, (list, tuple)) else str(relays)
|
||||
return self._run_command(["--off", relays_str])
|
||||
|
||||
def get_status(self, relays="all"):
|
||||
"""Get the status of specified relays."""
|
||||
return self._run_command(["--status", str(relays)])
|
||||
|
||||
def find_all_devices(self):
|
||||
"""Find all connected FTDI devices."""
|
||||
return self._run_command(["--findall"])
|
||||
|
||||
# Example usage:
|
||||
if __name__ == "__main__":
|
||||
relay = SainsmartRelay()
|
||||
|
||||
# Turn on relay 1
|
||||
print(relay.turn_on(1))
|
||||
|
||||
# Turn off all relays
|
||||
print(relay.turn_off("all"))
|
||||
|
||||
# Get the status of all relays
|
||||
print(relay.get_status())
|
||||
|
||||
# Find all FTDI devices
|
||||
print(relay.find_all_devices())
|
@ -1,122 +0,0 @@
|
||||
import serial
|
||||
import time
|
||||
|
||||
class WLEDController:
|
||||
def __init__(self, port: str, baud_rate: int = 115200, timeout: float = 1.0):
|
||||
"""
|
||||
Initialize the WLEDController.
|
||||
|
||||
:param port: The serial port to which the ESP32 is connected (e.g., '/dev/ttyUSB0').
|
||||
:param baud_rate: The baud rate for the serial connection.
|
||||
:param timeout: The timeout for serial communication in seconds.
|
||||
"""
|
||||
self.port = port
|
||||
self.baud_rate = baud_rate
|
||||
self.timeout = timeout
|
||||
self.connection = None
|
||||
|
||||
def connect(self):
|
||||
"""Establish the serial connection."""
|
||||
try:
|
||||
self.connection = serial.Serial(
|
||||
self.port, self.baud_rate, timeout=self.timeout
|
||||
)
|
||||
print(f"Connected to {self.port}")
|
||||
except serial.SerialException as e:
|
||||
print(f"Failed to connect to {self.port}: {e}")
|
||||
|
||||
def disconnect(self):
|
||||
"""Close the serial connection."""
|
||||
if self.connection and self.connection.is_open:
|
||||
self.connection.close()
|
||||
print(f"Disconnected from {self.port}")
|
||||
|
||||
def send_command(self, command: str):
|
||||
"""
|
||||
Send a command to the WLED device.
|
||||
|
||||
:param command: The JSON command string to send.
|
||||
"""
|
||||
if not self.connection or not self.connection.is_open:
|
||||
raise ConnectionError("Serial connection is not open.")
|
||||
try:
|
||||
self.connection.write(command.encode('utf-8'))
|
||||
print(f"Sent command: {command}")
|
||||
except serial.SerialException as e:
|
||||
print(f"Failed to send command: {e}")
|
||||
|
||||
def switch_to_red(self):
|
||||
"""Switch the light to red."""
|
||||
self.send_command('{"ps":"1"}')
|
||||
|
||||
def switch_to_yellow(self):
|
||||
"""Switch the light to yellow."""
|
||||
self.send_command('{"ps":"2"}')
|
||||
|
||||
def switch_to_green(self):
|
||||
"""Switch the light to green."""
|
||||
self.send_command('{"ps":"3"}')
|
||||
|
||||
def turn_off_all(self):
|
||||
"""Turn off all lights."""
|
||||
self.send_command('{"ps":"4"}')
|
||||
|
||||
def blink_yellow(self):
|
||||
"""Blink in yellow."""
|
||||
self.send_command('{"ps":"5"}')
|
||||
|
||||
def blink_red(self):
|
||||
"""blink in red."""
|
||||
self.send_command('{"ps":"7"}')
|
||||
|
||||
def blink_green(self):
|
||||
"""blink in green."""
|
||||
self.send_command('{"ps":"6"}')
|
||||
|
||||
def map_color_to_led(self, color):
|
||||
"""
|
||||
Map an RGB color to the corresponding WLED action based on predefined ranges.
|
||||
|
||||
:param color: A tuple of (R, G, B) values, where each component is an integer between 0 and 255.
|
||||
"""
|
||||
red, green, blue = color
|
||||
|
||||
# Check if the color is red (high R, low G and B)
|
||||
if red > 200 and green < 100 and blue < 100:
|
||||
self.switch_to_red()
|
||||
|
||||
# Check if the color is green (high G, low R and B)
|
||||
elif red < 100 and green > 200 and blue < 100:
|
||||
self.switch_to_green()
|
||||
|
||||
# Check if the color is yellow (high R and G, low B)
|
||||
elif red > 200 and green > 200 and blue < 100:
|
||||
self.switch_to_yellow()
|
||||
|
||||
# If none of the above, turn off the LEDs
|
||||
else:
|
||||
self.turn_off_all()
|
||||
|
||||
# Example usage:
|
||||
if __name__ == "__main__":
|
||||
controller = WLEDController(port="/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:1:1.0-port0")
|
||||
controller.connect()
|
||||
|
||||
try:
|
||||
controller.switch_to_red()
|
||||
time.sleep(2) # Wait for 2 seconds
|
||||
|
||||
controller.switch_to_yellow()
|
||||
time.sleep(2) # Wait for 2 seconds
|
||||
|
||||
controller.switch_to_green()
|
||||
time.sleep(2) # Wait for 2 seconds
|
||||
|
||||
controller.change_effect()
|
||||
time.sleep(2) # Wait for 2 seconds
|
||||
|
||||
controller.turn_off_all()
|
||||
time.sleep(2) # Wait for 2 seconds
|
||||
|
||||
finally:
|
||||
controller.disconnect()
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,33 +0,0 @@
|
||||
description: Ultralytics YOLOv10n model trained on rf_version2/geisi2-4/data.yaml
|
||||
author: Ultralytics
|
||||
date: '2024-09-24T13:16:48.802051'
|
||||
version: 8.2.100
|
||||
license: AGPL-3.0 License (https://ultralytics.com/license)
|
||||
docs: https://docs.ultralytics.com
|
||||
stride: 32
|
||||
task: detect
|
||||
batch: 1
|
||||
imgsz:
|
||||
- 640
|
||||
- 640
|
||||
names:
|
||||
0: box
|
||||
1: hand
|
||||
2: oring_100_b
|
||||
3: oring_40_b
|
||||
4: oring_d105
|
||||
5: oring_d300_b
|
||||
6: oring_l1150
|
||||
7: oring_l380_b
|
||||
8: oring_l500
|
||||
9: oring_l600
|
||||
10: oring_l650_b
|
||||
11: ring_40mm
|
||||
12: ring_45mm
|
||||
13: ring_58mm
|
||||
14: schraube_sk_m10x25
|
||||
15: schraube_sk_m10x30
|
||||
16: schraube_sk_m10x45
|
||||
17: schraube_sk_m12x20
|
||||
18: schraube_sk_m12x50
|
||||
19: table
|
Binary file not shown.
Binary file not shown.
BIN
pics/image-1.png
BIN
pics/image-1.png
Binary file not shown.
Before Width: | Height: | Size: 109 KiB |
74
pyqt_project/.gitignore
vendored
74
pyqt_project/.gitignore
vendored
@ -1,74 +0,0 @@
|
||||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
*.core
|
||||
*.moc
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*_pch.h.cpp
|
||||
*_resource.rc
|
||||
*.qm
|
||||
.#*
|
||||
*.*#
|
||||
core
|
||||
!core/
|
||||
tags
|
||||
.DS_Store
|
||||
.directory
|
||||
*.debug
|
||||
Makefile*
|
||||
*.prl
|
||||
*.app
|
||||
moc_*.cpp
|
||||
ui_*.h
|
||||
qrc_*.cpp
|
||||
Thumbs.db
|
||||
*.res
|
||||
*.rc
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
CMakeLists.txt.user*
|
||||
|
||||
# xemacs temporary files
|
||||
*.flc
|
||||
|
||||
# Vim temporary files
|
||||
.*.swp
|
||||
|
||||
# Visual Studio generated files
|
||||
*.ib_pdb_index
|
||||
*.idb
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*vcproj.*.*.user
|
||||
*.ncb
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.vcxproj
|
||||
*vcxproj.*
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Binaries
|
||||
# --------
|
||||
*.dll
|
||||
*.exe
|
||||
|
@ -1,23 +0,0 @@
|
||||
QMAKE_CXX.QT_COMPILER_STDCXX = 201703L
|
||||
QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 13
|
||||
QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 2
|
||||
QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 0
|
||||
QMAKE_CXX.COMPILER_MACROS = \
|
||||
QT_COMPILER_STDCXX \
|
||||
QMAKE_GCC_MAJOR_VERSION \
|
||||
QMAKE_GCC_MINOR_VERSION \
|
||||
QMAKE_GCC_PATCH_VERSION
|
||||
QMAKE_CXX.INCDIRS = \
|
||||
/usr/include/c++/13 \
|
||||
/usr/include/x86_64-linux-gnu/c++/13 \
|
||||
/usr/include/c++/13/backward \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/13/include \
|
||||
/usr/local/include \
|
||||
/usr/include/x86_64-linux-gnu \
|
||||
/usr/include
|
||||
QMAKE_CXX.LIBDIRS = \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/13 \
|
||||
/usr/lib/x86_64-linux-gnu \
|
||||
/usr/lib \
|
||||
/lib/x86_64-linux-gnu \
|
||||
/lib
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user