2

Using pygame to read info from controller, but when I add arduinoData.write(str.encode(ALL_DATA)) it reduces the speed a lot, what can I do?

The line is added almost at the bottom. Is it the placement of the line; it is definitely working but doesn't send updates as fast as if I wouldn't write to serial.

import sys
import serial
import pygame
import time

from pygame.locals import *
pygame.init()

A0_value = '0'
A1_value = '0'
A2_value = '0'
A3_value = '0'
A4_value = '0'
A5_value = '0'
A6_value = '0'
B2 = '0'
B3 = '0'
B4 = '0'
B5 = '0'
global axis_data 

## 
arduinoData = serial.Serial('COM8',9600)

##

def main():
    global axis_data , button_data
    screen = pygame.display.set_mode((500, 700))
    pygame.display.set_caption("Joystick example")

    clock = pygame.time.Clock()
    joysticks = {}

    while True:
        for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    done = True  # Flag that we are done so we exit this loop.

                if event.type == pygame.JOYBUTTONDOWN:
                    print("Joystick button pressed.")
                    if event.button == 0:
                        joystick = joysticks[event.instance_id]
                        if joystick.rumble(0, 0.7, 500):
                            print(
                                "Rumble effect played on joystick {}".format(
                                    event.instance_id
                                )
                            )

                if event.type == pygame.JOYBUTTONUP:
                    print("Joystick button released.")

                # Handle hotplugging
                if event.type == pygame.JOYDEVICEADDED:
                    # This event will be generated when the program starts for every
                    # joystick, filling up the list without needing to create them manually.
                    joy = pygame.joystick.Joystick(event.device_index)
                    joysticks[joy.get_instance_id()] = joy
                    print("Joystick {} connencted".format(joy.get_instance_id()))

                if event.type == pygame.JOYDEVICEREMOVED:
                    del joysticks[event.instance_id]
                    print("Joystick {} disconnected".format(event.instance_id))




        for joystick in joysticks.values():
            axes = joystick.get_numaxes()
            #print("Number of axes: {}".format(axes))
            axis_str = [''] * axes
            button_data = ""
            axis_data = ""



            for i in range(axes):
                axis = joystick.get_axis(i)
                axis_int = int(axis*100)
                axis_str[i] = str(axis_int)
                axis_data = axis_str[i] + "," + axis_data 
                #print("Axis {} value: {}".format(i, axis)) 
            
            #print(axis_data)
            buttons = joystick.get_numbuttons()
            #print("Number of buttons: {}".format(buttons))
            button_str = ['0'] * buttons

            for i in range(buttons):
                button = joystick.get_button(i)
                button_str[i] = str(button)
                #print("Button {} value: {}".format(i, button))
                button_data = button_str[i] + "," + button_data
            
            #print(button_data)
            ALL_DATA = axis_data + button_data
            ALL_DATA = ALL_DATA[:-1] + "!"
            print(ALL_DATA)
        arduinoData.write(str.encode(ALL_DATA))

        
            
       # pygame.display.update()
        clock.tick(60)


if __name__ == "__main__":
    main()
    # If you forget this line, the program will 'hang'
    # on exit if running from IDLE.
    pygame.quit()
Stabledog
  • 3,110
  • 2
  • 32
  • 43
  • 2
    The slowdown is being caused by the `arduinoData.write()` call blocking the event processing loop until it completes. To work around that you could use create a separate thread to the writing or use the experimental [`asyncio` support](https://pythonhosted.org/pyserial/pyserial_api.html#module-serial.aio) the `pyserial` module has. – martineau Jun 15 '22 at 21:23
  • 1
    Using a higher baud rate would reduce the time taken to send updates. Choosing a more compact representation for your updates (for example, using bits in a byte rather than two ASCII characters for each button state) would also help. – jasonharper Jun 15 '22 at 21:31

1 Answers1

7

Writing to serial at 9600 baud is really quite slow. Referencing this answer on baud-rate send-time, to send each letter is a bit more than 1 millisecond (roughly). Note that at 60 FPS, each frame is allowed ~17 milliseconds. The code is writing this data as a string, so probably it's taking quite some milliseconds, every loop.

A really easy win is to simply use a faster baud-rate. You could at least try 230400 for a 24x speed-up.

Also almost never do we send real-time data as strings. You could use the Python struct module to pack all the various joystick readings into binary data, which would be much more compact. Especially if you treat button states as single bits, and don't need high-resolution on the joystick position.

And finally, your code could use a thread to perform the serial communications, writing in parallel to the main PyGame loop. This works well on "IO Bound" operations.

Kingsley
  • 14,398
  • 5
  • 31
  • 53