diff --git a/User_Interface.py b/User_Interface.py index 233bfe1..f6fd8ae 100644 --- a/User_Interface.py +++ b/User_Interface.py @@ -3,6 +3,7 @@ from tkinter import ttk import settings as g import cage_func as func import random as rand +import numpy as np NORM_FONT = () SUB_HEADER_FONT = ("Arial", 9, "bold") @@ -45,7 +46,6 @@ class HelmholtzGUI(Tk): class TopMenu: def __init__(self, window): - print("menu called") menu = Menu(window) window.config(menu=menu) @@ -53,16 +53,15 @@ class TopMenu: menu.add_cascade(label="Mode", menu=ModeSelector) ModeSelector.add_command(label="Static Manual Input", command=lambda: self.manual_mode(window)) - def manual_mode(self, window): - print("Switching to static manual mode") + @staticmethod + def manual_mode(window): window.show_frame(ManualMode) -class TestFrame(Frame): +class TestFrame(Frame): # ToDo: remove def __init__(self, parent, controller): Frame.__init__(self, parent) - print("TestFrame called") one = Label(self, text="One", bg="red") one.pack(fill=X) @@ -73,6 +72,9 @@ class TestFrame(Frame): class ManualMode(Frame): + # ToDo: Display maximum values + # ToDo: Add option to cancel ambient field + # ToDo: Add buttons to safe and set to 0 def __init__(self, parent, controller): Frame.__init__(self, parent) @@ -88,11 +90,15 @@ class ManualMode(Frame): dropdown_frame.grid_columnconfigure(ALL, weight=1) dropdown_frame.grid(row=row_counter, column=0) self.input_mode = StringVar() - self.modes = {"Raw Current": self.input_raw_current, - "Signed Current": self.input_signed_current, - "Magnetic Field": self.input_field} + # make dictionary with information on all modes. + # content: [function to call on button press, unit text to be displayed] + self.modes = {"Magnetic Field": [self.execute_field, "\u03BCT"], + "Current": [self.execute_current, "A"]} + # "Raw Current": [self.input_raw_current, "A"]} ToDo (optional): make functions for this + self.unit = StringVar() + default_mode = list(self.modes.keys())[0] - input_mode_selector = ttk.OptionMenu(dropdown_frame, self.input_mode, list(self.modes.keys())[2], *self.modes.keys()) + input_mode_selector = ttk.OptionMenu(dropdown_frame, self.input_mode, default_mode, *self.modes.keys()) input_mode_selector.grid(row=0, column=1, sticky=W) # place dropdown on the grid dropdown_frame.grid_columnconfigure(1, minsize=115) # set size of column with dropdown to keep it from moving @@ -106,16 +112,20 @@ class ManualMode(Frame): self.entries_frame = Frame(self) self.entries_frame.grid_rowconfigure(ALL, weight=1) self.entries_frame.grid_columnconfigure(ALL, weight=1) + self.entries_frame.grid_columnconfigure(2, weight=1, minsize=20) self.entries_frame.grid(row=row_counter, column=0) entry_texts = ["X-Axis:", "Y-Axis:", "Z-Axis:"] - entry_vars = [StringVar for _ in range(len(entry_texts))] + self.entry_vars = [StringVar() for _ in range(len(entry_texts))] row = 0 for text in entry_texts: - field = ttk.Entry(self.entries_frame, textvariable=entry_vars[row]) + field = ttk.Entry(self.entries_frame, textvariable=self.entry_vars[row]) + self.entry_vars[row].set(0) field.grid(row=row, column=1, sticky=W) - label = Label(self.entries_frame, text=text, padx=5, pady=10) - label.grid(row=row, column=0, sticky=W) + axis_label = Label(self.entries_frame, text=text, padx=5, pady=10) + axis_label.grid(row=row, column=0, sticky=W) + unit_label = Label(self.entries_frame, textvariable=self.unit) + unit_label.grid(row=row, column=2, sticky=W) row = row + 1 row_counter = row_counter + 1 @@ -123,7 +133,7 @@ class ManualMode(Frame): # Setup execute button Label(self, text="").grid(row=row_counter, column=0) # add spacer row_counter = row_counter + 1 - execute_button = Button(self, text="Execute!", command=lambda: self.execute(), + execute_button = Button(self, text="Execute!", command=self.execute, pady=5, padx=5, font=BIG_BUTTON_FONT) execute_button.grid(row=row_counter, column=0, columnspan=2) @@ -132,40 +142,36 @@ class ManualMode(Frame): Label(self, text="", pady=10).grid(row=row_counter, column=0) self.input_mode.trace_add('write', self.change_mode_callback) # call mode change function on dropdown change - self.input_field() # call up default mode at the start + self.input_mode.set(default_mode) # call up default mode at the start - def change_mode_callback(self, var, index, mode): - self.clear_widgets() - function_to_call = self.modes[self.input_mode.get()] - function_to_call() - print(self.entries_frame.grid_slaves(row=1, column=2)) - - def clear_widgets(self): - for col in [2, 3]: - for row in range(3): - try: - widget = self.entries_frame.grid_slaves(row=row, column=col)[0] - widget.grid_forget() - except IndexError: - pass - - def input_field(self): - for row in range(3): - label = Label(self.entries_frame, text="\u03BCT", padx=5, pady=10) - label.grid(row=row, column=2, sticky=W) - - def input_raw_current(self): - for row in range(3): - label = Label(self.entries_frame, text="A", padx=5, pady=10) - label.grid(row=row, column=2, sticky=W) - - def input_signed_current(self): - for row in range(3): - label = Label(self.entries_frame, text="A", padx=5, pady=10) - label.grid(row=row, column=2, sticky=W) + 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 def execute(self): - print("executing", self.input_mode.get()) + function_to_call = self.modes[self.input_mode.get()][0] # get function of appropriate mode + vector = np.array([0, 0, 0]) + i = 0 + for var in self.entry_vars: + vector[i] = float(var.get()) + i = i + 1 + print(vector) + function_to_call(vector) # call function + + @staticmethod + def execute_field(vector): + print("field executing") + try: + func.set_field_simple(vector*1e-6) # ToDo: change to set_field + except ValueError as e: + print(e) + + @staticmethod + def execute_current(vector): + print("current executing") + try: + func.set_current_vec(vector) + except ValueError as e: + print(e) class StatusDisplay(Frame): @@ -212,11 +218,12 @@ class StatusDisplay(Frame): for row in range(self.rowNo): # place row entries LabelCol[row].grid(row=row + rowCounter, column=col, sticky="nsew") col = col + 1 - rowCounter = rowCounter + self.rowNo # increase row counter to place future stuff below this + # rowCounter = rowCounter + self.rowNo # increase row counter to place future stuff below this self.update_labels(controller) def update_labels(self, controller): + # ToDo: do this with a dictionary i = 0 for axis in g.AXES: if axis.device is not None: diff --git a/cage_func.py b/cage_func.py index f0802fd..f51f669 100644 --- a/cage_func.py +++ b/cage_func.py @@ -98,18 +98,21 @@ class Axis: channel = self.channel ardPin = self.ardPin self.target_current = value - if abs(value) > self.max_amps: # prevent excessive currents - shut_down_all() # safe all devices - raise ValueError("Invalid current value. Tried %0.2fA, max. %0.2fA allowed" % (value, self.max_amps)) - elif value >= 0: # switch polarity as needed - g.ARDUINO.digitalWrite(ardPin, "LOW") - elif value < 0: - g.ARDUINO.digitalWrite(ardPin, "HIGH") + if self.connected == "Connected": + if abs(value) > self.max_amps: # prevent excessive currents + shut_down_all() # safe all devices # ToDo: safe this axis only, not full shutdown + raise ValueError("Invalid current value. Tried %0.2fA, max. %0.2fA allowed" % (value, self.max_amps)) + elif value >= 0: # switch polarity as needed + g.ARDUINO.digitalWrite(ardPin, "LOW") + elif value < 0: + g.ARDUINO.digitalWrite(ardPin, "HIGH") + else: + raise Exception("This should be impossible.") + device.set_current(abs(value), channel) + maxVoltage = min(max(1.1 * self.max_amps * self.resistance, 8), self.max_volts) # limit voltage + device.set_voltage(maxVoltage) else: - raise Exception("This should be impossible.") - device.set_current(abs(value), channel) - maxVoltage = min(max(1.1 * self.max_amps * self.resistance, 8), self.max_volts) # limit voltage - device.set_voltage(maxVoltage) + print(self.name, "not connected, can't set current.") def set_field_simple(self, value): # forms magnetic field as specified by value, w/o cancelling ambient field self.target_field = value @@ -258,9 +261,11 @@ def set_field(vector): # forms magnetic field as specified by vector, corrected g.AXES[i].set_field(vector[i]) -def set_current_vec(i_vec): # sets needed currents on each axis for given vector - for i in [0, 1, 2]: - g.AXES[i].set_signed_current(i_vec[i]) +def set_current_vec(vector): # sets needed currents on each axis for given vector + i = 0 + for axis in g.AXES: + axis.set_signed_current(vector[i]) + i = i + 1 def execute_csv(filepath, printing=0): # runs through csv file containing times and desired field vectors diff --git a/settings.py b/settings.py index 12b9839..be21673 100644 --- a/settings.py +++ b/settings.py @@ -10,7 +10,7 @@ global Z_AXIS AXES = [] # list containing [X_AXIS, Y_AXIS, Z_AXIS] # Constants: -COIL_CONST = np.array([38.6, 38.45, 37.9]) * 1e-9 # Coil constants [x,y,z] in T/A +COIL_CONST = np.array([38.6, 38.45, 37.9]) * 1e-6 # Coil constants [x,y,z] in T/A AMBIENT_FIELD = np.array([80, 80, 80]) * 1e-6 # ambient magnetic field in measurement area, to be cancelled out RESISTANCES = np.array([3.9, 1, 1]) # resistance of [x,y,z] circuits MAX_WATTS = np.array([8, 0, 0]) # max. allowed power for [x,y,z] circuits