BT controlled Servo

Im going through this example to control my servo:

// Control servo motor over Bluetooth using RoboRemo app
// www.roboremo.com

// Hardware setup:
// BT module   Arduino
// GND ------- GND
// VCC ------- 5V - I actually set this to the 3.3V on the arduino because im using the 5v pin for my servo
[color=red]// Is this ^^^^^ ok?[/color]
// TX-O ------ pin0
// RX-I ------ pin1

// Servo       Arduino
// GND ------- GND
// VCC ------- VCC
// signal ---- pin4

#define bluetooth Serial
#include <Servo.h>


Servo myServo;

char cmd[100];
int cmdIndex;


void exeCmd() {
  
  // "servo" is the servo motor id
  
  if(cmd[0]=='s' &&
     cmd[1]=='e' &&
     cmd[2]=='r' &&
     cmd[3]=='v' &&
     cmd[4]=='o' &&
     cmd[5]==' ') {
       
       int val = 0;
       for(int i=6; cmd[i]!=0; i++) {
         val = val*10 + (cmd[i]-'0');
       }
       // if cmd is "servo 1234", val will be 1234
          
       myServo.writeMicroseconds(val);      
     }   
}



void setup() {
  
  delay(500); // wait for bluetooth module to start

  bluetooth.begin(115200); // Bluetooth default baud is 115200
  
  myServo.attach(4, 1000, 2000); //defaults to 544,2400 respectively
  
  cmdIndex = 0;
}


void loop() {
  
  if(bluetooth.available()) {
    
    char c = (char)bluetooth.read();
    
    if(c=='\n') {
      cmd[cmdIndex] = 0;
      exeCmd();  // execute the command
      cmdIndex = 0; // reset the cmdIndex
    } else {      
      cmd[cmdIndex] = c;
      if(cmdIndex<99) cmdIndex++;
    }
   
    
  }
  
}

I have a few questions:

  1. Why does he set the min and max to 1000 and 2000?
  2. What does exeCmd do? I see it checks for the word servo but why? And what does the for loop do?
    I sorta get that its writing microseconds which is the position of the servo using that for loop, but Im kinda confused by how it works exactly.
  3. In the loop we check the serial coming in, we get character by character as explained to me once before in another post, store it in the variable c and if its a “carriage return?” it calls the exeCmd with a value of cmd = 0, which resets the servo to zero?
  4. The second part of the if, the else, it sets the cmd to c. Hmmm…ok im more confused than i thought.

Marciokoko:

  1. Why does he set the min and max to 1000 and 2000?

Presumably he has determined that those are appopriate limits for the servo he is using. Servos are not all identical.

  1. What does exeCmd do? I see it checks for the word servo but why? And what does the for loop do?
    I sorta get that its writing microseconds which is the position of the servo using that for loop, but Im kinda confused by how it works exactly.

I think it is explained in the comment. It seems a rather laborious way of sending data for a servo. I can’t imagine why he does not just send the number 1234 (or whatever). See serial input basics.

  1. In the loop we check the serial coming in, we get character by character as explained to me once before in another post, store it in the variable c and if its a “carriage return?” it calls the exeCmd with a value of cmd = 0, which resets the servo to zero?

It is adding a value of 0 as the last element in the char array to make it a valid string. See again serial input basics.

  1. The second part of the if, the else, it sets the cmd to c. Hmmm…ok im more confused than i thought.

The instruction cmd[cmdIndex] = c; writes the value of c into the array cmd at the location cmdIndex

Hope this helps

…R

Thanks Robin and great post.

I just have 2 lingering questions from that post on serial input. They're in reference to the serial input using end markers but not yet start markers.

  1. What is the innermost if doing? I see it checks if the ndx index is > than our array's capacity. Presumably because we can't hold any more data in that array. So if it is greater, it resets the ndx back down to the array's capacity - 1. But to what effect? Will this just truncate the received data? If our message is 34 characters long, after the 31st character, the next data will be placed at last position of our array. Pos 32 will replace 31 and so on until Pos 34. I think...need clarification please.

  2. Else, if the data received IS indeed the end marker, it just adds a 0 to the array and thus terminates it, resets the ndx to 0 and sets our flag for data complete. Oh, Ok it will always do so at whatever the last, non-endMarker ndx position was left. OK I get this one :-)

Marciokoko: Will this just truncate the received data?

Yes, it just over-writes all the extra characters in the last available position in the array. That is the simplest safe method of dealing with too many characters. C/C++ does not raise an error if your code writes past the end of an array and that usually causes a program to crash. You could extend the code to cause some form of warning is too much data is received.

...R

Hey, btw, so the code for writing to a servo from serial monitor vs bluetooth, is actually the same:

So if I do this:

myservo.write(val);

It doesnt matter how I got my val, obviously. Whether it came from a Pot analog read or from a serial monitor input which is what bt is actually 'converted' into anyway...:-) right?

So this code from roboremo would work even if i just hooked up the servo to the arduino and used the serial monitor.

So I would use this schematic, assuming that BT module is an HC-05, but I couldnt find the exact match on Fritzing.

The servo is attached to pin 4.

So any data coming into the arduino from the BT, would be written to pin 4.

But I remember that when I printed out the incoming data from BT serial on the LED example, when I entered 1 in the temrinal, I got 49. And I got 48 when I entered 0. I used this code:

void loop() {
 if (mySerial.available()>0){
   BluetoothData=mySerial.read();
   mySerial.println(BluetoothData);
   
   if(BluetoothData=='1'){   // if number 1 pressed ....
     digitalWrite(ledpin,1);
     mySerial.println("LED  On D13 ON ! ");
   }
  if (BluetoothData=='0'){// if number 0 pressed ....
    digitalWrite(ledpin,0);
    mySerial.println("LED  On D13 Off ! ");
  }
}

Why would 49, which was printed out when I entered the 1 in the terminal, be converted to 49? And why would 49 be recognized as a 1, because it worked and it logged LED On D13 ON and the LED came on each time.

Marciokoko: Why would 49, which was printed out when I entered the 1 in the terminal, be converted to 49? And why would 49 be recognized as a 1, because it worked and it logged LED On D13 ON and the LED came on each time.

49 is the Ascii code for the character '1' Because 48 is the code for '0' you can convert single digit characters to numbers like this

inputChar = '7';
val = inputChar - '0';
Serial.println(val);

However if you want to input multi-digit values you need to use the parse example in serial input basics to convert (say) "107" to the number 107.

...R

Right, then I would have to check for a beginning and ending marker.

Simple servo control code.

//zoomkat 3-5-12 simple delimited ',' string parse 
//from serial port input (via serial monitor)
//and print result out serial port

String readString;
#include <Servo.h> 
Servo myservo;  // create servo object to control a servo 

void setup() {
  Serial.begin(9600);

  myservo.writeMicroseconds(1500); //set initial servo position if desired
  myservo.attach(7);  //the pin for the servo control 
  Serial.println("servo-delomit-test-22-dual-input"); // so I can keep track of what is loaded
}

void loop() {

  //expect a string like 700, or 1500, or 2000,
  //or like 30, or 90, or 180,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      if (readString.length() >0) {
        Serial.println(readString); //prints string to serial port out

        int n = readString.toInt();  //convert readString into a number

        // auto select appropriate value, copied from someone elses code.
        if(n >= 500)
        {
          Serial.print("writing Microseconds: ");
          Serial.println(n);
          myservo.writeMicroseconds(n);
        }
        else
        {   
          Serial.print("writing Angle: ");
          Serial.println(n);
          myservo.write(n);
        }

        //do stuff with the captured readString 
        readString=""; //clears variable for new input
      }
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

Marciokoko: Right, then I would have to check for a beginning and ending marker.

I think this will make more sense to you if you write a short test program. If it does not work then post the code and we can help you.

...R

Well I would just go with your code from Serial Input Basics. I was just trying to figure out that roboremo code. I think the reason they use the if ‘servo’ test in exeCmd() is because they use an android app to control many things. So they use that test to make sure the user is wanting to control the servo vs a LED or DC motor or something else.

So that bit of code is unnecessary. Well, that would actually be their start marker :slight_smile:

I figured out how the exeCmd() spits out the values it does.

So this line:

if(cmdIndex<99) cmdIndex++;

keeps the array small, sorta :cold_sweat:

My code would be the same but using bluetooth as the serial. So tried it yesterday and it failed. I posted the link elsewhere because I considered it a troubleshooting issue (http://forum.arduino.cc/index.php?topic=321706.msg2224023#msg2224023).

There seems to be a comm error or something.

It is much better to keep everything in one Thread and I have asked the Moderator to merge your other Thread with this one.

...R

Thanks. I have tried it again and again. I tried moving the baud rate on the sketch down to 9600 because i saw some code sketches like that, but still nothing from the BT. No matter what I type, I get nothing from the BT module.

Any ideas how I can test to see what if anything is coming in from the BT module?

The BT is simply converted into a serial connection, right? But I cant use the Serial Monitor on the IDE because the USB is not connected. So how can I monitor if anything is coming in, say for example using the screen from terminal that Ive been using?

I've done ls tty...and I find my HC module, I use screen /dev/tty.... @ 115200 and @ 9600 but nothing. I just get a blank screen the first time. Any other time I try to use the screen command again, I just get a Could not establish PTY and couldnt write to resource R/W.

Thanks in advance

Marciokoko: Any ideas how I can test to see what if anything is coming in from the BT module?

My merge request does not seem to have worked, so can you post the code here please - the latest version.

...R

The only change I made in the code was, that after understanding how it works and testing it without success, I changed the baud rate to 9600 because i found other examples online at that baud rate and I figured that might have something to do with it. But that didnt work either. So Im basically still using:

#define bluetooth Serial
#include <Servo.h>
Servo myServo;
char cmd[100];
int cmdIndex;

void exeCmd() {
  
  // "servo" is the servo motor id
  if(cmd[0]=='s' &&
     cmd[1]=='e' &&
     cmd[2]=='r' &&
     cmd[3]=='v' &&
     cmd[4]=='o' &&
     cmd[5]==' ') {
       
       int val = 0;
       for(int i=6; cmd[i]!=0; i++) {
         val = val*10 + (cmd[i]-'0');
       }
       // if cmd is "servo 1234", val will be 1234
       myServo.writeMicroseconds(val);      
     }   
}

void setup() {
  
  delay(500); // wait for bluetooth module to start
  bluetooth.begin(115200); // Bluetooth default baud is 115200
  myServo.attach(4, 1000, 2000);
  cmdIndex = 0;
}

void loop() {
  
  if(bluetooth.available()) {    
    char c = (char)bluetooth.read();
    if(c=='\n') {
      cmd[cmdIndex] = 0;
      exeCmd();  // execute the command
      cmdIndex = 0; // reset the cmdIndex
    } else {      
      cmd[cmdIndex] = c;
      if(cmdIndex<99) cmdIndex++;
    }
  }
  
}

Your code does not have a 9600 baudrate so it must not be the “real” code ? ? ?

The baudrate must be the same as the Bluetooth module’s baudrate.

Are you connecting your Bluetooth module to pins 0 and 1 and ALSO trying to communicate with the PC using Serial? Or, put another way, is the Arduino connected to a PC using USB ?

…R

Yeah, it didn't work at 9600 so i changed it back to 115200. Otherwise the code is untouched. I just realized, while working thru my wifi connectivity, which went well btw considering I had to improvise with the tiny sine wifi shield and a different library, that the baud rate in the serial monitor must match with the one defined in code.

I realize that the baud rate specified when using the screen command is the equivalent to setting it in the serial monitor. So Im about to try the LED example again (which worked before) and then the servo one once again.

The way I did the servo test was the same way I did the led test. Uploaded the sketch without rx/tx connected, then plugged in the rx/tx and unplugged the usb but replaced it with the 9v battery pack.

So Ill run thru LED-then-Servo sketch again, but this time using the same baud rate (which I honestly don't remember checking before) but Ill use my Arduino Mega board cause its just sitting there in a box :-) plus my UNO is occupied with a big TinySine wifi shield on top of it.

Since we're on the subject, im thinking of getting a YUN to avoid having to configure these shields over the UNO. But I was wondering if there are any smaller boards with incorporated wifi/gprs because once i get this project off the ground, I don't want such a clunky setup.

Ill get back to you after my tests, but I gotta grab some dinner.

Thanks

Responding to Reply #16.

You have a long reply which completely managed to avoid answering my question in Reply #15 about how the Bluetooth module is connected.

How can I help if you don't answer questions ?

...R

Oh sorry, I didn't read the part about the pins, only the USB cable. I was so excited about my wifi working.

Yes, I'm connecting the BT Rx to the Arduino TX and the BT TX to the Arduino Rx just as I posted in my original sketch code and in my diagram on Reply #5 :-).

And as I mentioned, I only connect those pins after uploading the sketch thru the USB. After uploading, the pins are re-connected and the USB is disconnected in order to test whether BT data is received or not.

Marciokoko:
Yes, I’m connecting the BT Rx to the Arduino TX and the BT TX to the Arduino Rx just as I posted in my original sketch code and in my diagram on Reply #5 :-).

And as I mentioned, I only connect those pins after uploading the sketch thru the USB. After uploading, the pins are re-connected and the USB is disconnected in order to test whether BT data is received or not.

Why not use SoftwareSerial to create a second serial port on your Uno (?) on (say) pins 2 and 3, and use that for your Bluteooth module.

Then you could communicate with the Bluetooth module and also with the Serial Monitor for debugging purposes and there would be no need to disconnect and reconnect things.

…R