0

我一直在做一个项目,使用 circuitpython 和 neopixels 作为学习如何使用板载计时器的一种方式。我已经完成了我的功能待办事项列表的 90%,现在我担心我可能需要重建整个事情来获得最后的 10%。

该项目旨在以萤火虫图案闪烁 n 个新像素。每种萤火虫图案都有一个功能。在脚本开始时,我创建了与灯光一样多的变量。然后我遍历它们,根据计时器打开或关闭灯。

我设法手动完成所有这些(根据有多少灯创建'variable_1,variable_2,...'),现在我试图根据灯的数量自动产生变量的数量。我还想在每次脚本启动时随机分配闪烁模式给灯光,但我认为这是最后一块。

正如您从下面的代码中看到的那样,我已经设法根据顶部的灯光数量自动创建变量。但是,当我尝试在底部的 while 循环中做类似的事情时,事情就崩溃了。我的问题基本上是“这就是存在类的原因,所以重写整个事情以使用类”?还是有其他方法可以使这项工作?

谢谢!

#https://www.nps.gov/grsm/learn/nature/firefly-flash-patterns.htm

import board
import digitalio
import time
import neopixel
import random



#variables to hold the color that the LED will blink
neo_r = 255
neo_g = 255
neo_b = 0

# variable to hold the number of neopixels
number_of_lights = 7

#create the neopixel. auto_write=True avoids having to push changes (at the cost of speed, which probably doesn't matter here)
pixels = neopixel.NeoPixel(board.NEOPIXEL, number_of_lights, brightness = 0.2, auto_write=False)

# automatically spins up the seed reset times for each light
reset_time_dict = {}

# sets the seeds to zero
for i in range(0, number_of_lights):
    var_name = 'resetTime' + str(i)
    reset_time_dict[var_name] = time.monotonic()


print(reset_time_dict)

def on(light_num):
    pixels[light_num] = (neo_r, neo_g, neo_b)
    pixels.show()
def off(light_num):
    pixels[light_num] = (0, 0, 0)
    pixels.show()

def brimleyi(reset_time_input, light_number):
    #calculates how much time has passed since the new zero
    time_from_zero = time.monotonic() - reset_time_input
    # creates the carry over reset_time variable so that it can be returned even if it is not updated in the last if statement
    reset_time = reset_time_input

    # on flash
    if 5 <= time_from_zero <= 5.5:
        on(light_number)
    elif 15 <= time_from_zero <= 15.5:
        on(light_number)

    # reset (includes 10 seconds after second flash - 5 on the back end and 5 on the front end)
    elif time_from_zero > 20:
        off(light_number)
        reset_time = time.monotonic() + random.uniform(-3, 3)

    # all of the off times
    else:
        off(light_number)

    return reset_time

def macdermotti (reset_time_input, light_number):
    #calculates how much time has passed since the new zero
    time_from_zero = time.monotonic() - reset_time_input
    # creates the carry over reset_time variable so that it can be returned even if it is not updated in the last if statement
    reset_time = reset_time_input

    # on flash
    if 3 <= time_from_zero <= 3.5:
        on(light_number)
    elif 5 <= time_from_zero <= 5.5:
        on(light_number)
    elif 10 <= time_from_zero <= 10.5:
        on(light_number)
    elif 12 <= time_from_zero <= 12.5:
        on(light_number)

    elif time_from_zero > 14.5:
        off(light_number)
        reset_time = time.monotonic() + random.uniform(-3, 3)

    else:
        off(light_number)

    return reset_time

def carolinus(reset_time_input, light_number):
    time_from_zero = time.monotonic() - reset_time_input
    # creates the carry over reset_time variable so that it can be returned even if it is not updated in the last if statement
    reset_time = reset_time_input

    if 0 <= time_from_zero <= 0.5:
        on(light_number)
    elif 1 <= time_from_zero <= 1.5:
        on(light_number)
    elif 2 <= time_from_zero <= 2.5:
        on(light_number)
    elif 3 <= time_from_zero <= 3.5:
        on(light_number)
    elif 4 <= time_from_zero <= 4.5:
        on(light_number)
    elif 5 <= time_from_zero <= 5.5:
        on(light_number)
    elif 6 <= time_from_zero <= 6.5:
        on(light_number)

    elif time_from_zero >= 15:
        off(light_number)
        reset_time = time.monotonic()

    else:
        off(light_number)

    return reset_time



while True:

    reset_time_dict["resetTime2"] = brimleyi(reset_time_dict["resetTime2"], 2)
    reset_time_dict["resetTime3"] = brimleyi(reset_time_dict["resetTime3"], 3)
    reset_time_dict["resetTime4"] = macdermotti(reset_time_dict["resetTime4"], 4)
    reset_time_dict["resetTime5"] = carolinus(reset_time_dict["resetTime5"], 5)
    reset_time_dict["resetTime6"] = carolinus(reset_time_dict["resetTime6"], 6)





    #briefly pauses the loop to avoid crashing the USB bus. Also makes it easier to see what is happening.
    time.sleep(0.25)
4

2 回答 2

1

有很多方法可以做到这一点,但支持可变数量的 NeoPixels 的最简单更改是用循环遍历它们for。Python 允许将函数视为变量,这在此处很有用。保持现有的萤火虫模式并重复它可以通过 atuple然后在循环中调用适当的函数来实现。像这样的东西应该工作:

firefly_pattern = (brimleyi, brimleyi, macdermotti, carolinus, carolinus)
start_pixel = 2

while True:

    for pixel_pos in range(start_pixel, number_of_lights):
        key = "resetTime" + str(pixel_pos)
        firefly_fn = firefly_pattern[(pixel_pos - start_pixel) % len(firefly_pattern)]
        reset_time_dict[key] = firefly_fn(reset_time_dict[key], pixel_pos)

    #briefly pauses the loop to avoid crashing the USB bus. Also makes it easier to see what is happening.
    time.sleep(0.25)

您可以将三个萤火虫函数更改为管理开/关转换的通用类。在Adafruit Learn: Multi-tasking with CircuitPython: Multiple LEDs中有一个“无类”非常简单的版本。如果要添加更多类型,或者您想要进行渐进式脉动而不是突然闪烁或添加同步组行为,我想我只会在这方面投入时间。

pixels.show()在循环结束时对进行一次调用while而不是在on/内部进行调用会更有效off。拥有brightness=1并仅使用 51 而不是 255 来实现相同的目标还可以提高性能。如果您开始使用大量(100 个?)的 NeoPixels,这些优化将变得很重要。

如果您的代码要运行一天以上或在已通电数天的板上运行,那么time.monotonic_ns如果您的板支持它,则值得使用。

顺便说一句,倒数第二行关于 USB 的评论背后的故事是什么?

于 2020-10-11T15:36:03.340 回答
0

上面的 KevinJWalters 回答有一些有用的提示和选项。我最终确实为每个单独的灯光使用类重建了脚本。更新的脚本在这里,以防它对任何人都有帮助:

#https://www.nps.gov/grsm/learn/nature/firefly-flash-patterns.htm

import board
import digitalio
import time
import neopixel
import random



#variables to hold the color that the LED will blink
neo_r = 255
neo_g = 255
neo_b = 0

# variable to hold the number of neopixels
number_of_lights = 10

#create the neopixel. auto_write=True avoids having to push changes (at the cost of speed, which probably doesn't matter here)
pixels = neopixel.NeoPixel(board.NEOPIXEL, number_of_lights, brightness = 0.1, auto_write=False)

# sets up the bug holder list, which holds all of the bug objects 

bug_holder = []

    
# sets up the bug class

class Bug:
    def __init__(self, type, reset_time_input, light_number):
        self.type = type 
        self.reset_time_input = reset_time_input
        self.light_number = light_number 
        
    
#functions to turn light on and off 
def on(light_num):
    pixels[light_num] = (neo_r, neo_g, neo_b)
    pixels.show()
def off(light_num):
    pixels[light_num] = (0, 0, 0)
    pixels.show()
    

#functions for the types of fireflies 
def brimleyi(reset_time_input, light_number):
    #calculates how much time has passed since the new zero
    time_from_zero = time.monotonic() - reset_time_input
    # creates the carry over reset_time variable so that it can be returned even if it is not updated in the last if statement
    reset_time = reset_time_input

    # on flash
    if 5 <= time_from_zero <= 5.5:
        on(light_number)
    elif 15 <= time_from_zero <= 15.5:
        on(light_number)

    # reset (includes 10 seconds after second flash - 5 on the back end and 5 on the front end)
    elif time_from_zero > 20:
        off(light_number)
        reset_time = time.monotonic() + random.uniform(-3, 3)

    # all of the off times
    else:
        off(light_number)

    return reset_time

def macdermotti (reset_time_input, light_number):
    #calculates how much time has passed since the new zero
    time_from_zero = time.monotonic() - reset_time_input
    # creates the carry over reset_time variable so that it can be returned even if it is not updated in the last if statement
    reset_time = reset_time_input

    # on flash
    if 3 <= time_from_zero <= 3.5:
        on(light_number)
    elif 5 <= time_from_zero <= 5.5:
        on(light_number)
    elif 10 <= time_from_zero <= 10.5:
        on(light_number)
    elif 12 <= time_from_zero <= 12.5:
        on(light_number)

    elif time_from_zero > 14.5:
        off(light_number)
        reset_time = time.monotonic() + random.uniform(-3, 3)

    else:
        off(light_number)

    return reset_time

def carolinus(reset_time_input, light_number):
    time_from_zero = time.monotonic() - reset_time_input
    # creates the carry over reset_time variable so that it can be returned even if it is not updated in the last if statement
    reset_time = reset_time_input

    if 0 <= time_from_zero <= 0.5:
        on(light_number)
    elif 1 <= time_from_zero <= 1.5:
        on(light_number)
    elif 2 <= time_from_zero <= 2.5:
        on(light_number)
    elif 3 <= time_from_zero <= 3.5:
        on(light_number)
    elif 4 <= time_from_zero <= 4.5:
        on(light_number)
    elif 5 <= time_from_zero <= 5.5:
        on(light_number)
    elif 6 <= time_from_zero <= 6.5:
        on(light_number)

    elif time_from_zero >= 15:
        off(light_number)
        reset_time = time.monotonic()

    else:
        off(light_number)

    return reset_time


#create all of the light objects by appending a new light object to the list for each neopixel
#the first argument (random.randint(1, 3)) is used to assign a random number which corresponds to one of the ff functions
#if you start adding lots of those it might be worth using a universal variable

for i in range (0, number_of_lights):
    bug_holder.append(Bug(random.randint(1, 3), time.monotonic(), i))


while True:

    #iterates through all of the light objects in the bug_holder list 
    #use the series of if statements to match the randomly assigned number to the types of fireflies 
   
    for i in range (0, number_of_lights):
        if bug_holder[i].type == 1:
            bug_holder[i].reset_time_input = brimleyi(bug_holder[i].reset_time_input, i)
        elif bug_holder[i].type == 2:
            bug_holder[i].reset_time_input = macdermotti(bug_holder[i].reset_time_input, i)
        elif bug_holder[i].type == 3:
            bug_holder[i].reset_time_input = carolinus(bug_holder[i].reset_time_input, i)
        #this is just a catchall if there is some sort of error
        else:
            bug_holder[i].reset_time_input = brimleyi(bug_holder[i].reset_time_input, i)
            print("number error")
    
    
    #briefly pauses the loop to avoid crashing the USB bus. Also makes it easier to see what is happening.
    time.sleep(0.25)
于 2020-10-11T21:33:39.343 回答