Lab 22: Random Walk
Pixel says...
Meet the wandering pixel! It can't decide where to go, so it flips a coin at every step.
Heads, go left. Tails, go right!
Program file: 22-random-walk.py
What you'll learn
- What a random walk is
- How
randint(0,1)works like a coin flip - How
loc % NUMBER_PIXELSwraps a pixel around both ends of the strip - How
+=and-=move a number up or down
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 moves one dim white pixel a step left or right, chosen at random, about ten times each second.
# Lab 22: Random Walk
# Filename: 22-random-walk.py
# Version: 1.0.0
#
# A dim white pixel takes a random step left or right each time.
from machine import Pin
from neopixel import NeoPixel
from utime import sleep, ticks_ms
from urandom import randint
import config
# hardware settings from config.py
NEOPIXEL_PIN = config.NEOPIXEL_PIN
NUMBER_PIXELS = config.NUMBER_PIXELS
strip = NeoPixel(Pin(NEOPIXEL_PIN), NUMBER_PIXELS)
loc = int(NUMBER_PIXELS/2)
while True:
strip[loc % NUMBER_PIXELS] = (10,10,10)
strip.write()
sleep(.1)
strip[loc % NUMBER_PIXELS] = (0,0,0)
move_dir = randint(0,1)
if move_dir == 0:
loc -= 1
else:
loc += 1
Run it. A dim white dot starts in the middle of the strip and wanders. When it walks off one end, it appears at the other end.
How it works
Start in the middle
loc = int(NUMBER_PIXELS/2)
The name loc is short for location. It is a variable (a name that holds a value that can change). It holds the pixel number where the dot is now.
The / symbol divides and gives a decimal answer, so 30/2 is 15.0. The int() function drops the decimal part, so loc starts as the whole number 15.
Show the pixel, then erase it
strip[loc % NUMBER_PIXELS] = (10,10,10)
strip.write()
sleep(.1)
strip[loc % NUMBER_PIXELS] = (0,0,0)
The first line lights the pixel. Equal amounts of red, green, and blue make white, and the small number 10 keeps it dim. Then strip.write() shows it, and sleep(.1) holds it for a tenth of a second.
The last line turns the pixel off in the Pico's memory. The next strip.write() sends the erase and the new pixel together.
Flip a coin
move_dir = randint(0,1)
if move_dir == 0:
loc -= 1
else:
loc += 1
The call randint(0,1) gives 0 or 1, each about half the time. That's like a coin flip. The name move_dir is short for move direction.
The if line checks the coin. On 0, loc -= 1 subtracts 1 from loc, so the dot moves to a lower pixel number. On 1, loc += 1 adds 1, so the dot moves to a higher pixel number.
A path made of random steps is called a random walk. Scientists use random walks to study things like drifting smoke and wandering animals. Chapter 13 shows a random walk that stops at the ends of the strip instead of wrapping.
Wrap around with modulo
The variable loc has no limit. It can grow past 29 or shrink below 0. But the strip only has pixels 0 to 29. The modulo operator % gives the remainder after a division, and it fixes this puzzle. In every line that touches the strip, the code uses loc % NUMBER_PIXELS.
30 % 30is 0, so walking past the last pixel lands on the first.31 % 30is 1, so the walk keeps going from the start.-1 % 30is 29, so walking left from pixel 0 lands on the last pixel.
When you divide by 30, Python's % always gives an answer from 0 to 29. That's why the dot can leave either end and come back on the other side. You can watch this in the Modulo Wrap-Around Animation MicroSim.
Try it yourself
- Change the color on the first
strip[loc % NUMBER_PIXELS]line from(10,10,10)to(0,0,40). What color is the wanderer now? The erase line keeps(0,0,0). - Make the walk lopsided. Change
move_dir = randint(0,1)tomove_dir = randint(0,3). Only 0 sends the dot left. What happens over time?
Check your understanding
- Which pixel does the dot start on?
- What two values can
randint(0,1)give? What does each one do toloc? - What are
31 % 30and-1 % 30? - Why does the dot stay on the strip?
- Why does the code use
int()inint(NUMBER_PIXELS/2)?
Lab complete!
You made a pixel that wanders on its own! A coin flip and a bit of modulo can make surprising motion.
What's next: In Lab 23: Heartbeat, one pixel beats like a heart: a strong pulse, a softer pulse, and a rest.