Uppdatera trött reflexarmband med glada NeoPixlar

Reflexer är livsnödvändiga i vintermörkret, men med åren åldras de och kan behöva bytas ut. Här visar vi ett fiffigt sätt att återanvända en snap-on-reflex som mist sin lyster genom att bygga om den till ett ännu bättre och mycket roligare sätt att synas i mörkret. Samtidigt får du ett wearables-projekt som enkelt kan flyttas mellan olika plagg och användare.

Komponenter

Det mesta som behövs kan köpas i vår webshop.

 

Val av LED-list

Jag ville ha så många neopixlar som möjligt utan att fullständigt ruinera mig. Därför valde jag en medelväg: mini skinny NeoPixel med 60 LED/m. Jag fick plats med en meter delad i fyra delar på min reflex som är ca 34 cm lång och 3,5 cm bred. Här väljer man naturligtvis själv hur många rader man vill ha och hur tätt dioderna ska sitta. Det finns både billigare och dyrare alternativ.

Programmera Gemman

Gemma M0 programmeras annorlunda än tidigare generationer av Gemma. Det är bara att koppla in den till sin dator via USB så ska den dyka upp som en extern enhet. Öppna filen main.py som redan ska finnas och redigera i valfri texteditor. Programmet uppdateras i realtid varje gång du sparar. Du slipper alltså kompilera och ladda upp.

Programmet har nio olika lägen som man, i det färdiga armbandet, växlar mellan genom att trycka på knappen.

# NeoPixel bracelet

import board
import neopixel
import time

from digitalio import DigitalInOut, Direction, Pull
import board
import time
import random

class AniMode:
    all_modes = ['SEPARATE_RAINBOWS',
                 'ALL_THE_SAME_RAINBOW',
                 'WHITE_SPARKLE',
                 'RAINBOW_SPARKLE',
                 'WHITE_STRIPES',
                 'WHITE_BANDS',
                 'ALL_WHITE',
                 'ALL_ORANGE',
                 'ALL_BLUE']
    m = all_modes.index('WHITE_SPARKLE')

    def inc(self):
        self.m = (self.m + 1) % len(self.all_modes)

    def isMode(self, some_mode):
        return self.all_modes[self.m] == some_mode

class ModeButton:
    def __init__(self, pin):
        self.button = DigitalInOut(pin)
        self.button.direction = Direction.INPUT
        self.button.pull = Pull.UP

    def is_pressed(self):
        return not self.button.value

    def maybe_step_to_next_mode(self):
        if self.is_pressed():
            time.sleep(0.01)
            self.wait_until_button_released()
            animode.inc()
            return True
        else:
            return False

    def wait_until_button_released(self):
        while self.is_pressed():
            pass

    def wait_until_button_pressed(self):
        while not self.is_pressed():
            pass

led = DigitalInOut(board.D13)
led.direction = Direction.OUTPUT

button = ModeButton(board.D2)

pixpin = board.D1
numpix = 64
numrows = 4
numpix_per_row = numpix // numrows

strip = neopixel.NeoPixel(pixpin, numpix, brightness=0.02, auto_write=False)
sparkles = [-1 for x in range(10)]

animode = AniMode()

def make_random_color():
    return (random.randrange(0,255),
            random.randrange(0,255),
            random.randrange(0,255))

def wheel(pos):
    if (pos < 0) or (pos > 255):
        return (0, 0, 0)
    if (pos < 85):
        return (int(pos * 3), int(255 - (pos*3)), 0)
    elif (pos < 170):
        pos -= 85
        return (int(255 - pos*3), 0, int(pos*3))
    else:
        pos -= 170
        return (0, int(pos*3), int(255 - pos*3))

def rainbow_cycle(wait):
    for j in range(255):
        for i in range(len(strip)):
            idx = int ((i * 256 / len(strip)) + j)
            strip[i] = wheel(idx & 255)
        strip.show()
        if button.maybe_step_to_next_mode():
		    return # yes, step to next, abort this function
        time.sleep(wait)

def same_rainbow_cycle(wait):
    for j in range(255):
        for i in range(numpix_per_row):
            idx = int ((i * 256 / numpix_per_row) + j)
            one_color_column(i, wheel(idx & 255))
        strip.show()
        if button.maybe_step_to_next_mode():
		    return # yes, step to next, abort this function
        time.sleep(wait)

def one_color_column(i, color):
    # even rows
    strip[numpix_per_row * 0 + i] = color
    strip[numpix_per_row * 2 + i] = color
    # reverse odd rows
    strip[numpix_per_row * 2 - i - 1] = color
    strip[numpix_per_row * 4 - i - 1] = color

def sparkle(random_color = False, color = (255, 255, 255), wait = 0.001):
    for i in range(len(sparkles)):
        old_led = sparkles[i]
        new_led = random.randrange(0, len(strip))
        # turn of old led, if lit
        if old_led != -1:
            strip[old_led] = (0, 0, 0)
        # turn on new led and store it
        if random_color:
            strip[new_led] = make_random_color()
        else:
            strip[new_led] = color
        sparkles[i] = new_led
    strip.show()
    time.sleep(wait)

def stripes(color):
    for i in range(numpix_per_row):
        for j in range(numpix_per_row):
            if (i+j) % 4 == 0:
                one_color_column(j, (255, 255, 255))
            else:
                one_color_column(j, (0, 0, 0))
        strip.show()
        if button.is_pressed():
            return

def bands(color):
    for x in (a for b in (range(numrows), range(numrows)[::-1]) for a in b):
        for row in range(numrows):
            for i in range(numpix_per_row):
                if row == x:
                    strip[i + row * numpix_per_row] = (255, 255, 255)
                else:
                    strip[i + row * numpix_per_row] = (0, 0, 0)
        strip.show()
        if button.is_pressed():
            return

def one_color(color):
    strip.fill(color)
    strip.show()
    button.wait_until_button_pressed()


while True:
    if animode.isMode('SEPARATE_RAINBOWS'):
        rainbow_cycle(0.001)       # rainbowcycle with 1ms delay per step
    elif animode.isMode('ALL_THE_SAME_RAINBOW'):
        same_rainbow_cycle(0.001)  # rainbowcycle with 1ms delay per step
    elif animode.isMode('WHITE_SPARKLE'):
        sparkle(color = (255, 255, 255))
    elif animode.isMode('RAINBOW_SPARKLE'):
        sparkle(random_color = True)
    elif animode.isMode('WHITE_STRIPES'):
        stripes((255, 255, 255))
    elif animode.isMode('WHITE_BANDS'):
        bands((255, 255, 255))
    elif animode.isMode('ALL_WHITE'):
        one_color((255, 255, 255))
    elif animode.isMode('ALL_ORANGE'):
        one_color((255, 65, 0))
    elif animode.isMode('ALL_BLUE'):
        one_color((0, 0, 255))

    button.maybe_step_to_next_mode()

 

Prototyp-koppling

Testa programmet genom att koppla LED-listen till Gemmans utgångar GND, D1 och Vout samt den lilla knappen mellan GND och Gemmans ingång D2.

Spänningsmata antingen via USB eller batteriet.

Bygg LED-listen

Jag delade min list i fyra delar för att sen löda ihop dem i ändarna. Tänk på att vända bitarna så slingan blir kontinuerlig (se pilarna) och du inte behöver löda i kors.

För att hålla ihop delarna trädde jag transparent krympslang över listerna parvis omväxlande enligt nedan. Om du vill göra likadant, kom ihåg att trä på den innan du löder ändkablarna.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Löd fast övriga komponenter

Löd in slide switchen på den svarta delen i förlängningskabeln. Passa även på att förkorta förlängningskabeln eftersom den är för lång för att få plats i lådan. Isolera runt benen på switchen med krympslang för att undvika kortslutning.

 

 

 

 

 

 

 

 

Löd på samma sätt den andra knappen mellan GND och Gemmans ingång D2.

Löd samtidigt fast LED-listen i Gemman eftersom den också ska in på GND.

Lägg till krympslang innan du löder fast LED-listen i Gemman:

 

 

 

 

 

 

Ny prototyp-koppling

Nu är det dags att testa hela den kompletta lösningen. Schematiskt bör det se ut ungefär så här.

 

Placera i lådan

Lådan modifieras enkelt med lite borrande. Gör hål på ena långsidan för knapparna och gör hål på ena kortsidan för kablarna till slingan.

Fäst knapparna med smältlim från insidan.

 

 

 

 

 

 

Jag klädde in kablarna från slingan till Gemman med en längre bit krympslang och satte dessutom dit ett buntband som dragavlastning.

 

 

 

 

 

 

 

Det blir trångt i lådan, men det går att få plats. Blir det för trångt rekommenderas att ta bort lite mer av skarvkabeln.

Väderskydd

När du testat att allt fungerar som det ska är det dags att fästa konstruktionen på reflexen och samtidigt väderskydda hela härligheten. Börja genom att täcka alla kablar i ändarna med krympslang. Transparent blir finast.

 

 

 

 

 

 

 

Kläm ihop den i änden medan den är varm med en flacktång.

 

 

 

 

 

 

 

Jag avslutade med att klä in både listen och reflexen med en jättestor transparent krympslang.

 

 

 

 

 

Observera att du fortfarande behöver kunna komma åt lådan för att ta ur och ladda batteriet. Lådan fäste jag därför med ett gummiband. En alternativ lösning är att fästa både listen och lådan med gummiband eller buntband i reflexen.

 

Om du använder den jättestora krympslangen är ett tips att låta den svalna med reflexen ihoprullad, annars blir det svårt att rulla ihop den sedan eftersom krympslangen är bastant.

 

 

 

 

 

 

 

 

Dags för promenad!

Ut och syns!

 

 

 

 

 

 

 

 

 

Adafruit har gjort ett liknande projekt där led-listen istället kapslas in i en 3D-utskriven låda. Kolla gärna in det också här.

Vi har även gjort ett icke plågsamt djurförsök som föll väl ut: https://www.youtube.com/watch?v=5BDqD5_P-ps

Tack

Klas för programmeringen, Åsa för limningen och Erik för lådmodifieringen.

Lämna ett svar