Skip to content

Commit fec74ba

Browse files
authored
Merge pull request #2937 from adafruit/motor-pov-display
adding code for motorized pov display project
2 parents 2264eef + a27d5f2 commit fec74ba

File tree

7 files changed

+130
-0
lines changed

7 files changed

+130
-0
lines changed

Motorized_POV_Display/blinka.bmp

3.78 KB
Binary file not shown.

Motorized_POV_Display/code.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# SPDX-FileCopyrightText: 2017 Limor Fried for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
# Dotstar POV Display! Can handle up to ~2300 pixel size image (e.g. 36 x 64)
5+
6+
import gc
7+
import time
8+
from adafruit_motorkit import MotorKit
9+
import board
10+
import busio
11+
import digitalio
12+
13+
kit = MotorKit(i2c=board.I2C())
14+
15+
FILENAME = "nyan-xmas.bmp"
16+
IMAGE_DELAY = 0.001
17+
REPEAT = True
18+
BRIGHTNESS = 0.3
19+
PIXEL_DELAY = 0.003
20+
21+
dotstar = busio.SPI(board.SCK, board.MOSI)
22+
while not dotstar.try_lock():
23+
pass
24+
dotstar.configure(baudrate=44000000)
25+
26+
# we'll resize this later
27+
databuf = bytearray(0)
28+
29+
led = digitalio.DigitalInOut(board.D13)
30+
led.switch_to_output()
31+
32+
def read_le(s):
33+
# as of this writting, int.from_bytes does not have LE support, DIY!
34+
result = 0
35+
shift = 0
36+
for byte in bytearray(s):
37+
result += byte << shift
38+
shift += 8
39+
return result
40+
41+
class BMPError(Exception):
42+
pass
43+
44+
try:
45+
with open("/" + FILENAME, "rb") as f:
46+
print("File opened")
47+
if f.read(2) != b'BM': # check signature
48+
raise BMPError("Not BitMap file")
49+
50+
bmpFileSize = read_le(f.read(4))
51+
f.read(4) # Read & ignore creator bytes
52+
53+
bmpImageoffset = read_le(f.read(4)) # Start of image data
54+
headerSize = read_le(f.read(4))
55+
bmpWidth = read_le(f.read(4))
56+
bmpHeight = read_le(f.read(4))
57+
flip = True
58+
59+
print("Size: %d\nImage offset: %d\nHeader size: %d" %
60+
(bmpFileSize, bmpImageoffset, headerSize))
61+
print("Width: %d\nHeight: %d" % (bmpWidth, bmpHeight))
62+
63+
if read_le(f.read(2)) != 1:
64+
raise BMPError("Not singleplane")
65+
bmpDepth = read_le(f.read(2)) # bits per pixel
66+
print("Bit depth: %d" % (bmpDepth))
67+
if bmpDepth != 24:
68+
raise BMPError("Not 24-bit")
69+
if read_le(f.read(2)) != 0:
70+
raise BMPError("Compressed file")
71+
72+
print("Image OK!")
73+
74+
rowSize = (bmpWidth * 3 + 3) & ~3 # 32-bit line boundary
75+
76+
# its huge! but its also fast :)
77+
databuf = bytearray(bmpWidth * bmpHeight * 4)
78+
79+
for row in range(bmpHeight): # For each scanline...
80+
if flip: # Bitmap is stored bottom-to-top order (normal BMP)
81+
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize
82+
else: # Bitmap is stored top-to-bottom
83+
pos = bmpImageoffset + row * rowSize
84+
85+
# print ("seek to %d" % pos)
86+
f.seek(pos)
87+
for col in range(bmpWidth):
88+
b, g, r = bytearray(f.read(3)) # BMP files store RGB in BGR
89+
# front load brightness, gamma and reordering here!
90+
order = [b, g, r]
91+
idx = (col * bmpHeight + (bmpHeight - row - 1)) * 4
92+
databuf[idx] = 0xFF # first byte is 'brightness'
93+
idx += 1
94+
for color in order:
95+
databuf[idx] = int(
96+
pow((color * BRIGHTNESS) / 255, 2.7) * 255 + 0.5)
97+
idx += 1
98+
99+
except BMPError as e:
100+
print("Failed to parse BMP: " + e.args[0])
101+
102+
gc.collect()
103+
print(gc.mem_free())
104+
print("Ready to go!")
105+
106+
kit.motor1.throttle = 1
107+
108+
while True:
109+
print("Draw!")
110+
index = 0
111+
112+
for col in range(bmpWidth):
113+
row = databuf[index:index + bmpHeight * 4]
114+
dotstar.write(bytearray([0x00, 0x00, 0x00, 0x00]))
115+
dotstar.write(row)
116+
dotstar.write(bytearray([0x00, 0x00, 0x00, 0x00]))
117+
index += bmpHeight * 4
118+
time.sleep(PIXEL_DELAY)
119+
120+
# clear it out
121+
dotstar.write(bytearray([0x00, 0x00, 0x00, 0x00]))
122+
for r in range(bmpHeight * 5):
123+
dotstar.write(bytearray([0xFF, 0x00, 0x00, 0x00]))
124+
dotstar.write(bytearray([0xff, 0xff, 0xff, 0xff]))
125+
gc.collect()
126+
127+
if not REPEAT:
128+
break
129+
130+
time.sleep(IMAGE_DELAY)

Motorized_POV_Display/dreidel.bmp

3.05 KB
Binary file not shown.

Motorized_POV_Display/nyan-xmas.bmp

6.8 KB
Binary file not shown.

Motorized_POV_Display/pipesky.bmp

9.05 KB
Binary file not shown.

Motorized_POV_Display/xmas.bmp

6.8 KB
Binary file not shown.

Motorized_POV_Display/xmastree.bmp

3.05 KB
Binary file not shown.

0 commit comments

Comments
 (0)