Servo Control through serial monitor

hello guys!

I am working on controlling 2 servos from the serial monitor thorugh commands like these:

PP ----> returns the pan position
PP1500 ----> moves the servo to position 1500

I posted my code below

#include <Servo.h>

char buffer[16];
int  bufferIndex = 0;

Servo myServo1;
Servo myServo2;

void setup()
{
  pinMode(9, OUTPUT);
  pinMode(8, OUTPUT);
  myServo1.attach(9);
  myServo2.attach(8); 
  Serial.begin(9600);
  Serial.println("Welcome!");
}

void loop()
{
    static int val = 0;
    static int temp = 150; 
  
    if( Serial.available())
    {
       char ch = Serial.read();
           
           if( ch == '\r')  // is this the terminating carriage return
           {

              bufferIndex = 0;
                     
              if (strcmp (buffer,"a") == 0) {
                Serial.println("waiting for 1 second");
                delay(1000);
              }

              if (strcmp (buffer,"pp") == 0) {
                if (Serial.available())
                {
                  char temp = Serial.read();
                  switch (temp) 
                  {
                    case '0'...'9':
                      val = val * 10 + ch - '0';
                      break;
                    case 'p':
                      myServo1.write(val);
                      Serial.print("horizontal servo is set to: ");
                      Serial.print(val, DEC);
                      Serial.println(" degrees");
                      val = 0;
                      break;
                  }
                }
                
                else
                {
                  Serial.print("current pan position is ");
                  Serial.println(val, DEC);
                }
              }
              
       
              if (strcmp (buffer,"tp") == 0) {
                Serial.print("current tilt position is ");
                Serial.println(val, DEC);
              }
 
              if (strcmp (buffer," ") == 0) {
                val = 90;
                myServo1.write(val);
                myServo2.write(val);
                Serial.println("both servos are reset");
                val = 0;
              }             
   
              for (int i=0; i<=20; i++)
              {
                buffer[i] = '\0'; 
              }
           }
         
           else
             buffer[ bufferIndex++ ] = ch; // add the character into the buffer
    }
}

the first part works fine which is returning the pan position, but the second part where you tell the servo to move does not seem to work.

please help me and guide me to where i should make modifications in the code considering that i am new to Arduino.

thanks in advance.

              if (strcmp (buffer,"pp") == 0) {
                if (Serial.available())
                {
                  char temp = Serial.read();
                  switch (temp) 
                  {
                    case '0'...'9':
                      val = val * 10 + ch - '0';
                      break;

After the pp, you read a single character. Hard to stuff "1500" into a single character, isn't it. Perhaps the use of a loop to read data up to the end of packet marker is needed. You are sending some kind of end-of-packet marker, aren't you?

but what about if there was no end-of-packet marker?!

the command is supposed to look like this:

PP1500

but what about if there was no end-of-packet marker?!

How do you know when to stop reading There is a reason that we use punctuation symbols when typing It makes it much easier to know when a sentence ends, doesn't it

so i found some code from another thread and modified it to work with my servos:

void loop() {

  while (Serial.available()) {
    delay(10);
    if (Serial.available() >0) {
    char c = Serial.read();  //gets one byte from serial buffer
    readString += c; //makes the string readString
    }
  }

  if (readString.length() >0) {
        
    // expect a string like 07002100 containing the two servo positions
    command = readString.substring(0, 2);
        servo1 = readString.substring(2, 6); //get the first four characters
    servo2 = readString.substring(2, 6); //get the next four characters
        

    int n1; //declare as number
    int n2;

        if (command == "pp")
        {
           if (servo1 == "")
          {
            Serial.print("current pan position is ");
          }
          
          else
          {  
            char carray1[6]; //magic needed to convert string to a number
             servo1.toCharArray(carray1, sizeof(carray1));
             n1 = atoi(carray1);
            myservo1.writeMicroseconds(n1); //set servo position
          }
        }

so now when i enter something like this in the terminal

PP2000

the servo moves accordingly, but when i enter the command to get the current position

PP

the code assumes that i entered

PP0000

and moves the servo to the initial position which is zero

how can i modify so that it can stop after the second character?

how can i modify so that it can stop after the second character?

Gee, I don't know. You might consider using an end-of-packet marker. Or not.

Some code for two servos. If you are using the serial monitor, you don’t need an end of packet marker as the code is processed much faster than you can type characters and hit the enter key. :wink:

// zoomkat 11-22-10 serial servo (2) test
// for writeMicroseconds, use a value like 1500
// for IDE 0019 and later
// Powering a servo from the arduino usually DOES NOT WORK.
// two servo setup with two servo commands
// send eight character string like 15001500 or 14501550

#include <Servo.h> 
String readString, servo1, servo2;
Servo myservo1;  // create servo object to control a servo 
Servo myservo2;

void setup() {
  Serial.begin(9600);
  myservo1.attach(6);  //the pin for the servo control 
  myservo2.attach(7);
  Serial.println("servo-test-21"); // so I can keep track of what is loaded
}

void loop() {

  while (Serial.available()) {
    delay(1);  
    if (Serial.available() >0) {
      char c = Serial.read();  //gets one byte from serial buffer
      readString += c; //makes the string readString
    } 
  }

  if (readString.length() >0) {
      Serial.println(readString); //see what was received
      
      // expect a string like 07002100 containing the two servo positions      
      servo1 = readString.substring(0, 4); //get the first four characters
      servo2 = readString.substring(4, 8); //get the next four characters 
      
      Serial.println(servo1);  //print to serial monitor to see results
      Serial.println(servo2);
      
      int n1; //declare as number  
      int n2;
      
      char carray1[6]; //magic needed to convert string to a number 
      servo1.toCharArray(carray1, sizeof(carray1));
      n1 = atoi(carray1); 
      
      char carray2[6];
      servo2.toCharArray(carray2, sizeof(carray2));
      n2 = atoi(carray2); 
      
      myservo1.writeMicroseconds(n1); //set servo position 
      myservo2.writeMicroseconds(n2);
    readString="";
  } 
}

If you are using the serial monitor, you don't need an end of packet marker as the code is processed much faster than you can type characters and hit the enter key.

No data is sent until you hit the enter key. Then, it is all sent, one character at a time.

The Arduino CAN read data faster than it can be sent. Much faster.

Of course, if you are willing to take a break after each character, and do nothing for a while, you can make the Arduino run slower than serial data can be sent.

If this is a problem, use an end of packet marker.

If this is a problem, use an end of packet marker.

But it isn’t using the serial monitor. :wink:

But it isn't using the serial monitor.

What isn't?

What isn’t?

Your imiginary issue with not having an end of packet marker when sending packets using the serial monitor. Perhaps you were speaking to some other issue?

hi zoomkat! thanx for your input.

here is my code so far:

// zoomkat 11-22-10 serial servo (2) test
// for writeMicroseconds, use a value like 1500
// for IDE 0019 and later
// Powering a servo from the arduino usually DOES NOT WORK.
// two servo setup with two servo commands
// send eight character string like 15001500 or 14501550

#include <Servo.h>

int lastReadPan = 1500; 
int lastReadTilt = 1500;
  
String readString, servo1, servo2, command, command2;

Servo myservo1;  // create servo object to control a servo
Servo myservo2;


void setup() {
  Serial.begin(9600);
  myservo1.attach(9);  //the pin for the servo control
  myservo2.attach(8);
  Serial.println("welcome!"); // so I can keep track of what is loaded
}

void loop() {
    while (Serial.available()) {
    delay(10);
    if (Serial.available() >0) {
	char c = Serial.read();  //gets one byte from serial buffer

        readString += c; //makes the string readString
    }
  }

 
  if (readString.length() > 0) {
	//Serial.println(readString); //see what was received   
	//expect a string like 07002100 containing the two servo positions
	command2 = readString.substring(0, 1);
        command = readString.substring(0, 2);
        servo1 = readString.substring(2, 6); //get the first four characters
	servo2 = readString.substring(2, 6); //get the next four characters

	//Serial.println(servo1);  //print ot serial monitor to see results
	//Serial.println(servo2);
        

	int n1; //declare as number
	int n2;

        if (command2 == "a")
        {
          Serial.println("waiting for 1 second");
          delay(1000);
        }
        
        if (command2 == " ")
        {
          myservo1.writeMicroseconds(1500);
          myservo2.writeMicroseconds(1500);
          Serial.println("both servos are reset");
          lastReadPan = 1500;
          lastReadTilt = 1500;
        }
        
        if (command == "pp")
        {
          if (servo1 == '\r')
          {
            Serial.print("current pan position is ");
            Serial.println(lastReadPan, DEC); 
          }
          else
          {
            char carray1[6]; //magic needed to convert string to a number
    	    servo1.toCharArray(carray1, sizeof(carray1));
    	    n1 = atoi(carray1);
            myservo1.writeMicroseconds(n1); //set servo position
            lastReadPan = n1;
          }
        }

        if (command == "tp")
        {
          if (servo2 == '\r')
          {
            Serial.print("current tilt position is ");
            Serial.println(lastReadTilt, DEC); 
          }
          else
          {
            char carray2[6]; //magic needed to convert string to a number
    	    servo2.toCharArray(carray2, sizeof(carray2));
    	    n2 = atoi(carray2);
            myservo2.writeMicroseconds(n2); //set servo position
            lastReadTilt = n2;
          }
        }
        readString="";
  }
}

now i can run commands like

PP2500 ----------> the servo moves accordingly

PP ----------> returns the current pan position

what i want to do now is modify the code so that it reads:

PP-2500

notice the minus sign which should mean turn to the left

how can i make the code look for the minus sign and if it does not find the minus sign it will assume “turn right”?

thanks

ok nevermind i figured it out

here is my latest code

// zoomkat 11-22-10 serial servo (2) test
// for writeMicroseconds, use a value like 1500
// for IDE 0019 and later
// Powering a servo from the arduino usually DOES NOT WORK.
// two servo setup with two servo commands
// send eight character string like 15001500 or 14501550

#include <Servo.h>

int lastReadPan = 90; 
int lastReadTilt = 90;
int p, p2, t, t2;

String readString, servo1, servo11, servo2, servo22, command, command2, sign;

Servo myservo1;  // create servo object to control a servo
Servo myservo2;


void setup() {
  Serial.begin(9600);
  myservo1.attach(9);  //the pin for the servo control
//  myservo11.attach(9);
  myservo2.attach(8);
  Serial.println("welcome!"); // so I can keep track of what is loaded
}

void loop() {
    while (Serial.available()) {
    delay(10);
    
    if (Serial.available() >0) {
	char c = Serial.read();  //gets one byte from serial buffer

        readString += c; //makes the string readString
    }
  }

 
  if (readString.length() > 0) {
	//Serial.println(readString); //see what was received   
	//expect a string like 07002100 containing the two servo positions
        sign = readString.substring(2, 3);
        command = readString.substring(0, 2);
        command2 = readString.substring(0, 1);    
        servo1 = readString.substring(2, 5);
        servo11 = readString.substring(3, 6);
        servo22 = readString.substring(3, 6); //get the first four characters
	servo2 = readString.substring(2, 5); //get the next four characters

	//Serial.println(servo1);  //print ot serial monitor to see results
	//Serial.println(servo2);
        

	int n1; //declare as number
	int n2;

        if (command2 == "a")
        {
          Serial.println("waiting for 1 second");
          delay(1000);
        }
        
        if (command2 == " ")
        {
          myservo1.write(90);
          myservo2.write(90);
          Serial.println("both servos are reset");
          lastReadPan = 90;
          lastReadTilt = 90;
        }
        
        if (command == "pp")
        {
          if (servo1 == '\r')
          {
            Serial.print("current pan position is ");
            Serial.println(lastReadPan, DEC); 
          }
          
          else
          {
            if (sign == "-")
            {
              char carray11[6]; //magic needed to convert string to a number
    	      servo11.toCharArray(carray11, sizeof(carray11));
    	      n1 = atoi(carray11);
              
              if (n1 <= 90)
              {
                p2 = 90 - n1;
                p = map(p2,0,90,90,180);
                myservo1.write(p); //set servo position
                lastReadPan = -n1;
                //Serial.println("minus");
              }
          
              else
              {
                Serial.println("invalid input!");  
              }    
            }
            
            else
            {
              char carray1[6]; //magic needed to convert string to a number
    	      servo1.toCharArray(carray1, sizeof(carray1));
    	      n1 = atoi(carray1);
              
              if (n1 <= 90)
              {
                myservo1.write(n1); //set servo position
                lastReadPan = n1;
              }
              
              else
              {
                Serial.println("invalid input!");  
              }
            }
          }
        }

        if (command == "tp")
        {
          if (servo2 == '\r')
          {
            Serial.print("current tilt position is ");
            Serial.println(lastReadTilt, DEC); 
          }
          
          else
          {
            if (sign == "-")
            {
              char carray22[6]; //magic needed to convert string to a number
    	      servo22.toCharArray(carray22, sizeof(carray22));
    	      n2 = atoi(carray22);
              
              if (n2 <= 90)
              {
                t2 = 90 - n2;
                t = map(t2,0,90,90,180);
                myservo2.write(t); //set servo position
                lastReadTilt = -n2;
                //Serial.println("minus");
              }
          
              else
              {
                Serial.println("invalid input!");  
              }    
            }
            
            else
            {
              char carray2[6]; //magic needed to convert string to a number
    	      servo2.toCharArray(carray2, sizeof(carray2));
    	      n2 = atoi(carray2);
              
              if (n2 <= 90)
              {
                myservo2.write(n2); //set servo position
                lastReadTilt = n2;
              }
              
              else
              {
                Serial.println("invalid input!");  
              }
            }
          }
        }
        
        readString="";
  }
}

the code works fine with both a minus sign or not and executes accordingly

now my goal is to provide a continuous serial input to test the two servos , i.e., something like this:

pp45 --------------> move right to position 45
a --------------> wait for 1 second
pp-80 --------------> move left to position 80
a
tp-60 --------------> move down to position -60
a
tp20 --------------> move up to position 20

i don’t want to enter the commands manually so please help me on how to provide something like this to the arduino terminal?

thanks

i don't want to enter the commands manually so please help me on how to provide something like this to the arduino terminal?

Well, if you don't want to type you probably need to make a program or setup to provide you some type of GUI to send the control commands. Below is an example of a wed based GUI to control servos.

http://web.comporium.net/~shb/wc2000-PT-script.htm

thanks for the link

but i am not entirely sure how to use it, could you explain more?

but i am not entirely sure how to use it, could you explain more?

The web page contains clickable links (which forms the GUI with which the user interacts), that when clicked send a get request to a web server (apache in this case, or could be an arduino with an ethernet shield). The web server takes info from the get request and performs the action to control the servo. In the apache server setup, a batch file is executed which sends the servo control info out the pc serial port to a servo controller. With an ethernet shield, the arduino runs the web server program that takes the servo control info from the get request and positions the servo accordingly.

I am having the same problem you mentioned earlier, my program works only for the first time, after that it just twitches. :)

vivanta: I am having the same problem you mentioned earlier, my program works only for the first time, after that it just twitches. :)

Post your code and a diagram of how the servo is wired.

Don't power the servo from the Arduino 5v pin - give it a separate power supply and connect the servo GND to the Arduino GND.

...R

Hi hussam

I tried to compile your code but got the following errors. What could be wrong?

Arduino: 1.5.7 (Windows 7), Board: “Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)”

Build options changed, rebuilding all

servoMotorControl_2_r1.ino: In function ‘void loop()’:
servoMotorControl_2_r1.ino:75:25: error: invalid conversion from ‘char’ to ‘const char*’ [-fpermissive]
In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:220:0,
from servoMotorControl_2_r1.ino:10:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:143:16: error: initializing argument 1 of ‘unsigned char String::operator==(const char*) const’ [-fpermissive]
unsigned char operator == (const char cstr) const {return equals(cstr);}
^
servoMotorControl_2_r1.ino:126:25: error: invalid conversion from ‘char’ to 'const char
’ [-fpermissive]
In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:220:0,
from servoMotorControl_2_r1.ino:10:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:143:16: error: initializing argument 1 of ‘unsigned char String::operator==(const char*) const’ [-fpermissive]
unsigned char operator == (const char *cstr) const {return equals(cstr);}
^

This report would have more information with
“Show verbose output during compilation”
enabled in File > Preferences.

hussam:
ok nevermind i figured it out

here is my latest code

// zoomkat 11-22-10 serial servo (2) test

// for writeMicroseconds, use a value like 1500
// for IDE 0019 and later
// Powering a servo from the arduino usually DOES NOT WORK.
// two servo setup with two servo commands
// send eight character string like 15001500 or 14501550

#include <Servo.h>

int lastReadPan = 90;
int lastReadTilt = 90;
int p, p2, t, t2;

String readString, servo1, servo11, servo2, servo22, command, command2, sign;

Servo myservo1;  // create servo object to control a servo
Servo myservo2;

void setup() {
  Serial.begin(9600);
  myservo1.attach(9);  //the pin for the servo control
//  myservo11.attach(9);
  myservo2.attach(8);
  Serial.println(“welcome!”); // so I can keep track of what is loaded
}

void loop() {
    while (Serial.available()) {
    delay(10);
   
    if (Serial.available() >0) {
char c = Serial.read();  //gets one byte from serial buffer

readString += c; //makes the string readString
    }
  }

if (readString.length() > 0) {
//Serial.println(readString); //see what was received   
//expect a string like 07002100 containing the two servo positions
        sign = readString.substring(2, 3);
        command = readString.substring(0, 2);
        command2 = readString.substring(0, 1);   
        servo1 = readString.substring(2, 5);
        servo11 = readString.substring(3, 6);
        servo22 = readString.substring(3, 6); //get the first four characters
servo2 = readString.substring(2, 5); //get the next four characters

//Serial.println(servo1);  //print ot serial monitor to see results
//Serial.println(servo2);

int n1; //declare as number
int n2;

if (command2 == “a”)
        {
          Serial.println(“waiting for 1 second”);
          delay(1000);
        }
       
        if (command2 == " ")
        {
          myservo1.write(90);
          myservo2.write(90);
          Serial.println(“both servos are reset”);
          lastReadPan = 90;
          lastReadTilt = 90;
        }
       
        if (command == “pp”)
        {
          if (servo1 == ‘\r’)
          {
            Serial.print("current pan position is ");
            Serial.println(lastReadPan, DEC);
          }
         
          else
          {
            if (sign == “-”)
            {
              char carray11[6]; //magic needed to convert string to a number
          servo11.toCharArray(carray11, sizeof(carray11));
          n1 = atoi(carray11);
             
              if (n1 <= 90)
              {
                p2 = 90 - n1;
                p = map(p2,0,90,90,180);
                myservo1.write(p); //set servo position
                lastReadPan = -n1;
                //Serial.println(“minus”);
              }
         
              else
              {
                Serial.println(“invalid input!”); 
              }   
            }
           
            else
            {
              char carray1[6]; //magic needed to convert string to a number
          servo1.toCharArray(carray1, sizeof(carray1));
          n1 = atoi(carray1);
             
              if (n1 <= 90)
              {
                myservo1.write(n1); //set servo position
                lastReadPan = n1;
              }
             
              else
              {
                Serial.println(“invalid input!”); 
              }
            }
          }
        }

if (command == “tp”)
        {
          if (servo2 == ‘\r’)
          {
            Serial.print(“current tilt position is “);
            Serial.println(lastReadTilt, DEC);
          }
         
          else
          {
            if (sign == “-”)
            {
              char carray22[6]; //magic needed to convert string to a number
          servo22.toCharArray(carray22, sizeof(carray22));
          n2 = atoi(carray22);
             
              if (n2 <= 90)
              {
                t2 = 90 - n2;
                t = map(t2,0,90,90,180);
                myservo2.write(t); //set servo position
                lastReadTilt = -n2;
                //Serial.println(“minus”);
              }
         
              else
              {
                Serial.println(“invalid input!”); 
              }   
            }
           
            else
            {
              char carray2[6]; //magic needed to convert string to a number
          servo2.toCharArray(carray2, sizeof(carray2));
          n2 = atoi(carray2);
             
              if (n2 <= 90)
              {
                myservo2.write(n2); //set servo position
                lastReadTilt = n2;
              }
             
              else
              {
                Serial.println(“invalid input!”); 
              }
            }
          }
        }
       
        readString=””;
  }
}








the code works fine with both a minus sign or not and executes accordingly

now my goal is to provide a continuous serial input to test the two servos , i.e., something like this:




pp45 --------------> move right to position 45 
a --------------> wait for 1 second
pp-80 --------------> move left to position 80 
a
tp-60 --------------> move down to position -60
a
tp20 --------------> move up to position 20



i don't want to enter the commands manually so please help me on how to provide something like this to the arduino terminal?

thanks

Just commentary
I have found reading both Servo files ( header and source) to explain few things about “standard” servos.
The main one being – the Servo accepts two numerical info – the “degree” range 0 thru 180 refers to true angle position / degrees of servo, the range above 500 (something ) refers to microseconds time to set the servo to desired position / angle. This timing data should be in servo data sheet.

The servo should “assume idle position” on power up, but so far I have not found many references to this, but I have not look that hard. (It would be prudent to set it to 0 or whatever desired position initially anyway.)
Since the expected “degrees” range is from 0 to 180 only positive numbers should are used.
I have not look if Servo class methods checks for this range validity, only above 500 it switches to microseconds.

Same goes for “microseconds” range , how do you set negative time?

I really thing servo (hardware) data sheet should tell which data to send – true degrees or microseconds.
It looks as in your case microseconds are used to set the servo position.

Lastly, SOME servos setting speed can be controlled by using faster refresh rate / frequency.
Arduino Servo class is “hardwired” / set to use 50Hz refresh frequency only.