lunes, 16 de abril de 2007

Manejo analógico de vehículo mediante GamePad

En esta entrada voy a comentar como realicé la conexión del mando Logitech Dual Action, para poder usarlo en simulaciones con PlayerStage.

La API que utilicé fue la Light Weight Java Game Library, que descargué y añadí en eclipse como biblioteca de usuario mediante Build Path (vía de acceso de construcción)

Para hacer uso de la biblioteca es necesario decirle a la JVM donde se encuentran los binarios (.dll en Windows o .so en linux). Están en el directorio native del paquete lwjgl que descargamos en el paso anterior. Es decir, que en eclipse nos vamos a "Ejecutar...", y en los argumentos de la VM ponemos (en mi caso):
-Djava.library.path=/home/diego/JavaLibraries/lwjgl-1.0beta4/native/linux

Dependiendo de la instalación ponermos el directorio correspondiente. En MS Windows podría ser:
-Djava.library.path=C:\JavaLibraries\lwjgl-1.0beta4\native\windows

Y el código de mi GamePad.java sería:


import org.lwjgl.LWJGLException;
import org.lwjgl.input.Controller;
import org.lwjgl.input.Controllers;


public class GamePad {

public static final int START = 4;
public static final int END = 6;
private Controller controller = null;
private int buttonCount;
private int axisCount;
private int SO = -1; /* 0 GNU/Linux || 1 MS Windows */

public GamePad() {


try {
Controllers.create();
} catch (LWJGLException e) {
e.printStackTrace();
}

int numberOfControllers = Controllers.getControllerCount();

if (numberOfControllers==0)
{
System.out.println("No se han encontrado controladores");
}

for(int i=0;i<numberofcontrollers;i++)
{
controller = Controllers.getController(i);
System.out.println(controller.getName());
}

buttonCount = controller.getButtonCount();
axisCount = controller.getAxisCount();

System.out.println("El controlador tiene " +
buttonCount + " botones y " +
axisCount + " ejes");

//Configuración de mando para sistemas MS y Linux
System.out.println("El sistema operativo es " + System.getProperty("os.name"));
if (System.getProperty("os.name").equalsIgnoreCase("Linux"))
this.SO = 0;
else
this.SO = 1;

}

public float[] getRightAxisValues(){
float[] values = new float[2];
Controllers.poll();
if (this.SO == 1){ //MS Windows
//Valor vertical (aceleracion)
values[0] = controller.getAxisValue(0)*(-1.0f);
//Valor horizontal (direccion)
values[1] = controller.getAxisValue(1)*(-1.0f);
}
else if (this.SO == 0){ //Linux
//Valor vertical (aceleracion)
values[0] = controller.getAxisValue(3)*(-1.0f);
//Valor horizontal (direccion)
values[1] = controller.getAxisValue(2)*(-1.0f);
//System.out.println(values[0] +" "+ values[1]);

}
else
System.exit(-1);

return values;
}

public boolean getButton(int n){
try{
Controllers.poll();
return controller.isButtonPressed(n);
}catch(Exception e){
return false;
}
}

}

En la caso de ejecución en GNU/Linux tuve un problema con un mensaje:
/dev/input/event0 cannot open device event0

La solución fue alterar los permisos de los dispositivos que eran 660 para el usuario root. Haciendo sudo chmod 666 /dev/input/event* se soluciona el problema.

Espero le sea útil a alguien.

jueves, 12 de abril de 2007

Los ficheros de configuración de PlayerStage

Para lanzar el servidor necesitamos un fichero .cfg que define los drivers que necesitaremos para la simulación.

Para cargar el simulador Stage y los dispositivos a simular del robot (el propio robot y dispositivo de ultrasonidos), el fichero sería el siguiente:

# load the Stage plugin simulation driver
driver
(
name "stage"
provides ["simulation:0" ]
plugin "libstageplugin"

# load the named file into the simulator
worldfile "simple.world"
)

driver
(
name "stage"
provides ["position2d:0" "sonar:0"]
model "robot1"
)

En primer lugar veamos el fichero de configuración del entorno en el que realizaremos la simulación. En el fichero .cfg teníamos:
worldfile "simple.world"

Esta línea, especifica en el driver de Stage que configuración de entorno (world) usaremos. En este caso el contenido del fichero simple.world es:

# Importamos el archivo en el que están definidos los datos del robot a utilizar
include "pioneer.inc"

# Importamos el archivo en el que están definidos los parametros del mapa
include "map.inc"

# Tamaño del entorno en metros
size [60 45]

# set the resolution of the underlying raytrace model in meters
resolution 0.02

# Configuraión de la ventana (tamaño, centro y escalado)
window ( size [ 800.000 600.000 ] center [0.000 0.000] scale 0.08 )

# Carga de la imagen con el mapa y definición del tamaño respecto al entorno
map
(
bitmap "bitmaps/robotux.png"
size [60 45]
)

# El robot
pioneer2dx
(
name "robot1"
color "red"
pose [-7.603 -4.391 -490.303]
)

El robot por defecto es el Pioneer2DX que si observamos en el fichero pioneer.inc da la posibilidad de configurarse con 8 ó 16 sónares en el anillo. En nuestro caso usaremos un anillo de 7 sonares por lo que debemos crear esa nueva configuración, lo único que hay que hacer es añadir a robot.inc la siguiente configuración:

# ---[ Configuración de anillo de 7 sonares ]---
define mi_sonar7 ranger (
scount 7
# transducer pose [Xpos Ypos Heading]
spose[0] [ 0.075 0.130 90 ]
spose[1] [ 0.115 0.115 60 ]
spose[2] [ 0.150 0.080 30 ]
spose[3] [ 0.170 0.025 0 ]
spose[4] [ 0.170 -0.025 -30 ]
spose[5] [ 0.150 -0.080 -60 ]
spose[6] [ 0.075 -0.130 -90 ]
# transducer size in meters [X Y] (affects the Stage window)
ssize[0] [ 0.01 0.05 ]
ssize[1] [ 0.01 0.05 ]
ssize[2] [ 0.01 0.05 ]
ssize[3] [ 0.01 0.05 ]
ssize[4] [ 0.01 0.05 ]
ssize[5] [ 0.01 0.05 ]
ssize[6] [ 0.01 0.05 ]
# transducer viewing parameters [Range_min Range_max FOV]
sview[0] [ 0 5.0 15 ]
sview[1] [ 0 5.0 15 ]
sview[2] [ 0 5.0 15 ]
sview[3] [ 0 5.0 15 ]
sview[4] [ 0 5.0 15 ]
sview[5] [ 0 5.0 15 ]
sview[6] [ 0 5.0 15 ]
)

Y al final de la definición estándar del robot (el bloque define pioneer2dx position) añadir el driver del anillo que hemos creado añadiendo la línea mi_sonar7() :

# use the sonar array defined above
mi_sonar7()
)