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

524 lines
17 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特效
包含物理效果、游戏效果和节日主题特效
"""
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(int(r), int(g), int(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()
# ===== 物理效果类特效 =====
def gravity_bounce(ws, ball_color=(255, 100, 0), cycles=5):
"""重力弹跳效果"""
print("重力弹跳效果开始...")
for cycle in range(cycles):
print(f" 弹跳 {cycle + 1}/{cycles}")
# 模拟重力弹跳
height = 0
velocity = 0
gravity = 0.5
bounce_damping = 0.8
for _ in range(50):
velocity += gravity
height += velocity
# 检查是否触底
if height >= ws.led_count - 1:
height = ws.led_count - 1
velocity = -velocity * bounce_damping
# 显示球的位置
colors = [(0, 0, 0)] * ws.led_count
ball_pos = int(height)
if 0 <= ball_pos < ws.led_count:
colors[ball_pos] = ball_color
# 添加影子效果
if ball_pos > 0:
shadow_intensity = max(0, int(50 - abs(height - ball_pos) * 20))
colors[ball_pos - 1] = (shadow_intensity, shadow_intensity // 2, 0)
ws.show(colors)
time.sleep(0.05)
ws.show([(0, 0, 0)] * ws.led_count)
print("重力弹跳效果完成!")
def wave_ripple(ws, center_color=(0, 100, 255), cycles=8):
"""波纹扩散效果"""
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
# 从中心向两边扩散
center = ws.led_count // 2
distance = abs(i - center)
# 在两边对称的位置显示波纹
if center - distance >= 0:
intensity = max(0, 255 - distance * 50)
colors[center - distance] = (
int(center_color[0] * intensity / 255),
int(center_color[1] * intensity / 255),
int(center_color[2] * intensity / 255)
)
if center + distance < ws.led_count and distance > 0:
intensity = max(0, 255 - distance * 50)
colors[center + distance] = (
int(center_color[0] * intensity / 255),
int(center_color[1] * intensity / 255),
int(center_color[2] * intensity / 255)
)
ws.show(colors)
time.sleep(0.1)
ws.show([(0, 0, 0)] * ws.led_count)
print("波纹扩散效果完成!")
def magnet_effect(ws, metal_color=(150, 150, 150), magnet_color=(255, 0, 0), cycles=6):
"""磁铁吸引效果"""
print("磁铁吸引效果开始...")
for cycle in range(cycles):
print(f" 磁铁循环 {cycle + 1}/{cycles}")
# 磁铁位置(左右两端)
magnet_positions = [0, ws.led_count - 1]
for frame in range(30):
colors = [(0, 0, 0)] * ws.led_count
# 显示磁铁
for pos in magnet_positions:
colors[pos] = magnet_color
# 计算金属粒子位置
for i in range(3): # 3个金属粒子
particle_pos = int(4 + 2 * math.sin(frame * 0.3 + i * 2))
if 0 < particle_pos < ws.led_count - 1:
colors[particle_pos] = metal_color
ws.show(colors)
time.sleep(0.1)
ws.show([(0, 0, 0)] * ws.led_count)
print("磁铁吸引效果完成!")
def pendulum_swing(ws, pendulum_color=(255, 255, 0), cycles=10):
"""钟摆摆动效果"""
print("钟摆摆动效果开始...")
for cycle in range(cycles):
print(f" 钟摆循环 {cycle + 1}/{cycles}")
# 模拟钟摆运动
for angle in range(-60, 61, 5):
colors = [(0, 0, 0)] * ws.led_count
# 计算钟摆位置
center = ws.led_count // 2
position = int(center + angle / 15)
if 0 <= position < ws.led_count:
colors[position] = pendulum_color
# 添加运动模糊效果
if angle > -60 and position > 0:
colors[position - 1] = (pendulum_color[0] // 3, pendulum_color[1] // 3, pendulum_color[2] // 3)
ws.show(colors)
time.sleep(0.08)
# 反向摆动
for angle in range(60, -61, -5):
colors = [(0, 0, 0)] * ws.led_count
center = ws.led_count // 2
position = int(center + angle / 15)
if 0 <= position < ws.led_count:
colors[position] = pendulum_color
if angle < 60 and position < ws.led_count - 1:
colors[position + 1] = (pendulum_color[0] // 3, pendulum_color[1] // 3, pendulum_color[2] // 3)
ws.show(colors)
time.sleep(0.08)
ws.show([(0, 0, 0)] * ws.led_count)
print("钟摆摆动效果完成!")
# ===== 游戏效果类特效 =====
def snake_game(ws, cycles=3):
"""贪吃蛇游戏效果"""
print("贪吃蛇游戏效果开始...")
snake_color = (0, 255, 0)
food_color = (255, 0, 0)
for cycle in range(cycles):
print(f" 贪吃蛇 {cycle + 1}/{cycles}")
# 初始化蛇的位置
snake = [(0, 0), (0, 1), (0, 2)] # 简化为线性移动
food = random.randint(3, ws.led_count - 1)
for step in range(20):
colors = [(0, 0, 0)] * ws.led_count
# 移动蛇
if step < 15:
new_head = (snake[-1][0] + 1) % ws.led_count
snake.append((new_head, snake[-1][1] + 1))
snake.pop(0)
# 显示蛇
for i, (pos, _) in enumerate(snake):
if i == len(snake) - 1: # 蛇头
colors[pos % ws.led_count] = (0, 150, 0)
else: # 蛇身
colors[pos % ws.led_count] = snake_color
# 显示食物
colors[food] = food_color
ws.show(colors)
time.sleep(0.2)
ws.show([(0, 0, 0)] * ws.led_count)
print("贪吃蛇游戏效果完成!")
def space_invaders(ws, cycles=5):
"""太空侵略者效果"""
print("太空侵略者效果开始...")
alien_color = (0, 255, 0)
bullet_color = (255, 255, 0)
for cycle in range(cycles):
print(f" 入侵者 {cycle + 1}/{cycles}")
# 外星人移动
for direction in [1, -1]:
for step in range(ws.led_count - 2):
colors = [(0, 0, 0)] * ws.led_count
# 显示外星人
alien_pos = 3 + step * direction
if 0 <= alien_pos < ws.led_count:
colors[alien_pos] = alien_color
# 随机子弹
if random.random() < 0.3:
bullet_pos = random.randint(0, ws.led_count - 1)
colors[bullet_pos] = bullet_color
ws.show(colors)
time.sleep(0.15)
ws.show([(0, 0, 0)] * ws.led_count)
print("太空侵略者效果完成!")
def pong_game(ws, cycles=10):
"""乒乓球游戏效果"""
print("乒乓球游戏效果开始...")
paddle_color = (255, 255, 255)
ball_color = (255, 100, 100)
for cycle in range(cycles):
print(f" 乒乓球 {cycle + 1}/{cycles}")
# 球的初始位置和速度
ball_pos = ws.led_count // 2
ball_velocity = 1
for _ in range(30):
colors = [(0, 0, 0)] * ws.led_count
# 显示球拍
colors[0] = paddle_color
colors[ws.led_count - 1] = paddle_color
# 显示球
if 0 <= ball_pos < ws.led_count:
colors[ball_pos] = ball_color
# 移动球
ball_pos += ball_velocity
# 碰撞检测
if ball_pos <= 0 or ball_pos >= ws.led_count - 1:
ball_velocity = -ball_velocity
ws.show(colors)
time.sleep(0.1)
ws.show([(0, 0, 0)] * ws.led_count)
print("乒乓球游戏效果完成!")
def matrix_rain(ws, cycles=8):
"""黑客帝国数字雨效果"""
print("黑客帝国数字雨效果开始...")
for cycle in range(cycles):
print(f" 数字雨 {cycle + 1}/{cycles}")
for frame in range(20):
colors = [(0, 0, 0)] * ws.led_count
# 随机生成数字雨
for i in range(ws.led_count):
if random.random() < 0.3:
intensity = random.randint(100, 255)
colors[i] = (0, intensity, 0)
elif random.random() < 0.1:
# 更亮的"头部"
colors[i] = (100, 255, 100)
ws.show(colors)
time.sleep(0.1)
ws.show([(0, 0, 0)] * ws.led_count)
print("黑客帝国数字雨效果完成!")
# ===== 节日主题特效 =====
def christmas_lights(ws, cycles=8):
"""圣诞彩灯效果"""
print("圣诞彩灯效果开始...")
colors_list = [
(255, 0, 0), # 红
(0, 255, 0), # 绿
(255, 255, 255), # 白
(255, 215, 0), # 金
(0, 0, 255), # 蓝
]
for cycle in range(cycles):
print(f" 圣诞彩灯 {cycle + 1}/{cycles}")
# 随机闪烁
for i in range(15):
colors = [(0, 0, 0)] * ws.led_count
# 随机点亮一些LED
for j in range(ws.led_count):
if random.random() < 0.4:
colors[j] = random.choice(colors_list)
ws.show(colors)
time.sleep(0.2)
ws.show([(0, 0, 0)] * ws.led_count)
print("圣诞彩灯效果完成!")
def fireworks(ws, cycles=6):
"""烟花爆炸效果"""
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
colors[i] = (255, 255, 0) # 黄色上升轨迹
ws.show(colors)
time.sleep(0.05)
# 爆炸效果
explosion_colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (255, 0, 255)]
for frame in range(15):
colors = [(0, 0, 0)] * ws.led_count
# 随机爆炸粒子
for _ in range(random.randint(3, 6)):
pos = random.randint(0, ws.led_count - 1)
colors[pos] = random.choice(explosion_colors)
ws.show(colors)
time.sleep(0.1)
ws.show([(0, 0, 0)] * ws.led_count)
print("烟花爆炸效果完成!")
def valentine_heart(ws, cycles=5):
"""情人节心跳效果"""
print("情人节心跳效果开始...")
for cycle in range(cycles):
print(f" 心跳 {cycle + 1}/{cycles}")
# 心跳模式
for beat in range(3):
colors = [(255, 0, 100)] * ws.led_count # 粉红色
ws.show(colors)
time.sleep(0.1)
colors = [(150, 0, 50)] * ws.led_count # 暗粉色
ws.show(colors)
time.sleep(0.1)
# 暂停
colors = [(0, 0, 0)] * ws.led_count
ws.show(colors)
time.sleep(0.5)
ws.show([(0, 0, 0)] * ws.led_count)
print("情人节心跳效果完成!")
def halloween_pumpkin(ws, cycles=8):
"""万圣节南瓜灯效果"""
print("万圣节南瓜灯效果开始...")
for cycle in range(cycles):
print(f" 南瓜灯 {cycle + 1}/{cycles}")
# 摇曳的橙色光
for i in range(20):
colors = [(0, 0, 0)] * ws.led_count
for j in range(ws.led_count):
# 随机亮度变化模拟摇曳
intensity = random.randint(100, 255)
colors[j] = (intensity, intensity // 2, 0) # 橙色
ws.show(colors)
time.sleep(0.1)
ws.show([(0, 0, 0)] * ws.led_count)
print("万圣节南瓜灯效果完成!")
def new_year_countdown(ws, cycles=3):
"""新年倒计时效果"""
print("新年倒计时效果开始...")
for cycle in range(cycles):
print(f" 倒计时 {cycle + 1}/{cycles}")
# 倒计时数字效果
for countdown in [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]:
colors = [(255, 215, 0)] * countdown + [(0, 0, 0)] * (ws.led_count - countdown)
ws.show(colors)
time.sleep(0.5)
# 新年庆祝
for i in range(10):
colors = []
for j in range(ws.led_count):
if random.random() < 0.5:
colors.append((random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
else:
colors.append((0, 0, 0))
ws.show(colors)
time.sleep(0.1)
ws.show([(0, 0, 0)] * ws.led_count)
print("新年倒计时效果完成!")
# ===== 主展示函数 =====
def show_fun_effects():
"""展示所有趣味LED特效"""
ws = WS2812B_WS281X(led_count=10, brightness=100)
try:
print("🎮 趣味LED特效展示开始")
print("=" * 50)
# 特效列表
effects = [
("物理效果 - 重力弹跳", lambda: gravity_bounce(ws, cycles=3)),
("物理效果 - 波纹扩散", lambda: wave_ripple(ws, cycles=6)),
("物理效果 - 磁铁吸引", lambda: magnet_effect(ws, cycles=4)),
("物理效果 - 钟摆摆动", lambda: pendulum_swing(ws, cycles=6)),
("游戏效果 - 贪吃蛇", lambda: snake_game(ws, cycles=2)),
("游戏效果 - 太空侵略者", lambda: space_invaders(ws, cycles=3)),
("游戏效果 - 乒乓球", lambda: pong_game(ws, cycles=6)),
("游戏效果 - 黑客帝国", lambda: matrix_rain(ws, cycles=5)),
("节日效果 - 圣诞彩灯", lambda: christmas_lights(ws, cycles=6)),
("节日效果 - 烟花爆炸", lambda: fireworks(ws, cycles=4)),
("节日效果 - 情人心跳", lambda: valentine_heart(ws, cycles=4)),
("节日效果 - 万圣南瓜", lambda: halloween_pumpkin(ws, cycles=6)),
("节日效果 - 新年倒计时", lambda: new_year_countdown(ws, 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🎉 所有趣味特效播放完成!")
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_fun_effects()