Example #1
0
 def setUp(self):
     #logging.basicConfig(level=logging.INFO)
     #random.seed("WSlice")
     self.ws = ws = WS2812(1, 64)
     for i in range(len(ws)):
         ws[i] = (i, 2 * i, 3 * i)
     self.p = Percolator(ws)
 def setUp(self):
     #logging.basicConfig(level=logging.INFO)
     #random.seed("WSlice")
     self.ws = ws = WS2812(1,64)
     for i in range(len(ws)):
         ws[i] = (i, 2*i, 3*i)
     self.p = Percolator(ws)
Example #3
0
    def __init__(self, write_fun=None, config={}):
        self.config = config

        if write_fun is None:

            @coroutine
            def write(self, *args):
                print(*args)

            self.write = write
        else:
            self.write = write_fun

        self.act_led = pyb.LED(3)
        self.err_led = pyb.LED(1)
        self.pkt_led = pyb.LED(2)

        self.pots = [0] * 4

        self.percolator = \
                Percolator(WS2812(spi_bus=config['leds'].get('spi'),
                                  led_count=config['leds'].get('qty')))
        self.percolator.bingo = self.bingo

        self.ws_rings = WS2812(2, 2 * 7 + 45)
        self.ring_lights = Lights(self.ws_rings)

        self.feed_rollers = [
            Jewel7(lights=self.ring_lights[0:7]),
            Jewel7(lights=self.ring_lights[7:14])
        ]

        self.rr = RingRamp(lights=self.ring_lights[14:],
                           circumference=60, \
                           bottom=7, \
                           g=-40.0,
                           ball_check_fun = self.ball_check)

        #        self.zap_balls = False
        self.set_brightness(31)
Example #4
0
    def __init__(self, write_fun=None, config={}):
        self.config = config

        if write_fun is None:
            @coroutine
            def write(self, *args):
                print(*args)
            self.write = write
        else:
            self.write = write_fun

        self.act_led = pyb.LED(3)
        self.err_led = pyb.LED(1)
        self.pkt_led = pyb.LED(2)

        self.pots = [0] * 4

        self.percolator = \
                Percolator(WS2812(spi_bus=config['leds'].get('spi'),
                                  led_count=config['leds'].get('qty')))
        self.percolator.bingo = self.bingo

        self.ws_rings = WS2812(2, 2*7 + 45)
        self.ring_lights = Lights(self.ws_rings)

        self.feed_rollers = [Jewel7(lights=self.ring_lights[0:7]),
                             Jewel7(lights=self.ring_lights[7:14])]

        self.rr = RingRamp(lights=self.ring_lights[14:],
                           circumference=60, \
                           bottom=7, \
                           g=-40.0,
                           ball_check_fun = self.ball_check)

#        self.zap_balls = False
        self.set_brightness(31)
Example #5
0
class Lightshow:
    def __init__(self, write_fun=None, config={}):
        self.config = config

        if write_fun is None:

            @coroutine
            def write(self, *args):
                print(*args)

            self.write = write
        else:
            self.write = write_fun

        self.act_led = pyb.LED(3)
        self.err_led = pyb.LED(1)
        self.pkt_led = pyb.LED(2)

        self.pots = [0] * 4

        self.percolator = \
                Percolator(WS2812(spi_bus=config['leds'].get('spi'),
                                  led_count=config['leds'].get('qty')))
        self.percolator.bingo = self.bingo

        self.ws_rings = WS2812(2, 2 * 7 + 45)
        self.ring_lights = Lights(self.ws_rings)

        self.feed_rollers = [
            Jewel7(lights=self.ring_lights[0:7]),
            Jewel7(lights=self.ring_lights[7:14])
        ]

        self.rr = RingRamp(lights=self.ring_lights[14:],
                           circumference=60, \
                           bottom=7, \
                           g=-40.0,
                           ball_check_fun = self.ball_check)

        #        self.zap_balls = False
        self.set_brightness(31)

    def set_brightness(self, v):
        self.brightness = self.rr.brightness = self.percolator.brightness = v
        self.feed_rollers[0].brightness = self.feed_rollers[1].brightness = v

    @coroutine
    def flash_LED(self, led, dur=1):
        led.on()
        yield from sleep(dur)
        led.off()

    @coroutine
    def fuzzle(self, quit_name):
        # For testing
        while not getattr(self, quit_name):
            #yield from self.flash_LED(self.err_led)
            # More queue-costly but let's us proceed without waiting for photons
            yield self.flash_LED(
                self.err_led)  # let a coro do it so we can proceed
            yield from sleep(100)
        assert getattr(self, quit_name)
        setattr(self, quit_name, max(getattr(self, quit_name) - 1, 0))

    @coroutine
    def handle_pots(self, b):
        for i in range(4):
            self.pots[i] = big_endian_int(b[2 * i:2 * (i + 1)])
        yield from self.show_pots()

    @coroutine
    def show_pots(self):
        s = ', '.join("%d" % v for v in self.pots)
        yield from self.supertitle("Pots: " + s)

    @coroutine
    def supertitle(self, text):
        yield from self.write(b'\x1b[s\x1b[1;1H\x1b[2K')
        yield from self.write(text)
        yield from self.write('\x1b[u')

    @coroutine
    def perk(self, cli, cmd, rol):
        sdelay, _, scolor = str(rol, 'ASCII').partition(' ')
        try:
            delay = int(sdelay)
        except:
            delay = 100
        try:
            color = eval(scolor)
        except:
            color = bytes((8, 0, 0))
        if not hasattr(self.percolator, 'perk_quit'):
            self.percolator.perk_quit = 0
        yield self.percolator.perk(delay, color)  # Launch this and return

    def ball_check(self, ball, θ, ω):
        # Checks a Ball and possibly affects it
        # Return a list of balls to replace it
        # (e.g. just [ball] to make no changes)
        rv = []
        #        if self.zap_balls:
        #            ball.zap = True
        #            rv.append(ball)
        #        if θ > π:
        #            θ -= 2 * π

        #        elif θ <= -2.408554 <= ball.θ: # and ball.ω >= 0:
        if θ <= -2.408554 <= ball.θ:  # and ball.ω >= 0:
            # crossed off the top of the "C"
            #            ball.zap = True
            #            rv.append(ball)
            #print("θ=%f, ω=%f" % (θ, ω ))
            #print("zapped %r" % ball)
            self.loop.call_soon(self.perk_and_roll(100, ball.color))

        #elif θ < 0.0 < ball.θ: # and ball.ω >= 0:
        #elif θ < 0.0 < ball.θ or θ > 0.0 > ball.θ : # and ball.ω >= 0:
        elif θ < 0.0 < ball.θ or \
                θ > 0.0 > ball.θ and max(abs(θ), abs(ball.θ)) < 1.5: # and ball.ω >= 0:
            # Crossed the centerline of the drive rollers
            #print("rollered %r" % ball)
            #ball.ω = max(ball.ω , 2.08)
            #            # Can't omit this ball, have to zap it for correct rendering
            #            ball.zap = True
            #            rv.append(ball)

            # Grind this ball up into primary colors
            color = list(iter(ball.color))
            #Below does not grind up fused primaries of same color:
            #colors = list(v for v in [(color[0], 0, 0),
            #                          (0, color[1], 0),
            #                          (0, 0, color[2])]
            #              if sum(v))

            t = stoichiometric = self.percolator.stoichiometric
            stoi_primaries = [(t[0], 0, 0), (0, t[1], 0), (0, 0, t[2])]
            colors = []
            for i in range(3):
                while color[i] >= stoichiometric[i]:
                    colors.append(stoi_primaries[i])
                    color[i] -= stoichiometric[i]
                if color[i]:
                    t = [0, 0, 0]
                    t[i] = color[i]
                    colors.append(tuple(t))

            assert colors, colors  # At least one
            for c in colors:
                rv.append(Ball(θ=0.1, ω=rand.gauss(4.5, 0.2), color=c))
            #print(rv)
        else:
            rv.append(ball)
        return rv

    @coroutine
    def perk_and_roll(self, speed, color, i=None):
        out_color = yield from self.percolator.perk(speed, color, i)
        if out_color is not None:
            ball = Ball(θ=2 * π * -7 / 60, ω=0.3, color=out_color)
            self.rr.balls.append(ball)
        #else:
        #    print("perk yielded a None")

    @coroutine
    def bingo(self):
        stars = list(range(7, 63, 7))
        p = self.percolator
        lattice = p.lattice
        rand.shuffle(stars)
        for i in stars:
            yield from sleep(200)
            color = tuple(lattice[i])
            p.set_color_of(i, (0, 0, 0))
            i = self.percolator.down(i, rng() & 1)
            yield self.perk_and_roll(100, color, i)

    @coroutine
    def spin_feed_rollers(self):
        lower, upper = self.feed_rollers
        lower.center[2] = upper.center[2] = 1
        v = 1.0
        for i in range(len(lower.gear)):
            lower.gear[i] = [v, 0, 0]
            upper.gear[(3 - i) % len(lower.gear)] = [0, v, 0]
            v *= 0.3
        while True:
            #time = self.loop.time
            #then = time()
            lower.gear.cw()
            upper.gear.ccw()
            lower.render()
            upper.render()
            #now = time()
            #t = 20 - (now - then)
            #then = now
            #yield from sleep(t)
            yield from sleep(20)

    @coroutine
    def manage_brightness(self):
        a = pyb.ADC(pyb.Pin('Y12'))
        amb = a.read() / 4096
        while True:
            v = a.read()
            amb = 0.95 * amb + 0.05 * v / 4096
            bv = 254 * amb + 1
            self.set_brightness(bv)
            yield from sleep(123)

    @coroutine
    def play(self, cli, cmd, rol):
        yield self.percolator.play()

    @coroutine
    def stop(self, cli, cmd, rol):
        self.percolator.play_on = False
        yield

    @coroutine
    def master(self):
        self.loop = yield GetRunningLoop(None)
        yield self.manage_brightness()
        yield self.percolator.keep_leds_current(10)
        for i in range(7, 63, 7):
            self.percolator.set_color_of(i, self.percolator.stoichiometric)
        yield self.percolator.bingo()
        yield self.rr.integrate_continuously()
        yield self.spin_feed_rollers()
        while True:
            yield from self.flash_LED(self.act_led)
            yield from sleep(1000)

    def run(self):
        loop = get_event_loop()
        loop.run_until_complete(self.master())
Example #6
0
class Lightshow:
    def __init__(self, write_fun=None, config={}):
        self.config = config

        if write_fun is None:
            @coroutine
            def write(self, *args):
                print(*args)
            self.write = write
        else:
            self.write = write_fun

        self.act_led = pyb.LED(3)
        self.err_led = pyb.LED(1)
        self.pkt_led = pyb.LED(2)

        self.pots = [0] * 4

        self.percolator = \
                Percolator(WS2812(spi_bus=config['leds'].get('spi'),
                                  led_count=config['leds'].get('qty')))
        self.percolator.bingo = self.bingo

        self.ws_rings = WS2812(2, 2*7 + 45)
        self.ring_lights = Lights(self.ws_rings)

        self.feed_rollers = [Jewel7(lights=self.ring_lights[0:7]),
                             Jewel7(lights=self.ring_lights[7:14])]

        self.rr = RingRamp(lights=self.ring_lights[14:],
                           circumference=60, \
                           bottom=7, \
                           g=-40.0,
                           ball_check_fun = self.ball_check)

#        self.zap_balls = False
        self.set_brightness(31)
        
    def set_brightness(self, v):
        self.brightness = self.rr.brightness = self.percolator.brightness = v
        self.feed_rollers[0].brightness = self.feed_rollers[1].brightness = v
        
    @coroutine
    def flash_LED(self, led, dur=1):
        led.on()
        yield from sleep(dur)
        led.off()

    @coroutine
    def fuzzle(self, quit_name):
        # For testing
        while not getattr(self, quit_name):
            #yield from self.flash_LED(self.err_led)
            # More queue-costly but let's us proceed without waiting for photons
            yield self.flash_LED(self.err_led) # let a coro do it so we can proceed
            yield from sleep(100)
        assert getattr(self, quit_name)
        setattr(self, quit_name, max(getattr(self, quit_name) - 1, 0))
        

    @coroutine
    def handle_pots(self, b):
        for i in range(4):
            self.pots[i] = big_endian_int(b[2*i:2*(i+1)])
        yield from self.show_pots()
        
    @coroutine
    def show_pots(self):
        s = ', '.join("%d" % v for v in self.pots)
        yield from self.supertitle("Pots: " + s)


    @coroutine
    def supertitle(self, text):
        yield from self.write(b'\x1b[s\x1b[1;1H\x1b[2K')
        yield from self.write(text)
        yield from self.write('\x1b[u')


    @coroutine
    def perk(self, cli, cmd, rol):
        sdelay, _, scolor = str(rol, 'ASCII').partition(' ')
        try:
            delay = int(sdelay)
        except:
            delay = 100
        try:
            color = eval(scolor)
        except:
            color = bytes((8,0,0))
        if not hasattr(self.percolator, 'perk_quit'):
            self.percolator.perk_quit = 0
        yield self.percolator.perk(delay, color) # Launch this and return


    def ball_check(self, ball, θ, ω ):
        # Checks a Ball and possibly affects it
        # Return a list of balls to replace it
        # (e.g. just [ball] to make no changes)
        rv = []
#        if self.zap_balls:
#            ball.zap = True
#            rv.append(ball)
#        if θ > π:
#            θ -= 2 * π

#        elif θ <= -2.408554 <= ball.θ: # and ball.ω >= 0:
        if θ <= -2.408554 <= ball.θ: # and ball.ω >= 0:
            # crossed off the top of the "C"
#            ball.zap = True
#            rv.append(ball)
            #print("θ=%f, ω=%f" % (θ, ω ))
            #print("zapped %r" % ball)
            self.loop.call_soon(self.perk_and_roll(100, ball.color))

        #elif θ < 0.0 < ball.θ: # and ball.ω >= 0:
        #elif θ < 0.0 < ball.θ or θ > 0.0 > ball.θ : # and ball.ω >= 0:
        elif θ < 0.0 < ball.θ or \
                θ > 0.0 > ball.θ and max(abs(θ), abs(ball.θ)) < 1.5: # and ball.ω >= 0:
            # Crossed the centerline of the drive rollers
            #print("rollered %r" % ball)
            #ball.ω = max(ball.ω , 2.08)
#            # Can't omit this ball, have to zap it for correct rendering
#            ball.zap = True
#            rv.append(ball)

            # Grind this ball up into primary colors
            color = list(iter(ball.color))
            #Below does not grind up fused primaries of same color:
            #colors = list(v for v in [(color[0], 0, 0),
            #                          (0, color[1], 0),
            #                          (0, 0, color[2])]
            #              if sum(v))

            t = stoichiometric = self.percolator.stoichiometric
            stoi_primaries = [(t[0], 0, 0),
                             (0, t[1], 0),
                             (0, 0, t[2])]
            colors = []
            for i in range(3):
                while color[i] >= stoichiometric[i]:
                    colors.append(stoi_primaries[i])
                    color[i] -= stoichiometric[i]
                if color[i]:
                    t = [0, 0, 0]
                    t[i] = color[i]
                    colors.append(tuple(t))

            assert colors, colors # At least one
            for c in colors:
                rv.append(Ball(θ=0.1, ω =rand.gauss(4.5, 0.2), color=c))
            #print(rv)
        else:
            rv.append(ball)
        return rv

    @coroutine
    def perk_and_roll(self, speed, color, i=None):
        out_color = yield from self.percolator.perk(speed, color, i)
        if out_color is not None:
            ball = Ball(θ = 2*π * -7/60,
                        ω = 0.3,
                        color=out_color)
            self.rr.balls.append(ball)
        #else:
        #    print("perk yielded a None")

    @coroutine
    def bingo(self):
        stars = list(range(7, 63, 7))
        p = self.percolator
        lattice = p.lattice
        rand.shuffle(stars)
        for i in stars:
            yield from sleep(200)
            color = tuple(lattice[i])
            p.set_color_of(i, (0,0,0))
            i = self.percolator.down(i, rng()&1)
            yield self.perk_and_roll(100, color, i)

    @coroutine
    def spin_feed_rollers(self):
        lower, upper = self.feed_rollers
        lower.center[2] = upper.center[2] = 1
        v = 1.0
        for i in range(len(lower.gear)):
            lower.gear[i] = [v, 0, 0]
            upper.gear[(3-i)%len(lower.gear)] = [0, v, 0]
            v *= 0.3
        while True:
            #time = self.loop.time
            #then = time()
            lower.gear.cw()
            upper.gear.ccw()
            lower.render()
            upper.render()
            #now = time()
            #t = 20 - (now - then)
            #then = now
            #yield from sleep(t)
            yield from sleep(20)

    @coroutine
    def manage_brightness(self):
        a = pyb.ADC(pyb.Pin('Y12'))
        amb = a.read()/4096
        while True:
            v = a.read()
            amb = 0.95*amb + 0.05*v/4096
            bv = 254*amb + 1
            self.set_brightness(bv)
            yield from sleep(123)

    @coroutine
    def play(self, cli, cmd, rol):
        yield self.percolator.play()

    @coroutine
    def stop(self, cli, cmd, rol):
        self.percolator.play_on = False
        yield

    @coroutine
    def master(self):
        self.loop = yield GetRunningLoop(None)
        yield self.manage_brightness()
        yield self.percolator.keep_leds_current(10)
        for i in range(7, 63, 7):
            self.percolator.set_color_of(i, self.percolator.stoichiometric)
        yield self.percolator.bingo()
        yield self.rr.integrate_continuously()
        yield self.spin_feed_rollers()
        while True:
            yield from self.flash_LED(self.act_led)
            yield from sleep(1000)

    def run(self):
        loop = get_event_loop()
        loop.run_until_complete(self.master())
class PercolatorTestCase(unittest.TestCase):
    def setUp(self):
        #logging.basicConfig(level=logging.INFO)
        #random.seed("WSlice")
        self.ws = ws = WS2812(1,64)
        for i in range(len(ws)):
            ws[i] = (i, 2*i, 3*i)
        self.p = Percolator(ws)

    def tearDown(self):
        self.ws = self.p = None
        gc.collect()
    
    def test_render_init(self):
        # A Percolator is initially in a state that renders all off
        self.p.render()
        self.assertTrue(all(sum(v)==0 for v in self.ws))

    def test_render_time(self):
        # Rendering takes the expected amount of time
        n = 10
        t0 = pyb.micros()
        for i in range(n):
            self.p.render()
        dt = pyb.elapsed_micros(t0)
        average_ms = dt / (n * 1000)
        print("%d renders average %f ms" % (n, average_ms), end='')
        self.assertTrue(average_ms < 15, "average render time %f ms" % (average_ms))

    def test_render_at_index_0(self):
        # A Percolator can render itself to the backing LEDs
        lattice = self.p.lattice
        ref = (12, 34, 56)
        for i, v in enumerate(ref):
            lattice[0][i] = v
        self.p.render()
        self.assertEqual(tuple(self.ws[0]), ref)
        self.assertTrue(all(sum(v)==0 for v in self.ws[1:]))

    def test_render_at_index_0_various_brightness(self):
        # A Percolator can render itself to the backing LEDs with controlled brightness
        lattice = self.p.lattice
        color = (12, 34, 56)
        ref = [0] * 3
        for brightness in (1.0, 0.5, 0.1, 0.01, 3/17, 1/254, 1/255, 1/256, 0.0):
            print(' %r' % brightness, end='')
            self.p.brightness = brightness
            for i, v in enumerate(color):
                lattice[0][i] = v
                ref[i] = round(brightness * v)
            self.p.render()
            self.assertEqual(tuple(self.ws[0]), tuple(ref))
            self.assertTrue(all(sum(v)==0 for v in self.ws[1:]))

    def test_render_at_several_positions(self):
        # A Percolator can render itself to the backing LEDs
        lattice = self.p.lattice
        for k, g in enumerate(tg(64, 0)):
            for i, v in enumerate(g):
                lattice[k][i] = v
        self.p.render()
        for led, g in zip(self.ws, tg(64,0)):
            self.assertEqual(tuple(led), tuple(g))
Example #8
0
class PercolatorTestCase(unittest.TestCase):
    def setUp(self):
        #logging.basicConfig(level=logging.INFO)
        #random.seed("WSlice")
        self.ws = ws = WS2812(1, 64)
        for i in range(len(ws)):
            ws[i] = (i, 2 * i, 3 * i)
        self.p = Percolator(ws)

    def tearDown(self):
        self.ws = self.p = None
        gc.collect()

    def test_render_init(self):
        # A Percolator is initially in a state that renders all off
        self.p.render()
        self.assertTrue(all(sum(v) == 0 for v in self.ws))

    def test_render_time(self):
        # Rendering takes the expected amount of time
        n = 10
        t0 = pyb.micros()
        for i in range(n):
            self.p.render()
        dt = pyb.elapsed_micros(t0)
        average_ms = dt / (n * 1000)
        print("%d renders average %f ms" % (n, average_ms), end='')
        self.assertTrue(average_ms < 15,
                        "average render time %f ms" % (average_ms))

    def test_render_at_index_0(self):
        # A Percolator can render itself to the backing LEDs
        lattice = self.p.lattice
        ref = (12, 34, 56)
        for i, v in enumerate(ref):
            lattice[0][i] = v
        self.p.render()
        self.assertEqual(tuple(self.ws[0]), ref)
        self.assertTrue(all(sum(v) == 0 for v in self.ws[1:]))

    def test_render_at_index_0_various_brightness(self):
        # A Percolator can render itself to the backing LEDs with controlled brightness
        lattice = self.p.lattice
        color = (12, 34, 56)
        ref = [0] * 3
        for brightness in (1.0, 0.5, 0.1, 0.01, 3 / 17, 1 / 254, 1 / 255,
                           1 / 256, 0.0):
            print(' %r' % brightness, end='')
            self.p.brightness = brightness
            for i, v in enumerate(color):
                lattice[0][i] = v
                ref[i] = round(brightness * v)
            self.p.render()
            self.assertEqual(tuple(self.ws[0]), tuple(ref))
            self.assertTrue(all(sum(v) == 0 for v in self.ws[1:]))

    def test_render_at_several_positions(self):
        # A Percolator can render itself to the backing LEDs
        lattice = self.p.lattice
        for k, g in enumerate(tg(64, 0)):
            for i, v in enumerate(g):
                lattice[k][i] = v
        self.p.render()
        for led, g in zip(self.ws, tg(64, 0)):
            self.assertEqual(tuple(led), tuple(g))