Ramping / Easing servo between points

First time poster, long time reader. Let me start by saying that I really appreciate any help you can offer me. I am very new to this, but have been able to learn so much already thanks to these forums.

Let me begin by letting you know what I have already accomplished. I basically have a servo that can be moved with a forward button, a back button and 2 more buttons to set “markers”. When the switch is high, pressing the marker button sets the marker to the current position of the servo. When the switch is low, pressing the marker button will move the servo to the marker. There is also a pot that controls speed.

What I’m having trouble with (by “trouble” I mean “I have no idea where to begin”) is when traveling between 2 marker positions I would like the servo to accelerate up to speed, continue traveling at speed and then decelerate to a stop. This “ramping” would also be effected by the speed. Like I said, any help is appreciated. Thanks for your time.

#include <Servo.h> 

Servo myServo;              // Servo
int potpin = 0;            // Analog pin for potentiometer
int delaySet;              // Delay for speed, controlled by analog pot 
int marker1 = 120;         // Initial value of marker1
int marker2 = 40;          // Initial value of marker2

const int bPin1 = 7;       // marker1 button pin
const int bPin2 = 6;       // marker2 button pin
const int bPin3 = 3;       // Forward button pin
const int bPin4 = 8;       // Back button pin
const int SwitchPin = 5;   // Switch Pin

int b1 = 0;         // marker1 button
int b2 = 0;         // marker2 button
int b3 = 0;         // Forward button
int b4 = 0;         // Back button
int Switch = 0;     // Switch
int pos = 90;       // Servo position


void setup() 
{ 
  myServo.attach(9);
  pinMode(bPin1, INPUT);
  pinMode(bPin2, INPUT);
  pinMode(bPin3, INPUT);
  pinMode(bPin4, INPUT);
  pinMode(SwitchPin, INPUT);
} 

void loop() 
{ 

  delaySet = analogRead(potpin);
  delaySet = map(delaySet, 0, 1023, 40, 0);  
  b1 = digitalRead(bPin1);
  b2 = digitalRead(bPin2);
  b3 = digitalRead(bPin3);
  b4 = digitalRead(bPin4);
  Switch = digitalRead(SwitchPin);

  if (b1 == LOW && Switch == LOW) {        // If marker1 button pressed in run mode
       
    for(int i = pos; i < marker1; i ++)    // If current position is less than marker1 travel forward
    {
      myServo.write(i); 
      delay(delaySet);                     // Speed at which we will travel
      pos ++;                              // Tell position variable where we are
    } 
    
    for(int i = pos; i > marker1; i --)    // If current position is greater than marker1 travel backward
    {
      myServo.write(i); 
      delay(delaySet);                     // Speed at which we will travel
      pos --;                              // Tell position variable where we are
    } 
  }
    

  else if (b2 == LOW && Switch == LOW) {

    for(int i = pos; i < marker2; i ++)   // If current position is less than marker1 travel forward
    {
      myServo.write(i); 
      delay(delaySet);                    // Speed at which we will travel
      pos ++;                             // Tell position variable where we are
    } 
    for(int i = pos; i > marker2; i --)   // If current position is greater than marker1 travel backward
    {  
      myServo.write(i); 
      delay(delaySet);                    // Speed at which we will travel
      pos --;                             // Tell position variable where we are
    } 
  }

  if (b1 == LOW && Switch == HIGH) {               // If the marker1 button is pressed set marker1 to current position
    marker1 = pos;
  } 

  else   if (b2 == LOW && Switch == HIGH) {       // If the marker2 button is pressed set marker2 to current position
    marker2 = pos;
  } 

  if (b3 == LOW) {                    // If back button is pressed, go back 
    pos = pos --;
  }
  
  if (b4 == LOW){                     // If forward button is pressed, go forward
    pos = pos ++;
  }

  if (pos < 1)                        // If the current position is less than 1 then position equals 1 ( min limit of servo )  
    pos=1;

  if (pos > 167)                      // If the current position is greater than 169 then position equals 169 ( max limit of servo ) 
    pos=167;

  myServo.write(pos);		      // Write current position to servo
  delay(delaySet);                    // Delay writes to servo (speed)
}

So, what you want is a variable delay(), rather than a fixed delay(). There are various ways to do this.The simplest is just to use an if statement, based in the loop index, to determine which value to use in the delay statement.

Since the servo itself doesn't see any benefit in starting and stopping for different periods of time, I'm not sure what benefit you will gain. It all depends on what the servos are controlling, I guess.

Try something like this:

int oldpos = pos;
int dist = abs(marker1 - pos);
int d = dist > 10 ? 5 : dist >> 1;
int del = delaySet * 3;
for (; pos < marker1; pos++) {
  myServo.write(pos);
  delay(del);
  if (pos - oldpos < d) {
    del = delaySet * (1 + (pos - oldpos) * 2 / 5);
  } else if (marker1 - pos < d) {
    del = delaySet * (1 + (marker1 - pos) * 2 / 5);
  } else {
    del = delaySet;
  }
}

You have to adapt this for every movement “for” loop in your existing code. This just gives you a ramp at the beginning and the end.

1 Like

rekeem:
What I'm having trouble with (by "trouble" I mean "I have no idea where to begin") is when traveling between 2 marker positions I would like the servo to accelerate up to speed, continue traveling at speed and then decelerate to a stop. This "ramping" would also be effected by the speed. Like I said, any help is appreciated. Thanks for your time.

You could write your own logic to determine how far the servo is away from it's set point and the desired speed based on that, compare that with the current speed and ramp it up or down.

If you want something that responds more smoothly and continuously you could consider using a PID controller to do it for you.

Isn't there a variable speed version of the Servo library somewhere?