Skip to content

Commit 83e706e

Browse files
authored
Merge pull request #2703 from adafruit/neopixel_fidget
adding neopixel fidget spinner code
2 parents ac9f36c + 3c63086 commit 83e706e

File tree

1 file changed

+190
-0
lines changed

1 file changed

+190
-0
lines changed

NeoPixel_Fidget_Spinner/code.py

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
4+
import time
5+
import random
6+
import board
7+
import neopixel
8+
from adafruit_seesaw import seesaw, rotaryio, digitalio
9+
from adafruit_debouncer import Button
10+
from rainbowio import colorwheel
11+
from adafruit_led_animation import color
12+
13+
# NeoPixel ring setup. Update num_pixels if using a different ring.
14+
num_pixels = 24
15+
pixels = neopixel.NeoPixel(board.D5, num_pixels, auto_write=False)
16+
17+
i2c = board.STEMMA_I2C()
18+
seesaw = seesaw.Seesaw(i2c, addr=0x49)
19+
20+
buttons = []
21+
for b in range(1, 6):
22+
seesaw.pin_mode(b, seesaw.INPUT_PULLUP)
23+
ss_pin = digitalio.DigitalIO(seesaw, b)
24+
button = Button(ss_pin, long_duration_ms=1000)
25+
buttons.append(button)
26+
27+
encoder = rotaryio.IncrementalEncoder(seesaw)
28+
last_position = 0
29+
30+
button_names = ["Select", "Up", "Left", "Down", "Right"]
31+
colors = [color.RED, color.YELLOW, color.ORANGE, color.GREEN,
32+
color.TEAL, color.CYAN, color.BLUE, color.PURPLE, color.MAGENTA]
33+
34+
# rainbow cycle function
35+
def rainbow_cycle(wait):
36+
for j in range(255):
37+
for i in range(num_pixels):
38+
rc_index = (i * 256 // num_pixels) + j
39+
pixels[i] = colorwheel(rc_index & 255)
40+
pixels.show()
41+
time.sleep(wait)
42+
43+
color_index = 0
44+
game_mode = False
45+
pixel = 0
46+
num = 0
47+
last_num = 0
48+
now_color = 0
49+
next_color = 1
50+
speed = 0.1
51+
level = 0.005
52+
final_level = 0.001
53+
new_target = True
54+
55+
while True:
56+
if not game_mode:
57+
for b in range(5):
58+
buttons[b].update()
59+
if buttons[b].released or buttons[b].pressed:
60+
pixels.fill(color.BLACK)
61+
position = encoder.position
62+
if position != last_position:
63+
pixels[last_position % num_pixels] = color.BLACK
64+
pixels[position % num_pixels] = colors[color_index]
65+
# print("Position: {}".format(position))
66+
last_position = position
67+
68+
if buttons[0].pressed:
69+
# print("Center button!")
70+
pixels.fill(colors[color_index])
71+
72+
elif buttons[0].long_press:
73+
# print("long press detected")
74+
pixels.fill(color.BLACK)
75+
new_target = True
76+
game_mode = True
77+
78+
if buttons[1].pressed:
79+
# print("Up button!")
80+
color_index = (color_index + 1) % len(colors)
81+
pixels[10] = colors[color_index]
82+
83+
if buttons[2].pressed:
84+
# print("Left button!")
85+
color_index = (color_index + 1) % len(colors)
86+
pixels[4] = colors[color_index]
87+
88+
if buttons[3].pressed:
89+
# print("Down button!")
90+
color_index = (color_index - 1) % len(colors)
91+
pixels[22] = colors[color_index]
92+
93+
if buttons[4].pressed:
94+
# print("Right button!")
95+
color_index = (color_index - 1) % len(colors)
96+
pixels[16] = colors[color_index]
97+
98+
pixels.show()
99+
if game_mode:
100+
buttons[0].update()
101+
if buttons[0].long_press:
102+
# print("long press detected")
103+
pixels.fill(color.BLACK)
104+
pixels.show()
105+
game_mode = False
106+
pixels.fill(colors[color_index])
107+
# if new level starting..
108+
if new_target:
109+
if buttons[0].released:
110+
# randomize target location
111+
y = random.randint(5, 22)
112+
x = y - 1
113+
z = y + 1
114+
new_target = False
115+
pixels[x] = color.WHITE
116+
pixels[y] = colors[next_color]
117+
pixels[z] = color.WHITE
118+
else:
119+
# delay without time.sleep()
120+
if (pixel + speed) < time.monotonic():
121+
# turn off pixel behind chaser
122+
if num > 0:
123+
last_num = num - 1
124+
pixels[last_num] = color.BLACK
125+
pixels.show()
126+
# keep target pixels their colors when the chaser passes
127+
if last_num in (x, y, z):
128+
pixels[x] = color.WHITE
129+
pixels[y] = colors[next_color]
130+
pixels[z] = color.WHITE
131+
# move chaser pixel by one
132+
if num < num_pixels:
133+
pixels[num] = colors[now_color]
134+
pixels.show()
135+
num += 1
136+
# send chaser back to the beginning of the circle
137+
if num == num_pixels:
138+
last_num = num - 1
139+
pixels[last_num] = color.BLACK
140+
pixels.show()
141+
num = 0
142+
# if the chaser hits the target...
143+
if last_num in [x, y, z] and not buttons[0].value:
144+
# fills with the next color
145+
pixels.fill(colors[next_color])
146+
pixels.show()
147+
# chaser resets
148+
num = 0
149+
time.sleep(0.5)
150+
pixels.fill(color.BLACK)
151+
pixels.show()
152+
# speed increases for next level
153+
speed = speed - level
154+
# color updates
155+
next_color = (next_color + 1) % 9
156+
now_color = (now_color + 1) % 9
157+
# setup for new target
158+
new_target = True
159+
# if the chaser misses the target...
160+
if last_num not in [x, y, z] and not buttons[0].value:
161+
# fills with current chaser color
162+
pixels.fill(color.BLACK)
163+
pixels.show()
164+
# chaser is reset
165+
num = 0
166+
# speed is reset to default
167+
speed = 0.1
168+
# colors are reset
169+
next_color = 1
170+
now_color = 0
171+
# setup for new target
172+
new_target = True
173+
# when you have beaten all the levels...
174+
if speed < final_level:
175+
# rainbows!
176+
rainbow_cycle(0.01)
177+
time.sleep(1)
178+
# chaser is reset
179+
num = 0
180+
pixels.fill(color.BLACK)
181+
pixels.show()
182+
# speed is reset to default
183+
speed = 0.1
184+
# colors are reset
185+
next_color = 1
186+
now_color = 0
187+
# setup for new target
188+
new_target = True
189+
# time.monotonic() is reset for the delay
190+
pixel = time.monotonic()

0 commit comments

Comments
 (0)