This is another tutorial on developing graphical user interfaces on the Raspberry Pi. In these articles, we use the popular Guizero library to develop user interfaces for various projects, ranging from LED control to motor speed control. In this tutorial, I will show you how to create a graphical user interface on your Raspberry Pi that you can use to control the position of four SG90 servo motors. This will prove critical in certain projects, so let’s dive in!

Uses for Servos on the Rpi

The SG-90 microservo is a small, lightweight, and high-output power rotary electrical device. Its shaft can rotate approximately 180 degrees (90 in each direction) by sending the servo a coded signal. The servo motor is an excellent piece of hardware that you can find in model boats, radio-controlled aircraft, industrial applications, and robots. The servo is fit for any project where you need to do the following:

  • Control the position of any object or surface regularly
  • Steering system
  • Actuation
  • Position control

How Servos Work

For us to understand how servos work, we need to look at their internal structure.

Servo motor internal structure

The diagram above shows the various components such as the DC motor, gearbox, control electronics, and a potentiometer. This means that we add a gearbox and a motor controller with a feedback loop to the conventional DC motor to create a servo motor. Unlike a DC motor which spins continuously in one direction or the other, the servo motor allows precise control of the angular position of its shaft between 0 and 180°. To achieve this, we make use of the feedback loop, as shown in the diagram below.

The user enters the desired target position of the shaft by sending a coded signal to the servo. The signal is then interpreted by the motor controller, which will turn the shaft. Then, the actual position of the shaft is measured continuously by the potentiometer, and the result is fed back to the input, where the error concerning the desired output is measured. After that, the error signal goes back to the motor controller, which will control the amount of input until we get the desired target position.

Servo Internal Structure and Pin Diagram

The SG-90 servo motor has three cables for connecting to the Raspberry Pi.

Here are the connections:

Red5V pin
BrownGND
OrangePWM signal

In some datasheets, the stall current of the SG-90 micro servo is roughly 650mA. This is more than the maximum RPi GPIO current draw. The best solution is to use an external power supply to provide this current to get around this drawback. I often use a 9V battery and a breadboard power supply to power my motors. This can provide enough current, especially in this project where I have four servos.

How to Set the Position of a Servo

The position of a servo motor is set by controlling the length of a high pulse, i.e., the pulse’s width. The servo typically accepts a 50Hz signal frequency or a pulse that repeats every 20ms.

As we can see from the diagram above, a 1ms pulse gives a servo angle of 0°, 1.5ms duration moves the servo to 90° and finally, a 2ms pulse will set the servo at 1800. Please note that software-generated pulses may not be as accurate as dedicated hardware. However, this is sufficient to give us the expected output.

How to Connect a Servo (SG90 Micro Servo) to the Rpi

It’s easy to connect an SG90 micro servo to the RPi. We will only need an external power supply since the RPi GPIO does not provide sufficient current. We will need the following:

  • Raspberry Pi
  • Micro servo
  • Breadboard
  • Breadboard power supply
  • 9V battery
  • Connecting wires
Servo signal pin 1RPi GPIO 4
Servo signal pin 2RPi GPIO 17
Servo signal pin 3RPi GPIO 23
Servo signal pin 4RPi GPIO 24
Servo power pinsExternal power supply

How to Program the Servo With Python

There are so many ways of programming the servo motor with Python. You can write your own PWM code, but here, we will use the AngularServo class from the gpiozero library for convenience.

For the sample project, we will create a simple GUI (using guizero) to control the position of four servos individually. Start by creating a python file and copying the following code.

from gpiozero import AngularServo
from guizero import App, ButtonGroup, Text

app=App(title="Servo_GUI", layout="grid")
s = AngularServo(17, min_angle=-90, max_angle=90)
s1 = AngularServo(23, min_angle=-90, max_angle=90)
s2 = AngularServo(24, min_angle=-90, max_angle=90)
s3 = AngularServo(4, min_angle=-90, max_angle=90)

def update_text():
    s.angle = int(choice.value)
    print("motor1: ", s.angle)
    s1.angle = int(choice1.value)
    print("motor2: ",s1.angle)
    s2.angle = int(choice2.value)
    print("motor3: ",s2.angle)
    s3.angle = int(choice3.value)
    print("motor4: ",s3.angle, "\n------------------------------------------------")


choice =ButtonGroup(app, options=["-90", "-45", "0", "45", "90"], selected="-90",command=update_text, grid=[1,2])
choice1 =ButtonGroup(app, options=["-90", "-45", "0", "45", "90"], selected="-90", command=update_text, grid=[2,2])
choice2 =ButtonGroup(app, options=["-90", "-45", "0", "45", "90"], selected="-90", command=update_text, grid=[3,2])
choice3 =ButtonGroup(app, options=["-90", "-45", "0", "45", "90"], selected="-90", command=update_text, grid=[4,2])

Text(app, "M1",grid=[1,1])
Text(app, "M2",grid=[2,1])
Text(app, "M3",grid=[3,1])
Text(app, "M4",grid=[4,1])
app.display()

Code Description

We only need two libraries to develop this project. We need the gpiozero library, which provides a simple interface to GPIO devices, and the guizero library for developing graphical user interfaces.

For the initial setup, we initialize our app with the following code: app=App(title="Servo_GUI", layout="grid"). Next, we create four servo motors, S1-S4 by the code: s = AngularServo(17, min_angle=-90, max_angle=90). def update_text(): This function checks the value of the selected radio buttons and sets the motor direction using those values.

Note that this function only accepts integers, so we change a string to a numerical value with the code s.angle = int(choice.value). choice =ButtonGroup(app, options=["-90", "-45", "0", "45", "90"], selected="-90",command=update_text, grid=[1,2]). This line of code creates a radio button where a sure can select the desired angle from a set of five options.

Remember, the guizero library requires Python 3, so run the above code by typing the following command: sudo Python3 servoGui.py. If all goes well, you will get the following on your terminal and GUI.

RPi terminal output messages for four runs
Result GUI

The code above uses a set of radio buttons to control the positions of four servo motors from -90° to 90° in 45° steps. I have written a bonus code that uses a slider to set the position instead. The only difference is that the angle of increment in the first is at 45°.

Bonus Code

from gpiozero import AngularServo
from guizero import App, Slider, Text

app=App(title="Servo_GUI", layout="grid")
s = AngularServo(17, min_angle=-90, max_angle=90)
s1 = AngularServo(23, min_angle=-90, max_angle=90)
s2 = AngularServo(24, min_angle=-90, max_angle=90)
s3 = AngularServo(4, min_angle=-90, max_angle=90)

def update_text():
    s.angle = int(slider.value)
    print("motor1: ", s.angle)
    s1.angle = int(slider1.value)
    print("motor2: ",s1.angle)
    s2.angle = int(slider2.value)
    print("motor3: ",s2.angle)
    s3.angle = int(slider3.value)
    print("motor4: ",s3.angle, "\n------------------------------------------------")


slider =Slider(app, start=-90, end=90, command=update_text, grid=[1,2])
slider1 =Slider(app, start=-90, end=90, command=update_text, grid=[2,2])
slider2 =Slider(app, start=-90, end=90, command=update_text, grid=[3,2])
slider3 =Slider(app, start=-90, end=90, command=update_text, grid=[4,2])

Text(app, "M1",grid=[1,1])
Text(app, "M2",grid=[2,1])
Text(app, "M3",grid=[3,1])
Text(app, "M4",grid=[4,1])
app.display()
Four sliders for four different servo motors