Pygame + Joystick


#1

Hi,

Has anyone used Pygame’s Joystick to read joystick input?
I’ve augmented the Basic Tutorial to init pygame and a joystick, but I can’t seem to properly read the buttons.

E.g.
self.mJoystick.get_button(0) is never pygame.JOYBUTTONDOWN. But I am pushing on the button (I pushed every button just to be safe).

In fact, querying all the buttons on my joystick never results in a button down event (pygame returns 10 buttons were found with my controller).

I’m pretty sure I’m missing something since I’m new to Python and I’m jumping straight into Panda 3D. For example, I don’t know how Tutorial 1 lesson (the solar system) constantly updates! More than likely my code is not frequently calling the function that polls the joystick buttons.

Any help would be appreciated!!! Thanks!


#2

#3

I got my joystick to work using pygame. First I tried following the joystick part of the Panda3D manual on this site. However, that did not work. Like you, I did not receive the events when you press a button.

Next I tried this code snippet on the forum:
discourse.panda3d.org/viewtopic.php?t=1288
Works for me :slight_smile: .


#4

I’m getting the pygame “video system not initialized” error with the event.get() statement in the example code. Any idea what is casuing this?

#Setup event information and print data from joystick 
while 1: 
    for e in event.get(): 
        if e.type != QUIT: 
            print '%s: %s' % (event.event_name(e.type), e.dict) 

Traceback (most recent call last):
File “foo.py”, line 34, in
for e in event.get():
pygame.error: video system not initialized


#5

From my perspective the problem with getting a joystick read in panda seems to be that panda and pygames have two seperate event systems. The problem seems to be getting the events from pygames into the event list of panda.

Yes I know that this does not add anything to the solution. If I were a better programmer I could add to it. But I will watch this thread to see if anyone has any ideas.


#6

I found the problem; I had to initialize the pygame display

from pygame import * 

init() 
display.init()

#Setup and init joystick 
j=joystick.Joystick(0) 
j.init() 

#Check init status 
if j.get_init() == 1: print "Joystick is initialized" 

#Setup event information and print data from joystick 
while 1: 
    for e in event.get(): 
        if e.type != QUIT: 
            print '%s: %s' % (event.event_name(e.type), e.dict) 

#7

display.init()

Does this bring up a pygame window? I didnt have to do this to get pygame up and running.

Snippet from my Codes

#way before other codes
pygame.init()


#in constructor
self.currentJoystick = pygame.joystick.Joystick(0)
self.currentJoystick.init()
numAxes = self.currentJoystick.get_numaxes()
---other logic here for what axes does what but oh well ---


#some other class file
for e in pygame.event.get(): 
            self.newR = self.currentJoystick.get_axis(self.X)
            self.newP = self.currentJoystick.get_axis(self.Y)
            self.newH = -self.currentJoystick.get_axis(self.RotateAxis)

#8

yeah but neither of those addresses how to get that info recognized by panda. You are both still working within pygame.


#9

Well, this is my yesterday written snippet:

__author__ = 'Emanuele Bertoldi <zuck@fastwebnet.it>'
__copyright__ = 'Copyright (c) 2009 Emanuele Bertoldi'

import pygame
from direct.showbase import DirectObject
from direct.showbase.MessengerGlobal import messenger

class JoystickHandler(DirectObject.DirectObject):
    def __init__(self):
        pygame.init()
        
        count = pygame.joystick.get_count()
        self.__joysticks = []
        for i in range(count):
            js = pygame.joystick.Joystick(i)
            js.init()
            self.__joysticks.append(js)

        taskMgr.add(self.__on_joystick_polling, 'Joystick Polling')
        
    def destroy(self):
        pygame.quit()
        
    def get_joysticks(self):
        return self.__joysticks
        
    def get_count(self):
        return len(self.__joysticks)
        
    def __on_joystick_polling(self, task):
        for ev in pygame.event.get():
        
            if ev.type is pygame.JOYBUTTONDOWN:
                name = 'joystick%d-button%d' % (ev.joy, ev.button)
                messenger.send(name)
                
            elif ev.type is pygame.JOYBUTTONUP:
                name = 'joystick%d-button%d-up' % (ev.joy, ev.button)
                messenger.send(name)
                
            elif ev.type is pygame.JOYAXISMOTION:
                name = 'joystick%d-axis%d' % (ev.joy, ev.axis)
                messenger.send(name, [ev.value])
                
            elif ev.type is pygame.JOYBALLMOTION:
                name = 'joystick%d-ball%d' % (ev.joy, ev.hat)
                messenger.send(name, [ev.rel])
                
            elif ev.type is pygame.JOYHATMOTION:
                name = 'joystick%d-hat%d' % (ev.joy, ev.hat)
                messenger.send(name, [ev.value])
    
        return task.cont

Now you can accept joystick input with the classical approach. For instance:

class Player(JoystickHandler):
    def __init__(self):
        JoystickHandler.__init__(self)

        self.accept('joystick0-axis2', self.steer)
        self.accept('joystick0-button1', self.brake, [True])
        self.accept('joystick0-button1-up', self.brake, [False])
        self.accept('joystick1-button2', self.do_something)
        ...

It works for me :wink:


#10

i also used pygame to support joypad input.
this class adds support for all buttons and sticks, which you can then accept to do something.
there is the dict “self.mapping”, where i define some mappings, the first one is default. you could modify its values to set the right buttons/sticks to the right value.

from pandac.PandaModules import *
import pygame as pg
from string import strip as strip

class joypad:
    def __init__(self):
        pg.init()
        self.padsConnected = False
        self.controllerType = []
        self.setupGamepads()
        self.runPads()
        
    def setupGamepads(self):        
        #Get the number of controllers so we know how many to init
        count = pg.joystick.get_count()
        if count == 0:
            self.padsConnected = False
#            print "no pads connected"
            return
        else: self.padsConnected = True
        #Initialize the controllers
        if count > 0:
            self.c1=pg.joystick.Joystick(0)
            self.c1.init()
            self.controllerType.append(strip(self.c1.get_name()))
        if count > 1:
            self.c2=pg.joystick.Joystick(1)
            self.c2.init()
            self.controllerType.append(strip(self.c2.get_name()))
        if count > 2:
            self.c3=pg.joystick.Joystick(2)
            self.c3.init()          
            self.controllerType.append(strip(self.c3.get_name()))
        if count > 3:
            self.c4=pg.joystick.Joystick(3)
            self.c4.init()
            self.controllerType.append(strip(self.c4.get_name()))
        #print "%i joypads inited" % count
        
        self.mapping = { "default" : {"NORTH-BUTTON":0, "EAST-BUTTON":1, "SOUTH-BUTTON":2, "WEST-BUTTON":3,
                                        "L1-BUTTON" : 4, "R1-BUTTON" : 5, "L2-BUTTON" : 6, "R2-BUTTON" : 7,
                                        "SELECT-BUTTON":8, "START-BUTTON":9,
                                        "L-STICK-BUTTON":10, "R-STICK-BUTTON":11,
                                        "L-STICK-X" : 0, "L-STICK-Y" : 1, "R-STICK-X" : 2, "R-STICK-Y" : 3,
                                        "HAT-WEST":(-1,0), "HAT-EAST":(1,0), "HAT-NORTH":(0,1), "HAT-SOUTH":(0,-1),
                                        "HAT-SOUTH-WEST":(-1,-1), "HAT-NORTH-WEST":(-1,1), "HAT-NORTH-EAST":(1,1), "HAT-SOUTH-EAST":(1,-1),
                                        "HATS-UP":(0,0)
                                        },
                        #my speedlink
                         "USB  Joystick" : {"NORTH-BUTTON":0, "EAST-BUTTON":1, "SOUTH-BUTTON":2, "WEST-BUTTON":3,
                                        "L1-BUTTON" : 4, "R1-BUTTON" : 5, "L2-BUTTON" : 6, "R2-BUTTON" : 7,
                                        "SELECT-BUTTON":8, "START-BUTTON":9,
                                        "L-STICK-BUTTON":10, "R-STICK-BUTTON":11,
                                        "L-STICK-X" : 0, "L-STICK-Y" : 1, "R-STICK-X" : 2, "R-STICK-Y" : 3,
                                        "HAT-WEST":(-1,0), "HAT-EAST":(1,0), "HAT-NORTH":(0,1), "HAT-SOUTH":(0,-1),
                                        "HAT-SOUTH-WEST":(-1,-1), "HAT-NORTH-WEST":(-1,1), "HAT-NORTH-EAST":(1,1), "HAT-SOUTH-EAST":(1,-1),
                                        "HATS-UP":(0,0)
                                        },
                         #my impact
                         "USB Game Controllers" : {"NORTH-BUTTON":1, "EAST-BUTTON":3, "SOUTH-BUTTON":2, "WEST-BUTTON":0,
                                        "L1-BUTTON" : 4, "R1-BUTTON" : 6, "L2-BUTTON" : 5, "R2-BUTTON" : 7,
                                        "SELECT-BUTTON":8, "START-BUTTON":9,
                                        "L-STICK-BUTTON":10, "R-STICK-BUTTON":11,
                                        "L-STICK-X" : 0, "L-STICK-Y" : 1, "R-STICK-X" : 3, "R-STICK-Y" : 2,
                                        "HAT-WEST":(-1,0), "HAT-EAST":(1,0), "HAT-NORTH":(0,1), "HAT-SOUTH":(0,-1),
                                        "HAT-SOUTH-WEST":(-1,-1), "HAT-NORTH-WEST":(-1,1), "HAT-NORTH-EAST":(1,1), "HAT-SOUTH-EAST":(1,-1),
                                        "HATS-UP":(0,0)
                                        },
                                        
                         "USB Joystick" : {"NORTH-BUTTON":0, "EAST-BUTTON":1, "SOUTH-BUTTON":2, "WEST-BUTTON":3,
                                        "L1-BUTTON" : 4, "R1-BUTTON" : 5, "L2-BUTTON" : 6, "R2-BUTTON" : 7,
                                        "SELECT-BUTTON":8, "START-BUTTON":9,
                                        "L-STICK-BUTTON":10, "R-STICK-BUTTON":11,
                                        "L-STICK-X" : 0, "L-STICK-Y" : 1, "R-STICK-X" : 2, "R-STICK-Y" : 3,
                                        "HAT-WEST":(-1,0), "HAT-EAST":(1,0), "HAT-NORTH":(0,1), "HAT-SOUTH":(0,-1),
                                        "HAT-SOUTH-WEST":(-1,-1), "HAT-NORTH-WEST":(-1,1), "HAT-NORTH-EAST":(1,1), "HAT-SOUTH-EAST":(1,-1),
                                        "HATS-UP":(0,0)
                                        }
                         }
    
    def runPads(self):
        if self.padsConnected:
            taskMgr.add(self.gamepadPollingTask, "gamepadPollingTask")
                                
    def gamepadPollingTask(self, task):
        for e in pg.event.get():
#            print e
            #Get which controller this is and add it to the eventName
            if e.dict["joy"] == 0:
                c_number = "C1_"
                c_type = 0
            elif e.dict["joy"] == 1:
                c_number = "C2_"
                c_type = 1
            elif e.dict["joy"] == 2:
                c_number = "C3_"
                c_type = 2
            elif e.dict["joy"] == 3:
                c_number = "C4_"  
                c_type = 3
            
            if self.mapping.has_key(self.controllerType[c_type]):
                type = self.controllerType[c_type]
            else:
                type = "default"
            #Handle the BUTTON DOWN events
            if e.type == pg.JOYBUTTONDOWN:
                if (e.dict["button"] == self.mapping[type]["NORTH-BUTTON"]): 
                    eventName = c_number +  "NORTH-BUTTON_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["EAST-BUTTON"]): 
                    eventName = c_number +  "EAST-BUTTON_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["SOUTH-BUTTON"]): 
                    eventName = c_number +  "SOUTH-BUTTON_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["WEST-BUTTON"]): 
                    eventName = c_number +  "WEST-BUTTON_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["L1-BUTTON"]):
                    eventName = c_number +  "L1-BUTTON_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["R1-BUTTON"]):
                    eventName = c_number +  "R1-BUTTON_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["L2-BUTTON"]):
                    eventName = c_number +  "L2-BUTTON_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["R2-BUTTON"]):
                    eventName = c_number +  "R2-BUTTON_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["SELECT-BUTTON"]):
                    eventName = c_number +  "SELECT-BUTTON_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["START-BUTTON"]):
                    eventName = c_number +  "START-BUTTON_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["L-STICK-BUTTON"]):
                    eventName = c_number +  "L-STICK-BUTTON_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["R-STICK-BUTTON"]):
                    eventName = c_number +  "R-STICK-BUTTON_DOWN"
                    messenger.send(eventName, [])        
                             
#                                                                                                                                                
            #Handle the BUTTONUP events 
            elif e.type == pg.JOYBUTTONUP:
                if (e.dict["button"] == self.mapping[type]["NORTH-BUTTON"]): 
                    eventName = c_number +  "NORTH-BUTTON_UP"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["EAST-BUTTON"]): 
                    eventName = c_number +  "EAST-BUTTON_UP"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["SOUTH-BUTTON"]): 
                    eventName = c_number +  "SOUTH-BUTTON_UP"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["WEST-BUTTON"]): 
                    eventName = c_number +  "WEST-BUTTON_UP"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["L1-BUTTON"]):
                    eventName = c_number +  "L1-BUTTON_UP"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["R1-BUTTON"]):
                    eventName = c_number +  "R1-BUTTON_UP"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["L2-BUTTON"]):
                    eventName = c_number +  "L2-BUTTON_UP"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["R2-BUTTON"]):
                    eventName = c_number +  "R2-BUTTON_UP"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["SELECT-BUTTON"]):
                    eventName = c_number +  "SELECT-BUTTON_UP"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["START-BUTTON"]):
                    eventName = c_number +  "START-BUTTON_UP"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["L-STICK-BUTTON"]):
                    eventName = c_number +  "L-STICK-BUTTON_UP"
                    messenger.send(eventName, [])
                elif (e.dict["button"] == self.mapping[type]["R-STICK-BUTTON"]):
                    eventName = c_number +  "R-STICK-BUTTON_UP"
                    messenger.send(eventName, [])
                                                   
            #Handle the directional pad
            elif e.type == pg.JOYHATMOTION:
                if (e.dict["value"] == self.mapping[type]["HAT-NORTH"]): 
                    eventName = c_number +  "HAT-NORTH_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["value"] == self.mapping[type]["HAT-EAST"]): 
                    eventName = c_number +  "HAT-EAST_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["value"] == self.mapping[type]["HAT-SOUTH"]): 
                    eventName = c_number +  "HAT-SOUTH_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["value"] == self.mapping[type]["HAT-WEST"]): 
                    eventName = c_number +  "HAT-WEST_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["value"] == self.mapping[type]["HAT-SOUTH-WEST"]): 
                    eventName = c_number +  "HAT-SOUTH-WEST_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["value"] == self.mapping[type]["HAT-NORTH-WEST"]): 
                    eventName = c_number +  "HAT-NORTH-WEST_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["value"] == self.mapping[type]["HAT-NORTH-EAST"]): 
                    eventName = c_number +  "HAT-NORTH-EAST_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["value"] == self.mapping[type]["HAT-SOUTH-EAST"]): 
                    eventName = c_number +  "HAT-SOUTH-EAST_DOWN"
                    messenger.send(eventName, [])
                elif (e.dict["value"] == self.mapping[type]["HATS-UP"]): 
                    eventName = c_number +  "HATS-UP"
                    messenger.send(eventName, [])
                  
                   
            #Handle the analog sticks
            elif e.type == pg.JOYAXISMOTION: 
                #Handle the left analog stick X axis
                if (e.dict["axis"] == self.mapping[type]["L-STICK-X"]):
                    if (e.dict["value"] != 0):
                        eventName = c_number +  "L-STICK-X"
                        messenger.send(eventName, [e.dict["value"]])
                                                                                                     
                #Handle the left analog stick Y axis
                elif (e.dict["axis"] == self.mapping[type]["L-STICK-Y"]):
                    if (e.dict["value"] != 0):
                        eventName = c_number +  "L-STICK-Y"
                        messenger.send(eventName, [e.dict["value"]])              
#                        
                #Handle the right analog stick X axis
                elif (e.dict["axis"] == self.mapping[type]["R-STICK-X"]):
                    if (e.dict["value"] != 0):
                        eventName = c_number +  "R-STICK-X"
                        messenger.send(eventName, [e.dict["value"]])    
                                                                               
                #Handle the right analog stick Y axis
                elif (e.dict["axis"] == self.mapping[type]["R-STICK-Y"]):
                    if (e.dict["value"] != 0):
                        eventName = c_number +  "R-STICK-Y"
                        messenger.send(eventName, [e.dict["value"]]) 
                                                                              
        return task.cont

then import the class into your code and initialze it:

self.controllers = joypad()

and to accept events, for example for controller1:

self.accept('C1_NORTH-BUTTON_UP', self.doSomething)

to read the stick-values constantly, start a task and just read the stick-axis-value:

x = self.controllers.c1.get_axis(0)

#11

Thank you zuck and kampfgnu: This took the mystery out of getting pygames recongized in panda.,


#12

Thanks zuck and kampfgnu, great work here!