Please do not post a support request without first reading and following the advice in https://retropie.org.uk/forum/topic/3/read-this-first

Analog Joystick



  • Hey everyone. I'm trying to put the finishing touches on my PSPi, but I need some help.

    I'm using an MCP3002 analog/digital converter. I've got the OS correctly reading the values (not easy because spidev could not be installed until I did a full reinstall of python 2.7.9), and I need to know how to get it working in games. I've searched everywhere for this answer and cannot find it. I hacked some code together, and right now the python script below grabs the values from the ADC and uses uinput to send the values to ABS_X and ABS_Y. I know the ABS method was a long shot, but it was worth a try.

    I know that the most recent version of Retropie asks for analog up/down/left/right during configuration, so something is obviously built in. Can anyone tell me how to connect the dots? I have no hair left to pull out.

    #!/usr/bin/python
    
    import spidev
    import time
    import os
    import uinput
    
    DEBUG = 0
    
    spi = spidev.SpiDev()
    spi.open(0,0)
    spi.max_speed_hz = 100000
    
    def get_adc(channel):
            if ((channel > 1) or (channel < 0)):
                    return -1
    
            r = spi.xfer2([1,(2+channel)<<6,0])
            ret = ((r[1]&31) << 6) + (r[2] >> 2)
            return ret
    
    device =uinput.Device([uinput.ABS_X+(0,1023,0,0),
                          uinput.ABS_Y+(0,1023,0,0),
                          ])
    
    
    
    
    joy_x=1
    joy_y=2
    
    #!/usr/bin/python
    
    import spidev
    import time
    import os
    import uinput
    
    DEBUG = 0
    
    spi = spidev.SpiDev()
    spi.open(0,0)
    spi.max_speed_hz = 100000
    
    def get_adc(channel):
            if ((channel > 1) or (channel < 0)):
                    return -1
    
            r = spi.xfer2([1,(2+channel)<<6,0])
            ret = ((r[1]&31) << 6) + (r[2] >> 2)
            return ret
    
    device =uinput.Device([uinput.ABS_X+(0,1023,0,0),
                          uinput.ABS_Y+(0,1023,0,0),
                          ])
    
    
    
    
    joy_x=1
    joy_y=2
    
    while True:
      
        joy_x_value=ReadChannel(joy_x)
           
        device.emit(uinput.ABS_X,joy_x_value,syn=False)
    
        joy_y_value=ReadChannel(joy_y)
           
        device.emit(uinput.ABS_Y,joy_y_value)    
        time.sleep(0.020)

  • Global Moderator

    @adamspc said in Analog Joystick:

    I know that the most recent version of Retropie asks for analog up/down/left/right during configuration, so something is obviously built in.

    so is it getting picked up here?

    I need to know how to get it working in games.

    in retroarch cores there's an analog to digital configuration option that will work if your answer to my previous question is 'yes'. check out https://github.com/retropie/retropie-setup/wiki/Configuration-Editor



  • @dankcushions
    It's not.

    I'm using retrogame, so when I press a button to configure input it says its using keyboard as an input. I then configure the regular buttons and it gets to analog, and moving the stick around does nothing.

    For clarification, so far I've only managed to print the current ACD values and then use uinput to send those values to ABS_X/Y. That's as far as I've made it and I'm not even sure ABS_X/Y is the right thing to do.


  • Global Moderator

    @adamspc so when you say the OS can 'see' it, what do you mean by that? it appears as a js device in jstest?



  • @dankcushions the OS is communicating with the ADC and receiving the values using the Python file. The only info I could find was one person saying use uinput and ABS, so that's as far as I got. I havent used jtest but im researching it now. Im just trying to connect the dots on getting this configured as a joystick. I know it's not that something is wrong with it. I just can't find the information.


  • Global Moderator

    @adamspc

    http://thiemonge.org/getting-started-with-uinput

    uinput is a linux kernel module that allows to handle the input subsystem from user land. It can be used to create and to handle input devices from an application. It creates a character device in /dev/input directory. The device is a virtual interface, it doesn't belong to a physical device.

    looks to me like this wouldn't be visible to ES or retroarch which are looking for keyboard or joystick devices. i think you'd need to create your own driver to translate like http://blog.petrockblock.com/2014/06/01/xarcade2jstick/



  • @dankcushions I appreciate the responses. My hope was that someone in the forum had already done what I'm attempting and I could get a shortcut to the solution. I'm continuing to research and I'll post the solution once I find it (or create it). I'm digging into some slightly different code now that I found here.

    """ rpi-gpio-jstk.py by Chris Swan 9 Aug 2012
    GPIO Joystick driver for Raspberry Pi for use with 80s 5 switch joysticks
    based on python-uinput/examples/joystick.py by tuomasjjrasanen
    https://github.com/tuomasjjrasanen/python-uinput/blob/master/examples/joystick.py
    requires uinput kernel module (sudo modprobe uinput)
    requires python-uinput (git clone https://github.com/tuomasjjrasanen/python-uinput)
    requires python RPi.GPIO (from http://pypi.python.org/pypi/RPi.GPIO/0.3.1a)
    for detailed usage see http://blog.thestateofme.com/2012/08/10/raspberry-pi-gpio-joystick/
    Changes
    19 Aug 2012 - inputs set to use internal pull ups rather than external 10k resistors
    """
    
    
    import uinput
    import time
    import RPi.GPIO as GPIO
    
    GPIO.setmode(GPIO.BOARD)
    # Up, Down, left, right, fire
    GPIO.setup(11, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(13, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(15, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(7, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    
    events = (uinput.BTN_JOYSTICK, uinput.ABS_X + (0, 255, 0, 0), uinput.ABS_Y + (0, 255, 0, 0))
    
    device = uinput.Device(events)
    
    # Bools to keep track of movement
    fire = False
    up = False
    down = False
    left = False
    right = False
    
    # Center joystick
    # syn=False to emit an "atomic" (128, 128) event.
    device.emit(uinput.ABS_X, 128, syn=False)
    device.emit(uinput.ABS_Y, 128)
    
    while True:
      if (not fire) and (not GPIO.input(7)):  # Fire button pressed
        fire = True
        device.emit(uinput.BTN_JOYSTICK, 1)
      if fire and GPIO.input(7):              # Fire button released
        fire = False
        device.emit(uinput.BTN_JOYSTICK, 0) 
      if (not up) and (not GPIO.input(11)):   # Up button pressed
        up = True
        device.emit(uinput.ABS_Y, 0)          # Zero Y
      if up and GPIO.input(11):               # Up button released
        up = False
        device.emit(uinput.ABS_Y, 128)        # Center Y
      if (not down) and (not GPIO.input(13)): # Down button pressed
        down = True
        device.emit(uinput.ABS_Y, 255)        # Max Y
      if down and GPIO.input(13):             # Down button released
        down = False
        device.emit(uinput.ABS_Y, 128)        # Center Y
      if (not left) and (not GPIO.input(15)): # Left button pressed
        left = True
        device.emit(uinput.ABS_X, 0)          # Zero X
      if left and GPIO.input(15):             # Left button released
        left = False
        device.emit(uinput.ABS_X, 128)        # Center X
      if (not right) and (not GPIO.input(16)):# Right button pressed
        right = True
        device.emit(uinput.ABS_X, 255)        # Max X
      if right and GPIO.input(16):            # Right button released
        right = False
        device.emit(uinput.ABS_X, 128)        # Center X
      time.sleep(.02)  # Poll every 20ms (otherwise CPU load gets too high)
    


  • Sorry for necroposting a little, but I was wondering if @adamspc had ever actually managed to get an analog joystick to work, since it has been several months and I haven't seen anything else posted about this.



  • @Shojiro No progress yet, but that's only because all my time is taken working on the boards I'm designing. I ended up doing a simple joystick using an LM339, but that's only a temporary solution.

    I will succeed in getting the analog working using the MCP3002, but it won't be soon. Hopefully one of the software guys reading this has time to help out.



  • @adamspc I know this thread is old, but I'm currently having the same issue. Did you manage to made any progress with the analog joystick?



Contributions to the project are always appreciated, so if you would like to support us with a donation you can do so here.

Hosting provided by Mythic-Beasts. See the Hosting Information page for more information.