I picked up a pair of Atari-style Gemini paddles for $5 at that gaming show and hooked them up to my Windows machine using an Arduino Leonardo running a gamepad HID library. The boy was intrigued because they are so different from an Xbox controller or a mouse; and I got him to play Kaboom! on an Atari 800XL emulator. Definitely different from Breakout or Pong:
Tell me that's not at least as fun as many casual iOS games. I really like the reveal of the 1812 Overture as one advances in the game. Other paddle games are discussed over at AtariAge.
My $5 deal:
My $5 deal:
Technical Details
The paddles are 1-megaohm linear potentiometers tied to 5V. To measure the resistance, the original Atari system would measure how long it took to charge a capacitor. It actually counted the number of TV scan lines. The higher the resistance, the longer it took. This was a straightforward way to do it with a purely digital readout system and the 8-bits have a custom POKEY chip that does the work. (The POKEY designer Doug Neubauer tells a couple entertaining stories.) This is called an analog-to-digital converter by many - it is, but not in the sense of modern ADC's. It's a current-measuring ADC (with the current source being the potentiometer series resistance biased by +5V) vs. a typical voltage-measuring ADC. Many modern microcontrollers have voltage ADC's built in, so my implementation uses a voltage divider instead of an RC charging circuit. Despite some erroneous circuit diagrams found on the interwebs, the pot in the paddle has one end floating. Thus, the readout circuit needs an external drop resistor to make up the voltage divider. Here's my circuit:
The microcontoller is a Leonardo because it runs an ATmega 32u4 microcontroller with an on board USB interface. Two ADC channels are used to read the voltages from the dividers. Digital inputs D0 and D1 are used to read the trigger buttons. The software relies on the HID Project. I started using the absolute mouse device, but switched to the 16-bit axes on the gamepad device. My method isn't new; however, I added some integer math to compute the resistance value from the voltage that I haven't seen elsewhere. Otherwise, the reading will be highly nonlinear. Atari went out of their way to use linear potentiometers in the design (vs. logarithmic which are used in audio volume controls), so it's only fitting to keep the system linear. The code also includes a startup calibration to find the minimum voltage when the paddle is turned completely counter-clockwise.
Here's my sketch:
#include <HID-Project.h>
#include <HID-Settings.h>
int oldx;
int x=0;
int calx=0;
int oldy;
int y=0;
int caly=0;
int readpaddle(int p) {
int a=0;
for (int x=0; x<32; x++) {
a+=analogRead(p);
}
return a;
}
int paddlemap(int a) {
return 65535-uint32_t(uint32_t(1072693248)/uint32_t(a));
}
void setup() {
// put your setup code here, to run once:
pinMode(0,INPUT_PULLUP);
pinMode(1,INPUT_PULLUP);
delay(2000);
Serial.begin(9600);
Serial.println("calibrating");
for (int i=0; i<10; i++) {
int temp=paddlemap(readpaddle(0));
calx=max(temp,calx);
Serial.println(calx);
temp=paddlemap(readpaddle(1));
caly=max(temp,caly);
Serial.println(caly); }
Gamepad.begin();
}
void loop() {
boolean changed=false;
oldx=x;
oldy=y;
int tempx=paddlemap(readpaddle(0));
tempx=max(tempx,calx);
x=map(tempx,calx,32767,-32768,32767);
delay(7); //need to clear residual from ADC and limit update rate
int tempy=paddlemap(readpaddle(1));
tempy=max(tempy,caly);
y=map(tempy,caly,32767,-32768,32767);
if (abs(x-oldx)>63 || abs(y-oldy)>63){
changed=true;
}
Gamepad.releaseAll();
if (!digitalRead(0)){
Gamepad.press(1);
changed=true;
}
if (!digitalRead(1)){
Gamepad.press(2);
changed=true;
}
if (changed){
Gamepad.xAxis(x);
Gamepad.yAxis(y);
Gamepad.write();
}
//Serial.println(x);
}
I'm pretty happy with the results. My code uses the full range of the paddles, but
No comments:
Post a Comment