Created
June 22, 2023 19:15
-
-
Save nooitaf/1b1693047f44ee3c0099a131eabf0a59 to your computer and use it in GitHub Desktop.
neopixel pico pi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Example showing how functions, that accept tuples of rgb values, | |
# simplify working with gradients | |
import time | |
import random | |
import math | |
from neopixel import Neopixel | |
from machine import Pin | |
push_button = Pin(13, Pin.IN) # 13 number pin is input | |
numpix = 27 | |
strip = Neopixel(numpix, 0, 0, "RGB") | |
class Pixel: | |
def __init__(self,color,brightness): | |
self.color = (255,0,0) | |
self.brightnessvalue = 50 | |
def brightness(self, brightness=None): | |
if brightness == None: | |
return self.brightnessvalue | |
else: | |
if brightness < 1: | |
self.brightnessvalue = 1 | |
elif brightness > 255: | |
self.brightnessvalue = 255 | |
else: | |
self.brightnessvalue = brightness | |
def colorWithBrightness(self): | |
r = round(self.color[0] * self.brightness()/255) | |
g = round(self.color[1] * self.brightness()/255) | |
b = round(self.color[2] * self.brightness()/255) | |
return (r,g,b) | |
pixels = [] | |
for i in range(numpix): | |
pixel = Pixel((255,255,0),20) | |
pixels.append(pixel) | |
# strip = Neopixel(numpix, 0, 0, "GRBW") | |
red = (255, 0, 0) | |
orange = (255, 50, 0) | |
yellow = (255, 100, 0) | |
green = (0, 255, 0) | |
blue = (0, 0, 255) | |
indigo = (100, 0, 90) | |
violet = (200, 0, 100) | |
colors_rgb = [red, orange, yellow, green, blue, indigo, violet] | |
# same colors as normaln rgb, just 0 added at the end | |
colors_rgbw = [color+tuple([0]) for color in colors_rgb] | |
colors_rgbw.append((0, 0, 0, 255)) | |
# uncomment colors_rgbw if you have RGBW strip | |
colors = colors_rgb | |
# colors = colors_rgbw | |
state = random.randint(1, 5) | |
#print("state",state) | |
speed = 0.043 | |
# rgb_light_still = (204,252,22) | |
BRIGHTNESS = 0 | |
BRIGHTNESS_MAX = 100 | |
BRIGHTNESS_SPEED = 0.5 | |
def setPixels(): | |
i = 0 | |
for pixel in pixels: | |
pixel.brightness(BRIGHTNESS) | |
strip.set_pixel(i, pixel.colorWithBrightness()) | |
i += 1 | |
def updatePixel(idx,col): | |
pixels[idx].color = col | |
def rotatePixels(dir): | |
if dir == 'L': | |
globals()['pixels'] = pixels[-1:] + pixels[:-1] | |
if dir == 'R': | |
globals()['pixels'] = pixels[1:] + pixels[:1] | |
def createPixelGradient(pixel1, pixel2, left_rgb_w, right_rgb_w): | |
if pixel2 - pixel1 == 0: | |
return | |
right_pixel = max(pixel1, pixel2) | |
left_pixel = min(pixel1, pixel2) | |
for i in range(right_pixel - left_pixel + 1): | |
fraction = i / (right_pixel - left_pixel) | |
red = round((right_rgb_w[0] - left_rgb_w[0]) * fraction + left_rgb_w[0]) | |
green = round((right_rgb_w[1] - left_rgb_w[1]) * fraction + left_rgb_w[1]) | |
blue = round((right_rgb_w[2] - left_rgb_w[2]) * fraction + left_rgb_w[2]) | |
# if it's (r, g, b, w) | |
if len(left_rgb_w) == 4 and 'W' in self.mode: | |
white = round((right_rgb_w[3] - left_rgb_w[3]) * fraction + left_rgb_w[3]) | |
updatePixel(left_pixel + i, (red, green, blue, white)) | |
else: | |
updatePixel(left_pixel + i, (red, green, blue)) | |
def rainbow(): | |
huestep = round((8*8*8*8*16)/numpix) | |
for i in range(numpix): | |
hue = huestep * i | |
updatePixel(i,strip.colorHSV(hue,255,255)) | |
# ABSOLUTELY SCUFFED SHIT | |
# | |
# | |
# | |
sinsteplength = 4 | |
sinsteps = [] | |
for i in range(sinsteplength): | |
sinsteps.append(math.sin(random.uniform(-math.pi/2,math.pi/2))) | |
def updateSinSteps(): | |
# sinsteplength = globals()['sinsteplength'] | |
# sinsteps = globals()['sinsteps'] | |
for i in range(sinsteplength): | |
newstep = sinsteps[i] + random.uniform(-0.03,0.03) #math.sin(random.uniform(-math.pi/2,math.pi/2)) | |
if newstep < -1: | |
newstep = -1 | |
if newstep > 1: | |
newstep = 1 | |
sinsteps[i] = newstep | |
# globals()['sinsteps'] = sinsteps | |
def rainbowSpecial(): | |
# sinsteplength = globals()['sinsteplength'] | |
# sinsteps = globals()['sinsteps'] | |
# print(sinsteps) | |
lastcolor = (0,0,0) | |
lastp2 = 0 | |
for i in range(sinsteplength): | |
hue = round((sinsteps[i] + 1) * 8*8*8*8*16) | |
color = strip.colorHSV(hue,255,255) | |
p1 = i*round(numpix/sinsteplength) | |
p2 = p1 + round(numpix/sinsteplength) -1 | |
if p2 >= numpix: | |
p2 = numpix -1 | |
createPixelGradient(p1,p2,color,lastcolor) | |
lastcolor = color | |
# print(p2) | |
updateSinSteps() | |
# print(sinsteps) | |
# print(math.sin(math.pi)) | |
# steps = 8 | |
# huestep = round((8*8*8*8*16)/numpix) | |
# step = 0 | |
# for i in range(numpix): | |
# step += 1 | |
# if step > steps: | |
# step = 0 | |
# hue = huestep * step | |
# updatePixel(i,strip.colorHSV(hue,255,255)) | |
state = random.randint(1,7) | |
# state = 7 | |
state_last = 0 | |
RAMPSTEPS = round(BRIGHTNESS_MAX/BRIGHTNESS_SPEED) | |
BRIGHTNESS = 0 | |
STATETIMER = 0 | |
STATETIMER_MAX = RAMPSTEPS*2 + 500 | |
RANDOMHUE = 0 | |
while True: | |
# button stuff | |
logic_state = push_button.value() | |
if logic_state == True: | |
BRIGHTNESS = BRIGHTNESS_MAX | |
STATETIMER = STATETIMER_MAX | |
# state check | |
if STATETIMER >= STATETIMER_MAX: | |
while state == state_last: | |
state = random.randint(1,5) | |
STATETIMER = 0 | |
if BRIGHTNESS != BRIGHTNESS_MAX: | |
BRIGHTNESS = 0 | |
if state != state_last: | |
hue = random.randint(0,8*8*8*8*16) | |
rgb_light_still = strip.colorHSV(hue,255,255) | |
# print(state) | |
if state == 1: | |
col = rgb_light_still | |
for i in range(numpix): | |
updatePixel(i,col) | |
if state == 2: | |
rainbow() | |
speed = 0.043 | |
if state == 3: | |
for i in range(numpix): | |
on = (i % 7) | |
col = (0,0,0) | |
if not on: | |
col = rgb_light_still | |
updatePixel(i,col) | |
speed = 0.08 | |
if state == 4: | |
for i in range(numpix): | |
on = (i % 3) | |
col = (0,0,0) | |
if not on: | |
col = rgb_light_still | |
updatePixel(i,col) | |
speed = 0.08 | |
if state == 5: | |
for i in range(numpix): | |
on = (i % 2) | |
col = (0,0,0) | |
if not on: | |
col = rgb_light_still | |
updatePixel(i,col) | |
speed = 0.08 | |
if state == 6: | |
for i in range(numpix): | |
col = (0,0,0) | |
if i == 1: | |
col = rgb_light_still | |
updatePixel(i,col) | |
speed = 0.04 | |
if state == 7: | |
RANDOMHUE = random.randint(0,8*8*8*8*16) | |
if state == 8: | |
rainbowSpecial() | |
state_last = state | |
STATETIMER += 1 | |
ramp_up = True | |
if STATETIMER > STATETIMER_MAX - RAMPSTEPS: | |
ramp_up = False | |
if ramp_up == True and BRIGHTNESS < BRIGHTNESS_MAX: | |
BRIGHTNESS += BRIGHTNESS_SPEED | |
if ramp_up == False and BRIGHTNESS > 0: | |
BRIGHTNESS -= BRIGHTNESS_SPEED | |
# print(state,BRIGHTNESS, STATETIMER,RAMPSTEPS) | |
if state == 1: | |
rotatePixels('L') | |
elif state == 2: # rainbow | |
rotatePixels('L') | |
elif state == 3: | |
rotatePixels('L') | |
elif state == 4: | |
rotatePixels('R') | |
elif state == 5: | |
rotatePixels('L') | |
elif state == 6: | |
rotatePixels('L') | |
elif state == 7: | |
for i in range(numpix): | |
updatePixel(i,strip.colorHSV(RANDOMHUE,255,255)) | |
speed = 0.04 | |
RANDOMHUE += 200 | |
if RANDOMHUE >= 8*8*8*8*16: | |
RANDOMHUE = 0 | |
else: | |
rotatePixels('L') | |
setPixels() | |
time.sleep(speed) | |
strip.show() | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import array, time | |
from machine import Pin | |
import rp2 | |
# PIO state machine for RGB. Pulls 24 bits (rgb -> 3 * 8bit) automatically | |
@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=24) | |
def ws2812(): | |
T1 = 2 | |
T2 = 5 | |
T3 = 3 | |
wrap_target() | |
label("bitloop") | |
out(x, 1) .side(0) [T3 - 1] | |
jmp(not_x, "do_zero") .side(1) [T1 - 1] | |
jmp("bitloop") .side(1) [T2 - 1] | |
label("do_zero") | |
nop().side(0) [T2 - 1] | |
wrap() | |
# PIO state machine for RGBW. Pulls 32 bits (rgbw -> 4 * 8bit) automatically | |
@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=32) | |
def sk6812(): | |
T1 = 2 | |
T2 = 5 | |
T3 = 3 | |
wrap_target() | |
label("bitloop") | |
out(x, 1) .side(0) [T3 - 1] | |
jmp(not_x, "do_zero") .side(1) [T1 - 1] | |
jmp("bitloop") .side(1) [T2 - 1] | |
label("do_zero") | |
nop() .side(0) [T2 - 1] | |
wrap() | |
# Delay here is the reset time. You need a pause to reset the LED strip back to the initial LED | |
# however, if you have quite a bit of processing to do before the next time you update the strip | |
# you could put in delay=0 (or a lower delay) | |
# | |
# Class supports different order of individual colors (GRB, RGB, WRGB, GWRB ...). In order to achieve | |
# this, we need to flip the indexes: in 'RGBW', 'R' is on index 0, but we need to shift it left by 3 * 8bits, | |
# so in it's inverse, 'WBGR', it has exactly right index. Since micropython doesn't have [::-1] and recursive rev() | |
# isn't too efficient we simply do that by XORing (operator ^) each index with 3 (0b11) to make this flip. | |
# When dealing with just 'RGB' (3 letter string), this means same but reduced by 1 after XOR!. | |
# Example: in 'GRBW' we want final form of 0bGGRRBBWW, meaning G with index 0 needs to be shifted 3 * 8bit -> | |
# 'G' on index 0: 0b00 ^ 0b11 -> 0b11 (3), just as we wanted. | |
# Same hold for every other index (and - 1 at the end for 3 letter strings). | |
class Neopixel: | |
def __init__(self, num_leds, state_machine, pin, mode="RGB", delay=0.0001): | |
self.pixels = array.array("I", [0 for _ in range(num_leds)]) | |
self.mode = set(mode) # set for better performance | |
if 'W' in self.mode: | |
# RGBW uses different PIO state machine configuration | |
self.sm = rp2.StateMachine(state_machine, sk6812, freq=8000000, sideset_base=Pin(pin)) | |
# dictionary of values required to shift bit into position (check class desc.) | |
self.shift = {'R': (mode.index('R') ^ 3) * 8, 'G': (mode.index('G') ^ 3) * 8, | |
'B': (mode.index('B') ^ 3) * 8, 'W': (mode.index('W') ^ 3) * 8} | |
else: | |
self.sm = rp2.StateMachine(state_machine, ws2812, freq=8000000, sideset_base=Pin(pin)) | |
self.shift = {'R': ((mode.index('R') ^ 3) - 1) * 8, 'G': ((mode.index('G') ^ 3) - 1) * 8, | |
'B': ((mode.index('B') ^ 3) - 1) * 8, 'W': 0} | |
self.sm.active(1) | |
self.num_leds = num_leds | |
self.delay = delay | |
self.brightnessvalue = 255 | |
# Set the overal value to adjust brightness when updating leds | |
def brightness(self, brightness=None): | |
if brightness == None: | |
return self.brightnessvalue | |
else: | |
if brightness < 1: | |
brightness = 1 | |
if brightness > 255: | |
brightness = 255 | |
self.brightnessvalue = brightness | |
# Create a gradient with two RGB colors between "pixel1" and "pixel2" (inclusive) | |
# Function accepts two (r, g, b) / (r, g, b, w) tuples | |
def set_pixel_line_gradient(self, pixel1, pixel2, left_rgb_w, right_rgb_w): | |
if pixel2 - pixel1 == 0: | |
return | |
right_pixel = max(pixel1, pixel2) | |
left_pixel = min(pixel1, pixel2) | |
for i in range(right_pixel - left_pixel + 1): | |
fraction = i / (right_pixel - left_pixel) | |
red = round((right_rgb_w[0] - left_rgb_w[0]) * fraction + left_rgb_w[0]) | |
green = round((right_rgb_w[1] - left_rgb_w[1]) * fraction + left_rgb_w[1]) | |
blue = round((right_rgb_w[2] - left_rgb_w[2]) * fraction + left_rgb_w[2]) | |
# if it's (r, g, b, w) | |
if len(left_rgb_w) == 4 and 'W' in self.mode: | |
white = round((right_rgb_w[3] - left_rgb_w[3]) * fraction + left_rgb_w[3]) | |
self.set_pixel(left_pixel + i, (red, green, blue, white)) | |
else: | |
self.set_pixel(left_pixel + i, (red, green, blue)) | |
# Set an array of pixels starting from "pixel1" to "pixel2" (inclusive) to the desired color. | |
# Function accepts (r, g, b) / (r, g, b, w) tuple | |
def set_pixel_line(self, pixel1, pixel2, rgb_w): | |
for i in range(pixel1, pixel2 + 1): | |
self.set_pixel(i, rgb_w) | |
# Set red, green and blue value of pixel on position <pixel_num> | |
# Function accepts (r, g, b) / (r, g, b, w) tuple | |
def set_pixel(self, pixel_num, rgb_w): | |
pos = self.shift | |
red = round(rgb_w[0] * (self.brightness() / 255)) | |
green = round(rgb_w[1] * (self.brightness() / 255)) | |
blue = round(rgb_w[2] * (self.brightness() / 255)) | |
white = 0 | |
# if it's (r, g, b, w) | |
if len(rgb_w) == 4 and 'W' in self.mode: | |
white = round(rgb_w[3] * (self.brightness() / 255)) | |
self.pixels[pixel_num] = white << pos['W'] | blue << pos['B'] | red << pos['R'] | green << pos['G'] | |
# Converts HSV color to rgb tuple and returns it | |
# Function accepts integer values for <hue>, <saturation> and <value> | |
# The logic is almost the same as in Adafruit NeoPixel library: | |
# https://github.com/adafruit/Adafruit_NeoPixel so all the credits for that | |
# go directly to them (license: https://github.com/adafruit/Adafruit_NeoPixel/blob/master/COPYING) | |
def colorHSV(self, hue, sat, val): | |
if hue >= 65536: | |
hue %= 65536 | |
hue = (hue * 1530 + 32768) // 65536 | |
if hue < 510: | |
b = 0 | |
if hue < 255: | |
r = 255 | |
g = hue | |
else: | |
r = 510 - hue | |
g = 255 | |
elif hue < 1020: | |
r = 0 | |
if hue < 765: | |
g = 255 | |
b = hue - 510 | |
else: | |
g = 1020 - hue | |
b = 255 | |
elif hue < 1530: | |
g = 0 | |
if hue < 1275: | |
r = hue - 1020 | |
b = 255 | |
else: | |
r = 255 | |
b = 1530 - hue | |
else: | |
r = 255 | |
g = 0 | |
b = 0 | |
v1 = 1 + val | |
s1 = 1 + sat | |
s2 = 255 - sat | |
r = ((((r * s1) >> 8) + s2) * v1) >> 8 | |
g = ((((g * s1) >> 8) + s2) * v1) >> 8 | |
b = ((((b * s1) >> 8) + s2) * v1) >> 8 | |
return r, g, b | |
# Rotate <num_of_pixels> pixels to the left | |
def rotate_left(self, num_of_pixels): | |
if num_of_pixels == None: | |
num_of_pixels = 1 | |
self.pixels = self.pixels[num_of_pixels:] + self.pixels[:num_of_pixels] | |
# Rotate <num_of_pixels> pixels to the right | |
def rotate_right(self, num_of_pixels): | |
if num_of_pixels == None: | |
num_of_pixels = 1 | |
num_of_pixels = -1 * num_of_pixels | |
self.pixels = self.pixels[num_of_pixels:] + self.pixels[:num_of_pixels] | |
# Update pixels | |
def show(self): | |
# If mode is RGB, we cut 8 bits of, otherwise we keep all 32 | |
cut = 8 | |
if 'W' in self.mode: | |
cut = 0 | |
for i in range(self.num_leds): | |
self.sm.put(self.pixels[i], cut) | |
time.sleep(self.delay) | |
# Set all pixels to given rgb values | |
# Function accepts (r, g, b) / (r, g, b, w) | |
def fill(self, rgb_w): | |
for i in range(self.num_leds): | |
self.set_pixel(i, rgb_w) | |
time.sleep(self.delay) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import array, time | |
from machine import Pin | |
import rp2 | |
@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=24) | |
def ws2812(): | |
T1 = 2 | |
T2 = 5 | |
T3 = 3 | |
wrap_target() | |
label("bitloop") | |
out(x, 1) .side(0) [T3 - 1] | |
jmp(not_x, "do_zero") .side(1) [T1 - 1] | |
jmp("bitloop") .side(1) [T2 - 1] | |
label("do_zero") | |
nop() .side(0) [T2 - 1] | |
wrap() | |
#delay here is the reset time. You need a pause to reset the LED strip back to the initial LED | |
#however, if you have quite a bit of processing to do before the next time you update the strip | |
#you could put in delay=0 (or a lower delay) | |
class ws2812b: | |
def __init__(self, num_leds, state_machine, pin, delay=0.001): | |
self.pixels = array.array("I", [0 for _ in range(num_leds)]) | |
self.sm = rp2.StateMachine(state_machine, ws2812, freq=8000000, sideset_base=Pin(pin)) | |
self.sm.active(1) | |
self.num_leds = num_leds | |
self.delay = delay | |
self.brightnessvalue = 255 | |
# Set the overal value to adjust brightness when updating leds | |
def brightness(self, brightness = None): | |
if brightness == None: | |
return self.brightnessvalue | |
else: | |
if (brightness < 1): | |
brightness = 1 | |
if (brightness > 255): | |
brightness = 255 | |
self.brightnessvalue = brightness | |
# Create a gradient with two RGB colors between "pixel1" and "pixel2" (inclusive) | |
def set_pixel_line_gradient(self, pixel1, pixel2, left_red, left_green, left_blue, right_red, right_green, right_blue): | |
if pixel2 - pixel1 == 0: return | |
right_pixel = max(pixel1, pixel2) | |
left_pixel = min(pixel1, pixel2) | |
for i in range(right_pixel - left_pixel + 1): | |
fraction = i / (right_pixel - left_pixel) | |
red = round((right_red - left_red) * fraction + left_red) | |
green = round((right_green - left_green) * fraction + left_green) | |
blue = round((right_blue - left_blue) * fraction + left_blue) | |
self.set_pixel(left_pixel + i, red, green, blue) | |
# Set an array of pixels starting from "pixel1" to "pixel2" to the desired color. | |
def set_pixel_line(self, pixel1, pixel2, red, green, blue): | |
for i in range(pixel1, pixel2+1): | |
self.set_pixel(i, red, green, blue) | |
def set_pixel(self, pixel_num, red, green, blue): | |
# Adjust color values with brightnesslevel | |
blue = round(blue * (self.brightness() / 255)) | |
red = round(red * (self.brightness() / 255)) | |
green = round(green * (self.brightness() / 255)) | |
self.pixels[pixel_num] = blue | red << 8 | green << 16 | |
# rotate x pixels to the left | |
def rotate_left(self, num_of_pixels): | |
if num_of_pixels == None: | |
num_of_pixels = 1 | |
self.pixels = self.pixels[num_of_pixels:] + self.pixels[:num_of_pixels] | |
# rotate x pixels to the right | |
def rotate_right(self, num_of_pixels): | |
if num_of_pixels == None: | |
num_of_pixels = 1 | |
num_of_pixels = -1 * num_of_pixels | |
self.pixels = self.pixels[num_of_pixels:] + self.pixels[:num_of_pixels] | |
def show(self): | |
for i in range(self.num_leds): | |
self.sm.put(self.pixels[i],8) | |
time.sleep(self.delay) | |
def fill(self, red, green, blue): | |
for i in range(self.num_leds): | |
self.set_pixel(i, red, green, blue) | |
time.sleep(self.delay) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment