Search code examples
arduinoservo

Servo delay on direction change


I'm using a SG-90 servo and sweeping left and right between two values. My problem is that there is a distinct delay of about 500ms between direction changes. I would like the position of the servo to be predictable, but due to this at direction changes it is not.

bool servoDir = true;
int servoCnt = 90;
int servoInc = 1;
int servoMin = servoCnt - 5;
int servoMax = servoCnt + 5;

void loop() {
    if (servoDir) {
      dx = servoInc;
      if (servoCnt > servoMax) {
        servoDir = false;
      }
    } else {
      dx = -servoInc;
      if (servoCnt < servoMin) {
        servoDir = true;
      }
    }
    servoCnt += dx;
    servo.write(servoCnt);
    // delay or other code here (mine is 40ms)
}

I've tried both the Arduino Servo library and the VarspeedServo library. They both show the same thing.

What is the cause of this and what can I do about it?

Update

So if I up the speed at direction change, like so:

int extra = 5;
void loop() {
    if (servoDir) {
      dx = servoInc;
      if (servoCnt > servoMax) {
        dx -= extra;
        servoDir = false;
      }
    } else {
      dx = -servoInc;
      if (servoCnt < servoMin) {
        dx += extra;
        servoDir = true;
      }
    }
    servoCnt += dx;
    servo.write(servoCnt);
    // delay or other code here (mine is 40ms)
}

the delay disappears, but the servo position does become a lot less predictable.


Solution

  • You would experience exactly these symptoms if servoMin and servoMax were out of the servo range.... Which they are.

    More seriously, these servos are not very precise. Incrementing by 1 at a time is probably the issue. You are experiencing some form of backlash.

    You should check and clamp the count against the range AFTER incrementing/decrementing. That's one of the basic rules of embedded programming. Lives may be at stake, or equipment destroyed when sending out out of range values.

    bool servoDir = true;
    int servoCnt = 90;
    int servoInc = 1;             // <-- exclusively use this to control speed.
    int servoMin = servoCnt - 5;  // <-- this range is a bit short for testing
    int servoMax = servoCnt + 5;
    
    void loop() {
    
        // 'jog' the servo.
        servoCnt += (servoDir) ? servoInc : -servoInc;
    
        // past this point, all position jogging is final
        if (servoCnt > servoMax) 
        {
            servoCnt = servoMax;
            servoDir = false;
        }
        else if (servoCnt < servoMin) 
        {
            servoCnt = servoMin;
            servoDir = true;
        }
    
        servo.write(servoCnt);
    
        // 40ms sounds a bit short for tests.
        // 100 ms should give you a 2 seconds (0.5Hz) oscillation
        delay(100);
    }