|
|
|
|
@@ -1,5 +1,5 @@
|
|
|
|
|
import tkinter as tk
|
|
|
|
|
from tkinter import ttk, messagebox
|
|
|
|
|
from tkinter import ttk, messagebox, PhotoImage, simpledialog
|
|
|
|
|
import customtkinter
|
|
|
|
|
customtkinter.set_appearance_mode("light")
|
|
|
|
|
customtkinter.set_default_color_theme("blue")
|
|
|
|
|
@@ -11,6 +11,8 @@ import threading
|
|
|
|
|
import time
|
|
|
|
|
import numpy as np
|
|
|
|
|
import csv
|
|
|
|
|
import os
|
|
|
|
|
from PIL import Image, ImageTk
|
|
|
|
|
|
|
|
|
|
class ArduinoGUI:
|
|
|
|
|
def __init__(self, root):
|
|
|
|
|
@@ -19,14 +21,7 @@ class ArduinoGUI:
|
|
|
|
|
self.root.title("PRG 342 GUI")
|
|
|
|
|
self.root.attributes('-fullscreen', True) # Setzt das Fenster in den Vollbildmodus
|
|
|
|
|
|
|
|
|
|
self.ser = serial.Serial(
|
|
|
|
|
port='/dev/serial0',
|
|
|
|
|
baudrate=192000,
|
|
|
|
|
parity=serial.PARITY_NONE,
|
|
|
|
|
stopbits=serial.STOPBITS_ONE,
|
|
|
|
|
bytesize=serial.EIGHTBITS,
|
|
|
|
|
timeout=1
|
|
|
|
|
)
|
|
|
|
|
self.ser = None
|
|
|
|
|
|
|
|
|
|
self.arduino = None
|
|
|
|
|
self.ports = list(serial.tools.list_ports.comports())
|
|
|
|
|
@@ -50,8 +45,6 @@ class ArduinoGUI:
|
|
|
|
|
self.load_configurations()
|
|
|
|
|
|
|
|
|
|
# Start the communication thread
|
|
|
|
|
self.lsp_communication_tread = threading.Thread(target=self.lsp_communication_loop)
|
|
|
|
|
self.lsp_communication_tread.start()
|
|
|
|
|
self.communication_thread = threading.Thread(target=self.communication_loop)
|
|
|
|
|
self.communication_thread.start()
|
|
|
|
|
|
|
|
|
|
@@ -89,75 +82,88 @@ class ArduinoGUI:
|
|
|
|
|
|
|
|
|
|
def create_widgets(self):
|
|
|
|
|
|
|
|
|
|
# Laden und Skalieren des Logos
|
|
|
|
|
original_image = Image.open("src/logo1.png")
|
|
|
|
|
resized_image = original_image.resize((500, 121), Image.LANCZOS) # Passen Sie die Größe (200, 100) nach Bedarf an
|
|
|
|
|
self.logo_image = ImageTk.PhotoImage(resized_image)
|
|
|
|
|
# Logo anstelle des Platzhalters
|
|
|
|
|
self.logo_label = customtkinter.CTkLabel(self.root, image=self.logo_image, text="")
|
|
|
|
|
self.logo_label.image = self.logo_image # Referenz behalten, um Garbage Collection zu verhindern
|
|
|
|
|
self.logo_label.grid(row=0, column=0, columnspan=3, padx=(10, 5), pady=(10, 0), sticky="w")
|
|
|
|
|
|
|
|
|
|
# Placeholer
|
|
|
|
|
self.placeholer = customtkinter.CTkLabel(self.root, text="")
|
|
|
|
|
self.placeholer.grid(row=1, column=0, padx=(10, 5), pady=(10, 0), sticky="w")
|
|
|
|
|
|
|
|
|
|
# Labels and ComboBox for Stellantriebstyp
|
|
|
|
|
self.stellantriebstyp_label = customtkinter.CTkLabel(self.root, text="Stellantriebstyp:", font=self.my_font)
|
|
|
|
|
self.stellantriebstyp_label.grid(row=0, column=0, padx=(10, 5), pady=(10, 0), sticky="w")
|
|
|
|
|
self.stellantriebstyp_label.grid(row=3, column=0, padx=(10, 5), pady=(10, 0), sticky="w")
|
|
|
|
|
|
|
|
|
|
self.config_combobox_value = customtkinter.StringVar()
|
|
|
|
|
self.config_combobox = customtkinter.CTkComboBox(self.root, variable=self.config_combobox_value, state="readonly", font=self.my_font)
|
|
|
|
|
self.config_combobox.grid(row=0, column=1, columnspan=1, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
self.config_combobox.grid(row=3, column=1, columnspan=1, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
#self.config_combobox.bind("<<ComboboxSelected>>", self.on_config_selected)
|
|
|
|
|
|
|
|
|
|
# Setzen Button für Stellantriebstyp
|
|
|
|
|
self.set_pid_button = customtkinter.CTkButton(self.root, text="Setzen", command=self.set_pid_parameters, font=self.my_font)
|
|
|
|
|
self.set_pid_button.grid(row=0, column=2, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
self.set_pid_button.grid(row=3, column=2, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
|
|
|
|
|
# Labels and ComboBox for COM Port
|
|
|
|
|
self.com_label = customtkinter.CTkLabel(self.root, text="COM Port:", font=self.my_font)
|
|
|
|
|
self.com_label.grid(row=1, column=0, padx=(10, 5), pady=(10, 0), sticky="w")
|
|
|
|
|
self.com_label.grid(row=2, column=0, padx=(10, 5), pady=(10, 0), sticky="w")
|
|
|
|
|
|
|
|
|
|
self.combobox_value = customtkinter.StringVar()
|
|
|
|
|
self.combobox = customtkinter.CTkComboBox(self.root, variable=self.combobox_value, font=self.my_font)
|
|
|
|
|
self.combobox.configure(values=[port.device for port in self.ports])
|
|
|
|
|
self.combobox.grid(row=1, column=1, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
self.combobox.grid(row=2, column=1, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
|
|
|
|
|
self.connect_button = customtkinter.CTkButton(self.root, text="Verbinden", command=self.connect_arduino, font=self.my_font)
|
|
|
|
|
self.connect_button.grid(row=1, column=2, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
self.connect_button.grid(row=2, column=2, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
|
|
|
|
|
# Setpoint entry
|
|
|
|
|
self.setpoint_label = customtkinter.CTkLabel(self.root, text="Sollwerteingabe in Nm:", font=self.my_font)
|
|
|
|
|
self.setpoint_label.grid(row=2, column=0, padx=(10, 5), pady=(10, 0), sticky="w")
|
|
|
|
|
self.setpoint_label.grid(row=4, column=0, padx=(10, 5), pady=(10, 0), sticky="w")
|
|
|
|
|
|
|
|
|
|
self.setpoint_entry = customtkinter.CTkEntry(self.root, font=self.my_font)
|
|
|
|
|
self.setpoint_entry.grid(row=2, column=1, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
self.setpoint_entry.grid(row=4, column=1, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
|
|
|
|
|
self.set_setpoint_button = customtkinter.CTkButton(self.root, text="Setzen", command=self.set_setpoint, font=self.my_font)
|
|
|
|
|
self.set_setpoint_button.grid(row=2, column=2, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
self.set_setpoint_button.grid(row=4, column=2, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
|
|
|
|
|
# Multi Setpoints Textbox and Button
|
|
|
|
|
self.multi_setpoints_label = customtkinter.CTkLabel(self.root, text="Sollwerteeingabe\n(Winkel;Drehmoment):", font=self.my_font)
|
|
|
|
|
self.multi_setpoints_label.grid(row=3, column=0, padx=(10, 5), pady=(10, 0), sticky="w")
|
|
|
|
|
self.multi_setpoints_label.grid(row=5, column=0, padx=(10, 5), pady=(10, 0), sticky="w")
|
|
|
|
|
|
|
|
|
|
self.multi_setpoints_text = customtkinter.CTkTextbox(self.root, font=self.my_font)
|
|
|
|
|
self.multi_setpoints_text.grid(row=3, column=1, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
self.multi_setpoints_text.grid(row=5, column=1, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
|
|
|
|
|
self.send_multi_setpoints_button = customtkinter.CTkButton(self.root, text="Sollwerte senden", command=self.send_multi_setpoints, font=self.my_font)
|
|
|
|
|
self.send_multi_setpoints_button.grid(row=3, column=2, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
self.send_multi_setpoints_button.grid(row=5, column=2, padx=(0, 10), pady=(10, 0), sticky="ew")
|
|
|
|
|
|
|
|
|
|
# Analog Control CheckBox
|
|
|
|
|
self.checkbox_var = customtkinter.IntVar()
|
|
|
|
|
self.checkbox = customtkinter.CTkCheckBox(self.root, text="Analogsteuerung", variable=self.checkbox_var, command=self.input_source_Switch, font=self.my_font)
|
|
|
|
|
self.checkbox.grid(row=4, column=0, columnspan=3, padx=(10, 10), pady=(10, 0), sticky="w")
|
|
|
|
|
self.checkbox.grid(row=6, column=0, columnspan=3, padx=(10, 10), pady=(10, 0), sticky="w")
|
|
|
|
|
|
|
|
|
|
# Tare and Demagnetize Buttons
|
|
|
|
|
self.tare_button = customtkinter.CTkButton(self.root, text="Drehwinkel tarieren", command=self.tare_angle, font=self.my_font)
|
|
|
|
|
self.tare_button.grid(row=5, column=0, padx=(10, 5), pady=(10, 0), sticky="sew")
|
|
|
|
|
self.tare_button.grid(row=7, column=0, padx=(10, 5), pady=(10, 0), sticky="sew")
|
|
|
|
|
|
|
|
|
|
self.demag_button = customtkinter.CTkButton(self.root, text="Manuelle Entmagnetisierung", command=self.demagnetize, font=self.my_font)
|
|
|
|
|
self.demag_button.grid(row=5, column=1, padx=(0, 5), pady=(10, 0), sticky="sew")
|
|
|
|
|
self.demag_button.grid(row=7, column=1, padx=(0, 5), pady=(10, 0), sticky="sew")
|
|
|
|
|
|
|
|
|
|
# Exit Button
|
|
|
|
|
self.exit_button = customtkinter.CTkButton(self.root, text="Beenden", command=self.on_closing, font=self.my_font)
|
|
|
|
|
self.exit_button.grid(row=5, column=2, padx=(0, 10), pady=(10, 0), sticky="sew")
|
|
|
|
|
self.exit_button.grid(row=7, column=2, padx=(0, 10), pady=(10, 0), sticky="sew")
|
|
|
|
|
|
|
|
|
|
#Datalogger
|
|
|
|
|
self.datalogger_button = customtkinter.CTkButton(self.root, text="Datenlogger", command=self.toggle_datalogger, font=self.my_font)
|
|
|
|
|
self.datalogger_button.grid(row=4, column=0, padx=(0, 10), pady=(10, 0), sticky="sew")
|
|
|
|
|
self.datalogger_button.grid(row=6, column=2, padx=(0, 10), pady=(10, 0), sticky="sew")
|
|
|
|
|
|
|
|
|
|
# Plot
|
|
|
|
|
self.figure, self.ax = plt.subplots()
|
|
|
|
|
self.canvas = FigureCanvasTkAgg(self.figure, self.root)
|
|
|
|
|
self.canvas.get_tk_widget().grid(row=0, column=3, rowspan=6, columnspan=4, padx=(10, 10), pady=(10, 0), sticky="nsew")
|
|
|
|
|
self.canvas.get_tk_widget().grid(row=0, column=3, rowspan=8, columnspan=4, padx=(10, 10), pady=(10, 0), sticky="nsew")
|
|
|
|
|
|
|
|
|
|
self.ax.set_title("Drehmoment-Drehwinkel-Kennlinie")
|
|
|
|
|
self.ax.set_xlabel("Winkel (°)")
|
|
|
|
|
@@ -169,26 +175,28 @@ class ArduinoGUI:
|
|
|
|
|
self.current_angle = 0
|
|
|
|
|
self.current_torque = 0
|
|
|
|
|
self.analogInput = 0
|
|
|
|
|
self.currentSetpoint = 0
|
|
|
|
|
self.currentOutput = 0
|
|
|
|
|
|
|
|
|
|
self.angle_label_var = customtkinter.StringVar()
|
|
|
|
|
self.angle_label_var.set("Drehwinkel: 0")
|
|
|
|
|
self.angle_label = customtkinter.CTkLabel(self.root, textvariable=self.angle_label_var, font=self.my_font)
|
|
|
|
|
self.angle_label.grid(row=6, column=3, padx=(10, 5), pady=(10, 0), sticky="sw")
|
|
|
|
|
self.angle_label.grid(row=8, column=3, padx=(10, 5), pady=(10, 0), sticky="sw")
|
|
|
|
|
|
|
|
|
|
self.torque_label_var = customtkinter.StringVar()
|
|
|
|
|
self.torque_label_var.set("Istwert: 0")
|
|
|
|
|
self.torque_label = customtkinter.CTkLabel(self.root, textvariable=self.torque_label_var, font=self.my_font)
|
|
|
|
|
self.torque_label.grid(row=6, column=4, padx=(10, 5), pady=(10, 0), sticky="sw")
|
|
|
|
|
self.torque_label.grid(row=8, column=4, padx=(10, 5), pady=(10, 0), sticky="sw")
|
|
|
|
|
|
|
|
|
|
self.analogread_label_var = customtkinter.StringVar()
|
|
|
|
|
self.analogread_label_var.set("Analogeingang: 0")
|
|
|
|
|
self.analogread_label = customtkinter.CTkLabel(self.root, textvariable=self.analogread_label_var, font=self.my_font)
|
|
|
|
|
self.analogread_label.grid(row=6, column=5, padx=(10, 5), pady=(10, 0), sticky="sw")
|
|
|
|
|
self.analogread_label.grid(row=8, column=5, padx=(10, 5), pady=(10, 0), sticky="sw")
|
|
|
|
|
|
|
|
|
|
self.currentSetpoint_label_var = customtkinter.StringVar()
|
|
|
|
|
self.currentSetpoint_label_var.set("Aktueller Sollwert: 0")
|
|
|
|
|
self.currentSetpoint_label = customtkinter.CTkLabel(self.root, textvariable=self.currentSetpoint_label_var, font=self.my_font)
|
|
|
|
|
self.currentSetpoint_label.grid(row=6, column=6, padx=(10, 5), pady=(10, 0), sticky="sw")
|
|
|
|
|
self.currentSetpoint_label.grid(row=8, column=6, padx=(10, 5), pady=(10, 0), sticky="sw")
|
|
|
|
|
|
|
|
|
|
self.root.grid_columnconfigure(0, weight=0)
|
|
|
|
|
self.root.grid_columnconfigure(1, weight=0)
|
|
|
|
|
@@ -202,8 +210,11 @@ class ArduinoGUI:
|
|
|
|
|
self.root.grid_rowconfigure(2, weight=0)
|
|
|
|
|
self.root.grid_rowconfigure(3, weight=0)
|
|
|
|
|
self.root.grid_rowconfigure(4, weight=0)
|
|
|
|
|
self.root.grid_rowconfigure(5, weight=1)
|
|
|
|
|
self.root.grid_rowconfigure(5, weight=0)
|
|
|
|
|
self.root.grid_rowconfigure(6, weight=0)
|
|
|
|
|
self.root.grid_rowconfigure(7, weight=1)
|
|
|
|
|
self.root.grid_rowconfigure(8, weight=0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def set_pid_parameters(self):
|
|
|
|
|
if self.arduino:
|
|
|
|
|
@@ -252,6 +263,38 @@ class ArduinoGUI:
|
|
|
|
|
messagebox.showerror("Fehler", str(e))
|
|
|
|
|
else:
|
|
|
|
|
messagebox.showwarning("Warnung", "Bitte einen COM-Port auswählen")
|
|
|
|
|
|
|
|
|
|
def connect_lsp(self):
|
|
|
|
|
try:
|
|
|
|
|
ports = serial.tools.list_ports.comports()
|
|
|
|
|
used_ports = [port.device for port in ports]
|
|
|
|
|
|
|
|
|
|
serPort = None
|
|
|
|
|
|
|
|
|
|
if os.name == 'nt':
|
|
|
|
|
for i in range(1, 257):
|
|
|
|
|
port = f'(COM{i}'
|
|
|
|
|
if (port not in used_ports) and (serPort == None):
|
|
|
|
|
serPort = port
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
for i in range(256):
|
|
|
|
|
port = f'/dev/ttyS{i}'
|
|
|
|
|
if (port not in used_ports) and (serPort == None):
|
|
|
|
|
serPort = port
|
|
|
|
|
pass
|
|
|
|
|
for i in range(256):
|
|
|
|
|
port = f'/dev/ttyUSB{i}'
|
|
|
|
|
if (port not in used_ports) and (serPort == None):
|
|
|
|
|
serPort = port
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
if serPort != None:
|
|
|
|
|
self.ser = serial.Serial(serPort, 9600, timeout=1)
|
|
|
|
|
print(F"Slave Port bereit an {serPort}")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(F"Fehler beim Öffnen des Slave Ports an {serPort}")
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def set_setpoint(self):
|
|
|
|
|
if self.arduino:
|
|
|
|
|
@@ -356,23 +399,28 @@ class ArduinoGUI:
|
|
|
|
|
if self.setpoint_flag:
|
|
|
|
|
self.arduino.write(f"s{self.setpoint:.0f},0\n".encode())
|
|
|
|
|
self.setpoint_flag = False
|
|
|
|
|
time.sleep(0.1)
|
|
|
|
|
while self.arduino.out_waiting:
|
|
|
|
|
pass
|
|
|
|
|
if self.multi_setpoints_flag:
|
|
|
|
|
self.send_interpolated_points()
|
|
|
|
|
self.multi_setpoints_flag = False
|
|
|
|
|
time.sleep(0.1)
|
|
|
|
|
while self.arduino.out_waiting:
|
|
|
|
|
pass
|
|
|
|
|
if self.tare_flag:
|
|
|
|
|
self.arduino.write(b'w\n')
|
|
|
|
|
self.tare_flag = False
|
|
|
|
|
time.sleep(0.1)
|
|
|
|
|
while self.arduino.out_waiting:
|
|
|
|
|
pass
|
|
|
|
|
if self.demag_flag:
|
|
|
|
|
self.arduino.write(b'e\n')
|
|
|
|
|
self.demag_flag = False
|
|
|
|
|
time.sleep(0.1)
|
|
|
|
|
while self.arduino.out_waiting:
|
|
|
|
|
pass
|
|
|
|
|
if self.input_source_flag:
|
|
|
|
|
self.arduino.write(b'S\n')
|
|
|
|
|
self.input_source_flag = False
|
|
|
|
|
time.sleep(0.1)
|
|
|
|
|
while self.arduino.out_waiting:
|
|
|
|
|
pass
|
|
|
|
|
if self.pid_flag:
|
|
|
|
|
self.send_pid_parameters()
|
|
|
|
|
self.pid_flag = False
|
|
|
|
|
@@ -411,19 +459,39 @@ class ArduinoGUI:
|
|
|
|
|
|
|
|
|
|
self.csv_writer.writerow([formatted_time, formatted_angle, formatted_setpoint, formatted_torque, formatted_output])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(e)
|
|
|
|
|
|
|
|
|
|
time.sleep(0.1)
|
|
|
|
|
time.sleep(0.01)
|
|
|
|
|
|
|
|
|
|
def lsp_communication_loop(self):
|
|
|
|
|
while self.running:
|
|
|
|
|
if self.ser:
|
|
|
|
|
|
|
|
|
|
if self.ser:
|
|
|
|
|
if self.ser.in_waiting:
|
|
|
|
|
command = self.ser.readline
|
|
|
|
|
self.ser.write(command)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
command = ""
|
|
|
|
|
while self.ser.in_waiting:
|
|
|
|
|
command += self.ser.read(1).decode(errors='ignore').strip()
|
|
|
|
|
if command[0] == 'a':
|
|
|
|
|
message = f"{self.current_angle};{self.current_torque};{self.analogInput};{self.currentSetpoint};{self.currentOutput}\n"
|
|
|
|
|
self.ser.write(message.encode())
|
|
|
|
|
if command[0] == 'w':
|
|
|
|
|
self.tare_angle()
|
|
|
|
|
if command[0] == 'u':
|
|
|
|
|
outCommand = F"{command}\n"
|
|
|
|
|
self.arduino.write(outCommand.encode())
|
|
|
|
|
print(self.arduino.readline())
|
|
|
|
|
time.sleep(0.1)
|
|
|
|
|
|
|
|
|
|
self.ser.read()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(e)
|
|
|
|
|
#self.ser.write(b'Hallo\n')
|
|
|
|
|
else :
|
|
|
|
|
try:
|
|
|
|
|
pass
|
|
|
|
|
self.connect_lsp()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(e)
|
|
|
|
|
|
|
|
|
|
def send_pid_parameters(self):
|
|
|
|
|
if self.selected_pid in self.pid_params:
|
|
|
|
|
@@ -441,11 +509,20 @@ class ArduinoGUI:
|
|
|
|
|
messagebox.showerror("Fehler", "Ausgewählte PID Konfiguration nicht gefunden.")
|
|
|
|
|
|
|
|
|
|
def on_closing(self):
|
|
|
|
|
self.running = False
|
|
|
|
|
if self.arduino:
|
|
|
|
|
self.arduino.close()
|
|
|
|
|
self.root.quit()
|
|
|
|
|
self.root.destroy()
|
|
|
|
|
userInput = simpledialog.askstring("Masterpasswort eingeben", "Zum Ausführen dieses Befehls ist das Masterpasswort notwendig.\n")
|
|
|
|
|
if userInput == "976638":
|
|
|
|
|
self.running = False
|
|
|
|
|
if self.arduino:
|
|
|
|
|
self.arduino.close()
|
|
|
|
|
self.communication_thread = None
|
|
|
|
|
if self.ser:
|
|
|
|
|
self.ser.close()
|
|
|
|
|
self.root.quit()
|
|
|
|
|
self.root.destroy()
|
|
|
|
|
elif userInput == None:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
messagebox.showerror("Fehler", "Es wurde ein falsches Passwort eingegeben.")
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
root = customtkinter.CTk()
|
|
|
|
|
|