Controlling Multiple Servo Motors with Raspberry Pi (No PWM Module)

This is a quick note on how to control multiple servo motors using only the GPIO pins on a Raspberry Pi—without relying on any PWM or servo controller modules.

Introduction

I’ve been tinkering with my Raspberry Pi.

When looking into how to control multiple servo motors, most examples online use external PWM or servo control modules. However, this time I wanted to try controlling multiple servos just with GPIO, without any external modules.

So here’s a simple log of how I did it.

Note: This article was translated from my original post.

Controlling Multiple Servos on Raspberry Pi

OS Environment

I used a Raspberry Pi 4 Model B (4GB RAM).

The OS is Ubuntu 22.04.1 LTS (64-bit). Other OSs like Raspberry Pi OS should work similarly.

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.1 LTS
Release:    22.04
Codename:   jammy

Wiring the Circuit

The circuit was assembled like this:

  • The servo motors used are SG90
  • Power is supplied via a 4x AAA battery pack (6V)
    (According to the datasheet, this is just within the operating range)
  • The ground from the external power source is connected to the Raspberry Pi’s GND
  • Each servo's PWM signal wire is connected to a Raspberry Pi GPIO pin through a 1kΩ resistor
    (Pins 17, 18, and 27 are used here)

Writing a Script to Move the Servos

Now let’s write a simple script to test the servo motor movements. We'll use Python.

Source code:
github.com

import math
import time
from gpiozero import AngularServo


def main():
    servo_17 = AngularServo(17)
    servo_18 = AngularServo(18)
    servo_27 = AngularServo(27)

    t = 0
    max_angle = 60
    gap_angle = 30

    try:
        while True:
            servo_17.angle = math.sin(math.radians(t % 360)) * max_angle
            servo_18.angle = math.sin(math.radians((t % 360) + gap_angle)) * max_angle
            servo_27.angle = math.sin(math.radians((t % 360) + (gap_angle * 2))) * max_angle

            t += 2
            time.sleep(0.01)
    except KeyboardInterrupt:
        servo_17.angle = 0
        servo_18.angle = 0
        servo_27.angle = 0


if __name__ == '__main__':
    main()

This script uses AngularServo from gpiozero to control 3 servos. To make the movements smoother, the angles are calculated using sine functions.

Running the Servo Script

Now let’s run the script on the Raspberry Pi.

First, clone the repository and install the required packages:

# Clone
git clone https://github.com/bioerrorlog/raspberry-pi-examples.git
cd raspberry-pi-examples/multi_servo_gpio/

# Install required packages
sudo apt update
sudo apt upgrade
sudo apt install python3-pip python3-dev gcc git
sudo pip install -r requirements.txt

Then, run the Python script:

sudo python3 main.py

# Use sudo to avoid this error:
# RuntimeError: No access to /dev/mem. Try running as root!

If everything works correctly, the servo motors should move like this:

(The servos are held together with cardboard.)

Conclusion

This was a simple record of how I controlled multiple servos with a Raspberry Pi.

Since I didn’t use a PWM controller or implement any advanced software tricks, there's a fair amount of jitter.
Still, it works “well enough” to see the basic behavior.

That’s it for this note.

[Related Articles]

en.bioerrorlog.work

en.bioerrorlog.work

References