Fuente: http://www.jalcdeveloper.com/projects/chapters/arduino-android-usb-cap1/
Buenas a tod@s, en este tutorial veremos como conectar un Arduino Leonardo con un móvil Android por USB.
Montaremos un circuito muy simple con un sensor de temperatura y humedad, que utilizaremos de ejemplo. Veremos un poco de conceptos sobre el USB OTG las diferentes clases de comunicación y crearemos una aplicación móvil, en la que podremos ver los valores de temperatura y humedad.
Para seguir este tutorial necesitaremos:
- Un Arduino Leonardo ( chip Atmega32u4 ) no sirve un Arduino Uno
- Un cable USB OTG
- Un cable MicroUSB a USB
- Un móvil Android versión 3.2 o superior.
- Un sensor de temperatura y humedad DHT22
- Una resistencia de 10k
Contents
- 1Porque un Arduino Leonardo
- 2¿ Que es USB CDC ?
- 3El USB OTG
- 4El sensor DHT22
- 5El circuito
- 6Sketch de Arduino
- 7Aplicación Android
- 8Diagrama de flujo App
- 9Variables
- 10PASO 1: Declarar BroadcastReveiver
- 11PASO 2: Detectar y solicitar permiso
- 12PASO 3: Conectar al Arduino
- 13PASO 4: Obtener Interface y Endpoints
- 14PASO 5: Enviar los mensajes de configuración
- 15PASO 6: Obtener datos
- 16Probando la App
- 17Conclusión
Porque un Arduino Leonardo
Para los que se preguntan por que usamos un Arduino Leonardo y no un Arduino UNO, se debe a que el Arduino Leonardo, tiene soporte nativo de USB con las clases de protocolo CDC y HID, encontra el Arduino UNO utiliza un chip separado que convierte de serie a USB. La programación seria distinta a la que mostramos en este tutorial.
¿ Que es USB CDC ?
El USB dispone de diferentes clases de protocolos de comunicación, según el dispositivo que conectemos. Tenemos básicamente cinco clases.
- ADC : Audio Device Class
- CDC: Comminication Device Class
- HID: Human Interface Device
- MSC: Mass Storage Class
- Custom Class
Sus nombres son bastante desciptivos, para nuestro proyecto nos interesa la clase CDC, esta clase emula un puerto serie y nos permite comunicar con la placa Arduino Leonardo de una manera muy sencilla. El Arduino Leonardo también soporta la clase HID, así que lo podríamos utilizar como si de un mouse o teclado se tratara. ¿ Alguien se anima a probarlo ? ( más info )
El USB OTG
Para aquellos que desconozcan que es el USB OTG, se trata de una extensión del USB 2.0 la cual tiene una mayor flexibilidad permitiendo que un dispositivo funcione como esclavo o maestro (host). Con otras palabras nos permite conectar cualquier dispositivo (pendrive, camaras, discos, arduino’s, … ) a nuestro móvil.
Para ello necesitaremos un cable USB OTG, el cual en un extremo tiene un conector microUSB que conectamos a nuestro móvil y en el otro extremo tiene un conector USB hembra, al que podremos conectar el cable USB del Arduino Leonardo. ( el mismo cable que utilizamos para programarlo).
Este tipo de cable lo podemos conseguir en cualquier tienda de electronica, centros comerciales o tiendas de móviles.
El sensor DHT22
Hemos elegido montar un sensor ambiental para dar un giro practico al tutorial, no entraremos en el detalle de su funcionamiento. Si cabe mencionar para aquellos que no lo conozcan, que se trata de un sensor de humedad y temperatura, muy fácil de utilizar ya que el mismo se encarga de convertir los valores en una señal digital, así que no necesitaremos utilizar pins analógicos, ni electrónica adicional pa
Para los que queráis profundizar en este sensor os dejo un par de enlaces, con muchísimas mas información
Datasheet – http://www.adafruit.com/datasheets/DHT22.pdf
Tutoriales sobre el sensor (Ingles) – https://learn.adafruit.com/dht
El circuito
El montaje del circuito es muy simple como podemos ver en el esquema, solo tenemos que alimentar el sensor y conectar el pin de datos al Arduino, junto a la resistencia pull-up de 10k.
Sketch de Arduino
El sketch del Arduino es muy simple ya que para enviar datos por el USB solo tenemos que utilizar la función Serial.print() o Serial.println().
La parte que tenemos que hacer algo mas complicada es la lectura del sensor de temperatura, lo primero es descargar la librería que nuestros amigos de Adafruit han preparado ( aquí ), esta nos permite leer los datos del sensor sin complicaciones. Una vez descargada descomprimiremos el zip, renombrados la carpeta que acabamos de descomprimir, con el nombre DHT y por ultimo la copiamos a la carpeta
En el entono de programación de Arduino copiaremos el siguiente código, y lo cargaremos en nuestro Arduino Leonardo.
#include "DHT.h" #define DHTPIN 2 #define DHTTYPE DHT22 DHT dht(DHTPIN, DHTTYPE); void setup() { Serial.begin(9600); dht.begin(); } void loop() { // Reading temperature or humidity takes about 250 milliseconds! // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) float h = dht.readHumidity(); float t = dht.readTemperature(); // check if returns are valid, if they are NaN (not a number) then something went wrong! if (isnan(t) || isnan(h)) { Serial.println("Failed to read from DHT"); } else { Serial.print("H:"); Serial.print(h); Serial.print(","); Serial.print("T:"); Serial.print(t); Serial.println(";"); } }
Antes de seguir comprobamos con el «monitor serie» que leemos correctamente el sensor, deberíamos de tener una lectura parecida a la de esta imagen:
Donde «H» indica la humedad y T indica la temperatura, prestar mucha atención a las «comas», «dos puntos» y «punto y como» ya que los utilizaremos para separar los valores.
Aplicación Android
Llega el momento que tod@s esperábamos, crear una aplicación Android que nos permite leer datos por USB desde nuestro Arduino.
Para poder realizarlo tendremos que seguir unos cuantos pasos:
- Obtener la lista de dispositivos conectados
- Obtener el dispositivo con el que queremos comunicar
- Solicitar permiso al usuario, para poder utilizarlo
- Obtener el Interface según la clase de comunicación que queramos usar. Para nuestro ejemplo la clase es la CDC.
- Obtener los Endpoints de entrada y salida para esta clase.
- Enviar los mensajes de configuración a nuestro Arduino Leonardo
- Por fin! Leer y escribir los datos que queramos.
Empezando por descargar el código fuente de ejemplo, completamente funcional, desde GitHub e importarlo a vuestro Eclipse:
NOTA: En las explicaciones omitiremos todas las partes no fundamentales, a la programación del USB.
Diagrama de flujo App
Variables
Para manejar la conexión USB necesitaremos las siguientes Variables.
// TODO: Variables USB UsbManager mUsbManager; UsbDevice mUsbDevice; PendingIntent mPermissionIntent; UsbDeviceConnection mUsbDeviceConnection; UsbEndpoint epIN = null; UsbEndpoint epOUT = null;
UsbManager
Esta variable nos permite manejar todo lo referente al USB de nuestro móvil asi como obtener una lista de dispositivos conectados.
UsbDevice
Con esta variables manejaremos un dispositivo concreto, de todos los que podamos tener conectados. Obtener su nombre, fabricante, versión, los protocolos e interfases que soporta, etc.
PendingIntent
La necesitaremos para llamar al Intent que solicita al usuario el permiso de uso del USB.
UsbDeviceConnection
Necesaria para conectar con el dispositivo USB que tengamos conectado.
UsbEndPoint
Por ultimo necesitamos este tipo de variable para poder comunicar con el dispositivo USB. Vienen a ser los caneles que disponen, pueden ser tanto de entrada como de salida de datos.
PASO 1: Declarar BroadcastReveiver
Declaramos un BroadCastReceiver, que se encarga de comprobar que el usuario acepta el permiso de uso del USB y tambien detecta cuando desconectamos el dispositivo USB para limpiar las variables.
// TODO: Al conectar a un dispositvo USB se solicita un permiso al usuario // este broadcast se encarga de recoger la respuesta del usuario. private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver(){ public void onReceive(Context context, android.content.Intent intent) { String action = intent.getAction(); // TODO: Al aceptar el permiso del usuario. if (ACTION_USB_PERMISSION.equals(action)){ synchronized (this) { //UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)){ Log.d(TAG, "Permiso aceptado"); processComunicationUSB(); }else{ Log.e(TAG, "Permiso denegado"); } } } // TODO: Al desconectar el dispositivo USB cerramos las conexiones y liberamos la variables. if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (device != null) { // call your method that cleans up and closes communication with the device } } } };
Como todos los BroadcastReceiver tenemos que registrarlos, por norma suelo hacerlo en el método onResume(), para asegurar que estos siempre se registran, ( no olvides hacer el unregisterReceiver en el método onPause())
@Override protected void onResume() { super.onResume(); //TODO: Solicitamos permiso al usuario si este esta pendiente mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); //TODO: Registro del Broadcast registerReceiver(mUsbReceiver, new IntentFilter(ACTION_USB_PERMISSION)); registerReceiver(mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED)); }
PASO 2: Detectar y solicitar permiso
El único botón que dispone nuestra app, programaremos el evento OnClick, para que realice la búsqueda de los dispositivos USB conectados. Una vez encontrado conectara con el primero y solicitara permiso al usuario para utilizarlo. Todo esto lo podemos hacer con este simple código:
// TODO: Boton Conectar. btn = (Button) findViewById(R.id.button1); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //TODO: Obtemos el Manager USB del sistema Android mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); // TODO: Recuperamos todos los dispositvos USB detectados HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList(); //TODO: en nuestro ejemplo solo conectamos un disposito asi que sera // el unico que encontraremos. Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); if(deviceIterator.hasNext()){ mUsbDevice = deviceIterator.next(); Log.d(TAG, "Name: " + mUsbDevice.getDeviceName()); Log.d(TAG, "Protocol: " + mUsbDevice.getDeviceProtocol()); //TODO: Solicitamos el permiso al usuario. mUsbManager.requestPermission(mUsbDevice, mPermissionIntent); }else{ Log.e(TAG, "Dispositvo USB no detectado."); } } });
Si el usuario acepta el permiso se ejecuta la función processComunicationUSB(), veamos que pasos cumple esta función.
PASO 3: Conectar al Arduino
El primer paso que realiza nuestra función processComunicationUSB() es conectar al Arduino
// TODO: Conectar al dispositivo (Arduino) mUsbDeviceConnection = mUsbManager.openDevice(mUsbDevice); if(mUsbDeviceConnection == null){ Log.e(TAG, "No se ha podido conectar con el dispositivo USB."); finish(); }
PASO 4: Obtener Interface y Endpoints
Anteriormente vimos que el usb tiene diferentes clases de comunicación ( CDC, HID, etc. ) en el framework de Android esto son los llamadas interfases. Destras de las interfases y dependiendo de la clase estan los enpoints que vendrian a ser los caneles de comunicación que dispone la clase. Como comunicaremos con un Arduino Leonardo obtenemos el interfase de clase CDC y los endpoints necesitaremos, con el siguiente código.
// TODO: getInterfase(1) Obtiene el tipo de comunicacion CDC (USB_CLASS_CDC_DATA) UsbInterface mUsbInterface = mUsbDevice.getInterface(1); // TODO: Obtenemos los Endpoints de entrada y salida para el interface que hemos elegido. for (int i = 0; i < mUsbInterface.getEndpointCount(); i++) { if (mUsbInterface.getEndpoint(i).getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) { if (mUsbInterface.getEndpoint(i).getDirection() == UsbConstants.USB_DIR_IN) epIN = mUsbInterface.getEndpoint(i); else epOUT = mUsbInterface.getEndpoint(i); } }
NOTA: En caso de que queráis investigar con otros dispositivo USB que no sea un Arduino Leonardo, este punto un poco confuso. Os recomiendo utilizar las funciones getClass() del UsbInterface para saber con que clases admite trabajar el dispositivo que estéis trasteando.
PASO 5: Enviar los mensajes de configuración
Para los que estamos acostumbrados a trabajar con comunicación serie, esta parte puede ser un poco rara. El protocolo USB dispone de unos comandos que podemos enviar del Host al Device para indicarle como nos vamos a comunicar. En este caso le enviamos dos mensajes al Arduino, uno indicando la configuración de velocidad, bits, pariedad etc. y otro mensaje mas para que active la linea DTR.
mUsbDeviceConnection.claimInterface(mUsbInterface, true); // TODO: Mensaje de configuración para el Device. int baudRate = 115200; byte stopBitsByte = 1; byte parityBitesByte = 0; byte dataBits = 8; byte[] msg = { (byte) (baudRate & 0xff), (byte) ((baudRate >> 8) & 0xff), (byte) ((baudRate >> 16) & 0xff), (byte) ((baudRate >> 24) & 0xff), stopBitsByte, parityBitesByte, (byte) dataBits }; mUsbDeviceConnection.controlTransfer(UsbConstants.USB_TYPE_CLASS | 0x01, 0x20, 0, 0, msg, msg.length, 5000); // (UsbConstants.USB_TYPE_CLASS | 0x01) 0x21 -> Indica que se envia un parametro/mensaje del Host al Device (movil a la placa leonardo) // 0x20 -> paramtro/mensaje SetLineCoding mUsbDeviceConnection.controlTransfer(UsbConstants.USB_TYPE_CLASS | 0x01, 0x22, 0x1, 0, null, 0, 0); // (UsbConstants.USB_TYPE_CLASS | 0x01) 0x21 -> Indica que se envia un parametro/mensaje del Host al Device (movil a la placa leonardo) // 0x22 -> paramtro/mensaje SET_CONTROL_LINE_STATE (DTR) // 0x1 -> Activado.
Si tenéis curiosidad o quereis profundizar más en estos comandos del USB os dejo este enlace: http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
PASO 6: Obtener datos
Siguiendo todos los pasos anteriores solo nos queda crear un clase AsynTask, que nosotros hemos llamado UpdateHumidityTemperature, que se encargara de obtener y tratar los datos que recibimos por el USB. La parte fundamental del código son estas lineas:
int bufferMaxLength=epIN.getMaxPacketSize(); ByteBuffer mBuffer = ByteBuffer.allocate(bufferMaxLength); UsbRequest inRequest = new UsbRequest(); inRequest.initialize(mUsbDeviceConnection, epIN); while(inRequest.queue(mBuffer, bufferMaxLength) == true){ mUsbDeviceConnection.requestWait(); ..... ..... .....
Creamos e inicializamos una petición con UsbRequest en el enpoint de entrada de datos ( Arduino -> móvil ) , la siguiente instrucción «queque» indicaremos las variables de buffer donde se guardaran los datos que recibimos y por ultimo con requestWait esperaremos a rebir datos desde el USB.
Probando la App
Llego el momento de la verdad y si no hemos cometido fallos conectaremos la placa Arduino Leonardo al móvil con un cable USB OTG, arrancamos la aplicación «TestUSB2Android» y veremos la siguiente pantalla.
Pulsamos el botón conectar y nos el sistema nos solicitara que demos permiso para usar el USB
Pulsamos sobre aceptar y eureka!!!! ya tenemos en la pantalla del móvil la temperatura y humedad.
Si abrimos el LogCat, podemos ver como recibimos desde el Arduino la actualización de la temperatura y humedad.
Conclusión
Parece un proceso muy complicado, pero una vez lo hemos ello una vez se adopta muy bien la mecánica de su funcionamiento. Espero que os guste este microproyecto y que os aventureis ha hacer vuestros proyectos con conexión USB. Cualquier duda que tengais dejar un comentario, será bienvenido.
Fuente: http://www.jalcdeveloper.com/projects/chapters/arduino-android-usb-cap1/
Me gustaría saber si es posible realizarlo para arduino mega ya que he intentado pero no he podidio, quisiera saber como debo hacer la comunicación para que solo escuche.
Hola Hans, te recomendamos que preguntes en el artículo original http://www.jalcdeveloper.com/projects/chapters/arduino-android-usb-cap1 Este sólo es una copia, por interés de Hackeando el Genoma.
Hola Hans me gustaria saber si lo has conseguido, ya que tengo la misma duda pero con ARDUINO MEGA ADK
Buenas, me gusto mucho tu articulo, muy bien explicado, pero en el momento necesito desarrollar un proyecto que lea datos de una bascula por medio del cable serial rs23. obviamente necesito un adaptador de serial a mini USB, pero no he podido encontrar mas información que me ayude,te estaría muy agradecido si me puedes colaborar con mi proyecto.
Muchas Gracias y saludos.
Hola Javier, te recomendamos que preguntes en el artículo original http://www.jalcdeveloper.com/projects/chapters/arduino-android-usb-cap1 Este sólo es una copia, por interés de Hackeando el Genoma.
Hola. donde iría el código del paso 4?
Hola Sebastian, te recomendamos que preguntes en el artículo original http://www.jalcdeveloper.com/projects/chapters/arduino-android-usb-cap1 Este sólo es una copia, por interés de Hackeando el Genoma.
Cuales serian los pasos para realizar este mismo proyecto pero utilizando el Arduino Uno. Necesito ayuda por favor.
Hola Raúl, te recomendamos que preguntes en el artículo original http://www.jalcdeveloper.com/projects/chapters/arduino-android-usb-cap1 Este sólo es una copia, por interés de Hackeando el Genoma.
Interfaz Java y Arduino.
Tutorial diseño de interfaz con Java bajo NetBeans para controlar Arduino desde el puerto serie / USB, odrás encender y apagar un Led, recibir mensajes de textos o comandos desde Arduino.
Ver tutorial.
http://www.slideshare.net/Metaconta2/interfaz-java-y-arduino
Saludos.
HAY Q CONFIGURAR EL CELULAR EN MODO «DESARROLLADOR» ???
parece q ya no responden consultas, cerraron la pagina de jalc. probe ell programa y no funciona, tenia varias consultas
Por fin!! Para que ellos que preguntan si sirve para otros modelos de Arduino, les respondo que si, funcionaría con cualquier Arduino que soporte USB, y desde Android que disponga o soporte OTG (tendría que ser muy viejo el teléfono o la tableta para que no lo soporte). Parte de la información, como entablar la comunicación por OTG en Android ya la tenía, pero en esta página he encontrado la información relacionada a la configuración, que me ha servido mucho, gracias equipo de «HackeandoELGenoma».
Gracias @WhiteSkull !
Hola como estas, me gustaria saber si tienes algun ejemplo para iniciar con un proyecto similar al que proponen aqui, gracias de antemano.
rarojas82 » arroba » misena.edu.co