domingo, 9 de diciembre de 2012

1.- Arduino Mega ADK y Android Tutorial "Como Comenzar"

Hello World Arduino Mega ADK y Android


Esta entrada está desactualizada, para ver la información más reciente favor de ver mi nueva wiki: https://code.google.com/p/proyect-general-es/wiki/ArduinoADK_Android

Enciende y apaga un led (led pin 13) de tu Arduino Mega ADK por medio de un dispositivo Android.



Que rollo!!,, compraste un Arduino Mega ADK pensando que sería fácil programar algo, que en media hora estarías controlando ya la placa por medio de tu celular o de tu tablet?
Ooo decepción!!
Si eres nuevo en Android y en Arduino a la vez, esto si que es una jalada, pero bueno para eso está hecho este tutorial.
La página de Google ADK es bonita y explicativa? O claro que lo és (para una persona que llevo mínimo unos 5 años trabajando en este rollo), pero si queremos comenzar no nos sirve, bueno, al menos hasta que nos motivemos viendo que hicimos algo bien, ya de allí despegamos solos.

Material:

  1. Un Arduino Mega ADK
  2. Un dispositivo Android (tu celular!!!!)
  3. Los cables para conectar =P

Vista preliminar



Y así se supone debe quedar todo

Sip, así mero

Software Necesario


  1. IDE de Arduino (mínimo la 1.0.2) la cual incluye ya las librerias necesarias (Max3421e.h y Usb.h). link
  2. Obtener las librerías del ADK (Google Tuto) o si bien no deseas descargar todo el repositorio con repo, aquí te coloco lo único necesario para este tutorial y más: android_accessories_descarga. Debo aclarar que ese código viene directo del repositorio de google y no ha sido modificado.
  3. Eclipse. Si ya tienes Eclipse instala bien el plugin para programar Android o si eres novato en esto recomiendo que descargues mejor el ADT Bundle (Version de Eclipse ya lista), o si ya eres master en esto saltatelo LOL!!!.
    1. Debes tener las APIS de Google tal y como indica aqui.


APIS de Google instaladas





Comienza lo divertido.

Librearías para Arduino.
Del repositorio que descargaste de Google copia las librerías necesarias al directorio de librearías de Arduino IDE:


Copia los directorios:
*android-accesories/adk1/board/AndroidAccesory
*android-accesories/adk1/board/USB_Host_Shield
a
.../arduino-1.0.2/libraries/



Nuevo proyecto y APIS necesarias

Crea un nuevo Android Application Project y ponle de nombre ArduinoBlinkLED, haz clic en Next, Next, Finish hasta terminar.


Nuevo Proyecto Android

Deberías tener mínimo:

  • Un layout principal llamado activity_main.xml
  • Un archivo de actividad java principal llamado MainActivity.java dentro del paquete com.example.arduinoblinkled
  • Un archivo manifest llamado AndroidManifest.xml



Que bonito Código!!! Manos a la obra

Así es como se verá tu Package Explorer en Eclipse:






0
Agrega las APIS de Google al proyecto.

  1. Clic derecho a la carpeta del proyecto, propiedades
  2. Resource/Android y selecciona Google APIs como Project Buil Target






1
Cambia el código de nuestro activity_main.xml por este:

Archivo: layout/activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:layout_width="fill_parent"
       android:id="@+id/relativeLayout1"
       android:layout_height="fill_parent"
       android:layout_weight="0.72" xmlns:android="http://schemas.android.com/apk/res/android">
       <ToggleButton
       android:text="ToggleButton"
       android:id="@+id/toggleButtonLED"
       android:layout_width="500px"
       android:layout_height="200px"
       android:layout_centerVertical="true"
       android:layout_centerHorizontal="true"
       android:textSize="50px"
       android:onClick="blinkLED"></ToggleButton>
</RelativeLayout>




2
Crea una carpeta dentro de "res" llamada xml y dentro de ella crea un nuevo archivo llamado accessory_filter.xml, coloca el siguiente codigo en el archivo:

Archivo: xml/accessory_filter.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <usb-accessory manufacturer="Manufacturer" model="Model" version="1.0" />
</resources>


3
Modifica el código de AndroidManifest.xml de tal manera que te quede algo parecido a esto:

Archivo: AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.arduinoblinkled"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="13"
        android:targetSdkVersion="16" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.arduinoblinkled.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
           
            <intent-filter>
                           <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
                    </intent-filter>
           
            <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
                           android:resource="@xml/accessory_filter" />
           
        </activity>
       
        <uses-library android:name="com.android.future.usb.accessory"></uses-library>
       
    </application>

</manifest>


En este ultimo paso se declara que se usaran las librearías USB accessory y también se pide permiso de que cuando conectes el dispositivo al aparato android nuestra aplicación comience por default. Recuerda usar el minSdkVersion adecuado a tus librerías, para estar seguro puedes verificar las referencias de google.

Referencias de google:



4
Cambia el codigo del archivo MainActivity.java por este:

Archivo: com.example.arduinoblikled/MainActivity.java
package com.example.arduinoblinkled;

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.view.View;
import android.widget.ToggleButton;

import com.android.future.usb.UsbAccessory;
import com.android.future.usb.UsbManager;

public class MainActivity extends Activity {

       // TAG is used to debug in Android logcat console
       private static final String TAG = "ArduinoAccessory";

       private static final String ACTION_USB_PERMISSION = "com.google.android.DemoKit.action.USB_PERMISSION";

       private UsbManager mUsbManager;
       private PendingIntent mPermissionIntent;
       private boolean mPermissionRequestPending;
       private ToggleButton buttonLED;

       UsbAccessory mAccessory;
       ParcelFileDescriptor mFileDescriptor;
       FileInputStream mInputStream;
       FileOutputStream mOutputStream;

       private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
                    String action = intent.getAction();
                    if (ACTION_USB_PERMISSION.equals(action)) {
                           synchronized (this) {
                                  UsbAccessory accessory = UsbManager.getAccessory(intent);
                                  if (intent.getBooleanExtra(
                                               UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                                        openAccessory(accessory);
                                  } else {
                                        Log.d(TAG, "permission denied for accessory "
                                                      + accessory);
                                  }
                                  mPermissionRequestPending = false;
                           }
                    } else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
                           UsbAccessory accessory = UsbManager.getAccessory(intent);
                           if (accessory != null && accessory.equals(mAccessory)) {
                                  closeAccessory();
                           }
                    }
             }
       };


       @Override
       public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);

             mUsbManager = UsbManager.getInstance(this);
             mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
             IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
             filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
             registerReceiver(mUsbReceiver, filter);

             if (getLastNonConfigurationInstance() != null) {
                    mAccessory = (UsbAccessory) getLastNonConfigurationInstance();
                    openAccessory(mAccessory);
             }

             setContentView(R.layout.activity_main);
             buttonLED = (ToggleButton) findViewById(R.id.toggleButtonLED);
            
       }

       @Override
       public Object onRetainNonConfigurationInstance() {
             if (mAccessory != null) {
                    return mAccessory;
             } else {
                    return super.onRetainNonConfigurationInstance();
             }
       }

       @Override
       public void onResume() {
             super.onResume();

             if (mInputStream != null && mOutputStream != null) {
                    return;
             }

             UsbAccessory[] accessories = mUsbManager.getAccessoryList();
             UsbAccessory accessory = (accessories == null ? null : accessories[0]);
             if (accessory != null) {
                    if (mUsbManager.hasPermission(accessory)) {
                           openAccessory(accessory);
                    } else {
                           synchronized (mUsbReceiver) {
                                  if (!mPermissionRequestPending) {
                                         mUsbManager.requestPermission(accessory,mPermissionIntent);
                                        mPermissionRequestPending = true;
                                  }
                           }
                    }
             } else {
                    Log.d(TAG, "mAccessory is null");
             }
       }

       @Override
       public void onPause() {
             super.onPause();
             closeAccessory();
       }

       @Override
       public void onDestroy() {
             unregisterReceiver(mUsbReceiver);
             super.onDestroy();
       }

       private void openAccessory(UsbAccessory accessory) {
             mFileDescriptor = mUsbManager.openAccessory(accessory);
             if (mFileDescriptor != null) {
                    mAccessory = accessory;
                    FileDescriptor fd = mFileDescriptor.getFileDescriptor();
                    mInputStream = new FileInputStream(fd);
                    mOutputStream = new FileOutputStream(fd);
                    Log.d(TAG, "accessory opened");
             } else {
                    Log.d(TAG, "accessory open fail");
             }
       }


       private void closeAccessory() {
             try {
                    if (mFileDescriptor != null) {
                           mFileDescriptor.close();
                    }
             } catch (IOException e) {
             } finally {
                    mFileDescriptor = null;
                    mAccessory = null;
             }
       }

       public void blinkLED(View v){

             byte[] buffer = new byte[1];

             if(buttonLED.isChecked())
                    buffer[0]=(byte)0; // button says on, light is off
             else
                    buffer[0]=(byte)1; // button says off, light is on

             if (mOutputStream != null) {
                    try {
                           mOutputStream.write(buffer);
                    } catch (IOException e) {
                           Log.e(TAG, "write failed", e);
                    }
             }
       }

}


4
Carga el siguiente sketch a tu Arduino Mega ADK:

sketch:
____________________________________________________________
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
#define  LED_PIN  13
AndroidAccessory acc("Manufacturer",
  "Model",
  "Description",
  "1.0",
  "http://example.com",
                "0000000012345678");
void setup()
{
  // set communiation speed
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  acc.powerOn();
}
 
void loop()
{
  byte msg[0];
  if (acc.isConnected()) {
    int len = acc.read(msg, sizeof(msg), 1); // read data into msg variable
    if (len > 0) {
      if (msg[0] == 1) // compare received data
        digitalWrite(LED_PIN,HIGH); // turn on light
      else
        digitalWrite(LED_PIN,LOW); // turn off light
    }
  } 
  else
    digitalWrite(LED_PIN , LOW); // turn off light
}
____________________________________________________________



5

  • Carga la aplicación android a tu dispositivo androi (dígase celular, tableta...)
  • Conecta el Arduino a tu PC y abre un SerialMonitor
  • Conecta el dispositivo Android al Arduino
  • Listo!!!!!!!!!!!



Video de muestra


Descargas:

Proyecto de eclipse aqui.
Sketch arduino aqui.

Error Comun:
error: WProgram.h: No such file or directory






Si la IDE de Arduino te tira ese error es porque a partir de la versión 1.0.1 WProgram.h que contiene declaraciones para la API de Arduino fue cambiada por Arduino.h.

Parece que Arduino se le olvido mencionarle a Google que había cambiado su API, bueno este error se soluciona fácil basta con cambiar en todos los archivos que contengan ese error WProgram.h por Arduino.h y ya.

En nuestro caso solo debería ser en el archivo de librería AndroidAccessory.h como muestra el compilador.







Fuentes:
Especial agradecimiento a esta Web, todo el código presentado en esta entrada es de su propiedad, yo sólo me estoy encargando de colocar tips en español.

http://allaboutee.com/2011/12/31/arduino-adk-board-blink-an-led-with-your-phone-code-and-explanation/




Aquí encontré la solución del error:
https://github.com/adafruit/DHT-sensor-library/issues/1






TAGS:



  • Arduino Mega ADK Tutorial
  • Android ADK Tutorial
  • Arduino y Android
  • Arduino ADK Tuto
  • Arduino Hellow World
  • How to Begin Tutorial
  • WProgram.h error

33 comentarios:

  1. Hola, que tal, he estado siguiendo el tutorial, pero no puedo hacer que entre en la aplicación, no se puede abrir, si lo intento dice que desafortunadamente la aplicación se detuvo, y es el .apk que subiste... ademas que jamas inicia por si sola después de conectar el dispositivo (motorola razr i).
    Espero que me puedas ayudar.
    Saludos
    Luis Antonio Fregoso

    ResponderEliminar
    Respuestas
    1. Si no inicia por si sola es porque la descripción de Arduino ADK en el archivo "xml/accessory_filter.xml" no coincide con la que se da en el código de Arduino



      =

      AndroidAccessory acc("Manufacturer",
      "Model",
      "Description",
      "1.0",
      "http://example.com",
      "0000000012345678");

      No recuerdo haber subido un .apk, mejor compila el proyecto siguiendo los pasos dados, no es tan dificil y así podrás ir leyendo el código también.

      Algo más podría ser que la versión de tu Android no sea compatible, en tal caso, al momento de crear un proyecto nuevo en eclipse coloca el rango de versiones de tal manera que tu dispositivo Android quede dentro y después sigues los pasos.

      Saludos Luis Antonio.

      Eliminar
  2. Muchas gracias por el tutorial, me has ayudado mucho con un proyecto, llevaba dos días atascado.

    Muchas gracias y un saludo a todos.

    ResponderEliminar
    Respuestas
    1. De nada Fran, un placer apoyar a la comunidad!

      Saludos

      Eliminar
  3. Hola, buenos dias, estuve realizando el tutorial, pero tenia unos cuantos errores, asi que descargue el proyecto de eclipse y el de arduino, pero no me detecta las clases:
    import com.android.future.usb.UsbAccessory;
    import com.android.future.usb.UsbManager;

    pude encontrar desde los paquetes de android:
    import android.hardware.usb.UsbAccessory;
    import android.hardware.usb.UsbManager;

    pero sigo teniendo unos cuantos errores con un getAccessory. Asi que me preguntaba si podrias pasarme el codico de tus clases UsbAccessory UsbManager para evitar estos errores.
    Saludos y gracias.

    ResponderEliminar
    Respuestas
    1. No deberías tener errores, lo único que puedo deducir es que posees alguna versión antigua de Eclipse, o el plugin Android esta fallando.

      Recomiendo que descargues el ADT Bundle (http://developer.android.com/sdk/index.html)

      Eliminar
    2. Muchas gracias, ya quedo.
      Saludos.

      Eliminar
    3. De nada, me da gusta saber eso Juan ;)

      Saludos

      Eliminar
    4. Bunas tardes tengo el mismo error como solucionarlo? gracias

      Eliminar
  4. ¿Cómo puedo solucionar este error?

    Device addressed... Requesting device descriptor.
    found possible device. swithcing to serial mode
    Data packet error: 5could not read device protocol version

    ResponderEliminar
  5. Muy buen aporte Hazael, bueno soy nuevo en esto y tengo unas cuantas dudas, finalizando las modificaciones de los códigos en el IDE de JAVA me salen 2 errores:

    (Description Resource Path Location Type
    error: Error: No resource found that matches the given name (at 'resource' with value '@xml/accessory_filter'). AndroidManifest.xml /ArduinoBlinkLED line 29 Android AAPT Problem
    )
    (Description Resource Path Location Type
    toggleButtonLED cannot be resolved or is not a field MainActivity.java /ArduinoBlinkLED/src/com/example/arduinoblinkled line 82 Java Problem)

    creo que son de librerías, segui paso a paso todo lo anterior a excepción de:

    Librearías para Arduino.
    Del repositorio que descargaste de Google copia las librerías necesarias al directorio de librearías de Arduino IDE:


    Copia los directorios:
    *android-accesories/adk1/board/AndroidAccesory
    *android-accesories/adk1/board/USB_Host_Shield
    a
    .../arduino-1.0.2/libraries/


    en este paso no hice nada al respecto debido a que no me quedo claro si eran para el arduino o para las de JAVA,

    ResponderEliminar
    Respuestas
    1. Hola amigo Anónimo.
      Creo que el error " Error: No resource found that matches the given name (at 'resource' with value '@xml/accessory_filter')"
      se debe a que no creaste el archivo accessory_filter.xml.

      Verifica eso.

      Lo de copiar las librerias del android-accesories al directorio de librerias de Arduino es para poder compilar el codigo de "Arduino" no el de Android.

      Saludos y éxito.

      Eliminar
    2. Agradezco tu respuesta inmediata, inicie de nuevo el tutorial con mas cuidado y ahora el error es otro y se manifiesta a partir de crear el archivo o File dentro de la carpeta xml que se crea antes en res, pongo el código y error se describe:

      Description Resource Path Location Type
      Premature end of file. accessory_filter.xml /ArduinoBlinkLED/res/xml line 1 Android XML Format Problem

      y me lleva hacia la primer linea del código del xml accessory_filter

      Eliminar
    3. Este comentario ha sido eliminado por el autor.

      Eliminar
  6. ya cree el proyecto como lo instalo en mi celular alguien me puede ayudar

    ResponderEliminar
  7. Estoy utilizando un motorola pro xt610 con android 2.3.6 , en el proyecto selecciono la version 10 , cuando instalo la app en mi celular, la instalación falla por: Package X requires unavailable shared library com.android.future.usb.accessory

    En teoria a partir de Android 2.3.4 esta disponible de Accessory
    El celular es de la empresa Personal de Argentina

    Cualquier ayuda te lo agracederie, he intentado con toda la info que pude encontrar y estoy pensando en cambiar de celular que ya tenga Android 3.1 ICS.
    Saludos y gracias

    ResponderEliminar
  8. Hola, gran aporte, soy un principiante y Eclipse me da un error en Accesory filter.xml : Final prematuro, ademas no encuentro el Mainactivity.java, te agradeceria mucho que me ayudes.
    Saludos

    ResponderEliminar
  9. Hola a todos y enhorabuena por el tutorial. Mi duda por si alguien supiera la posible razon es, instale la app en un tablet (Motorola Xoom 10.1) y el sketch en un arduino mega adk. El tablet me cambia de estado el boton pero no hace nada en el arduino. Alguien tiene alguna idea? De todos modos he de decir que no he tenido mucho tiempo para dedicar a la resolucion de este problema pero me pondre el proximo dia :)

    ResponderEliminar
  10. No sabes si se puede usar con un Arduino Uno sin ninguna shield ADK?

    ResponderEliminar
    Respuestas
    1. No, para hostear un dispositivo USB necesitas forsozamente el IC MAX3421e, por tanto ocupas una shield para usar cualquier Arduino que no tenga dicho IC.

      Eliminar
  11. ¿La comunicación es por medio de serial?, ¿no sabes como hacer una comunicación a través de internet?

    ResponderEliminar
  12. hola, estoy tratando de realizar la configuracion de android para ejecutar el codigo que aqui describes, pero en el paso # 2 No comprendo que se debe de hacer con las librerias de google, donde se usan o donde se colocan, espero tu respuesta. Saludos

    ResponderEliminar
    Respuestas
    1. Las librerias que descargas del repositorio de google, que son dos librerias creadas por google para la comunicación de dispositivos Android con Arduino.

      Dichas librerías son:

      *android-accesories/adk1/board/AndroidAccesory
      *android-accesories/adk1/board/USB_Host_Shield

      Estas librerías las debes de colocar en el directorio de librerías de la IDE de Arduino que estes usando para que puedas compilar el sketch y las puedes descargar de diversas maneras, por ejemplo, usando el link de sourceforge arriba mencionado ().

      Yo por ejemplo tengo la IDE de Arduino en:
      D:\SOFTWARE_tempo\arduino-1.0.2\
      por tanto debo copiar las librerías antes mencionadas a:
      D:\SOFTWARE_tempo\arduino-1.0.2\libraries\

      Eliminar
  13. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  14. hola amigo, sabes hise todo lo que esta en el tutorial no me da ningun error en los codigos pero cuando inicio la aplicacion me cambia el estado del boton pero no pasa nada, espero me respondas porfa ya estoy desesperado.

    ResponderEliminar
    Respuestas
    1. Habria que debuggear y ver que esta pasando.
      Conecta el Puerto del COM USB a la computadora (No el que conectas a tu dispositivo Android sino el otro) y abriendo el Serial Monitor.



      Modifica el codigo del loop():
      void loop()
      {
      byte msg[0];
      if (acc.isConnected()) {
      int len = acc.read(msg, sizeof(msg), 1); // read data into msg variable
      if (len > 0) {
      if (msg[0] == 1) // compare received data
      {
      Serial.println("Enciende");
      digitalWrite(LED_PIN,HIGH); // turn on light
      }
      else
      {
      Serial.println("Apaga");
      digitalWrite(LED_PIN,LOW); // turn off light
      }
      }
      }
      else
      {
      Serial.println("No conectado");
      digitalWrite(LED_PIN , LOW); // turn off light
      }
      }

      Y me dices que te arroja en el Serial Monitor.

      Eliminar
  15. hola que tal no he podido hacer funcionar mi arduino mega adk con android a travez de android studio por favor si alguien tiene informacion o un tutorial le agradesco gracias mi correo es fahernandez41@misena.edu.co

    ResponderEliminar
    Respuestas
    1. Hola.
      Este tuto cubre unicamente Eclipse ADT, tengo que actualizarlo para usar la nueva IDE Android Studio, asi que mientras tanto... intenta hacerlo con Eclipse y despues hacer la migracion http://developer.android.com/sdk/installing/migrate.html.

      Saludos!

      Eliminar
  16. hola. quisiera ayuda en como poder adquirir los datos de mi arduino y guardarlos en archivos .tex en una usb conectada al arduino adk

    ResponderEliminar
    Respuestas
    1. Qué onda Miguel.
      Sigue los pasos que propongo arriba para la conexión entre el Arduino y el Android Device.

      Ahora, coloca en alguna parte del código de Arduino: acc.write(data_to_send, 1);
      data_to_send son los caracteres que deseas enviar al Android Device.
      Captura esa información en tu código Java para Android y escribela en el archivo .txt, Android tiene muchas librerías para manejar archivos de texto, con mucha documentación.

      Aquí la librería AndroidAccesory:
      https://android.googlesource.com/device/google/accessory/arduino/+/abc5159a3ca9dbb5c7e364a1eab99901a4440ac5/AndroidAccessory/AndroidAccessory.h

      Saludos

      Eliminar
  17. hola .me gusto mucho el proyecto.esto funciona si al igual le colocamos varios leds???

    ResponderEliminar
  18. oie si no tengo un arduino mega ADK con cual otro puedo usar para poder probar tu codigo?? o sirve si tengo un arduino con una sola entrada usb??

    ResponderEliminar