Servo Motor Control With Raspberry Pi

Published

Introduction: Servo Motor Control With Raspberry Pi

Use a Raspberry Pi 3 and Python Scripts to control a servo motor.

Step 1: Materials and Tools

Materials:

  • Raspberry Pi 3 (RPi)
  • Jumper Wires, Male to Female (M/F)
  • Servo Motor

**In this project, it is necessary to access the Raspberry Pi desktop. This can be done by plugging a monitor, keyboard and mouse into the RPi or by using an SSH connection.**

No tools are necessary for this project as none of the connections are permanent and use jumper wires and a breadboard. If you want to make a permanent, more durable version, simply make the same connections with a soldering iron and some wire.

Step 2: Background Info.

**This step is all background info. If you don't care about how this is done and just want to do it without learning, skip to Step 3.**

This project uses Python scripts run on a Raspberry Pi microcontroller to send GPIO PWM outputs to a servo motor to set its angle. If all that sounds confusing, don't worry, I'm about to explain it.

First things first; a Raspberry Pi is an open-source credit card sized computer with 40 open GPIO pins. GPIO stands for "General Purpose Input/Output", which means these pins can either send electrical signals to drive hardware or receive them and read sensor data. We're using them as outputs, to send signals to a servo motor. Nothing special.

Python is a computer programming language, comparable to Javascript or C++. We'll be using very simple python commands, and no prior computer programming knowledge will be necessary.

A servo motor is a type of DC motor that, upon receiving a signal of a certain frequency, can rotate itself to any angle from 0-180 degrees. Its 90 degree position is generally referred to as 'neutral' position, because it can rotate equally in either direction from that point.

The way a servo motor reads the information it's being sent is by using an electrical signal called PWM. PWM stands for "Pulse Width Modulation". That just means sending ON electrical signals for a certain amount of time, followed by an OFF period, repeated hundreds of times a second. The amount of time the signal is on sets the angle the servo motor will rotate to. In most servos, the expected frequency is 50Hz, or 3000 cycles per minute. Servos will set to 0 degrees if given a signal of .5 ms, 90 when given 1.5 ms, and 180 when given 2.5ms pulses. This translates to about 2.5-12.5% duty in a 50Hz PWM cycle.

We'll be sending PWM signals from one GPIO pin on the RPi, and powering it from the GPIO board, so three wires will run from the servo to the RPi.

Now that we know what's going on, it's time to wire it up.

Step 3: Hardware Setup

The hardware for this project is very simple.

I recommend creating something to go on the end of the servo to better show its rotation, but that's totally unnecessary.

The only thing that you have to do is plug the three wires from the servo into the GPIO board. Refer to the diagram above for the pin numbers.

Plug a M/F jumper into each of the holes on the end of the servo cord, then plug the one coming off the red wire into pin #2, the one coming off of the brown into pin #6, and the one coming out of the yellow wire into pin #3. That's all there is to it, and if those instructions aren't clear enough, just look above at the pictures.

Step 4: Software Setup

First, we need to open a program on the Pi to write our code. We're going to use IDLE 2, so go to the top left of your desktop, click Menu, click Programming, and click Python 2(IDLE). You should see a blank text editor with an untitled document. You should not see a console with a shell prompt (ie. '>>>"). IF you do, click File, then New.

The first thing we need to do is import the GPIO module. So, on the first line, type exactly, CaSe sensitive,

import RPi.GPIO as GPIO

this imports the GPIO module
next, we need a command called 'sleep', so write

from time import sleep

next we need to name all of the pins, so set the naming mode by writing

GPIO.setmode(GPIO.BOARD)

this sets the names to board mode, which just names the pins according to the numbers in the middle of the diagram above.

Now we need an output to send our PWM signal on, so write

GPIO.setup(03, GPIO.OUT)

Now setup PWM on pin #3 at 50Hz

pwm=GPIO.PWM(03, 50)

Then start it with 0 duty cycle so it doesn't set any angles on startup

pwm.start(0)

Now, to set the angle of the servo, we need to send a specific signal to it. This can differ from servo to servo, as normally it's from 2.5-12.5%, and on the ones I'm using it's 2-12%. Regardless, it will be a 10% window, so to calculate the duty cycle for your desired angle, divide by 18, then add the lowest available value, in this case 2.

So, for 90 degrees, divide by 18, which is 5, then add 2, and you get 7. So on this servo 7% duty is 90 degrees.

As you can see, this math is not very friendly and would be tedious to do every time you wanted to set an angle, so in order to simplify that we're going to write a function in Python that does the math automatically then sets the angle.

So, first define a function. You can name it whatever you like.

def SetAngle(angle):
	duty = angle / 18 + 2
	GPIO.output(03, True)
	pwm.ChangeDutyCycle(duty)
	sleep(1)
	GPIO.output(03, False)
	pwm.ChangeDutyCycle(0)

Now that probably looks like a lot of confusing code, so let me explain everything I did.

  • The first line sets up a function called 'SetAngle' that we can call later in the code and give our input as an angle.
  • The second line (which needs to be indented inside the function) sets a variable equal to our angle divided by 18 and 2 added like I showed above
  • The third line turns on the pin for output
  • The fourth line changes the duty cycle to match what we calculated
  • The fifth line waits 1 second so the servo has time to make the turn. Depending on the speed of your servo you might need longer, or you might not need this long
  • The sixth line turns off the pin
  • And the seventh line changes the duty back to 0 so we aren't continuously sending inputs to the servo

Now in your code you can call the function, by writing

SetAngle(90) 

to tell the servo to turn to 90 degrees.

So, in your code, call a few angles, and when we run the code we'll see how they run on the servo.

At the end of your code, make sure to write

pwm.stop()
GPIO.cleanup()

And that's it! You now have a code that can set your servo to any angle. Press F5, then save to test your code!


*Note: you may receive an error that says the selected GPIO channels are already in use. This won't affect your project, and you can make the warnings stop appearing by writing "GPIO.setwarnings(False)" to your code.*

Share

    Recommendations

    • Make it Move Contest

      Make it Move Contest
    • Casting Contest

      Casting Contest
    • Clocks Contest

      Clocks Contest
    user

    We have a be nice policy.
    Please be positive and constructive.

    Tips

    4 Questions

    Hey, i have another question regarding the servo.

    I've noticed that my servo twitches a lot when powered on and stationary. Do you happen to know how i could fix this?

    No, I have noticed the same thing and I’m unsure if it’s fluctuating PWM or main power or some type of mechanical issue, but I’d suggest researching the servo you’re using and whether or not raspberry pi’s typically have stable PWM. Sorry I couldn’t be of more help!

    1 more answer

    I've been able to sort it out, to prevent it from twitching i had to send a signal once, and then stop the pwm. Untill i want to change it again.

    Thank you very much for this, everything on this page has been very helpful! However, I'm trying to automatically control the servo motors at definite times for a day (8:00AM, 12:00PM and 4:00PM), would this be possible?

    Note that when you don't connect the RPi to the internet, the clock in your RPi will start shifting, but if it's connected to the internet and can sync up to that. You can use a RTC module to fix this problem if needed. (some of those include an alarm function, wich you can use to start a function.

    2 more answers

    If I were you, I would look at using the code here along with cron. Cron is a tool used to schedule jobs in unix/linux environments. There are tons of resources online to learn how to use it. I highly recommend adding it to your skill set.

    0

    I am not sure, but if you were to use my code as a baseline to define some functions and then find out how to check the current time on a RPi, you could create a constantly looping ‘if’ statement that executed my functions when the time input was equal to your desired times. Like I said, I’ve never done anything like that or researched it, but to my knowledge it should be totally possible. Hope this helped!

    've heard many times that it's recomended to use an external suply to power the servo, altough you don't do this, why? I ask this because i'm currently working on a project. And it would save me a bit of wiring.

    That is certainly a good idea to avoid overloading and possibly causing damage to your RPi, but I checked the current draw and voltage requirements of the servo I was using and made sure it would be okay to use directly from the Pi’s GPIO board. If you are unsure of how to do that, or are using an excessive amounts of servos or other power requirements it’s definitely a good idea to use an external power supply. Just swap the jumpers from where I hooked them up to the 5V and GND pins on the Pi and connect them to the appropriate power source to power your servos instead. Hope this helped!

    0

    hi i want to run this code slower for example if i change pwm=GPIO.PWM(03, 50) to pwm=GPIO.PWM(03, 25) how the code would change for correct result?

    0

    The second number given as an argument in that statement sets the frequency of modulation in Hz, so your given example would change the PWM signal to cycle 25 times per second instead of my stated 50. If your intention is less cycles per second or minute, that is the correct way to achieve it. If you want the output motor to run slower that is just a matter of lowering the duty cycle, or the percentage you set later in the code. I hope this helped!

    16 Comments

    user

    how would you code it if you're using the Adafruit servo Pihat to control more than one servo. pwm.ChangeDutyCycle(duty) would not work in this case right?

    1 reply

    I'm not familiar with that hat, but Adafruit is typically pretty good about having online tutorials for the libraries their hats contain. I would check there, and if not some RPi forums may have help for you depending on the popularity of the hat. If neither of those works your best bet is to read the libraries included with the hat and figure out how they work. I hope this helped, sorry I didn't know more!

    i tried this code three times but my servos broke down all time.my three servos are gone.i didnt get it why?

    2 replies

    I’m not sure why this would have happened, my only suggestion would be to check the specifications of your motors and make sure they’re compatible with whatever setup you’re using. Other than that I’m afraid I won’t be of much use. I’m sorry if this really broke your servos, I’ve never had any problems like that with it! Best of luck to you :)

    Thanks for replying.i use sg90.maybe raspberry's 5v supply pin is higher than 5v.Could be?.because i tested it motors with arduino and stm32f.before rasp my motor worked clearly.but i set motor to rasp.my motor never work after that.

    Yes, this was done on a Raspberry Pi 3, so it is all correct for that model. If you want to use a later model the only difference might be the python version and therefore some syntax, and the pins might be laid out differently on the Pi so just look up a Pinout diagram for the other model and connect it to the names of the pins I said above and ignore the numbers I said. Hope this helped!

    Hi, I run the code with an error indicate that "GPIO.setup(03, GPIO.OUT)"? arrow is point at "03"

    2 replies

    Sorry I missed this comment, but yes depending on the version on python you are coding in sometimes the 0 in front creates an error. The version I wrote in was older, but removing the 0 should fix the issue like popcornpack329 said.

    Well this may be a good way to make my project a little easier. I am creating a doggy treat dispenser with either video feed back or live feed all with camera/mic/speaker on the raspberry pi3 side also either recording or live streaming. I am also trying to run a python command for a servo or two to dispense treats to my puppers. I'm going to look into if I can power that all of the pi, or if I'll need a switchboard/relay type setup. Thanks for this!

    How do you connect an extra servo for pan-tilt?

    i like you man

    you make it very simple and easy

    thanks

    best tutorial on the web

    Thanks!!

    simple but very useful

    it works

    Thanks for sharing :)