14. Interfaces

Servo Motor Control Interface

This project demonstrates how to control a servo motor using a graphical user interface (GUI) built with PyQt5 and a Seeed Studio Xiao RP2040 microcontroller.

If you want to see more here is what we did in our group assignment. Group Assignment

Project Description

A Python GUI application sends a serial command to the Xiao RP2040, which controls a servo motor. When the button in the interface is pressed, the servo moves to 90° and then returns to 0°.

Materials

  • Seeed Studio Xiao RP2040
  • Servo Motor (SG90 or similar)
  • External 5V Power Supply

Wiring Diagram

  • Servo Signal → Xiao Pin D0
  • Servo VCC → 5V Power Supply
  • Servo GND → Xiao GND and Power Supply GND

As you see in the image I used the pcb from our CNC project, I had to use an external 5v supply instead of the build in 5V regulator because got burned after testing last week and havent had another regulator yet.

Python Code PyQt5

import sys
  from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QHBoxLayout, QVBoxLayout
  from PyQt5.QtCore import Qt
  import serial
  
 
  SERIAL_PORT = 'COM7' 
  BAUD_RATE = 9600
  
  class ServoControlApp(QWidget):
      def __init__(self):
          super().__init__()
          self.initUI()
          try:
              self.ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
              self.status_label.setText(f"Connected to {SERIAL_PORT}")
          except Exception as e:
              self.status_label.setText(f"Serial connection error: {e}")
              self.ser = None
  
      def initUI(self):
          self.setWindowTitle('Servo Motor Control (+90°, -90°)')
          self.setGeometry(100, 100, 400, 200)
          self.setStyleSheet("background-color: black;")
  
         
          main_layout = QVBoxLayout()
          main_layout.setAlignment(Qt.AlignCenter)
  
        
          self.status_label = QLabel('Connecting...', self)
          self.status_label.setStyleSheet("color: white; font-size: 16px;")
          self.status_label.setAlignment(Qt.AlignCenter)
          main_layout.addWidget(self.status_label)
  
         
          button_layout = QHBoxLayout()
  
         
          self.button_pos90 = QPushButton('+90°', self)
          self.button_pos90.clicked.connect(self.move_pos90)
          self.button_pos90.setFixedSize(120, 60)
          self.button_pos90.setStyleSheet("""
              QPushButton {
                  background-color: white;
                  color: black;
                  font-size: 20px;
                  border-radius: 10px;
              }
              QPushButton:hover {
                  background-color: #dddddd;
              }
          """)
          button_layout.addWidget(self.button_pos90)
  
          
          button_layout.addStretch()
  
        
          self.button_neg90 = QPushButton('-90°', self)
          self.button_neg90.clicked.connect(self.move_neg90)
          self.button_neg90.setFixedSize(120, 60)
          self.button_neg90.setStyleSheet("""
              QPushButton {
                  background-color: white;
                  color: black;
                  font-size: 20px;
                  border-radius: 10px;
              }
              QPushButton:hover {
                  background-color: #dddddd;
              }
          """)
          button_layout.addWidget(self.button_neg90)
  
          main_layout.addLayout(button_layout)
          self.setLayout(main_layout)
  
      def move_pos90(self):
          self.send_command("POS90")
  
      def move_neg90(self):
          self.send_command("POS-90")
  
      def send_command(self, command):
          if self.ser and self.ser.is_open:
              try:
                  full_command = (command + '\n').encode('utf-8')
                  self.ser.write(full_command)
                  self.status_label.setText(f'Sent: {command}')
              except Exception as e:
                  self.status_label.setText(f'Error sending command: {e}')
          else:
              self.status_label.setText('Serial port not connected.')
  
      def closeEvent(self, event):
          if self.ser and self.ser.is_open:
              self.ser.close()
  
  if __name__ == '__main__':
      app = QApplication(sys.argv)
      window = ServoControlApp()
      window.show()
      sys.exit(app.exec_())

Microcontroller Code (Xiao RP2040 - Arduino IDE)

#include 

  Servo myServo;
  
  void setup() {
    myServo.attach(D0);  // Pin
    Serial.begin(9600);
  }
  
  void loop() {
    if (Serial.available()) {
      String command = Serial.readStringUntil('\n');
      command.trim();
  
      if (command == "POS90") {
        myServo.write(90);   //
      } else if (command == "POS-90") {
        myServo.write(0);    // 
      }
    }
  }

Interface

This is how the interface looks. I wanted a minimalistic design on it.

Result

When the button is pressed in the GUI, the servo moves to 90 degrees and returns to 0 degrees.

Useful links