Byonoy L96 — LED bar#
The L96 has a 20-pixel addressable RGB front bar on the chassis. PyLabRobot exposes two methods to drive it:
Method |
Use for |
|---|---|
|
Single color across all 20 pixels, optionally animated by the firmware ( |
|
Per-pixel control — supply a list of up to 20 RGB triplets. Fast enough for real-time animation. |
Connect#
We’ll talk to the device’s driver directly, so the bar can be driven without setting up a plate read.
from pylabrobot.byonoy import byonoy_l96
base, reader = byonoy_l96(name="l96")
await reader.setup()
drv = reader.driver
Solid colors#
The simplest call: one color, SOLID effect (the default). The firmware snaps the bar to that color.
import asyncio
await drv.set_led_color((255, 0, 0)) # red
await asyncio.sleep(1)
await drv.set_led_color((0, 255, 0)) # green
await asyncio.sleep(1)
await drv.set_led_color((0, 0, 255)) # blue
await asyncio.sleep(1)
await drv.set_led_color((0, 0, 0)) # off
Built-in effects#
The firmware can animate the base color for you. Pass duration_ms to set how long the effect runs before reverting to firmware control. Use force=True to override an unexpired previous duration.
Effect |
Behavior |
|---|---|
|
Snap to color (default) |
|
Pulse brightness |
|
Flash on/off |
|
Bouncing dot across the bar |
|
Cycle through hues (ignores supplied color) |
|
Fill progressively, driven by |
await drv.set_led_color((0, 255, 0), "breathing", duration_ms=6000)
await asyncio.sleep(6)
await drv.set_led_color((255, 0, 255), "cylon", duration_ms=4000, force=True)
await asyncio.sleep(4)
await drv.set_led_color((0, 0, 0)) # back to off
Per-pixel control#
set_led_colors(colors) takes a list of up to 20 (r, g, b) triplets, one per pixel (left to right). Shorter lists are zero-padded; longer ones are truncated.
# Left half red, right half blue
await drv.set_led_colors([(255, 0, 0)] * 10 + [(0, 0, 255)] * 10)
await asyncio.sleep(2)
# Rainbow gradient across the bar
import colorsys
def hue(i, n=20):
r, g, b = colorsys.hsv_to_rgb(i / n, 1, 1)
return (int(r * 255), int(g * 255), int(b * 255))
await drv.set_led_colors([hue(i) for i in range(20)])
await asyncio.sleep(3)
# Every other pixel
await drv.set_led_colors([(0, 255, 0) if i % 2 == 0 else (0, 0, 0) for i in range(20)])
await asyncio.sleep(2)
await drv.set_led_colors([(0, 0, 0)] * 20) # off
Animation recipe: KITT scanner#
A back-and-forth scanner with a fading trail — the kind of thing you’d want as a “robot is busy” indicator. Frame rate is set by how fast you call set_led_colors; ~30 fps is comfortable.
import asyncio
N = 20
trail = 4 # length of the fading trail
decay = 0.45 # brightness ratio per trail step
step_s = 0.06 # ~16 fps; lower for faster
def frame(head):
px = [(0, 0, 0)] * N
for k in range(trail + 1):
v = int(255 * (decay ** k))
if 0 <= head - k < N:
px[head - k] = (v, 0, 0) # red trail
return px
positions = list(range(N)) + list(range(N - 2, 0, -1)) # 0..19..1
for _ in range(3): # 3 ping-pong cycles
for head in positions:
await drv.set_led_colors(frame(head))
await asyncio.sleep(step_s)
await drv.set_led_colors([(0, 0, 0)] * 20)
Animation recipe: walking dot#
Simplest possible animation — one bright pixel marches across the bar. Useful as a progress indicator with a known step count.
for pos in range(20):
px = [(0, 0, 0)] * 20
px[pos] = (0, 255, 0)
await drv.set_led_colors(px)
await asyncio.sleep(0.15)
await drv.set_led_colors([(0, 0, 0)] * 20)
Teardown#
await drv.set_led_color((0, 0, 0)) # ensure bar is off
await reader.stop()
Reference#
set_led_color(color, effect, *, duration_ms=0, force=False, low_power=False)— single uniform color, optional firmware-driven effect.set_led_colors(colors)— list of up to 20(r, g, b)triplets, one per pixel. Pads with black; truncates if longer.Both methods live on
reader.driver. Source:pylabrobot/byonoy/driver.py.