【问题标题】:Automatically create n calls of a function within a while loop?在while循环中自动创建函数的n个调用?
【发布时间】:2020-11-27 18:03:32
【问题描述】:

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

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

我设法手动完成所有这些(根据有多少灯创建“变量_1,变量_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)

【问题讨论】:

    标签: python while-loop python-class adafruit-circuitpython


    【解决方案1】:

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

    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 中有一个“无类”非常简单的版本。我想我只会在有更多类型要添加或者你想做渐进式脉动而不是突然闪烁或添加同步组行为时投入时间。

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

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

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

    【讨论】:

    • 感谢您花时间看这个!要回答您的最后一个问题,如果没有它,脚本会循环得如此之快,以至于我笔记本电脑上的风扇开始高速运转而没有任何真正的好处。它的循环速度也非常快,以至于无法真正看到我的任何故障排除打印语句。
    【解决方案2】:

    上面的 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)
    

    【讨论】:

      猜你喜欢
      • 2016-01-11
      • 2014-04-16
      • 1970-01-01
      • 2015-07-13
      • 2015-07-26
      • 2023-03-22
      • 2012-10-22
      • 2022-06-24
      • 2023-03-19
      相关资源
      最近更新 更多