-
Notifications
You must be signed in to change notification settings - Fork 3
Home
Welcome to the photon-counting wiki! - Mikel Zemborain, Fuming Qiu, Houghton Yonge
Our code was made in Python using the following imported modules:
- datetime
- numpy
- os
- PyQt5 (QtWidgets & QtCore)
- sys
- datetime
- visa
- serial
Our GUI was visually created using QtDesigner which was included with our version of Anaconda.
-
QtDesigner is a GUI-based GUI designer (go figure). As such, it is entirely visual: after selecting a particular QWidget class to as your main GUI frame, you can drag and drop widgets of your choice into it, resize and rearrange those widgets, and even edit their parameters (size, formatting, signals & slots, etc.) using drop-down menus. The advantage in using this program to design GUIs is the luxury of having to traditionally code the layout of a GUI with different lines isolating increasingly more specific parameters. Even better, **QtDesigner generates this automatically as source code for your project!!
-
QtDesigner, However, does not allow complete freedom in formatting the widgets into your desired layout. Sometimes it is best to generate a new widget in QtDesigner, copy the widget's python code and paste it into your .GUI code, and customize the location of the widget onto your panel using gridLayout.addWidget. Learn the syntax of this function here.
-
** While QtDesigner projects are saved as .ui files (and their source code is in XML when previewed in the application), they can be simply converted to Python code to use with other projects.
Converting a file is easy and only requires a few steps:
-
Save your project. It should save as a .ui file by default.
-
Start up your favorite Python IDE (we used SPyDEr, as mentioned above) and open up a new terminal.
-
Use cd commands in the terminal to make sure Python is accessing the directory you want the converted code to be stored in. Note that cd commands only need the next step in the path you're on rather than the entirety of the path up to that point (e.g. if Folder_3 is in Folder_2 which is in Folder_1 and your current directory is Folder_2, you would write cd Folder_3, not cd Folder_1/Folder_2/Folder_3).
-
Enter the following command into the terminal:
pyuic(num) -x filename1.ui -o filename2.py
pyuic5 accesses Python's internal ui-py conversion package, and the (num) is for whatever version of PyQt you are using (ours was 5). -x generates additional code at the end of your .ui file that will allow it to be properly displayed when it is implemented into your other Python code (see the ______ section for more information). filename1.ui is the exact name of the .ui file you want to convert. -o is for "output" and goes in front of filename2.py, which will name your newly-converted file whatever comes before the .py extension.
Those with experience in coding are no strangers to running into syntax issues that prevent them from running programs, and these can be particularly pernicious when trying to properly access one Python file containing GUI code from another. This section goes over the correct way to format the code necessary to do this and explains the process.
As an example, suppose you have two files you want to work with: GUI.py (the converted source code of your QtDesigner project) and main.py, the "regular" program that you're planning to access it with. The first thing to do is to have certain import statements at the beginning of your code:
from PyQt(num) import QtWidgets import sys import GUI
Note that your GUI code file is imported using its filename before the .py extension.
To load the GUI you must use it as the parent of a new class in your main.py file:
class MainApp(GUI.Ui_form)
MainApp is the name of your new child class, and Ui_form is the class of its parent GUI.py. The latter can be directly found as the main class of your GUI from its source code.
As mentioned in the previous section, using -x before your .ui filename in a pyuic command generates additional code at the end of your .py converted code so it can be used with other Python projects. That code looks something like this:
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
Here Form.show() is the command that actually displays the GUI on the screen and refers to the new QWidget created three lines above it, which is explicitly called Form. setupUi creates this form within Ui_Form, which is the name of the auto-generated class from QtDesigner. It is also possible to simply include a Form.show() line somewhere in the init() statement of a class if you so choose provided the proper name is used.
Having tried connecting to the SR400 both through its GPIB and its serial RS-232 ports, we recommend using GPIB. The main reason for this is that GPIB connections are far more stable than serial ones; the volatility of serial ports' switching behavior can lead what was an active connection with an available port to fail without warning as the port suddenly becomes inaccessible. There is also an advantage to GPIB when troubleshooting code, as unlike with serial connectivity the kernel of the Python console used does not need to be reset every time the GUI window is closed down and the code restarted.
To connect to the SR400 through GPIB you will need a GPIB-to-USB adapter, the PyVisa packaged installed (see "visa" in "Packages Used", which can be pip installed), and a "driver" program (used to connect computers with external hardware) which can be downloaded here. (Note that this program only needs to be installed rather than opened for GPIB connectivity).
PyVisa is a package used to connect Python code to external devices with different connection ports, including GPIB, Ethernet, and VXI among others, and using it within your program is mostly uniform for all accepted connection types. An example of this code from our program Photon_Counter_Code._GPIB.py can be seen below:
rm = visa.ResourceManager()
instList = rm.list_resources()
print(instList)
GPIBName = ''
for instr in instList:
if instr.find('GPIB') == 0:
GPIBName = instr
sr400 = rm.open_resource(GPIBName)
sr400.timeout = 1000
Here ResourceManager() creates an access point to the shared VISA library which links devices with different connection types to driver software. Once this is created, list_resources() displays all available devices to connect to in the library. However, if you want to actually see this list in a command window, you must put it within a print() command like any other variable in Python.
The second paragraph of code in the example was our way of having the computer automatically find the GPIB port to connect to. It simply searches for the word "GPIB" at the start of each instrument in list_resources() (which would correspond to an index of 0) as PyVISA formats these instruments with their connection types at the beginning of their names. Lastly, once the correct port has been chosen, it must be formally connected to by calling it as a parameter in your ResourceManager object's open_resource() function. The timeout in the last line simply gives the device a maximum time limit (in milliseconds) to complete tasks sent to it from the program.
As mentioned in the previous sub-section, using a serial connection is not recommended for stability reasons. Establishing it takes more work than using PyVISA for GPIB,