Controlling a Servo motor with Raspberry Pi and Python : A Fun weekend Project

Controlling a Servo motor with Python

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

Project overview

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.

Getting started

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

Wiring up a servo motor to the Raspberry Pi

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

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:

Capture1

Picture courtsey: WikiPedia

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:

Picture1

DC motors

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:

Picture1

Servo motors

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 pulse width modulation (PWM) and the position of a 180-degree servo:

Capture1

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.

Picture1.png

The following is a chart of servo color codes that will help you with the wiring:

Capture1.JPG

Connecting the servo motor to our Raspberry Pi

Our circuit will consist of a simple servo and LED. The following is the Fritzing diagram of the circuit:

Picture1.png

Picture courtsey: Fritzing

We connect:

  • 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:

Picture1

Control the servo through the command line

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 Shell:

Capture1

Type the following in the shell:

from gpiozero import Servo

After a short delay, the cursor should return. What we have done here is load the servo object from gpiozero into memory. We will assign pin GPIO 17 with the following statement:

servo = Servo(17)

We will now move the servo motor to the minimum (min) position. Type the following into the command line:

servo.min()

You should hear the servo motor moving, and the needle will go to its farthest position (if it is not already there).

Let’s move the servo motor to the maximum ( max) position with the following command:

servo.max()

Now, move the servo to the middle ( mid) position with the following command:

servo.mid()

The servo motor should move to its middle position.

When you place your hand over the servo motor, you may feel a slight jerking motion. To temporarily disable control of the servo, type the following into the command line and press Enter:

servo.detach()

The jerking motion should stop, and the needle indicator attached to the servo should stay in its current position.

As we can see, it is very easy to move the servo motor to its minimum, middle, and maximum values. But what if we want to have more precise control of the servo? For those instances, we may use the value property of the servo object. A value between -1 (minimum) and 1 (maximum) can be used to move the servo motor.

Type the following into the command line:

servo.value=-1

The servo should move to its minimum position. Now, type the following:

servo.value=1

The servo should now move to its maximum position. Let’s use the value property to indicate weather conditions. Type the following into the command line:

weather_conditions = {'cloudy':-1, 'partly cloudy':-0.5, 'partly sunny': 0.5, 'sunny':1}

Test the code in the shell with the following:

weather_conditions['partly cloudy']

You should see the following in the shell:

-0.5

With our servo object and our weather_conditions dictionary, we may now use the servo motor to indicate the weather conditions physically. Type the following into the shell:

servo.value = weather_conditions['cloudy']

The servo motor should move to the minimum position to indicate that the weather conditions are cloudy. Now, let’s try sunny:

servo.value = weather_conditions['sunny']

The servo should move to the maximum position to indicate sunny weather conditions.

For partly cloudy and partly_sunny conditions, use the following:

servo.value = weather_conditions['partly cloudy']
servo.value = weather_conditions['partly sunny']

Write a Python program to control the servo

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:

  1. Open up Thonny from Application Menu | Programming | Thonny Python IDE
  2. Click on the New icon to create a new file
  3. Type the following:
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)
  1. Save the file as WeatherDashboard.py
  2. Run the code
  3. You should see the servo move to the middle position, and the LED should turn on

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 14, respectively. GPIO Zero allows us to assign GPIO values easily without boilerplate code.

In our class initialization method, we create Servo and LED objects called servo and led respectively:

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 to 1, and we are passing a value from 0 to 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 -1 to 1 scale 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 50 represents the middle value in a 0 to 100 scale. Multiplying 50 by 0.02 produces the value of 1. Subtracting 1 from this value produces 0, which is the middle value in a -1 to 1 scale.

To set the status of the LED (offon, or 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()

In set_led_status, we set our LED to off if the value passed in is 0on if the value is 1, and blink if it is any other value.

We test out our class with the following code:

if __name__=="__main__":
    weather_dashboard = WeatherDashboard(50, 1)

 

———————————————————————-

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s