Voting resources, early voting, and poll worker information - VOTE. ... Adafruit is open and shipping.
0

Code Assistance for FireWalker
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Code Assistance for FireWalker

by ftvideo on Sat Sep 05, 2020 10:41 am

Hello,

I am running CircutPython version 6 for my neopixel firewalker shoe build. The sample code here (https://learn.adafruit.com/gemma-led-sn ... ython-code) works with the sensor but I cannot figure out how to adjust the code to play the animation every time the sensor is triggered.

I adjusted line #39 "speed" from a value of 1 to 2 and the speed is faster, but there is a 30 second delay before the trigger will allow the animation to play again.

What would the code values be for a shoe that has 30 LED and 24" circumference? Basically I would like for it to respond as the demo.
Thank you

ftvideo
 
Posts: 21
Joined: Sun Aug 23, 2020 1:26 pm

Re: Code Assistance for FireWalker

by danhalbert on Sat Sep 05, 2020 11:40 am

For 30 LEDs, change these lines to 30 instead of 40. The circumference in inches doesn't matter -- it's just how many NeoPixels are around the shoe.
Code: Select all | TOGGLE FULL SIZE
num_leds = 40  # How many LEDs you have
circumference = 40  # Shoe circumference, in pixels, may be > NUM_LEDS


Have you tried 5.3.1? You don't need to change the libraries: the 5.x and 6.x libraries are the same right now. If 5.3.1 also doesn't work well, I am suspicious that your vibration sensor is taking 30 seconds to trigger. You could add a print statement inside the vibration sensor checker to see if it's getting stuck there:
Code: Select all | TOGGLE FULL SIZE
def vibration_detector():
    print("waiting for vibration")
    while True:
        print(".", end="")  # Will print "." over and over until triggered
        if not pin.value:
            return True

danhalbert
 
Posts: 2118
Joined: Tue Aug 08, 2017 12:37 pm

Re: Code Assistance for FireWalker

by ftvideo on Sat Sep 05, 2020 5:12 pm

hello and thank you for the reply.

I did change the num_leds = 30. Since it would not trigger again after 30 seconds, I thought there was another value I was missing that thought the pixel strip was longer than that and therefore playing the animation 30 seconds longer.

I pasted:

Code: Select all | TOGGLE FULL SIZE
def vibration_detector():
    print("waiting for vibration")
    while True:
        print(".", end="")  # Will print "." over and over until triggered
        if not pin.value:
            return True


into lines 122-127. The serial command showed a line of "..................................................................................................................................." and then it stops and the MU editor freezes up.

I then applied: adafruit-circuitpython-gemma_m0-en_US-5.3.1.uf2 and verified (Adafruit CircuitPython 5.3.1 on 2020-07-13; Adafruit Gemma M0 with samd21e18) in the editor. I have these two files in my 'lib' folder:
adafruit_pypixelbuf.mpy
neopixel.py

The GEMMA MO and sensor are wired up according to the diagram (https://learn.adafruit.com/gemma-led-sn ... it-diagram) and the main.py file has the FireWalker code with the lines added as described above for lines 122-127.

The MU REPL did display a line and a half of dots but the editor locked up again.

I then ejected the device, reversed the wiring for the sensor, plugged it back into my USB and re-started the MU editor. I also reset the GEMMA MO board. The GEMMA MO displays a solid green light.

The NeoPixel did trigger but only again after about 60 seconds. It will do it repeatedly after 60 seconds.

Re-started the MU editor and it freezes up when attempting to open the serial connection. The MU editor is locked up and the motion sensor will not trigger at all.

Reset the GEMMA MO board and it will not fire until I close out the MU editor.
Thank you
James

I re-saved the 'main.py' file and the

ftvideo
 
Posts: 21
Joined: Sun Aug 23, 2020 1:26 pm

Re: Code Assistance for FireWalker

by danhalbert on Sat Sep 05, 2020 5:30 pm

When you say that the editor "locked up", if you type ctrl-C into the Serial window, you should be able to interrupt the program. I will try this also but if you could paste what is printed when you type ctrl-C, that will help. THanks.

danhalbert
 
Posts: 2118
Joined: Tue Aug 08, 2017 12:37 pm

Re: Code Assistance for FireWalker

by ftvideo on Sat Sep 05, 2020 5:43 pm

thank you for the prompt reply.
the program is 'not responding' (see the attached screenshot of the REPL) before it locks up
not RESPONDING_.jpg
not RESPONDING_.jpg (74.98 KiB) Viewed 44 times

ftvideo
 
Posts: 21
Joined: Sun Aug 23, 2020 1:26 pm

Re: Code Assistance for FireWalker

by danhalbert on Sat Sep 05, 2020 10:56 pm

How are you powering everything right now? Is it all from the USB plug?. That might OK, but it's possible that you might be drawing too much power from USB, and it's shutting off temporarily.

Try setting the number of pixels much smaller, to say, 5, and see if it still has the 30-second delay.

danhalbert
 
Posts: 2118
Joined: Tue Aug 08, 2017 12:37 pm

Re: Code Assistance for FireWalker

by ftvideo on Sun Sep 06, 2020 8:14 am

Ah OK. This is real progress!

So yes, 5 lights (and I also switched to battery) will trigger the animation properly each time. Increasing that number to 26 (on battery) will also allow the sensor to trigger with no delay.

26 lights is what is on my test strip as I have not committed to the solder work until I was confident with the operation.

So here would be my programming question more specifically:

With 5 lights, the animation (and frame rate) plays fast and repeatedly. With 26 lights, the frame rate drops and the travel is much slower (like 30 seconds to complete). Changing the 'speed' value creates a delay in the trigger. Increasing the frame rate fails to trigger (the green LED on the GEMMA MO will flash a series of colors etc, looking like an error in the code)

Is there a way to get 26 LEDs (or more) to behave like the 5 LED's? Thank you

ftvideo
 
Posts: 21
Joined: Sun Aug 23, 2020 1:26 pm

Re: Code Assistance for FireWalker

by danhalbert on Sun Sep 06, 2020 3:34 pm

Unfortunately, the problem here is that the original project used Arduino code (and on a Gemma V2, not a Gemma M0). It was translated to CircuitPython, but never well tested in terms of speed. The speed is terrible, because the computations are complicated. I made some minor adjustments to the program to speed up a few things, but it didn't help that much. I will discuss this with staff and see what we should do about this guide.

If you really want to do the original project, then I recommend Arduino, and you'd need to get a Gemma V2, which is sad. An alternative to to scrap most of the existing CircuitPython code, and instead use some easier-to-compute animations, such as some of those described in this guide: https://learn.adafruit.com/circuitpython-led-animations. I was able to get various animations running quite fast.

Here is an example that you might use:
Code: Select all | TOGGLE FULL SIZE
import board
import digitalio
import neopixel

from adafruit_led_animation.animation.rainbowcomet import RainbowComet

# vibration sensor
motion_pin = board.D0  # Pin where vibration switch is connected
sensor = digitalio.DigitalInOut(motion_pin)
sensor.direction = digitalio.Direction.INPUT
sensor.pull = digitalio.Pull.UP

# Update to match the pin connected to your NeoPixels
pixel_pin = board.D1
# Update to match the number of NeoPixels you have connected
pixel_num = 24

pixels = neopixel.NeoPixel(pixel_pin, pixel_num, brightness=0.1, auto_write=False)

rainbow_comet = RainbowComet(pixels, speed=0, tail_length=12, bounce=True)

while True:
    if not sensor.value:
        rainbow_comet.animate()

One issue is that there is not much room on the Gemma M0 CIRCUITPY drive, so you cannot copy all the animations in the adafruit_led_animation/animations/ library folder onto the board. So for instance, for the example above, you need just these files (and perhaps fewer):
Code: Select all | TOGGLE FULL SIZE
adafruit_led_animation/
    animation/
        comet.mpy
        __init__.mpy
        rainbowcomet.mpy
        rainbow.mpy
    color.mpy
    grid.mpy
    group.mpy
    helper.mpy
    __init__.mpy
    sequence.mpy

danhalbert
 
Posts: 2118
Joined: Tue Aug 08, 2017 12:37 pm

Re: Code Assistance for FireWalker

by ftvideo on Sun Sep 06, 2020 4:24 pm

Ah OK. That is fine. I dont mind purchasing something to make this work correctly. (I'm somewhat relieved to know that I'm not crazy.) I will take comfort in knowing that my work on this will make a better product for others in the future.

So if I purchase 2x Gemma V2, will my 2x 500mAh lipoly batteries be sufficient to power about 35 Neopixels?

There is Arduino code for the Firewalker (with Gemma V2) here: https://learn.adafruit.com/gemma-led-sneakers/code. Will that work for me?

Thank you
James

ftvideo
 
Posts: 21
Joined: Sun Aug 23, 2020 1:26 pm

Re: Code Assistance for FireWalker

by danhalbert on Sun Sep 06, 2020 4:41 pm

I believe those batteries should be OK.

The board-specific code in the Gemma V2 code that you linked to mostly has to do with sleeping and checking the battery voltage. It would not be so much work to change this to work on the Gemma M0. the animation code would not change. If you are willing to use the on/off switch then some of the sleep code could be discarded. It would take a knowledgeable person a few hours (or maybe much less) to do the rewrite.

danhalbert
 
Posts: 2118
Joined: Tue Aug 08, 2017 12:37 pm

Re: Code Assistance for FireWalker

by ftvideo on Sun Sep 06, 2020 4:51 pm

Well what do you suggest? $20 is not a big deal for me to spend on a GEMMA V2. I'm building these shoes for another person and would like as much 'turn-key' functionality to make it work and spend my time on soldering and stitching the wearables. I can say for sure that I cannot re-write code. But I'm an expert with control + C and control + v.

ftvideo
 
Posts: 21
Joined: Sun Aug 23, 2020 1:26 pm

Re: Code Assistance for FireWalker

by danhalbert on Sun Sep 06, 2020 5:57 pm

If the money is not a problem, then definitely order the Gemma V2's and use the existing Arduino code. We know it works: it was used to make the demo movies.

danhalbert
 
Posts: 2118
Joined: Tue Aug 08, 2017 12:37 pm

Re: Code Assistance for FireWalker

by ftvideo on Sun Sep 06, 2020 6:04 pm

OK, thank you! I went ahead and submitted the order for the V2. I assume my existing battery will plug into the V2?

ftvideo
 
Posts: 21
Joined: Sun Aug 23, 2020 1:26 pm

Re: Code Assistance for FireWalker

by kevinjwalters on Mon Sep 07, 2020 12:51 pm

I have some friends who have all the bits for this project including the Gemma M0 but they clearly haven't built the project as I would have ended up discussing this with them!

I just spent 20 minutes on some minor performance improvements if you want something to get you going in the meantime but i think it's still only running around 1/4 of intended speed. The biggest gain is the one already designed into the code, reducing the number of "waves" from 3 to 1. Remove or comment out the second vibration_detector function - that was just for my testing.

Code: Select all | TOGGLE FULL SIZE
### Some very quick hacks to improve performance
### Biggest win is in reducing number of waves from 3 to 1

# Gemma "Firewalker Lite" sneakers
#  - Uses the following Adafruit parts (X2 for two shoes):
#    * Gemma M0 3V microcontroller (#3501)
#    * 150 mAh LiPoly battery (#1317) or larger
#    * Medium vibration sensor switch (#2384)
#    * 60/m NeoPixel RGB LED strip (#1138 or #1461)
#    * LiPoly charger such as #1304
#
# - originally written by Phil Burgess for Gemma using Arduino
#   * https://learn.adafruit.com/gemma-led-sneakers

import board
import digitalio
import neopixel

from micropython import const

import time

try:
    import urandom as random
except ImportError:
    import random

# Declare a NeoPixel object on led_pin with num_leds as pixels
# No auto-write.
led_pin = board.D1  # Which pin your pixels are connected to
num_leds = 40  # How many LEDs you have
circumference = 40  # Shoe circumference, in pixels, may be > NUM_LEDS
frames_per_second = 50  # Animation frames per second
brightness = 0  # Current wave height
strip = neopixel.NeoPixel(led_pin, num_leds, brightness=1, auto_write=False)
offset = 0

# vibration sensor
motion_pin = board.D0  # Pin where vibration switch is connected
pin = digitalio.DigitalInOut(motion_pin)
pin.direction = digitalio.Direction.INPUT
pin.pull = digitalio.Pull.UP
ramping_up = False

center = const(0)  # Center point of wave in fixed-point space (0 - 255)
speed = const(1)  # Distance to move between frames (-128 - +127)
width = const(2)  # Width from peak to bottom of triangle wave (0 - 128)
hue = const(3)  # Current wave hue (color) see comments later
hue_target = const(4)  # Final hue we're aiming for
red = const(5)  # LED RGB color calculated from hue
green = const(6)  # LED RGB color calculated from hue
blue = const(7)  # LED RGB color calculated from hue

y = 0
brightness = 0
count = 0

# Gemma can animate 3 of these on 40 LEDs at 50 FPS
# More LEDs and/or more waves will need lower
## wave = [0] * 8, [0] * 8, [0] * 8
wave = [[0] * 8]

# Note that the speeds of each wave are different prime numbers.
# This avoids repetition as the waves move around the
# perimeter...if they were even numbers or multiples of each
# other, there'd be obvious repetition in the pattern of motion...
# beat frequencies.
n_waves = len(wave)

# 90 distinct hues (0-89) around color wheel
hue_table = [255, 255, 255, 255, 255, 255, 255, 255, 237, 203,
             169, 135, 101, 67, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 18, 52, 86, 120, 154, 188, 222,
             255, 255, 255, 255, 255, 255, 255, 255]

# Gamma-correction table
gammas = [
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
    2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
    5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
    10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
    17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
    25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
    37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
    51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
    69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
    90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110,
    112, 114, 115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133,
    135, 137, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158,
    160, 162, 164, 167, 169, 171, 173, 175, 177, 180, 182, 184, 186,
    189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213, 215, 218,
    220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252,
    255
]


def h2rgb(colour_hue):
    colour_hue %= 90
    h = hue_table[colour_hue >> 1]

    if colour_hue & 1:
        ret = h & 15
    else:
        ret = (h >> 4)

    return ret * 17


# pylint: disable=global-statement
def wave_setup():
    global wave

    ##wave = [[0, 3, 60, 0, 0, 0, 0, 0],
    ##        [0, -5, 45, 0, 0, 0, 0, 0],
    ##        [0, 7, 30, 0, 0, 0, 0, 0]]
    wave = [[0, 3, 60, 0, 0, 0, 0, 0]]

    # assign random starting colors to waves
    for current_wave in wave:
        random_offset = random.randint(0, 90)

        new_hue = current_wave[hue] = current_wave[hue_target] = 90 + random_offset
        current_wave[red] = h2rgb(new_hue - 30)
        current_wave[green] = h2rgb(new_hue)
        current_wave[blue] = h2rgb(new_hue + 30)


def vibration_detector():
    while True:
        if not pin.value:
            return True


### TODO - REMOVE THIS REDEFINITION
def vibration_detector():
    time.sleep(random.random() * 10.0)
    ##random.seed(123456)
    return True


while True:

    # wait for vibration sensor to trigger
    if not ramping_up:
        ramping_up = vibration_detector()
        wave_setup()

    # But it's not just a straight shot that it ramps up.
    # This is a low-pass filter...it makes the brightness
    # value decelerate as it approaches a target (200 in
    # this case).  207 is used here because integers round
    # down on division and we'd never reach the target;
    # it's an ersatz ceil() function: ((199*7)+200+7)/8 = 200;
    ##brightness = int(((brightness * 7) + 207) / 8)
    brightness = ((brightness * 7) + 207) >> 3
    count += 1

    if count == (circumference + num_leds + 5):
        ramping_up = False
        count = 0

    # Wave positions and colors are updated...
    ##t1 = time.monotonic()
    for w_outer in wave:
        # Move wave; wraps around ends, is OK!
        w_outer[center] += w_outer[speed]

        # Hue not currently changing?
        if w_outer[hue] == w_outer[hue_target]:

            # There's a tiny random chance of picking a new hue...
            if not random.randint(frames_per_second * 4, 255):
                # Within 1/3 color wheel
                w_outer[hue_target] = random.randint(
                    w_outer[hue] - 30, w_outer[hue] + 30)

        # This wave's hue is currently shifting...
        else:

            if w_outer[hue] < w_outer[hue_target]:
                w_outer[hue] += 1  # Move up or
            else:
                w_outer[hue] -= 1  # down as needed

            # Reached destination?
            if w_outer[hue] == w_outer[hue_target]:
                w_outer[hue] = 90 + w_outer[hue] % 90  # Clamp to 90-180 range
                w_outer[hue_target] = w_outer[hue]  # Copy to target

            w_outer[red] = h2rgb(w_outer[hue] - 30)
            w_outer[green] = h2rgb(w_outer[hue])
            w_outer[blue] = h2rgb(w_outer[hue] + 30)

        # Now render the LED strip using the current
        # brightness & wave states.
        # Each LED in strip is visited just once...
        for i in range(num_leds):

            # Transform 'i' (LED number in pixel space) to the
            # equivalent point in 8-bit fixed-point space (0-255)
            # "* 256" because that would be
            # the start of the (N+1)th pixel
            # "+ 127" to get pixel center.
            x = int((i * 256 + 127) / circumference)

            # LED assumed off, but wave colors will add up here
            r = g = b = 0

            # For each item in wave[] array...
            for w_inner in wave:
                # Calculate distance from pixel center to wave
                # center point, using both signed and unsigned
                # 8-bit integers...
                d = abs(x - w_inner[center])

                # Then take the lesser of the two, resulting in
                # a distance (0-128)
                # that 'wraps around' the ends of the strip as
                # necessary...it's a contiguous ring, and waves
                # can move smoothly across the gap.
                ##if d2 < d1:
                ##    d1 = d2  # d1 is pixel-to-wave-center distance

                # d2 distance, relative to wave width, is then
                # proportional to the wave's brightness at this
                # pixel (basic linear y=mx+b stuff).
                # Is distance within wave's influence?
                # d2 is opposite; distance to wave's end
                w_width = w_inner[width]
                if d < w_width:
                    ##d2 = w_width - d1
                    ##y = int(brightness * d2 / w_width)  # 0 to 200
                    y = int(brightness * d / w_width)  # 0 to 200
                    # y is a brightness scale value --
                    # proportional to, but not exactly equal
                    # to, the resulting RGB value.
                    if y < 128:  # Fade black to RGB color
                        # In HSV colorspace, this would be
                        # tweaking 'value'
                        n = y << 1 + 1  # 1-256
                        r += (w_inner[red] * n) >> 8  # More fixed-point math
                        # Wave color is scaled by 'n'
                        g += (w_inner[green] * n) >> 8
                        b += (w_inner[blue] * n) >> 8  # >>8 is equiv to /256
                    else:  # Fade RGB color to white
                        # In HSV colorspace, this tweaks 'saturation'
                        n = int((y - 128) * 2)  # 0-255 affects white level
                        ##m = 256 * n
                        m = n << 8
                        n = 256 - n  # 1-256 affects RGB level
                        r += (m + w_inner[red] * n) >> 8
                        g += (m + w_inner[green] * n) >> 8
                        b += (m + w_inner[blue] * n) >> 8

            # r,g,b are 16-bit types that accumulate brightness
            # from all waves that affect this pixel; may exceed
            # 255.  Now clip to 0-255 range:
            ##if r > 255:
            ##    r = 255
            ##if g > 255:
            ##    g = 255
            ##if b > 255:
            ##    b = 255

            # Store resulting RGB value and we're done with
            # this pixel!
            strip[i] = (r & 0xff, g & 0xff, b & 0xff)

        # Once rendering is complete, a second pass is made
        # through pixel data applying gamma correction, for
        # more perceptually linear colors.
        # https://learn.adafruit.com/led-tricks-gamma-correction
        ##for j in range(num_leds):
        ##    (red_gamma, green_gamma, blue_gamma) = strip[j]
        ##    red_gamma = gammas[red_gamma]
        ##    green_gamma = gammas[green_gamma]
        ##    blue_gamma = gammas[blue_gamma]
        ##    strip[j] = (red_gamma, green_gamma, blue_gamma)

        strip.show()
    ##t2 = time.monotonic()
    ##print("DURATION", t2 - t1)

kevinjwalters
 
Posts: 735
Joined: Sun Oct 01, 2017 3:15 pm

Re: Code Assistance for FireWalker

by danhalbert on Mon Sep 07, 2020 1:12 pm

I moved the call to `wave_setup()` out of the `while True` loop and changed the division operators from float to fixed (`//'). Those things some.

danhalbert
 
Posts: 2118
Joined: Tue Aug 08, 2017 12:37 pm

Please be positive and constructive with your questions and comments.