GPIO Zero, the new GPIO library from the Raspberry Pi Foundation, is becoming my go-to method for doing simple things with the Pi’s GPIO pins. Over the past couple of weeks, I’ve been having fun preparing for the Bett exhibition, and more specifically the Raspberry Jam that is being held there on the 23rd January.
Part of my exhibit is a Raspberry Pi Zero with a Scroll pHAT attached. Getting that working was a story in and of itself, but I want to focus today on the 4 LEDs I soldered onto some prototyping board that is attached to the Zero. You can see them in the picture above.
Back to GPIO Zero. It contains a class called PWMLED which allows you to do software PWM with LEDs. What this means is that instead of just blinking them on and off you can fade them in and out. This takes a little bit of doing (unless I’ve missed something) so I thought I’d share with you my method. One thing to understand is that I’ve done it in a ‘thread’, which means that while the Scroll pHAT is doing it’s job of displaying messages, I can have the LEDs doing something disconnected from that process. The individual functions, however, could be removed from inside the threading ‘object’ if you don’t need to do anything else except pulse the LEDs.
Here’s a video to prove that it works!
Anyhoo. Here’s the code. (I’ve removed anything to do with the Scroll pHAT) (You can skip this bit and go straight to the bold bit to download the code from Github.
First of all, let’s import the libraries:
import time, threading, random from gpiozero import LED, PWMLED
Now, let’s define the LEDs:
# Set-up LEDs led_red = PWMLED(17) led_yellow = PWMLED(27) led_green = PWMLED(22) led_blue = PWMLED(10)
Now, in order to get a smooth fading action, we’re going to want to loop from 0 to 1 using a ‘float’ (decimal) value. (0.1… 0.2… 0.3… 0.4… etc). We can’t do that without a helper function. Note, Python doesn’t seem to do float subtraction very well, so I found I had to round the floats to one decimal place just to make it play nice! If I’m missing something, please leave a comment!
# Helper function to iterate over a float def frange(start, stop, step): i = start if (start < stop): while i <= stop: yield i i += step # For some reason, += doesn't always add an exact decimal, so we have to round the value i = round(i, 1) else: while i >= stop: yield i i += step # For some reason, += doesn't always add an exact decimal, so we have to round the value i = round(i, 1)
Now let’s define a class that we can start as part of a new thread:
class RandomLEDs(threading.Thread): def __init__(self, threadID, name): threading.Thread.__init__(self) self.threadID = threadID self.name = name def run(self): while True: led_list = [led_blue,led_yellow,led_green,led_red] the_led = random.choice(led_list) self.fade_in_led(the_led, 0.03) time.sleep(0.3) self.fade_out_led(the_led, 0.02) time.sleep(0.3) # PWM the LED value from 0 to 1 (or from 1 to 0) with a 0.1 step def fade_in_led(self, led, speed): for i in frange(0.0, 1.0, 0.1): led.value = i time.sleep(speed) def fade_out_led(self, led, speed): for i in frange(1.0, 0.0, -0.1): led.value = i time.sleep(speed)
Now, let’s kick the whole thing off:
# Start independent threads # This one lights up random LEDs thread1 = RandomLEDs(1, "Thread-1") thread1.start()
I’m hoping that all the indents have come through okay (I just spent the last 10 minutes putting spaces in, so hopefully so).
If you want to download the code, do the following:
git clone https://github.com/recantha/scroller
And the file you want is pwm_leds.py
You can run it by doing:
I’d be very happy to get any feedback you might want to give about my code, and my approach. I expect that there is a much easier way to do this – the float looping deserves a bit of consideration, for instance – but this is what I got working! In any case, I hope you found the post interesting! 🙂