Android Bluetooth joystick

@tolisn63

I just tried out the new sketch. It is working great. All button now work as well as the data fields. Also the camera has very little lag (<0.5sec) after I switched it to a lower res. (320x240) which is absolutely usable.

Thanks for the good new 8) 8) 8)

  1. Is it possible to change the orientation of the settings screen so it is the same as the main control screen ? 2.Also it would be nice if the data receiving fields could also accept incoming text.

Will look into that matter ;)

one question, when the buttons are pressed and the color becomes green, does the tablet do that or is it feedback from the arduino ?

This is the real button position - button first becomes green "locally" as an Android feature - position is then sent to Arduino - Arduino sends back the actual button position See replies #36 and #73

A good example is toggle (momentary) buttons Button is set green by Android and reset white by Arduino after 250 milliseconds, to create a visual effect.

thanks for all your hard work. Looking forward to trying your newest version.

:)

@tolisn63

  1. Is it possible to change the orientation of the settings screen so it is the same as the main control screen ? 2.Also it would be nice if the data receiving fields could also accept incoming text.

Will look into that matter ;)

You got it ;) ;) ;) check your mail

Total RC Commander V1.1A - Data fields now accept integers, floats and text messages - Improved video management - adjustable Option screen orientation

Important: To allow text messages, Arduino to Android communication protocol has been modified Please use and adapt "AndroTest_PlusV12_string.ino" demo sketch

Let me have your feedback and a screenshot for your specific Android device

@all Joystick BT Plus (6 buttons, 3 datafields) and Total RC Commander (video from IP camera) will be available on Google Play within a month for a symbolic fee

In the meantime, please contact me via PM

Next version: remote control using built-in accelerometers (see reply #165) :P

Enjoy

EDIT: Joystick BT Plus is now Joystick bluetooth Commander V4.0 available on Google Play as a free upgrade See reply #181

I just posted a video showing tank control using Total RC Commander.

See it in action in the Exhibition Section

To obtain the App, please contact me via PM

Hi Kas Thanks for the reply Can I use hardware serial with this on my mega2560 (it has 4 hardware serial ports) and how ?

Hi tolisn63 Not too familiar with the Mega :|

  • remove #include "SoftwareSerial.h"
  • remove SoftwareSerial mySerial(2,3);
  • search/replace mySerial >> Serial1

pin#19 to TX bluetooth module pin#18 to RX bluetooth module

You should be all set ;) Let me know the outcome

Hi Kas

Thanks for the information. It work great as you suggested.

Joystick BT Plus (up to 6 buttons, up to 3 free format datafields) is now - Joystick bluetooth Commander V4.0 - and will be available on Google Play as a free upgrade.

RC car remote control

here, Joystick bluetooth Commander is configured as a tool for remotely tuning a PID loop in various projects (DC motor control, balancing bot, Gyro stabilized camera gimbal ...) For this purpose, buttons are configured as "momentary"

To allow text datafield, [u]Communication Protocol has changed[/u] Please use and adapt this new demo sketch (AndroTest_V13.ino) to your own needs

#define VERSION     "AndroTest V1.3 - @kas2014\ndemo for V4.X  (6 button version)"


// V1.3  renamed for publishing
// V1.2  Text display   ** not backward compatible **
// V1.1  Integer display
// V1.0  6 buttons + 4 data char implemented

// Demo setup:
// Button #1 controls pin13 LED
// Button #2 starts DEBUG
// Button #3 displays demo message
// Button #4 toggle datafield display rate
// Button #5 configured as "push" button (momentary)

// Arduino pin#2 to TX BlueTooth module
// Arduino pin#3 to RX BlueTooth module
// make sure your BT board is set @57600 bps
// better remove SoftSerial for PWM based projects

// For Mega 2560:
// remove   #include "SoftwareSerial.h", SoftwareSerial mySerial(2,3);
// search/replace  mySerial  >> Serial1
// pin#18 to RX bluetooth module, pin#19 to TX bluetooth module

#include "SoftwareSerial.h"

#define    STX          0x01
#define    ETX          0x00
#define    ledPin       13
#define    SLOW         1000                           // Datafields refresh rate (ms)
#define    FAST         250                            // Datafields refresh rate (ms)

boolean DEBUG = false;

** The message exceeds the maximum allowed length (9500 characters)  **
See my next message

App will be uploaded within a few hours

As of today, Joystick bluetooth Commander has been downloaded 3720 times :) :) :) thanks for your ongoing interest

** deprecated, please use AndroTest V1.41 ** see reply #212

AndroTest V1.3.ino Demo sketch for Joystick bluetooth Commander V4.X

#define VERSION     "AndroTest V1.3 - @kas2014\ndemo for V4.X  (6 button version)"

// V1.3  renamed for publishing
// V1.2  Text display   not backward compatible
// V1.1  Integer display
// V1.0  6 buttons + 4 data char implemented

// Demo setup:
// Button #1 controls pin13 LED
// Button #2 starts DEBUG
// Button #3 displays demo message
// Button #4 toggle datafield display rate
// Button #5 configured as "push" button (momentary)

// Arduino pin#2 to TX BlueTooth module
// Arduino pin#3 to RX BlueTooth module
// make sure your BT board is set @57600 bps
// better remove SoftSerial for PWM based projects

// For Mega 2560:
// remove   #include "SoftwareSerial.h", SoftwareSerial mySerial(2,3);
// search/replace  mySerial  >> Serial1
// pin#18 to RX bluetooth module, pin#19 to TX bluetooth module

#include "SoftwareSerial.h"

#define    STX          0x01
#define    ETX          0x00
#define    ledPin       13
#define    SLOW         1000                         // Datafields refresh rate (ms)
#define    FAST         250                          // Datafields refresh rate (ms)

boolean DEBUG = false;

SoftwareSerial mySerial(2,3);                         // BlueTooth module: pin#2=TX pin#3=RX
int i=0;
byte cmd[6] = {0, 0, 0, 0, 0, 0};                     // bytes received
byte buttonStatus = 0;                                // first Byte sent to Android device
long previousMillis = 0;                              // last time Buttons status was updated
boolean setButtonFeedback = false;                    // momentary buttons feedback to Android device
long sendInterval = SLOW;                             // interval between Buttons status transmission (milliseconds)
String displayStatus = "xxxx";                        // message to Android device

void setup()  {
  Serial.begin(57600);
  mySerial.begin(57600);                              // adjust to your BT board
  pinMode(ledPin, OUTPUT);     
  Serial.println(VERSION);
  delay(300);
}

void loop() {
  if(mySerial.available())  {                          // data received from smartphone
    delay(5);
    cmd[0] =  mySerial.read();  
    if(cmd[0] == STX)  {  
      i=1;      
      while(mySerial.available())  {
        cmd[i] = mySerial.read();
        if(cmd[i] == ETX)  {
          if(i==2 && cmd[1]>48)                    break;    // Button data
          if(i==5 && cmd[1]<3 && cmd[3]<3)         break;    // Joystick data
        }
        if(i>5)   break;
        i++;
      }
      if     (i==2)   getButtonState(cmd[1]);            // 3 Bytes
      else if(i==5)   getJoystickState(cmd);             // 6 Bytes
      else            Serial.println("**  Communication error **");
      if(DEBUG)       printDebug(i);
    }
  }  else  
      sendBlueToothData();  
  delay(5);
}

void sendBlueToothData()  {
  static long previousMillis = 0;                             
  long currentMillis = millis();
  if(setButtonFeedback == true)  {                      // allow momentary button visual effect
    previousMillis = currentMillis + 250;   
//  previousMillis = currentMillis - 200;   
    setButtonFeedback = false;
  }
  if(currentMillis - previousMillis > sendInterval) {   // send data to smartphone
    previousMillis = currentMillis; 

// Data frame transmitted back from Arduino to Android device:
// < 0X02   Buttons state   0X01   DataField#1   0x04   DataField#2   0x05   DataField#3    0x03 >  
// < 0X02       01011       0X01      120.00     0x04      -4500      0x05   Motor enabled  0x03 >    // example

    mySerial.print((char)0x2);                                             // 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)0x3);                                             // End of Transmission
  }  
}

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

int GetdataInt1()  {             // Data dummy values sent to Android device for demo purpose
  static int i= -3000;           // Replace with your own code
  i += 111;
  if(i >0)    i = -3000;
  return i;  
}

float GetdataFloat2()  {           // Data dummy values sent to Android device for demo purpose
  static float i=50;               // Replace with your own code
  i-=.8;
  if(i <-50)    i = 50;
  return i;  
}

void getJoystickState(byte data[5])    {
  int joyX = (data[1]<<7) + data[2];
  int joyY = (data[3]<<7) + data[4];
  joyX = joyX - 200;              // Offset to avoid
  joyY = joyY - 200;              // transmitting negative numbers
  
  if(!DEBUG)  {
    Serial.print("Joystick position:  ");
    Serial.print(joyX);  
    Serial.print(", ");  
    Serial.println(joyY); 
  }
// Your code here ...
}

void getButtonState(int bStatus)  {
  switch (bStatus) {
// -----------------  BUTTON #1  -----------------------
    case '1':
      buttonStatus |= B000001;        // ON
      Serial.println("\n** Button_1: ON **");
      // your code...      
      displayStatus = "LED ";
      Serial.println(displayStatus);
      digitalWrite(ledPin, HIGH);
      break;
    case '2':
      buttonStatus &= B111110;        // OFF
      Serial.println("\n** Button_1: OFF **");
      // your code...      
      displayStatus = "LED ";
      Serial.println(displayStatus);
      digitalWrite(ledPin, LOW);
      break;

// -----------------  BUTTON #2  -----------------------
    case '3':
      buttonStatus |= B000010;        // ON
      Serial.println("\n** Button_2: ON **");
      // your code...      
      displayStatus = "DEBUG ";
      Serial.println(displayStatus);
      DEBUG = true;
      break;
    case '4':
      buttonStatus &= B111101;        // OFF
      Serial.println("\n** Button_2: OFF **");
      // your code...      
      displayStatus = "DEBUG ";
      Serial.println(displayStatus);
      DEBUG = false;
      break;

// -----------------  BUTTON #3  -----------------------
    case '5':
      buttonStatus |= B000100;        // ON
      setButtonFeedback = true;
      Serial.println("\n** Button_3: ON **");
      // your code...      
      displayStatus = "Motor #1 enabled"; // Demo text message
      Serial.println(displayStatus);
      break;
    case '6':
      buttonStatus &= B111011;      // OFF
      Serial.println("\n** Button_3: OFF **");
      // your code...      
      displayStatus = "Motor #1 stopped";
      Serial.println(displayStatus);
      break;

// -----------------  BUTTON #4  -----------------------
    case '7':
      buttonStatus |= B001000;       // ON
      setButtonFeedback = true;
      Serial.println("\n** Button_4: ON **");
      // your code...      
      displayStatus = "Datafield update ";
      Serial.println(displayStatus);
      sendInterval = FAST;
      break;
    case '8':
      buttonStatus &= B110111;    // OFF
      Serial.println("\n** Button_4: OFF **");
      // your code...      
      displayStatus = "Datafield update ";
      Serial.println(displayStatus);
      sendInterval = SLOW;
     break;

// -----------------  BUTTON #5  -----------------------
    case '9':           // configured as momentary button
//      buttonStatus |= B010000;        // ON
      Serial.println("\n** Button_5: ++ pushed ++ **");
      // your code...      
      displayStatus = "Button_5: ++ pushed ++";
      break;
//   case 'A':
//     buttonStatus &= B101111;        // OFF
//     // your code...      
//     break;

// -----------------  BUTTON #6  -----------------------
    case 'B':
      buttonStatus |= B100000;        // ON
      Serial.println("\n** Button_6: ON **");
      // your code...      
       displayStatus = "Button #6 ON"; // Demo text message
     break;
    case 'C':
      buttonStatus &= B011111;        // OFF
      Serial.println("\n** Button_6: OFF **");
      // your code...      
      displayStatus = "Button #6 OFF";
      break;
  }
// ---------------------------------------------------------------
}

void printDebug(int nByte)  {
  if(nByte ==2)    {   
    Serial.print("buttonStatus: "); Serial.print(buttonStatus); 
    Serial.print("  bin: "); Serial.println(getButtonStatusString());    
    Serial.print("Button: < ");
  }
  else if(nByte ==5)  Serial.print("Joystick: < ");
  else                Serial.print("*error*: < ");
  for(int j =0; j");
}

EDIT: This sketch assumes that your BT card is configured @57600bps

I have just tried the version 4 of joystick BT controller, but don't get any response in the serial monitor with sketch AndroTest V1.3.ino. What does Arduino pin #2 and #3 means? I used the same setting as for joystick BT controller v3.1 but it doesn't work. Any ideas what to do?

Hi hulkpeppe, welcome to the Forum as a new contributor

What does Arduino pin #2 and #3 means?

Digital I/O #2 to be connected to TX pin from Bluetooth module Digital I/O #3 to be connected to RX pin from Bluetooth module

...but it doesn't work. Any ideas what to do?

I need more information to make a clever guess ;)

I understand you are already seasoned with V3.1 and AndroLEDV10_3.ino

[u]Android side/u: 1) go to Option/About and confirm that installed version is V4.0 (or higher) 2) can you move the joystick and display position at bottom left 3) are you connected ("connected to: XXX", green text)

[u]Arduino side:[/u] 4) are you using AndroTest V1.3.ino (or higher) 5) are RX/TX connected as per above 6) is your Bluetooth card already configured @57600 bps (most are 9600bps by default) 7) is your Bluetooth card LED solid red (blinking red = not connected) 8 ) is your Serial monitor configured @57600 bps

[u]Finally:[/u] 9) your serial monitor should anycase display: AndroTest V1.3 - @kas2014 demo for V4.X (6 button version) does it ??

  • any additional information ??

Please advise

@all Please confirm V4.0 works OK for you

I'm using Itead BT shield and here are not Arduino pin #2 and #3 routed to BT TX and RX. I made a strap from Arduino pin #2 to BT shield TX and Pin #3 to RX. But still no sucess. :~

Yes, I got the V3.1 and AndroLEDV10_3.ino working with serial monitor and was able to visulize button #1 ON/OFF.

All checkpoints (1-7) in your answer are fulfilled.

In the Androind BT commander I observed some information under Data1 and Data2 (not under Data3). When I push any buttons they only got activated (green) a very short time. I don't see that LED at Arduino pin#13 got active when pushing button 1.

In the Androind BT commander I observed some information under Data1 and Data2 (not under Data3)

Interesting

IF - Data1 cycles from -3000 to 0 with 111 increment (see GetdataInt1) - Data2 cycles from 50 to -50 with -0.8 increment (see GetdataFloat2) - Data3 shows "xxxx"

THEN Arduino to Android communication is OK Android to Arduino communication is not wired correctly

When I push any buttons they only got activated (green) a very short time

Makes sense, Arduino will always feed back its own real buttons position and overwrite the Android display

Assuming you have the "Master/Slave" model: - make sure the switch is in DAT mode - place the TX jumper on pin 4 and the RX on Pin 5 - change "SoftwareSerial mySerial(2,3);" to "SoftwareSerial mySerial(4,5);"

Should work ;)

Hi Kas

Can you please post the communication protocol for Total RC commander V1.1 ? The communication from the android device to the arduino and between the arduino and the android device.

Total RC commander is the "video aware" version of Joystick BT Commander V4.x They both share the same Communication Protocol with Arduino

[u]Communication from Android to Arduino/u

  • Joystick information: Joystick data is transmitted as an integer = 2 Bytes (Most Significant Byte + Less Significant Byte) according to this data frame:

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
          sendMessage( new String(new byte[] {STX, (byte) (XvalB / 128), (byte)(XvalB % 128), (byte)(YvalB / 128), (byte)(YvalB % 128), ETX } ));

So, for Xval=0 Yval=0: XvalB = YvalB = 200 XvalB / 128 = YvalB / 128 = 1 XvalB % 128 = XvalB % 128 = 72 Data frame: <2 1 72 1 72 3>

for Xval=100 Yval=100: XvalB = YvalB = 300 XvalB / 128 = YvalB / 128 = 2 XvalB % 128 = XvalB % 128 = 44 Data frame: <2 2 44 2 44 3>

The data frame is send via BlueTooth to the arduino board and decoded. This is the AndroTest V1.3.ino code snippet:

 void getJoystickState(byte data[5])    {
  int joyX = (data[1]<<7) + data[2];
  int joyY = (data[3]<<7) + data[4];
  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: 1 Button #1 OFF: 2 Button #2 ON: 3 Button #2 OFF: 4 Button #3 ...

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

void getButtonState(int bStatus)  {
  switch (bStatus) {
// -----------------  BUTTON #1  -----------------------
    case '1':
      buttonStatus |= B000001;        // ON
      Serial.println("\n** Button_1: ON **");
      // your code...      
      displayStatus = "LED ";
      Serial.println(displayStatus);
      digitalWrite(ledPin, HIGH);
      break;
    case '2':
      buttonStatus &= B111110;        // OFF
      Serial.println("\n** Button_1: OFF **");
      // your code...      
      displayStatus = "LED ";
      Serial.println(displayStatus);
      digitalWrite(ledPin, LOW);
      break;

// -----------------  BUTTON #2  -----------------------
    case '3':
      buttonStatus |= B000010;        // ON
      Serial.println("\n** Button_2: ON **");
      // your code...      
      displayStatus = "DEBUG ";
      Serial.println(displayStatus);
      DEBUG = true;
      break;
    case '4':
      buttonStatus &= B111101;        // OFF
      Serial.println("\n** Button_2: OFF **");
      // your code...      
      displayStatus = "DEBUG ";
      Serial.println(displayStatus);
      DEBUG = false;
      break;

    ....
}

[u]Communication back from Arduino to Android:[/u]

Arduino code

void sendBlueToothData()  {

  ....

    mySerial.print((char)0x2);                                             // 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)0x3);                                             // 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 ;)

Firstly thanks Kas this is a great app/sketch.

I too couldnt get it to work but after some playing around i got this to work with these settings:

// Arduino RX to TX BlueTooth module // Arduino TX to RX BlueTooth module // make sure your BT board is set @9600 bps //Set Serial Monitor rate to 9600 bps

Thanks Kas for the protocol information

@Maudey Thanks for the feedback I edited reply #182 based on your comments Please post an App screenshot, together with your screen size and resolution This will help me optimizing App display layout

What BT brand are you using ?? Most boards default to 9600bps, which is a bit slow I strongly suggest to boost your board @57600bps

@tolisn63 Did you try the on board mini router ?? I hardwired connection between IP camera and router and still have to observe any noticiable lag 8)

Hi Kas

The mini router did not come in yet. I'm waiting to see how it goes.

Hi kas

Thank's for your help! Now it works fine for me :) I really appreciate this app/sketch :D

Hi I have a small problem. I didnt get receive any of datafields.

Hi kas Thanks for your help! Now it works fine for me :) I really appreciate this app/sketch :D

Thanks hulkpeppe for this positive feedback

@n3kx

Hi I have a small problem. I didn't get receive any of datafields.

I bit more information would definitely help ...