Android Bluetooth joystick

New communication protocol for Joystick BT Commander V5.x

Communication from Android to Arduino (or to any microcontroller)

  • Joystick information:
    Joystick data is transmitted as ASCII data, according to this data frame:
    <STX "Joy_X + 200" "Joy_Y + 200" ETX>

with STX=0x2, ETX=0x3

This is the relevant Android (Java) code snippet from Joystick Bluetooth Commander:

    final int XvalB = Xval + 200;
    final int YvalB = Yval + 200;
    if((((Xant!=Xval) || (Yant!=Yval)) || (mTimeoutCounter>=mMaxTimeoutCount && mMaxTimeoutCount>-1)))	   // joystick position changed, or timeout occurred
    	String toSend = String.format("%c%d%d%c", STX, XvalB, YvalB, ETX);
    	sendMessage(toSend);

So, for Xval=0 Yval=0:
XvalB = YvalB = 200
'2' is Ascii 32 hex (decimal 50)
'0' is Ascii 30 hex (decimal 48)
Data frame: <0x02 0x32 0x30 0x30 0x32 0x30 0x30 0x03>

for Xval=100 Yval=100:
XvalB = YvalB = 300
'3' is Ascii 33 hex (decimal 51)
'0' is Ascii 30 hex (decimal 48)
Data frame: <0x02 0x33 0x30 0x30 0x33 0x30 0x30 0x03>

The data frame is send via BlueTooth to the arduino board and decoded.
This is the Arduino code snippet from AndroTest V2.0:

 void getJoystickState(byte data[8])    {
  int joyX = (data[1]-48)*100 + (data[2]-48)*10 + (data[3]-48);       // obtain an Int from the ASCII representation
  int joyY = (data[4]-48)*100 + (data[5]-48)*10 + (data[6]-48);
  joyX = joyX - 200;                                                  // Offset to avoid
  joyY = joyY - 200;                                                  // transmitting negative numbers
 }
  • Button information:
    Each time an android button is pressed, the following data frame is transmitted

buttonState is transmitted as a Byte value and reflects the state of the pushed button
Button #1: ON: 'A' OFF: 'B'
Button #2: ON: 'C' OFF: 'D'
Button #3 ...

On the Arduino side, data frame is decoded in getButtonState()

void getButtonState(int bStatus)  {
  switch (bStatus) {
// -----------------  BUTTON #1  -----------------------
    case 'A':
      buttonStatus |= B000001;        // ON
      Serial.println("\n** Button_1: ON **");
      // your code...      
      break;
    case 'B':
      buttonStatus &= B111110;        // OFF
      Serial.println("\n** Button_1: OFF **");
      // your code...      
      break;

// -----------------  BUTTON #2  -----------------------
    case 'C':
      buttonStatus |= B000010;        // ON
      Serial.println("\n** Button_2: ON **");
      // your code...      
      break;
    case 'D':
      buttonStatus &= B111101;        // OFF
      Serial.println("\n** Button_2: OFF **");
      // your code...      
      break;

    ....
}

Communication back from Arduino to Android:
(same as V4.0)

Arduino code

void sendBlueToothData()  {

  ....

    mySerial.print((char)STX);                                             // Start of Transmission
    mySerial.print(getButtonStatusString());  mySerial.print((char)0x1);   // buttons status feedback
    mySerial.print(GetdataInt1());            mySerial.print((char)0x4);   // datafield #1
    mySerial.print(GetdataFloat2());          mySerial.print((char)0x5);   // datafield #2
    mySerial.print(displayStatus);                                         // datafield #3
    mySerial.print((char)ETX);                                             // End of Transmission
  
  ....  
}

Data frame transmitted back from Arduino to Android device: (by default, every 1000ms)
< STX Buttons state 0X01 DataField#1 0x04 DataField#2 0x05 DataField#3 ETX >

example: < 0X02 001011 0X01 120.00 0x04 -4500 0x05 Motor enabled 0x03 >

Button state:
This is a six character string reflecting the Arduino state for buttons position
button #1,#2,#4: ON, all others: OFF >>> 001011
This feedback avoid any discrepancy with the Android device button state
An Arduino Reset will reinitialize the Android buttons, Two way communication is mandatory for "clean" control
Button state string is created in the getButtonStatusString() function.

String getButtonStatusString()  {
  String bStatus = "";
  for(i=0; i<6; i++)  {
    if(buttonStatus & B100000 >>i)      bStatus += "1";
    else                                bStatus += "0";
  }
  return bStatus;
}

Datafields:
Data is transmitted as ASCII characters using Serial.print()
Numbers are printed using an ASCII character for each digit
120.00 >>> 0X31, 0X32, 0X30, 0X2E, 0X30, 0X30

So < 0x02 001011 0x01 120.00 0x04 -4500 0x05 Motor enabled 0x03 >
is actually transmitted as
< 0x02, 0x30,0x30,0x31,0x30,0x31,0x31, 0X01, 0x31,0x32,0x30,0x2E,0x30,0x30, **
** 0x04, 0x2D,0x34,0x35,0x30,0x30, 0x05, 0x4D,0x6F,0x74,0x6F,0x72,0x20,0x65,

** 0x6E,0x61,0x62,0x6C,0x65,0x64, 0x03 >**
without commas and spaces

Should you have additional questions, let me know :wink: