Android Bluetooth joystick

kas, I have good news I got rover working. I calibrated ESC and now it's working fine.
I do have a video but its not very good. Rover is very difficult to control as Left and Right Stick movements
cause the rover to go forward or backwards and up/down movements cause it to turn.

I tried to capture this on video but it was difficult by myself. I also need to dial in some expo as it's very sensitive before it gets full power.

Thank you sir.

Video

I do have a video but its not very good. Rover is very difficult to control as Left and Right Stick movements cause the rover to go forward or backwards and up/down movements cause it to turn.

As mentioned in the code, adjust motors direction

Depending on your motor connections, you probably have to change
servo_L = map(servo_L, -100, 100, 180, 0); // << adjust to change motor direction XXX
servo_R = map(servo_R, -100, 100, 0, 180);

to
servo_L = map(servo_L, -100, 100, 0, 180); // << adjust to change motor direction XXX
servo_R = map(servo_R, -100, 100, 0, 180);

During testing, you may change
myservoX.write(servo_L);
myservoY.write(servo_R);

to
myservoX.write(servo_L /2);
myservoY.write(servo_R /2);

I found out I have to calibrate the esc every time I make changes to the pwn signal. After a couple more hours of messing it I now have a drivable unit . I can't thank you enough Kas . :slight_smile:

Here is a video , it's not very good as it's hard to drive and video . I will have my wife help me tomorrow .

How can I display mAh and voltage ? The other things I'm curious about as if signal is weak or missing then it will act as dead man switch to motors .

Also can I insert code from example ino file for the button commands to actual a servo ?

Video

Thanks ,
FullSpool

Here is a video

Seems we are on the right track :wink:

How can I display mAh and voltage ? The other things I'm curious about as if signal is weak or missing then it will act as dead man switch to motors .

Let's start by the Dead Man implementation
Which safety level do you require ??

  • moderate: boot will stop if signal is lost and immediately restart when signal is back
  • high: needs Arduino reboot to restart motion

Let me have a copy of your actual working sketch
We need to work on the very same code

Is there mV and mA outputs on your driver board ??

Also can I insert code from example ino file for the button commands to actual a servo ?

Please elaborate

Out of curiosity, where are you based in this Global Village ?

Kas,

This sketch is working really well but I have expo jumper installed on the ESC . If not, it's to sensitive with the joy stick commander app. I am in the USA , if you want exact location I can PM you .

I have no pins assigned on my UNO yet for mA or voltage read out. I am powering my rover with
a 3s lipo (4.1v x 3= 12.3 v fully charged) so I assume I will need to solder in a jumper off the main feed and tie it into an analog pin on the uno? or tie into the balance port on the Lipo battery itself? I can't use the 5v out pin on the uno as it wont show me true voltage as I am powering it with more then 5v.

I just need moderate dead mans kill switch.

I would also like button 1 to tie into pin 8 on the uno, when button 1 is pushed a new servo will sweep 90 degrees, when button 1 is pressed again it will move back to original state.

#define VERSION     "\n\nAndro_Pan&Tilt V3.6 - @kas2014\n** servo's demo for V5.x App **"

// Controls two servo motors

// V3.6: Android BT Commander V5.X compatible, no button data management
// V3.0: Android BT Commander V3.X compatible, no button data management
// V2.5 can receive both Byte & Integer data
// V2.0: removed SoftwareSerial

// Android BT Commander settings:
// Options/Options for advanced users/Data Range        >>>  -100 to +100
// Options/Options for advanced users/Refresh interval  >>>  50ms

//  Arduino pin #0 to TX BlueTooth module
// BT TX to be disconnected from D0 during sketch upload

#include <Servo.h> 

boolean    DEBUG =         true;

#define    pinServo_X     9            //<<  ServoX pin
#define    pinServo_Y     10           //<<  ServoY pin
#define    STX            0x02
#define    ETX            0x03
#define    MIN_Y          0  //45             // vertical move limitation,
#define    MAX_Y          180                 // adjust to needs
#define    ZERO_Y         -1  //60             // vertical zero offset

byte cmd[8] = {0, 0, 0, 0, 0, 0, 0, 0};
Servo myservoX;                         // create servo objects
Servo myservoY; 

void setup()  {
 Serial.begin(57600);
 myservoX.attach(pinServo_X);  
 myservoY.attach(pinServo_Y);  
 if(DEBUG)    Serial.println(VERSION);
}

void loop() {
  if(Serial.available())  {                            // data received from smartphone
   delay(2);
   cmd[0] =  Serial.read();  
   if(cmd[0] == STX)  {
     int i=1;      
     while(Serial.available())  {
       delay(1);
       cmd[i] = Serial.read();
       if(cmd[i]>127 || i>7)                 break;     // Communication error
       if((cmd[i]==ETX) && (i==2 || i==7))   break;     // Button or Joystick data
       i++;
     }
     if(i==7)     setServoPosition(cmd);
   }
 }
}

void setServoPosition(byte data[8])    {   // differential steering version
 int servo_L, servo_R;
 int joyX = (data[1]-48)*100 + (data[2]-48)*10 + (data[3]-48);       // obtain the 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

 if(joyX<-100 || joyX>100 || joyY<-100 || joyY>100)     return;      // communication error

 if(joyY >-10)  {                                                    // differential steering
   servo_L = (joyY - (3*joyX)/4);
   servo_R = (joyY + (3*joyX)/4);
 }  else  {
   servo_L = (joyY + (3*joyX)/4);
   servo_R = (joyY - (3*joyX)/4);
 }
 
 servo_L = map(servo_L, -100, 100, 0, 180);   //  << adjust to change motor direction XXX
 servo_R = map(servo_R, -100, 100, 0, 180);   //  <<
 servo_L = constrain(servo_L, 0, 180);
 servo_R = constrain(servo_R, 0, 180);

 myservoX.write(servo_L/2);
 myservoY.write(servo_R/2);
 if(DEBUG)    {Serial.print(joyX); Serial.print(", "); Serial.println(joyY);}

}

This sketch is working really well but I have expo jumper installed on the ESC . If not, it's to sensitive with the joy stick commander app

Is it OK with the expo jumper ??
The signal can also be tuned within the Arduino code

I am powering my rover with a 3s lipo (4.1v x 3= 12.3 v fully charged) so I assume I will need to solder in a jumper off the main feed and tie it into an analog pin on the uno?

Don't do that :astonished: you will fry your Uno
Analog pins accept no more than 5 Volts, you need a voltage divider

Back to full blown code, with feedback to smartphone
This is AndroTest_Servo_fullspool V1.1, with Dead Man implementation

#define VERSION     "\n\nAndroTest_Servo_fullspool V1.x - @kas2016\ndemo for servo's"

// V1.1  added Dead Man feature
// V1.0  Basic implementattion

// Android BT Commander settings:
// Options/Options for advanced users/Data Range        >>>  -100 to +100
// Options/Options for advanced users/Refresh interval  >>>  50ms

//  Arduino pin #0 to TX BlueTooth module
// BT TX to be disconnected from D0 during sketch upload

#include <Servo.h> 

#define    pinServo_X     9            //<<  ServoX pin
#define    pinServo_Y     10           //<<  ServoY pin
#define    STX            0x02
#define    ETX            0x03
#define    ledPin         13

Servo myservoX;                                         // create servo objects
Servo myservoY; 
byte cmd[8] = {0, 0, 0, 0, 0, 0, 0, 0};                 // bytes received
byte buttonStatus = 0;                                  // first Byte sent to Android device
long previousMillis = 0;                                // will store last time Buttons status was updated
long sendInterval = 750;                                // interval between Buttons status transmission (milliseconds)
long deadManInterval = 1100;                            // interval between Dead Man checks (milliseconds)
boolean deadManTimeout = false;                         // dead man flag
String displayStatus = "xxxx";                          // message to Android device
int servo_L, servo_R = 90;                              // servo's positioning values

void setup()  {
  Serial.begin(57600);
  myservoX.attach(pinServo_X);  
  myservoY.attach(pinServo_Y);  
  pinMode(ledPin, OUTPUT);     
  while(Serial.available())  Serial.read();          // empty RX buffer
}

void loop() {
  if(Serial.available())  {                              // data received from smartphone
    deadManTimeout = false;                              // reset Dead Man
    delay(2);
    cmd[0] =  Serial.read();  
    if(cmd[0] == STX)  {
      int i=1;      
      while(Serial.available())  {
        delay(1);
        cmd[i] = Serial.read();
        if(cmd[i]>127 || i>7)                 break;     // Communication error
        if((cmd[i]==ETX) && (i==2 || i==7))   break;     // Button or Joystick data
        i++;
      }
      if     (i==2)          getButtonState(cmd[1]);    // 3 Bytes  ex: < STX "C" ETX >
      else if(i==7)          getJoystickState(cmd);     // 6 Bytes  ex: < STX "200" "180" ETX >
    }
  } 
  sendBlueToothData();
  checkDeadMan();
  motorsControl(); 
}

void checkDeadMan()  {                                                  // stop engines if signal is lost
  static long previousMillis = 0;                             
  long currentMillis = millis();
  if(currentMillis - previousMillis > deadManInterval) {                // check is performed every deadManInterval ms
    previousMillis = currentMillis;
    if(deadManTimeout)  { 
      myservoX.write(90);                                               // stop motors
      myservoY.write(90);
    }
    deadManTimeout = true;
  }  
}

void motorsControl()  {
  myservoX.write(servo_L/2);
  myservoY.write(servo_R/2);
}

void sendBlueToothData()  {
  static long previousMillis = 0;                             
  long currentMillis = millis();
  if(currentMillis - previousMillis > sendInterval) {   // send data back 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

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

String getButtonStatusString()  {
  String bStatus = "";
  for(int 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= -30;              // Replace with your own code
  i ++;
  if(i >0)    i = -30;
  return i;  
}

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

void getJoystickState(byte data[8])    {
  int joyX = (data[1]-48)*100 + (data[2]-48)*10 + (data[3]-48);       // obtain the 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

  if(joyX<-100 || joyX>100 || joyY<-100 || joyY>100)     return;      // communication error

  if(joyY >-10)  {                                                    // differential steering
    servo_L = (joyY - (3*joyX)/4);
    servo_R = (joyY + (3*joyX)/4);
  }  else  {
    servo_L = (joyY + (3*joyX)/4);
    servo_R = (joyY - (3*joyX)/4);
  }
  
  servo_L = map(servo_L, -100, 100, 0, 180);   //         << adjust to change motor direction
  servo_R = map(servo_R, -100, 100, 0, 180);
  servo_L = constrain(servo_L, 0, 180);
  servo_R = constrain(servo_R, 0, 180);
}

void getButtonState(int bStatus)  {
  switch (bStatus) {
// -----------------  BUTTON #1  -----------------------
    case 'A':
      buttonStatus |= B000001;        // ON
      displayStatus = "LED <ON>";
      digitalWrite(ledPin, HIGH);
      break;
    case 'B':
      buttonStatus &= B111110;        // OFF
      displayStatus = "LED <OFF>";
      digitalWrite(ledPin, LOW);
      break;

// -----------------  BUTTON #2  -----------------------
    case 'C':
      buttonStatus |= B000010;        // ON
      displayStatus = "Button2 <ON>";
      break;
    case 'D':
      buttonStatus &= B111101;        // OFF
      displayStatus = "Button2 <OFF>";
      break;

// -----------------  BUTTON #3  -----------------------
    case 'E':
      buttonStatus |= B000100;        // ON
      displayStatus = "Button3 <ON>";
      break;
    case 'F':
      buttonStatus &= B111011;      // OFF
      displayStatus = "Button3 <OFF>";
      break;

// -----------------  BUTTON #4  -----------------------
    case 'G':
      buttonStatus |= B001000;       // ON
      displayStatus = "Button4 <ON>";
      break;
    case 'H':
      buttonStatus &= B110111;    // OFF
      displayStatus = "Button4 <OFF>";
     break;

// -----------------  BUTTON #5  -----------------------
    case 'I':                   // configured as momentary button
      displayStatus = "Button5: <pushed>";
      break;

// -----------------  BUTTON #6  -----------------------
    case 'K':
      buttonStatus |= B100000;        // ON
      displayStatus = "Button6 <ON>"; // Demo text message
      break;
    case 'L':
      buttonStatus &= B011111;        // OFF
      displayStatus = "Button6 <OFF>";
      break;
  }
// ---------------------------------------------------------------
}

I have no possibilities to test the code for the moment, but at least, it compiles :wink:

Make me a favor, edit your last post and embed your code as such
[c ode] ... code... [/c ode] (ommit the two spaces)
or use the </> button at the top left of the "Post reply" dialog
Post will be more legible

kas:
Is it OK with the expo jumper ??
The signal can also be tuned within the Arduino code

Don't do that :astonished: you will fry your Uno
Analog pins accept no more than 5 Volts, you need a voltage divider

Make me a favor, edit your last post and embed your code as such
[c ode] ... code... [/c ode] (ommit the two spaces)
or use the </> button at the top left of the "Post reply" dialog
Post will be more legible

So I can keep tuning the signal by adjusting this part of the code correct?
myservoX.write(servo_L/2);
myservoY.write(servo_R/2);

If I do a voltage divider will it only show the 5v on the telemetry? Or give me my actual 12v reading?

I fixed the post, thanks for the feed back. I will work on it more today.

So I can keep tuning the signal by adjusting this part of the code correct?
myservoX.write(servo_L/2);
myservoY.write(servo_R/2);

Yes, you can use any mathematical function (linear or non linear)

If I do a voltage divider will it only show the 5v on the telemetry? Or give me my actual 12v reading

You will read actual battery voltage
Be prepared to have 1/4W resistors:
1X 4.7K + 1X 10K
or
3X 4.7K

For Amp you will need a 5A Current Sensor Module ACS712 such as this one (2 bucks, shipped)

Thank you Kas , I will get the parts ordered and research the voltage divider .

I tried the new code , when I press button 1 it lights up the LED however when I connect a servo to pin 13 it just twitches.

Next I tested Deadman , whenever signal is lost the motors keep turning in the last known position .

I am not sure how to fix it ?

On a side note I made some new axles as my aluminum axles bend to easy . These are made from drill stock so should be much stronger .

I tried the new code , when I press button 1 it lights up the LED however when I connect a servo to pin 13 it just twitches.
Next I tested Deadman , whenever signal is lost the motors keep turning in the last known position .
I am not sure how to fix it ?

This is AndroTest_Servo_fullspool Version 1.2
// V1.2 added 3rd servo control, fixed Dead Man
Code is attached, you need to be logged to access it
Make sure to connect the AUX servo to pin #8
What is it used for ??

I also noticed on your video that your smartphone don't get any feedback from Arduino
Please connect BT board RX pin to Arduino pin #1
On your smartphone Datafield #1 and #2 will (should) display demo changing numbers
Datafield #3 will display AUX servo and buttons status

These are made from drill stock so should be much stronger

At least they won't bend anymore :wink:

Again, if you make any change to the code, please send me a copy
We really need to stay synchronized

AndroTest_Servo_fullspool_V1.2.ino (7.74 KB)

Kas,

I tested the servo with button 1 and it works now however the dead man test goes from last known for a second or 2 then motors go wide open until signal is restored . The reason I want to move servo arm is for my locking mechanism .

I will test further , the code is attached.

AndroTest_Servo_fullspool_V1.2.ino (7.74 KB)

Please replace

if(deadManTimeout) {
servo_L = 0; // stop motors
servo_R = 0;
}

by

if(deadManTimeout) {
servo_L = 90; // stop motors
servo_R = 90;
}

Can you see changing values in App's datafields ??

That fixed it however there is a 2 second delay from last known position till the motors quit.

Controls are getting really smooth , led lights up and servo actuates as it should for now.
I am really happy how this is progressing . I can't wait till my telemetry parts come in.

New video

That fixed it however there is a 2 second delay from last known position till the motors quit

Want a fast Dead Man ??

replace
long deadManInterval = 1100; // interval between Dead Man checks (milliseconds)
by
long deadManInterval = 550; // interval between Dead Man checks (milliseconds)

Want it faster ?? just let me know :wink:

I am really happy how this is progressing . I can't wait till my telemetry parts come in

Let me know the actual resistors values as soon as you receive them
You can get them right away at your local RadioShack

My local radio shack only had 4.7k 1/2 watt resistors so I will be using 3 of those .

Would it be better to use a zener diode since my voltage may change ? (Not now but may in future)

Résistors are OK

Let me know if 1 second signal drop is OK for Dead Man safety, and please let me have a copy of the modified code

The deadman works perfect, thanks :slight_smile:

Code is attached.

AndroTest_Servo_fullspool_V1.2.ino (7.74 KB)

Here is a new video .

The deadman works perfect, thanks :slight_smile:

finally :wink:

Battery monitoring

Please make sure you understand what you are doing, both on the hard and software sides
You may google for "voltage divider" "arduino"

solder the three 4.7K resistors in series
connect both ends to battery <+> and <->
connect analog input A0 as per drawing

4.7K 4.7K 4.7K
<+> ----///---///-|-///---- <->
|
A0

Before actually connecting to Arduino board, check voltage with a DVM
should read 4 to 4.5 Volts (not 8 to 9V :astonished: )
I don't know your setup, if you have more than one power supply, make sure that grounds are connected

Upload and run AndroTest_Servo_fullspool V1.3
Battery level should be displayed with two decimal digits in DataField #1
Let me have a video including phone screen

AndroTest_Servo_fullspool_V1.3.ino (8.22 KB)

hi... i am new .... i have 1 arduino uno ent 1 motor shield adafruit motor / stepper /servo shield... ent 1 adafruit servo shield...
how to conect the shield adafruit whith rover 5 robot platform? sory for the bad english i am greek ent i don know veri good english... pliz foto how conect the shield whith rover ent how conect the ultra sonic sensor whith arduino?

imail:
pantelis4ever1@hotmail.com