En esta página se describe un demo de tecnología usando el sistema de captura de movimiento PhaseSpace para capturar el movimiento de la mano derecha de un humano. Al final de la página encontrará un link con los archivos necesarios para correr la demo.

En este link puede encontrar un video demostrativo de la aplicación.

http://youtu.be/eiCDRmuP0W8

Descripción

El objetivo de este demo, es usar el sistema de captura de movimiento PhaseSpace junto con un guante y 8 marcadores del sistema, para controlar una mano virtual. La disposición de los marcadores sobre el guante es la siguiente:

  • 1 marcador en la punta de cada dedo
  • 1 marcador en la base del dedo pulgar
  • 2 marcadores en la parte de arriba de la mano

La siguiente es una imagen del guante.

Dada la disposición de los marcadores, los movimientos reflejados en la mano virtual no incluyen flexiones en los dedos. A continuación se muestra una imagen del modelo utilizado para la mano virtual.

El demo está hecho para utilizar un guante que se use en la mano derecha de una persona.

Tutorial

El demo usa diferentes tecnologías para cumplir su objetivo. Para la visualización y lógica se utiliza Blender, la comunicación entre el dispositivo y Blender se hace usando la versión Java de VRPN y por último se utilizan las herramientas que provee el sistema PhaseSpace para la calibración y configuración de PhaseSpace.

Configuración PhaseSpace

Primero se deben posicionar las cámaras de tal forma que se tenga una buena cobertura del espacio en donde se va a utilizar el sistema. Una vez las cámaras se encuentren en una buena posición, se debe realizar la calibración del sistema. En el siguiente video se muestra el proceso de calibración del sistema con las cámaras posicionadas de una buena forma.

http://www.youtube.com/watch?v=uWETQxn1fgQ

Una vez calibrado el sistema, se procede a configurar un controlador de LED del sistema para que se puedan utilizar los marcadores del guante. Para esto se debe crear un perfil en el sistema de configuración que provee PhaseSpace.

Se le da un nombre al perfil y el número de slots debe ser 4.

Se selecciona la opción mostrada en la imagen.

Dado que el guante tiene 8 marcadores, se especifíca la opción de 8 LEDs y se da clic en “Add this String” y luego en “Save this driver”.

Finalmente se guarda el perfil. Una vez se encuentre creado el perfil, se procede a configurar el controlador de LEDs con el perfil que se creó.

Por ultimo se codifica el controlador de LEDs con la configuración creada

Una vez se ha realizado todo el proceso, se puede comenzar la captura de movimiento. Para esto se debe usar el programa “Master” ingresando como parametro la ip del servidor PhaseSpace

VRPN

Con el sistema PhaseSpace listo para usar con el guante, se debe configurar el ambiente VRPN que viene integrado con el servidor de PhaseSpace.

Se debe usar el siguiente archivo de configuración (vrpn.cfg) para el servidor VRPN.

vrpn_Tracker_PhaseSpace TrackerPhase 157.253.192.178  120.0 1 1
<owl>
0 :     pt      0
1 :     pt      1
2 :     pt      2
3 :     pt      3
4 :     pt      4
5 :     pt      5
6 :     pt      6
7 :     pt      7

Para arrancar el servidor VRPN, se debe tener “Master” abierto y conectado con toda la configuración descrita anteriormente. Posteriormente, se debe ejecutar el comando que inicia el servidor VRPN en la máquina.

$ <ruta al servidor VRPN>/vrpn_server

Una vez se ha ejecutado este comando, el servidor VRPN comienza su funcionamiento y envía la información capturada.

Para que Blender reciba la información de PhaseSpace, utilizamos la versión Java de VRPN como cliente. Se debe contar con las librerías previamente compiladas para poder conectarse de esta forma. Al final de esta página encontrará un archivo comprimido con los archivos necesarios para correr esta demo. en la carpeta vrpn, encontrará un archivo llamado java_vrpn.dll, este archivo de debe copiar en la carpeta System32 de su equipo (para ambientes diferentes a windows se debe compilar la librería para la versión Java de vrpn). Adicionalmente encontrará un archivo llamado vrpn.jar, este archivo debe incluirse en el classpath del ambiente java que desee utilizar. Por último encontrará 2 archivos: Cliente.java y ThreadConexion.java. Debe modificar el archivo Cliente.java en la línea 45 para ingresar la dirección ip del servidor PhaseSpace.

Una vez hecho esto, puede correr el archivo Cliente.java y si el servidor VRPN de PhaseSpace se encuentra configurado y corriendo, el programa imprimirá por consola la información de tracking capturada.

Blender

Instrucciones para correr el demo

Para iniciar la demo, se debe abrir el archivo Demo.blend que se encuentra en la carpeta Blender. Antes de iniciar, se debe tener corriendo el programa Java descrito anteriormente junto con el sistema PhaseSpace configurado correctamente con VRPN.

Para correr el programa se debe estar en el modo “Game” dentro de Blender.

Una vez dentro de este modo, se selecciona la opción “Start Game Engine” o se presiona la tecla “P” con el mouse dentro de la vista 3D.

Integración con VRPN

La función del código Java mostrado anteriormente, es conectarse con el servidor VRPN del sistema PhaseSpace para capturar la información de movimiento que arroja el sistema. Por cada punto capturado, el programa en java replica los datos capturados y los envía como cadenas de caracteres por medio de un socket en el puerto 40001. Esto se hace por que la integración VRPN con Blender es difícil y no se logró encontrar una librería Python que logre integrar Blender con VRPN directamente.

Una vez que el programa Java envía los datos por ese puerto, Blender puede capturar esos datos por medio de otro socket. El siguiente código es un script en Python que sirve para establecer la conexión entre el programa Java y Blender.

import bge
import threading
from socket import *
import GameLogic as gl
import mathutils as math

gl.conectado=False

scene = bge.logic.getCurrentScene()
         
sock = socket(AF_INET, SOCK_STREAM)
sock.setsockopt(SOL_SOCKET, SO_REUSEADDR,1)
#sock.bind((HOST,PORT))
sock.connect(("localhost",40001))
#sock.connect(("localhost",40001))
sock.setblocking(0) #Dejar el socket como NO Blocking
sock.settimeout(1/100)
         
gl.conexionVrpn=sock
gl.conectado=True
print ("se creo la conexion")

Explicación del código del demo

En esta sección se explican las partes más importantes del código en Blender del demo. Consta de 4 scripts en Blender:

  • inicializacion.py: Se ejecuta 1 vez al inicio del programa y sirve para la inicialización de algunos valores y estructuras de datos (como la matriz de transformación de coordenadas entre las posiciones reales y virtuales) que se usan en toda la aplicación.
  • conexionVRPN.py: También se ejecuta una vez y sirve para establecer la conexión entre el socket del programa en Java y el socket en Blender.
  • LeerVRPN.py: Este script captura la información arrojada por el sistema PhaseSpace y guarda los valores en estructuras de datos organizadas según el marcador del guante.
  • movimientoMano.py: Es el script principal. En este script se usa la información capturada y se traduce en el movimiento de la mano virtual.

A continuación se explica como se logra el movimiento de la mano virtual. El código está dividido en 3 secciones: traslación de la mano, rotación de la mano y movimiento de los dedos.

Traslación de la mano

Para la posición de la mano se toma el marcador mostrado en la imagen. Se utiliza una constante llamada PUNTO_IZQ para identificar este punto.

Primero se hace un chequeo para ver si existen coordenadas que se puedan usar para el movimiento. Después, se toma la última y la penúltima coordenada enviada por PhaseSpace para ese marcador. Se calculan los vectores que van desde la coordenada inicial del marcador (coordenada al momento de iniciar el programa) hasta la última y la penúltima coordenada. A estos vectores se les aplica una escala para que concuerden los movimientos reales con los movimientos en pantalla. Finalmente se calcula la diferencia entre estos dos vectores y se aplica la traslación con la función applyMovement().

if(bge.puntosGuanteActual[bge.PUNTO_IZQ]!=None and bge.puntosGuanteInicio[bge.PUNTO_IZQ]!=None):
        posAnterior = bge.escalaMapeo*(bge.puntosGuanteAnterior[bge.PUNTO_IZQ]-bge.puntosGuanteInicio[bge.PUNTO_IZQ])
        pos = bge.escalaMapeo*(bge.puntosGuanteActual[bge.PUNTO_IZQ]-bge.puntosGuanteInicio[bge.PUNTO_IZQ])
        bge.mano.applyMovement(pos-posAnterior)

Rotación de la mano

Para calcular la orientación de la mano, se toman los 2 marcadores que se encuentran en la parte superior de la mano, formando un vector de orientación.

Para que las rotaciones sean fluidas, se utilizan coordenadas en donde la diferencia en el tiempo de lectura entre la penúltima y la última coordenada no sea mayor a un tiempo determinado. Luego se calcula el vector entre los puntos mostrados en la imagen anterior. Para calcular el cuaternión de la nueva orientación, se toma el vector inicial (vector calculado al inicio del programa), se calcula el ángulo de diferencia entre el vector inicial y el nuevo vector y se arma el cuaternión tomando el vector inicial como eje de rotación. En cada frame se calcula esta orientación, por lo tanto se guarda el cuaternión calculado con anterioridad y se calcula la diferencia con el nuevo cuaternión, esto nos arroja un cuaternión que representa la rotación que se debe aplicar a la orientación de la mano. Teniendo esto, se utiliza la función rotate() con el cuaternión de diferencia como parámetro. Para evitar cambios tan bruscos de orientación cuando PhaseSpace pierde la posición de los marcadores, se verifica que el ángulo de rotación del cuaternión sea menor a 45 grados, o 1.570796 radianes.

if bge.tiemposUltimaLectura[bge.PUNTO_DER]-bge.tiemposLecturaAnterior[bge.PUNTO_DER]<bge.tiempoMaxLectura and bge.tiemposUltimaLectura[bge.PUNTO_IZQ]-bge.tiemposLecturaAnterior[bge.PUNTO_IZQ]<bge.tiempoMaxLectura:
      vectDif=(bge.puntosGuanteActual[bge.PUNTO_DER]-bge.puntosGuanteActual[bge.PUNTO_IZQ])
      axis=bge.vectIniMano.cross(vectDif)
      angle=bge.vectIniMano.angle(vectDif,0)
      quat=math.Quaternion(axis,-angle)
      
      if bge.quatAnteriorMano!=None:
          quatTemp=quat
          quat=quat.rotation_difference(bge.quatAnteriorMano)
          bge.quatAnteriorMano=quatTemp
      elif bge.quatAnteriorMano==None:
          bge.quatAnteriorMano=math.Quaternion((1,0,0,0))
      
      if angle<1.570796:
          bge.mano.worldOrientation.rotate(quat)

Movimiento de los dedos

El vector de orientación que se utiliza para cada dedo es el vector que se forma entre el marcador más cercano a la punta del dedo, y el marcador de la punta del dedo.

Básicamente se cambia la orientación de cada uno de los dedos de la misma forma en la que se cambia la orientación de la mano pero no se hace el chequeo de los 45 grados.

if bge.tiemposUltimaLectura[bge.PUNTO_MEDIO]-bge.tiemposLecturaAnterior[bge.PUNTO_MEDIO]<bge.tiempoMaxLectura and bge.tiemposUltimaLectura[bge.PUNTO_DER]-bge.tiemposLecturaAnterior[bge.PUNTO_DER]<bge.tiempoMaxLectura:
      vectDif=(bge.escalaMapeoDedos*(bge.puntosGuanteActual[bge.PUNTO_MEDIO]-bge.puntosGuanteActual[bge.PUNTO_DER]))
      axis=bge.vectsIniDedos[bge.PUNTO_MEDIO].cross(vectDif)
      angle=bge.vectsIniDedos[bge.PUNTO_MEDIO].angle(vectDif,0)
      quat=math.Quaternion(axis,angle*multAng)
      bge.medio.rotation_quaternion=quat

Archivos

Este archivo contiene los archivos necesarios para correr la demo.

demo.zip

guante_phasespace.txt · Última modificación: 2012/05/13 23:04 por n.mendoza26
Departamento de Ingeniería de Sistemas y Computación - Facultad de Ingeniería - Universidad de los Andes
CC Attribution-Noncommercial-Share Alike 3.0 Unported
Valid CSS Driven by DokuWiki Recent changes RSS feed Valid XHTML 1.0