Lab 18: Candle Flicker
Pixel says...
Warm light, and no wax needed! We'll use random numbers to make the strip flicker like a
candle flame. Let's light this up!
Program file: 18-candle-flicker.py
What you'll learn
- How
randint()picks a random whole number - How red and green light mix to make orange and yellow
- How to change a random pixel on the strip
- Why a program with no erase step can still look alive
What you'll need
- Your base kit: a Pico, a breadboard, and the 30-pixel LED strip, wired as shown in the Kit User's Guide
- The
config.pyfile saved on the Pico (see Getting Code onto the Kit) - Thonny open and connected to your Pico
The program
This program gives random pixels random warm colors, over and over, so the strip flickers like a flame.
Power check
After a moment, nearly all 30 pixels hold a warm color. On average the strip then draws about 690 mA, and bright picks push it higher. A USB port supplies about 500 mA. Read How Bright Can You Go? for the details. To fix it, change the pixel line to strip[randint(0,NUMBER_PIXELS - 1)] = (red // 4, green // 4, 0). The // symbol divides and drops the remainder. That lowers the average to about 175 mA.
# Lab 18: Candle Flicker
# Filename: 18-candle-flicker.py
# Version: 1.0.0
#
# A warm, random flicker like a candle flame.
from machine import Pin
from neopixel import NeoPixel
from utime import sleep
from urandom import randint
# https://docs.micropython.org/en/latest/library/random.html
import config
# hardware settings from config.py
NEOPIXEL_PIN = config.NEOPIXEL_PIN
NUMBER_PIXELS = config.NUMBER_PIXELS
strip = NeoPixel(Pin(NEOPIXEL_PIN), NUMBER_PIXELS)
def candle(delay):
for i in range(0, NUMBER_PIXELS):
green = 50 + randint(0,155)
red = green + randint(25,50)
strip[randint(0,NUMBER_PIXELS - 1)] = (red, green, 0)
strip.write()
sleep(delay)
counter = 0
while True:
candle(.001)
# wrap
counter = counter % (NUMBER_PIXELS-1)
counter += 1
Run it. The strip fills with orange and yellow lights that keep changing.
How it works
Random numbers
from urandom import randint
A random number is a number the computer picks by chance. The call randint(a, b) gives back a random whole number from a to b. Both ends can appear. So randint(0,155) can give 0, 155, or anything in between.
Warm colors
green = 50 + randint(0,155)
red = green + randint(25,50)
The first line makes green a random number from 50 to 205. The second line makes red bigger than green by 25 to 50. The biggest possible red is 205 + 50, which is exactly 255.
A mix of red and green light with more red than green looks orange. When both numbers are high, it looks yellow. When both are low, it looks like dim orange. The blue amount stays 0, so every color stays in the orange and yellow family. Chapter 12 shows another way to build a candle flicker.
Pick a random pixel
strip[randint(0,NUMBER_PIXELS - 1)] = (red, green, 0)
strip.write()
sleep(delay)
The first line picks a random pixel number and gives that pixel the new color. The pixels are numbered 0 to 29, and randint can return its top number. That's why the code uses NUMBER_PIXELS - 1, which is 29. Then strip.write() shows the change, and sleep(delay) pauses.
Thirty changes in one call
def candle(delay):
for i in range(0, NUMBER_PIXELS):
A function is a named block of code you can reuse. The candle function has one parameter (a named slot for a value), called delay. It repeats the three lines above 30 times. The same pixel can be picked twice in one call, and some pixels get skipped. That's what random means.
while True:
candle(.001)
The main loop calls candle forever with a delay of .001, which is one thousandth of a second. Each change pauses for that long, so the strip can change up to about 1,000 times a second. Writing to the strip takes some time too, so it changes a little less often.
Nothing gets erased
No line in this program turns a pixel off. New random colors replace old ones. Within a moment or two every pixel holds a warm color, and every pixel keeps changing. That's why the whole strip looks like a field of flickering oranges.
A leftover variable
counter = 0
while True:
candle(.001)
# wrap
counter = counter % (NUMBER_PIXELS-1)
counter += 1
The counter lines do nothing useful. No other line reads counter. The program behaves the same with or without them.
Try it yourself
- Change
candle(.001)tocandle(.05). Does the flicker look more like a candle or less? Try.02too. - Make the flame redder and dimmer. Change
green = 50 + randint(0,155)togreen = 20 + randint(0,60). What colors can you get now? Dimmer numbers also draw less current.
Check your understanding
- Which numbers can
randint(25,50)give? - Why is
redalways bigger thangreen? What color family does that give? - Why does the code write
NUMBER_PIXELS - 1inrandint(0,NUMBER_PIXELS - 1)? - Do lit pixels ever turn off in this program? What happens to them instead?
- What does the
countervariable do?
Lab complete!
You made a flame out of random numbers! A little bit of chance turns plain colors into something that feels alive.
What's next: In Lab 19: Theater Chase, every fourth pixel lights up and the pattern marches along the strip like a marquee sign.