[SOLVED] Need help to change icon on LED matrix with serial input

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
stiw47
Posts: 5
Joined: Sat Apr 11, 2020 11:33 am

[SOLVED] Need help to change icon on LED matrix with serial input

Post by stiw47 » Sat Apr 11, 2020 11:58 am

Hi guys. I am not a dev, just trying to make things working as I want. Cannot understand this:

From one side, this is my python script on Ubuntu PC which sending button inputs from Playstation 4 joystick to serial port of micro:bit (joystick is connected to Ubuntu via bluetooth):

Code: Select all

import serial
import pygame

pygame.init()
pygame.joystick.init()

joystick = pygame.joystick.Joystick(0)
joystick.init()

screen = pygame.display.set_mode((100,100))

device = serial.Serial('/dev/ttyACM0', 115200)

try:
    while True:
        events = pygame.event.get()
        for event in events:
            if event.type == pygame.JOYBUTTONDOWN:
                if event.button == 7:
                    device.write(b"1\r\n")
                elif event.button == 6:
                    device.write(b"2\r\n")
            elif event.type == pygame.JOYBUTTONUP:
                if joystick.get_button(7) == 1:
                    device.write(b"1\r\n")
                elif joystick.get_button(6) == 1:
                    device.write(b"2\r\n")
                elif joystick.get_axis(0) < 0:
                    device.write(b"3\r\n")
                elif joystick.get_axis(0) > 0:
                    device.write(b"4\r\n")
                else:
                    device.write(b"5\r\n")
            if event.type == pygame.JOYAXISMOTION:
                if event.axis == 0:
                    if event.value < 0:
                        device.write(b"3\r\n")
                    elif event.value > 0:
                        device.write(b"4\r\n")
                    elif event.value == 0:
                        if joystick.get_button(7) == 1:
                            device.write(b"1\r\n")
                        elif joystick.get_button(6) == 1:
                            device.write(b"2\r\n")
                        else:
                            device.write(b"5\r\n")
except KeyboardInterrupt:
    print("EXITING NOW")
    joystick.quit()
device.close()
From other side, this is the micropython code I flashed to micro:bit from Mu editor and expected it will work, but it doesn't :lol:

Code: Select all

from microbit import *

uart.init(baudrate=115200)

while True:
    joyinput = uart.read()
    if joyinput == "1":
        display.show(Image.ARROW_N)
    elif joyinput == "2":
        display.show(Image.ARROW_S)
    elif joyinput == "3":
        display.show(Image.ARROW_W)
    elif joyinput == "4":
        display.show(Image.ARROW_E)
    elif joyinput == "5":
        display.show(Image.HAPPY)
In REPL console of Mu editor, I can see that communication is going well, i.e. as far as I'm holding pressed some button or joystick axis moved, I'm getting REPL with appropriate number:
  • 1 for joystick button 7 (R2)
    2 for joystick button 6 (L2)
    3 for joystick axis 0 left position (left analog on joystick)
    3 for joystick axis 0 right position (left analog on joystick)
    5 if nothing is pressed/moved
But icons on LED matrix never appear.

Till now, it was possible for me to display some icon, only if I add one more "else" statement at the end of script, but this is normal cause it is "else".
E.g.

Code: Select all

from microbit import *

uart.init(baudrate=115200)

while True:
    joyinput = uart.read()
    if joyinput == "1":
        display.show(Image.ARROW_N)
    elif joyinput == "2":
        display.show(Image.ARROW_S)
    elif joyinput == "3":
        display.show(Image.ARROW_W)
    elif joyinput == "4":
        display.show(Image.ARROW_E)
    elif joyinput == "5":
        display.show(Image.HAPPY)
    else:
        display.show(Image.HAPPY)
Image

Many thanks in advance, I would be glad to provide any additional info needed.
Last edited by stiw47 on Tue Apr 14, 2020 4:21 am, edited 1 time in total.

Iyassou
Posts: 42
Joined: Sun Jun 26, 2016 9:15 am

Re: Need help to change icon on LED matrix with serial input

Post by Iyassou » Sun Apr 12, 2020 9:27 pm

I don't have a microbit, but I think the issue might be the comparisons.

Code: Select all

joystick = uart.read() 
should be returning a bytes object according to the docs, in which case comparing it to strings (e.g. "1") would never be equal.

One suggestion: since you're sending bytes objects ending with a newline why not make use of the

Code: Select all

uart.readline
method? It would handle tokenising your input. Once that's handled and you get a steady stream of data, you can compare the first character inside of the bytes object to the strings "1", "2", etc using the chr method:

Code: Select all

if chr(joystick[0]) == "1":
    display.show(Image.ARROW_N)
# elif ...

stiw47
Posts: 5
Joined: Sat Apr 11, 2020 11:33 am

Re: Need help to change icon on LED matrix with serial input

Post by stiw47 » Mon Apr 13, 2020 3:52 am

Iyassou wrote:
Sun Apr 12, 2020 9:27 pm
I don't have a microbit, but I think the issue might be the comparisons.

Code: Select all

joystick = uart.read() 
should be returning a bytes object according to the docs, in which case comparing it to strings (e.g. "1") would never be equal.

One suggestion: since you're sending bytes objects ending with a newline why not make use of the

Code: Select all

uart.readline
method? It would handle tokenising your input. Once that's handled and you get a steady stream of data, you can compare the first character inside of the bytes object to the strings "1", "2", etc using the chr method:

Code: Select all

if chr(joystick[0]) == "1":
    display.show(Image.ARROW_N)
# elif ...
Hi! Thanks a lot for answer. I tried this, below is full code, but I ended with:
Line 7 TypeError: 'NoneType' object is not subscriptable

Code: Select all

from microbit import *

uart.init(baudrate=115200)

while True:
    joyinput = uart.readline()
    if chr(joyinput[0]) == "1":
        display.show(Image.ARROW_N)
    elif chr(joyinput[0]) == "2":
        display.show(Image.ARROW_S)
    elif chr(joyinput[0]) == "3":
        display.show(Image.ARROW_W)
    elif chr(joyinput[0]) == "4":
        display.show(Image.ARROW_E)
    elif chr(joyinput[0]) == "5":
        display.show(Image.HAPPY)
Thanks once again.

stiw47
Posts: 5
Joined: Sat Apr 11, 2020 11:33 am

Re: Need help to change icon on LED matrix with serial input

Post by stiw47 » Mon Apr 13, 2020 11:05 am

I searched Google for above error
TypeError: 'NoneType' object is not subscriptable
And found this is because I have empty response from serial until joystick is connected. I.e.
  • If I connect micro:bit first I have no input on serial until I not start python script on Ubuntu.
    From other side, python script on Ubuntu is crashing if it is started first, because there is no serial device on /dev/ttyACM0
I tried to add time.sleep(15) on beginning of loop, just to be sure is this only problem, but icons on LED matrix still not appear and everything is seems OK in REPL console of Mu editor (I can see printing of new lines with appropriate number if I'm holding down appropriate button).

This is new try:

Code: Select all

from microbit import *
import time

uart.init(baudrate=115200)

while True:
    time.sleep(15)
    joyinput = uart.readline()
    if chr(joyinput[0]) == "1":
        display.show(Image.ARROW_N)
    elif chr(joyinput[0]) == "2":
        display.show(Image.ARROW_S)
    elif chr(joyinput[0]) == "3":
        display.show(Image.ARROW_W)
    elif chr(joyinput[0]) == "4":
        display.show(Image.ARROW_E)
    elif chr(joyinput[0]) == "5":
        display.show(Image.HAPPY)

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Need help to change icon on LED matrix with serial input

Post by jimmo » Tue Apr 14, 2020 2:22 am

stiw47 wrote:
Mon Apr 13, 2020 11:05 am
I tried to add time.sleep(15) on beginning of loop, just to be sure is this only problem, but icons on LED matrix still not appear and everything is seems OK in REPL console of Mu editor (I can see printing of new lines with appropriate number if I'm holding down appropriate button).

This is new try:
Three things:
- readline returns None if there's no input, otherwise it returns the input line.
- When there is input, readline will include the '\r' at the end of the line (use strip to remove it).
- As already pointed out, readline returns "bytes" (not strings), so you need to compare to bytes (or convert it to a string first). (The distinction here is that in Python, strings are UTF-8 encoded, whereas bytes are just ... well... bytes).

So, instead of sleeping, just do nothing if the input is None.

Code: Select all

while True:
    joyinput = uart.readline()
    if not joyinput:
      continue
    joyinput = joyinput.strip()
    if joyinput == b"1":             # note the b at the start says that "1" is also in "bytes".
      display.show(...)
    ... etc
You could also change the strip line to:

Code: Select all

joyinput = str(joyinput.strip(), 'utf-8')
if joyinput == "1":
  ...
Which will tell Python to interpret the input as utf-8 encoded data (so you can now compare it to strings directly).

stiw47
Posts: 5
Joined: Sat Apr 11, 2020 11:33 am

Re: Need help to change icon on LED matrix with serial input

Post by stiw47 » Tue Apr 14, 2020 4:21 am

jimmo wrote:
Tue Apr 14, 2020 2:22 am
Three things:
- readline returns None if there's no input, otherwise it returns the input line.
- When there is input, readline will include the '\r' at the end of the line (use strip to remove it).
- As already pointed out, readline returns "bytes" (not strings), so you need to compare to bytes (or convert it to a string first). (The distinction here is that in Python, strings are UTF-8 encoded, whereas bytes are just ... well... bytes).

So, instead of sleeping, just do nothing if the input is None.

........

Thank you very much, this is exactly what I wanted, but had no enough skill to accomplish on my own. It is working.

So final code for micro:bit is looking now as below:

Code: Select all

from microbit import *

uart.init(baudrate=115200)

while True:
    joyinput = uart.readline()
    if not joyinput:
        continue
    joyinput = str(joyinput.strip(), 'utf-8')
    if joyinput == "1":
        display.show(Image.ARROW_N)
    elif joyinput == "2":
        display.show(Image.ARROW_S)
    elif joyinput == "3":
        display.show(Image.ARROW_W)
    elif joyinput == "4":
        display.show(Image.ARROW_E)
    elif joyinput == "5":
        display.show(Image.HAPPY)
Just to have everything in one place, and maybe it will be useful for some n00b as I am :D , below is python code for Linux PC, Raspberry Pi, whatever where joystick is connected, etc (Please change the name of serial port according your needs. On RPI, it should be /dev/ttyACM0 always I think, but e.g. on my Ubuntu Lenovo T440p it was sometimes ACM1, ACM2 or ACM3, etc.)

Code: Select all

import serial
import pygame

pygame.init()
pygame.joystick.init()

joystick = pygame.joystick.Joystick(0)
joystick.init()

screen = pygame.display.set_mode((100,100))

device = serial.Serial('/dev/ttyACM0', 115200)

try:
    while True:
        events = pygame.event.get()
        for event in events:
            if event.type == pygame.JOYBUTTONDOWN:
                if event.button == 7:
                    device.write(b"1\r\n")
                elif event.button == 6:
                    device.write(b"2\r\n")
            elif event.type == pygame.JOYBUTTONUP:
                if joystick.get_button(7) == 1:
                    device.write(b"1\r\n")
                elif joystick.get_button(6) == 1:
                    device.write(b"2\r\n")
                elif joystick.get_axis(0) < 0:
                    device.write(b"3\r\n")
                elif joystick.get_axis(0) > 0:
                    device.write(b"4\r\n")
                else:
                    device.write(b"5\r\n")
            if event.type == pygame.JOYAXISMOTION:
                if event.axis == 0:
                    if event.value < 0:
                        device.write(b"3\r\n")
                    elif event.value > 0:
                        device.write(b"4\r\n")
                    elif event.value == 0:
                        if joystick.get_button(7) == 1:
                            device.write(b"1\r\n")
                        elif joystick.get_button(6) == 1:
                            device.write(b"2\r\n")
                        else:
                            device.write(b"5\r\n")
except KeyboardInterrupt:
    print("EXITING NOW")
    joystick.quit()
device.close()
Now I can add little blinking or scrolling on these arrows, cause this is actually addition for my Lego RPi robo-car (Work In Progress) :D :

https://www.youtube.com/watch?v=zCzD2hbr3R0

I flagged topic as SOLVED, thanks once again.
Last edited by stiw47 on Tue Apr 14, 2020 6:40 am, edited 1 time in total.

stiw47
Posts: 5
Joined: Sat Apr 11, 2020 11:33 am

Re: [SOLVED] Need help to change icon on LED matrix with serial input

Post by stiw47 » Tue Apr 14, 2020 6:37 am

One more thing: Since I asked same question on another site, same time as here, now I answered my question there and included link to this thread. I also gave credits to people who helped me here. I hope this is ok, didn't found anything regarding that here on mycropython forum FAQ and sorry if I missed, but didn't found forum rules at all :D

https://stackoverflow.com/questions/611 ... erial-port

Post Reply