Code: Select all
""" rpi-gpio-atari2key.py by Ian Guebert 21 Oct 2012 Atari Joystick to GPIO to Keyboard driver for raspberry Pi, based on Chris Swan's rpi-gpio-kbrd.py driver. Going to experiment with this to see if 2 Atari joysticks can be used at the same time for Stella Emulator. Console switches such as Select and Reset have been added, a pause button too for gameplay sake. """ """ rpi-gpio-kbrd.py by Chris Swan 9 Aug 2012 GPIO Keyboard driver for Raspberry Pi for use with 80s 5 switch joysticks *** This did not work with AdvMAME - failed attempt - may be useful for another project based on python-uinput/examples/keyboard.py by tuomasjjrasanen https://github.com/tuomasjjrasanen/python-uinput/blob/master/examples/keyboard.py requires uinput kernel module (sudo modprobe uinput) requires python-uinput (git clone https://github.com/tuomasjjrasanen/python-uinput) requires (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/ """ import uinput import time import RPi.GPIO as GPIO GPIO.setmode(GPIO.BOARD) GPIO.setup(3, GPIO.IN) GPIO.setup(5, GPIO.IN) GPIO.setup(7, GPIO.IN) GPIO.setup(8, GPIO.IN) GPIO.setup(10, GPIO.IN) GPIO.setup(11, GPIO.IN) GPIO.setup(12, GPIO.IN) GPIO.setup(13, GPIO.IN) GPIO.setup(15, GPIO.IN) GPIO.setup(16, GPIO.IN) GPIO.setup(18, GPIO.IN) GPIO.setup(19, GPIO.IN) GPIO.setup(21, GPIO.IN) events = (uinput.KEY_UP, uinput.KEY_DOWN, uinput.KEY_LEFT, uinput.KEY_RIGHT, uinput.KEY_SPACE, uinput.KEY_Y, uinput.KEY_H, uinput.KEY_G, uinput.KEY_J, uinput.KEY_F, uinput.KEY_F1, uinput.KEY_F2, uinput.KEY_PAUSE) device = uinput.Device(events) 1fire = False 1up = False 1down = False 1left = False 1right = False 2fire = False 2up = False 2down = False 2left = False 2right = False select = False resetB = False pause = False while True: #Player 1 controls if (not 1fire) and (not GPIO.input(10)): # player 1 Fire button pressed 1fire = True device.emit(uinput.KEY_SPACE, 1) # player 1 Press space bar if 1fire and GPIO.input(10): # player 1 Fire button released 1fire = False device.emit(uinput.KEY_SPACE, 0) # player 1 Release space bar if (not 1up) and (not GPIO.input(3)): # player 1 Up button pressed 1up = True device.emit(uinput.KEY_UP, 1) # player 1 Press Up key if 1up and GPIO.input(3): # player 1 Up button released 1up = False device.emit(uinput.KEY_UP, 0) # player 1 Release Up key if (not 1down) and (not GPIO.input(5)): # player 1 Down button pressed 1down = True device.emit(uinput.KEY_DOWN, 1) # player 1 Press Down key if 1down and GPIO.input(5): # player 1 Down button released 1down = False device.emit(uinput.KEY_DOWN, 0) # player 1 Release Down key if (not 1left) and (not GPIO.input(7)): # player 1 Left button pressed 1left = True device.emit(uinput.KEY_LEFT, 1) # player 1 Press Left key if 1left and GPIO.input(7): # player 1 Left button released 1left = False device.emit(uinput.KEY_LEFT, 0) # player 1 Release Left key if (not 1right) and (not GPIO.input(8)): # player 1 Right button pressed 1right = True device.emit(uinput.KEY_RIGHT, 1) # player 1 Press Right key if 1right and GPIO.input(8): # player 1 Right button released 1right = False device.emit(uinput.KEY_RIGHT, 0) # player 1 Release Right key #Player 2 controls if (not 2fire) and (not GPIO.input(18)): # player 2 Fire button pressed 2fire = True device.emit(uinput.KEY_F, 1) # player 2 Press F Key if 2fire and GPIO.input(18): # player 2 Fire button released 2fire = False device.emit(uinput.KEY_F, 0) # player 2 Release F Key if (not 2up) and (not GPIO.input(11)): # player 2 Up button pressed 2up = True device.emit(uinput.KEY_Y, 1) # player 2 Press Y Key if 2up and GPIO.input(11): # player 2 Up button released 2up = False device.emit(uinput.KEY_Y, 0) # player 2 Release Y key if (not 2down) and (not GPIO.input(13)): # player 2 Down button pressed 2down = True device.emit(uinput.KEY_H, 1) # player 2 Press H key if 2down and GPIO.input(13): # player 2 Down button released 2down = False device.emit(uinput.KEY_H, 0) # player 2 Release H key if (not 2left) and (not GPIO.input(15)): # player 2 Left button pressed 2left = True device.emit(uinput.KEY_G, 1) # player 2 Press G key if 2left and GPIO.input(15): # player 2 Left button released 2left = False device.emit(uinput.KEY_G, 0) # player 2 Release G key if (not 2right) and (not GPIO.input(16)): # player 2 Right button pressed 2right = True device.emit(uinput.KEY_J, 1) # player 2 Press J key if 2right and GPIO.input(16): # player 2 Right button released 2right = False device.emit(uinput.KEY_J, 0) # player 2 Release J key #Switches if (not select) and (not GPIO.input(19)): # Select button pressed select = True device.emit(uinput.KEY_F1, 1) # F1 key pressed if select and GPIO.input(19): # release select button select = False device.emit(uinput.KEY_F1, 0) # release F1 key if (not resetB) and (not GPIO.input(21)): # Reset button pressed resetB = True device.emit(uinput.KEY_F2, 1) # F2 key pressed if resetB and GPIO.input(21): # release reset button resetB = False device.emit(uinput.KEY_F2, 0) # release F2 key if (not pause) and (not GPIO.input(12)): pause = True device.emit(uinput.KEY_PAUSE, 1) if pause and GPIO.input(12): pause = False device.emit(uinput.KEY_PAUSE, 0) time.sleep(.04)
Well the whole point of this is so that I don't need to use a USB controller, or a RetroUSB adapter. The Atari 2600 joystick is just a set of switches, no other electronics, so I should be able to program a driver that will read when a GPIO is turned on and off and emulate a keyboard stroke from it.teeth_03 wrote:Have you been able to get 2 player to work? I have emulationstation/retropie and it doesnt.
Also, i wonder if the usb to dual joystick adapter works fine with the Pi...
Code: Select all
[email protected] ~/GPIOtoKEY $ python -c rpi-gpio-atari2key.py Traceback (most recent call last): File "<string>", line 1, in <module> NameError: name 'rpi' is not defined [email protected] ~/GPIOtoKEY $
Could do... But I'm sticking with 5v since the paddle's potentiometer uses a 5v input. You know, one less thing to worry about. However... I've been studying ADCs today, and it looks like I'm going to use 3.3v for a MCP3008, which I'm going to use to to convert resistance into a digital number then use that to plot the position for a paddles axis.marqs wrote:Have you tried using 3.3V and internal pull-ups? I think atari vcs joysticks are purely switch based (besides the pot), so they should work well that setup too.
Heh, I'm a bit of a noob when it comes to electronics, so I had to look up what a resistor network is. And hey, that would seriously help and make room for when I build the final PCB for this Atari-to-GPIO interface.marqs wrote:The paddle could probably be read with a suitable resistor network, although it'd require quite many pins for good A/D.
Ok, interesting... Just because I noticed when I was making a mock script for the upcoming paddle-to-gpio python program, I was using this tutorial about using the MCP3008 on the RPi's GPIOs and noticed that pin 10 goes to pin 25, which from this image looks like it ends up on a ground. Though I have noticed that the names of each GPIO pin isn't the same as the pin number, e.g. pin 19 is GPIO10 according to that image. This might get confusing, lmao!marqs wrote:There's also a db9 joystick driver for parport in the kernel, which could be modified to work with GPIOs with a bit effort. I did similar port for the gamecon driver, and the most time-taking task actually was to generate the kernel headers package for build environment preparation.
db9.c is in located drivers/input/joystick in the kernel tree, and is documented in Documentation/input/joystick-parport.txt
Code: Select all
import uinput import time import os import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) DEBUG = 1 def readadc(adcnum, clockpin, mosipin, misopin, cspin): if ((adcnum > 7) or (adcnum < 0)): return -1 GPIO.output(cspin, True) GPIO.output(clockpin, False) # start clock low GPIO.output(cspin, False) # bring CS low commandout = adcnum commandout |= 0x18 # start bit + single-ended bit commandout <<= 3 # we only need to send 5 bits here for i in range(5): if (commandout & 0x80): GPIO.output(mosipin, True) else: GPIO.output(mosipin, False) commandout <<= 1 GPIO.output(clockpin, True) GPIO.output(clockpin, False) adcout = 0 # read in one empty bit, one null bit and 10 ADC bits for i in range(12): GPIO.output(clockpin, True) GPIO.output(clockpin, False) adcout <<= 1 if (GPIO.input(misopin)): adcout |= 0x1 GPIO.output(cspin, True) adcout >>= 1 # first bit is 'null' so drop it return adcout SPICLK = 19 SPIMISO = 21 SPIMOSI = 23 SPICS = 25 GPIO.setup(SPIMOSI, GPIO.OUT) GPIO.setup(SPIMISO, GPIO.IN) GPIO.setup(SPICLK, GPIO.OUT) GPIO.setup(SPICS, GPIO.OUT) events = (uinput.ABS_X + (0, 255, 0, 0), uinput.ABS_Y + (0, 255, 0, 0)) device = uinput.Device(events) # 10k trim pot connected to adc #0 paddle_ADC0 = 0; paddle_ADC1 = 1; last_read = 0 # this keeps track of the last potentiometer value tolerance = 5 # to keep from being jittery we'll only change # volume when the pot has moved more than 5 'counts' while True: #Start reading Paddle 0 (player 1) trim_pot0_changed = False # we'll assume that paddle 0 didn't move trim_pot0 = readadc(paddle_ADC0, SPICLK, SPIMOSI, SPIMISO, SPICS) # read Paddle 0 pot0_adjust = abs(trim_pot0 - last_read) # how much has it changed since the last read? if ( pot0_adjust > tolerance ): trim_pot0_changed = True if ( trim_pot0_changed ): set_xAxis = trim_pot0 / 4 # convert 10bit adc0 (0-1024) trim pot read 0-256 for joystick 1 X axis set_xAxis = round(set_xAxis) # round out decimal value set_xAxis = int(set_xAxis) # cast axis as integer device.emit(uinput.ABS_X, set_xAxis) #Set joystick x axis to the rounded down value given from paddle 0 last_read = trim_pot0 # save the potentiometer reading for the next loop #Start reading Paddle 1 (player 2) trim_pot1_changed = False # we'll assume that the paddle 1 didn't move trim_pot1 = readadc(paddle_ADC1, SPICLK, SPIMOSI, SPIMISO, SPICS) # Read paddle 1 pot1_adjust = abs(trim_pot1 - last_read) # how much has it changed since the last read? if ( pot1_adjust > tolerance ): trim_pot0_changed = True if ( trim_pot_changed ): set_yAxis = trim_pot1 / 4 # convert 10bit adc0 (0-1024) trim pot read 0-256 for joystick 1 X axis set_yAxis = round(set_yAxis) # round out decimal value set_yAxis = int(set_yAxis) # cast axis as integer device.emit(uinput.ABS_Y, set_yAxis) #Set joystick y axis to the rounded down value given from paddle 1 # save the potentiometer reading for the next loop last_read = trim_pot1 time.sleep(.02)