|
37 | 37 | """
|
38 | 38 |
|
39 | 39 | import sys
|
40 |
| -from PyQt5.QtWidgets import QDialog, QApplication, QLabel, QRadioButton, QSlider, QPushButton, QVBoxLayout, QHBoxLayout, QFormLayout, QFileDialog, QLineEdit, QSpinBox, QDoubleSpinBox, QMessageBox, QCheckBox, QTableWidget, QTableWidgetItem, QHeaderView, QGroupBox, QComboBox, QTabWidget, QWidget |
| 40 | +from PyQt5.QtWidgets import QDialog, QApplication, QLabel, QRadioButton, QSlider, QPushButton, QVBoxLayout, QHBoxLayout, QFormLayout, QFileDialog, QLineEdit, QSpinBox, QDoubleSpinBox, QMessageBox, QCheckBox, QTableWidget, QTableWidgetItem, QHeaderView, QGroupBox, QComboBox, QTabWidget, QWidget, QGridLayout |
41 | 41 | from PyQt5.QtCore import Qt
|
42 | 42 |
|
43 | 43 | from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
@@ -289,91 +289,102 @@ def printImproperTfError(self):
|
289 | 289 | msg.exec_()
|
290 | 290 |
|
291 | 291 | def createPidLayout(self):
|
292 |
| - layout_pid = QFormLayout() |
| 292 | + layout_pid = QGridLayout() |
293 | 293 |
|
294 |
| - layout_structure = QHBoxLayout() |
295 |
| - layout_structure.addWidget(QLabel("Ideal/Standard: Kp * [1 + Ki + Kd]\t(Parallel: Kp + Ki + Kd)")) |
| 294 | + layout_options = QHBoxLayout() |
296 | 295 | self.pid_no_zero_box = QCheckBox("PI no-zero", self)
|
297 | 296 | self.pid_no_zero_box.setChecked(False)
|
298 | 297 | self.pid_no_zero_box.stateChanged.connect(self.updateClosedLoop)
|
299 |
| - layout_structure.addWidget(self.pid_no_zero_box) |
| 298 | + layout_options.addWidget(self.pid_no_zero_box) |
| 299 | + |
300 | 300 | self.negate_control_box = QCheckBox("Negate control output", self)
|
301 | 301 | self.negate_control_box.setChecked(False)
|
302 | 302 | self.negate_control_box.stateChanged.connect(self.updateClosedLoop)
|
303 |
| - layout_structure.addWidget(self.negate_control_box) |
304 |
| - layout_pid.addRow(layout_structure) |
| 303 | + layout_options.addWidget(self.negate_control_box) |
| 304 | + layout_pid.addLayout(layout_options, 0, 1) |
| 305 | + |
| 306 | + layout_pid.addWidget(QLabel("Ideal/Standard\nKp * [1 + Ki + Kd]"), 0, 2) |
| 307 | + layout_pid.addWidget(QLabel("Parallel\nKp + Ki + Kd"), 0, 3) |
305 | 308 |
|
306 |
| - layout_k = QHBoxLayout() |
| 309 | + layout_pid.addWidget(QLabel("K"), 1, 0) |
307 | 310 | self.slider_k = DoubleSlider(Qt.Horizontal)
|
308 | 311 | self.slider_k.setMinimum(0.001)
|
309 | 312 | self.slider_k.setMaximum(4.0)
|
310 | 313 | self.slider_k.setInterval(0.001)
|
311 |
| - self.lbl_k = QLabel("{:.3f} ({:.3f})".format(self.kc, self.kc)) |
312 |
| - layout_k.addWidget(self.slider_k) |
313 |
| - layout_k.addWidget(self.lbl_k) |
314 | 314 | self.slider_k.valueChanged.connect(self.updateLabelK)
|
315 |
| - layout_pid.addRow(QLabel("K"), layout_k) |
| 315 | + layout_pid.addWidget(self.slider_k, 1, 1) |
| 316 | + self.lbl_k_standard = QLabel("{:.3f}".format(self.kc)) |
| 317 | + layout_pid.addWidget(self.lbl_k_standard, 1, 2) |
| 318 | + self.lbl_k_parallel = QLabel("{:.3f}".format(self.kc)) |
| 319 | + layout_pid.addWidget(self.lbl_k_parallel, 1, 3) |
316 | 320 |
|
317 |
| - layout_i = QHBoxLayout() |
| 321 | + layout_pid.addWidget(QLabel("I"), 2, 0) |
318 | 322 | self.slider_i = DoubleSlider(Qt.Horizontal)
|
319 | 323 | self.slider_i.setMinimum(0.0)
|
320 | 324 | self.slider_i.setMaximum(20.0)
|
321 | 325 | self.slider_i.setInterval(0.1)
|
322 |
| - self.lbl_i = QLabel("{:.2f} ({:.2f})".format(self.ki, self.kc * self.ki)) |
323 |
| - layout_i.addWidget(self.slider_i) |
324 |
| - layout_i.addWidget(self.lbl_i) |
325 | 326 | self.slider_i.valueChanged.connect(self.updateLabelI)
|
326 |
| - layout_pid.addRow(QLabel("I"), layout_i) |
| 327 | + layout_pid.addWidget(self.slider_i, 2, 1) |
| 328 | + self.lbl_i_standard = QLabel("{:.2f}".format(self.ki)) |
| 329 | + layout_pid.addWidget(self.lbl_i_standard, 2, 2) |
| 330 | + self.lbl_i_parallel = QLabel("{:.2f}".format(self.kc * self.ki)) |
| 331 | + layout_pid.addWidget(self.lbl_i_parallel, 2, 3) |
327 | 332 |
|
328 |
| - layout_d = QHBoxLayout() |
| 333 | + layout_pid.addWidget(QLabel("D"), 3, 0) |
329 | 334 | self.slider_d = DoubleSlider(Qt.Horizontal)
|
330 | 335 | self.slider_d.setMinimum(0.0)
|
331 | 336 | self.slider_d.setMaximum(0.2)
|
332 | 337 | self.slider_d.setInterval(0.001)
|
333 |
| - self.lbl_d = QLabel("{:.3f} ({:.4f})".format(self.kd, self.kc * self.kd)) |
334 |
| - layout_d.addWidget(self.slider_d) |
335 |
| - layout_d.addWidget(self.lbl_d) |
336 | 338 | self.slider_d.valueChanged.connect(self.updateLabelD)
|
337 |
| - layout_pid.addRow(QLabel("D"), layout_d) |
| 339 | + layout_pid.addWidget(self.slider_d, 3, 1) |
| 340 | + self.lbl_d_standard = QLabel("{:.3f}".format(self.kd)) |
| 341 | + layout_pid.addWidget(self.lbl_d_standard, 3, 2) |
| 342 | + self.lbl_d_parallel = QLabel("{:.4f}".format(self.kc * self.kd)) |
| 343 | + layout_pid.addWidget(self.lbl_d_parallel, 3, 3) |
338 | 344 |
|
339 |
| - layout_ff = QHBoxLayout() |
| 345 | + layout_pid.addWidget(QLabel("FF"), 4, 0) |
340 | 346 | self.slider_ff = DoubleSlider(Qt.Horizontal)
|
341 | 347 | self.slider_ff.setMinimum(0.0)
|
342 | 348 | self.slider_ff.setMaximum(5.0)
|
343 | 349 | self.slider_ff.setInterval(0.01)
|
344 |
| - self.lbl_ff = QLabel("{:.3f} ({:.3f})".format(self.kff, self.kff)) |
345 |
| - layout_ff.addWidget(self.slider_ff) |
346 |
| - layout_ff.addWidget(self.lbl_ff) |
347 | 350 | self.slider_ff.valueChanged.connect(self.updateLabelFF)
|
348 |
| - layout_pid.addRow(QLabel("FF"), layout_ff) |
| 351 | + layout_pid.addWidget(self.slider_ff, 4, 1) |
| 352 | + self.lbl_ff_standard = QLabel("{:.3f}".format(self.kff)) |
| 353 | + layout_pid.addWidget(self.lbl_ff_standard, 4, 2) |
| 354 | + self.lbl_ff_parallel = QLabel("{:.3f}".format(self.kff)) |
| 355 | + layout_pid.addWidget(self.lbl_ff_parallel, 4, 3) |
349 | 356 |
|
350 | 357 | return layout_pid
|
351 | 358 |
|
352 | 359 | def updateLabelK(self):
|
353 | 360 | self.kc = self.slider_k.value()
|
354 |
| - self.lbl_k.setText("{:.3f} ({:.3f})".format(self.kc, self.kc)) |
| 361 | + self.lbl_k_standard.setText("{:.3f}".format(self.kc)) |
| 362 | + self.lbl_k_parallel.setText("{:.3f}".format(self.kc)) |
355 | 363 |
|
356 | 364 | # Kc also modifies the Ki and Kd gains of the parallel form
|
357 |
| - self.lbl_i.setText("{:.2f} ({:.2f})".format(self.ki, self.kc * self.ki)) |
358 |
| - self.lbl_d.setText("{:.3f} ({:.4f})".format(self.kd, self.kc * self.kd)) |
| 365 | + self.lbl_i_parallel.setText("{:.2f}".format(self.kc * self.ki)) |
| 366 | + self.lbl_d_parallel.setText("{:.4f}".format(self.kc * self.kd)) |
359 | 367 | if self.slider_k.isSliderDown():
|
360 | 368 | self.updateClosedLoop()
|
361 | 369 |
|
362 | 370 | def updateLabelI(self):
|
363 | 371 | self.ki = self.slider_i.value()
|
364 |
| - self.lbl_i.setText("{:.2f} ({:.2f})".format(self.ki, self.kc * self.ki)) |
| 372 | + self.lbl_i_standard.setText("{:.2f}".format(self.ki)) |
| 373 | + self.lbl_i_parallel.setText("{:.2f}".format(self.kc * self.ki)) |
365 | 374 | if self.slider_i.isSliderDown():
|
366 | 375 | self.updateClosedLoop()
|
367 | 376 |
|
368 | 377 | def updateLabelD(self):
|
369 | 378 | self.kd = self.slider_d.value()
|
370 |
| - self.lbl_d.setText("{:.3f} ({:.4f})".format(self.kd, self.kc * self.kd)) |
| 379 | + self.lbl_d_standard.setText("{:.3f}".format(self.kd)) |
| 380 | + self.lbl_d_parallel.setText("{:.4f}".format(self.kc * self.kd)) |
371 | 381 | if self.slider_d.isSliderDown():
|
372 | 382 | self.updateClosedLoop()
|
373 | 383 |
|
374 | 384 | def updateLabelFF(self):
|
375 | 385 | self.kff = self.slider_ff.value()
|
376 |
| - self.lbl_ff.setText("{:.3f} ({:.3f})".format(self.kff, self.kff)) |
| 386 | + self.lbl_ff_standard.setText("{:.3f}".format(self.kff)) |
| 387 | + self.lbl_ff_parallel.setText("{:.3f}".format(self.kff)) |
377 | 388 | if self.slider_ff.isSliderDown():
|
378 | 389 | self.updateClosedLoop()
|
379 | 390 |
|
|
0 commit comments