mirror of
https://github.com/danbulant/ambientlightdemo
synced 2026-05-19 04:18:32 +00:00
new wiring
This commit is contained in:
parent
7b394e16a3
commit
2c8dd76031
6 changed files with 279 additions and 93 deletions
33
rpi/gdmath.py
Normal file
33
rpi/gdmath.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
colors = ["d062ff", "00b097", "50cc00", "8dcaff", "d062ff"]
|
||||
colors_rgb = [tuple(int(colors[i][j:j+2], 16) for j in (0, 2, 4)) for i in range(len(colors))]
|
||||
color_offsets = [0, .25, .5, .75, 1]
|
||||
|
||||
FULL_DARK_ROTATION_DELTA = .1
|
||||
PATTERN_REPETITION = 5
|
||||
LIGHT_SLOWDOWN_SPEED = 1
|
||||
|
||||
def clamp(value, min_value, max_value):
|
||||
return max(min_value, min(value, max_value))
|
||||
def wrap(value, min_value, max_value):
|
||||
range_size = max_value - min_value
|
||||
while value < min_value:
|
||||
value += range_size
|
||||
while value >= max_value:
|
||||
value -= range_size
|
||||
return value
|
||||
def lerp(a, b, t):
|
||||
return a + (b - a) * t
|
||||
def pingpong(value, max):
|
||||
value = wrap(value, 0, max * 2)
|
||||
if value > max:
|
||||
value = max * 2 - value
|
||||
return value
|
||||
def sample_color_gradient(t):
|
||||
t = wrap(t, 0, 1)
|
||||
for i in range(len(color_offsets) - 1):
|
||||
if t >= color_offsets[i] and t <= color_offsets[i + 1]:
|
||||
local_t = (t - color_offsets[i]) / (color_offsets[i + 1] - color_offsets[i])
|
||||
color_a = colors_rgb[i]
|
||||
color_b = colors_rgb[i + 1]
|
||||
return tuple(int(lerp(color_a[j], color_b[j], local_t)) for j in range(3))
|
||||
return colors_rgb[-1]
|
||||
9
rpi/light-test.py
Normal file
9
rpi/light-test.py
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import board
|
||||
import neopixel
|
||||
|
||||
pixels = neopixel.NeoPixel(
|
||||
board.D12, 10, brightness=1, auto_write=False, pixel_order=neopixel.GRB
|
||||
)
|
||||
|
||||
pixels.fill((0, 0, 0))
|
||||
pixels.show()
|
||||
|
|
@ -1,70 +1,10 @@
|
|||
import socket
|
||||
import time
|
||||
import board
|
||||
import neopixel
|
||||
import json
|
||||
from gdmath import *
|
||||
|
||||
num_pixels = 30
|
||||
local_pixels = neopixel.NeoPixel(
|
||||
board.D18, num_pixels, brightness=0.2, auto_write=False, pixel_order=neopixel.GRB
|
||||
pixels = neopixel.NeoPixel(
|
||||
board.D12, 10, brightness=.2, auto_write=False, pixel_order=neopixel.GRB
|
||||
)
|
||||
networked_pixels = neopixel.NeoPixel(
|
||||
board.D21, num_pixels, brightness=0.2, auto_write=False, pixel_order=neopixel.GRB
|
||||
)
|
||||
|
||||
colors = ["d062ff", "00b097", "50cc00", "8dcaff", "d062ff"]
|
||||
colors_rgb = [tuple(int(colors[i][j:j+2], 16) for j in (0, 2, 4)) for i in range(len(colors))]
|
||||
color_offsets = [0, .25, .5, .75, 1]
|
||||
|
||||
UDP_HOST = "steamdeck"
|
||||
UDP_PORT_LOCAL = 4444
|
||||
UDP_PORT_NETWORKED = 4433
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.bind(("", UDP_PORT_LOCAL))
|
||||
sock.setblocking(0)
|
||||
|
||||
FULL_DARK_ROTATION_DELTA = .1
|
||||
PATTERN_REPETITION = 5
|
||||
LIGHT_SLOWDOWN_SPEED = 1
|
||||
|
||||
def clamp(value, min_value, max_value):
|
||||
return max(min_value, min(value, max_value))
|
||||
def wrap(value, min_value, max_value):
|
||||
range_size = max_value - min_value
|
||||
while value < min_value:
|
||||
value += range_size
|
||||
while value >= max_value:
|
||||
value -= range_size
|
||||
return value
|
||||
def lerp(a, b, t):
|
||||
return a + (b - a) * t
|
||||
def pingpong(value, max):
|
||||
value = wrap(value, 0, max * 2)
|
||||
if value > max:
|
||||
value = max * 2 - value
|
||||
return value
|
||||
def sample_color_gradient(t):
|
||||
t = wrap(t, 0, 1)
|
||||
for i in range(len(color_offsets) - 1):
|
||||
if t >= color_offsets[i] and t <= color_offsets[i + 1]:
|
||||
local_t = (t - color_offsets[i]) / (color_offsets[i + 1] - color_offsets[i])
|
||||
color_a = colors_rgb[i]
|
||||
color_b = colors_rgb[i + 1]
|
||||
return tuple(int(lerp(color_a[j], color_b[j], local_t)) for j in range(3))
|
||||
return colors_rgb[-1]
|
||||
def send_data(value, delta):
|
||||
message = json.dumps({"value": value, "delta": delta}).encode('utf-8')
|
||||
sock.sendto(message, (UDP_HOST, UDP_PORT_NETWORKED))
|
||||
def shortest_diff(old, new):
|
||||
diff = old - new
|
||||
wrapped_diff = (new + 1) - old
|
||||
if abs(wrapped_diff) < abs(diff):
|
||||
diff = -wrapped_diff
|
||||
wrapped_diff = (old + 1) - new
|
||||
if abs(wrapped_diff) < abs(diff):
|
||||
diff = wrapped_diff
|
||||
return diff
|
||||
|
||||
class Lights:
|
||||
virtual_rotation = 0
|
||||
|
|
@ -76,39 +16,10 @@ class Lights:
|
|||
def process(self, delta):
|
||||
self.virtual_rotation += self.expected_rotation_delta * (delta * 60)
|
||||
max_darkness = clamp(abs(self.expected_rotation_delta / FULL_DARK_ROTATION_DELTA), 0, 1)
|
||||
for i in range(num_pixels):
|
||||
for i in range(pixels.n):
|
||||
pattern_offset = wrap((i + (self.virtual_rotation * PATTERN_REPETITION)) / PATTERN_REPETITION, 0, 1)
|
||||
energy = (1 - (1 - pattern_offset) * max_darkness)
|
||||
new_color = tuple(x * energy for x in self.color)
|
||||
self.pixels[i] = new_color
|
||||
self.pixels.show()
|
||||
self.expected_rotation_delta = lerp(self.expected_rotation_delta, 0, delta * LIGHT_SLOWDOWN_SPEED)
|
||||
|
||||
local_lights = Lights(local_pixels)
|
||||
networked_lights = Lights(networked_pixels)
|
||||
|
||||
last_time = time.time()
|
||||
while True:
|
||||
current_time = time.time()
|
||||
delta = current_time - last_time
|
||||
last_time = current_time
|
||||
|
||||
try:
|
||||
data, addr = sock.recvfrom(1024)
|
||||
message = json.loads(data.decode('utf-8'))
|
||||
value = message.get("value", 0)
|
||||
delta_value = message.get("delta", 0)
|
||||
|
||||
if value:
|
||||
networked_lights.color = sample_color_gradient(value)
|
||||
if delta_value:
|
||||
networked_lights.expected_rotation_delta = delta_value
|
||||
except BlockingIOError:
|
||||
pass
|
||||
|
||||
# todo: get input from local sensors
|
||||
|
||||
local_lights.process(delta)
|
||||
networked_lights.process(delta)
|
||||
|
||||
time.sleep(0.03)
|
||||
114
rpi/old-all.py
Normal file
114
rpi/old-all.py
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
import socket
|
||||
import time
|
||||
import board
|
||||
import neopixel
|
||||
import json
|
||||
|
||||
num_pixels = 30
|
||||
local_pixels = neopixel.NeoPixel(
|
||||
board.D18, num_pixels, brightness=0.2, auto_write=False, pixel_order=neopixel.GRB
|
||||
)
|
||||
networked_pixels = neopixel.NeoPixel(
|
||||
board.D21, num_pixels, brightness=0.2, auto_write=False, pixel_order=neopixel.GRB
|
||||
)
|
||||
|
||||
colors = ["d062ff", "00b097", "50cc00", "8dcaff", "d062ff"]
|
||||
colors_rgb = [tuple(int(colors[i][j:j+2], 16) for j in (0, 2, 4)) for i in range(len(colors))]
|
||||
color_offsets = [0, .25, .5, .75, 1]
|
||||
|
||||
UDP_HOST = "steamdeck"
|
||||
UDP_PORT_LOCAL = 4444
|
||||
UDP_PORT_NETWORKED = 4433
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.bind(("", UDP_PORT_LOCAL))
|
||||
sock.setblocking(0)
|
||||
|
||||
FULL_DARK_ROTATION_DELTA = .1
|
||||
PATTERN_REPETITION = 5
|
||||
LIGHT_SLOWDOWN_SPEED = 1
|
||||
|
||||
def clamp(value, min_value, max_value):
|
||||
return max(min_value, min(value, max_value))
|
||||
def wrap(value, min_value, max_value):
|
||||
range_size = max_value - min_value
|
||||
while value < min_value:
|
||||
value += range_size
|
||||
while value >= max_value:
|
||||
value -= range_size
|
||||
return value
|
||||
def lerp(a, b, t):
|
||||
return a + (b - a) * t
|
||||
def pingpong(value, max):
|
||||
value = wrap(value, 0, max * 2)
|
||||
if value > max:
|
||||
value = max * 2 - value
|
||||
return value
|
||||
def sample_color_gradient(t):
|
||||
t = wrap(t, 0, 1)
|
||||
for i in range(len(color_offsets) - 1):
|
||||
if t >= color_offsets[i] and t <= color_offsets[i + 1]:
|
||||
local_t = (t - color_offsets[i]) / (color_offsets[i + 1] - color_offsets[i])
|
||||
color_a = colors_rgb[i]
|
||||
color_b = colors_rgb[i + 1]
|
||||
return tuple(int(lerp(color_a[j], color_b[j], local_t)) for j in range(3))
|
||||
return colors_rgb[-1]
|
||||
def send_data(value, delta):
|
||||
message = json.dumps({"value": value, "delta": delta}).encode('utf-8')
|
||||
sock.sendto(message, (UDP_HOST, UDP_PORT_NETWORKED))
|
||||
def shortest_diff(old, new):
|
||||
diff = old - new
|
||||
wrapped_diff = (new + 1) - old
|
||||
if abs(wrapped_diff) < abs(diff):
|
||||
diff = -wrapped_diff
|
||||
wrapped_diff = (old + 1) - new
|
||||
if abs(wrapped_diff) < abs(diff):
|
||||
diff = wrapped_diff
|
||||
return diff
|
||||
|
||||
class Lights:
|
||||
virtual_rotation = 0
|
||||
color = (255, 255, 255)
|
||||
expected_rotation_delta = 0
|
||||
def __init__(self, pixels):
|
||||
self.pixels = pixels
|
||||
|
||||
def process(self, delta):
|
||||
self.virtual_rotation += self.expected_rotation_delta * (delta * 60)
|
||||
max_darkness = clamp(abs(self.expected_rotation_delta / FULL_DARK_ROTATION_DELTA), 0, 1)
|
||||
for i in range(num_pixels):
|
||||
pattern_offset = wrap((i + (self.virtual_rotation * PATTERN_REPETITION)) / PATTERN_REPETITION, 0, 1)
|
||||
energy = (1 - (1 - pattern_offset) * max_darkness)
|
||||
new_color = tuple(x * energy for x in self.color)
|
||||
self.pixels[i] = new_color
|
||||
self.pixels.show()
|
||||
self.expected_rotation_delta = lerp(self.expected_rotation_delta, 0, delta * LIGHT_SLOWDOWN_SPEED)
|
||||
|
||||
local_lights = Lights(local_pixels)
|
||||
networked_lights = Lights(networked_pixels)
|
||||
|
||||
last_time = time.time()
|
||||
while True:
|
||||
current_time = time.time()
|
||||
delta = current_time - last_time
|
||||
last_time = current_time
|
||||
|
||||
try:
|
||||
data, addr = sock.recvfrom(1024)
|
||||
message = json.loads(data.decode('utf-8'))
|
||||
value = message.get("value", 0)
|
||||
delta_value = message.get("delta", 0)
|
||||
|
||||
if value:
|
||||
networked_lights.color = sample_color_gradient(value)
|
||||
if delta_value:
|
||||
networked_lights.expected_rotation_delta = delta_value
|
||||
except BlockingIOError:
|
||||
pass
|
||||
|
||||
# todo: get input from local sensors
|
||||
|
||||
local_lights.process(delta)
|
||||
networked_lights.process(delta)
|
||||
|
||||
time.sleep(0.03)
|
||||
69
rpi/stepper-test.py
Normal file
69
rpi/stepper-test.py
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#!/usr/bin/python3
|
||||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
|
||||
out1 = 17
|
||||
out2 = 27
|
||||
out3 = 22
|
||||
out4 = 23
|
||||
|
||||
# careful lowering this, at some point you run into the mechanical limitation of how quick your motor can move
|
||||
step_sleep = 0.002
|
||||
|
||||
step_count = 200
|
||||
|
||||
# setting up
|
||||
GPIO.setmode( GPIO.BCM )
|
||||
GPIO.setup( out1, GPIO.OUT )
|
||||
GPIO.setup( out2, GPIO.OUT )
|
||||
GPIO.setup( out3, GPIO.OUT )
|
||||
GPIO.setup( out4, GPIO.OUT )
|
||||
|
||||
# initializing
|
||||
GPIO.output( out1, GPIO.LOW )
|
||||
GPIO.output( out2, GPIO.LOW )
|
||||
GPIO.output( out3, GPIO.LOW )
|
||||
GPIO.output( out4, GPIO.LOW )
|
||||
|
||||
|
||||
def cleanup():
|
||||
GPIO.output( out1, GPIO.LOW )
|
||||
GPIO.output( out2, GPIO.LOW )
|
||||
GPIO.output( out3, GPIO.LOW )
|
||||
GPIO.output( out4, GPIO.LOW )
|
||||
GPIO.cleanup()
|
||||
|
||||
|
||||
# the meat
|
||||
try:
|
||||
i = 0
|
||||
for i in range(step_count):
|
||||
if i%4==0:
|
||||
GPIO.output( out4, GPIO.HIGH )
|
||||
GPIO.output( out3, GPIO.LOW )
|
||||
GPIO.output( out2, GPIO.LOW )
|
||||
GPIO.output( out1, GPIO.LOW )
|
||||
elif i%4==1:
|
||||
GPIO.output( out4, GPIO.LOW )
|
||||
GPIO.output( out3, GPIO.LOW )
|
||||
GPIO.output( out2, GPIO.HIGH )
|
||||
GPIO.output( out1, GPIO.LOW )
|
||||
elif i%4==2:
|
||||
GPIO.output( out4, GPIO.LOW )
|
||||
GPIO.output( out3, GPIO.HIGH )
|
||||
GPIO.output( out2, GPIO.LOW )
|
||||
GPIO.output( out1, GPIO.LOW )
|
||||
elif i%4==3:
|
||||
GPIO.output( out4, GPIO.LOW )
|
||||
GPIO.output( out3, GPIO.LOW )
|
||||
GPIO.output( out2, GPIO.LOW )
|
||||
GPIO.output( out1, GPIO.HIGH )
|
||||
|
||||
time.sleep( step_sleep )
|
||||
|
||||
except KeyboardInterrupt:
|
||||
cleanup()
|
||||
exit( 1 )
|
||||
|
||||
cleanup()
|
||||
exit( 0 )
|
||||
50
rpi/stepper.py
Normal file
50
rpi/stepper.py
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
|
||||
class StepperMotor:
|
||||
pins = (17, 27, 22, 23)
|
||||
step_sleep = 0.002
|
||||
step_count = 200
|
||||
|
||||
def __init__(self):
|
||||
GPIO.setmode( GPIO.BCM )
|
||||
for pin in self.pins:
|
||||
GPIO.setup( pin, GPIO.OUT )
|
||||
GPIO.output( pin, GPIO.LOW )
|
||||
|
||||
def cleanup(self):
|
||||
for pin in self.pins:
|
||||
GPIO.output( pin, GPIO.LOW )
|
||||
GPIO.cleanup()
|
||||
|
||||
def _set_pins(self, out1, out2, out3, out4):
|
||||
GPIO.output( self.pins[0], out1 )
|
||||
GPIO.output( self.pins[1], out2 )
|
||||
GPIO.output( self.pins[2], out3 )
|
||||
GPIO.output( self.pins[3], out4 )
|
||||
|
||||
current_step = 0
|
||||
def _apply_single_step(self):
|
||||
if self.current_step%4==0:
|
||||
self._set_pins(GPIO.HIGH, GPIO.LOW, GPIO.LOW, GPIO.LOW)
|
||||
elif self.current_step%4==1:
|
||||
self._set_pins(GPIO.LOW, GPIO.HIGH, GPIO.LOW, GPIO.LOW)
|
||||
elif self.current_step%4==2:
|
||||
self._set_pins(GPIO.LOW, GPIO.LOW, GPIO.HIGH, GPIO.LOW)
|
||||
elif self.current_step%4==3:
|
||||
self._set_pins(GPIO.LOW, GPIO.LOW, GPIO.LOW, GPIO.HIGH)
|
||||
time.sleep(self.step_sleep)
|
||||
def single_step(self):
|
||||
self._apply_single_step()
|
||||
self.current_step += 1
|
||||
def single_step_back(self):
|
||||
self.current_step -= 1
|
||||
self._apply_single_step()
|
||||
def step(self, steps):
|
||||
for _ in range(abs(steps)):
|
||||
if steps > 0:
|
||||
self.single_step()
|
||||
else:
|
||||
self.single_step_back()
|
||||
def pos(self):
|
||||
return self.current_step % self.step_count
|
||||
Loading…
Reference in a new issue