RESUMEN En este trabajo plasmamos las acciones para realizar un programa que controla servomotores con un dispositivo móvil, de la electrónica y de la programación de android Con respecto a la electrónica describimos los elementos necesarios para este proyecto y como conectarlos, también el programa que controla toda la electrónica, Señalizamos esquemas e imágenes para su mejor compresión. En la parte de la programación de android, explicamos los requerimientos mininos para realizarlo, encontraran puntos como instalación de las herramientas para realizar la tarea, la forma de programar, variables, métodos y llamados. Insertamos varias imágenes ilustrando los pasos realizados, en la preparación de las herramientas y en la conformación del programa En la parte de los anexos están todos los códigos de MPIDE y de ECLIPSE realizados para completar la meta, solo son códigos no contiene ilustraciones. 1 OBJETIVO. 3 MARCO TEÓRICO 3 DESARROLLO 4 MATERIALES Placa Chip KIT Uno32 Puerto Bluetooth Protoboard Servo motores Dispositivo Móvil 4 4 4 4 4 4 Programación chip KIT Uno32 Hardware Software Bibliotecas Variables 5 5 5 6 6 Programación Android 13 RESULTADOS 30 CONCLUSIONES 31 BIBLIOGRAFÍA 31 ANEXO 33 Código de Android 33 Codigo MPIDE 42 2 Objetivo. Disponer de un sistema de software y hardware que permita controlar 5 servomotores con una aplicación desarrollada para un dispositivo móvil con Sistema operativo Android. Uno de estos motores deberá ser controlado mediante las señales del acelerómetro del dispositivo móvil. Marco Teórico Este proyecto abarca aspectos tanto de electrónica como de computación, ya que tiene como objetivo controlar servomotores, de manera remota, mediante el uso de un puerto Bluetooth. La aplicación conjunta los sistemas Android y Arduino. El sistema Arduino fue programado para recibir y enviar los datos que permitirán controlar los servomotores. Un dispositivo móvil con Sistema Operativo Android y con un acelerómetro contiene los programas para enviar la información de control. Los programas desarrollados para la aplicación del dispositivo móvil fueron hechos con el lenguaje de programación Java y con el ambiente de desarrollo integrado (IDE) Eclipse. Se usa un chip KIT Uno32, que es completamente compatible con la tarjeta Arduino, para las funciones de control y comunicación. La aplicación se realizó con el ambiente de desarrollo multiplataforma Arduino (MPIDE). La aplicación es bastante eficiente ya que puede controlar hasta 5 servo motores independientes, y la conexión entre ambos dispositivos es bastante rápida; uno de los servomotores será controlado con los datos que envía el dispositivo móvil de acuerdo a la información generada por el acelerómetro. 3 Desarrollo MATERIALES Placa Chip KIT Uno32 La placa Chip KIT Uno32, es una herramienta muy útil para la programación y control de dispositivos electrónicos. Esta es de software libre, no se requiere de licencias de ningún tipo para hacer uso de ella. Es posible realizar cuantas aplicaciones necesitemos y funciona con muchas herramientas de los sistemas Arduino. Otra ventaja es que existe una gran cantidad de documentación que ayuda en el desarrollo de aplicaciones. Puerto Bluetooth El puerto se denomina HC-06. Este se encuentra en un clico de 9600bps y está configurado como esclavo; estas opciones se configuran de acuerdo con la aplicación se está creando. La configuración de sincronización también se puede personalizar Protoboard Necesitamos una placa protoboard para la conexión de los diferentes dispositivos como los puerto bluetooth, indicadores (led) e interruptores para su funcionamiento. Servo motores Motores que controlan la posición y el sentido de giro. La precisión de la posición puede variar para distintos servo motores y el rango del movimiento puede ir de 0 a 180 grados o de 0 a 360 grados. Dispositivo Móvil Cualquier dispositivo que tenga el sistema operativo android puede ser una Tableta o un celular, la aplicación diseñada y programada se ejecuta en cualquier dispositivo con el Sistema Operativo Android. Empezando en la versión 2.2 hasta la versión 4.02. El dispositivo debe contar con sensor de acelerómetro ya que la aplicación aprovecha estos sensores para enviar señales de movimiento a los servo-motores. 4 Programación chip KIT Uno32 Hardware Empezaremos explicando los elementos básicos del sistema Arduino. Es una plataforma dirigida a electrónica la cual ayuda a controlar señales digitales y analógicas tanto de entrada como de salida, la plataforma contiene un chip en el cual se realiza la aplicación, se guarda para su uso posterior. Cuenta con 11 entradas analógicas y 39 salidas digitales estas también tienen la opción usarse como entradas digitales, también cuenta con 5 puertos PWM, los que en versiones anteriores ejecutan la señal tipo cuadrada que controla servo-motores. En las más recientes se usa la biblioteca SERVO, de esta forma cualquier puerto de salida puede controlar servo-motores, no sólo los puertos PWM La edición del programa utiliza el puerto USB, la alimentación de voltaje es de 5v y 3.3v. Para trabajar con voltaje mayores será necesaria una fuente de alimentación externa y configurar la tarjeta para aceptar este voltaje. Software Usamos la Multiplataforma Arduino IDE(MPIDE) versión libre. Este software tiene las mismas bibliotecas de funciones y aplicaciones que un programa para Arduino. El lenguaje es similar al "Lenguaje C". Usamos la misma sintaxis y para declarar variables aunque cambia es la forma de definir bibliotecas y constantes. Para realizar una aplicación necesitamos dos métodos indispensables: void setup. Donde declaramos variables globales y/o inicializar las variables que usaremos para el resto del programa, establecemos configuraciones necesarias para el programa y periféricos para su funcionamiento. void loop. Método de ciclo infinito lo que se programe aquí se reproducirá siempre, también podemos contar con variables locales, usar las globales y llamar a otros métodos. En este se pueden declarar métodos como en "Lenguaje C", sean procesos que no regresan resultados o que si regresen algún valor. 5 Bibliotecas Incluimos la biblioteca de este modo: #include <servo.h>. Esto para construir objetos de tipo “servo” mismos que se encargan de mandar la señal de onda cuadrada para el control de movimiento del servo. Para el puerto Bluetooth no es necesario declarar bibliotecas. Variables Tipo char: Las variables “data1” y ”data2” servirán para la recepción de datos que llegan por el puerto Bluetooth. Tipo entero: Las variables “motor1”, “motor2”, “motor3”, “motor4”, “motor5” se inician con valor 0 y sirven para identificar el motor que estamos controlando. Sólo podemos controlar un motor a la vez. Tipo entero: Las variables “m1”, “m2”, “m3”, “m4”, “m5” tendrán valor 2, 3, 4, 5 y 6 respectivamente, son puertos de salida digital, permite la salida a los servomotores por la biblioteca anteriormente incluida. Tipo entero: Las variables “motor1_pos”, “motor2_pos”, “motor3_pos”, “motor4_pos”, “motor5_pos”, guardarán la última posición de cada servo. Esto evita algún movimiento no solicitado en los servos y saber cuando el motor correspondiente llega a su límite. Tipo servo: “miservo1”, “miservo2”, “miservo3”,”miservo4” y “miservo5” son para controlar mediante las terminales de salida a los correspondientes servos. Si utilizamos uno para todos los servo motores existirá una mezcla de posiciones y movimientos involuntarios, cada objeto mantiene la posición actual de un motor. La variable “miservoX” deben vincular un puerto de salida al objeto servo utilizando, por ejemplo, “miservo1.attach(m1)”. Una vez creado el vinculo en el método setup se inicia la posición de cada motor mediante la sentencia miservo1.write(pos), en "pos" ponemos la posición en grados. Sólo acepta valores enteros, en un rango de 0 a 360 grados dependiendo del tipo de motor. Existen algunos motores que comprenden rango de 0 a 180 grados. También se declara Serial.begin(9600) esto es la frecuencia de comunicación del puerto Bluetooth que instalamos en la placa chip KIT Uno32. 6 La declaración del método loop. utilizamos data1 para recibir el primer valor del puerto Bluetooth como sigue data1=Serial.read(), El puerto de comunicación toma datos en serie. El dato de entrada lo tenemos en data1 y es un tipo char, sólo podemos recibir un dato por recepción. Utilizamos "if" para usar los datos de entrada, si es orden de movimiento podemos regresar un mensaje de error, en caso de seleccionar un motor mandaremos llamar un método selector motor if(data1 == '1'){ Serial.write("0"); } if(data1 == '2'){ Serial.write("0"); } else{ selectormotor(data1); } Siguiendo la información del dato recibido ejecutamos el proceso adecuado que controla un motor en particular. Debemos crear 5 métodos, es decir, un método para cada servo. Los nombres serán: servo1, servo2, servo3, servo4 y servo5 respectivamente. El cuerpo de estos procesos será muy similar. Cada uno de ellos contiene un ciclo infinito para poder ejecutar más de un movimiento, se obtiene el dato de entrada y se ocupa la condicional "IF" para saber el movimiento a realizar. Para el dato 1 o 2 procede a hacer rotación. Ésta se realiza de un modo suave desplazándose 2 grados en cada paso como se muestra a continuación: delay(2); while(1){ comprobación(); data2 = Serial.read(); } if(data2 == '1'){ } if(motor1_pos < max){ for(i=0;i<N;i++){ motor1_pos +=2; } if(data2 == '2'){ if(motor1_pos > min){ miservo1.write(motor1_pos); for(i=0;i<N;i++){ 7 } motor1_pos -=2; } miservo1.write(motor1_pos); else{ delay(2); selectormotor(data2); comprobación(); } } } Lo anterior contempla el ejemplo de mover 10 grados un servo. Estas líneas se deben repetir en cada subproceso servo. Mostramos el código para el programa que controla los servos en la chip kit Uno32. #include <Servo.h> pinMode(salida,OUTPUT); int N=5; digitalWrite(salida,HIGH); char data1; miservo1.attach(m1); char data2; miservo2.attach(m2); int motor1_pos = 0; miservo3.attach(m3); int motor2_pos = 0; miservo4.attach(m4); int motor3_pos = 0; miservo5.attach(m5); int motor4_pos = 0; miservo1.write(motor1_pos); int motor5_pos = 0; miservo2.write(motor2_pos); int m1 = 2; miservo3.write(motor3_pos); int m2 = 3; miservo4.write(motor4_pos); int m3 = 4; miservo5.write(motor5_pos); int m4 = 5; int m5 = 6; } int max = 180; void loop(){ int min = 0; data1 = Serial.read(); int salida = 13; if(data1 == '1'){ Serial.write("0"); Servo miservo1; Servo miservo2; } Servo miservo3; if(data1 == '2'){ Serial.write("0"); Servo miservo4; } Servo miservo5; else{ selectormotor(data1); } void setup(){ } void servo1(){ Serial.begin(9600); int i; 8 comprobación(); while(1){ data2 = Serial.read(); } if(data2 == '1'){ } if(motor1_pos < max){ } for(i=0;i<N;i++){ if(data2 =='2'){ motor1_pos +=2; if(motor2_pos > min){ miservo1.write(motor1_pos); for(i=0;i<N;i++){ delay(2); motor2_pos -=2; comprobación(); miservo2.write(motor2_pos); } delay(2); } comprobación(); } if(data2 == '2'){ } if(motor1_pos > min){ } for(i=0;i<N;i++){ } motor1_pos -=2; else{ miservo1.write(motor1_pos); selectormotor(data2); delay(2); comprobación(); } } } } } } else{ void servo3(){ selectormotor(data2); int i; while(1){ } data2 = Serial.read(); } if(data2 == '1'){ } if(motor3_pos < max){ void servo2(){ for(i=0;i<N;i++){ motor3_pos +=2; while(1){ miservo3.write(motor3_pos); int i; data2 = Serial.read(); delay(2); if(data2 == '1'){ comprobación(); if(motor2_pos < max){ } for(i=0;i<N;i++){ } motor2_pos+=2; } miservo2.write(motor2_pos); if(data2 =='2'){ delay(2); 9 } if(motor3_pos > min){ } for(i=0;i<N;i++){ } motor3_pos -=2; else{ miservo3.write(motor3_pos); selectormotor(data2); delay(2); comprobación(); } } } } } void servo5(){ } int i; else{ while(1){ selectormotor(data2); data2 = Serial.read(); if(data2 == '1'){ } if(motor5_pos < max){ } for(i=0;i<N;i++){ } motor5_pos +=2; void servo4(){ miservo5.write(motor5_pos); int i; delay(2); while(1){ comprobación(); data2 = Serial.read(); if(data2 == '1'){ } if(motor4_pos < max){ } for(i=0;i<N;i++){ motor4_pos +=2; } if(data2 =='2'){ miservo4.write(motor4_pos); if(motor5_pos > min){ delay(2); for(i=0;i<N;i++){ comprobación(); motor5_pos -=2; miservo5.write(motor5_pos); } delay(2); } comprobación(); } if(data2 =='2'){ } if(motor4_pos > min){ } for(i=0;i<N;i++){ motor4_pos -=2; } else{ miservo4.write(motor4_pos); selectormotor(data2); delay(2); comprobación(); } 10 break; } case '7': } servo5(); void selectormotor(char id){ break; switch(id){ } case '3': servo1(); break; } void comprobación(){ int i; case '4': for(i=0; i<10; i++){ servo2(); digitalWrite(salida,LOW); break; delay(20); case '5': digitalWrite(salida,HIGH); servo3(); delay(20); break; } case '6': servo4(); } Los métodos que contemplamos son • • • Movimiento del servo Selección de servo Comprobación Este último envía la señal de confirmación Procedemos a conectar todos los dispositivos. La placa dispone de puertos de VCC (corriente) y GND (tierra). La tarjeta se conecta como se muestra a continuación. 11 La configuración del voltaje de la placa es un paso impostarte cuyo fin es que las conexiones funcionen, el puerto bluetooth funciona con 3.3v o 5v. El servo motor, se alimenta de un amperaje mayor al de la placa y por ello debe conectarse a corriente extra. 12 Programación Android Para esto ocupamos la versión 2.2 o posteriores, la programación se realiza en Eclipse IDE, este es libre (sin licencia) y se puede descargar de la página http://www.eclipse.org/downloads/ donde existen varias versiones. No requiere instalación. En el directorio hay un archivo ejecutable, el cual se encargará de la instalación. Debemos instalar previamente la versión del JDK de Java que podemos encontrar http://www.oracle.com/technetwork/java/javase/downloads/index.html Otro requisito será instalar los elementos necesarios para programar en Android. Comenzamos la explicación de instalar el SDK de Android en eclipse. Hacemos un clic en el menú Help y seleccionamos Install new software así saldrá una ventana como la que sigue Al Seleccionar Add aparecerá la ventana siguiente: 13 Ponemos el Plugin a instalar Android-SDK, y proporcionaremos una dirección para que este la descargue e instale, https://dl-ssl.google.com/android/eclipse/. El sistema muestra lo siguiente: Selecciona OK. Aparecen dos opciones que hay que seleccionar, para instalar el Plugin de Android, quedando la siguiente ventana: 14 Hacemos clic en el botón Next, hasta terminar con el proceso de instalación. Una vez concluido el proceso será necesario reiniciar el IDE Eclipse. La ventana siguiente es para instalar las herramientas y obtener lo necesario para programar en versiones de Android hasta 4.1. Seleccionamos el menú Window y la opción Android SDK manager aparece la pantalla siguiente: 15 En esta podemos seleccionar las SDK Platform, plataformas de diferentes versiones de Android, debemos contar con estas para usar las herramientas y opciones de las últimas versiones de Android. Con esto terminamos la instalación. Ahora procedemos a realizar la aplicación para poder lograr una conexión Bluetooth y enviar datos que se registren en puerto de arduino. Seleccionamos el menú file, opción new. Aparece la ventana siguiente: Selecciona Android Application Project, esta opción crea una proyecto de una aplicación Android y muestra la siguiente ventana 16 En esta ventana debemos proporcionar un nombre así como una versión mínima de Android para usar la aplicación que vamos a crear seleccionamos siguiente y aparece la ventana siguiente: En esta pantalla se puede personalizar el tipo de imagen y el tamaño que tendrá nuestra aplicación como icono para ser llamado, los que son valores dados por omisión usan las caritas mismas que pueden cambiar de color. 17 En el siguiente paso aparece la ventana siguiente: En esta opción podemos cambiar el nombre a la actividad esta es la que aparece en las siguientes carpetas, como el nombre que tendrá el acceso de la aplicación, por último presionamos Finish y aparece nuestro proyecto en el explorador de paquetes Aparece esta ventana donde se crea el proyecto. 18 La carpeta tiene archivos que explicaremos paso a paso. Uno de los más importantes, AndroidMainfest.xml es un archivo principal del proyecto. En él se alojan los permisos para usar las diferentes herramientas, como nombres de Layout. Los identificadores de estas y los nombres de las actividades. Se recomienda que este no se altere más de lo necesario, ya que puede causar errores que serán difíciles de encontrar. A este debemos agregar las líneas para el permiso de trabajar con dispositivos Bluetooth y lograr la conexión. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH" /> Estas líneas garantizan que podemos trabajar con adaptadores Bluetooth. Para el uso del acelerómetro no se requieren permisos adicionales. La carpeta siguiente es la carpeta Res. En esta habrá varias carpetas como se muestra en la siguiente imagen: Las importantes son layout y valúes, en layout se encuentran las ventanas de salida, las que mostrará nuestra aplicación, se crean tantos archivos layout como vistas deseamos mostrar, la forma de crear los layout es con clic en el botón derecho sobre la carpeta layout, seleccionando new other y aparece la ventana siguiente: 19 Seleccionamos Android XML Layout file, posteriormente hay que dar el nombre con el cual se conocerá el layout. Tendiendo las dos vistas que necesitamos, debemos agregar botones y algunas herramientas. Contaremos con 7 botones como se muestra en la imagen, así también con un list view para los mensajes del control de la aplicación. 20 Se deberá disponer de otro layout para el menú para que podamos mostrar todas las conexiones posibles como lo muestra la siguiente imagen: Esta contiene un list view que sirve para mostrar la lista de los dispositivos que están vinculados previamente. Con esto programamos el cuerpo de la aplicación Nos ubicamos en la carpeta SRC es donde se encuentran los archivos de android java proyecto que será una imagen como la siguiente: 21 En la imagen ubicamos y abrimos el archivo ConexionBluetooth.java esta está vinculada al layout main.xml que es la principal ventana que se ejecuta cuando abre la aplicación. Todo lo que realicemos sobre el archivo se ejecuta al inicio de la aplicación si lo deseamos. Empezamos a definir las variables globales necesarias para la aplicación. int curX =0,prevX=0; int curY=0,prevY=0; int curZ=0,prevZ=0; //variables para identificar movimiento en un tiempo long last_update=0,last_movement=0; private static final String TAG = "BluetoothChat"; private static final Boolean D = true; // tipos de mensaje public static final int MESSAGE_STATE_CHANGE = 1; public static final int MESSAGE_READ = 2; public static final int MESSAGE_WRITE = 3; public static final int MESSAGE_DEVICE_NAME = 4; public static final int MESSAGE_TOAST = 5; public static final String DEVICE_NAME = "device_name"; public static final String TOAST = "toast"; private static final int REQUEST_CONNECT_DEVICE = 1; private static final int REQUEST_ENABLE_BT = 2; // la vistas private TextView mTitle; private ListView mConversationView; //variables de los botones que controlan y envían private Button btn_r; private Button btn_l; private ToggleButton Servo_1; private ToggleButton Servo_2; private ToggleButton Servo_3; private ToggleButton Servo_4; private ToggleButton Servo_5; private int motor_accionado =0; Integer valor = 0; private String mConnectedDeviceName = null; private ArrayAdapter<String> mConversationArrayAdapter; private StringBuffer mOutStringBuffer; private BluetoothAdapter mBluetoothAdapter = null; private ConexionBluetoothService mChatService = null; Para que se ejecute cuando la aplicación abra sobrescribimos el método ONSTAR, queda como sigue: 22 public void onStart() { super.onStart(); if(D) Log.e(TAG, "++ ON START ++"); if (!mBluetoothAdapter.isEnabled()) { Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, REQUEST_ENABLE_BT); } else { if (mChatService == null) setupChat(); } } Verificamos si hay puerto bluetooth en el móvil, posteriormente hacemos la activación con el objeto intent luego con uso del starActivityforResult, en este se pasa como parámetro un intent y una constante que es la necesaria para verificar si la conexión está activada, después se pone un texto de activación del puerto Bluetooth del móvil. Crearemos el menú de opciones con las siguientes líneas. public Boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.option_menu, menu); return true; } Con esto hacemos que el botón menú tenga función. Si no se declara esto por más que se oprima no realizará ninguna acción, esto igual para las versiones 4.2 de Android, en las líneas hacemos que el botón aparezca en la aplicación. public Boolean onOptionsItemSelected(MenuItem item) { // TODO Auto-generated method stub switch(item.getItemId()){ case R.id.menu_conexiones: Intent about = new Intent(this, MenuActivity.class); startActivity(about); return true; } return false; } Seleccionando menú ejecuta la vista activity_conexion_android, para esta se crea un proyecto java android, lo llamaremos MenuActivity.java, se realiza la programación para mostrar los bluetooth previamente vinculados al móvil. 23 Pasamos a la creación de MenuActivity.java, mencionamos las variables más importantes: private final BluetoothAdapter mAdapter; mAdapter es de tipo bluetoothAdapter. Es un objeto que tiene los métodos para conectar y activar los puertos Bluetooth El siguiente método onCreate, se inicializa al momento de acceder a Device, la que muestra las conexiones previamente vinculadas. protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_ INDETERMINATE_PROGRESS); setContentView(R.layout.device_list) ; setResult(Activity.RESULT_CANCELED); Button scanButton = (Button) findViewById(R.id.button_scan); scanButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { doDiscovery(); v.setVisibility(View.GONE); } }); mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name); mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name); ListView pairedListView = (ListView) findViewById(R.id.paired_devices); pairedListView.setAdapter(mPairedDev icesArrayAdapter); pairedListView.setOnItemClickListene r(mDeviceClickListener); ListView newDevicesListView = (ListView) findViewById(R.id.new_devices); newDevicesListView.setAdapter(mNewDe vicesArrayAdapter); newDevicesListView.setOnItemClickLis tener(mDeviceClickListener); IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_ FOUND); this.registerReceiver(mReceiver, filter); filter = new IntentFilter(BluetoothAdapter.ACTION _DISCOVERY_FINISHED); this.registerReceiver(mReceiver, filter); mBtAdapter = BluetoothAdapter.getDefaultAdapter() ; Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices(); if (pairedDevices.size() > 0) { findViewById(R.id.title_paired_devic es).setVisibility(View.VISIBLE); for (BluetoothDevice device : pairedDevices) { mPairedDevicesArrayAdapter.add(devic 24 e.getName() + "\n" + device.getAddress()); } } else { String noDevices = getResources().getText(R.string.none _paired).toString(); mPairedDevicesArrayAdapter.add(noDev ices); } } Lo anterior realiza un llenado de un array con datos de los puertos que están vinculados al móvil. Los muestra en orden en un listview. Obtenida la lista creamos un setonitemclicklistener que es el método que escucha cuando seleccionamos una opción, se actualización los datos para la conexión. Esta se realiza por hilos sincronizados, se extiende de thread y debe tener métodos de run, para que su ejecución. private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mainstream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket) { Log.d(TAG, "create ConnectedThread"); mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { Log.e(TAG, "temp sockets not created", e); } } mainstream = tmpIn; mmOutStream = tmpOut; public void run() { Log.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[1024]; int bytes; while (true) { try { bytes = mmInStream.read(buffer); mHandler.obtainMessage(ConexionBluet ooth.MESSAGE_READ, bytes, -1, buffer) .sendToTarget(); e) { } catch (IOException "disconnected", e); connectionLost(); } } Log.e(TAG, break; } Esto crea la conexión y también crea el buffer de entrada y salida para el envío de datos. Creamos los clic listener de los botones que envían una señal cuando el usuario da clic en algún botón de la aplicación. btn_r = (Button) findViewById(R.id.btn_der); btn_r.setOnClickListener(new OnClickListener() { 25 public void onClick(View v) { sendMessage("1"); } }); btn_l = (Button) findViewById(R.id.btn_izq); btn_l.setOnClickListener(new OnClickListener() { onClick(View v) { public void sendMessage("2"); } }); Servo_1 = (ToggleButton) findViewById(R.id.Servo_1); Servo_1.setOnClickListener(new View.OnClickListener() { onClick(View v) { public void if(Servo_1.isChecked()){ limpiarmotor(motor_accionado); sendMessage("3"); } }); Servo_3 = (ToggleButton) findViewById(R.id.Servo_3); Servo_3.setOnClickListener(new View.OnClickListener() { onClick(View v) { limpiarmotor(motor_accionado); sendMessage("5"); motor_accionado = 3; } } }); Servo_4 = (ToggleButton) findViewById(R.id.Servo_4); Servo_4.setOnClickListener(new View.OnClickListener() { v) { public void onClick(View v) { if(Servo_2.isChecked()){ limpiarmotor(motor_accionado); public void onClick(View if(Servo_4.isChecked()){ limpiarmotor(motor_accionado); } Servo_2.setOnClickListener(new View.OnClickListener() { public void if(Servo_3.isChecked()){ motor_accionado = 1; } }); Servo_2 = (ToggleButton) findViewById(R.id.Servo_2); } sendMessage("6"); motor_accionado = 4; } } }); Servo_5 = (ToggleButton) findViewById(R.id.Servo_5); Servo_5.setOnClickListener(new View.OnClickListener() { v) { public void onClick(View if(Servo_5.isChecked()){ sendMessage("4"); limpiarmotor(motor_accionado); motor_accionado = 2; sendMessage("7"); 26 motor_accionado = 5; } } }); Envían cada dato usando sendMessage(). Otra acción que realiza es la condición if(servo_i.ischecked) es para no realizar alguna acción cuando el botón se encuentra apagado solo cuando esta encendido. Otra variable es motor_accionado con ella registramos las acciones de los botones, para reiniciarla usamos el proceso limpiarmotor. void limpiarmotor(int motor){ switch (motor) { case 1: Servo_1.setChecked(false); break; case 2: Servo_2.setChecked(false); break; case 3: Servo_3.setChecked(false); break; case 4: Servo_4.setChecked(false); break; case 5: Servo_5.setChecked(false); break; default: break; } } Los botones que usan el método sendMessage, envían datos previamente seleccionamos en coordinación con Arduino para mover los servo-motores. private void sendMessage(String message) { if (mChatService.getState() != ConexionBluetoothService.STATE_CONNECTED) { Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show(); return; } if (message.length() > 0) { byte[] send = message.getBytes(); mChatService.write(send); mOutStringBuffer.setLength(0); } } Al completar la conexión con arduino contamos con dos vías de comunicación entrada y salida, por lo que hay comunicación constante confirmando o enviado errores. Estos mensajes se muestran en las líneas siguientes: byte[] readBuf = (byte[]) msg.obj; String readMessage = new String(readBuf, 0, msg.arg1); mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage); Con esto observamos el mensaje recibido en listview, muestra tanto los datos enviados como los recibidos. En este punto realizado lo necesario para una 27 aplicación que conecta por Bluetooth y enviar datos necesario para mover servomotores. Avanzamos un paso ampliamos la aplicación para enviar señales cuando se activen acelerómetros dentro del dispositivo móvil en los tres ejes "x","y","z" despacha una señal de movimiento, la selección del motor ocupamos los botones como se hace normalmente. Empezamos implementando en la clase principal de la siguiente manera: public class ConexionBluetooth extends Activity implements SensorEventListener. Creamos los métodos necesarios que conllevan la implementación: public void onAccuracyChanged(Sensor sensor, int accuracy) { } public void onSensorChanged(SensorEvent event) { synchronized (this) { } long current_time = event.timestamp; curX = (int) event.values[0]; curY = (int) event.values[1]; curZ = (int) event.values[2]; if (prevX == 0 && prevY == 0 && prevZ == 0) { last_update = current_time; last_movement = current_time; prevX = curX; prevY = curY; prevZ = curZ; } long time_difference = current_time - last_update; if (time_difference > 0) { float movement = Math.abs((curX + curY + curZ) - (prevX - prevY - prevZ)) / time_difference; int limit = 2000; float min_movement = 1; if (movement > min_movement) { if (current_time last_movement >= limit) { Toast.makeText(getApplicationContext (), "Hay movimiento de " + movement, Toast.LENGTH_SHORT).show(); } last_movement = current_time; } prevX = curX; prevY = curY; prevZ = curZ; last_update = current_time; } if(curX>3){ sendMessage("1"); } if(curY>3){ sendMessage("2"); } } El único modificamos es onSensorChanged. en el cual las variables permiten checar movimiento en los sensores, prev almacena el valor del eje x en cualquier momento, cur guarda el dato del mismo eje después de algún tiempo. La variable de tiempo current_time es la que determina el espacio cuando se graban las variables prev y cur las que checan el tiempo es last_update y last_movement. 28 Cuando hay diferencia entre los valores de tiempo, se revisan cambios en los valores de los ejes si existe se actualiza prev=cur, limit es la que indica la sensibilidad de los sensores. Existen condicionantes por si hay cambios en cur o llega a un valor se manda movimiento del motor. En el sensor Z es difícil de obtener una alteración de este, por el modo del dispositivo. Debemos sobrescribir el método onStop para cuando se termina de usar la aplicación también se apaguen los sensores. public void onStop() { super.onStop(); SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE); sm.unregisterListener(this); if(D) Log.e(TAG, "-- ON STOP --"); } 29 Resultados Se concluyó la primera aplicación que sólo mueve a los servo-motores por medio de botones y, posteriormente, se realizó otra versión par el uso de los sensores. Es muy complicado crear una conexión permanente por lo que nos apoyamos en ejemplos libres de Android como el Bluetooth chat, porque estos códigos son libres. En la parte de Arduino realizamos una gran cantidad de pruebas y concluimos que es mejor mover los motores de pocos grados; se realizó en ciclo para mover 2 grados a la vez. Es un proyecto muy divertido y agradable por la posibilidad de aprender distintas tecnologías que están, en este momento, a la vanguardia. Se encontraron bastantes problemas para hacer la conexión de estos elementos, por lo tipos de puertos y la tecnología de HC06 que es el puerto Bluetooth con el que se trabajó, la conexión a la placa Arduino es cruzada lo que quiere decir que la conexión Rx del Bluetooth debe conectarse en el Tx de la placa Arduino y lo mismo con el Tx del bluetooth. En esta parte del proyecto se tomó mucho tiempo por los problemas de conexión. Así mismo nos encontramos otros problemas en el proceso de lograr la conexión de envío y recepción de los datos. Se tuvieron problemas al momento de declarar las variables de Arduino y realizar la lectura de los datos de entrada. Una vez resuelto esto, se procedió a la programación en donde también se presentaron algunos detalles en la parte de visualizar la forma de controlar un motor y posteriormente seleccionar otro servo sin que se perdiera la posición del servo anterior, y que el nuevo servo seleccionado no escribiera la posición del servo anterior. Al final todo se solucionó y se logró el objetivo 30 Conclusiones Se logró el objetivo de poder mover los motores por medio de la ayuda de los acelerómetros de los teléfonos inteligentes o las Tabletas. El problema que tuvimos que resolver fue accionar en una forma continua los motores, que estos no realicen brincos de muchos grados, encontrar una forma de que el motor se mueva despacio y con firmeza. Otro de los conflictos encontrados es la forma de enviar y recibir los datos que se comparten entre la aplicación y la placa chip KIT, ya que solo se realizó el trabajo para controlar 5 motores no hubo inconveniente de mandar números, pero si fueran 100 o 1000 motores se tendría que hacer alguna modificación para recibir y enviar más de un dato en conjunto. Bibliografía http://www.slideshare.net/ykro/trabajando-con-acelermetros-enandroid#btnNext http://www.sgoliver.net/blog/?p=1363 http://www.maestrosdelweb.com/editorial/curso-android-sensores-trabajar-conacelerometro/ http://www.flu-project.com/curso-de-introduccion-a-android-ii-creando-nuestraprimera-aplicacion.html http://androideity.com/2012/08/05/sockets-en-android/ http://tcrobotics.blogspot.mx/2011/05/tutorial-arduino-uno-adk-degoogle.html#more http://www.arduino.cc/ El Gran Libro de Android, de Tomás Gironés, Jesús, Editorial MARCOMBO, S.A. ANDROID - CURSO PRÁCTICO PARA TODO LOS NIVELES, de MUñIZ TROYANO, Editorial Alfaomega, Altaria Editorial COMO PROGRAMAR EN JAVA, de PAUL J. DEITEL, Editorial PEARSON 31 ELGRAN LIBRO DE ANDROID AVANZADO, de JESUS TOMAS, Editorial ALFAOMEGA GRUPO EDITOR ANDROID: DESARROLLO DE APLICACIONES GANADORAS, de LEE WEI MENG, Editorial ANAYA MULTIMEDIA 32 Anexo Código de Android package com.example.android.BluetoothChat; import java.util.List; import android.annotation.SuppressLint; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.Intent; import android.content.pm.ActivityInfo; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListen er; import android.hardware.SensorManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.Window; import android.view.View.OnClickListener; import android.view.inputmethod.EditorInfo; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import android.widget.ToggleButton; @SuppressLint({ "NewApi", "NewApi", "NewApi" }) public class ConexionBluetooth extends Activity implements SensorEventListener { //variables para el acelerometro int curX =0,prevX=0; int curY=0,prevY=0; int curZ=0,prevZ=0; //variables para identificar movimiento en un tiempo long last_update=0,last_movement=0; private static final String TAG = "BluetoothChat"; private static final boolean D = true; // tipos de mensaje public static final int MESSAGE_STATE_CHANGE = 1; public static final int MESSAGE_READ = 2; public static final int MESSAGE_WRITE = 3; public static final int MESSAGE_DEVICE_NAME = 4; public static final int MESSAGE_TOAST = 5; // Key names received from the BluetoothChatService Handler public static final String DEVICE_NAME = "device_name"; public static final String TOAST = "toast"; // Intent request codes private static final int REQUEST_CONNECT_DEVICE = 1; 33 private static final int REQUEST_ENABLE_BT = 2; // las vistas private TextView mTitle; private ListView mConversationView; //variables de los botones que controlan y envian private Button btn_r; private Button btn_l; private ToggleButton Servo_1; private ToggleButton Servo_2; private ToggleButton Servo_3; private ToggleButton Servo_4; private ToggleButton Servo_5; private int motor_accionado =0; Integer valor = 0; private String mConnectedDeviceName = null; conversation thread private ArrayAdapter<String> mConversationArrayAdapter; messages private StringBuffer mOutStringBuffer; private BluetoothAdapter mBluetoothAdapter = null; private ConexionBluetoothService mChatService = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setRequestedOrientation(ActivityI nfo.SCREEN_ORIENTATION_PORT RAIT); if(D) Log.e(TAG, "+++ ON CREATE +++"); // Set up the window layout requestWindowFeature(Window.FEA TURE_CUSTOM_TITLE); setContentView(R.layout.main); getWindow().setFeatureInt(Window.F EATURE_CUSTOM_TITLE, R.layout.custom_title); mTitle = (TextView) findViewById(R.id.title_left_text); mTitle.setText(R.string.app_name); mTitle = (TextView) findViewById(R.id.title_right_text); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter() ; Bluetooth is not supported if (mBluetoothAdapter == null) { Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show(); finish(); return; } } @Override public void onStart() { super.onStart(); if(D) Log.e(TAG, "++ ON START ++"); // If BT is not on, request that it be enabled. if (!mBluetoothAdapter.isEnabled()) { Intent enableIntent = new Intent(BluetoothAdapter.ACTION_RE QUEST_ENABLE); startActivityForResult(enableIntent, REQUEST_ENABLE_BT); // Otherwise, setup the chat session } else { if (mChatService == null) setupChat(); } 34 } @Override//metodo para poder accionar los sensores del inicio public synchronized void onResume() { super.onResume(); SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVIC E); List<Sensor> sensors = sm.getSensorList(Sensor.TYPE_ACC ELEROMETER); if (sensors.size() > 0) { sm.registerListener(this, sensors.get(0), SensorManager.SENSOR_DELAY_G AME); } if(D) Log.e(TAG, "+ ON RESUME +"); // Performing this check in onResume() covers the case in which BT was // not enabled during onStart(), so we were paused to enable it... // onResume() will be called when ACTION_REQUEST_ENABLE activity returns. if (mChatService != null) { // Only if the state is STATE_NONE, do we know that we haven't started already if (mChatService.getState() == ConexionBluetoothService.STATE_N ONE) { // Start the Bluetooth chat services mChatService.start(); } } } private void setupChat() { Log.d(TAG, "setupChat()"); // Initialize the array adapter for the conversation thread mConversationArrayAdapter = new ArrayAdapter<String>(this, R.layout.message); mConversationView = (ListView) findViewById(R.id.in); mConversationView.setAdapter(mCo nversationArrayAdapter); /* // Initialize the compose field with a listener for the return key mOutEditText = (EditText) findViewById(R.id.edit_text_out); mOutEditText.setOnEditorActionListe ner(mWriteListener); // Initialize the send button with a listener that for click events mSendButton = (Button) findViewById(R.id.button_send); mSendButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { // Send a message using content of the edit text widget TextView view = (TextView) findViewById(R.id.edit_text_out); String message = view.getText().toString(); sendMessage(message); } });*/ btn_r = (Button) findViewById(R.id.btn_der); 35 } btn_r.setOnClickListener(new OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub } }); Servo_2 = (ToggleButton) findViewById(R.id.Servo_2); Servo_2.setOnClickListener(new View.OnClickListener() { sendMessage("1"); public void } }); btn_l = (Button) findViewById(R.id.btn_izq); btn_l.setOnClickListener(new OnClickListener() { onClick(View v) { // TODO Auto-generated method stub if(Servo_2.isChecked()){ limpiarmotor(motor_accionado) public void ; onClick(View v) { sendMessage("4"); // TODO Auto-generated method stub motor_accionado = 2; sendMessage("2"); } }); Servo_1 = (ToggleButton) findViewById(R.id.Servo_1); Servo_1.setOnClickListener(new View.OnClickListener() { } } }); Servo_3 = (ToggleButton) findViewById(R.id.Servo_3); Servo_3.setOnClickListener(new View.OnClickListener() { public void public void onClick(View v) { // TODO Auto-generated method stub onClick(View v) { // TODO Auto-generated method stub if(Servo_1.isChecked()){ if(Servo_3.isChecked()){ limpiarmotor(motor_accionado) limpiarmotor(motor_accionado) ; ; sendMessage("3"); sendMessage("5"); motor_accionado = 1; motor_accionado = 3; } 36 } }); Servo_4 = (ToggleButton) findViewById(R.id.Servo_4); Servo_4.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { // TODO Autogenerated method stub // Initialize the BluetoothChatService to perform bluetooth connections mChatService = new ConexionBluetoothService(this, mHandler); // Initialize the buffer for outgoing messages mOutStringBuffer = new StringBuffer(""); } if(Servo_4.isChecked()){ limpiarmotor(motor_accionado) ; sendMessage("6"); motor_accionado = 4; } } }); Servo_5 = (ToggleButton) findViewById(R.id.Servo_5); Servo_5.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { // TODO Autogenerated method stub @Override public synchronized void onPause() { super.onPause(); if(D) Log.e(TAG, "- ON PAUSE -"); } @Override//metodo para poder detener los acelerometros y todo lo de la aplicacion public void onStop() { super.onStop(); SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVIC E); sm.unregisterListener(this); if(D) Log.e(TAG, "-- ON STOP --"); } if(Servo_5.isChecked()){ limpiarmotor(motor_accionado) ; sendMessage("7"); motor_accionado = 5; } } }); @Override public void onDestroy() { super.onDestroy(); // Stop the Bluetooth chat services if (mChatService != null) mChatService.stop(); if(D) Log.e(TAG, "--- ON DESTROY ---"); } 37 private void ensureDiscoverable() { if(D) Log.d(TAG, "ensure discoverable"); if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CO NNECTABLE_DISCOVERABLE) { Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_RE QUEST_DISCOVERABLE); discoverableIntent.putExtra(Bluetooth Adapter.EXTRA_DISCOVERABLE_D URATION, 300); startActivity(discoverableIntent); } } /** * Sends a message. * @param message A string of text to send. */ private void sendMessage(String message) { // Check that we're actually connected before trying anything if (mChatService.getState() != ConexionBluetoothService.STATE_C ONNECTED) { Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show(); return; } // Check that there's actually something to send if (message.length() > 0) { // Get the message bytes and tell the BluetoothChatService to write byte[] send = message.getBytes(); mChatService.write(send); // Reset out string buffer to zero and clear the edit text field mOutStringBuffer.setLength(0); //mOutEditText.setText(mOutStringBu ffer); } } // The action listener for the EditText widget, to listen for the return key private TextView.OnEditorActionListener mWriteListener = new TextView.OnEditorActionListener() { public boolean onEditorAction(TextView view, int actionId, KeyEvent event) { // If the action is a key-up event on the return key, send the message if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) { String message = view.getText().toString(); sendMessage(message); } if(D) Log.i(TAG, "END onEditorAction"); return true; } }; 38 // The Handler that gets information back from the BluetoothChatService private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_STATE_CHANGE: if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1); switch (msg.arg1) { case ConexionBluetoothService.STATE_C ONNECTED: mTitle.setText(R.string.title_connecte d_to); mTitle.append(mConnectedDeviceNa me); mConversationArrayAdapter.clear(); break; case ConexionBluetoothService.STATE_C ONNECTING: mTitle.setText(R.string.title_connectin g); break; case ConexionBluetoothService.STATE_LI STEN: case ConexionBluetoothService.STATE_N ONE: mTitle.setText(R.string.title_not_conn ected); break; } break; case MESSAGE_WRITE: byte[] writeBuf = (byte[]) msg.obj; // construct a string from the buffer String writeMessage = new String(writeBuf); mConversationArrayAdapter.add("Me: " + writeMessage); break; case MESSAGE_READ: byte[] readBuf = (byte[]) msg.obj; // construct a string from the valid bytes in the buffer String readMessage = new String(readBuf, 0, msg.arg1); mConversationArrayAdapter.add(mC onnectedDeviceName+": " + readMessage); break; case MESSAGE_DEVICE_NAME: // save the connected device's name mConnectedDeviceName = msg.getData().getString(DEVICE_NA ME); Toast.makeText(getApplicationConte xt(), "Connected to " + mConnectedDeviceName, Toast.LENGTH_SHORT).show(); break; case MESSAGE_TOAST: Toast.makeText(getApplicationConte xt(), msg.getData().getString(TOAST), Toast.LENGTH_SHORT).show(); break; } } }; 39 public void onActivityResult(int requestCode, int resultCode, Intent data) { if(D) Log.d(TAG, "onActivityResult " + resultCode); switch (requestCode) { case REQUEST_CONNECT_DEVICE: // When DeviceListActivity returns with a device to connect if (resultCode == Activity.RESULT_OK) { // Get the device MAC address String address = data.getExtras() .getString(DeviceListActivity.EXTRA_ DEVICE_ADDRESS); // Get the BLuetoothDevice object BluetoothDevice device = mBluetoothAdapter.getRemoteDevice (address); // Attempt to connect to the device mChatService.connect(device); } break; case REQUEST_ENABLE_BT: // When the request to enable Bluetooth returns if (resultCode == Activity.RESULT_OK) { // Bluetooth is now enabled, so set up a chat session setupChat(); } else { // User did not enable Bluetooth or an error occured Log.d(TAG, "BT not enabled"); Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show(); finish(); } } } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.option_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.scan: // Launch the DeviceListActivity to see devices and do scan Intent serverIntent = new Intent(this, DeviceListActivity.class); startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE); return true; case R.id.discoverable: // Ensure this device is discoverable by others ensureDiscoverable(); return true; } return false; } void limpiarmotor(int motor){ switch (motor) { case 1: Servo_1.setChecked(false); 40 break; case 2: Servo_2.setChecked(false); break; case 3: Servo_3.setChecked(false); break; case 4: Servo_4.setChecked(false); break; case 5: Servo_5.setChecked(false); break; default: break; } } public void onAccuracyChanged(Sensor sensor, int accuracy) { // TODO Auto-generated method stub } public void onSensorChanged(SensorEvent event) { // TODO Auto-generated method stub synchronized (this) { } long current_time = event.timestamp; curX = (int) event.values[0]; curY = (int) event.values[1]; curZ = (int) event.values[2]; if (prevX == 0 && prevY == 0 && prevZ == 0) { last_update = current_time; last_movement = current_time; prevX = curX; prevY = curY; prevZ = curZ; } long time_difference = current_time - last_update; if (time_difference > 0) { float movement = Math.abs((curX + curY + curZ) (prevX - prevY - prevZ)) / time_difference; int limit = 2000; float min_movement = 1; if (movement > min_movement) { if (current_time last_movement >= limit) { Toast.makeText(getApplicationConte xt(), "Hay movimiento de " + movement, Toast.LENGTH_SHORT).show(); } last_movement = current_time; } prevX = curX; prevY = curY; prevZ = curZ; last_update = current_time; } if(curX>3){ sendMessage("1"); } if(curY>3){ sendMessage("2"); } } 41 Codigo MPIDE /* Programa realizado por Oswaldo Santander Este pretende realizar una conexion bluetooth y llevar el control de 5 servomotores guardando la ultima posicion de cada servo, asi tambien se intenta que el movimiento de los servo sea progresivo que no se llegue a la posicion de un golpe */ #include <Servo.h> int N=5; char data1; char data2; int motor1_pos = 0; int motor2_pos = 0; int motor3_pos = 0; int motor4_pos = 0; int motor5_pos = 0; int m1 = 2; int m2 = 3; int m3 = 4; int m4 = 5; int m5 = 6; int max = 180; int min = 0; int salida = 13; Servo miservo1; Servo miservo2; Servo miservo3; Servo miservo4; Servo miservo5; void setup(){ Serial.begin(9600); pinMode(salida,OUTPUT); digitalWrite(salida,HIGH); miservo1.attach(m1); miservo2.attach(m2); miservo3.attach(m3); miservo4.attach(m4); miservo5.attach(m5); miservo1.write(motor1_pos); miservo2.write(motor2_pos); miservo3.write(motor3_pos); miservo4.write(motor4_pos); miservo5.write(motor5_pos); } void loop(){ data1 = Serial.read(); if(data1 == '1'){ Serial.write("0"); } if(data1 == '2'){ Serial.write("0"); } else{ selectormotor(data1); } } void servo1(){ int i; while(1){ data2 = Serial.read(); if(data2 == '1'){ if(motor1_pos < max){ for(i=0;i<N;i++){ motor1_pos +=2; miservo1.write(motor1_pos); delay(2); comprobacion(); } } } if(data2 == '2'){ if(motor1_pos > min){ for(i=0;i<N;i++){ motor1_pos -=2; miservo1.write(motor1_pos); delay(2); comprobacion(); } } 42 } else{ selectormotor(data2); if(data2 == '1'){ if(motor3_pos < max){ for(i=0;i<N;i++){ motor3_pos +=2; } } } void servo2(){ while(1){ int i; data2 = Serial.read(); if(data2 == '1'){ if(motor2_pos < max){ for(i=0;i<N;i++){ motor2_pos+=2; miservo2.write(motor2_pos); delay(2); comprobacion(); miservo3.write(motor3_pos); delay(2); comprobacion(); } } } if(data2 =='2'){ if(motor3_pos > min){ for(i=0;i<N;i++){ motor3_pos -=2; miservo3.write(motor3_pos); delay(2); comprobacion(); } } } } if(data2 =='2'){ if(motor2_pos > min){ for(i=0;i<N;i++){ motor2_pos -=2; miservo2.write(motor2_pos); delay(2); comprobacion(); } } } else{ selectormotor(data2); } } } void servo3(){ int i; while(1){ data2 = Serial.read(); } } else{ selectormotor(data2); } } } void servo4(){ int i; while(1){ data2 = Serial.read(); if(data2 == '1'){ if(motor4_pos < max){ for(i=0;i<N;i++){ motor4_pos +=2; miservo4.write(motor4_pos); delay(2); comprobacion(); } } } if(data2 =='2'){ 43 if(motor4_pos > min){ for(i=0;i<N;i++){ motor4_pos -=2; miservo4.write(motor4_pos); delay(2); comprobacion(); } } } else{ selectormotor(data2); } } } void servo5(){ int i; while(1){ data2 = Serial.read(); if(data2 == '1'){ if(motor5_pos < max){ for(i=0;i<N;i++){ motor5_pos +=2; miservo5.write(motor5_pos); delay(2); comprobacion(); } } } if(data2 =='2'){ if(motor5_pos > min){ for(i=0;i<N;i++){ motor5_pos -=2; } } } void selectormotor(char id){ switch(id){ case '3': servo1(); break; case '4': servo2(); break; case '5': servo3(); break; case '6': servo4(); break; case '7': servo5(); break; } } void comprobacion(){ int i; for(i=0; i<10; i++){ digitalWrite(salida,LOW); delay(20); digitalWrite(salida,HIGH); delay(20); } } miservo5.write(motor5_pos); delay(2); comprobacion(); } } } else{ selectormotor(data2); 44