|
| 1 | +""" |
| 2 | +LED Snowboard with Feather M4 and PropMaker Wing |
| 3 | +Adafruit invests time and resources providing this open source code. |
| 4 | +Please support Adafruit and open source hardware by purchasing |
| 5 | +products from Adafruit! |
| 6 | +Written by Erin St Blaine & Limor Fried for Adafruit Industries |
| 7 | +Copyright (c) 2020-2021 Adafruit Industries |
| 8 | +Licensed under the MIT license. |
| 9 | +All text above must be included in any redistribution. |
| 10 | +
|
| 11 | +
|
| 12 | +
|
| 13 | +""" |
| 14 | +# pylint: disable=import-error |
| 15 | +# pylint: disable=no-member |
| 16 | +import time |
| 17 | +import board |
| 18 | +import digitalio |
| 19 | +from digitalio import DigitalInOut, Direction, Pull |
| 20 | +import adafruit_lis3dh |
| 21 | +import neopixel |
| 22 | +from adafruit_led_animation.helper import PixelMap |
| 23 | +from adafruit_led_animation.sequence import AnimationSequence |
| 24 | +from adafruit_led_animation.group import AnimationGroup |
| 25 | +from adafruit_led_animation.animation.sparkle import Sparkle |
| 26 | +from adafruit_led_animation.animation.rainbow import Rainbow |
| 27 | +from adafruit_led_animation.animation.rainbowchase import RainbowChase |
| 28 | +from adafruit_led_animation.animation.rainbowcomet import RainbowComet |
| 29 | +from adafruit_led_animation.animation.solid import Solid |
| 30 | +from adafruit_led_animation.animation.chase import Chase |
| 31 | +from adafruit_led_animation.animation.comet import Comet |
| 32 | +from adafruit_led_animation.color import colorwheel |
| 33 | +from adafruit_led_animation.color import ( |
| 34 | + BLACK, |
| 35 | + RED, |
| 36 | + GREEN, |
| 37 | + ORANGE, |
| 38 | + BLUE, |
| 39 | + PURPLE, |
| 40 | + WHITE, |
| 41 | +) |
| 42 | + |
| 43 | +btn = DigitalInOut(board.A1) |
| 44 | +btn.direction = Direction.INPUT |
| 45 | +btn.pull = Pull.UP |
| 46 | + |
| 47 | +prev_state = btn.value |
| 48 | + |
| 49 | +THRESHOLD = -1 #shake threshold |
| 50 | +CARVE_THRESHOLD = 5 |
| 51 | + |
| 52 | +# Set to the length in seconds for the animations |
| 53 | +POWER_ON_DURATION = 2 |
| 54 | + |
| 55 | +NUM_PIXELS = 211 # Number of pixels used in project |
| 56 | +NEOPIXEL_PIN = board.D5 |
| 57 | +POWER_PIN = board.D10 |
| 58 | + |
| 59 | +enable = digitalio.DigitalInOut(POWER_PIN) |
| 60 | +enable.direction = digitalio.Direction.OUTPUT |
| 61 | +enable.value = False |
| 62 | + |
| 63 | + |
| 64 | +# Set up accelerometer on I2C bus, 4G range: |
| 65 | +i2c = board.I2C() |
| 66 | +accel = adafruit_lis3dh.LIS3DH_I2C(i2c) |
| 67 | +accel.range = adafruit_lis3dh.RANGE_4_G |
| 68 | +accel.set_tap(2, 15) |
| 69 | + |
| 70 | +pixels = neopixel.NeoPixel(NEOPIXEL_PIN, NUM_PIXELS, brightness=1, auto_write=False) |
| 71 | +pixels.fill(0) # NeoPixels off ASAP on startup |
| 72 | +pixels.show() |
| 73 | + |
| 74 | + |
| 75 | +#PIXEL MAPS: Used for reordering pixels so the animations can run in different configurations. |
| 76 | +#My LED strips inside the neck are accidentally swapped left-right, |
| 77 | +#so these maps also correct for that |
| 78 | + |
| 79 | + |
| 80 | +#Bottom up along both sides at once |
| 81 | +pixel_map_right = PixelMap(pixels, [ |
| 82 | + 150, 151, 152, 149, 148, 147, 146, 145, 144, 143, 142, |
| 83 | + 141, 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, |
| 84 | + 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 120, |
| 85 | + 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, |
| 86 | + 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, |
| 87 | + 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, |
| 88 | + 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, |
| 89 | + 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, |
| 90 | + 54, 53, 52, 51, 50, 49, 48, 47, 46, |
| 91 | + ], individual_pixels=True) |
| 92 | + |
| 93 | +#Starts at the bottom and goes around clockwise |
| 94 | +pixel_map_left = PixelMap(pixels, [ |
| 95 | + 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, |
| 96 | + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, |
| 97 | + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, |
| 98 | + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, |
| 99 | + 203, 204, 205, 206, 207, 208, 209, 210, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, |
| 100 | + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, |
| 101 | + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, |
| 102 | + ], individual_pixels=True) |
| 103 | + |
| 104 | +#Radiates from the center outwards like a starburst |
| 105 | +pixel_map_radiate = PixelMap(pixels, [ |
| 106 | + 206, 98, 205, 99, 207, 97, 204, 100, 208, 96, 203, 101, 209, |
| 107 | + 95, 202, 102, 210, 94, 0, 93, 92, 201, 103, 1, 91, 200, 104, |
| 108 | + 2, 90, 199, 105, 3, 89, 198, 106, 4, 88, 197, 107, 5, 87, 196, |
| 109 | + 108, 6, 86, 195, 109, 7, 85, 194, 110, 8, 84, 193, 111, 9, 83, |
| 110 | + 192, 112, 10, 82, 191, 113, 11, 81, 190, 114, 12, 80, 189, 115, |
| 111 | + 13, 79, 188, 116, 14, 78, 187, 117, 15, 77, 186, 118, 16, 76, 185, |
| 112 | + 119, 17, 75, 184, 120, 18, 74, 183, 121, 19, 73, 182, 122, 20, 72, |
| 113 | + 181, 123, 21, 71, 180, 124, 22, 70, 179, 125, 23, 69, 178, 126, 24, |
| 114 | + 68, 177, 127, 25, 67, 176, 128, 26, 66, 175, 129, 27, 65, 174, 130, |
| 115 | + 28, 64, 173, 131, 29, 63, 172, 132, 30, 62, 171, 133, 31, 61, 170, 134, 32, |
| 116 | + 60, 169, 135, 33, 69, 168, 136, 34, 58, 167, 137, 35, 57, 166, 138, 36, 56, |
| 117 | + 165, 139, 37, 55, 164, 140, 38, 54, 163, 141, 39, 53, 162, 142, 40, 52, 161, |
| 118 | + 143, 41, 51, 160, 144, 42, 50, 159, 145, 43, 49, 158, 146, 44, 48, 157, 147, |
| 119 | + 45, 47, 156, 148, 46, 46, 155, 149, 47, 154, 149, 153, 150, 152, 151, |
| 120 | + ], individual_pixels=True) |
| 121 | + |
| 122 | +#Top down along both sides at once |
| 123 | +pixel_map_sweep = PixelMap(pixels, [ |
| 124 | + 151, 152, 150, 153, 149, 154, 148, 155, 147, 156, 146, 157, 145, 158, |
| 125 | + 144, 159, 143, 160, 142, 161, 141, 162, 140, 163, 139, 164, 138, 165, |
| 126 | + 137, 166, 136, 167, 135, 168, 134, 169, 133, 170, 132, 171, 131, 172, |
| 127 | + 130, 173, 129, 174, 128, 175, 127, 176, 126, 177, 125, 178, 124, 179, |
| 128 | + 123, 180, 122, 181, 121, 182, 120, 183, 119, 184, 118, 185, 117, 186, |
| 129 | + 116, 187, 115, 188, 114, 189, 113, 190, 112, 191, 111, 192, 110, 193, |
| 130 | + 109, 194, 108, 195, 107, 196, 106, 197, 105, 198, 104, 199, 103, 200, |
| 131 | + 102, 201, 101, 202, 100, 203, 99, 204, 98, 205, 97, 206, 96, 207, 95, |
| 132 | + 208, 94, 209, 93, 210, 92, 91, 0, 90, 1, 89, 2, 88, 3, 87, 4, 86, 5, 85, |
| 133 | + 6, 84, 7, 83, 8, 82, 9, 81, 10, 80, 11, 79, 12, 78, 13, 77, 14, 76, 15, |
| 134 | + 75, 16, 74, 17, 73, 18, 72, 19, 71, 20, 70, 21, 69, 22, 68, 23, 67, 24, |
| 135 | + 66, 25, 65, 24, 64, 25, 63, 26, 62, 27, 61, 28, 60, 29, 59, 30, 58, 31, |
| 136 | + 57, 32, 56, 33, 55, 34, 54, 35, 53, 36, 52, 37, 51, 38, 50, 39, 49, 40, |
| 137 | + 48, 41, 47, 42, 46, 43, 45, 44, |
| 138 | + ], individual_pixels=True) |
| 139 | + |
| 140 | +pixel_map_tail = PixelMap(pixels, [ |
| 141 | + 15, 75, 16, 74, 17, 73, 18, 72, 19, 71, 20, 70, 21, 69, 22, 68, 23, 67, |
| 142 | + 24, 66, 25, 65, 24, 64, 25, 63, 26, 62, 27, 61, 28, 60, 29, 59, 30, 58, |
| 143 | + 31, 57, 32, 56, 33, 55, 34, 54, 35, 53, 36, 52, 37, 51, 38, 50, 39, 49, |
| 144 | + 40, 48, 41, 47, 42, 46, 43, 45, 44, |
| 145 | + ], individual_pixels=True) |
| 146 | + |
| 147 | +pixel_map = [ |
| 148 | + pixel_map_right, |
| 149 | + pixel_map_left, |
| 150 | + pixel_map_radiate, |
| 151 | + pixel_map_sweep, |
| 152 | + pixel_map_tail, |
| 153 | +] |
| 154 | + |
| 155 | + |
| 156 | +def power_on(duration): |
| 157 | + """ |
| 158 | + Animate NeoPixels for power on. |
| 159 | + """ |
| 160 | + start_time = time.monotonic() # Save start time |
| 161 | + while True: |
| 162 | + elapsed = time.monotonic() - start_time # Time spent |
| 163 | + if elapsed > duration: # Past duration? |
| 164 | + break # Stop animating |
| 165 | + powerup.animate() |
| 166 | + |
| 167 | + |
| 168 | +# Cusomize LED Animations ------------------------------------------------------ |
| 169 | +powerup = RainbowComet(pixel_map[3], speed=0, tail_length=25, bounce=False) |
| 170 | +rainbow = Rainbow(pixel_map[2], speed=0, period=6, name="rainbow", step=2.4) |
| 171 | +rainbow_chase = RainbowChase(pixels, speed=0, size=6, spacing=15, step=10) |
| 172 | +rainbow_chase2 = RainbowChase(pixels, speed=0, size=10, spacing=1, step=18, name="rainbow_chase2") |
| 173 | +chase = RainbowChase(pixel_map[3], speed=0, size=20, spacing=20) |
| 174 | +chase2 = Chase(pixels, speed=0.1, color=ORANGE, size=6, spacing=6) |
| 175 | +rainbow_comet = RainbowComet(pixel_map[2], speed=0, tail_length=200, bounce=True) |
| 176 | +rainbow_comet2 = RainbowComet( |
| 177 | + pixels, speed=0, tail_length=104, colorwheel_offset=80, bounce=True |
| 178 | + ) |
| 179 | +rainbow_comet3 = RainbowComet( |
| 180 | + pixel_map[2], speed=0, tail_length=80, colorwheel_offset=80, step=4, bounce=False |
| 181 | + ) |
| 182 | +strum = RainbowComet( |
| 183 | + pixel_map[3], speed=0, tail_length=50, bounce=False, colorwheel_offset=50, step=4 |
| 184 | + ) |
| 185 | +fuego = RainbowComet( |
| 186 | + pixel_map[4], speed=0.05, colorwheel_offset=40, step=2, tail_length=40 |
| 187 | + ) |
| 188 | +fuego2 = RainbowComet( |
| 189 | + pixel_map[4], speed=0.02, colorwheel_offset=40, step=2, tail_length=40 |
| 190 | + ) |
| 191 | +lava = Comet(pixel_map[4], speed=0, color=ORANGE, tail_length=40, bounce=False) |
| 192 | +sparkle = Sparkle(pixel_map[3], speed=0.05, color=BLUE, num_sparkles=10) |
| 193 | +sparkle2 = Sparkle(pixels, speed=0.05, color=PURPLE, num_sparkles=4) |
| 194 | +sparkle3 = Sparkle(pixels, speed=0, color=WHITE, num_sparkles=1) |
| 195 | +carve_left = Solid(pixel_map[0], color=GREEN) |
| 196 | +carve_right = Solid(pixel_map[1], color=RED) |
| 197 | +black_left = Solid(pixel_map[0], color=BLACK, name="BLACK") |
| 198 | +black_right = Solid(pixel_map[1], color=BLACK) |
| 199 | + |
| 200 | +# Animations Playlist - reorder as desired. AnimationGroups play at the same time |
| 201 | +animations = AnimationSequence( |
| 202 | + AnimationGroup( |
| 203 | + fuego, |
| 204 | + fuego2, |
| 205 | + lava, |
| 206 | + sparkle, |
| 207 | + ), |
| 208 | + chase, |
| 209 | + rainbow_chase2, |
| 210 | + rainbow, |
| 211 | + AnimationGroup( |
| 212 | + rainbow_comet, |
| 213 | + sparkle3, |
| 214 | + ), |
| 215 | + AnimationGroup( |
| 216 | + rainbow_comet2, |
| 217 | + sparkle3, |
| 218 | + ), |
| 219 | + AnimationGroup( |
| 220 | + sparkle, |
| 221 | + strum, |
| 222 | + ), |
| 223 | + AnimationGroup( |
| 224 | + sparkle2, |
| 225 | + rainbow_comet3, |
| 226 | + ), |
| 227 | + AnimationGroup( |
| 228 | + black_left, |
| 229 | + black_right, |
| 230 | + ), |
| 231 | + black_left, |
| 232 | + auto_clear=True, |
| 233 | + auto_reset=True, |
| 234 | +) |
| 235 | + |
| 236 | + |
| 237 | +MODE = 0 |
| 238 | +LASTMODE = 1 |
| 239 | +i = 0 |
| 240 | + |
| 241 | +# Main loop |
| 242 | +while True: |
| 243 | + i = (i + 0.5) % 256 # run from 0 to 255 |
| 244 | + TILT_COLOR = colorwheel(i) |
| 245 | + if MODE == 0: # If currently off... |
| 246 | + enable.value = True |
| 247 | + power_on(POWER_ON_DURATION) # Power up! |
| 248 | + MODE = LASTMODE |
| 249 | + |
| 250 | + elif MODE >= 1: # If not OFF MODE... |
| 251 | + # Read button |
| 252 | + cur_state = btn.value |
| 253 | + if cur_state != prev_state: |
| 254 | + if not cur_state: |
| 255 | + animations.next() |
| 256 | + print("BTN is down") |
| 257 | + else: |
| 258 | + print("BTN is up") |
| 259 | + prev_state = cur_state |
| 260 | + # Read accelerometer |
| 261 | + x, y, z = accel.acceleration |
| 262 | + accel_total = z # x=tilt, y=rotate |
| 263 | + accel_total_y = y # x=tilt, y=rotate |
| 264 | + print(accel_total_y) |
| 265 | + if accel_total > THRESHOLD: |
| 266 | + print("THRESHOLD: ", accel_total) |
| 267 | + if MODE == 1: |
| 268 | + animations.animate() |
| 269 | + if animations.current_animation.name == "BLACK": |
| 270 | + MODE = 2 |
| 271 | + if MODE == 2: |
| 272 | + if y > CARVE_THRESHOLD: |
| 273 | + black_right.animate() |
| 274 | + carve_left.animate() |
| 275 | + if y < (CARVE_THRESHOLD * -1): |
| 276 | + black_left.animate() |
| 277 | + carve_right.animate() |
| 278 | + #print (MODE) |
| 279 | + cur_state = btn.value |
| 280 | + if cur_state != prev_state: |
| 281 | + if not cur_state: |
| 282 | + MODE = 1 |
0 commit comments