Search code examples
python-3.xlinuxmultithreadingopencvpynput

Python Multithreading with pynput.keyboard.listener


I am building a self-driving rc car. The car is controlled by a raspberry pi (client) that sends image data to my computer (server) and the computer processes the image frames and responds to the car with what to do (all using python sockets). This works perfectly well. I am now trying to add a key listener to python so I can manually control the car WHILE all of the socket interractions are happening. I would like to use multithreading to do so. Here is how I believe it should work:

import cv2
from pynput import keyboard
from Server import Server

###Keyboard Listener###
def keyPress(key): #send keypress to client
    server.sendCommand((str(key)))
with keyboard.Listener(on_press=keyPress) as listener: #new listener thread
    listener.join() #activate thread

###Server/ client interaction###
host, port = '10.78.1.195', 8000  # home
server = Server(host, port) #server object
server.connect() #connect
while server.isOpened(): #do while the server is open
    frame = server.getStreamImage() #get an image from the client each frame
    server.sendCommand("0") #send a command to the server (arbituary for now, but will be a neural network ouotput
    cv2.imshow("t", frame)  # show image
    # cv2.imshow("tttttt", nnInput)  # show image CONFIGURE PERSPECTIVE TRANSFORM AFTER CAMERA MOUNT
    if cv2.waitKey(1) == ord('q'): #quit if q pressed
        server.sendCommand('q')  # tell client to close
        server.close()  # break if 'q' pressed
cv2.destroyAllWindows() #close opencv windows

If you would like any of the client or server code, I would be happy to show it. I didn't inlude it because it's working perfectly.

SO, in my mind, the while loop and the keyboard listener should operate in parallel, and I'm not sure why they are not. With this configuration, the keypresses are tracked, but the server/client interactions never begin. I have tried reformatting the code and I can't seem to get the operations to happen parallel.

If there is a simpler or less resource intensive way to do this, I am open to new ideas. This is just what makes the most sense to me. I really just want the code to be as clean as possible.

My python version is 3.7. I am running Ubuntu 19.10. pynput is version 1.4.5.

If I can provide any additional info, please ask. Thank you very much!


Solution

  • Instead of using the with statement to initialise your listener try:

    listener = keyboard.Listener(on_press=keyPress)
    listener.start()
    

    The with statement is blocking the main thread. Using start instead of with / join you create a non-blocking thread allowing the main loop to start.