Boxless Arcade Stick


#1

As discussed in the Ultimate Tech Talk Hang Out thread, I am interested in starting a new project. Wish I had pictures at the moment, but that will have to come later.

Essentially this project can be summarized as: Wii remote without the sensor bar.

I had planned on using an IMU & Arduino (something) and wiring it up to the PCB (preferably PS360+) ; the IMU would’ve been placed at the tip of a baton/wand, the PCB elsewhere. The direction of the baton’s tip would be read in the Arudino board, which would then (somehow) turn into an electrical signal that the PCB would read. I am not too sure how that would work though, which is why I’m making this thread asking for (even tidbits of) advice.

@deserada (strongly) recommended an analog gyro. From little I’ve read, it measures rotation about an axis - how would it handle straight motions? I’m probably not understanding it right, or something.


#2

Gyro would only measure orientation. Accelerometers measure linear motion:

EDIT: ah wait, is this for a “floating” arcade stick? Gyro would be simpler. Positioned at the base, with one axis locked out, it would simulate the actuator in a conventional stick.

ie:

x= 0 degrees
y= +15 degrees
z= locked out

total= up command


#3

Yeah, I might not have been clear on your application before.

Say if you wanted to make a boxing glove controller, you would want to put accelerometers in the gloves to trigger an input when the player’s fist is accelerated towards the screen.

For any kind of rotational movement (not change in position) you would want a gyro. It’s possible that for what you are thinking, you may want both.

With your project, a gyro would indeed allow the wand’s direction to be read, while a flick of the wand may be reported by an accelerometer. Both would report an analog signal however (think any value between 0 and 100%), so if you wanted to trigger a button it would either need to be done in software, or with some logic conversion based on a voltage threshold to give you a digital (on/off) value (say any acceleration resulting in over 50% voltage is on (button signal is grounded), less is off(button signal is open)).


#4

Okay, that makes sense.

Here was my original (basic) plan:

  1. When the “stick” was plugged into a System (PS3/360/etc), so when it’s powered, it’s initial position would be the origin. (EDIT: a Reset button can also apply).
  2. A small buffer zone would have been programmed in - reduce sensitivity so that not every micro-twitch would register a different direction. (Small buffer like 1/2 in)
  3. Tilt/Move the tip (or where the sensor is located) in a direction. It registers the value - let’s say, -50%, +50% (Is this how it works?)
  4. The value is sent to the Arduino program - probably logic based. I had planned on using conditional statements. -50% = left, while +50% = up.
  5. An analog signal is sent from the sensor’s pin to the Controller PCB (PS360+) appropriate pin’s - Left and Up.
  6. The signal is run into the System. My cursor moves Diagonally Up+Left (7).

Was this plan erroneous? Or is it still usable?


#5

Forego the Arduino and you could use something like this behind the analog voltage outputs:
http://www.mouser.com/ProductDetail/Texas-Instruments/SN74LV1T34DCKR/?qs=sGAEpiMZZMtOwpHsRTkso1w2FFrRgZoCXZNMDOdKncMRVMLllwXnLA%3D%3D
That would give line-level voltage to the signal lines of your directionals.

Not sure if you’ll want to do more signal processing, depends on how fast your controller PCB can process the input and the amount of sensitivity you desire (which is better explained by the Gyro’s data sheet than I could do here in a few sentences).

The controller PCB is only expecting digital (ON/OFF) on the directional signal lines. You could get away with analog if you were padhacking a controller with analog sticks, however.

In general, your theory is correct.


#6

This is interesting.
It sounds like it’d be possible to integrate a gyro unit into an existing arcade stick (albeit with heavy modifications), and potentially get analog stick controls, without having to go the route of the out-of-production LS-64…


#7

If you wanted to modify an existing lever to produce analog signals, one option might be to mount the gyro on a custom e-clip. Wiring would be an issue as it would have to be highly flexible, and all of the mechanical connections must be able to withstand constant movement.

You could also switch whether the signals are going through an A/D converter equivalent (and to the D-pad), or direct to the analog stick wiper signal. Hori does something like this on many of their products, although it is only capable of sending the extreme cardinal directions over analog because the lever itself is digital, of course.


#8

Using the SN74LV1T34DCKR and LPY450AL, would it be as simple as wiring the two and the pcb together? (Really hopeful that it isn’t too complicated, but knowing my luck…)


#9

Are you looking for something like a custom-modded Razor Hydra?


#10

Basically, I want to make this into the joystick:

http://i.imgur.com/sV5Yxx2.png


#11

Take your design inspiration from a saxophone, a clarinet, or the like.

Your best option is to make a segmented design, held together internally with bungie cord, not unlike fiberglass tent poles (in fact, you should source those exact same cords). All sections will lock into place to make the completed assembly, but fold down for carry/storage. Focus on fitting your electronics into a single compartment or two made of PVC, and then you have the option to make the remainder out of wood or PVC (the former being easier to work and incorporate designs into). Thankfully, the Gae Bolg already has a segmented design, so this will be easier to conceal.

Figure out next how to best align your buttons in an ergonomic manner. They do not have to fit into the same section as your electronics, so long as the wiring has appropriate strain relief. Recess the buttons into the PVC so that the rims are flush; all action buttons will have to be 24mm diameter or smaller.

Your base material (enclosing the electronics) is going to have to be about 1.5" diameter. In general, if the price for a dowel of these dimensions is too expensive, look into tool handles. A heavy-duty broomhandle may be suitable, but also consider shovel handles as they are around the diameter you want.

Your gyro can still be implemented, you just need to design a circuit which will feed your directional input to the USB encoder. I would advise also including physical buttons for directionals, in case space is a limitation and you cannot swing it around.

Consider a wireless PCB+dongle, if you cannot find an appropriate way to provide slack for the cord. The wireless PDP afterglow controllers for PS3 have a very thin board (no more than 2" at the widest) which can likely be trimmed further for your use. They will include a battery and a dongle, of course. As I recall, they are not common ground, but I don’t expect you to do a dualmod here. If you want wired, a ZD encoder could be trimmed small enough to fit inside a polearm, and the Cerberus could definitely fit as well.

Edit:
Here’s a source for elastic/bungie cord. Use two runs if the tension is not high enough, but your build should ideally be light enough and the cords mounted tight enough that it will not be a problem.


#12

Well… umm… thanks @deserada?

I’m still at the how-do-I-connect-a-gyroscope-to-the-board-phase, so I didn’t give too much thought to how I can turn GB into a controller. Since I’ve caught your attention though, here’s a question:

Using the SN74LV1T34DCKR and LPY450AL, would it be as simple as wiring the two and the pcb together to get it to work?


#13

That gyro would be a drop-in for an analog stick, (which would work perfectly with the PDP controller, as it has daughterboards for its analog stick and you can use the ribbon cable it connects to the main board with (which is conveniently silkscreened on the board)). For any of the other boards, or for any board without analog support, you’d have to add some more logic in there to get digital signals compatible with a standard d-pad style setup. You’d also have to invert all the signals because it’s probably going to report high (as opposed to low) when moved in the direction you want. You could find another gyro with analog+digital out to rectify this problem, but if you decide to do a padhack as I’d alluded to before, it won’t be necessary.

More importantly, the internally amplified outputs of your gyro may be enough to get your directionals in full, but it depends on what voltage your board is supplying to the potentiometers. Say the pots from the analog stick originally on that board are only getting 3.3V on the high, and 0V (ground) on the low. If your gyro can supply an analog signal of 3.3V (it can), then you already have the full range of motion for every axis. If the pot is getting supplied more than what your gyro can provide, you might only be able to go up 80% as high as you should be able to, for example. Pick a pad/pcb out and see what the pots are being supplied, then we can decide how the design of the circuit should proceed. My guess is that it is getting 3.3V (or at least something less than 5V), but it’s best to make sure. Also take note if there is a voltage source you can steal 3.3V from, as you will need to power your gyro. If there isn’t one available, we can talk about installing a linear regulator to do that job.


#14

Update 1/16:

Probably should’ve bought it from Digi-key or something. I just realized that Mouser required extra documentation before they would ship my package.

As an aside, I also picked up an Afterglow PDP, so I’ll be trying to figure out how to connect the gyros to the board - but since I don’t have them yet, I can’t actually test my ideas. Other than that, I’m sort of concerned on the buttons. I’m not sure if I want to use the 24mm Sanwa/Seimitsu buttons, or something smaller like 16mm, 12mm, or even 10mm. I didn’t even know that smaller buttons existed. Recommendations?

Gotta head out to my home improvement store and pick up some 1.5" PVC, since I doubt I have some lying around.

Before I forget and lose this:

http://i.imgur.com/8PCazpO.png

Very Important Image

Pins 1, 7, 14, 20 and GND are self explanatory. 4xIN X/Z are the inputs for the 4x amplifiers (I suppose, where some external power is attached to). VDD is the power supply. I’m not sure if the other pins are important enough.

… I’m gonna have to look around for a PDP schematic…

Oh, and as always, thanks for your response @deserada.


#15

Alright! With school finished and summer approaching, I got more time to work on this bugger.

Rather than what @deserada suggested, I decided to return to the accelerometer & Arduino combination since I had more practice with that in class.

Accelerometer: MPU6050
(test) PCB: Afterglow PS3 AP.2 (Actually, I messed up with one of my Dualshock 3 controllers, so I returned to this…)

MPU6050 Code (Obtain Raw Data)

Spoiler

// MPU-6050 Accelerometer + Gyro

#include <Wire.h>
#include <MPUdev.h> //All the MPU6050 definitions and inclusions were put in this header to save space


#define MPU6050_I2C_ADDRESS 0x68
 
 
typedef union accel_t_gyro_union
{
  struct
  {
    uint8_t x_accel_h;
    uint8_t x_accel_l;
    uint8_t y_accel_h;
    uint8_t y_accel_l;
    uint8_t z_accel_h;
    uint8_t z_accel_l;
    uint8_t t_h;
    uint8_t t_l;
    uint8_t x_gyro_h;
    uint8_t x_gyro_l;
    uint8_t y_gyro_h;
    uint8_t y_gyro_l;
    uint8_t z_gyro_h;
    uint8_t z_gyro_l;
  } reg;
  struct
  {
    int16_t x_accel;
    int16_t y_accel;
    int16_t z_accel;
    int16_t temperature;
    int16_t x_gyro;
    int16_t y_gyro;
    int16_t z_gyro;
  } value;
};
 

void setup()
{      
  int error;
  uint8_t c;
      
  Serial.begin(9600);
  Serial.println(F("InvenSense MPU-6050"));
  Serial.println(F("June 2012"));   

  Wire.begin();
 
  error = MPU6050_read (MPU6050_WHO_AM_I, &c, 1);
  Serial.print(F("WHO_AM_I : "));
  Serial.print(c,HEX);
  Serial.print(F(", error = "));
  Serial.println(error,DEC);
 
  error = MPU6050_read (MPU6050_PWR_MGMT_1, &c, 1);
  Serial.print(F("PWR_MGMT_1 : "));
  Serial.print(c,HEX);
  Serial.print(F(", error = "));
  Serial.println(error,DEC);
      
  MPU6050_write_reg (MPU6050_PWR_MGMT_1, 0);
}
 
 
void loop()
{
  int error;
  double dT;
  accel_t_gyro_union accel_t_gyro;

  Serial.println(F(""));
  Serial.println(F("MPU-6050"));
 
  // With the default settings of the MPU-6050,
  // there is no filter enabled, and the values
  // are not very stable.
  error = MPU6050_read (MPU6050_ACCEL_XOUT_H, (uint8_t *) &accel_t_gyro, sizeof(accel_t_gyro));
  Serial.print(F("Read accel, temp and gyro, error = "));
  Serial.println(error,DEC);
 
  uint8_t swap;
  #define SWAP(x,y) swap = x; x = y; y = swap
 
  SWAP (accel_t_gyro.reg.x_accel_h, accel_t_gyro.reg.x_accel_l);
  SWAP (accel_t_gyro.reg.y_accel_h, accel_t_gyro.reg.y_accel_l);
  SWAP (accel_t_gyro.reg.z_accel_h, accel_t_gyro.reg.z_accel_l);
  SWAP (accel_t_gyro.reg.t_h, accel_t_gyro.reg.t_l);
  SWAP (accel_t_gyro.reg.x_gyro_h, accel_t_gyro.reg.x_gyro_l);
  SWAP (accel_t_gyro.reg.y_gyro_h, accel_t_gyro.reg.y_gyro_l);
  SWAP (accel_t_gyro.reg.z_gyro_h, accel_t_gyro.reg.z_gyro_l);         
      
  Serial.print(F("accel x,y,z: "));
  Serial.print(ax, 2);
  Serial.print(F(", "));
  Serial.print(ay, 2);
  Serial.print(F(", "));
  Serial.print(az, 2);
  Serial.println(F(""));
      
  Serial.print(F("temperature: "));
  dT = ( (double) accel_t_gyro.value.temperature + 12412.0) / 340.0;
  Serial.print(dT, 3);
  Serial.print(F(" degrees Celsius"));
  Serial.println(F(""));
       
  Serial.print(F("gyro x,y,z : "));
  Serial.print(gx, DEC);
  Serial.print(F(", "));
  Serial.print(gy, DEC);
  Serial.print(F(", "));
  Serial.print(gz, DEC);
  Serial.print(F(", "));
  Serial.println(F(""));

  delay(1000);
}
 
 
int MPU6050_read(int start, uint8_t *buffer, int size)
{
  int i, n, error;
 
  Wire.beginTransmission(MPU6050_I2C_ADDRESS);
  n = Wire.write(start);
  if (n != 1)
    return (-10);
 
  n = Wire.endTransmission(false);
  if (n != 0)
    return (n);
 
  Wire.requestFrom(MPU6050_I2C_ADDRESS, size, true);
  i = 0;
  while(Wire.available() && i<size)
  {
    buffer[i++]=Wire.read();
  }
  if ( i != size)
    return (-11);
 
  return (0);
}
 
int MPU6050_write(int start, const uint8_t *pData, int size)
{
  int n, error;
 
  Wire.beginTransmission(MPU6050_I2C_ADDRESS);
  n = Wire.write(start);        
  if (n != 1)
    return (-20);
 
  n = Wire.write(pData, size);  
  if (n != size)
    return (-21);
 
  error = Wire.endTransmission(true);
  if (error != 0)
    return (error);
 
  return (0);     
}
 
int MPU6050_write_reg(int reg, uint8_t data)
{
  int error;
 
  error = MPU6050_write(reg, &data, 1);
 
  return (error);
}

AP.2 PCB (With some wires soldered)

Spoiler

http://imgur.com/TSBpBea.jpg

Simple Code to test Arduino

Spoiler

int Left = 4; // Where the ground connects to on the Arduino
int Up = 5;

void setup() {
pinMode(Left, OUTPUT);
pinMode(Up, OUTPUT);

}

void loop() {
digitalWrite(Left, HIGH); //On
delay(1000); //0.1 s
digitalWrite(Left, LOW); //Off
delay(1000);
digitalWrite(Up, HIGH);
delay(1000);
digitalWrite(Up, LOW);
delay(1000);

}

Result: Failure.

While I can get ONE direction to blink properly, trying out two fails to work. Instead of alternating between up and left, the damn thing “blinks” diagonal up+left instead. Other attempts to fix this has also ended in failure. It could be the AP.2 PCB.

Of note: at the end, the program no longer works with the AP.2. The button still works - touching the two ends still closes the switch. Testing the program with LEDs instead has them flash as expected.


#16

This project is super awesome and I really want to see it take off!

It may be blinking because of the refresh rate of your loop. Instead of constantly updating your signal/output, just constantly update the reading and only change the signal if it goes out of bounds of that direction(s).

One thing I noticed about your PCB is that the analog sticks were not neutralized. This is known to cause erratic behaviour in most pads, but what you are experiencing is not congruent with the problems I’ve seen from lack of neutralization.


#17

Hmm… I see, that is an idea I didn’t think of before. Unfortunately, I left all my equipment back in the states (I’m currently working in China for the rest of the year). Though I might be able to test it with some Chinese knockoffs… hmm.

As for the out of bounds, would something as simple as an if command with the readingValue > desiredValue work? Well, I’ll brainstorm more later and restart this project when I get back - after completing two more sticks that I want to make. One of which is an even older idea :3

As always thanks for your help, @deserada!


#18

Yup! That’s exactly it.

Something like:

if(readingValue>lowerBound&&readingValue<upperBound){
signalOutput=direction1;
}
else if{…}

else if{…} //use enough conditionals until you have all eight directions covered
else{…} //do some error handling


#19

After working on and off on this project for over a year now, I’ve decided to give up - on trying to make my own version of a IMU. Instead, I bit the bullet and bought a PS move.

I intend to padhack it so that it will fit inside the spear shaft, but eventually intend to find a way to remove the damn PS3/4 Move/Camera requirement. Current idea was to remove/rip out the gyro/micro-controller and still if I can wire it up to another pcb. We’ll (and by that, I mean I’ll) see if that’s an option.

EDIT:

Still tinkering around with the MPU6050, would this process check out @deserada ? (Not real code)

While(device = on) {

i = old_signal(x_axis)
j = old_signal(y_axis)

x = signal(x_axis)
y = signal(y_axis)

if(x is significantly different from i OR y is significantly different from j) { //Or if signal has changed drastically

Switch(x,y) {

Case(+x, 0):
move right //6
break;

Case(-x, 0):
move right //4
break;

Default:
neutral //?
break
}

else if(x && y is not significantly different from i && j) { //Signal did not change
Repeat/Hold last input //?? holding the last input might be a bit out of my hands - I’m trying to get a “Walk” forward
}

else{
error troubleshooting and stuff
}