-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathneopixels.py
119 lines (94 loc) · 4.21 KB
/
neopixels.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import serial, time
import matplotlib as mpl
import matplotlib.cm as cm
import numpy as np
class NeoPixels(object):
def __init__(self, usb_port, colormap=None, baud_rate=115200,
x_range=None, num_pixels=60, update=3, normalize=True, vrange=None, range_tracking=0.):
if colormap is None:
colormap = cm.seismic
if x_range is None:
x_range = (0, 2 * np.pi)
# connection to Arduino
self.arduino = serial.Serial(usb_port, baud_rate, timeout=.1)
time.sleep(2) # give the connection some time to settle
self.frame_count = 0
self.update = update # update every <this> number of frames
# neopixel parameters
self.num_pixels = num_pixels
# color mapping - http://matplotlib.org/users/colormaps.html
self.default_values = np.zeros(self.num_pixels)
self.x_range = x_range
self.positions = np.linspace(self.x_range[0], self.x_range[1],
self.num_pixels, endpoint=False)
if colormap is not None:
norm = mpl.colors.Normalize(vmin=0, vmax=1)
self.mapper = cm.ScalarMappable(norm=norm, cmap=colormap)
else:
self.mapper = None
# normalization setup
self.normalize = normalize
self.vrange = vrange if vrange is not None else np.array([0., 1.])
self.range_tracking = range_tracking
if self.range_tracking > 0:
self.vrange[1] = 0.
self.norm_start_count = 0
self.lightify()
def lightify(self, vals=None, realtime=False):
if realtime is True: # cannot update every frame
self.frame_count += 1
if (self.frame_count % self.update) != 0:
return
if vals is None:
pixel_values = self.default_values
else:
# First reverse the array since the LED are clockwise,
# and the direction of arrivals counterclockwise...
vals = vals[::-1]
# interpolate and normalize
if len(vals) != self.num_pixels:
xvals = np.linspace(self.x_range[0], self.x_range[1],
len(vals), endpoint=False)
pixel_values = np.interp(self.positions, xvals, vals)
else:
pixel_values = vals
if self.range_tracking > 0.:
new_range = np.array([np.min(vals), np.max(vals)])
if self.norm_start_count < 100:
self.norm_start_count += 1
self.vrange = ((self.norm_start_count - 1) * self.vrange + new_range) / self.norm_start_count
else:
self.vrange = (
self.range_tracking * self.vrange
+ (1 - self.range_tracking) * new_range
)
if self.normalize:
pixel_values -= self.vrange[0]
pixel_values /= self.vrange[1] - self.vrange[0]
pixel_values[pixel_values < 0.] = 0.
pixel_values[pixel_values > 1.] = 1.
if self.mapper is not None:
colors = self.mapper.to_rgba(pixel_values)
colors = colors[:, :3]
else:
# nice map ?
# It is good to have slightly less intensity
# for lower sound intensity
colors = np.zeros((len(pixel_values), 3), dtype=np.float)
colors[:, 0] = pixel_values
colors[:, 1] = 0.05 * (1. - pixel_values)
colors[:, 2] = 0.1 * (1. - pixel_values)
# Send to the arduino
self.send_colors(colors)
def send_colors(self, colors):
colors = np.reshape((colors * 254).round().astype(np.uint8), -1)
self.arduino.write(colors.tobytes())
def lightify_mono(self, rgb=[255, 0, 0], realtime=False):
if realtime is True: # cannot update every frame
self.frame_count += 1
if (self.frame_count % self.update) != 0:
return
pixel_values = np.array(rgb) / 255
pixel_values = np.tile(pixel_values, (60, 1))
colors = np.reshape((pixel_values * 255).round().astype(np.uint8), -1)
self.arduino.write(colors.tobytes())