126 lines
2.8 KiB
Python
126 lines
2.8 KiB
Python
import math
|
|
import time
|
|
|
|
import serial
|
|
|
|
|
|
def clamp(x, ab):
|
|
(a, b) = ab
|
|
return max(a, min(b, x))
|
|
|
|
|
|
def rescale(x, from_limits, to_limits):
|
|
(a, b) = from_limits
|
|
x_0_1 = (x - a) / (b - a)
|
|
|
|
(c, d) = to_limits
|
|
return c + (d - c) * x_0_1
|
|
|
|
|
|
class MovingHead:
|
|
def __init__(self, start_addr):
|
|
self.start_addr = start_addr
|
|
|
|
self.pan = 0 # -3pi/2 to 3pi/2
|
|
self.tilt = 0 # -pi/2 to pi/2
|
|
self.speed = 0
|
|
self.dimmer = 0 # 0 to 1
|
|
self.rgbw = (0, 0, 0, 0)
|
|
|
|
def __str__(self):
|
|
|
|
return (
|
|
f"MovingHead({self.start_addr}): pan={self.pan!r}, "
|
|
f"tilt={self.tilt!r}, speed={self.speed!r}, "
|
|
f"dimmer={self.dimmer!r}, rgbw={self.rgbw!r}"
|
|
)
|
|
|
|
def render(self, dst):
|
|
|
|
pan = rescale(self.pan, (-1.5 * math.pi, 1.5 * math.pi), (255, 0))
|
|
pan = clamp(int(pan), (0, 255))
|
|
pan_fine = 0
|
|
|
|
tilt = rescale(self.tilt, (-0.5 * math.pi, 0.5 * math.pi), (0, 255))
|
|
tilt = clamp(int(tilt), (0, 255))
|
|
tilt_fine = 0
|
|
|
|
dimmer = clamp(7 + int(127 * self.dimmer), (7, 134))
|
|
|
|
(r, g, b, w) = self.rgbw
|
|
|
|
channels = [
|
|
pan,
|
|
pan_fine,
|
|
tilt,
|
|
tilt_fine,
|
|
self.speed,
|
|
dimmer,
|
|
r,
|
|
g,
|
|
b,
|
|
w,
|
|
0, # color mode
|
|
0, # auto jump speed
|
|
0, # control mode
|
|
0, # reset
|
|
]
|
|
|
|
offset = self.start_addr - 1
|
|
|
|
dst[offset : offset + len(channels)] = channels
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
lighting = MovingHead(43)
|
|
lighting.tilt = -0.5 * math.pi
|
|
lighting.rgbw = (0, 0, 0, 0xFF)
|
|
lighting.dimmer = 1
|
|
|
|
head = MovingHead(1)
|
|
head.rgbw = (0x00, 0x00, 0xFF, 0)
|
|
head.tilt = -0.5 * math.pi
|
|
head.dimmer = 1
|
|
|
|
dmx_data = bytearray(512)
|
|
|
|
with serial.Serial("/dev/ttyUSB0", 500_000) as ser:
|
|
|
|
def sync():
|
|
# wait for sync
|
|
while True:
|
|
b = ser.readline()
|
|
if b.strip() == b"Sync.":
|
|
return
|
|
|
|
print("syncing")
|
|
sync()
|
|
|
|
t0 = time.time()
|
|
|
|
left = -0.5 * math.pi
|
|
right = 0.5 * math.pi
|
|
|
|
while True:
|
|
|
|
now = time.time() - t0
|
|
|
|
|
|
if int(now) % 10 < 5:
|
|
head.tilt = left
|
|
head.rgbw = (0xFF, 0x00, 0x00, 0)
|
|
else:
|
|
head.tilt = right
|
|
head.rgbw = (0x00, 0xFF, 0x00, 0)
|
|
|
|
head.render(dmx_data)
|
|
lighting.render(dmx_data)
|
|
|
|
ser.write(dmx_data)
|
|
ser.flush()
|
|
response = ser.readline()
|
|
if response.strip() != b"Ack.":
|
|
print(f"received bad response: {response!r}")
|
|
sync()
|