Moved files. Bug fixes from clean room

This commit is contained in:
Martin Zietz
2021-08-19 09:51:49 +02:00
parent 3a526ec26d
commit 8177402ba1
9 changed files with 74 additions and 24 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ class ArduinoDevice(Arduino):
ui_print("\nConnecting to Arduino...")
# try to set up the arduino. Exceptions are handled by caller
# search for connected arduino and connect by initializing arduino library class
Arduino.__init__(self, timeout=0.2)
Arduino.__init__(self, port="COM4", timeout=2)
for pin in self.pins:
self.pinMode(pin, "Output")
self.digitalWrite(pin, "LOW")
+5 -2
View File
@@ -165,8 +165,10 @@ class CoilConstantCalibration(Thread):
time.sleep(self.SETTLE_TIME)
# Get coil constant
field_diff_mag = np.linalg.norm(g.MAGNETOMETER.field - ambient_field)
k_samples.append(field_diff_mag / c)
field = g.MAGNETOMETER.field
field_diff_mag = np.linalg.norm(field - ambient_field)
sign = 1 if field[i] - ambient_field[i] >= 0 else -1
k_samples.append((field_diff_mag * sign) / c)
# Save vector as principal coil direction if it is the last sample with the largest positive current
if c_idx == currents.shape[0] - 1:
@@ -177,6 +179,7 @@ class CoilConstantCalibration(Thread):
k_deviations[i], _ = self.calculate_standard_deviation(k_samples)
# Put device into an off and ready state
time.sleep(3)
self.cage_dev.idle()
angles = {'xy': self.angle_between(axis_field_directions[0], axis_field_directions[1]) * 180 / pi,
+1 -1
View File
@@ -48,4 +48,4 @@ default_psu_config = {
# Configuration for socket interface
SOCKET_PORT = 6677
SOCKET_MAX_CONNECTIONS = 5
SOCKET_MAX_CONNECTIONS = 5
+18 -20
View File
@@ -1,3 +1,4 @@
import time
import traceback
from threading import RLock, Thread, Event
from tkinter import messagebox
@@ -206,25 +207,21 @@ class HelmholtzCageDevice:
command_buffer = HelmholtzCageDevice._copy_command(self.command)
self.command = None # Processed commands are removed from "buffer"
if command_buffer:
try:
# Unpack command into "action" and argument
command_string = command_buffer['command']
command_arg = command_buffer['arg']
# Check which command and delegate to responsible function
if command_string == "set_signed_currents":
self._set_signed_currents(command_arg)
elif command_string == "set_field_raw":
self._set_field_raw(command_arg)
elif command_string == "set_field_compensated":
self._set_field_compensated(command_arg)
elif command_string == 'idle':
self.idle()
else:
raise Exception("Command unknown!")
except Exception as e:
# No ui print, since this is really not something that should happen... (relevant for devs)
print("An error occurred while processing command: {}".format(self.command))
traceback.print_exc()
# Unpack command into "action" and argument
command_string = command_buffer['command']
command_arg = command_buffer['arg']
# Check which command and delegate to responsible function
if command_string == "set_signed_currents":
self._set_signed_currents(command_arg)
elif command_string == "set_field_raw":
self._set_field_raw(command_arg)
elif command_string == "set_field_compensated":
self._set_field_compensated(command_arg)
elif command_string == 'idle':
self.idle()
else:
raise Exception("Command unknown!")
def _hw_poll_thread_method(self):
"""This method forms the main thread for hardware command execution."""
@@ -282,6 +279,7 @@ class HelmholtzCageDevice:
axis.set_signed_current(current)
except Exception as e:
ui_print("Error {}: Unexpected error occured:\n{}".format(axis.name, e))
traceback.print_exc()
def get_psu_for_axis(self, axis_index):
"""Determine which channel of which psu is required"""
@@ -443,7 +441,7 @@ class Axis:
voltage_limit = min(max(1.3 * abs(safe_current) * self.resistance, 8), self.max_volts) # limit voltage
# Set voltages and currents. Outputs should already be active from initializer.
self.psu.set_current(self.channel, safe_current)
self.psu.set_current(self.channel, abs(safe_current))
self.psu.set_voltage(self.channel, voltage_limit)
@property
+3
View File
@@ -16,6 +16,7 @@
# [1] = "PS 2000B Programming Guide" from 2015-05-28
# [2] = "PS 2000B object list"
#
import time
import serial
import struct
@@ -388,7 +389,9 @@ class PS2000B:
def set_current(self, value, channel):
self.update_device_information(channel)
time.sleep(0.05)
self.enable_remote_control(channel)
time.sleep(0.05)
curr = int(round((value * 25600.0) / self.__device_information.nominal_current))
self.__send_device_data(Objects.SET_VALUE_CURRENT, curr, channel)
+11
View File
@@ -1,4 +1,5 @@
# ABC is template used to create python abstract classes
import time
from abc import ABC, abstractmethod
import serial
@@ -84,12 +85,15 @@ class PSUDevicePS2000B(PSUDevice):
"""Provides HW support for the Elektro-Automatik PS2000B power supply.
This class is an adapter for the already existing PS2000B library, to have a consistent interface"""
MIN_DELAY = 0.05
def __init__(self, com_port):
super().__init__(com_port)
"""Can fail; Check for serial.SerialException"""
self.dev = PS2000B.PS2000B(com_port)
# dev_info is a class which contains hw specific constants, such as nominal voltage and current
self.dev_info = self.dev.get_device_information() # Cache this result
time.sleep(self.MIN_DELAY)
@staticmethod
def valid_channels():
@@ -98,25 +102,32 @@ class PSUDevicePS2000B(PSUDevice):
def enable_channel(self, channel_nr):
self.dev.enable_output(channel_nr)
time.sleep(self.MIN_DELAY)
def disable_channel(self, channel_nr):
self.dev.enable_output(channel_nr)
time.sleep(self.MIN_DELAY)
def set_current(self, channel_nr, current):
self.dev.set_current(current, channel_nr)
time.sleep(self.MIN_DELAY)
def set_voltage(self, channel_nr, voltage):
self.dev.set_voltage(voltage, channel_nr)
time.sleep(self.MIN_DELAY)
def poll_channel_state(self, channel_nr):
self.dev.update_device_information(channel_nr) # update the information in the device object
time.sleep(self.MIN_DELAY)
dev_status = self.dev.get_device_status_information(channel_nr) # get object with new status info
# This is more efficient than the dev.get_voltage() call, since it does not require another update_device_info
voltage = dev_status.actual_voltage_percent * self.dev_info.nominal_voltage # Extracted from PS2000B library
voltage_setp = self.dev.get_voltage_setpoint(channel_nr)
time.sleep(self.MIN_DELAY)
current = dev_status.actual_current_percent * self.dev_info.nominal_current
current_setp = self.dev.get_current_setpoint(channel_nr)
time.sleep(self.MIN_DELAY)
# Format should match the provided template in abstract PSUDevice class.
return {'active': dev_status.output_active, 'remote_active': dev_status.remote_control_active,

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

+35
View File
@@ -0,0 +1,35 @@
import serial
from datetime import datetime
import socket
# Lookup table for cage axis to magnetometer transformation
# First entry: Magnetometer y axis to cage x (reversed)
# axis_mapping = [[1, -1 ...]
axis_mapping = [[2, -1], [0, 1], [1, -1]]
# Helmholtz control software tcp port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", 6677))
s.sendall("declare_api_version 2\n".encode())
# FGM3D software virtual serial port
ser = serial.Serial("COM11")
line = b""
ready = False
while True:
line += ser.read()
if line[-2:] == b"\r\n":
new_line = line[:-2].decode('ascii')
delta = datetime.now().timestamp()*1000 - int(new_line.split(';')[0])+(2*60*60*1000)
if delta < 500 and not ready:
ready = True
print("Program ready!")
if ready:
# Data is not valid otherwise
# Only use the x y and z values
tokens = [float(v) for v in new_line.split(";")[1:-1]]
axis_fields = [tokens[m[0]]*m[1] for m in axis_mapping]
axis_fields = ["{:.6e}".format(v) for v in axis_fields]
s.sendall(("magnetometer_field {} {} {}\n".format(*axis_fields)).encode())
line = b""