Servo Control (SOLVED)

Hello everybody,

I am a new to hobby robotics. I have lots of programming experience but not with arduino itself. This is my issue.

I want to turn a servo from 0 degrees to 90 degrees in increments of 2 degrees every 125 milliseconds. After the servo reaches 90 degrees it then goes the other direction back to 0 degrees in increments of 4 degrees every 125 milliseconds. This will just repeat back and forth. I can get it to work as long as I increment the angle in the for loop so that by the time it reaches its minimum or maximum it lands perfectly on 0 or 90 degrees depending on the direction its rotating. Going from 0 degrees I increment the angle every 2 degrees. Rotating back from 90 to 0 degrees, I increment it every 4 degrees. If I do it this way the servo doesnt work properly. When it comes back from 90 to 0 degrees, it hits 0 degrees and then moves back to 90 degrees at full speed and repeats. This is not the behavior I want. It also fails to run through the first if...endif logic section because the turnTo90 boolean variable never gets switched back to true.

I know that if I divide 90 degrees by 4 I get 22.5. As long as my increment amount divided by my total degrees to move gives a division remainder its doesnt work. The only way to fix the problem is to increment by 5 instead of 4. Can anybody tell me why it behaves like this? Any help would greatly be appreciated. Thanks!!

Stuff used:

Arduino Uno
Futaba S3004 180 degree servo
Servo signal in Pin 9 (PWM)

Code:

#include <Servo.h>
Servo calServo;

int servoPin = 9;
boolean turnTo90 = true;
boolean firstRun = true;//True if the program is running thru its first iteration thru the main loop

void setup()
{
  //Attach the servo object
  calServo.attach(servoPin);
  pinMode(debugLEDPin, OUTPUT); 
}


void loop()
{ 
  //If this is the first iteration thru the main loop, set the servo to default angle of 0 degrees
  if(firstRun)
  {
    firstRun = false;//Set to false to stop this code from running
    calServo.write(0);
  }
  
  //Turn the servo from 0 to 90 degrees slowly
  if(turnTo90 == true)
  {
     for(int i = 0; i <= 90; i += 2)
    {
      //If the servo has reached 90 degrees, start to move the other direction to 0 degrees
      if(calServo.read() > 89)
      {
        turnTo90 = false;  
        calServo.write(90);//Set the servo to 90 degrees exactly
        break;
      }
      
      calServo.write(i);
      delay(125);
    }
  }
  else if(turnTo90 == false)//Rotate back to 0 degrees faster then from 0 to 90
  {
    for(int i = 90; i >= 0; i-= 4)
    {
      //If the servo has reached 0 degrees, start to move the other direction to 90 degrees
      if(calServo.read() <= 0)
      {
        turnTo90 = true;  
        calServo.write(0);//Set the servo to 0 degrees exactly
        break;
      }      
      
      calServo.write(i);
      delay(125);
    }
  }

Have you looked a the servo sweep example?

You are reading the servo position before you set it. Use 'i' for the comparison.

  else if(turnTo90 == false)//Rotate back to 0 degrees faster then from 0 to 90
  {
    for(int i = 90; i >= 0; i-= 4)
    {
      //If the servo has reached 0 degrees, start to move the other direction to 90 degrees
      if(i <= 0)
      {
        turnTo90 = true;  
        calServo.write(0);//Set the servo to 0 degrees exactly
        break;
      }      
      else
      {
         calServo.write(i);
      }
      delay(125);
    }

I would use the same type code for increment also.

I have tried the changes that you suggested surfer. The servo still behaves the same way as before. I also checked out the sweep example and that only increments 1 degree at a time. That forces the incrementing variable pos from landing perfectly on 0 or 180 degrees. What if I wanted to increment at 3 degrees at a time. That would end up ending in a result of a negative number. My posted code increments every 4 degrees.

If i start out at 90 degrees and keep decrementing it would eventually end up at -2 on the very last iteration of the loop. To prevent sending a -2 in the servo.write() function, I do a check to see if the iteration variable i is less then 0 degrees. If it is I just set the servo to 0 degrees and setup the setTo90 variable to true so the servo can travel the other direction. But it does not do this. It never even enters the if block which it should. The iteration variable i is -2 which is less then 0 so the logic statement should evaluate to true and it should be ran. I am either missing something really dumb or there is some understanding of arduino C based code that I just dont understand yet that is causing this behavior.

Use a Serial.println() to determine what is happening. I would test the status of turnto90 first.

  if(turnTo90 == true)
  {
      Serial.println("True");
      // rest of code

and

   else if(turnTo90 == false)//Rotate back to 0 degrees faster then from 0 to 90
  {
      Serial.println("False");
      // rest of code

Is the serial output changing from "True" to "False" at about the correct rate?

Edit: I would remove the "break;" also. That may not be doing what you think at that point.

WOOT!! I figured it out. I used a while() loop that always evaluated to true causing an infinite loop. I just used a control variable to keep track. This let me have a little more control of what to do with the servo. The for...loop I was using before would exit before I even got a chance to evaluate the control variable so I would never set turnTo90 back to true. Thats what made it get stuck in the section of the else{...} logic block giving me the weird behavior.

Thanks for your help surfer and zoomkat.