Skip to content

Commit

Permalink
Bugfix and various improvements, please pull. :-) (#26)
Browse files Browse the repository at this point in the history
* Extended documentation.

Closer explanation of pixel_map.csv format.

* Example file for a 16x10 pixel panel.

* Content of this folder

* PNG files (16x10 pixel) for testing purposes

* Removed, new set of PNG files in directory images

* major bug fixed in 'array', various improvements

Changes:
   * function 'array':
     - fixed a major (!) bug, works now
     - added some output
     - added some maybe useful debugging output (formerly unused option '--verbose')

Still a lot to do, but it works now.

* Enhanced doku, beautified

Added some spaces for a nice layout in github.

* Even more makeup

* more makeup

* More. Make. Up.
  • Loading branch information
aloishockenschlohe authored and scottjgibson committed Oct 27, 2017
1 parent 7c134d1 commit 45c6c62
Show file tree
Hide file tree
Showing 15 changed files with 309 additions and 30 deletions.
116 changes: 99 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ http://thegreatgeekery.blogspot.ca/2012/08/raspberry-pi-and-ws2801.html

- Originally based on http://learn.adafruit.com/light-painting-with-raspberry-pi/software

Changelog:
- Version 20171026, enhancements by Alois Hockenschlohe:
* enhanced documentation (this file)
* added some png files for testing purposes (16x10 pixel, see directory 'images')
* function 'array':
- fixed a major (!) bug, works now
- added some output
- added some maybe useful debugging output (formerly unused option '--verbose')
* added example file 'pixel_map_16x10.csv'

Supported Chips:
- WS2801
- LPD8806
Expand Down Expand Up @@ -206,20 +216,92 @@ Supported Chips:

pixel_map.csv format
===================
- each line pertains to a pixel, the first line is the first pixel in the string (closest to the RaspberryPi)
- each line has two entries (x and y location)


The image is mapped like so:

X0Y0 X1Y0 X2Y0...
X0Y1
X0Y2
...

- so if the first pixel of your array is the lower left hand corner (of a 7x7 array) the entry would be
0,6
if your second pixel is the lower second from left pixel the entry would be:
1,6


Each line of this file pertains to a pixel, the first line is the
first pixel in the LED string (closest to the RaspberryPi).
Each line has two entries (x and y location)

Closer explanation:

Each pixel of a png image is mapped with x and y coordinates,
starting in the upper left corner of the image

/======> X
||
|| 0/0 1/0 2/0 3/0 4/0 ...
|| 0/1 1/1 2/1 3/1 4/1 ...
\/ 0/2 1/2 2/2 3/2 4/2 ...
Y 0/3 1/3 2/3 3/3 4/3 ...
... ... ... ... ... ...

The file pixel_map.csv describes, which LED represents which pixel of the png,
where the line number in the file adresses the LED and the values written in
the line for the x/y coordinates of the pixel

line number -> x/y coordinates

Here is an example:

Let's take a look at a home-made 16x10 matrix.
The matrix is made out of 2 rows with 4 panels (crates) each.
Each panel (crate) consists of 20 LED's (bottles) each.

Here the wiring layout of a crate (bottom/lights are facing toward the viewer):

/---------------\
| O---O O---O |
| | | | | |
| O O O O |
| | | | | |
| O O O O |
| | | | | |
| O O O O |
| | | | | |
in >--+-O O---O O-+--> out
\---------------/

In our setup the Raspberry is located at the lower left corner and all
LED's (bottles) are connected with a single line.

The wiring for all the 160 LED's looks like this
(notice the connection between the LED's (bottle) 79 and 80):


/======> X
||
|| /-----------------\/-----------------\/-----------------\/-----------------\
|| | 84--85 94--95 || 104-105 114-115 || 124-125 134-135 || 144-145 154-155 |
\/ | 83 86 93 96 || 103 106 113 116 || 123 126 133 136 || 143 146 153 156 |
| 82 87 92 97 || 102 107 112 117 || 122 127 132 137 || 142 147 152 157 |
Y | 81 88 91 98 || 101 108 111 118 || 121 128 131 138 || 141 148 151 158 |
/---+--80 89--90 99-++-100 109-110 119-++-120 129-130 139-++-140 149-150 159 |
| \-----------------/\-----------------/\-----------------/\-----------------/
|
\----------------------------------------------------------------------------------\
|
/-----------------\/-----------------\/-----------------\/-----------------\ |
| 4---5 14--15 || 24--25 34--35 || 44--45 54--55 || 64--65 74--75 | |
| 3 6 13 16 || 23 26 33 36 || 43 46 53 56 || 63 66 73 76 | |
| 2 7 12 17 || 22 27 32 37 || 42 47 52 57 || 62 67 72 77 | |
+-----+ | 1 8 11 18 || 21 28 31 38 || 41 48 51 58 || 61 68 71 78 | |
| RPi |--+---0 9--10 19-++--20 29--30 39-++--40 49--50 59-++--60 69--70 79-+---/
+-----+ \-----------------/\-----------------/\-----------------/\-----------------/

For a propper mapping, the file pixel_map.csv should look like this
(without the comments, of course):

+-- START ---
|0,9 # Line 0: LED 0 (closest to the raspberry) represents the pixel with the x/y coordinates 0/9
|0,8 # Line 1: LED 1 represents the pixel with the x/y coordinates 0/8
|0,7 # Line 2: LED 2 represents the pixel with the x/y coordinates 0/7
|...
|14,9 # Line 78: LED 78 represents the pixel with the x/y coordinates 14/9
|15,9 # Line 79: LED 79 represents the pixel with the x/y coordinates 15/9
|0,4 # Line 80: LED 80 represents the pixel with the x/y coordinates 0/4
|0,3 # Line 81: LED 81 represents the pixel with the x/y coordinates 0/3
|...
|15,2 # Line 157: LED 157 represents the pixel with the x/y coordinates 15/2
|15,3 # Line 158: LED 158 represents the pixel with the x/y coordinates 15/3
|15,4 # Line 159: LED 159 (the last one in the line) represents the pixel with the x/y coordinates 15/3
+--- END ---

You can find the whole mapping of the example in file "pixel_map_16x10.csv".
Binary file added images/black_16x10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/blue_16x10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/bw-pattern-1_16x10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/bw-pattern-2_16x10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/frame-red_16x10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/green_16x10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions images/readme.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
In this folder you find some PNG files for testing purposes.
Binary file added images/red_16x10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/rgb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/smiley_16x10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/white_16x10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
160 changes: 160 additions & 0 deletions pixel_map_16x10.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
0,9
0,8
0,7
0,6
0,5
1,5
1,6
1,7
1,8
1,9
2,9
2,8
2,7
2,6
2,5
3,5
3,6
3,7
3,8
3,9
4,9
4,8
4,7
4,6
4,5
5,5
5,6
5,7
5,8
5,9
6,9
6,8
6,7
6,6
6,5
7,5
7,6
7,7
7,8
7,9
8,9
8,8
8,7
8,6
8,5
9,5
9,6
9,7
9,8
9,9
10,9
10,8
10,7
10,6
10,5
11,5
11,6
11,7
11,8
11,9
12,9
12,8
12,7
12,6
12,5
13,5
13,6
13,7
13,8
13,9
14,9
14,8
14,7
14,6
14,5
15,5
15,6
15,7
15,8
15,9
0,4
0,3
0,2
0,1
0,0
1,0
1,1
1,2
1,3
1,4
2,4
2,3
2,2
2,1
2,0
3,0
3,1
3,2
3,3
3,4
4,4
4,3
4,2
4,1
4,0
5,0
5,1
5,2
5,3
5,4
6,4
6,3
6,2
6,1
6,0
7,0
7,1
7,2
7,3
7,4
8,4
8,3
8,2
8,1
8,0
9,0
9,1
9,2
9,3
9,4
10,4
10,3
10,2
10,1
10,0
11,0
11,1
11,2
11,3
11,4
12,4
12,3
12,2
12,1
12,0
13,0
13,1
13,2
13,3
13,4
14,4
14,3
14,2
14,1
14,0
15,0
15,1
15,2
15,3
15,4
62 changes: 49 additions & 13 deletions pixelpi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import csv
import socket
import time
import sys

try:
import cwiid
Expand Down Expand Up @@ -289,42 +290,75 @@ def array():
for filename in file:
filename = filename.rstrip()
if not filename:
print "[ERROR] Not a file or not readable: ",filename
continue
print filename
images.append(Image.open(filename).convert("RGB"))
print "[INFO] Added file ",filename
else:
images.append(Image.open(args.filename).convert("RGB"))
print "[INFO] Added file ",args.filename

for img in images:
input_image = img.load()
print "%dx%d pixels" % img.size
print "Reading in array map"
print "[INFO] Imaged loaded: %dx%d pixels" % img.size

print "[INFO] Reading pixel_map.csv"
pixel_map_csv = csv.reader(open("pixel_map.csv", "rb"))
pixel_map = []
for p in pixel_map_csv:
pixel_map.append(p)

# 171026-AHo: added verbose output
if args.verbose:
print "[debug] pixel_map:"
for i in range(1, len(pixel_map)):
print pixel_map[i]

if len(pixel_map) != args.array_width * args.array_height:
print "Map size error"
print "Remapping"
print "[ERROR] Reading array map from pixel_map.csv: Map size error"

print "[INFO] Creating buffer for color values (",PIXEL_SIZE," bytes)"
value = bytearray(PIXEL_SIZE)

# Create a byte array ordered according to the pixel map file
# Create empty byte array (will be filled with SPI data)
print "[INFO] Creating buffer for SPI data"
if args.chip_type == "SM16716":
pixel_output = bytearray(args.array_width * args.array_height * PIXEL_SIZE_SM16716)
print "[INFO] Buffersize = ",args.array_width * args.array_height * PIXEL_SIZE_SM16716," Bytes"
else:
pixel_output = bytearray(args.array_width * args.array_height * PIXEL_SIZE + 1)
print "[INFO] Buffersize = ",args.array_width * args.array_height * PIXEL_SIZE + 1," Bytes"

# 171026-AHo: added verbose output
if args.verbose:
print "[debug] pixel_output:"
print ''.join('{:02x}'.format(x) for x in pixel_output)

print "[INFO] Creating SPI data"
for array_index in range(len(pixel_map)):
value = bytearray(input_image[int(pixel_map[array_index][0]), int(pixel_map[array_index][1])])

if args.verbose:
print "[debug] Processing ",int(pixel_map[array_index][0]),"/",int(pixel_map[array_index][1])," -> ",input_image[int(pixel_map[array_index][0]), int(pixel_map[array_index][1])], ''.join('{:02x}'.format(x) for x in value)

if args.chip_type == "SM16716":
pixel_output[(array_index * PIXEL_SIZE_SM16716):] = filter_pixel(value[:], 1)
else:
pixel_output[(array_index * PIXEL_SIZE):] = filter_pixel(value[:], 1)
print "Displaying..."
# 171026-AHo: bugfix, this block has to be executed inside the "for"-loop
if args.chip_type == "SM16716":
pixel_output[(array_index * PIXEL_SIZE_SM16716):] = filter_pixel(value[:], 1)
else:
pixel_output[(array_index * PIXEL_SIZE):] = filter_pixel(value[:], 1)
# 171026-AHo: added verbose output
#if args.verbose:
# print "[debug] pixel_output:"
# print ''.join('{:02x}'.format(x) for x in pixel_output)

print "[INFO] Displaying SPI data"
if args.verbose:
print "[debug] pixel_output:"
print ''.join('{:02x}'.format(x) for x in pixel_output)
write_stream(pixel_output)
spidev.flush()
time.sleep((args.refresh_rate) / 1000.0)

print "[INFO] Goodbye"

def pan():
img = Image.open(args.filename).convert("RGB")
Expand Down Expand Up @@ -549,7 +583,9 @@ def filter_pixel(input_pixel, brightness):
subparsers = parser.add_subparsers(help='sub command help?')
common_parser = argparse.ArgumentParser(add_help=False)
common_parser.add_argument('--chip', action='store', dest='chip_type', default='WS2801', choices=['WS2801', 'LPD8806', 'LPD6803', 'SM16716'], help='Specify chip type LPD6803, LPD8806, WS2801 or SM16716')
common_parser.add_argument('--verbose', action='store_true', dest='verbose', default=True, help='enable verbose mode')
#171026-AHo: default for --verbose changed from 'true' to 'false'
#action="store_true", default=False
common_parser.add_argument('--verbose', action='store_true', default=False, dest='verbose', help='enable verbose mode')
common_parser.add_argument('--spi_dev', action='store', dest='spi_dev_name', required=False, default='/dev/spidev0.0', help='Set the SPI device descriptor')
common_parser.add_argument('--refresh_rate', action='store', dest='refresh_rate', required=False, default=500, type=int, help='Set the refresh rate in ms (default 500ms)')
parser_strip = subparsers.add_parser('strip', parents=[common_parser], help='Stip Mode - Display an image using POV and a LED strip')
Expand Down
Binary file removed test.png
Binary file not shown.

1 comment on commit 45c6c62

@Pythonjase
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi can this run on a raspberry pi zero w ?

Please sign in to comment.