13 Commits

Author SHA1 Message Date
Martin Zietz cad62899c0 Update readme.md 2021-03-27 14:23:23 +01:00
Martin Zietz 7da0efd9f0 added documentation pdf to repo 2021-03-27 14:13:09 +01:00
Martin Zietz 796c3df94b documentation 2021-03-27 14:10:06 +01:00
Martin Zietz e0104b5604 Update longtable.sty 2021-03-27 13:08:45 +01:00
Martin Zietz f5bf9cbf68 documentation 2021-03-27 13:08:36 +01:00
Martin Zietz 929e0ed50a added documentation folder 2021-03-27 12:53:51 +01:00
Martin Zietz 3e8490d353 renamed test stand to test bench 2021-03-14 21:08:35 +01:00
Martin Zietz 606cfa1f40 readme test 2021-03-13 15:39:10 +01:00
Martin Zietz 9475657865 Create readme.txt 2021-03-13 15:33:36 +01:00
Martin Zietz eeb6a230e6 added auto-py-to-exe tool 2021-03-11 16:19:26 +01:00
Martin Zietz d3ffe4d642 Release V1.1 added 2021-03-10 18:49:19 +01:00
Martin Zietz 640d99c9e2 minor UI tweaks
- fixed bug where log data could not be cleared after saving to file
- added description for coil constant in settings page
- minor message tweaks
2021-03-08 18:36:23 +01:00
Martin Zietz 12de3c3587 User test feedback
- added cancel option for "clear log data" pop-up
- removed "!" for Execute! button
- separated start and stop logging buttons
2021-03-06 22:38:01 +01:00
36 changed files with 3280 additions and 56 deletions
+17
View File
@@ -0,0 +1,17 @@
*.aux
*.bbl
*.bcf
*.blg
*.log
*.lof
*.lot
*.out
*.gz
*.xml
*.glg
*.glo
*.gls
*.ist
*.toc
*.txss
*.aux
+175
View File
@@ -0,0 +1,175 @@
% please capatalize all abbreviations
\newacronym{irs}{IRS}{Institute of Space Systems at the University of Stuttgart}
\newacronym{flp}{FLP}{Flying Laptop}
\newacronym{ksat}{KSat}{Small Satellite Student Society at the University of Stuttgart}
\newacronym{acs}{ACS}{Attitude Control System}
\newacronym{obdh}{OBDH}{onboard data handling}
\newacronym{source}{SOURCE}{Stuttgart Operated University Research CubeSat for Evaluation and Education}
\newacronym{iras}{IRAS}{Integrated Research Platform for Affordable Satellites}
\newacronym{dlr}{DLR}{German Aerospace Center}
\newacronym{esa}{ESA}{European Space Agency}
\newacronym{eps}{EPS}{electrical power system}
\newacronym{com}{COM}{Communication Port}
\newacronym{st}{S\&T}{structure and thermal control system}
\newacronym{pl}{PL}{payload}
\newacronym{sim}{SIM}{simulation and test bed}
\newacronym{pr}{PR}{public relations}
\newacronym{prf}{PRF}{power reduction factor}
\newacronym{trl}{TRL}{Technology Readiness Level}
\newacronym{ilr}{ILR}{Institut für Luft- und Raumfahrt}
\newacronym{leo}{LEO}{Low Earth Orbit}
\newacronym{meo}{MEO}{Medium Earth Orbit}
\newacronym{geo}{GEO}{Geostationary Orbit}
\newacronym{pcdu}{PCDU}{Power Control and Distribution Unit}
\newacronym{pwm}{PWM}{Pulse Width Modulation}
\newacronym{opa}{OpAmp}{Operational Amplifier}
\newacronym{adc}{ADC}{Analogue to Digital Converter}
\newacronym{iss}{ISS}{International Space Station}
\newacronym{gsoc}{GSOC}{German Space Operation Centre}
\newacronym{tps}{TPS}{Thermal Protection System}
\newacronym{acu}{ACU}{Address Control Unit}
\newacronym{p-pod}{P-POD}{Poly Picosatellite Orbital Deployer}
\newacronym{csp}{CSP}{?}
\newacronym{gosh}{GOSH}{?}
\newacronym{pdu}{PDU}{Power Distribution Unit}
\newacronym{tfm}{TFM}{?}
\newacronym{tml}{TML}{Total Mass Loss}
\newacronym{cvcm}{CVCM}{collected volatile condensed material}
\newacronym{bpx}{BPX}{NanoPower BPX}
\newacronym{obc}{OBC}{Onboard Computer}
\newacronym{pe}{PE}{Port Expander}
\newacronym{obsw}{OBSW}{Onboard Software}
\newacronym{soc}{SoC}{State of Charge}
\newacronym{dod}{DoD}{Depth of Discharge}
\newacronym{ipa}{IPA}{Institute for Manufacturing Engineering and Automation}
\newacronym{sso}{SSO}{Sun Synchronous Orbit}
\newacronym{ksc}{KSC}{Kennedy Space Center}
\newacronym{csg}{CSG}{Centre Spatial Guyanais}
\newacronym{ploc}{PLOC}{Payload Onboard Computer}
\newacronym{uhf}{UHF}{ultra high frequency}
\newacronym{ccsds}{CCSDS}{Consultative Committee for Space Data Systems}
\newacronym{ecss}{ECSS}{European Cooperation for Space Standardization}
\newacronym{fsfw}{FSFW}{Flight Software Framework}
\newacronym{obcp}{OBCP}{On-board control procedure}
\newacronym{apid}{APID}{Application Process ID}
\newacronym{soa}{SOA}{Service Oriented Architecture}
\newacronym{pus}{PUS}{Packet Utilisation Standard}
\newacronym{stem}{STEM}{Science, technology, engineering, and mathematics}
\newacronym{pcb}{PCB}{Printed Circuit Board}
\newacronym{fipex}{FIPEX}{Flux Phi Probe Experiment}
\newacronym{spi}{SPI}{Serial Peripheral Interface}
\newacronym{i2c}{I2C}{Inter-Integrated Circuit}
\newacronym{rtd}{RTD}{Resistance Temperature Detector}
\newacronym{fdir}{FDIR}{Failure Detection, Isolation, and Recovery}
\newacronym{mcs}{MCS}{Mission Control Software}
\newacronym{vm}{VM}{Virtuell Maschine}
\newacronym{tmtc}{TM/TC}{Telemetry and Telecommand}
\newacronym{oop}{OOP}{Object-oriented Programming}
\newacronym{mgt}{MGT}{Magnetorquer}
\newacronym{sus}{SuS}{Sun Sensors}
\newacronym{mgm}{MGM}{Magnetometer}
\newacronym{gps}{GPS}{Global Positioning System}
\newacronym{prima}{PRIma}{PR Imager}
\newacronym{meshcam}{MeSHCam}{Meteor, Star and Horizon tracking Camera}
\newacronym{mib}{MIB}{Mission Information Base}
\newacronym{scos}{SCOS-2000}{Satellite Control and Operation System 2000}
\newacronym{leop}{LEOP}{Launch and Early Orbit Phase}
\newacronym{cots}{COTS}{commercial off-the-shelf}
\newacronym{em}{EM}{Engineering Model}
\newacronym{fm}{FM}{Flight Model}
\newacronym{qm}{QM}{Qualification Model}
\newacronym{bbm}{BBM}{Breadboard Model}
\newacronym{uart}{UART}{Universal Asynchronous Receiver-Transmitter}
\newacronym{fpga}{FPGA}{Field-Programmable Gate Array}
\newacronym{lsb}{LSB}{least significant bit}
\newacronym{tc}{TC}{telecommand}
\newacronym{tm}{TM}{telemetry}
\newacronym{itu}{ITU}{International Telecommunication Union}
\newacronym{isl}{ISL}{intersatellite link}
\newacronym{fov}{FOV}{field of view}
\newacronym{gsd}{GSD}{ground sampling distance}
\newacronym{snr}{SNR}{signal to noise ratio}
\newacronym{dsp}{DSP}{Digital Signal Processing}
\newacronym{fifo}{FIFO}{First In First Out}
\newacronym{fec}{FEC}{Forward Error Correction}
\newacronym{bpsk}{BPSK}{Binary Phase Shift Keying}
\newacronym{qpsk}{QPSK}{Quaternary Phase-Shift Keying}
\newacronym{ber}{BER}{Bit Error Rate}
\newacronym{hpc}{HPC}{high priority command}
\newacronym{imu}{IMU}{inertial measurement unit}
\newacronym{imus}{IMU's}{inertial measurement units}
\newacronym{bch}{BCH}{Bose-Chaudhuri-Hocquenghem}
\newacronym{il}{IL}{interleaving depth}
\newacronym{mems}{MEMS}{Micro-Electro-Mechanical Systems}
\newacronym{hefdig}{HEFDiG}{High Enthalpy Flow Diagnostics Group}
\newacronym{nisi}{NISI}{Noninteger System Identification}
\newacronym{pwt}{PWT}{IRS Plasma Wind Tunnel}
\newacronym{jtag}{JTAG}{Joint Test Action Group}
\newacronym{dcsa}{DCSA}{Deployable CubeSat Solar Array}
\newacronym{pvch}{PVCH}{Photovoltaic Characterization Hardware}
\newacronym{srn}{SRN}{Switchable Resistor Network}
\newacronym{pdr}{PDR}{Preliminary Design Review}
\newacronym{fys}{FYS}{Fly Your Satellite}
\newacronym{nga}{NGA}{National Geospatial-Intelligence Agency}
\newacronym{dgc}{DGC}{Defence Geographic Centre}
\newacronym{fdm}{FDM}{Fused Deposition Modeling}
\newacronym{osi}{OSI}{Open Systems Interconnection}
\newacronym{vhdl}{VHDL}{Very High Speed Integrated Circuit Hardware Description Language}
\newacronym{mss}{MSS}{mobile satellite communications systems}
\newacronym{nasa}{Nasa}{National Aeronautics and Space Administration}
\newacronym{rr}{RR}{Radio Regulations}
\newacronym{cdr}{CRD}{Critical Design Review}
\newacronym{lna}{LNA}{low noise amplifier}
\newacronym{pa}{PA}{power amplifier}
\newacronym{sti}{STI}{SpaceTech GmbH Immenstaad}
\newacronym{esd}{ESD}{Electrostatic Discharge}
\newacronym{hil}{HiL}{Hardware in the Loop}
\newacronym{sil}{SiL}{Software in the Loop}
\newacronym[description=Application Programming Interface]{api}{API}{application programming interface}
\newacronym{sdi}{SDI}{Serial Digital Interface}
\newacronym{aoi}{AOI}{Area Of Interest}
\newacronym{dr}{DR}{Dynamic Range}
\newacronym{iag}{IAG}{Institute of Aerodynamics and Gas Dynamics}
\newacronym{dsmc}{DSMC}{Direct Simulation Monte Carlo}
\newacronym{afwa}{AFWA}{Air Force Weather Agency}
\newacronym{pslv}{PSLV}{Polar Satellite Launch Vehicle}
\newacronym{isro}{ISRO}{Indian Space Research Organisation}
\newacronym{sdsc}{SDSC}{Satish Dhawan Space Centre}
\newacronym{simcard}{SIM card}{Subscriber Identity Module card}
\newacronym{emc}{EMC}{electromagnetic compability}
\newacronym{sbd}{SBD}{Short Burst Data}
\newacronym{rudics}{RUDICS}{ Router based Unrestricted Digital Interworking Connectivity Solution}
\newacronym{sms}{SMS}{Short Message Service}
\newacronym{rhcp}{RHCP}{Right-Hand Circular Polarization}
\newacronym{fa}{FA}{Field Application}
\newacronym{isu}{ISU}{Iridium Subscriber Unit}
\newacronym{peek}{PEEK}{Polyether ether ketone}
\newacronym{cf}{CF}{Carbon fiber}
\newacronym{mosfet}{MOSFET}{MetalOxideSemiconductor Field-Effect Transistor}
\newacronym{plv}{PlV}{Payload Processor Vorago}
\newacronym{plp}{PlP}{Payload Processor PIC24}
\newacronym{edac}{EDAC}{Error Detectionn And Correction}
\newacronym{gpio}{GPIO}{General Purpose Input/Output}
\newacronym{tfsp}{TFSP}{Thin Film Solar Panel}
\newacronym{mgse}{MGSE}{Mechanical Ground Support Equipment}
\newacronym{egse}{EGSE}{Electrical Ground Support Equipment}
\newacronym{ogse}{OGSE}{Optical Ground Support Equipment}
\newacronym{gse}{GSE}{Ground Support Equipment}
\newacronym{tid}{TID}{total ionizing dose}
\newacronym{hdm}{HdM}{Hochschule der Medien}
\newacronym{syoc}{SoC}{System on a Chip}
\newacronym{cskb}{CSKB}{CubeSat Kit Bus}
\newacronym{str}{STR}{Star Tracker}
\newacronym{htr}{HTR}{Horizon Tracker}
\newacronym{wmm}{WMM}{World Magnetic Model}
\newacronym{igrf}{IGRF}{International Geomagnetic Reference Field}
\newacronym{gafe}{GAFE}{Generic AOCS GNC Techniques and Design Framework for FDIR}
\newacronym{eive}{EIVE}{Extraplanetary In-Orbit Verification of an E-/W-Link}
\newacronym{psu}{PSU}{Power Supply Unit}
\newacronym[description=User Interface]{ui}{UI}{user interface}
\newacronym[description=Comma Separated Values file]{csv}{CSV}{Comma Separated Values}
\newacronym{usb}{USB}{Universal Serial Bus}
\newacronym[description=Light-Emitting Diode]{led}{LED}{light-emitting diode}
\newacronym{pla}{PLA}{Polylactic Acid, a thermoplastic polyester}
\newacronym{pc}{PC}{Personal Computer}
\newacronym{tbd}{TBD}{To Be Determined}
+10
View File
@@ -0,0 +1,10 @@
\chapter{Example Program Auxiliary Files} \label{app:example_files}
\textbf{Example Configuration File}
\begin{small}
\lstinputlisting{Appendix/example_config.ini}
\end{small}
\bigskip
\textbf{Example Log File}
\begin{small}
\lstinputlisting{Appendix/logfile_example.csv}
\end{small}
@@ -0,0 +1,10 @@
Date;Time;t (s);X Target Field;Y Target Field;Z Target Field
2021-03-08;16:18:34,583986;0,0;0,0;0,0;0,0
2021-03-08;16:18:39,595109;5,011123;0,0;0,0;0,0
2021-03-08;16:18:44,217410;9,633424;-4,499999996e-05;-4,999999996e-05;0,0
2021-03-08;16:18:44,597378;10,013392;-4,499999996e-05;-4,999999996e-05;0,0
2021-03-08;16:18:49,604153;15,020167;-4,499999996e-05;-4,999999996e-05;0,0
2021-03-08;16:18:54,619011;20,035025;-4,499999996e-05;-4,999999996e-05;0,0
2021-03-08;16:18:57,713520;23,129534;-4,499999996e-05;4,999999996e-05;0,0
2021-03-08;16:18:59,635428;25,051442;-4,499999996e-05;4,999999996e-05;0,0
2021-03-08;16:19:00,759706;26,17572;0,0;0,0;0,0
1 Date Time t (s) X Target Field Y Target Field Z Target Field
2 2021-03-08 16:18:34,583986 0,0 0,0 0,0 0,0
3 2021-03-08 16:18:39,595109 5,011123 0,0 0,0 0,0
4 2021-03-08 16:18:44,217410 9,633424 -4,499999996e-05 -4,999999996e-05 0,0
5 2021-03-08 16:18:44,597378 10,013392 -4,499999996e-05 -4,999999996e-05 0,0
6 2021-03-08 16:18:49,604153 15,020167 -4,499999996e-05 -4,999999996e-05 0,0
7 2021-03-08 16:18:54,619011 20,035025 -4,499999996e-05 -4,999999996e-05 0,0
8 2021-03-08 16:18:57,713520 23,129534 -4,499999996e-05 4,999999996e-05 0,0
9 2021-03-08 16:18:59,635428 25,051442 -4,499999996e-05 4,999999996e-05 0,0
10 2021-03-08 16:19:00,759706 26,17572 0,0 0,0 0,0
+181
View File
@@ -0,0 +1,181 @@
\chapter{Software Implementation}\label{chp:software}
\section{Program Structure}
\glsunset{psu}
\glsunset{irs}
To operate the test bench, a Python software with graphical \gls{ui} was developed. It controls the used PS2000B Power Supply Units (\gls{psu}) as well as the Arduino microcontroller inside the switch box. This chapter focuses on the overall implementation. More detailed information is provided in the form of comments in the source code, which is available on the \gls{irs} git server.\footnote{\url{https://egit.irs.uni-stuttgart.de/zietzm/Helmholtz_Test_Bench.git}} A users guide can be found in Section \ref{sec:software_guide}.\\
Software development and testing were done in Windows 10 and Python 3.7. Some aspects may need to be adapted to use the software on a different operating system or Python version. The code was tested with a \gls{psu} or the switch box individually. However, integrated verification with both \gls{psu}s and the switch box Arduino connected simultaneously was not possible up to this point, as some of the equipment was located inside the \gls{irs} cleanroom.\\
The program file architecture is shown in Figure \ref{fig:softwarelayout}. This is meant to give an overview of the structure, therefore it does not show all interactions between the files.
\begin{figure}[hb]
\centering
\includegraphics[width=0.8\textwidth]{media/Software layout}
\caption{Software file architecture}
\label{fig:softwarelayout}
\end{figure}
Upon execution of \code{main.py}, the test bench devices (\gls{psu}s and switch box Arduino), program objects and variables are initialized. Next, the \gls{ui} (controlled by \code{User\_Interface.py}) is set up and displayed. Program elements needed for more complex functionalities are coded in \code{csv\_logging.py}, \code{config\_handling.py} and \code{csv\_threading.py}.\\
All program elements use the classes in the \code{cage\_func.py} file to control and read data from the test bench. Communication with the actual hardware (power supply units and switch box Arduino) is achieved via the libraries in \code{PS2000B.py} and \code{Arduino.py}, which were taken from online sources \cite{PS2000B_lib, Arduino_lib} with only minor modifications.\\
\code{globals.py} is used to easily pass frequently used variables between the different program files. It contains mainly variable initializations, that can be accessed and changed by the other program elements after importing it.\\
The application is able to operate with one or all test bench devices disconnected. For example, it is possible to generate a magnetic field in only one test bench axis with just a single \gls{psu}. The program also provides error handling for a variety of device disconnects and user mistakes. This includes protection against the commanding of excessive currents and voltages, as well as the display of warnings when attempting to enter a potentially dangerous value in the settings.
\section{Program Files}
\subsection{Main Executable \code{main.py}}
The main executable file contains the framework code for start and end of the program.\\
During initialization the information from the configuration file is read out to set the necessary constants. Then the test bench is prepared using the \code{setup\_all} function (see Section \ref{sec:cage_func}), the \gls{ui} is initialized and its \code{mainloop} started.\\
The \code{program\_end} function in this file ensures a safe shutdown of all equipment at the end of the program. It is immediately called when the user closes the window. The function stops any other operational threads (see Section \ref{sec:csv_exec}) and powers down the \gls{psu}s and Arduino. It also asks the user to store possible unsaved log data and then destroys the application window.\\
For exceptions that were not caught by lower level error handling, the main file also includes a global error protection. In such a case an error message is displayed and the \code{program\_end} function called. This is to ensure a safe shutdown, regardless of the current program state.
\subsection{Global Variables File \code{globals.py}}
This file holds global variables and constants that are used often and by more than one module.\\
Examples of these are \code{PS2000B} and \code{ArduinoCtrl} objects that represent the test bench devices, \code{Axis} objects for each spatial axis but also status indicators like \code{exitFlag}, which signals the end of the program to all modules.\\
The file also contains the default values for all constants used to run the test bench, like coil constants, resistances and maximum currents. These are stored in a hard-coded dictionary, which can be used to generate a default configuration. The dictionary also includes the minimum and maximum safe value for each constant. These limits are used to warn users if they attempt to set a value that may damage equipment. In the future, it may be advantageous to store this information in a separate configuration file to allow easier modification.
\subsection{Test Bench Control File \code{cage\_func.py}}\label{sec:cage_func}
This file contains all classes and functions directly related to the operation of the test bench. It includes the two main control classes \code{Axis} and \code{ArduinoCtrl}, functions for initialization and shutdown as well as for controlling more than one axis at a time.
\myparagraph{Axis Control Class \code{Axis}}
This is the main class representing an axis (x,y,z) of the test bench. It contains static and dynamic status information about the axis in its attributes and the means to command the axis in its methods. During program initialization an object of this class is created for each of the three axes and stored in \code{globals.py} \\
Apart from methods to get status information from the appropriate \gls{psu}, the class contains the primary way to command the test bench in form of the \code{set\_signed\_current} method. Its parameter is a positive or negative current value in Ampere. The method first checks if this value exceeds the safe limits defined in the program configuration. If not, the appropriate \gls{psu} channel and the switch box Arduino are commanded to supply the desired current and to actuate the polarity change relay as needed.\\
To generate a specific magnetic field, the \code{set\_field} method can be called. It takes a given field value $B$ in Tesla and calculates the needed current:
\begin{align}
I=\frac{B-B_0}{K}
\label{eq:field_current}
\end{align}
$B_0$ is the background magnetic field in the measurement area for this axis in Tesla and $K$ is the coil constant in [\si{\tesla\per\ampere}]. The calculated value $I$ is passed to the \code{set\_signed\_current} method to command the test bench. The \code{set\_field\_simple} method works the same way, but without subtracting the ambient field.\\
Similarly the minimum and maximum achievable field values $B_{min}$ and $B_{max}$ are calculated in the class initialization, mainly in order to provide this information to the user:
\begin{align}
B_{max} &= B_0 + I_{max}*K\\
B_{min} &= B_0 - I_{max}*K
\end{align}
Here $I_{max}$ is the maximum allowed current, as defined in the configuration page of the \gls{ui}.
\myparagraph{Arduino Control Class \code{ArduinoCtrl}}
This is the main class used to control the Arduino microcontroller inside the switch box. It inherits the \code{Arduino} class from the Arduino command \gls{api} \cite{Arduino_lib}. This provides a way to pass commands directly through the class object, which is created during program initialization and stored in \code{globals.py}. \\
Most commands to the switch box are passed directly through the inherited \code{Arduino} class. For example, the \code{digitalWrite()} method is called to energize a pin that actuates a specific relay. The purpose of the \code{ArduinoCtrl} class is mainly to provide supporting functionality directly related to the specific use case on the test bench, including:
\begin{itemize}
\item{Configuration of output pins used to trigger polarity switch relays}
\item{Checking Arduino connection and output pin status}
\item{\code{safe} method to set all used output pins to "LOW" for safe shutdown}
\end{itemize}
\myparagraph{Setup Function \code{setup\_all}}
This is the main initialization function. It is used at application start-up and during the runtime whenever the user updates settings or (re)connects a device. Its main tasks are:
\begin{itemize}
\item Read the latest information from the configuration object (see Section \ref{sec:config_handling})
\item Initiate communication with switch box Arduino and create object of \code{ArduinoCtrl} class
\item Initiate communication with \gls{psu}s
\item Create object of class \code{Axis} for each axis (x,y,z)
\end{itemize}
During these tasks it also handles different error cases, like disconnected devices or wrong settings in the configuration object.
\myparagraph{Shutdown Function \code{shut\_down\_all}}
This function is used to safely shut down all devices at the end of the program or if an error occurs. It is called in the \code{program\_end} function of \code{main.py}. Its primary tasks are:
\begin{itemize}
\item Secure all connected \gls{psu}s
\begin{itemize}
\item Set voltages and currents on both channels to \SI{0}{\volt} and \SI{0}{\ampere}
\item Disable power outputs on both channels
\end{itemize}
\item Secure Arduino
\begin{itemize}
\item Set all used output pins to "LOW"
\item Close serial connection
\end{itemize}
\item Show message to user with shutdown status of all devices and any errors encountered
\end{itemize}
During this process different error cases, like disconnected devices, are handled and the user is informed.
\myparagraph{Other Functions}
In addition to those discussed above, the file also contains functions to:
\begin{itemize}
\item Command currents or magnetic fields on all axes, based on a given vector
\item Check if all devices are still connected
\item Check if a given value is within the safe limits defined in \code{globals.py}
\end{itemize}
\newpage
\subsection{Graphical User Interface \code{User\_Interface.py}}
This file is used to construct the \gls{ui}, that the user interacts with to control the test bench. It contains several classes, each with code to build a specific section of the \gls{ui} as well as methods to perform the actions that are triggered by different user inputs in that section.\\
\begin{figure}[h]
\centering
\includegraphics[width=\linewidth]{media/csv_mode_full}
\caption{User interface (example state)}
\label{fig:ui_overview}
\end{figure}
The general layout of the application window is shown in Figure \ref{fig:ui_overview}. At the bottom left is a status display, that is constantly updated with the current state of all connected devices. To its right is a text area that can be used to print out information to the user, similar to a basic console output. The top half is the main area, used to display the interactive elements. Its content changes depending on which mode the user has selected. At the very top of the window a drop-down menu is used to switch between the different modes. For more detailed usage instructions please refer to Section \ref{sec:software_guide}.\\
The interface is setup through a central object of class \code{HelmholtzGUI}, which inherits the \code{Tk} main application class from the \code{tkinter} library. The other \gls{ui} element classes (except the top menu) inherit from \code{tkinter.Frame} and are placed in the layout by the main object. This structure is based on a proposal by H. Kinsley \cite{Tkinter_tutorial}. Each class is briefly described below.
\myparagraph{Main Application Class \code{HelmholtzGUI}}
An instance of this class represents the application window. The program \code{mainloop} is running on this object. The major \gls{ui} elements are initialized here and placed at their appropriate positions. This class's only method is \code{show\_frame}, which is used to switch between the different operating modes by displaying their respective frame in the main area.
\myparagraph{Menu Bar Class \code{TopMenu}}
The menu bar at the very top of the application window is constructed by this class. It contains methods to implement each option of the menu. At this time, it is only used to switch between modes, but more functionalities could be added in the future if needed.
\myparagraph{Static Manual Input Mode Class \code{ManualMode}}
The manual input mode interface is used to manually command static values of magnetic fields or currents on the test bench. It is placed in the main area of the application window, the layout can be seen in Figure \ref{fig:manualmodepure}. The methods provided in this class interface mainly with the \code{cage\_func.py} file to command the devices.
\myparagraph{CSV Sequence Execution Mode Class \code{ExecuteCSVMode}}
This class constructs and operates the interface for executing magnetic field sequences from a \gls{csv} file. It is placed in the application's main area, its layout is shown in Figure \ref{fig:csvmodepure}.\\
Apart from a method to load \gls{csv} files, the class manages the separate thread that needs to be created every time a sequence is run. For this purpose, it interfaces mainly with the \code{csv\_threading.py} file to initialize, start and (if needed) stop the thread object. More details on the multithreading functionality is provided in Section \ref{sec:csv_exec}.
\myparagraph{Settings Page Class \code{Configuration}}
The program settings page is constructed in this class. It also controls the reading and writing of configuration files. Like the actual test bench control modes, the settings page is placed in the application's main area. Its layout can be seen in Figure \ref{fig:settingspure}.\\
The class generates and reads out all entry fields the user can use to set program constants like used serial ports, resistances and current limits. It interfaces with the \code{config\_handling.py} file to store this information in a \code{ConfigParser} object and to read and write it from and to configuration files (see Section \ref{sec:config_handling}).\\
Individual entry fields can be highlighted to point out values that exceed the safe limits defined in \code{globals.py} to the user.
\myparagraph{Data Logging Configuration Page Class \code{ConfigureLogging}}
This class generates the page for configuring the logging of test bench data to a \gls{csv} file. Similarly to the settings page it is placed in the main area, its layout is shown in Figure \ref{fig:loggingpure}.\\
The page provides a number of checkboxes used to select what specific data is to be logged. This information is stored in a list of string keys. Whenever a row of data needs to be logged, a method in the class calls the \code{log\_datapoint} function in \code{csv\_logging.py}. To indicate what data to log, the string key list is passed as the function parameter (see Section \ref{sec:logging}). \\
There are two options to control when and how often data is logged: in regular intervals and on event. These can also be used at the same time. The information, which of these is enabled, is stored in two boolean attributes of the class object. For logging in regular intervals a method in the \code{ConfigureLogging} class object periodically calls itself. \\
For logging on event, a data point is generated whenever a significant change on the test bench is commanded. As of now, this is simply done by inserting a piece of code in every function where it was seen as appropriate. However, this is somewhat inconsistent and carries the risk of missing some state changes. A better balance between logging consistency and excessive data generation should be devised in a future update.
\myparagraph{Status Display Class \code{StatusDisplay}}
The status display (bottom left in Figure \ref{fig:ui_overview}) is used to monitor the state of the test bench devices. The individual values are displayed and updated through labels tied to variables of type \code{tkinter.StringVar()}, which are stored in a dictionary. The \code{update\_labels} method then polls the current values from the \code{Axis} and \code{ArduinoCtrl} objects described in Section \ref{sec:cage_func} and updates the label variables. This is done both periodically and on major test bench commands.
\myparagraph{Output Console Class \code{OutputConsole}}
The output console in the bottom right of the \gls{ui} (see Figure \ref{fig:ui_overview}) is generated in this class. The main body is a \code{tkinter.Text} widget. Printing of information to it is done via the custom \code{ui\_print} function, which can be used exactly like the built-in \code{print}.
\subsection{Sequence Execution File \code{csv\_threading.py}}\label{sec:csv_exec}
This file contains code for executing a timed sequence of magnetic field vectors from a \gls{csv} file. To do this without interfering with the \gls{ui}, it must run in a separate thread.\\
The main class for this is \code{ExecCSVThread}. It inherits the \code{Thread} class from the \code{threading} library, so each of its instances represents a unique thread. Its main method, apart from those needed to start and stop it, is \code{execute\_sequence}. It takes the desired sequence in the form of a \code{numpy} array and commands the test bench at the appropriate times. When a new field vector is set, all related actions need to be performed before the scheduler returns to the main thread. A \code{threading.Lock} object is used to ensure this. The method also continuously checks that all devices are still connected and that the run has not been aborted by user input or closing of the main application window.\\
Apart from the main class this file contains functions to read data from a \gls{csv} file to a \code{numpy} array and check that no values in it exceed the test bench limits. There is also a function to generate a plot of the data for display in the \gls{ui}. The line plot is modified to reflect the discrete and nearly instantaneous change of fields in the test bench (see result in Figure \ref{fig:ui_overview}).
\newpage
\subsection{Configuration Handling File \code{config\_handling.py}}\label{sec:config_handling}
This file contains functions and variables for reading and writing configuration files. The processing is done using the \code{configparser} library. \\
The current program configuration is stored in \code{CONFIG\_OBJECT}, an instance of \code{ConfigParser}. It contains all configurable information and can be stored in its entirety in a .ini file. The \code{write\_config\_to\_file} and \code{get\_config\_from\_file} functions are used to read/write the entire \code{CONFIG\_OBJECT} from/to such a file. An example is provided in Appendix \ref{app:example_files}.\\
To access or change specific values the \code{read\_from\_config} and \code{edit\_config} functions are provided. The latter also checks if a value is within the safe limits defined in \code{globals.py}. If it is not, the user is warned and asked to confirm, before the value is written to \code{CONFIG\_OBJECT}.\\
The \code{check\_config} function does this check for all values of a provided configuration object. If excessive values are found, a warning message is displayed and the configuration \gls{ui} page opened, where they are highlighted.\\
The last function of the file is \code{reset\_config\_to\_default}, which overwrites the entire \code{CONFIG\_OBJECT} with the default values defined in \code{globals.py}.
\subsection{Data Logging Handling File \code{csv\_logging.py}}\label{sec:logging}
This file handles the logging of test bench status data to a \gls{csv} file, using the \code{pandas} library. Within the program the logged data is stored in a \code{pandas.DataFrame} object, which represents a table with column headers and data rows.\\
The information about what data can be logged and how to access the specific values is stored in a central dictionary. Its keys are the names of the values as they are displayed in the \gls{ui}, e.g. "Voltage Setpoint" or "Actual Current". The keys are used as handles for accessing the dictionary elements and as labels for the checkboxes in the logging configuration \gls{ui} page (see Figure \ref{fig:loggingpure}). The \code{ConfigureLogging} class of the \gls{ui} generates a list containing the keys belonging to the ticked checkboxes, which is then passed to the logging functions to indicate what data should be logged.
The keys are intentionally identical to the labels used for the status display. This makes it easier for the user to know what each value means. It may also allow unifying some of the code for these two functionalities in the future.\\
The dictionary elements themselves are a string representation of the respective attribute names in the \code{Axis} class. They are used with the \code{getattr} command to get the values of these attributes from the individual axis objects.\\
To log a data point, the mentioned list of keys is passed to the \code{log\_datapoint} function. For each of its elements, the data from all three axes is read out using \code{getattr} as described above. To form the correct number of column headers, the key list is expanded to include each item three times, for example \code{["Target Field"]} becomes \code{["Target Field X", "Target Field Y", "Target Field Z"]}. Together with the values this forms a new \code{DataFrame}, which is then appended to the previously logged data.\\
When the logging is finished, the entire \code{DataFrame} can then be saved to a \gls{csv} file using the \code{write\_to\_file} function. The file also provides functions to allow the user to choose a filename and clear the logged data.
\newpage
\subsection{Hardware Control Libraries}
\myparagraph{PS2000B \gls{psu} Control Library \code{PS2000B.py}}
The code necessary to control the power supply units was adapted from S. Spr{\"o}ßig \cite{PS2000B_lib} with only minor modifications. The library provides the class \code{PS2000B} and some supporting functions. Each object of the class represents a physical \gls{psu}. These objects can be used to access status information and command the device, for example to set currents and voltages. More information can be found in the readme file provided by the original author.\\
The main modification to this library done as part of this thesis, was to implement independent commanding of both \gls{psu} channels. For this an additional parameter \code{channel} (integer type, 0 or 1) was added to all methods of the \code{PS2000B} class that interact with the device.
Additionally the properties \code{PS2000B.output1}, \code{PS2000B.voltage1} and \code{PS2000B.current1} were duplicated to support the second channel (e.g. \code{PS2000B.output2}).
\myparagraph{Arduino Command \gls{api} \code{arduino.py}}
To control the Arduino microcontroller the online library from \cite{Arduino_lib} was integrated without major modifications. To use it, the provided \code{prototype.ino} file needs to be transferred to the Arduino. An object of class \code{Arduino} can then be used to control the board (connected via \gls{usb}) with methods that closely resemble the ones used in the standard Arduino programming language. More details can be found in the readme file provided by the original author \cite{Arduino_lib}.
\section{Conversion to Executable}
The program is compiled to a .exe executable file to enable simple use without a Python installation. For this, the "Auto Py to Exe" tool developed by B. Vollebregt \cite{auto_py_to_exe} is used. The resulting files are distributed in a separate repository on the \gls{irs} git server.\footnote{\url{https://egit.irs.uni-stuttgart.de/zietzm/Helmholtz_Test_Bench_Releases}} When a new software version is ready for publication, the following procedure should be used to release it:
\begin{enumerate}
\item Run "auto-py-to-exe.exe" (provided in main development repository)
\item In the Auto Py to Exe \gls{ui}, select \code{main.py} file as "Script Location"
\item Select options "One File" and "Window Based"
\item Select file "Helmholtz.ico" as the "Icon"
\item Select "Releases" in the development repository as the output folder
\item Execute conversion
\item Rename resulting "main.exe" file to "Helmholtz Cage Control.exe"
\item Verify correct program operation from created executable
\item Copy new executable to the release repository\footnotemark[\value{footnote}] and replace previous version
\item Commit, merge and create a new release in the git web interface
\item Record changes in release notes and changelog and update the documentation
\end{enumerate}
+455
View File
@@ -0,0 +1,455 @@
\chapter{Operating Instructions}\label{chp:users_guide}
\section{Test Bench Assembly Instructions}
Because of the limited space available in the \gls{irs} cleanroom, the test bench may need to be disassembled and reassembled in the future. Instructions for this are provided here. Mentioned position numbers relate to those shown in Figure \ref{fig:assembly}.
\begin{figure}[h]
% preliminary
\sbox\twosubbox{%
\resizebox{\dimexpr.99\textwidth-1em}{!}{%
\includegraphics[trim={3 0 3 0}, clip, height=4cm]{media/Frame_iso.pdf}%
\includegraphics[height=4cm]{media/Cable Routing.png}%
}%
}
\setlength{\twosubht}{\ht\twosubbox}
\centering
\subcaptionbox{Structural frame \cite{Blessing_TestBench} \label{fig:frame_iso2}}{%
\includegraphics[height=\twosubht]{media/Frame_iso.pdf}%
}\quad
\subcaptionbox{Full test bench and cable routing\protect\footnotemark \label{fig:cable_routing2}}{%
\includegraphics[height=\twosubht]{media/Cable Routing.png}%
}
\caption{Test bench assembly drawings}
\label{fig:assembly}
\end{figure}
\footnotetext{Base drawing from \cite{Blessing_TestBench}}
\subsection{Disassembly Procedure}\label{sec:disassembly}
\myparagraph{Notes:}
The coils must always be supported on two sides during handling to avoid bending.\\
The used slot nuts are wedged in the structural profiles and will stay in place even when their screw is removed. In most cases this is desirable, to mark the correct positions for reassembly. If one needs to be removed, loosen the attached screw and gently tap its head with a hammer.\\
\textbf{All removed screws must be stored orderly, as they are needed for future reassembly!}
\paragraph{Procedure:}
\begin{enumerate}
\item Undo cabling
\begin{enumerate}
\item Disconnect switch box from main cable and \gls{psu}s
\item Disconnect coil cables from central screw terminal (Fig. \ref{fig:main_connector})
\item Disconnect screw terminals between coils, leave terminal on one side
\item Untie wires from their guiding structures
\end{enumerate}
\item Remove Z-axis coils
\begin{enumerate}
\item Unscrew upper coil brackets (20) from profiles (08), but leave them on the coil
\item Lift off upper coil (A6)
\item Remove upper coil support profiles (08), leave angle pieces on main structure
\item Repeat procedure for lower coil
\end{enumerate}
\item Remove Y and X-axis coils
\begin{enumerate}
\item Unscrew coil brackets (19) for one Y-axis coil (A5) from frame profiles (07), but leave them on the coil
\item Lift off coil (A5)
\item Repeat procedure for second coil (A5) and X-axis coils (A4)
\end{enumerate}
\item Remove mounting plate (21)
\item Lay remaining frame on its side, mounting plate profiles (09) should be on top and bottom (orientation shown in Figure \ref{fig:assembly_rectangle})
\item Separate "upper" rectangular frame section (highlighted yellow in Figure \ref{fig:assembly_rectangle})
\begin{enumerate}
\item Remove bolts of angles connecting rectangle to cross-member profiles (07), angle pieces should remain on "upper" rectangle
\item Lift off entire rectangle section
\end{enumerate}
\item Remove cross-member profiles (07) from "lower" rectangle section, angles stay attached
\end{enumerate}
\begin{figure}[h!]
\begin{minipage}{0.49\textwidth}
\includegraphics[width=\textwidth]{media/wire_collector}
\caption{Main connector (X-cables temp.)}
\label{fig:main_connector}
\end{minipage}
\begin{minipage}{0.49\textwidth}
\includegraphics[width=\textwidth]{media/disassembly_frame1}
\caption{Intermediate (dis-)assembly step}
\label{fig:assembly_rectangle}
\end{minipage}
\end{figure}
\subsection{Reassembly Procedure}
\myparagraph{Notes:}
These instructions assume a disassembly according to Section \ref{sec:disassembly}. Most slot nuts should still be in place and simplify positioning the parts. However, the angle pieces do allow some tolerance, so care should still be taken to get the correct alignments.
\paragraph{Procedure:}
\begin{enumerate}
\item Lay one main frame rectangle on the floor as shown in Figure \ref{fig:assembly_rectangle}
\item Attach cross-member profiles (07)
\item Attach second frame rectangle on top, state should now be as shown in Figure \ref{fig:assembly_rectangle}.
\item Lift frame upright and adjust foot heights for solid stand
\item Attach mounting plate (21)
\item Install X and Y-axis coils
\begin{enumerate}
\item Lift +X coil (A4) onto cross-member profiles (07); mind wire exit position (Fig. \ref{fig:cable_routing2})
\item If needed, adjust cross-member profile height; coil should be supported equally on upper and lower profiles without bending
\item Centre coil and secure with 3D-printed brackets (19)
\item Repeat for -X (A4)and Y-axis coils (A5)
\end{enumerate}
\item Install Z-axis coils (A6)
\begin{enumerate}
\item Attach lower coil support profiles (08)
\item Lift -Z coil over X/Y coils onto support profiles; mind wire exit position (Fig. \ref{fig:cable_routing2})
\item Centre coil and secure with 3D-printed brackets (20)
\item Repeat for upper support profiles and +Z coil
\end{enumerate}
\item Make electrical connections
\begin{enumerate}
\item Connect screw terminals between coils (unmarked wire ends)
\item Route and tie down wires as shown in Figure \ref{fig:cable_routing2}
\item Check that there are no short circuits between coil wires and frames
\item Connect main screw terminal as shown in Figure \ref{fig:main_connector}
\item Connect main cable to switch box
\item Verify contact on all axes (multimeter at switch box inputs), resistances approx. {\SI{3.1}{\ohm}}
\item Connect switch box to \gls{psu}s: X-axis to \gls{psu} 1 channel 1, Y-axis to \gls{psu} 1 channel 2, Z-axis to \gls{psu} 2 channel 1
\end{enumerate}
\item Setup laptop and initialize control program as described in Section \ref{sec:software_init}
\item Verify correct polarity on all axes through magnetic field measurements at different currents
\item Calibrate test bench (exact procedure to be developed)
\end{enumerate}
\newpage
\section{Software Users Guide}\label{sec:software_guide}
\subsection{Installation}
\begin{enumerate}
\item Download latest release: \url{https://egit.irs.uni-stuttgart.de/zietzm/Helmholtz_Test_Bench_Releases/releases}
\item Unpack ZIP-folder and run "Helmholtz Cage Control.exe"
\item Setup hardware and program according to Section \ref{sec:software_init}
\end{enumerate}
\subsection{User Interface Elements}
The general \gls{ui} layout is shown in Figure \ref{fig:ui_overview}. The upper area contains the interactive elements of each operating mode and settings page. Switching between these pages is done using the top "Menu" bar. The lower half of the \gls{ui} contains the status display and a console output.
\subsubsection*{Status Display}
The status display shows the current state of the test bench devices. Explanations of the different values are given in Table \ref{tab:status_contents}.
\small
\begin{longtable}{lp{12.5cm}}
\caption{Status display entries}\\
\hline
\textbf{Entry} & \textbf{Explanation}\\ \hline
\endfirsthead
\multicolumn{2}{c}%
{\tablename\ \thetable\ -- \textit{Continued from previous page}} \\
\hline
\textbf{Entry} & \textbf{Explanation}\\ \hline
\endhead
\hline \multicolumn{2}{r}{\textit{Continued on next page}} \\
\endfoot
\hline
\endlastfoot
\gls{psu} Serial Port: & Serial \gls{com} port used to connect to the \gls{psu} for this axis. \\[8pt]
\gls{psu} Channel: & \gls{psu} output channel for this axis (0$\rightarrow$channel 1, 1$\rightarrow$channel 2). \\[8pt]
\gls{psu} Status: & Connection status of \gls{psu} for this axis. Possible states: \vspace{-1.5mm}
\begin{itemize}
\setlength\itemsep{-0.2em}
\item \textit{Connected:} communication nominal
\item \textit{Not Connected:} \gls{psu} not found during initialization
\item \textit{Connection Error:} \gls{psu} was connected but then an error occurred, e.g. it was disconnected
\end{itemize} \\[-4pt]
Arduino Status: & Connection status of switch box Arduino (identical for all axes). Possible states: \vspace{-1.5mm}
\begin{itemize}
\setlength\itemsep{-0.2em}
\item \textit{Connected:} communication nominal
\item \textit{Not Connected:} Arduino not found during initialization
\item \textit{Connection Error:} Arduino was connected but then an error occurred, e.g. it was disconnected
\end{itemize} \\[-4pt]
Output: & Status of \gls{psu} output channel. Possible states: \vspace{-1.5mm}
\begin{itemize}
\setlength\itemsep{-0.2em}
\item \textit{Active:} set current or voltage is applied to the output jacks
\item \textit{Inactive:} output jacks are unpowered
\item \textit{Unknown:} no connection to \gls{psu}
\end{itemize} \\[-4pt]
Remote Control: & Status of \gls{psu} channel remote interface. Possible states: \vspace{-1.5mm}
\begin{itemize}
\setlength\itemsep{-0.2em}
\item \textit{Active:} channel can be controlled remotely
\item \textit{Inactive:} channel can not be controlled remotely
\item \textit{Unknown:} no connection to \gls{psu}
\end{itemize}\\[-4pt]
Voltage Setpoint: & Maximum voltage \gls{psu} is set to supply. \\[4pt]
Actual Voltage: & Voltage across \gls{psu} channel output jacks. Usually lower than "Voltage Setpoint", as voltage is throttled to achieve the desired current. \\[16pt]
Current Setpoint: & Current the \gls{psu} output channel is set to supply \\[8pt]
Actual Current: & Current flowing through the \gls{psu} output channel. \\[8pt]
Target Field: & Desired magnetic flux density in the measurement area. \\[8pt]
Trgt. Field Raw: & Flux density used to calculate needed current (after ambient field compensation). \\[8pt]
Target Current: & Desired current to flow through the coils. Negative values mean reversed polarity. \\[8pt]
Inverted: & Status of polarity change relay for this axis inside the switch box. Possible states:\vspace{-1.5mm}
\begin{itemize}
\setlength\itemsep{-0.2em}
\item \textit{True:} (Arduino pin "HIGH"$\rightarrow$relay switched$\rightarrow$polarity inverted, status \gls{led} should be illuminated)
\item \textit{False:} pin "LOW"$\rightarrow$opposite of "True" state
\item \textit{Unknown:} no connection to Arduino
\end{itemize}\\[-20pt]
\label{tab:status_contents}
\end{longtable}
\normalsize
\subsubsection*{Manual Mode}\label{sec:manual_mode_guide}
The manual input mode is used to set static currents or magnetic fields on the test bench. Its layout is shown in Figure \ref{fig:manualmodepure}. The main \gls{ui} elements are listed below.
\begin{figure}[h]
\centering
\includegraphics[width=0.5\linewidth]{media/manual_mode_pure}
\caption{Manual input mode user interface}
\label{fig:manualmodepure}
\end{figure}
\begin{itemize}
\item \textbf{"Select Input Mode" drop-down}: Switches between setting currents or magnetic fields
\item \textbf{Value entry fields:} Enter values to be set on the test bench here
\begin{itemize}
\item Entries must be numeric (decimal point)
\item Entries must be in indicated safe range (may be changed in the settings page)
\end{itemize}
\item \textbf{"Compensate ambient field" checkbox:} When ticked, the ambient magnetic field (set in settings page) is subtracted from entered values before commanding the test bench (inactive for "Current" input mode)
\item \textbf{"Execute" button:} Implements values from the entry fields
\begin{itemize}
\item Commands currents on \gls{psu}s and polarity on switch box
\item If a device is not connected, the remaining ones are still commanded
\item Values beyond safe limits (indicated to the right of entry fields) are rejected
\item Device status and any errors are displayed in status display and console
\end{itemize}
\item \textbf{"Power Down All" button}: "Panic button", sets currents on both \gls{psu}s to 0, deactivates outputs and sets switch box relay pins to inactive state
\item \textbf{"Reinitialize" button:} Reruns program initialization
\begin{itemize}
\item Reinitializes connection to \gls{psu}s and switch box Arduino
\item Press after (re)connecting a device to let program establish communications
\end{itemize}
\end{itemize}
\textbf{To command a field vector or currents on the test bench:}
\begin{enumerate}
\item Select needed input mode, using the drop-down menu
\item Enter desired values in entry fields
\item For magnetic fields, choose whether ambient field should be compensated by (un)ticking the checkbox
\item Press "Execute" button, devices will now implement set values
\item Check console output to see if any errors occurred
\item Monitor behaviour in status display and on devices
\item When finished, press "Power Down All" button to remove currents from the test bench
\end{enumerate}
\subsubsection*{CSV Sequence Execution Mode}\label{sec:csv_mode_guide}
This mode is used to run timed sequences of magnetic fields. These have to be defined in a \gls{csv} file of the following form:
\begin{itemize}
\item \textit{Column separator:} Semicolon (;)
\item \textit{Decimal:} Comma (,)
\item \textit{Line terminator:} Tested with Windows standard (\code{\textbackslash r\textbackslash n}), other options may work as well
\item \textit{Columns:} Time in seconds; X-axis, Y-axis and Z-axis flux density in Tesla
\end{itemize}
An example for the \gls{csv} file structure is given below:
%[caption=Example \gls{csv} file]
\begin{lstlisting}
Time (s);xField (T);yField (T);zField (T)
0,5;0,000015;0,000025;0,00002
1;0,0000155;0,0000245;0,0000205
\end{lstlisting}
When loading such a file, the application will check that there are no values exceeding the safe test bench limits in the sequence. If any are found, a warning message is shown and the limits displayed in the sequence graph. It is still possible to execute such a sequence, however the excessive values will not be commanded. For those time stamps, \SI{0}{\ampere} is set instead. The limits may be adjusted in the program settings page, but care should be taken to avoid equipment damage.\\
\begin{figure}[h]
\centering
\includegraphics[width=\textwidth]{media/csv_mode_pure}
\caption{CSV sequence mode user interface}
\label{fig:csvmodepure}
\end{figure}
The \gls{ui} layout is shown in Figure \ref{fig:csvmodepure}, its main elements are listed below.
\begin{itemize}
\item \textbf{"Select csv file..." button:} Opens a file dialog to let user choose a \gls{csv} file to execute
\item \textbf{"Run Sequence" button} Starts executing the sequence from the chosen \gls{csv} file
\item \textbf{"Stop Run" button:} Aborts sequence execution
\item \textbf{"Reinitialize devices" button:} Reruns program initialization
\begin{itemize}
\item Reinitializes connection to \gls{psu}s and switch box Arduino
\item Press after (re)connecting a device to let program establish communications
\end{itemize}
\item \textbf{"Disable device connection checks" checkboxes:} Disable connection check for specific devices, allowing sequence execution with some equipment missing
\item \textbf{Graph display:} Displays graph of field sequence, as it will be executed by the test bench
\end{itemize}
\newpage
\textbf{To execute a field sequence:}
\begin{enumerate}
\item Ensure correct configuration of program and test bench in the settings page
\item Prepare sequence in \gls{csv} file with correct format (external program)
\item Press "Select csv file..." button, select prepared file and open
\item Check plots to confirm sequence was loaded correctly and no values exceed safe limits
\item If not all devices are used, check boxes of unused devices to disable connection check
\item Press "Run Sequence" button
\item Monitor execution in console, status display and on devices
\end{enumerate}
\subsubsection*{Data Logging Configuration Page}\label{sec:logging_guide}
The application has the ability to log test bench data to a \gls{csv} file. The data is temporarily stored internally and must be saved to an external file by user request.\\
An example of a log file is given in Appendix \ref{app:example_files}. The first three columns are time stamps: date, system time and time since the start of logging in seconds. The other columns contain the data, as selected by the user. All dynamic values from the status display can be logged, see Table \ref{tab:status_contents} for explanations. Each type of data is logged for all three axes. The units for numerical values are Volt, Ampere and Tesla.\\
There are two options as for when and how often data is logged. The first option logs a row of data in a regular time interval specified by the user. The second option logs, whenever a significant command is sent to the test bench, for example when a new field vector is commanded. Both options can be used simultaneously.\\
The logging configuration \gls{ui} is shown in Figure \ref{fig:loggingpure}. Its elements are listed below.
\begin{figure}[h]
\centering
\includegraphics[width=0.6\linewidth]{media/logging_mode_pure}
\caption{Data logging configuration page}
\label{fig:loggingpure}
\end{figure}
\begin{itemize}
\item \textbf{"Start Logging" button:} Starts the logging of data, as configured in the other elements
\item \textbf{"Stop Logging" button:} Stops the logging of data
\item \textbf{"Write data to file" button:} Lets user save the logged data to a file
\begin{itemize}
\item Opens dialogue to let user select a file path (chosen file name must be *.csv)
\item Saves logged data to the selected file
\end{itemize}
\item \textbf{"Clear logged data" button:} Deletes all data logged internally by the program, user will be asked if data should be saved to a file first
\item \textbf{"Datapoints logged" counter:} Displays the current number of logged data rows
\item \textbf{"Log in regular intervals" controls:} Enable checkbox to periodically log data, set interval (in seconds) in the entry field to the right
\item \textbf{"Log whenever test bench is commanded" checkbox:} Enable, to log data on significant changes to the test bench (e.g. a new field vector is commanded)
\item \textbf{Data selection checkboxes:} Select what data to log, explanations are given in Table \ref{tab:status_contents}
\end{itemize}
\textbf{To collect and save log data:}
\begin{enumerate}
\item Select when to log data (both options can be used simultaneously)
\begin{itemize}
\item For regular logging, enable "Log in regular intervals" checkbox and set desired interval
\item For logging on test bench command, enable second checkbox
\end{itemize}
\item Select what data to log, using the lower checkboxes
\item Press "Start Logging" button
\item When finished, press "Stop Logging" button
\item Press "Write data to file" button
\item Choose file location and name (must be *.csv, e.g. my\_log.csv), and press save
\item Press "Clear logged data" button (optional)
\end{enumerate}
\newpage
\subsubsection*{Settings Page}\label{sec:settings_guide}
This is the main page for configuring the program. The settings can be stored to and loaded from *.ini configuration files.\\
The different program constants are set through a series of entry fields. All imputs must be numerical values (decimal points). Safe limits for each value are set inside the program. The constants and limits are listed in Table \ref{tab:settings_entries}. If a value exceeding those boundaries is entered, a warning message is displayed and the respective entry field marked in red. \textbf{It is not recommended to ignore these warnings, as incorrect settings can damage equipment on the test bench!}
\begin{figure}[h]
\centering
\includegraphics[width=0.8\linewidth]{media/config_mode_pure}
\caption{Program settings page}
\label{fig:settingspure}
\end{figure}
Figure \ref{fig:settingspure} shows a screenshot of the \gls{ui} layout with the default settings. The main elements are listed below.
\begin{itemize}
\item \textbf{"Load config file..." button:} Imports an existing configuration file
\begin{itemize}
\item Opens file dialogue for selecting configuration file
\item Loads settings from selected file
\item Checks if any settings exceed safe limits and, if so, displays warning messages
\item Reinitializes test bench devices with new settings
\end{itemize}
\item \textbf{"Save current config" button:} Writes settings to the currently selected file and reinitializes test bench devices with new settings
\item \textbf{"Save current config as..." button:} Writes settings to a new file
\begin{itemize}
\item Opens dialogue to let user choose new file path and name (must be *.ini)
\item Reinitializes test bench devices with current settings
\end{itemize}
\item \textbf{"\gls{psu} Serial Port" entries:} Input \gls{com} ports for both \gls{psu}s here
\begin{itemize}
\item Use Windows device manager to find correct port names (connect \gls{psu}s separately to differentiate between devices)
\item Test bench X- and Y-axes need to be connected to channel 1 and 2 of one \gls{psu}, Z-axis to channel 1 of the other
\item \textit{Note: Switch box Arduino should be found automatically}
\end{itemize}
\item \textbf{Program constant entry fields:} Set constants here, details are listed in Table \ref{tab:settings_entries}
\item \textbf{"Update and Reinitialize" button:} Implements any changed settings in the program and on test bench devices, needs to be pressed for changes to take effect
\item \textbf{"Restore Defaults" button:} Restores default settings
\end{itemize}
\begin{table}[ht]
\small
\caption{Settable program constants}
\begin{tabular}{llp{10.2cm}}
\hline
\textbf{Entry} & \textbf{Limits} & \textbf{Explanation}\\ \hline
\rule{0pt}{12pt} Coil Constants: & 0 to \SI{50}{\micro\tesla\per\ampere} & Magnetic field generated per applied current \vspace{-1.5mm}
\begin{itemize}
\setlength\itemsep{-0.2em}
\item Used to calculate current needed to achieve desired field
\item Must be measured and tuned before test campaigns
\end{itemize}\\[-4pt]
Ambient Field: & -200 to \SI{200}{\micro\tesla} & Background magnetic field in the measurement area \vspace{-1.5mm}
\begin{itemize}
\setlength\itemsep{-0.2em}
\item Subtracted from desired field to compensate ambient field
\item Must be measured and tuned before test campaigns
\end{itemize}\\[-4pt]
Resistances: & 1 to \SI{5}{\ohm} & Electrical resistance of each axis, measure from \gls{psu} connectors \\[8pt]
Max. Current: & 0 to 6 \si{\ampere} & Current limit for each axis \vspace{-1.5mm}
\begin{itemize}
\setlength\itemsep{-0.2em}
\item Program will block commanding of higher values on \gls{psu}
\item Maximum safe permanent current: $I_{max}=\SI{5.5}{\ampere}$ \cite{Blessing_TestBench}
\end{itemize}\\[-4pt]
Max. Voltage: & 0 to \SI{16}{\volt} & Voltage limit for each axis \vspace{-1.5mm}
\begin{itemize}
\setlength\itemsep{-0.2em}
\item Program will block commanding of higher values on \gls{psu}
\item Maximum safe voltage, limited by diodes inside switch box: $U_{max}=\SI{16}{\volt}$
\end{itemize}\\[-4pt]
Arduino Pins: & 15,16,17 & Output pins on switch box Arduino for inverting polarity on each axis (hard wired inside switch box, should not need to be changed) \\
\hline
\end{tabular}
\label{tab:settings_entries}
\end{table}
\clearpage
\subsection{Hardware Connections and Program Setup}\label{sec:software_init}
\begin{enumerate}
\item Connect hardware
\begin{enumerate}
\item Connect switch box to test bench main cable bundle (connector on the back)
\item Connect switch box to \gls{psu}s: \textbf{X-axis to \gls{psu} 1 channel 1, Y-axis to \gls{psu} 1 channel 2, Z-axis to \gls{psu} 2 channel 1}
\item Connect switch box power supply (\SI{12}{\volt} DC)
\item Connect switch box \gls{usb} port to \gls{pc}
\item Connect \gls{psu} \gls{usb} ports to \gls{pc}
\end{enumerate}
\item Configure interfaces to hardware
\begin{enumerate}
\item Start program (run "Helmholtz Cage Control.exe")
\item Go to settings page (Menu$\rightarrow$Settings...)
\end{enumerate}
\begin{itemize}
\item If program has not been configured before:
\begin{enumerate}
\setcounter{enumii}{2}
\item Use Windows device manager to find correct serial \gls{com} ports for \gls{psu}s (connect /disconnect in turn to differentiate between devices)
\item Enter \gls{com} port names in application (switch box should be found automatically)
\item Press "Update and Reinitialize" button
\end{enumerate}
\item If a previous configuration exists:
\begin{enumerate}
\setcounter{enumii}{2}
\item Press "Load config file..." button
\item Select configuration file (e.g. "myconfig.ini") and open
\item Check that the settings were loaded correctly and no values violate the safe limits (fields highlighted in red)
\end{enumerate}
\end{itemize}
\begin{enumerate}
\setcounter{enumii}{5}
\item Check console print to see if all devices were found, otherwise check physical connections and \gls{com} port settings
\end{enumerate}
\item Test configuration
\begin{enumerate}
\item Go to manual mode (Menu$\rightarrow$Static Manual Input)
\item Switch input mode to "Current" (see Section \ref{sec:manual_mode_guide})
\item Set different currents and check device response:
\begin{itemize}
\item Current should be activated on correct \gls{psu} channel
\item For negative currents, corresponding status \gls{led} on switch box should light up and relay actuation be audible as clicking sound
\end{itemize}
\end{enumerate}
\item Go back to the settings page (Menu$\rightarrow$Settings...)
\item Change program constants as needed (e.g. enter measured ambient field), see Section \ref{sec:settings_guide}
\item Save configuration:
\begin{itemize}
\item Press "Save current config" button to update the current configuration file
\item Press "Save current config as..." button to save to a new configuration file, set new file name in file dialogue (e.g. "myconfig.ini")
\end{itemize}
\end{enumerate}
@@ -0,0 +1,190 @@
% Template for B.Sc, M.Sc. thesis, etc.
% Originally created by Michael Lauer and Dagmar Bock
% Updated by Roland A. Gabrielli
% Translated and updated by Adam S. Pagan
%
% Font size 11pt, paper size DIN A4, Book, additional 0.5cm for binding on the left
% pdf created via dvi and ps
\documentclass[a4paper,DIV14,11pt,headsepline,oneside,openany,listof=totoc,BCOR5mm]{scrbook}
% Page formatting
\usepackage{scrlayer-scrpage}
\pagestyle{scrheadings}
\ofoot[\pagemark]{\pagemark}
\cfoot[]{}
\ohead{\textsc{\headmark}}
\chead{}
\ihead{}
% Special packages
\usepackage[dvipsnames]{xcolor}
\usepackage{graphicx}
\usepackage[dvips]{rotating}
\usepackage{floatflt,wrapfig}
\usepackage{verbatim}
\usepackage{isotope}
\usepackage[absolute]{textpos}
\usepackage{siunitx}
\sisetup{
per-mode=fraction,
fraction-function=\tfrac
}
\usepackage{pythonhighlight}
\usepackage{listings}
\usepackage{todonotes}
\usepackage{placeins}
\usepackage{footnote}
% AMS-LaTeX packages:
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsthm}
% Improved pdf presentation
\usepackage{ae}
\usepackage{pdfpages}
% Additional table commands
\usepackage{array}
\usepackage{dcolumn}
\usepackage{longtable}
\usepackage{tabularx}
\usepackage{ltxtable}
\usepackage{longtable}
\usepackage{supertabular}
\usepackage{subcaption}
\usepackage{booktabs}
\usepackage{multicol}
\usepackage{multirow}
\usepackage{threeparttable}
% Additional symbols
\usepackage{wasysym}
\usepackage{textcomp}
\usepackage{pifont}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{eurosym}
\chardef\_=`_ % enable use of underscores in text with \_
% Text commands
\newcommand{\code}[1]{\texttt{#1}} % command for inline code (changes font)
\newcommand{\myparagraph}[1]{\paragraph{#1}\mbox{}\\} % create paragraph where text starts in new line
% Positioning of tables and figures after first mention
\usepackage{flafter}
% DOI and URL
\usepackage{url}
%\usepackage{doi}
% Referencing
\usepackage[backend=biber,style=iso-numeric]{biblatex}
\addbibresource{References.bib}
\DeclareFieldFormat{labelnumberwidth}{\mkbibbrackets{#1}}
\usepackage[hidelinks]{hyperref}
\usepackage[nopostdot]{glossaries}
\makeglossaries
\setacronymstyle{long-short}
\loadglsentries{Abbreviation}
\usepackage{enumitem}
% Sets automatic graphics path
\graphicspath{{media}}
% Maximum size of figures
\renewcommand{\floatpagefraction}{.8}
\renewcommand{\topfraction}{.85}
% Define thicker table line
\makeatletter
\def\thickhline{%
\noalign{\ifnum0=`}\fi\hrule \@height \thickarrayrulewidth \futurelet
\reserved@a\@xthickhline}
\def\@xthickhline{\ifx\reserved@a\thickhline
\vskip\doublerulesep
\vskip-\thickarrayrulewidth
\fi
\ifnum0=`{\fi}}
\makeatother
% place floats on top of the pages where there are only floats
\makeatletter
\setlength{\@fptop}{10pt}
\makeatother
\makeatletter
\g@addto@macro{\UrlBreaks}{\do\2\do\1}
\makeatother
\newlength{\thickarrayrulewidth}
\setlength{\thickarrayrulewidth}{3\arrayrulewidth}
% prepare subfigure of same height (https://tex.stackexchange.com/questions/218378/forcing-subfigures-to-have-same-height-and-take-overall-x-of-linewidth-in-latex)
\newlength{\twosubht}
\newsavebox{\twosubbox}
%
\setlength{\parindent}{0mm}
%\setlength{\unitlength}{1mm}
%\sloppy
% ********************************************************************
% Begin of document
\begin{document}
% Title page
\include{Preamble/TitlePage}
\frontmatter
% Subject, preface, abstract, acknowledgements, etc.
% \includepdf{SubjectOfThesis\_Signed.pdf}
\pagestyle{scrplain}
% Table of contents
\tableofcontents
%\addcontentsline{toc}{chapter}{Contents} % Manually adds self-reference of contents
% List of figures and list of tables
\listoffigures
\listoftables
%\begin{small}
% List of symbols
\include{Preamble/ListOfSymbols}
%\end{small}
\setlist[description]{leftmargin=!, labelwidth=5em} % Change for glossaries
\printglossary[nonumberlist]
\setlist[description]{style=standard} % reset settings back to default
% Main body of work (starting with the introduction)
\mainmatter
\pagestyle{scrheadings}
% acronyms that should not be expanded at first mention:
\glsunset{pla}
\glsunset{usb}
\glsunset{pc}
\glsunset{tbd}
\glsunset{com}
\include{Chapters/03_Software}
\include{Chapters/04_Users Guide}
% References
%\bibliographystyle{acm}
%\bibliography{References}
\addcontentsline{toc}{chapter}{Bibliography} % Manually adds bibliography to contents
\printbibliography
% Appendix
\newpage
\appendix
\include{Appendix/AppendixA}
\end{document}
% End of document
% ********************************************************************
+15
View File
@@ -0,0 +1,15 @@
\chapter{List of Symbols}
\begin{tabular}[t]{p{1.5cm}lc}
\textbf{Symbol} & \textbf{Description} & \textbf{Unit} \\[0.6em]
$B$ & Magnetic flux density & \si{\tesla} \\[0.6em]
$B_0$ & Ambient magnetic flux density & \si{\tesla} \\[0.6em]
$B_{max}$ & Maximum achievable magnetic flux density & \si{\tesla} \\[0.6em]
$B_{max}$ & Minimum achievable magnetic flux density & \si{\tesla} \\[0.6em]
$I$ & Current & \si{\ampere} \\[0.6em]
$I_{max}$ & Maximum current & \si{\ampere} \\[0.6em]
$K$ & Coil constant & \si{\tesla\per\ampere} \\[0.6em]
$R$ & Electrical resistance & \si{\ohm} \\[0.6em]
$U$ & Voltage & \si{\volt} \\[0.6em]
$U_{max}$ & Maximum voltage & \si{\volt} \\[0.6em]
\end{tabular}
+29
View File
@@ -0,0 +1,29 @@
\mbox{}
\thispagestyle{empty}
\begin{textblock*}{124mm}(51mm,47mm)
\begin{center}
\begin{Large}
\textbf{Helmholtz Test Bench Control Software Documentation}\\[5mm]
\end{Large}
\end{center}
\end{textblock*}
\begin{textblock*}{124mm}(51mm,180mm)
\begin{center}
Author:\\
Martin Zietz\\
Supervisors:\\
M.Sc. Markus T. Koller\\
M.Sc. Lukas-Maximilian Loidold\\
\end{center}
\end{textblock*}
\begin{textblock*}{124mm}(51mm,250mm)
\begin{center}
Institut f{\"u}r Raumfahrtsysteme, Universit{\"a}t Stuttgart\\
März 2021
\end{center}
\end{textblock*}
@@ -0,0 +1,11 @@
Using the modified AIAA style:
1. Copy modified file aiaa.bst into path 'C:\Program Files\MiKTeX 2.9\bibtex\bst\aiaa' (or equivalent) and overwrite original file (be sure to createe a backup first).
2. Implement the packages 'url' and 'doi' into the master file of your thesis:
\usepackage{url}
\usepackage{doi}.
3. Modify your bibliography (.bib) file in the following manner:
Instead of 'url = {http://www.url.de}', use 'url = {\url{http://www.url.de}}' to create an active hyperlink in the resulting PDF file. Proceed in the same manner for DOI links, e.g.
'doi={\doi{10.2514/6.1997-3074}}' instead of 'doi={10.2514/6.1997-3074}'.
+1
View File
@@ -0,0 +1 @@
+175
View File
@@ -0,0 +1,175 @@
% Instead of 'url = {http://www.url.de}', use 'url = {\url{http://www.url.de}}' to create an active hyperlink in the resulting PDF file.
% Same manner for DOI links, e.g. 'doi={\doi{10.2514/6.1997-3074}}' instead of 'doi={10.2514/6.1997-3074}'.
@thesis{Blessing_TestBench,
author = {Steffen Blessing},
title = {Design of a CubeSat Magnetic Field Cage for the Verification of CubeSats Attitude Control Systems},
date = {2020},
institution = {Institute for Space Systems (IRS), University of Stuttgart},
location = {Stuttgart},
}
@online{PS2000B_lib,
author = {Sören Sprößig},
title = {Python PS2000B Library},
url = {https://github.com/ssproessig/Python-PS2000B},
urldate = {2020-11-18},
}
@online{Arduino_lib,
title = {Arduino Python 3 Command API},
url = {https://github.com/mkals/Arduino-Python3-Command-API},
urldate = {2020-12-09},
}
@online{auto_py_to_exe,
title = {Auto Py to Exe},
author = {Brent Vollebregt},
url = {https://github.com/brentvollebregt/auto-py-to-exe},
urldate = {2020-03-02},
}
@online{Tkinter_tutorial,
author = {Harrison Kinsley},
title = {Object Oriented Programming Crash Course with Tkinter},
url = {https://pythonprogramming.net/object-oriented-programming-crash-course-tkinter/},
urldate = {2021-01-19},
}
@INPROCEEDINGS{eive_paper,
author={B. {Schoch} and S. {Chartier} and U. {Mohr} and M. {Koller} and S. {Klinkner} and I. {Kallfass}},
booktitle={2020 IEEE Space Hardware and Radio Conference (SHaRC)},
title={Towards a CubeSat Mission for a Wideband Data Transmission in E-Band},
year={2020},
volume={},
number={},
pages={16-19},
doi={10.1109/SHaRC47220.2020.9034007}
}
@report{em_präsi_ital,
author = {Lorenzo Lunini},
title = {Future Satellite TLC systems: The challenge of using very high frequency bands},
type = {5th International Multi-Topic ICT Conference},
institution = {Politecnico die Milano},
date = {2018-04-25},
url = {http://luini.deib.polimi.it/docs/Pubblicazioni/AtmosphericChannelModeling_IMTIC2018.pdf},
pages = {7},
}
@online{esa_em_bands,
title = {Satellite frequency bands},
url = {https://www.esa.int/Applications/Telecommunications_Integrated_Applications/Satellite_frequency_bands},
organization = {European Space Agency},
urldate = {2021-02-27},
}
@report{wegertseder_steels,
title = {Werkstoffe - Edelstähle},
institution = {Wegertseder GmbH},
url = {https://www.wegertseder.com/download/techdat/pdf/420-Zusammensetzung-Edelstahl.pdf},
urldate = {2020-11-13},
}
@report{austenitic_steel,
title = {Austenitischer Stahl},
institution = {BorTec SMT GmbH},
url = {https://www.edelstahl-haerten.de/werkstoffe/austenitischer-stahl/},
urldate = {2020-11-13},
}
@report{cds_6u,
title = {6U CubeSat Design Specification},
date = {2018-06-07},
version = {Revision 1.0},
institution = {California Polytechnic State University},
url = {https://static1.squarespace.com/static/5418c831e4b0fa4ecac1bacd/t/5b75dfcd70a6adbee5908fd9/1534451664215/6U_CDS_2018-06-07_rev_1.0.pdf},
urldate = {2020-03-03},
}
@report{cds,
title = {CubeSat Design Specification},
date = {2014-02-20},
version = {Revision 13},
institution = {California Polytechnic State University},
url = {https://blogs.esa.int/philab/files/2019/11/RD-02_CubeSat_Design_Specification_Rev._13_The.pdf},
urldate = {2020-03-03},
}
@report{ps2000b_datasheet,
title = {EA-PS 2000B Power Supply Unit},
date = {2020},
institution = {Elektro-Automatik GmbH},
url = {https://elektroautomatik.com/shop/media/pdf/7e/58/df/datasheet_ps2000b_tft.pdf},
urldate = {2020-11-27},
}
@book{lin_regression,
doi = {10.1007/978-3-658-19732-2},
url = {https://doi.org/10.1007%2F978-3-658-19732-2},
year = 2018,
publisher = {Springer Fachmedien Wiesbaden},
author = {Irasianty Frost},
title = {Einfache lineare Regression},
pages = {9},
}
@report{lis3mdl_datasheet,
title = {LIS3MDL Digital Output Magnetic Sensor},
date = {2017},
institution = {ST Microelectronics},
url = {https://www.st.com/resource/en/datasheet/lis3mdl.pdf},
urldate = {2020-03-06},
}
@book{Fasoulas_rs,
doi = {10.1007/978-3-662-49638-1},
url = {https://doi.org/10.1007%2F978-3-662-49638-1},
year = 2017,
publisher = {Springer Berlin Heidelberg},
author = {Ernst Messerschmid and Stefanos Fasoulas},
title = {Raumfahrtsysteme}
}
@report{sensys_software,
title = {Manual Digitizer FGM3D TD},
date = {2020},
institution = {SENSYS GmbH},
version = {Version 1.1},
}
@report{relay,
title = {Serie 55 - Industrie-Relais 7 - 10 A},
date = {2018},
institution = {Finder S.p.A.},
url = {https://finder-relais.net/de/finder-relais-serie-55.pdf},
urldate = {2020-12-13},
}
@report{arduino_uno,
title = {Arduino Uno Rev3 SMD},
institution = {Arduino AG},
url = {https://store.arduino.cc/arduino-uno-rev3-smd},
urldate = {2021-03-02},
}
@report{phyphox,
title = {Phyphox Application},
institution = {2nd Institute of Physics, RWTH Aachen},
url = {https://phyphox.org/de/download-de/},
urldate = {2021-02-20},
}
@report{fgm3d_mgm,
title = {FGM3D three-axis Fluxgate Magnetometer},
institution = {SENSYS GmbH},
url = {https://sensysmagnetometer.com/products/sensors-recorder/fluxgates/fgm3d-magnetometer/},
urldate = {2021-03-03},
}
@article{source,
title={Combination of Interdisciplinary Training in Space Technology with Project-Related Work through the CubeSat SOURCE},
author={Stier, Annika and Schweigert, Robin and Galla, Daniel and Lengowski, Michael and Klinkner, Sabine},
year={2020},
publisher={University of Leicester}
}
File diff suppressed because it is too large Load Diff
+449
View File
@@ -0,0 +1,449 @@
%%
%% This is file `longtable.sty',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% longtable.dtx (with options: `package')
%%
%% This is a generated file.
%%
%% The source is maintained by the LaTeX Project team and bug
%% reports for it can be opened at http://latex-project.org/bugs.html
%% (but please observe conditions on bug reports sent to that address!)
%%
%% Copyright 1993-2016
%% The LaTeX3 Project and any individual authors listed elsewhere
%% in this file.
%%
%% This file was generated from file(s) of the Standard LaTeX `Tools Bundle'.
%% --------------------------------------------------------------------------
%%
%% It may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License, either version 1.3c
%% of this license or (at your option) any later version.
%% The latest version of this license is in
%% http://www.latex-project.org/lppl.txt
%% and version 1.3c or later is part of all distributions of LaTeX
%% version 2005/12/01 or later.
%%
%% This file may only be distributed together with a copy of the LaTeX
%% `Tools Bundle'. You may however distribute the LaTeX `Tools Bundle'
%% without such generated files.
%%
%% The list of all files belonging to the LaTeX `Tools Bundle' is
%% given in the file `manifest.txt'.
%%
%% File: longtable.dtx Copyright (C) 1990-2001 David Carlisle
\NeedsTeXFormat{LaTeX2e}[1995/06/01]
\ProvidesPackage{longtable}
[2014/10/28 v4.11 Multi-page Table package (DPC)]
\def\LT@err{\PackageError{longtable}}
\def\LT@warn{\PackageWarning{longtable}}
\def\LT@final@warn{%
\AtEndDocument{%
\LT@warn{Table \@width s have changed. Rerun LaTeX.\@gobbletwo}}%
\global\let\LT@final@warn\relax}
\DeclareOption{errorshow}{%
\def\LT@warn{\PackageInfo{longtable}}}
\DeclareOption{pausing}{%
\def\LT@warn#1{%
\LT@err{#1}{This is not really an error}}}
\DeclareOption{set}{}
\DeclareOption{final}{}
\ProcessOptions
\newskip\LTleft \LTleft=\fill
\newskip\LTright \LTright=\fill
\newskip\LTpre \LTpre=\bigskipamount
\newskip\LTpost \LTpost=\bigskipamount
\newcount\LTchunksize \LTchunksize=20
\let\c@LTchunksize\LTchunksize
\newdimen\LTcapwidth \LTcapwidth=4in
\newbox\LT@head
\newbox\LT@firsthead
\newbox\LT@foot
\newbox\LT@lastfoot
\newcount\LT@cols
\newcount\LT@rows
\newcounter{LT@tables}
\newcounter{LT@chunks}[LT@tables]
\ifx\c@table\undefined
\newcounter{table}
\def\fnum@table{\tablename~\thetable}
\fi
\ifx\tablename\undefined
\def\tablename{Table}
\fi
\newtoks\LT@p@ftn
\mathchardef\LT@end@pen=30000
\def\longtable{%
\par
\ifx\multicols\@undefined
\else
\ifnum\col@number>\@ne
\@twocolumntrue
\fi
\fi
\if@twocolumn
\LT@err{longtable not in 1-column mode}\@ehc
\fi
\begingroup
\@ifnextchar[\LT@array{\LT@array[x]}}
\def\LT@array[#1]#2{%
\refstepcounter{table}\stepcounter{LT@tables}%
\if l#1%
\LTleft\z@ \LTright\fill
\else\if r#1%
\LTleft\fill \LTright\z@
\else\if c#1%
\LTleft\fill \LTright\fill
\fi\fi\fi
\let\LT@mcol\multicolumn
\let\LT@@tabarray\@tabarray
\let\LT@@hl\hline
\def\@tabarray{%
\let\hline\LT@@hl
\LT@@tabarray}%
\let\\\LT@tabularcr\let\tabularnewline\\%
\def\newpage{\noalign{\break}}%
\def\pagebreak{\noalign{\ifnum`}=0\fi\@testopt{\LT@no@pgbk-}4}%
\def\nopagebreak{\noalign{\ifnum`}=0\fi\@testopt\LT@no@pgbk4}%
\let\hline\LT@hline \let\kill\LT@kill\let\caption\LT@caption
\@tempdima\ht\strutbox
\let\@endpbox\LT@endpbox
\ifx\extrarowheight\@undefined
\let\@acol\@tabacol
\let\@classz\@tabclassz \let\@classiv\@tabclassiv
\def\@startpbox{\vtop\LT@startpbox}%
\let\@@startpbox\@startpbox
\let\@@endpbox\@endpbox
\let\LT@LL@FM@cr\@tabularcr
\else
\advance\@tempdima\extrarowheight
\col@sep\tabcolsep
\let\@startpbox\LT@startpbox\let\LT@LL@FM@cr\@arraycr
\fi
\setbox\@arstrutbox\hbox{\vrule
\@height \arraystretch \@tempdima
\@depth \arraystretch \dp \strutbox
\@width \z@}%
\let\@sharp##\let\protect\relax
\begingroup
\@mkpream{#2}%
\xdef\LT@bchunk{%
\global\advance\c@LT@chunks\@ne
\global\LT@rows\z@\setbox\z@\vbox\bgroup
\LT@setprevdepth
\tabskip\LTleft \noexpand\halign to\hsize\bgroup
\tabskip\z@ \@arstrut \@preamble \tabskip\LTright \cr}%
\endgroup
\expandafter\LT@nofcols\LT@bchunk&\LT@nofcols
\LT@make@row
\m@th\let\par\@empty
\everycr{}\lineskip\z@\baselineskip\z@
\LT@bchunk}
\def\LT@no@pgbk#1[#2]{\penalty #1\@getpen{#2}\ifnum`{=0\fi}}
\def\LT@start{%
\let\LT@start\endgraf
\endgraf\penalty\z@\vskip\LTpre
\dimen@\pagetotal
\advance\dimen@ \ht\ifvoid\LT@firsthead\LT@head\else\LT@firsthead\fi
\advance\dimen@ \dp\ifvoid\LT@firsthead\LT@head\else\LT@firsthead\fi
\advance\dimen@ \ht\LT@foot
\dimen@ii\vfuzz
\vfuzz\maxdimen
\setbox\tw@\copy\z@
\setbox\tw@\vsplit\tw@ to \ht\@arstrutbox
\setbox\tw@\vbox{\unvbox\tw@}%
\vfuzz\dimen@ii
\advance\dimen@ \ht
\ifdim\ht\@arstrutbox>\ht\tw@\@arstrutbox\else\tw@\fi
\advance\dimen@\dp
\ifdim\dp\@arstrutbox>\dp\tw@\@arstrutbox\else\tw@\fi
\advance\dimen@ -\pagegoal
\ifdim \dimen@>\z@\vfil\break\fi
\global\@colroom\@colht
\ifvoid\LT@foot\else
\global\advance\vsize-\ht\LT@foot
\global\advance\@colroom-\ht\LT@foot
\dimen@\pagegoal\advance\dimen@-\ht\LT@foot\pagegoal\dimen@
\maxdepth\z@
\fi
\ifvoid\LT@firsthead\copy\LT@head\else\box\LT@firsthead\fi\nobreak
\output{\LT@output}}
\def\endlongtable{%
\crcr
\noalign{%
\let\LT@entry\LT@entry@chop
\xdef\LT@save@row{\LT@save@row}}%
\LT@echunk
\LT@start
\unvbox\z@
\LT@get@widths
\if@filesw
{\let\LT@entry\LT@entry@write\immediate\write\@auxout{%
\gdef\expandafter\noexpand
\csname LT@\romannumeral\c@LT@tables\endcsname
{\LT@save@row}}}%
\fi
\ifx\LT@save@row\LT@@save@row
\else
\LT@warn{Column \@width s have changed\MessageBreak
in table \thetable}%
\LT@final@warn
\fi
\endgraf\penalty -\LT@end@pen
\ifvoid\LT@foot\else
\global\advance\vsize\ht\LT@foot
\global\advance\@colroom\ht\LT@foot
\dimen@\pagegoal\advance\dimen@\ht\LT@foot\pagegoal\dimen@
\fi
\endgroup
\global\@mparbottom\z@
\endgraf\penalty\z@\addvspace\LTpost
\ifvoid\footins\else\insert\footins{}\fi}
\def\LT@nofcols#1&{%
\futurelet\@let@token\LT@n@fcols}
\def\LT@n@fcols{%
\advance\LT@cols\@ne
\ifx\@let@token\LT@nofcols
\expandafter\@gobble
\else
\expandafter\LT@nofcols
\fi}
\def\LT@tabularcr{%
\relax\iffalse{\fi\ifnum0=`}\fi
\@ifstar
{\def\crcr{\LT@crcr\noalign{\nobreak}}\let\cr\crcr
\LT@t@bularcr}%
{\LT@t@bularcr}}
\let\LT@crcr\crcr
\let\LT@setprevdepth\relax
\def\LT@t@bularcr{%
\global\advance\LT@rows\@ne
\ifnum\LT@rows=\LTchunksize
\gdef\LT@setprevdepth{%
\prevdepth\z@\global
\global\let\LT@setprevdepth\relax}%
\expandafter\LT@xtabularcr
\else
\ifnum0=`{}\fi
\expandafter\LT@LL@FM@cr
\fi}
\def\LT@xtabularcr{%
\@ifnextchar[\LT@argtabularcr\LT@ntabularcr}
\def\LT@ntabularcr{%
\ifnum0=`{}\fi
\LT@echunk
\LT@start
\unvbox\z@
\LT@get@widths
\LT@bchunk}
\def\LT@argtabularcr[#1]{%
\ifnum0=`{}\fi
\ifdim #1>\z@
\unskip\@xargarraycr{#1}%
\else
\@yargarraycr{#1}%
\fi
\LT@echunk
\LT@start
\unvbox\z@
\LT@get@widths
\LT@bchunk}
\def\LT@echunk{%
\crcr\LT@save@row\cr\egroup
\global\setbox\@ne\lastbox
\unskip
\egroup}
\def\LT@entry#1#2{%
\ifhmode\@firstofone{&}\fi\omit
\ifnum#1=\c@LT@chunks
\else
\kern#2\relax
\fi}
\def\LT@entry@chop#1#2{%
\noexpand\LT@entry
{\ifnum#1>\c@LT@chunks
1}{0pt%
\else
#1}{#2%
\fi}}
\def\LT@entry@write{%
\noexpand\LT@entry^^J%
\@spaces}
\def\LT@kill{%
\LT@echunk
\LT@get@widths
\expandafter\LT@rebox\LT@bchunk}
\def\LT@rebox#1\bgroup{%
#1\bgroup
\unvbox\z@
\unskip
\setbox\z@\lastbox}
\def\LT@blank@row{%
\xdef\LT@save@row{\expandafter\LT@build@blank
\romannumeral\number\LT@cols 001 }}
\def\LT@build@blank#1{%
\if#1m%
\noexpand\LT@entry{1}{0pt}%
\expandafter\LT@build@blank
\fi}
\def\LT@make@row{%
\global\expandafter\let\expandafter\LT@save@row
\csname LT@\romannumeral\c@LT@tables\endcsname
\ifx\LT@save@row\relax
\LT@blank@row
\else
{\let\LT@entry\or
\if!%
\ifcase\expandafter\expandafter\expandafter\LT@cols
\expandafter\@gobble\LT@save@row
\or
\else
\relax
\fi
!%
\else
\aftergroup\LT@blank@row
\fi}%
\fi}
\let\setlongtables\relax
\def\LT@get@widths{%
\setbox\tw@\hbox{%
\unhbox\@ne
\let\LT@old@row\LT@save@row
\global\let\LT@save@row\@empty
\count@\LT@cols
\loop
\unskip
\setbox\tw@\lastbox
\ifhbox\tw@
\LT@def@row
\advance\count@\m@ne
\repeat}%
\ifx\LT@@save@row\@undefined
\let\LT@@save@row\LT@save@row
\fi}
\def\LT@def@row{%
\let\LT@entry\or
\edef\@tempa{%
\ifcase\expandafter\count@\LT@old@row
\else
{1}{0pt}%
\fi}%
\let\LT@entry\relax
\xdef\LT@save@row{%
\LT@entry
\expandafter\LT@max@sel\@tempa
\LT@save@row}}
\def\LT@max@sel#1#2{%
{\ifdim#2=\wd\tw@
#1%
\else
\number\c@LT@chunks
\fi}%
{\the\wd\tw@}}
\def\LT@hline{%
\noalign{\ifnum0=`}\fi
\penalty\@M
\futurelet\@let@token\LT@@hline}
\def\LT@@hline{%
\ifx\@let@token\hline
\global\let\@gtempa\@gobble
\gdef\LT@sep{\penalty-\@medpenalty\vskip\doublerulesep}%
\else
\global\let\@gtempa\@empty
\gdef\LT@sep{\penalty-\@lowpenalty\vskip-\arrayrulewidth}%
\fi
\ifnum0=`{\fi}%
\multispan\LT@cols
\unskip\leaders\hrule\@height\arrayrulewidth\hfill\cr
\noalign{\LT@sep}%
\multispan\LT@cols
\unskip\leaders\hrule\@height\arrayrulewidth\hfill\cr
\noalign{\penalty\@M}%
\@gtempa}
\def\LT@caption{%
\noalign\bgroup
\@ifnextchar[{\egroup\LT@c@ption\@firstofone}\LT@capti@n}
\def\LT@c@ption#1[#2]#3{%
\LT@makecaption#1\fnum@table{#3}%
\def\@tempa{#2}%
\ifx\@tempa\@empty\else
{\let\\\space
\addcontentsline{lot}{table}{\protect\numberline{\thetable}{#2}}}%
\fi}
\def\LT@capti@n{%
\@ifstar
{\egroup\LT@c@ption\@gobble[]}%
{\egroup\@xdblarg{\LT@c@ption\@firstofone}}}
\def\LT@makecaption#1#2#3{%
\LT@mcol\LT@cols c{\hbox to\z@{\hss\parbox[t]\LTcapwidth{%
\sbox\@tempboxa{#1{#2: }#3}%
\ifdim\wd\@tempboxa>\hsize
#1{#2: }#3%
\else
\hbox to\hsize{\hfil\box\@tempboxa\hfil}%
\fi
\endgraf\vskip\baselineskip}%
\hss}}}
\def\LT@output{%
\ifnum\outputpenalty <-\@Mi
\ifnum\outputpenalty > -\LT@end@pen
\LT@err{floats and marginpars not allowed in a longtable}\@ehc
\else
\setbox\z@\vbox{\unvbox\@cclv}%
\ifdim \ht\LT@lastfoot>\ht\LT@foot
\dimen@\pagegoal
\advance\dimen@\ht\LT@foot
\advance\dimen@-\ht\LT@lastfoot
\ifdim\dimen@<\ht\z@
\setbox\@cclv\vbox{\unvbox\z@\copy\LT@foot\vss}%
\@makecol
\@outputpage
\global\vsize\@colroom
\setbox\z@\vbox{\box\LT@head}%
\fi
\fi
\unvbox\z@\ifvoid\LT@lastfoot\copy\LT@foot\else\box\LT@lastfoot\fi
\fi
\else
\setbox\@cclv\vbox{\unvbox\@cclv\copy\LT@foot\vss}%
\@makecol
\@outputpage
\global\vsize\@colroom
\copy\LT@head\nobreak
\fi}
\def\LT@end@hd@ft#1{%
\LT@echunk
\ifx\LT@start\endgraf
\LT@err
{Longtable head or foot not at start of table}%
{Increase LTchunksize}%
\fi
\setbox#1\box\z@
\LT@get@widths
\LT@bchunk}
\def\endfirsthead{\LT@end@hd@ft\LT@firsthead}
\def\endhead{\LT@end@hd@ft\LT@head}
\def\endfoot{\LT@end@hd@ft\LT@foot}
\def\endlastfoot{\LT@end@hd@ft\LT@lastfoot}
\def\LT@startpbox#1{%
\bgroup
\let\@footnotetext\LT@p@ftntext
\setlength\hsize{#1}%
\@arrayparboxrestore
\vrule \@height \ht\@arstrutbox \@width \z@}
\def\LT@endpbox{%
\@finalstrut\@arstrutbox
\egroup
\the\LT@p@ftn
\global\LT@p@ftn{}%
\hfil}
\def\LT@p@ftntext#1{%
\edef\@tempa{\the\LT@p@ftn\noexpand\footnotetext[\the\c@footnote]}%
\global\LT@p@ftn\expandafter{\@tempa{#1}}}%
\endinput
%%
%% End of file `longtable.sty'.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

+165
View File
@@ -0,0 +1,165 @@
%PDF-1.4
%âãÏÓ
1 0 obj
<<
/Title ()
/Author ()
/Subject ()
/Keywords ()
/Creator (yExport 1.5)
/Producer (org.freehep.graphicsio.pdf.YPDFGraphics2D 1.5)
/CreationDate (D:20210314231237+01'00')
/ModDate (D:20210314231237+01'00')
/Trapped /False
>>
endobj
2 0 obj
<<
/Type /Catalog
/Pages 3 0 R
/ViewerPreferences 4 0 R
/OpenAction [5 0 R /Fit]
>>
endobj
4 0 obj
<<
/FitWindow true
/CenterWindow false
>>
endobj
5 0 obj
<<
/Parent 3 0 R
/Type /Page
/Contents 6 0 R
>>
endobj
6 0 obj
<<
/Length 7 0 R
/Filter [/ASCII85Decode /FlateDecode]
>>
stream
Gb"/*D3*J\&cSq?_,!?9F;;NG'_Tjnj1%M[f^Yg:&-R`*:Ud5gX1`1jrUTD=Uc?jr]6>W+;U,Od"'Ii5
^'m"4LGL4#@LE,IgA>$X*gAF6^QA+HqE=*[gdW_/EJH'_Y"BH%S#E'nkW_oRm<nZ&]"cE+g$Ar<\t<SU
=oS#R&\B='-j5OerdfJ,k@Q^IiS4k)Y+;&mAiN?S`sOV:43UCq[d_CdZ@5A0T,6TCT.AOGb-e[;A4fW$
'abRBg[S[:1I5+(0"V#!N'(>'i@lT\iF7MI!I%RP1lZWE&glYgfRPanCQ5jp3"[a^njAAtc2:N2:XD=g
d)/YCN%qq^milXkZX*3G$Y=6pN"<!DoUUpe<Y(>2#rhSSrb=.LX./=b=,\hN't_&:rc2$*%qL12lPoEW
h(SZ?P,nUP5?raMHY<DQP<4=O4B8XcSQujXj%OXfN#:r4jbJ'ecHNKHo5KG"@J0C^cKmc]L\2[uhL/Rl
3DS70&#rs#)kRYY&Xe@g+_&^34IIdX\FMV!fN1$G@#[1gZ\Wo0rWG6A(hg_$`%#AF,RHBZmQ.QFnbqXr
nkXA6ii*k#2?%]&5Hf:]%;@mK+7c;QYH),cRgN^8K+L:@,/BJuodg6*\O'PH/0)\#6]C,>h4J<2D$!eK
fjmu)369W@)m8d,nc&5aY=$sZd^1#`&uY!8NaD/=6aNi7U%;*XgI&NP+6#t4m(X1p7VR@$_k(`iY%'a8
0#0&J_0LNj&J&LKf9<(,Qk3nfVOI.,J-d%RL'c5"jKO_6/5cXd3!%WCdYo*#7Ee&%Ql<d@ak2:Pp7"M:
88&oS.:Sq^<.a6#Yg>u=e[FNN_n$VY,#p"PZ.-S.[Oo,N;Zgb2[>!qfl%/u3\5a7II\:P!K5n)MiHLf3
-<&@mZ1E3+IQEOhRn'Z23Z*ooXla9i>i;ZQknIaa#nA0#f4W5CF9UCim-t61rOVhqI41O&4RgPMG&(./
C\V7:esiQXETf7'ju!+Q<,eg!)-N!W,u#`u.'u^"(R-Dp.,kT=6L;i*YqJ?-/igO];^*]t:IkO];C4kN
?GGibk.P&7\,!T@g+%eNr'V<u//d-qO%!>2q4Sq?%;_K6!Z(Gf!?H2:<t^Z#-:`5]DXXW8>LWmuKRo;l
^-<YS#imrVT7\#X&K/od5U*':<uu.4Z2>/Cq,rp$fl`bsa<c[K*t#[&kWj%ciI/,gCr#Xtn<9=AQ.q+4
FNjOSr/_TD(HLj'bBNtmJ1OB`3T(S\!]/"WilYc$E%F5lF:#7sY1jYrJ;99FcV.$J`fan7hj0c+G:li#
+q-G+UH:CUD.IiT(\u>5aF1C!(]-AkL4!g[6P2T2eFo74S:e0N4G"B'r.<^iM^50i1)!Z$gt%-N9miUR
RrXl&1j`GULjf)%.6>(YP:2m=>`^LIb;K:cE7Y)264$8l*=3/tkRX;Cp!HZKG7/49WZ/5sIQnV@qNNp7
G+;^=bl`1t48d\):\(4'anAgW8jDGA%T5-Zm>A!(;'DY=;D?b1U_d!:+AmYhc31l(XE!5T$;P"^\2eN2
.p+C`j0rl3ej2$"QF(-5!UJbnk_-=U2<Sl<(&59N.:4QMQB;*,8bk!\_'4siBos%g/_^(<nARFU>^;i"
N9,gs/TCDA^MZuU$Edi0D2L;6NdC:,+oqIf#Z\6T@gG,@gMW'p\Sh/YO5OG9hC"#?L!*BsCnh+qU#Ol2
,=VcCq&s'r/G&0cJLoB1M(l6rc-<MpG<n<a9%l!n,Kl"Rk7N*(PX1>Zs"So3,R9ea'_E%M\[jIuRe(<S
\FMV!(s<FEQCj?ooBZ*4Q\\4rg!^EPO@js@QZY<WAVmsL(H+l-:$.dL&tXlIE"XsPS7LGiJ7N@I]18s9
[G17>]YmC\r45$-1R2B\clpH=0r,!5R0`o))/71F#+iNaQiiAPQ^M!W"^#+up9,'0L`%::H[pP?"dh<F
DU66p-"AAHK3Xq7/:a.lqIuohGe5S!F0*-Zk8fMe=@);9MDigb0bn=pTqLrX6+rqnE[L9UAprUBN.M_;
_%jn$MS]jlM=CfUDjoLZagYbC<2c:;&OM<-^*Ra),U)^?.&]1XoE&+U9Rp,T2WGDW5**TaR>YDUMEpen
RK5(%T?=1XS'O"cs14d,Y*bW)o1h)]ehIJ,b#(uXJcl6Zj\12)k,$BJ$9f,OQoX`e@4qfAgjS$HRTGV5
a=KR<c%s94.:H!0;8S3Y6\!eNlO5[FfSk7XN>V8.?f=\_`+d(4l:oqubdkE$9rI"hnCebOi7"cWQ.Jae
PRmVROmfREKd>:;HS"dT+jl)fI=Kf5_-E<ufU(>O)-b&YXk[FX`A2dgTeI1'Qmqc%"KuSQImI<$,)i,M
k4(*CMc";Kp@2X04oHRboj>Y>b\2?YjB`C2'0L1,7^4UQe5I9\"U1LM3\9ftT$3-sB3:.u\1='-MJTPI
`B?XCOYCkBE/)EsKk4+7LI^STV"O&6=\opo"EW)@0b&&iI0mul%E<0G!OL.$YP`T<\VsJ*UT1I5hI::G
PJ(;m]/XNbZ15:6-^8O4Z)LO.nh:O>9$e@Nr^F!pISWK,O0)>s4dGa#ZWgj_(#"qo/B4GHOfD^sr(\@!
s6ZHW+/QZ)5Q:fghd`J~>
endstream
endobj
7 0 obj
2645
endobj
8 0 obj
<<
/Type /Font
/Subtype /Type1
/Name /F1
/BaseFont /Helvetica
/Encoding 9 0 R
>>
endobj
9 0 obj
<<
/Type /Encoding
/Differences [0 /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore /grave /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /asciitilde /.notdef /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction /guilsinglleft /guilsinglright /minus /perthousand /quotedblbase /quotedblleft /quotedblright /quoteleft /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron /Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron /.notdef /Euro /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /.notdef /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis]
>>
endobj
3 0 obj
<<
/Parent null
/Type /Pages
/MediaBox [0.0000 0.0000 723.00 557.00]
/Resources 10 0 R
/Kids [5 0 R]
/Count 1
>>
endobj
11 0 obj
[/PDF /Text /ImageC]
endobj
12 0 obj
<<
/F1 8 0 R
>>
endobj
13 0 obj
<<
/S /Transparency
/CS /DeviceRGB
/I true
/K false
>>
endobj
14 0 obj
<<
/Alpha1
<<
/ca 1.0000
/CA 1.0000
/BM /Normal
/AIS false
>>
>>
endobj
10 0 obj
<<
/ProcSet 11 0 R
/Font 12 0 R
/ExtGState 14 0 R
>>
endobj
xref
0 15
0000000000 65535 f
0000000015 00000 n
0000000315 00000 n
0000005659 00000 n
0000000445 00000 n
0000000521 00000 n
0000000609 00000 n
0000003364 00000 n
0000003387 00000 n
0000003520 00000 n
0000006160 00000 n
0000005830 00000 n
0000005870 00000 n
0000005915 00000 n
0000006017 00000 n
trailer
<<
/Size 15
/Root 2 0 R
/Info 1 0 R
>>
startxref
6254
%%EOF
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.
+57 -40
View File
@@ -110,7 +110,7 @@ class TopMenu:
class ManualMode(Frame):
# Mode for manually setting currents and fields on the test stand.
# Mode for manually setting currents and fields on the test bench.
# Inherits the Frame object from Tkinter and is placed in the mainArea of the application window.
def __init__(self, parent, controller):
Frame.__init__(self, parent) # initialize the frame object
@@ -204,7 +204,7 @@ class ManualMode(Frame):
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,
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, padx=5)
@@ -267,7 +267,7 @@ class ManualMode(Frame):
# log change to the log file if user has selected event logging in the Configure Logging window
logger = self.controller.pages[ConfigureLogging] # get object of logging configurator
if logger.event_logging: # data should be logged when test stand is commanded
if logger.event_logging: # data should be logged when test bench is commanded
logger.log_datapoint() # log data
def power_down(self): # called on "power down" button press
@@ -275,13 +275,13 @@ class ManualMode(Frame):
# log change to the log file if user has selected event logging in the Configure Logging window
logger = self.controller.pages[ConfigureLogging] # get object of logging configurator
if logger.event_logging: # data should be logged when test stand is commanded
if logger.event_logging: # data should be logged when test bench is commanded
logger.log_datapoint() # log data
def execute(self): # called on "Execute!" button press
# reads values from the entry fields and commands the test stand accordingly
# reads values from the entry fields and commands the test bench accordingly
vector = np.array([0, 0, 0], dtype=float) # initialize vector to later send to test stand
vector = np.array([0, 0, 0], dtype=float) # initialize vector to later send to test bench
i = 0
try: # try to read values from the entry fields
for var in self.entry_vars:
@@ -296,24 +296,24 @@ class ManualMode(Frame):
# log change to the log file if user has selected event logging in the Configure Logging window
logger = self.controller.pages[ConfigureLogging] # get object of logging configurator
if logger.event_logging: # data should be logged when test stand is commanded
if logger.event_logging: # data should be logged when test bench is commanded
logger.log_datapoint() # log data
def execute_field(self, vector): # convert magnetic field vector and send to test stand
def execute_field(self, vector): # convert magnetic field vector and send to test bench
ui_print("Field executing:", vector, "\u03BCT")
compensate = self.compensate.get() # read out if compensate ambient field checkbox is ticked
if compensate: # ambient field should be compensated
func.set_field(vector * 1e-6) # convert to Tesla and send to test stand
func.set_field(vector * 1e-6) # convert to Tesla and send to test bench
elif not compensate: # ambient field should not be compensated
func.set_field_simple(vector * 1e-6) # convert to Tesla and send to test stand
func.set_field_simple(vector * 1e-6) # convert to Tesla and send to test bench
else: # this really should never happen
ui_print("Unexpected value encountered: compensate =", compensate)
messagebox.showerror("Unexpected Value!", ("Unexpected value encountered: compensate =", compensate))
@staticmethod
def execute_current(vector): # send current vector to the test stand
def execute_current(vector): # send current vector to the test bench
ui_print("Current executing:", vector, "A")
func.set_current_vec(vector) # command test stand
func.set_current_vec(vector) # command test bench
class ExecuteCSVMode(Frame):
@@ -468,7 +468,7 @@ class ExecuteCSVMode(Frame):
# log change to the log file if user has selected event logging in the Configure Logging window
logger = self.controller.pages[ConfigureLogging] # get object of logging configurator
if logger.event_logging: # data should be logged when test stand is commanded
if logger.event_logging: # data should be logged when test bench is commanded
logger.log_datapoint() # log data
def reinitialize(self): # called on "Reinitialize devices" button press
@@ -476,7 +476,7 @@ class ExecuteCSVMode(Frame):
# log change to the log file if user has selected event logging in the Configure Logging window
logger = self.controller.pages[ConfigureLogging] # get object of logging configurator
if logger.event_logging: # data should be logged when test stand is commanded
if logger.event_logging: # data should be logged when test bench is commanded
logger.log_datapoint() # log data
def display_plot(self): # generate and display a plot of the data loaded from a csv file
@@ -574,7 +574,8 @@ class Configuration(Frame):
# Setup dictionary to generate entry table from
# {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],
"Coil Constants:": [[DoubleVar() for _ in range(3)], "\u03BCT/A", "Field generated per applied current",
"coil_const", 1e6],
"Ambient Field:": [[DoubleVar() for _ in range(3)], "\u03BCT",
"Field to be compensated", "ambient_field", 1e6],
"Resistances:": [[DoubleVar() for _ in range(3)], "\u03A9",
@@ -624,7 +625,7 @@ class Configuration(Frame):
self.buttons_frame.grid(row=row_counter, column=0, sticky=W, padx=20)
# Create and place buttons
# button to read the values from all fields, update the config and reinitialize the test stand
# button to read the values from all fields, update the config and reinitialize the test bench
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)
@@ -760,12 +761,14 @@ class Configuration(Frame):
config.CONFIG_FILE = filename # set global config file to the new file
self.write_values() # write current entry field values to the config object
config.write_config_to_file(config.CONFIG_OBJECT) # write contents of config object to file
ui_print("\nReinitializing devices...")
func.setup_all() # reinitialize devices and program with new values
self.update_fields() # update entry fields to show values as they are in the config
def save_config(self): # same as save_config_as() but with the current config file
self.write_values() # write current entry field values to the config object
config.write_config_to_file(config.CONFIG_OBJECT) # write contents of config object to file
ui_print("\nReinitializing devices...")
func.setup_all() # reinitialize devices and program with new values
self.update_fields() # update entry fields to show values as they are in the config
@@ -782,9 +785,9 @@ class ConfigureLogging(Frame):
self.log_file = None # string containing path of log file
self.regular_logging = False # True if data should be logged regularly
self.event_logging = False # True if data should be logged every time a command is sent to the test stand
# log_datapoint() has to be called wherever a command is sent to the test stand and data should be logged
# it does not happen automatically whenever something is sent to the test stand
self.event_logging = False # True if data should be logged every time a command is sent to the test bench
# log_datapoint() has to be called wherever a command is sent to the test bench and data should be logged
# it does not happen automatically whenever something is sent to the test bench
# It is done mainly in the functions for UI buttons, but rather inconsistently ToDo(optional): make consistent
self.grid_rowconfigure(ALL, weight=1)
@@ -805,22 +808,22 @@ class ConfigureLogging(Frame):
self.top_buttons_frame.grid_columnconfigure(ALL, weight=1)
self.top_buttons_frame.grid(row=row_counter, column=0, sticky=W, padx=20, pady=5)
# button to stop data logging
self.stop_logging_button = Button(self.top_buttons_frame, text="Stop Logging", command=self.stop_logging,
pady=5, padx=5, font=SMALL_BUTTON_FONT)
self.stop_logging_button.grid(row=0, column=0, padx=5)
# button to start data logging
self.start_logging_button = Button(self.top_buttons_frame, text="Start Logging", command=self.start_logging,
pady=5, padx=5, font=SMALL_BUTTON_FONT)
self.start_logging_button.grid(row=0, column=0, padx=5) # same place as stop logging button, replace each other
self.start_logging_button.grid(row=0, column=0, padx=5)
# button to stop data logging
self.stop_logging_button = Button(self.top_buttons_frame, text="Stop Logging", command=self.stop_logging,
pady=5, padx=5, font=SMALL_BUTTON_FONT, state="disabled")
self.stop_logging_button.grid(row=0, column=1, padx=5)
# button to write log data to a file
self.write_to_file_button = Button(self.top_buttons_frame, text="Write data to file", font=SMALL_BUTTON_FONT,
command=self.write_to_file, pady=5, padx=5, state="disabled")
self.write_to_file_button.grid(row=0, column=1, padx=5)
self.write_to_file_button.grid(row=0, column=2, padx=5)
# button to clear all logged data
self.clear_data_button = Button(self.top_buttons_frame, text="Clear logged data", font=SMALL_BUTTON_FONT,
command=self.clear_data, pady=5, padx=5, state="disabled")
self.clear_data_button.grid(row=0, column=2, padx=5)
self.clear_data_button.grid(row=0, column=3, padx=5)
row_counter += 1
@@ -850,14 +853,14 @@ class ConfigureLogging(Frame):
# create checkbox variable for logging in regular time intervals
self.regular_logging_var = BooleanVar(value=True)
# create checkbox variable for logging whenever test stand is commanded
# create checkbox variable for logging whenever test bench is commanded
self.event_logging_var = BooleanVar(value=True)
self.log_interval = DoubleVar(value=1) # create variable for logging interval entry field
# create checkboxes for regular and event logging:
self.regular_logging_checkbox = Checkbutton(self.settings_frame, text="Log in regular intervals",
variable=self.regular_logging_var, onvalue=True, offvalue=False)
self.event_logging_checkbox = Checkbutton(self.settings_frame, text="Log whenever test stand is commanded",
self.event_logging_checkbox = Checkbutton(self.settings_frame, text="Log whenever test bench is commanded",
variable=self.event_logging_var, onvalue=True, offvalue=False)
self.regular_logging_checkbox.grid(row=0, column=0, sticky=W)
self.event_logging_checkbox.grid(row=1, column=0, sticky=W, columnspan=3)
@@ -896,10 +899,15 @@ class ConfigureLogging(Frame):
self.checkboxes.append(checkbox) # add created checkbox to list of all checkboxes
row += 1
# self.controller.bind('<Escape>', self.escape_press) ToDo: implement escape button press event to power down
def page_switch(self): # function that is called when switching to this window
# every class in the UI needs this, even if it doesn't do anything
pass
# def escape_press(self, event): ToDo: implement escape button press event to power down
# stop_logging()
def start_logging(self): # start logging data (called by button)
ui_print("Started data logging.")
self.update_choices() # update list with ticked checkboxes
@@ -926,18 +934,20 @@ class ConfigureLogging(Frame):
if (self.regular_logging or self.event_logging) and not error: # logging is active and no error during setup
# lock/unlock buttons and checkboxes:
self.stop_logging_button["state"] = "normal"
self.start_logging_button["state"] = "disabled"
self.write_to_file_button["state"] = "disabled"
self.clear_data_button["state"] = "normal"
self.lock_checkboxes()
self.stop_logging_button.tkraise() # switch button to "stop"
def stop_logging(self): # stop the data logging, called by "Stop Logging" button
ui_print("Stopped data logging. Remember to save data to file!")
self.regular_logging = False # tell everything its time to stop periodic logging
self.event_logging = False # tell everything its time to stop logging on test stand commands
self.event_logging = False # tell everything its time to stop logging on test bench commands
self.write_to_file_button["state"] = "normal" # enable write to file button
self.stop_logging_button["state"] = "disabled" # disable stop logging button
self.start_logging_button["state"] = "normal" # enable start logging button
self.unlock_checkboxes() # enable checkboxes
self.start_logging_button.tkraise() # switch start/stop button to "start"
def write_to_file(self): # lets user select a file and writes logged data to it
filepath = log.select_file() # select a file to write to
@@ -951,15 +961,22 @@ class ConfigureLogging(Frame):
def clear_data(self): # called on button press, asks user if he want to save logged data and then deletes it
if log.unsaved_data: # there is logged data that has not been written to a file yet
# open pop-up to ask user if he wants to save the data:
save_log = messagebox.askquestion("Save log data?", "There seems to be unsaved logging data. "
"Do you wish to write it to a file before deleting?")
if save_log == 'yes': # user has chosen yes
# open pop-up to ask user if he wants to save the data or cancel clearing it:
save_log = messagebox.askyesnocancel("Save log data?", "There seems to be unsaved logging data. "
"Do you wish to write it to a file before deleting?")
if save_log: # user has chosen yes
self.write_to_file() # run write to file function to save data
log.clear_logged_data() # delete the logged data
log.unsaved_data = False # tell everything that there is no unsaved data remaining
self.logged_datapoints.set(len(log.log_data)) # update the label showing how much data has been logged
ui_print("Log data cleared.")
if save_log is not None: # user has chosen yes or no (not cancel)
log.clear_logged_data() # delete the logged data
log.unsaved_data = False # tell everything that there is no unsaved data remaining
self.logged_datapoints.set(len(log.log_data)) # update the label showing how much data has been logged
ui_print("Log data cleared.")
else: # user has chosen to cancel
ui_print("Log data not cleared.")
else: # there is no unsaved data
log.clear_logged_data() # delete the logged data
self.logged_datapoints.set(len(log.log_data)) # update the label showing how much data has been logged
ui_print("Log data cleared.")
def update_choices(self): # updates the list storing which checkboxes are currently ticked
# (this is passed to logging functions and determines which data is logged)
@@ -998,7 +1015,7 @@ class ConfigureLogging(Frame):
class StatusDisplay(Frame):
# status display to show information on test stand status in real time
# status display to show information on test bench status in real time
# noinspection PyUnusedLocal
def __init__(self, parent, controller):
Binary file not shown.
+8 -8
View File
@@ -1,4 +1,4 @@
# This file contains all classes and functions directly related to the operation of the helmholtz test stand.
# This file contains all classes and functions directly related to the operation of the helmholtz test bench.
# The two main classes are Axis and ArduinoCtrl, see their definitions for details.
# import packages:
@@ -16,7 +16,7 @@ import globals as g
class Axis:
# Main class representing an axis (x,y,z) of the test stand
# Main class representing an axis (x,y,z) of the test bench
# contains static and dynamic status information about this axis and methods to control it
def __init__(self, index, device, PSU_channel, arduino_pin):
@@ -117,7 +117,7 @@ class Axis:
messagebox.showerror("PSU Error!", "Error while powering down %s: \n%s" % (self.name, e))
def set_signed_current(self, value):
# sets current with correct polarity on this axis, this is the primary way to control the test stand
# sets current with correct polarity on this axis, this is the primary way to control the test bench
# ui_print("Attempting to set current", value, "A")
self.target_current = value # show target value in object attribute for status display, logging etc.
@@ -146,14 +146,14 @@ class Axis:
self.target_field = value # update object attribute for display
self.target_field_comp = value # same as above, bc no compensation
current = value / self.coil_constant # calculate needed current
self.set_signed_current(current) # command the test stand
self.set_signed_current(current) # command the test bench
def set_field(self, value): # forms magnetic field as specified by value, corrected for ambient field
self.target_field = value # update object attribute for display
field = value - self.ambient_field # calculate needed field after compensation
self.target_field_comp = field # update object attribute for display
current = field / self.coil_constant # calculate needed current
self.set_signed_current(current) # command the test stand
self.set_signed_current(current) # command the test bench
class ArduinoCtrl(Arduino):
@@ -216,7 +216,7 @@ def value_in_limits(axis, key, value): # Check if value is within safe limits (
return 'OK'
def setup_all(): # main test stand initialization function
def setup_all(): # main test bench initialization function
# creates device objects for all PSUs and Arduino and sets their values
# initializes an object of class Axis for all three axes (x,y,z)
@@ -251,7 +251,7 @@ def setup_all(): # main test stand initialization function
g.PORTS = [g.XY_PORT, g.XY_PORT, g.Z_PORT] # write list with PSU port for each axis (X/Y share PSU)
# setup PSU and axis objects for X and Y axes:
ui_print("\nConnecting to XY Device on %s..." % g.XY_PORT)
ui_print("Connecting to XY Device on %s..." % g.XY_PORT)
try: # try to connect to the PSU
if g.XY_DEVICE is not None: # if PSU has previously been connected we need to close the serial link first
ui_print("Closing serial connection on XY device")
@@ -386,7 +386,7 @@ def set_current_vec(vector): # sets currents on each axis according to given ve
axis.target_field = 0 # set target field attribute to 0 to show that current, not field is controlled atm
axis.target_field_comp = 0 # as above
axis.set_signed_current(vector[i]) # command test stand to set the current
axis.set_signed_current(vector[i]) # command test bench to set the current
except ValueError as e: # current was too high
ui_print(e) # print out the error message
i += 1
+1 -1
View File
@@ -71,7 +71,7 @@ def select_file(): # select a file to write logs to
defaultextension=[("Comma Separated Values", "*.csv*")])
if filepath == '': # this happens when file selection window is closed without selecting a file
ui.ui_print("No file selected, can not save logged data.")
ui.ui_print("No file selected, can't save logged data.")
return None
else: # a valid file name was entered
return filepath
+7 -7
View File
@@ -47,7 +47,7 @@ class ExecCSVThread(Thread):
def execute_sequence(self, array, delay, parent, controller):
# main execution method of the class
# runs through array with times and desired fields and commands test stand accordingly
# runs through array with times and desired fields and commands test bench accordingly
# array format: [time (s), xField (T), yField (T), zField (T)]
func.power_down_all() # sets outputs on PSUs to 0 and Arduino pins to LOW before starting
@@ -73,12 +73,12 @@ class ExecCSVThread(Thread):
field_vec = array[i, 1:4] # extract desired field vector
ui.ui_print("%0.5f s: t = %0.2f s, target field vector ="
% (time.time() - t_zero, array[i, 0]), field_vec * 1e6, "\u03BCT")
func.set_field(field_vec) # send field vector to test stand
func.set_field(field_vec) # send field vector to test bench
controller.StatusDisplay.update_labels() # update status display after change
# log change to the log file if user has selected event logging in the Configure Logging window
logger = controller.pages[ui.ConfigureLogging] # get object of logging configurator
if logger.event_logging: # data should be logged when test stand is commanded
if logger.event_logging: # data should be logged when test bench is commanded
logger.log_datapoint() # log data
i = i + 1 # next row
@@ -115,17 +115,17 @@ def read_csv_to_array(filepath): # convert a given csv file to a numpy array
def check_array_ok(array):
# check if any magnetic fields in an array exceed the test stand limits and if so display a warning message
# check if any magnetic fields in an array exceed the test bench limits and if so display a warning message
values_ok = True
for i in [0, 1, 2]: # go through axes/columns
max_val = g.AXES[i].max_comp_field[1] # get limits the test stand can do
max_val = g.AXES[i].max_comp_field[1] # get limits the test bench can do
min_val = g.AXES[i].max_comp_field[0]
data = array[:, i + 1] # extract data for this axis from array
# noinspection PyTypeChecker
if any(data > max_val) or any(data < min_val): # if any datapoint is out of bounds
values_ok = False
if not values_ok: # show warning pop-up if values are exceeding limits
messagebox.showwarning("Value Limits Warning!", "Found field values exceeding limits of test stand."
messagebox.showwarning("Value Limits Warning!", "Found field values exceeding limits of test bench."
"\nSee plot and check values in csv.")
@@ -140,7 +140,7 @@ def plot_field_sequence(array, width, height): # create plot of fixed size (pix
figure.suptitle("Magnetic Field Sequence") # set figure title
# modify data to show instantaneous jumps in field to reflect test stand operation
# modify data to show instantaneous jumps in field to reflect test bench operation
new_array = np.array([[0, 0, 0, 0]], dtype=float) # initialize modified array, zeros to show start from no fields
last_vals = [0, 0, 0] # [x,y,z] field values from last data point (zero here), used to create step in data
+32
View File
@@ -0,0 +1,32 @@
# Helmholtz Cage Control Software
This software is used to control the magnetic field test bench at the Institute for Space Systems (IRS) at
the University of Stuttgart. The test bench consists of three Helmholtz coil pairs, one in each spatial axis.
The amount of current flowing through these coils is controlled by two PS2000B power supply units.
The polarity is switched by a set of relays that are controller by an Arduino Uno.
This repository contains the source code and is used to develop and modify the program. Releases are distributed
in a [separate repository](https://egit.irs.uni-stuttgart.de/zietzm/Helmholtz_Test_Bench_Releases/releases).
## Installation
1. Download latest release from
[distribution repository](https://egit.irs.uni-stuttgart.de/zietzm/Helmholtz_Test_Bench_Releases/releases)
2. Unpack ZIP-Folder
3. Run `Helmholtz Cage Control.exe`
Alternatively use the `Helmholtz Cage Control.exe` from the `Release` folder in this repository.
## Users Guide
For detailed instructions please refer to the main documentation PDF in the `Documentation` folder.
## Changelog
### V 1.0 (02.03.2021)
Initial Version
### V 1.1 (10.03.2021)
- updated UI with user feedback
### V 1.15 (27.03.2021)
- added documentation
- tweaks and ToDo's after testing with all devices connected (communication with PSUs is too slow)
- UI tweaks to better fit smaller display of cleanroom PC
+4
View File
@@ -0,0 +1,4 @@
Date;Time;t (s);X PSU Status;Y PSU Status;Z PSU Status;X Voltage Setpoint;Y Voltage Setpoint;Z Voltage Setpoint;X Actual Voltage;Y Actual Voltage;Z Actual Voltage;X Current Setpoint;Y Current Setpoint;Z Current Setpoint;X Actual Current;Y Actual Current;Z Actual Current;X Target Field;Y Target Field;Z Target Field;X Trgt. Field Raw;Y Trgt. Field Raw;Z Trgt. Field Raw;X Target Current;Y Target Current;Z Target Current;X Inverted;Y Inverted;Z Inverted
2021-03-22;10:58:32,248216;0,0;Not Connected;Not Connected;Not Connected;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;Unknown;Unknown;Unknown
2021-03-22;10:58:33,262910;1,014694;Not Connected;Not Connected;Not Connected;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;Unknown;Unknown;Unknown
2021-03-22;10:58:34,271188;2,022972;Not Connected;Not Connected;Not Connected;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;Unknown;Unknown;Unknown
1 Date Time t (s) X PSU Status Y PSU Status Z PSU Status X Voltage Setpoint Y Voltage Setpoint Z Voltage Setpoint X Actual Voltage Y Actual Voltage Z Actual Voltage X Current Setpoint Y Current Setpoint Z Current Setpoint X Actual Current Y Actual Current Z Actual Current X Target Field Y Target Field Z Target Field X Trgt. Field Raw Y Trgt. Field Raw Z Trgt. Field Raw X Target Current Y Target Current Z Target Current X Inverted Y Inverted Z Inverted
2 2021-03-22 10:58:32,248216 0,0 Not Connected Not Connected Not Connected 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Unknown Unknown Unknown
3 2021-03-22 10:58:33,262910 1,014694 Not Connected Not Connected Not Connected 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Unknown Unknown Unknown
4 2021-03-22 10:58:34,271188 2,022972 Not Connected Not Connected Not Connected 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Unknown Unknown Unknown