463 lines
15 KiB
Python
463 lines
15 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
WS2812B LED特效展示脚本
|
||
基于精确时序的多种LED效果
|
||
"""
|
||
|
||
import time
|
||
import random
|
||
import math
|
||
import RPi.GPIO as GPIO
|
||
from rpi_ws281x import Color, PixelStrip
|
||
|
||
|
||
class WS2812B_WS281X:
|
||
def __init__(self, led_count=10, brightness=100):
|
||
self.led_count = led_count
|
||
self.brightness = brightness
|
||
|
||
# WS2812B配置
|
||
LED_PIN = 10 # GPIO引脚(SPI模式)
|
||
LED_FREQ_HZ = 800000 # LED信号频率
|
||
LED_DMA = 10 # DMA通道
|
||
LED_INVERT = False # 是否反转信号
|
||
LED_CHANNEL = 0 # PWM通道
|
||
|
||
# 创建PixelStrip对象
|
||
self.strip = PixelStrip(led_count, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, brightness, LED_CHANNEL)
|
||
self.strip.begin()
|
||
|
||
# 初始化后清空
|
||
time.sleep(0.1)
|
||
for i in range(led_count):
|
||
self.strip.setPixelColor(i, Color(0, 0, 0))
|
||
self.strip.show()
|
||
time.sleep(0.1)
|
||
|
||
def show(self, colors):
|
||
"""显示颜色"""
|
||
for i, (r, g, b) in enumerate(colors):
|
||
self.strip.setPixelColor(i, Color(r, g, b))
|
||
self.strip.show()
|
||
|
||
def cleanup(self):
|
||
"""清理资源"""
|
||
# 清空所有LED
|
||
for i in range(self.led_count):
|
||
self.strip.setPixelColor(i, Color(0, 0, 0))
|
||
self.strip.show()
|
||
|
||
# ===== 新增LED特效函数 =====
|
||
|
||
def breathing_effect(ws, color=(255, 0, 0), cycles=5, min_brightness=0.1, max_brightness=0.8):
|
||
"""呼吸灯效果"""
|
||
print("呼吸灯效果开始...")
|
||
|
||
steps = 50
|
||
for cycle in range(cycles):
|
||
print(f" 呼吸循环 {cycle + 1}/{cycles}")
|
||
|
||
# 呼吸(渐亮)
|
||
for i in range(steps):
|
||
brightness = min_brightness + (max_brightness - min_brightness) * (i / steps)
|
||
r = int(color[0] * brightness)
|
||
g = int(color[1] * brightness)
|
||
b = int(color[2] * brightness)
|
||
|
||
colors = [(r, g, b)] * ws.led_count
|
||
ws.show(colors)
|
||
time.sleep(0.02)
|
||
|
||
# 呼吸(渐暗)
|
||
for i in range(steps):
|
||
brightness = max_brightness - (max_brightness - min_brightness) * (i / steps)
|
||
r = int(color[0] * brightness)
|
||
g = int(color[1] * brightness)
|
||
b = int(color[2] * brightness)
|
||
|
||
colors = [(r, g, b)] * ws.led_count
|
||
ws.show(colors)
|
||
time.sleep(0.02)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("呼吸灯效果完成!")
|
||
|
||
def color_wipe(ws, color=(255, 0, 0), delay=0.1, cycles=3):
|
||
"""颜色擦除效果"""
|
||
print("颜色擦除效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 擦除循环 {cycle + 1}/{cycles}")
|
||
|
||
# 正向擦除
|
||
for i in range(ws.led_count):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
for j in range(i + 1):
|
||
colors[j] = color
|
||
ws.show(colors)
|
||
time.sleep(delay)
|
||
|
||
# 反向擦除
|
||
for i in range(ws.led_count - 1, -1, -1):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
for j in range(i + 1):
|
||
colors[j] = color
|
||
ws.show(colors)
|
||
time.sleep(delay)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("颜色擦除效果完成!")
|
||
|
||
def theater_chase(ws, color1=(255, 0, 0), color2=(0, 0, 0), delay=0.1, cycles=10):
|
||
"""剧院追逐效果"""
|
||
print("剧院追逐效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 剧院循环 {cycle + 1}/{cycles}")
|
||
|
||
for i in range(3):
|
||
colors = []
|
||
for j in range(ws.led_count):
|
||
if (j + i) % 3 == 0:
|
||
colors.append(color1)
|
||
else:
|
||
colors.append(color2)
|
||
ws.show(colors)
|
||
time.sleep(delay)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("剧院追逐效果完成!")
|
||
|
||
def rainbow_cycle(ws, delay=0.02, cycles=3):
|
||
"""彩虹循环效果"""
|
||
print("彩虹循环效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 彩虹循环 {cycle + 1}/{cycles}")
|
||
|
||
for i in range(256):
|
||
colors = []
|
||
for j in range(ws.led_count):
|
||
pixel_index = (i * 256 // ws.led_count + j) % 256
|
||
colors.append(wheel(pixel_index))
|
||
ws.show(colors)
|
||
time.sleep(delay)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("彩虹循环效果完成!")
|
||
|
||
def wheel(pos):
|
||
"""生成彩虹颜色"""
|
||
pos = 255 - pos
|
||
if pos < 85:
|
||
return (255 - pos * 3, 0, pos * 3)
|
||
elif pos < 170:
|
||
pos -= 85
|
||
return (0, pos * 3, 255 - pos * 3)
|
||
else:
|
||
pos -= 170
|
||
return (pos * 3, 255 - pos * 3, 0)
|
||
|
||
def fire_effect(ws, delay=0.1, cycles=10):
|
||
"""火焰效果"""
|
||
print("火焰效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 火焰循环 {cycle + 1}/{cycles}")
|
||
|
||
colors = []
|
||
for i in range(ws.led_count):
|
||
# 随机生成火焰颜色(红、橙、黄)
|
||
rand = random.random()
|
||
if rand < 0.3:
|
||
colors.append((255, 0, 0)) # 红
|
||
elif rand < 0.6:
|
||
colors.append((255, 100, 0)) # 橙
|
||
else:
|
||
colors.append((255, 255, 0)) # 黄
|
||
|
||
ws.show(colors)
|
||
time.sleep(delay)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("火焰效果完成!")
|
||
|
||
def sparkle_effect(ws, base_color=(50, 50, 50), sparkle_color=(255, 255, 255), delay=0.1, cycles=20):
|
||
"""闪烁效果"""
|
||
print("闪烁效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
colors = [base_color] * ws.led_count
|
||
|
||
# 随机选择几个LED进行闪烁
|
||
sparkle_count = random.randint(1, 3)
|
||
for _ in range(sparkle_count):
|
||
pos = random.randint(0, ws.led_count - 1)
|
||
colors[pos] = sparkle_color
|
||
|
||
ws.show(colors)
|
||
time.sleep(delay)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("闪烁效果完成!")
|
||
|
||
def pulse_effect(ws, color=(255, 0, 0), cycles=5):
|
||
"""脉冲效果"""
|
||
print("脉冲效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 脉冲循环 {cycle + 1}/{cycles}")
|
||
|
||
# 从中心向外扩散
|
||
for i in range(ws.led_count // 2 + 1):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
|
||
# 设置左右对称的LED
|
||
if i < ws.led_count:
|
||
colors[i] = color
|
||
colors[ws.led_count - 1 - i] = color
|
||
|
||
ws.show(colors)
|
||
time.sleep(0.05)
|
||
|
||
# 从边缘向中心收缩
|
||
for i in range(ws.led_count // 2, -1, -1):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
|
||
if i < ws.led_count:
|
||
colors[i] = color
|
||
colors[ws.led_count - 1 - i] = color
|
||
|
||
ws.show(colors)
|
||
time.sleep(0.05)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("脉冲效果完成!")
|
||
|
||
def color_mixing(ws, color1=(255, 0, 0), color2=(0, 0, 255), delay=0.1, cycles=10):
|
||
"""颜色混合效果"""
|
||
print("颜色混合效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 混合循环 {cycle + 1}/{cycles}")
|
||
|
||
# 计算混合比例
|
||
ratio = (cycle % 20) / 20.0
|
||
if ratio > 0.5:
|
||
ratio = 1.0 - ratio
|
||
|
||
# 混合颜色
|
||
r = int(color1[0] * (1 - ratio) + color2[0] * ratio)
|
||
g = int(color1[1] * (1 - ratio) + color2[1] * ratio)
|
||
b = int(color1[2] * (1 - ratio) + color2[2] * ratio)
|
||
|
||
colors = [(r, g, b)] * ws.led_count
|
||
ws.show(colors)
|
||
time.sleep(delay)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("颜色混合效果完成!")
|
||
|
||
def running_light(ws, colors=None, delay=0.15, cycles=2):
|
||
"""跑马灯效果(保留原有函数)"""
|
||
if colors is None:
|
||
colors = [(150, 0, 0), (0, 150, 0), (0, 0, 150)]
|
||
|
||
print("跑马灯效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 跑马灯循环 {cycle + 1}/{cycles}")
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
time.sleep(0.2)
|
||
|
||
for i in range(ws.led_count):
|
||
led_colors = [(0, 0, 0)] * ws.led_count
|
||
for j, color in enumerate(colors):
|
||
pos = (i + j) % ws.led_count
|
||
led_colors[pos] = color
|
||
|
||
ws.show(led_colors)
|
||
time.sleep(delay)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("跑马灯效果完成!")
|
||
|
||
def simple_single_chase(ws, color=(255, 0, 0), delay=0.15, cycles=2):
|
||
"""简化版单点追逐效果(保留原有函数)"""
|
||
print("简化版单点追逐效果开始...")
|
||
|
||
color = (min(color[0], 150), min(color[1], 150), min(color[2], 150))
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 循环 {cycle + 1}/{cycles}")
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
time.sleep(0.3)
|
||
|
||
for i in range(ws.led_count):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
colors[i] = color
|
||
ws.show(colors)
|
||
time.sleep(delay)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
time.sleep(0.2)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
time.sleep(0.2)
|
||
print("简化版单点追逐效果完成!")
|
||
|
||
def rainbow_effect(ws, delay=0.2, cycles=3):
|
||
"""彩虹效果(保留原有函数)"""
|
||
print("彩虹效果开始...")
|
||
|
||
rainbow_colors = [
|
||
(150, 0, 0), # 红
|
||
(150, 75, 0), # 橙
|
||
(150, 150, 0), # 黄
|
||
(0, 150, 0), # 绿
|
||
(0, 0, 150), # 蓝
|
||
(50, 0, 100), # 靛
|
||
(100, 0, 150) # 紫
|
||
]
|
||
|
||
for cycle in range(cycles):
|
||
colors = []
|
||
for i in range(ws.led_count):
|
||
color_index = i % len(rainbow_colors)
|
||
colors.append(rainbow_colors[color_index])
|
||
|
||
for shift in range(len(colors)):
|
||
shifted_colors = []
|
||
for i in range(ws.led_count):
|
||
color_index = (i + shift) % len(rainbow_colors)
|
||
shifted_colors.append(rainbow_colors[color_index])
|
||
|
||
ws.show(shifted_colors)
|
||
time.sleep(delay)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("彩虹效果完成!")
|
||
|
||
def rainbow_simple(ws, wait_ms=20, iterations=1):
|
||
"""简单彩虹效果(基于原始文件)"""
|
||
print("简单彩虹效果开始...")
|
||
|
||
for j in range(256 * iterations):
|
||
colors = []
|
||
for i in range(ws.led_count):
|
||
colors.append(wheel((i + j) & 255))
|
||
ws.show(colors)
|
||
time.sleep(wait_ms / 1000.0)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("简单彩虹效果完成!")
|
||
|
||
def reset_strip(ws):
|
||
"""重置LED灯带"""
|
||
print("重置LED灯带...")
|
||
for i in range(ws.led_count):
|
||
ws.strip.setPixelColor(i, Color(0, 0, 0))
|
||
ws.strip.show()
|
||
time.sleep(0.1)
|
||
|
||
def test_single_color_with_reset(ws, color, color_name):
|
||
"""测试单个颜色并立即重置"""
|
||
print(f"测试{color_name}...")
|
||
|
||
try:
|
||
# 设置颜色
|
||
for i in range(ws.led_count):
|
||
ws.strip.setPixelColor(i, color)
|
||
ws.strip.show()
|
||
time.sleep(0.001)
|
||
|
||
# 短暂显示
|
||
time.sleep(0.5)
|
||
|
||
# 立即清空
|
||
for i in range(ws.led_count):
|
||
ws.strip.setPixelColor(i, Color(0, 0, 0))
|
||
ws.strip.show()
|
||
time.sleep(0.1)
|
||
|
||
print(f"{color_name}测试完成")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"{color_name}测试失败: {e}")
|
||
return False
|
||
|
||
def safe_color_test(ws):
|
||
"""安全颜色测试"""
|
||
print("安全颜色测试...")
|
||
|
||
success = True
|
||
success &= test_single_color_with_reset(ws, Color(255, 0, 0), "红色")
|
||
time.sleep(0.5)
|
||
|
||
success &= test_single_color_with_reset(ws, Color(0, 255, 0), "绿色")
|
||
time.sleep(0.5)
|
||
|
||
success &= test_single_color_with_reset(ws, Color(0, 0, 255), "蓝色")
|
||
time.sleep(0.5)
|
||
|
||
success &= test_single_color_with_reset(ws, Color(255, 255, 255), "白色")
|
||
|
||
if success:
|
||
print("所有颜色测试完成")
|
||
else:
|
||
print("颜色测试过程中出现问题")
|
||
reset_strip(ws)
|
||
|
||
# ===== 主函数:按顺序播放所有特效 =====
|
||
|
||
def show_all_effects():
|
||
"""按顺序播放所有LED特效"""
|
||
ws = WS2812B_WS281X(led_count=10, brightness=100)
|
||
|
||
try:
|
||
print("🎆 LED特效展示开始!")
|
||
print("=" * 50)
|
||
|
||
# 特效列表
|
||
effects = [
|
||
("安全颜色测试", lambda: safe_color_test(ws)),
|
||
("呼吸灯效果", lambda: breathing_effect(ws, color=(255, 0, 0), cycles=3)),
|
||
("颜色擦除效果", lambda: color_wipe(ws, color=(0, 255, 0), cycles=2)),
|
||
("剧院追逐效果", lambda: theater_chase(ws, color1=(255, 255, 0), color2=(0, 0, 0), cycles=8)),
|
||
("彩虹循环效果", lambda: rainbow_cycle(ws, delay=0.05, cycles=2)),
|
||
("简单彩虹效果", lambda: rainbow_simple(ws, wait_ms=20, iterations=1)),
|
||
("火焰效果", lambda: fire_effect(ws, delay=0.15, cycles=8)),
|
||
("闪烁效果", lambda: sparkle_effect(ws, base_color=(20, 20, 20), sparkle_color=(255, 255, 255), cycles=15)),
|
||
("脉冲效果", lambda: pulse_effect(ws, color=(255, 0, 255), cycles=3)),
|
||
("颜色混合效果", lambda: color_mixing(ws, color1=(255, 0, 0), color2=(0, 255, 0), cycles=10)),
|
||
("跑马灯效果", lambda: running_light(ws, colors=[(255, 0, 0), (0, 255, 0), (0, 0, 255)], delay=0.2, cycles=2)),
|
||
("单点追逐效果", lambda: simple_single_chase(ws, color=(0, 255, 255), delay=0.15, cycles=2)),
|
||
("彩虹效果", lambda: rainbow_effect(ws, delay=0.2, cycles=2)),
|
||
]
|
||
|
||
# 按顺序播放每个特效
|
||
for i, (name, effect_func) in enumerate(effects):
|
||
print(f"\n🎭 特效 {i+1}/{len(effects)}: {name}")
|
||
print("-" * 30)
|
||
|
||
effect_func()
|
||
|
||
# 特效之间短暂停顿
|
||
time.sleep(1)
|
||
|
||
print("\n🎉 所有LED特效播放完成!")
|
||
print("=" * 50)
|
||
|
||
except KeyboardInterrupt:
|
||
print("\n⏹️ 用户中断,停止播放...")
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
except Exception as e:
|
||
print(f"\n❌ 播放出错: {e}")
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
finally:
|
||
ws.cleanup()
|
||
print("🧹 清理完成")
|
||
|
||
if __name__ == "__main__":
|
||
show_all_effects() |