Let's Make Robots! | RobotShop

Android Java Newbie bluetooth help.

I am NOT a java devloper.  I work primarily in PHP and Asp.Net so you'll have to forgive me for this post, but i'm hitting up my favorite community of geeks for help as I'm sure many of you have written android bluetooth robot controllers before.

So after a long time of trying to create an application that can do serial BT communication i finally found a working example of code to send data to/from my arduino via a bluetooth module.  The code on the arduino is really basic, it just parses the bytes sent for a few commands like "F", "B", "R", "L", 5...  and then runs a motor driver to drive my robot using a motor controller.

(also note that the arduino/hardware is solid because i run this all the time with an android application "Bluetooth Serial Controller" and it works perfectly)

I set up the buttons and seem to have the messages being sent fairly well, but where i'm running into a few problems with stability:

1) The application currently allows multiple connections to open and can open a bunch of sockets that aren't closing.  I'm pretty sure i can find a way to close them on application exit or something like that.  I have to reboot the phone if i accidentally make this happen.

2) The bluetooth module (adafruit ez-link) that i'm using sometimes seems to "hang" meaning it just has a solid red light on and doesn't want to accept commands until i turn it off and back on again.

3) Sometimes data doesn't seem to go through.  meaning i send a command and on my phoneit tells me it was sent, but on the robot it doesn't respond.  may be related to #2 above.

4) THIS IS THE BIGGEST ONE.  The code example i found only has one class and everything runs on the main activity.  I THINK the author didn't set up the threads properly so the application doesn't make good use of threading.  Being a newbie java developer i'm a little confused about how to properly fix this to use threading correctly.  Right now i keep getting an error in my Log saying that frames are skipping (sometimes hundreds to thousands) from the android "coreographer".  

If someone who is smarter and more experienced than me could take a look and shed some light as to what i can do to fix my application, or point me to a CLEARLY written tutorial on how to make this work i'd be forever grateful.

Here is the full source of my MainActivity:

package com.example.mcr_bt;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.Set;

import java.util.UUID;

 

import android.os.AsyncTask;

import android.os.Bundle;

import android.os.Handler;

import android.app.Activity;

import android.util.Log;

import android.view.Menu;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.TextView;

import android.widget.Toast;

import android.bluetooth.*;

import android.content.Intent;

 

public class MainActivity extends Activity {

TextView myLabel;

 EditText myTextbox;

 BluetoothAdapter mBluetoothAdapter;

 BluetoothSocket mmSocket;

 BluetoothDevice mmDevice;

 OutputStream mmOutputStream;

 InputStream mmInputStream;

 Thread workerThread;

 byte[] readBuffer;

 int readBufferPosition;

 int counter;

 volatile boolean stopWorker;

 @Override

 public void onCreate(Bundle savedInstanceState) {

   super.onCreate(savedInstanceState);

   setContentView(R.layout.activity_main);

 

   Button openButton = (Button)findViewById(R.id.open);

   Button sendButton = (Button)findViewById(R.id.send);

   Button closeButton = (Button)findViewById(R.id.close);

   

   Button bF = (Button)findViewById(R.id.buttonF);

   Button bL = (Button)findViewById(R.id.buttonL);

   Button bR = (Button)findViewById(R.id.buttonR);

   Button bB = (Button)findViewById(R.id.buttonB);

   Button bH = (Button)findViewById(R.id.buttonH);

   

   myLabel = (TextView)findViewById(R.id.label);

   myTextbox = (EditText)findViewById(R.id.entry);

 

   //Open Button

   openButton.setOnClickListener(new View.OnClickListener() {

     public void onClick(View v) {

       try {

         findBT();

         openBT();

       }

       catch (IOException ex) { }

     }

   });

 

   //Send Button

   sendButton.setOnClickListener(new View.OnClickListener() {

     public void onClick(View v) {

       try {

         sendData(myTextbox.getText().toString());

       }

       catch (IOException ex) {

           showMessage("SEND FAILED");

       }

     }

   });

 

   bF.setOnClickListener(new View.OnClickListener() {

     public void onClick(View v) {

       try {

         sendData("F");

       }

       catch (IOException ex) {

           showMessage("SEND FAILED");

       }

     }

   });

   bL.setOnClickListener(new View.OnClickListener() {

     public void onClick(View v) {

       try {

         sendData("L");

       }

       catch (IOException ex) {

           showMessage("SEND FAILED");

       }

     }

   });

   bR.setOnClickListener(new View.OnClickListener() {

     public void onClick(View v) {

       try {

         sendData("R");

       }

       catch (IOException ex) {

           showMessage("SEND FAILED");

       }

     }

   });

   bB.setOnClickListener(new View.OnClickListener() {

     public void onClick(View v) {

       try {

         sendData("B");

       }

       catch (IOException ex) {

           showMessage("SEND FAILED");

       }

     }

   });

   bH.setOnClickListener(new View.OnClickListener() {

     public void onClick(View v) {

       try {

         sendData("5");

       }

       catch (IOException ex) {

           showMessage("SEND FAILED");

       }

     }

   });

   

   //Close button

   closeButton.setOnClickListener(new View.OnClickListener() {

    public void onClick(View v) {

       try {

         closeBT();

       }

       catch (IOException ex) { 

        showMessage("Close Failed");

       }

     }

   });

 }

 void findBT() {

   mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

   if(mBluetoothAdapter == null) {

     myLabel.setText("No bluetooth adapter available");

   }

 

   if(!mBluetoothAdapter.isEnabled()) {

     Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

     startActivityForResult(enableBluetooth, 0);

   }

 

   Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();

   if(pairedDevices.size() > 0) {

     for(BluetoothDevice device : pairedDevices) {

       if(device.getName().equals("Adafruit EZ-Link 05f5")) {

       

         mmDevice = device;

         break;

       }

     }

   }

   myLabel.setText("Bluetooth Device Found");

 }

 

 void openBT() throws IOException {

   UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); //Standard //SerialPortService ID

   mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);    

   mmSocket.connect();

   mmOutputStream = mmSocket.getOutputStream();

   mmInputStream = mmSocket.getInputStream();

   beginListenForData();

   myLabel.setText("Bluetooth Opened");

 }

 

 void beginListenForData() {

   final Handler handler = new Handler(); 

   final byte delimiter = 10; //This is the ASCII code for a newline character

 

   stopWorker = false;

   readBufferPosition = 0;

   readBuffer = new byte[1024];

   workerThread = new Thread(new Runnable() {

     public void run() {

        while(!Thread.currentThread().isInterrupted() && !stopWorker) {

         try {

           int bytesAvailable = mmInputStream.available();            

           if(bytesAvailable > 0) {

             byte[] packetBytes = new byte[bytesAvailable];

             mmInputStream.read(packetBytes);

             for(int i=0;i<bytesAvailable;i++) {

               byte b = packetBytes[i];

               if(b == delimiter) {

                 byte[] encodedBytes = new byte[readBufferPosition];

                 System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);

                 final String data = new String(encodedBytes, "US-ASCII");

                 readBufferPosition = 0;

 

                 handler.post(new Runnable() {

                   public void run() {

                     myLabel.setText(data);

                   }

                 });

               }

               else {

                 readBuffer[readBufferPosition++] = b;

               }

             }

           }

         } 

         catch (IOException ex) {

           stopWorker = true;

         }

        }

     }

   });

 

   workerThread.start();

 }

 

 void sendData(String msg) throws IOException {

   mmOutputStream.write(msg.getBytes());

   myLabel.setText("Data Sent");

 }

 

 void closeBT() throws IOException {

   stopWorker = true;

   mmOutputStream.close();

   mmInputStream.close();

   mmSocket.close();

   myLabel.setText("Bluetooth Closed");

 }

 

 private void showMessage(String theMsg) {

       Toast msg = Toast.makeText(getBaseContext(),

               theMsg, (Toast.LENGTH_LONG)/160);

       msg.show();

   }

}

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

So today i tested this app communication a bit more and discovered a few things.

1)  It is perfectly stable in regards to opening/closing sockets as long as i don't kill the application or unplug the phone etc  when i'm testing it.  Another cause seems to be rotating the phone accidentally to change the screen from horizontal to vertical.  non-issue as my actual application i've been building for this is locked to only be horizontal.

2/3)  This wasn't happening when i was testing it today... so maybe there is a clue there?  perhaps it could mean there was something else running on my phone at the time of testing, or it could have been from the sockets continually opening, or it could be coincidental 

4) Didn't get much time to mess around with the actual code so i'll have to look into this more later.