update
This commit is contained in:
parent
c3e5f0313b
commit
3139e10ecb
Binary file not shown.
Before Width: | Height: | Size: 518 KiB |
@ -73,6 +73,30 @@ class WLEDController:
|
|||||||
"""blink in green."""
|
"""blink in green."""
|
||||||
self.send_command('{"ps":"6"}')
|
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:
|
# Example usage:
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
controller = WLEDController(port="/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:1:1.0-port0")
|
controller = WLEDController(port="/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:1:1.0-port0")
|
||||||
|
BIN
pics/image-1.png
Normal file
BIN
pics/image-1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 109 KiB |
85
readme.md
85
readme.md
@ -37,7 +37,7 @@ Die Dateien und Ordner sind wie folgt strukturiert:
|
|||||||
|
|
||||||
## Systemanforderungen
|
## Systemanforderungen
|
||||||
|
|
||||||
- **Betriebssystem**: Ubuntu 24.04 oder kompatibel.
|
- **Betriebssystem**: Kubuntu 24.04 oder kompatibel.
|
||||||
- **Python-Version**: Python 3.10 oder höher.
|
- **Python-Version**: Python 3.10 oder höher.
|
||||||
- **Abhängigkeiten**:
|
- **Abhängigkeiten**:
|
||||||
- Conda oder Miniforge zur Verwaltung von Python-Bibliotheken.
|
- Conda oder Miniforge zur Verwaltung von Python-Bibliotheken.
|
||||||
@ -51,7 +51,7 @@ Die Dateien und Ordner sind wie folgt strukturiert:
|
|||||||
|
|
||||||
## Funktionsumfang
|
## Funktionsumfang
|
||||||
|
|
||||||
Der **CPS Geislinger Packaging Assistant** bietet eine Vielzahl an Funktionen, um den Verpackungsprozess effizient zu unterstützen.
|
Der **CPS Geislinger PackPal** bietet eine Vielzahl an Funktionen, um den Verpackungsprozess effizient zu unterstützen.
|
||||||
|
|
||||||
### Lichtsteuerung
|
### Lichtsteuerung
|
||||||
|
|
||||||
@ -136,24 +136,80 @@ python3 workflow.py
|
|||||||
|
|
||||||
Die Benutzeroberfläche wird gestartet und alle Geräte (Waage, Kamera, ESP32) werden automatisch initialisiert.
|
Die Benutzeroberfläche wird gestartet und alle Geräte (Waage, Kamera, ESP32) werden automatisch initialisiert.
|
||||||
|
|
||||||
![[Workspace Overview]](image.png)
|
![Workspace Overview](pics/image-1.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Arbeitsablauf
|
### Arbeitsablauf
|
||||||
|
|
||||||
1. Auftrag laden
|
Der **CPS Geislinger PackPal** unterstützt den Verpackungsprozess mit einer intuitiven Benutzeroberfläche. Es stehen zwei Arbeitsmodi zur Verfügung: **statisch** und **dynamisch**, die über die Checkbox **"static workflow"** ausgewählt werden können.
|
||||||
Geben Sie die Auftragsnummer in das entsprechende Feld ein und laden Sie die Auftragsdaten.
|
|
||||||
|
|
||||||
2. Bauteilerkennung
|
- **Statischer Workflow**:
|
||||||
Wählen Sie das Bauteil manuell aus oder lassen Sie es automatisch durch die Kamera und Waage bestimmen.
|
Der Benutzer wählt die Positionsnummer (Artikel) manuell aus, und die Waage addiert die Gewichte der eingelegten Bauteile, bis die gewünschte Stückzahl erreicht ist.
|
||||||
|
|
||||||
3. Bestücken
|
- **Dynamischer Workflow** (Standardmodus):
|
||||||
Legen Sie die Teile auf, bis die Waage die gewünschte Stückzahl bestätigt.
|
Die Kamera und die Waage arbeiten zusammen, um das eingelegte Bauteil automatisch zu erkennen und die korrekte Positionsnummer auszuwählen. Die Waage überwacht die eingelegten Teile, bis die erforderliche Stückzahl erreicht ist.
|
||||||
|
|
||||||
4. Weiterverpacken
|
#### Schritt-für-Schritt-Anleitung
|
||||||
Wiederholen Sie den Vorgang für alle Bauteile im Auftrag.
|
|
||||||
|
|
||||||
5. Auftragsabschluss
|
1. **Auftrag laden**
|
||||||
Sobald alle Bauteile verpackt sind, schließen Sie den Auftrag ab.
|
- Geben Sie die Auftragsnummer in das Feld **"Auftragsnummer"** ein.
|
||||||
|
- Klicken Sie auf **"load Auftrag"**, um die Auftragsdaten zu laden.
|
||||||
|
- Die Liste der Bauteile (mit Positionsnummer, Beschreibung, Soll-Menge, Ist-Menge und Lagerort) wird im linken Tabellenbereich angezeigt.
|
||||||
|
|
||||||
|
2. **Bauteilerkennung**
|
||||||
|
- **Manuelle Auswahl (statisch)**: Wählen Sie die gewünschte Positionsnummer direkt aus der Tabelle. Klicken Sie auf **"check Waage"**, um die Gewichtserfassung zu starten.
|
||||||
|
- **Automatische Erkennung (dynamisch)**:
|
||||||
|
- Legen Sie ein Bauteil auf die Waage und klicken Sie auf **"check Waage"**.
|
||||||
|
- Die automatisch erkannte Positionsnummer wird im Feld **"Pos.-Nr."** markiert.
|
||||||
|
|
||||||
|
3. **Bestücken**
|
||||||
|
- Legen Sie die Bauteile auf die Waage, bis die angezeigte **Ist-Menge** die **Soll-Menge** erreicht.
|
||||||
|
- Das System zeigt die aktuelle Stückzahl an.
|
||||||
|
- Falls die Waage nicht korrekt eingestellt ist, können Sie diese mit **"Waage tarieren"** neu kalibrieren.
|
||||||
|
|
||||||
|
4. **Weiterverpacken**
|
||||||
|
- Wiederholen Sie den Vorgang für alle Bauteile im Auftrag.
|
||||||
|
- Die Benutzeroberfläche führt Sie Schritt für Schritt durch die einzelnen Arbeitsvorgänge. Der aktuelle Arbeitsfortschritt wird in der **ToDo-Liste** rechts angezeigt.
|
||||||
|
|
||||||
|
5. **Auftragsabschluss**
|
||||||
|
- Sobald alle Bauteile verpackt sind, zeigt das System an, dass der Auftrag abgeschlossen ist.
|
||||||
|
- Überprüfen Sie die Daten und schließen Sie den Auftrag ab.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Zusätzliche Funktionen
|
||||||
|
|
||||||
|
- **Lichtsteuerung**:
|
||||||
|
Die LEDs und der Scheinwerfer können über die Schaltflächen gesteuert werden:
|
||||||
|
- **Turn on light / Turn off light**: Hauptbeleuchtung.
|
||||||
|
- **Turn on red/yellow/green LED**: Status-LEDs für visuelle Hinweise.
|
||||||
|
- **Blink Yellow LED**: Blinkt gelb zur Hervorhebung.
|
||||||
|
- **Turn off all LEDs**: Schaltet alle LEDs aus.
|
||||||
|
|
||||||
|
- **Kamera-Steuerung**:
|
||||||
|
- Aktivieren oder deaktivieren Sie den Kamera-Workflow über die Checkbox **"Camera Workflow"**.
|
||||||
|
- Starten und stoppen Sie die Kamera mit den Schaltflächen **"Start Camera"** und **"Stop Camera"**.
|
||||||
|
- Wählen Sie ein Modell für die automatische Bauteilerkennung aus der Dropdown-Liste aus (z. B. **"best_8n.pt"**).
|
||||||
|
|
||||||
|
- **Automatisches Tarieren**:
|
||||||
|
Aktivieren Sie die Checkbox **"automatisches Tarieren"**, um die Waage automatisch zu kalibrieren, sobald ein Arbeitsablauf gestartet wird.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Hinweise
|
||||||
|
|
||||||
|
- **ToDo-Liste**:
|
||||||
|
Die **ToDo-Liste** in der Benutzeroberfläche bietet eine klare Übersicht über die nächsten Schritte und den aktuellen Status. Befolgen Sie die Anweisungen, um den Workflow effizient abzuschließen.
|
||||||
|
|
||||||
|
- **Überwachung des Vorgangs**:
|
||||||
|
Verfolgen Sie die Statusanzeigen in der Benutzeroberfläche. Fehler oder Warnungen werden dort direkt angezeigt.
|
||||||
|
|
||||||
|
- **Stückzahlkontrolle**:
|
||||||
|
Die Waage erkennt automatisch Über- oder Unterfüllungen und zeigt entsprechende Hinweise an.
|
||||||
|
|
||||||
|
- **Korrektur**:
|
||||||
|
Sollten Fehler auftreten, können Sie jederzeit den aktuellen Artikel neu auswählen oder den Auftrag zurücksetzen.
|
||||||
|
|
||||||
## Fehlerbehebung
|
## Fehlerbehebung
|
||||||
|
|
||||||
@ -169,6 +225,9 @@ Die Benutzeroberfläche wird gestartet und alle Geräte (Waage, Kamera, ESP32) w
|
|||||||
- Datenbankfehler:
|
- Datenbankfehler:
|
||||||
Vergewissern Sie sich, dass die Datenbank MariaDB läuft und die Zugangsdaten korrekt in der Konfiguration hinterlegt sind.
|
Vergewissern Sie sich, dass die Datenbank MariaDB läuft und die Zugangsdaten korrekt in der Konfiguration hinterlegt sind.
|
||||||
|
|
||||||
|
- Konsolenausgaben kontrollieren:
|
||||||
|
Sollte es Probleme mit der Bauteilerkennung oder Waage geben, überprüfen Sie die Konsolenausgabe des Programms. Diese zeigt hilfreiche Diagnosen an.
|
||||||
|
|
||||||
## Kontakt
|
## Kontakt
|
||||||
|
|
||||||
Für weitere Unterstützung oder Fragen wenden Sie sich bitte an:
|
Für weitere Unterstützung oder Fragen wenden Sie sich bitte an:
|
||||||
|
BIN
readme.pdf
Normal file
BIN
readme.pdf
Normal file
Binary file not shown.
BIN
vids/beispielvideo_bedienung1.mp4
Normal file
BIN
vids/beispielvideo_bedienung1.mp4
Normal file
Binary file not shown.
@ -576,8 +576,9 @@ class Ui_MainWindow(object):
|
|||||||
for col in range(tableObject.columnCount()-1):
|
for col in range(tableObject.columnCount()-1):
|
||||||
tableObject.item(rowID, col).setBackground(QtGui.QColor(r,g,b))
|
tableObject.item(rowID, col).setBackground(QtGui.QColor(r,g,b))
|
||||||
|
|
||||||
# call change led color
|
# # call change led color
|
||||||
#light_app.map_color_to_led(r,g,b)
|
# later_instance = light_app_reference()
|
||||||
|
# later_instance.map_color_to_led(r,g,b)
|
||||||
|
|
||||||
def auftragsBtnClicked(self):
|
def auftragsBtnClicked(self):
|
||||||
databaseQueryWorking = False #wird für die Überprüfung, ob die Datenbankabfrage fehlerhaft ist, verwendet
|
databaseQueryWorking = False #wird für die Überprüfung, ob die Datenbankabfrage fehlerhaft ist, verwendet
|
||||||
|
991
workflow3.py
Normal file
991
workflow3.py
Normal file
@ -0,0 +1,991 @@
|
|||||||
|
|
||||||
|
#from PyQt5 import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QProgressBar
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
from PyQt5.QtWidgets import QApplication, QComboBox
|
||||||
|
from PyQt5.QtCore import QTimer, QThread, pyqtSignal, QObject, Qt
|
||||||
|
from PyQt5.QtGui import QColor
|
||||||
|
|
||||||
|
import serial
|
||||||
|
import binascii
|
||||||
|
import math
|
||||||
|
import mariadb
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
|
||||||
|
from lib.CameraStream import YOLOv8CameraStream # Import the YOLOv8CameraStream class
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
import lib.sainsmartrelay as sainsmartrelay
|
||||||
|
import lib.wledControl as wledControl
|
||||||
|
|
||||||
|
|
||||||
|
# ## in der Ui_MainWindow-Klasse wird die GUI erstellt - der MainThread läuft in dieser -> Farben Drop Down
|
||||||
|
|
||||||
|
|
||||||
|
# ## Aufsetzen der Datenbank und Waagenverbindung
|
||||||
|
# # Definieren der Datenbankverbindung
|
||||||
|
db_config = {
|
||||||
|
'user': 'dbUser',
|
||||||
|
'password': 'dbPassword',
|
||||||
|
'host': '127.0.0.1', # 'host': 'localhost', changed because more compatible
|
||||||
|
'database': 'projectGeislinger',
|
||||||
|
'port': 3306 # Standard port for MariaDB
|
||||||
|
}
|
||||||
|
|
||||||
|
# # Establishing the connection
|
||||||
|
# conn = mariadb.connect(**db_config)
|
||||||
|
# # Create a cursor to execute queries
|
||||||
|
# cursor = conn.cursor()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Attempt to establish the connection
|
||||||
|
conn = mariadb.connect(**db_config)
|
||||||
|
print("Database connection established successfully.")
|
||||||
|
|
||||||
|
# Create a cursor to execute queries
|
||||||
|
cursor = conn.cursor()
|
||||||
|
except mariadb.Error as e:
|
||||||
|
# Handle connection errors
|
||||||
|
print(f"Error connecting to the database: {e}")
|
||||||
|
conn = None
|
||||||
|
cursor = None
|
||||||
|
|
||||||
|
|
||||||
|
# Configuration of the serial port
|
||||||
|
try:
|
||||||
|
ser = serial.Serial('/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:3:1.0-port0', 9600)
|
||||||
|
print("Serial port connected successfully.")
|
||||||
|
except serial.SerialException:
|
||||||
|
ser = None
|
||||||
|
print("Warning: Serial port not found. Continuing without serial connection. Only working for demo-purposes.")
|
||||||
|
|
||||||
|
# die Workerklasse ist dazu da die Schleifen - in welchen der Bauteiltyp erkannt wird und die Anzahl der Bauteile, welche auf der Waage liegen - in einem seperaten Thread auszuführen, um ein Blockieren des Mainthreads zu verhindern
|
||||||
|
class Worker(QObject):
|
||||||
|
#progress = pyqtSignal(int)
|
||||||
|
objectDetectionStartSignal = pyqtSignal(str)
|
||||||
|
objectDetectionFinishedSignal = pyqtSignal(int, object)
|
||||||
|
|
||||||
|
checkWaageStartSignal = pyqtSignal(int, int, str)
|
||||||
|
checkWaageUpdateSignal = pyqtSignal(int, int)
|
||||||
|
checkWaageFinishedSignal = pyqtSignal(int)
|
||||||
|
|
||||||
|
waageStoppedSignal = pyqtSignal(int)
|
||||||
|
stopLoopSignal = pyqtSignal(bool) #das Signal wird verwendet um direkt den stopLoop-Wert zu ändern (also kein Funktionsaufruf)
|
||||||
|
|
||||||
|
waageEingeschwungen = False
|
||||||
|
stopLoop = False
|
||||||
|
btTypeIsSet = False
|
||||||
|
correctBtNr = False
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(Worker, self).__init__()
|
||||||
|
stopLoop = False
|
||||||
|
|
||||||
|
|
||||||
|
def getDataOfArticleType(self, allArticles, articleType):
|
||||||
|
''' die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück '''
|
||||||
|
for i in allArticles:
|
||||||
|
if i[1] == articleType:
|
||||||
|
return i
|
||||||
|
|
||||||
|
return -1
|
||||||
|
|
||||||
|
def waageNichtEingeschwungenOutput(self):
|
||||||
|
print("Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft.")
|
||||||
|
|
||||||
|
def wahrscheinlichkeitsDichte(self, x,mue, var):
|
||||||
|
''' in der Funktion wird der Wahrscheinlichkeitsdichtenwert der Variable x für eine bestimmte Normalverteilung berechnet '''
|
||||||
|
standardabweichung = var**0.5
|
||||||
|
|
||||||
|
result = 1/(standardabweichung * (2*math.pi)**0.5 ) * math.exp(-0.5 * ((x-mue)/standardabweichung)**2)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def readWaage(self):
|
||||||
|
''' in folgender Funktion wird die Waage ausgelesen '''
|
||||||
|
|
||||||
|
if ser.is_open == False:
|
||||||
|
ser.open()
|
||||||
|
|
||||||
|
#an die Waage den Befehl senden, dass sie ausgelesen werden soll
|
||||||
|
ser.write(b'getWeight\n')
|
||||||
|
serialString = ser.readline().decode('utf-8').rstrip() #Auslesen des Serial-Strings/der Messung der Waage
|
||||||
|
|
||||||
|
# wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft
|
||||||
|
lenString = len(serialString)-1
|
||||||
|
if serialString[lenString] == "g" and serialString[lenString-1] == "k":
|
||||||
|
waageEingeschwungen = True
|
||||||
|
else:
|
||||||
|
print("die Waage ist noch nicht eingeschwungen")
|
||||||
|
waageEingeschwungen = False
|
||||||
|
|
||||||
|
#aus dem String werden alle Zeichen, welche nicht zur Darstellung der Zahl benötigt werden entfernt
|
||||||
|
intString = ""
|
||||||
|
for i in serialString:
|
||||||
|
if i=="-" or i=="0" or i=="." or i=="1" or i=="2" or i=="3" or i=="4" or i=="5" or i=="6" or i=="7" or i=="8" or i=="9":
|
||||||
|
intString = intString + i
|
||||||
|
print("Wert, welcher von der Waage ausgelesen wurde: " + intString + "kg")
|
||||||
|
|
||||||
|
ser.close()
|
||||||
|
|
||||||
|
return waageEingeschwungen, intString
|
||||||
|
|
||||||
|
def objectTypeDetectionThread(self, auftragsnummer):
|
||||||
|
''' in dieser Funktion wird der Typ des Bauteils automatisch erkannt '''
|
||||||
|
|
||||||
|
# Parameterdefinition
|
||||||
|
propDensVect = []
|
||||||
|
|
||||||
|
self.btTypeIsSet = False
|
||||||
|
|
||||||
|
while(self.btTypeIsSet == False and self.stopLoop == False):
|
||||||
|
|
||||||
|
# Auslesen der Waage
|
||||||
|
waageEingeschwungen, intString = self.readWaage()
|
||||||
|
if waageEingeschwungen == False:
|
||||||
|
self.waageNichtEingeschwungenOutput()
|
||||||
|
else:
|
||||||
|
|
||||||
|
# Datenbankabfrage
|
||||||
|
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer
|
||||||
|
cursor.execute(sql_query)
|
||||||
|
auftragEinzelteilDaten = cursor.fetchall()
|
||||||
|
|
||||||
|
# in der Folge werden alle Wahrscheinlichkeitsdichten der Auftragsbauteile berechnet und in dem Vektor gesammelt
|
||||||
|
for row in auftragEinzelteilDaten:
|
||||||
|
propDensVect.append([self.wahrscheinlichkeitsDichte(float(intString),float(row[6]), float(row[7])), row[1], row[5]])
|
||||||
|
|
||||||
|
# Jenen Eintrag des propDensVect raussuchen, welcher die größte Wahrscheinlichkeitsdichte beinhaltet
|
||||||
|
maxpropDens = 0
|
||||||
|
einzelteilID = 0
|
||||||
|
rowData = None
|
||||||
|
for row in propDensVect:
|
||||||
|
if row[0] > maxpropDens:
|
||||||
|
maxpropDens = row[0]
|
||||||
|
einzelteilID = row[1]
|
||||||
|
rowData = row
|
||||||
|
|
||||||
|
# überprüfen, ob das aufliegende Bauteil in der Auftragstabelle vorhanden ist
|
||||||
|
if(einzelteilID == 0):
|
||||||
|
print("Es wurde kein Bauteil aus der Auftragsliste (Tabelle) erkannt.")
|
||||||
|
else:
|
||||||
|
print("Bei dem Bauteil" , einzelteilID , "wurde die höchste Wahrscheinlichkeitsdichte berechnet.")
|
||||||
|
|
||||||
|
# den Bool auf true setzen, damit die Schleife beendet wird - dieser wird auf True gesetzt, wenn ein Bauteiltyp erkannt wird
|
||||||
|
self.btTypeIsSet = True
|
||||||
|
|
||||||
|
if(self.stopLoop == False):
|
||||||
|
# ein Signal zurück an den MainThreat senden, mit den Infos/Ergebnissen, der Typenbestimmung
|
||||||
|
self.objectDetectionFinishedSignal.emit(einzelteilID, rowData)
|
||||||
|
else:
|
||||||
|
self.waageStoppedSignal.emit(einzelteilID)
|
||||||
|
|
||||||
|
def checkWaageThread(self, einzelteilID, teileZuViel, auftragsnummer):
|
||||||
|
''' in dieser Funktion wird die Stückzahl der Bauteile, welche auf der Waage liegen, berechnet '''
|
||||||
|
|
||||||
|
self.correctBtNr = False
|
||||||
|
prevAnzahl = 0
|
||||||
|
anzahl = 0
|
||||||
|
einzelteilID = einzelteilID
|
||||||
|
|
||||||
|
while (self.correctBtNr == False and self.stopLoop == False):
|
||||||
|
|
||||||
|
#überprüfen, ob die Waage eingeschwungen ist (und damit korrekte Ergebnisse liefert)
|
||||||
|
waageEingeschwungen, intString = self.readWaage()
|
||||||
|
if waageEingeschwungen == False:
|
||||||
|
self.waageNichtEingeschwungenOutput()
|
||||||
|
else:
|
||||||
|
|
||||||
|
# Datenbankabfrage - holen der Auftrags- und Bauteilinfos
|
||||||
|
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer
|
||||||
|
cursor.execute(sql_query)
|
||||||
|
auftragDaten = cursor.fetchall()
|
||||||
|
|
||||||
|
#auslesen, wie viele Bauteile des Types laut Auftrag vorhanden sein sollen
|
||||||
|
anzBauteile_soll = 0
|
||||||
|
idVorhanden = False
|
||||||
|
|
||||||
|
for row in auftragDaten:
|
||||||
|
if row[1] == einzelteilID:
|
||||||
|
anzBauteile_soll = row[3]
|
||||||
|
idVorhanden = True
|
||||||
|
|
||||||
|
if(idVorhanden == False):
|
||||||
|
print("Die gewählte Pos.Nr ist nicht in der Auftragsliste (Tabelle) vorhanden.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Berechnen der Wahrscheinlichkeitsdichten - der Betrag aller Wahrscheinlichkeitsdichten werden im propDensVect gespeichert
|
||||||
|
propDensVect = []
|
||||||
|
articleData = self.getDataOfArticleType(auftragDaten, einzelteilID)
|
||||||
|
for i in range(1,anzBauteile_soll+teileZuViel+1):
|
||||||
|
# Mathematische Sätze, auf welchen die Berechnung basiert:
|
||||||
|
# seien X1,..., Xn unabhängige Zufallsvariablen die N(mue_i, sigma_i^2) verteilt sind, dann ist X = X1+...+Xn - N(mue, sigma^2) verteilt mit mue=mue1+...+mue_n, sigma^2 = sigma_1^2+...+sigma_n^2
|
||||||
|
mueGes = float(articleData[6])*i # Berechnen des äquivalenten Mittelwert
|
||||||
|
varGes = float(articleData[7])*i # Berechnen der äquivalenten Varianz
|
||||||
|
propDensVect.append([self.wahrscheinlichkeitsDichte(float(intString),mueGes, varGes), i])
|
||||||
|
|
||||||
|
# durch den propDensVect iterieren und jenen Eintrag mit der höchsten Wahrscheinlichkeitsdichte raussuchen
|
||||||
|
maxpropDens = 0
|
||||||
|
for row in propDensVect:
|
||||||
|
if row[0] > maxpropDens:
|
||||||
|
maxpropDens = row[0]
|
||||||
|
anzahl = row[1]
|
||||||
|
|
||||||
|
# damit nur etwas gemacht wird (zb ein Updatesignal an den Hauptthread zurücksenden), wenn sich die berechnete Anzahl ändert
|
||||||
|
if prevAnzahl != anzahl:
|
||||||
|
prevAnzahl = anzahl
|
||||||
|
|
||||||
|
# wenn genug Bauteile vorhanden sind, dann soll die Schleife beendet werden
|
||||||
|
if (anzahl == anzBauteile_soll):
|
||||||
|
self.correctBtNr = True
|
||||||
|
|
||||||
|
# Konsolenausgabe
|
||||||
|
if maxpropDens > 0:
|
||||||
|
print("Bei der Anzahl" , anzahl , "des Bauteiltypes", einzelteilID, ",wurde die höchste Wahrscheinlichkeitsdichte berechnet.")
|
||||||
|
self.checkWaageUpdateSignal.emit(einzelteilID, anzahl)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Von der ausgewählten Bauteiltype liegt die berechnete Wahrscheinlichkeit bei 0, dass zwischen 0 und", anzBauteile_soll+teileZuViel, "Bauteilen auf der Waage liegen.")
|
||||||
|
print("Falls die korrekte Anzhl an Bauteilen auf der Waage liegt, könnte der Fehler in einer falschen Kalibrierung der Waage liegen (TARE).")
|
||||||
|
|
||||||
|
if(self.stopLoop == False):
|
||||||
|
self.checkWaageFinishedSignal.emit(einzelteilID)
|
||||||
|
else:
|
||||||
|
self.waageStoppedSignal.emit(einzelteilID)
|
||||||
|
|
||||||
|
|
||||||
|
## in der Ui_MainWindow-Klasse wird die GUI erstellt - der MainThread läuft in dieser
|
||||||
|
class Ui_MainWindow(object):
|
||||||
|
def setupUi(self, MainWindow):
|
||||||
|
self.auftragsnummer = ""
|
||||||
|
self.teileZuViel = 100 # Anzahl an Bauteilen, welche zu viel drinnen sein können - der Parameter kann selbst gesetzt werden #####
|
||||||
|
self.correctBtNr = False
|
||||||
|
self.btTypeIsSet = False
|
||||||
|
|
||||||
|
MainWindow.setObjectName("MainWindow")
|
||||||
|
MainWindow.resize(1400, 675)
|
||||||
|
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
||||||
|
self.centralwidget.setObjectName("centralwidget")
|
||||||
|
self.btn1 = QtWidgets.QPushButton(self.centralwidget)
|
||||||
|
self.btn1.setGeometry(QtCore.QRect(700, 45, 111, 25))
|
||||||
|
self.btn1.setObjectName("btn1")
|
||||||
|
# Tabelle zur Darstellung der Auftragsdetails
|
||||||
|
self.AuftragsdetailsTable = QtWidgets.QTableWidget(self.centralwidget)
|
||||||
|
self.AuftragsdetailsTable.setGeometry(QtCore.QRect(10, 100, 661, 400))
|
||||||
|
self.AuftragsdetailsTable.setObjectName("AuftragsdetailsTable")
|
||||||
|
self.AuftragsdetailsTable.setColumnCount(7)
|
||||||
|
self.AuftragsdetailsTable.setRowCount(0)
|
||||||
|
item = QtWidgets.QTableWidgetItem()
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(8)
|
||||||
|
item.setFont(font)
|
||||||
|
self.AuftragsdetailsTable.setHorizontalHeaderItem(0, item)
|
||||||
|
item = QtWidgets.QTableWidgetItem()
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(8)
|
||||||
|
item.setFont(font)
|
||||||
|
self.AuftragsdetailsTable.setHorizontalHeaderItem(1, item)
|
||||||
|
item = QtWidgets.QTableWidgetItem()
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(8)
|
||||||
|
item.setFont(font)
|
||||||
|
self.AuftragsdetailsTable.setHorizontalHeaderItem(2, item)
|
||||||
|
item = QtWidgets.QTableWidgetItem()
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(8)
|
||||||
|
item.setFont(font)
|
||||||
|
self.AuftragsdetailsTable.setHorizontalHeaderItem(3, item)
|
||||||
|
item = QtWidgets.QTableWidgetItem()
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(8)
|
||||||
|
item.setFont(font)
|
||||||
|
self.AuftragsdetailsTable.setHorizontalHeaderItem(5, item)
|
||||||
|
item = QtWidgets.QTableWidgetItem()
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(8)
|
||||||
|
item.setFont(font)
|
||||||
|
self.AuftragsdetailsTable.setHorizontalHeaderItem(4, item)
|
||||||
|
item = QtWidgets.QTableWidgetItem()
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(8)
|
||||||
|
item.setFont(font)
|
||||||
|
self.AuftragsdetailsTable.setHorizontalHeaderItem(6, item)
|
||||||
|
|
||||||
|
# Tabelle zur Darstellung der Arbeitsschritte
|
||||||
|
self.ArbeitsschrittTable = QtWidgets.QTableWidget(self.centralwidget)
|
||||||
|
self.ArbeitsschrittTable.setGeometry(QtCore.QRect(1000, 50, 395, 400))
|
||||||
|
self.ArbeitsschrittTable.setObjectName("AuftragsdetailsTable")
|
||||||
|
self.ArbeitsschrittTable.setColumnCount(2)
|
||||||
|
self.ArbeitsschrittTable.setRowCount(4)
|
||||||
|
self.ArbeitsschrittTable.setColumnWidth(0, 100)
|
||||||
|
self.ArbeitsschrittTable.setColumnWidth(1, 280)
|
||||||
|
self.ArbeitsschrittTable.setRowHeight(0, 80)
|
||||||
|
self.ArbeitsschrittTable.setRowHeight(1, 180)
|
||||||
|
self.ArbeitsschrittTable.setRowHeight(2, 50)
|
||||||
|
self.ArbeitsschrittTable.setRowHeight(3, 50)
|
||||||
|
item = QtWidgets.QTableWidgetItem()
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(8)
|
||||||
|
item.setFont(font)
|
||||||
|
self.ArbeitsschrittTable.setHorizontalHeaderItem(0, item)
|
||||||
|
item = QtWidgets.QTableWidgetItem()
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(8)
|
||||||
|
item.setFont(font)
|
||||||
|
self.ArbeitsschrittTable.setHorizontalHeaderItem(1, item)
|
||||||
|
|
||||||
|
self.label = QtWidgets.QLabel(self.centralwidget)
|
||||||
|
self.label.setGeometry(QtCore.QRect(500, 20, 121, 17))
|
||||||
|
self.label.setObjectName("label")
|
||||||
|
self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
|
||||||
|
self.textEdit.setGeometry(QtCore.QRect(450, 40, 221, 31))
|
||||||
|
self.textEdit.setObjectName("textEdit")
|
||||||
|
self.bauteilTypBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||||
|
self.bauteilTypBtn.setGeometry(QtCore.QRect(700, 100, 161, 25))
|
||||||
|
self.bauteilTypBtn.setObjectName("bauteilTypBtn")
|
||||||
|
self.checkWaageBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||||
|
self.checkWaageBtn.setGeometry(QtCore.QRect(700, 150, 161, 25))
|
||||||
|
self.checkWaageBtn.setObjectName("checkWaageBtn")
|
||||||
|
self.stopLoopBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||||
|
self.stopLoopBtn.setGeometry(QtCore.QRect(700, 350, 161, 25))
|
||||||
|
self.stopLoopBtn.setObjectName("stopLoopBtn")
|
||||||
|
self.waageTareBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||||
|
self.waageTareBtn.setGeometry(QtCore.QRect(700, 400, 161, 25))
|
||||||
|
self.waageTareBtn.setObjectName("waageTareBtn")
|
||||||
|
self.bauteiltypTextbox = QtWidgets.QTextEdit(self.centralwidget)
|
||||||
|
self.bauteiltypTextbox.setGeometry(QtCore.QRect(700, 290, 221, 31))
|
||||||
|
self.bauteiltypTextbox.setObjectName("bauteiltypTextbox")
|
||||||
|
self.BezeichnungLabel = QtWidgets.QLabel(self.centralwidget)
|
||||||
|
self.BezeichnungLabel.setGeometry(QtCore.QRect(700, 270, 181, 20))
|
||||||
|
self.BezeichnungLabel.setObjectName("BezeichnungLabel")
|
||||||
|
self.PosNrLabel = QtWidgets.QLabel(self.centralwidget)
|
||||||
|
self.PosNrLabel.setGeometry(QtCore.QRect(700, 200, 67, 17))
|
||||||
|
self.PosNrLabel.setObjectName("PosNrLabel")
|
||||||
|
self.PosNrTxtFeld = QtWidgets.QTextEdit(self.centralwidget)
|
||||||
|
self.PosNrTxtFeld.setGeometry(QtCore.QRect(700, 220, 191, 31))
|
||||||
|
self.PosNrTxtFeld.setObjectName("PosNrTxtFeld")
|
||||||
|
self.teileZuVielLabel = QtWidgets.QLabel(self.centralwidget)
|
||||||
|
self.teileZuVielLabel.setGeometry(QtCore.QRect(1000, 560, 350, 17))
|
||||||
|
self.teileZuVielLabel.setObjectName("teileZuVielLabel")
|
||||||
|
self.teileZuVielTxtFeld = QtWidgets.QTextEdit(self.centralwidget)
|
||||||
|
self.teileZuVielTxtFeld.setGeometry(QtCore.QRect(1000, 580, 191, 31))
|
||||||
|
MainWindow.setCentralWidget(self.centralwidget)
|
||||||
|
self.menubar = QtWidgets.QMenuBar(MainWindow)
|
||||||
|
self.menubar.setGeometry(QtCore.QRect(0, 0, 1090, 22))
|
||||||
|
self.menubar.setObjectName("menubar")
|
||||||
|
MainWindow.setMenuBar(self.menubar)
|
||||||
|
self.statusbar = QtWidgets.QStatusBar(MainWindow)
|
||||||
|
self.statusbar.setObjectName("statusbar")
|
||||||
|
MainWindow.setStatusBar(self.statusbar)
|
||||||
|
self.checkBox = QtWidgets.QCheckBox(self.centralwidget)
|
||||||
|
self.checkBox.setGeometry(QtCore.QRect(1000, 480, 151, 23))
|
||||||
|
self.checkBox.setObjectName("checkBox")
|
||||||
|
self.checkBoxAutoTare = QtWidgets.QCheckBox(self.centralwidget)
|
||||||
|
self.checkBoxAutoTare.setGeometry(QtCore.QRect(1000, 520, 180, 23))
|
||||||
|
self.checkBoxAutoTare.setObjectName("checkBoxAutoTare")
|
||||||
|
|
||||||
|
# button and checkbox for camera workflow + graphicsview widget
|
||||||
|
self.camWorkFlowcheckBox = QtWidgets.QCheckBox(self.centralwidget)
|
||||||
|
self.camWorkFlowcheckBox.setGeometry(QtCore.QRect(700, int(1080/2), 151, 23))
|
||||||
|
self.camWorkFlowcheckBox.setObjectName("camWorkFlowcheckBox")
|
||||||
|
self.modelComboBox = QtWidgets.QComboBox(self.centralwidget)
|
||||||
|
self.modelComboBox.setGeometry(QtCore.QRect(700, int(1080/2)+50, 161, 25))
|
||||||
|
self.modelComboBox.setObjectName("modelComboBox")
|
||||||
|
self.startCamBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||||
|
self.startCamBtn.setGeometry(QtCore.QRect(700, int(1080/2)+100, 161, 25)) #int(1080/2)+100
|
||||||
|
self.startCamBtn.setObjectName("startCamBtn")
|
||||||
|
self.stopCamBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||||
|
self.stopCamBtn.setGeometry(QtCore.QRect(700, int(1080/2)+150, 161, 25))
|
||||||
|
self.stopCamBtn.setObjectName("stopCamBtn")
|
||||||
|
self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget)
|
||||||
|
self.graphicsView.setGeometry(QtCore.QRect(10, int(1080/2), 661, int(480*1.05))) # position and size of camera frame # int(640*1.05)
|
||||||
|
self.graphicsView.setObjectName("graphicsView")
|
||||||
|
|
||||||
|
# relay control buttons
|
||||||
|
self.startSpotlightBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||||
|
self.startSpotlightBtn.setGeometry(QtCore.QRect(700+200, int(1080/2)+100, 161, 25)) #int(1080/2)+100
|
||||||
|
self.startSpotlightBtn.setObjectName("startSpotlightBtn")
|
||||||
|
self.stopSpotlightBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||||
|
self.stopSpotlightBtn.setGeometry(QtCore.QRect(700+200, int(1080/2)+150, 161, 25))
|
||||||
|
self.stopSpotlightBtn.setObjectName("stopSpotlightBtn")
|
||||||
|
|
||||||
|
# led control buttons
|
||||||
|
self.redLightBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||||
|
self.redLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+100, 161, 25))
|
||||||
|
self.yellowLightBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||||
|
self.yellowLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+150, 161, 25))
|
||||||
|
self.greenLightBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||||
|
self.greenLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+200, 161, 25))
|
||||||
|
self.offLightBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||||
|
self.offLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+250, 161, 25))
|
||||||
|
self.blinkLightBtn = QtWidgets.QPushButton(self.centralwidget)
|
||||||
|
self.blinkLightBtn.setGeometry(QtCore.QRect(700+200+200, int(1080/2)+300, 161, 25))
|
||||||
|
|
||||||
|
# Maximize the window on startup
|
||||||
|
MainWindow.showMaximized()
|
||||||
|
|
||||||
|
self.retranslateUi(MainWindow)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||||
|
|
||||||
|
def retranslateUi(self, MainWindow):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
|
||||||
|
self.btn1.setText(_translate("MainWindow", "load Auftrag"))
|
||||||
|
self.btn1.clicked.connect(self.auftragsBtnClicked)
|
||||||
|
|
||||||
|
# Tabelle zur Darstellung der Auftragsdetails
|
||||||
|
item = self.AuftragsdetailsTable.horizontalHeaderItem(0)
|
||||||
|
item.setText(_translate("MainWindow", "Pos.-Nr"))
|
||||||
|
item = self.AuftragsdetailsTable.horizontalHeaderItem(1)
|
||||||
|
item.setText(_translate("MainWindow", "Matnr mit hoechster Version"))
|
||||||
|
item = self.AuftragsdetailsTable.horizontalHeaderItem(2)
|
||||||
|
item.setText(_translate("MainWindow", "Bezeichnung + Werkstoff"))
|
||||||
|
item = self.AuftragsdetailsTable.horizontalHeaderItem(3)
|
||||||
|
item.setText(_translate("MainWindow", "Soll-Menge"))
|
||||||
|
item = self.AuftragsdetailsTable.horizontalHeaderItem(4)
|
||||||
|
item.setText(_translate("MainWindow", "Ist-Menge"))
|
||||||
|
item = self.AuftragsdetailsTable.horizontalHeaderItem(5)
|
||||||
|
item.setText(_translate("MainWindow", "Lgort"))
|
||||||
|
item = self.AuftragsdetailsTable.horizontalHeaderItem(6)
|
||||||
|
item.setText(_translate("MainWindow", "set Farbe"))
|
||||||
|
|
||||||
|
# Tabelle zur Darstellung der Arbeitsschritte
|
||||||
|
item = self.ArbeitsschrittTable.horizontalHeaderItem(0)
|
||||||
|
item.setText(_translate("MainWindow", "Arbeitsschritt"))
|
||||||
|
item = self.ArbeitsschrittTable.horizontalHeaderItem(1)
|
||||||
|
item.setText(_translate("MainWindow", "ToDo:"))
|
||||||
|
|
||||||
|
# Ein neues QTableWidgetItem erstellen und den Text setzen
|
||||||
|
item = QtWidgets.QTableWidgetItem("Auftrag laden")
|
||||||
|
self.ArbeitsschrittTable.setItem(0, 0, item)
|
||||||
|
item = QtWidgets.QTableWidgetItem("--> Auftragsnummer eingeben \n--> \"load Auftrag\" Buttonclick")
|
||||||
|
self.ArbeitsschrittTable.setItem(0, 1, item)
|
||||||
|
item = QtWidgets.QTableWidgetItem("Bauteiltyp erkennen")
|
||||||
|
self.ArbeitsschrittTable.setItem(1, 0, item)
|
||||||
|
item = QtWidgets.QTableWidgetItem("visuell: \n--> ein Bauteil in die Kamera halten\n\nWaage: \n--> ein Bauteil auf die Waage legen\n--> \"Bauteiltyp erkennen\" Buttonclick\n\nmanuell:\n--> Bauteiltypen auswählen\n-->\"ckeck Waage\" Button click")
|
||||||
|
self.ArbeitsschrittTable.setItem(1, 1, item)
|
||||||
|
item = QtWidgets.QTableWidgetItem("Bauteilanzahl erkennen")
|
||||||
|
self.ArbeitsschrittTable.setItem(2, 0, item)
|
||||||
|
item = QtWidgets.QTableWidgetItem("--> Bauteile auflegen")
|
||||||
|
self.ArbeitsschrittTable.setItem(2, 1, item)
|
||||||
|
item = QtWidgets.QTableWidgetItem("Prozess beendet")
|
||||||
|
self.ArbeitsschrittTable.setItem(3, 0, item)
|
||||||
|
self.ArbeitsschrittTable.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers)
|
||||||
|
|
||||||
|
self.label.setText(_translate("MainWindow", "Auftragsnummer:"))
|
||||||
|
self.bauteilTypBtn.setText(_translate("MainWindow", "Bauteiltyp erkennen"))
|
||||||
|
self.bauteilTypBtn.clicked.connect(self.objectTypeDetection)
|
||||||
|
self.AuftragsdetailsTable.cellClicked.connect(self.onTableCellClick)
|
||||||
|
self.BezeichnungLabel.setText(_translate("MainWindow", "Bezeichnung"))
|
||||||
|
self.PosNrLabel.setText(_translate("MainWindow", "Pos.-Nr:"))
|
||||||
|
self.teileZuVielLabel.setText(_translate("MainWindow", "Zu prüfende Teileanzahl über Auftragsanzahl:"))
|
||||||
|
self.teileZuVielTxtFeld.setText(str(self.teileZuViel))
|
||||||
|
self.checkWaageBtn.setText(_translate("MainWindow", "check Waage"))
|
||||||
|
self.checkWaageBtn.clicked.connect(self.checkWaage)
|
||||||
|
self.stopLoopBtn.setText(_translate("MainWindow", "stop loop"))
|
||||||
|
self.stopLoopBtn.clicked.connect(self.stopLoopClicked)
|
||||||
|
self.waageTareBtn.setText(_translate("MainWindow", "Waage tarieren"))
|
||||||
|
self.waageTareBtn.clicked.connect(self.onTareClick)
|
||||||
|
self.checkBox.setText(_translate("MainWindow", "static workflow"))
|
||||||
|
self.checkBox.clicked.connect(self.onCheckboxCheck)
|
||||||
|
self.checkBoxAutoTare.setText(_translate("MainWindow", "automatisches Tarieren"))
|
||||||
|
self.checkBoxAutoTare.clicked.connect(self.autoTareCheck)
|
||||||
|
|
||||||
|
self.setRowColor(self.ArbeitsschrittTable, 0,255,165,0) # zum setzen der ersten Spalte der Arbeitsschrittetabelle auf orange
|
||||||
|
self.checkBoxAutoTare.setCheckState(Qt.Checked)
|
||||||
|
self.checkBox.setCheckState(Qt.Unchecked)
|
||||||
|
|
||||||
|
# new camera workflow
|
||||||
|
self.startCamBtn.setText(_translate("MainWindow", "Start Camera"))
|
||||||
|
self.stopCamBtn.setText(_translate("MainWindow", "Stop Camera"))
|
||||||
|
self.camWorkFlowcheckBox.setText(_translate("MainWindow", "Camera Workflow"))
|
||||||
|
self.modelComboBox
|
||||||
|
|
||||||
|
# relay control buttons
|
||||||
|
self.startSpotlightBtn.setText(_translate("MainWindow", "Turn on light"))
|
||||||
|
self.stopSpotlightBtn.setText(_translate("MainWindow", "Turn off light"))
|
||||||
|
|
||||||
|
# led control buttons
|
||||||
|
self.redLightBtn.setText(_translate("MainWindow", "Turn on red LED"))
|
||||||
|
self.yellowLightBtn.setText(_translate("MainWindow", "Turn on yellow LED"))
|
||||||
|
self.greenLightBtn.setText(_translate("MainWindow", "Turn on green LED"))
|
||||||
|
self.offLightBtn.setText(_translate("MainWindow", "Turn off all LEDs"))
|
||||||
|
self.blinkLightBtn.setText(_translate("MainWindow", "Blink Yellow LED"))
|
||||||
|
|
||||||
|
def mousePressEvent(self, event):
|
||||||
|
print("Das MainWindow wurde angeklickt.")
|
||||||
|
self.setFocus()
|
||||||
|
super().mousePressEvent(event)
|
||||||
|
|
||||||
|
def onTareClick(self):
|
||||||
|
''' Tarieren der Waage '''
|
||||||
|
if ser.is_open == False:
|
||||||
|
ser.open()
|
||||||
|
ser.write(b'tare\n')
|
||||||
|
ser.close()
|
||||||
|
|
||||||
|
def onCheckboxCheck(self):
|
||||||
|
if self.checkBox.isChecked() == True:
|
||||||
|
print("static workflow activated")
|
||||||
|
else:
|
||||||
|
print("static workflow deactivated")
|
||||||
|
|
||||||
|
def autoTareCheck(self):
|
||||||
|
if self.checkBoxAutoTare.isChecked() == True:
|
||||||
|
print("automatisches Tarieren ist aktiviert")
|
||||||
|
else:
|
||||||
|
print("automatisches Tarieren ist deaktiviert")
|
||||||
|
|
||||||
|
def getRowNr(self, posNr):
|
||||||
|
for i in range(0,self.AuftragsdetailsTable.rowCount()):
|
||||||
|
if(self.AuftragsdetailsTable.item(i,0).text() == str(posNr)):
|
||||||
|
return i
|
||||||
|
|
||||||
|
def onTableCellClick(self):
|
||||||
|
self.PosNrTxtFeld.setText(self.AuftragsdetailsTable.item(self.AuftragsdetailsTable.currentRow(),0).text())
|
||||||
|
self.bauteiltypTextbox.setText(self.AuftragsdetailsTable.item(self.AuftragsdetailsTable.currentRow(),2).text())
|
||||||
|
|
||||||
|
def setAuftragsnummer(self):
|
||||||
|
self.auftragsnummer = self.textEdit.toPlainText()
|
||||||
|
if(not self.auftragsnummer):
|
||||||
|
self.auftragsnummer = ""
|
||||||
|
self.textEdit.setText("")
|
||||||
|
|
||||||
|
def checkAuftragsnummerEmpty(self):
|
||||||
|
if self.auftragsnummer == "":
|
||||||
|
print("Das Auftragsnummernfeld ist leer.")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def checkPosNrEmpty(self):
|
||||||
|
if self.PosNrTxtFeld.toPlainText() == "":
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def updateGUI(self):
|
||||||
|
self.PosNrLabel.repaint() #GUI aktualisieren
|
||||||
|
QApplication.processEvents() #GUI aktualisieren
|
||||||
|
|
||||||
|
def setRowColor(self, tableObject, rowID,r,g,b):
|
||||||
|
for col in range(tableObject.columnCount()-1):
|
||||||
|
tableObject.item(rowID, col).setBackground(QtGui.QColor(r,g,b))
|
||||||
|
|
||||||
|
# # call change led color
|
||||||
|
# Check if the 'w' object already exists
|
||||||
|
# hier könnte noch nachgearbeitet werden
|
||||||
|
if not hasattr(self, 'w'):
|
||||||
|
w = wledControl.WLEDController(port="/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:1:1.0-port0")
|
||||||
|
w.connect()
|
||||||
|
w.map_color_to_led([r,g,b])
|
||||||
|
|
||||||
|
def auftragsBtnClicked(self):
|
||||||
|
databaseQueryWorking = False #wird für die Überprüfung, ob die Datenbankabfrage fehlerhaft ist, verwendet
|
||||||
|
auftragEinzelteilDaten = []
|
||||||
|
|
||||||
|
self.setAuftragsnummer()
|
||||||
|
if(not self.checkAuftragsnummerEmpty()):
|
||||||
|
|
||||||
|
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + self.auftragsnummer
|
||||||
|
try:
|
||||||
|
cursor.execute(sql_query)
|
||||||
|
# Fetch results
|
||||||
|
auftragEinzelteilDaten = cursor.fetchall()
|
||||||
|
databaseQueryWorking = True
|
||||||
|
except:
|
||||||
|
print("Fehler in der Datenbankabfrage.")
|
||||||
|
|
||||||
|
|
||||||
|
if databaseQueryWorking==True and len(auftragEinzelteilDaten)>0:
|
||||||
|
|
||||||
|
### die Auftragsdaten in die Tabelle laden
|
||||||
|
self.AuftragsdetailsTable.setRowCount(len(auftragEinzelteilDaten))
|
||||||
|
self.item = QtWidgets.QTableWidgetItem()
|
||||||
|
counter = 0
|
||||||
|
for row in auftragEinzelteilDaten:
|
||||||
|
self.item = QtWidgets.QTableWidgetItem()
|
||||||
|
self.AuftragsdetailsTable.setItem(counter, 0, self.item)
|
||||||
|
self.item.setText(str(row[1]))
|
||||||
|
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||||
|
self.item = QtWidgets.QTableWidgetItem()
|
||||||
|
self.AuftragsdetailsTable.setItem(counter, 1, self.item)
|
||||||
|
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||||
|
self.item = QtWidgets.QTableWidgetItem()
|
||||||
|
self.AuftragsdetailsTable.setItem(counter, 2, self.item)
|
||||||
|
self.item.setText(str(row[5]))
|
||||||
|
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||||
|
self.item = QtWidgets.QTableWidgetItem()
|
||||||
|
self.AuftragsdetailsTable.setItem(counter, 3, self.item)
|
||||||
|
self.item.setText(str(row[3]))
|
||||||
|
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||||
|
self.item = QtWidgets.QTableWidgetItem()
|
||||||
|
self.AuftragsdetailsTable.setItem(counter, 4, self.item)
|
||||||
|
self.item.setText(str("0"))
|
||||||
|
self.item = QtWidgets.QTableWidgetItem()
|
||||||
|
self.AuftragsdetailsTable.setItem(counter, 5, self.item)
|
||||||
|
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
||||||
|
|
||||||
|
# Dropdown für Farben in die 6. Spalte einfügen
|
||||||
|
#self.item = QtWidgets.QTableWidgetItem()
|
||||||
|
#self.AuftragsdetailsTable.setItem(counter, 6, self.item)
|
||||||
|
combo = QComboBox()
|
||||||
|
combo.addItems(["Farbe", "Weiß", "Orange", "Grün"])
|
||||||
|
combo.currentIndexChanged.connect(lambda index, rowId =counter: self.change_row_color(rowId, index))
|
||||||
|
self.AuftragsdetailsTable.setCellWidget(counter, 6, combo)
|
||||||
|
counter = counter +1
|
||||||
|
|
||||||
|
self.setRowColor(self.ArbeitsschrittTable, 0,0,255,0) #zum setzen der ersten Zeile der Auftragstabelle auf grün
|
||||||
|
self.setRowColor(self.ArbeitsschrittTable, 1,255,165,0) #zum setzen der zweiten Zeile der Auftragstabelle auf orange
|
||||||
|
self.setRowColor(self.ArbeitsschrittTable, 2,255,255,255) #zum setzen der dritten Zeile der Auftragstabelle auf weiß
|
||||||
|
self.setRowColor(self.ArbeitsschrittTable, 3,255,255,255) #zum setzen der vierten Zeile der Auftragstabelle auf weiß
|
||||||
|
|
||||||
|
# setzen der beiden Felder auf einen leeren String, um Fehler zu Vermeiden, wenn ein neuer Auftrag geladen wird
|
||||||
|
self.bauteiltypTextbox.setText("")
|
||||||
|
self.PosNrTxtFeld.setText("")
|
||||||
|
|
||||||
|
elif(databaseQueryWorking==True and len(auftragEinzelteilDaten)==0):
|
||||||
|
print("Es wurde in der Datenbank kein Auftrag mit dieser Auftragsnummer gefunden.")
|
||||||
|
|
||||||
|
def change_row_color(self, row, color_index):
|
||||||
|
if(color_index == 1):
|
||||||
|
self.setRowColor(self.AuftragsdetailsTable, row,255,255,255)
|
||||||
|
if(color_index == 2):
|
||||||
|
self.setRowColor(self.AuftragsdetailsTable, row,255,165,0)
|
||||||
|
if(color_index == 3):
|
||||||
|
self.setRowColor(self.AuftragsdetailsTable, row,0,255,0)
|
||||||
|
|
||||||
|
def stopLoopClicked(self):
|
||||||
|
''' damit wird beim Klick auf den Stopbutton der stopLoop-boolWert in der Workerklasse auf true gesetzt -> der Stop des Threads wird initiiert '''
|
||||||
|
if hasattr(self, 'objectDetectionWorker'):
|
||||||
|
self.objectDetectionWorker.stopLoopSignal.emit(True)
|
||||||
|
|
||||||
|
if hasattr(self, 'checkWaageWorker'):
|
||||||
|
self.checkWaageWorker.stopLoopSignal.emit(True)
|
||||||
|
|
||||||
|
def checkFinished(self):
|
||||||
|
''' die Funktion geht alle Zeilen der Auftragsliste durch und schaut, ob die richtige Anzahl an Teilen vorhanden sind '''
|
||||||
|
for i in range(0,self.AuftragsdetailsTable.rowCount()):
|
||||||
|
if self.AuftragsdetailsTable.item(i,3).text() != self.AuftragsdetailsTable.item(i,4).text():
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def checkWaage(self):
|
||||||
|
QApplication.processEvents()
|
||||||
|
|
||||||
|
# überprüfen, ob der Auftrag geladen wurde
|
||||||
|
if(self.AuftragsdetailsTable.item(0,0) == None):
|
||||||
|
print("Der Auftrag muss zuerst geladen werden.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# überprüfen, ob ein Bauteiltyp gesetzt wurde
|
||||||
|
if(self.checkPosNrEmpty()==True and self.checkBox.isChecked() == False):
|
||||||
|
print("Das Pos.-Nr.-Feld ist leer.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# den GUI Wert von Textfeld TeileZuViel in die Variable schreiben
|
||||||
|
self.teileZuViel = int(float(self.teileZuVielTxtFeld.toPlainText()))
|
||||||
|
self.teileZuVielTxtFeld.setText(str(self.teileZuViel))
|
||||||
|
|
||||||
|
einzelteilID = -1 # Initialisieren der Variable mit einem Defaultwert, welcher nie eingenommen werden können sollte
|
||||||
|
if (self.checkBox.isChecked() == False):
|
||||||
|
#übernehmen der BauteilID aus dem Feld Pos.-Nr - wenn der Workflow dynamisch gewählt wurde
|
||||||
|
einzelteilID = int(self.PosNrTxtFeld.toPlainText())
|
||||||
|
else:
|
||||||
|
# wenn der Workflow statisch gesetzt wurde, dann soll das erste Item aus der Auftragsliste geladen werden, von welchem noch nicht genug Bauteile auf der Waage liegen
|
||||||
|
for i in range(0,self.AuftragsdetailsTable.rowCount()):
|
||||||
|
if self.AuftragsdetailsTable.item(i,3).text() != self.AuftragsdetailsTable.item(i,4).text():
|
||||||
|
einzelteilID = int(self.AuftragsdetailsTable.item(i,0).text())
|
||||||
|
self.PosNrTxtFeld.setText(str(self.AuftragsdetailsTable.item(i,0).text()))
|
||||||
|
self.bauteiltypTextbox.setText(str(self.AuftragsdetailsTable.item(i,2).text()))
|
||||||
|
break
|
||||||
|
|
||||||
|
if einzelteilID == -1:
|
||||||
|
# den Thread beenden
|
||||||
|
self.checkWaageThread.quit()
|
||||||
|
self.checkWaageThread.wait()
|
||||||
|
try:
|
||||||
|
self.checkWaageThread.started.disconnect() # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt
|
||||||
|
print("Der Thread wurde beendet.")
|
||||||
|
except:
|
||||||
|
print("Disconnecting the thread did not work.")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
#zum setzen den Farbe der gesamten Reihe auf Orange
|
||||||
|
self.setRowColor(self.AuftragsdetailsTable, self.getRowNr(einzelteilID),255,165,0)
|
||||||
|
self.setRowColor(self.ArbeitsschrittTable, 1,0,255,0) # zum setzen der zweiten Spalte der Arbeitsschrittetabelle auf grün
|
||||||
|
self.setRowColor(self.ArbeitsschrittTable, 2,255,165,0) # zum setzen der dritten Spalte der Arbeitsschrittetabelle auf orange
|
||||||
|
|
||||||
|
# den Thread starten, welcher die Bauteilanzahl überprüft
|
||||||
|
self.checkWaageWorker = Worker()
|
||||||
|
self.checkWaageThread = QThread()
|
||||||
|
|
||||||
|
self.checkWaageWorker.moveToThread(self.checkWaageThread)
|
||||||
|
|
||||||
|
self.checkWaageWorker.checkWaageStartSignal.connect(self.checkWaageWorker.checkWaageThread)
|
||||||
|
self.checkWaageWorker.checkWaageUpdateSignal.connect(self.checkWaageUpdate)
|
||||||
|
self.checkWaageWorker.checkWaageFinishedSignal.connect(self.checkWaageFinished)
|
||||||
|
self.checkWaageWorker.waageStoppedSignal.connect(self.threadStopped)
|
||||||
|
self.checkWaageWorker.stopLoopSignal.connect(lambda status: setattr(self.checkWaageWorker, 'stopLoop', status)) #wird fürs aktive Stoppen des Threads benötigt
|
||||||
|
|
||||||
|
self.checkWaageThread.started.connect(lambda: self.checkWaageWorker.checkWaageStartSignal.emit(einzelteilID, self.teileZuViel, self.auftragsnummer))
|
||||||
|
self.checkWaageThread.start()
|
||||||
|
|
||||||
|
def checkWaageUpdate(self, einzelteilID, anzahl):
|
||||||
|
# die Funktion updated die (vom Thread) berechnete Bauteilanzahl in der GUI
|
||||||
|
self.AuftragsdetailsTable.item(self.getRowNr(einzelteilID), 4).setText(str(anzahl)) # in die Tabelle die Anzahl an berechneten Bauteilen reinschreiben
|
||||||
|
|
||||||
|
def checkWaageFinished(self, einzelteilID):
|
||||||
|
self.setRowColor(self.AuftragsdetailsTable, self.getRowNr(einzelteilID),0,255,0) #zum setzen den Farbe der gesamten Reihe auf Grün
|
||||||
|
|
||||||
|
if self.checkFinished(): # wenn alle Bauteile auf der Waage liegen, soll folgender Code ausgeführt werden
|
||||||
|
self.setRowColor(self.ArbeitsschrittTable, 2,0,255,0) # zum setzen der zweiten Spalte der Arbeitsschrittetabelle auf orange
|
||||||
|
self.setRowColor(self.ArbeitsschrittTable, 3,0,255,0) # zum setzen der dritten Spalte der Arbeitsschrittetabelle auf weiß
|
||||||
|
else: # wenn noch nicht alle Bauteile des Auftrags auf der Waage liegen, soll folgernder Code ausgeführt werden
|
||||||
|
self.setRowColor(self.ArbeitsschrittTable, 1,255,165,0) # zum setzen der zweiten Spalte der Arbeitsschrittetabelle auf orange
|
||||||
|
self.setRowColor(self.ArbeitsschrittTable, 2,255,255,255) # zum setzen der dritten Spalte der Arbeitsschrittetabelle auf weiß
|
||||||
|
if self.checkBoxAutoTare.isChecked():
|
||||||
|
self.onTareClick()
|
||||||
|
|
||||||
|
# den Thread beenden
|
||||||
|
self.checkWaageThread.quit()
|
||||||
|
self.checkWaageThread.wait()
|
||||||
|
|
||||||
|
# auch wenn die Länge der Liste überschritten wurde
|
||||||
|
# wenn der statische Workflow aktiviert ist, dann soll die checkwaage-funktion erneut aufgerufen werden
|
||||||
|
if(self.checkBox.isChecked() == True):
|
||||||
|
self.checkWaage()
|
||||||
|
|
||||||
|
# GUI updaten
|
||||||
|
#self.updateGUI()
|
||||||
|
|
||||||
|
def objectTypeDetection(self):
|
||||||
|
''' in dieser Funktion wird der Typ des Bauteils automatisch erkannt '''
|
||||||
|
|
||||||
|
# wenn der statische Workflow ausgewählt wurde, dann soll die checkWaage Funktion aufgerufen werden, auch wenn die detectBauteiltyp-Funkion aufgerufen wurde
|
||||||
|
if self.checkBox.isChecked() == True:
|
||||||
|
self.checkWaage()
|
||||||
|
return
|
||||||
|
|
||||||
|
# überprüfen, ob der Auftrag in die Tabelle geladen wurde
|
||||||
|
if(self.AuftragsdetailsTable.item(0,0) == None):
|
||||||
|
print("Der Auftrag muss zuerst geladen werden.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# speichert den Wert, welcher im Textfeld steht in Variablen im Code
|
||||||
|
self.setAuftragsnummer()
|
||||||
|
|
||||||
|
# starten des Threats, welcher den Bauteiltyp zurück gibt
|
||||||
|
self.objectDetectionWorker = Worker()
|
||||||
|
self.objectDetectionThread = QThread()
|
||||||
|
|
||||||
|
self.objectDetectionWorker.moveToThread(self.objectDetectionThread)
|
||||||
|
|
||||||
|
self.objectDetectionWorker.objectDetectionStartSignal.connect(self.objectDetectionWorker.objectTypeDetectionThread)
|
||||||
|
self.objectDetectionWorker.objectDetectionFinishedSignal.connect(self.objectTypeDetectionFinished)
|
||||||
|
self.objectDetectionWorker.waageStoppedSignal.connect(self.threadStopped)
|
||||||
|
self.objectDetectionWorker.stopLoopSignal.connect(lambda status: setattr(self.objectDetectionWorker, 'stopLoop', status)) #wird fürs aktive Stoppen des Threads benötigt
|
||||||
|
|
||||||
|
self.objectDetectionThread.started.connect(lambda: self.objectDetectionWorker.objectDetectionStartSignal.emit(self.auftragsnummer))
|
||||||
|
self.objectDetectionThread.start()
|
||||||
|
|
||||||
|
def objectTypeDetectionFinished(self, einzelteilID, rowData):
|
||||||
|
''' wenn der Typ des Objektes erkannt wurde, dann soll die Funktion aufgerufen werden '''
|
||||||
|
|
||||||
|
# Schreiben der Bauteiltype und Pos.-Nr in die jeweiligen Felder
|
||||||
|
self.PosNrTxtFeld.setText(str(rowData[1]))
|
||||||
|
self.bauteiltypTextbox.setText(rowData[2])
|
||||||
|
|
||||||
|
# setzt den Boolean, um aus der Schleife raus zu gehen
|
||||||
|
self.btTypeIsSet = True
|
||||||
|
|
||||||
|
#zum setzen den Farbe der gesamten Reihe auf Orange
|
||||||
|
self.setRowColor(self.AuftragsdetailsTable, self.getRowNr(einzelteilID),255,165,0)
|
||||||
|
|
||||||
|
# den Thread beenden
|
||||||
|
self.objectDetectionThread.quit()
|
||||||
|
self.objectDetectionThread.wait()
|
||||||
|
|
||||||
|
# wenn der Bauteiltyp erkannt wurde, dann soll die GUI aktualisiert werden und anschließend die CheckWaage-Funktion aufgerufen werden
|
||||||
|
self.updateGUI()
|
||||||
|
self.checkWaage()
|
||||||
|
|
||||||
|
def threadStopped(self, einzelteilID):
|
||||||
|
''' wenn kein Bauteil erkannt wurde, dann ist die EinzenteilID = 0 '''
|
||||||
|
if self.checkFinished() == False:
|
||||||
|
if(einzelteilID > 0):
|
||||||
|
self.setRowColor(self.AuftragsdetailsTable, self.getRowNr(einzelteilID),255,255,255) #zum setzen den Farbe der gesamten Reihe auf Weiß
|
||||||
|
self.setRowColor(self.ArbeitsschrittTable, 2,255,255,255)
|
||||||
|
self.setRowColor(self.ArbeitsschrittTable, 1,255,165,0)
|
||||||
|
|
||||||
|
# den Thread beenden
|
||||||
|
if hasattr(self, 'objectDetectionThread'):
|
||||||
|
self.objectDetectionThread.quit()
|
||||||
|
self.objectDetectionThread.wait()
|
||||||
|
print("Der ObjektDetection-Thread wurde beendet.")
|
||||||
|
|
||||||
|
if hasattr(self, 'checkWaageThread'):
|
||||||
|
self.checkWaageThread.quit()
|
||||||
|
self.checkWaageThread.wait()
|
||||||
|
print("Der CheckWaage-Thread wurde beendet.")
|
||||||
|
|
||||||
|
# new class for Camera Object detection with YOLOv8
|
||||||
|
class CameraStreamApp(QtWidgets.QMainWindow):
|
||||||
|
def __init__(self, ui):
|
||||||
|
super().__init__()
|
||||||
|
self.ui = ui
|
||||||
|
self.yolo_stream = None # Initialize YOLOv8CameraStream as None
|
||||||
|
self.timer = QtCore.QTimer(self)
|
||||||
|
self.timer.timeout.connect(self.update_frame)
|
||||||
|
|
||||||
|
# Populate the model dropdown menu
|
||||||
|
self.populate_model_dropdown()
|
||||||
|
|
||||||
|
self.ui.startCamBtn.clicked.connect(self.start_camera) # start camera if button LoadAuftrag is clicked
|
||||||
|
self.ui.stopCamBtn.clicked.connect(self.stop_camera) # start camera if button LoadAuftrag is clicked
|
||||||
|
self.scene = QtWidgets.QGraphicsScene(self)
|
||||||
|
self.ui.graphicsView.setScene(self.scene)
|
||||||
|
|
||||||
|
def populate_model_dropdown(self):
|
||||||
|
"""Populate the dropdown menu with model files from the models directory."""
|
||||||
|
models_dir = "models"
|
||||||
|
model_files = [f for f in os.listdir(models_dir) if f.endswith(".pt")]
|
||||||
|
self.ui.modelComboBox.clear()
|
||||||
|
self.ui.modelComboBox.addItems(model_files)
|
||||||
|
|
||||||
|
def start_camera(self):
|
||||||
|
# Start the YOLOv8 camera stream (only if not already started)
|
||||||
|
if self.yolo_stream is None:
|
||||||
|
self.yolo_stream = YOLOv8CameraStream(model_path="models/yolov8m_seg_e300.pt", logging_level="high")
|
||||||
|
# self.yolo_stream.start() # Start the YOLOv8 stream
|
||||||
|
self.timer.start(30) # Start the timer to update the frame every 30ms (about 33 FPS)
|
||||||
|
|
||||||
|
def stop_camera(self):
|
||||||
|
# Stop the camera stream and processing
|
||||||
|
if self.yolo_stream is not None:
|
||||||
|
self.timer.stop() # Stop the timer
|
||||||
|
self.yolo_stream.cap.release() # Release the camera resource
|
||||||
|
self.yolo_stream = None # Reset the YOLOv8 stream object
|
||||||
|
self.scene.clear() # Clear the displayed frame from the graphicsView
|
||||||
|
print("Camera stream stopped and resources released.")
|
||||||
|
|
||||||
|
def update_frame(self):
|
||||||
|
# Update the frame from YOLOv8 stream
|
||||||
|
if self.yolo_stream:
|
||||||
|
ret, frame = self.yolo_stream.cap.read() # Capture frame from YOLOv8 stream
|
||||||
|
|
||||||
|
if ret:
|
||||||
|
# new part including processing via yolo model
|
||||||
|
processed_frame = self.yolo_stream.process_frame(frame)
|
||||||
|
|
||||||
|
# Convert the frame from BGR (OpenCV format) to RGB
|
||||||
|
# frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||||
|
frame = cv2.cvtColor(processed_frame, cv2.COLOR_BGR2RGB)
|
||||||
|
|
||||||
|
# Convert the frame to QImage
|
||||||
|
h, w, ch = frame.shape
|
||||||
|
bytes_per_line = ch * w
|
||||||
|
qt_image = QtGui.QImage(frame.data, w, h, bytes_per_line, QtGui.QImage.Format_RGB888)
|
||||||
|
|
||||||
|
# Add the QImage to a QPixmap
|
||||||
|
pixmap = QtGui.QPixmap.fromImage(qt_image)
|
||||||
|
|
||||||
|
# Get the size of the graphicsView and scale the pixmap to fit
|
||||||
|
view_size = self.ui.graphicsView.size()
|
||||||
|
scaled_pixmap = pixmap.scaled(view_size, QtCore.Qt.KeepAspectRatio)
|
||||||
|
|
||||||
|
# Update the scene with the scaled pixmap
|
||||||
|
self.scene.clear()
|
||||||
|
self.scene.addPixmap(scaled_pixmap)
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
# Release the camera when the application is closed
|
||||||
|
if self.yolo_stream is not None:
|
||||||
|
self.yolo_stream.cap.release()
|
||||||
|
event.accept()
|
||||||
|
|
||||||
|
# new class for light control
|
||||||
|
class LightControl(QtWidgets.QMainWindow):
|
||||||
|
def __init__(self, ui):
|
||||||
|
super().__init__()
|
||||||
|
self.ui = ui
|
||||||
|
|
||||||
|
# init relay control
|
||||||
|
self.ui.startSpotlightBtn.clicked.connect(self.spot_on)
|
||||||
|
self.ui.stopSpotlightBtn.clicked.connect(self.spot_off)
|
||||||
|
self.r = sainsmartrelay.SainsmartRelay()
|
||||||
|
|
||||||
|
# init led control
|
||||||
|
self.ui.redLightBtn.clicked.connect(self.red_on)
|
||||||
|
self.ui.yellowLightBtn.clicked.connect(self.yellow_on)
|
||||||
|
self.ui.greenLightBtn.clicked.connect(self.green_on)
|
||||||
|
self.ui.offLightBtn.clicked.connect(self.leds_off)
|
||||||
|
self.ui.blinkLightBtn.clicked.connect(self.blink_yellow)
|
||||||
|
self.w = wledControl.WLEDController(port="/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:1:1.0-port0")
|
||||||
|
self.w.connect()
|
||||||
|
#self.w.switch_to_green() # at appstart the light is green
|
||||||
|
self.w.blink_green() # and switches to green blinking until the workflow gets started successfully#
|
||||||
|
|
||||||
|
# Connect app exit signal to the cleanup method
|
||||||
|
app.aboutToQuit.connect(self.cleanup)
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
"""Clean up resources and switch off LEDs."""
|
||||||
|
print("Cleaning up resources and switching off LEDs")
|
||||||
|
self.leds_off() # Turn off LEDs
|
||||||
|
self.w.disconnect() # Disconnect WLED controller
|
||||||
|
|
||||||
|
def spot_on(self):
|
||||||
|
print("Turn on light clicked")
|
||||||
|
self.r.turn_on(1)
|
||||||
|
|
||||||
|
def spot_off(self):
|
||||||
|
print("Turn off light clicked")
|
||||||
|
self.r.turn_off(1)
|
||||||
|
|
||||||
|
def red_on(self):
|
||||||
|
print("Red light is on")
|
||||||
|
self.w.switch_to_red()
|
||||||
|
|
||||||
|
def yellow_on(self):
|
||||||
|
print("Yellow light is on")
|
||||||
|
self.w.switch_to_yellow()
|
||||||
|
|
||||||
|
def green_on(self):
|
||||||
|
print("Green light is on")
|
||||||
|
self.w.switch_to_green()
|
||||||
|
|
||||||
|
def leds_off(self):
|
||||||
|
print("LEDs are off")
|
||||||
|
self.w.turn_off_all()
|
||||||
|
|
||||||
|
def blink_yellow(self):
|
||||||
|
print("Yellow color is blinking")
|
||||||
|
self.w.blink_yellow()
|
||||||
|
|
||||||
|
def blink_red(self):
|
||||||
|
print("Red color is blinking")
|
||||||
|
self.w.blink_red()
|
||||||
|
|
||||||
|
def blink_green(self):
|
||||||
|
print("Green color is blinking")
|
||||||
|
self.w.blink_green()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
MainWindow = QtWidgets.QMainWindow()
|
||||||
|
ui = Ui_MainWindow()
|
||||||
|
ui.setupUi(MainWindow)
|
||||||
|
|
||||||
|
# Initialize the CameraStreamApp with the UI
|
||||||
|
camera_app = CameraStreamApp(ui)
|
||||||
|
# initialize light control app
|
||||||
|
light_app = LightControl(ui)
|
||||||
|
|
||||||
|
MainWindow.show()
|
||||||
|
sys.exit(app.exec_())
|
Loading…
Reference in New Issue
Block a user