129 lines
4.4 KiB
Python
129 lines
4.4 KiB
Python
import time
|
|
import datetime
|
|
import pyads
|
|
import matplotlib.pyplot as plt
|
|
import matplotlib.dates as mdates
|
|
|
|
# ==========================================
|
|
# KONFIGURATION
|
|
# ==========================================
|
|
AMS_NET_ID = "5.17.17.136.1.1"
|
|
PLC_PORT = 851 # Standard SPS-Port in TwinCAT 3
|
|
|
|
# SPS-Symbole
|
|
TEMP_SYMBOL = 'MAIN.temperature' # Typ: INT
|
|
BRAKE_SYMBOL = 'MAIN.brakeManualValue' # Typ: BOOL
|
|
|
|
LOG_FILENAME = "temperature_and_brake_log_underload_50mm_s_30_s_cycle.csv"
|
|
READ_INTERVAL = 1.0 # Ausleseintervall in Sekunden
|
|
|
|
# ==========================================
|
|
# SETUP LOGDATEI & PLOT
|
|
# ==========================================
|
|
try:
|
|
with open(LOG_FILENAME, 'a', encoding='utf-8') as f:
|
|
if f.tell() == 0:
|
|
f.write("Zeitstempel;Temperatur_C;Bremse_Manuell\n")
|
|
except IOError as e:
|
|
print(f"Fehler beim Erstellen der Log-Datei: {e}")
|
|
|
|
# Matplotlib Live-Plot vorbereiten
|
|
plt.ion()
|
|
fig, ax = plt.subplots(figsize=(10, 5))
|
|
|
|
timestamps = []
|
|
temp_values = []
|
|
|
|
line, = ax.plot([], [], 'r-o', linewidth=2, label="Temperatur (°C)")
|
|
ax.set_title("TwinCAT SPS Überwachung: Temperatur & Bremse")
|
|
ax.set_xlabel("Uhrzeit")
|
|
ax.set_ylabel("Temperatur [°C]")
|
|
ax.grid(True)
|
|
|
|
# Textanzeige für den aktuellen Bremsenstatus im Diagramm
|
|
status_text = ax.text(0.98, 0.92, '', transform=ax.transAxes,
|
|
ha='right', va='top', fontsize=11, fontweight='bold',
|
|
bbox=dict(boxstyle='round,pad=0.5', facecolor='white', alpha=0.8))
|
|
|
|
ax.legend(loc="upper left")
|
|
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))
|
|
fig.autofmt_xdate()
|
|
|
|
# ==========================================
|
|
# HAUPTPROGRAMM
|
|
# ==========================================
|
|
def main():
|
|
plc = pyads.Connection(AMS_NET_ID, PLC_PORT)
|
|
|
|
try:
|
|
plc.open()
|
|
print(f"Verbindung zu TwinCAT PLC ({AMS_NET_ID}:{PLC_PORT}) erfolgreich hergestellt.")
|
|
print(f"Lese Symbole:\n - '{TEMP_SYMBOL}' (INT)\n - '{BRAKE_SYMBOL}' (BOOL)...")
|
|
print("Schließe das Plot-Fenster oder drücke Strg+C zum Beenden.\n")
|
|
|
|
print(f"{'Zeitstempel':<20} | {'Temperatur (°C)':<15} | {'Bremse (0/1)':<15}")
|
|
print("-" * 56)
|
|
|
|
while plt.fignum_exists(fig.number):
|
|
loop_start = time.time()
|
|
now = datetime.datetime.now()
|
|
time_str = now.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
try:
|
|
# 1. Messwerte aus der SPS auslesen
|
|
raw_temp = plc.read_by_name(TEMP_SYMBOL, pyads.PLCTYPE_INT)
|
|
temp_val = float(raw_temp/10.0)
|
|
|
|
brake_val = plc.read_by_name(BRAKE_SYMBOL, pyads.PLCTYPE_BOOL)
|
|
brake_int = 1 if brake_val else 0 # Konvertierung Bool zu 0 / 1
|
|
|
|
# 2. In Log-Datei schreiben (speichert 0 oder 1)
|
|
with open(LOG_FILENAME, 'a', encoding='utf-8') as f:
|
|
f.write(f"{time_str};{temp_val:.2f};{brake_int}\n")
|
|
|
|
# 3. Konsolenausgabe
|
|
print(f"{time_str:<20} | {temp_val:<15.2f} | {brake_int:<15}")
|
|
|
|
# 4. Daten für Plot aufbereiten
|
|
timestamps.append(now)
|
|
temp_values.append(temp_val)
|
|
|
|
# if len(timestamps) > 60:
|
|
# timestamps.pop(0)
|
|
# temp_values.pop(0)
|
|
|
|
# Plot-Daten aktualisieren
|
|
line.set_xdata(timestamps)
|
|
line.set_ydata(temp_values)
|
|
|
|
# Status-Anzeige im Plot
|
|
if brake_val:
|
|
status_text.set_text("Bremse: GELÖST (1)")
|
|
status_text.set_color('green')
|
|
else:
|
|
status_text.set_text("Bremse: EINGEFALLEN (0)")
|
|
status_text.set_color('red')
|
|
|
|
ax.relim()
|
|
ax.autoscale_view()
|
|
fig.canvas.draw()
|
|
fig.canvas.flush_events()
|
|
|
|
except pyads.ADSError as err:
|
|
print(f"[{time_str}] ADS Fehler beim Lesen: {err}")
|
|
|
|
elapsed = time.time() - loop_start
|
|
sleep_time = max(0.0, READ_INTERVAL - elapsed)
|
|
time.sleep(sleep_time)
|
|
|
|
except KeyboardInterrupt:
|
|
print("\nMessung durch Benutzer abgebrochen.")
|
|
except Exception as e:
|
|
print(f"\nUnerwarteter Fehler: {e}")
|
|
finally:
|
|
plc.close()
|
|
plt.ioff()
|
|
print(f"ADS-Verbindung geschlossen. Daten gespeichert in '{LOG_FILENAME}'.")
|
|
|
|
if __name__ == '__main__':
|
|
main() |