readScale.py

This commit is contained in:
ClemensFritze 2024-07-02 12:42:04 +02:00
parent 0b1adac4a7
commit 2342bfb78b
8 changed files with 598 additions and 0 deletions

View File

@ -0,0 +1 @@
,clemens,cps-aio-001,01.07.2024 13:17,file:///home/clemens/.config/libreoffice/4;

BIN
Anleitung-Schnittstelle.pdf Normal file

Binary file not shown.

View File

@ -0,0 +1,66 @@
/*
* This ESP32 code is created by esp32io.com
*
* This ESP32 code is released in the public domain
*
* For more detail (instruction and wiring diagram), visit https://esp32io.com/tutorials/esp32-rs232
*/
//########################
char hexValues[] = "1B74";
// Länge des Hexadezimal-Arrays berechnen
int lengthHexArray = sizeof(hexValues) - 1;
//es würde auch funktionieren, wenn man als Länge 2 einfügt, dann printed er in der Konsole nur ein N
//char asciiVal[lengthHexArray / 2 + 1] = {(char) 0x1B, (char) 0x70}; //70 ist Print - 74 ist tare
char asciiVal_read[3] = {(char) 0x1B, (char) 0x70}; //70 ist Print
char asciiVal_tare[3] = {(char) 0x1B, (char) 0x74}; //74 ist tare
void setup() {
// start communication with baud rate 9600
Serial.begin(9600); // Serial Monitor
Serial2.begin(9600); // RS232
// wait a moment to allow serial ports to initialize
delay(100);
//
// Beispiel-Hexadezimalwerte
}
void loop() {
//Serial.println(asciiVal);
//char pcData = Serial.read();
String pcData = Serial.readStringUntil('\n');
// abhängig davon, was vom PC empfangen wird, wird der entsprechende Befehl zur Waage geschickt
if(pcData == "tare"){
Serial2.write(asciiVal_tare);
} else if(pcData == "getWeight"){
Serial2.write(asciiVal_read);
}
pcData == "";
//Serial2.write(asciiVal_read);
// Check if there's data available on Serial
if (Serial2.available()) {
//char data = Serial2.read(); // read the received character
String data = Serial2.readStringUntil('\n'); // read the received character
data = data + "\n";
Serial.write(data.c_str());
}
}

Binary file not shown.

Binary file not shown.

92
readMe.txt Normal file
View File

@ -0,0 +1,92 @@
https://pro.cps.unileoben.ac.at/index.php/login
bei der cps-ProCould anmelden - FRITZE - CPS$123456789
git anlegen
-> Mail 4.6
https://git.cps.unileoben.ac.at/
unimail
Git/.
-------------
-------------
https://pyserial.readthedocs.io/en/latest/shortintro.html - Schnittstelle-Python-Serial
-------------
MariaDB
DBName: projectGeislinger
Tabellenname: Einzelteile
User:
BN: dbUser
PW: dbPassword
Einloggen als Root: sudo mariadb
Adminaccount:
BN: admin
PW: admin
zum Einloggen:
mysql -u [databaseUser] -p -> nach dem Enter das PW eingeben
Erstellen einer neuen DB
create database [Datenbankname];
Erstellen eines neuen DBUsers:
create user '[username]'@'localhost' identified by '[Passwort]';
erstellen einer Tabelle:
create table [Datenbankname].[Tabellenname] (id int auto_increment not null primary key, Bezeichnung varchar(500), Gewicht FLOAT, BildPfad varchar(500));
create table projectGeislinger.Einzelteile (id int auto_increment not null primary key, Bezeichnung varchar(500), GewichtMittelwert FLOAT, GewichtVarianz FLOAT, BildPfad varchar(500));
zum aktivieren des Autostarts:
sudo systemctl enable mariadb.service
den Benutzer die Rechte auf die DB zuweisen:
GRANT ALL PRIVILEGES ON projectGeislinger.* TO "dbUser"@"localhost" identified by "dbPassword";
Insert:
insert into projectGeislinger.Einzelteile (Bezeichnung, GewichtMittelwert, GewichtVarianz) values ('25mm', 0.00415, 0.0000000087);
id, Bezeichnung, Gewicht, imagePath
-------------------
Bauteile:
Tellerfedern:
Durchmesser:
57mm - 12mal
45mm - 8mal
40mm - 10mal
31mm - 2mal
25mm - 16mal
Messungen:
57mm: 0.0417; 0.0418; 0.0415; 0.0418; 0.0419; 0.0415; 0.0419; 0.0416; 0.0418; 0.0418; 0.0418; 0.0418
45mm: 0.0219; 0.0220; 0.0219; 0.0219; 0.0219; 0.0219; 0.0219; 0.0219
40mm: 0.0137; 0.0138; 0.0137; 0.0137; 0.0137; 0.0137; 0.0137; 0.0137; 0.0137; 0.0137
31mm: 0.0070; 0.0069
25mm: 0.0041; 0.0040; 0.0041; 0.0042; 0.0040; 0.0043; 0.0042; 0.0042; 0.0041; 0.0040; 0.0042; 0.0042; 0.0041; 0.0043; 0.0042; 0,0042
erledigte Schritte:
Wage mit Esp auslesen
Kommunikation zwischen dem ESP und Python am Rechner
Die Datenbank aufsetzen
Verbindung zwischen Python und DB aufsetzen
Die Bauteile "vermessen" -> ein Excelfile mit den Daten aufsetzen
-> Varianz und Mittelwert in die DB eintragen
Die Wahrscheinlichkeitsdichte einer Messung berechnen und damit den Bauteiltypen bestimmen

301
readScale.py Normal file
View File

@ -0,0 +1,301 @@
import serial
import binascii
import math
import mariadb
import copy
# aktuell ist es so programmiert, dass es annimmt, dass in kg gemessen wird (andere Einheiten liefern also flasche Ergebnisse)
# das was man noch dazuprogrammieren kann, ist wenn mehrere Teile auf der Waage liegen, ob dann die Typen noch immer erkannt werden
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 wahrscheinlichkeitsDichteMultipVar(waageMessung, numberObjectList, results):
# in der Funktion wird der Wahrscheinlichkeitsdichtenwert der Variable waageMessung für eine bestimmte Normalverteilung berechnet
# Mathematische Sätze, auf welchen die Berechnung basiert:
# seien X1,..., Xn unabhängige Zufallsvariablen mit Dichten f1,..., fn, dann hat X = (X1,...,Xn) die gemeinsame Dichte f(x1,...,xn) = f1(x1) * ... + fn(xn)
# 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
result = 0
# Berechnung vom Gesamtmittelwert
mueGes = 0
for i in range(0, len(numberObjectList)):
mueGes = mueGes + numberObjectList[i] * results[i][2]
# Berechnung von der Gesamtvarianz (var = sigma^2)
varGes = 0
for i in range(0, len(numberObjectList)):
varGes = varGes + numberObjectList[i] * results[i][3]
# Berechnung der Wahrscheinlichkeitsdichte
standardabweichungGes = varGes**0.5
result = 1/(standardabweichungGes * (2*math.pi)**0.5 ) * math.exp(-0.5 * ((waageMessung-mueGes)/standardabweichungGes)**2)
return result
# die Funktion kann man vermutlich rauslöschen
def numberSmallerObjects(numberBiggerObjects, messungWaage, mue1,mue2, sigma2):
for i in range(1,10000):
#damit wird geprüft, ob eh auch ein Objekt vom Typ1 auf der Waage liegt, oder nur ein Objekt vom Typ2
# eigentlich müsste da 3*sigma drinnen stehen, um 99,7% der Fälle abzudecken, aber das ist nur bei einer gültigen Normalverteilung zutreffend (mit ausreichend Messungen)
if (messungWaage-numberBiggerObjects*(mue2+10*sigma2))/mue1 > 0:
if i > (messungWaage-numberBiggerObjects*mue2)/mue1:
return i
else:
return -1
def sumMaxWeightObjects(objectType, numberObjectList, results):
sum = 0
# die Anzahl an Bauteilen, welche dem Objekttypen zugeordnet sind, sollen nicht mit dazugerechnet werden
for i in range(objectType+1, len(numberObjectList)):
# eigentlich müsste man nur mit 3 multiplizieren, um 99,7% der Bauteile im Bereich zu haben - das gilt aber nur für eine gültige Normalverteilung
#sum = sum + numberObjectList[i] * (results[i][2] + 3 * math.sqrt(results[i][3]))
sum = sum + numberObjectList[i] * (results[i][2])
return sum
def numberPossibleObjects(objectType, numberObjectList, results, messungWaage):
# der objectType definiert, welcher der Objekte das Anschauungsobjekt ist
# wenn nur ein Objekt darauf gelegt wird, welches nicht vom Typen des Anschauungsobjektes ist, dann wird 1 zurück gegeben
#print(results[objectType][2]-10*math.sqrt(results[objectType][3]))
#print((messungWaage-sumMaxWeightObjects(objectType, numberObjectList, results))/results[objectType][2])
# wenn kein Gewicht auf der Waage liegt, dann soll -1 zurück gegeben werden.
if messungWaage <= 0:
return -1
#print(results[objectType][2])
#print(((messungWaage-sumMaxWeightObjects(objectType, numberObjectList, results))/(results[objectType][2]+3*math.sqrt(results[objectType][3]))))
#print(((messungWaage-sumMaxWeightObjects(objectType, numberObjectList, results))/(results[objectType][2]-3*math.sqrt(results[objectType][3]))))
#zwischenSumme = ((messungWaage-sumMaxWeightObjects(objectType, numberObjectList, results))/(results[objectType][2]+3*math.sqrt(results[objectType][3])))
zwischenSumme = ((messungWaage-sumMaxWeightObjects(objectType, numberObjectList, results))/(results[objectType][2]))
for i in range(1,10000):
if zwischenSumme <= 0: #in diesem Fall wird das gesamte Gewicht der Messung durch Objekte eines anderen Typen "aufgebraucht"
return 0
if i > zwischenSumme:
return i # i entspricht beim returnen der Anzahl der möglichen Objekte
def anzBauteileCountFunction(numberObjectList):
counter = 0
for i in range(0,len(numberObjectList)):
if numberObjectList[i] > 0:
counter = counter + 1
return counter
"""
for i in range(1,10000):
#damit wird geprüft, ob eh auch ein Objekt vom Typ1 auf der Waage liegt, oder nur ein Objekt vom Typ2
# eigentlich müsste da 3*sigma drinnen stehen, um 99,7% der Fälle abzudecken, aber das ist nur bei einer gültigen Normalverteilung zutreffend (mit ausreichend Messungen)
if (messungWaage-numberBiggerObjects*(mue2+10*sigma2))/mue1 > 0:
if i > (messungWaage-numberBiggerObjects*mue2)/mue1:
return i
else:
return -1
"""
def main():
print("connection is open: ", ser.is_open)
print("port to which it is connected: ", ser.portstr)
#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")
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")
# wenn die Waage nicht eingeschwungen ist, dann soll auch nichts weiter gemacht werden
if( waageEingeschwungen == True and float(intString)>0):
# Define the SQL query
sql_query = "SELECT * FROM projectGeislinger.Einzelteile"
# Execute the query
cursor.execute(sql_query)
# Fetch results
results = cursor.fetchall()
# Display data
print("Ausgabe der Daten der Datenbank:")
for row in results:
print(row)
anzBauteiltypen = len(results)
anzBauteile = anzBauteiltypen * [0] # erstellt eine Liste, in welcher die Anzahl der Bauteiltypen gespeichert ist, welche für die weiteren Schleifen verwendet wird
wahrscheinleichkeitsMatrix = []
# Berechnen der Anzahl an Objekten
for i in range(0, anzBauteiltypen):
#bauteilTypCounter = i+1 #zum hochzählen der Anzahlen der Bauteiltypen nach der k-Schleife
while(True):
if i<(anzBauteiltypen-1): # wenn i die letzte Spalte der Bauteiltypenmatrix ist, dann soll der Teil übersprungen werden
for k in range(0, 10000):
anzBauteile[i+1] = k
nrObjects = numberPossibleObjects(i, anzBauteile, results, float(intString))
if nrObjects == -1 or nrObjects == 0:
break
anzBauteile[i] = nrObjects
wahrscheinleichkeitsMatrix.append([wahrscheinlichkeitsDichteMultipVar(float(intString), anzBauteile[:], results), anzBauteile[:]])
# da die Berechnete Anzahl an möglichen Messobjekten um 0 bis +1 um den "wahren" Wert schwankt, wird in der Folge auch die Wahrscheinlichkeit mit einer um 1 verringerten Bauteilanzahl berechnet (sollte diese größer als 1 sein)
if(anzBauteile[i] >= 1 and anzBauteileCountFunction(anzBauteile)>1):
anzBauteile = anzBauteile[:]
anzBauteile[i] = anzBauteile[i]-1
wahrscheinleichkeitsMatrix.append([wahrscheinlichkeitsDichteMultipVar(float(intString), anzBauteile[:], results), anzBauteile[:]])
anzBauteile[i+1] = 0
elif i == (anzBauteiltypen-1):
nrObjects = numberPossibleObjects(i, anzBauteile, results, float(intString))
if nrObjects == -1 or nrObjects == 0:
break
anzBauteile[i] = nrObjects
wahrscheinleichkeitsMatrix.append([wahrscheinlichkeitsDichteMultipVar(float(intString), anzBauteile[:], results), anzBauteile[:]])
if(anzBauteile[i] >= 1 and anzBauteileCountFunction(anzBauteile)>1):
anzBauteile = anzBauteile[:]
anzBauteile[i] = anzBauteile[i]-1
wahrscheinleichkeitsMatrix.append([wahrscheinlichkeitsDichteMultipVar(float(intString), anzBauteile[:], results), anzBauteile[:]])
if i >= (anzBauteiltypen-2): #wenn der Fall eintritt, dann wurden alle Fälle überprüft -> dadurch kann die i-Schleife in die letzte Runde gehen, kann das Programm sich ganz beenden
anzBauteile[i] = 0
break
for m in range(i+2,anzBauteiltypen):
anzBauteile[m] = anzBauteile[m] + 1
nrObjects = numberPossibleObjects(i, anzBauteile, results, float(intString))
if nrObjects >= 1:
break
elif nrObjects < 1 and m == (anzBauteiltypen-1) :
break
else:
anzBauteile[m] = 0
nrObjects = numberPossibleObjects(i, anzBauteile, results, float(intString))
if (nrObjects == -1 or nrObjects == 0):
anzBauteile[anzBauteiltypen-1] = 0
anzBauteile[i] = 0
break
# Suchen der höchsten Wahrscheinlichkeitsdichte
countMaxPropDensity = 0
maxPropDensity = 0
#print(wahrscheinleichkeitsMatrix[0][0])
for i in range(0, len(wahrscheinleichkeitsMatrix)):
if(wahrscheinleichkeitsMatrix[i][0] > maxPropDensity):
maxPropDensity = wahrscheinleichkeitsMatrix[i][0]
countMaxPropDensity = i
if wahrscheinleichkeitsMatrix[i][0] >0:
print(wahrscheinleichkeitsMatrix[i])
print(wahrscheinleichkeitsMatrix[countMaxPropDensity][0])
# die Bauteilkombination mit der höchsten Wahrscheinlichkeitsdichte ausgeben
for i in range(0, len(wahrscheinleichkeitsMatrix[0][1])):
print("Bauteiltyp: ", results[i][1]," Anzahl: ", wahrscheinleichkeitsMatrix[countMaxPropDensity][1][i])
#nrObjects = numberPossibleObjects(0, anzBauteile, results, float(intString))
#print("number objects: ", nrObjects-1)
"""
for i in range(3,0,-1):
numberOfSmallObjects = numberSmallerObjects(1, float(intString),results[4][2], results[3][2], math.sqrt(results[3][3]))
print("number of smaller objects: ", numberOfSmallObjects-1)
"""
"""
# in der Folge wird nun berechnet, welcher Normalverteilung die Messung am ehesten entspricht
dBId = 0
maxPropDensity = 0
for row in results:
propDens = wahrscheinlichkeitsDichte(float(intString) ,row[2], row[3])
if propDens > maxPropDensity:
maxPropDensity = propDens
dBId = row[0]
#Ausgabe des Bauteiltypen, welchem die Messung am ehesten entspricht
for row in results:
if row[0] == dBId:
print(row[1])
#propDens = wahrscheinlichkeitsDichte(0.042 ,results[0][2], results[0][3])
#print(propDens)
"""
ser.close()
print("connection is open: ", ser.is_open)
if __name__ == "__main__":
main()

138
readScale_Stand01.07.py Normal file
View File

@ -0,0 +1,138 @@
import serial
import binascii
import math
import mariadb
# aktuell ist es so programmiert, dass es annimmt, dass in kg gemessen wird (andere Einheiten liefern also flasche Ergebnisse)
# das was man noch dazuprogrammieren kann, ist wenn mehrere Teile auf der Waage liegen, ob dann die Typen noch immer erkannt werden
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 numberSmallerObjects(numberBiggerObjects, messungWaage, mue1,mue2, sigma2):
for i in range(1,10000):
#damit wird geprüft, ob eh auch ein Objekt vom Typ1 auf der Waage liegt, oder nur ein Objekt vom Typ2
# eigentlich müsste da 3*sigma drinnen stehen, um 99,7% der Fälle abzudecken, aber das ist nur bei einer gültigen Normalverteilung zutreffend (mit ausreichend Messungen)
if (messungWaage-numberBiggerObjects*(mue2+10*sigma2))/mue1 > 0:
print((messungWaage-numberBiggerObjects*(mue2+10*sigma2))/mue1)
if i > (messungWaage-numberBiggerObjects*mue2)/mue1:
return i
else:
return -1
def main():
print("connection is open: ", ser.is_open)
print("port to which it is connected: ", ser.portstr)
#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")
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")
# wenn die Waage nicht eingeschwungen ist, dann soll auch nichts weiter gemacht werden
if( waageEingeschwungen == True):
# Define the SQL query
sql_query = "SELECT * FROM projectGeislinger.Einzelteile"
# Execute the query
cursor.execute(sql_query)
# Fetch results
results = cursor.fetchall()
# Display data
print("Ausgabe der Daten der Datenbank:")
for row in results:
print(row)
# in der Folge wird nun berechnet, welcher Normalverteilung die Messung am ehesten entspricht
dBId = 0
maxPropDensity = 0
for row in results:
propDens = wahrscheinlichkeitsDichte(float(intString) ,row[2], row[3])
if propDens > maxPropDensity:
maxPropDensity = propDens
dBId = row[0]
#Ausgabe des Bauteiltypen, welchem die Messung am ehesten entspricht
for row in results:
if row[0] == dBId:
print(row[1])
#propDens = wahrscheinlichkeitsDichte(0.042 ,results[0][2], results[0][3])
#print(propDens)
ser.close()
print("connection is open: ", ser.is_open)
if __name__ == "__main__":
main()