lunes, 19 de octubre de 2015

Conexión bluetooth Android con Arduino





Buenas este es el primer tutorial enlazado a mis segundo blog CursoAndroidStudio.
Este tutorial consiste conectar a través de una conexión bluetooth tu dispositivo Android con el Arduino.
Vamos a enviar y recibir información.
Desde el celular Android, vamos a tener dos botones. ON OFF que van encender o apagar respectivamente
Desde el Arduino vamos a enviar 1, 2,3, 4. Ahora utilizamos estos numeros pero podría ser cualquier tipo de información como la temperatura y la humedad de un DHT11 
Todos los demás botones es puramente demostrativo que otras funcionalidades se le pueden agregar.

Un dato importante si usamos el hc06 en el ARDUINO UNO y queremos subir el programa, debemos desconectar el HC06 porque utiliza el mismo puerto serie, que de comunicación. O sea, el puerto usb computadora a arduino es el mismo que del arduino al hc06
Pero si usamos el ARDUINO MEGA, ya tiene varios puertos TX0 RX0, TX1 RX1, TX2 RX2, TX3 RX3.
Entonces lo que hacemos dejamos el puerto 0 (TX0 y RX0) para la comunicación en serie y usamos el TX1 y RX1 para estas conectando y desconectando el VCC del HC06 (agregando si no hacemos esto podrías quemar el arduino o nuestra pc)
Para poder solucionarlo
MultiSerialMega

Vamos a hacer dos declaraciones
Serial.begin(9600);
Serial1.begin(9600);  

y cambiaremos todos los Serial
if (Serial.available() > 0)
  {
    inbyte = Serial.read();
por Seria1.
if (Serial1.available() > 0)
  {
    inbyte = Serial1.read();
etc....

Pero para nuestro ejemplo trabajeremos el ARDUINO UNO, y como tiene un solo puerto habrá que desconectarlo el VCC del HC06 para subir el programa, luego de esto le volvemos a dar alimentación al VCC para poder enviar y recibir información

Fuentes: wingoodharry arduino

Configurar HC06

Comencemos con arduino
//#include "DHT.h"
//#define DHTPIN 7
//#define DHTTYPE DHT11
//DHT dht(DHTPIN, DHTTYPE);
 
int led = 13; //led Rojo de prueba de conexión

float voltageValue[4] = {0,0,0,0};
char inbyte = 0; //Char para leer el led
 
void setup() {
  // initialise serial communications at 9600 bps:
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);
  //dht.begin();
}
 
void loop() {
  getVoltageValue();
  //when serial values have been received this will be true
  
  if (Serial.available() > 0)
  {
    inbyte = Serial.read();
    Serial.println(inbyte);
    if (inbyte == '2')
    {
      digitalWrite(led, LOW); //LED off
      voltageValue[0] = 0;
    }
    if (inbyte == '1')
    {
      digitalWrite(led, HIGH); //LED on
      voltageValue[0] = 1;
    }
  }
  sendAndroidValues();
  delay(2000); 
}
 
void getVoltageValue()
{
  voltageValue[0] = 1; //led
  voltageValue[1] = 2;
  voltageValue[2] = 3;
  voltageValue[3] = 4;
  
}

//enviar los valores por el dipositivo android por el modulo Bluetooth
void sendAndroidValues()
 {
  Serial.print('#'); //hay que poner # para el comienzo de los datos, así Android sabe que empieza el String de datos
  for(int k=0; k<4; k++)
  {
    Serial.print(voltageValue[k]);
    Serial.print('+'); //separamos los datos con el +, así no es más fácil debuggear la información que enviamos
  }
 Serial.print('~'); //con esto damos a conocer la finalización del String de datos
 Serial.println();
 delay(10);        //agregamos este delay para eliminar tramisiones faltantes
}


Ahora la conexión.
Nota: En código anterior no declaramos el TX y RX (recibir e enviar información) porque vamos a usar D0 y D1. En caso contrario deberíamos declararlo como en el siguiente ejemplo (ver)
SoftwareSerial BT(10,11); //10 RX, 11 TX.

  • TXD: Transmisión de datos.
  • RXD: Recepción de datos a un voltaje de 3,3V.

Muestro dos opciones. Ambas funcionan.
Lo más importante, cual es muy fácil de equivocarse si uno trabajo apurado, rápido.
Es que 
  • el RXD hc06 va con el TX0 del arduino
  • el TXD hc06 va con el RX0 del arduino
como muestro en las imágenes



Fotos reales





Y sin mas preámbulos a los que nos interesa el código de Android

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tatoado.ramabluewingood" >

    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".DeviceListActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".MainActivity"></activity>
    </application>

</manifest>

device_name.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="18sp"
    android:padding="5dp">

</TextView>

activy_main.xml (esto tiene que estar dentro de un linearlayout o relative o como gusten, para no ser muy largo solo puse lo esencial en este layout)
 <Button
    android:id="@+id/buttonOn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="LED ON" />

<Button
    android:id="@+id/buttonOff"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="LED OFF />

<TextView
    android:id="@+id/sensorView0"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
<TextView
    android:id="@+id/sensorView1
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
<TextView
    android:id="@+id/sensorView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
<TextView
    android:id="@+id/sensorView3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

device_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <TextView android:id="@+id/title_paired_devices"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Seleccione un dispositivo btSerial "
        android:visibility="gone"
        android:background="#666"
        android:textColor="#fff"
        android:paddingLeft="5dp"
    />
    <ListView android:id="@+id/paired_devices"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:stackFromBottom="false"
        android:layout_weight="1"
    />

    <TextView
        android:id="@+id/connecting"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/infoText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Si no hay dispositivos en la lista, por favor enlaza tu dispositivo en la configuración de Android"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:layout_margin="5dp"
        android:textSize="18dp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center">

    </LinearLayout>

</LinearLayout>

MainActivity.java
       

            package com.tatoado.ramabluewingood;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

    Button btnOn, btnOff;
    TextView txtArduino, txtString, txtStringLength, sensorView0, sensorView1, sensorView2, sensorView3;
    TextView txtSendorLDR;
    Handler bluetoothIn;

    final int handlerState = 0;             //used to identify handler message
    private BluetoothAdapter btAdapter = null;
    private BluetoothSocket btSocket = null;
    private StringBuilder recDataString = new StringBuilder();

    private ConnectedThread mConnectedThread;

    // SPP UUID service - this should work for most devices
    private static final UUID BTMODULEUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

    // String for MAC address
    private static String address = null;

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

        setContentView(R.layout.activity_main);

        //Link the buttons and textViews to respective views
        btnOn = (Button) findViewById(R.id.buttonOn);
        btnOff = (Button) findViewById(R.id.buttonOff);
        txtString = (TextView) findViewById(R.id.txtString);
        txtStringLength = (TextView) findViewById(R.id.testView1);
        sensorView0 = (TextView) findViewById(R.id.sensorView0);
        sensorView1 = (TextView) findViewById(R.id.sensorView1);
        sensorView2 = (TextView) findViewById(R.id.sensorView2);
        sensorView3 = (TextView) findViewById(R.id.sensorView3);

        txtSendorLDR = (TextView) findViewById(R.id.tv_sendorldr);


        bluetoothIn = new Handler() {
            public void handleMessage(android.os.Message msg) {
                if (msg.what == handlerState) {          //if message is what we want
                    String readMessage = (String) msg.obj;                                                                // msg.arg1 = bytes from connect thread
                    recDataString.append(readMessage);              //keep appending to string until ~
                    int endOfLineIndex = recDataString.indexOf("~");                    // determine the end-of-line
                    if (endOfLineIndex > 0) {                                           // make sure there data before ~
                        String dataInPrint = recDataString.substring(0, endOfLineIndex);    // extract string
                        txtString.setText("Datos recibidos = " + dataInPrint);
                        int dataLength = dataInPrint.length();       //get length of data received
                        txtStringLength.setText("Tamaño del String = " + String.valueOf(dataLength));

                        if (recDataString.charAt(0) == '#')        //if it starts with # we know it is what we are looking for
                        {
                            String sensor0 = recDataString.substring(1, 5);             //get sensor value from string between indices 1-5
                            String sensor1 = recDataString.substring(6, 10);            //same again...
                            String sensor2 = recDataString.substring(11, 15);
                            String sensor3 = recDataString.substring(16, 20);

                            if(sensor0.equals("1.00"))
                            sensorView0.setText("Encendido"); //update the textviews with sensor values
                            else
                                sensorView0.setText("Apagado"); //update the textviews with sensor values
                            sensorView1.setText(sensor1);
                            sensorView2.setText(sensor2);
                            sensorView3.setText(sensor3);
                            //sensorView3.setText(" Sensor 3 Voltage = " + sensor3 + "V");
                        }
                        recDataString.delete(0, recDataString.length());      //clear all string data
                        // strIncom =" ";
                        dataInPrint = " ";
                    }
                }
            }
        };

        btAdapter = BluetoothAdapter.getDefaultAdapter();       // get Bluetooth adapter
        checkBTState();


        // Set up onClick listeners for buttons to send 1 or 0 to turn on/off LED
        btnOff.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                mConnectedThread.write("2");    // Send "0" via Bluetooth
                Toast.makeText(getBaseContext(), "Apagar el LED", Toast.LENGTH_SHORT).show();
            }
        });

        btnOn.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                mConnectedThread.write("1");    // Send "1" via Bluetooth
                Toast.makeText(getBaseContext(), "Encender el LED", Toast.LENGTH_SHORT).show();
            }
        });
    }


    private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {

        return  device.createRfcommSocketToServiceRecord(BTMODULEUUID);
        //creates secure outgoing connecetion with BT device using UUID
    }

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

        //Get MAC address from DeviceListActivity via intent
        Intent intent = getIntent();

        //Get the MAC address from the DeviceListActivty via EXTRA
        address = intent.getStringExtra(DeviceListActivity.EXTRA_DEVICE_ADDRESS);

        //create device and set the MAC address
        //Log.i("ramiro", "adress : " + address);
        BluetoothDevice device = btAdapter.getRemoteDevice(address);

        try {
            btSocket = createBluetoothSocket(device);
        } catch (IOException e) {
            Toast.makeText(getBaseContext(), "La creacción del Socket fallo", Toast.LENGTH_LONG).show();
        }
        // Establish the Bluetooth socket connection.
        try
        {
            btSocket.connect();
        } catch (IOException e) {
            try
            {
                btSocket.close();
            } catch (IOException e2)
            {
                //insert code to deal with this
            }
        }
        mConnectedThread = new ConnectedThread(btSocket);
        mConnectedThread.start();

        //I send a character when resuming.beginning transmission to check device is connected
        //If it is not an exception will be thrown in the write method and finish() will be called
        mConnectedThread.write("x");
    }

    @Override
    public void onPause()
    {
        super.onPause();
        try
        {
            //Don't leave Bluetooth sockets open when leaving activity
            btSocket.close();
        } catch (IOException e2) {
            //insert code to deal with this
        }
    }

    //Checks that the Android device Bluetooth is available and prompts to be turned on if off
    private void checkBTState() {

        if(btAdapter==null) {
            Toast.makeText(getBaseContext(), "El dispositivo no soporta bluetooth", Toast.LENGTH_LONG).show();
        } else {
            if (btAdapter.isEnabled()) {
            } else {
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent, 1);
            }
        }
    }

    //create new class for connect thread
    private class ConnectedThread extends Thread {
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;

        //creation of the connect thread
        public ConnectedThread(BluetoothSocket socket) {
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            try {
                //Create I/O streams for connection
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) { }

            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }


        public void run() {
            byte[] buffer = new byte[256];
            int bytes;

            // Keep looping to listen for received messages
            while (true) {
                try {
                    bytes = mmInStream.read(buffer);         //read bytes from input buffer
                    String readMessage = new String(buffer, 0, bytes);
                    // Send the obtained bytes to the UI Activity via handler
                    bluetoothIn.obtainMessage(handlerState, bytes, -1, readMessage).sendToTarget();
                } catch (IOException e) {
                    break;
                }
            }
        }
        //write method
        public void write(String input) {
            byte[] msgBuffer = input.getBytes();           //converts entered String into bytes
            try {
                mmOutStream.write(msgBuffer);                //write bytes over BT connection via outstream
            } catch (IOException e) {
                //if you cannot write, close the application
                Toast.makeText(getBaseContext(), "La Conexión fallo", Toast.LENGTH_LONG).show();
                finish();

            }
        }
    }
}

DeviceListActivity.java
       

            package com.tatoado.ramabluewingood;

import java.util.Set;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;


public class DeviceListActivity extends Activity {
    // Debugging for LOGCAT
    private static final String TAG = "DeviceListActivity";
    private static final boolean D = true;
    
  
    // declare button for launching website and textview for connection status
    Button tlbutton;
    TextView textView1;
    
    // EXTRA string to send on to mainactivity
    public static String EXTRA_DEVICE_ADDRESS = "device_address";

    // Member fields
    private BluetoothAdapter mBtAdapter;
    private ArrayAdapter mPairedDevicesArrayAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.device_list);
    }
    
    @Override
    public void onResume() 
    {
     super.onResume();
     //*************** 
     checkBTState();

     textView1 = (TextView) findViewById(R.id.connecting);
     textView1.setTextSize(40);
     textView1.setText(" ");

     // Initialize array adapter for paired devices
     mPairedDevicesArrayAdapter = new ArrayAdapter(this, R.layout.device_name);

     // Find and set up the ListView for paired devices
     ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
     pairedListView.setAdapter(mPairedDevicesArrayAdapter);
     pairedListView.setOnItemClickListener(mDeviceClickListener);

     // Get the local Bluetooth adapter
     mBtAdapter = BluetoothAdapter.getDefaultAdapter();

     // Get a set of currently paired devices and append to 'pairedDevices'
     Set pairedDevices = mBtAdapter.getBondedDevices();

     // Add previosuly paired devices to the array
     if (pairedDevices.size() > 0) {
      findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);//make title viewable
      for (BluetoothDevice device : pairedDevices) {
       mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
      }
     } else {
      String noDevices = "Ningun dispositivo pudo ser emparejado";
      mPairedDevicesArrayAdapter.add(noDevices);
     }
  }

    // Set up on-click listener for the list (nicked this - unsure)
    private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
        public void onItemClick(AdapterView av, View v, int arg2, long arg3) {

         textView1.setText("Conectando...");
            // Get the device MAC address, which is the last 17 chars in the View
            String info = ((TextView) v).getText().toString();
            String address = info.substring(info.length() - 17);

            // Make an intent to start next activity while taking an extra which is the MAC address.
   Intent i = new Intent(DeviceListActivity.this, MainActivity.class);
            i.putExtra(EXTRA_DEVICE_ADDRESS, address);
   startActivity(i);   
        }
    };

    private void checkBTState() {
        // Check device has Bluetooth and that it is turned on
      mBtAdapter=BluetoothAdapter.getDefaultAdapter(); // CHECK THIS OUT THAT IT WORKS!!!
        if(mBtAdapter==null) { 
         Toast.makeText(getBaseContext(), "El dispositivo no soporta Bluetooth", Toast.LENGTH_SHORT).show();
        } else {
          if (mBtAdapter.isEnabled()) {
            Log.d(TAG, "...Bluetooth Activado...");
          } else {
            //Prompt user to turn on Bluetooth
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, 1);
 
            }
          }
        }
}

6 comentarios:

  1. HOla me gustaría que lo hiciera con arduino uno + blouttton + sensor de humedad + android y que me muestre la humedad a cuanto va a la medida que valla tocando mas el agua y que envié mensaje indicando el numero de humedad cada 5 minutos.. mi correo es abirca93@hotmail.com

    ResponderEliminar
  2. hola una duda el programa que usas para programar android es eclipse o android estudio

    ResponderEliminar
  3. Hola, excelente aporte, mil gracias, pero tengo una duda, las resistencias de que capasidad son cada una ?

    ResponderEliminar
  4. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  5. Hola,
    Gracias por la recomendación. En el caso del Arduino Mega, si conectamos al Serial1 y cambiamos todos los Serial.print a Serial1.print, puedo ver en terminal de mi Android toda la información, pero ya no la puedo ver en la PC a través del monitor serial. ¿Tendré que poner ambas instrucciones? Tanto ¿Serial.print, como Serial1 print? Anteriormente conectaba como comentas todo a TX0 y RX0 y con eso podía ver todo tando en Android como en PC, pero me recomendaron cambiarlo. Gracias.

    ResponderEliminar