NeoPixel example
This documents Python example code for the 50mm 12 NeoPixel (WS2812B) Ring connected to a BBC micro:bit
through the micro:bit
Python Editor.
Assumptions
- This example code uses the micro:bit Python NeoPixel library with initialization
np = neopixel.NeoPixel(pin2, 12)
to initialize $12$ NeoPixels connected toDI
onpin2
. The NeoPixel library works onpin0
,pin1
, orpin2
.pin2
is the nearest clippable micro:bit pin to the3V
andGND
clippable pins. - The 50mm 12 NeoPixel (WS2812B) Ring mounting holes are 2mm diameter on the corners of a 32mm square.
- The 50mm 12 NeoPixel (WS2812B) Ring electrical connector has 4 solder-pad connections that are on 0.1” centers and are ≈2.54mm × ≈1.27mm. The pins are:
Pin | Signal | I/O | Notes |
---|---|---|---|
1 | DI |
I | DI (input) |
2 | 5V |
+V | +5-7V |
3 | GND |
⏚ | 0V |
4 | DO |
O | DO (output to further NeoPixel strands) |
- NeoPixels can take RGB values on $[0, 255]$, but saturate at brightness levels $> 30$. Limiting each color to $30$ also limits the current needed to $\approx 12\%$ of the $60$ ma quoted as the maximum for a WS2812B NeoPixel (or $7$ ma).
- To limit the RGB color values to $< 30$ the example code uses the
compress
function to compress values on $[0, 1)$ to generate integers up to a maximum value on an exponential scale such that smaller values cover a larger part of the range and larger values cover a smaller part of the range. This is shown on a Desmos graph. - The example code includes
random_lights
andchase_lights
functions.random_lights
creates $12$ random colors withcompress
ed RGB color values $< 30$ then uses the unbiased Fisher-Yates (aka Knuth) algorithm to shuffle them everydelay
ms.chase_lights
creates $12$ colors scaled by $\frac{i}{12}$ for $i$ on $[\negthinspace[ 0, 12 )\negthinspace)$ withcompress
ed RGB color values $< 30$ then rotates them everydelay
ms.
- The example event loop sets random NeoPixels and shuffles them every
delay
ms untilbutton_a
is pressed, then sets chasing NeoPixels everydelay
ms untilbutton_a
is pressed, then repeats.
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# Imports go at the top
from microbit import *
import math, neopixel, random
np = neopixel.NeoPixel(pin2, 12)
n, delay, maximum = 12, 200, 30
# https://stackoverflow.com/a/2450976/17467335
# The de-facto unbiased shuffle algorithm is the Fisher-Yates
# (aka Knuth) Shuffle.
# See https://github.com/coolaj86/knuth-shuffle.
def shuffle(array):
"""Return array shuffled in place with the unbiased Fisher-Yates
(aka Knuth) algorithm."""
current_index = len(array)
# While there remain elements to shuffle...
while 0 != current_index:
# Pick a remaining element...
random_index = int(random.random() * current_index)
current_index -= 1
# And swap it with the current element.
array[current_index], array[random_index] = \
array[random_index], array[current_index]
return array
def compress(x, scale=1):
"""Return x on [0, 1) exponentially compressed, scaled to scale,
and floored."""
# https://www.desmos.com/calculator/gdcw7rndv2
# The compression factor of 4 is good. It must be greater than e
# for color[j] > 0.
return int(math.exp(4 * (x - 1)) * scale)
def random_lights(n=12, maximum=30):
"""Return n random leds with maximum brightness (< 256)."""
leds, color = [tuple(), ] * n, [0, ] * 3
for i in range(len(leds)):
for j in range(len(color)):
color[j] = compress(random.random(), maximum)
leds[i] = tuple(color)
return leds
def chase_lights(rot, color=(102, 51, 153, ), n=12, maximum=30):
"""Return n leds of color divided over n steps scaled by maximum
rotated by rot."""
leds = [tuple(), ] * n
for i in range(len(leds)):
scaled = [ compress(c / 255 * i / n, maximum) for c in color ]
leds[i] = tuple(scaled)
# Rotate by rot.
return leds[rot: ] + leds[: rot]
# Code in a 'while True:' loop repeats forever
while True:
# Set random leds and shuffle every delay ms until button_a pressed.
leds = random_lights(n, maximum)
while not button_a.was_pressed():
leds = shuffle(leds)
for j in range(len(leds)):
np[j] = leds[j]
np.show()
sleep(delay)
# Set chasing leds every delay ms until button_a pressed.
chase = 0
while not button_a.was_pressed():
leds = chase_lights(chase, (0, 255, 0, )) # chase green leds
for j in range(len(leds)):
np[j] = leds[j]
np.show()
sleep(delay)
chase = (chase + 1) % 12
1234567890123456789012345678901234567890123456789012345678901234567890
Links
Link | Description |
---|---|
https://www.desmos.com/calculator/gdcw7rndv2 | Desmos exponential compression graph |
https://universal-solder.ca/12-led-ring-ws2812b-rgb-addressable-50mm/)) | 50mm 12 NeoPixel (WS2812B) Ring available from Universal Solder |
https://photos.app.goo.gl/hWqZB8di2HHBCWo19 | A 50mm 12 NeoPixel (WS2812B) Ring with soldered 0.1” headers and wired through a KS0360 Keyestudio Sensor Shield V2 |
https://photos.app.goo.gl/zHPtcBgjWh99wYCZ6 | micro:bit examples videos (NeoPixel Ring & Snake) |
https://tech.microbit.org/hardware/edgeconnector/ | micro:bit pinouts |
https://microbit-micropython.readthedocs.io/en/v2-docs/neopixel.html | micro:bit Python NeoPixel |
https://docs.python.org/3.4/ | Python 3.4 documentation |
#microbit #embedded #Python