Compare commits

92 Commits

Author SHA1 Message Date
5bc9206bc0 Data.csv gelöscht 2024-08-05 22:24:19 +02:00
e010d1de02 .gitignore aktualisiert 2024-08-05 22:24:07 +02:00
5a08029bad Readme.md aktualisiert 2024-08-05 22:19:01 +02:00
3e410de064 Readme.md aktualisiert 2024-08-05 22:18:21 +02:00
dcc9ef6801 Readme.md aktualisiert 2024-08-05 22:16:45 +02:00
ee7194d439 installer.sh aktualisiert 2024-08-05 22:07:44 +02:00
1bc44a8dc8 installer.sh aktualisiert 2024-08-05 21:50:50 +02:00
aca293eb6a installer.sh erstellt um Installation zu vereinfachen. 2024-08-05 21:34:13 +02:00
88ba988c1e requirements.txt aktualisiert 2024-08-05 21:29:45 +02:00
705dcaa9a9 Abgabe der Arbeit. 2024-07-26 12:03:37 +02:00
d4533ea54c Passwort geändert auf 976638. 2024-07-26 09:47:19 +02:00
2563626def Passwortschutz eingeführt. 2024-07-25 16:39:55 +02:00
bff7daff82 PID Parameter angepasst. 2024-07-25 15:49:11 +02:00
d1f32f1719 Software sollte nun richtig beendet werden. 2024-07-23 13:45:11 +02:00
2afb5fa266 Reihenfolge der Bedienelemente umgestellt. 2024-07-23 13:32:57 +02:00
75a1f05dc8 Logo eingefügt. 2024-07-23 13:31:10 +02:00
7a077b4879 Optimierung LSP1 Kommunikation 2024-07-23 11:16:47 +02:00
3fe31f6bf0 Optimierung LSP1 Kommunikation 2024-07-23 11:15:51 +02:00
4df758ccf1 Optimierung LSP1 Kommunikation 2024-07-23 11:13:47 +02:00
b12a416110 Optimierung LSP1 Kommunikation 2024-07-23 11:09:21 +02:00
897bb59e01 Konfigurationen angepasst, Schnittstelle schneller gemacht. 2024-07-23 10:42:49 +02:00
5685eebe2c Merge pull request 'feature_lsp_com' (#9) from feature_lsp_com into main
Reviewed-on: https://gitea.msb24.duckdns.org/musabe24/t2000_gui/pulls/9
2024-07-22 12:15:25 +02:00
f2ed9c9724 typo fix 2024-07-22 12:14:50 +02:00
db17fbc1d9 Optimierung LSP Schnittstelle 2024-07-22 12:12:56 +02:00
451cd9bc68 Optimierung der LSP Schnittstelle 2024-07-22 11:55:41 +02:00
f8d788d92e Optimierung der LSP Schnittstelle 2024-07-22 11:54:12 +02:00
b1ceb7c913 Optimierung der LSP Schnittstelle 2024-07-22 11:53:03 +02:00
ac2180b041 Optimierung der LSP Schnittstelle 2024-07-22 11:51:11 +02:00
729bf18aec Optimierung der LSP Schnittstelle 2024-07-22 11:49:23 +02:00
6013acc226 Optimierung der LSP Schnittstelle 2024-07-22 11:47:42 +02:00
945e088667 Optimierung der LSP Schnittstelle 2024-07-22 11:45:38 +02:00
8269b5112f Optimierung der LSP Schnittstelle 2024-07-22 11:43:21 +02:00
582bdec6c5 Optimierung der LSP Schnittstelle 2024-07-22 11:41:57 +02:00
74c7746142 Optimierung der LSP Schnittstelle 2024-07-22 11:09:36 +02:00
1a1f228b69 Merge pull request 'feature_lsp_com' (#8) from feature_lsp_com into main
Reviewed-on: https://gitea.msb24.duckdns.org/musabe24/t2000_gui/pulls/8
2024-07-18 12:26:57 +02:00
a099481b3e LSP Kommunikation optimiert 2024-07-18 11:51:09 +02:00
ffce232d47 optimierung 2024-07-18 10:38:33 +02:00
87d012086b optimierung 2024-07-18 10:36:56 +02:00
7456e7f02a optimierung 2024-07-18 10:32:00 +02:00
9dbe3e1f5d optimierung 2024-07-18 10:29:01 +02:00
c8d8118d98 optimierung 2024-07-18 10:26:26 +02:00
4b093e86de optimierung 2024-07-18 10:22:42 +02:00
083767f626 optimierung 2024-07-18 10:20:21 +02:00
b081c33748 optimierung 2024-07-18 10:19:24 +02:00
eae3d4bae1 optimierung 2024-07-18 10:15:42 +02:00
5531952667 optimierung 2024-07-18 10:13:42 +02:00
48d347fb06 optimierung 2024-07-18 10:12:05 +02:00
be2a4a8c24 optimierung 2024-07-18 10:08:53 +02:00
8efc607e03 optimierung 2024-07-18 10:07:29 +02:00
6e717027c6 optimierung 2024-07-18 10:06:11 +02:00
8686a8ef19 lsp kommunikation optimierung 2024-07-18 10:04:00 +02:00
deb7f54bfb LSP Kommunikation verbessert. 2024-07-18 09:56:56 +02:00
678357b838 USB Kommunikation zur LSP1 eingeführt. 2024-07-17 16:38:07 +02:00
bcb45f3174 Beispiel Kennlinien eingeführt. 2024-07-17 15:22:01 +02:00
b31b5cd6c4 Merge pull request 'Datalogger eingeführt.' (#7) from feature_logging into main
Reviewed-on: https://gitea.msb24.duckdns.org/musabe24/t2000_gui/pulls/7
2024-07-17 12:04:17 +02:00
4a2692c52c Datalogger eingeführt. 2024-07-17 12:03:20 +02:00
145cb418ab Conf aktualisiert. 2024-07-16 10:21:52 +02:00
4aea4432c3 Konfiguration und Serielle Schnittstelle aktualisiert. 2024-07-15 18:39:30 +02:00
33fff0baf8 Übersetzung auf Deutsch. 2024-07-15 12:23:01 +02:00
31a0393c16 ausführbar gemacht. 2024-07-15 11:43:20 +02:00
d53b4d3080 Dateinamen angepasst. 2024-07-15 11:42:06 +02:00
eeedb5505a Komplette Umstellung auf V3. 2024-07-15 11:41:52 +02:00
1117fa90a6 Startbefehl für RPI angepasst. 2024-07-15 11:37:13 +02:00
04760db19e config angepasst 2024-07-15 11:26:04 +02:00
250d82d470 venv wird nicht mehr synchronisiert. 2024-07-15 11:22:21 +02:00
08ca590e92 venv wird nicht mehr synchronisiert. 2024-07-15 11:21:11 +02:00
960ed0ba67 gitignore angepasst. 2024-07-15 11:17:57 +02:00
bfe8d4c2a7 Reparatur der venv. 2024-07-15 11:11:46 +02:00
a7955bc775 Fullscreen eingestellt. 2024-07-15 11:01:34 +02:00
0c4926f0d5 Umstellung auf Customtkinter. 2024-07-15 09:40:40 +02:00
e0d1fc976a gitignore entfernt. 2024-07-12 10:46:49 +02:00
6e015d30a1 Umstellung auf v3 2024-07-12 10:36:16 +02:00
a92f04cfde Update auf v3 2024-07-12 10:34:05 +02:00
5cfb0c7847 start.bat für Windows angelegt. 2024-06-11 14:33:24 +02:00
31d7dc0396 Merge pull request 'issue-#4' (#6) from issue-#4 into main
Reviewed-on: https://gitea.msb24.duckdns.org/musabe24/t2000_gui/pulls/6
2024-06-11 13:32:23 +02:00
d716fe0a6f Überflüssige Zeile entfernt. 2024-06-11 13:27:21 +02:00
716563f3e0 Umstellung auf grid anstatt place, die Frames menu_frame und plot_frame eingeführt, PID Anteile werden nicht mehr angezeigt, Diagrammgröße passt sich automatisch je nach Display an. 2024-06-11 13:26:20 +02:00
1a02111482 Shell Dateien mit chmod +x ausführbar gemacht. 2024-06-11 10:35:11 +02:00
f6574b75c5 Testkommentare wieder entfern. 2024-06-11 10:34:06 +02:00
7913195a38 Testkommentare hinzugefügt. 2024-06-11 10:31:30 +02:00
8b91c9b4fa Merge branch 'main' of https://gitea.msb24.duckdns.org/musabe24/t2000_gui 2024-06-11 10:30:23 +02:00
5868cd6b15 Shell Befehle für start und update hinzugefügt. 2024-06-11 10:30:19 +02:00
dacd6b6329 self.root.overrideredirect(True) auskommentiert, da sonst keine Eingabe unter Raspbian möglich ist. 2024-06-03 10:34:22 +02:00
294747cadb Merge pull request 'issue-#1' (#5) from issue-#1 into main
Reviewed-on: https://gitea.msb24.duckdns.org/musabe24/t2000_gui/pulls/5
2024-05-24 10:51:06 +02:00
1e31b0f3fb Nun kompatibel mit Linux. 2024-05-24 10:01:13 +02:00
f8923844bb 'self.' nachgefügt. 2024-05-24 09:46:04 +02:00
58044aac0b Die GUI wird nun in Vollbildmodus gestartet und die obere Leiste wird nicht dargestellt. 2024-05-24 09:39:19 +02:00
4969ad3b14 Leere Zeile gelöcht. 2024-05-22 18:49:18 +02:00
40bd342181 Leerzeichen vor '°' eingefügt. 2024-05-22 18:47:23 +02:00
376aaa040a Die Variablen set_torque, act_torque und act_angle eingeführt; Umschaltung zwischen Drehmomentprofil und direkter Drehmomentvorgabe eingeführt; Werte auf der GUI werden nun alle 200 ms aktualisiert; Möglichkeit eingeführt, Pseudowerte für act_torque und act_angle zu setzen. 2024-05-22 18:35:25 +02:00
622ac95912 Merge branch 'main' of https://gitea.msb24.duckdns.org/musabe24/t2000_gui 2024-05-22 18:06:20 +02:00
12a9070e51 Globale Variablen für P und I Anteile eingeführt, Beisiel Koordinaten stehen nun bereits in der Textbox und auch ein Graph wird bereits erstellt, die Funktion 'on_plot_button_click()' wurde eingeführt, nun werden die eingestellten P und I Werte in die globalen Variablen abgespeichert, dies geschicht immer dann, wenn der Button 'plot_button' geklickt wird. 2024-05-22 18:06:06 +02:00
12 changed files with 671 additions and 67 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.venv/
*.csv

View File

@@ -0,0 +1,91 @@
0;10.0
1;10.7
2;11.4
3;12.0
4;12.6
5;13.2
6;13.7
7;14.1
8;14.5
9;14.8
10;14.9
11;15.0
12;15.0
13;14.9
14;14.6
15;14.3
16;13.9
17;13.5
18;12.9
19;12.3
20;11.7
21;11.0
22;10.3
23;9.7
24;9.0
25;8.3
26;7.7
27;7.1
28;6.5
29;6.1
30;5.7
31;5.4
32;5.1
33;5.0
34;5.0
35;5.1
36;5.2
37;5.5
38;5.9
39;6.3
40;6.8
41;7.4
42;8.0
43;8.6
44;9.3
45;10.0
46;10.7
47;11.4
48;12.0
49;12.6
50;13.2
51;13.7
52;14.1
53;14.5
54;14.8
55;14.9
56;15.0
57;15.0
58;14.9
59;14.6
60;14.3
61;13.9
62;13.5
63;12.9
64;12.3
65;11.7
66;11.0
67;10.3
68;9.7
69;9.0
70;8.3
71;7.7
72;7.1
73;6.5
74;6.1
75;5.7
76;5.4
77;5.1
78;5.0
79;5.0
80;5.1
81;5.2
82;5.5
83;5.9
84;6.3
85;6.8
86;7.4
87;8.0
88;8.6
89;9.3
90;10.0

View File

@@ -0,0 +1,30 @@
0;0
4.9;0
5;5
9.9;5
10;7
14.9;7
15;10
19.9;10
20;12
24.9;12
25;15
29.9;15
30;17
34.9;17
35;15
39.9;15
40;12
44.9;12
45;10
49.9;10
50;7
54.9;7
55;5
59.9;5
60;0
69.9;0
70;15
79.9;15
80;0
90;0

View File

@@ -1 +1,5 @@
# GUI zur T2000
# GUI zur T2000
## Installation unter Linux
~~~
curl -s https://gitea.msb24.duckdns.org/musabe24/t2000_gui/raw/branch/main/installer.sh | bash
~~~

10
conf.txt Normal file
View File

@@ -0,0 +1,10 @@
227C-024-15{
Kp:0.11
Ki:0.09
Kd:0.00
}
328CS-024-10{
Kp:0.3
Ki:1.0
Kd:0.00
}

7
installer.sh Normal file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
sudo apt-get install python3-tk -y
cd ~
git clone https://gitea.msb24.duckdns.org/musabe24/t2000_gui.git
cd t2000_gui
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt

576
main.py
View File

@@ -1,87 +1,531 @@
import tkinter as tk
from tkinter import messagebox
from tkinter import ttk, messagebox, PhotoImage, simpledialog
import customtkinter
customtkinter.set_appearance_mode("light")
customtkinter.set_default_color_theme("blue")
import serial
import serial.tools.list_ports
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import threading
import time
import numpy as np
import csv
import os
from PIL import Image, ImageTk
class T2000ErdemGUI:
class ArduinoGUI:
def __init__(self, root):
self.my_font = customtkinter.CTkFont(family="Calibri", size=15)
self.root = root
self.root.title("T2000 Erdem")
self.root.geometry("1024x600")
self.root.title("PRG 342 GUI")
self.root.attributes('-fullscreen', True) # Setzt das Fenster in den Vollbildmodus
# P- und I-Anteil Input Felder
tk.Label(self.root, text="P-Anteil:").place(x=10, y=10)
self.p_value = tk.DoubleVar()
tk.Entry(self.root, textvariable=self.p_value).place(x=100, y=10)
self.ser = None
tk.Label(self.root, text="I-Anteil:").place(x=10, y=50)
self.i_value = tk.DoubleVar()
tk.Entry(self.root, textvariable=self.i_value).place(x=100, y=50)
self.arduino = None
self.ports = list(serial.tools.list_ports.comports())
self.running = True
self.current_point = None
self.setpoints = []
# Eingabefelder für Koordinaten
tk.Label(self.root, text="Koordinaten der Drehmoment-Drehwinkel-Kennlinie:").place(x=10, y=90)
self.coordinates_text = tk.Text(self.root, height=5, width=20)
self.coordinates_text.place(x=20, y=110)
# Flags for user actions
self.setpoint_flag = False
self.multi_setpoints_flag = False
self.tare_flag = False
self.demag_flag = False
self.input_source_flag = False
self.pid_flag = False # Flag for sending PID parameters
# Eingabefeld für direkte Drehmomentvorgabe
tk.Label(self.root, text="Soll-Drehmoment in Nm:").place(x=10, y=220)
self.torque_value = tk.DoubleVar()
tk.Entry(self.root, textvariable=self.torque_value).place(x=200, y=220)
self.pid_params = {}
self.selected_pid = None
# Anzeige für aktuellen Drehwinkel und Drehmoment
tk.Label(self.root, text="Aktueller Drehwinkel:").place(x=10, y=260)
self.current_angle = tk.Label(self.root, text="0" + "°")
self.current_angle.place(x=200, y=260)
self.create_widgets()
tk.Label(self.root, text="Aktuelles Drehmoment:").place(x=10, y=300)
self.current_torque = tk.Label(self.root, text="0" + " Nm")
self.current_torque.place(x=200, y=300)
self.load_configurations()
# Button zum Schließen der Anwendung
self.close_button = tk.Button(self.root, text="Beenden", command=self.close_application)
self.close_button.place(x=300, y=560)
# Start the communication thread
self.communication_thread = threading.Thread(target=self.communication_loop)
self.communication_thread.start()
# Button zur Erstellung des Diagramms
self.plot_button = tk.Button(self.root, text="Eingaben übernehmen", command=self.create_diagram)
self.plot_button.place(x=10, y=560)
self.logging = False
self.start_time = None
self.log_file = None
self.csv_writer = None
# Diagramm
self.figure = Figure(figsize=(6,6), dpi=100)
self.plot = self.figure.add_subplot(111)
self.plot.set_xlim(0, 90)
self.plot.set_ylim(ymin=0)
self.plot.set_xlabel('Drehwinkel in Grad')
self.plot.set_ylabel('Drehmoment in Nm')
def toggle_datalogger(self):
if not self.logging:
self.start_logging()
else:
self.stop_logging()
def start_logging(self):
self.logging = True
self.start_time = time.time()
self.log_file = open("Data.csv", mode='w', newline='', encoding='utf-8')
self.csv_writer = csv.writer(self.log_file, delimiter='\t')
# PID parameters under each other
self.csv_writer.writerow(["Kp", f"{self.pid_params[self.selected_pid]['Kp']:.3f}".replace('.', ',')])
self.csv_writer.writerow(["Ki", f"{self.pid_params[self.selected_pid]['Ki']:.3f}".replace('.', ',')])
self.csv_writer.writerow(["Kd", f"{self.pid_params[self.selected_pid]['Kd']:.3f}".replace('.', ',')])
self.csv_writer.writerow(["Zeit in s", "Winkel in Grad", "Sollwert in Nm", "Istwert in Nm", "Erregerspannung in V"])
messagebox.showinfo("Info", "Datalogging gestartet")
def stop_logging(self):
self.logging = False
if self.log_file:
self.log_file.close()
messagebox.showinfo("Info", "Datalogging gestoppt")
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=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=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=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=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=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=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=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=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=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=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=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=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=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=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=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=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=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().place(x=424, y=0)
self.canvas.get_tk_widget().grid(row=0, column=3, rowspan=8, columnspan=4, padx=(10, 10), pady=(10, 0), sticky="nsew")
def close_application(self):
if messagebox.askokcancel("Beenden", "Möchten Sie die Anwendung wirklich beenden?"):
self.root.quit()
self.ax.set_title("Drehmoment-Drehwinkel-Kennlinie")
self.ax.set_xlabel("Winkel (°)")
self.ax.set_ylabel("Drehmoment (Nm)")
self.ax.set_xlim(0, 90)
self.ax.set_ylim(0, 50)
def create_diagram(self):
self.plot.clear()
self.plot.set_xlim(0, 90)
self.plot.set_xlabel('Drehwinkel in Grad')
self.plot.set_ylabel('Drehmoment in Nm')
coordinates = self.coordinates_text.get("1.0", tk.END).strip().split("\n")
x_coords, y_coords = [], []
for coord in coordinates:
x, y = map(float, coord.split(','))
x_coords.append(x)
y_coords.append(y)
self.plot.plot(x_coords, y_coords, marker='o', linestyle='-')
self.plot.set_ylim(bottom=0)
# Current readings labels
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=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=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=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=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)
self.root.grid_columnconfigure(2, weight=0)
self.root.grid_columnconfigure(3, weight=1)
self.root.grid_columnconfigure(4, weight=1)
self.root.grid_columnconfigure(5, weight=1)
self.root.grid_columnconfigure(6, weight=1)
self.root.grid_rowconfigure(0, weight=0)
self.root.grid_rowconfigure(1, weight=0)
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=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:
self.selected_pid = self.config_combobox.get()
if self.selected_pid in self.pid_params:
self.pid_flag = True
else:
messagebox.showerror("Fehler", "Ausgewählte PID Konfiguration nicht gefunden.")
else:
messagebox.showwarning("Warnung", "Keine Verbindung zum Arduino hergestellt.")
def load_configurations(self):
try:
with open("conf.txt", "r") as file:
config_name = None
for line in file:
line = line.strip()
if line.startswith("#") or not line:
continue
if "{" in line:
config_name = line.split("{")[0].strip()
self.pid_params[config_name] = {"Kp": 0.0, "Ki": 0.0, "Kd": 0.0}
elif "}" in line:
config_name = None
else:
if config_name:
key, value = line.split(":")
key = key.strip()
value = round(float(value.strip()), 3)
self.pid_params[config_name][key] = value
self.config_combobox.configure(values=list(self.pid_params.keys()))
if self.pid_params:
self.config_combobox.set(list(self.pid_params.keys())[0])
self.selected_pid = list(self.pid_params.keys())[0]
except Exception as e:
messagebox.showerror("Fehler", f"Fehler beim Laden der Konfigurationen: {e}")
def connect_arduino(self):
com_port = self.combobox_value.get()
if com_port:
try:
self.arduino = serial.Serial(com_port, 19200, timeout=1)
messagebox.showinfo("Info", "Arduino verbunden an " + com_port)
except Exception as e:
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:
try:
self.setpoint = float(self.setpoint_entry.get()) * 1000
self.setpoint_flag = True
except ValueError:
messagebox.showerror("Fehler", "Ungültiger Setpoint.")
else:
messagebox.showwarning("Warnung", "Keine Verbindung zum Arduino hergestellt")
def send_multi_setpoints(self):
if self.arduino:
setpoints = self.multi_setpoints_text.get("1.0", tk.END).strip().split("\n")
coordinates = []
for point in setpoints:
try:
angle, torque = map(float, point.split(";"))
coordinates.append((angle, torque))
except ValueError:
messagebox.showerror("Fehler", f"Ungültige Eingabe: {point}")
return
coordinates.sort()
self.setpoints = coordinates
self.plot_coordinates(coordinates)
self.multi_setpoints_flag = True
else:
messagebox.showwarning("Warnung", "Keine Verbindung zum Arduino hergestellt")
def plot_coordinates(self, coordinates):
angles, torques = zip(*coordinates)
self.ax.clear()
self.ax.plot(angles, torques, 'bo-', label="Setpoints")
self.ax.set_title("Drehmoment-Drehwinkel-Kennlinie")
self.ax.set_xlabel("Winkel in °")
self.ax.set_ylabel("Drehmoment in Nm")
self.ax.set_xlim(0, 90)
self.ax.set_ylim(0, 50)
self.ax.legend()
self.canvas.draw()
def update_current_values(self, angle, torque):
self.current_angle.config(text=str(angle))
self.current_torque.config(text=str(torque))
def interpolate_coordinates(self, coordinates):
interpolated_points = []
for i in range(len(coordinates) - 1):
start_angle, start_torque = coordinates[i]
end_angle, end_torque = coordinates[i + 1]
num_points = int((end_angle - start_angle) * 2)
angles = np.linspace(start_angle, end_angle, num_points + 1)
torques = np.linspace(start_torque, end_torque, num_points + 1)
interpolated_points.extend(zip(angles, torques))
# Anwendung starten
root = tk.Tk()
app = T2000ErdemGUI(root)
root.mainloop()
full_interpolated_points = [(angle, 0) for angle in np.arange(0, 90.5, 0.5)]
for angle, torque in interpolated_points:
index = int(angle * 2)
full_interpolated_points[index] = (angle, torque)
return full_interpolated_points
def send_interpolated_points(self):
if self.arduino:
setpoints_command = "u"
for angle, torque in self.setpoints:
torque_mnm = torque * 1000
setpoints_command += f"{int(angle * 2)},{torque_mnm:.1f};"
setpoints_command = setpoints_command.rstrip(';') + "u\n"
self.arduino.write(setpoints_command.encode())
timeout_ctr = time.time()
while(self.arduino.in_waiting == 0 and time.time() - timeout_ctr < 2):
pass
try:
print(self.arduino.readline())
#print(self.arduino.read_all())
except Exception as e:
print(e)
def tare_angle(self):
if self.arduino:
self.tare_flag = True
else:
messagebox.showwarning("Warnung", "Keine Verbindung zum Arduino hergestellt")
def demagnetize(self):
if self.arduino:
self.demag_flag = True
else:
messagebox.showwarning("Warnung", "Keine Verbindung zum Arduino hergestellt")
def input_source_Switch(self):
if self.arduino:
self.input_source_flag = True
else:
messagebox.showwarning("Warnung", "Keine Verbindung zum Arduino hergestellt")
def communication_loop(self):
while self.running:
if self.arduino:
self.arduino.read_all()
if self.setpoint_flag:
self.arduino.write(f"s{self.setpoint:.0f},0\n".encode())
self.setpoint_flag = False
while self.arduino.out_waiting:
pass
if self.multi_setpoints_flag:
self.send_interpolated_points()
self.multi_setpoints_flag = False
while self.arduino.out_waiting:
pass
if self.tare_flag:
self.arduino.write(b'w\n')
self.tare_flag = False
while self.arduino.out_waiting:
pass
if self.demag_flag:
self.arduino.write(b'e\n')
self.demag_flag = False
while self.arduino.out_waiting:
pass
if self.input_source_flag:
self.arduino.write(b'S\n')
self.input_source_flag = False
while self.arduino.out_waiting:
pass
if self.pid_flag:
self.send_pid_parameters()
self.pid_flag = False
self.arduino.write(b'a\n')
timeout_ctr = time.time()
while(self.arduino.in_waiting == 0 and time.time() - timeout_ctr < 2):
pass
try:
data = self.arduino.readline().decode(errors='ignore').strip().split(";")
if len(data) >= 4 and all(data): # Ensure all fields are not empty
self.current_angle = float(data[0]) / 1000 if data[0] else 0
self.current_torque = float(data[1]) / 1000 if data[1] else 0
self.analogInput = float(data[2]) / 1000 if data[2] else 0
self.currentSetpoint = float(data[3]) / 1000 if data[3] else 0
self.currentOutput = float(data[4]) * 0.006349206 if data[4] else 0
self.angle_label_var.set(f"Drehwinkel: {self.current_angle:.1f} °")
self.torque_label_var.set(f"Istwert: {self.current_torque:.1f} Nm")
self.analogread_label_var.set(f"Analogeingang: {self.analogInput:.1f} V")
self.currentSetpoint_label_var.set(f"Aktueller Sollwert: {self.currentSetpoint:.1f} Nm")
if self.current_point is not None:
self.current_point.remove()
self.current_point, = self.ax.plot([self.current_angle], [self.current_torque], 'ro')
self.canvas.draw()
if self.logging:
elapsed_time = time.time() - self.start_time
formatted_time = f"{elapsed_time:.3f}".replace('.', ',')
formatted_angle = f"{self.current_angle:.3f}".replace('.', ',')
formatted_setpoint = f"{self.currentSetpoint:.3f}".replace('.', ',')
formatted_torque = f"{self.current_torque:.3f}".replace('.', ',')
formatted_output = f"{self.currentOutput:.3f}".replace('.', ',')
self.csv_writer.writerow([formatted_time, formatted_angle, formatted_setpoint, formatted_torque, formatted_output])
except Exception as e:
print(e)
time.sleep(0.01)
if self.ser:
if self.ser.in_waiting:
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:
pid_values = self.pid_params[self.selected_pid]
kp = f"{pid_values['Kp']:.3f}"
ki = f"{pid_values['Ki']:.3f}"
kd = f"{pid_values['Kd']:.3f}"
self.arduino.write(f"p{kp}\n".encode())
time.sleep(0.1)
self.arduino.write(f"i{ki}\n".encode())
time.sleep(0.1)
self.arduino.write(f"d{kd}\n".encode())
messagebox.showinfo("Info", f"PID-Parameter gesendet: Kp={kp}, Ki={ki}, Kd={kd}")
else:
messagebox.showerror("Fehler", "Ausgewählte PID Konfiguration nicht gefunden.")
def on_closing(self):
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()
app = ArduinoGUI(root)
root.protocol("WM_DELETE_WINDOW", app.on_closing)
root.mainloop()

6
requirements.txt Normal file
View File

@@ -0,0 +1,6 @@
tk==0.1.0
customtkinter==5.2.2
pyserial==3.5
matplotlib==3.9.0
numpy==2.0.1
Pillow==10.4.0

BIN
src/logo1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

2
start_linux.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
.venv/bin/python main.py

3
start_windows.bat Normal file
View File

@@ -0,0 +1,3 @@
@ECHO OFF
call ./.venv/Scripts/activate.bat
python main.py

5
update.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
git checkout main
git reset --hard
git fetch
git reset --hard origin/main