Add help menu with documentation and ... help
This commit is contained in:
parent
bb2249c574
commit
a0f7de8b70
@ -1,3 +1,4 @@
|
||||
import os
|
||||
import sys
|
||||
if __name__ == "__main__":
|
||||
if __package__ is None:
|
||||
@ -14,5 +15,4 @@ from cpdctrl_gui import init
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
sys.exit(init.run())
|
||||
sys.exit(init.run())
|
@ -1,4 +1,5 @@
|
||||
## About
|
||||
`cpdctrl-gui` is a program for conducting contact potential difference (CPD) measurements under illumination.
|
||||
|
||||
- Author: Matthias Quintern
|
||||
- License: [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
15
cpdctrl_gui/resources/data_recording.md
Normal file
15
cpdctrl_gui/resources/data_recording.md
Normal file
@ -0,0 +1,15 @@
|
||||
## Data recording
|
||||
|
||||
### Buffer mode
|
||||
**TODO**
|
||||
|
||||
### Data flushing
|
||||
Measurements can be performed over many hours or multiple days.
|
||||
To make sure that unforeseen accidents like Windows Updates do not ruin the entire measurement,
|
||||
the data can be continuously written to the disk.
|
||||
To enable this feature, set `Flush After` to a non-zero value (in the Measurement Settings tab).
|
||||
After \<Flush After\> number of datapoints are recorded, they are written to the cache directory
|
||||
as serialized numpy array.
|
||||
When the measurement is finished, all partial arrays are loaded again and the complete data
|
||||
can be saved as `csv` or serialized numpy array (`.pkl`).
|
||||
|
42
cpdctrl_gui/resources/led_control.md
Normal file
42
cpdctrl_gui/resources/led_control.md
Normal file
@ -0,0 +1,42 @@
|
||||
## LED Control
|
||||
To automatically control the LED state during the measurement, you can
|
||||
use a LED script.
|
||||
The LED script is a simple text file with lines in this format:
|
||||
`<duration> <led state>`
|
||||
The script starts at the top, applies `<led state>` for `<duration>` and moves to the next line.
|
||||
|
||||
- `<duration>`: Integer, time in seconds. Alternatively, you may append `s`, `m` or `h`, for seconds, minutes, hours.
|
||||
- `<led state>`: LED brightness in percent. Can be an integer between 0-100 or `on` or `off`.
|
||||
Numbers between 1-99 may only be used if the LED controller supports that (the Arduino/LEDD1B does not).
|
||||
|
||||
Comments may start with `#`. Leading and trailing whitespaces as well as empty lines are ignored.
|
||||
|
||||
### Example
|
||||
```
|
||||
# turn on (100%) for 20 seconds
|
||||
20 on
|
||||
5 off# comments after statements allowed
|
||||
5 100 # whitespace before comments after statements allowed
|
||||
# turn off for 5 seconds
|
||||
5s 0
|
||||
# set to 65% for 1 minute
|
||||
1m 65
|
||||
# turn off for 1 minute and 10 seconds
|
||||
1m10s off
|
||||
# turn on off for 1 hour, 5 minutes and 45 seconds
|
||||
1h5m45s on
|
||||
```
|
||||
|
||||
### Live changes
|
||||
The script can be adapted during the measurement in two ways:
|
||||
First, in the GUI through the table in the `LED Script` tab on the left.
|
||||
Second, by modifying the text file that was loaded (requires "Watch LED Script" checkbox to be ticked).
|
||||
|
||||
You can:
|
||||
- change any LED value
|
||||
- change durations of future steps
|
||||
- add/remove future lines (currently only by modifying the file)
|
||||
|
||||
You can not:
|
||||
- change steps from the past
|
||||
- make the current step so short that it would be skipped
|
42
cpdctrl_gui/resources/sample_changing.md
Normal file
42
cpdctrl_gui/resources/sample_changing.md
Normal file
@ -0,0 +1,42 @@
|
||||
## Changing the sample
|
||||
1. Stop the turbopump:
|
||||
1. Press the stop button on the control panel
|
||||
2. Close the valve between pump and chamber (on top of the turbo pump), by screwing it into the pump
|
||||
2. Ventilate the chamber
|
||||
1. Open the gate valve
|
||||
2. Carefully open the needle valve (usually less than 1/8 turn)
|
||||
3. When the chamber can be moved, close both valves again
|
||||
3. Take off the chamber
|
||||
1. Make some space to put the chamber (mind the grease on the bottom edge)
|
||||
2. Carefully lift the chamber. Good places to grab it are the tubing on the left and the right bottom edge.
|
||||
***Caution***: The tube connecting the chamber with the pump will exert a force to the right!
|
||||
**Make sure you do not crash the chamber into the sample tray!**
|
||||
4. Move the sample away from the gold mesh
|
||||
1. Move the tray fully down by turning the upper micrometer screw *counterclockwise*
|
||||
2. Move the tray fully to the left using the larger micrometer screw
|
||||
3. Loosen the screw on the clamp holding the sample in place and remove the sample
|
||||
5. Prepare the new sample
|
||||
1. Put the sample on the tray and place the clamp on it.
|
||||
2. Tighten the clamp screw (you might need to grab the nut on the bottom side)
|
||||
3. Move the tray in x-position using the large micrometer screw.
|
||||
The gold mesh should be well aligned with the sample surface
|
||||
4. Carefully move the tray up by turning the small micrometer screw *clockwise*.
|
||||
Leave about half a millimeter of space between the sample and the gold mesh
|
||||
**Do not crash the sample into the gold mesh!**
|
||||
6. Put the chamber back on
|
||||
1. Put the chamber back on and align it on the two posts on the bottom and right
|
||||
2. Check the backside to make sure that no cables are sticking out
|
||||
7. Vacuum the chamber
|
||||
1. Make sure the nitrogen venting valves are closed
|
||||
2. **Make sure the turbopump is not spinning anymore**
|
||||
3. When the turbopump has fully stopped, slowly open the valve on top of the pump
|
||||
4. Fully open the valve
|
||||
5. **Wait** until the vacuum is in the lower 1E-2 range, eg 4.0E-2 (read the value from the sensor attached to the turbopump)
|
||||
6. Only when this target pressure is reached, turn on the turbopump (control panel on top shelf)
|
||||
7. Wait until the desired vacuum for measurement is reached (usually 1E-5)
|
||||
- 1E-4: **TODO**
|
||||
- 1E-5: **TODO**
|
||||
- 1E-6: after 1-2 days
|
||||
|
||||
If the pressure does not drop enough: Use isopropanol to inspect for leaks
|
||||
|
5
cpdctrl_gui/resources/small_about.md
Normal file
5
cpdctrl_gui/resources/small_about.md
Normal file
@ -0,0 +1,5 @@
|
||||
## About
|
||||
|
||||
- Author: Matthias Quintern
|
||||
- License: [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
- Source Code: https://git.quintern.xyz/MatthiasQuintern/cpdctrl-gui
|
23
cpdctrl_gui/resources/technical_information.md
Normal file
23
cpdctrl_gui/resources/technical_information.md
Normal file
@ -0,0 +1,23 @@
|
||||
## Technical Information
|
||||
### cpdctrl-gui Software
|
||||
`cpdctrl-gui` is written in python and uses the Qt framework for the graphical user interface.
|
||||
Most functionality like interaction with the various devices is provided by the `cpdctrl` package,
|
||||
which can be used without the GUI in an ipython shell for advanced or debugging purposes.
|
||||
|
||||
|
||||
|
||||
### Arduino Code
|
||||
To control the ThorLabs LEDD1B, it is connected to an Arduino Nano, which is connected to the lab PC
|
||||
via USB. The Arduino must have the correct software loaded in order to communicate with `cpdctrl` and the LEDD1B.
|
||||
1. Open the Arduino IDE
|
||||
2. Open the sketch `~/cpd-dev/cpdctrl/arduino-thorlabs-led/led_control/led_control.ino`
|
||||
3. Select `COM4` and `Arduino Nano` and then 'Upload Sketch'
|
||||
|
||||
### CPD Controller Calibration
|
||||
**TODO**
|
||||
This process is not always necessary.
|
||||
1. Set CPD Controller to Manual, Offset=Gold Work Function, Filter off (so you can see what happens immediately), Oscillator to ~2
|
||||
2. Move the micrometer screw close until a signal appears
|
||||
3. Set Automatic offset so that the output is 0V
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
## Troubleshooting
|
||||
### 1) The LED does not work
|
||||
### 1) General
|
||||
The program writes information to a log file, which might contain helpful information.
|
||||
It is located in the cache directory, usually in `~/.cache/cpdctrl-gui`.
|
||||
|
||||
### 2) The Arduino/LEDD1B does not work
|
||||
1) Make sure the Thorlabs LED is plugged in, turned on (turn the dial to a non-zero value) and that the switch is in the **TRIG**er position
|
||||
2) Reset the Arduino by pressing the white button on the top and restart the program
|
||||
3) Unplug and replug the Arduino and restart the program
|
||||
4) Re-upload the code (see section "Arduino Code")
|
||||
4) Re-upload the code (see section "Technical Information/Arduino Code")
|
||||
|
@ -1,54 +1 @@
|
||||
# CPD User Guide
|
||||
## Changing the sample
|
||||
1. Stop the turbopump:
|
||||
1. Press the stop button on the control panel
|
||||
2. Close the valve between pump and chamber (on top of the turbo pump), by screwing it into the pump
|
||||
2. Ventilate the chamber
|
||||
1. Open the gate valve
|
||||
2. Carefully open the needle valve (usually less than 1/8 turn)
|
||||
3. When the chamber can be moved, close both valves again
|
||||
3. Take off the chamber
|
||||
1. Make some space to put the chamber (mind the grease on the bottom edge)
|
||||
2. Carefully lift the chamber. Good places to grab it are the tubing on the left and the right bottom edge.
|
||||
***Caution***: The tube connecting the chamber with the pump will exert a force to the right!
|
||||
**Make sure you do not crash the chamber into the sample tray!**
|
||||
4. Move the sample away from the gold mesh
|
||||
1. Move the tray fully down by turning the upper micrometer screw *counterclockwise*
|
||||
2. Move the tray fully to the left using the larger micrometer screw
|
||||
3. Loosen the screw on the clamp holding the sample in place and remove the sample
|
||||
5. Prepare the new sample
|
||||
1. Put the sample on the tray and place the clamp on it.
|
||||
2. Tighten the clamp screw (you might need to grab the nut on the bottom side)
|
||||
3. Move the tray in x-position using the large micrometer screw.
|
||||
The gold mesh should be well aligned with the sample surface
|
||||
4. Carefully move the tray up by turning the small micrometer screw *clockwise*.
|
||||
Leave about half a millimeter of space between the sample and the gold mesh
|
||||
**Do not crash the sample into the gold mesh!**
|
||||
6. Put the chamber back on
|
||||
1. Put the chamber back on and align it on the two posts on the bottom and right
|
||||
2. Check the backside to make sure that no cables are sticking out
|
||||
7. Vacuum the chamber
|
||||
1. Make sure the nitrogen venting valves are closed
|
||||
2. **Make sure the turbopump is not spinning anymore**
|
||||
3. When the turbopump has fully stopped, very slowly open the valve on top of the pump
|
||||
4. Fully open the valve **TODO: hier noch irgendwelche checks?**
|
||||
5. **Wait** until the vacuum is in the lower $10^{-2}$ range (read the value from the sensor attached to the turbopump)
|
||||
6. Only when this target pressure is reached, turn on the turbopump (control panel on top)
|
||||
7. Wait until the desired vacuum for measurement is reached (usually $10^{-5}$)
|
||||
- $10^{-4}$: **TODO**
|
||||
- $10^{-5}$: **TODO**
|
||||
- $10^{-6}$: after 1-2 days
|
||||
|
||||
If the pressure does not drop enough: Use isopropanol to inspect for leaks
|
||||
|
||||
## CPD Controller Calibration
|
||||
**TODO**
|
||||
|
||||
This process is not always necessary.
|
||||
1. Set CPD Controller to Manual, Offset=Gold Work Function, Filter off (so you can see what happens immediately), Oscillator to ~2
|
||||
2. Move the micrometer screw close until a signal appears
|
||||
3. Set Automatic offset so that the output is 0V
|
||||
Calibration: Fresh graphite probe
|
||||
|
||||
## cpdctrl-gui Software
|
||||
**TODO**
|
||||
## User Guide
|
||||
|
@ -5,9 +5,10 @@ from PyQt6.QtCore import Qt, QTimer, QFileSystemWatcher
|
||||
from PyQt6.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QLabel, QStatusBar, QFileDialog, \
|
||||
QVBoxLayout
|
||||
from PyQt6.QtWidgets import QTabWidget
|
||||
from PyQt6.QtGui import QIcon, QPixmap, QAction, QKeySequence, QDragEnterEvent
|
||||
from PyQt6.QtGui import QIcon, QAction, QKeySequence, QDragEnterEvent
|
||||
from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QMessageBox
|
||||
|
||||
from .widgets.help import HelpMenu
|
||||
from ..resources import get_resource_path
|
||||
from .widgets.menubar import MenuBar
|
||||
from .widgets.toolbar import ToolBar
|
||||
@ -15,8 +16,9 @@ from .widgets.metadata_input import MetadataInput
|
||||
from cpdctrl_gui.ui.widgets.settings import MeasurementSettings, AppSettings
|
||||
from .widgets.plot import Plot
|
||||
from .widgets.device_select import ListChoice
|
||||
from .widgets.about import MarkdownView
|
||||
from .widgets.about import About
|
||||
from .widgets.led_script import LedScriptViewer
|
||||
from .widgets.help import HelpMenu
|
||||
# from .widgets.treeview import TreeView
|
||||
|
||||
import time
|
||||
@ -332,7 +334,6 @@ class MainWindow(QMainWindow):
|
||||
raise RuntimeError("No led control device selected")
|
||||
self.idle_stop()
|
||||
|
||||
raise KeyError("Exception for testing")
|
||||
name = self.w_measurement_settings.get_value("name")
|
||||
script = self.w_measurement_settings.get_value("led_script")
|
||||
flush_after = self.w_measurement_settings.get_value("flush_after")
|
||||
@ -615,17 +616,7 @@ class MainWindow(QMainWindow):
|
||||
buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok)
|
||||
buttons.accepted.connect(dialog.accept)
|
||||
dialog.setLayout(QVBoxLayout())
|
||||
# show the logo via a pixmap in a label
|
||||
img_path = get_resource_path("icons/logo.svg")
|
||||
pixmap = QPixmap(img_path)
|
||||
pixmap = pixmap.scaled(128, 128, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)
|
||||
# qt cant find the file
|
||||
label = QLabel()
|
||||
label.setPixmap(pixmap)
|
||||
label.setAlignment(Qt.AlignmentFlag.AlignCenter) # center the image
|
||||
dialog.layout().addWidget(label)
|
||||
# show about.md
|
||||
dialog.layout().addWidget(MarkdownView("about.md"))
|
||||
dialog.layout().addWidget(About())
|
||||
dialog.layout().addWidget(buttons)
|
||||
dialog.exec()
|
||||
|
||||
@ -635,9 +626,7 @@ class MainWindow(QMainWindow):
|
||||
buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok)
|
||||
buttons.accepted.connect(dialog.accept)
|
||||
dialog.setLayout(QVBoxLayout())
|
||||
# show help.md
|
||||
#dialog.layout().addWidget(MarkdownView("troubleshooting.md"))
|
||||
dialog.layout().addWidget(MarkdownView("user_guide.md"))
|
||||
dialog.layout().addWidget(HelpMenu())
|
||||
dialog.layout().addWidget(buttons)
|
||||
# set larger window size
|
||||
dialog.resize(800, 600)
|
||||
|
@ -1,5 +1,6 @@
|
||||
from PyQt6.QtWidgets import QTextBrowser
|
||||
from PyQt6.QtGui import QDesktopServices
|
||||
from PyQt6.QtWidgets import QTextBrowser, QWidget, QLabel, QVBoxLayout
|
||||
from PyQt6.QtCore import Qt
|
||||
from PyQt6.QtGui import QDesktopServices, QPixmap
|
||||
|
||||
from ...resources import get_resource_path
|
||||
|
||||
@ -8,19 +9,45 @@ import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class MarkdownView(QTextBrowser):
|
||||
def __init__(self, path):
|
||||
super().__init__()
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setReadOnly(True)
|
||||
self.filepath = get_resource_path(path)
|
||||
try:
|
||||
with open(self.filepath, "r") as file:
|
||||
content = file.read()
|
||||
self.setMarkdown(content)
|
||||
except FileNotFoundError:
|
||||
log.error(f"File not found: {self.filepath}")
|
||||
self.setMarkdown(f"## File not found\n`{self.filepath}`")
|
||||
|
||||
# open links with the OS web browser
|
||||
self.anchorClicked.connect(QDesktopServices.openUrl)
|
||||
# dont follow links
|
||||
self.setOpenLinks(False)
|
||||
|
||||
class About(QWidget):
|
||||
"""
|
||||
Small about text with logo
|
||||
"""
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setLayout(QVBoxLayout())
|
||||
# show the logo via a pixmap in a label
|
||||
img_path = get_resource_path("icons/logo.svg")
|
||||
pixmap = QPixmap(img_path)
|
||||
pixmap = pixmap.scaled(128, 128, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)
|
||||
# qt cant find the file
|
||||
w_label = QLabel()
|
||||
w_label.setPixmap(pixmap)
|
||||
w_label.setAlignment(Qt.AlignmentFlag.AlignCenter) # center the image
|
||||
self.layout().addWidget(w_label)
|
||||
# show about.md
|
||||
w_md_view = MarkdownView()
|
||||
filepath = get_resource_path("small_about.md")
|
||||
try:
|
||||
with open(filepath, "r") as file:
|
||||
content = file.read()
|
||||
try:
|
||||
from importlib.metadata import version
|
||||
cpdversion = version('cpdctrl_gui')
|
||||
content += f"\n- Version: {cpdversion}"
|
||||
except Exception as e:
|
||||
log.info(f"Failed to get cpdctrl_gui version: {e}")
|
||||
# content += f"\n- Version: Unknown"
|
||||
w_md_view.setMarkdown(content)
|
||||
except FileNotFoundError:
|
||||
log.error(f"File not found: {filepath}")
|
||||
w_md_view.setMarkdown(f"## File not found\n`{filepath}`")
|
||||
self.layout().addWidget(w_md_view)
|
||||
|
49
cpdctrl_gui/ui/widgets/help.py
Normal file
49
cpdctrl_gui/ui/widgets/help.py
Normal file
@ -0,0 +1,49 @@
|
||||
from PyQt6.QtWidgets import QWidget, QTextBrowser, QHBoxLayout, QListWidget, QListWidgetItem
|
||||
from PyQt6.QtGui import QDesktopServices
|
||||
from ...resources import get_resource_path
|
||||
from .about import MarkdownView
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# Ordered list of help files to use
|
||||
GUI_FILES = [
|
||||
("about.md", "About"),
|
||||
("sample_changing.md", "Changing the Sample"),
|
||||
("data_recording.md", "Data recording"),
|
||||
("led_control.md", "LED control"),
|
||||
("troubleshooting.md", "Troubleshooting"),
|
||||
("technical_information.md", "Technical Information"),
|
||||
]
|
||||
|
||||
class HelpMenu(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setLayout(QHBoxLayout())
|
||||
self.w_list = QListWidget()
|
||||
self.w_list.setMaximumWidth(200)
|
||||
self.layout().addWidget(self.w_list)
|
||||
self.w_viewer = MarkdownView()
|
||||
self.layout().addWidget(self.w_viewer)
|
||||
files = [(get_resource_path(f), name) for (f,name) in GUI_FILES]
|
||||
for i, (f, name) in enumerate(files):
|
||||
w_item = QListWidgetItem(name)
|
||||
w_item.filepath = f
|
||||
self.w_list.addItem(w_item)
|
||||
if i == 0:
|
||||
self.set_view(w_item)
|
||||
self.w_list.setCurrentRow(0)
|
||||
self.w_list.itemClicked.connect(self.set_view)
|
||||
|
||||
def set_view(self, list_item):
|
||||
try:
|
||||
filepath = list_item.filepath
|
||||
try:
|
||||
with open(filepath, "r") as file:
|
||||
content = file.read()
|
||||
self.w_viewer.setMarkdown(content)
|
||||
except FileNotFoundError:
|
||||
log.error(f"File not found: {filepath}")
|
||||
self.w_viewer.setMarkdown(f"## File not found\n`{filepath}`")
|
||||
except AttributeError:
|
||||
log.error(f"Invalid list item")
|
@ -2,9 +2,9 @@
|
||||
requires = ["setuptools"]
|
||||
|
||||
[project]
|
||||
name = "cpdctrl-gui"
|
||||
version = "0.1.0"
|
||||
description = "GUI Utility for CPD measurements with a Keitley 2700 SMU and an Arduino-controlled light source"
|
||||
name = "cpdctrl_gui"
|
||||
version = "1.0.0"
|
||||
description = "GUI Utility for CPD measurements with a Keitley 2700 SMU and a controlled light source"
|
||||
requires-python = ">=3.10"
|
||||
readme = "README.md"
|
||||
license = {file = "LICENSE"}
|
||||
|
Loading…
x
Reference in New Issue
Block a user