Android and Arduino Serial Bluetooth App – BlueSerial

I’ve finally been able to figure out the entire Bluetooth API of Android and I felt it was more difficult than writing Arduino code in Assembly. In it’s current avatar, I think it’s ready for a Beta release. Based on the feedback I receive, I’ll make a few changes and release the code and put it on the Android Play Store (for which I still need to register a developer account).

A quick how-to about the app – The app can be used to communicate with serial (RX-TX/UART) bluetooth devices. This largely includes devices that are used to control microcontrollers and other electronic projects which use bluetooth to send and receive information. I developed this app to use with a bluetooth enabled robot that I had been dying to build for quite some time now. I think it’s pretty self-explanatory and if it’s not, then I need to work a bit more on it.

With the robot running successfully, I didn’t want to lose the knowledge I gained from the whole experience. So I decided to put in the extra effort to build an open source app which others can find some use out of.

Full disclaimer though. The idea came to me from the Bluetooth SPP app I found on the play store. It had pretty much everything I needed, but I couldn’t find the source code (which might be because it wasn’t meant to be open source!). So I decided to do my own research and release the source so that others struggling with the Android Bluetooth API can have something to start with.

PS: I’m aware of the Amarino, but the whole code is GPL’d. So, using it for commercial purposes is out of the question. I’d like to release this with an Open Source license with no restrictions on usage except a little credit.

Here’s the download link to the APK: Click here to download

======

EDIT (23-Oct-2013): The Blue Serial App is now available on Play store at the following link: https://play.google.com/store/apps/details?id=com.blueserial

And the entire source code is available on github at: https://github.com/plastygrove/BlueSerial

======

Works on Android 2.2+. Tested on Android 2.3.4 and 4.2.2

If you find it useful, please leave a comment below. If not, please leave a comment anyway :).

Arduino Code for the Robot

Here’s the code for the robot. Please note that it’s very specific to my setup i.e. 2 12V motors run by an L293D motor driver IC. The battery is 12V which is powers the motors and is also directly connected to the Arduino.

int motorOneEnablePin = 7;
int motorOnePinA = 6;
int motorOnePinB = 5;

int motorTwoEnablePin = 10;
int motorTwoPinA = 9;
int motorTwoPinB = 11;

int speed = 100;

int irPin = 3;

long irCounter = 0;
long irCheck = 10;

char EOM = '';

int direction = -1;
const int FORWARD = 1;
const int BACKWARD = 2;
const int RIGHT = 3;
const int LEFT = 4;

const int MAX_INPUT_SIZE = 10;

void setup(){
  pinMode(motorOneEnablePin, OUTPUT);
  pinMode(motorOnePinA, OUTPUT);
  pinMode(motorOnePinB, OUTPUT);    

  pinMode(motorTwoEnablePin, OUTPUT);
  pinMode(motorTwoPinA, OUTPUT);
  pinMode(motorTwoPinB, OUTPUT);

  pinMode(irPin, INPUT);
  Serial.begin(9600);
}

char newCommand = 0;
char currCommand = 10;
boolean isColliding = false;

void loop(){
  char cmd[MAX_INPUT_SIZE] = "";
  getStrCommand(cmd);
  if(strlen(cmd)>0){
    performStrCommand(cmd);
  } 
}
/*
void loop(){
  newCommand = getCommand();
  performCommand(newCommand);
  checkCollision();
  delay(100);
}*/

/*Implemented in the older version, haven't 
implemented yet in the version with speed control
*/

void checkCollision(){
  if(digitalRead(irPin)){
    isColliding = true;
    Serial.write("WARNING: Obstacle in path!");
    if(direction == FORWARD){
      motorReset();
    }
  } 
  else {
    isColliding = false;
    //Serial.write("All Clear!");
  }
}

//Old function
int getCommand(){
  int val = 0;
  if(Serial.available()){
    val = Serial.read();
  }
  return val;
}

//New function
void getStrCommand(char str[]){
  int idx = 0;

  while(Serial.available()>0){
    char ch = Serial.read();
    /*
    Block below ensures that we only capture the 
     chars that can fit and ignore the rest
     This is because Serial.flush() doesn't clear 
     input stream
     */
    if(idx<MAX_INPUT_SIZE-2){
      str[idx++]=ch;
      delay(10);
    }
  }

  if(idx>0){
    str[idx] = EOM;
  }

}

/*The new function which was required
since we wanted to control speed of the motor as well
A character array is passed from the Android
phone which needs to be parsed correctly
*/
void performStrCommand(char cmd[]){
  int tmpSpeed=0;
  if(cmd[0] == currCommand)
    return;

  switch(cmd[0]){
  case 'F':
    if(isColliding)
      return; //Don't move forward if there's an obstacle
    pinMode(motorOnePinB, OUTPUT);
    pinMode(motorTwoPinB, OUTPUT);
    digitalWrite(motorOnePinB, LOW);
    digitalWrite(motorTwoPinB, LOW);

    digitalWrite(motorOneEnablePin, HIGH);
    digitalWrite(motorTwoEnablePin, HIGH);

    analogWrite(motorOnePinA, speed);
    analogWrite(motorTwoPinA, speed);

    direction = FORWARD;
    break;
  case 'B':
    pinMode(motorOnePinA, OUTPUT);
    pinMode(motorTwoPinA, OUTPUT);
    digitalWrite(motorOnePinA, LOW);
    digitalWrite(motorTwoPinA, LOW);

    digitalWrite(motorOneEnablePin, HIGH);
    digitalWrite(motorTwoEnablePin, HIGH);

    analogWrite(motorOnePinB, speed);
    analogWrite(motorTwoPinB, speed);
    direction = BACKWARD;
    break;
  case 'L':
    pinMode(motorOnePinA, OUTPUT);
    pinMode(motorTwoPinB, OUTPUT);
    digitalWrite(motorOnePinA, LOW);
    digitalWrite(motorTwoPinB, LOW);

    digitalWrite(motorOneEnablePin, HIGH);
    digitalWrite(motorTwoEnablePin, HIGH);

    analogWrite(motorOnePinB, speed);
    analogWrite(motorTwoPinA, speed);
    direction = LEFT;
    break;
  case 'R':
    pinMode(motorOnePinB, OUTPUT);
    pinMode(motorTwoPinA, OUTPUT);
    digitalWrite(motorOnePinB, LOW);
    digitalWrite(motorTwoPinA, LOW);

    digitalWrite(motorOneEnablePin, HIGH);
    digitalWrite(motorTwoEnablePin, HIGH);

    analogWrite(motorOnePinA, speed);
    analogWrite(motorTwoPinB, speed);
    direction = RIGHT;
    break;
  case 'S': //Index 1-3 chars will be speed
    tmpSpeed = (cmd[1] - '0')*100+(cmd[2] - '0')*10+(cmd[3] - '0');
    //100 - 0
    //200 - 255
    speed = ((tmpSpeed-100)*255)/100;
    break;
  case '0':
    motorReset();
    break;
  default:
    break;
  }
  currCommand = cmd[0];
}

/*The old function which required
just a single character to be passed
from the android phone
*/
void performCommand(char command){
  if(command == currCommand)
    return;

  switch(command){
  case 'F':
    if(isColliding)
      return; //Don't move forward if there's an obstacle
    pinMode(motorOnePinB, OUTPUT);
    pinMode(motorTwoPinB, OUTPUT);
    digitalWrite(motorOnePinB, LOW);
    digitalWrite(motorTwoPinB, LOW);

    digitalWrite(motorOneEnablePin, HIGH);
    digitalWrite(motorTwoEnablePin, HIGH);

    analogWrite(motorOnePinA, speed);
    analogWrite(motorTwoPinA, speed);

    direction = FORWARD;
    break;
  case 'B':
    pinMode(motorOnePinA, OUTPUT);
    pinMode(motorTwoPinA, OUTPUT);
    digitalWrite(motorOnePinA, LOW);
    digitalWrite(motorTwoPinA, LOW);

    digitalWrite(motorOneEnablePin, HIGH);
    digitalWrite(motorTwoEnablePin, HIGH);

    analogWrite(motorOnePinB, speed);
    analogWrite(motorTwoPinB, speed);
    direction = BACKWARD;
    break;
  case 'L':
    pinMode(motorOnePinA, OUTPUT);
    pinMode(motorTwoPinB, OUTPUT);
    digitalWrite(motorOnePinA, LOW);
    digitalWrite(motorTwoPinB, LOW);

    digitalWrite(motorOneEnablePin, HIGH);
    digitalWrite(motorTwoEnablePin, HIGH);

    analogWrite(motorOnePinB, speed);
    analogWrite(motorTwoPinA, speed);
    direction = LEFT;
    break;
  case 'R':
    pinMode(motorOnePinB, OUTPUT);
    pinMode(motorTwoPinA, OUTPUT);
    digitalWrite(motorOnePinB, LOW);
    digitalWrite(motorTwoPinA, LOW);

    digitalWrite(motorOneEnablePin, HIGH);
    digitalWrite(motorTwoEnablePin, HIGH);

    analogWrite(motorOnePinA, speed);
    analogWrite(motorTwoPinB, speed);
    direction = RIGHT;
    break;
  case '0':
    motorReset();
    break;
  default:
    break;
  }
  currCommand = command;
}

//This stops the motors from running 
//by putting both pins of each motor to 0
void motorReset(){
  analogWrite(motorOnePinA, 0);
  analogWrite(motorTwoPinA, 0);
  analogWrite(motorOnePinB, 0);
  analogWrite(motorTwoPinB, 0);
}

Feel free to leave a comment if anything isn’t clear.

15 thoughts on “Android and Arduino Serial Bluetooth App – BlueSerial

  1. Glad you found it useful. I plan to release it on github one of these days as soon as I get some time. I’ve posted the Arduino code as well, let me know if you have any questions about it.

  2. Hi
    I am s/w programmer, and novice in getting android commanding devices via Bluetooth. Please help me know what i would be needing to get android phones to send and receive information to microcontrollers, any place link to give me good start

    • It depends on your goals in a lot of ways. To interface android to microcontrollers, there are primarily 3 ways – bluetooth, internet and direct usb interface, arranged in the order of increasing difficulty. My suggestion to you would be to start with a bluetooth interface since that’s the easiest and simplest way to get started. Later on, you can work with internet connectivity which would be needed the minute you want to do something more complicated

  3. I’m looking to send data (voltage, current, speed) from my arduino to my android. I’ve used your app and it works perfectly! However, I would like to use this data on my android and do calculations. How can I convert these “strings” of text/numbers into integers to use for calculations? Is that possible?

  4. How to Hold the button and let the robot moving?
    What I can do for my robot is only setOnClickListener. Do you mind to share your code with me? Thank you very much.

  5. Hi Zoro – To answer your question, you set it to send one command on touch and another command on release. Similar to this answer:

    http://stackoverflow.com/a/5765920/1287554

    So the robot will keep moving forward until it receives the stop command which is on release.

    The entire code for the app is shared on github and the link is provided above. I figure it’s a simple task to modify the code to do this!

  6. After I initially commented I seem to have clicked the
    -Notify me when new comments are added- checkbox and from now on each time a comment is added I recieve 4
    emails with the same comment. There has to be an easy method
    you can remove me from that service? Thanks a lot!

Leave a reply to voidcast Cancel reply