Controlling a Servo motor with Raspberry Pi and Python : A Fun weekend Project
Analog meters and instrumentation were the only ways to display data prior to the rise of digital technologies. Once the move was made to digital, analog meters fell out of vogue. Generations that grew up learning to tell the time on an analog clock may suddenly find this skill to be out of date, as digital displays of time have become the norm.
In this post which can be your fun weekend project, we will bridge the gap between the digital and analog worlds by changing the position of a servo motor based on a digital value.
We will cover the following topics:
- Wiring up a servo motor to the Raspberry Pi
- Controlling the servo through the command line
- Writing a Python program to control the servo
In this interesting and nerdy project, we will wire up a servo motor and LED, and control it using the
GPIO Zero library. We will start by designing the circuit in Fritzing, and then we will assemble it.
We will start controlling the servo using Python shell.
Finally, we will expand on this knowledge by creating a Python class that will turn the servo motor based on a percentage amount, and turn on, turn off, or flash the LED based on a number passed to the class.
This project should take about 2 hours to complete.
To complete this project, the following will be required:
- A Raspberry Pi Model 3 (2015 model or newer)
- A USB power supply
- A computer monitor
- A USB keyboard
- A USB mouse
- A small servo motor
- A breadboard
- A LED (any color)
- Jumper wires for the breadboard
This project involves wiring up a servo motor to our Raspberry Pi. Many people confuse servo motors with stepper and DC motors. Since the electrical engineer embedded deep inside me is prompting me to, let’s take a look at the differences between these types of motors.
Stepper motors are brushless DC electrical motors that move a full rotation of equal steps. The position of the motor is controlled without the use of a feedback system (open-loop system). This makes stepper motors relatively inexpensive and popular for robotics, 3-D printers, and CNC-type applications.
The following is a crude diagram of the internal workings of a stepper motor:
By turning on and off the coils A and B in sequence, the Permanent Magnet (which is attached to the shaft of the motor) is spun. Precise steps are used, allowing precise control of the motor, as the number of steps may be controlled easily.
Stepper motors tend to be heavier and bulkier than other types of small motors.
The following photo shows a typical stepper motor used in a 3-D printer:
DC motors are similar to stepper motors, but do not divide motion into equal steps. They were the first widely used electrical motors, and are in use in electric cars, elevators, and any other application that does not require precise control of the position of the motor. DC motors may be brushed or brushless.
Note: Brushed motors are simpler to operate, but have limitations on revolutions per minute ( RPM) and usage life. Brushless motors are more complicated, and require electronics for control-for example, the Electronic Speed Controllers ( ESCs) used on some drones. Brushless motors may be operated at a much higher RPM, and have a longer usage life than brushed motors.
DC motors have a much shorter response time than stepper motors, and tend to be lighter than comparable stepper motors.
The following is a photo of a typical small brushed DC motor:
Servo motors use a closed-loop feedback mechanism to provide extremely precise control of the position of the motor. They are considered a high-performance alternative to stepper motors. The range can vary depending on the servo, with some servos limited to 180-degree movement while others can move a full 360 degrees.
Note: Closed-loop control systems, unlike open-loop control systems, maintain an output by measuring the actual condition of the output, and comparing it to the desired outcome. Closed-loop control systems are often called feedback control systems, as it is this feedback that is used to adjust the condition.
The angle of a servo is determined by pulses passed to the control pin on the servo. Different brands of servo have different maximum and minimum values to determine the angle of the servo needle.
The following is a diagram to demonstrate the relationship between p ulse width modulation ( PWM) and the position of a 180-degree servo:
The following is a photo of the small servo motor that we will be using for our circuit. We are able to connect this servo directly to our Raspberry Pi (this may not be possible with larger servos). You can easily buy these small servo motors on Amazon but if you need help identifying one, shoot me a note.
The following is a chart of servo color codes that will help you with the wiring:
Our circuit will consist of a simple servo and LED. The following is the Fritzing diagram of the circuit:
- The positive power of the servo to the 5V DC supply, and the ground to GND
- The control signal from the servo to GPIO 17
- The positive end of the LED to GPIO 14, and the resistor to GND
Be sure to use a small servo motor, as larger ones may require more power than the Raspberry Pi is able to supply. The circuit should resemble the following:
Now that our servo is connected to our Raspberry Pi, let’s write some code at the command line to control it. We will use the Raspberry Pi Python library
GPIO Zero to do this.
Load up Thonny and click on
Jerry Seinfeld once joked that all we need to know about the weather is: Should we bring a coat or not? For the rest of this chapter and the next, we will build an analog meter needle dashboard to indicate the wardrobe needed for the weather conditions.
We will also add an LED that will turn on to indicate that an umbrella is needed, and flash to indicate a very bad storm.
The key objective here is that we need code to control the servo and LED. We will start by creating a class to do just that.
This class will set the servo position and LED state on our circuit:
from gpiozero import Servo from gpiozero import LED class WeatherDashboard: servo_pin = 17 led_pin = 14 def __init__(self, servo_position=0, led_status=0): self.servo = Servo(self.servo_pin) self.led = LED(self.led_pin) self.move_servo(servo_position) self.set_led_status(led_status) def move_servo(self, servo_position=0): self.servo.value=self.convert_percentage_to_integer (servo_position) def set_led_status(self, led_status=0): if(led_status==0): self.led.off() elif (led_status==1): self.led.on() else: self.led.blink() def convert_percentage_to_integer(self, percentage_amount): return (percentage_amount*0.02)-1 if __name__=="__main__": weather_dashboard = WeatherDashboard(50, 1)
Experiment with other values and see if you can move the servo to 75% and have the LED blink.
Let’s take a look at the code. After defining the class, we set GPIO pin values for the servo and LED with the following:
servo_pin = 17 led_pin = 14
As you saw in the circuit we built, we connected the servo and LED to GPIO
17 and GPIO
GPIO Zero allows us to assign GPIO values easily without boilerplate code.
In our class initialization method, we create
LED objects called
self.servo = Servo(self.servo_pin) self.led = LED(self.led_pin)
From here, we call the methods in our class that move the servo and set the LED. Let’s look at the first method:
def move_servo(self, servo_position=0): self.servo.value=self.convert_percentage_to_integer (servo_position)
In this method, we simply set the value property in
servo object. As this property only accepts values from
1, and we are passing a value from
100, we need to convert our
servo_position. We do that with the following method:
def convert_percentage_to_integer(self, percentage_amount): return (percentage_amount*0.02)-1
Note: In order to convert a percentage value to a
1scale value, we multiply the percentage value by
0.02, and then subtract
1. It's easy to verify this math by using the percentage value of
50. The value of
50represents the middle value in a
0.02produces the value of
1from this value produces
0, which is the middle value in a
To set the status of the LED (
blink) we call the following method from our initialization method:
def set_led_status(self, led_status=0): if(led_status==0): self.led.off() elif (led_status==1): self.led.on() else: self.led.blink()
set_led_status, we set our LED to
off if the value passed in is
on if the value is
blink if it is any other value.
We test out our class with the following code:
if __name__=="__main__": weather_dashboard = WeatherDashboard(50, 1)
Originally published at http://smartsupplychains.ai on January 11, 2020.