Browse Source

support multiple chained panels. color remapping for differing panel brightness.

Thomas Buck 1 year ago
parent
commit
91cc703efc
8 changed files with 144 additions and 31 deletions
  1. 1
    4
      README.md
  2. 6
    6
      draw.py
  3. 45
    0
      mapper.py
  4. 38
    9
      pi.py
  5. 32
    3
      solid.py
  6. 13
    8
      splash.py
  7. 4
    0
      test.py
  8. 5
    1
      util.py

+ 1
- 4
README.md View File

14
 
14
 
15
 You always need:
15
 You always need:
16
 
16
 
17
-    pip install pil
18
-    pip install bdfparser
19
-    pip install "qrcode[pil]"
20
-    pip install evdev
17
+    pip install Pillow bdfparser "qrcode[pil]" evdev
21
 
18
 
22
 For evdev to find all devices you may need to add your user to the `input` group or run the scripts as root.
19
 For evdev to find all devices you may need to add your user to the `input` group or run the scripts as root.
23
 
20
 

+ 6
- 6
draw.py View File

166
     m = Manager(t)
166
     m = Manager(t)
167
 
167
 
168
     m.add(ScrollText(t, "tom-thumb Abcdefgh tom-thumb", "tom-thumb",
168
     m.add(ScrollText(t, "tom-thumb Abcdefgh tom-thumb", "tom-thumb",
169
-                     1, 75, (0, 255, 0), (0, 0, 255)))
169
+                     1, 75, (0, 255, 0), (0, 0, 25)))
170
     m.add(ScrollText(t, "antidote Abcdefgh antidote", "antidote",
170
     m.add(ScrollText(t, "antidote Abcdefgh antidote", "antidote",
171
-                     1, 75, (0, 255, 0), (0, 0, 255)))
171
+                     1, 75, (0, 255, 0), (0, 0, 25)))
172
     m.add(ScrollText(t, "uushi Abcdefgh uushi", "uushi",
172
     m.add(ScrollText(t, "uushi Abcdefgh uushi", "uushi",
173
-                     1, 75, (0, 255, 0), (0, 0, 255)))
173
+                     1, 75, (0, 255, 0), (0, 0, 25)))
174
     m.add(ScrollText(t, "lemon Abcdefgh lemon", "lemon",
174
     m.add(ScrollText(t, "lemon Abcdefgh lemon", "lemon",
175
-                     1, 75, (0, 255, 0), (0, 0, 255)))
175
+                     1, 75, (0, 255, 0), (0, 0, 25)))
176
     m.add(ScrollText(t, "ib8x8u Abcdefgh ib8x8u", "ib8x8u",
176
     m.add(ScrollText(t, "ib8x8u Abcdefgh ib8x8u", "ib8x8u",
177
-                     1, 75, (0, 255, 0), (0, 0, 255)))
177
+                     1, 75, (0, 255, 0), (0, 0, 25)))
178
     m.add(ScrollText(t, "iv18x16u Abcdefgh iv18x16u", "iv18x16u",
178
     m.add(ScrollText(t, "iv18x16u Abcdefgh iv18x16u", "iv18x16u",
179
-                     1, 75, (0, 255, 0), (0, 0, 255)))
179
+                     1, 75, (0, 255, 0), (0, 0, 25)))
180
 
180
 
181
     m.restart()
181
     m.restart()
182
     t.debug_loop(m.draw)
182
     t.debug_loop(m.draw)

+ 45
- 0
mapper.py View File

1
+#!/usr/bin/env python3
2
+
3
+# ----------------------------------------------------------------------------
4
+# "THE BEER-WARE LICENSE" (Revision 42):
5
+# <xythobuz@xythobuz.de> wrote this file.  As long as you retain this notice
6
+# you can do whatever you want with this stuff. If we meet some day, and you
7
+# think this stuff is worth it, you can buy me a beer in return.   Thomas Buck
8
+# ----------------------------------------------------------------------------
9
+
10
+# Does nothing. Take this as an example for new Mappers.
11
+class MapperNull:
12
+    def __init__(self, g):
13
+        self.gui = g
14
+        self.width = self.gui.width
15
+        self.height = self.gui.height
16
+        self.multiplier = self.gui.multiplier
17
+        self.panelW = self.gui.panelW
18
+        self.panelH = self.gui.panelH
19
+
20
+    def loop_start(self):
21
+        return self.gui.loop_start()
22
+
23
+    def loop_end(self):
24
+        self.gui.loop_end()
25
+
26
+    def debug_loop(self, func = None):
27
+        self.gui.debug_loop(func)
28
+
29
+    def set_pixel(self, x, y, color):
30
+        self.gui.set_pixel(x, y, color)
31
+
32
+# For some reason the red and green LEDs on newer Pimoroni panels
33
+# are far brighter than on older panels.
34
+# Adjust this by multiplying rg channels with 0.75, depending
35
+# on hard-corded coordinate ranges.
36
+class MapperColorAdjust(MapperNull):
37
+    def set_pixel(self, x, y, color):
38
+        # right-most panel, with maximum x coordinates,
39
+        # is "old" type with less bright LEDs.
40
+        # rest of panels to the left are brighter.
41
+        # so adjust brightness of left panel rg channels down.
42
+        if x < self.gui.panelW:
43
+            color = (int(color[0] * 0.75), int(color[1] * 0.75), color[2])
44
+
45
+        self.gui.set_pixel(x, y, color)

+ 38
- 9
pi.py View File

6
 # And the pillow Python Imaging Library:
6
 # And the pillow Python Imaging Library:
7
 # https://github.com/python-pillow/Pillow
7
 # https://github.com/python-pillow/Pillow
8
 #
8
 #
9
+# For the wiring of multiple panels, check out:
10
+# https://github.com/hzeller/rpi-rgb-led-matrix/blob/master/wiring.md#chains
11
+#
12
+# Basically each chain only stretches in the X-direction.
13
+# For the Y-direction, multiple parallel chains are used.
14
+# Up to 3 are theoretically possible with the Pi, but my hardware only supports
15
+# one.
16
+#
17
+# The physical layout of the chained panels can be different of course.
18
+# For four panels, you could do 64x64 or 32x128.
19
+# But this PiMatrix object will always present it as 128x32,
20
+# chained in the X-direction.
21
+#
22
+# Use the objects from mapper.py to adjust this.
23
+#
9
 # ----------------------------------------------------------------------------
24
 # ----------------------------------------------------------------------------
10
 # "THE BEER-WARE LICENSE" (Revision 42):
25
 # "THE BEER-WARE LICENSE" (Revision 42):
11
 # <xythobuz@xythobuz.de> wrote this file.  As long as you retain this notice
26
 # <xythobuz@xythobuz.de> wrote this file.  As long as you retain this notice
17
 from PIL import Image
32
 from PIL import Image
18
 
33
 
19
 class PiMatrix:
34
 class PiMatrix:
20
-    def __init__(self, w = 32, h = 32):
21
-        self.width = w
22
-        self.height = h
35
+    def __init__(self, w = 64, h = 32, panelW = 32, panelH = 32):
36
+        self.width = w # x-axis
37
+        self.height = h # y-axis
38
+
39
+        self.panelW = panelW # x-axis
40
+        self.panelH = panelH # y-axis
41
+
42
+        # compatibility to TestGUI
43
+        self.multiplier = 1.0
23
 
44
 
24
         options = RGBMatrixOptions()
45
         options = RGBMatrixOptions()
25
-        options.rows = w
26
-        options.cols = h
27
-        options.chain_length = 1
28
-        options.parallel = 1
46
+
47
+        options.cols = self.panelW # x-axis
48
+        options.rows = self.panelH # y-axis
49
+
50
+        options.chain_length = int(self.width / options.cols) # x-axis
51
+        options.parallel = int(self.height / options.rows) # y-axis
52
+
29
         options.row_address_type = 0
53
         options.row_address_type = 0
30
         options.multiplexing = 0
54
         options.multiplexing = 0
31
         options.pwm_bits = 11
55
         options.pwm_bits = 11
33
         options.pwm_lsb_nanoseconds = 130
57
         options.pwm_lsb_nanoseconds = 130
34
         options.led_rgb_sequence = 'RGB'
58
         options.led_rgb_sequence = 'RGB'
35
         #options.hardware_mapping = 'regular'  # If you have an Adafruit HAT: 'adafruit-hat'
59
         #options.hardware_mapping = 'regular'  # If you have an Adafruit HAT: 'adafruit-hat'
36
-        options.gpio_slowdown = 2
37
-        options.pixel_mapper_config = "Rotate:270"
60
+        #options.gpio_slowdown = 2
61
+        #options.pixel_mapper_config = "Rotate:270"
62
+
63
+        # newer Pimoroni 32x32 panels require this setting for additional
64
+        # initialization of the shift-registers on there.
65
+        # fortunately this also works for the older type of panels.
66
+        options.panel_type = "FM6126A"
38
 
67
 
39
         self.matrix = RGBMatrix(options = options)
68
         self.matrix = RGBMatrix(options = options)
40
 
69
 

+ 32
- 3
solid.py View File

13
     def __init__(self, g, t = 1.0, c = (0, 0, 0)):
13
     def __init__(self, g, t = 1.0, c = (0, 0, 0)):
14
         self.gui = g
14
         self.gui = g
15
         self.time = t
15
         self.time = t
16
-        self.color = c
16
+        self.setColor(c)
17
         self.restart()
17
         self.restart()
18
 
18
 
19
+    def setColor(self, c):
20
+        self.color = c
21
+
19
     def restart(self):
22
     def restart(self):
20
         self.start = time.time()
23
         self.start = time.time()
21
 
24
 
31
     import util
34
     import util
32
     t = util.getTarget()
35
     t = util.getTarget()
33
 
36
 
34
-    d = Solid(t, 1.0, (0, 255, 0))
35
-    t.debug_loop(d.draw)
37
+    colors = [
38
+        (251, 72, 196), # camp23 pink
39
+        (63, 255, 33), # camp23 green
40
+        (255, 0, 0),
41
+        (0, 255, 0),
42
+        (0, 0, 255),
43
+        (255, 255, 0),
44
+        (0, 255, 255),
45
+        (255, 0, 255),
46
+        (255, 255, 255),
47
+    ]
48
+    ci = 0
49
+
50
+    d = Solid(t, 1.0, colors[ci])
51
+
52
+    s = time.time()
53
+    def helper():
54
+        global s, colors, ci
55
+
56
+        if (time.time() - s) >= 1.0:
57
+            s = time.time()
58
+            ci = (ci + 1) % len(colors)
59
+            c = colors[ci]
60
+            d.setColor(c)
61
+
62
+        d.draw()
63
+
64
+    t.debug_loop(helper)

+ 13
- 8
splash.py View File

14
         self.height = height
14
         self.height = height
15
 
15
 
16
     def draw(self):
16
     def draw(self):
17
-        self.gui.set_pixel(             0,               0, (255, 255, 255))
18
-        self.gui.set_pixel(             0, self.height - 1, (  0,   0, 255))
19
-        self.gui.set_pixel(self.width - 1,               0, (255,   0,   0))
20
-        self.gui.set_pixel(self.width - 1, self.height - 1, (  0, 255,   0))
17
+        for x in range(0, int(self.gui.width / self.width)):
18
+            for y in range(0, int(self.gui.height / self.height)):
19
+                self.drawOnce(x * self.width, y * self.height)
20
+
21
+    def drawOnce(self, x, y):
22
+        self.gui.set_pixel(             x,               y, (255, 255, 255))
23
+        self.gui.set_pixel(             x, self.height - 1 + y, (  0,   0, 255))
24
+        self.gui.set_pixel(self.width - 1 + x,               y, (255,   0,   0))
25
+        self.gui.set_pixel(self.width - 1 + x, self.height - 1 + y, (  0, 255,   0))
21
 
26
 
22
         for i in range(0, int(min(self.width, self.height) / 3)):
27
         for i in range(0, int(min(self.width, self.height) / 3)):
23
-            self.gui.set_pixel((self.width / 2) - 1 + i, (self.height / 2) - 1 + i, (255, 255, 255))
24
-            self.gui.set_pixel((self.width / 2) - 1 - i, (self.height / 2) - 1 - i, (255, 255, 255))
25
-            self.gui.set_pixel((self.width / 2) - 1 + i, (self.height / 2) - 1 - i, (255, 255, 255))
26
-            self.gui.set_pixel((self.width / 2) - 1 - i, (self.height / 2) - 1 + i, (255, 255, 255))
28
+            self.gui.set_pixel((self.width / 2) - 1 + i + x, (self.height / 2) - 1 + i + y, (255, 255, 255))
29
+            self.gui.set_pixel((self.width / 2) - 1 - i + x, (self.height / 2) - 1 - i + y, (255, 255, 255))
30
+            self.gui.set_pixel((self.width / 2) - 1 + i + x, (self.height / 2) - 1 - i + y, (255, 255, 255))
31
+            self.gui.set_pixel((self.width / 2) - 1 - i + x, (self.height / 2) - 1 + i + y, (255, 255, 255))
27
 
32
 
28
     def finished(self):
33
     def finished(self):
29
         return True
34
         return True

+ 4
- 0
test.py View File

18
         self.height = height
18
         self.height = height
19
         self.multiplier = multiplier
19
         self.multiplier = multiplier
20
 
20
 
21
+        # compatibility to PiMatrix
22
+        self.panelW = self.width
23
+        self.panelH = self.height
24
+
21
         pygame.display.init()
25
         pygame.display.init()
22
         self.screen = pygame.display.set_mode((self.width * self.multiplier, self.height * self.multiplier))
26
         self.screen = pygame.display.set_mode((self.width * self.multiplier, self.height * self.multiplier))
23
         self.clock = pygame.time.Clock()
27
         self.clock = pygame.time.Clock()

+ 5
- 1
util.py View File

22
     target = None
22
     target = None
23
     try:
23
     try:
24
         from pi import PiMatrix
24
         from pi import PiMatrix
25
-        target = PiMatrix()
25
+        pi = PiMatrix()
26
+
27
+        # TODO hard-coded adjustments
28
+        from mapper import MapperColorAdjust
29
+        target = MapperColorAdjust(pi)
26
 
30
 
27
         if targetIsPi == None:
31
         if targetIsPi == None:
28
             # only print once
32
             # only print once

Loading…
Cancel
Save