noahwilliamsson / lamatrix

Animated 8x32 LED matrix display / smart clock with a microcontroller and (Micro)Python
MIT License
38 stars 7 forks source link

Using Raspberry PI directly to 8 x 32 not working? #1

Open evanjmg opened 4 years ago

evanjmg commented 4 years ago

Hi, thank you so much for this LED text example! I'm a total noob but got my 8 row x 32 columns BTF - 256 pixels working with this other tutorial to display animated rainbows etc. However, I can't seem to get anything running with your code - I get the following port error below. Did I miss a step? Thank you for such a detailed readme - I've followed all the python setup and am using the pin setup from the other tutorial above.

pi@raspberrypi:~/lamatrix $ python main.py
SerialProtocol: opening port /dev/ttyACM0 @ 115200 baud
Traceback (most recent call last):
  File "main.py", line 67, in <module>
    driver = HAL(config)
  File "/home/pi/lamatrix/arduinoserialhal.py", line 23, in __init__
    self.reset()
  File "/home/pi/lamatrix/arduinoserialhal.py", line 44, in reset
    self.ser = serial.Serial(self.port, baudrate=self.baudrate, rtscts=True, timeout=0.1, write_timeout=0.5)
  File "/usr/lib/python2.7/dist-packages/serial/serialutil.py", line 240, in __init__
    self.open()
  File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 268, in open
    raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg))
serial.serialutil.SerialException: [Errno 2] could not open port /dev/ttyACM0: [Errno 2] No such file or directory: '/dev/ttyACM0'
noahwilliamsson commented 4 years ago

Hi,

Unfortunately this project does not support driving the LED matrix from a Raspberry Pi alone. Instead it's expected that the LED matrix is driven via micro controller that either supports MicroPython (e.g. PyCom devices) or the Arduino FastLED library (e.g. a Teensy).

The error message happens because the current code think it's running on the "host side" and expects to find a micro controller to talk to (using a special protocol) over a serial interface. When the serial port wasn't available the code crashed.

Thanks for the link to the tutorial. It seems they make use of https://github.com/jgarff/rpi_ws281x to generate the necessary signals to control the LEDs using existing hardware on the Raspberry Pi. It also seems there are Python bindings available for this library: https://github.com/rpi-ws281x/rpi-ws281x-python.

I suppose it would be technically possible to implement the HAL (hardware abstraction layer) expected by this project on top of the rpi-ws281x-python library. Something that would provide most of the methods as seen in upyhal.py.

You would then need to make some modifications to main.py to make it all work because currently it's a bit of a mess to detect if the code is running on the host side or on the MCU side.

willumpie82 commented 3 years ago

Hi, @evanjmg, did you manage to port this project to run the led matrix natively connected to the pi?

noahwilliamsson commented 3 years ago

Hi @willumpie82, @evanjmg. I just pushed two changes that should allow you to try this project on a Raspberry Pi (tested on a 3 model B+).

To try it out:

# Install dependencies
sudo apt install -y python-pip python-requests
sudo pip install rpi_ws281x

# Per the instructions on https://github.com/jgarff/rpi_ws281x#pwm
echo blacklist snd_bcm2835 | sudo tee /etc/modprobe.d/snd-blacklist.conf
echo hdmi_force_hotplug=1 | sudo tee -a /boot/config.txt
echo hdmi_force_edid_audio=1 | sudo tee -a /boot/config.txt
sudo reboot
# Wait for the Raspberry Pi to reboot

Next, clone this repo and download necessary resources:

git clone https://github.com/noahwilliamsson/lamatrix
cd lamatrix

# Download icons (see https://github.com/noahwilliamsson/lamatrix/tree/master/icons)
curl -o icons/game-brick.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=1524
curl -o icons/game-invaders-1.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=3405
curl -o icons/game-invaders-2.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=3407
curl -o icons/game-tetris.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=4007
curl -o icons/game-nintendo.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=5038
curl -o icons/game-pacman-ghosts.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=20117
curl -o icons/game-pingpong.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=4075
curl -o icons/game-snake.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=16036
curl -o icons/matrix.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=653
curl -o icons/newyears.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=9356
curl -o icons/tv-movie.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=7862
# Convert JSON to a less verbose binary representation
scripts/convert-animation.py icons/*.json
rm icons/*.json

# Download weather icons (see https://github.com/noahwilliamsson/lamatrix/tree/master/weather)
curl -o weather/sunny.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=1338
curl -o weather/sunny-with-clouds.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=8756
curl -o weather/cloud-partly.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=2286
curl -o weather/cloudy.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=12019
curl -o weather/fog.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=17056
curl -o weather/moon-stars.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=16310
curl -o weather/rain-snow.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=160
curl -o weather/rain.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=72
curl -o weather/snow-house.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=7075
curl -o weather/snowy.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=2289
curl -o weather/thunderstorm.json https://developer.lametric.com/api/v1/dev/preloadicons?icon_id=11428
# Convert JSON to a less verbose binary representation
scripts/convert-animation.py weather/*.json
rm weather/*.json

Wire up the display's +5V, GND and DIN to the Raspberry Pi header pins 4 (5v Power), 6 (GND) and 12 (GPIO 18 PCM CLK) respectively (see https://pinout.xyz).

Finally, try running the code:

python main.py
willumpie82 commented 3 years ago

It works (Y) on my rpiZeroW I do have one challange and that is the rotation of my individual panales are rotated 90degr each.

I have CJMCU-8*8 panels from Ali, i'll rotate them

edit: unfourtunatly not so easy to rotate the panels, the panel for this software is 1 panel of 64x8 with 64pixels in a row, I have 4 panels with 8x8 layout, any hint where to change for this layout?

noahwilliamsson commented 3 years ago

You could try to modify LedMatrix.xy_to_phys() to account for that: https://github.com/noahwilliamsson/lamatrix/blob/master/ledmatrix.py#L50-L76.

My particular 32x8 display is laid out in a zig-zag pattern with the first eight pixels starting at the top-left corner going down in the first column. Pixels 9-16 start in the bottom of the second column going upwards.

The above mentioned method takes care of translating a (x,y) coordinate (with (0,0) being the top-left corner) in a grid of columns x stride to a physical pixel number. These two numbers (32 and 8 respectively) are configured here in https://github.com/noahwilliamsson/lamatrix/blob/master/config.json#L19-L20.

HTH.

willumpie82 commented 3 years ago

Thanx for the hints,

I came up with a formula to calculate (verified in Excel), need to be extended to be more configurable, and input and outputs protected for invalid values

phys_addr = ((x-1)%self.panelcolumn) + ((y-1)self.panelcolumn) + (self.round_down((x-1)/self.panelcolumn) self.panelcolumn * self.panelrow)

image

results in: Traceback (most recent call last): File "main.py", line 202, in r.next_frame(button_state) File "/home/pi/lamatrix/renderloop.py", line 91, in next_frame loop_again = scene.render(self.frame, self.frame - self.prev_frame - 1, self.fps) File "/home/pi/lamatrix/demoscene.py", line 62, in render display.put_pixel(dot_x, dot_y, color, color, color >> 1) File "/home/pi/lamatrix/ledmatrix.py", line 117, in put_pixel offset = pixel3 TypeError: unsupported operand type(s) for : 'NoneType' and 'int'

edit: Fixed it (y) I removed the -1 from the formula, (and i forgot to ucomment the return call)