From b0c5beb444bce553756212a0c21e28c1fa8c7ea4 Mon Sep 17 00:00:00 2001 From: Martin Zietz Date: Wed, 3 Feb 2021 18:26:44 +0100 Subject: [PATCH] code cleanup --- ArduinoTest.py | 29 ---------------- One_Unit_Test.py | 72 --------------------------------------- User_Interface.py | 46 ++++++++++++++----------- cage_func.py | 85 ++++++++++++++++++++--------------------------- main.py | 4 +-- 5 files changed, 64 insertions(+), 172 deletions(-) delete mode 100644 ArduinoTest.py delete mode 100644 One_Unit_Test.py diff --git a/ArduinoTest.py b/ArduinoTest.py deleted file mode 100644 index 2436f73..0000000 --- a/ArduinoTest.py +++ /dev/null @@ -1,29 +0,0 @@ -import time - -from Arduino import Arduino - -print("Searching for Arduino...") -board = Arduino() -print("Arduino found.") -board.pinMode(15, "Output") -board.pinMode(16, "Output") -board.pinMode(17, "Output") -board.digitalWrite(15, "LOW") -board.digitalWrite(16, "LOW") -board.digitalWrite(17, "LOW") - - -i = 0 -while i <= 1: - print("running: ", i) - for var in [15,16,17]: - board.digitalWrite(var, "HIGH") - time.sleep(0.5) - time.sleep(5) - for var in [15,16,17]: - board.digitalWrite(var, "LOW") - time.sleep(0.5) - time.sleep(2) - i = i + 1 - -board.close() diff --git a/One_Unit_Test.py b/One_Unit_Test.py deleted file mode 100644 index a9420bd..0000000 --- a/One_Unit_Test.py +++ /dev/null @@ -1,72 +0,0 @@ -# import platform -import time as t -import numpy as np -import globals as g -import cage_func as func -from pyps2000b import PS2000B - -# User Inputs/Configuration---------------------------------- -Test1 = 0 -Test2 = 1 -Test3 = 0 -Test4 = 0 - -# Constants: -g.COIL_CONST = np.array([38.6, 38.45, 37.9]) * 1e-9 # Coil constants [x,y,z] in T/A -g.AMBIENT_FIELD = np.array([80]) * 1e-6 # ambient magnetic field in measurement area, to be cancelled out -g.RESISTANCES = np.array([3.9, 3.9, 1]) # resistance of [x,y,z] circuits -g.MAX_WATTS = np.array([8, 8, 0]) # max. allowed power for [x,y,z] circuits - -# COM-Ports for power supply units: -XY_PORT = "COM7" -g.XY_DEVICE = PS2000B.PS2000B(XY_PORT) - -g.MAX_AMPS = np.sqrt(g.MAX_WATTS / g.RESISTANCES) -#print(g.MAX_AMPS) - - -'''def print_status(): - print("Output 1:") - func.print_status(g.X_AXIS) - print("Output 2:") - func.print_status(g.Y_AXIS)''' - - -func.set_to_zero(g.XY_DEVICE) -#print_status() -t.sleep(3) - -if Test1 == 1: - print("setting") - g.XY_DEVICE.voltage1 = 5 - g.XY_DEVICE.current1 = 1 - g.XY_DEVICE.enable_all() - t.sleep(1) - #print_status() - t.sleep(5) - print("setting to zero") - func.set_to_zero(g.XY_DEVICE) - -if Test2 == 1: - print("setting current") - g.XY_DEVICE.set_current(0.2, 0) - g.XY_DEVICE.set_voltage(5, 0) - g.XY_DEVICE.enable_all() - t.sleep(1) - #print_status() - t.sleep(5) - func.set_to_zero(g.XY_DEVICE) - -if Test4 == 1: - func.set_axis_current(g.XY_DEVICE, 0.2) - t.sleep(1) - print_status() - t.sleep(10) - func.set_to_zero(g.XY_DEVICE) - t.sleep(1) - -#print_status() - -g.XY_DEVICE.disable_all() - -#print_status() diff --git a/User_Interface.py b/User_Interface.py index b039cd0..c89986c 100644 --- a/User_Interface.py +++ b/User_Interface.py @@ -21,7 +21,7 @@ class HelmholtzGUI(Tk): self.Menu = TopMenu(self) # displays menu bar at the top - mainArea = Frame(self) + mainArea = Frame(self, padx=20, pady=20) mainArea.pack(side="top", fill="both", expand=False) mainArea.grid_rowconfigure(0, weight=1) @@ -163,7 +163,7 @@ class ManualMode(Frame): execute_button.grid(row=row_counter, column=0, padx=5) # add button for reinitialization - reinit_button = Button(self.buttons_frame, text="Reinitialize", command=func.setup_axes, + reinit_button = Button(self.buttons_frame, text="Reinitialize", command=func.setup_all, pady=5, padx=5, font=BIG_BUTTON_FONT) reinit_button.grid(row=row_counter, column=1, padx=5) @@ -179,6 +179,7 @@ class ManualMode(Frame): def page_switch(self): # function that is called when switching to this page in the UI self.modes[self.input_mode.get()][2]() # update max values, e.g. calls update_max_fields function + # noinspection PyUnusedLocal def change_mode_callback(self, var, index, mode): # not sure what the parameters are for, but they are necessary self.unit.set(self.modes[self.input_mode.get()][1]) # change unit text self.modes[self.input_mode.get()][2]() # update max values, e.g. calls update_max_fields function @@ -287,10 +288,13 @@ class Configuration(Frame): # {Key: [[x-value,y-value,z-value], unit, description, config file key, unit conversion factor]} self.entries = { "Coil Constants:": [[DoubleVar() for _ in range(3)], "\u03BCT/A", "", "coil_const", 1e6], - "Ambient Field:": [[DoubleVar() for _ in range(3)], "\u03BCT/A", "Field to be compensated", "ambient_field", 1e6], - "Resistances:": [[DoubleVar() for _ in range(3)], "\u03A9", "Resistance of coils + equipment", "resistance", 1], + "Ambient Field:": [[DoubleVar() for _ in range(3)], "\u03BCT/A", + "Field to be compensated", "ambient_field", 1e6], + "Resistances:": [[DoubleVar() for _ in range(3)], "\u03A9", + "Resistance of coils + equipment", "resistance", 1], "Max. Power:": [[DoubleVar() for _ in range(3)], "W", "Max. allowed power", "max_watts", 1], - "Max. Voltage:": [[DoubleVar() for _ in range(3)], "V", "Max. allowed voltage, must not exceed 16V!", "max_volts", 1], + "Max. Voltage:": [[DoubleVar() for _ in range(3)], "V", + "Max. allowed voltage, must not exceed 16V!", "max_volts", 1], "Arduino Pins:": [[IntVar() for _ in range(3)], "-", "Should be 15, 16, 17", "relay_pin", 1] } @@ -320,8 +324,6 @@ class Configuration(Frame): row_counter += 1 - print(self.fields) - self.update_fields() # set current values from config file Label(self, text="", pady=10).grid(row=row_counter, column=0) # add spacer @@ -335,7 +337,7 @@ class Configuration(Frame): self.buttons_frame.grid(row=row_counter, column=0, sticky=W, padx=20) # Create and place buttons - implement_button = Button(self.buttons_frame, text="Update and Reconnect", command=self.implement, + implement_button = Button(self.buttons_frame, text="Update and Reinitialize", command=self.implement, pady=5, padx=5, font=BIG_BUTTON_FONT) implement_button.grid(row=0, column=0, padx=5) restore_button = Button(self.buttons_frame, text="Restore Defaults", command=self.restore_defaults, @@ -348,9 +350,9 @@ class Configuration(Frame): def page_switch(self): # function that is called when switching to this window self.update_fields() - def restore_defaults(self): + def restore_defaults(self): # restore all default settings func.create_default_config(g.CONFIG_FILE) # overwrite config file with default - func.setup_axes() # setup everything with the defaults ToDo: take out? + func.setup_all() # setup everything with the defaults self.update_fields() # update fields in config window def update_fields(self): @@ -366,11 +368,12 @@ class Configuration(Frame): factor = self.entries[key][4] # get unit conversion factor self.entries[key][0][i].set(round(type_value * factor, 3)) # set value with correct unit conversion + # check if values are within safe limits: value_check = func.value_in_limits(g.AXIS_NAMES[i], self.entries[key][3], value) - if value_check == 'OK': - self.fields[key][i].config(background="White") - else: - self.fields[key][i].config(background="Red") + if value_check == 'OK': # value is acceptable + self.fields[key][i].config(background="White") # set colour of this entry to white + else: # value exceeds limits + self.fields[key][i].config(background="Red") # set colour of this entry to red to show problem def implement(self): # update config file with user inputs into entry fields and reinitialize @@ -395,6 +398,7 @@ class Configuration(Frame): config_key = self.entries[key][3] # handle by which value is indexed in config file value_ok = func.value_in_limits(g.AXIS_NAMES[i], config_key, value) unit = self.entries[key][1] # get unit string for error messages + axis = g.AXIS_NAMES[i] # get axis name for error messages if value_ok == 'OK': func.edit_config(g.AXIS_NAMES[i], config_key, value) # write new value to config file @@ -402,15 +406,17 @@ class Configuration(Frame): if value_ok == 'HIGH': max_value = g.default_arrays[config_key][1][i] # get max value message = "Attempted to set too high value for {s} {k}\n" \ - "{v} {unit}, max. {mv} {unit} allowed. Excessive values may damage equipment!\n" \ + "{v} {unit}, max. {mv} {unit} allowed.\n" \ + "Excessive values may damage equipment!\n" \ "Do you really want to use this value?"\ - .format(s=g.AXIS_NAMES[i], k=key, v=value*factor, mv=round(max_value*factor, 1), unit=unit) + .format(s=axis, k=key, v=value*factor, mv=round(max_value*factor, 1), unit=unit) elif value_ok == 'LOW': min_value = g.default_arrays[config_key][2][i] # get min value message = "Attempted to set too low value for {s} {k}\n" \ - "{v} {unit}, min. {mv} {unit} allowed. Excessive values may damage equipment!\n" \ + "{v} {unit}, min. {mv} {unit} allowed.\n" \ + "Excessive values may damage equipment!\n" \ "Do you really want to use this value?"\ - .format(s=g.AXIS_NAMES[i], k=key, v=value*factor, mv=round(min_value*factor, 1), unit=unit) + .format(s=axis, k=key, v=value*factor, mv=round(min_value*factor, 1), unit=unit) else: message = "Unknown case, this should not happen." # display pop-up message to ask user if he really wants the value @@ -421,7 +427,7 @@ class Configuration(Frame): func.edit_config(g.AXIS_NAMES[i], config_key, value, True) # if user chooses 'no' nothing happens, old value is kept - func.setup_axes() # reinitialize devices and program with new values + func.setup_all() # reinitialize devices and program with new values self.update_fields() # update entry fields to show new values @@ -498,7 +504,7 @@ class StatusDisplay(Frame): controller.after(500, lambda: self.update_labels(controller)) -class OutputConsole(Frame): # console to print stuff in +class OutputConsole(Frame): # console to print stuff in, similar to standard python output def __init__(self, parent): Frame.__init__(self, parent, relief=SUNKEN, bd=1) diff --git a/cage_func.py b/cage_func.py index 28b9a1a..b47510a 100644 --- a/cage_func.py +++ b/cage_func.py @@ -6,6 +6,7 @@ import time import numpy as np import serial import traceback +# noinspection PyPep8Naming import User_Interface as ui from tkinter import * from tkinter import messagebox @@ -140,7 +141,7 @@ class ArduinoCtrl(Arduino): def __init__(self): self.connected = "Unknown" self.pins = [0, 0, 0] - for i in range(3): + for i in range(3): # get correct pins from config file self.pins[i] = int(read_config(g.AXIS_NAMES[i], "relay_pin")) ui_print("\nConnecting to Arduino...") try: @@ -177,24 +178,11 @@ class ArduinoCtrl(Arduino): def read_config(section, key): # read specific value from config file - # ToDo (optional): better error handling - config_object = ConfigParser() # initialize config parser try: config_object.read(g.CONFIG_FILE) # open config file section_obj = config_object[section] # get relevant section value = section_obj[key] # get relevant value in the section - - # Value checking: ToDo: decide if we want this - '''if section in g.AXIS_NAMES: # only check numerical values - max_value = g.default_arrays[key][1][g.AXIS_NAMES.index(section)] # get max value - min_value = g.default_arrays[key][2][g.AXIS_NAMES.index(section)] - if float(value) > float(max_value): - ui_print("\nWARNING: Too high value for", section, key, "read from config file:", - value, "max.", max_value, "allowed. Excessive values may damage equipment!\n") - elif float(value) < float(min_value): - ui_print("\nWARNING: Too low value for", section, key, "read from config file:", - value, "max.", max_value, "allowed. Excessive values may damage equipment!\n")''' return value except KeyError as e: ui_print("Error while reading config file:", e) @@ -204,32 +192,30 @@ def read_config(section, key): # read specific value from config file def edit_config(section, key, value, override=False): # edit specific value in config file config_object = ConfigParser() # initialize config parser - # Check if value is within acceptable limits (set in globals.py) + # Check if value to write is within acceptable limits (set in globals.py) try: - value_ok = True + value_ok = 'OK' if section in g.AXIS_NAMES and not override: # only check numerical values and not if overridden by user - value_ok = False + value_ok = value_in_limits(section, key, value) # check if value is ok, too high or too low max_value = g.default_arrays[key][1][g.AXIS_NAMES.index(section)] # get max value min_value = g.default_arrays[key][2][g.AXIS_NAMES.index(section)] # get min value - if value > max_value: + if value_ok == 'HIGH': message = "Prevented writing too high value for {s} {k} to config file:\n" \ "{v}, max. {mv} allowed. Erroneous values may damage equipment!" \ .format(s=section, k=key, v=value, mv=max_value) raise ValueError(message) - elif value < min_value: + elif value_ok == 'LOW': message = "Prevented writing too low value for {s} {k} to config file:\n" \ "{v}, max. {mv} allowed. Erroneous values may damage equipment!" \ .format(s=section, k=key, v=value, mv=min_value) raise ValueError(message) - else: - value_ok = True - if value_ok or override: + if value_ok == 'OK' or override: # value is within limits or user has overridden config_object.read(g.CONFIG_FILE) # open config file section_obj = config_object[section] # get relevant section section_obj[key] = str(value) # get relevant value in the section - with open(g.CONFIG_FILE, 'w') as conf: # Write changes back to file + with open(g.CONFIG_FILE, 'w') as conf: # Write changes to config file config_object.write(conf) except KeyError as e: @@ -237,31 +223,32 @@ def edit_config(section, key, value, override=False): # edit specific value in raise KeyError("Could not find key", key, "in config file.") -def check_config(): +def check_config(): # check all numeric values in the config file and see if they are within safe limits ui_print("Checking config file for values exceeding limits:") i = 0 - concerns = {} + concerns = {} # initialize dictionary for found problems problem_counter = 0 for axis in g.AXIS_NAMES: - concerns[axis] = [] - for key in g.default_arrays.keys(): - value = float(read_config(axis, key)) + concerns[axis] = [] # create dictionary entry for this axis + for key in g.default_arrays.keys(): # go over entries in this axis + value = float(read_config(axis, key)) # read value to check from config file max_value = g.default_arrays[key][1][i] # get max value min_value = g.default_arrays[key][2][i] # get min value - if not min_value <= value <= max_value: - concerns[axis].append(key) + if not min_value <= value <= max_value: # value is not in safe limits + concerns[axis].append(key) # add this entry to the problem dictionary problem_counter += 1 if len(concerns[axis]) == 0: concerns[axis].append("No problems detected.") - ui_print(axis, ":", *concerns[axis]) + ui_print(axis, ":", *concerns[axis]) # print out results for this axis i += 1 - if problem_counter > 0: - messagebox.showwarning("Warning!", "Found values exceeding limits in config file. Check values in " - "configuration page to avoid equipment damage!") - g.app.show_frame(ui.Configuration) + if problem_counter > 0: # some values are not ok + # shop pup-up warning message: + messagebox.showwarning("Warning!", "Found values exceeding limits in config file. Check values " + "to ensure correct operation and avoid equipment damage!") + g.app.show_frame(ui.Configuration) # open configuration window so user can check values def create_default_config(file): # create config file from default values (stored in globals.py) @@ -307,7 +294,7 @@ def value_in_limits(axis, key, value): # Check if value is within safe limits ( return 'OK' -def setup_axes(): # creates device objects for all PSUs and sets their values +def setup_all(): # main initialization function, creates device objects for all PSUs and Arduino and sets their values # Connect to Arduino: try: if g.ARDUINO is not None: @@ -336,7 +323,7 @@ def setup_axes(): # creates device objects for all PSUs and sets their values ui_print("\nConnecting to XY Device on %s..." % g.XY_PORT) try: if g.XY_DEVICE is not None: - ui_print("closing serial connection on XY device") + ui_print("Closing serial connection on XY device") g.XY_DEVICE.serial.close() g.XY_DEVICE = None g.XY_DEVICE = PS2000B.PS2000B(g.XY_PORT) # setup PSU @@ -350,6 +337,10 @@ def setup_axes(): # creates device objects for all PSUs and sets their values ui_print("Connecting to Z Device on %s..." % g.Z_PORT) try: + if g.Z_DEVICE is not None: + ui_print("Closing serial connection on Z device") + g.Z_DEVICE.serial.close() + g.Z_DEVICE = None g.Z_DEVICE = PS2000B.PS2000B(g.Z_PORT) ui_print("Connection established.") g.Z_AXIS = Axis(2, g.Z_DEVICE, 0, g.ARDUINO.pins[2]) @@ -454,25 +445,21 @@ def set_current_vec(vector): # sets needed currents on each axis for given vect i = i + 1 -def execute_csv(filepath, printing=0): # runs through csv file containing times and desired field vectors +def execute_csv(filepath): # runs through csv file containing times and desired field vectors # csv format: time (s); xField (T); yField (T); zField (T) # decimal commas ui_print("Reading File:", filepath) file = pandas.read_csv(filepath, sep=';', decimal=',', header=0) # read csv file array = file.to_numpy() # convert csv to array - t_zero = time.time() - t_ref = t_zero + t_zero = time.time() # set reference time for start of run i = 0 - ui_print("Starting Execution...") + ui_print("Starting File Execution...") while i < len(array): t = time.time() - t_zero - if t >= array[i, 0]: - field_vec = array[i, 1:4] - ui_print("t = %0.2f s, target field vector = " % (array[i, 0]), field_vec) - set_field(field_vec) - i = i + 1 - if t - t_ref >= 1 and printing == 1: # print status every second - print_status_3() - t_ref = t + if t >= array[i, 0]: # time for this row has come + field_vec = array[i, 1:4] # extract desired field vector + # ui_print("t = %0.2f s, target field vector = " % (array[i, 0]), field_vec) + set_field(field_vec) # send field vector to test stand + i = i + 1 # next row ui_print("File executed, powering down channels.") power_down_all() # set currents and voltages to 0, set arduino pins to low diff --git a/main.py b/main.py index ad10971..ab8f0cf 100644 --- a/main.py +++ b/main.py @@ -13,7 +13,7 @@ try: # start normal operations func.create_default_config(g.CONFIG_FILE) print("Starting setup...") - func.setup_axes() # initiate communication, set handles + func.setup_all() # initiate communication, set handles print("\nOpening User Interface...") @@ -22,7 +22,7 @@ try: # start normal operations func.check_config() # check config file for values exceeding limits func.ui_print("\nStarting setup...") # do it again, so it is printed in the UI console ToDo: do it only once - func.setup_axes() # initiate communication, set handles + func.setup_all() # initiate communication, set handles g.app.mainloop() g.app = None # reset to None so nothing tries to print in the UI output