-
Notifications
You must be signed in to change notification settings - Fork 0
/
interfaz.py
148 lines (124 loc) · 6.67 KB
/
interfaz.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import sys
import serial
import time
import collections
import threading
from PyQt5 import QtWidgets, QtCore
import pyqtgraph as pg
SERIAL_PORT = 'COM3'
BAUD_RATE = 9600
MAX_POINTS = 50
class RealTimeGraph(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
# Configuración de la interfaz gráfica de usuario
self.init_ui()
# Inicialización de la conexión serial y el thread de lectura
self.serial = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
time.sleep(2) # Espera para la inicialización del puerto serial
self.serial.flushInput()
self.serial_thread = threading.Thread(target=self.read_from_port, args=(self.serial,))
self.serial_thread.daemon = True
self.serial_thread.start()
# Variables para guardar los datos leídos
self.latest_data = None
self.lock = threading.Lock()
def init_ui(self):
self.layout = QtWidgets.QVBoxLayout(self)
# Parámetros PID
self.pid_layout = QtWidgets.QHBoxLayout()
self.p_input = QtWidgets.QLineEdit(self)
self.i_input = QtWidgets.QLineEdit(self)
self.d_input = QtWidgets.QLineEdit(self)
self.ref_input = QtWidgets.QLineEdit(self) # Entrada para la referencia
self.windup_checkbox = QtWidgets.QCheckBox('Anti-windup Enable', self) # Checkbox para el anti-windup
self.pid_button = QtWidgets.QPushButton('Set PID', self)
self.ref_button = QtWidgets.QPushButton('Set Reference', self) # Botón para establecer la referencia
self.pid_button.clicked.connect(self.update_pid)
self.ref_button.clicked.connect(self.update_reference) # Conectar botón con la función de actualización de referencia
self.pid_layout.addWidget(QtWidgets.QLabel("P:"))
self.pid_layout.addWidget(self.p_input)
self.pid_layout.addWidget(QtWidgets.QLabel("I:"))
self.pid_layout.addWidget(self.i_input)
self.pid_layout.addWidget(QtWidgets.QLabel("D:"))
self.pid_layout.addWidget(self.d_input)
self.pid_layout.addWidget(QtWidgets.QLabel("Ref:"))
self.pid_layout.addWidget(self.ref_input) # Añadir entrada de referencia al layout
self.pid_layout.addWidget(self.windup_checkbox) # Añadir checkbox al layout
self.pid_layout.addWidget(self.pid_button)
self.pid_layout.addWidget(self.ref_button) # Añadir botón de referencia al layout
self.layout.addLayout(self.pid_layout)
# Gráficos
self.win = pg.GraphicsLayoutWidget(show=True)
self.plot = self.win.addPlot(row=1, col=1)
self.error_plot = self.win.addPlot(row=2, col=1) # Nuevo gráfico para los errores
self.plot.setLabels(left='Position', bottom='Time', title='Reference vs Actual Position')
self.error_plot.setLabels(left='Error', bottom='Time', title='Errors Over Time') # Etiquetas para el gráfico de errores
self.plot.addLegend()
self.error_plot.addLegend() # Leyenda para el gráfico de errores
self.layout.addWidget(self.win)
# Curvas para el gráfico de posición
self.ref_curve = self.plot.plot(pen='r', name='Reference Position')
self.actual_curve = self.plot.plot(pen='b', name='Actual Position')
# Curvas para el gráfico de errores
self.error_curve = self.error_plot.plot(pen='g', name='Error')
self.dedt_curve = self.error_plot.plot(pen='y', name='Error derivative')
self.eintegral_curve = self.error_plot.plot(pen='c', name='Error integral')
# Deques para almacenar datos
self.data_ref = collections.deque(maxlen=MAX_POINTS)
self.data_actual = collections.deque(maxlen=MAX_POINTS)
self.data_error = collections.deque(maxlen=MAX_POINTS) # Datos de error
self.data_dedt = collections.deque(maxlen=MAX_POINTS) # Datos de la derivada del error
self.data_eintegral = collections.deque(maxlen=MAX_POINTS) # Datos del error integral
self.time_stamps = collections.deque(maxlen=MAX_POINTS)
# Configurar timer para actualizar gráfico
self.timer = pg.QtCore.QTimer()
self.timer.timeout.connect(self.update)
self.timer.start(50)
def update_pid(self):
p = self.p_input.text()
i = self.i_input.text()
d = self.d_input.text()
windup = '1' if self.windup_checkbox.isChecked() else '0' # Estado del checkbox anti-windup
command = f"P{p},I{i},D{d},W{windup}\n" # Incluir estado del anti-windup en el comando
self.serial.write(command.encode())
def update_reference(self):
ref = self.ref_input.text() # Obtener el valor de la referencia del campo de entrada
command = f"R{ref}\n" # Preparar el comando para enviar
self.serial.write(command.encode()) # Enviar el nuevo valor de referencia
def read_from_port(self, ser):
while True:
line = ser.readline().decode('utf-8').strip()
if line:
data = line.split(" ")
if len(data) == 5: # Asegurarse de que hay cinco elementos: referencia, actual, error, dedt, eintegral
with self.lock:
self.latest_data = list(map(float, data)) # Almacenar los últimos datos leídos
def update(self):
with self.lock:
if self.latest_data is not None:
ref, actual, error, dedt, eintegral = self.latest_data
current_time = time.time()
# Añadir nuevos puntos de datos a los deques
self.data_ref.append(ref)
self.data_actual.append(actual)
self.data_error.append(error) # Error
self.data_dedt.append(dedt) # Derivada del error
self.data_eintegral.append(eintegral) # Error integral
self.time_stamps.append(current_time)
# Actualizar curvas con nuevos datos
self.ref_curve.setData(self.time_stamps, self.data_ref)
self.actual_curve.setData(self.time_stamps, self.data_actual)
self.error_curve.setData(self.time_stamps, self.data_error) # Curva de error
self.dedt_curve.setData(self.time_stamps, self.data_dedt) # Curva de la derivada del error
self.eintegral_curve.setData(self.time_stamps, self.data_eintegral) # Curva del error integral
self.latest_data = None # Resetear los últimos datos leídos
def closeEvent(self, event):
self.serial.close() # Cerrar conexión serial cuando se cierra la aplicación
def main():
app = QtWidgets.QApplication(sys.argv)
main = RealTimeGraph()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()