In part 1 of this series, we looked at the basic commands for using software pulse-width modulation (PWM) in RPi.GPIO 0.5.2a and higher. In this article we’ll get a bit more hands-on and into some practical applications for it. It’s all very well being able to make nice square-wave pulses on an oscilloscope, but what’s it actually useful for?
Our servo said? EEEEH AAAAH
I tried using RPi.GPIO soft PWM with servos in response to a query after the last article, but, although it did change the servo positions, it was jittery. Servos require quite precise PWM inputs. These appear to be better suited to hardware PWM solutions (or lower level programming languages). So we’ll leave servos for now and concentrate on controlling the brightness of leds and simple brushed motor speed control.
The idea here is that you can switch an led on and off very fast and trick the eye into thinking it’s on all the time. Most people can see flickering at or below about 50 Hertz (50 times per second). I remember the “good old days” of CRT monitors. I used to prefer one with a refresh rate of at least 72 Hz to avoid eye strain and headaches. So let’s pick an arbitrary number above 50 Hz, but not too high. Let’s say 100 Hz. That gives us a frequency, which we will leave as it is throughout the program.
Dimming leds using duty cycle
Remembering from last time, the duty cycle is the percentage of time the pulse is “ON”. :)
We will vary the duty cycle to get our variable brightness. A duty cycle value of 0 means fully off, 100 is fully on. Anything in between gives a proportion of full brightness. (Well that’s what your eye thinks. It actually gives full brightness for a proportion of the time.)
The led dimming circuit
Before we can do anything we have to hook it all together. Your leds may need different value resistors than mine, so check.
We have the +ve ends of: a white led connected to GPIO 25; a red led to GPIO 24. White gets a 330R resistor (it’s a superbright led) from -ve to GND. Red gets 56R (diagram shows 68R, which would also be fine) from -ve to GND. GND on the breadboard is connected to pin 6 GND on the Pi.
These leds are taking their power straight from the Pi’s GPIO ports, which is why I’m being careful to restrict the current drawn by my superbright white led.
Now we’ve got the circuit sorted out, let’s look at the software.
In the program below, we are running a couple of loops which change the duty cycles of red and white leds, such that when one is 100, the other is 0. The first loop (lines 27-30) cycles up to 100 and the second one (31-34) cycles down from 100 to 0 (both from the white led’s point of view).
Those two loops are enclosed in a
while True: loop (lines 26-34) that will keep going until you hit
CTRL+C. And that
while True: loop is inside a
try: ... Except KeyboardInterrupt: block that will stop the PWM, clean up the GPIO ports we opened and exit gracefully when we do hit CTRL+C. (Always clean up after yourself ;) ).
#!/usr/bin/env python2.7 # script by Alex Eames https://raspi.tv #https://raspi.tv/2013/how-to-use-soft-pwm-in-rpi-gpio-pt-2-led-dimming-and-motor-speed-control # Using PWM with RPi.GPIO pt 2 - requires RPi.GPIO 0.5.2a or higher import RPi.GPIO as GPIO # always needed with RPi.GPIO from time import sleep # pull in the sleep function from time module GPIO.setmode(GPIO.BCM) # choose BCM or BOARD numbering schemes. I use BCM GPIO.setup(25, GPIO.OUT)# set GPIO 25 as output for white led GPIO.setup(24, GPIO.OUT)# set GPIO 24 as output for red led white = GPIO.PWM(25, 100) # create object white for PWM on port 25 at 100 Hertz red = GPIO.PWM(24, 100) # create object red for PWM on port 24 at 100 Hertz white.start(0) # start white led on 0 percent duty cycle (off) red.start(100) # red fully on (100%) # now the fun starts, we'll vary the duty cycle to # dim/brighten the leds, so one is bright while the other is dim pause_time = 0.02 # you can change this to slow down/speed up try: while True: for i in range(0,101): # 101 because it stops when it finishes 100 white.ChangeDutyCycle(i) red.ChangeDutyCycle(100 - i) sleep(pause_time) for i in range(100,-1,-1): # from 100 to zero in steps of -1 white.ChangeDutyCycle(i) red.ChangeDutyCycle(100 - i) sleep(pause_time) except KeyboardInterrupt: white.stop() # stop the white PWM output red.stop() # stop the red PWM output GPIO.cleanup() # clean up GPIO on CTRL+C exit
This program will continually oscillate white and red leds between dim and bright until CTRL+C is pressed. When white is bright, red will be dim and vice versa.
You can play with the value of pause_time in line 23 to speed up or slow down the oscillation rate.
Getting the script on your Pi
You can either cut and paste the above code into a nano window on your pi, like this…
cut and paste the above code from this page
Or, type the following directly from the command line (e.g. LXTerminal) on your Pi…
Either way, after that you can run it with
sudo python pwm2.py (But you will need RPi.GPIO 0.5.2a or higher)
The video shows what the results should look like
The software to control the speed of a motor is exactly the same idea. I’m going to prove that by using the same program and just adding…
- a couple more wires
- a Darlington Array (ULN2003) chip
- a motor
- a battery to power the motor
Why the Darlington Array?
Most motors need to run at a higher voltage than the Pi’s 3.3V offers, and a higher current than the GPIO ports can cope with. So we need a way of being able to switch a higher voltage with the 3V3 from a GPIO port. The ULN2003 is seven pairs of transistors that allow this switching in a safe way. You could just use a standard transistor, but this chip only costs ~30 pence or 50 cents so why not have the capability of switching 7 things at once – you don’t have to use them all?
The other nice thing this chip does is protect your Pi’s GPIO port from the voltage spike that can occur when an inductive load (a relay, solenoid, motor etc.) is switched off. It has built-in freewheeling diodes that give the required protection – all for much less than the cost of the separate parts. So in my opinion it would be rude not to use one. :)
You can get dedicated H-bridge motor control chips that will give you bidirectional motor control, but for this experiment I wanted to keep things simple and feed the motor raw PWM.
See what the circuit looks like below…
You should now have a pretty good idea how to use RPi.GPIO’s soft PWM to control leds and motors. I hope you found this useful. Let us know what you’re going to use it for in the comments below.