Skip to content

Commit 41808f0

Browse files
authored
Merge pull request adafruit#1134 from caternuson/hourglass
Code for LED hourglass
2 parents 793e63e + e02446b commit 41808f0

File tree

4 files changed

+275
-0
lines changed

4 files changed

+275
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import time
2+
import board
3+
import adafruit_lsm6ds
4+
from adafruit_ht16k33 import matrix
5+
import matrixsand
6+
7+
DELAY = 0.00 # add some delay if you want
8+
9+
# the accelo
10+
accelo = adafruit_lsm6ds.LSM6DS33(board.I2C())
11+
12+
# the matrix
13+
matrix1 = matrix.Matrix8x8(board.I2C(), 0x70)
14+
matrix2 = matrix.Matrix8x8(board.I2C(), 0x71)
15+
16+
# the sand
17+
sand = matrixsand.MatrixSand(8, 16)
18+
19+
# simple helper
20+
def update_matrix():
21+
for x in range(8):
22+
for y in range(16):
23+
if y < 8:
24+
matrix1[x, y] = sand[x, y]
25+
else:
26+
matrix2[x, y-8] = sand[x, y]
27+
28+
# add some initial sand
29+
for sx in range(4):
30+
for sy in range(4):
31+
sand[sx, sy] = 1
32+
33+
update_matrix()
34+
35+
# loop forever
36+
while True:
37+
# read accelo
38+
ax, ay, az = accelo.acceleration
39+
40+
# rotate coord sys
41+
xx = ay
42+
yy = ax
43+
zz = az
44+
45+
# iterate the sand
46+
updated = sand.iterate((xx, yy, zz))
47+
48+
# update matrix if needed
49+
if updated:
50+
update_matrix()
51+
52+
# sleep
53+
time.sleep(DELAY)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import time
2+
import board
3+
import adafruit_lsm6ds
4+
from adafruit_ht16k33 import matrix
5+
import matrixsand
6+
7+
DELAY = 0.05 # overall update rate
8+
9+
# the accelo
10+
accelo = adafruit_lsm6ds.LSM6DS33(board.I2C())
11+
12+
# the matrices
13+
m1 = matrix.Matrix8x8(board.I2C(), 0x70)
14+
m2 = matrix.Matrix8x8(board.I2C(), 0x71)
15+
16+
# the sand
17+
sand1 = matrixsand.MatrixSand(8, 8)
18+
sand2 = matrixsand.MatrixSand(8, 8)
19+
20+
# simple helper
21+
def update_matrix(m, s):
22+
for x in range(8):
23+
for y in range(8):
24+
m[x,y] = s[x,y]
25+
26+
# fill up some sand
27+
for sx in range(8):
28+
for sy in range(8):
29+
sand1[sx, sy] = True
30+
sand1[0,0] = sand1[0,1] = sand1[1,0] = False
31+
sand1[0,2] = sand1[1,1] = sand1[2,0] = False
32+
33+
update_matrix(m1, sand1)
34+
update_matrix(m2, sand2)
35+
36+
updated1 = updated2 = False
37+
38+
while True:
39+
# read accelo
40+
ax, ay, az = accelo.acceleration
41+
# rotate coords
42+
xx = -ax - ay
43+
yy = -ax + ay
44+
zz = az
45+
46+
# move grain of sand from upper to lower?
47+
if yy > 0 and sand1[7,7] and not sand2[0,0] and not updated2:
48+
sand1[7,7] = False
49+
sand2[0,0] = True
50+
updated1 = updated2 = True
51+
# move grain of sand from lower to upper?
52+
elif yy <= 0 and sand2[0,0] and not sand1[7,7] and not updated1:
53+
sand2[0,0] = False
54+
sand1[7,7] = True
55+
updated1 = updated2 = True
56+
# nope, just a regular update
57+
else:
58+
updated1 = sand1.iterate((xx, yy, zz))
59+
updated2 = sand2.iterate((xx, yy, zz))
60+
61+
# update matrices if needed
62+
if updated1:
63+
update_matrix(m1, sand1)
64+
if updated2:
65+
update_matrix(m2, sand2)
66+
67+
time.sleep(DELAY)
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
class MatrixSand:
2+
"""Class to simulate simplified sand physics."""
3+
4+
def __init__(self, width, height):
5+
self._width = width
6+
self._height = height
7+
self._grains = [False] * width * height
8+
9+
def __getitem__(self, value):
10+
if isinstance(value, tuple):
11+
value = value[0] + self._width * value[1]
12+
return self._grains[value]
13+
14+
def __setitem__(self, value, key):
15+
if isinstance(value, tuple):
16+
value = value[0] + self._width * value[1]
17+
self._grains[value] = key
18+
19+
def _side_count(self, upside_down=False):
20+
left = right = 0
21+
for x in range(self._width):
22+
for y in range(self._height):
23+
if x != y and self[x, y]:
24+
if x > y:
25+
right += 1
26+
else:
27+
left += 1
28+
if upside_down:
29+
return right, left
30+
else:
31+
return left, right
32+
33+
def iterate(self, acceleration):
34+
"""Update sand based on supplied acceleration tuple. Returns True if
35+
any motion occurred, otherwise False."""
36+
#pylint: disable=too-many-locals,too-many-nested-blocks,too-many-branches
37+
38+
ax, ay, az = acceleration
39+
40+
# if z dominates, don't do anything
41+
if abs(az) > abs(ax) and abs(az) > abs(ay):
42+
return False
43+
44+
# unit vectors for accelo
45+
ix = iy = 0
46+
if abs(ax) > 0.01:
47+
ratio = abs(ay / ax)
48+
if ratio < 2.414: # tan(67.5deg)
49+
ix = 1 if ax > 0 else -1
50+
if ratio > 0.414: # tan(22.5deg)
51+
iy = 1 if ay > 0 else -1
52+
else:
53+
iy = 1 if ay > 0 else -1
54+
55+
# buffer
56+
new_grains = self._grains[:]
57+
58+
# flag to indicate change
59+
updated = False
60+
61+
# loop through the grains
62+
for x in range(self._width):
63+
for y in range(self._height):
64+
# is there a grain here?
65+
if self[x, y]:
66+
moved = False
67+
# compute new location
68+
newx = x + ix
69+
newy = y + iy
70+
# bounds check
71+
newx = max(min(self._width-1, newx), 0)
72+
newy = max(min(self._height-1, newy), 0)
73+
# wants to move?
74+
if x != newx or y != newy:
75+
moved = True
76+
# is it blocked?
77+
if new_grains[newx + self._width * newy]:
78+
# can we move diagonally?
79+
if not new_grains[x + self._width * newy] and \
80+
not new_grains[newx + self._width * y]:
81+
# can move either way
82+
# move away from fuller side
83+
left, right = self._side_count(ax < 0 and ay < 0)
84+
if left >= right:
85+
newy = y
86+
elif right > left:
87+
newx = x
88+
elif not new_grains[x + self._width * newy]:
89+
# move in y only
90+
newx = x
91+
elif not new_grains[newx + self._width * y]:
92+
# move in x only
93+
newy = y
94+
else:
95+
# nope, totally blocked
96+
moved = False
97+
# did it move?
98+
if moved:
99+
new_grains[x + self._width * y] = False
100+
new_grains[newx + self._width * newy] = True
101+
updated = True
102+
103+
# did things change?
104+
if updated:
105+
self._grains = new_grains
106+
107+
return updated
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import time
2+
import board
3+
import adafruit_lsm6ds
4+
from adafruit_ht16k33 import matrix
5+
import matrixsand
6+
7+
DELAY = 0.00 # add some delay if you want
8+
9+
# the accelo
10+
accelo = adafruit_lsm6ds.LSM6DS33(board.I2C())
11+
12+
# the matrix
13+
matrix = matrix.Matrix8x8(board.I2C(), 0x70)
14+
15+
# the sand
16+
sand = matrixsand.MatrixSand(8, 8)
17+
18+
# simple helper
19+
def update_matrix():
20+
for x in range(8):
21+
for y in range(8):
22+
matrix[x,y] = sand[x,y]
23+
24+
# add some initial sand
25+
for sx in range(4):
26+
for sy in range(4):
27+
sand[sx, sy] = 1
28+
update_matrix()
29+
30+
# loop forever
31+
while True:
32+
# read accelo
33+
ax, ay, az = accelo.acceleration
34+
35+
# rotate coord sys
36+
xx = ay
37+
yy = ax
38+
zz = az
39+
40+
# iterate the sand
41+
updated = sand.iterate((xx, yy, zz))
42+
43+
# update matrix if needed
44+
if updated:
45+
update_matrix()
46+
47+
# sleep
48+
time.sleep(DELAY)

0 commit comments

Comments
 (0)