diff --git a/User_Interface.py b/User_Interface.py index 19a8dec..d48af3e 100644 --- a/User_Interface.py +++ b/User_Interface.py @@ -86,8 +86,8 @@ class ManualMode(Frame): self.input_mode = StringVar() # 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"]} + self.modes = {"Magnetic Field": [self.execute_field, "\u03BCT", self.update_max_fields], + "Current": [self.execute_current, "A", self.update_max_currents]} # "Raw Current": [self.input_raw_current, "A"]} ToDo (optional): make functions for this self.unit = StringVar() default_mode = list(self.modes.keys())[0] @@ -107,10 +107,12 @@ class ManualMode(Frame): 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_columnconfigure(3, weight=1, minsize=110) self.entries_frame.grid(row=row_counter, column=0) entry_texts = ["X-Axis:", "Y-Axis:", "Z-Axis:"] - self.entry_vars = [StringVar() for _ in range(len(entry_texts))] + self.entry_vars = [StringVar() for _ in range(3)] + self.max_value_vars = [StringVar() for _ in range(3)] row = 0 for text in entry_texts: field = ttk.Entry(self.entries_frame, textvariable=self.entry_vars[row]) @@ -120,19 +122,33 @@ class ManualMode(Frame): 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) + max_value_label = Label(self.entries_frame, textvariable=self.max_value_vars[row]) + max_value_label.grid(row=row, column=3, sticky=W) row = row + 1 - row_counter = row_counter + 1 + row_counter += 1 - # Setup execute button + # setup checkbox for compensating ambient field + checkbox_frame = Frame(self, padx=20) + checkbox_frame.grid(row=row_counter, column=0, sticky=W) + + self.compensate = IntVar(value=1) + self.compensate_checkbox = Checkbutton(checkbox_frame, text="Compensate ambient field", + variable=self.compensate, onvalue=1, offvalue=0) + self.compensate_checkbox.pack(side="left") + + row_counter += 1 + + # Setup buttons self.buttons_frame = Frame(self) self.buttons_frame.grid_rowconfigure(ALL, weight=1) self.buttons_frame.grid_columnconfigure(ALL, weight=1) self.buttons_frame.grid_columnconfigure(2, weight=1, minsize=20) self.buttons_frame.grid(row=row_counter, column=0) - Label(self.buttons_frame, text="").grid(row=row_counter, column=0) # add spacer + Label(self.buttons_frame, text="").grid(row=0, column=0) # add spacer + # add button for executing the current entries execute_button = Button(self.buttons_frame, text="Execute!", command=self.execute, pady=5, padx=5, font=BIG_BUTTON_FONT) execute_button.grid(row=row_counter, column=0) @@ -149,9 +165,33 @@ class ManualMode(Frame): self.input_mode.trace_add('write', self.change_mode_callback) # call mode change function on dropdown change self.input_mode.set(default_mode) # call up default mode at the start + self.compensate.trace_add('write', self.change_mode_callback) # call mode change function on dropdown change 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 + + def update_max_fields(self): # update labels with maximum allowable field values + self.compensate_checkbox.config(state=NORMAL) + i = 0 + for val in self.max_value_vars: + comp = self.compensate.get() + if comp == 0: + field = g.AXES[i].max_field * 1e6 + elif comp == 1: + field = g.AXES[i].max_comp_field * 1e6 + else: + field = [0, 0] + func.ui_print("Unexpected value encountered: compensate =", comp) + val.set("(%0.1f to %0.1f \u03BCT)" % (field[0], field[1])) + i += 1 + + def update_max_currents(self): # update labels with maximum allowable current values + self.compensate_checkbox.config(state=DISABLED) + i = 0 + for val in self.max_value_vars: + val.set("(%0.2f to %0.2f A)" % (-g.AXES[i].max_amps, g.AXES[i].max_amps)) + i += 1 def execute(self): function_to_call = self.modes[self.input_mode.get()][0] # get function of appropriate mode @@ -167,7 +207,7 @@ class ManualMode(Frame): def execute_field(vector): func.ui_print("field executing", vector) try: - func.set_field_simple(vector*1e-6) # ToDo: change to set_field + func.set_field_simple(vector * 1e-6) # ToDo: change to set_field except ValueError as e: func.ui_print(e) @@ -253,7 +293,7 @@ class StatusDisplay(Frame): controller.after(500, lambda: self.update_labels(controller)) -class OutputConsole(Frame): +class OutputConsole(Frame): # console to print stuff in def __init__(self, parent): Frame.__init__(self, parent, relief=SUNKEN, bd=1) @@ -263,6 +303,8 @@ class OutputConsole(Frame): scrollbar = Scrollbar(self) self.console = Text(self) + self.console.bind("", lambda e: "break") # prevent user input into the console + scrollbar.grid(row=0, column=1, sticky="ns") self.console.grid(row=0, column=0, sticky="nesw") scrollbar.config(command=self.console.yview) diff --git a/cage_func.py b/cage_func.py index 39083b8..51846f2 100644 --- a/cage_func.py +++ b/cage_func.py @@ -20,15 +20,17 @@ class Axis: self.name = g.AXIS_NAMES[index] self.port = g.ports[index] - self.resistance = 0 # [Ohm] - # maximum allowable values to pass through this circuit - self.max_watts = 0 # [W] - self.max_amps = 0 # [A] - self.max_volts = 0 # [V] + self.resistance = g.RESISTANCES[index] + self.max_watts = g.MAX_WATTS[index] + self.max_amps = np.sqrt(self.max_watts / self.resistance) + self.max_volts = g.MAX_VOLTS[index] - self.coil_constant = 0 # coil constant of this axis [T/A] - self.ambient_field = 0 # ambient field in this axis [T] - # ToDo: get this info from settings file + self.coil_constant = g.COIL_CONST[index] + self.ambient_field = g.AMBIENT_FIELD[index] + + max_field = self.max_amps * self.coil_constant # max field reachable in this axis + self.max_field = np.array([-max_field, max_field]) + self.max_comp_field = np.array([self.ambient_field - max_field, self.ambient_field + max_field]) # dynamic information self.connected = "Not Connected" @@ -142,7 +144,7 @@ class ArduinoCtrl(Arduino): self.pinMode(pin, "Output") self.digitalWrite(pin, "LOW") except Exception as e: - ui_print("Connection to Arduino failed:", e) + ui_print("Connection to Arduino failed.", e) self.connected = "Not Connected" else: self.connected = "Connected" @@ -172,7 +174,7 @@ class ArduinoCtrl(Arduino): def ui_print(*content): # prints text to built in console output = "" for text in content: - output = " ".join((output, str(text))) + output = " ".join((output, str(text))) # append content if g.app is not None: output = "".join(("\n", output)) # begin new line each time g.app.OutputConsole.console.insert(END, output) # print to console @@ -232,18 +234,6 @@ def setup_axes(): # creates device objects for all PSUs and sets their values g.AXES.append(g.Z_AXIS) ui_print("") # new line - i = 0 - for axis in g.AXES: # ToDo: move to axis init - axis.resistance = g.RESISTANCES[i] - axis.max_watts = g.MAX_WATTS[i] - axis.max_amps = np.sqrt(axis.max_watts / axis.resistance) - ui_print(axis.name, "max Current:", axis.max_amps) - axis.max_volts = g.MAX_VOLTS[i] - - axis.coil_constant = g.COIL_CONST[i] - axis.ambient_field = g.AMBIENT_FIELD[i] - i = i + 1 - ui_print("") def activate_all(): # enables remote control and output on all PSUs and channels diff --git a/main.py b/main.py index 9d23a46..14b8d50 100644 --- a/main.py +++ b/main.py @@ -11,6 +11,9 @@ try: # start normal operations print("\nOpening User Interface...") g.app = HelmholtzGUI() + func.ui_print("Program Initialized") + func.ui_print("Starting setup...") + func.setup_axes() # initiate communication, set handles g.app.mainloop() g.app = None # reset to None so nothing tries to print in the UI output diff --git a/settings.py b/settings.py index 10b3d61..fd6ae92 100644 --- a/settings.py +++ b/settings.py @@ -11,9 +11,9 @@ AXES = None # list containing [X_AXIS, Y_AXIS, Z_AXIS] # Constants: 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([4.5, 8, 4]) # resistance of [x,y,z] circuits -MAX_WATTS = np.array([8, 25, 8]) # max. allowed power for [x,y,z] circuits +AMBIENT_FIELD = np.array([30, 30, 30]) * 1e-6 # ambient magnetic field in measurement area, to be cancelled out +RESISTANCES = np.array([1.7, 1.7, 1.7]) # resistance of [x,y,z] circuits +MAX_WATTS = np.array([15, 15, 15]) # max. allowed power for [x,y,z] circuits MAX_VOLTS = [16, 16, 16] # max. allowed voltage, limited to 16V by used diodes! # COM-Ports for power supply units: