Game Gun con Arduino y Acelerometro

Hola a todos.
He iniciado un proyecto que espero llegue a buen termino. He visto en Internet a un tío que se ha montado una Game Gun(- YouTube) con un ratón 3d y un mando USB ademas de una pantalla.
Pues bien, mi proyecto es igual, pero sustituyo el raton3d por arduino con un acelerometro.
He hecho un programa en java que me lee del puerto serie del arduino y con eso dibujo sobre un Canvas los datos, en teoría, de desplazamiento del acelerometro. Aunque creo que mi interpretación de los mismos no es muy fiable o eso me parece.
Pero me encontrado con algunos problemas:

  • El acelerometro sobre el arduino directamente me da valores distintos a los que me da sobre una placa prototipo.
    Sobre arduino: x=520, y=520, z=600
    Sobre placa: x=320,y=429,z=290

  • Al no poder ponerlo directamente sobre la placa (necesito 2 pin analógicos de salida para conectar contra el mando de la PS3) me falsea los datos. Y necesito obligatoriamente montarlo sobre la placa prototipo.

  • Tengo algunos problemas para reproducir de forma fidedigna el movimiento en X en plano ya que la fuerza G no actúa sobre él.

Si alguien me puede echar una mano o esta interesado en colaborar o tenga alguna sugerencia, que lo escriba en el post.
Gracias.

Yo creo que usa un ratón del tipo:

Además,asi ya tienes el driver del PC hecho y no tienes que hacer nada...

Para medir giros, necesitas un giróscopo ó un sensor magnético.

Ten en cuenta, que un movimiento viene descrito por 6 grados de libertad. Con 3 acelerómetros, sólo tienes 3. Faltan los 3 giros...
Mira la Wii, tiene dos mandos: uno con acelerómetros y otro con giróscopos.

Lee esto para que veas los problemas que supone crear una plataforma inercial => http://www.nec-tokin.com/english/product/3d/construction.html

Camara + ratones con gyro para jugar:

Si quieres hacerte una "brujula", para detertar sólo cuando giras en el eje Z (sobre ti mismo) http://personales.ya.com/perropinto/robotidus/BRUJULA.htm

Hola Igor, gracias por la ayuda.
He analizado los datos recibidos por el acelerometro con Arduino, y la Game Gun tan solo realizará el cabeceo (X e Y). Sino fuera así, necesitaría una nave industrial para poder jugar al Call Of Duty ;D
Creo que con los datos que recibo es suficiente para realizarlo, además mi presupuesto esta muy limitado. Pero tengo el problema de la lectura de los datos. No se interpretar los valores del Adxl335. No se como puedo adaptar los valores a movimientos sobre un mando.
Leeré de nuevo toda la documentación que tengo y la que me has proporcionado para ver si logro averiguar a través de las matemáticas vectoriales como transformar esos datos en movimientos, bueno, en voltajes/tiempo sobre el mando de la ps3.
Si alguien tiene alguna sugerencia o se anima a participar, es bienvenido.
Gracias de nuevo Igor.

Una ayudita con las mates:
http://tom.pycke.be/mav/69/accelerometer-to-attitude

:wink:

jejej, gracias de nuevo Igor. :wink:
En cuanto realice los cálculos los expondré por si me he confundido en algo.
Gracias de nuevo.

Bueno, ya he resuelto los cálculos.
La verdad es que no tengo todas conmigo, pero echarle un vistazo por si os ayuda algo.
Aun así sigo teniendo un problema con los datos de vibración que me devuelve, sin moverlo sobre la mesa, me varían los valores.
Bueno, aquí os pongo el código y espero que alguien me ayude y me diga si me equivoco en algo.

FELIZ NAVIDAD Y PROSPERO AÑO NUEVO A TODOS!!! :wink:

/*
ADXL3xx

Reads an Analog Devices ADXL3xx accelerometer and communicates the
acceleration to the computer. The pins used are designed to be easily
compatible with the breakout boards from Sparkfun, available from:
http://www.sparkfun.com/commerce/categories.php?c=80

http://www.arduino.cc/en/Tutorial/ADXL3xx

The circuit:
analog 0: accelerometer self test
analog 1: z-axis
analog 2: y-axis
analog 3: x-axis
analog 4: ground
analog 5: vcc

created 2 Jul 2008
by David A. Mellis
modified 26 Jun 2009
by Tom Igoe
*/
#include <math.h>
const int groundpin = 18; // analog input pin 4 -- ground
const int powerpin = 19; // analog input pin 5 -- voltage
const int xpin = 3; // x-axis of the accelerometer
const int ypin = 2; // y-axis
const int zpin = 1; // z-axis (only on 3-axis models)
const int CUADRANTE_Q_1 = 1; // Cuadrante 1 = AX+ AY+
const int CUADRANTE_Q_2 = 2; // Cuadrante 2 = AX+ AY-
const int CUADRANTE_Q_3 = 3; // Cuadrante 3 = AX- AY-
const int CUADRANTE_Q_4 = 4; // Cuadrante 4 = AX- AY+

// EJE X
//Angle -90,-80,-70,-60,-50,-40,-30,-20,-10,0,10,20,30,40,50,60,70,80,90
//Acceleration 633,631,626,618,608,594,567,552,534,520,500,480,460,446,431,421,413,408,407
// EJE Y
//Angle -90,-80,-70,-60,-50,-40,-30,-20,-10,0,10,20,30,40,50,60,70,80,90
//Acceleration 385,386,390,399,410,424,447,466,483,500,520,538,552,573,586,596,604,610,611
int angx[20] = {
-90,-80,-70,-60,-50,-40,-30,-20,-10,0,10,20,30,40,50,60,70,80,90};
int accx[20] = {
633,631,626,618,608,594,567,552,534,520,500,480,460,446,431,421,413,408,407};
int accy[20] = {
611,610,604,596,586,573,552,538,520,500,483,466,447,424,410,399,390,386,385};
int angy[20] = {
90,80,70,60,50,40,30,20,10,0,-10,-20,-30,-40,-50,-60,-70,-80,-90};

// ANGULOS
float x,y,z;
float x1,y1,z1;
// ACELERACIONES
float ax, ay, az = 0;
float ax1, ay1, az1 = 0;
// DISTANCIA
float dx, dy, dz = 0;
float dx1, dy1, dz1 = 0;
int cuadranteActual = 0;

void setup(){
// initialize the serial communications:
Serial.begin(9600);

// Provide ground and power by using the analog inputs as normal
// digital pins. This makes it possible to directly connect the
// breakout board to the Arduino. If you use the normal 5V and
// GND pins on the Arduino, you can remove these lines.
pinMode(groundpin, OUTPUT);
pinMode(powerpin, OUTPUT);
digitalWrite(groundpin, LOW);
digitalWrite(powerpin, HIGH);
}

void loop()
{
Serial.print(" INI ");
Serial.print(analogRead(xpin));
Serial.print(",");
Serial.print(analogRead(ypin));
Serial.print(",");
Serial.print(analogRead(zpin));
x = convertirAngulos( analogRead(xpin), 'x');
y = convertirAngulos( analogRead(ypin), 'y');
z = convertirAngulos( analogRead(zpin), 'z');

calcularAceleraciones(x,y,z);
Serial.print(" ANGULOS ");
Serial.print(x);
Serial.print(",");
Serial.print(y);
Serial.print(",");
Serial.print(z);
Serial.print(" ACELERACIONES ");
Serial.print(ax);
Serial.print(",");
Serial.print(ay);
Serial.print(",");
Serial.print(az);
Serial.print(" DISTANCIAS(metros) ");
Serial.print(dx);
Serial.print(",");
Serial.print(dy);
Serial.print(",");
Serial.print(dz);
Serial.println();
// delay before next reading:
delay(100);
}

// Funcion que convierte los valores de entrada a angulos resultantes.
// En esta funcion no se realiza ningun calculo, tan solo un valor
// aproximativo de los resultados recopilados del acelerometro ADXL335
int convertirAngulos(int veje, char eje) {
int vresultante = 0;
if (eje == 'x'){
// LONGITUD DEL ARRAY
int longi = (sizeof(accx)/sizeof(accx[0])) -1;
vresultante = angx[ (buscarConstanteX( veje, longi)) ];
}
else if (eje == 'y') {
// LONGITUD DEL ARRAY
int longi = (sizeof(accy)/sizeof(accy[0])) -1;
vresultante = angy[ (buscarConstanteY( veje, longi)) ];
}
else if (eje == 'z') {
// LONGITUD DEL ARRAY
int longi = (sizeof(accx)/sizeof(accx[0])) -1;
vresultante = angx[ (buscarConstanteY( veje, longi)) ];
}

return vresultante;
}
int buscarConstanteX(int valor, int inicio) {
int idx = inicio;
int constante = 0;
int constante2 = 0;
boolean encontrado = false;
while (idx > 0) {
constante = accx[idx];
idx--;
constante2 = accx[idx];
if ((valor > constante) && (valor > constante2)) {
return buscarConstanteX(valor, idx);
}
else if ((valor > constante) && (valor < constante2)) {
return idx;
}
else if (valor == constante) {
return idx - 1;
}
else if (valor == constante2) {
return idx;
}
}
return 0;
}
int buscarConstanteY(int valor, int inicio) {
int idx = inicio;
int constante = 0;
int constante2 = 0;
boolean encontrado = false;
while (idx > 0) {
constante = accy[idx];
idx--;
constante2 = accy[idx];
if ((valor > constante) && (valor > constante2)) {
return buscarConstanteY(valor, idx);
}
else if ((valor > constante) && (valor < constante2)) {
return idx;
}
else if (valor == constante) {
return idx - 1;
}
else if (valor == constante2) {
return idx;
}
}
return 0;
}
void calcularAceleraciones(float pitch, float roll, float yaw){
ax1 = ax;
ay1 = ay;
az1 = az;
ax = (float)sin(pitch);
ay = (float)cos(roll);
// yaw = 1/tan * ax/az
az = (float)(ax/(tan(yaw)));
cuadrante();
}
void cuadrante (){
if( (ax >= 0) && (ay >= 0 )){
cuadranteActual = CUADRANTE_Q_1;
// CUADRANTE 1
}else if( (ax >= 0) && (ay <= 0 ) ){
// CUADRANTE 2
cuadranteActual = CUADRANTE_Q_2;
}else if((ax < 0) && (ay < 0 )){
// CUADRANTE 3
cuadranteActual = CUADRANTE_Q_3;
}else if((ax < 0) && (ay >= 0 )){
// CUADRANTE 4
cuadranteActual = CUADRANTE_Q_4;
}
calcularDistancia();
}
void calcularDistancia(){
dx1 = dx;
dy1 = dy;
dz1 = dz;
float tx,ty,tz = 0;
// Cambio los valores a positivos ya que serán distancias
// y ya tenemos el cuadrante en el que se han de desplazar
if(ax < 0){
tx = ax*-1;
}else{
tx = ax;
}
if(ay < 0){
ty = ay*-1;
}else{
ty = ay;
}
if(az < 0){
tz = az*-1;
}else{
tz = az;
}
// EL VALOR 0.5 representa el tiempo de refresco entre los valores 500ms
dx = (float)sqrt(tx)/0.5f;
dy = (float)sqrt(ty)/0.5f;
dz = (float)sqrt(tz)/0.5f;
}

Los valores del cuadrante son en un eje de coordenadas, donde se supone que se ha de posicionar el punto xy del desplazamiento.
Si a alguien ve algún dato que esté equivocado, que por favor me lo diga.
Gracias a todos.

Estos son los resultados con el acelerometro sobre la mesa y sin moverlo.

Admito todo tipo de sugerencias.

Nota: Los valores de la conversión a ángulos han sido "medidos" sobre el terreno, con un medidor de ángulos y lo mejor que he sabido hacerlo. ;D

INI 362,467,600 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,498,610 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,501,604 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,500,606 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 518,498,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 518,498,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 517,498,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 518,498,609 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 518,497,609 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 518,498,609 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,498,611 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 520,498,609 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 520,499,609 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 520,499,608 ANGULOS -10.00,10.00,-90.00 ACELERACIONES 0.54,-0.84,0.27 DISTANCIAS(metros) 1.48,1.83,1.04

INI 518,499,611 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,502,609 ANGULOS -10.00,0.00,-80.00 ACELERACIONES 0.54,1.00,-0.06 DISTANCIAS(metros) 1.48,2.00,0.49

INI 519,498,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,499,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 520,498,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,498,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 518,498,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,499,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,498,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 521,496,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,499,608 ANGULOS -10.00,10.00,-90.00 ACELERACIONES 0.54,-0.84,0.27 DISTANCIAS(metros) 1.48,1.83,1.04

INI 520,498,610 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,498,610 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,498,609 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,498,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,499,610 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,499,609 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,501,610 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 518,500,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,499,608 ANGULOS -10.00,10.00,-90.00 ACELERACIONES 0.54,-0.84,0.27 DISTANCIAS(metros) 1.48,1.83,1.04

INI 521,498,610 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 518,499,606 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 518,499,606 ANGULOS -10.00,10.00,-90.00 ACELERACIONES 0.54,-0.84,0.27 DISTANCIAS(metros) 1.48,1.83,1.04

INI 520,498,610 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,498,610 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,498,610 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,497,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 521,500,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 520,499,609 ANGULOS 0.00,10.00,-90.00 ACELERACIONES 0.00,-0.84,0.00 DISTANCIAS(metros) 0.00,1.83,0.00

INI 518,499,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,499,608 ANGULOS -10.00,0.00,-80.00 ACELERACIONES 0.54,1.00,-0.06 DISTANCIAS(metros) 1.48,2.00,0.49

INI 519,500,608 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 518,498,611 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 517,499,611 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 520,498,611 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 517,498,610 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

INI 519,498,612 ANGULOS 0.00,0.00,-80.00 ACELERACIONES 0.00,1.00,0.00 DISTANCIAS(metros) 0.00,2.00,0.00

Me he dado por vencido :'(, finalmente voy a optar por hacer la GameGun con el Wiimotion plus ya que el acelerometro no es capaz de darme lecturas validas sobre el eje Z, y de hecho es uno de los ejes mas importantes.
Ya comentaré cuando tenga algo como avanza el proyecto y mostraré los fuentes.

Un saludo.