Skip to content
Extraits de code Groupes Projets
Valider ded1838a rédigé par Simon Collignon's avatar Simon Collignon
Parcourir les fichiers

Initial commit

parent
Branches master
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
Pipeline #77825 annulé
Affichage de
avec 1216 ajouts et 0 suppression
env
env
"""Main entry point for the application."""
from app import main
if __name__ == '__main__':
main.run()
import logging
import serial
import serial.tools.list_ports
from simple_pid import PID
import time
import PySide6.QtGui
from PySide6.QtWidgets import QWidget, QMainWindow, QFileDialog, QSpacerItem, QSizePolicy
from PySide6.QtCore import Qt, Slot, QTimer
from PySide6 import QtGui, QtWidgets
from app.ui.dist.ui_mainwindow import Ui_MainWindow
from app.code.module import Module
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s")
def find_serial_device(serial_number:str) -> str:
"""Check the `hwid` through the list ports for a `SER` key
that matches `serial_number`
"""
for port, desc, hwid in serial.tools.list_ports.comports():
# print(port)
infos = hwid.split(" ")
print(infos)
for info in infos:
if not info.startswith("SER"):
continue
serial_num = info.split("=")[-1]
print(serial_num)
if not serial_num == serial_number:
break
return port
return ""
class MainWindow(QMainWindow, Ui_MainWindow):
"""The MainWindow is the parent class of the application."""
def __init__(self):
"""Initialize the MainWindow and setup the UI."""
super().__init__()
self.setupUi(self)
self.setWindowTitle("Autowaveguide")
self.timer = QTimer()
self.timer.timeout.connect(self.the_loop)
self.timer.start(1) # Update every 200 ms
self.timer_gui = QTimer()
self.timer_gui.timeout.connect(self.gui_loop)
self.timer_gui.start(100)
self.timer_gui_true_pressure = QTimer()
self.timer_gui_true_pressure.timeout.connect(self.true_pressure_loop)
self.timer_gui_true_pressure.start(1000)
self.qlevel = 0.0
self.p_offset = 871
self.p_scale = 4.818666666666666e-03
self.mks_controller : MKS627H = MKS627H()
# burkert solenoid valve
SOLENOID_SERIAL_NUMBER : str = "3307142A37323835191D33324B572D44"
VALVE_PORT : str = find_serial_device(SOLENOID_SERIAL_NUMBER)
self.valve = serial.Serial()
self.valve.port = VALVE_PORT
self.valve.baudrate = 1_000_000
self.valve.open()
self.module : Module = Module()
self.central_layout.addWidget(self.module)
self.module.setpoint.editingFinished.connect(self.update_pid)
self.module.pid_kp.editingFinished.connect(self.update_pid)
self.module.pid_ki.editingFinished.connect(self.update_pid)
self.module.pid_kd.editingFinished.connect(self.update_pid)
self.pid = PID(self.module.pid_kp.value(),
self.module.pid_ki.value(),
self.module.pid_kd.value(),
self.module.setpoint.value(),
output_limits=(40, 70))
def update_valve(self, valve_percent:float):
self.valve.write(b'u')
data = str(valve_percent)
self.valve.write(data.encode() + b'\n')
try:
response = float(self.valve.readline().decode('utf-8').rstrip().split()[0])
except ValueError as error:
logging.error(error)
return -1
return response
def update_pid(self):
self.pid.setpoint = self.pressure_to_qlevel(self.module.setpoint.value())
self.pid.tunings = (self.module.pid_kp.value(), self.module.pid_ki.value(), self.module.pid_kd.value())
def qlevel_to_pressure(self, level:int) -> float:
"""Convert the quantization level of the 14 bit ADC of the arduino R4 minima to pressure in ubar."""
return float(self.p_scale*(level-self.p_offset))
def pressure_to_qlevel(self, pressure:float) -> int:
"""Convert pressure in ubar to the quantization level of the 14 bit ADC of the arduino R4 minima."""
return int(pressure/self.p_scale + self.p_offset)
def the_loop(self):
_ql = self.update_valve(self.pid(self.qlevel))
if _ql != -1:
self.qlevel = _ql
def gui_loop(self):
"""This is the main loop of the GUI."""
self.module.update_plot_data(self.qlevel_to_pressure(self.qlevel))
def true_pressure_loop(self):
"""A simple loop to display the absolute pressure read from the MKS gauge controller."""
self.module.true_pressure.setText(f"{self.mks_controller.read_pressure():.2f}")
def closeEvent(self, event):
try:
self.timer.timeout.disconnect(self.the_loop)
self.valve.write(b'r')
logging.info("Exited normally.")
except Exception as e:
logging.error(f"Abnormal exit with error: {e}")
event.accept()
class MKS627H():
def __init__(self):
PGAUGE_SERIAL_NUMBER : str = "FT6VYF8DA"
PGAUGE_PORT : str = find_serial_device(PGAUGE_SERIAL_NUMBER)
self.pgauge = serial.Serial()
self.pgauge.port = PGAUGE_PORT
self.pgauge.timeout = 1
self.pgauge.baudrate = 9600
self.pgauge.open()
def read_pressure(self) -> float:
"""Return the pressure read from the PDR 2000 MKS controller in ubar.
I added the `in_waiting` while loop because I think I was accumulating
data in the serial buffer. This helps to prevent this issue.
TODO: in the future we might implement a maximum number of tries to read the pressure
and if it fails we should throw an error to stop the experiment and display something
well.
"""
try:
self.pgauge.write(b'p\n')
# Check if there's data in the buffer
while self.pgauge.in_waiting > 0:
# Read all data available in the buffer
response = self.pgauge.readline().decode('utf-8').rstrip()
return float(response.split()[0])*1e3
except Exception as e:
logging.error(e)
return -1
\ No newline at end of file
import numpy as np
import pyqtgraph as pg
from PySide6.QtWidgets import QWidget, QSizePolicy
from PySide6.QtGui import QLinearGradient, QBrush, QColor
from app.ui.dist.ui_module import Ui_module
class Module(QWidget, Ui_module):
"""Handles all the post-processing settings of an `experiment` object."""
def __init__(self):
super().__init__()
self.setupUi(self)
self.graph = Graph()
self.graph.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.graph.setFixedSize(500, 200)
view_box = self.graph.getViewBox()
# Disable mouse interactivity (zoom, pan)
view_box.setMouseEnabled(x=False, y=False)
# view_box.setInteractive(False)
data_count = 100
self.x = np.arange(data_count)
self.y = np.zeros(data_count)
y2 = np.zeros(data_count)
self.curve = self.graph.plot(self.x, self.y, pen=pg.mkPen(QColor(237, 240, 96), width=2))
curve2 = self.graph.plot(self.x, y2, pen=pg.mkPen(QColor(0, 0, 255, 0), width=0))
# Create a gradient brush
gradient = QLinearGradient(0, 0, 0, 1)
gradient.setCoordinateMode(QLinearGradient.ObjectBoundingMode)
gradient.setColorAt(0, QColor(237, 240, 96, 10)) # Blue at the bottom, semi-transparent
gradient.setColorAt(1, QColor(237, 240, 96, 100)) # Transparent at the top
brush = QBrush(gradient)
# Fill the area under the curve with the gradient brush
fill = pg.FillBetweenItem(self.curve, curve2, brush=brush)
self.graph.addItem(fill)
self.graph.showGrid(x=True, y=True, alpha=0.3)
self.graph.getPlotItem().hideAxis('bottom')
self.graph_layout.addWidget(self.graph)
def update_plot_data(self, new_y):
# Update y data with a new sine wave that changes over time
self.y[:-1] = self.y[1:]
self.y[-1] = new_y
self.curve.setData(self.x, self.y)
class Graph(pg.PlotWidget):
"""Handles all the post-processing settings of an `experiment` object."""
def __init__(self, parent=None):
super(Graph, self).__init__(parent)
self.setBackground("#2c2e36")
self.color_white = '#f2f2f2'
self.pen = pg.mkPen(color="#EDF060", width=1)
self.label_styles = {'color':'#a2a2a2', 'font-size':'14px'}
"""
`run` function to be called from __main__.py. Creates the QApplication,
the MainWindow, and then runs the application.
"""
import sys
from PySide6.QtWidgets import QApplication
from app.code.mainwindow import MainWindow
def run():
app = QApplication(sys.argv)
app.setStyle("Fusion")
mw = MainWindow()
# mw.resize(1400, 560) # seems like a nice aspect ratio for spectra
mw.show()
sys.exit(app.exec())
Fichier ajouté
Fichier ajouté
Fichier ajouté
Fichier ajouté
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'mainwindow.ui'
##
## Created by: Qt User Interface Compiler version 6.8.0
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QHBoxLayout, QLayout, QMainWindow,
QSizePolicy, QWidget)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.resize(448, 639)
MainWindow.setAcceptDrops(False)
MainWindow.setWindowOpacity(1.000000000000000)
MainWindow.setStyleSheet(u"QMainWindow,\n"
"QToolBar { \n"
" background-color: #010101; \n"
" border: 1px solid #010101;\n"
"}\n"
"#side_frame_auto,\n"
"#side_frame_instr,\n"
"#main_frame_fid,\n"
"#main_frame_spectrum {\n"
" border: 0;\n"
" background-color: #12141a;\n"
" border-radius: 5px;\n"
"}\n"
"#frame_title_auto,\n"
"#frame_title_instr,\n"
"#frame_title_spectrum,\n"
"#frame_title_fid {\n"
" color: #d2d2d2;\n"
" font-weight:600;\n"
" font-size: 14px;\n"
"}\n"
"QMenu {\n"
" background-color: #12141a;\n"
" border-radius: 5px;\n"
" padding: 0px;\n"
" color: #d2d2d2;\n"
"}\n"
"QMenu::item:selected {\n"
" background-color: #3b3d47;\n"
"}\n"
"QCheckBox {\n"
" color: #f2f2f2;\n"
"}\n"
"/*---- MODULE STYLE ----*/\n"
"/*\n"
"#my_module {\n"
" border: 0;\n"
" color: #444b59;\n"
" background-color: #363e4d;\n"
" border-radius: 5px;\n"
"}\n"
"#my_module QLabel {\n"
" color: #f2f2f2;\n"
"}\n"
"#my_module #module_title {\n"
" color: #fffffft;\n"
" font-weight: 600;\n"
" font-size: 16px;\n"
" border: 0;\n"
" margin: 10px 0px 0px 2px;\n"
"}"
"\n"
"#my_module Line {\n"
" background-color: #5b6a87;\n"
" border-color: #363e4d;\n"
"}\n"
"*/\n"
"/*---- END MODULE STYLE ----*/\n"
"\n"
"\n"
"/*---- SCROLL AREA ----*/\n"
"\n"
"#side_scroll_area_auto,\n"
"#side_scroll_area_widget_auto,\n"
"#side_scroll_area_instr,\n"
"#side_scroll_area_widget_instr {\n"
" background-color: #12141a;\n"
" border-width: 0px;\n"
" border-color: #12141a;\n"
" padding: 0;\n"
"}\n"
"\n"
"QScrollBar:vertical {\n"
" border: 0px solid #12141a;\n"
" background:#12141a;\n"
" width:10px; \n"
" margin: 0px 0px 0px 0px;\n"
"}\n"
"QScrollBar::handle:vertical { \n"
" min-height: 0px;\n"
" border: 0px solid red;\n"
" border-radius: 4px;\n"
" background-color: #2c2e36;\n"
"}\n"
"QScrollBar::add-line:vertical { \n"
" height: 0px;\n"
" subcontrol-position: bottom;\n"
" subcontrol-origin: margin;\n"
"}\n"
"QScrollBar::sub-line:vertical {\n"
" height: 0 px;\n"
" subcontrol-position: top;\n"
" subcontrol-origin: margin;\n"
"}\n"
"\n"
"/*--"
"-- END SCROLL AREA ----*/\n"
"\n"
"/*---- BUTTONS ----*/\n"
"#apply_button,\n"
"#cancel_button {\n"
" background: #1db954;\n"
" border: 0;\n"
" border-radius: 10px;\n"
" padding: .5em 2em;\n"
" color: 535353;\n"
"}\n"
"#cancel_button {\n"
" background: #2c2e36;\n"
" color: #d2d2d2;\n"
"}\n"
"#apply_button:pressed {\n"
" background: #41e17a;\n"
" color: #000000;\n"
"}\n"
"QSpinBox, QDoubleSpinBox, QComboBox {\n"
" background-color:#2c2e36;\n"
" color: white;\n"
"}\n"
"\n"
"/*--- END BUTTIONS ---*/\n"
"\n"
"/*--- QProgressBar ---*/\n"
"QProgressBar\n"
"{\n"
" background: #585b66;\n"
" border-style: plain;\n"
" border-width: 0px;\n"
" border-radius: 3px;\n"
"}\n"
"QProgressBar::chunk\n"
"{\n"
" background-color: #fafafa;\n"
" border-style: plain;\n"
" border-width: 0px;\n"
" border-radius: 3px;\n"
"}\n"
"/*--- END QProgressBar ---*/")
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.horizontalLayout_3 = QHBoxLayout(self.centralwidget)
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
self.horizontalLayout_3.setSizeConstraint(QLayout.SetFixedSize)
self.central_layout = QHBoxLayout()
self.central_layout.setSpacing(8)
self.central_layout.setObjectName(u"central_layout")
self.central_layout.setSizeConstraint(QLayout.SetFixedSize)
self.horizontalLayout_3.addLayout(self.central_layout)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QMetaObject.connectSlotsByName(MainWindow)
# setupUi
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
# retranslateUi
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'module.ui'
##
## Created by: Qt User Interface Compiler version 6.8.0
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QDoubleSpinBox, QFrame, QGridLayout,
QHBoxLayout, QLabel, QLayout, QLineEdit,
QSizePolicy, QSpacerItem, QVBoxLayout, QWidget)
class Ui_module(object):
def setupUi(self, module):
if not module.objectName():
module.setObjectName(u"module")
module.resize(442, 639)
self.verticalLayout = QVBoxLayout(module)
self.verticalLayout.setObjectName(u"verticalLayout")
self.verticalLayout.setSizeConstraint(QLayout.SetFixedSize)
self.side_frame_auto = QFrame(module)
self.side_frame_auto.setObjectName(u"side_frame_auto")
self.side_frame_auto.setMaximumSize(QSize(16777215, 16777215))
self.side_frame_auto.setFrameShape(QFrame.StyledPanel)
self.side_frame_auto.setFrameShadow(QFrame.Plain)
self.side_frame_auto.setLineWidth(0)
self.horizontalLayout = QHBoxLayout(self.side_frame_auto)
self.horizontalLayout.setSpacing(8)
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.horizontalLayout.setSizeConstraint(QLayout.SetMinimumSize)
self.horizontalLayout.setContentsMargins(10, 10, 10, 10)
self.module_layout_auto = QVBoxLayout()
self.module_layout_auto.setSpacing(10)
self.module_layout_auto.setObjectName(u"module_layout_auto")
self.auto_module = QWidget(self.side_frame_auto)
self.auto_module.setObjectName(u"auto_module")
self.auto_module.setStyleSheet(u"#auto_module {\n"
" border: 0;\n"
" color: #444b59;\n"
" background-color: #2c2e36;\n"
" border-radius: 5px;\n"
"}\n"
"#auto_module QLabel {\n"
" color: #f2f2f2;\n"
"}\n"
"#auto_module #module_title_auto {\n"
" color: #ffffff;\n"
" font-weight: 600;\n"
" font-size: 16px;\n"
" border: 0;\n"
" margin: 10px 0px 5px 2px;\n"
"}")
self.verticalLayout_14 = QVBoxLayout(self.auto_module)
self.verticalLayout_14.setObjectName(u"verticalLayout_14")
self.verticalLayout_14.setContentsMargins(0, 0, 0, 0)
self.module_title_auto = QLabel(self.auto_module)
self.module_title_auto.setObjectName(u"module_title_auto")
self.module_title_auto.setMargin(0)
self.verticalLayout_14.addWidget(self.module_title_auto)
self.title_line = QFrame(self.auto_module)
self.title_line.setObjectName(u"title_line")
self.title_line.setMaximumSize(QSize(16777215, 2))
self.title_line.setStyleSheet(u"background: #12141a;\n"
"background-color: #12141a;\n"
"color: #12141a;")
self.title_line.setFrameShadow(QFrame.Plain)
self.title_line.setLineWidth(1)
self.title_line.setFrameShape(QFrame.Shape.HLine)
self.verticalLayout_14.addWidget(self.title_line)
self.graph_layout = QVBoxLayout()
self.graph_layout.setSpacing(5)
self.graph_layout.setObjectName(u"graph_layout")
self.graph_layout.setSizeConstraint(QLayout.SetFixedSize)
self.graph_layout.setContentsMargins(5, 5, 5, 5)
self.horizontalLayout_2 = QHBoxLayout()
self.horizontalLayout_2.setSpacing(0)
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
self.horizontalLayout_2.addItem(self.horizontalSpacer)
self.frame = QFrame(self.auto_module)
self.frame.setObjectName(u"frame")
self.frame.setStyleSheet(u"background: #585b66;\n"
"padding: 2px 3px 3px 3px;\n"
"border: 0;\n"
"border-radius: 5px;")
self.frame.setFrameShape(QFrame.StyledPanel)
self.frame.setFrameShadow(QFrame.Raised)
self.gridLayout = QGridLayout(self.frame)
self.gridLayout.setSpacing(0)
self.gridLayout.setObjectName(u"gridLayout")
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.label_units = QLabel(self.frame)
self.label_units.setObjectName(u"label_units")
sizePolicy = QSizePolicy(QSizePolicy.Policy.Maximum, QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.label_units.sizePolicy().hasHeightForWidth())
self.label_units.setSizePolicy(sizePolicy)
font = QFont()
font.setBold(True)
self.label_units.setFont(font)
self.label_units.setStyleSheet(u"")
self.label_units.setAlignment(Qt.AlignCenter)
self.gridLayout.addWidget(self.label_units, 0, 0, 1, 1)
self.horizontalLayout_2.addWidget(self.frame)
self.graph_layout.addLayout(self.horizontalLayout_2)
self.verticalLayout_14.addLayout(self.graph_layout)
self.param_line = QFrame(self.auto_module)
self.param_line.setObjectName(u"param_line")
self.param_line.setMaximumSize(QSize(16777215, 2))
self.param_line.setStyleSheet(u"background: #12141a;\n"
"background-color: #12141a;\n"
"color: #12141a;")
self.param_line.setFrameShadow(QFrame.Plain)
self.param_line.setLineWidth(1)
self.param_line.setFrameShape(QFrame.Shape.HLine)
self.verticalLayout_14.addWidget(self.param_line)
self.auto_module_grid_layout_5 = QGridLayout()
self.auto_module_grid_layout_5.setSpacing(10)
self.auto_module_grid_layout_5.setObjectName(u"auto_module_grid_layout_5")
self.auto_module_grid_layout_5.setContentsMargins(10, 10, 10, 10)
self.field_layout_t0_9 = QVBoxLayout()
self.field_layout_t0_9.setSpacing(4)
self.field_layout_t0_9.setObjectName(u"field_layout_t0_9")
self.field_layout_t0_9.setSizeConstraint(QLayout.SetFixedSize)
self.field_layout_t0_9.setContentsMargins(-1, -1, -1, 6)
self.label_33 = QLabel(self.auto_module)
self.label_33.setObjectName(u"label_33")
sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
sizePolicy1.setHorizontalStretch(0)
sizePolicy1.setVerticalStretch(0)
sizePolicy1.setHeightForWidth(self.label_33.sizePolicy().hasHeightForWidth())
self.label_33.setSizePolicy(sizePolicy1)
self.label_33.setMinimumSize(QSize(120, 0))
self.label_33.setMaximumSize(QSize(16777215, 16777215))
self.label_33.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.field_layout_t0_9.addWidget(self.label_33)
self.pid_kp = QDoubleSpinBox(self.auto_module)
self.pid_kp.setObjectName(u"pid_kp")
self.pid_kp.setMinimumSize(QSize(80, 0))
self.pid_kp.setMaximumSize(QSize(100, 16777215))
font1 = QFont()
font1.setPointSize(10)
self.pid_kp.setFont(font1)
self.pid_kp.setFocusPolicy(Qt.ClickFocus)
self.pid_kp.setMinimum(-1000.000000000000000)
self.pid_kp.setMaximum(1000.000000000000000)
self.field_layout_t0_9.addWidget(self.pid_kp)
self.auto_module_grid_layout_5.addLayout(self.field_layout_t0_9, 1, 0, 1, 1)
self.field_layout_t0_10 = QVBoxLayout()
self.field_layout_t0_10.setSpacing(4)
self.field_layout_t0_10.setObjectName(u"field_layout_t0_10")
self.field_layout_t0_10.setSizeConstraint(QLayout.SetFixedSize)
self.field_layout_t0_10.setContentsMargins(-1, -1, -1, 6)
self.label_34 = QLabel(self.auto_module)
self.label_34.setObjectName(u"label_34")
sizePolicy1.setHeightForWidth(self.label_34.sizePolicy().hasHeightForWidth())
self.label_34.setSizePolicy(sizePolicy1)
self.label_34.setMinimumSize(QSize(120, 0))
self.label_34.setMaximumSize(QSize(16777215, 16777215))
self.label_34.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.field_layout_t0_10.addWidget(self.label_34)
self.pid_ki = QDoubleSpinBox(self.auto_module)
self.pid_ki.setObjectName(u"pid_ki")
self.pid_ki.setMinimumSize(QSize(80, 0))
self.pid_ki.setMaximumSize(QSize(100, 16777215))
self.pid_ki.setFont(font1)
self.pid_ki.setFocusPolicy(Qt.ClickFocus)
self.pid_ki.setMinimum(-1000.000000000000000)
self.pid_ki.setMaximum(1000.000000000000000)
self.field_layout_t0_10.addWidget(self.pid_ki)
self.auto_module_grid_layout_5.addLayout(self.field_layout_t0_10, 1, 1, 1, 1)
self.field_layout_t0_11 = QVBoxLayout()
self.field_layout_t0_11.setSpacing(4)
self.field_layout_t0_11.setObjectName(u"field_layout_t0_11")
self.field_layout_t0_11.setSizeConstraint(QLayout.SetFixedSize)
self.field_layout_t0_11.setContentsMargins(-1, -1, -1, 6)
self.label_35 = QLabel(self.auto_module)
self.label_35.setObjectName(u"label_35")
sizePolicy1.setHeightForWidth(self.label_35.sizePolicy().hasHeightForWidth())
self.label_35.setSizePolicy(sizePolicy1)
self.label_35.setMinimumSize(QSize(120, 0))
self.label_35.setMaximumSize(QSize(16777215, 16777215))
self.label_35.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.field_layout_t0_11.addWidget(self.label_35)
self.pid_kd = QDoubleSpinBox(self.auto_module)
self.pid_kd.setObjectName(u"pid_kd")
self.pid_kd.setMinimumSize(QSize(80, 0))
self.pid_kd.setMaximumSize(QSize(100, 16777215))
self.pid_kd.setFont(font1)
self.pid_kd.setFocusPolicy(Qt.ClickFocus)
self.pid_kd.setMinimum(-1000.000000000000000)
self.pid_kd.setMaximum(1000.000000000000000)
self.field_layout_t0_11.addWidget(self.pid_kd)
self.auto_module_grid_layout_5.addLayout(self.field_layout_t0_11, 1, 2, 1, 1)
self.field_layout_t0_8 = QVBoxLayout()
self.field_layout_t0_8.setSpacing(4)
self.field_layout_t0_8.setObjectName(u"field_layout_t0_8")
self.field_layout_t0_8.setSizeConstraint(QLayout.SetFixedSize)
self.field_layout_t0_8.setContentsMargins(-1, -1, -1, 6)
self.label_32 = QLabel(self.auto_module)
self.label_32.setObjectName(u"label_32")
sizePolicy1.setHeightForWidth(self.label_32.sizePolicy().hasHeightForWidth())
self.label_32.setSizePolicy(sizePolicy1)
self.label_32.setMinimumSize(QSize(120, 0))
self.label_32.setMaximumSize(QSize(16777215, 16777215))
self.label_32.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.field_layout_t0_8.addWidget(self.label_32)
self.setpoint = QDoubleSpinBox(self.auto_module)
self.setpoint.setObjectName(u"setpoint")
self.setpoint.setMinimumSize(QSize(80, 0))
self.setpoint.setMaximumSize(QSize(100, 16777215))
self.setpoint.setFont(font1)
self.setpoint.setFocusPolicy(Qt.ClickFocus)
self.setpoint.setMaximum(9999999.000000000000000)
self.field_layout_t0_8.addWidget(self.setpoint)
self.auto_module_grid_layout_5.addLayout(self.field_layout_t0_8, 0, 0, 1, 1)
self.field_layout_t0_12 = QVBoxLayout()
self.field_layout_t0_12.setSpacing(4)
self.field_layout_t0_12.setObjectName(u"field_layout_t0_12")
self.field_layout_t0_12.setSizeConstraint(QLayout.SetFixedSize)
self.field_layout_t0_12.setContentsMargins(-1, -1, -1, 6)
self.label_36 = QLabel(self.auto_module)
self.label_36.setObjectName(u"label_36")
sizePolicy1.setHeightForWidth(self.label_36.sizePolicy().hasHeightForWidth())
self.label_36.setSizePolicy(sizePolicy1)
self.label_36.setMinimumSize(QSize(120, 0))
self.label_36.setMaximumSize(QSize(16777215, 16777215))
self.label_36.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.field_layout_t0_12.addWidget(self.label_36)
self.true_pressure = QLineEdit(self.auto_module)
self.true_pressure.setObjectName(u"true_pressure")
self.true_pressure.setEnabled(False)
self.true_pressure.setMaximumSize(QSize(80, 16777215))
self.field_layout_t0_12.addWidget(self.true_pressure)
self.auto_module_grid_layout_5.addLayout(self.field_layout_t0_12, 0, 2, 1, 1)
self.verticalLayout_14.addLayout(self.auto_module_grid_layout_5)
self.module_layout_auto.addWidget(self.auto_module)
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
self.module_layout_auto.addItem(self.verticalSpacer)
self.horizontalLayout.addLayout(self.module_layout_auto)
self.verticalLayout.addWidget(self.side_frame_auto)
self.retranslateUi(module)
QMetaObject.connectSlotsByName(module)
# setupUi
def retranslateUi(self, module):
module.setWindowTitle(QCoreApplication.translate("module", u"Form", None))
self.module_title_auto.setText(QCoreApplication.translate("module", u"Autowaveguide", None))
self.label_units.setText(QCoreApplication.translate("module", u"\u03bcbar", None))
self.label_33.setText(QCoreApplication.translate("module", u"<html><head/><body><p>K<span style=\" vertical-align:sub;\">p</span></p></body></html>", None))
self.label_34.setText(QCoreApplication.translate("module", u"<html><head/><body><p>K<span style=\" vertical-align:sub;\">i</span></p></body></html>", None))
self.label_35.setText(QCoreApplication.translate("module", u"<html><head/><body><p>K<span style=\" vertical-align:sub;\">d</span></p></body></html>", None))
self.label_32.setText(QCoreApplication.translate("module", u"<html><head/><body><p>Set point ( \u03bcbar)</p></body></html>", None))
self.label_36.setText(QCoreApplication.translate("module", u"<html><head/><body><p>True pressure ( \u03bcbar)</p></body></html>", None))
# retranslateUi
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>448</width>
<height>639</height>
</rect>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="windowOpacity">
<double>1.000000000000000</double>
</property>
<property name="styleSheet">
<string notr="true">QMainWindow,
QToolBar {
background-color: #010101;
border: 1px solid #010101;
}
#side_frame_auto,
#side_frame_instr,
#main_frame_fid,
#main_frame_spectrum {
border: 0;
background-color: #12141a;
border-radius: 5px;
}
#frame_title_auto,
#frame_title_instr,
#frame_title_spectrum,
#frame_title_fid {
color: #d2d2d2;
font-weight:600;
font-size: 14px;
}
QMenu {
background-color: #12141a;
border-radius: 5px;
padding: 0px;
color: #d2d2d2;
}
QMenu::item:selected {
background-color: #3b3d47;
}
QCheckBox {
color: #f2f2f2;
}
/*---- MODULE STYLE ----*/
/*
#my_module {
border: 0;
color: #444b59;
background-color: #363e4d;
border-radius: 5px;
}
#my_module QLabel {
color: #f2f2f2;
}
#my_module #module_title {
color: #fffffft;
font-weight: 600;
font-size: 16px;
border: 0;
margin: 10px 0px 0px 2px;
}
#my_module Line {
background-color: #5b6a87;
border-color: #363e4d;
}
*/
/*---- END MODULE STYLE ----*/
/*---- SCROLL AREA ----*/
#side_scroll_area_auto,
#side_scroll_area_widget_auto,
#side_scroll_area_instr,
#side_scroll_area_widget_instr {
background-color: #12141a;
border-width: 0px;
border-color: #12141a;
padding: 0;
}
QScrollBar:vertical {
border: 0px solid #12141a;
background:#12141a;
width:10px;
margin: 0px 0px 0px 0px;
}
QScrollBar::handle:vertical {
min-height: 0px;
border: 0px solid red;
border-radius: 4px;
background-color: #2c2e36;
}
QScrollBar::add-line:vertical {
height: 0px;
subcontrol-position: bottom;
subcontrol-origin: margin;
}
QScrollBar::sub-line:vertical {
height: 0 px;
subcontrol-position: top;
subcontrol-origin: margin;
}
/*---- END SCROLL AREA ----*/
/*---- BUTTONS ----*/
#apply_button,
#cancel_button {
background: #1db954;
border: 0;
border-radius: 10px;
padding: .5em 2em;
color: 535353;
}
#cancel_button {
background: #2c2e36;
color: #d2d2d2;
}
#apply_button:pressed {
background: #41e17a;
color: #000000;
}
QSpinBox, QDoubleSpinBox, QComboBox {
background-color:#2c2e36;
color: white;
}
/*--- END BUTTIONS ---*/
/*--- QProgressBar ---*/
QProgressBar
{
background: #585b66;
border-style: plain;
border-width: 0px;
border-radius: 3px;
}
QProgressBar::chunk
{
background-color: #fafafa;
border-style: plain;
border-width: 0px;
border-radius: 3px;
}
/*--- END QProgressBar ---*/</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item>
<layout class="QHBoxLayout" name="central_layout">
<property name="spacing">
<number>8</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
</layout>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>
Ce diff est replié.
float valve_percent;
float scale_factor = (4096-1)/100.0;
int avg_depth = 32;
void setup() {
// put your setup code here, to run once:
pinMode(A0, OUTPUT); // sets the pin as output
pinMode(A1, INPUT);
Serial.begin(1000000);
}
void loop() {
// put your main code here, to run repeatedly:
if (Serial.available() > 0) {
char command = Serial.read();
if (command == 'u') { // write command
//--- actuate solenoid valve ---
float valve_percent = 0.0;
String data = Serial.readStringUntil('\n'); // Read the incoming data until newline
char *ptr = strtok(const_cast<char*>(data.c_str()), ",");
valve_percent = atof(ptr);
set_signal(valve_percent);
//--- read pressure
analogReadResolution(14);
int x = analogRead(A1);
for (int i = 0; i < avg_depth-1; i++) {
analogReadResolution(14);
x += analogRead(A1);
}
Serial.println(x/avg_depth);
}
else if (command == 'r') {
set_signal(0.0);
}
}
}
void set_signal(float valve_percent) {
// IMPORTANT NOTE: it has been observed that the reset signal
// doesn't function properly with a 5 V logic high signal (arduino's default).
// A resistive voltage divider is required to set the logic high to 3.3 V.
analogWriteResolution(12);
analogWrite(A0, int(scale_factor*valve_percent));
}
#!/bin/bash
# This script compiles the ui and ressources files
source ./env/bin/activate
for i in $(ls ./app/ui/src | grep .ui)
do
echo "compiling ui file: $i..."
pyside6-uic ./app/ui/src/$i > ./app/ui/dist/$i
mv -- "./app/ui/dist/$i" "./app/ui/dist/ui_${i%.ui}.py"
done
for i in $(ls ./app/ui/src | grep .qrc)
do
echo "compiling ressources file: $i..."
pyside6-rcc ./app/ui/src/$i > ./app/ui/dist/$i
mv -- "./app/ui/dist/$i" "./app/ui/dist/${i%.qrc}_rc.py"
done
deactivate
echo "--- operation complete ---"
numpy==2.1.3
pyqtgraph==0.13.7
pyserial==3.5
PySide6==6.8.0.2
PySide6_Addons==6.8.0.2
PySide6_Essentials==6.8.0.2
shiboken6==6.8.0.2
simple-pid==2.0.1
//
// Arduino R4 minima
//
float valve_percent;
float scale_factor = (4096-1)/100.0;
int avg_depth = 32;
void setup() {
pinMode(A0, OUTPUT); // to Burkert valve
pinMode(A1, INPUT); // from mks gauge controller
Serial.begin(1000000);
}
void loop() {
if (Serial.available() > 0) {
char command = Serial.read();
if (command == 'u') { // update PID cycle
float valve_percent = 0.0;
String data = Serial.readStringUntil('\n'); // Read the incoming data until newline
char *ptr = strtok(const_cast<char*>(data.c_str()), ",");
valve_percent = atof(ptr);
set_signal(valve_percent); // actuate valve
analogReadResolution(14);
int x = analogRead(A1);
for (int i = 0; i < avg_depth-1; i++) {
analogReadResolution(14);
x += analogRead(A1);
}
Serial.println(x/avg_depth); // read analog pressure and average before sending value back to computer
}
else if (command == 'r') { // reset valve to 0
set_signal(0.0);
}
}
}
void set_signal(float valve_percent) {
// Write the valve percentage onto the Burkert valve
analogWriteResolution(12);
analogWrite(A0, int(scale_factor*valve_percent));
}
\ No newline at end of file
import serial
import serial.tools.list_ports
import time
SERIAL_NUMBER : str = "3307142A37323835191D33324B572D44"
# ser = serial.Serial("/dev/tty.usbmodem1101", 9600)
def find_device(serial_number:str) -> str:
"""Check the `hwid` through the list ports for a `SER` key
that matches `serial_number`
"""
for port, desc, hwid in serial.tools.list_ports.comports():
infos = hwid.split(" ")
for info in infos:
if not info.startswith("SER"):
continue
serial_num = info.split("=")[-1]
if not serial_num == serial_number:
break
return port
return ""
MY_PORT : str = find_device(SERIAL_NUMBER)
print(MY_PORT)
device = serial.Serial()
device.port = MY_PORT
device.timeout = 1
device.baudrate = 9600
device.open()
def write_value(valve_percent:float):
device.write(b'w')
data = str(valve_percent)
device.write(data.encode() + b'\n')
def read_value():
device.write(b'r')
time.sleep(0.1)
response = float(device.readline().decode().strip())
return response
def read_pressure():
device.write(b'p')
time.sleep(0.1)
response = float(device.readline().decode().strip())
return response
if __name__ == "__main__":
while True:
print("Enter valve opening percentage:")
valve_percent = input()
if float(valve_percent) < 0:
break
write_value(valve_percent)
print(read_value())
# print(read_pressure())
device.close()
asttokens==2.4.1
colorama==0.4.6
comm==0.2.1
contourpy==1.2.0
cycler==0.12.1
debugpy==1.8.0
decorator==5.1.1
distlib==0.3.7
executing==2.0.1
filelock==3.13.1
fonttools==4.44.0
future==1.0.0
greenlet==3.0.3
ipykernel==6.28.0
ipympl==0.9.3
ipython==8.20.0
ipython-genutils==0.2.0
ipywidgets==8.1.2
iso8601==2.1.0
jedi==0.19.1
jupyter_client==8.6.0
jupyter_core==5.7.1
jupyterlab_widgets==3.0.10
kiwisolver==1.4.5
llvmlite==0.43.0
matplotlib==3.8.1
matplotlib-inline==0.1.6
mendeleev==0.15.0
mpmath==1.3.0
nest-asyncio==1.5.8
numba==0.60.0
numpy==1.26.1
packaging==23.2
pandas==2.2.0
parso==0.8.3
Pillow==10.1.0
platformdirs==3.11.0
prompt-toolkit==3.0.43
psutil==5.9.7
pure-eval==0.2.2
pyfiglet==0.8.post1
Pygments==2.17.2
pyparsing==3.1.1
PyQt5==5.15.10
PyQt5-Qt5==5.15.2
PyQt5-sip==12.13.0
pyserial==3.5
python-dateutil==2.8.2
pytz==2024.1
pywin32==306
PyYAML==6.0.2
pyzmq==25.1.2
qutip==5.0.3.post1
rdkit==2024.3.3
scipy==1.11.3
six==1.16.0
SQLAlchemy==2.0.25
stack-data==0.6.3
sympy==1.12.1
tornado==6.4
traitlets==5.14.1
typing_extensions==4.9.0
tzdata==2023.4
virtualenv==20.25.1
wcwidth==0.2.13
widgetsnbextension==4.0.10
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter