mein Programm wird jetzt etwas komplexer. Für mich jedenfalls.
Das Programm läuft eigentlich auf einem Raspi.
Damit ich es im Laptop programmieren kann, hab ich alles was die Schnittstellen betrifft raus genommen.
Was läuft:
- Tkinter läuft
- die Klasse Datenbank funktioniert und füllt meine Combobox richtig aus
- Klasse Geber soll self.geber_db_id und self.motor_db_id aus Klasse Datenbank vererbt bekommen
Gern auch Kritik, denn ich bin in einer krassen Lernphase und mir qualmt das Hirn
Code: Alles auswählen
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Aug 26 20:11:54 2026
@author: ralf
"""
from tkinter import ttk, Label, Button, Entry, Menu, LabelFrame, Text, messagebox,StringVar, END
from ttkthemes import ThemedTk
import sqlite3
import time
from contextlib import contextmanager
from threading import Lock
import serial
import math
from crccheck.checksum import ChecksumXor8
import sick_error
verbindung = sqlite3.connect("servo.db", timeout=10)
db_abfrage = verbindung.cursor()
TXDEN_1 = 27
TXDEN_2 = 22
geber_id=0
"""
import RPi.GPIO as GPIO #GPIO einrichten
def setup_gpio():
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
#GPIO.setup((TXDEN_1, TXDEN_2), GPIO.OUT, value=True)
GPIO.setup((TXDEN_1, TXDEN_2), GPIO.OUT)
@contextmanager
def enable_send(channel):
GPIO.output(channel, GPIO.HIGH)
yield # ab dann wird der Code im with-Block ausgeführt
# ab hier ist der Code des Kontext-Managers abgearbeitet
# output auf 0 setzen, um wieder empfangen zu können
GPIO.output(channel, GPIO.LOW)
#Serial config ist aktuell für Hiperface
class RS485config(object):
def __init__(self, dev, enable_gpio, baudrate=9600,
bytesize = serial.EIGHTBITS, parity = serial.PARITY_EVEN,
stopbits = serial.STOPBITS_ONE):
self.serial = serial.Serial(dev, baudrate, bytesize, parity, stopbits, timeout=1)
self.enable_gpio = enable_gpio
# soll gleichzeitiges Senden und Empfangen unterbinden
self.send_receive_lock = Lock()
def send(self, data):
# zuerst wird der Lock abgefragt, danach der GPIO durch den Kontextmanager gesetzt
# wenn er z.B. gerade Daten empfängt, wartet er, bis der Lock wieder freigegeben ist
# danach wird erst der GPIO auf High gesetzt
app_instance.conect_progress.step(10)
with (
self.send_receive_lock,
enable_send(self.enable_gpio),
):
self.serial.write(data)
def receive(self, size):
app_instance.conect_progress.step(10)
time.sleep(0.01)
with self.send_receive_lock:
data = self.serial.read(size)
return data
def set_baudrate(self, baudrate):
self.serial.close()
self.serial = serial.Serial(self.serial.port, baudrate)
setup_gpio()
# Signatur geändert: Port, Enable-GPIO, Baudrate
endat_clock = RS485config("/dev/ttySC0", TXDEN_1)
endat_data = RS485config("/dev/ttySC1", TXDEN_2)
"""
class MainWindow():
def __init__(self):
self.hauptfenster = ThemedTk(theme="blue")
self.hauptfenster.title("Servo-Box Version 1.1")
# rootgröße ermitteln
#w, h = root.winfo_screenwidth(), root.winfo_screenheight()
#root.geometry("%dx%d+0+0" % (w, h))
self.hauptfenster.geometry("1000x750")
#root. minsize(width=900, height=950)
my_menu=Menu(self.hauptfenster )
self.hauptfenster.config(menu=my_menu)
file_menu= Menu(my_menu)
geber_menu = Menu(my_menu)
messung_menu = Menu(my_menu)
info_menu = Menu(my_menu)
my_menu.add_cascade(label="Menu", menu=file_menu)
file_menu.add_command(label="Motor Datenbank")
file_menu.add_command(label="Geber Datenbank")
file_menu.add_command(label="Exit",command=self.hauptfenster.destroy)
if 1 !=1:
messagebox.showerror('Beenden', 'Keine Schnittstelle, kein Gerät vorhanden. Bitte Anlage überprüfen und Programm neu starten.') # kommt eventuell spät was rein
else:
my_menu.add_cascade(label="Geber", menu=geber_menu)
geber_menu.add_command(label="Hyperface + DSL")
geber_menu.add_command(label="Resolver")
geber_menu.add_command(label="Endat analog")
geber_menu.add_command(label="Endat digital")
my_menu.add_cascade(label="Data", menu=messung_menu)
messung_menu.add_command(label="Analog")
messung_menu.add_command(label="RS485")
messung_menu.add_command(label="RS422")
#motorsetup
my_menu.add_cascade(label="Info", menu=info_menu)
label_titel = Label(self.hauptfenster,text="Servo-Prüfbox", font=('times', 25, 'bold', 'italic'), foreground="#0000ff")
label_titel.grid(column=0, row=0, padx=20, pady=20)
frame_motorsetup = LabelFrame(self.hauptfenster, bg="#eeeeee")
frame_motorsetup.grid(column=0, row=1, sticky="nwse", padx=5, pady=5)
label_motor = Label(frame_motorsetup,text="Motor-Hersteller", bg="#eeeeee")
label_motor.grid(column=0, row=0, sticky="nw", padx=5, pady=5)
motorhersteller_var = StringVar(self.hauptfenster)
motorhersteller_combo = ttk.Combobox(frame_motorsetup,
state="readonly",
textvariable= motorhersteller_var,
postcommand= lambda: datenbank.motorhersteller_sqlite())
motorhersteller_combo.grid(column=1, row=0, sticky="we", padx=5, pady=5)
label_motortyp = Label(frame_motorsetup,text="Model", bg="#eeeeee")
label_motortyp.grid(column=0, row=1, sticky="nw", padx=5, pady=5)
motortyp_var = StringVar(self.hauptfenster)
motortyp_combo = ttk.Combobox(frame_motorsetup,
state="readonly",
textvariable= motortyp_var,
postcommand= lambda: datenbank.motortyp_sqlite())
motortyp_combo.grid(column=1, row=1, sticky="we", padx=5, pady=5)
label_motorpolpaar = Label(frame_motorsetup,text="Motorpole", bg="#eeeeee")
label_motorpolpaar.grid(column=0, row=2, sticky="nw", padx=5, pady=5)
motorpolpaar_var = StringVar(self.hauptfenster)
motorpolpaar_combo = ttk.Combobox(frame_motorsetup,
state="readonly",
textvariable= motorpolpaar_var,
postcommand= lambda: datenbank.motorpolpaar_sqlite())
motorpolpaar_combo.grid(column=1, row=2, sticky="we", padx=5, pady=5)
#Motorinfos anzeigen
motordaten = Text(frame_motorsetup, bg="#FFFFee", width=40, height=8)
motordaten.grid(column=0, row=3, sticky="nw", padx=5, pady=5, columnspan=2)
#Gebersetup
frame_gebersetup = LabelFrame(self.hauptfenster, bg="#eeeeee")
frame_gebersetup.grid(column=0, row=2, sticky="nwse", padx=5, pady=5)
label_geber = Label(frame_gebersetup,text="Geber-Hersteller", bg="#eeeeee")
label_geber.grid(column=0, row=1, sticky="nw", padx=5, pady=5)
geberhersteller_var = StringVar(self.hauptfenster)
geberhersteller_combo = ttk.Combobox(frame_gebersetup,
state="readonly",
textvariable= geberhersteller_var,
postcommand= lambda: datenbank.geberhersteller_sqlite())
geberhersteller_combo.grid(column=1, row=1, sticky="we", padx=5, pady=5)
label_gebertyp = Label(frame_gebersetup,text="Model", bg="#eeeeee")
label_gebertyp.grid(column=0, row=2, sticky="nw", padx=5, pady=5)
gebertyp_var = StringVar(self.hauptfenster)
gebertyp_combo = ttk.Combobox(frame_gebersetup,
state="readonly",
textvariable= gebertyp_var,
postcommand= lambda: datenbank.gebertyp_sqlite())
gebertyp_combo.grid(column=1, row=2, sticky="we", padx=5, pady=5)
label_gebersuche = Label(frame_gebersetup,text="Datenübertragung", bg="#eeeeee")
label_gebersuche.grid(column=0, row=3, sticky="nw", padx=5, pady=5)
conect_progress = ttk.Progressbar(frame_gebersetup, value=10, orient='horizontal', length=200 )
conect_progress.grid(column=1, row=3, sticky="nw", padx=5, pady=5)
self.conect_progress =conect_progress
#Geberinfos anzeigen
geberdaten = Text(frame_gebersetup, bg="#FFFFee", width=40, height=12)
geberdaten.grid(column=0, row=5, sticky="nw", padx=5, pady=5, columnspan=2)
#Projektdaten
frame_projekt = LabelFrame(self.hauptfenster, bg="#eeeeee")
frame_projekt.grid(column=1, row=0, sticky="nwse", padx=5, pady=5)
label_name = Label(frame_projekt,text="Projekt", bg="#eeeeee")
label_name.grid(column=0, row=0, sticky="nw", padx=5, pady=5)
projekt_eingabe = Entry(frame_projekt,text="Projekt", bg="#FFFFFF")
projekt_eingabe.grid(column=0, row=1, sticky="nw", padx=5, pady=5)
projekt_speichern = Button(frame_projekt,text="Speichern")
projekt_speichern.grid(column=1, row=1, sticky="nw", padx=5, pady=5)
starten_buttom = Button(frame_projekt,text="Start", bg="#aaff00", activebackground="#7bb900", activeforeground="#ffffff" ,command= lambda: Geber.starten())
starten_buttom.grid(column=0, row=2, sticky="nw", padx=5, pady=5)
stoppen_buttom = Button(frame_projekt,text="Start", bg="#ff6619", activebackground="#d45515", activeforeground="#ffffff" ,command= lambda: Geber.stoppen())
stoppen_buttom.grid(column=1, row=2, sticky="nw", padx=5, pady=5)
frame_messungen = LabelFrame(self.hauptfenster, bg="#eeeeee")
frame_messungen.grid(column=1, row=1, sticky="nws", padx=5, pady=5)
positions_titel = Label(frame_messungen,text="absolute Position", bg="#eeeeee")
positions_titel.grid(column=0, row=0, sticky="w", padx=5, pady=5)
self.positions_value = Label(frame_messungen,text="0", bg="#eeeeee", width=20)
self.positions_value.grid(column=1, row=0, sticky="e", padx=5, pady=5)
mech_winkel_titel = Label(frame_messungen,text="mech. Winkel", bg="#eeeeee")
mech_winkel_titel.grid(column=0, row=1, sticky="w", padx=5, pady=5)
self.mech_winkel_value = Label(frame_messungen,text="---", bg="#eeeeee")
self.mech_winkel_value.grid(column=1, row=1, sticky="w", padx=5, pady=5)
offset_winkel_titel = Label(frame_messungen,text="Offset Winkel", bg="#eeeeee")
offset_winkel_titel.grid(column=0, row=2, sticky="w", padx=5, pady=5)
self.offset_winkel_value = Label(frame_messungen,text="---", bg="#eeeeee")
self.offset_winkel_value.grid(column=1, row=2, sticky="w", padx=5, pady=5)
datenbank = Datenbank(motorhersteller_combo, motorhersteller_var,
motortyp_combo, motortyp_var, motorpolpaar_combo,
motorpolpaar_var, geberhersteller_combo, geberhersteller_var,
gebertyp_combo, gebertyp_var,
geberdaten, conect_progress, motordaten)
def mainloop(self):
self.hauptfenster.mainloop()
class Datenbank():
def __init__(self, motorhersteller_combo, motorhersteller_var, motortyp_combo, motortyp_var,
motorpolpaar_combo, motorpolpaar_var, geberhersteller_combo, geberhersteller_var,
gebertyp_combo, gebertyp_var,
geberdaten, conect_progress, motordaten):
self.motorhersteller_combo = motorhersteller_combo
self.motorhersteller_var = motorhersteller_var
self.motortyp_combo = motortyp_combo
self.motortyp_var = motortyp_var
self.motorpolpaar_combo = motorpolpaar_combo
self.motorpolpaar_var = motorpolpaar_var
self.geberhersteller_combo = geberhersteller_combo
self.geberhersteller_var = geberhersteller_var
self.gebertyp_combo = gebertyp_combo
self.gebertyp_var = gebertyp_var
self.geberdaten = geberdaten
self.conect_progress = conect_progress
self.motordaten=motordaten
def motorhersteller_sqlite(self):
try:
db_abfrage.execute("SELECT DISTINCT hersteller FROM motor")
self.motorhersteller_combo['values'] = db_abfrage.fetchall()
except verbindung.DatabaseError as error:
print(error)
def motortyp_sqlite(self):
try:
db_abfrage.execute('SELECT typ FROM motor WHERE hersteller = ?' , (self.motorhersteller_var.get(),))
self.motortyp_combo['values'] = db_abfrage.fetchall()
except verbindung.DatabaseError as error:
print(error)
def motorpolpaar_sqlite(self):
try:
db_abfrage.execute('SELECT id,pole,uvw,bemerkung FROM motor WHERE typ = ?' , (self.motortyp_var.get(),))
abfrage=db_abfrage.fetchall()
self.motorpolpaar_combo['values'] = abfrage[0][1]
#print(db_abfrage)
self.motor_db_id = int(abfrage[0][0])
self.motordaten.delete("1.0", END)
datenkopf=["ID: ", "Pole: ", "Prüfung bei UVW: ","Bemerkung: "]
motordatensatz = "{} {} \n{} {} \n{} {} \n{} {} \n".format(datenkopf[0], abfrage[0][0],
datenkopf[1] , abfrage[0][1], datenkopf[2], abfrage[0][2],datenkopf[3], abfrage[0][3] )
self.motordaten.insert('1.0',motordatensatz)
except verbindung.DatabaseError as error:
print(error)
#Geberauswahl
def geberhersteller_sqlite(self):
self.geberdaten.delete("1.0", END)
try:
db_abfrage.execute("SELECT DISTINCT hersteller FROM geber")
self.geberhersteller_combo['values'] = db_abfrage.fetchall()
except verbindung.DatabaseError as error:
print(error)
def gebertyp_sqlite(self):
if self.geberhersteller_var.get() == "Sick":
self.gebertyp_combo['values'] = "Hiperface-Auto"
self.geberdaten.insert('1.0', "Es wird nach einem Geber an \nSchnittstelle X gesucht und automatisch eingestellt")
data = bytearray.fromhex("FF52")
data.append(ChecksumXor8.calc(data))
try:
data = endat_data.send(data)
response = endat_data.receive(7)
if response.hex()[2:4] == "50" or ChecksumXor8.calc(response) != 0:
error = sick_error.error(response.hex()[4:6])
print(error)
else:
model_id = response[3:4].hex()
try:
db_abfrage.execute('SELECT * FROM geber WHERE model_id =?', (model_id,))
abfrage = db_abfrage.fetchall()
self.geberdaten.delete("1.0", END)
except verbindung.DatabaseError as error:
print(error)
except Exception as e1:
print ("error communicating...: " + str(e1))
else:
try:
db_abfrage.execute('SELECT model FROM geber WHERE hersteller = ?' , (self.geberhersteller_var.get(),))
self.gebertyp_combo['values'] = db_abfrage.fetchall()
db_abfrage.execute('SELECT * FROM geber WHERE hersteller = ?' , (self.geberhersteller_var.get(),))
abfrage = db_abfrage.fetchall()
except verbindung.DatabaseError as error:
print("Fehler: ",error)
datenkopf=["Typ:", "Datenverbindung:", "Model-ID:", "Sin-Cos / U:", "Singleturn:", "Multiturn:", "Speicher", "Hersteller:","Z-Spur:","DB-id:"]
datensatz = "{} {} \n{} {} \n{} {} \n{} {} \n{} {} \n{} {} \n{} {} \n{} {} \n{} {} \n{} {}".format(datenkopf[0], abfrage[0][1],
datenkopf[1] , abfrage[0][2], datenkopf[2] ,abfrage[0][3],
datenkopf[3] ,abfrage[0][4], datenkopf[4] ,abfrage[0][5],
datenkopf[5] ,abfrage[0][6], datenkopf[6] ,abfrage[0][7],
datenkopf[7] ,abfrage[0][8], datenkopf[8] ,abfrage[0][9],
datenkopf[9] ,abfrage[0][0])
self.geberdaten.insert('1.0',datensatz)
self.geber_db_id = abfrage[0][0]
class Geber(Datenbank):
def __init__(self):
print(self.geber_db_id)
def starten(self):
print("starten")
print(self.geber_db_id)
def stoppen(self):
print("stoppen ")
def hiperface_position(self):
db_abfrage.execute('SELECT * FROM geber WHERE id = ?' , (self.geber_db_id,))
geber_abfrage = db_abfrage.fetchall()
#ingleturn = geber_abfrage[0][5]
multiturn=geber_abfrage[0][6]
db_abfrage.execute('SELECT * FROM motor WHERE id = ?' , (self.motor_db_id,))
motor_abfrage = db_abfrage.fetchall()
motorpolpaar = motor_abfrage[0][3]/2
data = bytearray.fromhex("FF42")
data.append(ChecksumXor8.calc(data))
try:
data = endat_data.send(data)
response = endat_data.receive(7)
if response.hex()[2:4] == "50" or ChecksumXor8.calc(response) != 0:
error = sick_error.error(response.hex()[4:6])
print(error)
else:
realposition = int.from_bytes(response[2:6],'big',signed=True)
self.positions_value["text"] = realposition
schrittzahl_umdrehung_faktor = math.modf(realposition / multiturn)
#Achtung aktuell nur Multiturn
mech_winkel = round((360 / 1) * (schrittzahl_umdrehung_faktor[0]))
self.mech_winkel_value["text"] = mech_winkel
offset_winkel = divmod(mech_winkel * motorpolpaar, 360)
self.offset_winkel_value["text"] = offset_winkel[1]
except Exception as e1:
print ("error communicating...: " + str(e1))
self.positions_value.after(10, self.hiperface_position)
if __name__ == "__main__":
app_instance = MainWindow()
app_instance.mainloop()
