Local-Voice/led_demo/ws2812b_effects_show.py
2025-09-27 14:30:19 +08:00

463 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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()