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.