How to use soft PWM in RPi.GPIO 0.5.2a pt 2 – led dimming and motor speed control
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.
RasPiO® GPIO Reference Aids
Our sister site RasPiO has three really useful reference products for Raspberry Pi GPIO work...
What language and program would you recommend for precise control of motors and reasonably accurate control of servos?? (robotic project coming up hopefully :heh: ) well if all goes to plan anyway :idk: because from reading though it sounds like pwm through RPI.GPIO isn’t accurate enough for that kind of application.
Also from experience of boards/chips which from your point of view are the best for this kind of multiple motor use because if im honest we are starting from very little knowledge and have quite high aims which means unfortuanately we need lots of advice :L
People speak highly of the adafruit servo board. You could use ATmega or Guzunty as well. Python is ok as long as it’s just sending signals to control hardware PWM.
[…] How to drive leds and motors with PWM & RPi.GPIO on the Raspberry Pi: 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? […]
I’m a bit concerned about the non-real-time and non-timing-critical aspects. What kinds of inaccuracies are you talking about here?
I’m planning on building a robot with lego motors and parts, with a pi brain. Lego gear chains have plenty of slop in them already. Would python timing issues be noticable on top of that when the pi cpu is heavily loaded or python garbage collection kicks in?
I’m not out for incredible accuracy here, but I’m hoping my motors will respond within a few hundred miliseconds
I think we’re talking milli to microseconds. I’ve noticed the occasional jitter on a brushed motor. You should be OK with a small robot, but I wouldn’t want to use it on a CNC router or something big, powerful and accurate.
I managed a native Python motor driver in the Gertboard software that could cope with 3000 Hz pulses. It did jitter a bit, but it was usable.
With this PWM function it’s noticably better than mine. It’s just not quite there for critical things like servos which require precisely timed pulses.
I’m thinking of using a 555 timer chip for more accurate PWM, would it work?
Thank you for this tutorial. It’s very clear and helpful. I will suggest that a more common cycling loop pattern would be:
lo, hi, step = 0, 10, 1
for i in range(min(lo, hi), max(lo, hi), abs(step)):
print (lo, hi)
lo += step
hi -= step
step *= -1
and if you hate the use of min, max, and abs you can always duplicate the variable at the beginning:
lo, hi, step = 0, 10, 1
rlo, rhi, rstep = lo, hi, step
for i in range(rlo, rhi, rstep):
print (lo, hi)
lo += step
hi -= step
step *= -1
In the diagram with the motor there’s a red wire just to the left/above the motor that doesn’t seem to actually do anything. It’s connected to the Positive power line on one end of the wire but the other end does not appear to actually connect to anything.
It’s connecting the positive rail to the motor’s green wire. It’s redundant, but the way the Fritzing diagram is laid out it would have looked crap to have the green wire bent backwards straight into the positive rail. (Actually it looks a bit crap anyway, but I’m not going to change it now, just for that).
[…] Taken from RasPi.tv. Use a green light instead of that white color, so that our “Red Light, Green Light” game makes sense. […]
Hi, how can I change the phase of the pwm? I’m trying to make 4 leds blink at different times with the same frequency but different phase, how can I manage that? I’ve tried to make a delay before starting each pwm object, but they tend to sync at the first blink, what can I do to change each phase?
If you’re trying to make LEDs blink, rather than dim them, wouldn’t you be better off coding it manually, rather than using PWM, which is designed for fast blinking (faster than you can see)?
Thank you for your reply.
Well, the actual purpose of the code is to make pulses for a stepper motor, which uses 4 outputs. I’m using LEDs so I can see the actual outputs of the code before using the stepper motor.
I’m using webiopi to control de RPi from a webpage. When a button gets pressed, it calls a function from another script that contains the pwm setup in the 4 outputs at 1 Hz and a duty cycle of 25%.
Here’s a bit of my code:
b1 = GPIO.PWM(18, 1)
b2 = GPIO.PWM(22, 1)
b3 = GPIO.PWM(23, 1)
b4 = GPIO.PWM(27, 1)
Notice the delays I made so the pwm outputs alternate, the delays work, but the pwm outputs sync just after the first blink, which is bad for me :(.
Thing is… I cannot code the pins manually on/off in a loop because the function is called only once (when the button is pressed), when the button is not pressed and the function HAS ENDED, my main script calls a function that stops the pwm outputs turning them off.
I cannot put the function in the main script because webiopi does not support software pwm with low frequencies, so i’m forced to use another script.
Webiopi does work with PWM.. you just have to start webiopi within the python script and then execute the python script. Source https://code.google.com/p/webiopi/wiki/PYTHON
I also rewrote some part of the code to work like a traffic light (3 leds).
Works like a charm.
I’m building a solar water heater and plan to use something like this to control the speed of the circulation pump. Most suitable pumps have a flow rate of 4 litres per minute upwards, but I need a variable rate, possibly as as low as 1 litre per minute, depending on the relative temperatures of the hot water tank and the solar collector.
Phil, can you send me an email, I would like to discuss your solar water heater. Thanks. Michael email email@example.com
Hi I have just stumbled upon your site, I wonder if you could tell me how to put a pause before the cycle begins again, I have managed to get the LEDs to stay on at full brightness for a short period what I would like is to put a short pause before the cycle begins again, any help greatly appreciated
Just copy line 34
and “de-indent” (I think it’s called dedent???) one level. If you want to, you can change
to a fixed time period in seconds.
Sorry for being dim but i am new to this but where would i put the newly copied line
If I understand you correctly Keith, this is what you need…
…but you really do need to learn the basics of Python. I recommend “learn python the hard way” by Zed Shaw
Thankyou for the reply, Sorry for not getting back to you but I have been working away, I assume this will give me a fade up Pause then fade down Pause then fade up and repeat.
I would love to learn python, but with family work etc I dont get the time to sit down and learn, thanks for the continued suppport
how can you connect multiple motors?
If you use a L293D chip (about £1 each) they have 2 outputs, so can control 2 motors. You’ll need 2 GPIO pins to control the direction of each motor, and a third for the PWM control.
In my application, my motor always spins in the same direction (it’s a water pump), so I was able to eliminate the direction control and use a single GPIO pin to control the PWM.
[…] https://raspi.tv/2013/how-to-use-soft-pwm-in-rpi-gpio-pt-2-led-dimming-and-motor-speed-control […]
Maybe I’m missing something… But confused and really want to understand… What is the green wire connected to?
Gah never mind..
The positive rail on the breadboard, via the red wire. If I was doing the diagram again today, I’d probably do it a little more clearly. I always try to use red for positive. The gree dangly wire on the motor cannot be edited though.
What actually happens when you do a PWM.start(10) then PWM.stop() then PWM.start(10) ? I don’t know if it is my mistake or there are something wrong in the PWM threading?
Hi great article. I’m trying to make a system for a friend who has a model fair ground ride. He’s asked me to try to make the lighting system for him and also play music from the pi. My question is how would one code light sequences on all outputs? As my efforts don’t seem to work.
Also if I copy your text in to Python it’s fine if I make a .py file and run it nothing happens?
I’m quite new to all of this raspberry stuff. But I would like to know, if you can set the dutycycle in .1 steps? Can you set “i” to something like “0.1”?
Thank you, cheers, Dominic
Off the top of my head I don’t remember, but try it, if it doesn’t work, the answer is no.
Hey first of all, thank you for this tutorial.
I’ve tried running the script and it works perfectly fine with my setup.
However, I would like to make a slight modification.
I would like for the duty cycle to stop once it reaches 100% instead of looping and going back to 0%.
Can you help me do that?
Thank you very much once again
Simply remove the “while True:” line and un-indent the remaining lines as appropriate.
And depending on what you’re trying to do, you may want to remove the whole of the second ‘for’ block, and you might want to ‘pause’ the script before getting to the end http://gpiozero.readthedocs.org/en/v1.2.0/notes.html#keep-your-script-running
please do any one have an idea about importance of connecting 16 1-k resistor with h-bridge to drive motor on the raspberry ?
and can I connect motors without resistors with h-bridge ???
I suspect it probably depends on which h-bridge chip you’re using??
But see e.g. https://gpiozero.readthedocs.io/en/v1.2.0/recipes.html#motors or https://thepihut.com/products/motozero
hi,cant we use grovepi light sensors instead of led and apply pwm to that.i didn’t see any codes realeting these two.
is there any programs relating these on python?
can I have programs applying pwm to grovepi light sensor instead of GPIO?