MindWave Mobile de NeuroSky es una diadema que capta las ondas EGG y el pestañeo del usuario que la porta. Como su nombre sugiere, esta pensada para usarse con dispositivos móviles(IOS y Android) y computadoras de escritorio Mac o Windows. Cuenta con varias aplicaciones compatibles en las diferentes tiendas móviles(Apptore y PlaySotre), de esta forma, podemos probar sus capacidades nada más sacarla de la caja. Estas aplicaciones también vienen incluidas en el DVD que acompaña el producto.
Lo interesante de este aparato es que como desarrolladores tenemos a un costo reducido ($129.99 dólares actualmente), un sensor EEG con interfaz para conectarse a dispositivos móviles fácilmente y poder utilizarlo en juegos y aplicaciones.
En el sitio developer.neurosky.com podemos encontrar documentos, tutoriales y aplicaciones de prueba para distintas plataformas como son Android, Ios, Unity 3d, Arduino, Raspberry Pi, .Net, entre otras.
Algo curioso es que para descargar las aplicaciones de prueba, hay que hacerlo a través de la tienda de NeuroSky como si de un producto más se tratara, incluso hay que proporcionar nuestra dirección para entrega. Eso si, el costo de estas aplicaciones esta en $0.00 dólares, por lo que no se debe preocupar uno de pagar nada.
MindWave Mobile en Android
Para Android, NeuroSky nos provee de una API en Java para interactuar con la diadema, documentación, una guía en pdf y una aplicación de prueba en donde se hace uso de las funciones más comunes de esta API. El paquete se puede obtener en http://store.neurosky.com/products/developer-tools-3-android. Una vez completados los pasos de la tienda, recibiremos un correo electrónico con un enlace para descargar un archivo .zip con todo lo antes mencionado.
La aplicación de ejemplo es un text view dentro de un scroll en donde se va mostrando lo que se recibe de la diadema y un botón para conectar con el dispositivo.
Así luce la aplicación de ejemplo incluida en el kit para Android |
Conociendo la API
La clase básica que vamos a utilizar en cualquier aplicación es la clase TGDevice ubicada en el paquete com.neurosky.thinkgear.TGDevice
El constructor
TGDevice(BluetoothAdapter btAdapter, Handler handler)
El constructor de la clase TGDevice recibe un adaptdor de Bluetooth y un manejador o handler, que veremos más adelante.
Los mensajes de la diadema
Antes que nada, debemos conocer las siguientes constantes que están dentro de la clase TGDevice que representan los tipos de mensajes que se pueden recibir:
MSG_ATTENTION
Indica que el mensaje recibido incluye el valor del nivel de atención del usuario(el valor recibido oscila entre 0 y 100)
MSG_BLINK
Indica que se ha producido un pestañeo. El mensaje recibido incluye un valor de 0 a 100 que es la precisión en detectar el parpadeo
MSG_HEART_RATE
Indica que el mensaje recibido es el pulso cardiaco. Nota: El producto Mindwave Mobile no es capaz de obtener el pulso cardiaco, pero viene incluido porque la API sirve para varios productos de NeuroSky
MSG_LOW_BATTERY
Es un mensaje para indicar que la batería del dispositivo tiene poca carga
MSG_MEDITATION
Indica que el mensaje recibido incluye el valor del nivel de meditación del usuario(el valor recibido oscila entre 0 y 100)
MSG_POOR_SIGNAL
Indica que la señal recibida del dispositivo es muy baja, el valor del mensaje es el valor de la señal.
MSG_RAW_DATA
Indica que el mensaje recibido contiene los datos en brutos de la lectura EEG que da el dipositivo.
MSG_STATE_CHANGE
Es un mensaje para indicar que el estado del dispositivo ha cambiado. El valor del mensaje puede ser uno de los siguientes estados del dispositivo:
Estados del dispositivo
STATE_CONNECTED
Indica que el dispositivo se encuentra correctamente conectado
STATE_CONNECTING
Indica que el dispositivo ha sido encontrado y se esta realizando la conexión
STATE_DISCONNECTED
Indica que el dispositivo se encuentra desconectado
STATE_NOT_FOUND
Indica que el dispositivo no pude ser encontrado
STATE_NOT_PAIRED
Indica que no hay ningún dispositivo pareado mediante Bluetooth
STATE_IDLE
Indica que el dispositivo esta en modo reposo
Utilizando la API
Para comprender el funcionamiento y características de la API crearemos una aplicación para probar sus funcionalidades con el siguiente aspecto:
Aspecto de la aplicación |
El xml de la vista anterior:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.ejemplomindwavemobile.MainActivity$PlaceholderFragment" > <Button android:id="@+id/btnConectar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:text="Conectar" /> <TextView android:id="@+id/txtEstado" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/btnConectar" android:layout_alignLeft="@+id/textView1" android:layout_alignTop="@+id/btnConectar" android:layout_toLeftOf="@+id/btnConectar" android:background="#eeeeee" android:paddingLeft="2dp" android:paddingTop="5dp" android:text="Estado del dispositivo" /> <ScrollView android:id="@+id/scrollView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignRight="@+id/btnConectar" android:layout_below="@+id/TextView02" android:layout_marginTop="48dp" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/txtRawdata" android:layout_width="match_parent" android:layout_height="match_parent" android:text="Data EEG en bruton--------------------" /> </LinearLayout> </ScrollView> <TextView android:id="@+id/TextView02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/scrollView1" android:layout_below="@+id/TextView01" android:layout_marginTop="22dp" android:text="Pestañeos" /> <TextView android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/TextView02" android:layout_below="@+id/textView1" android:layout_marginTop="21dp" android:text="Meditación:" /> <TextView android:id="@+id/txtConcentracion" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/TextView01" android:layout_centerHorizontal="true" android:background="#eeeeee" android:text="0" /> <TextView android:id="@+id/txtMeditacion" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/TextView02" android:layout_alignLeft="@+id/txtConcentracion" android:background="#eeeeee" android:text="0" /> <TextView android:id="@+id/txtPestaneos" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/TextView02" android:layout_alignBottom="@+id/TextView02" android:layout_alignLeft="@+id/txtMeditacion" android:background="#eeeeee" android:text="0" /> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/TextView01" android:layout_below="@+id/lblEstado" android:layout_marginTop="48dp" android:text="Concentración:" /> <CheckBox android:id="@+id/checkRaw" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/txtPestaneos" android:layout_alignParentRight="true" android:text="Ver raw" /> </RelativeLayout>
Lo primero que tenemos que hacer en una aplicación Android que use Mindwave Mobile es incluir la API contenida en el archivo ThinkGear.jar
Para la comunicación con la diadema, la aplicación debe solicitar el permiso para Bluetooth. En el archivo AndroidManifest.xml agregamos la siguiente linea: <uses-permission android:name=”android.permission.BLUETOOTH” />
<?xml version="1.0" encoding="utf-8" ?> <manifest> <uses-permission android:name="android.permission.BLUETOOTH" /> </manifest>
En el cuerpo de la aplicación como variables globales de la clase, tenemos que declarar un adaptador de bluetooth BluetoothAdapter para manejar la conexión, una variable del tipo TGDevice que es la que va a representar el dispositivo, un variable boleana activarRaw para indicar si queremos leer los datos en bruto o solo la concentración, meditación y pestañeos, una variable entera para llevar el conteo de los pestañeos y por último las variables para manejar la interfaz gráfica
BluetoothAdapter bluetoothAdapter; com.neurosky.thinkgear.TGDevice tgDevice; boolean activarRaw = false; int pestaneos=0; //Variables de interfaz de usuario Button btnConectar; TextView txtEstado; TextView txtConcentracion; TextView txtMeditacion; TextView txtPestaneos; TextView txtRawdata; CheckBox checkRaw;
En el método onCreate de la aplicación obtenemos el bluetooth, definimos las referencias a los objetos de la interfaz gráfica y las acciones del botón y el checkBox
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Se obtiene un adaptador bluetooth bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); //Se compruba si el bluetooth esta disponible if(bluetoothAdapter == null) { //Indicar al usuario que el bluetooth no esta disponible Toast.makeText(this, "Bluetooth no disponible", Toast.LENGTH_LONG).show(); finish(); //Terminar el programa }else { //Crear un nuevo dispositivo con el adaptador bluetooth y el manejador tgDevice = new TGDevice(bluetoothAdapter, handler); } //Se obtiene la referencia a los objetos de la interfaz grafica btnConectar = (Button)findViewById(R.id.btnConectar); txtEstado = (TextView)findViewById(R.id.txtEstado); txtConcentracion = (TextView)findViewById(R.id.txtConcentracion); txtMeditacion = (TextView)findViewById(R.id.txtMeditacion); txtPestaneos = (TextView)findViewById(R.id.txtPestaneos); txtRawdata = (TextView)findViewById(R.id.txtRawdata); checkRaw = (CheckBox)findViewById(R.id.checkRaw); //Acciones btnConectar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { conectar(); } }); checkRaw.setOnCheckedChangeListener(new OnCheckedChangeListener(){ @Override public void onCheckedChanged(CompoundButton arg0, boolean checked) { activarRaw=checked; tgDevice.stop(); tgDevice.close(); tgDevice.connect(activarRaw); } }); }
La función conectar, que conecta la diadema y especifica si se quieren los datos en bruto o depurados ya(concentración, meditación y pestañeo). Comprueba que la diadema no este ya conectada.
public void conectar() { if(tgDevice.getState() != TGDevice.STATE_CONNECTING && tgDevice.getState() != TGDevice.STATE_CONNECTED) tgDevice.connect(activarRaw); }
Y la parte más importante de todas, el manejador o handler, gracias a el podemos entender y comunicarnos con el dispositivo Mindwave. Su estructura es sencilla y fácil de usar.
private final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case TGDevice.MSG_STATE_CHANGE: switch (msg.arg1) { case TGDevice.STATE_IDLE: txtEstado.setText("Dispositivo en reposo"); break; case TGDevice.STATE_CONNECTING: txtEstado.setText("Conectando..."); break; case TGDevice.STATE_CONNECTED: tgDevice.start(); txtEstado.setText("Conectado"); break; case TGDevice.STATE_NOT_FOUND: txtEstado.setText("Dispositivo no encontrado"); break; case TGDevice.STATE_NOT_PAIRED: txtEstado.setText("Dispositivo no vinculado"); break; case TGDevice.STATE_DISCONNECTED: txtEstado.setText("Desconectado"); } break; case TGDevice.MSG_POOR_SIGNAL: break; case TGDevice.MSG_RAW_DATA: txtRawdata.setText(String.valueOf(msg.arg1)+"\n"); break; case TGDevice.MSG_HEART_RATE: break; case TGDevice.MSG_ATTENTION: txtConcentracion.setText(String.valueOf(msg.arg1)); break; case TGDevice.MSG_MEDITATION: txtMeditacion.setText(String.valueOf(String.valueOf(msg.arg1))); break; case TGDevice.MSG_BLINK: pestaneos++; txtPestaneos.setText(String.valueOf(pestaneos)); break; case TGDevice.MSG_RAW_COUNT: break; case TGDevice.MSG_LOW_BATTERY: Toast.makeText(getApplicationContext(), "¡Bateria baja!", Toast.LENGTH_LONG).show(); break; case TGDevice.MSG_RAW_MULTI: TGRawMulti rawM = (TGRawMulti)msg.obj; default: break; } } };
Conociendo esto ya se debe ser capaz de usar la API de Mindwave Mobile en otras aplicaciones Android o utilizar su homologa en otra tecnología como Unity o C# ya que el principio es el mismo.
El código fuente del proyecto está disponible en Github: https://github.com/notasdesoftware/EjemploMindwaveMobile
con esta carpeta genéro una apk?
Hola Felipe. Si, con el proyecto de Github puedes generar un apk.
coo hago para imprimir los graficos de eeg mind wave?
Hola Elvis, este post explica como obtener los datos de la diadema Mind Wave a través de una API Java.
Con estos datos puedes construir cualquier representación que tu quieras, tal como lo hace la aplicación de visualización de NeuroSky “Brainwave Visualizer” https://play.google.com/store/apps/details?id=com.neurosky.unitythinkgear&hl=es
Este aparato sirve para monitorear el sueño? para el pago se puede utilizar paypal?
Hola Andres, no está pensado para ello, además de no ser muy cómodo de usar.
Como comentó en el artículo, para descargar el SDK nos pide datos de pago, pero no se cobra nada por qué el costo es cero. Y si, se permite “pagar” con Paypal.