From 59606f050f2e41950c6a06fb14c43bdfc26c8b81 Mon Sep 17 00:00:00 2001 From: Martin Zietz Date: Fri, 22 Jan 2021 12:26:22 +0100 Subject: [PATCH] Status display work, Error handling for not connected devices --- User_Interface.py | 60 ++++++++++---- cage_func.py | 78 ++++++++++++++++--- main.py | 24 ++++-- pyps2000b/__pycache__/PS2000B.cpython-37.pyc | Bin 14119 -> 0 bytes settings.py | 16 +++- 5 files changed, 141 insertions(+), 37 deletions(-) delete mode 100644 pyps2000b/__pycache__/PS2000B.cpython-37.pyc diff --git a/User_Interface.py b/User_Interface.py index 81de9be..0801e7d 100644 --- a/User_Interface.py +++ b/User_Interface.py @@ -1,7 +1,7 @@ from tkinter import * from tkinter import ttk -import settings -import cage_func +import settings as g +import cage_func as func import random as rand NORM_FONT = () @@ -19,7 +19,7 @@ class HelmholtzGUI(Tk): self.Menu = TopMenu(self) # displays menu bar at the top mainArea = Frame(self) - mainArea.pack(side="top", fill="both", expand=True) + mainArea.pack(side="top", fill="both", expand=False) mainArea.grid_rowconfigure(0, weight=1) mainArea.grid_columnconfigure(0, weight=1) @@ -81,25 +81,39 @@ class StatusDisplay(Frame): col = col + 1 # move to next column rowCounter = rowCounter + 1 # increase row counter to place future stuff below header - LabelTexts = ["Port:", "Channel:", "Output:"] # define content of row entries - rowNo = len(LabelTexts) # get number of label rows - columnNo = 3 # number of label columns - Labels = [[] for _ in range(columnNo)] - # prepare list of lists to contain all labels for row entries in all columns + TextLabels = ["Port:", "Channel:", "Output:"] # define content of row entries + self.rowNo = len(TextLabels) # get number of label rows - for i in range(0, rowNo): # create label objects for row entries - for j in range(columnNo): - Labels[j].append(Label(self, text=LabelTexts[i])) + self.columnNo = 6 # number of label columns + # prepare list of lists to contain all labels for row entries in all columns: + self.Labels = [[] for _ in range(self.columnNo)] + + self.label_dict = {} + for name in TextLabels: + self.label_dict[name] = [StringVar() for _ in range(int(self.columnNo/2))] + for col in range(int(self.columnNo/2)): + self.Labels[col*2].append(Label(self, text=name)) + self.Labels[col*2+1].append(Label(self, textvariable=self.label_dict[name][col])) col = 0 - for LabelCol in Labels: # place row entries in grid layout for all columns - for row in range(rowNo): # place row entries - LabelCol[row].grid(row=row+rowCounter, column=col*2, sticky="w") + for LabelCol in self.Labels: # place row entries in grid layout for all columns + for row in range(self.rowNo): # place row entries + LabelCol[row].grid(row=row+rowCounter, column=col, sticky="w") col = col + 1 - rowCounter = rowCounter + rowNo # increase row counter to place future stuff below this + rowCounter = rowCounter + self.rowNo # increase row counter to place future stuff below this - toBeRemoved = Label(self, text="Active TBD") - toBeRemoved.grid(row=1, column=1) + self.update_labels(controller) + + def update_labels(self, controller): + i = 0 + for axis in g.AXES: # ToDo: switch to proper axes when PSU connected + if axis.device is not None: + axis.update_values() + self.label_dict["Port:"][i].set(g.ports[i]) + self.label_dict["Channel:"][i].set(axis.channel) + self.label_dict["Output:"][i].set(axis.output_active) + i = i+1 + controller.after(2000, lambda: self.update_labels(controller)) def print_stuff(stuff): @@ -108,3 +122,15 @@ def print_stuff(stuff): def random_no(): return rand.uniform(0, 20) + + +class TestValues: + def __init__(self): + self.val1 = 0 + self.val2 = 0 + self.val3 = 0 + + def update_values(self): + self.val1 = rand.uniform(0, 20) + self.val2 = rand.uniform(0, 20) + self.val3 = rand.uniform(0, 20) diff --git a/cage_func.py b/cage_func.py index b0e8c50..d937105 100644 --- a/cage_func.py +++ b/cage_func.py @@ -1,12 +1,15 @@ from pyps2000b import PS2000B +from Arduino import Arduino import settings as g import pandas import time import numpy as np +import serial class Axis: - def __init__(self, device, PSU_channel, arduino_pin): + def __init__(self, index, device, PSU_channel, arduino_pin): + self.index = index self.device = device # power supply object (PS2000B class) self.channel = PSU_channel # power supply unit channel (1 or 2) self.ardPin = arduino_pin # output pin on the arduino for switching polarity on this axis @@ -21,6 +24,33 @@ class Axis: self.ambient_field = 0 # ambient field in this axis [T] # ToDo: get this info from settings file + self.output_active = 0 # power output on the PSU enabled? + self.remote_ctrl_active = 0 # remote control on the PSU enabled? + self.voltage_setpoint = 0 # target voltage on PSU [V] + self.voltage = 0 # actual voltage on PSU [V] + self.current_setpoint = 0 # target current on PSU [A] + self.current = 0 # actual current on PSU [A] + + self.polarity_switched = 0 # polarity switched on the Arduino? + + if self.device is not None: + self.update_status_info() + + self.name = g.AXIS_NAMES[index] + + def update_status_info(self): # Read out the values of the parameters stored in this class and update them + self.device.update_device_information(self.channel) + device_status = self.device.get_device_status_information(self.channel) + self.output_active = device_status.output_active + self.remote_ctrl_active = device_status.remote_control_active + + self.voltage = self.device.get_voltage(self.channel) + self.voltage_setpoint = self.device.get_voltage_setpoint(self.channel) + self.current = self.device.get_current(self.channel) + self.current_setpoint = self.device.get_current_setpoint(self.channel) + + self.polarity_switched = g.ARDUINO.digitalRead(self.ardPin) # ToDo: Test if this actually works + def print_status(self): # axis = axis control variable, stored in settings.py print("%s, %0.2f V, %0.2f A" % (self.device.get_device_status_information(self.channel), @@ -59,13 +89,35 @@ class Axis: def setup_axes(): # creates device objects for all PSUs and sets their values - g.XY_DEVICE = PS2000B.PS2000B(g.XY_PORT) - g.Z_DEVICE = PS2000B.PS2000B(g.Z_PORT) - g.X_AXIS = Axis(g.XY_DEVICE, 0, g.RELAY_PINS[0]) - g.Y_AXIS = Axis(g.XY_DEVICE, 1, g.RELAY_PINS[1]) - g.Z_AXIS = Axis(g.Z_DEVICE, 0, g.RELAY_PINS[2]) - g.axes = [g.X_AXIS, g.Y_AXIS, g.Z_AXIS] + print("Connecting to XY Device on %s..." % g.XY_PORT) + try: + g.XY_DEVICE = PS2000B.PS2000B(g.XY_PORT) # setup PSU + print("Connection established.") + g.X_AXIS = Axis(0, g.XY_DEVICE, 0, g.RELAY_PINS[0]) # create axis objects + g.Y_AXIS = Axis(1, g.XY_DEVICE, 1, g.RELAY_PINS[1]) + except serial.serialutil.SerialException: + g.X_AXIS = Axis(0, None, 0, g.RELAY_PINS[0]) # create axis objects + g.Y_AXIS = Axis(1, None, 1, g.RELAY_PINS[1]) + print("XY Device not connected or incorrect port set.") + + if g.Z_PORT == "NC": # check if device is connected + g.Z_AXIS = Axis(2, None, 0, g.RELAY_PINS[2]) + print("Z Device not connected or port not set.") + + print("Connecting to Z Device on %s..." % g.XY_PORT) + try: + g.Z_DEVICE = PS2000B.PS2000B(g.Z_PORT) + print("Connection established.") + g.Z_AXIS = Axis(2, g.Z_DEVICE, 0, g.RELAY_PINS[2]) + except serial.serialutil.SerialException: + g.Z_AXIS = Axis(2, None, 0, g.RELAY_PINS[2]) + print("Z Device not connected or incorrect port set.") + + g.AXES.append(g.X_AXIS) + g.AXES.append(g.Y_AXIS) + g.AXES.append(g.Z_AXIS) + i = 0 for axis in g.AXES: axis.resistance = g.RESISTANCES[i] @@ -89,9 +141,15 @@ def deactivate_all(): # disables remote control and output on all PSUs and chan def setup_arduino(): - for pin in g.RELAY_PINS: - g.ARDUINO.pinMode(pin, "Output") - g.ARDUINO.digitalWrite(pin, "LOW") + try: + g.ARDUINO = Arduino() # search for connected arduino and set handle + except Exception: + print("There seems to be no Arduino connected.") + else: + for pin in g.RELAY_PINS: + g.ARDUINO.pinMode(pin, "Output") + g.ARDUINO.digitalWrite(pin, "LOW") + print("Arduino ready.") def safe_arduino(): # sets output pins to low and closes serial connection diff --git a/main.py b/main.py index 5adf36c..c9376e8 100644 --- a/main.py +++ b/main.py @@ -1,10 +1,22 @@ -import numpy as np -import settings as g -from tkinter import * -from Arduino import Arduino - -import cage_func as func import User_Interface as ui +import cage_func as func +import settings as g + + +print("Connecting to PSUs...") +func.setup_axes() # initiate communication, set handles + +print("Connecting to Arduino...") +#print("Arduino found, configuring pins...") +func.setup_arduino() + +print("Opening User Interface...") +'''g.TestValuesX = ui.TestValues() +g.TestValuesY = ui.TestValues() +#g.TestValuesZ = ui.TestValues() +g.TestValues = [g.TestValuesX, g.TestValuesY]#, g.TestValuesZ]''' application = ui.HelmholtzGUI() application.mainloop() + +# func.shut_down_all() diff --git a/pyps2000b/__pycache__/PS2000B.cpython-37.pyc b/pyps2000b/__pycache__/PS2000B.cpython-37.pyc deleted file mode 100644 index 77b78daf058a6a183b6fd632a12a37870ba15c60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14119 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 diff --git a/settings.py b/settings.py index d0ee122..12b9839 100644 --- a/settings.py +++ b/settings.py @@ -7,21 +7,29 @@ global X_AXIS # object structure: (device, channel, arduino pin, axis index) global Y_AXIS global Z_AXIS -global AXES # list containing [X_AXIS, Y_AXIS, 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 -AMBIENT_FIELD = np.array([80]) * 1e-6 # ambient magnetic field in measurement area, to be cancelled out +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 MAX_VOLTS = [16, 16, 16] # max. allowed voltage, limited to 16V by used diodes! # COM-Ports for power supply units: -XY_PORT = "COM1" # placeholders -Z_PORT = "COM2" +XY_PORT = "COM10" # placeholders +Z_PORT = "COM11" + +AXIS_NAMES = ["X-Axis", "Y-Axis", "Z-Axis"] +ports = [XY_PORT, XY_PORT, Z_PORT] global ARDUINO RELAY_PINS = [15, 16, 17] # pin on the Arduino for switching relay of each axis [x,y,z] # ToDo: make proper settings file to read from and write to + +global TestValuesX +global TestValuesY +global TestValuesZ +global TestValues