Slowing down servos. How to write it into the program.

Hi everyone,
I am very new to all of this and have been tinkering extensively for several days working on a program to change the position of a servo between 0, 45 and 90 degrees by using a digital input. No input = 0 degrees, a HIGH input on digital pin 3 moves the servo to 45 degress and a HIGH input on digital pin 4 moves the servo to 90 degrees. What I am now having trouble programming is how to slow the movement of the servo down. What I am trying to emulate is a old style of railway signal used in NSW Australia for many years known as an upper quadrant signal. See photo Upper quadrant signal, NSW main south IMG_3663 (Medium) | Flickr . They are driven off a motor that moves realatively slowly i nreal life and that is what I am trying to emulate. I have been using the sweep sketch in the examples as a reference but have come up trumps after reading all the posts forums and books I have acess to and searching you tube. There is obviously something I am missing. If you need to see the sketch I am happy to post it. But the notes are incomplete at this stage.

Thanks in advance,
Briggsy

Write small angular increments to the Servo, with a delay between the writes.
Bonus marks for not using "delay()".

If you post your code, we can help you with it.

Here is the sketch.

//Upper Quadrant servo sketch 1
#include <Servo.h> 
 
Servo myservo;  // create servo object to control a servo 
                
int yellowState;
int greenState;
    
// constants won't change. They're used here to 
// set pin numbers:

const int yellowPin = 3; 
const int greenPin = 4;

void setup() 
{ 
  
 // initialize the trigger pins as an input:
   
pinMode(yellowPin, INPUT);
pinMode(greenPin, INPUT);
myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
}
 
void loop(){
 // read the state of the trigger value:
yellowState = digitalRead(yellowPin);
greenState = digitalRead(greenPin);

  // check if either of the triggers are HIGH
  // if it is, the relavant State is HIGH:
                      
if (yellowState == HIGH)  
                                   
    myservo.write(45);     //sends servo to 45 degrees         
    
if (greenState == HIGH)

   myservo.write(90);      //sends servo to 90 degrees
   
if ((yellowState == LOW) && (greenState == LOW))
   myservo.write(0);
}

Thanks for taking the time to have a look. I worked out how to play with the delay in the sweep example but I could never get it to work in my sketch.

Briggsy

As written, your servo will move as quickly as it can from one position to the next.
If, instead of a simple "servo.write (90);" you did something like (and I'm going to lose marks for this)

for (int angle = 0; angle < 90; angle+=10) {
  servo.write (angle);
  delay (50);
}

, your sweep will take longer.

Play with it, change the values, particularly the start, end and increment values (you don't want to go back to zero if you're already at 45 and moving to 90)

AWOL,
Thanks for the help but that has not appeared to have worked. I have tinkered gto the best of my knowledge. I there a way to just slow down the PWM change to the servo so that all of it's movements are slowed to the same rate? It just waved the servo about like a crazy thing.

Briggsy

It just waved the servo about like a crazy thing.

Time to put up or shut up. Where IS your code?

briggsy:
that has not appeared to have worked. I have tinkered gto the best of my knowledge.

Post your new code.

briggsy:
I there a way to just slow down the PWM change to the servo so that all of it's movements are slowed to the same rate? It just waved the servo about like a crazy thing.

Yes there is. It'd need some changes to your code, though. The approach I'd take is to add a variable holding the current position of the servo, and a variable that holds the target position. At the point in your code where you currently move the servo, just update the target position instead.

Add some code that runs at regular intervals - every 10 ms would be a reasonable starting point. Look at the 'blink without delay' example sketch to see how to do things at regular intervals. Every interval, compare the current and target position of the servo. If they're different then move the servo one unit towards the target position. You will need to experiment with the interval to get the speed of movement that you require.

This technique could be extended easily to support multiple servos - just convert the variables involved to arrays and add code to apply the logic above to each element in the array.

If you were looking to make a very modular and reusable solution, you might go one step further and create a class that contains this logic (i.e. a speed-limited servo).

There is a variable speed servo library somewhere.

My apologies. My aim is not to upset or annoy. I tinkered some more and got it to stop waving about by removing the time interval bit off the 90 degree part of the sketch. But it still moves quickly to 45 degrees with it in on that part. Here is how it currently stands.

//Upper Quadrant servo sketch 1
#include <Servo.h> 
 
Servo myservo;  // create servo object to control a servo 
                
int yellowState;
int greenState;
int angle = 0;    
// constants won't change. They're used here to 
// set pin numbers:

const int yellowPin = 3; 
const int greenPin = 4;

void setup() 
{ 
  
 // initialize the trigger pins as an input:
   
pinMode(yellowPin, INPUT);
pinMode(greenPin, INPUT);
myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
}
 
void loop(){
 // read the state of the trigger value:
yellowState = digitalRead(yellowPin);
greenState = digitalRead(greenPin);

  // check if either of the triggers are HIGH
  // if it is, the relavant State is HIGH:
                      
if (yellowState == HIGH)  
                                   
    for (int angle = 1; angle < 45; angle += 1) 
  myservo.write (angle);
  delay (100);
       //sends servo to 45 degrees         
    
if (greenState == HIGH)

  
  myservo.write (90);
  
        //sends servo to 90 degrees
   
if ((yellowState == LOW) && (greenState == LOW))
   
  myservo.write (0);
  
}

AWOL that sounds promising.

Thanks again for all the help,
Briggsy

if (yellowState == HIGH)  
                                   
    for (int angle = 1; angle < 45; angle += 1) 
  myservo.write (angle);
  delay (100);

When I wrote the example in reply #3, I very carefully put in a set of { } braces.
They're important, and they're missing from your code.

AWOL,
My apologies. I must have left them out after my tinkering. I'll have another go after I put them back in. My mistake.

Thanks again,
Briggsy

AWOL,
They are back in and it has slowed the servo down on the movement from 0 to 45 degrees but it now immediately returns to to zero degrees at full speed once it has reached 45 degrees. I'll include the updated code again.

//Upper Quadrant servo sketch 1
#include <Servo.h> 
 
Servo myservo;  // create servo object to control a servo 
                
int yellowState;
int greenState;
int angle = 0;    
// constants won't change. They're used here to 
// set pin numbers:

const int yellowPin = 3; 
const int greenPin = 4;

void setup() 
{ 
  
 // initialize the trigger pins as an input:
   
pinMode(yellowPin, INPUT);
pinMode(greenPin, INPUT);
myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
}
 
void loop(){
 // read the state of the trigger value:
yellowState = digitalRead(yellowPin);
greenState = digitalRead(greenPin);

  // check if either of the triggers are HIGH
  // if it is, the relavant State is HIGH:
                      
if (yellowState == HIGH)  
                                   
    for (int angle = 1; angle < 45; angle += 1){ 
  myservo.write (angle);
  delay (100);
    }
       //sends servo to 45 degrees         
    
if (greenState == HIGH)

  
  myservo.write (90);
  
        //sends servo to 90 degrees
   
if ((yellowState == LOW) && (greenState == LOW))
   
  myservo.write (0);
  
}

Thanks,
Briggsy

but it now immediately returns to to zero degrees at full speed once it has reached 45 degrees

Presumably because after four-and-a-half seconds, you've let go of the buttons, and they're both low again?

It would really help you understand what your code is doing if you put every { on a new line, and used Tools + Auto Format.

Code that jerks
all over the
page is very
hard to read.

Yes there is. It'd need some changes to your code, though. The approach I'd take is to add a variable holding the current position of the servo, and a variable that holds the target position. At the point in your code where you currently move the servo, just update the target position instead.

Add some code that runs at regular intervals - every 10 ms would be a reasonable starting point. Look at the 'blink without delay' example sketch to see how to do things at regular intervals. Every interval, compare the current and target position of the servo. If they're different then move the servo one unit towards the target position. You will need to experiment with the interval to get the speed of movement that you require.

This technique could be extended easily to support multiple servos - just convert the variables involved to arrays and add code to apply the logic above to each element in the array.

If you were looking to make a very modular and reusable solution, you might go one step further and create a class that contains this logic (i.e. a speed-limited servo).

PeterH,
Thanks for that info. I'll do some more reading and have a go at it fresh next time. It's late and I've annoyed you gentleman enough for now. Sorry for it being everywhere. I'm still learning how to clean it up without stuffing it up.

Thanks again,
Briggsy

You haven't annoyed us, but please bear with us when we're trying to decide at what level to pitch solutions.
I'm assuming that you're a modeller, and most modellers I know like to build up to a solution themselves, rather than being given the completed article.

i think my way of doing if it is just one servo to control

first i would declare a variable Current position
then i would declare a variable called target position
then i would make a function
in that function i would use an idea from blink without delay to increment the current position
if the current position still haven reach target loop again until it does
when it does keep the value of current position and then stop

ash901226:
i think my way of doing if it is just one servo to control

first i would declare a variable Current position
then i would declare a variable called target position
then i would make a function
in that function i would use an idea from blink without delay to increment the current position
if the current position still haven reach target loop again until it does
when it does keep the value of current position and then stop

The fundamental problem with that is that there is no feedback from the servo as to what position it presently is at if moving, from how far it has progressed from the previous position command given, and when it finally reaches the desired new position.

Servos have different speeds and speed can be effected by the amount of mechanical load placed on the servo. So one has to have a pretty well priory worked out 'characterization' for the specific servo under it's real world load condition, to even be able to estimate approximate position attained Vs time elapsed from last position command to new desired position.

It would be nice to have a higher order servo.write function something like:

moveServo(lastPosition, newPosition, step_Size_to_use, total_desired_Elapsed_time_for_completion)

But it would need to be non-blocking with some way to test when the function as completed? Probably really needs to be an addition integrated with the existing servo library.

Lefty

retrolefty:

ash901226:
i think my way of doing if it is just one servo to control

first i would declare a variable Current position
then i would declare a variable called target position
then i would make a function
in that function i would use an idea from blink without delay to increment the current position
if the current position still haven reach target loop again until it does
when it does keep the value of current position and then stop

The fundamental problem with that is that there is no feedback from the servo as to what position it presently is at if moving, from how far it has progressed from the previous position command given, and when it finally reaches the desired new position.

Servos have different speeds and speed can be effected by the amount of mechanical load placed on the servo. So one has to have a pretty well priory worked out 'characterization' for the specific servo under it's real world load condition, to even be able to estimate approximate position attained Vs time elapsed from last position command to new desired position.

It would be nice to have a higher order servo.write function something like:

moveServo(lastPosition, newPosition, step_Size_to_use, total_desired_Elapsed_time_for_completion)

But it would need to be non-blocking with some way to test when the function as completed? Probably really needs to be an addition integrated with the existing servo library.

Lefty

i know that a servo will not return a value, but in this case i would think that the by increment/decrement the value of current position will atleast give the arduino of what is the current position of the servo rite now... i guess you could say that its the same as how we control a stepper motor for a cnc machine... we do not know the actual position/ how much the stepper have rotate. but atleast we have some basic idea of where it should be....
btw retrolefty one thing that would say about servo that is better then a stepper motor is that if a stepper motor get stall, it will loose step and making the position we thick we at and the actual be false.
but for a servo once it receive a command to go to that point, the servo circuitry will make sure it reach that point. so we could actually safely asume that what we think we at and where it is actually is might just be true most of the time.(i say most of the time is due to unforeseen behavior).

and retrolefty if you dont mind hacking your servo to get angular measurement heres 2 link that might be useful
Trossen Robotics Community Database Error and
http://www.lynxmotion.net/viewtopic.php?f=2&t=2748

Have a look at.... Arduino servo sweep - Bajdi electronics for an article describing the VarSpeedServo library for Arduino..I have used this library and it works very well indeed!!

Best regards and good luck

David Garrison