Week 08 ‐ Implement GUI and PID control logic - AkinduID/EyeRiz GitHub Wiki
- Implement Simple GUI
- Implemnt PID control logic in track face function
- Kivy
- PyQT
- Streamlit
I initially attempted to implement a GUI using Streamlit, leveraging my previous experience with it. However, since Streamlit is web-based, it didn't meet my requirements. I then explored Kivy and PyQt, ultimately finding that PyQt is much more flexible and faster.
This sample code demonstrates how to use PyQt as a GUI framework to display a webcam stream in a window
from PyQt5 import QtWidgets
from PyQt5.QtGui import QImage,QPixmap
from PyQt5.QtCore import QThread,pyqtSignal as Signal,pyqtSlot as Slot
import cv2,imutils
import sys
class MyThread(QThread):
frame_signal = Signal(QImage)
def run(self):
self.cap = cv2.VideoCapture(0)
while self.cap.isOpened():
_,frame = self.cap.read()
frame = self.cvimage_to_label(frame)
self.frame_signal.emit(frame)
def cvimage_to_label(self,image):
image = imutils.resize(image,width = 640)
image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
image = QImage(image,
image.shape[1],
image.shape[0],
QImage.Format_RGB888)
return image
class MainApp(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.init_ui()
self.show()
def init_ui(self):
self.setFixedSize(640,640)
self.setWindowTitle("Camera FeedBack")
widget = QtWidgets.QWidget(self)
layout = QtWidgets.QVBoxLayout()
widget.setLayout(layout)
self.label = QtWidgets.QLabel()
layout.addWidget(self.label)
self.open_btn = QtWidgets.QPushButton("Open The Camera", clicked=self.open_camera)
layout.addWidget(self.open_btn)
self.camera_thread = MyThread()
self.camera_thread.frame_signal.connect(self.setImage)
self.setCentralWidget(widget)
def open_camera(self):
self.camera_thread.start()
print(self.camera_thread.isRunning())
@Slot(QImage)
def setImage(self,image):
self.label.setPixmap(QPixmap.fromImage(image))
if __name__ == "__main__":
app = QtWidgets.QApplication([])
main_window = MainApp()
sys.exit(app.exec())
The following image shows the simple GUI that was created for the main Program.
#----------------------------------------------------------------------------------------
Kp = 0.02 # Proportional gain
Ki = 0.001 # Integral gain
Kd = 0.05 # Derivative gain
# Initialize PID state variables
integral_pan = 0
integral_tilt = 0
previous_error_pan = 0
previous_error_tilt = 0
def track_face_pid(face_center_x, face_center_y):
global pan_angle, tilt_angle
global integral_pan, integral_tilt, previous_error_pan, previous_error_tilt
# Calculate the error from the center positions
pan_error = abs(center_x - face_center_x)
tilt_error = abs(center_y - face_center_y)
# Calculate the integral term
integral_pan += pan_error
integral_pan = max(-10, min(10, integral_pan))
integral_tilt += tilt_error
integral_tilt = max(-10, min(10, integral_tilt))
# Calculate the derivative term
derivative_pan = pan_error - previous_error_pan
derivative_tilt = tilt_error - previous_error_tilt
# Calculate PID output
pan_output = Kp * pan_error + Ki * integral_pan + Kd * derivative_pan
tilt_output = Kp * tilt_error + Ki * integral_tilt + Kd * derivative_tilt
# Update previous error
previous_error_pan = pan_error
previous_error_tilt = tilt_error
if face_center_x < center_x - tolerance:
# pan_angle -= horizontal_step # Move left min 0
pan_angle = max(pan_min, min(pan_max, int(pan_angle-pan_output)))
elif face_center_x > center_x + tolerance:
# pan_angle += horizontal_step # Move right max 180
pan_angle = max(pan_min, min(pan_max, int(pan_angle+pan_output)))
# Tilt servo control (vertical)
if face_center_y < center_y - tolerance:
# tilt_angle -= vertical_step # Move up min 0
tilt_angle = max(tilt_min, min(tilt_max, int(tilt_angle-tilt_output)))
elif face_center_y > center_y + tolerance:
# tilt_angle += vertical_step # Move down max 180
tilt_angle = max(tilt_min, min(tilt_max, int(tilt_angle+tilt_output)))
# Send angles to Arduino
move_servos(pan_angle, tilt_angle)
#--------------------------------------------------------------------------------
- PyQT proved to be fast and flexible for my purpose
- PID control logic did not make a significant change in camera movement compared to the stepwise logic I used earlier.
- PID parameters need further tuning.
- Improve servo movements.
- Add error handling logic to main program
- Add functionality to detect webcam ad microcontroller to main program
- Improve gestures
- Improve GUI