Android Bluetooth joystick

KAS the ESC works perfect when you use traditional radio control , I am thinking it may need to see throttle position at 0 for x seconds before it will power the motors?

Here is me controlling the rover programmed to my radio

Here is serial pic request, I am still researching on my ESC

Kas , I owe you a beer for the help thus far . :slight_smile:

It appears we need to cut the signal for 3-5 seconds or put throttle to 0 . If it see signal then the esc won't engage .

I hooked everything up and moved joy stick to back position on your app and it engaged. Therefore I was able to drive rover forward and back for this video . When I tried to do same procedure and test again it would not engaged the esc ???

Here is video

Here is me controlling the rover programmed to my radio
https://www.youtube.com/watch?v=RBomaEX9W1E

Nice and powerful bot
At which level is differential steering implemented ??

Here is serial pic request, I am still researching on my ESC

Perfect :wink:

It appears we need to cut the signal for 3-5 seconds or put throttle to 0 . If it see signal then the esc won't engage .
I hooked everything up and moved joy stick to back position on your app and it engaged. Therefore I was able to drive rover forward and back for this video . When I tried to do same procedure and test again it would not engaged the esc

Sorry, can't help you for this specific ESC

I suggest you dedicate one App button for LOW speed mode :wink:

On my RC radio differential steering in activated on initial start up, there is no delay as it reacts exactly to my stick movements.

Is there a way to write a section of code to send signal inputs to -100 or low position for X seconds ? I don't mind to use the button just to test this. I think it's very close but the pwm signal seems to be out of range
for the ESC, I will keep test further as I really want this to work.

Here is a PDF of more information that I am reading now.

http://www.robotpower.com/downloads/RobotPower_Scorpion_XL_quickstart.pdf

Thanks KAS

Is there a way to write a section of code to send signal inputs to -100 or low position for X seconds ? I don't mind to use the button just to test this.

Change your setServoPosition function for this one:

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, 180, 0);   //  << 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);
  myservoY.write(servo_R);
  if(DEBUG)    {Serial.print(joyX); Serial.print(", "); Serial.println(joyY);}
}

This version implements differential steering
By moving joystick "full south", you will send 'low' to both motors
Should you post a new video, please move joystick slowly :wink:

I really wish I understood the code that you give me, thanks for your patience. I will try it asap and slow my stick movements on next video :slight_smile:

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